From ce3638538cd2d04c1a33258b9cfba36747920be1 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Wed, 26 Sep 2012 15:45:45 -0400 Subject: [PATCH] Make inline editing save to mongo and then update the preview --- cms/djangoapps/contentstore/views.py | 5 +- cms/static/coffee/src/models/module.coffee | 22 +- .../coffee/src/views/module_edit.coffee | 84 +++---- cms/static/js/base.js | 235 +++++++++--------- .../xmodule/js/src/sequence/display.coffee | 2 +- common/static/coffee/src/xmodule.coffee | 51 ++-- common/templates/xmodule_edit.html | 6 +- lms/static/coffee/src/courseware.coffee | 2 +- 8 files changed, 206 insertions(+), 201 deletions(-) diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py index adcffe100e..a9961c1b9d 100644 --- a/cms/djangoapps/contentstore/views.py +++ b/cms/djangoapps/contentstore/views.py @@ -327,7 +327,10 @@ def load_preview_module(request, preview_id, descriptor, instance_state, shared_ module, "xmodule_edit.html", { + 'location': descriptor.location.url(), 'editor_content': descriptor.get_html(), + 'editor_type': descriptor.js_module_name, + 'editor_class': descriptor.__class__.__name__, # TODO (cpennington): Make descriptors know if they have data that can be editng 'editable_data': descriptor.definition.get('data'), 'editable_class': 'editable' if descriptor.definition.get('data') else '', @@ -396,7 +399,7 @@ def save_item(request): export_to_github(course, "CMS Edit", author_string) descriptor = modulestore().get_item(item_location) - preview_html = get_module_previews(request, descriptor) + preview_html = get_module_previews(request, descriptor)[0] return HttpResponse(json.dumps(preview_html)) diff --git a/cms/static/coffee/src/models/module.coffee b/cms/static/coffee/src/models/module.coffee index 52357795ed..c3988b26e0 100644 --- a/cms/static/coffee/src/models/module.coffee +++ b/cms/static/coffee/src/models/module.coffee @@ -5,24 +5,12 @@ class CMS.Models.Module extends Backbone.Model children: '' metadata: {} - loadModule: (element) -> - elt = $(element).find('.xmodule_edit').first() - @module = XModule.loadModule(elt) - # find the metadata edit region which should be setup server side, - # so that we can wire up posting back those changes - @metadata_elt = $(element).find('.metadata_edit') - - editUrl: -> - "/edit_item?#{$.param(id: @get('id'))}" + initialize: (attributes) -> + @module = attributes.module + @unset('module') + delete attributes.module + super(attributes) save: (args...) -> @set(data: @module.save()) if @module - # cdodge: package up metadata which is separated into a number of input fields - # there's probably a better way to do this, but at least this lets me continue to move onwards - if @metadata_elt - _metadata = {} - # walk through the set of elments which have the 'xmetadata_name' attribute and - # build up a object to pass back to the server on the subsequent POST - _metadata[$(el).data("metadata-name")]=el.value for el in $('[data-metadata-name]', @metadata_elt) - @set(metadata: _metadata) super(args...) diff --git a/cms/static/coffee/src/views/module_edit.coffee b/cms/static/coffee/src/views/module_edit.coffee index 2c4eb26eff..b9d0245ed9 100644 --- a/cms/static/coffee/src/views/module_edit.coffee +++ b/cms/static/coffee/src/views/module_edit.coffee @@ -1,60 +1,60 @@ class CMS.Views.ModuleEdit extends Backbone.View - tagName: 'section' - className: 'edit-pane' - - events: - 'click .cancel': 'cancel' - 'click .module-edit': 'editSubmodule' - 'click .save-update': 'save' + tagName: 'div' + className: 'xmodule_edit' initialize: -> - @$el.load @model.editUrl(), => - @model.loadModule(@el) + @delegate() - # Load preview modules - XModule.loadModules('display') - @$children = @$el.find('#sortable') - @enableDrag() + @$component_editor = @$el.find('.component-editor') + @$metadata = @$component_editor.find('.metadata_edit') - enableDrag: => - # Enable dragging things in the #sortable div (if there is one) - if @$children.length > 0 - @$children.sortable( - placeholder: "ui-state-highlight" - update: (event, ui) => - @model.set(children: @$children.find('.module-edit').map( - (idx, el) -> $(el).data('id') - ).toArray()) - ) - @$children.disableSelection() + delegate: -> + id = @$el.data('id') + + events = {} + events["click .component-editor[data-id=#{ id }] .cancel-button"] = 'cancel' + events["click .component-editor[data-id=#{ id }] .save-button"] = 'save' + events["click .component-actions[data-id=#{ id }] .edit-button"] = 'edit' + + @delegateEvents(events) + + metadata: -> + # cdodge: package up metadata which is separated into a number of input fields + # there's probably a better way to do this, but at least this lets me continue to move onwards + _metadata = {} + + if @$metadata + # walk through the set of elments which have the 'xmetadata_name' attribute and + # build up a object to pass back to the server on the subsequent POST + _metadata[$(el).data("metadata-name")] = el.value for el in $('[data-metadata-name]', @$metadata) + + _metadata save: (event) => event.preventDefault() - @model.save().done((previews) => + @model.save( + metadata: @metadata() + ).done((preview) => alert("Your changes have been saved.") - previews_section = @$el.find('.previews').empty() - $.each(previews, (idx, preview) => - preview_wrapper = $('
', class: 'preview').append preview - previews_section.append preview_wrapper - ) + + new_el = $(preview) + @$el.replaceWith(new_el) + @$el = new_el - XModule.loadModules('display') + @delegate() + + @model.module = XModule.loadModule(@$el) + XModule.loadModules(@$el) ).fail( -> alert("There was an error saving your changes. Please try again.") ) cancel: (event) -> event.preventDefault() - CMS.popView() - @enableDrag() + @$el.removeClass('editing') + @$component_editor.slideUp(150) - editSubmodule: (event) -> + edit: (event) -> event.preventDefault() - previewType = $(event.target).data('preview-type') - moduleType = $(event.target).data('type') - CMS.pushView new CMS.Views.ModuleEdit - model: new CMS.Models.Module - id: $(event.target).data('id') - type: if moduleType == 'None' then null else moduleType - previewType: if previewType == 'None' then null else previewType - @enableDrag() + @$el.addClass('editing') + @$component_editor.slideDown(150) diff --git a/cms/static/js/base.js b/cms/static/js/base.js index a82984c5c1..c560524676 100644 --- a/cms/static/js/base.js +++ b/cms/static/js/base.js @@ -6,162 +6,175 @@ var $newComponentStep1; var $newComponentStep2; $(document).ready(function() { - $body = $('body'); - $modal = $('.history-modal'); - $modalCover = $('.modal-cover'); - $newComponentItem = $('.new-component-item'); - $newComponentStep1 = $('.new-component-step-1'); - $newComponentStep2 = $('.new-component-step-2'); - $newComponentButton = $('.new-component-button'); + $body = $('body'); + $modal = $('.history-modal'); + $modalCover = $('.modal-cover'); + $newComponentItem = $('.new-component-item'); + $newComponentStep1 = $('.new-component-step-1'); + $newComponentStep2 = $('.new-component-step-2'); + $newComponentButton = $('.new-component-button'); - $('.expand-collapse-icon').bind('click', toggleSubmodules); - $('.visibility-options').bind('change', setVisibility); + $(document).bind('XModule.loaded', function(e, element) { + if ($(element).hasClass('.xmodule_display')) { + return + } + var previewType = $(element).data('preview-type'); + var moduleType = $(element).data('type'); + new CMS.Views.ModuleEdit({ + el: element, + model: new CMS.Models.Module({ + module: $(element).data('module'), + id: $(element).data('id'), + type: moduleType == 'None' ? null : moduleType, + previewType: previewType == 'None' ? null : previewType, + }) + }); + }); + XModule.loadModules() - $body.delegate('.xmodule_edit .edit-button', 'click', editComponent); - $body.delegate('.component-editor .save-button, .component-editor .cancel-button', 'click', closeComponentEditor); + $('.expand-collapse-icon').bind('click', toggleSubmodules); + $('.visibility-options').bind('change', setVisibility); - $newComponentButton.bind('click', showNewComponentForm); - $newComponentStep1.find('.new-component-type a').bind('click', showNewComponentProperties); - $newComponentStep2.find('.save-button').bind('click', saveNewComponent); - $newComponentStep2.find('.cancel-button').bind('click', cancelNewComponent); + $newComponentButton.bind('click', showNewComponentForm); + $newComponentStep1.find('.new-component-type a').bind('click', showNewComponentProperties); + $newComponentStep2.find('.save-button').bind('click', saveNewComponent); + $newComponentStep2.find('.cancel-button').bind('click', cancelNewComponent); - $('.unit-history ol a').bind('click', showHistoryModal); - $modal.bind('click', hideHistoryModal); - $modalCover.bind('click', hideHistoryModal); - - XModule.loadModules('display'); + $('.unit-history ol a').bind('click', showHistoryModal); + $modal.bind('click', hideHistoryModal); + $modalCover.bind('click', hideHistoryModal); }); function toggleSubmodules(e) { - e.preventDefault(); - $(this).toggleClass('expand').toggleClass('collapse'); - $(this).closest('.branch, .window').toggleClass('collapsed'); + e.preventDefault(); + $(this).toggleClass('expand').toggleClass('collapse'); + $(this).closest('.branch, .window').toggleClass('collapsed'); } function setVisibility(e) { - $(this).find('.checked').removeClass('checked'); - $(e.target).closest('.option').addClass('checked'); + $(this).find('.checked').removeClass('checked'); + $(e.target).closest('.option').addClass('checked'); } function editComponent(e) { - e.preventDefault(); - $(this).closest('.xmodule_edit').addClass('editing').find('.component-editor').slideDown(150); + e.preventDefault(); + $(this).closest('.xmodule_edit').addClass('editing').find('.component-editor').slideDown(150); } function closeComponentEditor(e) { - e.preventDefault(); - $(this).closest('.xmodule_edit').removeClass('editing').find('.component-editor').slideUp(150); + e.preventDefault(); + $(this).closest('.xmodule_edit').removeClass('editing').find('.component-editor').slideUp(150); } function showNewComponentForm(e) { - e.preventDefault(); - $newComponentItem.addClass('adding'); - $(this).slideUp(150); - $newComponentStep1.slideDown(150); + e.preventDefault(); + $newComponentItem.addClass('adding'); + $(this).slideUp(150); + $newComponentStep1.slideDown(150); } function showNewComponentProperties(e) { - e.preventDefault(); + e.preventDefault(); - var displayName; - var componentSource; - var selectionRange; - var $renderedComponent; + var displayName; + var componentSource; + var selectionRange; + var $renderedComponent; - switch($(this).attr('data-type')) { - case 'video': - displayName = 'Video'; - componentSource = '