wip: experiments with Canvas support for exercise.assign
[fnpeditor.git] / src / editor / modules / documentCanvas / canvas / container.js
1 define(function(require) {
2     
3 'use strict';
4
5 var $ = require('libs/jquery'),
6     _ = require('libs/underscore'),
7     utils = require('./utils');
8
9
10 var Container = function(nodes, params, element) {
11     params = params || {};
12     _.extend(this, params);
13     this.dom = this.dom || $('<div>');
14     this.dom.addClass('canvas-container');
15     this.dom.toggleClass('reset-background', !!params.resetBackground);
16     this.element = element;
17
18     nodes.forEach(function(node) {
19         var el = this.element.createElement(node, {mirror: this.mirrors});
20         if(el.dom) {
21             this.dom.append(el.dom);
22         }
23     }.bind(this));
24 };
25
26 _.extend(Container.prototype, {
27     remove: function() {
28         this.element.removeContainer(this);
29     },
30
31     onNodeAdded: function(event) {
32         if(event.meta.node.isRoot()) {
33             this.element.canvas.reloadRoot();//
34             return;
35         }
36
37         var ptr = event.meta.node.prev(),
38             referenceElement, referenceAction, actionArg;
39             
40         while(ptr && !(referenceElement = utils.getElementForElementRootNode(ptr, false, this))) {
41             ptr = ptr.prev();
42         }
43
44         if(referenceElement) {
45             referenceAction = 'after';
46         } else {
47             referenceElement = this;
48             referenceAction = '_prepend';
49         }
50       
51         if(event.meta.move) {
52             /* Let's check if this node had its own canvas element and it's accessible. */
53             actionArg = utils.getElementForElementRootNode(event.meta.node, false, this);
54         }
55         if(!actionArg) {
56             actionArg = event.meta.node;
57         }
58
59         if(referenceAction === 'after') {
60             referenceElement.after(actionArg, {mirror: this.mirrors});
61         } else {
62             referenceElement[referenceAction](actionArg);
63         }
64     },
65     onNodeDetached: function(event) {
66         var container = this;
67         this.dom.contents().each(function() {
68             var childElement = container.element.canvas.getDocumentElement(this);
69             if(childElement && childElement.wlxmlNode.sameNode(event.meta.node)) {
70                 childElement.detach();
71                 return false;
72             }
73         });
74     },
75     getVerticallyFirstTextElement: function(params) {
76         var documentElement = require('./documentElement'),
77             toret;
78         
79         params = _.extend({
80             considerChildren: true
81         }, params);
82         
83         this.children().some(function(child) {
84             if(child instanceof documentElement.DocumentTextElement) {
85                 toret = child;
86                 return true; // break
87             } else if(params.considerChildren) {
88                 toret = child.getVerticallyFirstTextElement();
89                 if(toret) {
90                     return true; // break
91                 }
92             }
93         });
94         return toret;
95     },
96     getFirst: function(e1, e2) {
97         var idx1 = this._childIndex(e1),
98             idx2 = this._childIndex(e2);
99         if(e1 === null || e2 === null) {
100             return undefined;
101         }
102         return idx1 <= idx2 ? e1: e2;
103     },
104
105     _prepend: function(param) {
106         var documentElement = require('./documentElement'),
107             element;
108         if(param instanceof documentElement.DocumentElement) {
109             element = param;
110         } else {
111             element = this.element.createElement(param, {mirror: this.mirrors});//
112         }
113         if(element.dom) {
114             this.dom.prepend(element.dom);
115         }
116         return element;
117     },
118     _childIndex: function(child) {
119         var children = this.children(),
120             toret = null;
121         children.forEach(function(c, idx) {
122             if(c.sameNode(child)) {
123                 toret = idx;
124                 return false;
125             }
126         });
127         return toret;
128     },
129     containsBlock: function() {
130         var documentElement = require('./documentElement');
131         return this.children()
132             .filter(function(child) {
133                 return child instanceof documentElement.DocumentNodeElement;
134             })
135             .some(function(child) {
136                 if(child.isBlock()) {
137                     return true;
138                 } else {
139                     return child.containsBlock();
140                 }
141             });
142     },
143     children: function() {
144         var element = this.element.canvas,
145             toret = [];
146         this.dom.contents().each(function() {
147             var childElement = element.getDocumentElement(this);
148             if(childElement === undefined) {
149                 return true;
150             }
151
152             toret.push(childElement);
153         });
154         return toret;
155     },
156 });
157
158 return {
159     create: function(nodes, params, element) {
160         return new Container(nodes, params, element);
161     }
162 };
163
164 });