1 // Module that implements main WYSIWIG edit area
\r
4 'libs/underscore-min',
\r
5 './transformations',
\r
7 'libs/text!./template.html'], function(_, transformations, wlxmlNode, template) {
\r
11 return function(sandbox) {
\r
14 node: $(_.template(template)()),
\r
16 shownAlready: false,
\r
17 scrollbarPosition: 0,
\r
21 this.node.find('#rng-module-documentCanvas-content').on('keyup', function() {
\r
23 sandbox.publish('contentChanged');
\r
26 this.node.on('mouseover', '[wlxml-tag]', function(e) {
\r
27 e.stopPropagation();
\r
28 sandbox.publish('nodeHovered', new wlxmlNode.Node($(e.target)));
\r
30 this.node.on('mouseout', '[wlxml-tag]', function(e) {
\r
31 e.stopPropagation();
\r
32 sandbox.publish('nodeBlured', new wlxmlNode.Node($(e.target)));
\r
34 this.node.on('click', '[wlxml-tag]', function(e) {
\r
35 e.stopPropagation();
\r
36 console.log('clicked node type: '+e.target.nodeType);
\r
37 view.selectNode(new wlxmlNode.Node($(e.target)));
\r
40 this.node.on('keyup', '#rng-module-documentCanvas-contentWrapper', function(e) {
\r
41 var anchor = $(window.getSelection().anchorNode);
\r
42 if(anchor[0].nodeType === Node.TEXT_NODE)
\r
43 anchor = anchor.parent();
\r
44 if(!anchor.is('[wlxml-tag]'))
\r
46 view.selectNode(new wlxmlNode.Node(anchor));
\r
49 this.node.on('keydown', '#rng-module-documentCanvas-contentWrapper', function(e) {
\r
50 if(e.which === 13) {
\r
52 view.insertNewNode(null, null);
\r
55 var anchor = window.getSelection().anchorNode;
\r
56 var len = anchor.length;
\r
60 $(anchor).parent().text('');
\r
65 this.node.onShow = function() {
\r
66 if(!view.shownAlready) {
\r
67 view.shownAlready = true;
\r
68 view.selectFirstNode();
\r
69 } else if(view.currentNode) {
\r
70 view.movecaretToNode(view.getNodeElement(view.currentNode));
\r
71 view.node.find('#rng-module-documentCanvas-contentWrapper').scrollTop(view.scrollbarPosition);
\r
74 this.node.onHide = function() {
\r
75 view.scrollbarPosition = view.node.find('#rng-module-documentCanvas-contentWrapper').scrollTop();
\r
78 this.gridToggled = false;
\r
80 _createNode: function(wlxmlTag, wlxmlClass) {
\r
81 var toBlock = ['div', 'document', 'section', 'header'];
\r
82 var htmlTag = _.contains(toBlock, wlxmlTag) ? 'div' : 'span';
\r
83 var toret = $('<' + htmlTag + '>');
\r
84 toret.attr('wlxml-tag', wlxmlTag);
\r
86 toret.attr('wlxml-class', wlxmlClass);
\r
87 toret.attr('id', 'xxxxxxxx-xxxx-xxxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {var r = Math.random()*16|0,v=c=='x'?r:r&0x3|0x8;return v.toString(16);}));
\r
90 insertNewNode: function(wlxmlTag, wlxmlClass) {
\r
91 //TODO: Insert inline
\r
92 var anchor = $(window.getSelection().anchorNode);
\r
93 var anchorOffset = window.getSelection().anchorOffset;
\r
95 if(anchor[0].nodeType === Node.TEXT_NODE) {
\r
96 textLen = anchor.text().length;
\r
97 anchor = anchor.parent();
\r
99 if(anchor.text() === '') {
\r
100 var todel = anchor;
\r
101 anchor = anchor.parent();
\r
104 if(anchorOffset > 0 && anchorOffset < textLen) {
\r
105 if(wlxmlTag === null && wlxmlClass === null) {
\r
106 return this.splitWithNewNode(anchor);
\r
108 return this.wrapSelectionWithNewNode(wlxmlTag, wlxmlClass);
\r
110 var newNode = this._createNode(wlxmlTag || anchor.attr('wlxml-tag'), wlxmlClass || anchor.attr('wlxml-class'));
\r
111 if(anchorOffset === 0)
\r
112 anchor.before(newNode)
\r
114 anchor.after(newNode);
\r
115 this.selectNode(new wlxmlNode.Node(newNode), {movecaret: true});
\r
117 sandbox.publish('contentChanged');
\r
119 wrapSelectionWithNewNode: function(wlxmlTag, wlxmlClass) {
\r
120 var selection = window.getSelection();
\r
121 if(selection.anchorNode === selection.focusNode && selection.anchorNode.nodeType === Node.TEXT_NODE) {
\r
122 var startOffset = selection.anchorOffset;
\r
123 var endOffset = selection.focusOffset;
\r
124 if(startOffset > endOffset) {
\r
125 var tmp = startOffset;
\r
126 startOffset = endOffset;
\r
129 var node = selection.anchorNode;
\r
130 var prefix = node.data.substr(0, startOffset);
\r
131 var suffix = node.data.substr(endOffset);
\r
132 var core = node.data.substr(startOffset, endOffset - startOffset);
\r
133 var newNode = this._createNode(wlxmlTag, wlxmlClass);
\r
134 newNode.text(core || 'test');
\r
135 $(node).replaceWith(newNode);
\r
136 newNode.before(prefix);
\r
137 newNode.after(suffix);
\r
139 this.selectNode(new wlxmlNode.Node(newNode), {movecaret: true});
\r
141 sandbox.publish('contentChanged');
\r
144 splitWithNewNode: function(node) {
\r
145 var selection = window.getSelection();
\r
146 if(selection.anchorNode === selection.focusNode && selection.anchorNode.nodeType === Node.TEXT_NODE) {
\r
147 var startOffset = selection.anchorOffset;
\r
148 var endOffset = selection.focusOffset;
\r
149 if(startOffset > endOffset) {
\r
150 var tmp = startOffset;
\r
151 startOffset = endOffset;
\r
154 var anchor = selection.anchorNode;
\r
155 var prefix = anchor.data.substr(0, startOffset);
\r
156 var suffix = anchor.data.substr(endOffset);
\r
157 var prefixNode = this._createNode(node.attr('wlxml-tag'), node.attr('wlxml-class'));
\r
158 var newNode = this._createNode(node.attr('wlxml-tag'), node.attr('wlxml-class'));
\r
159 var suffixNode = this._createNode(node.attr('wlxml-tag'), node.attr('wlxml-class'));
\r
160 prefixNode.text(prefix);
\r
161 suffixNode.text(suffix);
\r
162 node.replaceWith(newNode);
\r
163 newNode.before(prefixNode);
\r
164 newNode.after(suffixNode);
\r
166 this.selectNode(new wlxmlNode.Node(newNode), {movecaret: true});
\r
168 sandbox.publish('contentChanged');
\r
171 setBody: function(HTMLTree) {
\r
172 this.node.find('#rng-module-documentCanvas-content').html(HTMLTree);
\r
174 getBody: function() {
\r
175 return this.node.find('#rng-module-documentCanvas-content').html();
\r
177 selectNode: function(wlxmlNode, options) {
\r
178 options = options || {};
\r
179 var nodeElement = this.getNodeElement(wlxmlNode)
\r
181 this.dimNode(wlxmlNode);
\r
183 this.node.find('.rng-module-documentCanvas-currentNode').removeClass('rng-module-documentCanvas-currentNode');
\r
184 nodeElement.addClass('rng-module-documentCanvas-currentNode');
\r
186 if(options.movecaret) {
\r
187 this.movecaretToNode(nodeElement);
\r
190 this.currentNode = wlxmlNode;
\r
191 sandbox.publish('nodeSelected', wlxmlNode);
\r
193 highlightNode: function(wlxmlNode) {
\r
194 var nodeElement = this.getNodeElement(wlxmlNode);
\r
195 if(!this.gridToggled) {
\r
196 nodeElement.addClass('rng-common-hoveredNode');
\r
197 var label = nodeElement.attr('wlxml-tag');
\r
198 if(nodeElement.attr('wlxml-class'))
\r
199 label += ' / ' + nodeElement.attr('wlxml-class');
\r
200 var tag = $('<div>').addClass('rng-module-documentCanvas-hoveredNodeTag').text(label);
\r
201 nodeElement.append(tag);
\r
204 dimNode: function(wlxmlNode) {
\r
205 var nodeElement = this.getNodeElement(wlxmlNode);
\r
206 if(!this.gridToggled) {
\r
207 nodeElement.removeClass('rng-common-hoveredNode');
\r
208 nodeElement.find('.rng-module-documentCanvas-hoveredNodeTag').remove();
\r
211 selectFirstNode: function() {
\r
212 var firstNodeWithText = this.node.find('[wlxml-tag]').filter(function() {
\r
213 return $(this).clone().children().remove().end().text().trim() !== '';
\r
216 if(firstNodeWithText.length)
\r
217 node = $(firstNodeWithText[0])
\r
219 node = this.node.find('[wlxml-class|="p"]')
\r
221 this.selectNode(new wlxmlNode.Node(node), {movecaret: true});
\r
223 toggleGrid: function(toggle) {
\r
224 this.node.find('[wlxml-tag]').toggleClass('rng-common-hoveredNode', toggle);
\r
225 this.gridToggled = toggle;
\r
227 getNodeElement: function(wlxmlNode) {
\r
228 return this.node.find('#'+wlxmlNode.id);
\r
230 movecaretToNode: function(nodeElement) {
\r
231 var range = document.createRange();
\r
232 range.selectNodeContents(nodeElement[0]);
\r
233 range.collapse(false);
\r
234 var selection = document.getSelection();
\r
235 selection.removeAllRanges()
\r
236 selection.addRange(range);
\r
244 start: function() { sandbox.publish('ready'); },
\r
245 getView: function() {
\r
248 setDocument: function(xml) {
\r
249 var transformed = transformations.fromXML.getDocumentDescription(xml);
\r
250 view.setBody(transformed.HTMLTree);
\r
251 sandbox.publish('documentSet');
\r
253 getDocument: function() {
\r
254 return transformations.toXML.getXML(view.getBody());
\r
256 modifyCurrentNode: function(attr, value) {
\r
257 if(view.currentNode) {
\r
258 view.getNodeElement(view.currentNode).attr('wlxml-'+attr, value);
\r
259 sandbox.publish('contentChanged');
\r
262 highlightNode: function(wlxmlNode) {
\r
263 view.highlightNode(wlxmlNode);
\r
265 dimNode: function(wlxmlNode) {
\r
266 view.dimNode(wlxmlNode);
\r
268 selectNode: function(wlxmlNode) {
\r
269 if(!wlxmlNode.is(view.currentNode))
\r
270 view.selectNode(wlxmlNode, {movecaret: true});
\r
272 toggleGrid: function(toggle) {
\r
273 view.toggleGrid(toggle);
\r
275 insertNewNode: function(wlxmlTag, wlxmlClass) {
\r
276 view.insertNewNode(wlxmlTag, wlxmlClass);
\r
278 wrapSelectionWithNewNode: function(wlxmlTag, wlxmlClass) {
\r
279 view.wrapSelectionWithNewNode(wlxmlTag, wlxmlClass);
\r