Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Bililite range

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

  • Login to see the comments

  • Be the first to like this

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);};})();

×