6e01d6efa546035976a5af08e03f18492cc77fee
[fnpeditor.git] / src / wlxml / extensions / edumed / edumed.js
1 define(function(require) {
2     
3 'use strict';
4
5 var _ = require('libs/underscore'),
6     templates = {
7         order: require('libs/text!./order.xml'),
8         choice: require('libs/text!./choice.xml'),
9         'choice.single': require('libs/text!./choiceSingle.xml'),
10         'choice.true-or-false': require('libs/text!./choiceTrueOrFalse.xml'),
11         gap: require('libs/text!./gaps.xml'),
12         replace: require('libs/text!./replace.xml')
13     };
14
15 var Item = function(node, exerciseNode) {
16     Object.defineProperty(this, 'text', {
17         get: function() {
18             /* globals Node */
19             var firstNode = node.contents()[0];
20             if(firstNode && firstNode.nodeType === Node.TEXT_NODE) {
21                 return firstNode.getText();
22             }
23             return '';
24         }
25     });
26     this.node = node;
27     this.exerciseNode = exerciseNode;
28 };
29 _.extend(Item.prototype, {
30     setText: function(text) {
31         /* globals Node */
32         var contents = this.node.contents();
33         if(contents.length === 1 && contents[0].nodeType === Node.TEXT_NODE) {
34             contents[0].setText(text);
35         } else {
36             contents.forEach(function(childNode) {
37                 childNode.detach();
38             });
39             contents.append({text: text});
40         }
41     },
42     remove: function() {
43         this.node.detach();
44     },
45     getAnswer: function() {
46         var toret = parseInt(this.node.getAttr('answer'), 10);
47         if(_.isNaN(toret)) {
48             toret = 1;
49         }
50         return toret;
51     },
52     setAnswer: function(answer) {
53         answer = parseInt(answer, 10);
54         var prev = answer;
55         if(!_.isNumber(answer)) {
56             return;
57         }
58         
59         this.exerciseNode.object.getItems()
60             .sort(function(item1, item2) {
61                 if(item1.getAnswer() > item2.getAnswer()) {
62                     return 1;
63                 }
64                 return -1;
65             })
66             .some(function(item) {
67                 if(item.getAnswer() === prev && !item.node.sameNode(this.node)) {
68                     item.node.setAttr('answer', prev+1);
69                     prev = prev + 1;
70                 }
71             }.bind(this));
72         this.node.setAttr('answer', answer);
73         
74     }
75 });
76
77 var isItemsList = function(node) {
78     return node.is('list.orderable');
79 };
80
81
82 var extension = {wlxmlClass: {'exercise.order': {
83     methods: {
84         isContextRoot: function(node) {
85             return this.object.isItemNode(node) || this.sameNode(node);
86         },
87         getItems: function() {
88             var toret = [],
89                 exerciseNode = this;
90
91             this.contents().some(function(node) {
92                 if(isItemsList(node)) {
93                     node.contents()
94                         .filter(function(node) {
95                             return node.is('item.answer');
96                         })
97                         .forEach(function(node) {
98                             toret.push(new Item(node, exerciseNode));
99                         });
100                     return true;
101                 }
102             });
103             return toret;
104         },
105         isItemNode: function(node) {
106             var list;
107             if(!node) {
108                 return;
109             }
110             this.contents().some(function(node) {
111                 if(isItemsList(node)) {
112                     list = node;
113                     return true;
114                 }
115             });
116             return list && list.sameNode(node.parent());
117         },
118         getDescription: function() {
119             var toret = [];
120             this.contents().some(function(node) {
121                 if(isItemsList(node)) {
122                    return true;
123                 }
124                 toret.push(node);
125             });
126             return toret;
127         }
128     },
129     transformations: {
130         addItem: function(text) {
131             var toret;
132             this.contents().some(function(node) {
133                 if(isItemsList(node)) {
134                     var itemNode = this.document.createDocumentNode({tagName: 'div', attrs: {'class': 'item.answer', answer: this.object.getItems().length+1}});
135                     toret = itemNode.append({text: text});
136                     node.append(itemNode);
137                     return true;
138                 }
139             }.bind(this));
140             return toret;
141         },
142         setDescription: function(text) {
143             this.contents().some(function(node) {
144                 var textNode;
145                 if(node.is('p')) {
146                     textNode = node.contents()[0];
147                     if(!(textNode && textNode.nodeType === Node.TEXT_NODE)) {
148                         node.prepend({text:text});
149                     } else {
150                         textNode.setText(text);
151                     }
152                     return true;
153                 }
154             });
155         }
156     }
157 }}};
158
159 var choiceMethods = {
160     getChoiceList: function() {
161         return this.contents()
162             .filter(function(n) { return this.object.isChoiceList(n); }.bind(this))[0];
163     },
164     isChoiceList: function(node) {
165         return node.is('list') && this.sameNode(node.parent());
166     },
167     isChoiceListItem: function(node) {
168         return this.object.isChoiceList(node.parent()) && node.is('item.answer');
169     }
170 };
171
172 extension.wlxmlClass['exercise.choice'] = {
173     transformations: {
174         setAnswer: function(itemNode, answer) {
175             if(!this.object.isChoiceListItem(itemNode)) {
176                 return;
177             }
178             itemNode.setAttr('answer', answer ? 'true' : 'false');
179         }
180     },
181     methods: choiceMethods
182 };
183
184 extension.wlxmlClass['exercise.choice.single'] = {
185     transformations: {
186         markAsAnswer: function(itemNode) {
187             if(!this.object.isChoiceListItem(itemNode)) {
188                 return;
189             }
190             this.object.getChoiceList().contents()
191                 .filter(function(node) { return node.is('item.answer'); })
192                 .forEach(function(node) {
193                     node.setAttr('answer', node.sameNode(itemNode) ? 'true' : 'false');
194                 });
195         }
196     },
197     methods: choiceMethods
198 };
199
200 extension.wlxmlClass['exercise.choice.true-or-false'] = {
201     transformations: {
202         setAnswer: function(itemNode, answer) {
203             if(!this.object.isChoiceListItem(itemNode)) {
204                 return;
205             }
206             itemNode.setAttr('answer', answer ? 'true' : 'false');
207         }
208     },
209     methods: choiceMethods
210 };
211
212 extension.document = {
213     methods: {
214          edumedCreateExerciseNode: function(klass) {
215             void(klass);
216             return this.createDocumentNode(templates[klass]);
217          }
218     }
219 };
220
221 return extension;
222
223 });