wip: wlxml layer
[fnpeditor.git] / src / wlxml / extensions / edumed / edumed.js
index 3176ae0..edb16dc 100644 (file)
@@ -3,7 +3,15 @@ define(function(require) {
 'use strict';
 
 var _ = require('libs/underscore'),
-    orderExerciseTemplate = require('libs/text!./order.xml');
+    templates = {
+        order: require('libs/text!./order.xml'),
+        choice: require('libs/text!./choice.xml'),
+        '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'),
+        assign: require('libs/text!./assign.xml')
+    };
 
 var Item = function(node, exerciseNode) {
     Object.defineProperty(this, 'text', {
@@ -149,11 +157,180 @@ var extension = {wlxmlClass: {'exercise.order': {
     }
 }}};
 
+var choiceMethods = {
+    isContextRoot: function(node) {
+        return this.object.isChoiceList(node.parent()) || this.sameNode(node);
+    },
+    getChoiceList: function() {
+        return this.contents()
+            .filter(function(n) { return this.object.isChoiceList(n); }.bind(this))[0];
+    },
+    isChoiceList: function(node) {
+        return node.is('list') && this.sameNode(node.parent());
+    },
+    isChoiceListItem: function(node) {
+        return this.object.isChoiceList(node.parent()) && node.is('item.answer');
+    }
+};
+
+extension.wlxmlClass['exercise.choice'] = {
+    transformations: {
+        setAnswer: function(itemNode, answer) {
+            if(!this.object.isChoiceListItem(itemNode)) {
+                return;
+            }
+            itemNode.setAttr('answer', answer ? 'true' : 'false');
+        }
+    },
+    methods: choiceMethods
+};
+
+extension.wlxmlClass['exercise.choice.single'] = {
+    transformations: {
+        markAsAnswer: function(itemNode) {
+            if(!this.object.isChoiceListItem(itemNode)) {
+                return;
+            }
+            this.object.getChoiceList().contents()
+                .filter(function(node) { return node.is('item.answer'); })
+                .forEach(function(node) {
+                    node.setAttr('answer', node.sameNode(itemNode) ? 'true' : 'false');
+                });
+        }
+    },
+    methods: choiceMethods
+};
+
+extension.wlxmlClass['exercise.choice.true-or-false'] = {
+    transformations: {
+        setAnswer: function(itemNode, answer) {
+            if(!this.object.isChoiceListItem(itemNode)) {
+                return;
+            }
+            itemNode.setAttr('answer', answer ? 'true' : 'false');
+        }
+    },
+    methods: choiceMethods
+};
+
+extension.wlxmlClass['exercise.gap'] = extension.wlxmlClass['exercise.replace'] = {
+    methods: {
+        isContextRoot: function(node) {
+            return this.sameNode(node);
+        }
+    }
+};
+
+
+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) {
             void(klass);
-            return this.createDocumentNode(orderExerciseTemplate);
+            return this.createDocumentNode(templates[klass]);
          }
     }
 };