Setting caret after moving list elements up one level
[fnpeditor.git] / modules / documentCanvas / canvasManager.js
1 define([
2 'libs/jquery-1.9.1.min',
3 './canvasNode'
4 ], function($, canvasNode) {
5
6 'use strict';
7
8 var getCursorPosition = function() {
9     var selection = window.getSelection();
10     var anchorNode = $(selection.anchorNode);
11     var parent = anchorNode.parent();
12     return {
13         textNode: anchorNode,
14         textNodeOffset: selection.anchorOffset,
15         textNodeIndex: parent.contents().index(anchorNode),
16         parentNode: parent,
17         focusNode: $(selection.focusNode).parent(),
18         isAtEnd: selection.anchorOffset === anchorNode.text().length
19     };
20 };
21
22 var Manager = function(canvas, sandbox) {
23     this.canvas = canvas;
24     this.sandbox = sandbox;
25     this.shownAlready = false;
26     this.scrollbarPosition = 0;
27     this.currentNode = null;
28     var manager = this;
29         
30     // canvas.doc().dom().find('#rng-module-documentCanvas-content').on('keyup', function() {
31     //     manager.sandbox.publish('contentChanged');
32     // });
33
34     // canvas.doc().dom().on('mouseover', '[wlxml-tag]', function(e) {
35     //     e.stopPropagation();
36     //     manager.sandbox.publish('nodeHovered', canvasNode.create($(e.target)));
37     // });
38     // canvas.doc().dom().on('mouseout', '[wlxml-tag]', function(e) {
39     //     e.stopPropagation();
40     //     manager.sandbox.publish('nodeBlured', canvasNode.create($(e.target)));
41     // });
42     // canvas.doc().dom().on('click', '[wlxml-tag]', function(e) {
43     //     e.stopPropagation();
44     //     console.log('clicked node type: '+e.target.nodeType);
45     //     manager.selectNode(canvasNode.create($(e.target)));
46     // });
47
48     // canvas.doc().dom().on('keyup', '#rng-module-documentCanvas-contentWrapper', function(e) {
49     //     var anchor = $(window.getSelection().anchorNode);
50         
51     //     if(anchor[0].nodeType === Node.TEXT_NODE)
52     //         anchor = anchor.parent();
53     //     if(!anchor.is('[wlxml-tag]'))
54     //         return;
55     //     manager.selectNode(canvasNode.create(anchor));
56     // });
57     
58     // canvas.doc().dom().on('keydown', '#rng-module-documentCanvas-contentWrapper', function(e) {
59     //     if(e.which === 13) { 
60     //         manager.onEnterKey(e);
61     //     }
62     //     if(e.which === 8) {
63     //         manager.onBackspaceKey(e);
64     //     }
65     // });
66               
67     // canvas.doc().dom().onShow = function() {
68     //     if(!manager.shownAlready) {
69     //         manager.shownAlready = true;
70     //         manager.selectFirstNode();
71     //     } else if(manager.currentNode) {
72     //         manager.movecaretToNode(manager.getNodeElement(manager.currentNode));
73     //         canvas.doc().dom().find('#rng-module-documentCanvas-contentWrapper').scrollTop(manager.scrollbarPosition);
74     //     }
75     // };
76     // canvas.doc().dom().onHide = function() {
77     //    manager.scrollbarPosition = canvas.doc().dom().find('#rng-module-documentCanvas-contentWrapper').scrollTop();
78     // };
79 };
80     
81 Manager.prototype.selectNode = function(cnode, options) {
82     options = options || {};
83     var nodeElement = this.getNodeElement(cnode);
84     
85     this.dimNode(cnode);
86     
87     this.canvas.doc().dom().find('.rng-module-documentCanvas-currentNode').removeClass('rng-module-documentCanvas-currentNode');
88     nodeElement.addClass('rng-module-documentCanvas-currentNode');
89     
90     if(options.movecaret) {
91         this.movecaretToNode(nodeElement, options.movecaret);
92     }
93     
94     this.currentNode = cnode;
95     this.sandbox.publish('nodeSelected', cnode);
96 };
97
98 Manager.prototype.getNodeElement = function(cnode) {
99     return this.canvas.doc().dom().find('#'+cnode.getId());
100 };
101
102 Manager.prototype.highlightNode = function(cnode) {
103     var nodeElement = this.getNodeElement(cnode);
104     if(!this.gridToggled) {
105         nodeElement.addClass('rng-common-hoveredNode');
106         var label = nodeElement.attr('wlxml-tag');
107         if(nodeElement.attr('wlxml-class'))
108             label += ' / ' + nodeElement.attr('wlxml-class');
109         var tag = $('<div>').addClass('rng-module-documentCanvas-hoveredNodeTag').text(label);
110         nodeElement.append(tag);
111     }
112 };
113
114 Manager.prototype.dimNode = function(cnode) {
115     var nodeElement = this.getNodeElement(cnode);
116     if(!this.gridToggled) {
117         nodeElement.removeClass('rng-common-hoveredNode');
118         nodeElement.find('.rng-module-documentCanvas-hoveredNodeTag').remove();
119     }
120 };
121
122 Manager.prototype.selectFirstNode = function() {
123     var firstNodeWithText = this.canvas.doc().dom().find('[wlxml-tag]').filter(function() {
124         return $(this).clone().children().remove().end().text().trim() !== '';
125     }).first();
126     var node;
127     if(firstNodeWithText.length)
128         node = $(firstNodeWithText[0]);
129     else {
130         node = this.canvas.doc().dom().find('[wlxml-class|="p"]');
131     }
132     this.selectNode(canvasNode.create(node), {movecaret: true});
133 };
134
135 Manager.prototype.movecaretToNode = function(nodeElement, where) {
136     if(!nodeElement.length)
137         return;
138     var range = document.createRange();
139     range.selectNodeContents(nodeElement[0]);
140     
141     var collapseArg = true;
142     if(where === 'end')
143         collapseArg = false;
144     range.collapse(collapseArg);
145     var selection = document.getSelection();
146     selection.removeAllRanges();
147     selection.addRange(range);
148 };
149
150 Manager.prototype.onEnterKey = function(e) {
151     e.preventDefault();
152     var pos = getCursorPosition();
153     var contextNode = this.canvas.getNodeById(pos.parentNode.attr('id'));
154     var newNode;
155
156     if(pos.isAtEnd) {
157         newNode = canvasNode.create({tag: pos.parentNode.attr('wlxml-tag'), klass: pos.parentNode.attr('wlxml-class')});
158         this.canvas.nodeInsertAfter({node: newNode, after: this.canvas.getNodeById(pos.parentNode.attr('id'))});
159     } else {
160         newNode = this.canvas.nodeSplit({node: contextNode, textNodeIdx: pos.textNodeIndex, offset: pos.textNodeOffset});
161     }
162     if(newNode)
163         this.selectNode(newNode, {movecaret: true});
164     this.sandbox.publish('contentChanged');
165 };
166
167 Manager.prototype.onBackspaceKey = function(e) {
168     var pos = getCursorPosition();
169     var len = pos.textNode.text().length;
170     if(len === 1) {
171         // Prevent deleting node by browser after last character removed;
172         e.preventDefault();
173         pos.parentNode.text('');
174     }
175     if(len === 0) {
176         e.preventDefault();
177         var toRemove = canvasNode.create(pos.textNode);
178         var prevNode = this.canvas.getPrecedingNode({node:toRemove});
179         this.canvas.nodeRemove({node: toRemove}); // jesli nie ma tekstu, to anchor nie jest tex nodem
180         this.selectNode(prevNode, {movecaret: 'end'});
181     }
182 };
183
184
185 return Manager;
186     
187 });