vendor/assets/javascripts/aloha/lib/aloha/ierange-m2.js in locomotive-aloha-rails-0.20.1.5 vs vendor/assets/javascripts/aloha/lib/aloha/ierange-m2.js in locomotive-aloha-rails-0.23.2.1

- old
+ new

@@ -1,546 +1,29 @@ -/*! - * This file is part of Aloha Editor - * Author & Copyright (c) 2010 Gentics Software GmbH, aloha@gentics.com - * Licensed unter the terms of http://www.aloha-editor.com/license.html +/* ierange-m2.js is part of Aloha Editor project http://aloha-editor.org + * + * Aloha Editor is a WYSIWYG HTML5 inline editing library and editor. + * Copyright (c) 2010-2012 Gentics Software GmbH, Vienna, Austria. + * Contributors http://aloha-editor.org/contribution.php + * + * Aloha Editor is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * Aloha Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * As an additional permission to the GNU GPL version 2, you may distribute + * non-source (e.g., minimized or compacted) forms of the Aloha-Editor + * source code without the copy of the GNU GPL normally required, + * provided you include this license notice and a URL through which + * recipients can access the Corresponding Source. */ -(function(window, undefined) { - - var - jQuery = window.alohaQuery || window.jQuery, $ = jQuery, -// GENTICS = window.GENTICS, -// Aloha = window.Aloha, - DOMUtils, TextRangeUtils, selection, DOMRange, RangeIterator, DOMSelection; - -/* - * Only execute the following code if we are in IE (check for - * document.attachEvent, this is a microsoft event and therefore only available - * in IE). - */ - -if(document.attachEvent && document.selection) { -/*! -* DOM Ranges for Internet Explorer (m2) -* -* Copyright (c) 2009 Tim Cameron Ryan -* Released under the MIT/X License -* available at http://code.google.com/p/ierange/ -*/ - - /* - Range reference: - http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html - http://mxr.mozilla.org/mozilla-central/source/content/base/src/nsRange.cpp - https://developer.mozilla.org/En/DOM:Range - Selection reference: - http://trac.webkit.org/browser/trunk/WebCore/page/DOMSelection.cpp - TextRange reference: - http://msdn.microsoft.com/en-us/library/ms535872.aspx - Other links: - http://jorgenhorstink.nl/test/javascript/range/range.js - http://jorgenhorstink.nl/2006/07/05/dom-range-implementation-in-ecmascript-completed/ - http://dylanschiemann.com/articles/dom2Range/dom2RangeExamples.html - */ - - //[TODO] better exception support - - - /* - DOM functions - */ - - DOMUtils = { - findChildPosition: function (node) { - for (var i = 0; node = node.previousSibling; i++) - continue; - return i; - }, - isDataNode: function (node) { - return node && node.nodeValue !== null && node.data !== null; - }, - isAncestorOf: function (parent, node) { - return !DOMUtils.isDataNode(parent) && - (parent.contains(DOMUtils.isDataNode(node) ? node.parentNode : node) || - node.parentNode == parent); - }, - isAncestorOrSelf: function (root, node) { - return DOMUtils.isAncestorOf(root, node) || root == node; - }, - findClosestAncestor: function (root, node) { - if (DOMUtils.isAncestorOf(root, node)) - while (node && node.parentNode != root) - node = node.parentNode; - return node; - }, - getNodeLength: function (node) { - return DOMUtils.isDataNode(node) ? node.length : node.childNodes.length; - }, - splitDataNode: function (node, offset) { - if (!DOMUtils.isDataNode(node)) - return false; - var newNode = node.cloneNode(false); - node.deleteData(offset, node.length); - newNode.deleteData(0, offset); - node.parentNode.insertBefore(newNode, node.nextSibling); - } - }; - - /* - Text Range utilities - functions to simplify text range manipulation in ie - */ - - TextRangeUtils = { - convertToDOMRange: function (textRange, document) { - var domRange,adoptBoundary; - - adoptBoundary = function(domRange, textRange, bStart) { - // iterate backwards through parent element to find anchor location - var cursorNode = document.createElement('a'), - cursor = textRange.duplicate(), - parent; - - cursor.collapse(bStart); - parent = cursor.parentElement(); - do { - parent.insertBefore(cursorNode, cursorNode.previousSibling); - cursor.moveToElementText(cursorNode); - } while (cursor.compareEndPoints(bStart ? 'StartToStart' : 'StartToEnd', textRange) > 0 && cursorNode.previousSibling); - - // when we exceed or meet the cursor, we've found the node - if (cursor.compareEndPoints(bStart ? 'StartToStart' : 'StartToEnd', textRange) == -1 && cursorNode.nextSibling) { - // data node - cursor.setEndPoint(bStart ? 'EndToStart' : 'EndToEnd', textRange); - domRange[bStart ? 'setStart' : 'setEnd'](cursorNode.nextSibling, cursor.text.length); - } else { - // element - domRange[bStart ? 'setStartBefore' : 'setEndBefore'](cursorNode); - } - cursorNode.parentNode.removeChild(cursorNode); - }; - - // return a DOM range - domRange = new DOMRange(document); - adoptBoundary(domRange, textRange, true); - adoptBoundary(domRange, textRange, false); - return domRange; - }, - - convertFromDOMRange: function (domRange) { - function adoptEndPoint(textRange, domRange, bStart) { - // find anchor node and offset - var container = domRange[bStart ? 'startContainer' : 'endContainer'], - offset = domRange[bStart ? 'startOffset' : 'endOffset'], textOffset = 0, - anchorNode = DOMUtils.isDataNode(container) ? container : container.childNodes[offset], - anchorParent = DOMUtils.isDataNode(container) ? container.parentNode : container, - cursorNode, cursor; - - // visible data nodes need a text offset - if (container.nodeType == 3 || container.nodeType == 4) { - textOffset = offset; - } - - // create a cursor element node to position range (since we can't select text nodes) - cursorNode = domRange._document.createElement('a'); - anchorParent.insertBefore(cursorNode, anchorNode); - cursor = domRange._document.body.createTextRange(); - cursor.moveToElementText(cursorNode); - cursorNode.parentNode.removeChild(cursorNode); - // move range - textRange.setEndPoint(bStart ? 'StartToStart' : 'EndToStart', cursor); - textRange[bStart ? 'moveStart' : 'moveEnd']('character', textOffset); - } - - // return an IE text range - var textRange = domRange._document.body.createTextRange(); - adoptEndPoint(textRange, domRange, true); - adoptEndPoint(textRange, domRange, false); - return textRange; - } - }; - - /* - DOM Range - */ - DOMRange = function(document) { - // save document parameter - this._document = document; - - // initialize range - //[TODO] this should be located at document[0], document[0] - this.startContainer = this.endContainer = document.body; - this.endOffset = DOMUtils.getNodeLength(document.body); - }; - - DOMRange.START_TO_START = 0; - DOMRange.START_TO_END = 1; - DOMRange.END_TO_END = 2; - DOMRange.END_TO_START = 3; - - DOMRange.prototype = { - // public properties - startContainer: null, - startOffset: 0, - endContainer: null, - endOffset: 0, - commonAncestorContainer: null, - collapsed: false, - // private properties - _document: null, - - // private methods - _refreshProperties: function () { - // collapsed attribute - this.collapsed = (this.startContainer == this.endContainer && this.startOffset == this.endOffset); - // find common ancestor - var node = this.startContainer; - while (node && node != this.endContainer && !DOMUtils.isAncestorOf(node, this.endContainer)) - node = node.parentNode; - this.commonAncestorContainer = node; - }, - - // range methods - //[TODO] collapse if start is after end, end is before start - setStart: function(container, offset) { - this.startContainer = container; - this.startOffset = offset; - this._refreshProperties(); - }, - setEnd: function(container, offset) { - this.endContainer = container; - this.endOffset = offset; - this._refreshProperties(); - }, - setStartBefore: function (refNode) { - // set start to beore this node - this.setStart(refNode.parentNode, DOMUtils.findChildPosition(refNode)); - }, - setStartAfter: function (refNode) { - // select next sibling - this.setStart(refNode.parentNode, DOMUtils.findChildPosition(refNode) + 1); - }, - setEndBefore: function (refNode) { - // set end to beore this node - this.setEnd(refNode.parentNode, DOMUtils.findChildPosition(refNode)); - }, - setEndAfter: function (refNode) { - // select next sibling - this.setEnd(refNode.parentNode, DOMUtils.findChildPosition(refNode) + 1); - }, - selectNode: function (refNode) { - this.setStartBefore(refNode); - this.setEndAfter(refNode); - }, - selectNodeContents: function (refNode) { - this.setStart(refNode, 0); - this.setEnd(refNode, DOMUtils.getNodeLength(refNode)); - }, - collapse: function (toStart) { - if (toStart) - this.setEnd(this.startContainer, this.startOffset); - else - this.setStart(this.endContainer, this.endOffset); - }, - - // editing methods - cloneContents: function () { - // clone subtree - return (function cloneSubtree(iterator) { - for (var node, frag = document.createDocumentFragment(); node = iterator.next(); ) { - node = node.cloneNode(!iterator.hasPartialSubtree()); - if (iterator.hasPartialSubtree()) - node.appendChild(cloneSubtree(iterator.getSubtreeIterator())); - frag.appendChild(node); - } - return frag; - })(new RangeIterator(this)); - }, - extractContents: function () { - // cache range and move anchor points - var range = this.cloneRange(); - if (this.startContainer != this.commonAncestorContainer) - this.setStartAfter(DOMUtils.findClosestAncestor(this.commonAncestorContainer, this.startContainer)); - this.collapse(true); - // extract range - return (function extractSubtree(iterator) { - for (var node, frag = document.createDocumentFragment(); node = iterator.next(); ) { - if ( iterator.hasPartialSubtree() ) { - node = node.cloneNode(false); - } - else { - iterator.remove(); - } - if (iterator.hasPartialSubtree()) - node.appendChild(extractSubtree(iterator.getSubtreeIterator())); - frag.appendChild(node); - } - return frag; - })(new RangeIterator(range)); - }, - deleteContents: function () { - // cache range and move anchor points - var range = this.cloneRange(); - if (this.startContainer != this.commonAncestorContainer) - this.setStartAfter(DOMUtils.findClosestAncestor(this.commonAncestorContainer, this.startContainer)); - this.collapse(true); - // delete range - (function deleteSubtree(iterator) { - while (iterator.next()) { - if ( iterator.hasPartialSubtree() ) { - deleteSubtree(iterator.getSubtreeIterator()); - } - else { - iterator.remove(); - } - } - })(new RangeIterator(range)); - }, - insertNode: function (newNode) { - // set original anchor and insert node - if (DOMUtils.isDataNode(this.startContainer)) { - DOMUtils.splitDataNode(this.startContainer, this.startOffset); - this.startContainer.parentNode.insertBefore(newNode, this.startContainer.nextSibling); - } else { - this.startContainer.insertBefore(newNode, this.startContainer.childNodes[this.startOffset]); - } - // resync start anchor - this.setStart(this.startContainer, this.startOffset); - }, - surroundContents: function (newNode) { - // extract and surround contents - var content = this.extractContents(); - this.insertNode(newNode); - newNode.appendChild(content); - this.selectNode(newNode); - }, - - // other methods - compareBoundaryPoints: function (how, sourceRange) { - // get anchors - var containerA, offsetA, containerB, offsetB; - switch (how) { - case DOMRange.START_TO_START: - case DOMRange.START_TO_END: - containerA = this.startContainer; - offsetA = this.startOffset; - break; - case DOMRange.END_TO_END: - case DOMRange.END_TO_START: - containerA = this.endContainer; - offsetA = this.endOffset; - break; - } - switch (how) { - case DOMRange.START_TO_START: - case DOMRange.END_TO_START: - containerB = sourceRange.startContainer; - offsetB = sourceRange.startOffset; - break; - case DOMRange.START_TO_END: - case DOMRange.END_TO_END: - containerB = sourceRange.endContainer; - offsetB = sourceRange.endOffset; - break; - } - - // compare - return containerA.sourceIndex < containerB.sourceIndex ? -1 : - containerA.sourceIndex == containerB.sourceIndex ? - offsetA < offsetB ? -1 : offsetA == offsetB ? 0 : 1 - : 1; - }, - cloneRange: function () { - // return cloned range - var range = new DOMRange(this._document); - range.setStart(this.startContainer, this.startOffset); - range.setEnd(this.endContainer, this.endOffset); - return range; - }, - detach: function () { - //[TODO] Releases Range from use to improve performance. - }, - toString: function () { - return TextRangeUtils.convertFromDOMRange(this).text; - }, - createContextualFragment: function (tagString) { - // parse the tag string in a context node - var - content = (DOMUtils.isDataNode(this.startContainer) ? this.startContainer.parentNode : this.startContainer).cloneNode(false), - fragment; - - content.innerHTML = tagString; - // return a document fragment from the created node - for (fragment = this._document.createDocumentFragment(); content.firstChild; ) - fragment.appendChild(content.firstChild); - return fragment; - } - }; - - /* - Range iterator - */ - RangeIterator = function(range) { - this.range = range; - if (range.collapsed) { - return; - } - - //[TODO] ensure this works - // get anchors - var root = range.commonAncestorContainer; - this._next = range.startContainer == root && !DOMUtils.isDataNode(range.startContainer) ? - range.startContainer.childNodes[range.startOffset] : - DOMUtils.findClosestAncestor(root, range.startContainer); - this._end = range.endContainer == root && !DOMUtils.isDataNode(range.endContainer) ? - range.endContainer.childNodes[range.endOffset] : - DOMUtils.findClosestAncestor(root, range.endContainer).nextSibling; - }; - - RangeIterator.prototype = { - // public properties - range: null, - // private properties - _current: null, - _next: null, - _end: null, - - // public methods - hasNext: function () { - return !!this._next; - }, - next: function () { - // move to next node - var current = this._current = this._next; - this._next = this._current && this._current.nextSibling != this._end ? - this._current.nextSibling : null; - - // check for partial text nodes - if (DOMUtils.isDataNode(this._current)) { - if (this.range.endContainer == this._current) - (current = current.cloneNode(true)).deleteData(this.range.endOffset, current.length - this.range.endOffset); - if (this.range.startContainer == this._current) - (current = current.cloneNode(true)).deleteData(0, this.range.startOffset); - } - return current; - }, - remove: function () { - var end, start; - // check for partial text nodes - if (DOMUtils.isDataNode(this._current) && - (this.range.startContainer == this._current || this.range.endContainer == this._current)) { - start = this.range.startContainer == this._current ? this.range.startOffset : 0; - end = this.range.endContainer == this._current ? this.range.endOffset : this._current.length; - this._current.deleteData(start, end - start); - } else - this._current.parentNode.removeChild(this._current); - }, - hasPartialSubtree: function () { - // check if this node be partially selected - return !DOMUtils.isDataNode(this._current) && - (DOMUtils.isAncestorOrSelf(this._current, this.range.startContainer) || - DOMUtils.isAncestorOrSelf(this._current, this.range.endContainer)); - }, - getSubtreeIterator: function () { - // create a new range - var subRange = new DOMRange(this.range._document); - subRange.selectNodeContents(this._current); - // handle anchor points - if (DOMUtils.isAncestorOrSelf(this._current, this.range.startContainer)) - subRange.setStart(this.range.startContainer, this.range.startOffset); - if (DOMUtils.isAncestorOrSelf(this._current, this.range.endContainer)) - subRange.setEnd(this.range.endContainer, this.range.endOffset); - // return iterator - return new RangeIterator(subRange); - } - }; - - /* - DOM Selection - */ - - //[NOTE] This is a very shallow implementation of the Selection object, based on Webkit's - // implementation and without redundant features. Complete selection manipulation is still - // possible with just removeAllRanges/addRange/getRangeAt. - - DOMSelection = function (document) { - // save document parameter - this._document = document; - - // add DOM selection handler - var selection = this; - document.attachEvent('onselectionchange', function () { selection._selectionChangeHandler(); }); - }; - - DOMSelection.prototype = { - // public properties - rangeCount: 0, - // private properties - _document: null, - - // private methods - _selectionChangeHandler: function () { - // check if there exists a range - this.rangeCount = this._selectionExists(this._document.selection.createRange()) ? 1 : 0; - }, - _selectionExists: function (textRange) { - // checks if a created text range exists or is an editable cursor - return textRange.compareEndPoints('StartToEnd', textRange) !== 0 || - textRange.parentElement().isContentEditable; - }, - - // public methods - addRange: function (range) { - // add range or combine with existing range - var selection = this._document.selection.createRange(), textRange = TextRangeUtils.convertFromDOMRange(range); - if (!this._selectionExists(selection)) - { - // select range - textRange.select(); - } - else - { - // only modify range if it intersects with current range - if (textRange.compareEndPoints('StartToStart', selection) == -1) - if (textRange.compareEndPoints('StartToEnd', selection) > -1 && - textRange.compareEndPoints('EndToEnd', selection) == -1) - selection.setEndPoint('StartToStart', textRange); - else - if (textRange.compareEndPoints('EndToStart', selection) < 1 && - textRange.compareEndPoints('EndToEnd', selection) > -1) - selection.setEndPoint('EndToEnd', textRange); - selection.select(); - } - }, - removeAllRanges: function () { - // remove all ranges - this._document.selection.empty(); - }, - getRangeAt: function (index) { - // return any existing selection, or a cursor position in content editable mode - var textRange = this._document.selection.createRange(); - if (this._selectionExists(textRange)) - return TextRangeUtils.convertToDOMRange(textRange, this._document); - return null; - }, - toString: function () { - // get selection text - return this._document.selection.createRange().text; - } - }; - - /* - scripting hooks - */ - - document.createRange = function () { - return new DOMRange(document); - }; - - selection = new DOMSelection(document); - window.getSelection = function () { - return selection; - }; - - //[TODO] expose DOMRange/DOMSelection to window.? -} - -})(window); \ No newline at end of file +define(['vendor/ierange-m2'], function () { + 'use strict'; +});