summaryrefslogtreecommitdiff
path: root/lib/dijit/_editor/selection.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/_editor/selection.js')
-rw-r--r--lib/dijit/_editor/selection.js620
1 files changed, 361 insertions, 259 deletions
diff --git a/lib/dijit/_editor/selection.js b/lib/dijit/_editor/selection.js
index 3c99c0610..6fed82770 100644
--- a/lib/dijit/_editor/selection.js
+++ b/lib/dijit/_editor/selection.js
@@ -1,267 +1,369 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._editor.selection"]){
-dojo._hasResource["dijit._editor.selection"]=true;
+if(!dojo._hasResource["dijit._editor.selection"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._editor.selection"] = true;
dojo.provide("dijit._editor.selection");
-dojo.mixin(dijit._editor.selection,{getType:function(){
-if(dojo.isIE){
-return dojo.doc.selection.type.toLowerCase();
-}else{
-var _1="text";
-var _2;
-try{
-_2=dojo.global.getSelection();
-}
-catch(e){
-}
-if(_2&&_2.rangeCount==1){
-var _3=_2.getRangeAt(0);
-if((_3.startContainer==_3.endContainer)&&((_3.endOffset-_3.startOffset)==1)&&(_3.startContainer.nodeType!=3)){
-_1="control";
-}
-}
-return _1;
-}
-},getSelectedText:function(){
-if(dojo.isIE){
-if(dijit._editor.selection.getType()=="control"){
-return null;
-}
-return dojo.doc.selection.createRange().text;
-}else{
-var _4=dojo.global.getSelection();
-if(_4){
-return _4.toString();
-}
-}
-return "";
-},getSelectedHtml:function(){
-if(dojo.isIE){
-if(dijit._editor.selection.getType()=="control"){
-return null;
-}
-return dojo.doc.selection.createRange().htmlText;
-}else{
-var _5=dojo.global.getSelection();
-if(_5&&_5.rangeCount){
-var i;
-var _6="";
-for(i=0;i<_5.rangeCount;i++){
-var _7=_5.getRangeAt(i).cloneContents();
-var _8=dojo.doc.createElement("div");
-_8.appendChild(_7);
-_6+=_8.innerHTML;
-}
-return _6;
-}
-return null;
-}
-},getSelectedElement:function(){
-if(dijit._editor.selection.getType()=="control"){
-if(dojo.isIE){
-var _9=dojo.doc.selection.createRange();
-if(_9&&_9.item){
-return dojo.doc.selection.createRange().item(0);
-}
-}else{
-var _a=dojo.global.getSelection();
-return _a.anchorNode.childNodes[_a.anchorOffset];
-}
-}
-return null;
-},getParentElement:function(){
-if(dijit._editor.selection.getType()=="control"){
-var p=this.getSelectedElement();
-if(p){
-return p.parentNode;
-}
-}else{
-if(dojo.isIE){
-var r=dojo.doc.selection.createRange();
-r.collapse(true);
-return r.parentElement();
-}else{
-var _b=dojo.global.getSelection();
-if(_b){
-var _c=_b.anchorNode;
-while(_c&&(_c.nodeType!=1)){
-_c=_c.parentNode;
-}
-return _c;
-}
-}
-}
-return null;
-},hasAncestorElement:function(_d){
-return this.getAncestorElement.apply(this,arguments)!=null;
-},getAncestorElement:function(_e){
-var _f=this.getSelectedElement()||this.getParentElement();
-return this.getParentOfType(_f,arguments);
-},isTag:function(_10,_11){
-if(_10&&_10.tagName){
-var _12=_10.tagName.toLowerCase();
-for(var i=0;i<_11.length;i++){
-var _13=String(_11[i]).toLowerCase();
-if(_12==_13){
-return _13;
-}
-}
-}
-return "";
-},getParentOfType:function(_14,_15){
-while(_14){
-if(this.isTag(_14,_15).length){
-return _14;
-}
-_14=_14.parentNode;
-}
-return null;
-},collapse:function(_16){
-if(window.getSelection){
-var _17=dojo.global.getSelection();
-if(_17.removeAllRanges){
-if(_16){
-_17.collapseToStart();
-}else{
-_17.collapseToEnd();
-}
-}else{
-_17.collapse(_16);
-}
-}else{
-if(dojo.isIE){
-var _18=dojo.doc.selection.createRange();
-_18.collapse(_16);
-_18.select();
-}
-}
-},remove:function(){
-var sel=dojo.doc.selection;
-if(dojo.isIE){
-if(sel.type.toLowerCase()!="none"){
-sel.clear();
-}
-return sel;
-}else{
-sel=dojo.global.getSelection();
-sel.deleteFromDocument();
-return sel;
-}
-},selectElementChildren:function(_19,_1a){
-var win=dojo.global;
-var doc=dojo.doc;
-var _1b;
-_19=dojo.byId(_19);
-if(doc.selection&&dojo.isIE&&dojo.body().createTextRange){
-_1b=_19.ownerDocument.body.createTextRange();
-_1b.moveToElementText(_19);
-if(!_1a){
-try{
-_1b.select();
-}
-catch(e){
-}
-}
-}else{
-if(win.getSelection){
-var _1c=dojo.global.getSelection();
-if(dojo.isOpera){
-if(_1c.rangeCount){
-_1b=_1c.getRangeAt(0);
-}else{
-_1b=doc.createRange();
-}
-_1b.setStart(_19,0);
-_1b.setEnd(_19,(_19.nodeType==3)?_19.length:_19.childNodes.length);
-_1c.addRange(_1b);
-}else{
-_1c.selectAllChildren(_19);
-}
-}
-}
-},selectElement:function(_1d,_1e){
-var _1f;
-var doc=dojo.doc;
-var win=dojo.global;
-_1d=dojo.byId(_1d);
-if(dojo.isIE&&dojo.body().createTextRange){
-try{
-_1f=dojo.body().createControlRange();
-_1f.addElement(_1d);
-if(!_1e){
-_1f.select();
-}
-}
-catch(e){
-this.selectElementChildren(_1d,_1e);
-}
-}else{
-if(dojo.global.getSelection){
-var _20=win.getSelection();
-_1f=doc.createRange();
-if(_20.removeAllRanges){
-if(dojo.isOpera){
-if(_20.getRangeAt(0)){
-_1f=_20.getRangeAt(0);
-}
-}
-_1f.selectNode(_1d);
-_20.removeAllRanges();
-_20.addRange(_1f);
-}
-}
-}
-},inSelection:function(_21){
-if(_21){
-var _22;
-var doc=dojo.doc;
-var _23;
-if(dojo.global.getSelection){
-var sel=dojo.global.getSelection();
-if(sel&&sel.rangeCount>0){
-_23=sel.getRangeAt(0);
-}
-if(_23&&_23.compareBoundaryPoints&&doc.createRange){
-try{
-_22=doc.createRange();
-_22.setStart(_21,0);
-if(_23.compareBoundaryPoints(_23.START_TO_END,_22)===1){
-return true;
-}
-}
-catch(e){
-}
-}
-}else{
-if(doc.selection){
-_23=doc.selection.createRange();
-try{
-_22=_21.ownerDocument.body.createControlRange();
-if(_22){
-_22.addElement(_21);
-}
-}
-catch(e1){
-try{
-_22=_21.ownerDocument.body.createTextRange();
-_22.moveToElementText(_21);
-}
-catch(e2){
-}
-}
-if(_23&&_22){
-if(_23.compareEndPoints("EndToStart",_22)===1){
-return true;
-}
-}
-}
-}
-}
-return false;
-}});
+
+
+dojo.getObject("_editor.selection", true, dijit);
+
+// FIXME:
+// all of these methods branch internally for IE. This is probably
+// sub-optimal in terms of runtime performance. We should investigate the
+// size difference for differentiating at definition time.
+
+dojo.mixin(dijit._editor.selection, {
+ getType: function(){
+ // summary:
+ // Get the selection type (like dojo.doc.select.type in IE).
+ if(dojo.isIE < 9){
+ return dojo.doc.selection.type.toLowerCase();
+ }else{
+ var stype = "text";
+
+ // Check if the actual selection is a CONTROL (IMG, TABLE, HR, etc...).
+ var oSel;
+ try{
+ oSel = dojo.global.getSelection();
+ }catch(e){ /*squelch*/ }
+
+ if(oSel && oSel.rangeCount == 1){
+ var oRange = oSel.getRangeAt(0);
+ if( (oRange.startContainer == oRange.endContainer) &&
+ ((oRange.endOffset - oRange.startOffset) == 1) &&
+ (oRange.startContainer.nodeType != 3 /* text node*/)
+ ){
+ stype = "control";
+ }
+ }
+ return stype; //String
+ }
+ },
+
+ getSelectedText: function(){
+ // summary:
+ // Return the text (no html tags) included in the current selection or null if no text is selected
+ if(dojo.isIE < 9){
+ if(dijit._editor.selection.getType() == 'control'){
+ return null;
+ }
+ return dojo.doc.selection.createRange().text;
+ }else{
+ var selection = dojo.global.getSelection();
+ if(selection){
+ return selection.toString(); //String
+ }
+ }
+ return '';
+ },
+
+ getSelectedHtml: function(){
+ // summary:
+ // Return the html text of the current selection or null if unavailable
+ if(dojo.isIE < 9){
+ if(dijit._editor.selection.getType() == 'control'){
+ return null;
+ }
+ return dojo.doc.selection.createRange().htmlText;
+ }else{
+ var selection = dojo.global.getSelection();
+ if(selection && selection.rangeCount){
+ var i;
+ var html = "";
+ for(i = 0; i < selection.rangeCount; i++){
+ //Handle selections spanning ranges, such as Opera
+ var frag = selection.getRangeAt(i).cloneContents();
+ var div = dojo.doc.createElement("div");
+ div.appendChild(frag);
+ html += div.innerHTML;
+ }
+ return html; //String
+ }
+ return null;
+ }
+ },
+
+ getSelectedElement: function(){
+ // summary:
+ // Retrieves the selected element (if any), just in the case that
+ // a single element (object like and image or a table) is
+ // selected.
+ if(dijit._editor.selection.getType() == "control"){
+ if(dojo.isIE < 9){
+ var range = dojo.doc.selection.createRange();
+ if(range && range.item){
+ return dojo.doc.selection.createRange().item(0);
+ }
+ }else{
+ var selection = dojo.global.getSelection();
+ return selection.anchorNode.childNodes[ selection.anchorOffset ];
+ }
+ }
+ return null;
+ },
+
+ getParentElement: function(){
+ // summary:
+ // Get the parent element of the current selection
+ if(dijit._editor.selection.getType() == "control"){
+ var p = this.getSelectedElement();
+ if(p){ return p.parentNode; }
+ }else{
+ if(dojo.isIE < 9){
+ var r = dojo.doc.selection.createRange();
+ r.collapse(true);
+ return r.parentElement();
+ }else{
+ var selection = dojo.global.getSelection();
+ if(selection){
+ var node = selection.anchorNode;
+ while(node && (node.nodeType != 1)){ // not an element
+ node = node.parentNode;
+ }
+ return node;
+ }
+ }
+ }
+ return null;
+ },
+
+ hasAncestorElement: function(/*String*/tagName /* ... */){
+ // summary:
+ // Check whether current selection has a parent element which is
+ // of type tagName (or one of the other specified tagName)
+ // tagName: String
+ // The tag name to determine if it has an ancestor of.
+ return this.getAncestorElement.apply(this, arguments) != null; //Boolean
+ },
+
+ getAncestorElement: function(/*String*/tagName /* ... */){
+ // summary:
+ // Return the parent element of the current selection which is of
+ // type tagName (or one of the other specified tagName)
+ // tagName: String
+ // The tag name to determine if it has an ancestor of.
+ var node = this.getSelectedElement() || this.getParentElement();
+ return this.getParentOfType(node, arguments); //DOMNode
+ },
+
+ isTag: function(/*DomNode*/ node, /*String[]*/ tags){
+ // summary:
+ // Function to determine if a node is one of an array of tags.
+ // node:
+ // The node to inspect.
+ // tags:
+ // An array of tag name strings to check to see if the node matches.
+ if(node && node.tagName){
+ var _nlc = node.tagName.toLowerCase();
+ for(var i=0; i<tags.length; i++){
+ var _tlc = String(tags[i]).toLowerCase();
+ if(_nlc == _tlc){
+ return _tlc; // String
+ }
+ }
+ }
+ return "";
+ },
+
+ getParentOfType: function(/*DomNode*/ node, /*String[]*/ tags){
+ // summary:
+ // Function to locate a parent node that matches one of a set of tags
+ // node:
+ // The node to inspect.
+ // tags:
+ // An array of tag name strings to check to see if the node matches.
+ while(node){
+ if(this.isTag(node, tags).length){
+ return node; // DOMNode
+ }
+ node = node.parentNode;
+ }
+ return null;
+ },
+
+ collapse: function(/*Boolean*/beginning){
+ // summary:
+ // Function to collapse (clear), the current selection
+ // beginning: Boolean
+ // Boolean to indicate whether to collapse the cursor to the beginning of the selection or end.
+ if(window.getSelection){
+ var selection = dojo.global.getSelection();
+ if(selection.removeAllRanges){ // Mozilla
+ if(beginning){
+ selection.collapseToStart();
+ }else{
+ selection.collapseToEnd();
+ }
+ }else{ // Safari
+ // pulled from WebCore/ecma/kjs_window.cpp, line 2536
+ selection.collapse(beginning);
+ }
+ }else if(dojo.isIE){ // IE
+ var range = dojo.doc.selection.createRange();
+ range.collapse(beginning);
+ range.select();
+ }
+ },
+
+ remove: function(){
+ // summary:
+ // Function to delete the currently selected content from the document.
+ var sel = dojo.doc.selection;
+ if(dojo.isIE < 9){
+ if(sel.type.toLowerCase() != "none"){
+ sel.clear();
+ }
+ return sel; //Selection
+ }else{
+ sel = dojo.global.getSelection();
+ sel.deleteFromDocument();
+ return sel; //Selection
+ }
+ },
+
+ selectElementChildren: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
+ // summary:
+ // clear previous selection and select the content of the node
+ // (excluding the node itself)
+ // element: DOMNode
+ // The element you wish to select the children content of.
+ // nochangefocus: Boolean
+ // Boolean to indicate if the foxus should change or not.
+ var win = dojo.global;
+ var doc = dojo.doc;
+ var range;
+ element = dojo.byId(element);
+ if(doc.selection && dojo.isIE < 9 && dojo.body().createTextRange){ // IE
+ range = element.ownerDocument.body.createTextRange();
+ range.moveToElementText(element);
+ if(!nochangefocus){
+ try{
+ range.select(); // IE throws an exception here if the widget is hidden. See #5439
+ }catch(e){ /* squelch */}
+ }
+ }else if(win.getSelection){
+ var selection = dojo.global.getSelection();
+ if(dojo.isOpera){
+ //Opera's selectAllChildren doesn't seem to work right
+ //against <body> nodes and possibly others ... so
+ //we use the W3C range API
+ if(selection.rangeCount){
+ range = selection.getRangeAt(0);
+ }else{
+ range = doc.createRange();
+ }
+ range.setStart(element, 0);
+ range.setEnd(element,(element.nodeType == 3)?element.length:element.childNodes.length);
+ selection.addRange(range);
+ }else{
+ selection.selectAllChildren(element);
+ }
+ }
+ },
+
+ selectElement: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
+ // summary:
+ // clear previous selection and select element (including all its children)
+ // element: DOMNode
+ // The element to select.
+ // nochangefocus: Boolean
+ // Boolean indicating if the focus should be changed. IE only.
+ var range;
+ var doc = dojo.doc;
+ var win = dojo.global;
+ element = dojo.byId(element);
+ if(dojo.isIE < 9 && dojo.body().createTextRange){
+ try{
+ var tg = element.tagName ? element.tagName.toLowerCase() : "";
+ if(tg === "img" || tg === "table"){
+ range = dojo.body().createControlRange();
+ }else{
+ range = dojo.body().createRange();
+ }
+ range.addElement(element);
+ if(!nochangefocus){
+ range.select();
+ }
+ }catch(e){
+ this.selectElementChildren(element,nochangefocus);
+ }
+ }else if(dojo.global.getSelection){
+ var selection = win.getSelection();
+ range = doc.createRange();
+ if(selection.removeAllRanges){ // Mozilla
+ // FIXME: does this work on Safari?
+ if(dojo.isOpera){
+ //Opera works if you use the current range on
+ //the selection if present.
+ if(selection.getRangeAt(0)){
+ range = selection.getRangeAt(0);
+ }
+ }
+ range.selectNode(element);
+ selection.removeAllRanges();
+ selection.addRange(range);
+ }
+ }
+ },
+
+ inSelection: function(node){
+ // summary:
+ // This function determines if 'node' is
+ // in the current selection.
+ // tags:
+ // public
+ if(node){
+ var newRange;
+ var doc = dojo.doc;
+ var range;
+
+ if(dojo.global.getSelection){
+ //WC3
+ var sel = dojo.global.getSelection();
+ if(sel && sel.rangeCount > 0){
+ range = sel.getRangeAt(0);
+ }
+ if(range && range.compareBoundaryPoints && doc.createRange){
+ try{
+ newRange = doc.createRange();
+ newRange.setStart(node, 0);
+ if(range.compareBoundaryPoints(range.START_TO_END, newRange) === 1){
+ return true;
+ }
+ }catch(e){ /* squelch */}
+ }
+ }else if(doc.selection){
+ // Probably IE, so we can't use the range object as the pseudo
+ // range doesn't implement the boundry checking, we have to
+ // use IE specific crud.
+ range = doc.selection.createRange();
+ try{
+ newRange = node.ownerDocument.body.createControlRange();
+ if(newRange){
+ newRange.addElement(node);
+ }
+ }catch(e1){
+ try{
+ newRange = node.ownerDocument.body.createTextRange();
+ newRange.moveToElementText(node);
+ }catch(e2){/* squelch */}
+ }
+ if(range && newRange){
+ // We can finally compare similar to W3C
+ if(range.compareEndPoints("EndToStart", newRange) === 1){
+ return true;
+ }
+ }
+ }
+ }
+ return false; // boolean
+ }
+
+});
+
}