jquery.syntax.editor.js
3.62 KB
// This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
Syntax.Editor=function(a,c){this.container=a;this.current=this.getLines()};Syntax.Editor.prototype.getLines=function(){for(var a=this.container.childNodes,c=[],b=[],d="",f=0,g=0;g<a.length;g+=1){var h=Syntax.innerText([a[g]]).split("\n");if(1<h.length){h[0]=d+h[0];for(var d=h.pop(),e=0;e<h.length;e+=1)b.push(f-c.length),c.push(h[e]);f=g+1}else d+=h[0]}""!=d?(b.push(f-c.length),c.push(d)):f-=1;b.push(f);console.log("getLines",b,c,a);return{lines:c,offsets:b}};
Syntax.Editor.prototype.updateChangedLines=function(){for(var a={},c=this.getLines(),b=0,d=0;b<this.current.lines.length&&d<c.lines.length;)if(this.current.lines[b]==c.lines[d])b+=1,d+=1;else break;a.start=d;b=this.current.lines.length;for(d=c.lines.length;b>a.start&&d>a.start;)if(this.current.lines[b-1]==c.lines[d-1])b-=1,d-=1;else break;a.end=d;a.originalEnd=b;for(a.difference=c.lines.length-this.current.lines.length;0<a.start&&c.offsets[a.start]!=c.offsets[a.start-1];)a.start-=1;if(0<a.difference)for(;a.end<
c.lines.length-1&&c.offsets[a.end-1]!=c.offsets[a.end];)a.end+=1,a.originalEnd+=1;this.current=c;return this.changed=a};Syntax.Editor.prototype.textForLines=function(a,c){return this.current.lines.slice(a,c).join("\n")+"\n"};
Syntax.Editor.prototype.updateLines=function(a,c){if(a.start!=a.end){var b=a.start,d=a.end,b=b+this.current.offsets[b],d=d+this.current.offsets[d],b=Array.prototype.slice.call(this.container.childNodes,b,d);$(b).replaceWith(c)}else 0==a.start?$(this.container).prepend(c):(b=a.start,b+=this.current.offsets[b],$(this.container.childNodes[b]).after(c))};
Syntax.Editor.getCharacterOffset=function(a){var c=0;if("undefined"!=typeof window.getSelection){var c=window.getSelection().getRangeAt(0),b=c.cloneRange();b.selectNodeContents(a);b.setEnd(c.endContainer,c.endOffset);c=b.toString().length}else"undefined"!=typeof document.selection&&"Control"!=document.selection.type&&(c=document.selection.createRange(),b=document.body.createTextRange(),b.moveToElementText(a),b.setEndPoint("EndToEnd",c),c=b.text.length);return c};
Syntax.Editor.getNodesForCharacterOffsets=function(a,c){for(var b=document.createTreeWalker(c,NodeFilter.SHOW_TEXT,function(a){return NodeFilter.FILTER_ACCEPT},!1),d=[],f=0,g=0;g<a.length&&b.nextNode();){for(var h=f+b.currentNode.length;g<a.length&&a[g]<h;)d.push([b.currentNode,f,h]),g+=1;f=h}return d};
Syntax.Editor.prototype.getClientState=function(){var a={},c=window.getSelection();0<c.rangeCount&&(a.range=c.getRangeAt(0));a.range&&(a.startOffset=Syntax.Editor.getCharacterOffset(this.container));return a};
Syntax.Editor.prototype.setClientState=function(a){if(a.startOffset){var c=Syntax.Editor.getNodesForCharacterOffsets([a.startOffset],this.container),b=document.createRange();b.setStart(c[0][0],a.startOffset-c[0][1]);b.setEnd(c[0][0],a.startOffset-c[0][1]);a=window.getSelection();a.removeAllRanges();a.addRange(b)}};
Syntax.layouts.editor=function(a,c){var b=jQuery('<div class="editor syntax highlighted" contentEditable="true">');b.append(c.children());var d=new Syntax.Editor(b.get(0)),f=function(b){var c=d.getClientState(),e=d.updateChangedLines();0>e.difference&&0<e.start&&(e.start-=1);b=d.textForLines(e.start,e.end);e.start==e.end?d.updateLines(e,[]):Syntax.highlightText(b,a,function(a){d.updateLines(e,a.children().get());d.setClientState(c)})};b.bind("keyup",function(){f()});b.bind("paste",function(a){f()});
b.bind("keydown",function(a){9==a.keyCode?(a.preventDefault(),document.execCommand("insertHTML",!1," ")):13==a.keyCode&&(a.preventDefault(),document.execCommand("insertHTML",!1,"\n"))});return jQuery('<div class="syntax-container">').append(b)};