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