From 3dfe15d50b60598341b9754876db4a48162c5cd0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Aleksander=20=C5=81ukasz?= Date: Thu, 3 Jul 2014 16:32:47 +0200 Subject: [PATCH 1/1] editor: core plugin - edumed - first take on replace exercise --- src/editor/plugins/core/edumed/edumed.js | 8 +- src/editor/plugins/core/edumed/edumed.less | 1 + .../plugins/core/edumed/replace/actions.js | 154 ++++++++++++++++++ .../plugins/core/edumed/replace/element.js | 86 ++++++++++ .../plugins/core/edumed/replace/replace.less | 16 ++ .../plugins/core/edumed/replace/tip.html | 2 + .../plugins/core/edumed/replace/view.html | 4 + 7 files changed, 268 insertions(+), 3 deletions(-) create mode 100644 src/editor/plugins/core/edumed/replace/actions.js create mode 100644 src/editor/plugins/core/edumed/replace/element.js create mode 100644 src/editor/plugins/core/edumed/replace/replace.less create mode 100644 src/editor/plugins/core/edumed/replace/tip.html create mode 100644 src/editor/plugins/core/edumed/replace/view.html diff --git a/src/editor/plugins/core/edumed/edumed.js b/src/editor/plugins/core/edumed/edumed.js index 25f31c9..e4a330b 100644 --- a/src/editor/plugins/core/edumed/edumed.js +++ b/src/editor/plugins/core/edumed/edumed.js @@ -4,12 +4,14 @@ define(function(require) { var actions = require('./actions'), gapsActions = require('./gaps/actions'), + replaceActions = require('./replace/actions'), orderExerciseElement = require('./order/element'), - gapsExerciseElement = require('./gaps/element'); + gapsExerciseElement = require('./gaps/element'), + replaceExerciseElement = require('./replace/element'); return { - actions: actions.concat(gapsActions), - canvasElements: [orderExerciseElement, gapsExerciseElement] + actions: actions.concat(gapsActions).concat(replaceActions), + canvasElements: [orderExerciseElement, gapsExerciseElement, replaceExerciseElement] }; }); \ 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 248bedb..e1a2c4d 100644 --- a/src/editor/plugins/core/edumed/edumed.less +++ b/src/editor/plugins/core/edumed/edumed.less @@ -1,5 +1,6 @@ @import 'order/order.less'; @import 'gaps/gaps.less'; +@import 'replace/replace.less'; .edumed-exercise { diff --git a/src/editor/plugins/core/edumed/replace/actions.js b/src/editor/plugins/core/edumed/replace/actions.js new file mode 100644 index 0000000..be4782a --- /dev/null +++ b/src/editor/plugins/core/edumed/replace/actions.js @@ -0,0 +1,154 @@ +define(function(require) { + +'use strict'; + +/* globals gettext */ + +var _ = require('libs/underscore'), + Dialog = require('views/dialog/dialog'); + +var markToReplace = { + name: 'markToReplace', + params: { + fragment: {type: 'context', name: 'fragment'} + }, + stateDefaults: { + icon: null, + label: gettext('Mark to replace'), + execute: function(callback, params) { + var doc = params.fragment.document, + dialog = Dialog.create({ + title: gettext('Enter text to replace with'), + executeButtonText: gettext('Apply'), + cancelButtonText: gettext('Cancel'), + fields: [ + {label: gettext('Text'), name: 'text', type: 'input'} + ] + }); + + + dialog.on('execute', function(event) { + doc.transaction(function() { + var wrapper = params.fragment.startNode.parent().wrapText({ + _with: {tagName: 'span', attrs: {'class': 'answer', answer: event.formData.text}}, + offsetStart: params.fragment.startOffset, + offsetEnd: params.fragment.endOffset, + textNodeIdx: [params.fragment.startNode.getIndex(), params.fragment.endNode.getIndex()] + }), + last = _.last(wrapper.contents()); + + return doc.createFragment(doc.CaretFragment, {node: last, offset: last.getText().length}); + }, { + metadata: { + description: gettext('Mark to replace') + }, + success: function(ret) { event.success(); callback(ret);} + }); + }); + dialog.show(); + + } + }, + getState: function(params) { + return { + allowed: params.fragment && + params.fragment.isValid() && + params.fragment instanceof params.fragment.TextRangeFragment && + params.fragment.hasSameBoundries() && + params.fragment.startNode.isInside('exercise.replace') && + !params.fragment.startNode.isInside({tagName: 'span', klass: 'answer'}), + + description: gettext('Mark selection to replacement') + }; + } +}; + +var removeReplaceMark = { + name: 'removeReplaceMark', + params: { + fragment: {type: 'context', name: 'fragment'} + }, + stateDefaults: { + icon: null, + label: gettext('Remove replace mark'), + execute: function(callback, params) { + var doc = params.fragment.document; + + doc.transaction(function() { + var ret = params.fragment.node.getParent('answer').unwrapContent(); + + return doc.createFragment(doc.CaretFragment, {node:ret.element2, offset: ret.element2.getText().length}); + }, { + metadata: { + description: gettext('Remove replace mark') + }, + success: callback + }); + } + }, + getState: function(params) { + return { + allowed: params.fragment && + params.fragment.isValid() && + params.fragment instanceof params.fragment.NodeFragment && + params.fragment.node.isInside('exercise.replace') && + params.fragment.node.isInside('answer'), + + description: gettext('Remove replace mark') + }; + } +}; + +var editReplaceMark = { + name: 'editReplaceMark', + params: { + fragment: {type: 'context', name: 'fragment'} + }, + stateDefaults: { + icon: null, + label: gettext('Edit replace mark'), + execute: function(callback, params) { + var doc = params.fragment.document, + answerNode = params.fragment.node.getParent('answer'), + dialog = Dialog.create({ + title: gettext('Edit text to replace with'), + executeButtonText: gettext('Apply'), + cancelButtonText: gettext('Cancel'), + fields: [ + {label: gettext('Text'), name: 'text', type: 'input', initialValue: answerNode.getAttr('answer')} + ] + }); + + + dialog.on('execute', function(event) { + doc.transaction(function() { + answerNode.setAttr('answer', event.formData.text); + var node = answerNode.contents()[0]; + return doc.createFragment(doc.CaretFragment, {node: node, offset: node.getText().length}); + }, { + metadata: { + description: gettext('Edit answer') + }, + success: function(ret) { event.success(); callback(ret);} + }); + }); + dialog.show(); + + } + }, + getState: function(params) { + return { + allowed: params.fragment && + params.fragment.isValid() && + params.fragment instanceof params.fragment.NodeFragment && + params.fragment.node.isInside('exercise.replace') && + params.fragment.node.isInside('answer'), + + description: gettext('Mark selection to replacement') + }; + } +}; + +return [markToReplace, removeReplaceMark, editReplaceMark]; + +}); \ No newline at end of file diff --git a/src/editor/plugins/core/edumed/replace/element.js b/src/editor/plugins/core/edumed/replace/element.js new file mode 100644 index 0000000..3f12f26 --- /dev/null +++ b/src/editor/plugins/core/edumed/replace/element.js @@ -0,0 +1,86 @@ +define(function(require) { + +'use strict'; + + +var $ = require('libs/jquery'), + _ = require('libs/underscore'), + documentElement = require('modules/documentCanvas/canvas/documentElement'), + genericElement = require('modules/documentCanvas/canvas/genericElement'), + viewTemplate = require('libs/text!./view.html'), + tipTemplate = require('libs/text!./tip.html'); + +var AnswerElement = Object.create(genericElement); +_.extend(AnswerElement, { + init: function() { + genericElement.init.call(this); + this.tip = $(tipTemplate); + this.tip.text(this.wlxmlNode.getAttr('answer') || ''); + this.tip.on('click', function(e) { + var doc = this.wlxmlNode.document, + textNode = this.wlxmlNode.contents()[0]; + e.preventDefault(); + e.stopPropagation(); + + if(textNode) { + this.canvas.select(doc.createFragment(doc.CaretFragment, {node:textNode, offset: textNode.getText().length})); + this.canvas.showContextMenu(this, {x: e.clientX, y: e.clientY}); + } + }.bind(this)); + this.addWidget(this.tip); + }, + onNodeAttrChange: function(event) { + if(event.meta.attr === 'answer') { + this.tip.text(event.meta.newVal || ''); + } + } +}); + +var ReplaceExerciseElement = Object.create(documentElement.DocumentNodeElement.prototype); +_.extend(ReplaceExerciseElement, { + init: function() { + documentElement.DocumentNodeElement.prototype.init.call(this); + var view = $(_.template(viewTemplate)()); + this._container().append(view); + + + this.elementsRegister.register( + {tag: 'span', klass: 'answer', prototype: AnswerElement} + ); + + this.createContainer(this.wlxmlNode.contents(), { + manages: function() { + return true; + }, + dom: view.find('.content') + }); + + this.addToContextMenu('core.markToReplace'); + this.contextMenuActions[0].on('actionExecuted', function(ret) { + if(ret instanceof this.wlxmlNode.document.Fragment && ret.isValid()) { + this.canvas.select(ret); + } + }.bind(this)); + this.addToContextMenu('core.editReplaceMark'); + this.addToContextMenu('core.removeReplaceMark'); + + }, + getVerticallyFirstTextElement: function() { + var toret; + this.containers.some(function(container) { + toret = container.getVerticallyFirstTextElement(); + return !!toret; + }); + return toret; + } +}); + +return {tag: 'div', klass: 'exercise.replace', prototype: ReplaceExerciseElement}; + +}); + + + + + + diff --git a/src/editor/plugins/core/edumed/replace/replace.less b/src/editor/plugins/core/edumed/replace/replace.less new file mode 100644 index 0000000..161a538 --- /dev/null +++ b/src/editor/plugins/core/edumed/replace/replace.less @@ -0,0 +1,16 @@ +.exercise-replace { + [wlxml-class="answer"] { + //color: @red; + text-decoration: line-through; + } + + .tip { + position: absolute; + top: -12px; + font-size: 9px; + line-height: 12px; + color: lighten(@red, 10%); + white-space: nowrap; + } + +} \ No newline at end of file diff --git a/src/editor/plugins/core/edumed/replace/tip.html b/src/editor/plugins/core/edumed/replace/tip.html new file mode 100644 index 0000000..5a82bef --- /dev/null +++ b/src/editor/plugins/core/edumed/replace/tip.html @@ -0,0 +1,2 @@ +
+ diff --git a/src/editor/plugins/core/edumed/replace/view.html b/src/editor/plugins/core/edumed/replace/view.html new file mode 100644 index 0000000..2378d40 --- /dev/null +++ b/src/editor/plugins/core/edumed/replace/view.html @@ -0,0 +1,4 @@ +
+
<%= gettext('Exercise') %>
+
+
\ No newline at end of file -- 2.20.1