From 001f12aa1576f93fbcec4d378a1e75474de73631 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Aleksander=20=C5=81ukasz?= Date: Mon, 18 Aug 2014 10:29:08 +0200 Subject: [PATCH] wip: experiments with Canvas support for exercise.assign Incomplete and somewhat messy: - partial custom element implementation (renders assignments when set manually via source editor), - experiments with mirroring elements on Canvas (partially working), - incomplete drag & drop code. --- .../modules/documentCanvas/canvas/canvas.js | 7 +- .../documentCanvas/canvas/container.js | 14 +- .../documentCanvas/canvas/documentElement.js | 64 +++++---- .../documentCanvas/canvas/genericElement.js | 3 +- .../modules/documentCanvas/canvas/utils.js | 26 +++- .../documentCanvas/canvas/wlxmlListener.js | 33 ++++- src/editor/plugins/core/edumed/actions.js | 6 + .../plugins/core/edumed/assign/assign.less | 21 +++ .../core/edumed/assign/destinationItem.html | 4 + .../plugins/core/edumed/assign/element.js | 77 ++++++++++ .../core/edumed/assign/sourceItem.html | 1 + .../plugins/core/edumed/assign/view.html | 12 ++ src/editor/plugins/core/edumed/assign/view.js | 135 ++++++++++++++++++ src/editor/plugins/core/edumed/edumed.js | 8 +- src/editor/plugins/core/edumed/edumed.less | 1 + 15 files changed, 367 insertions(+), 45 deletions(-) create mode 100644 src/editor/plugins/core/edumed/assign/assign.less create mode 100644 src/editor/plugins/core/edumed/assign/destinationItem.html create mode 100644 src/editor/plugins/core/edumed/assign/element.js create mode 100644 src/editor/plugins/core/edumed/assign/sourceItem.html create mode 100644 src/editor/plugins/core/edumed/assign/view.html create mode 100644 src/editor/plugins/core/edumed/assign/view.js diff --git a/src/editor/modules/documentCanvas/canvas/canvas.js b/src/editor/modules/documentCanvas/canvas/canvas.js index ebede40..5d432ea 100644 --- a/src/editor/modules/documentCanvas/canvas/canvas.js +++ b/src/editor/modules/documentCanvas/canvas/canvas.js @@ -120,8 +120,11 @@ $.extend(Canvas.prototype, Backbone.Events, { this.reloadRoot(); }, - createElement: function(wlxmlNode, register, useRoot) { + createElement: function(wlxmlNode, register, useRoot, params) { var Factory; + params = params || { + mirror: false + }; register = register || this.elementsRegister; if(wlxmlNode.nodeType === Node.TEXT_NODE) { Factory = documentElement.DocumentTextElement; @@ -136,7 +139,7 @@ $.extend(Canvas.prototype, Backbone.Events, { } if(Factory) { - return new Factory(wlxmlNode, this); + return new Factory(wlxmlNode, this, params); } }, diff --git a/src/editor/modules/documentCanvas/canvas/container.js b/src/editor/modules/documentCanvas/canvas/container.js index 663a159..28565bc 100644 --- a/src/editor/modules/documentCanvas/canvas/container.js +++ b/src/editor/modules/documentCanvas/canvas/container.js @@ -16,7 +16,7 @@ var Container = function(nodes, params, element) { this.element = element; nodes.forEach(function(node) { - var el = this.element.createElement(node); + var el = this.element.createElement(node, {mirror: this.mirrors}); if(el.dom) { this.dom.append(el.dom); } @@ -37,7 +37,7 @@ _.extend(Container.prototype, { var ptr = event.meta.node.prev(), referenceElement, referenceAction, actionArg; - while(ptr && !(referenceElement = utils.getElementForElementRootNode(ptr))) { + while(ptr && !(referenceElement = utils.getElementForElementRootNode(ptr, false, this))) { ptr = ptr.prev(); } @@ -50,13 +50,17 @@ _.extend(Container.prototype, { if(event.meta.move) { /* Let's check if this node had its own canvas element and it's accessible. */ - actionArg = utils.getElementForElementRootNode(event.meta.node); + actionArg = utils.getElementForElementRootNode(event.meta.node, false, this); } if(!actionArg) { actionArg = event.meta.node; } - referenceElement[referenceAction](actionArg); + if(referenceAction === 'after') { + referenceElement.after(actionArg, {mirror: this.mirrors}); + } else { + referenceElement[referenceAction](actionArg); + } }, onNodeDetached: function(event) { var container = this; @@ -104,7 +108,7 @@ _.extend(Container.prototype, { if(param instanceof documentElement.DocumentElement) { element = param; } else { - element = this.element.createElement(param);// + element = this.element.createElement(param, {mirror: this.mirrors});// } if(element.dom) { this.dom.prepend(element.dom); diff --git a/src/editor/modules/documentCanvas/canvas/documentElement.js b/src/editor/modules/documentCanvas/canvas/documentElement.js index a1965cd..c53f562 100644 --- a/src/editor/modules/documentCanvas/canvas/documentElement.js +++ b/src/editor/modules/documentCanvas/canvas/documentElement.js @@ -9,8 +9,12 @@ define([ /* global Node:false */ // DocumentElement represents a text or an element node from WLXML document rendered inside Canvas -var DocumentElement = function(wlxmlNode, canvas) { +var DocumentElement = function(wlxmlNode, canvas, params) { + params = params || { + mirror: false + }; this.wlxmlNode = wlxmlNode; + this.mirror = params.mirror; this.canvas = canvas; this.state = { exposed: false, @@ -19,7 +23,17 @@ var DocumentElement = function(wlxmlNode, canvas) { this.dom = this.createDOM(); this.dom.data('canvas-element', this); - this.wlxmlNode.setData('canvasElement', this); + + var mirrorElements = this.wlxmlNode.getData('mirrorElements'); + if(!mirrorElements) { + mirrorElements = []; + this.wlxmlNode.setData('mirrorElements', mirrorElements); + } + if(params.mirror) { + mirrorElements.push(this); + } else { + this.wlxmlNode.setData('canvasElement', this); + } }; $.extend(DocumentElement.prototype, { @@ -92,8 +106,8 @@ $.extend(DocumentElement.prototype, { // DocumentNodeElement represents an element node from WLXML document rendered inside Canvas -var DocumentNodeElement = function(wlxmlNode, canvas) { - DocumentElement.call(this, wlxmlNode, canvas); +var DocumentNodeElement = function(wlxmlNode, canvas, params) { + DocumentElement.call(this, wlxmlNode, canvas, params); this.containers = []; this.elementsRegister = canvas.createElementsRegister(); this.contextMenuActions = []; @@ -101,12 +115,12 @@ var DocumentNodeElement = function(wlxmlNode, canvas) { }; -var manipulate = function(e, params, action) { +var manipulate = function(e, params, action, params2) { var element; if(params instanceof DocumentElement) { element = params; } else { - element = e.createElement(params); + element = e.createElement(params, params2); } if(element.dom) { e.dom[action](element.dom); @@ -148,32 +162,34 @@ $.extend(DocumentNodeElement.prototype, { this.containers.splice(idx, 1); } }, - createElement: function(wlxmlNode) { + createElement: function(wlxmlNode, params) { + params = params || {mirror: false}; var parent = this.wlxmlNode.parent() ? utils.getElementForNode(this.wlxmlNode.parent()) : null; - return this.canvas.createElement(wlxmlNode, this.elementsRegister, !parent) || parent.createElement(wlxmlNode); + return this.canvas.createElement(wlxmlNode, this.elementsRegister, !parent, params) || parent.createElement(wlxmlNode, params); }, addToContextMenu: function(actionFqName) { this.contextMenuActions.push(this.canvas.createAction(actionFqName)); }, handle: function(event) { var method = 'on' + event.type[0].toUpperCase() + event.type.substr(1), - target; + containerExisted = false; if(event.type === 'nodeAdded' || event.type === 'nodeDetached') { this.containers.some(function(container) { if(container.manages(event.meta.node, event.meta.parent)) { - target = container; - return true; + //target = container; + container[method](event); + containerExisted = true; } }); } - if(!target && this[method]) { - target = this; + if(!containerExisted && this[method]) { + this[method](event); } - if(target) { - target[method](event); - } + // if(target) { + // target[method](event); + // } }, createDOM: function() { var wrapper = $('
').attr('document-node-element', ''), @@ -210,12 +226,12 @@ $.extend(DocumentNodeElement.prototype, { } return this; }, - before: function(params) { - return manipulate(this, params, 'before'); + before: function(params, params2) { + return manipulate(this, params, 'before', params2); }, - after: function(params) { - return manipulate(this, params, 'after'); + after: function(params, params2) { + return manipulate(this, params, 'after', params2); }, isBlock: function() { @@ -249,8 +265,8 @@ $.extend(DocumentNodeElement.prototype, { // DocumentNodeElement represents a text node from WLXML document rendered inside Canvas -var DocumentTextElement = function(wlxmlTextNode, canvas) { - DocumentElement.call(this, wlxmlTextNode, canvas); +var DocumentTextElement = function(wlxmlTextNode, canvas, params) { + DocumentElement.call(this, wlxmlTextNode, canvas, params); }; $.extend(DocumentTextElement, { @@ -297,7 +313,7 @@ $.extend(DocumentTextElement.prototype, { // Having at least Zero Width Space is guaranteed be Content Observer return this.dom.contents()[0].data === utils.unicode.ZWS; }, - after: function(params) { + after: function(params, params2) { if(params instanceof DocumentTextElement || params.text) { return false; } @@ -305,7 +321,7 @@ $.extend(DocumentTextElement.prototype, { if(params instanceof DocumentNodeElement) { element = params; } else { - element = this.parent().createElement(params); + element = this.parent().createElement(params, params2); } if(element.dom) { this.dom.wrap('
'); diff --git a/src/editor/modules/documentCanvas/canvas/genericElement.js b/src/editor/modules/documentCanvas/canvas/genericElement.js index fd0dfc4..44b340a 100644 --- a/src/editor/modules/documentCanvas/canvas/genericElement.js +++ b/src/editor/modules/documentCanvas/canvas/genericElement.js @@ -21,7 +21,8 @@ $.extend(generic, { this.container = this.createContainer(this.wlxmlNode.contents(), { manages: function(node) { return !node.isInside('comment'); }, - dom: this._container() + dom: this._container(), + mirrors: this.mirror }); this.commentsView = new CommentsView(this.wlxmlNode, this.canvas.metadata.user); diff --git a/src/editor/modules/documentCanvas/canvas/utils.js b/src/editor/modules/documentCanvas/canvas/utils.js index 620e652..3efc450 100644 --- a/src/editor/modules/documentCanvas/canvas/utils.js +++ b/src/editor/modules/documentCanvas/canvas/utils.js @@ -20,26 +20,38 @@ var nearestInDocumentOrder = function(selector, direction, element) { return null; }; -var getElementForElementRootNode = function(node) { - return node.getData('canvasElement'); +var getElementForElementRootNode = function(node, mirrors, canvasContainer) { + if(canvasContainer) { + var candidates = [node.getData('canvasElement')].concat(node.getData('mirrorElements')), + toret; + candidates.some(function(c) { + // @@ + if(c.dom.parents().index(canvasContainer.dom) !== -1) { + toret = c; + return true; + } + }); + return toret; + } + return node.getData(mirrors ? 'mirrorElements' : 'canvasElement'); }; -var getElementForNode = function(node) { +var getElementForNode = function(node, mirrors) { while(!node.getData('canvasElement')) { node = node.parent(); } - return node.getData('canvasElement'); + return node.getData(mirrors ? 'mirrorElements' : 'canvasElement'); }; -var getElementForDetachedNode = function(node, originalParent) { +var getElementForDetachedNode = function(node, originalParent, mirrors) { var ptr = originalParent; if(ptr === null) { - return node.getData('canvasElement'); + return node.getData(mirrors ? 'mirrorElements' : 'canvasElement'); } while(!ptr.getData('canvasElement')) { ptr = ptr.parent(); } - return ptr.getData('canvasElement'); + return ptr.getData(mirrors ? 'mirrorElements' : 'canvasElement'); }; var caretPositionFromPoint = function(x, y) { diff --git a/src/editor/modules/documentCanvas/canvas/wlxmlListener.js b/src/editor/modules/documentCanvas/canvas/wlxmlListener.js index b1a9582..ec626ac 100644 --- a/src/editor/modules/documentCanvas/canvas/wlxmlListener.js +++ b/src/editor/modules/documentCanvas/canvas/wlxmlListener.js @@ -35,14 +35,19 @@ $.extend(Listener.prototype, { var _metadataEventHandler = function(event) { - var element = utils.getElementForNode(event.meta.node); + var element = utils.getElementForNode(event.meta.node), + mirrors = utils.getElementForNode(event.meta.node, true); element.handle(event); + mirrors.forEach(function(mirror) { + mirror.handle(event); + }); }; var handlers = { nodeAttrChange: function(event) { var element = utils.getElementForNode(event.meta.node), + mirrors = utils.getElementForNode(event.meta.node, true), newElement; if(event.meta.attr === 'class') { if(element.wlxmlNode.getClass() !== event.meta.attr) { @@ -51,11 +56,18 @@ var handlers = { } else { newElement = element.parent().createElement(event.meta.node); element.dom.replaceWith(newElement.dom); + mirrors.forEach(function(mirror) { + var newElement = element.parent().createElement(event.meta.node, true); + mirror.dom.replaceWith(newElement.dom); + }); } } } else { element.handle(event); + mirrors.forEach(function(mirror) { + mirror.handle(event); + }); } }, nodeAdded: function(event) { @@ -63,19 +75,30 @@ var handlers = { this.canvas.reloadRoot(); return; } - var containingNode = event.meta.node.parent(), - containingElement = utils.getElementForNode(containingNode); + containingElement = utils.getElementForNode(containingNode), + mirrors = utils.getElementForNode(containingNode, true); containingElement.handle(event); + mirrors.forEach(function(mirror) { + mirror.handle(event); + }); }, nodeDetached: function(event) { - var element = utils.getElementForDetachedNode(event.meta.node, event.meta.parent); + var element = utils.getElementForDetachedNode(event.meta.node, event.meta.parent), + mirrors = utils.getElementForDetachedNode(event.meta.node, event.meta.parent, true); element.handle(event); + mirrors.forEach(function(mirror) { + mirror.handle(event); + }); }, nodeTextChange: function(event) { - var element = utils.getElementForNode(event.meta.node); + var element = utils.getElementForNode(event.meta.node), + mirrors = utils.getElementForNode(event.meta.node, true); element.handle(event); + mirrors.forEach(function(mirror) { + mirror.handle(event); + }); }, metadataChanged: _metadataEventHandler, diff --git a/src/editor/plugins/core/edumed/actions.js b/src/editor/plugins/core/edumed/actions.js index b79d109..4db4bc9 100644 --- a/src/editor/plugins/core/edumed/actions.js +++ b/src/editor/plugins/core/edumed/actions.js @@ -50,6 +50,11 @@ var createAction = function(actionConfig) { if(cursorTarget) { cursorTarget = cursorTarget.append({text: ''}); } + } else if(actionConfig.exercise === 'assign') { + cursorTarget = _.first(exerciseNode.contents('.p')); + if(cursorTarget) { + cursorTarget = cursorTarget.append({text: descriptionText}); + } } if(cursorTarget) { callback(doc.createFragment(doc.CaretFragment, {node: cursorTarget, offset: cursorTarget.getText().length})); @@ -69,6 +74,7 @@ var createAction = function(actionConfig) { }; return [ + createAction({name: 'insertAssignExercise', icon: 'resize-horizontal', exercise: 'assign', exerciseTitle: gettext('Assign')}), createAction({name: 'insertOrderExercise', icon: 'random', exercise: 'order', exerciseTitle: gettext('Order')}), createAction({name: 'insertChoiceSingleExercise', icon: 'ok-circle', exercise: 'choice.single', exerciseTitle: gettext('Single Choice')}), createAction({name: 'insertChoiceMultiExercise', icon: 'check', exercise: 'choice', exerciseTitle: gettext('Multiple Choice')}), diff --git a/src/editor/plugins/core/edumed/assign/assign.less b/src/editor/plugins/core/edumed/assign/assign.less new file mode 100644 index 0000000..caeadd4 --- /dev/null +++ b/src/editor/plugins/core/edumed/assign/assign.less @@ -0,0 +1,21 @@ +.exercise-assign { + .sources, .destinations { + width: 50%; + } + + .source-item { + border: 1px solid lighten(@green, 30%); + } + .destination-item { + border: 1px solid lighten(@red, 30%); + } + + .assignments { + margin-top: 5px; + border-top: 1px solid darken(#ddd,15%); + } + .wrapper { + border: 1px dashed #ddd; + margin: 5px 0; + } +} \ No newline at end of file diff --git a/src/editor/plugins/core/edumed/assign/destinationItem.html b/src/editor/plugins/core/edumed/assign/destinationItem.html new file mode 100644 index 0000000..42f5a50 --- /dev/null +++ b/src/editor/plugins/core/edumed/assign/destinationItem.html @@ -0,0 +1,4 @@ +
+
+
+
\ No newline at end of file diff --git a/src/editor/plugins/core/edumed/assign/element.js b/src/editor/plugins/core/edumed/assign/element.js new file mode 100644 index 0000000..cec77db --- /dev/null +++ b/src/editor/plugins/core/edumed/assign/element.js @@ -0,0 +1,77 @@ +define(function(require) { + +'use strict'; + + +var _ = require('libs/underscore'); + +var elementBase = require('plugins/core/edumed/elementBase'), + AssignExerciseView = require('./view'); + +var AssignExerciseElement = Object.create(elementBase); +_.extend(AssignExerciseElement, { + init: function() { + elementBase.init.call(this); + + this.view = new AssignExerciseView(this, this.wlxmlNode); + this._container().append(this.view.dom); + + this.view.on('assignmentAdded', function() { + + }.bind(this)); + + this.view.on('assignmentRemoved', function() { + + }.bind(this)); + + + var exerciseNode = this.wlxmlNode; + this.createContainer(this.wlxmlNode.object.getDescription(), { + resetBackground: true, + manages: function(node, removedFrom) { + if(exerciseNode.object.isList(node) || (removedFrom && exerciseNode.object.isList(removedFrom))) { + return false; + } + return exerciseNode.sameNode(node.parent() || removedFrom); + }.bind(), + dom: this.view.dom.find('.description') + }); + + this.reloadView(); + }, + onNodeAdded: function(event) { + var node = event.meta.node; + if(this.wlxmlNode.object.isItemNode(node)) { + this.reloadView(); + } + }, + onNodeAttrChange: function(event) { + void(event); + }, + onNodeDetached: function(event) { + if(this.wlxmlNode.object.isItemNode(event.meta.node, event.meta.parent)) { + this.reloadView(); + } + }, + reloadView: function() { + this.view.clearItems(); + this.wlxmlNode.object.getSourceItems().forEach(function(item) { + this.view.addSourceItem(item); + }.bind(this)); + this.wlxmlNode.object.getDestinationItems().forEach(function(item) { + this.view.addDestinationItem(item); + }.bind(this)); + }, + getVerticallyFirstTextElement: function() { + var toret; + this.containers.some(function(container) { + toret = container.getVerticallyFirstTextElement(); + return !!toret; + }); + return toret; + } +}); + +return {tag: 'div', klass: 'exercise.assign', prototype: AssignExerciseElement}; + +}); diff --git a/src/editor/plugins/core/edumed/assign/sourceItem.html b/src/editor/plugins/core/edumed/assign/sourceItem.html new file mode 100644 index 0000000..3ba53f5 --- /dev/null +++ b/src/editor/plugins/core/edumed/assign/sourceItem.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/editor/plugins/core/edumed/assign/view.html b/src/editor/plugins/core/edumed/assign/view.html new file mode 100644 index 0000000..6228d5c --- /dev/null +++ b/src/editor/plugins/core/edumed/assign/view.html @@ -0,0 +1,12 @@ +
+
<%= gettext('Exercise') %>: <%= gettext('Assign') %>
+
+ + + + + + +
+
+
\ No newline at end of file diff --git a/src/editor/plugins/core/edumed/assign/view.js b/src/editor/plugins/core/edumed/assign/view.js new file mode 100644 index 0000000..bfd2a0f --- /dev/null +++ b/src/editor/plugins/core/edumed/assign/view.js @@ -0,0 +1,135 @@ +define(function(require) { + +'use strict'; +var $ = require('libs/jquery'); + +var _ = require('libs/underscore'), + Backbone = require('libs/backbone'), + viewTemplate = require('libs/text!./view.html'), + sourceItemTemplate = require('libs/text!./sourceItem.html'), + destinationItemTemplate = require('libs/text!./destinationItem.html'); + + +var AssignExerciseView = function(element) { + this.element = element; + this.dom = $(_.template(viewTemplate)()); + this.modePills = this.dom.find('.modePills'); + this.sources = this.dom.find('.sources'); + this.destinations = this.dom.find('.destinations'); + this.description = this.dom.find('.description'); + this.sourceItemViews = []; + this.destinationItemViews = []; +}; + +_.extend(AssignExerciseView.prototype, Backbone.Events, { + addSourceItem: function(item) { + var view = new SourceItemView(item, this); + this.sources.append(view.dom); + this.sourceItemViews.push(view); + }, + addDestinationItem: function(item) { + var view = new DestinationItemView(item, this); + view.on('receivedDrop', function(sourceItem, destinationItem) { + //this.trigger(this.mode === 'initial' ? 'moveItem' : 'moveAnswer', droppedItem.item, item, 'after'); + sourceItem.assignTo(destinationItem); + }.bind(this)); + this.destinations.append(view.dom); + this.destinationItemViews.push(view); + }, + clearItems: function() { + this.sources.empty(); + this.destinations.empty(); + this.sourceItemViews.concat(this.destinationItemViews).forEach(function(view) { + view.remove(); + }); + this.sourceItemViews = []; + this.destinationItemViews = []; + } +}); + +var SourceItemView = function(item, exerciseView) { + this.item = item; + this.exerciseView = exerciseView; + this.dom = $(_.template(sourceItemTemplate)()); + + + var dragSources = this.dom.find('.handle'); + + dragSources.on('dragstart', function(e) { + e.originalEvent.dataTransfer.setData('text', this.dom.attr('sourceItemId')); + e.originalEvent.effectAllowed = 'move'; + + }.bind(this)); + + this.container = exerciseView.element.createContainer(item.node.contents(), { + resetBackground: true, + manages: function(node, originaParent) { + return item.node.sameNode(node.parent() || originaParent); + }, + dom: this.dom + }); + + this.dom.data('item', this.item); + this.dom.attr('itemDOMID', _.uniqueId()); +}; + +_.extend(SourceItemView.prototype, Backbone.Events, { + remove: function() { + this.container.remove(); + } +}); + +var DestinationItemView = function(item, exerciseView) { + this.item = item; + this.exerciseView = exerciseView; + this.dom = $(_.template(destinationItemTemplate)()); + + this.dom.on('dragover', function(e) { + e.preventDefault(); + e.originalEvent.dataTransfer.dropEffect = 'move'; + }); + + this.dom.on('drop', function(e) { + var DOMID = e.originalEvent.dataTransfer.getData('text'), + sourceItem = $('[DOMID='+DOMID+']').data('item'); + e.preventDefault(); + this.trigger('receivedDrop', sourceItem, this.item); + }.bind(this)); + + this.container = exerciseView.element.createContainer(item.node.contents(), { + resetBackground: true, + manages: function(node, originaParent) { + return item.node.sameNode(node.parent() || originaParent); + }, + dom: this.dom.find('.content') + }); + + this.containers = []; + + this.item.getAssignedSources().forEach(function(sourceItem) { + var wrapper = $('
'); + var container = exerciseView.element.createContainer(sourceItem.contents(), { + resetBackground: true, + manages: function(node, originaParent) { + return sourceItem.node.sameNode(node.parent() || originaParent); + }, + dom: wrapper, + mirrors: true + }); + this.containers.push(container); + + this.dom.find('.assignments').append(container.dom); + }.bind(this)); +}; +_.extend(DestinationItemView.prototype, Backbone.Events, { + remove: function() { + this.container.remove(); + this.containers.forEach(function(container) { + container.remove(); + }); + } +}); + +return AssignExerciseView; + +}); diff --git a/src/editor/plugins/core/edumed/edumed.js b/src/editor/plugins/core/edumed/edumed.js index 6ba5996..dd5b013 100644 --- a/src/editor/plugins/core/edumed/edumed.js +++ b/src/editor/plugins/core/edumed/edumed.js @@ -5,6 +5,7 @@ define(function(require) { var actions = require('./actions'), gapsActions = require('./gaps/actions'), replaceActions = require('./replace/actions'), + assignExerciseElement = require('./assign/element'), orderExerciseElement = require('./order/element'), gapsExerciseElement = require('./gaps/element'), replaceExerciseElement = require('./replace/element'), @@ -12,7 +13,12 @@ var actions = require('./actions'), return { actions: actions.concat(gapsActions).concat(replaceActions), - canvasElements: [orderExerciseElement, gapsExerciseElement, replaceExerciseElement].concat(choiceExerciseElements) + canvasElements: [ + assignExerciseElement, + orderExerciseElement, + gapsExerciseElement, + replaceExerciseElement + ].concat(choiceExerciseElements) }; }); \ No newline at end of file diff --git a/src/editor/plugins/core/edumed/edumed.less b/src/editor/plugins/core/edumed/edumed.less index fc79e39..9d0928f 100644 --- a/src/editor/plugins/core/edumed/edumed.less +++ b/src/editor/plugins/core/edumed/edumed.less @@ -1,3 +1,4 @@ +@import 'assign/assign.less'; @import 'order/order.less'; @import 'gaps/gaps.less'; @import 'replace/replace.less'; -- 2.20.1