]> git.wh0rd.org - tt-rss.git/blob - lib/dijit/_editor/selection.js.uncompressed.js
update dojo to 1.7.3
[tt-rss.git] / lib / dijit / _editor / selection.js.uncompressed.js
1 define("dijit/_editor/selection", [
2 "dojo/dom", // dom.byId
3 "dojo/_base/lang",
4 "dojo/_base/sniff", // has("ie") has("opera")
5 "dojo/_base/window", // win.body win.doc win.doc.createElement win.doc.selection win.doc.selection.createRange win.doc.selection.type.toLowerCase win.global win.global.getSelection
6 ".." // for exporting symbols to dijit._editor.selection (TODO: remove in 2.0)
7 ], function(dom, lang, has, win, dijit){
8
9 // module:
10 // dijit/_editor/selection
11 // summary:
12 // Text selection API
13
14
15 lang.getObject("_editor.selection", true, dijit);
16
17 // FIXME:
18 // all of these methods branch internally for IE. This is probably
19 // sub-optimal in terms of runtime performance. We should investigate the
20 // size difference for differentiating at definition time.
21
22 lang.mixin(dijit._editor.selection, {
23 getType: function(){
24 // summary:
25 // Get the selection type (like win.doc.select.type in IE).
26 if(has("ie") < 9){
27 return win.doc.selection.type.toLowerCase();
28 }else{
29 var stype = "text";
30
31 // Check if the actual selection is a CONTROL (IMG, TABLE, HR, etc...).
32 var oSel;
33 try{
34 oSel = win.global.getSelection();
35 }catch(e){ /*squelch*/ }
36
37 if(oSel && oSel.rangeCount == 1){
38 var oRange = oSel.getRangeAt(0);
39 if( (oRange.startContainer == oRange.endContainer) &&
40 ((oRange.endOffset - oRange.startOffset) == 1) &&
41 (oRange.startContainer.nodeType != 3 /* text node*/)
42 ){
43 stype = "control";
44 }
45 }
46 return stype; //String
47 }
48 },
49
50 getSelectedText: function(){
51 // summary:
52 // Return the text (no html tags) included in the current selection or null if no text is selected
53 if(has("ie") < 9){
54 if(dijit._editor.selection.getType() == 'control'){
55 return null;
56 }
57 return win.doc.selection.createRange().text;
58 }else{
59 var selection = win.global.getSelection();
60 if(selection){
61 return selection.toString(); //String
62 }
63 }
64 return '';
65 },
66
67 getSelectedHtml: function(){
68 // summary:
69 // Return the html text of the current selection or null if unavailable
70 if(has("ie") < 9){
71 if(dijit._editor.selection.getType() == 'control'){
72 return null;
73 }
74 return win.doc.selection.createRange().htmlText;
75 }else{
76 var selection = win.global.getSelection();
77 if(selection && selection.rangeCount){
78 var i;
79 var html = "";
80 for(i = 0; i < selection.rangeCount; i++){
81 //Handle selections spanning ranges, such as Opera
82 var frag = selection.getRangeAt(i).cloneContents();
83 var div = win.doc.createElement("div");
84 div.appendChild(frag);
85 html += div.innerHTML;
86 }
87 return html; //String
88 }
89 return null;
90 }
91 },
92
93 getSelectedElement: function(){
94 // summary:
95 // Retrieves the selected element (if any), just in the case that
96 // a single element (object like and image or a table) is
97 // selected.
98 if(dijit._editor.selection.getType() == "control"){
99 if(has("ie") < 9){
100 var range = win.doc.selection.createRange();
101 if(range && range.item){
102 return win.doc.selection.createRange().item(0);
103 }
104 }else{
105 var selection = win.global.getSelection();
106 return selection.anchorNode.childNodes[ selection.anchorOffset ];
107 }
108 }
109 return null;
110 },
111
112 getParentElement: function(){
113 // summary:
114 // Get the parent element of the current selection
115 if(dijit._editor.selection.getType() == "control"){
116 var p = this.getSelectedElement();
117 if(p){ return p.parentNode; }
118 }else{
119 if(has("ie") < 9){
120 var r = win.doc.selection.createRange();
121 r.collapse(true);
122 return r.parentElement();
123 }else{
124 var selection = win.global.getSelection();
125 if(selection){
126 var node = selection.anchorNode;
127 while(node && (node.nodeType != 1)){ // not an element
128 node = node.parentNode;
129 }
130 return node;
131 }
132 }
133 }
134 return null;
135 },
136
137 hasAncestorElement: function(/*String*/tagName /* ... */){
138 // summary:
139 // Check whether current selection has a parent element which is
140 // of type tagName (or one of the other specified tagName)
141 // tagName: String
142 // The tag name to determine if it has an ancestor of.
143 return this.getAncestorElement.apply(this, arguments) != null; //Boolean
144 },
145
146 getAncestorElement: function(/*String*/tagName /* ... */){
147 // summary:
148 // Return the parent element of the current selection which is of
149 // type tagName (or one of the other specified tagName)
150 // tagName: String
151 // The tag name to determine if it has an ancestor of.
152 var node = this.getSelectedElement() || this.getParentElement();
153 return this.getParentOfType(node, arguments); //DOMNode
154 },
155
156 isTag: function(/*DomNode*/ node, /*String[]*/ tags){
157 // summary:
158 // Function to determine if a node is one of an array of tags.
159 // node:
160 // The node to inspect.
161 // tags:
162 // An array of tag name strings to check to see if the node matches.
163 if(node && node.tagName){
164 var _nlc = node.tagName.toLowerCase();
165 for(var i=0; i<tags.length; i++){
166 var _tlc = String(tags[i]).toLowerCase();
167 if(_nlc == _tlc){
168 return _tlc; // String
169 }
170 }
171 }
172 return "";
173 },
174
175 getParentOfType: function(/*DomNode*/ node, /*String[]*/ tags){
176 // summary:
177 // Function to locate a parent node that matches one of a set of tags
178 // node:
179 // The node to inspect.
180 // tags:
181 // An array of tag name strings to check to see if the node matches.
182 while(node){
183 if(this.isTag(node, tags).length){
184 return node; // DOMNode
185 }
186 node = node.parentNode;
187 }
188 return null;
189 },
190
191 collapse: function(/*Boolean*/beginning){
192 // summary:
193 // Function to collapse (clear), the current selection
194 // beginning: Boolean
195 // Boolean to indicate whether to collapse the cursor to the beginning of the selection or end.
196 if(window.getSelection){
197 var selection = win.global.getSelection();
198 if(selection.removeAllRanges){ // Mozilla
199 if(beginning){
200 selection.collapseToStart();
201 }else{
202 selection.collapseToEnd();
203 }
204 }else{ // Safari
205 // pulled from WebCore/ecma/kjs_window.cpp, line 2536
206 selection.collapse(beginning);
207 }
208 }else if(has("ie")){ // IE
209 var range = win.doc.selection.createRange();
210 range.collapse(beginning);
211 range.select();
212 }
213 },
214
215 remove: function(){
216 // summary:
217 // Function to delete the currently selected content from the document.
218 var sel = win.doc.selection;
219 if(has("ie") < 9){
220 if(sel.type.toLowerCase() != "none"){
221 sel.clear();
222 }
223 return sel; //Selection
224 }else{
225 sel = win.global.getSelection();
226 sel.deleteFromDocument();
227 return sel; //Selection
228 }
229 },
230
231 selectElementChildren: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
232 // summary:
233 // clear previous selection and select the content of the node
234 // (excluding the node itself)
235 // element: DOMNode
236 // The element you wish to select the children content of.
237 // nochangefocus: Boolean
238 // Boolean to indicate if the foxus should change or not.
239 var global = win.global;
240 var doc = win.doc;
241 var range;
242 element = dom.byId(element);
243 if(doc.selection && has("ie") < 9 && win.body().createTextRange){ // IE
244 range = element.ownerDocument.body.createTextRange();
245 range.moveToElementText(element);
246 if(!nochangefocus){
247 try{
248 range.select(); // IE throws an exception here if the widget is hidden. See #5439
249 }catch(e){ /* squelch */}
250 }
251 }else if(global.getSelection){
252 var selection = win.global.getSelection();
253 if(has("opera")){
254 //Opera's selectAllChildren doesn't seem to work right
255 //against <body> nodes and possibly others ... so
256 //we use the W3C range API
257 if(selection.rangeCount){
258 range = selection.getRangeAt(0);
259 }else{
260 range = doc.createRange();
261 }
262 range.setStart(element, 0);
263 range.setEnd(element,(element.nodeType == 3)?element.length:element.childNodes.length);
264 selection.addRange(range);
265 }else{
266 selection.selectAllChildren(element);
267 }
268 }
269 },
270
271 selectElement: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
272 // summary:
273 // clear previous selection and select element (including all its children)
274 // element: DOMNode
275 // The element to select.
276 // nochangefocus: Boolean
277 // Boolean indicating if the focus should be changed. IE only.
278 var range;
279 var doc = win.doc;
280 var global = win.global;
281 element = dom.byId(element);
282 if(has("ie") < 9 && win.body().createTextRange){
283 try{
284 var tg = element.tagName ? element.tagName.toLowerCase() : "";
285 if(tg === "img" || tg === "table"){
286 range = win.body().createControlRange();
287 }else{
288 range = win.body().createRange();
289 }
290 range.addElement(element);
291 if(!nochangefocus){
292 range.select();
293 }
294 }catch(e){
295 this.selectElementChildren(element,nochangefocus);
296 }
297 }else if(global.getSelection){
298 var selection = global.getSelection();
299 range = doc.createRange();
300 if(selection.removeAllRanges){ // Mozilla
301 // FIXME: does this work on Safari?
302 if(has("opera")){
303 //Opera works if you use the current range on
304 //the selection if present.
305 if(selection.getRangeAt(0)){
306 range = selection.getRangeAt(0);
307 }
308 }
309 range.selectNode(element);
310 selection.removeAllRanges();
311 selection.addRange(range);
312 }
313 }
314 },
315
316 inSelection: function(node){
317 // summary:
318 // This function determines if 'node' is
319 // in the current selection.
320 // tags:
321 // public
322 if(node){
323 var newRange;
324 var doc = win.doc;
325 var range;
326
327 if(win.global.getSelection){
328 //WC3
329 var sel = win.global.getSelection();
330 if(sel && sel.rangeCount > 0){
331 range = sel.getRangeAt(0);
332 }
333 if(range && range.compareBoundaryPoints && doc.createRange){
334 try{
335 newRange = doc.createRange();
336 newRange.setStart(node, 0);
337 if(range.compareBoundaryPoints(range.START_TO_END, newRange) === 1){
338 return true;
339 }
340 }catch(e){ /* squelch */}
341 }
342 }else if(doc.selection){
343 // Probably IE, so we can't use the range object as the pseudo
344 // range doesn't implement the boundry checking, we have to
345 // use IE specific crud.
346 range = doc.selection.createRange();
347 try{
348 newRange = node.ownerDocument.body.createControlRange();
349 if(newRange){
350 newRange.addElement(node);
351 }
352 }catch(e1){
353 try{
354 newRange = node.ownerDocument.body.createTextRange();
355 newRange.moveToElementText(node);
356 }catch(e2){/* squelch */}
357 }
358 if(range && newRange){
359 // We can finally compare similar to W3C
360 if(range.compareEndPoints("EndToStart", newRange) === 1){
361 return true;
362 }
363 }
364 }
365 }
366 return false; // boolean
367 }
368
369 });
370
371 return dijit._editor.selection;
372 });