wip: wlxml layer
authorAleksander Łukasz <aleksander.lukasz@nowoczesnapolska.org.pl>
Mon, 18 Aug 2014 08:14:25 +0000 (10:14 +0200)
committerAleksander Łukasz <aleksander.lukasz@nowoczesnapolska.org.pl>
Mon, 18 Aug 2014 08:14:25 +0000 (10:14 +0200)
src/wlxml/extensions/edumed/assign.xml [new file with mode: 0644]
src/wlxml/extensions/edumed/edumed.js
src/wlxml/extensions/edumed/edumed.test.js

diff --git a/src/wlxml/extensions/edumed/assign.xml b/src/wlxml/extensions/edumed/assign.xml
new file mode 100644 (file)
index 0000000..7565a86
--- /dev/null
@@ -0,0 +1,9 @@
+<div class="exercise.assign">
+    <div class="p"></div>
+    <div class="list" target="categories">
+        <div class="item.answer">aaa</div>
+    </div>
+    <div class="list" id="categories">
+        <div class="item" id="kat1">bbb</div>
+    </div>
+</div>
\ No newline at end of file
index ca29ad3..edb16dc 100644 (file)
@@ -9,7 +9,8 @@ var _ = require('libs/underscore'),
         'choice.single': require('libs/text!./choiceSingle.xml'),
         'choice.true-or-false': require('libs/text!./choiceTrueOrFalse.xml'),
         gap: require('libs/text!./gaps.xml'),
-        replace: require('libs/text!./replace.xml')
+        replace: require('libs/text!./replace.xml'),
+        assign: require('libs/text!./assign.xml')
     };
 
 var Item = function(node, exerciseNode) {
@@ -220,6 +221,111 @@ extension.wlxmlClass['exercise.gap'] = extension.wlxmlClass['exercise.replace']
     }
 };
 
+
+var SourceItem = function(node) {
+    this.node = node;
+};
+_.extend(SourceItem.prototype, {
+    assignTo: function(destinationItem) {
+        var ids;
+        if(!destinationItem.accepts(this)) {
+            throw new Error('Cannot assign: target ids mismatch.');
+        }
+        ids = (this.node.getAttr('answer') || '').split(',');
+        ids.push(destinationItem.getId());
+        this.node.setAttr('answer', ids.filter(function(id) { return !!id; }).join(','));
+    },
+    removeFrom: function(destinationItem) {
+        var ids;
+        if(!destinationItem.accepts(this)) {
+            throw new Error('Cannot assign: target ids mismatch.');
+        }
+        ids = (this.node.getAttr('answer') || '').split(',');
+        this.node.setAttr('answer', ids.filter(function(id) { return id !== destinationItem.getId(); }).join(',') || undefined);
+    },
+    isAssignedTo: function(destinationItem) {
+        return (this.node.getAttr('answer') || '').indexOf(destinationItem.getId()) !== -1;
+    },
+    getMyTargetId: function() {
+        return this.node.parent().getAttr('target');
+    },
+    contents: function() {
+        return this.node.contents();
+    }
+});
+
+var DestinationItem = function(node, exerciseNode) {
+    this.node = node;
+    this.exerciseNode = exerciseNode;
+};
+_.extend(DestinationItem.prototype, {
+    getId: function() {
+        return this.node.getAttr('id');
+    },
+    getTargetId: function() {
+        return this.node.parent().getAttr('id');
+    },
+    accepts: function(sourceItem) {
+        return sourceItem && sourceItem.getMyTargetId() === this.getTargetId();
+    },
+    getAssignedSources: function() {
+        return this.exerciseNode.object.getSourceItems()
+            .filter(function(item) {
+                return item.isAssignedTo(this);
+            }.bind(this));
+    }
+});
+
+extension.wlxmlClass['exercise.assign'] = {
+    methods: {
+        isContextRoot: function(node) {
+            return this.object.isList(node.parent()) || this.sameNode(node);
+        },
+        getSourceItems: function() {
+            var list;
+            this.contents().some(function(node) {
+                if(node.is('list') && node.getAttr('target')) {
+                    list = node;
+                    return true;
+                }
+            });
+            if(!list) {
+                throw new Error('Missing source list');
+            }
+            return list.contents().map(function(node) {return new SourceItem(node, this);});
+        },
+        getDestinationItems: function() {
+            var list;
+            this.contents().some(function(node) {
+                if(node.is('list') && node.getAttr('id')) {
+                    list = node;
+                    return true;
+                }
+            });
+            if(!list) {
+                throw new Error('Missing destination list');
+            }
+            return list.contents().map(function(node) {return new DestinationItem(node, this);}.bind(this));
+        },
+        getDescription: function() {
+            var toret = [];
+            this.contents().some(function(node) {
+                if(this.isList(node)) {
+                   return true;
+                }
+                toret.push(node);
+            }.bind(this.object));
+            return toret;
+        },
+        isList: function(node) {
+            return this.sameNode(node.parent()) && node.is('list') && (node.getAttr('target') || node.getAttr('id'));
+        },
+        isItemNode: function(node, parent) {
+            return node && this.object.isList(node.parent() || parent);
+        }
+    }
+};
+
 extension.document = {
     methods: {
          edumedCreateExerciseNode: function(klass) {
index c039f0d..a3c9b89 100644 (file)
@@ -64,6 +64,57 @@ describe('Setting answer', function() {
     });
 });
 
+describe('Assign exercise', function() {
+    /* jshint multistr:true */
+    it('assigns source to destination', function() {
+        var doc = getDocumentFromXML('\
+                <div class="exercise.assign">\
+                    <div class="list" target="kategorie">\
+                        <div class="item.answer">Element 1</div>\
+                        <div class="item.answer">Element 2</div>\
+                    </div>\
+                    <div class="list" id="kategorie">\
+                        <div class="item" id="kat1">Kategoria 1</div>\
+                        <div class="item" id="kat2">Kategoria 2</div>\
+                    </div>\
+                </div>'),
+            exercise = doc.root,
+            element = exercise.object.getSourceItems()[1],
+            categories = exercise.object.getDestinationItems(),
+            elementNode = exercise.contents()[0].contents()[1];
+        
+        element.assignTo(categories[0]);
+        expect(elementNode.getAttr('answer')).to.equal('kat1');
+        expect(element.isAssignedTo(categories[0])).to.equal(true);
+
+        element.assignTo(categories[1]);
+        expect(elementNode.getAttr('answer')).to.equal('kat1,kat2');
+        expect(element.isAssignedTo(categories[1])).to.equal(true);
+    });
+    it('removes assignment between source and destination', function() {
+        var doc = getDocumentFromXML('\
+                <div class="exercise.assign">\
+                    <div class="list" target="kategorie">\
+                        <div class="item.answer">Element 1</div>\
+                        <div class="item.answer" answer="kat1,kat2">Element 2</div>\
+                    </div>\
+                    <div class="list" id="kategorie">\
+                        <div class="item" id="kat1">Kategoria 1</div>\
+                        <div class="item" id="kat2">Kategoria 2</div>\
+                    </div>\
+                </div>'),
+            exercise = doc.root,
+            element = exercise.object.getSourceItems()[1],
+            categories = exercise.object.getDestinationItems(),
+            elementNode = exercise.contents()[0].contents()[1];
+        
+        element.removeFrom(categories[0]);
+        expect(elementNode.getAttr('answer')).to.equal('kat2');
+
+        element.removeFrom(categories[1]);
+        expect(elementNode.getAttr('answer')).to.equal(undefined, 'empty');
+    });
+});