source: Dev/trunk/src/client/dijit/_editor/selection.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

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