fbae482a4b2368e3da78b4d39ced9e81e1de51a1
[fnpeditor.git] / src / editor / modules / documentCanvas / canvas / selection.js
1 define(function(require) {
2     
3 'use strict';
4
5 var $ = require('libs/jquery');
6
7 var Selection = function(canvas, params) {
8     this.canvas = canvas;
9     $.extend(this, params);
10 };
11
12 var CaretSelection = function(canvas, params) {
13     Selection.call(this, canvas, params);
14 };
15 CaretSelection.prototype = Object.create(Selection.prototype);
16 $.extend(CaretSelection.prototype, {
17     toDocumentFragment: function() {
18         var doc = this.canvas.wlxmlDocument;
19         return doc.createFragment(doc.CaretFragment, {node: this.element.wlxmlNode, offset: this.offset});
20     },
21     isAtEdge: function() {
22         return this.isAtBeginning() || this.isAtEnd();
23     },
24     isAtBeginning: function() {
25         return this.offset === 0;
26     },
27     isAtEnd: function() {
28         return this.offset === this.element.getText().length;
29     }
30 });
31
32 var TextSelection = function(canvas, params) {
33     var anchorFirst;
34
35     Selection.call(this, canvas, params);
36
37     if(this.anchorElement.sameNode(this.focusElement)) {
38         anchorFirst = this.anchorOffset <= this.focusOffset;
39     } else {
40         /*jshint bitwise: false*/
41         /* globals Node */
42         anchorFirst = this.anchorElement.dom[0].compareDocumentPosition(this.focusElement.dom[0]) & Node.DOCUMENT_POSITION_FOLLOWING;
43     }
44
45     if(anchorFirst) {
46         this.startElement = this.anchorElement;
47         this.startOffset = this.anchorOffset;
48         this.endElement = this.focusElement;
49         this.endOffset = this.focusOffset;
50
51     } else {
52         this.startElement = this.focusElement;
53         this.startOffset = this.focusOffset;
54         this.endElement = this.anchorElement;
55         this.endOffset = this.anchorOffset;
56     }
57 };
58 TextSelection.prototype = Object.create(Selection.prototype);
59 $.extend(TextSelection.prototype, {
60     toDocumentFragment: function() {
61         var doc = this.canvas.wlxmlDocument,
62             anchorNode = this.anchorElement ? this.anchorElement.wlxmlNode : null,
63             focusNode = this.focusElement ? this.focusElement.wlxmlNode : null;
64         
65         if(!anchorNode || !focusNode) {
66             return;
67         }
68
69         if(anchorNode.isSiblingOf(focusNode)) {
70             return doc.createFragment(doc.TextRangeFragment, {
71                 node1: anchorNode,
72                 offset1: this.anchorOffset,
73                 node2: focusNode,
74                 offset2: this.focusOffset,
75             });
76         }
77         else {
78             var siblingParents = doc.getSiblingParents({node1: anchorNode, node2: focusNode});
79             return doc.createFragment(doc.RangeFragment, {
80                 node1: siblingParents.node1,
81                 node2: siblingParents.node2
82             });
83         }
84     },
85     startsAtBeginning: function() {
86         return this.startOffset === 0;
87     },
88     endsAtEnd: function() {
89         return this.endOffset === this.endElement.getText().length;
90     }
91 });
92
93 var NodeSelection = function(canvas, params) {
94     Selection.call(this, canvas, params);
95 };
96 NodeSelection.prototype = Object.create(Selection.prototype);
97 $.extend(NodeSelection.prototype, {
98     toDocumentFragment: function() {
99         var doc = this.canvas.wlxmlDocument;
100         doc.createFragment(doc.NodeFragment, {node: this.element.wlxmlNode});
101     }
102 });
103
104
105 var isText = function(node) {
106     /* globals Node */
107     return node && node.nodeType === Node.TEXT_NODE && $(node.parentNode).is('[document-text-element]');
108 };
109
110 var types = {
111     caret: CaretSelection,
112     textSelection: TextSelection,
113     nodeSelection: NodeSelection
114 };
115
116 return {
117     fromParams: function(canvas, params) {
118         return new types[params.type](canvas, params);
119     },
120     fromNativeSelection: function(canvas) {
121         /* globals window */
122         var nativeSelection =  window.getSelection(),
123             params = {},
124             element;
125         if(nativeSelection.focusNode) {
126             if(nativeSelection.isCollapsed && isText(nativeSelection.focusNode)) {
127                 params = {
128                     type: 'caret',
129                     element: canvas.getDocumentElement(nativeSelection.focusNode),
130                     offset: nativeSelection.focusOffset
131                 };
132             } else if(isText(nativeSelection.focusNode) && isText(nativeSelection.anchorNode)) {
133                 params = {
134                     type: 'textSelection',
135                     anchorElement: canvas.getDocumentElement(nativeSelection.anchorNode),
136                     anchorOffset: nativeSelection.anchorOffset,
137                     focusElement: canvas.getDocumentElement(nativeSelection.focusNode),
138                     focusOffset: nativeSelection.focusOffset
139                 };
140             }
141         } else if((element = canvas.getCurrentNodeElement())) {
142             params = {
143                 type: 'nodeSelection',
144                 element: element
145             };
146         }
147         if(params.type) {
148             return this.fromParams(canvas, params);
149         }
150     }
151 };
152
153 });