text-angular-rails 1.4.2 → 1.5.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -5
- data/lib/text-angular-rails/version.rb +1 -1
- data/vendor/assets/javascripts/textAngular-rangy.min.js +478 -0
- data/vendor/assets/javascripts/textAngular-sanitize.min.js +322 -0
- data/vendor/assets/javascripts/textAngular.min.js +1481 -0
- data/vendor/assets/stylesheets/textAngular.css +193 -0
- metadata +7 -8
- data/vendor/assets/javascripts/text-angular-rangy.js +0 -2
- data/vendor/assets/javascripts/text-angular-sanitize.js +0 -6
- data/vendor/assets/javascripts/text-angular.js +0 -18
- data/vendor/assets/stylesheets/text-angular.css +0 -202
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f571da8fd5b12fb8423c5e8c86627150ae9ce78f
|
4
|
+
data.tar.gz: b8986a9211a2a1a6097fad4bd6d567706eb1eaf3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b99dba6b087c1bb9c3c45f4d21d5fccec389868c6047ccbe78c9a345ae2d1e3cad95f8b749622f371e168745b7cb8cfb1c994edbcb0aa38c718e0b6b3c790423
|
7
|
+
data.tar.gz: 51c644c55913ae1524de51b99bb4273237de0f8d5e8cce7f259963a3388acd9582e965ea55daece276d016f6d9f6ef4d284d932407c356543a0c543ca1c1a22f
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
# text-angular-rails v 1.
|
1
|
+
# text-angular-rails v 1.5.16
|
2
2
|
|
3
3
|
## Presentation
|
4
4
|
|
5
|
-
Rails package for textAngular https://github.com/
|
5
|
+
Rails package for textAngular https://github.com/textAngular/textAngular
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -25,15 +25,15 @@ Or install it yourself as:
|
|
25
25
|
In your application.js manifest:
|
26
26
|
|
27
27
|
//= require text-angular
|
28
|
-
|
29
|
-
|
28
|
+
//= require text-angular-sanitize
|
29
|
+
//= require text-angular-rangy
|
30
30
|
|
31
31
|
In your application.css manifest:
|
32
32
|
|
33
33
|
//=require text-angular
|
34
34
|
|
35
35
|
## Requirements
|
36
|
-
|
36
|
+
|
37
37
|
See basic textAngular requirements here https://github.com/fraywing/textAngular
|
38
38
|
|
39
39
|
## Contributing
|
@@ -0,0 +1,478 @@
|
|
1
|
+
/**
|
2
|
+
* Rangy, a cross-browser JavaScript range and selection library
|
3
|
+
* https://github.com/timdown/rangy
|
4
|
+
*
|
5
|
+
* Copyright 2015, Tim Down
|
6
|
+
* Licensed under the MIT license.
|
7
|
+
* Version: 1.3.0
|
8
|
+
* Build date: 10 May 2015
|
9
|
+
*/
|
10
|
+
!function(a,b){"function"==typeof define&&define.amd?
|
11
|
+
// AMD. Register as an anonymous module.
|
12
|
+
define(a):"undefined"!=typeof module&&"object"==typeof exports?
|
13
|
+
// Node/CommonJS style
|
14
|
+
module.exports=a():
|
15
|
+
// No AMD or CommonJS support so we place Rangy in (probably) the global variable
|
16
|
+
b.rangy=a()}(function(){/*----------------------------------------------------------------------------------------------------------------*/
|
17
|
+
// Trio of functions taken from Peter Michaux's article:
|
18
|
+
// http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting
|
19
|
+
function a(a,b){var c=typeof a[b];return c==u||!(c!=t||!a[b])||"unknown"==c}function b(a,b){return!(typeof a[b]!=t||!a[b])}function c(a,b){return typeof a[b]!=v}
|
20
|
+
// Creates a convenience function to save verbose repeated calls to tests functions
|
21
|
+
function d(a){return function(b,c){for(var d=c.length;d--;)if(!a(b,c[d]))return!1;return!0}}function e(a){return a&&A(a,z)&&C(a,y)}function f(a){return b(a,"body")?a.body:a.getElementsByTagName("body")[0]}function g(b){typeof console!=v&&a(console,"log")&&console.log(b)}function h(a,b){F&&b?alert(a):g(a)}function i(a){H.initialized=!0,H.supported=!1,h("Rangy is not supported in this environment. Reason: "+a,H.config.alertOnFail)}function j(a){h("Rangy warning: "+a,H.config.alertOnWarn)}function k(a){return a.message||a.description||String(a)}
|
22
|
+
// Initialization
|
23
|
+
function l(){if(F&&!H.initialized){var b,c=!1,d=!1;
|
24
|
+
// First, perform basic feature tests
|
25
|
+
a(document,"createRange")&&(b=document.createRange(),A(b,x)&&C(b,w)&&(c=!0));var h=f(document);if(!h||"body"!=h.nodeName.toLowerCase())return void i("No body element found");if(h&&a(h,"createTextRange")&&(b=h.createTextRange(),e(b)&&(d=!0)),!c&&!d)return void i("Neither Range nor TextRange are available");H.initialized=!0,H.features={implementsDomRange:c,implementsTextRange:d};
|
26
|
+
// Initialize modules
|
27
|
+
var j,l;for(var m in E)(j=E[m])instanceof p&&j.init(j,H);
|
28
|
+
// Call init listeners
|
29
|
+
for(var n=0,o=K.length;n<o;++n)try{K[n](H)}catch(a){l="Rangy init listener threw an exception. Continuing. Detail: "+k(a),g(l)}}}function m(a,b,c){c&&(a+=" in module "+c.name),H.warn("DEPRECATED: "+a+" is deprecated. Please use "+b+" instead.")}function n(a,b,c,d){a[b]=function(){return m(b,c,d),a[c].apply(a,G.toArray(arguments))}}function o(a){a=a||window,l();
|
30
|
+
// Notify listeners
|
31
|
+
for(var b=0,c=L.length;b<c;++b)L[b](a)}function p(a,b,c){this.name=a,this.dependencies=b,this.initialized=!1,this.supported=!1,this.initializer=c}function q(a,b,c){var d=new p(a,b,function(b){if(!b.initialized){b.initialized=!0;try{c(H,b),b.supported=!0}catch(b){var d="Module '"+a+"' failed to load: "+k(b);g(d),b.stack&&g(b.stack)}}});return E[a]=d,d}/*----------------------------------------------------------------------------------------------------------------*/
|
32
|
+
// Ensure rangy.rangePrototype and rangy.selectionPrototype are available immediately
|
33
|
+
function r(){}function s(){}var t="object",u="function",v="undefined",w=["startContainer","startOffset","endContainer","endOffset","collapsed","commonAncestorContainer"],x=["setStart","setStartBefore","setStartAfter","setEnd","setEndBefore","setEndAfter","collapse","selectNode","selectNodeContents","compareBoundaryPoints","deleteContents","extractContents","cloneContents","insertNode","surroundContents","cloneRange","toString","detach"],y=["boundingHeight","boundingLeft","boundingTop","boundingWidth","htmlText","text"],z=["collapse","compareEndPoints","duplicate","moveToElementText","parentElement","select","setEndPoint","getBoundingClientRect"],A=d(a),B=d(b),C=d(c),D=[].forEach?function(a,b){a.forEach(b)}:function(a,b){for(var c=0,d=a.length;c<d;++c)b(a[c],c)},E={},F=typeof window!=v&&typeof document!=v,G={isHostMethod:a,isHostObject:b,isHostProperty:c,areHostMethods:A,areHostObjects:B,areHostProperties:C,isTextRange:e,getBody:f,forEach:D},H={version:"1.3.0",initialized:!1,isBrowser:F,supported:!0,util:G,features:{},modules:E,config:{alertOnFail:!1,alertOnWarn:!1,preferTextRange:!1,autoInitialize:typeof rangyAutoInitialize==v||rangyAutoInitialize}};H.fail=i,H.warn=j;
|
34
|
+
// Add utility extend() method
|
35
|
+
var I;({}).hasOwnProperty?(G.extend=I=function(a,b,c){var d,e;for(var f in b)b.hasOwnProperty(f)&&(d=a[f],e=b[f],c&&null!==d&&"object"==typeof d&&null!==e&&"object"==typeof e&&I(d,e,!0),a[f]=e);
|
36
|
+
// Special case for toString, which does not show up in for...in loops in IE <= 8
|
37
|
+
return b.hasOwnProperty("toString")&&(a.toString=b.toString),a},G.createOptions=function(a,b){var c={};return I(c,b),a&&I(c,a),c}):i("hasOwnProperty not supported"),
|
38
|
+
// Test whether we're in a browser and bail out if not
|
39
|
+
F||i("Rangy can only run in a browser"),
|
40
|
+
// Test whether Array.prototype.slice can be relied on for NodeLists and use an alternative toArray() if not
|
41
|
+
function(){var a;if(F){var b=document.createElement("div");b.appendChild(document.createElement("span"));var c=[].slice;try{1==c.call(b.childNodes,0)[0].nodeType&&(a=function(a){return c.call(a,0)})}catch(a){}}a||(a=function(a){for(var b=[],c=0,d=a.length;c<d;++c)b[c]=a[c];return b}),G.toArray=a}();
|
42
|
+
// Very simple event handler wrapper function that doesn't attempt to solve issues such as "this" handling or
|
43
|
+
// normalization of event properties
|
44
|
+
var J;F&&(a(document,"addEventListener")?J=function(a,b,c){a.addEventListener(b,c,!1)}:a(document,"attachEvent")?J=function(a,b,c){a.attachEvent("on"+b,c)}:i("Document does not have required addEventListener or attachEvent method"),G.addListener=J);var K=[];G.deprecationNotice=m,G.createAliasForDeprecatedMethod=n,
|
45
|
+
// Allow external scripts to initialize this library in case it's loaded after the document has loaded
|
46
|
+
H.init=l,
|
47
|
+
// Execute listener immediately if already initialized
|
48
|
+
H.addInitListener=function(a){H.initialized?a(H):K.push(a)};var L=[];H.addShimListener=function(a){L.push(a)},F&&(H.shim=H.createMissingNativeApi=o,n(H,"createMissingNativeApi","shim")),p.prototype={init:function(){for(var a,b,c=this.dependencies||[],d=0,e=c.length;d<e;++d){if(b=c[d],a=E[b],!(a&&a instanceof p))throw new Error("required module '"+b+"' not found");if(a.init(),!a.supported)throw new Error("required module '"+b+"' not supported")}
|
49
|
+
// Now run initializer
|
50
|
+
this.initializer(this)},fail:function(a){throw this.initialized=!0,this.supported=!1,new Error(a)},warn:function(a){H.warn("Module "+this.name+": "+a)},deprecationNotice:function(a,b){H.warn("DEPRECATED: "+a+" in module "+this.name+" is deprecated. Please use "+b+" instead")},createError:function(a){return new Error("Error in Rangy "+this.name+" module: "+a)}},H.createModule=function(a){
|
51
|
+
// Allow 2 or 3 arguments (second argument is an optional array of dependencies)
|
52
|
+
var b,c;2==arguments.length?(b=arguments[1],c=[]):(b=arguments[2],c=arguments[1]);var d=q(a,c,b);
|
53
|
+
// Initialize the module immediately if the core is already initialized
|
54
|
+
H.initialized&&H.supported&&d.init()},H.createCoreModule=function(a,b,c){q(a,b,c)},H.RangePrototype=r,H.rangePrototype=new r,H.selectionPrototype=new s,/*----------------------------------------------------------------------------------------------------------------*/
|
55
|
+
// DOM utility methods used by Rangy
|
56
|
+
H.createCoreModule("DomUtil",[],function(a,b){
|
57
|
+
// Opera 11 puts HTML elements in the null namespace, it seems, and IE 7 has undefined namespaceURI
|
58
|
+
function c(a){var b;return typeof a.namespaceURI==F||null===(b=a.namespaceURI)||"http://www.w3.org/1999/xhtml"==b}function d(a){var b=a.parentNode;return 1==b.nodeType?b:null}function e(a){for(var b=0;a=a.previousSibling;)++b;return b}function f(a){switch(a.nodeType){case 7:case 10:return 0;case 3:case 8:return a.length;default:return a.childNodes.length}}function g(a,b){var c,d=[];for(c=a;c;c=c.parentNode)d.push(c);for(c=b;c;c=c.parentNode)if(K(d,c))return c;return null}function h(a,b,c){for(var d=c?b:b.parentNode;d;){if(d===a)return!0;d=d.parentNode}return!1}function i(a,b){return h(a,b,!0)}function j(a,b,c){for(var d,e=c?a:a.parentNode;e;){if(d=e.parentNode,d===b)return e;e=d}return null}function k(a){var b=a.nodeType;return 3==b||4==b||8==b}function l(a){if(!a)return!1;var b=a.nodeType;return 3==b||8==b}function m(a,b){var c=b.nextSibling,d=b.parentNode;return c?d.insertBefore(a,c):d.appendChild(a),a}
|
59
|
+
// Note that we cannot use splitText() because it is bugridden in IE 9.
|
60
|
+
function n(a,b,c){var d=a.cloneNode(!1);
|
61
|
+
// Preserve positions
|
62
|
+
if(d.deleteData(0,b),a.deleteData(b,a.length-b),m(d,a),c)for(var f,g=0;f=c[g++];)
|
63
|
+
// Handle case where position was inside the portion of node after the split point
|
64
|
+
f.node==a&&f.offset>b?(f.node=d,f.offset-=b):f.node==a.parentNode&&f.offset>e(a)&&++f.offset;return d}function o(a){if(9==a.nodeType)return a;if(typeof a.ownerDocument!=F)return a.ownerDocument;if(typeof a.document!=F)return a.document;if(a.parentNode)return o(a.parentNode);throw b.createError("getDocument: no document found for node")}function p(a){var c=o(a);if(typeof c.defaultView!=F)return c.defaultView;if(typeof c.parentWindow!=F)return c.parentWindow;throw b.createError("Cannot get a window object for node")}function q(a){if(typeof a.contentDocument!=F)return a.contentDocument;if(typeof a.contentWindow!=F)return a.contentWindow.document;throw b.createError("getIframeDocument: No Document object found for iframe element")}function r(a){if(typeof a.contentWindow!=F)return a.contentWindow;if(typeof a.contentDocument!=F)return a.contentDocument.defaultView;throw b.createError("getIframeWindow: No Window object found for iframe element")}
|
65
|
+
// This looks bad. Is it worth it?
|
66
|
+
function s(a){return a&&G.isHostMethod(a,"setTimeout")&&G.isHostObject(a,"document")}function t(a,b,c){var d;if(a?G.isHostProperty(a,"nodeType")?d=1==a.nodeType&&"iframe"==a.tagName.toLowerCase()?q(a):o(a):s(a)&&(d=a.document):d=document,!d)throw b.createError(c+"(): Parameter must be a Window object or DOM node");return d}function u(a){for(var b;b=a.parentNode;)a=b;return a}function v(a,c,d,f){
|
67
|
+
// See http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Comparing
|
68
|
+
var h,i,k,l,m;if(a==d)
|
69
|
+
// Case 1: nodes are the same
|
70
|
+
return c===f?0:c<f?-1:1;if(h=j(d,a,!0))
|
71
|
+
// Case 2: node C (container B or an ancestor) is a child node of A
|
72
|
+
return c<=e(h)?-1:1;if(h=j(a,d,!0))
|
73
|
+
// Case 3: node C (container A or an ancestor) is a child node of B
|
74
|
+
return e(h)<f?-1:1;if(i=g(a,d),!i)throw new Error("comparePoints error: nodes have no common ancestor");if(
|
75
|
+
// Case 4: containers are siblings or descendants of siblings
|
76
|
+
k=a===i?i:j(a,i,!0),l=d===i?i:j(d,i,!0),k===l)
|
77
|
+
// This shouldn't be possible
|
78
|
+
throw b.createError("comparePoints got to case 4 and childA and childB are the same!");for(m=i.firstChild;m;){if(m===k)return-1;if(m===l)return 1;m=m.nextSibling}}function w(a){var b;try{return b=a.parentNode,!1}catch(a){return!0}}/*----------------------------------------------------------------------------------------------------------------*/
|
79
|
+
function x(a){if(!a)return"[No node]";if(L&&w(a))return"[Broken node]";if(k(a))return'"'+a.data+'"';if(1==a.nodeType){var b=a.id?' id="'+a.id+'"':"";return"<"+a.nodeName+b+">[index:"+e(a)+",length:"+a.childNodes.length+"]["+(a.innerHTML||"[innerHTML not supported]").slice(0,25)+"]"}return a.nodeName}function y(a){for(var b,c=o(a).createDocumentFragment();b=a.firstChild;)c.appendChild(b);return c}function z(a,b,c){var d=H(a),e=a.createElement("div");e.contentEditable=""+!!c,b&&(e.innerHTML=b);
|
80
|
+
// Insert the test element at the start of the body to prevent scrolling to the bottom in iOS (issue #292)
|
81
|
+
var f=d.firstChild;return f?d.insertBefore(e,f):d.appendChild(e),e}function A(a){return a.parentNode.removeChild(a)}function B(a){this.root=a,this._next=a}function C(a){return new B(a)}function D(a,b){this.node=a,this.offset=b}function E(a){this.code=this[a],this.codeName=a,this.message="DOMException: "+this.codeName}var F="undefined",G=a.util,H=G.getBody;
|
82
|
+
// Perform feature tests
|
83
|
+
G.areHostMethods(document,["createDocumentFragment","createElement","createTextNode"])||b.fail("document missing a Node creation method"),G.isHostMethod(document,"getElementsByTagName")||b.fail("document missing getElementsByTagName method");var I=document.createElement("div");G.areHostMethods(I,["insertBefore","appendChild","cloneNode"]||!G.areHostObjects(I,["previousSibling","nextSibling","childNodes","parentNode"]))||b.fail("Incomplete Element implementation"),
|
84
|
+
// innerHTML is required for Range's createContextualFragment method
|
85
|
+
G.isHostProperty(I,"innerHTML")||b.fail("Element is missing innerHTML property");var J=document.createTextNode("test");G.areHostMethods(J,["splitText","deleteData","insertData","appendData","cloneNode"]||!G.areHostObjects(I,["previousSibling","nextSibling","childNodes","parentNode"])||!G.areHostProperties(J,["data"]))||b.fail("Incomplete Text Node implementation");/*----------------------------------------------------------------------------------------------------------------*/
|
86
|
+
// Removed use of indexOf because of a bizarre bug in Opera that is thrown in one of the Acid3 tests. I haven't been
|
87
|
+
// able to replicate it outside of the test. The bug is that indexOf returns -1 when called on an Array that
|
88
|
+
// contains just the document as a single element and the value searched for is the document.
|
89
|
+
var K=/*Array.prototype.indexOf ?
|
90
|
+
function(arr, val) {
|
91
|
+
return arr.indexOf(val) > -1;
|
92
|
+
}:*/
|
93
|
+
function(a,b){for(var c=a.length;c--;)if(a[c]===b)return!0;return!1},L=!1;!function(){var b=document.createElement("b");b.innerHTML="1";var c=b.firstChild;b.innerHTML="<br />",L=w(c),a.features.crashyTextNodes=L}();var M;typeof window.getComputedStyle!=F?M=function(a,b){return p(a).getComputedStyle(a,null)[b]}:typeof document.documentElement.currentStyle!=F?M=function(a,b){return a.currentStyle?a.currentStyle[b]:""}:b.fail("No means of obtaining computed style properties found"),B.prototype={_current:null,hasNext:function(){return!!this._next},next:function(){var a,b,c=this._current=this._next;if(this._current)if(a=c.firstChild)this._next=a;else{for(b=null;c!==this.root&&!(b=c.nextSibling);)c=c.parentNode;this._next=b}return this._current},detach:function(){this._current=this._next=this.root=null}},D.prototype={equals:function(a){return!!a&&this.node===a.node&&this.offset==a.offset},inspect:function(){return"[DomPosition("+x(this.node)+":"+this.offset+")]"},toString:function(){return this.inspect()}},E.prototype={INDEX_SIZE_ERR:1,HIERARCHY_REQUEST_ERR:3,WRONG_DOCUMENT_ERR:4,NO_MODIFICATION_ALLOWED_ERR:7,NOT_FOUND_ERR:8,NOT_SUPPORTED_ERR:9,INVALID_STATE_ERR:11,INVALID_NODE_TYPE_ERR:24},E.prototype.toString=function(){return this.message},a.dom={arrayContains:K,isHtmlNamespace:c,parentElement:d,getNodeIndex:e,getNodeLength:f,getCommonAncestor:g,isAncestorOf:h,isOrIsAncestorOf:i,getClosestAncestorIn:j,isCharacterDataNode:k,isTextOrCommentNode:l,insertAfter:m,splitDataNode:n,getDocument:o,getWindow:p,getIframeWindow:r,getIframeDocument:q,getBody:H,isWindow:s,getContentDocument:t,getRootContainer:u,comparePoints:v,isBrokenNode:w,inspectNode:x,getComputedStyleProperty:M,createTestElement:z,removeNode:A,fragmentFromNodeChildren:y,createIterator:C,DomPosition:D},a.DOMException=E}),/*----------------------------------------------------------------------------------------------------------------*/
|
94
|
+
// Pure JavaScript implementation of DOM Range
|
95
|
+
H.createCoreModule("DomRange",["DomUtil"],function(a,b){/*----------------------------------------------------------------------------------------------------------------*/
|
96
|
+
// Utility functions
|
97
|
+
function c(a,b){return 3!=a.nodeType&&(P(a,b.startContainer)||P(a,b.endContainer))}function d(a){return a.document||Q(a.startContainer)}function e(a){return W(a.startContainer)}function f(a){return new L(a.parentNode,O(a))}function g(a){return new L(a.parentNode,O(a)+1)}function h(a,b,c){var d=11==a.nodeType?a.firstChild:a;return N(b)?c==b.length?J.insertAfter(a,b):b.parentNode.insertBefore(a,0==c?b:S(b,c)):c>=b.childNodes.length?b.appendChild(a):b.insertBefore(a,b.childNodes[c]),d}function i(a,b,c){if(z(a),z(b),d(b)!=d(a))throw new M("WRONG_DOCUMENT_ERR");var e=R(a.startContainer,a.startOffset,b.endContainer,b.endOffset),f=R(a.endContainer,a.endOffset,b.startContainer,b.startOffset);return c?e<=0&&f>=0:e<0&&f>0}function j(a){for(var b,c,e,f=d(a.range).createDocumentFragment();c=a.next();){if(b=a.isPartiallySelectedSubtree(),c=c.cloneNode(!b),b&&(e=a.getSubtreeIterator(),c.appendChild(j(e)),e.detach()),10==c.nodeType)// DocumentType
|
98
|
+
throw new M("HIERARCHY_REQUEST_ERR");f.appendChild(c)}return f}function k(a,b,c){var d,e;c=c||{stop:!1};for(var f,g;f=a.next();)if(a.isPartiallySelectedSubtree()){if(b(f)===!1)return void(c.stop=!0);if(
|
99
|
+
// The node is partially selected by the Range, so we can use a new RangeIterator on the portion of
|
100
|
+
// the node selected by the Range.
|
101
|
+
g=a.getSubtreeIterator(),k(g,b,c),g.detach(),c.stop)return}else for(
|
102
|
+
// The whole node is selected, so we can use efficient DOM iteration to iterate over the node and its
|
103
|
+
// descendants
|
104
|
+
d=J.createIterator(f);e=d.next();)if(b(e)===!1)return void(c.stop=!0)}function l(a){for(var b;a.next();)a.isPartiallySelectedSubtree()?(b=a.getSubtreeIterator(),l(b),b.detach()):a.remove()}function m(a){for(var b,c,e=d(a.range).createDocumentFragment();b=a.next();){if(a.isPartiallySelectedSubtree()?(b=b.cloneNode(!1),c=a.getSubtreeIterator(),b.appendChild(m(c)),c.detach()):a.remove(),10==b.nodeType)// DocumentType
|
105
|
+
throw new M("HIERARCHY_REQUEST_ERR");e.appendChild(b)}return e}function n(a,b,c){var d,e=!(!b||!b.length),f=!!c;e&&(d=new RegExp("^("+b.join("|")+")$"));var g=[];return k(new p(a,!1),function(b){if((!e||d.test(b.nodeType))&&(!f||c(b))){
|
106
|
+
// Don't include a boundary container if it is a character data node and the range does not contain any
|
107
|
+
// of its character data. See issue 190.
|
108
|
+
var h=a.startContainer;if(b!=h||!N(h)||a.startOffset!=h.length){var i=a.endContainer;b==i&&N(i)&&0==a.endOffset||g.push(b)}}}),g}function o(a){var b="undefined"==typeof a.getName?"Range":a.getName();return"["+b+"("+J.inspectNode(a.startContainer)+":"+a.startOffset+", "+J.inspectNode(a.endContainer)+":"+a.endOffset+")]"}/*----------------------------------------------------------------------------------------------------------------*/
|
109
|
+
// RangeIterator code partially borrows from IERange by Tim Ryan (http://github.com/timcameronryan/IERange)
|
110
|
+
function p(a,b){if(this.range=a,this.clonePartiallySelectedTextNodes=b,!a.collapsed){this.sc=a.startContainer,this.so=a.startOffset,this.ec=a.endContainer,this.eo=a.endOffset;var c=a.commonAncestorContainer;this.sc===this.ec&&N(this.sc)?(this.isSingleCharacterDataNode=!0,this._first=this._last=this._next=this.sc):(this._first=this._next=this.sc!==c||N(this.sc)?T(this.sc,c,!0):this.sc.childNodes[this.so],this._last=this.ec!==c||N(this.ec)?T(this.ec,c,!0):this.ec.childNodes[this.eo-1])}}function q(a){return function(b,c){for(var d,e=c?b:b.parentNode;e;){if(d=e.nodeType,V(a,d))return e;e=e.parentNode}return null}}function r(a,b){if(ea(a,b))throw new M("INVALID_NODE_TYPE_ERR")}function s(a,b){if(!V(b,a.nodeType))throw new M("INVALID_NODE_TYPE_ERR")}function t(a,b){if(b<0||b>(N(a)?a.length:a.childNodes.length))throw new M("INDEX_SIZE_ERR")}function u(a,b){if(ca(a,!0)!==ca(b,!0))throw new M("WRONG_DOCUMENT_ERR")}function v(a){if(da(a,!0))throw new M("NO_MODIFICATION_ALLOWED_ERR")}function w(a,b){if(!a)throw new M(b)}function x(a,b){return b<=(N(a)?a.length:a.childNodes.length)}function y(a){return!!a.startContainer&&!!a.endContainer&&!(X&&(J.isBrokenNode(a.startContainer)||J.isBrokenNode(a.endContainer)))&&W(a.startContainer)==W(a.endContainer)&&x(a.startContainer,a.startOffset)&&x(a.endContainer,a.endOffset)}function z(a){if(!y(a))throw new Error("Range error: Range is not valid. This usually happens after DOM mutation. Range: ("+a.inspect()+")")}function A(a,b){z(a);var c=a.startContainer,d=a.startOffset,e=a.endContainer,f=a.endOffset,g=c===e;N(e)&&f>0&&f<e.length&&S(e,f,b),N(c)&&d>0&&d<c.length&&(c=S(c,d,b),g?(f-=d,e=c):e==c.parentNode&&f>=O(c)&&f++,d=0),a.setStartAndEnd(c,d,e,f)}function B(a){z(a);var b=a.commonAncestorContainer.parentNode.cloneNode(!1);return b.appendChild(a.cloneContents()),b.innerHTML}function C(a){a.START_TO_START=ja,a.START_TO_END=ka,a.END_TO_END=la,a.END_TO_START=ma,a.NODE_BEFORE=na,a.NODE_AFTER=oa,a.NODE_BEFORE_AND_AFTER=pa,a.NODE_INSIDE=qa}function D(a){C(a),C(a.prototype)}function E(a,b){return function(){z(this);var c,d,e=this.startContainer,f=this.startOffset,h=this.commonAncestorContainer,i=new p(this,!0);e!==h&&(c=T(e,h,!0),d=g(c),e=d.node,f=d.offset),
|
111
|
+
// Check none of the range is read-only
|
112
|
+
k(i,v),i.reset();
|
113
|
+
// Remove the content
|
114
|
+
var j=a(i);
|
115
|
+
// Move to the new position
|
116
|
+
return i.detach(),b(this,e,f,e,f),j}}function F(b,d){function e(a,b){return function(c){s(c,Z),s(W(c),$);var d=(a?f:g)(c);(b?h:i)(this,d.node,d.offset)}}function h(a,b,c){var e=a.endContainer,f=a.endOffset;b===a.startContainer&&c===a.startOffset||(
|
117
|
+
// Check the root containers of the range and the new boundary, and also check whether the new boundary
|
118
|
+
// is after the current end. In either case, collapse the range to the new position
|
119
|
+
W(b)==W(e)&&1!=R(b,c,e,f)||(e=b,f=c),d(a,b,c,e,f))}function i(a,b,c){var e=a.startContainer,f=a.startOffset;b===a.endContainer&&c===a.endOffset||(
|
120
|
+
// Check the root containers of the range and the new boundary, and also check whether the new boundary
|
121
|
+
// is after the current end. In either case, collapse the range to the new position
|
122
|
+
W(b)==W(e)&&R(b,c,e,f)!=-1||(e=b,f=c),d(a,e,f,b,c))}
|
123
|
+
// Set up inheritance
|
124
|
+
var j=function(){};j.prototype=a.rangePrototype,b.prototype=new j,K.extend(b.prototype,{setStart:function(a,b){r(a,!0),t(a,b),h(this,a,b)},setEnd:function(a,b){r(a,!0),t(a,b),i(this,a,b)},/**
|
125
|
+
* Convenience method to set a range's start and end boundaries. Overloaded as follows:
|
126
|
+
* - Two parameters (node, offset) creates a collapsed range at that position
|
127
|
+
* - Three parameters (node, startOffset, endOffset) creates a range contained with node starting at
|
128
|
+
* startOffset and ending at endOffset
|
129
|
+
* - Four parameters (startNode, startOffset, endNode, endOffset) creates a range starting at startOffset in
|
130
|
+
* startNode and ending at endOffset in endNode
|
131
|
+
*/
|
132
|
+
setStartAndEnd:function(){var a=arguments,b=a[0],c=a[1],e=b,f=c;switch(a.length){case 3:f=a[2];break;case 4:e=a[2],f=a[3]}d(this,b,c,e,f)},setBoundary:function(a,b,c){this["set"+(c?"Start":"End")](a,b)},setStartBefore:e(!0,!0),setStartAfter:e(!1,!0),setEndBefore:e(!0,!1),setEndAfter:e(!1,!1),collapse:function(a){z(this),a?d(this,this.startContainer,this.startOffset,this.startContainer,this.startOffset):d(this,this.endContainer,this.endOffset,this.endContainer,this.endOffset)},selectNodeContents:function(a){r(a,!0),d(this,a,0,a,U(a))},selectNode:function(a){r(a,!1),s(a,Z);var b=f(a),c=g(a);d(this,b.node,b.offset,c.node,c.offset)},extractContents:E(m,d),deleteContents:E(l,d),canSurroundContents:function(){z(this),v(this.startContainer),v(this.endContainer);
|
133
|
+
// Check if the contents can be surrounded. Specifically, this means whether the range partially selects
|
134
|
+
// no non-text nodes.
|
135
|
+
var a=new p(this,!0),b=a._first&&c(a._first,this)||a._last&&c(a._last,this);return a.detach(),!b},splitBoundaries:function(){A(this)},splitBoundariesPreservingPositions:function(a){A(this,a)},normalizeBoundaries:function(){z(this);var a,b=this.startContainer,c=this.startOffset,e=this.endContainer,f=this.endOffset,g=function(a){var b=a.nextSibling;b&&b.nodeType==a.nodeType&&(e=a,f=a.length,a.appendData(b.data),Y(b))},h=function(a){var d=a.previousSibling;if(d&&d.nodeType==a.nodeType){b=a;var g=a.length;if(c=d.length,a.insertData(0,d.data),Y(d),b==e)f+=c,e=b;else if(e==a.parentNode){var h=O(a);f==h?(e=a,f=g):f>h&&f--}}},i=!0;if(N(e))f==e.length?g(e):0==f&&(a=e.previousSibling,a&&a.nodeType==e.nodeType&&(f=a.length,b==e&&(i=!1),a.appendData(e.data),Y(e),e=a));else{if(f>0){var j=e.childNodes[f-1];j&&N(j)&&g(j)}i=!this.collapsed}if(i){if(N(b))0==c?h(b):c==b.length&&(a=b.nextSibling,a&&a.nodeType==b.nodeType&&(e==a&&(e=b,f+=b.length),b.appendData(a.data),Y(a)));else if(c<b.childNodes.length){var k=b.childNodes[c];k&&N(k)&&h(k)}}else b=e,c=f;d(this,b,c,e,f)},collapseToPoint:function(a,b){r(a,!0),t(a,b),this.setStartAndEnd(a,b)}}),D(b)}/*----------------------------------------------------------------------------------------------------------------*/
|
136
|
+
// Updates commonAncestorContainer and collapsed after boundary change
|
137
|
+
function G(a){a.collapsed=a.startContainer===a.endContainer&&a.startOffset===a.endOffset,a.commonAncestorContainer=a.collapsed?a.startContainer:J.getCommonAncestor(a.startContainer,a.endContainer)}function H(a,b,c,d,e){a.startContainer=b,a.startOffset=c,a.endContainer=d,a.endOffset=e,a.document=J.getDocument(b),G(a)}function I(a){this.startContainer=a,this.startOffset=0,this.endContainer=a,this.endOffset=0,this.document=a,G(this)}var J=a.dom,K=a.util,L=J.DomPosition,M=a.DOMException,N=J.isCharacterDataNode,O=J.getNodeIndex,P=J.isOrIsAncestorOf,Q=J.getDocument,R=J.comparePoints,S=J.splitDataNode,T=J.getClosestAncestorIn,U=J.getNodeLength,V=J.arrayContains,W=J.getRootContainer,X=a.features.crashyTextNodes,Y=J.removeNode;p.prototype={_current:null,_next:null,_first:null,_last:null,isSingleCharacterDataNode:!1,reset:function(){this._current=null,this._next=this._first},hasNext:function(){return!!this._next},next:function(){
|
138
|
+
// Move to next node
|
139
|
+
var a=this._current=this._next;
|
140
|
+
// Check for partially selected text nodes
|
141
|
+
return a&&(this._next=a!==this._last?a.nextSibling:null,N(a)&&this.clonePartiallySelectedTextNodes&&(a===this.ec&&(a=a.cloneNode(!0)).deleteData(this.eo,a.length-this.eo),this._current===this.sc&&(a=a.cloneNode(!0)).deleteData(0,this.so))),a},remove:function(){var a,b,c=this._current;!N(c)||c!==this.sc&&c!==this.ec?c.parentNode&&Y(c):(a=c===this.sc?this.so:0,b=c===this.ec?this.eo:c.length,a!=b&&c.deleteData(a,b-a))},
|
142
|
+
// Checks if the current node is partially selected
|
143
|
+
isPartiallySelectedSubtree:function(){var a=this._current;return c(a,this.range)},getSubtreeIterator:function(){var a;if(this.isSingleCharacterDataNode)a=this.range.cloneRange(),a.collapse(!1);else{a=new I(d(this.range));var b=this._current,c=b,e=0,f=b,g=U(b);P(b,this.sc)&&(c=this.sc,e=this.so),P(b,this.ec)&&(f=this.ec,g=this.eo),H(a,c,e,f,g)}return new p(a,this.clonePartiallySelectedTextNodes)},detach:function(){this.range=this._current=this._next=this._first=this._last=this.sc=this.so=this.ec=this.eo=null}};/*----------------------------------------------------------------------------------------------------------------*/
|
144
|
+
var Z=[1,3,4,5,7,8,10],$=[2,9,11],_=[5,6,10,12],aa=[1,3,4,5,7,8,10,11],ba=[1,3,4,5,7,8],ca=q([9,11]),da=q(_),ea=q([6,10,12]),fa=document.createElement("style"),ga=!1;try{fa.innerHTML="<b>x</b>",ga=3==fa.firstChild.nodeType}catch(a){}a.features.htmlParsingConforms=ga;var ha=ga?
|
145
|
+
// Implementation as per HTML parsing spec, trusting in the browser's implementation of innerHTML. See
|
146
|
+
// discussion and base code for this implementation at issue 67.
|
147
|
+
// Spec: http://html5.org/specs/dom-parsing.html#extensions-to-the-range-interface
|
148
|
+
// Thanks to Aleks Williams.
|
149
|
+
function(a){
|
150
|
+
// "Let node the context object's start's node."
|
151
|
+
var b=this.startContainer,c=Q(b);
|
152
|
+
// "If the context object's start's node is null, raise an INVALID_STATE_ERR
|
153
|
+
// exception and abort these steps."
|
154
|
+
if(!b)throw new M("INVALID_STATE_ERR");
|
155
|
+
// "Let element be as follows, depending on node's interface:"
|
156
|
+
// Document, Document Fragment: null
|
157
|
+
var d=null;
|
158
|
+
// "If this raises an exception, then abort these steps. Otherwise, let new
|
159
|
+
// children be the nodes returned."
|
160
|
+
// "Let fragment be a new DocumentFragment."
|
161
|
+
// "Append all new children to fragment."
|
162
|
+
// "Return fragment."
|
163
|
+
// "Element: node"
|
164
|
+
// "If either element is null or element's ownerDocument is an HTML document
|
165
|
+
// and element's local name is "html" and element's namespace is the HTML
|
166
|
+
// namespace"
|
167
|
+
// "let element be a new Element with "body" as its local name and the HTML
|
168
|
+
// namespace as its namespace.""
|
169
|
+
// "If the node's document is an HTML document: Invoke the HTML fragment parsing algorithm."
|
170
|
+
// "If the node's document is an XML document: Invoke the XML fragment parsing algorithm."
|
171
|
+
// "In either case, the algorithm must be invoked with fragment as the input
|
172
|
+
// and element as the context element."
|
173
|
+
return 1==b.nodeType?d=b:N(b)&&(d=J.parentElement(b)),d=null===d||"HTML"==d.nodeName&&J.isHtmlNamespace(Q(d).documentElement)&&J.isHtmlNamespace(d)?c.createElement("body"):d.cloneNode(!1),d.innerHTML=a,J.fragmentFromNodeChildren(d)}:
|
174
|
+
// In this case, innerHTML cannot be trusted, so fall back to a simpler, non-conformant implementation that
|
175
|
+
// previous versions of Rangy used (with the exception of using a body element rather than a div)
|
176
|
+
function(a){var b=d(this),c=b.createElement("body");return c.innerHTML=a,J.fragmentFromNodeChildren(c)},ia=["startContainer","startOffset","endContainer","endOffset","collapsed","commonAncestorContainer"],ja=0,ka=1,la=2,ma=3,na=0,oa=1,pa=2,qa=3;K.extend(a.rangePrototype,{compareBoundaryPoints:function(a,b){z(this),u(this.startContainer,b.startContainer);var c,d,e,f,g=a==ma||a==ja?"start":"end",h=a==ka||a==ja?"start":"end";return c=this[g+"Container"],d=this[g+"Offset"],e=b[h+"Container"],f=b[h+"Offset"],R(c,d,e,f)},insertNode:function(a){if(z(this),s(a,aa),v(this.startContainer),P(a,this.startContainer))throw new M("HIERARCHY_REQUEST_ERR");
|
177
|
+
// No check for whether the container of the start of the Range is of a type that does not allow
|
178
|
+
// children of the type of node: the browser's DOM implementation should do this for us when we attempt
|
179
|
+
// to add the node
|
180
|
+
var b=h(a,this.startContainer,this.startOffset);this.setStartBefore(b)},cloneContents:function(){z(this);var a,b;if(this.collapsed)return d(this).createDocumentFragment();if(this.startContainer===this.endContainer&&N(this.startContainer))return a=this.startContainer.cloneNode(!0),a.data=a.data.slice(this.startOffset,this.endOffset),b=d(this).createDocumentFragment(),b.appendChild(a),b;var c=new p(this,!0);return a=j(c),c.detach(),a},canSurroundContents:function(){z(this),v(this.startContainer),v(this.endContainer);
|
181
|
+
// Check if the contents can be surrounded. Specifically, this means whether the range partially selects
|
182
|
+
// no non-text nodes.
|
183
|
+
var a=new p(this,!0),b=a._first&&c(a._first,this)||a._last&&c(a._last,this);return a.detach(),!b},surroundContents:function(a){if(s(a,ba),!this.canSurroundContents())throw new M("INVALID_STATE_ERR");
|
184
|
+
// Extract the contents
|
185
|
+
var b=this.extractContents();
|
186
|
+
// Clear the children of the node
|
187
|
+
if(a.hasChildNodes())for(;a.lastChild;)a.removeChild(a.lastChild);
|
188
|
+
// Insert the new node and add the extracted contents
|
189
|
+
h(a,this.startContainer,this.startOffset),a.appendChild(b),this.selectNode(a)},cloneRange:function(){z(this);for(var a,b=new I(d(this)),c=ia.length;c--;)a=ia[c],b[a]=this[a];return b},toString:function(){z(this);var a=this.startContainer;if(a===this.endContainer&&N(a))return 3==a.nodeType||4==a.nodeType?a.data.slice(this.startOffset,this.endOffset):"";var b=[],c=new p(this,!0);return k(c,function(a){
|
190
|
+
// Accept only text or CDATA nodes, not comments
|
191
|
+
3!=a.nodeType&&4!=a.nodeType||b.push(a.data)}),c.detach(),b.join("")},
|
192
|
+
// The methods below are all non-standard. The following batch were introduced by Mozilla but have since
|
193
|
+
// been removed from Mozilla.
|
194
|
+
compareNode:function(a){z(this);var b=a.parentNode,c=O(a);if(!b)throw new M("NOT_FOUND_ERR");var d=this.comparePoint(b,c),e=this.comparePoint(b,c+1);return d<0?e>0?pa:na:e>0?oa:qa},comparePoint:function(a,b){return z(this),w(a,"HIERARCHY_REQUEST_ERR"),u(a,this.startContainer),R(a,b,this.startContainer,this.startOffset)<0?-1:R(a,b,this.endContainer,this.endOffset)>0?1:0},createContextualFragment:ha,toHtml:function(){return B(this)},
|
195
|
+
// touchingIsIntersecting determines whether this method considers a node that borders a range intersects
|
196
|
+
// with it (as in WebKit) or not (as in Gecko pre-1.9, and the default)
|
197
|
+
intersectsNode:function(a,b){if(z(this),W(a)!=e(this))return!1;var c=a.parentNode,d=O(a);if(!c)return!0;var f=R(c,d,this.endContainer,this.endOffset),g=R(c,d+1,this.startContainer,this.startOffset);return b?f<=0&&g>=0:f<0&&g>0},isPointInRange:function(a,b){return z(this),w(a,"HIERARCHY_REQUEST_ERR"),u(a,this.startContainer),R(a,b,this.startContainer,this.startOffset)>=0&&R(a,b,this.endContainer,this.endOffset)<=0},
|
198
|
+
// The methods below are non-standard and invented by me.
|
199
|
+
// Sharing a boundary start-to-end or end-to-start does not count as intersection.
|
200
|
+
intersectsRange:function(a){return i(this,a,!1)},
|
201
|
+
// Sharing a boundary start-to-end or end-to-start does count as intersection.
|
202
|
+
intersectsOrTouchesRange:function(a){return i(this,a,!0)},intersection:function(a){if(this.intersectsRange(a)){var b=R(this.startContainer,this.startOffset,a.startContainer,a.startOffset),c=R(this.endContainer,this.endOffset,a.endContainer,a.endOffset),d=this.cloneRange();return b==-1&&d.setStart(a.startContainer,a.startOffset),1==c&&d.setEnd(a.endContainer,a.endOffset),d}return null},union:function(a){if(this.intersectsOrTouchesRange(a)){var b=this.cloneRange();return R(a.startContainer,a.startOffset,this.startContainer,this.startOffset)==-1&&b.setStart(a.startContainer,a.startOffset),1==R(a.endContainer,a.endOffset,this.endContainer,this.endOffset)&&b.setEnd(a.endContainer,a.endOffset),b}throw new M("Ranges do not intersect")},containsNode:function(a,b){return b?this.intersectsNode(a,!1):this.compareNode(a)==qa},containsNodeContents:function(a){return this.comparePoint(a,0)>=0&&this.comparePoint(a,U(a))<=0},containsRange:function(a){var b=this.intersection(a);return null!==b&&a.equals(b)},containsNodeText:function(a){var b=this.cloneRange();b.selectNode(a);var c=b.getNodes([3]);if(c.length>0){b.setStart(c[0],0);var d=c.pop();return b.setEnd(d,d.length),this.containsRange(b)}return this.containsNodeContents(a)},getNodes:function(a,b){return z(this),n(this,a,b)},getDocument:function(){return d(this)},collapseBefore:function(a){this.setEndBefore(a),this.collapse(!1)},collapseAfter:function(a){this.setStartAfter(a),this.collapse(!0)},getBookmark:function(b){var c=d(this),e=a.createRange(c);b=b||J.getBody(c),e.selectNodeContents(b);var f=this.intersection(e),g=0,h=0;return f&&(e.setEnd(f.startContainer,f.startOffset),g=e.toString().length,h=g+f.toString().length),{start:g,end:h,containerNode:b}},moveToBookmark:function(a){var b=a.containerNode,c=0;this.setStart(b,0),this.collapse(!0);for(var d,e,f,g,h=[b],i=!1,j=!1;!j&&(d=h.pop());)if(3==d.nodeType)e=c+d.length,!i&&a.start>=c&&a.start<=e&&(this.setStart(d,a.start-c),i=!0),i&&a.end>=c&&a.end<=e&&(this.setEnd(d,a.end-c),j=!0),c=e;else for(g=d.childNodes,f=g.length;f--;)h.push(g[f])},getName:function(){return"DomRange"},equals:function(a){return I.rangesEqual(this,a)},isValid:function(){return y(this)},inspect:function(){return o(this)},detach:function(){}}),F(I,H),K.extend(I,{rangeProperties:ia,RangeIterator:p,copyComparisonConstants:D,createPrototypeRange:F,inspect:o,toHtml:B,getRangeDocument:d,rangesEqual:function(a,b){return a.startContainer===b.startContainer&&a.startOffset===b.startOffset&&a.endContainer===b.endContainer&&a.endOffset===b.endOffset}}),a.DomRange=I}),/*----------------------------------------------------------------------------------------------------------------*/
|
203
|
+
// Wrappers for the browser's native DOM Range and/or TextRange implementation
|
204
|
+
H.createCoreModule("WrappedRange",["DomRange"],function(a,b){var c,d,e=a.dom,f=a.util,g=e.DomPosition,h=a.DomRange,i=e.getBody,j=e.getContentDocument,k=e.isCharacterDataNode;if(/*----------------------------------------------------------------------------------------------------------------*/
|
205
|
+
a.features.implementsDomRange&&
|
206
|
+
// This is a wrapper around the browser's native DOM Range. It has two aims:
|
207
|
+
// - Provide workarounds for specific browser bugs
|
208
|
+
// - provide convenient extensions, which are inherited from Rangy's DomRange
|
209
|
+
!function(){function d(a){for(var b,c=m.length;c--;)b=m[c],a[b]=a.nativeRange[b];
|
210
|
+
// Fix for broken collapsed property in IE 9.
|
211
|
+
a.collapsed=a.startContainer===a.endContainer&&a.startOffset===a.endOffset}function g(a,b,c,d,e){var f=a.startContainer!==b||a.startOffset!=c,g=a.endContainer!==d||a.endOffset!=e,h=!a.equals(a.nativeRange);
|
212
|
+
// Always set both boundaries for the benefit of IE9 (see issue 35)
|
213
|
+
(f||g||h)&&(a.setEnd(d,e),a.setStart(b,c))}var k,l,m=h.rangeProperties;c=function(a){if(!a)throw b.createError("WrappedRange: Range must be specified");this.nativeRange=a,d(this)},h.createPrototypeRange(c,g),k=c.prototype,k.selectNode=function(a){this.nativeRange.selectNode(a),d(this)},k.cloneContents=function(){return this.nativeRange.cloneContents()},
|
214
|
+
// Due to a long-standing Firefox bug that I have not been able to find a reliable way to detect,
|
215
|
+
// insertNode() is never delegated to the native range.
|
216
|
+
k.surroundContents=function(a){this.nativeRange.surroundContents(a),d(this)},k.collapse=function(a){this.nativeRange.collapse(a),d(this)},k.cloneRange=function(){return new c(this.nativeRange.cloneRange())},k.refresh=function(){d(this)},k.toString=function(){return this.nativeRange.toString()};
|
217
|
+
// Create test range and node for feature detection
|
218
|
+
var n=document.createTextNode("test");i(document).appendChild(n);var o=document.createRange();/*--------------------------------------------------------------------------------------------------------*/
|
219
|
+
// Test for Firefox 2 bug that prevents moving the start of a Range to a point after its current end and
|
220
|
+
// correct for it
|
221
|
+
o.setStart(n,0),o.setEnd(n,0);try{o.setStart(n,1),k.setStart=function(a,b){this.nativeRange.setStart(a,b),d(this)},k.setEnd=function(a,b){this.nativeRange.setEnd(a,b),d(this)},l=function(a){return function(b){this.nativeRange[a](b),d(this)}}}catch(a){k.setStart=function(a,b){try{this.nativeRange.setStart(a,b)}catch(c){this.nativeRange.setEnd(a,b),this.nativeRange.setStart(a,b)}d(this)},k.setEnd=function(a,b){try{this.nativeRange.setEnd(a,b)}catch(c){this.nativeRange.setStart(a,b),this.nativeRange.setEnd(a,b)}d(this)},l=function(a,b){return function(c){try{this.nativeRange[a](c)}catch(d){this.nativeRange[b](c),this.nativeRange[a](c)}d(this)}}}k.setStartBefore=l("setStartBefore","setEndBefore"),k.setStartAfter=l("setStartAfter","setEndAfter"),k.setEndBefore=l("setEndBefore","setStartBefore"),k.setEndAfter=l("setEndAfter","setStartAfter"),/*--------------------------------------------------------------------------------------------------------*/
|
222
|
+
// Always use DOM4-compliant selectNodeContents implementation: it's simpler and less code than testing
|
223
|
+
// whether the native implementation can be trusted
|
224
|
+
k.selectNodeContents=function(a){this.setStartAndEnd(a,0,e.getNodeLength(a))},/*--------------------------------------------------------------------------------------------------------*/
|
225
|
+
// Test for and correct WebKit bug that has the behaviour of compareBoundaryPoints round the wrong way for
|
226
|
+
// constants START_TO_END and END_TO_START: https://bugs.webkit.org/show_bug.cgi?id=20738
|
227
|
+
o.selectNodeContents(n),o.setEnd(n,3);var p=document.createRange();p.selectNodeContents(n),p.setEnd(n,4),p.setStart(n,2),o.compareBoundaryPoints(o.START_TO_END,p)==-1&&1==o.compareBoundaryPoints(o.END_TO_START,p)?
|
228
|
+
// This is the wrong way round, so correct for it
|
229
|
+
k.compareBoundaryPoints=function(a,b){return b=b.nativeRange||b,a==b.START_TO_END?a=b.END_TO_START:a==b.END_TO_START&&(a=b.START_TO_END),this.nativeRange.compareBoundaryPoints(a,b)}:k.compareBoundaryPoints=function(a,b){return this.nativeRange.compareBoundaryPoints(a,b.nativeRange||b)};/*--------------------------------------------------------------------------------------------------------*/
|
230
|
+
// Test for IE deleteContents() and extractContents() bug and correct it. See issue 107.
|
231
|
+
var q=document.createElement("div");q.innerHTML="123";var r=q.firstChild,s=i(document);s.appendChild(q),o.setStart(r,1),o.setEnd(r,2),o.deleteContents(),"13"==r.data&&(
|
232
|
+
// Behaviour is correct per DOM4 Range so wrap the browser's implementation of deleteContents() and
|
233
|
+
// extractContents()
|
234
|
+
k.deleteContents=function(){this.nativeRange.deleteContents(),d(this)},k.extractContents=function(){var a=this.nativeRange.extractContents();return d(this),a}),s.removeChild(q),s=null,/*--------------------------------------------------------------------------------------------------------*/
|
235
|
+
// Test for existence of createContextualFragment and delegate to it if it exists
|
236
|
+
f.isHostMethod(o,"createContextualFragment")&&(k.createContextualFragment=function(a){return this.nativeRange.createContextualFragment(a)}),/*--------------------------------------------------------------------------------------------------------*/
|
237
|
+
// Clean up
|
238
|
+
i(document).removeChild(n),k.getName=function(){return"WrappedRange"},a.WrappedRange=c,a.createNativeRange=function(a){return a=j(a,b,"createNativeRange"),a.createRange()}}(),a.features.implementsTextRange){/*
|
239
|
+
This is a workaround for a bug where IE returns the wrong container element from the TextRange's parentElement()
|
240
|
+
method. For example, in the following (where pipes denote the selection boundaries):
|
241
|
+
|
242
|
+
<ul id="ul"><li id="a">| a </li><li id="b"> b |</li></ul>
|
243
|
+
|
244
|
+
var range = document.selection.createRange();
|
245
|
+
alert(range.parentElement().id); // Should alert "ul" but alerts "b"
|
246
|
+
|
247
|
+
This method returns the common ancestor node of the following:
|
248
|
+
- the parentElement() of the textRange
|
249
|
+
- the parentElement() of the textRange after calling collapse(true)
|
250
|
+
- the parentElement() of the textRange after calling collapse(false)
|
251
|
+
*/
|
252
|
+
var l=function(a){var b=a.parentElement(),c=a.duplicate();c.collapse(!0);var d=c.parentElement();c=a.duplicate(),c.collapse(!1);var f=c.parentElement(),g=d==f?d:e.getCommonAncestor(d,f);return g==b?g:e.getCommonAncestor(b,g)},m=function(a){return 0==a.compareEndPoints("StartToEnd",a)},n=function(a,b,c,d,f){var h=a.duplicate();h.collapse(c);var i=h.parentElement();
|
253
|
+
// Deal with nodes that cannot "contain rich HTML markup". In practice, this means form inputs, images and
|
254
|
+
// similar. See http://msdn.microsoft.com/en-us/library/aa703950%28VS.85%29.aspx
|
255
|
+
if(
|
256
|
+
// Sometimes collapsing a TextRange that's at the start of a text node can move it into the previous node, so
|
257
|
+
// check for that
|
258
|
+
e.isOrIsAncestorOf(b,i)||(i=b),!i.canHaveHTML){var j=new g(i.parentNode,e.getNodeIndex(i));return{boundaryPosition:j,nodeInfo:{nodeIndex:j.offset,containerElement:j.node}}}var l=e.getDocument(i).createElement("span");
|
259
|
+
// Workaround for HTML5 Shiv's insane violation of document.createElement(). See Rangy issue 104 and HTML5
|
260
|
+
// Shiv issue 64: https://github.com/aFarkas/html5shiv/issues/64
|
261
|
+
l.parentNode&&e.removeNode(l);for(var m,n,o,p,q,r=c?"StartToStart":"StartToEnd",s=f&&f.containerElement==i?f.nodeIndex:0,t=i.childNodes.length,u=t,v=u;;){if(v==t?i.appendChild(l):i.insertBefore(l,i.childNodes[v]),h.moveToElementText(l),m=h.compareEndPoints(r,a),0==m||s==u)break;if(m==-1){if(u==s+1)
|
262
|
+
// We know the endth child node is after the range boundary, so we must be done.
|
263
|
+
break;s=v}else u=u==s+1?s:v;v=Math.floor((s+u)/2),i.removeChild(l)}if(
|
264
|
+
// We've now reached or gone past the boundary of the text range we're interested in
|
265
|
+
// so have identified the node we want
|
266
|
+
q=l.nextSibling,m==-1&&q&&k(q)){
|
267
|
+
// This is a character data node (text, comment, cdata). The working range is collapsed at the start of
|
268
|
+
// the node containing the text range's boundary, so we move the end of the working range to the
|
269
|
+
// boundary point and measure the length of its text to get the boundary's offset within the node.
|
270
|
+
h.setEndPoint(c?"EndToStart":"EndToEnd",a);var w;if(/[\r\n]/.test(q.data)){/*
|
271
|
+
For the particular case of a boundary within a text node containing rendered line breaks (within a
|
272
|
+
<pre> element, for example), we need a slightly complicated approach to get the boundary's offset in
|
273
|
+
IE. The facts:
|
274
|
+
|
275
|
+
- Each line break is represented as \r in the text node's data/nodeValue properties
|
276
|
+
- Each line break is represented as \r\n in the TextRange's 'text' property
|
277
|
+
- The 'text' property of the TextRange does not contain trailing line breaks
|
278
|
+
|
279
|
+
To get round the problem presented by the final fact above, we can use the fact that TextRange's
|
280
|
+
moveStart() and moveEnd() methods return the actual number of characters moved, which is not
|
281
|
+
necessarily the same as the number of characters it was instructed to move. The simplest approach is
|
282
|
+
to use this to store the characters moved when moving both the start and end of the range to the
|
283
|
+
start of the document body and subtracting the start offset from the end offset (the
|
284
|
+
"move-negative-gazillion" method). However, this is extremely slow when the document is large and
|
285
|
+
the range is near the end of it. Clearly doing the mirror image (i.e. moving the range boundaries to
|
286
|
+
the end of the document) has the same problem.
|
287
|
+
|
288
|
+
Another approach that works is to use moveStart() to move the start boundary of the range up to the
|
289
|
+
end boundary one character at a time and incrementing a counter with the value returned by the
|
290
|
+
moveStart() call. However, the check for whether the start boundary has reached the end boundary is
|
291
|
+
expensive, so this method is slow (although unlike "move-negative-gazillion" is largely unaffected
|
292
|
+
by the location of the range within the document).
|
293
|
+
|
294
|
+
The approach used below is a hybrid of the two methods above. It uses the fact that a string
|
295
|
+
containing the TextRange's 'text' property with each \r\n converted to a single \r character cannot
|
296
|
+
be longer than the text of the TextRange, so the start of the range is moved that length initially
|
297
|
+
and then a character at a time to make up for any trailing line breaks not contained in the 'text'
|
298
|
+
property. This has good performance in most situations compared to the previous two methods.
|
299
|
+
*/
|
300
|
+
var x=h.duplicate(),y=x.text.replace(/\r\n/g,"\r").length;for(w=x.moveStart("character",y);(m=x.compareEndPoints("StartToEnd",x))==-1;)w++,x.moveStart("character",1)}else w=h.text.length;p=new g(q,w)}else
|
301
|
+
// If the boundary immediately follows a character data node and this is the end boundary, we should favour
|
302
|
+
// a position within that, and likewise for a start boundary preceding a character data node
|
303
|
+
n=(d||!c)&&l.previousSibling,o=(d||c)&&l.nextSibling,p=o&&k(o)?new g(o,0):n&&k(n)?new g(n,n.data.length):new g(i,e.getNodeIndex(l));
|
304
|
+
// Clean up
|
305
|
+
return e.removeNode(l),{boundaryPosition:p,nodeInfo:{nodeIndex:v,containerElement:i}}},o=function(a,b){var c,d,f,g,h=a.offset,j=e.getDocument(a.node),l=i(j).createTextRange(),m=k(a.node);
|
306
|
+
// Position the range immediately before the node containing the boundary
|
307
|
+
// Making the working element non-empty element persuades IE to consider the TextRange boundary to be within
|
308
|
+
// the element rather than immediately before or after it
|
309
|
+
// insertBefore is supposed to work like appendChild if the second parameter is null. However, a bug report
|
310
|
+
// for IERange suggests that it can crash the browser: http://code.google.com/p/ierange/issues/detail?id=12
|
311
|
+
// Clean up
|
312
|
+
// Move the working range to the text offset, if required
|
313
|
+
return m?(c=a.node,d=c.parentNode):(g=a.node.childNodes,c=h<g.length?g[h]:null,d=a.node),f=j.createElement("span"),f.innerHTML="&#feff;",c?d.insertBefore(f,c):d.appendChild(f),l.moveToElementText(f),l.collapse(!b),d.removeChild(f),m&&l[b?"moveStart":"moveEnd"]("character",h),l};/*------------------------------------------------------------------------------------------------------------*/
|
314
|
+
// This is a wrapper around a TextRange, providing full DOM Range functionality using rangy's DomRange as a
|
315
|
+
// prototype
|
316
|
+
d=function(a){this.textRange=a,this.refresh()},d.prototype=new h(document),d.prototype.refresh=function(){var a,b,c,d=l(this.textRange);m(this.textRange)?b=a=n(this.textRange,d,!0,!0).boundaryPosition:(c=n(this.textRange,d,!0,!1),a=c.boundaryPosition,
|
317
|
+
// An optimization used here is that if the start and end boundaries have the same parent element, the
|
318
|
+
// search scope for the end boundary can be limited to exclude the portion of the element that precedes
|
319
|
+
// the start boundary
|
320
|
+
b=n(this.textRange,d,!1,!1,c.nodeInfo).boundaryPosition),this.setStart(a.node,a.offset),this.setEnd(b.node,b.offset)},d.prototype.getName=function(){return"WrappedTextRange"},h.copyComparisonConstants(d);var p=function(a){if(a.collapsed)return o(new g(a.startContainer,a.startOffset),!0);var b=o(new g(a.startContainer,a.startOffset),!0),c=o(new g(a.endContainer,a.endOffset),!1),d=i(h.getRangeDocument(a)).createTextRange();return d.setEndPoint("StartToStart",b),d.setEndPoint("EndToEnd",c),d};
|
321
|
+
// IE 9 and above have both implementations and Rangy makes both available. The next few lines sets which
|
322
|
+
// implementation to use by default.
|
323
|
+
if(d.rangeToTextRange=p,d.prototype.toTextRange=function(){return p(this)},a.WrappedTextRange=d,!a.features.implementsDomRange||a.config.preferTextRange){
|
324
|
+
// Add WrappedTextRange as the Range property of the global object to allow expression like Range.END_TO_END to work
|
325
|
+
var q=function(a){return a("return this;")()}(Function);"undefined"==typeof q.Range&&(q.Range=d),a.createNativeRange=function(a){return a=j(a,b,"createNativeRange"),i(a).createTextRange()},a.WrappedRange=d}}a.createRange=function(c){return c=j(c,b,"createRange"),new a.WrappedRange(a.createNativeRange(c))},a.createRangyRange=function(a){return a=j(a,b,"createRangyRange"),new h(a)},f.createAliasForDeprecatedMethod(a,"createIframeRange","createRange"),f.createAliasForDeprecatedMethod(a,"createIframeRangyRange","createRangyRange"),a.addShimListener(function(b){var c=b.document;"undefined"==typeof c.createRange&&(c.createRange=function(){return a.createRange(c)}),c=b=null})}),/*----------------------------------------------------------------------------------------------------------------*/
|
326
|
+
// This module creates a selection object wrapper that conforms as closely as possible to the Selection specification
|
327
|
+
// in the HTML Editing spec (http://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#selections)
|
328
|
+
H.createCoreModule("WrappedSelection",["DomRange","WrappedRange"],function(a,b){
|
329
|
+
// Utility function to support direction parameters in the API that may be a string ("backward", "backwards",
|
330
|
+
// "forward" or "forwards") or a Boolean (true for backwards).
|
331
|
+
function c(a){return"string"==typeof a?/^backward(s)?$/i.test(a):!!a}function d(a,c){if(a){if(C.isWindow(a))return a;if(a instanceof r)return a.win;var d=C.getContentDocument(a,b,c);return C.getWindow(d)}return window}function e(a){return d(a,"getWinSelection").getSelection()}function f(a){return d(a,"getDocSelection").document.selection}function g(a){var b=!1;return a.anchorNode&&(b=1==C.comparePoints(a.anchorNode,a.anchorOffset,a.focusNode,a.focusOffset)),b}function h(a,b,c){var d=c?"end":"start",e=c?"start":"end";a.anchorNode=b[d+"Container"],a.anchorOffset=b[d+"Offset"],a.focusNode=b[e+"Container"],a.focusOffset=b[e+"Offset"]}function i(a){var b=a.nativeSelection;a.anchorNode=b.anchorNode,a.anchorOffset=b.anchorOffset,a.focusNode=b.focusNode,a.focusOffset=b.focusOffset}function j(a){a.anchorNode=a.focusNode=null,a.anchorOffset=a.focusOffset=0,a.rangeCount=0,a.isCollapsed=!0,a._ranges.length=0}function k(b){var c;return b instanceof F?(c=a.createNativeRange(b.getDocument()),c.setEnd(b.endContainer,b.endOffset),c.setStart(b.startContainer,b.startOffset)):b instanceof G?c=b.nativeRange:J.implementsDomRange&&b instanceof C.getWindow(b.startContainer).Range&&(c=b),c}function l(a){if(!a.length||1!=a[0].nodeType)return!1;for(var b=1,c=a.length;b<c;++b)if(!C.isAncestorOf(a[0],a[b]))return!1;return!0}function m(a){var c=a.getNodes();if(!l(c))throw b.createError("getSingleElementFromRange: range "+a.inspect()+" did not consist of a single element");return c[0]}
|
332
|
+
// Simple, quick test which only needs to distinguish between a TextRange and a ControlRange
|
333
|
+
function n(a){return!!a&&"undefined"!=typeof a.text}function o(a,b){
|
334
|
+
// Create a Range from the selected TextRange
|
335
|
+
var c=new G(b);a._ranges=[c],h(a,c,!1),a.rangeCount=1,a.isCollapsed=c.collapsed}function p(b){if(
|
336
|
+
// Update the wrapped selection based on what's now in the native selection
|
337
|
+
b._ranges.length=0,"None"==b.docSelection.type)j(b);else{var c=b.docSelection.createRange();if(n(c))
|
338
|
+
// This case (where the selection type is "Control" and calling createRange() on the selection returns
|
339
|
+
// a TextRange) can happen in IE 9. It happens, for example, when all elements in the selected
|
340
|
+
// ControlRange have been removed from the ControlRange and removed from the document.
|
341
|
+
o(b,c);else{b.rangeCount=c.length;for(var d,e=L(c.item(0)),f=0;f<b.rangeCount;++f)d=a.createRange(e),d.selectNode(c.item(f)),b._ranges.push(d);b.isCollapsed=1==b.rangeCount&&b._ranges[0].collapsed,h(b,b._ranges[b.rangeCount-1],!1)}}}function q(a,c){for(var d=a.docSelection.createRange(),e=m(c),f=L(d.item(0)),g=M(f).createControlRange(),h=0,i=d.length;h<i;++h)g.add(d.item(h));try{g.add(e)}catch(a){throw b.createError("addRange(): Element within the specified Range could not be added to control selection (does it have layout?)")}g.select(),
|
342
|
+
// Update the wrapped selection based on what's now in the native selection
|
343
|
+
p(a)}function r(a,b,c){this.nativeSelection=a,this.docSelection=b,this._ranges=[],this.win=c,this.refresh()}function s(a){a.win=a.anchorNode=a.focusNode=a._ranges=null,a.rangeCount=a.anchorOffset=a.focusOffset=0,a.detached=!0}function t(a,b){for(var c,d,e=ba.length;e--;)if(c=ba[e],d=c.selection,"deleteAll"==b)s(d);else if(c.win==a)return"delete"==b?(ba.splice(e,1),!0):d;return"deleteAll"==b&&(ba.length=0),null}function u(a,c){for(var d,e=L(c[0].startContainer),f=M(e).createControlRange(),g=0,h=c.length;g<h;++g){d=m(c[g]);try{f.add(d)}catch(a){throw b.createError("setRanges(): Element within one of the specified Ranges could not be added to control selection (does it have layout?)")}}f.select(),
|
344
|
+
// Update the wrapped selection based on what's now in the native selection
|
345
|
+
p(a)}function v(a,b){if(a.win.document!=L(b))throw new H("WRONG_DOCUMENT_ERR")}function w(b){return function(c,d){var e;this.rangeCount?(e=this.getRangeAt(0),e["set"+(b?"Start":"End")](c,d)):(e=a.createRange(this.win.document),e.setStartAndEnd(c,d)),this.setSingleRange(e,this.isBackward())}}function x(a){var b=[],c=new I(a.anchorNode,a.anchorOffset),d=new I(a.focusNode,a.focusOffset),e="function"==typeof a.getName?a.getName():"Selection";if("undefined"!=typeof a.rangeCount)for(var f=0,g=a.rangeCount;f<g;++f)b[f]=F.inspect(a.getRangeAt(f));return"["+e+"(Ranges: "+b.join(", ")+")(anchor: "+c.inspect()+", focus: "+d.inspect()+"]"}a.config.checkSelectionRanges=!0;var y,z,A="boolean",B="number",C=a.dom,D=a.util,E=D.isHostMethod,F=a.DomRange,G=a.WrappedRange,H=a.DOMException,I=C.DomPosition,J=a.features,K="Control",L=C.getDocument,M=C.getBody,N=F.rangesEqual,O=E(window,"getSelection"),P=D.isHostObject(document,"selection");J.implementsWinGetSelection=O,J.implementsDocSelection=P;var Q=P&&(!O||a.config.preferTextRange);if(Q)y=f,a.isSelectionValid=function(a){var b=d(a,"isSelectionValid").document,c=b.selection;
|
346
|
+
// Check whether the selection TextRange is actually contained within the correct document
|
347
|
+
return"None"!=c.type||L(c.createRange().parentElement())==b};else{if(!O)return b.fail("Neither document.selection or window.getSelection() detected."),!1;y=e,a.isSelectionValid=function(){return!0}}a.getNativeSelection=y;var R=y();
|
348
|
+
// In Firefox, the selection is null in an iframe with display: none. See issue #138.
|
349
|
+
if(!R)return b.fail("Native selection was null (possibly issue 138?)"),!1;var S=a.createNativeRange(document),T=M(document),U=D.areHostProperties(R,["anchorNode","focusNode","anchorOffset","focusOffset"]);J.selectionHasAnchorAndFocus=U;
|
350
|
+
// Test for existence of native selection extend() method
|
351
|
+
var V=E(R,"extend");J.selectionHasExtend=V;
|
352
|
+
// Test if rangeCount exists
|
353
|
+
var W=typeof R.rangeCount==B;J.selectionHasRangeCount=W;var X=!1,Y=!0,Z=V?function(b,c){var d=F.getRangeDocument(c),e=a.createRange(d);e.collapseToPoint(c.endContainer,c.endOffset),b.addRange(k(e)),b.extend(c.startContainer,c.startOffset)}:null;D.areHostMethods(R,["addRange","getRangeAt","removeAllRanges"])&&typeof R.rangeCount==B&&J.implementsDomRange&&!function(){
|
354
|
+
// Previously an iframe was used but this caused problems in some circumstances in IE, so tests are
|
355
|
+
// performed on the current document's selection. See issue 109.
|
356
|
+
// Note also that if a selection previously existed, it is wiped and later restored by these tests. This
|
357
|
+
// will result in the selection direction begin reversed if the original selection was backwards and the
|
358
|
+
// browser does not support setting backwards selections (Internet Explorer, I'm looking at you).
|
359
|
+
var b=window.getSelection();if(b){for(var c=b.rangeCount,d=c>1,e=[],f=g(b),h=0;h<c;++h)e[h]=b.getRangeAt(h);
|
360
|
+
// Create some test elements
|
361
|
+
var i=C.createTestElement(document,"",!1),j=i.appendChild(document.createTextNode(" ")),k=document.createRange();
|
362
|
+
// Test whether the native selection is capable of supporting multiple ranges.
|
363
|
+
if(k.setStart(j,1),k.collapse(!0),b.removeAllRanges(),b.addRange(k),Y=1==b.rangeCount,b.removeAllRanges(),!d){
|
364
|
+
// Doing the original feature test here in Chrome 36 (and presumably later versions) prints a
|
365
|
+
// console error of "Discontiguous selection is not supported." that cannot be suppressed. There's
|
366
|
+
// nothing we can do about this while retaining the feature test so we have to resort to a browser
|
367
|
+
// sniff. I'm not happy about it. See
|
368
|
+
// https://code.google.com/p/chromium/issues/detail?id=399791
|
369
|
+
var l=window.navigator.appVersion.match(/Chrome\/(.*?) /);if(l&&parseInt(l[1])>=36)X=!1;else{var m=k.cloneRange();k.setStart(j,0),m.setEnd(j,3),m.setStart(j,2),b.addRange(k),b.addRange(m),X=2==b.rangeCount}}for(
|
370
|
+
// Clean up
|
371
|
+
C.removeNode(i),b.removeAllRanges(),h=0;h<c;++h)0==h&&f?Z?Z(b,e[h]):(a.warn("Rangy initialization: original selection was backwards but selection has been restored forwards because the browser does not support Selection.extend"),b.addRange(e[h])):b.addRange(e[h])}}(),J.selectionSupportsMultipleRanges=X,J.collapsedNonEditableSelectionsSupported=Y;
|
372
|
+
// ControlRanges
|
373
|
+
var $,_=!1;T&&E(T,"createControlRange")&&($=T.createControlRange(),D.areHostProperties($,["item","add"])&&(_=!0)),J.implementsControlRange=_,
|
374
|
+
// Selection collapsedness
|
375
|
+
z=U?function(a){return a.anchorNode===a.focusNode&&a.anchorOffset===a.focusOffset}:function(a){return!!a.rangeCount&&a.getRangeAt(a.rangeCount-1).collapsed};var aa;E(R,"getRangeAt")?
|
376
|
+
// try/catch is present because getRangeAt() must have thrown an error in some browser and some situation.
|
377
|
+
// Unfortunately, I didn't write a comment about the specifics and am now scared to take it out. Let that be a
|
378
|
+
// lesson to us all, especially me.
|
379
|
+
aa=function(a,b){try{return a.getRangeAt(b)}catch(a){return null}}:U&&(aa=function(b){var c=L(b.anchorNode),d=a.createRange(c);
|
380
|
+
// Handle the case when the selection was selected backwards (from the end to the start in the
|
381
|
+
// document)
|
382
|
+
return d.setStartAndEnd(b.anchorNode,b.anchorOffset,b.focusNode,b.focusOffset),d.collapsed!==this.isCollapsed&&d.setStartAndEnd(b.focusNode,b.focusOffset,b.anchorNode,b.anchorOffset),d}),r.prototype=a.selectionPrototype;var ba=[],ca=function(a){
|
383
|
+
// Check if the parameter is a Rangy Selection object
|
384
|
+
if(a&&a instanceof r)return a.refresh(),a;a=d(a,"getNativeSelection");var b=t(a),c=y(a),e=P?f(a):null;return b?(b.nativeSelection=c,b.docSelection=e,b.refresh()):(b=new r(c,e,a),ba.push({win:a,selection:b})),b};a.getSelection=ca,D.createAliasForDeprecatedMethod(a,"getIframeSelection","getSelection");var da=r.prototype;
|
385
|
+
// Selecting a range
|
386
|
+
if(!Q&&U&&D.areHostMethods(R,["removeAllRanges","addRange"])){da.removeAllRanges=function(){this.nativeSelection.removeAllRanges(),j(this)};var ea=function(a,b){Z(a.nativeSelection,b),a.refresh()};W?da.addRange=function(b,d){if(_&&P&&this.docSelection.type==K)q(this,b);else if(c(d)&&V)ea(this,b);else{var e;X?e=this.rangeCount:(this.removeAllRanges(),e=0);
|
387
|
+
// Clone the native range so that changing the selected range does not affect the selection.
|
388
|
+
// This is contrary to the spec but is the only way to achieve consistency between browsers. See
|
389
|
+
// issue 80.
|
390
|
+
var f=k(b).cloneRange();try{this.nativeSelection.addRange(f)}catch(a){}if(
|
391
|
+
// Check whether adding the range was successful
|
392
|
+
this.rangeCount=this.nativeSelection.rangeCount,this.rangeCount==e+1){
|
393
|
+
// The range was added successfully
|
394
|
+
// Check whether the range that we added to the selection is reflected in the last range extracted from
|
395
|
+
// the selection
|
396
|
+
if(a.config.checkSelectionRanges){var g=aa(this.nativeSelection,this.rangeCount-1);g&&!N(g,b)&&(
|
397
|
+
// Happens in WebKit with, for example, a selection placed at the start of a text node
|
398
|
+
b=new G(g))}this._ranges[this.rangeCount-1]=b,h(this,b,ha(this.nativeSelection)),this.isCollapsed=z(this)}else
|
399
|
+
// The range was not added successfully. The simplest thing is to refresh
|
400
|
+
this.refresh()}}:da.addRange=function(a,b){c(b)&&V?ea(this,a):(this.nativeSelection.addRange(k(a)),this.refresh())},da.setRanges=function(a){if(_&&P&&a.length>1)u(this,a);else{this.removeAllRanges();for(var b=0,c=a.length;b<c;++b)this.addRange(a[b])}}}else{if(!(E(R,"empty")&&E(S,"select")&&_&&Q))return b.fail("No means of selecting a Range or TextRange was found"),!1;da.removeAllRanges=function(){
|
401
|
+
// Added try/catch as fix for issue #21
|
402
|
+
try{
|
403
|
+
// Check for empty() not working (issue #24)
|
404
|
+
if(this.docSelection.empty(),"None"!=this.docSelection.type){
|
405
|
+
// Work around failure to empty a control selection by instead selecting a TextRange and then
|
406
|
+
// calling empty()
|
407
|
+
var a;if(this.anchorNode)a=L(this.anchorNode);else if(this.docSelection.type==K){var b=this.docSelection.createRange();b.length&&(a=L(b.item(0)))}if(a){var c=M(a).createTextRange();c.select(),this.docSelection.empty()}}}catch(a){}j(this)},da.addRange=function(b){this.docSelection.type==K?q(this,b):(a.WrappedTextRange.rangeToTextRange(b).select(),this._ranges[0]=b,this.rangeCount=1,this.isCollapsed=this._ranges[0].collapsed,h(this,b,!1))},da.setRanges=function(a){this.removeAllRanges();var b=a.length;b>1?u(this,a):b&&this.addRange(a[0])}}da.getRangeAt=function(a){if(a<0||a>=this.rangeCount)throw new H("INDEX_SIZE_ERR");
|
408
|
+
// Clone the range to preserve selection-range independence. See issue 80.
|
409
|
+
return this._ranges[a].cloneRange()};var fa;if(Q)fa=function(b){var c;a.isSelectionValid(b.win)?c=b.docSelection.createRange():(c=M(b.win.document).createTextRange(),c.collapse(!0)),b.docSelection.type==K?p(b):n(c)?o(b,c):j(b)};else if(E(R,"getRangeAt")&&typeof R.rangeCount==B)fa=function(b){if(_&&P&&b.docSelection.type==K)p(b);else if(b._ranges.length=b.rangeCount=b.nativeSelection.rangeCount,b.rangeCount){for(var c=0,d=b.rangeCount;c<d;++c)b._ranges[c]=new a.WrappedRange(b.nativeSelection.getRangeAt(c));h(b,b._ranges[b.rangeCount-1],ha(b.nativeSelection)),b.isCollapsed=z(b)}else j(b)};else{if(!U||typeof R.isCollapsed!=A||typeof S.collapsed!=A||!J.implementsDomRange)return b.fail("No means of obtaining a Range or TextRange from the user's selection was found"),!1;fa=function(a){var b,c=a.nativeSelection;c.anchorNode?(b=aa(c,0),a._ranges=[b],a.rangeCount=1,i(a),a.isCollapsed=z(a)):j(a)}}da.refresh=function(a){var b=a?this._ranges.slice(0):null,c=this.anchorNode,d=this.anchorOffset;if(fa(this),a){
|
410
|
+
// Check the range count first
|
411
|
+
var e=b.length;if(e!=this._ranges.length)return!0;
|
412
|
+
// Now check the direction. Checking the anchor position is the same is enough since we're checking all the
|
413
|
+
// ranges after this
|
414
|
+
if(this.anchorNode!=c||this.anchorOffset!=d)return!0;
|
415
|
+
// Finally, compare each range in turn
|
416
|
+
for(;e--;)if(!N(b[e],this._ranges[e]))return!0;return!1}};
|
417
|
+
// Removal of a single range
|
418
|
+
var ga=function(a,b){var c=a.getAllRanges();a.removeAllRanges();for(var d=0,e=c.length;d<e;++d)N(b,c[d])||a.addRange(c[d]);a.rangeCount||j(a)};_&&P?da.removeRange=function(a){if(this.docSelection.type==K){for(var b,c=this.docSelection.createRange(),d=m(a),e=L(c.item(0)),f=M(e).createControlRange(),g=!1,h=0,i=c.length;h<i;++h)b=c.item(h),b!==d||g?f.add(c.item(h)):g=!0;f.select(),
|
419
|
+
// Update the wrapped selection based on what's now in the native selection
|
420
|
+
p(this)}else ga(this,a)}:da.removeRange=function(a){ga(this,a)};
|
421
|
+
// Detecting if a selection is backward
|
422
|
+
var ha;!Q&&U&&J.implementsDomRange?(ha=g,da.isBackward=function(){return ha(this)}):ha=da.isBackward=function(){return!1},
|
423
|
+
// Create an alias for backwards compatibility. From 1.3, everything is "backward" rather than "backwards"
|
424
|
+
da.isBackwards=da.isBackward,
|
425
|
+
// Selection stringifier
|
426
|
+
// This is conformant to the old HTML5 selections draft spec but differs from WebKit and Mozilla's implementation.
|
427
|
+
// The current spec does not yet define this method.
|
428
|
+
da.toString=function(){for(var a=[],b=0,c=this.rangeCount;b<c;++b)a[b]=""+this._ranges[b];return a.join("")},
|
429
|
+
// No current browser conforms fully to the spec for this method, so Rangy's own method is always used
|
430
|
+
da.collapse=function(b,c){v(this,b);var d=a.createRange(b);d.collapseToPoint(b,c),this.setSingleRange(d),this.isCollapsed=!0},da.collapseToStart=function(){if(!this.rangeCount)throw new H("INVALID_STATE_ERR");var a=this._ranges[0];this.collapse(a.startContainer,a.startOffset)},da.collapseToEnd=function(){if(!this.rangeCount)throw new H("INVALID_STATE_ERR");var a=this._ranges[this.rangeCount-1];this.collapse(a.endContainer,a.endOffset)},
|
431
|
+
// The spec is very specific on how selectAllChildren should be implemented and not all browsers implement it as
|
432
|
+
// specified so the native implementation is never used by Rangy.
|
433
|
+
da.selectAllChildren=function(b){v(this,b);var c=a.createRange(b);c.selectNodeContents(b),this.setSingleRange(c)},da.deleteFromDocument=function(){
|
434
|
+
// Sepcial behaviour required for IE's control selections
|
435
|
+
if(_&&P&&this.docSelection.type==K){for(var a,b=this.docSelection.createRange();b.length;)a=b.item(0),b.remove(a),C.removeNode(a);this.refresh()}else if(this.rangeCount){var c=this.getAllRanges();if(c.length){this.removeAllRanges();for(var d=0,e=c.length;d<e;++d)c[d].deleteContents();
|
436
|
+
// The spec says nothing about what the selection should contain after calling deleteContents on each
|
437
|
+
// range. Firefox moves the selection to where the final selected range was, so we emulate that
|
438
|
+
this.addRange(c[e-1])}}},
|
439
|
+
// The following are non-standard extensions
|
440
|
+
da.eachRange=function(a,b){for(var c=0,d=this._ranges.length;c<d;++c)if(a(this.getRangeAt(c)))return b},da.getAllRanges=function(){var a=[];return this.eachRange(function(b){a.push(b)}),a},da.setSingleRange=function(a,b){this.removeAllRanges(),this.addRange(a,b)},da.callMethodOnEachRange=function(a,b){var c=[];return this.eachRange(function(d){c.push(d[a].apply(d,b||[]))}),c},da.setStart=w(!0),da.setEnd=w(!1),
|
441
|
+
// Add select() method to Range prototype. Any existing selection will be removed.
|
442
|
+
a.rangePrototype.select=function(a){ca(this.getDocument()).setSingleRange(this,a)},da.changeEachRange=function(a){var b=[],c=this.isBackward();this.eachRange(function(c){a(c),b.push(c)}),this.removeAllRanges(),c&&1==b.length?this.addRange(b[0],"backward"):this.setRanges(b)},da.containsNode=function(a,b){return this.eachRange(function(c){return c.containsNode(a,b)},!0)||!1},da.getBookmark=function(a){return{backward:this.isBackward(),rangeBookmarks:this.callMethodOnEachRange("getBookmark",[a])}},da.moveToBookmark=function(b){for(var c,d,e=[],f=0;c=b.rangeBookmarks[f++];)d=a.createRange(this.win),d.moveToBookmark(c),e.push(d);b.backward?this.setSingleRange(e[0],"backward"):this.setRanges(e)},da.saveRanges=function(){return{backward:this.isBackward(),ranges:this.callMethodOnEachRange("cloneRange")}},da.restoreRanges=function(a){this.removeAllRanges();for(var b,c=0;b=a.ranges[c];++c)this.addRange(b,a.backward&&0==c)},da.toHtml=function(){var a=[];return this.eachRange(function(b){a.push(F.toHtml(b))}),a.join("")},J.implementsTextRange&&(da.getNativeTextRange=function(){var c;if(c=this.docSelection){var d=c.createRange();if(n(d))return d;throw b.createError("getNativeTextRange: selection is a control selection")}if(this.rangeCount>0)return a.WrappedTextRange.rangeToTextRange(this.getRangeAt(0));throw b.createError("getNativeTextRange: selection contains no range")}),da.getName=function(){return"WrappedSelection"},da.inspect=function(){return x(this)},da.detach=function(){t(this.win,"delete"),s(this)},r.detachAll=function(){t(null,"deleteAll")},r.inspect=x,r.isDirectionBackward=c,a.Selection=r,a.selectionPrototype=da,a.addShimListener(function(a){"undefined"==typeof a.getSelection&&(a.getSelection=function(){return ca(a)}),a=null})});/*----------------------------------------------------------------------------------------------------------------*/
|
443
|
+
// Wait for document to load before initializing
|
444
|
+
var M=!1,N=function(a){M||(M=!0,!H.initialized&&H.config.autoInitialize&&l())};
|
445
|
+
// Test whether the document has already been loaded and initialize immediately if so
|
446
|
+
// Add a fallback in case the DOMContentLoaded event isn't supported
|
447
|
+
return F&&("complete"==document.readyState?N():(a(document,"addEventListener")&&document.addEventListener("DOMContentLoaded",N,!1),J(window,"load",N))),H},this),/**
|
448
|
+
* Selection save and restore module for Rangy.
|
449
|
+
* Saves and restores user selections using marker invisible elements in the DOM.
|
450
|
+
*
|
451
|
+
* Part of Rangy, a cross-browser JavaScript range and selection library
|
452
|
+
* https://github.com/timdown/rangy
|
453
|
+
*
|
454
|
+
* Depends on Rangy core.
|
455
|
+
*
|
456
|
+
* Copyright 2015, Tim Down
|
457
|
+
* Licensed under the MIT license.
|
458
|
+
* Version: 1.3.0
|
459
|
+
* Build date: 10 May 2015
|
460
|
+
*/
|
461
|
+
function(a,b){"function"==typeof define&&define.amd?
|
462
|
+
// AMD. Register as an anonymous module with a dependency on Rangy.
|
463
|
+
define(["./rangy-core"],a):"undefined"!=typeof module&&"object"==typeof exports?
|
464
|
+
// Node/CommonJS style
|
465
|
+
module.exports=a(require("rangy")):
|
466
|
+
// No AMD or CommonJS support so we use the rangy property of root (probably the global variable)
|
467
|
+
a(b.rangy)}(function(a){return a.createModule("SaveRestore",["WrappedRange"],function(a,b){function c(a,b){return(b||document).getElementById(a)}function d(a,b){var c,d="selectionBoundary_"+ +new Date+"_"+(""+Math.random()).slice(2),e=o.getDocument(a.startContainer),f=a.cloneRange();
|
468
|
+
// Create the marker element containing a single invisible character using DOM methods and insert it
|
469
|
+
return f.collapse(b),c=e.createElement("span"),c.id=d,c.style.lineHeight="0",c.style.display="none",c.className="rangySelectionBoundary",c.appendChild(e.createTextNode(r)),f.insertNode(c),c}function e(a,d,e,f){var g=c(e,a);g?(d[f?"setStartBefore":"setEndBefore"](g),p(g)):b.warn("Marker element has been removed. Cannot restore selection.")}function f(a,b){return b.compareBoundaryPoints(a.START_TO_START,a)}function g(b,c){var e,f,g=a.DomRange.getRangeDocument(b),h=b.toString(),i=q(c);return b.collapsed?(f=d(b,!1),{document:g,markerId:f.id,collapsed:!0}):(f=d(b,!1),e=d(b,!0),{document:g,startMarkerId:e.id,endMarkerId:f.id,collapsed:!1,backward:i,toString:function(){return"original text: '"+h+"', new text: '"+b.toString()+"'"}})}function h(d,f){var g=d.document;"undefined"==typeof f&&(f=!0);var h=a.createRange(g);if(d.collapsed){var i=c(d.markerId,g);if(i){i.style.display="inline";var j=i.previousSibling;
|
470
|
+
// Workaround for issue 17
|
471
|
+
j&&3==j.nodeType?(p(i),h.collapseToPoint(j,j.length)):(h.collapseBefore(i),p(i))}else b.warn("Marker element has been removed. Cannot restore selection.")}else e(g,h,d.startMarkerId,!0),e(g,h,d.endMarkerId,!1);return f&&h.normalizeBoundaries(),h}function i(b,d){var e,h,i=[],j=q(d);
|
472
|
+
// Order the ranges by position within the DOM, latest first, cloning the array to leave the original untouched
|
473
|
+
b=b.slice(0),b.sort(f);for(var k=0,l=b.length;k<l;++k)i[k]=g(b[k],j);
|
474
|
+
// Now that all the markers are in place and DOM manipulation over, adjust each range's boundaries to lie
|
475
|
+
// between its markers
|
476
|
+
for(k=l-1;k>=0;--k)e=b[k],h=a.DomRange.getRangeDocument(e),e.collapsed?e.collapseAfter(c(i[k].markerId,h)):(e.setEndBefore(c(i[k].endMarkerId,h)),e.setStartAfter(c(i[k].startMarkerId,h)));return i}function j(c){if(!a.isSelectionValid(c))return b.warn("Cannot save selection. This usually happens when the selection is collapsed and the selection document has lost focus."),null;var d=a.getSelection(c),e=d.getAllRanges(),f=1==e.length&&d.isBackward(),g=i(e,f);
|
477
|
+
// Ensure current selection is unaffected
|
478
|
+
return f?d.setSingleRange(e[0],f):d.setRanges(e),{win:c,rangeInfos:g,restored:!1}}function k(a){for(var b=[],c=a.length,d=c-1;d>=0;d--)b[d]=h(a[d],!0);return b}function l(b,c){if(!b.restored){var d=b.rangeInfos,e=a.getSelection(b.win),f=k(d),g=d.length;1==g&&c&&a.features.selectionHasExtend&&d[0].backward?(e.removeAllRanges(),e.addRange(f[0],!0)):e.setRanges(f),b.restored=!0}}function m(a,b){var d=c(b,a);d&&p(d)}function n(a){for(var b,c=a.rangeInfos,d=0,e=c.length;d<e;++d)b=c[d],b.collapsed?m(a.doc,b.markerId):(m(a.doc,b.startMarkerId),m(a.doc,b.endMarkerId))}var o=a.dom,p=o.removeNode,q=a.Selection.isDirectionBackward,r="\ufeff";a.util.extend(a,{saveRange:g,restoreRange:h,saveRanges:i,restoreRanges:k,saveSelection:j,restoreSelection:l,removeMarkerElement:m,removeMarkers:n})}),a},this);
|