3dc9a81d173a67bee3b6f4440c22f6bfae44fee9
[fnpeditor.git] / src / editor / plugins / core / edumed / order / view.js
1 define(function(require) {
2     
3 'use strict';
4 var $ = require('libs/jquery');
5
6 var _ = require('libs/underscore'),
7     Backbone = require('libs/backbone'),
8     viewTemplate = require('libs/text!./view.html'),
9     viewItemTemplate = require('libs/text!./viewItem.html');
10
11
12 var OrderExerciseView = function(element) {
13     this.element = element;
14     this.dom = $(_.template(viewTemplate)());
15     this.modePills = this.dom.find('.modePills');
16     this.list = this.dom.find('ol');
17     this.description = this.dom.find('.description');
18     this.itemViews = [];
19
20     this.modePills.find('a').on('click', function(e) {
21         e.stopPropagation();
22         e.preventDefault();
23         this.setMode($(e.target).parent().attr('mode'));
24     }.bind(this));
25
26     this.mode = 'initial';
27
28     var dropTargets = this.dom.find('.placeholder-top');
29
30     dropTargets.on('dragend', function() {
31         dropTargets.removeClass('dragged');
32     });
33
34     dropTargets.on('dragenter', function() {
35         var first = this.itemViews[0];
36         if(this.mode === 'correct') {
37             first = this.itemViews.slice(0)
38                 .sort(function(view1, view2) {
39                     if(view1.item.getAnswer() > view2.item.getAnswer()) {
40                         return 1;
41                     }
42                     return -1;
43                 })[0];
44         }
45         if(!this.allowDropAt(first, true)) {
46             return;
47         }
48         dropTargets.addClass('active');
49     }.bind(this));
50
51     dropTargets.on('dragleave', function() {
52         dropTargets.removeClass('active');
53     }.bind(this));
54
55     dropTargets.on('dragover', function(e) {
56         e.preventDefault();
57         e.originalEvent.dataTransfer.dropEffect = 'move';
58     });
59
60     dropTargets.on('drop', function(e) {
61         var vid = e.originalEvent.dataTransfer.getData('text');
62         var droppedItem = $('[vid='+vid+']').data('viewInstance');
63
64         var first = this.itemViews[0];
65         if(this.mode === 'correct') {
66             first = this.itemViews.slice(0)
67                 .sort(function(view1, view2) {
68                     if(view1.item.getAnswer() > view2.item.getAnswer()) {
69                         return 1;
70                     }
71                     return -1;
72                 })[0];
73         }
74
75         this.trigger(this.mode === 'initial' ? 'moveItem' : 'moveAnswer', droppedItem.item, first.item, 'before');
76         dropTargets.removeClass('active');
77         e.preventDefault();
78     }.bind(this));
79 };
80 _.extend(OrderExerciseView.prototype, Backbone.Events, {
81     addItem: function(item) {
82         var view = new ItemView(item, this);
83         view.on('receivedDrop', function(droppedItem) {
84             this.trigger(this.mode === 'initial' ? 'moveItem' : 'moveAnswer', droppedItem.item, item, 'after');
85         }.bind(this));
86         view.on('dragStarted', function(view) {
87             this.draggedView = view;
88         }.bind(this));
89         this.list.append(view.dom);
90         this.itemViews.push(view);
91
92         if(this.mode === 'correct') {
93             this.setMode(this.mode);
94         }
95     },
96     clearItems: function() {
97         this.list.empty();
98         this.itemViews.forEach(function(view) {
99             view.remove();
100         });
101         this.itemViews = [];
102     },
103     setMode: function(mode) {
104         this.modePills.find('li').removeClass('active');
105         this.modePills.find('[mode='+mode+']').addClass('active');
106         this.mode = mode;
107         this.list.children().detach();
108
109         if(this.mode === 'initial') {
110             this.itemViews.forEach(function(itemView) {
111                 this.list.append(itemView.dom);
112             }.bind(this));
113         } else {
114             this.itemViews.slice(0)
115                 .sort(function(view1, view2) {
116                     if(view1.item.getAnswer() > view2.item.getAnswer()) {
117                         return 1;
118                     }
119                     return -1;
120                 })
121                 .forEach(function(itemView) {
122                     this.list.append(itemView.dom);
123                 }.bind(this));
124         }
125     },
126     allowDropAt: function(view, up) {
127         var arr = [this.draggedView.dom[0]];
128         if(!up) {
129             arr.push(this.draggedView.dom.prev()[0]);
130         }
131         return !_.contains(arr, view.dom[0]);
132     }
133 });
134
135 var ItemView = function(item, exerciseView) {
136     this.item = item;
137     this.exerciseView = exerciseView;
138     this.dom = $(_.template(viewItemTemplate)());
139     this.content = this.dom.find('.content');
140
141
142     var dropTargets = this.dom.find('.placeholder'),
143         dragSources = this.dom.find('.handle');
144
145     dragSources.on('dragstart', function(e) {
146         this.dom.addClass('dragged');
147         e.originalEvent.dataTransfer.setData('text', this.dom.attr('vid'));
148         e.originalEvent.effectAllowed = 'move';
149         this.trigger('dragStarted', this);
150
151     }.bind(this));
152
153     dropTargets.on('dragend', function() {
154         this.dom.removeClass('dragged');
155     });
156
157     dropTargets.on('dragenter', function() {
158         if(!this.exerciseView.allowDropAt(this)) {
159             return;
160         }
161         dropTargets.addClass('active');
162     }.bind(this));
163
164     dropTargets.on('dragleave', function() {
165         dropTargets.removeClass('active');
166     }.bind(this));
167
168     dropTargets.on('dragover', function(e) {
169         e.preventDefault();
170         e.originalEvent.dataTransfer.dropEffect = 'move';
171     });
172
173     dropTargets.on('drop', function(e) {
174         var vid = e.originalEvent.dataTransfer.getData('text');
175         var droppedItem = $('[vid='+vid+']').data('viewInstance');
176         e.preventDefault();
177         this.trigger('receivedDrop', droppedItem);
178     }.bind(this));
179
180     var content = this.content;
181     this.container = exerciseView.element.createContainer(item.node.contents(), {
182         resetBackground: true,
183         manages: function(node, originaParent) {
184             return item.node.sameNode(node.parent() || originaParent);
185         },
186         dom: content
187     });
188
189     this.dom.data('viewInstance', this);
190     this.dom.attr('vid', _.uniqueId());
191 };
192
193 _.extend(ItemView.prototype, Backbone.Events, {
194     remove: function() {
195         this.container.remove();
196     }
197 });
198
199 return OrderExerciseView;
200
201 });
202
203