2017-04-15 01:34:36 +03:00

167 lines
5.2 KiB
JavaScript
Executable File

(function() {
var exports = this, Bookmark;
Bookmark = function(env, range, keepOldBookmarks) {
this.env = env;
this.element = env.element;
this.selection = this.env.selection;
// Remove all bookmarks?
if (!keepOldBookmarks) {
this.removeBookmarks(this.element);
}
var currRange = range || this.selection.getRangeAt(0);
range = currRange.cloneRange();
var startContainer = range.startContainer;
var endContainer = range.endContainer;
var startOffset = range.startOffset;
var endOffset = range.endOffset;
var tmp;
// Collapse to the end of range.
range.collapse(false);
var endBookmark = this.env.document.createElement('span');
endBookmark.style.display = 'none';
ice.dom.setHtml(endBookmark, ' ');
ice.dom.addClass(endBookmark, 'iceBookmark iceBookmark_end');
endBookmark.setAttribute('iceBookmark', 'end');
range.insertNode(endBookmark);
if(!ice.dom.isChildOf(endBookmark, this.element)) {
this.element.appendChild(endBookmark);
}
// Move the range to where it was before.
range.setStart(startContainer, startOffset);
range.collapse(true);
// Create the start bookmark.
var startBookmark = this.env.document.createElement('span');
startBookmark.style.display = 'none';
ice.dom.addClass(startBookmark, 'iceBookmark iceBookmark_start');
ice.dom.setHtml(startBookmark, ' ');
startBookmark.setAttribute('iceBookmark', 'start');
try {
range.insertNode(startBookmark);
// Make sure start and end are in correct position.
if (startBookmark.previousSibling === endBookmark) {
// Reverse..
tmp = startBookmark;
startBookmark = endBookmark;
endBookmark = tmp;
}
} catch (e) {
// NS_ERROR_UNEXPECTED: I believe this is a Firefox bug.
// It seems like if the range is collapsed and the text node is empty
// (i.e. length = 0) then Firefox tries to split the node for no reason and fails...
ice.dom.insertBefore(endBookmark, startBookmark);
}
if (ice.dom.isChildOf(startBookmark, this.element) === false) {
if (this.element.firstChild) {
ice.dom.insertBefore(this.element.firstChild, startBookmark);
} else {
// Should not happen...
this.element.appendChild(startBookmark);
}
}
if (!endBookmark.previousSibling) {
tmp = this.env.document.createTextNode('');
ice.dom.insertBefore(endBookmark, tmp);
}
// The original range object must be changed.
if (!startBookmark.nextSibling) {
tmp = this.env.document.createTextNode('');
ice.dom.insertAfter(startBookmark, tmp);
}
currRange.setStart(startBookmark.nextSibling, 0);
currRange.setEnd(endBookmark.previousSibling, (endBookmark.previousSibling.length || 0));
this.start = startBookmark;
this.end = endBookmark;
};
Bookmark.prototype = {
selectBookmark: function() {
var range = this.selection.getRangeAt(0);
var startPos = null;
var endPos = null;
var startOffset = 0;
var endOffset = null;
if (this.start.nextSibling === this.end || ice.dom.getElementsBetween(this.start, this.end).length === 0) {
// Bookmark is collapsed.
if (this.end.nextSibling) {
startPos = ice.dom.getFirstChild(this.end.nextSibling);
} else if (this.start.previousSibling) {
startPos = ice.dom.getFirstChild(this.start.previousSibling);
if (startPos.nodeType === ice.dom.TEXT_NODE) {
startOffset = startPos.length;
}
} else {
// Create a text node in parent.
this.end.parentNode.appendChild(this.env.document.createTextNode(''));
startPos = ice.dom.getFirstChild(this.end.nextSibling);
}
} else {
if (this.start.nextSibling) {
startPos = ice.dom.getFirstChild(this.start.nextSibling);
} else {
if (!this.start.previousSibling) {
var tmp = this.env.document.createTextNode('');
ice.dom.insertBefore(this.start, tmp);
}
startPos = ice.dom.getLastChild(this.start.previousSibling);
startOffset = startPos.length;
}
if (this.end.previousSibling) {
endPos = ice.dom.getLastChild(this.end.previousSibling);
} else {
endPos = ice.dom.getFirstChild(this.end.nextSibling || this.end);
endOffset = 0;
}
}
ice.dom.remove([this.start, this.end]);
if (endPos === null) {
range.setEnd(startPos, startOffset);
range.collapse(false);
} else {
range.setStart(startPos, startOffset);
if (endOffset === null) {
endOffset = (endPos.length || 0);
}
range.setEnd(endPos, endOffset);
}
try {
this.selection.addRange(range);
} catch (e) {
// IE may throw exception for hidden elements..
}
},
getBookmark: function(parent, type) {
var elem = ice.dom.getClass('iceBookmark_' + type, parent)[0];
return elem;
},
removeBookmarks: function(elem) {
ice.dom.remove(ice.dom.getClass('iceBookmark', elem, 'span'));
}
};
exports.Bookmark = Bookmark;
}).call(this.ice);