Switching to explicit inheritance for canvas elements
[fnpeditor.git] / src / editor / modules / documentCanvas / canvas / genericElement.js
1 define(function(require) {
2     
3 'use strict';
4
5 var $ = require('libs/jquery'),
6     documentElement = require('./documentElement'),
7     utils = require('./utils'),
8     wlxmlUtils = require('utils/wlxml');
9
10 var labelWidget = function(tag, klass) {
11     return $('<span>')
12         .addClass('canvas-widget canvas-widget-label')
13         .text(wlxmlUtils.getTagLabel(tag) + (klass ? ' / ' + wlxmlUtils.getClassLabel(klass) : ''));
14 };
15 void(labelWidget); // for linters; labelWidget is unused on purpose for now
16
17 var DocumentNodeElement = documentElement.DocumentNodeElement;
18
19 var generic = Object.create(DocumentNodeElement.prototype);
20
21 $.extend(generic, {
22     onNodeAttrChange: function(event) {
23         if(event.meta.attr === 'class') {
24             this.setWlxmlClass(event.meta.newVal); //
25         }
26     },
27     onNodeAdded: function(event) {
28         if(event.meta.node.isRoot()) {
29             this.canvas.reloadRoot();
30             return;
31         }
32
33         var nodeIndex = event.meta.node.getIndex(),
34             referenceElement, referenceAction, actionArg;
35
36         if(nodeIndex === 0) {
37             referenceElement = this;
38             referenceAction = 'prepend';
39         } else {
40             referenceElement = this.children()[nodeIndex-1];
41             referenceAction = 'after';
42         }
43
44         actionArg = (event.type === 'nodeMoved' && utils.findCanvasElement(event.meta.node, event.meta.parent)) || event.meta.node;
45         referenceElement[referenceAction](actionArg);
46     },
47     onNodeMoved: function(event) {
48         return this.onNodeAdded.call(this, event, true);
49     },
50     onNodeDetached: function(event) {
51         if(event.meta.node.sameNode(this)) {
52             this.detach();
53         } else {
54             this.children().some(function(child) {
55                 if(child.wlxmlNode.sameNode(event.meta.node)) {
56                     child.detach();
57                     return true;
58                 }
59             });
60         }
61     },
62     onNodeTextChange: function(event) {
63         var toSet = event.meta.node.getText();
64         this.children().some(function(child) {
65             if(child.wlxmlNode.sameNode(event.meta.node)) {
66                 if(toSet === '') {
67                     toSet = utils.unicode.ZWS;
68                 }
69                 if(toSet !== child.getText()) {
70                     child.setText(toSet);
71                 }
72                 return true;
73             }
74         });
75     },
76
77     prepend: function(param) {
78         var element;
79         if(param instanceof documentElement.DocumentElement) {
80             element = param;
81         } else {
82             element = this.canvas.createElement(param);
83         }
84         this._container().prepend(element.dom);
85         this.refreshPath();
86         return element;
87     },
88
89     children: function() {
90         var element = this,
91             toret = [];
92         this._container().contents().each(function() {
93             var childElement = element.canvas.getDocumentElement(this);
94             if(childElement === undefined) {
95                 return true;
96             }
97
98             toret.push(childElement);
99         });
100         return toret;
101     },
102
103     getFirst: function(e1, e2) {
104         var idx1 = this.childIndex(e1),
105             idx2 = this.childIndex(e2);
106         if(e1 === null || e2 === null) {
107             return undefined;
108         }
109         return idx1 <= idx2 ? e1: e2;
110     },
111
112     childIndex: function(child) {
113         var children = this.children(),
114             toret = null;
115         children.forEach(function(c, idx) {
116             if(c.sameNode(child)) {
117                 toret = idx;
118                 return false;
119             }
120         });
121         return toret;
122     },
123
124     getWlxmlClass: function() {
125         var klass = this._container().attr('wlxml-class');
126         if(klass) {
127             return klass.replace(/-/g, '.');
128         }
129         return undefined;
130     },
131     setWlxmlClass: function(klass) {
132         if(klass === this.getWlxmlClass()) {
133             return;
134         }
135         if(klass) {
136             this._container().attr('wlxml-class', klass.replace(/\./g, '-'));
137         }
138         else {
139             this._container().removeAttr('wlxml-class');
140         }
141         this.refreshPath();
142     },
143     init: function() {
144         DocumentNodeElement.prototype.init.call(this);
145         this._container()
146             .attr('wlxml-tag', this.wlxmlNode.getTagName());
147         this.setWlxmlClass(this.wlxmlNode.getClass());
148         this.wlxmlNode.contents().forEach(function(node) {
149             this._container().append(this.canvas.createElement(node).dom);
150         }.bind(this));
151         this.refresh();
152
153     },
154     refresh: function() {
155         if(this.wlxmlNode.getTagName() === 'span') {
156             if(this.containsBlock()) {
157                 this.displayAsBlock();
158             } else {
159                 this.displayInline();
160             }
161         } else {
162             this.displayAsBlock();
163         }
164     },
165     containsBlock: function() {
166         return this.children()
167             .filter(function(child) {
168                 return child instanceof documentElement.DocumentNodeElement;
169             })
170             .some(function(child) {
171                 if(child.isBlock()) {
172                     return true;
173                 } else {
174                     return child.containsBlock();
175                 }
176             });
177     },
178     getVerticallyFirstTextElement: function() {
179         var toret;
180         this.children().some(function(child) {
181             if(child instanceof documentElement.DocumentTextElement) {
182                 toret = child;
183                 return true; // break
184             } else {
185                 toret = child.getVerticallyFirstTextElement();
186                 if(toret) {
187                     return true; // break
188                 }
189             }
190         });
191         return toret;
192     },
193 });
194
195
196 return generic;
197
198
199
200 });