📄 kupuhelpers.js
字号:
// now cut the chunk if (!startparent) { throw('Start offset out of range!'); }; if (!endparent) { throw('End offset out of range!'); }; var newrange = range.cloneRange(); newrange.setStart(startparent, startparentoffset); newrange.setEnd(endparent, endparentoffset); return newrange.extractContents(); }; this.getElementLength = function(element) { // XXX this should be a helper function var length = 0; var currnode = element.firstChild; while (currnode) { if (currnode.nodeType == 3) { // XXX should support CDATA as well length += currnode.nodeValue.length; }; currnode = currnode.nextSibling; }; return length; }; this.parentElement = function() { /* return the selected node (or the node containing the selection) */ // XXX this should be on a range object if (this.selection.rangeCount == 0) { var parent = this.document.getDocument().body; while (parent.firstChild) { parent = parent.firstChild; }; } else { var range = this.selection.getRangeAt(0); var parent = range.commonAncestorContainer; // the following deals with cases where only a single child is // selected, e.g. after a click on an image var inv = range.compareBoundaryPoints(Range.START_TO_END, range) < 0; var startNode = inv ? range.endContainer : range.startContainer; var startOffset = inv ? range.endOffset : range.startOffset; var endNode = inv ? range.startContainer : range.endContainer; var endOffset = inv ? range.startOffset : range.endOffset; var selectedChild = null; var child = parent.firstChild; while (child) { // XXX the additional conditions catch some invisible // intersections, but still not all of them if (range.intersectsNode(child) && !(child == startNode && startOffset == child.length) && !(child == endNode && endOffset == 0)) { if (selectedChild) { // current child is the second selected child found selectedChild = null; break; } else { // current child is the first selected child found selectedChild = child; }; } else if (selectedChild) { // current child is after the selection break; }; child = child.nextSibling; }; if (selectedChild) { parent = selectedChild; }; }; if (parent.nodeType == Node.TEXT_NODE) { parent = parent.parentNode; }; return parent; }; // deprecated alias of parentElement this.getSelectedNode = this.parentElement; this.moveStart = function(offset) { // XXX this should be on a range object var offsetparent = this.parentElement(); // the offset within the offsetparent var startoffset = this.startOffset(); var realoffset = offset + startoffset; if (realoffset >= 0) { var currnode = offsetparent.firstChild; var curroffset = 0; var startparent = null; var startoffset = 0; while (currnode) { if (currnode.nodeType == 3) { // XXX need to support CDATA sections var nodelength = currnode.nodeValue.length; if (curroffset + nodelength >= realoffset) { var range = this.selection.getRangeAt(0); //range.setEnd(this.endNode(), this.endOffset()); range.setStart(currnode, realoffset - curroffset); return; //this.selection.removeAllRanges(); //this.selection.addRange(range); }; }; currnode = currnode.nextSibling; }; // if we still haven't found the startparent we should walk to // all nodes following offsetparent as well var currnode = offsetparent.nextSibling; while (currnode) { if (currnode.nodeType == 3) { var nodelength = currnode.nodeValue.length; if (curroffset + nodelength >= realoffset) { var range = this.selection.getRangeAt(0); // XXX does IE switch the begin and end nodes here as well? var endnode = this.endNode(); var endoffset = this.endOffset(); range.setEnd(currnode, realoffset - curroffset); range.setStart(endnode, endoffset); return; }; curroffset += nodelength; }; currnode = currnode.nextSibling; }; throw('Offset out of document range'); } else if (realoffset < 0) { var currnode = offsetparent.prevSibling; var curroffset = 0; while (currnode) { if (currnode.nodeType == 3) { // XXX need to support CDATA sections var currlength = currnode.nodeValue.length; if (curroffset - currlength < realoffset) { var range = this.selection.getRangeAt(0); range.setStart(currnode, realoffset - curroffset); }; curroffset -= currlength; }; currnode = currnode.prevSibling; }; } else { var range = this.selection.getRangeAt(0); range.setStart(offsetparent, 0); //this.selection.removeAllRanges(); //this.selection.addRange(range); }; }; this.moveEnd = function(offset) { // XXX this should be on a range object }; this.reset = function() { this.selection = this.document.getWindow().getSelection(); }; this.cloneContents = function() { /* returns a document fragment with a copy of the contents */ var range = this.selection.getRangeAt(0); return range.cloneContents(); }; this.containsNode = function(node) { return this.selection.containsNode(node, true); } this.toString = function() { return this.selection.toString(); };};MozillaSelection.prototype = new BaseSelection;function IESelection(document) { this.document = document; this.selection = document.getDocument().selection; /* If no selection in editable document, IE returns selection from * main page, so force an inner selection. */ var doc = document.getDocument(); var range = this.selection.createRange() var parent = this.selection.type=="Text" ? range.parentElement() : this.selection.type=="Control" ? range.parentElement : null; if(parent && parent.ownerDocument != doc) { var range = doc.body.createTextRange(); range.collapse(); range.select(); } this.selectNodeContents = function(node) { /* select the contents of a node */ // a bit nasty, when moveToElementText is called it will move the selection start // to just before the element instead of inside it, and since IE doesn't reserve // an index for the element itself as well the way to get it inside the element is // by moving the start one pos and then moving it back (yuck!) var range = this.selection.createRange().duplicate(); range.moveToElementText(node); range.moveStart('character', 1); range.moveStart('character', -1); range.moveEnd('character', -1); range.moveEnd('character', 1); range.select(); this.selection = this.document.getDocument().selection; }; this.collapse = function(collapseToEnd) { var range = this.selection.createRange(); range.collapse(!collapseToEnd); range.select(); this.selection = document.getDocument().selection; }; this.replaceWithNode = function(newnode, selectAfterPlace) { /* replaces the current selection with a new node returns a reference to the inserted node newnode is the node to replace the content with, selectAfterPlace can either be a DOM node that should be selected after the new node was placed, or some value that resolves to true to select the placed node */ // XXX one big hack!! // XXX this method hasn't been optimized *at all* but can probably // be made a hell of a lot faster, however for now it's complicated // enough the way it is and I want to have it stable first if (this.selection.type == 'Control') { var range = this.selection.createRange(); range.item(0).parentNode.replaceChild(newnode, range.item(0)); for (var i=1; i < range.length; i++) { range.item(i).parentNode.removeChild(range[i]); }; if (selectAfterPlace) { var range = this.document.getDocument().body.createTextRange(); range.moveToElementText(newnode); range.select(); }; } else { var selrange = this.selection.createRange(); var startpoint = selrange.duplicate(); startpoint.collapse(); var endpoint = selrange.duplicate(); endpoint.collapse(false); var parent = selrange.parentElement(); if (parent.tagName=='IMG') parent=parent.parentElement; var elrange = selrange.duplicate(); elrange.moveToElementText(parent); // now find the start parent and offset var startoffset = this.startOffset(); var endoffset = this.endOffset(); // copy parent to contain new nodes, don't copy its children (false arg) var newparent = this.document.getDocument().createElement('span'); // also make a temp node to copy some temp nodes into later var tempparent = newparent.cloneNode(false); // this is awful, it is a hybrid DOM/copy'n'paste solution // first it gets the chunk of data before the selection and // pastes that (as a string) into the new parent, then it appendChilds // the new node and then it pastes the stuff behind the selection // to a temp node (there's no string paste method to append) and // copies the contents of that to the new node using appendChild... // first the first bit, straightforward string pasting var temprange = elrange.duplicate(); temprange.moveToElementText(parent); temprange.collapse(); temprange.moveEnd('character', startoffset); if (temprange.isEqual(elrange)) { // cursor was on the last position in the parent while (parent.hasChildNodes()) { newparent.appendChild(parent.firstChild); }; } else { // using htmlText here should fix markup problems (opening tags without closing ones etc.) newparent.insertAdjacentHTML('afterBegin', temprange.htmlText); }; // now some straightforward appendChilding the new node newparent.appendChild(newnode); // getting the rest of the elements behind the selection can only be // done using htmlText (afaik) so we end up with a string, which we // can not just use to attach to the new node (innerHTML would // overwrite the content) so we use set it as the innerHTML of the // temp node and after that's done appendChild all the child elements // of the temp node to the new parent temprange.moveToElementText(parent); temprange.collapse(false); temprange.moveStart('character', -endoffset); if (temprange.isEqual(elrange)) { // cursor was on position 0 of the parent while (parent.hasChildNodes()) { tempparent.appendChild(parent.firstChild); }; } else if (endoffset > 0) { tempparent.insertAdjacentHTML('afterBegin', temprange.htmlText); }; while (tempparent.hasChildNodes()) { newparent.appendChild(tempparent.firstChild); }; // so now we have the result in newparent, replace the old parent in // the document and we're done //parent.parentNode.replaceChild(newparent, parent); while (parent.hasChildNodes()) { parent.removeChild(parent.firstChild); }; while (newparent.hasChildNodes()) { var child = newparent.firstChild; parent.appendChild(newparent.firstChild); };
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -