Alice
view release on metacpan or search on metacpan
share/static/alice.js view on Meta::CPAN
},
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);
}
};
window.Range = (function() {
function Range(document) {
this._document = document;
this.startContainer = this.endContainer = document.body;
this.endOffset = DOMUtils.getNodeLength(document.body);
}
Range.START_TO_START = 0;
Range.START_TO_END = 1;
Range.END_TO_END = 2;
Range.END_TO_START = 3;
function findChildPosition(node) {
for (var i = 0; node = node.previousSibling; i++)
continue;
return i;
}
Range.prototype = {
startContainer: null,
startOffset: 0,
endContainer: null,
endOffset: 0,
commonAncestorContainer: null,
collapsed: false,
_document: null,
_toTextRange: function() {
function adoptEndPoint(textRange, domRange, bStart) {
var container = domRange[bStart ? 'startContainer' : 'endContainer'];
var offset = domRange[bStart ? 'startOffset' : 'endOffset'], textOffset = 0;
var anchorNode = DOMUtils.isDataNode(container) ? container : container.childNodes[offset];
var anchorParent = DOMUtils.isDataNode(container) ? container.parentNode : container;
if (container.nodeType == 3 || container.nodeType == 4)
textOffset = offset;
var cursorNode = domRange._document.createElement('a');
if (anchorNode)
anchorParent.insertBefore(cursorNode, anchorNode);
else
anchorParent.appendChild(cursorNode);
var cursor = domRange._document.body.createTextRange();
cursor.moveToElementText(cursorNode);
cursorNode.parentNode.removeChild(cursorNode);
textRange.setEndPoint(bStart ? 'StartToStart' : 'EndToStart', cursor);
textRange[bStart ? 'moveStart' : 'moveEnd']('character', textOffset);
}
var textRange = this._document.body.createTextRange();
adoptEndPoint(textRange, this, true);
adoptEndPoint(textRange, this, false);
return textRange;
},
_refreshProperties: function() {
this.collapsed = (this.startContainer == this.endContainer && this.startOffset == this.endOffset);
var node = this.startContainer;
while (node && node != this.endContainer && !DOMUtils.isAncestorOf(node, this.endContainer))
node = node.parentNode;
this.commonAncestorContainer = node;
},
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) {
this.setStart(refNode.parentNode, findChildPosition(refNode));
},
setStartAfter: function(refNode) {
this.setStart(refNode.parentNode, findChildPosition(refNode) + 1);
},
setEndBefore: function(refNode) {
this.setEnd(refNode.parentNode, findChildPosition(refNode));
},
setEndAfter: function(refNode) {
this.setEnd(refNode.parentNode, 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);
},
cloneContents: function() {
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()));
share/static/alice.js view on Meta::CPAN
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 = {
range: null,
_current: null,
_next: null,
_end: null,
hasNext: function() {
return !!this._next;
},
next: function() {
var current = this._current = this._next;
this._next = this._current && this._current.nextSibling != this._end ?
this._current.nextSibling : null;
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() {
if (DOMUtils.isDataNode(this._current) &&
(this.range.startContainer == this._current || this.range.endContainer == this._current)) {
var start = this.range.startContainer == this._current ? this.range.startOffset : 0;
var 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() {
return !DOMUtils.isDataNode(this._current) &&
(DOMUtils.isAncestorOrSelf(this._current, this.range.startContainer) ||
DOMUtils.isAncestorOrSelf(this._current, this.range.endContainer));
},
getSubtreeIterator: function() {
var subRange = new Range(this.range._document);
subRange.selectNodeContents(this._current);
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 new RangeIterator(subRange);
}
};
return Range;
})();
window.Range._fromTextRange = function(textRange, document) {
function adoptBoundary(domRange, textRange, bStart) {
var cursorNode = document.createElement('a'), cursor = textRange.duplicate();
cursor.collapse(bStart);
var parent = cursor.parentElement();
do {
parent.insertBefore(cursorNode, cursorNode.previousSibling);
cursor.moveToElementText(cursorNode);
} while (cursor.compareEndPoints(bStart ? 'StartToStart' : 'StartToEnd', textRange) > 0 && cursorNode.previousSibling);
if (cursor.compareEndPoints(bStart ? 'StartToStart' : 'StartToEnd', textRange) == -1 && cursorNode.nextSibling) {
cursor.setEndPoint(bStart ? 'EndToStart' : 'EndToEnd', textRange);
domRange[bStart ? 'setStart' : 'setEnd'](cursorNode.nextSibling, cursor.text.length);
} else {
domRange[bStart ? 'setStartBefore' : 'setEndBefore'](cursorNode);
}
cursorNode.parentNode.removeChild(cursorNode);
}
var domRange = new Range(document);
adoptBoundary(domRange, textRange, true);
adoptBoundary(domRange, textRange, false);
return domRange;
}
document.createRange = function() {
return new Range(document);
};
window.Selection = (function() {
function Selection(document) {
this._document = document;
var selection = this;
document.attachEvent('onselectionchange', function() {
selection._selectionChangeHandler();
});
}
Selection.prototype = {
rangeCount: 0,
_document: null,
_selectionChangeHandler: function() {
this.rangeCount = this._selectionExists(this._document.selection.createRange()) ? 1 : 0;
},
_selectionExists: function(textRange) {
return textRange.compareEndPoints('StartToEnd', textRange) != 0 ||
textRange.parentElement().isContentEditable;
},
addRange: function(range) {
var selection = this._document.selection.createRange(), textRange = range._toTextRange();
if (!this._selectionExists(selection)) {
textRange.select();
} else {
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() {
this._document.selection.empty();
},
getRangeAt: function(index) {
var textRange = this._document.selection.createRange();
if (this._selectionExists(textRange))
return Range._fromTextRange(textRange, this._document);
return null;
},
toString: function() {
return this._document.selection.createRange().text;
( run in 1.362 second using v1.01-cache-2.11-cpan-39bf76dae61 )