dijit
Version:
Dijit provides a complete collection of user interface controls based on Dojo, giving you the power to create web applications that are highly optimized for usability, performance, internationalization, accessibility, but above all deliver an incredible u
380 lines (357 loc) • 10.6 kB
JavaScript
define([
"dojo/dom", // dom.byId
"dojo/_base/lang",
"dojo/sniff", // has("ie") has("opera")
"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
"../main" // for exporting symbols to dijit._editor.selection
], function(dom, lang, has, win, dijit){
// module:
// dijit/_editor/selection
var selection = {
// summary:
// Deprecated text selection API. Will be removed in 2.0. New code should use dijit/selection.
getType: function(){
// summary:
// Get the selection type (like win.doc.select.type in IE).
if(win.doc.getSelection){
// W3C path
var stype = "text";
// Check if the actual selection is a CONTROL (IMG, TABLE, HR, etc...).
var oSel;
try{
oSel = win.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
}else{
// IE6-8
return win.doc.selection.type.toLowerCase();
}
},
getSelectedText: function(){
// summary:
// Return the text (no html tags) included in the current selection or null if no text is selected
if(win.doc.getSelection){
// W3C path
var selection = win.global.getSelection();
return selection ? selection.toString() : ""; //String
}else{
// IE6-8
if(dijit._editor.selection.getType() == 'control'){
return null;
}
return win.doc.selection.createRange().text;
}
},
getSelectedHtml: function(){
// summary:
// Return the html text of the current selection or null if unavailable
if(win.doc.getSelection){
// W3C path
var selection = win.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 = win.doc.createElement("div");
div.appendChild(frag);
html += div.innerHTML;
}
return html; //String
}
return null;
}else{
// IE6-8
if(dijit._editor.selection.getType() == 'control'){
return null;
}
return win.doc.selection.createRange().htmlText;
}
},
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(win.doc.getSelection){
// W3C path
var selection = win.global.getSelection();
return selection.anchorNode.childNodes[ selection.anchorOffset ];
}else{
// IE6-8
var range = win.doc.selection.createRange();
if(range && range.item){
return win.doc.selection.createRange().item(0);
}
}
}
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(win.doc.getSelection){
var selection = win.global.getSelection();
if(selection){
var node = selection.anchorNode;
while(node && (node.nodeType != 1)){ // not an element
node = node.parentNode;
}
return node;
}
}else{
var r = win.doc.selection.createRange();
r.collapse(true);
return r.parentElement();
}
}
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
// Indicates whether to collapse the cursor to the beginning of the selection or end.
if(win.doc.getSelection){
// W3C path
var selection = win.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{
// IE6-8
var range = win.doc.selection.createRange();
range.collapse(beginning);
range.select();
}
},
remove: function(){
// summary:
// Function to delete the currently selected content from the document.
var sel = win.doc.selection;
if(win.doc.getSelection){
// W3C path
sel = win.global.getSelection();
sel.deleteFromDocument();
return sel; //Selection
}else{
// IE6-8
if(sel.type.toLowerCase() != "none"){
sel.clear();
}
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
// Indicates if the focus should change or not.
var doc = win.doc;
var range;
element = dom.byId(element);
if(win.doc.getSelection){
// W3C
var selection = win.global.getSelection();
if(has("opera")){
//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);
}
}else{
// IE6-8
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 */}
}
}
},
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;
element = dom.byId(element); // TODO: remove for 2.0 or sooner, spec listed above doesn't allow for string
var doc = element.ownerDocument;
var global = win.global; // TODO: use winUtils.get(doc)?
if(doc.getSelection){
// W3C path
var selection = global.getSelection();
range = doc.createRange();
if(selection.removeAllRanges){ // Mozilla
// FIXME: does this work on Safari?
if(has("opera")){
//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);
}
}else{
// IE6-8
try{
var tg = element.tagName ? element.tagName.toLowerCase() : "";
if(tg === "img" || tg === "table"){
range = win.body(doc).createControlRange();
}else{
range = win.body(doc).createRange();
}
range.addElement(element);
if(!nochangefocus){
range.select();
}
}catch(e){
this.selectElementChildren(element, nochangefocus);
}
}
},
inSelection: function(node){
// summary:
// This function determines if 'node' is
// in the current selection.
// tags:
// public
if(node){
var newRange;
var doc = win.doc;
var range;
if(win.doc.getSelection){
// WC3
var sel = win.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{
// IE6-8, so we can't use the range object as the pseudo
// range doesn't implement the boundary 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
}
};
lang.setObject("dijit._editor.selection", selection);
return selection;
});