// Cross-broswer implementation of text ranges and selections// documentation: http://bililite.com/blog/2011/01/17/cross-b...
length: function() {return this._el[this._textProp].replace(/r/g, ).length; // needto correct for IEs CrLf weirdness},boun...
if (this._el.tagName == INPUT){// IE 8 is very inconsistent; textareas have createTextRange but itdoesnt workrng = this._e...
var len = constraint.text.replace(/r/g, ).length; // correct for IEsCrLf wierdnessif (rng.compareEndPoints (StartToStart, ...
// returns [start, end] for the selection constrained to be inelementvar rng = this._nativeRange(); // range of the elemen...
rng[bStart ? setStartAfter :setEndAfter](next);}if (next && next.nodeType == 1 && next.nodeName =="BR") rng[bStart ? setSt...
return this._el[this._textProp].substring(rng[0], rng[1]);};NothingRange.prototype._nativeSetText = function (text, rng){v...
Upcoming SlideShare
Loading in...5
×

Bililite range

125

Published on

1. // Cross-broswer implementation of text ranges and selections// documentation: http://bililite.com/blog/2011/01/17/cross-browser-text-ranges-and-selections/// Version: 1.1// Copyright (c) 2010 Daniel Wachsstock// MIT license:// Permission is hereby granted, free of charge, to any person// obtaining a copy of this software and associated documentation// files (th

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
125
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
1
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "Bililite range"

  1. 1. // Cross-broswer implementation of text ranges and selections// documentation: http://bililite.com/blog/2011/01/17/cross-browser-text-ranges-and-selections/// Version: 1.1// Copyright (c) 2010 Daniel Wachsstock// MIT license:// Permission is hereby granted, free of charge, to any person// obtaining a copy of this software and associated documentation// files (the "Software"), to deal in the Software without// restriction, including without limitation the rights to use,// copy, modify, merge, publish, distribute, sublicense, and/or sell// copies of the Software, and to permit persons to whom the// Software is furnished to do so, subject to the following// conditions:// The above copyright notice and this permission notice shall be// included in all copies or substantial portions of the Software.// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR// OTHER DEALINGS IN THE SOFTWARE.(function(){bililiteRange = function(el, debug){var ret;if (debug){ret = new NothingRange(); // Easier to force it to use the no-selection type than to try to find an old browser}else if (document.selection){// Internet Explorerret = new IERange();}else if (window.getSelection && el.setSelectionRange){// Standards. Element is an input or textarearet = new InputRange();}else if (window.getSelection){// Standards, with any other kind of elementret = new W3CRange();}else{// doesnt support selectionret = new NothingRange();}ret._el = el;ret._textProp = textProp(el);ret._bounds = [0, ret.length()];return ret;};function textProp(el){// returns the property that contains the text of the elementif (typeof el.value != undefined) return value;if (typeof el.text != undefined) return text;if (typeof el.textContent != undefined) return textContent;return innerText;}// base classfunction Range(){}Range.prototype = {
  2. 2. length: function() {return this._el[this._textProp].replace(/r/g, ).length; // needto correct for IEs CrLf weirdness},bounds: function(s){if (s === all){this._bounds = [0, this.length()];}else if (s === start){this._bounds = [0, 0];}else if (s === end){this._bounds = [this.length(), this.length()];}else if (s === selection){this.bounds (all); // first select the whole thing forconstrainingthis._bounds = this._nativeSelection();}else if (s){this._bounds = s; // dont error check now; the element maychange at any moment, so constrain it when we need it.}else{var b = [Math.max(0, Math.min (this.length(), this._bounds[0])),Math.max(0, Math.min (this.length(), this._bounds[1]))];return b; // need to constrain it to fit}return this; // allow for chaining},select: function(){this._nativeSelect(this._nativeRange(this.bounds()));return this; // allow for chaining},text: function(text, select){if (arguments.length){this._nativeSetText(text, this._nativeRange(this.bounds()));if (select == start){this.bounds ([this._bounds[0], this._bounds[0]]);this.select();}else if (select == end){this.bounds ([this._bounds[0]+text.length,this._bounds[0]+text.length]);this.select();}else if (select == all){this.bounds ([this._bounds[0],this._bounds[0]+text.length]);this.select();}return this; // allow for chaining}else{return this._nativeGetText(this._nativeRange(this.bounds()));}},insertEOL: function (){this._nativeEOL();this._bounds = [this._bounds[0]+1, this._bounds[0]+1]; // move pastthe EOL markerreturn this;}};function IERange(){}IERange.prototype = new Range();IERange.prototype._nativeRange = function (bounds){var rng;
  3. 3. if (this._el.tagName == INPUT){// IE 8 is very inconsistent; textareas have createTextRange but itdoesnt workrng = this._el.createTextRange();}else{rng = document.body.createTextRange ();rng.moveToElementText(this._el);}if (bounds){if (bounds[1] < 0) bounds[1] = 0; // IE tends to run elements out ofboundsif (bounds[0] > this.length()) bounds[0] = this.length();if (bounds[1] < rng.text.replace(/r/g, ).length){ // correct forIEs CrLf wierdness// block-display elements have an invisible, uncounted end ofelement marker, so we move an extra one and use the current length of the rangerng.moveEnd (character, -1);rng.moveEnd (character, bounds[1]-rng.text.replace(/r/g,).length);}if (bounds[0] > 0) rng.moveStart(character, bounds[0]);}return rng;};IERange.prototype._nativeSelect = function (rng){rng.select();};IERange.prototype._nativeSelection = function (){// returns [start, end] for the selection constrained to be in elementvar rng = this._nativeRange(); // range of the element to constrain tovar len = this.length();if (document.selection.type != Text) return [len, len]; // append to theendvar sel = document.selection.createRange();try{return [iestart(sel, rng),ieend (sel, rng)];}catch (e){// IE gets upset sometimes about comparing text to input elements,but the selections cannot overlap, so make a best guessreturn (sel.parentElement().sourceIndex < this._el.sourceIndex) ?[0,0] : [len, len];}};IERange.prototype._nativeGetText = function (rng){return rng.text.replace(/r/g, ); // correct for IEs CrLf weirdness};IERange.prototype._nativeSetText = function (text, rng){rng.text = text;};IERange.prototype._nativeEOL = function(){if (typeof this._el.value != undefined){this.text(n); // for input and textarea, insert it straight}else{this._nativeRange(this.bounds()).pasteHTML(<br/>);}};// IE internalsfunction iestart(rng, constraint){// returns the position (in character) of the start of rng withinconstraint. If its not in constraint, returns 0 if its before, length if itsafter
  4. 4. var len = constraint.text.replace(/r/g, ).length; // correct for IEsCrLf wierdnessif (rng.compareEndPoints (StartToStart, constraint) <= 0) return 0; //at or before the beginningif (rng.compareEndPoints (StartToEnd, constraint) >= 0) return len;for (var i = 0; rng.compareEndPoints (StartToStart, constraint) > 0; ++i, rng.moveStart(character, -1));return i;}function ieend (rng, constraint){// returns the position (in character) of the end of rng withinconstraint. If its not in constraint, returns 0 if its before, length if itsaftervar len = constraint.text.replace(/r/g, ).length; // correct for IEsCrLf wierdnessif (rng.compareEndPoints (EndToEnd, constraint) >= 0) return len; // ator after the endif (rng.compareEndPoints (EndToStart, constraint) <= 0) return 0;for (var i = 0; rng.compareEndPoints (EndToStart, constraint) > 0; ++i,rng.moveEnd(character, -1));return i;}// an input element in a standards document. "Native Range" is just the boundsarrayfunction InputRange(){}InputRange.prototype = new Range();InputRange.prototype._nativeRange = function(bounds) {return bounds || [0, this.length()];};InputRange.prototype._nativeSelect = function (rng){this._el.setSelectionRange(rng[0], rng[1]);};InputRange.prototype._nativeSelection = function(){return [this._el.selectionStart, this._el.selectionEnd];};InputRange.prototype._nativeGetText = function(rng){return this._el.value.substring(rng[0], rng[1]);};InputRange.prototype._nativeSetText = function(text, rng){var val = this._el.value;this._el.value = val.substring(0, rng[0]) + text + val.substring(rng[1]);};InputRange.prototype._nativeEOL = function(){this.text(n);};function W3CRange(){}W3CRange.prototype = new Range();W3CRange.prototype._nativeRange = function (bounds){var rng = document.createRange();rng.selectNodeContents(this._el);if (bounds){w3cmoveBoundary (rng, bounds[0], true, this._el);rng.collapse (true);w3cmoveBoundary (rng, bounds[1]-bounds[0], false, this._el);}return rng;};W3CRange.prototype._nativeSelect = function (rng){window.getSelection().removeAllRanges();window.getSelection().addRange (rng);};W3CRange.prototype._nativeSelection = function (){
  5. 5. // returns [start, end] for the selection constrained to be inelementvar rng = this._nativeRange(); // range of the element to constraintoif (window.getSelection().rangeCount == 0) return [this.length(),this.length()]; // append to the endvar sel = window.getSelection().getRangeAt(0);return [w3cstart(sel, rng),w3cend (sel, rng)];};W3CRange.prototype._nativeGetText = function (rng){return rng.toString();};W3CRange.prototype._nativeSetText = function (text, rng){rng.deleteContents();rng.insertNode (document.createTextNode(text));this._el.normalize(); // merge the text with the surrounding text};W3CRange.prototype._nativeEOL = function(){var rng = this._nativeRange(this.bounds());rng.deleteContents();var br = document.createElement(br);br.setAttribute (_moz_dirty, ); // for Firefoxrng.insertNode (br);rng.insertNode (document.createTextNode(n));rng.collapse (false);};// W3C internalsfunction nextnode (node, root){// in-order traversal// weve already visited node, so get kids then siblingsif (node.firstChild) return node.firstChild;if (node.nextSibling) return node.nextSibling;if (node===root) return null;while (node.parentNode){// get unclesnode = node.parentNode;if (node == root) return null;if (node.nextSibling) return node.nextSibling;}return null;}function w3cmoveBoundary (rng, n, bStart, el){// move the boundary (bStart == true ? start : end) n characters forward,up to the end of element el. Forward only!// if the start is moved after the end, then an exception is raisedif (n <= 0) return;var node = rng[bStart ? startContainer : endContainer];if (node.nodeType == 3){// we may be starting somewhere into the textn += rng[bStart ? startOffset : endOffset];}while (node){if (node.nodeType == 3){if (n <= node.nodeValue.length){rng[bStart ? setStart : setEnd](node, n);// special case: if we end next to a <br>, include thatnode.if (n == node.nodeValue.length){// skip past zero-length text nodesfor (var next = nextnode (node, el); next &&next.nodeType==3 && next.nodeValue.length == 0; next = nextnode(next, el)){
  6. 6. rng[bStart ? setStartAfter :setEndAfter](next);}if (next && next.nodeType == 1 && next.nodeName =="BR") rng[bStart ? setStartAfter : setEndAfter](next);}return;}else{rng[bStart ? setStartAfter : setEndAfter](node); //skip past this onen -= node.nodeValue.length; // and eat these characters}}node = nextnode (node, el);}}var START_TO_START = 0; // from the w3c definitionsvar START_TO_END = 1;var END_TO_END = 2;var END_TO_START = 3;// from the Mozilla documentation, for range.compareBoundaryPoints(how,sourceRange)// -1, 0, or 1, indicating whether the corresponding boundary-point of range isrespectively before, equal to, or after the corresponding boundary-point ofsourceRange.// * Range.END_TO_END compares the end boundary-point of sourceRange to theend boundary-point of range.// * Range.END_TO_START compares the end boundary-point of sourceRange tothe start boundary-point of range.// * Range.START_TO_END compares the start boundary-point of sourceRange tothe end boundary-point of range.// * Range.START_TO_START compares the start boundary-point of sourceRangeto the start boundary-point of range.function w3cstart(rng, constraint){if (rng.compareBoundaryPoints (START_TO_START, constraint) <= 0) return 0;// at or before the beginningif (rng.compareBoundaryPoints (END_TO_START, constraint) >= 0) returnconstraint.toString().length;rng = rng.cloneRange(); // dont change the originalrng.setEnd (constraint.endContainer, constraint.endOffset); // they nowend at the same placereturn constraint.toString().length - rng.toString().length;}function w3cend (rng, constraint){if (rng.compareBoundaryPoints (END_TO_END, constraint) >= 0) returnconstraint.toString().length; // at or after the endif (rng.compareBoundaryPoints (START_TO_END, constraint) <= 0) return 0;rng = rng.cloneRange(); // dont change the originalrng.setStart (constraint.startContainer, constraint.startOffset); // theynow start at the same placereturn rng.toString().length;}function NothingRange(){}NothingRange.prototype = new Range();NothingRange.prototype._nativeRange = function(bounds) {return bounds || [0,this.length()];};NothingRange.prototype._nativeSelect = function (rng){ // do nothing};NothingRange.prototype._nativeSelection = function(){return [0,0];};NothingRange.prototype._nativeGetText = function (rng){
  7. 7. return this._el[this._textProp].substring(rng[0], rng[1]);};NothingRange.prototype._nativeSetText = function (text, rng){var val = this._el[this._textProp];this._el[this._textProp] = val.substring(0, rng[0]) + text +val.substring(rng[1]);};NothingRange.prototype._nativeEOL = function(){this.text(n);};})();

×