| author | Yves-Marie Haussonne <ymh.work+github@gmail.com> |
| Fri, 09 May 2014 18:35:26 +0200 | |
| changeset 656 | a84519031134 |
| parent 600 | fda73ac53450 |
| permissions | -rw-r--r-- |
| 0 | 1 |
getWrapperAncestor = function(elt) { |
| 341 | 2 |
var parent = elt ; |
3 |
while (parent != null) { |
|
4 |
if (CY.DOM.hasClass(parent, 'c-s')) |
|
5 |
return parent ; |
|
6 |
parent = parent.parentNode ; |
|
7 |
} |
|
8 |
return null ; |
|
| 0 | 9 |
} |
10 |
||
11 |
hasWrapperAncestor = function(elt) { |
|
| 341 | 12 |
return (getWrapperAncestor(elt) != null) ; |
13 |
/* var parent = elt ; |
|
14 |
while (parent != null) { |
|
15 |
if (CY.DOM.hasClass(parent, 'c-s')) |
|
16 |
return true ; |
|
17 |
parent = parent.parentNode ; |
|
18 |
} |
|
19 |
return false ;*/ |
|
| 0 | 20 |
} |
21 |
||
22 |
// returns null or : |
|
23 |
// {'text' : textcontent, 'start': {'elt':startNode, 'nbChar':startOffset(==number of characters to selection start in the start node}, |
|
24 |
// 'end': ....} |
|
25 |
// the text attribute is informational having it empty doesn't mean selection is empty !! |
|
26 |
||
27 |
// when selection starts/ends in/on a non textual element (<hr/> for example) we very often have anchorNode/focusNode == body elt |
|
28 |
// TODO adapt this body case by considering offset ( cf. http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html) |
|
|
556
69503659fe8f
[c_selection.js] If safari_mobile, get current selection from a previously created global variable
Simon Descarpentries <sid@sopinspace.com>
parents:
532
diff
changeset
|
29 |
|
| 0 | 30 |
getSelectionInfo = function () { |
| 341 | 31 |
var startNode = null, endNode = null, startOffset = 0, endOffset = 0, text = '' ; |
32 |
|
|
33 |
if (window.getSelection) { // everything else than IE |
|
|
558
5ba711a2bd06
Add comments, fix missing compressed js
Simon Descarpentries <sid@sopinspace.com>
parents:
556
diff
changeset
|
34 |
// SID: if on safari_mobile get the previous meaningfull selection from a global variable set in text_view_comments.html |
|
556
69503659fe8f
[c_selection.js] If safari_mobile, get current selection from a previously created global variable
Simon Descarpentries <sid@sopinspace.com>
parents:
532
diff
changeset
|
35 |
var userSelection = safari_mobile ? storedSelection : window.getSelection (); |
| 0 | 36 |
|
| 341 | 37 |
if (userSelection.rangeCount > 0) { |
38 |
var range = userSelection.getRangeAt(0) ; |
|
39 |
text = range.toString() ; |
|
40 |
if (text != "") { |
|
41 |
|
|
42 |
// selection occured from right to left ? : |
|
43 |
var r1 = document.createRange() ;r1.setStart(userSelection.anchorNode, userSelection.anchorOffset) ;r1.collapse(true) ; |
|
44 |
var r2 = document.createRange() ;r2.setEnd(userSelection.focusNode, userSelection.focusOffset) ;r2.collapse(false) ; |
|
45 |
var leftToRight = (r2.compareBoundaryPoints(2, r1) == 1) ; // 2 is for END_TO_END |
|
46 |
// CY.log("leftToRight : " + leftToRight) ; |
|
47 |
startNode = (leftToRight) ? userSelection.anchorNode.parentNode : userSelection.focusNode.parentNode ; |
|
| 397 | 48 |
// GIB: when selecting amath, we should go up in the dom to find the accurate start/end Nodes |
49 |
if (startNode.nodeName == 'mi' || startNode.nodeName == 'mo') { |
|
50 |
startNode = startNode.parentElement.parentElement.parentElement.parentElement; |
|
51 |
} |
|
| 341 | 52 |
innerStartNode = (leftToRight) ? userSelection.anchorNode : userSelection.focusNode ; |
53 |
endNode = (leftToRight) ? userSelection.focusNode.parentNode : userSelection.anchorNode.parentNode; |
|
| 397 | 54 |
// GIB: when selecting amath, we should go up in the dom to find the accurate start/end Nodes |
55 |
if (endNode.nodeName == 'mi' || endNode.nodeName == 'mo') { |
|
56 |
endNode = endNode.parentElement.parentElement.parentElement.parentElement; |
|
57 |
} |
|
| 341 | 58 |
innerEndNode = (leftToRight) ? userSelection.focusNode : userSelection.anchorNode; |
59 |
|
|
60 |
startOffset = (leftToRight) ? userSelection.anchorOffset : userSelection.focusOffset; |
|
61 |
endOffset = (leftToRight) ? userSelection.focusOffset : userSelection.anchorOffset ; |
|
| 0 | 62 |
|
| 341 | 63 |
if (!hasWrapperAncestor(endNode) && hasWrapperAncestor(startNode)){ |
64 |
var r3 = document.createRange() ; |
|
65 |
r3.setStart(innerStartNode, startOffset) ; |
|
| 0 | 66 |
|
| 341 | 67 |
var csStartAncestor = getWrapperAncestor(startNode) ; |
68 |
var next = csStartAncestor ; |
|
69 |
r3.setEndAfter(next) ; |
|
70 |
|
|
71 |
var ind = parseInt(csStartAncestor.id.substring('sv_'.length)) ; |
|
72 |
while(r3.toString().length < range.toString().length) { |
|
73 |
ind++ ; |
|
|
600
fda73ac53450
Use YUI 3.10 (now that conflict with ASCIIMathML is solved).
gibus
parents:
558
diff
changeset
|
74 |
var node = CY.one("#sv_"+ind) ; |
| 341 | 75 |
if (node) { |
76 |
next = CY.Node.getDOMNode(node) ; |
|
77 |
r3.setEndAfter(next) ; |
|
78 |
} |
|
79 |
else |
|
80 |
break ; |
|
81 |
} |
|
82 |
endNode = next.lastChild ; |
|
83 |
endOffset = CY.DOM.getText(endNode).length ; |
|
84 |
} |
|
85 |
else if (!hasWrapperAncestor(startNode) && hasWrapperAncestor(endNode)){ |
|
86 |
var r3 = document.createRange() ; |
|
87 |
r3.setEnd(innerEndNode, endOffset) ; |
|
| 0 | 88 |
|
| 341 | 89 |
var csEndAncestor = getWrapperAncestor(endNode) ; |
90 |
var prev = csEndAncestor ; |
|
91 |
r3.setStartBefore(prev) ; |
|
92 |
|
|
93 |
var ind = parseInt(csEndAncestor.id.substring('sv_'.length)) ; |
|
94 |
while(r3.toString().length < range.toString().length) { |
|
95 |
ind-- ; |
|
|
600
fda73ac53450
Use YUI 3.10 (now that conflict with ASCIIMathML is solved).
gibus
parents:
558
diff
changeset
|
96 |
var node = CY.one("#sv_"+ind) ; |
| 341 | 97 |
if (node) { |
98 |
prev = CY.Node.getDOMNode(node) ; |
|
99 |
r3.setStartBefore(prev) ; |
|
100 |
} |
|
101 |
else |
|
102 |
break ; |
|
103 |
} |
|
104 |
startNode = prev.firstChild ; |
|
105 |
startOffset = 0 ; |
|
106 |
} |
|
107 |
else if (!hasWrapperAncestor(startNode) && !hasWrapperAncestor(endNode)){ |
|
108 |
var textLength = text.length ; |
|
109 |
|
|
110 |
// gather nodes with id sv_xxxx as candidates for start ancestor |
|
111 |
var startNodeInds = [] ; |
|
112 |
for (var ind = 0 ; ; ind++) { |
|
|
600
fda73ac53450
Use YUI 3.10 (now that conflict with ASCIIMathML is solved).
gibus
parents:
558
diff
changeset
|
113 |
var svNode = CY.one("#sv_"+ind) ; |
| 341 | 114 |
if (svNode == null) { |
115 |
break; |
|
116 |
} |
|
117 |
else { |
|
118 |
var svText = svNode.get("text") ; |
|
119 |
if (text.indexOf(svText) == 0) { |
|
120 |
startNodeInds.push(ind) ; |
|
121 |
} |
|
122 |
} |
|
123 |
} |
|
124 |
|
|
125 |
// gather nodes with id sv_xxxx as candidates for end ancestor |
|
126 |
var endNodeInds = [] ; |
|
127 |
for (var ind = 0 ; ; ind++) { |
|
|
600
fda73ac53450
Use YUI 3.10 (now that conflict with ASCIIMathML is solved).
gibus
parents:
558
diff
changeset
|
128 |
var svNode = CY.one("#sv_"+ind) ; |
| 341 | 129 |
if (svNode == null) { |
130 |
break; |
|
131 |
} |
|
132 |
else { |
|
133 |
var svText = svNode.get("text") ; |
|
134 |
if (text.indexOf(svText) == (textLength - svText.length)) { // i.e. the selection exactly ends with svText |
|
135 |
endNodeInds.push(ind) ; |
|
136 |
} |
|
137 |
} |
|
138 |
} |
|
| 0 | 139 |
|
| 341 | 140 |
var stop = false ; |
141 |
for (var i = 0 ; i < startNodeInds.length ; i++) { |
|
142 |
for (var j = 0 ; j < endNodeInds.length ; j++) { |
|
143 |
var r4 = document.createRange() ; |
|
144 |
|
|
|
600
fda73ac53450
Use YUI 3.10 (now that conflict with ASCIIMathML is solved).
gibus
parents:
558
diff
changeset
|
145 |
var s = CY.Node.getDOMNode(CY.one("#sv_"+startNodeInds[i])) ; var e = CY.Node.getDOMNode(CY.one("#sv_"+endNodeInds[j])) ; |
| 341 | 146 |
|
147 |
r4.setStartBefore(s) ; r4.setEndAfter(CY.Node.getDOMNode(e)) ; |
|
148 |
|
|
149 |
// does r4 starts after range start and r4 ends before range end ? |
|
150 |
if ((-1 < r4.compareBoundaryPoints(0, range)) && (1 > r4.compareBoundaryPoints(2, range))) { |
|
151 |
startNode = s.firstChild ; |
|
152 |
startOffset = 0 ; |
|
153 |
endNode = e.lastChild ; |
|
154 |
endOffset = CY.DOM.getText(e).length ; |
|
155 |
|
|
156 |
stop = true ; |
|
157 |
break ; |
|
158 |
} |
|
159 |
} |
|
160 |
if (stop) |
|
161 |
break ; |
|
162 |
} |
|
163 |
} |
|
164 |
|
|
165 |
r1.detach() ; |
|
166 |
r2.detach() ; |
|
167 |
} |
|
168 |
else |
|
169 |
return null ; |
|
170 |
} |
|
|
556
69503659fe8f
[c_selection.js] If safari_mobile, get current selection from a previously created global variable
Simon Descarpentries <sid@sopinspace.com>
parents:
532
diff
changeset
|
171 |
else |
| 341 | 172 |
return null ; |
173 |
|
|
174 |
} |
|
175 |
else if (document.selection) { // IE case |
|
176 |
var rng = document.selection.createRange(); |
|
177 |
if (rng.text.length == 0) |
|
178 |
return null ; |
|
179 |
var el = rng.parentElement(); |
|
| 0 | 180 |
|
| 341 | 181 |
// duplicate the range and collapse it to its start, to ask IE the parent element of the start textNode. |
182 |
var rngStart = rng.duplicate(); |
|
183 |
var rngEnd = rng.duplicate(); |
|
| 0 | 184 |
|
| 341 | 185 |
rngStart.collapse(true); // collapse to start |
186 |
rngEnd.collapse(false); // collapse to end |
|
187 |
|
|
188 |
startNode = rngStart.parentElement() ; |
|
189 |
while(rngStart.moveStart('character', -1) != 0) { |
|
190 |
if (rngStart.parentElement() != startNode) |
|
191 |
break ; |
|
192 |
startOffset++ ; |
|
193 |
} |
|
194 |
endNode = rngEnd.parentElement() ; |
|
195 |
while(rngEnd.moveEnd('character', -1) != 0) { |
|
196 |
if (rngEnd.parentElement() != endNode) |
|
197 |
break ; |
|
198 |
endOffset++ ; |
|
199 |
} |
|
200 |
|
|
201 |
text = rng.text ; |
|
202 |
} |
|
203 |
|
|
204 |
if (!hasWrapperAncestor(startNode) || !hasWrapperAncestor(endNode)){ |
|
205 |
// CY.log('no wrapper on one end') ; |
|
206 |
return null ; |
|
207 |
} |
|
208 |
return {'text' : text, 'start' : {'elt':startNode, 'offset':startOffset}, 'end' : {'elt':endNode, 'offset':endOffset}} ; |
|
209 |
} |