/** * XBlockEditorView displays the authoring view of an xblock, and allows the user to switch between * the available modes. */ define(['jquery', 'underscore', 'gettext', 'js/views/baseview', 'js/views/xblock', 'js/views/metadata', 'js/collections/metadata', 'jquery.inputnumber'], function($, _, gettext, BaseView, XBlockView, MetadataView, MetadataCollection) { var XBlockEditorView = XBlockView.extend({ // takes XBlockInfo as a model options: $.extend({}, XBlockView.prototype.options, { view: 'studio_view' }), initialize: function() { XBlockView.prototype.initialize.call(this); this.view = this.options.view; }, xblockReady: function(xblock) { XBlockView.prototype.xblockReady.call(this, xblock); this.initializeEditors(); }, initializeEditors: function() { var metadataEditor, pluginEl, defaultMode = 'editor'; metadataEditor = this.createMetadataEditor(); this.metadataEditor = metadataEditor; if (!this.hasCustomTabs()) { if (this.getDataEditor()) { defaultMode = 'editor'; } else if (metadataEditor) { defaultMode = 'settings'; } this.selectMode(defaultMode); } pluginEl = this.$('.wrapper-comp-plugins'); if (pluginEl.length > 0) { this.pluginEditor = new BaseView({ el: pluginEl }); } }, getDefaultModes: function() { return [ {id: 'editor', name: gettext('Editor')}, {id: 'settings', name: gettext('Settings')} ]; }, hasCustomTabs: function() { return this.$('.editor-with-tabs').length > 0; }, hasCustomButtons: function() { return this.$('.editor-with-buttons').length > 0; }, createMetadataEditor: function() { var metadataEditor, metadataData, models = [], key, xblock = this.xblock, metadataView = null; metadataEditor = this.$('.metadata_edit'); if (metadataEditor.length === 1) { metadataData = metadataEditor.data('metadata'); for (key in metadataData) { if (metadataData.hasOwnProperty(key)) { models.push(metadataData[key]); } } metadataView = new MetadataView.Editor({ el: metadataEditor, collection: new MetadataCollection(models) }); if (xblock.setMetadataEditor) { xblock.setMetadataEditor(metadataView); } } return metadataView; }, getDataEditor: function() { var editor = this.$('.wrapper-comp-editor'); return editor.length === 1 ? editor : null; }, getMetadataEditor: function() { return this.metadataEditor; }, getPluginEditor: function() { return this.pluginEditor; }, /** * Returns the updated field data for the xblock. Note that this works for all * XModules as well as for XBlocks that provide a 'collectFieldData' API. */ getXBlockFieldData: function() { var xblock = this.xblock, metadataEditor = this.getMetadataEditor(), data = null; // If the xblock supports returning its field data then collect it if (xblock.collectFieldData) { data = xblock.collectFieldData(); // ... else if this is an XModule then call its save method } else if (xblock.save) { data = xblock.save(); if (metadataEditor) { data.metadata = _.extend(data.metadata || {}, this.getChangedMetadata()); } // ... else log an error } else { console.error('Cannot save xblock as it has no save method'); } return data; }, /** * Returns the metadata that has changed in the editor. This is a combination of the metadata * modified in the "Settings" editor, as well as any custom metadata provided by the component. */ getChangedMetadata: function() { var metadataEditor = this.getMetadataEditor(); return _.extend(metadataEditor.getModifiedMetadataValues(), this.getCustomMetadata()); }, /** * Returns custom metadata defined by a particular xmodule that aren't part of the metadata editor. * In particular, this is used for LaTeX high level source. */ getCustomMetadata: function() { // Walk through the set of elements which have the 'data-metadata_name' attribute and // build up an object to pass back to the server on the subsequent POST. // Note that these values will always be sent back on POST, even if they did not actually change. var metadata, metadataNameElements, i, element, metadataName; metadata = {}; metadataNameElements = this.$('[data-metadata-name]'); for (i = 0; i < metadataNameElements.length; i++) { element = metadataNameElements[i]; metadataName = $(element).data('metadata-name'); metadata[metadataName] = element.value; } return metadata; }, getMode: function() { return this.mode; }, selectMode: function(mode) { var dataEditor = this.getDataEditor(), metadataEditor = this.getMetadataEditor(), pluginEditor = this.getPluginEditor(); if (dataEditor) { this.setEditorActivation(dataEditor, mode === 'editor'); } if (metadataEditor) { this.setEditorActivation(metadataEditor.$el, mode === 'settings'); } if (pluginEditor) { this.setEditorActivation(pluginEditor.$el, mode === 'plugins'); } this.mode = mode; }, setEditorActivation: function(editor, isActive) { editor.removeClass('is-active').removeClass('is-inactive'); editor.addClass(isActive ? 'is-active' : 'is-inactive'); } }); return XBlockEditorView; }); // end define();