1 // Module that implements main WYSIWIG edit area
\r
4 'libs/underscore-min',
\r
5 './transformations',
\r
6 'libs/text!./template.html'], function(_, transformations, template) {
\r
10 return function(sandbox) {
\r
13 node: $(_.template(template)()),
\r
18 this.node.find('#rng-module-documentCanvas-content').on('keyup', function() {
\r
20 sandbox.publish('contentChanged');
\r
23 this.node.on('mouseover', '[wlxml-tag]', function(e) { sandbox.publish('nodeHovered', $(e.target)); });
\r
24 this.node.on('mouseout', '[wlxml-tag]', function(e) { sandbox.publish('nodeBlured', $(e.target)); });
\r
25 this.node.on('click', '[wlxml-tag]', function(e) {
\r
26 console.log('clicked node type: '+e.target.nodeType);
\r
27 view._markSelected($(e.target));
\r
30 this.node.on('keyup', '#rng-module-documentCanvas-contentWrapper', function(e) {
\r
31 var anchor = $(window.getSelection().anchorNode);
\r
32 if(anchor[0].nodeType === Node.TEXT_NODE)
\r
33 anchor = anchor.parent();
\r
34 if(!anchor.is('[wlxml-tag]'))
\r
36 view._markSelected(anchor);
\r
39 this.node.on('keydown', '#rng-module-documentCanvas-contentWrapper', function(e) {
\r
40 if(e.which === 13) {
\r
42 view.insertNewNode(null, null);
\r
47 var observer = new MutationObserver(function(mutations) {
\r
48 mutations.forEach(function(mutation) {
\r
49 _.each(mutation.addedNodes, function(node) {
\r
51 node.parent().find('[wlxml-tag]').each(function() {
\r
54 tag.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
59 var config = { attributes: true, childList: true, characterData: true, subtree: true };
\r
60 observer.observe(this.node.find('#rng-module-documentCanvas-contentWrapper')[0], config);
\r
62 this.gridToggled = false;
\r
64 _createNode: function(wlxmlTag, wlxmlClass) {
\r
65 var toBlock = ['div', 'document', 'section', 'header'];
\r
66 var htmlTag = _.contains(toBlock, wlxmlTag) ? 'div' : 'span';
\r
67 var toret = $('<' + htmlTag + '>');
\r
68 toret.attr('wlxml-tag', wlxmlTag);
\r
70 toret.attr('wlxml-class', wlxmlClass);
\r
73 insertNewNode: function(wlxmlTag, wlxmlClass) {
\r
74 //TODO: Insert inline
\r
75 var anchor = $(window.getSelection().anchorNode);
\r
76 var anchorOffset = window.getSelection().anchorOffset;
\r
77 if(anchor[0].nodeType === Node.TEXT_NODE)
\r
78 anchor = anchor.parent();
\r
79 if(anchor.text() === '') {
\r
81 anchor = anchor.parent();
\r
84 if(anchorOffset > 0 && anchorOffset < anchor.text().length) {
\r
85 if(wlxmlTag === null && wlxmlClass === null) {
\r
86 return this.splitWithNewNode(anchor);
\r
88 return this.wrapSelectionWithNewNode(wlxmlTag, wlxmlClass);
\r
90 var newNode = this._createNode(wlxmlTag || anchor.attr('wlxml-tag'), wlxmlClass || anchor.attr('wlxml-class'));
\r
91 if(anchorOffset === 0)
\r
92 anchor.before(newNode)
\r
94 anchor.after(newNode);
\r
95 this.selectNode(newNode);
\r
97 sandbox.publish('contentChanged');
\r
99 wrapSelectionWithNewNode: function(wlxmlTag, wlxmlClass) {
\r
100 var selection = window.getSelection();
\r
101 if(selection.anchorNode === selection.focusNode && selection.anchorNode.nodeType === Node.TEXT_NODE) {
\r
102 var startOffset = selection.anchorOffset;
\r
103 var endOffset = selection.focusOffset;
\r
104 if(startOffset > endOffset) {
\r
105 var tmp = startOffset;
\r
106 startOffset = endOffset;
\r
109 var node = selection.anchorNode;
\r
110 var prefix = node.data.substr(0, startOffset);
\r
111 var suffix = node.data.substr(endOffset);
\r
112 var core = node.data.substr(startOffset, endOffset - startOffset);
\r
113 var newNode = this._createNode(wlxmlTag, wlxmlClass);
\r
114 newNode.text(core || 'test');
\r
115 $(node).replaceWith(newNode);
\r
116 newNode.before(prefix);
\r
117 newNode.after(suffix);
\r
119 this.selectNode(newNode);
\r
121 sandbox.publish('contentChanged');
\r
124 splitWithNewNode: function(node) {
\r
125 var selection = window.getSelection();
\r
126 if(selection.anchorNode === selection.focusNode && selection.anchorNode.nodeType === Node.TEXT_NODE) {
\r
127 var startOffset = selection.anchorOffset;
\r
128 var endOffset = selection.focusOffset;
\r
129 if(startOffset > endOffset) {
\r
130 var tmp = startOffset;
\r
131 startOffset = endOffset;
\r
134 var anchor = selection.anchorNode;
\r
135 var prefix = anchor.data.substr(0, startOffset);
\r
136 var suffix = anchor.data.substr(endOffset);
\r
137 var prefixNode = this._createNode(node.attr('wlxml-tag'), node.attr('wlxml-class'));
\r
138 var newNode = this._createNode(node.attr('wlxml-tag'), node.attr('wlxml-class'));
\r
139 var suffixNode = this._createNode(node.attr('wlxml-tag'), node.attr('wlxml-class'));
\r
140 prefixNode.text(prefix);
\r
141 suffixNode.text(suffix);
\r
142 node.replaceWith(newNode);
\r
143 newNode.before(prefixNode);
\r
144 newNode.after(suffixNode);
\r
146 this.selectNode(newNode);
\r
148 sandbox.publish('contentChanged');
\r
151 setBody: function(HTMLTree) {
\r
152 this.node.find('#rng-module-documentCanvas-content').html(HTMLTree);
\r
154 getBody: function() {
\r
155 return this.node.find('#rng-module-documentCanvas-content').html();
\r
157 _markSelected: function(node) {
\r
158 this.dimNode(node);
\r
160 this.node.find('.rng-current').removeClass('rng-current');
\r
162 node.addClass('rng-current');
\r
164 this.currentNode = node;
\r
165 sandbox.publish('nodeSelected', node);
\r
168 selectNode: function(node) {
\r
169 view._markSelected(node);
\r
170 var range = document.createRange();
\r
171 range.selectNodeContents(node[0]);
\r
172 range.collapse(false);
\r
174 var selection = document.getSelection();
\r
175 selection.removeAllRanges()
\r
176 selection.addRange(range);
\r
178 selectNodeById: function(id) {
\r
179 var node = this.node.find('#'+id);
\r
181 this.selectNode(node);
\r
183 highlightNode: function(node) {
\r
184 if(!this.gridToggled) {
\r
185 node.addClass('rng-hover');
\r
186 var label = node.attr('wlxml-tag');
\r
187 if(node.attr('wlxml-class'))
\r
188 label += ' / ' + node.attr('wlxml-class');
\r
189 var tag = $('<div>').addClass('rng-visualEditor-nodeHoverTag').text(label);
\r
193 dimNode: function(node) {
\r
194 if(!this.gridToggled) {
\r
195 node.removeClass('rng-hover');
\r
196 node.find('.rng-visualEditor-nodeHoverTag').remove();
\r
199 highlightNodeById: function(id) {
\r
200 var node = this.node.find('#'+id);
\r
202 this.highlightNode(node);
\r
204 dimNodeById: function(id) {
\r
205 var node = this.node.find('#'+id);
\r
207 this.dimNode(node);
\r
209 selectFirstNode: function() {
\r
210 var firstNodeWithText = this.node.find('[wlxml-tag]').filter(function() {
\r
211 return $(this).clone().children().remove().end().text().trim() !== '';
\r
214 if(firstNodeWithText.length)
\r
215 node = $(firstNodeWithText[0])
\r
217 node = this.node.find('[wlxml-class|="p"]')
\r
219 this.selectNode(node);
\r
221 toggleGrid: function(toggle) {
\r
222 this.node.find('[wlxml-tag]').toggleClass('rng-hover', toggle);
\r
223 this.gridToggled = toggle;
\r
231 start: function() { sandbox.publish('ready'); },
\r
232 getView: function() { return view.node; },
\r
233 setDocument: function(xml) {
\r
234 var transformed = transformations.fromXML.getDocumentDescription(xml);
\r
235 view.setBody(transformed.HTMLTree);
\r
236 view.selectFirstNode();
\r
239 modifyCurrentNode: function(attr, value) {
\r
240 if(view.currentNode)
\r
241 view.currentNode.attr('wlxml-'+attr, value);
\r
243 highlightNode: function(id) {
\r
244 view.highlightNodeById(id);
\r
246 dimNode: function(id) {
\r
247 view.dimNodeById(id);
\r
249 selectNode: function(id) {
\r
250 view.selectNodeById(id);
\r
252 toggleGrid: function(toggle) {
\r
253 view.toggleGrid(toggle);
\r
255 insertNewNode: function(wlxmlTag, wlxmlClass) {
\r
256 view.insertNewNode(wlxmlTag, wlxmlClass);
\r
258 wrapSelectionWithNewNode: function(wlxmlTag, wlxmlClass) {
\r
259 view.wrapSelectionWithNewNode(wlxmlTag, wlxmlClass);
\r