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