├── CNAME
├── favicon.ico
├── index.html
└── lib
├── codemirror.css
├── codemirror.js
├── codemirror.min.js
├── mergely.css
├── mergely.js
├── mergely.min.js
└── searchcursor.js
/CNAME:
--------------------------------------------------------------------------------
1 | diff.hust.cc
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aTool-org/diff-online/ff208644c24588c21da7dcf2fc018a464917d08e/favicon.ico
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 | Online File Diff and Mergely, Powered By aTool.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/lib/codemirror.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 |
3 | .CodeMirror {
4 | /* Set height, width, borders, and global font properties here */
5 | font-family: monospace;
6 | height: 300px;
7 | }
8 | .CodeMirror-scroll {
9 | /* Set scrolling behaviour here */
10 | overflow: auto;
11 | }
12 |
13 | /* PADDING */
14 |
15 | .CodeMirror-lines {
16 | padding: 4px 0; /* Vertical padding around content */
17 | }
18 | .CodeMirror pre {
19 | padding: 0 4px; /* Horizontal padding of content */
20 | }
21 |
22 | .CodeMirror-scrollbar-filler {
23 | background-color: white; /* The little square between H and V scrollbars */
24 | }
25 |
26 | /* GUTTER */
27 |
28 | .CodeMirror-gutters {
29 | border-right: 1px solid #ddd;
30 | background-color: #f7f7f7;
31 | }
32 | .CodeMirror-linenumbers {}
33 | .CodeMirror-linenumber {
34 | padding: 0 3px 0 5px;
35 | min-width: 20px;
36 | text-align: right;
37 | color: #999;
38 | }
39 |
40 | /* CURSOR */
41 |
42 | .CodeMirror div.CodeMirror-cursor {
43 | border-left: 1px solid black;
44 | }
45 | /* Shown when moving in bi-directional text */
46 | .CodeMirror div.CodeMirror-secondarycursor {
47 | border-left: 1px solid silver;
48 | }
49 | .CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
50 | width: auto;
51 | border: 0;
52 | background: transparent;
53 | background: rgba(0, 200, 0, .4);
54 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
55 | }
56 | /* Kludge to turn off filter in ie9+, which also accepts rgba */
57 | .CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor:not(#nonsense_id) {
58 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
59 | }
60 | /* Can style cursor different in overwrite (non-insert) mode */
61 | .CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
62 |
63 | /* DEFAULT THEME */
64 |
65 | .cm-s-default .cm-keyword {color: #708;}
66 | .cm-s-default .cm-atom {color: #219;}
67 | .cm-s-default .cm-number {color: #164;}
68 | .cm-s-default .cm-def {color: #00f;}
69 | .cm-s-default .cm-variable {color: black;}
70 | .cm-s-default .cm-variable-2 {color: #05a;}
71 | .cm-s-default .cm-variable-3 {color: #085;}
72 | .cm-s-default .cm-property {color: black;}
73 | .cm-s-default .cm-operator {color: black;}
74 | .cm-s-default .cm-comment {color: #a50;}
75 | .cm-s-default .cm-string {color: #a11;}
76 | .cm-s-default .cm-string-2 {color: #f50;}
77 | .cm-s-default .cm-meta {color: #555;}
78 | .cm-s-default .cm-error {color: #f00;}
79 | .cm-s-default .cm-qualifier {color: #555;}
80 | .cm-s-default .cm-builtin {color: #30a;}
81 | .cm-s-default .cm-bracket {color: #997;}
82 | .cm-s-default .cm-tag {color: #170;}
83 | .cm-s-default .cm-attribute {color: #00c;}
84 | .cm-s-default .cm-header {color: blue;}
85 | .cm-s-default .cm-quote {color: #090;}
86 | .cm-s-default .cm-hr {color: #999;}
87 | .cm-s-default .cm-link {color: #00c;}
88 |
89 | .cm-negative {color: #d44;}
90 | .cm-positive {color: #292;}
91 | .cm-header, .cm-strong {font-weight: bold;}
92 | .cm-em {font-style: italic;}
93 | .cm-emstrong {font-style: italic; font-weight: bold;}
94 | .cm-link {text-decoration: underline;}
95 |
96 | .cm-invalidchar {color: #f00;}
97 |
98 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
99 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
100 |
101 | /* STOP */
102 |
103 | /* The rest of this file contains styles related to the mechanics of
104 | the editor. You probably shouldn't touch them. */
105 |
106 | .CodeMirror {
107 | line-height: 1;
108 | position: relative;
109 | overflow: hidden;
110 | }
111 |
112 | .CodeMirror-scroll {
113 | /* 30px is the magic margin used to hide the element's real scrollbars */
114 | /* See overflow: hidden in .CodeMirror, and the paddings in .CodeMirror-sizer */
115 | margin-bottom: -30px; margin-right: -30px;
116 | padding-bottom: 30px; padding-right: 30px;
117 | height: 100%;
118 | outline: none; /* Prevent dragging from highlighting the element */
119 | position: relative;
120 | }
121 | .CodeMirror-sizer {
122 | position: relative;
123 | }
124 |
125 | /* The fake, visible scrollbars. Used to force redraw during scrolling
126 | before actuall scrolling happens, thus preventing shaking and
127 | flickering artifacts. */
128 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler {
129 | position: absolute;
130 | z-index: 6;
131 | display: none;
132 | }
133 | .CodeMirror-vscrollbar {
134 | right: 0; top: 0;
135 | overflow-x: hidden;
136 | overflow-y: scroll;
137 | }
138 | .CodeMirror-hscrollbar {
139 | bottom: 0; left: 0;
140 | overflow-y: hidden;
141 | overflow-x: scroll;
142 | }
143 | .CodeMirror-scrollbar-filler {
144 | right: 0; bottom: 0;
145 | z-index: 6;
146 | }
147 |
148 | .CodeMirror-gutters {
149 | position: absolute; left: 0; top: 0;
150 | height: 100%;
151 | padding-bottom: 30px;
152 | z-index: 3;
153 | }
154 | .CodeMirror-gutter {
155 | height: 100%;
156 | display: inline-block;
157 | /* Hack to make IE7 behave */
158 | *zoom:1;
159 | *display:inline;
160 | }
161 | .CodeMirror-gutter-elt {
162 | position: absolute;
163 | cursor: default;
164 | z-index: 4;
165 | }
166 |
167 | .CodeMirror-lines {
168 | cursor: text;
169 | }
170 | .CodeMirror pre {
171 | /* Reset some styles that the rest of the page might have set */
172 | -moz-border-radius: 0; -webkit-border-radius: 0; -o-border-radius: 0; border-radius: 0;
173 | border-width: 0;
174 | background: transparent;
175 | font-family: inherit;
176 | font-size: inherit;
177 | margin: 0;
178 | white-space: pre;
179 | word-wrap: normal;
180 | line-height: inherit;
181 | color: inherit;
182 | z-index: 2;
183 | position: relative;
184 | overflow: visible;
185 | }
186 | .CodeMirror-wrap pre {
187 | word-wrap: break-word;
188 | white-space: pre-wrap;
189 | word-break: normal;
190 | }
191 | .CodeMirror-linebackground {
192 | position: absolute;
193 | left: 0; right: 0; top: 0; bottom: 0;
194 | z-index: 0;
195 | }
196 |
197 | .CodeMirror-linewidget {
198 | position: relative;
199 | z-index: 2;
200 | overflow: auto;
201 | }
202 |
203 | .CodeMirror-widget {
204 | display: inline-block;
205 | }
206 |
207 | .CodeMirror-wrap .CodeMirror-scroll {
208 | overflow-x: hidden;
209 | }
210 |
211 | .CodeMirror-measure {
212 | position: absolute;
213 | width: 100%; height: 0px;
214 | overflow: hidden;
215 | visibility: hidden;
216 | }
217 | .CodeMirror-measure pre { position: static; }
218 |
219 | .CodeMirror div.CodeMirror-cursor {
220 | position: absolute;
221 | visibility: hidden;
222 | border-right: none;
223 | width: 0;
224 | }
225 | .CodeMirror-focused div.CodeMirror-cursor {
226 | visibility: visible;
227 | }
228 |
229 | .CodeMirror-selected { background: #d9d9d9; }
230 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
231 |
232 | .cm-searching {
233 | background: #ffa;
234 | background: rgba(255, 255, 0, .4);
235 | }
236 |
237 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */
238 | .CodeMirror span { *vertical-align: text-bottom; }
239 |
240 | @media print {
241 | /* Hide the cursor when printing */
242 | .CodeMirror div.CodeMirror-cursor {
243 | visibility: hidden;
244 | }
245 | }
246 |
--------------------------------------------------------------------------------
/lib/codemirror.min.js:
--------------------------------------------------------------------------------
1 | window.CodeMirror=function(){"use strict";function w(a,c){if(!(this instanceof w))return new w(a,c);this.options=c=c||{};for(var d in Mc)!c.hasOwnProperty(d)&&Mc.hasOwnProperty(d)&&(c[d]=Mc[d]);I(c);var e="string"==typeof c.value?0:c.value.first,f=this.display=x(a,e);f.wrapper.CodeMirror=this,F(this),c.autofocus&&!o&&Db(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,focused:!1,suppressEdits:!1,pasteIncoming:!1,draggingText:!1,highlight:new De},D(this),c.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap");var g=c.value;"string"==typeof g&&(g=new Rd(c.value,c.mode)),vb(this,Vd)(this,g),b&&setTimeout(Ne(Cb,this,!0),20),Fb(this);var h;try{h=document.activeElement==f.input}catch(i){}h||c.autofocus&&!o?setTimeout(Ne(_b,this),20):ac(this),vb(this,function(){for(var a in Lc)Lc.propertyIsEnumerable(a)&&Lc[a](this,c[a],Oc);for(var b=0;bb.maxLineLength&&(b.maxLineLength=d,b.maxLine=a)})}function I(a){for(var b=!1,c=0;ca.scroller.clientWidth,f=d>a.scroller.clientHeight;f?(a.scrollbarV.style.display="block",a.scrollbarV.style.bottom=e?$e(a.measure)+"px":"0",a.scrollbarV.firstChild.style.height=d-a.scroller.clientHeight+a.scrollbarV.clientHeight+"px"):a.scrollbarV.style.display="",e?(a.scrollbarH.style.display="block",a.scrollbarH.style.right=f?$e(a.measure)+"px":"0",a.scrollbarH.firstChild.style.width=a.scroller.scrollWidth-a.scroller.clientWidth+a.scrollbarH.clientWidth+"px"):a.scrollbarH.style.display="",e&&f?(a.scrollbarFiller.style.display="block",a.scrollbarFiller.style.height=a.scrollbarFiller.style.width=$e(a.measure)+"px"):a.scrollbarFiller.style.display="",k&&0===$e(a.measure)&&(a.scrollbarV.style.minWidth=a.scrollbarH.style.minHeight=l?"18px":"12px")}function K(a,b,c){var d=a.scroller.scrollTop,e=a.wrapper.clientHeight;"number"==typeof c?d=c:c&&(d=c.top,e=c.bottom-c.top),d=Math.floor(d-db(a));var f=Math.ceil(d+e);return{from:_d(b,d),to:_d(b,f)}}function L(a){var b=a.display;if(b.alignWidgets||b.gutters.firstChild&&a.options.fixedGutter){for(var c=O(b)-b.scroller.scrollLeft+a.doc.scrollLeft,d=b.gutters.offsetWidth,e=c+"px",f=b.lineDiv.firstChild;f;f=f.nextSibling)if(f.alignable)for(var g=0,h=f.alignable;ge.showingFrom&&g.tom&&e.showingTo-m<20&&(m=Math.min(k,e.showingTo)),v)for(l=$d(pd(f,Wd(f,l)));k>m&&qd(f,Wd(f,m));)++m;var n=[{from:Math.max(e.showingFrom,f.first),to:Math.min(e.showingTo,k)}];if(n=n[0].from>=n[0].to?[]:S(n,b),v)for(var j=0;jo.from)){n.splice(j--,1);break}o.to=q}for(var r=0,j=0;jm&&(o.to=m),o.from>=o.to?n.splice(j--,1):r+=o.to-o.from}if(r==m-l&&l==e.showingFrom&&m==e.showingTo)return R(a),void 0;n.sort(function(a,b){return a.from-b.from});var s=document.activeElement;.7*(m-l)>r&&(e.lineDiv.style.display="none"),U(a,l,m,n,i),e.lineDiv.style.display="",document.activeElement!=s&&s.offsetHeight&&s.focus();var t=l!=e.showingFrom||m!=e.showingTo||e.lastSizeC!=e.wrapper.clientHeight;t&&(e.lastSizeC=e.wrapper.clientHeight),e.showingFrom=l,e.showingTo=m,_(a,100);for(var x,u=e.lineDiv.offsetTop,w=e.lineDiv.firstChild;w;w=w.nextSibling)if(w.lineObj){if(c){var y=w.offsetTop+w.offsetHeight;x=y-u,u=y}else{var z=We(w);x=z.bottom-z.top}var A=w.lineObj.height-x;if(2>x&&(x=qb(e)),A>.001||-.001>A){Zd(w.lineObj,x);var B=w.lineObj.widgets;if(B)for(var j=0;jm&&Q(a,[],d),!0}}function R(a){var b=a.display.viewOffset=ae(a,Wd(a.doc,a.display.showingFrom));a.display.mover.style.top=b+"px"}function S(a,b){for(var c=0,d=b.length||0;d>c;++c){for(var e=b[c],f=[],g=e.diff||0,h=0,i=a.length;i>h;++h){var j=a[h];e.to<=j.from&&e.diff?f.push({from:j.from+g,to:j.to+g}):e.to<=j.from||e.from>=j.to?f.push(j):(e.from>j.from&&f.push({from:j.from,to:e.from}),e.ton){for(;k.lineObj!=b;)k=l(k);i&&n>=f&&k.lineNumber&&Ve(k.lineNumber,N(a.options,n)),k=k.nextSibling}else{if(b.widgets)for(var r,p=0,q=k;q&&20>p;++p,q=q.nextSibling)if(q.lineObj==b&&/div/i.test(q.nodeName)){r=q;break}var s=V(a,b,n,g,r);if(s!=r)j.insertBefore(s,k);else{for(;k!=r;)k=l(k);k=k.nextSibling}s.lineObj=b}++n});k;)k=l(k)}function V(a,b,d,e,f){var j,g=Hd(a,b),h=b.gutterMarkers,i=a.display;if(!(a.options.lineNumbers||h||b.bgClass||b.wrapClass||b.widgets))return g;if(f){f.alignable=null;for(var n,k=!0,l=0,m=f.firstChild;m;m=n)if(n=m.nextSibling,/\bCodeMirror-linewidget\b/.test(m.className)){for(var o=0,p=!0;ob&&(b=0),e.appendChild(Se("div",null,"CodeMirror-selected","position: absolute; left: "+a+"px; top: "+b+"px; width: "+(null==c?f-a:c)+"px; height: "+(d-b)+"px"))}function i(b,d,e,i){function m(c){return kb(a,oc(b,c),"div",j)}var j=Wd(c,b),k=j.text.length,l=i?1/0:-1/0;return ff(be(j),d||0,null==e?k:e,function(a,b,c){var j=m("rtl"==c?b-1:a),n=m("rtl"==c?a:b-1),o=j.left,p=n.right;n.top-j.top>3&&(h(o,j.top,null,j.bottom),o=g,j.bottomo&&(o=g),h(o,n.top,p-o,n.bottom)}),l}var b=a.display,c=a.doc,d=a.doc.sel,e=document.createDocumentFragment(),f=b.lineSpace.offsetWidth,g=eb(a.display);if(d.from.line==d.to.line)i(d.from.line,d.from.ch,d.to.ch);else{for(var l,n,j=Wd(c,d.from.line),k=j,m=[d.from.line,d.from.ch];l=od(k);){var o=l.find();if(m.push(o.from.ch,o.to.line,o.to.ch),o.to.line==d.to.line){m.push(d.to.ch),n=!0;break}k=Wd(c,o.to.line)}if(n)for(var p=0;pq&&h(g,q,null,r)}}Ue(b.selectionDiv,e),b.selectionDiv.style.display=""}function $(a){var b=a.display;clearInterval(b.blinker);var c=!0;b.cursor.style.visibility=b.otherCursor.style.visibility="",b.blinker=setInterval(function(){b.cursor.offsetHeight&&(b.cursor.style.visibility=b.otherCursor.style.visibility=(c=!c)?"":"hidden")},a.options.cursorBlinkRate)}function _(a,b){a.doc.mode.startState&&a.doc.frontier=a.display.showingTo)){var f,c=+new Date+a.options.workTime,d=Tc(b.mode,cb(a,b.frontier)),e=[];b.iter(b.frontier,Math.min(b.first+b.size,a.display.showingTo+500),function(g){if(b.frontier>=a.display.showingFrom){var h=g.styles;g.styles=Cd(a,g,d);for(var i=!h||h.length!=g.styles.length,j=0;!i&&jc?(_(a,a.options.workDelay),!0):void 0}),e.length&&vb(a,function(){for(var a=0;ag;--f){if(f<=e.first)return e.first;var h=Wd(e,f-1);if(h.stateAfter)return f;var i=Ee(h.text,null,a.options.tabSize);(null==d||c>i)&&(d=f-1,c=i)}return d}function cb(a,b){var c=a.doc,d=a.display;if(!c.mode.startState)return!0;var e=bb(a,b),f=e>c.first&&Wd(c,e-1).stateAfter;return f=f?Tc(c.mode,f):Uc(c.mode),c.iter(e,b,function(g){Ed(a,g,f);var h=e==b-1||0==e%5||e>=d.showingFrom&&ee&&0==f&&(e=1)}return{left:c>f?g.right:g.left,right:f>c?g.left:g.right,top:g.top,bottom:g.bottom}}function gb(a,b){for(var c=a.display,d=a.display.measureLineCache,e=0;e100){for(var i=document.createDocumentFragment(),j=10,k=h.childNodes.length,l=0,m=Math.ceil(k/j);m>l;++l){for(var n=Se("div",null,null,"display: inline-block"),o=0;j>o&&k;++o)n.appendChild(h.firstChild),--k;i.appendChild(n)}h.appendChild(i)}Ue(f.measure,h);var p=We(f.lineDiv),q=[],r=Me(e.text.length),s=h.offsetHeight;d&&f.measure.first!=h&&Ue(f.measure,h);for(var t,l=0;lw||v>y)&&(v>=x&&y>=w||x>=v&&w>=y||Math.min(w,y)-Math.max(v,x)>=w-v>>1)){q[o]=Math.min(v,x),q[o+1]=Math.max(w,y);break}}o==q.length&&q.push(v,w);var z=u.right;t.measureRight&&(z=We(t.measureRight).left),r[l]={left:u.left-p.left,right:z-p.left,top:o}}for(var t,l=0;lh)return f(h,n);var q=n?m.to:m.from,r=n?m.from:m.to;if(q==h)p=l&&m.level<(o=g[l-1]).level?f(o.level%2?o.from:o.to-1,!0):f(n&&m.from!=m.to?h-1:h),n==k?i=p:j=p;else if(r==h){var o=lc)return mb(d.first,0,!0);var e=_d(d,c),f=d.first+d.size-1;if(e>f)return mb(d.first+d.size-1,Wd(d,f).text.length,!0);for(0>b&&(b=0);;){var g=Wd(d,e),h=ob(a,g,e,b,c),i=od(g),j=i&&i.find();if(!(i&&h.ch>=j.from.ch))return h;e=j.to.line}}function ob(a,b,c,d,e){function j(d){var e=lb(a,oc(c,d),"line",b,i);return g=!0,f>e.bottom?Math.max(0,e.left-h):fq)return mb(c,n,r);for(;;){if(k?n==m||n==nf(b,m,1):1>=n-m){for(var s=q-d>d-o,t=s?m:n;Re.test(b.text.charAt(t));)++t;var u=mb(c,t,s?p:r);return u.after=s,u}var v=Math.ceil(l/2),w=m+v;if(k){w=m;for(var x=0;v>x;++x)w=nf(b,w,1)}var y=j(w);y>d?(n=w,q=y,(r=g)&&(q+=1e3),l-=v):(m=w,o=y,p=g,l=v)}}function qb(a){if(null!=a.cachedTextHeight)return a.cachedTextHeight;if(null==pb){pb=Se("pre");for(var b=0;49>b;++b)pb.appendChild(document.createTextNode("x")),pb.appendChild(Se("br"));pb.appendChild(document.createTextNode("x"))}Ue(a.measure,pb);var c=pb.offsetHeight/50;return c>3&&(a.cachedTextHeight=c),Te(a.measure),c||1}function rb(a){if(null!=a.cachedCharWidth)return a.cachedCharWidth;var b=Se("span","x"),c=Se("pre",[b]);Ue(a.measure,c);var d=b.offsetWidth;return d>2&&(a.cachedCharWidth=d),d||10}function tb(a){a.curOp={changes:[],updateInput:null,userSelChange:null,textChanged:null,selectionChanged:!1,updateMaxLine:!1,updateScrollPos:!1,id:++sb},xe++||(we=[])}function ub(a){var b=a.curOp,c=a.doc,d=a.display;if(a.curOp=null,b.updateMaxLine&&H(a),d.maxLineChanged&&!a.options.lineWrapping){var e=gb(a,d.maxLine).width;d.sizer.style.minWidth=Math.max(0,e+3+Be)+"px",d.maxLineChanged=!1;var f=Math.max(0,d.sizer.offsetLeft+d.sizer.offsetWidth-d.scroller.clientWidth);fi&&d[i]==g[i];)++i;var k=f.from,l=f.to;i1e3?c.value=a.display.prevInput="":a.display.prevInput=g,h&&ub(a),a.state.pasteIncoming=!1,!0}function Cb(a,b){var c,d,e=a.doc;pc(e.sel.from,e.sel.to)?b&&(a.display.prevInput=a.display.input.value=""):(a.display.prevInput="",c=df&&(e.sel.to.line-e.sel.from.line>100||(d=a.getSelection()).length>1e3),a.display.input.value=c?"-":d||a.getSelection(),a.state.focused&&Ie(a.display.input)),a.display.inaccurateSelection=c}function Db(a){"nocursor"==a.options.readOnly||o&&document.activeElement==a.display.input||a.display.input.focus()}function Eb(a){return a.options.readOnly||a.doc.cantEdit}function Fb(a){function c(){a.state.focused&&setTimeout(Ne(Db,a),0)}function d(){b.cachedCharWidth=b.cachedTextHeight=null,ib(a),xb(a,Ne(yb,a))}function e(){for(var a=b.wrapper.parentNode;a&&a!=document.body;a=a.parentNode);a?setTimeout(e,5e3):ue(window,"resize",d)}function f(b){a.options.onDragEvent&&a.options.onDragEvent(a,ne(b))||qe(b)}function g(){b.inaccurateSelection&&(b.prevInput="",b.inaccurateSelection=!1,b.input.value=a.getSelection(),Ie(b.input))}var b=a.display;te(b.scroller,"mousedown",vb(a,Kb)),te(b.scroller,"dblclick",vb(a,oe)),te(b.lineSpace,"selectstart",function(a){Gb(b,a)||oe(a)}),t||te(b.scroller,"contextmenu",function(b){cc(a,b)}),te(b.scroller,"scroll",function(){Ob(a,b.scroller.scrollTop),Pb(a,b.scroller.scrollLeft,!0),ve(a,"scroll",a)}),te(b.scrollbarV,"scroll",function(){Ob(a,b.scrollbarV.scrollTop)}),te(b.scrollbarH,"scroll",function(){Pb(a,b.scrollbarH.scrollLeft)}),te(b.scroller,"mousewheel",function(b){Sb(a,b)}),te(b.scroller,"DOMMouseScroll",function(b){Sb(a,b)}),te(b.scrollbarH,"mousedown",c),te(b.scrollbarV,"mousedown",c),te(b.wrapper,"scroll",function(){b.wrapper.scrollTop=b.wrapper.scrollLeft=0}),te(window,"resize",d),setTimeout(e,5e3),te(b.input,"keyup",vb(a,function(b){a.options.onKeyEvent&&a.options.onKeyEvent(a,ne(b))||16==b.keyCode&&(a.doc.sel.shift=!1)})),te(b.input,"input",Ne(Ab,a)),te(b.input,"keydown",vb(a,Zb)),te(b.input,"keypress",vb(a,$b)),te(b.input,"focus",Ne(_b,a)),te(b.input,"blur",Ne(ac,a)),a.options.dragDrop&&(te(b.scroller,"dragstart",function(b){Nb(a,b)}),te(b.scroller,"dragenter",f),te(b.scroller,"dragover",f),te(b.scroller,"drop",vb(a,Lb))),te(b.scroller,"paste",function(c){Gb(b,c)||(Db(a),Ab(a))}),te(b.input,"paste",function(){a.state.pasteIncoming=!0,Ab(a)}),te(b.input,"cut",g),te(b.input,"copy",g),j&&te(b.sizer,"mouseup",function(){document.activeElement==b.input&&b.input.blur(),Db(a)})}function Gb(a,b){for(var c=re(b);c!=a.wrapper;c=c.parentNode){if(!c)return!0;if(/\bCodeMirror-(?:line)?widget\b/.test(c.className)||c.parentNode==a.sizer&&c!=a.mover)return!0}}function Hb(a,b,c){var d=a.display;if(!c){var e=re(b);if(e==d.scrollbarH||e==d.scrollbarH.firstChild||e==d.scrollbarV||e==d.scrollbarV.firstChild||e==d.scrollbarFiller)return null}var f,g,h=We(d.lineSpace);try{f=b.clientX,g=b.clientY}catch(b){return null}return nb(a,f-h.left,g-h.top)}function Kb(a){function p(a){if("single"==j)return wc(c.doc,tc(f,h),a),void 0;if(n=tc(f,n),o=tc(f,o),"double"==j){var b=Jc(Wd(f,a.line).text,a);qc(a,n)?wc(c.doc,b.from,o):wc(c.doc,n,b.to)}else"triple"==j&&(qc(a,n)?wc(c.doc,o,tc(f,oc(a.line,0))):wc(c.doc,n,tc(f,oc(a.line+1,0))))}function s(a){var b=++r,e=Hb(c,a,!0);if(e)if(pc(e,l)){var h=a.clientYq.bottom?20:0;h&&setTimeout(vb(c,function(){r==b&&(d.scroller.scrollTop+=h,s(a))}),50)}else{c.state.focused||_b(c),l=e,p(e);var g=K(d,f);(e.line>=g.to||e.linei-400&&pc(Jb.pos,h))j="triple",oe(a),setTimeout(Ne(Db,c),20),Kc(c,h.line);else if(Ib&&Ib.time>i-400&&pc(Ib.pos,h)){j="double",Jb={time:i,pos:h},oe(a);var k=Jc(Wd(f,h.line).text,h);wc(c.doc,k.from,k.to)}else Ib={time:i,pos:h};var l=h;if(c.options.dragDrop&&Xe&&!Eb(c)&&!pc(g.from,g.to)&&!qc(h,g.from)&&!qc(g.to,h)&&"single"==j){var m=vb(c,function(b){e&&(d.scroller.draggable=!1),c.state.draggingText=!1,ue(document,"mouseup",m),ue(d.scroller,"drop",m),Math.abs(a.clientX-b.clientX)+Math.abs(a.clientY-b.clientY)<10&&(oe(b),wc(c.doc,h),Db(c))});return e&&(d.scroller.draggable=!0),c.state.draggingText=m,d.scroller.dragDrop&&d.scroller.dragDrop(),te(document,"mouseup",m),te(d.scroller,"drop",m),void 0}oe(a),"single"==j&&wc(c.doc,tc(f,h));var n=g.from,o=g.to,q=We(d.wrapper),r=0,v=vb(c,function(a){b||se(a)?s(a):u(a)}),w=vb(c,u);te(document,"mousemove",v),te(document,"mouseup",w)}}function Lb(a){var b=this;if(!(Gb(b.display,a)||b.options.onDragEvent&&b.options.onDragEvent(b,ne(a)))){oe(a);var c=Hb(b,a,!0),d=a.dataTransfer.files;if(c&&!Eb(b))if(d&&d.length&&window.FileReader&&window.File)for(var e=d.length,f=Array(e),g=0,h=function(a,d){var h=new FileReader;h.onload=function(){f[d]=h.result,++g==e&&(c=tc(b.doc,c),nc(b.doc,f.join(""),c,"around","paste"))},h.readAsText(a)},i=0;e>i;++i)h(d[i],i);else{if(b.state.draggingText&&!qc(c,b.doc.sel.from)&&!qc(b.doc.sel.to,c))return b.state.draggingText(a),setTimeout(Ne(Db,b),20),void 0;try{var f=a.dataTransfer.getData("Text");if(f){var j=b.doc.sel.from,k=b.doc.sel.to;yc(b.doc,c,c),b.state.draggingText&&nc(b.doc,"",j,k,"paste"),b.replaceSelection(f,null,"paste"),Db(b),_b(b)}}catch(a){}}}}function Mb(a,b){var c=a.display;try{var d=b.clientX,e=b.clientY}catch(b){return!1}if(d>=Math.floor(We(c.gutters).right))return!1;if(oe(b),!Ae(a,"gutterClick"))return!0;var f=We(c.lineDiv);if(e>f.bottom)return!0;e-=f.top-c.viewOffset;for(var g=0;g=d){var i=_d(a.doc,e),j=a.options.gutters[g];ye(a,"gutterClick",a,i,j,b);break}}return!0}function Nb(a,b){if(!Gb(a.display,b)){var c=a.getSelection();if(b.dataTransfer.setData("Text",c),b.dataTransfer.setDragImage&&!i){var d=Se("img",null,null,"position: fixed; left: 0; top: 0;");h&&(d.width=d.height=1,a.display.wrapper.appendChild(d),d._top=d.offsetTop),b.dataTransfer.setDragImage(d,0,0),h&&d.parentNode.removeChild(d)}}}function Ob(b,c){Math.abs(b.doc.scrollTop-c)<2||(b.doc.scrollTop=c,a||P(b,[],c),b.display.scroller.scrollTop!=c&&(b.display.scroller.scrollTop=c),b.display.scrollbarV.scrollTop!=c&&(b.display.scrollbarV.scrollTop=c),a&&P(b,[]))}function Pb(a,b,c){(c?b==a.doc.scrollLeft:Math.abs(a.doc.scrollLeft-b)<2)||(b=Math.min(b,a.display.scroller.scrollWidth-a.display.scroller.clientWidth),a.doc.scrollLeft=b,L(a),a.display.scroller.scrollLeft!=b&&(a.display.scroller.scrollLeft=b),a.display.scrollbarH.scrollLeft!=b&&(a.display.scrollbarH.scrollLeft=b))}function Sb(b,c){var d=c.wheelDeltaX,f=c.wheelDeltaY;if(null==d&&c.detail&&c.axis==c.HORIZONTAL_AXIS&&(d=c.detail),null==f&&c.detail&&c.axis==c.VERTICAL_AXIS?f=c.detail:null==f&&(f=c.wheelDelta),f&&p&&e)for(var g=c.target;g!=j;g=g.parentNode)if(g.lineObj){b.display.currentWheelTarget=g;
2 | break}var i=b.display,j=i.scroller;if(d&&!a&&!h&&null!=Rb)return f&&Ob(b,Math.max(0,Math.min(j.scrollTop+f*Rb,j.scrollHeight-j.clientHeight))),Pb(b,Math.max(0,Math.min(j.scrollLeft+d*Rb,j.scrollWidth-j.clientWidth))),oe(c),i.wheelStartX=null,void 0;if(f&&null!=Rb){var k=f*Rb,l=b.doc.scrollTop,m=l+i.wrapper.clientHeight;0>k?l=Math.max(0,l+k-50):m=Math.min(b.doc.height,m+k+50),P(b,[],{top:l,bottom:m})}20>Qb&&(null==i.wheelStartX?(i.wheelStartX=j.scrollLeft,i.wheelStartY=j.scrollTop,i.wheelDX=d,i.wheelDY=f,setTimeout(function(){if(null!=i.wheelStartX){var a=j.scrollLeft-i.wheelStartX,b=j.scrollTop-i.wheelStartY,c=b&&i.wheelDY&&b/i.wheelDY||a&&i.wheelDX&&a/i.wheelDX;i.wheelStartX=i.wheelStartY=null,c&&(Rb=(Rb*Qb+c)/(Qb+1),++Qb)}},200)):(i.wheelDX+=d,i.wheelDY+=f))}function Tb(a,b,c){if("string"==typeof b&&(b=Vc[b],!b))return!1;a.display.pollingFast&&Bb(a)&&(a.display.pollingFast=!1);var d=a.doc,e=d.sel.shift,f=!1;try{Eb(a)&&(a.state.suppressEdits=!0),c&&(d.sel.shift=!1),f=b(a)!=Ce}finally{d.sel.shift=e,a.state.suppressEdits=!1}return f}function Ub(a){var b=a.state.keyMaps.slice(0);return b.push(a.options.keyMap),a.options.extraKeys&&b.unshift(a.options.extraKeys),b}function Wb(a,b){var c=Xc(a.options.keyMap),e=c.auto;clearTimeout(Vb),e&&!Zc(b)&&(Vb=setTimeout(function(){Xc(a.options.keyMap)==c&&(a.options.keyMap=e.call?e.call(null,a):e)},50));var f=$c(b,!0),g=!1;if(!f)return!1;var h=Ub(a);return g=b.shiftKey?Yc("Shift-"+f,h,function(b){return Tb(a,b,!0)})||Yc(f,h,function(b){return"string"==typeof b&&/^go[A-Z]/.test(b)?Tb(a,b):void 0}):Yc(f,h,function(b){return Tb(a,b)}),"stop"==g&&(g=!1),g&&(oe(b),$(a),d&&(b.oldKeyCode=b.keyCode,b.keyCode=0)),g}function Xb(a,b,c){var d=Yc("'"+c+"'",Ub(a),function(b){return Tb(a,b,!0)});return d&&(oe(b),$(a)),d}function Zb(a){var c=this;if(c.state.focused||_b(c),b&&27==a.keyCode&&(a.returnValue=!1),!c.options.onKeyEvent||!c.options.onKeyEvent(c,ne(a))){var d=a.keyCode;c.doc.sel.shift=16==d||a.shiftKey;var e=Wb(c,a);h&&(Yb=e?d:null,!e&&88==d&&!df&&(p?a.metaKey:a.ctrlKey)&&c.replaceSelection(""))}}function $b(a){var b=this;if(!b.options.onKeyEvent||!b.options.onKeyEvent(b,ne(a))){var c=a.keyCode,d=a.charCode;if(h&&c==Yb)return Yb=null,oe(a),void 0;if(!(h&&(!a.which||a.which<10)||j)||!Wb(b,a)){var e=String.fromCharCode(null==d?c:d);this.options.electricChars&&this.doc.mode.electricChars&&this.options.smartIndent&&!Eb(this)&&this.doc.mode.electricChars.indexOf(e)>-1&&setTimeout(vb(b,function(){Fc(b,b.doc.sel.to.line,"smart")}),75),Xb(b,a,e)||Ab(b)}}}function _b(a){"nocursor"!=a.options.readOnly&&(a.state.focused||(ve(a,"focus",a),a.state.focused=!0,-1==a.display.wrapper.className.search(/\bCodeMirror-focused\b/)&&(a.display.wrapper.className+=" CodeMirror-focused"),Cb(a,!0)),zb(a),$(a))}function ac(a){a.state.focused&&(ve(a,"blur",a),a.state.focused=!1,a.display.wrapper.className=a.display.wrapper.className.replace(" CodeMirror-focused","")),clearInterval(a.display.blinker),setTimeout(function(){a.state.focused||(a.doc.sel.shift=!1)},150)}function cc(a,c){function k(){if(e.inputDiv.style.position="relative",e.input.style.cssText=j,d&&(e.scrollbarV.scrollTop=e.scroller.scrollTop=i),zb(a),null!=e.input.selectionStart&&(!b||d)){clearTimeout(bc);var c=e.input.value=" "+(pc(f.from,f.to)?"":e.input.value),g=0;e.prevInput=" ",e.input.selectionStart=1,e.input.selectionEnd=c.length;var h=function(){" "==e.prevInput&&0==e.input.selectionStart?vb(a,Vc.selectAll)(a):g++<10?bc=setTimeout(h,500):Cb(a)};bc=setTimeout(h,200)}}var e=a.display,f=a.doc.sel;if(!Gb(e,c)){var g=Hb(a,c),i=e.scroller.scrollTop;if(g&&!h){(pc(f.from,f.to)||qc(g,f.from)||!qc(g,f.to))&&vb(a,yc)(a.doc,g,g);var j=e.input.style.cssText;if(e.inputDiv.style.position="absolute",e.input.style.cssText="position: fixed; width: 30px; height: 30px; top: "+(c.clientY-5)+"px; left: "+(c.clientX-5)+"px; z-index: 1000; background: white; outline: none;"+"border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opacity: .05; filter: alpha(opacity=5);",Db(a),Cb(a,!0),pc(f.from,f.to)&&(e.input.value=e.prevInput=" "),t){qe(c);var l=function(){ue(window,"mouseup",l),setTimeout(k,20)};te(window,"mouseup",l)}else setTimeout(k,50)}}}function dc(a){return oc(a.from.line+a.text.length-1,He(a.text).length+(1==a.text.length?a.from.ch:0))}function ec(a,b,c){if(!qc(b.from,c))return tc(a,c);var d=b.text.length-1-(b.to.line-b.from.line);if(c.line>b.to.line+d){var e=c.line-d,f=a.first+a.size-1;return e>f?oc(f,Wd(a,f).text.length):uc(c,Wd(a,e).text.length)}if(c.line==b.to.line+d)return uc(c,He(b.text).length+(1==b.text.length?b.from.ch:0)+Wd(a,b.to.line).text.length-b.to.ch);var g=c.line-b.from.line;return uc(c,b.text[g].length+(g?0:b.from.ch))}function fc(a,b,c){if(c&&"object"==typeof c)return{anchor:ec(a,b,c.anchor),head:ec(a,b,c.head)};if("start"==c)return{anchor:b.from,head:b.from};var d=dc(b);if("around"==c)return{anchor:b.from,head:d};if("end"==c)return{anchor:d,head:d};var e=function(a){if(qc(a,b.from))return a;if(!qc(b.to,a))return d;var c=a.line+b.text.length-(b.to.line-b.from.line)-1,e=a.ch;return a.line==b.to.line&&(e+=d.ch-b.to.ch),oc(c,e)};return{anchor:e(a.sel.anchor),head:e(a.sel.head)}}function gc(a,b){var c={canceled:!1,from:b.from,to:b.to,text:b.text,origin:b.origin,update:function(b,c,d,e){b&&(this.from=tc(a,b)),c&&(this.to=tc(a,c)),d&&(this.text=d),void 0!==e&&(this.origin=e)},cancel:function(){this.canceled=!0}};return ve(a,"beforeChange",a,c),a.cm&&ve(a.cm,"beforeChange",a.cm,c),c.canceled?null:{from:c.from,to:c.to,text:c.text,origin:c.origin}}function hc(a,b,c,d){if(a.cm){if(!a.cm.curOp)return vb(a.cm,hc)(a,b,c,d);if(a.cm.state.suppressEdits)return}if(!(Ae(a,"beforeChange")||a.cm&&Ae(a.cm,"beforeChange"))||(b=gc(a,b))){var e=u&&!d&&ld(a,b.from,b.to);if(e){for(var f=e.length-1;f>=1;--f)ic(a,{from:e[f].from,to:e[f].to,text:[""]});e.length&&ic(a,{from:e[0].from,to:e[0].to,text:b.text},c)}else ic(a,b,c)}}function ic(a,b,c){var d=fc(a,b,c);fe(a,b,d,a.cm?a.cm.curOp.id:0/0),lc(a,b,d,jd(a,b));var e=[];Ud(a,function(a,c){c||-1!=Je(e,a.history)||(le(a.history,b),e.push(a.history)),lc(a,b,null,jd(a,b))})}function jc(a,b){var c=a.history,d=("undo"==b?c.done:c.undone).pop();if(d){c.dirtyCounter+="undo"==b?-1:1;var e={changes:[],anchorBefore:d.anchorAfter,headBefore:d.headAfter,anchorAfter:d.anchorBefore,headAfter:d.headBefore};("undo"==b?c.undone:c.done).push(e);for(var f=d.changes.length-1;f>=0;--f){var g=d.changes[f];g.origin=b,e.changes.push(ee(a,g));var h=f?fc(a,g,null):{anchor:d.anchorBefore,head:d.headBefore};lc(a,g,h,kd(a,g));var i=[];Ud(a,function(a,b){b||-1!=Je(i,a.history)||(le(a.history,g),i.push(a.history)),lc(a,g,null,kd(a,g))})}}}function kc(a,b){function c(a){return oc(a.line+b,a.ch)}a.first+=b,a.cm&&yb(a.cm,a.first,a.first,b),a.sel.head=c(a.sel.head),a.sel.anchor=c(a.sel.anchor),a.sel.from=c(a.sel.from),a.sel.to=c(a.sel.to)}function lc(a,b,c,d){if(a.cm&&!a.cm.curOp)return vb(a.cm,lc)(a,b,c,d);if(b.to.linea.lastLine())){if(b.from.linef&&(b={from:b.from,to:oc(f,Wd(a,f).text.length),text:[b.text[0]],origin:b.origin}),c||(c=fc(a,b,null)),a.cm?mc(a.cm,b,d,c):Nd(a,b,d,c)}}function mc(a,b,c,d){var e=a.doc,f=a.display,g=b.from,h=b.to,i=!1,j=g.line;a.options.lineWrapping||(j=$d(pd(e,Wd(e,g.line))),e.iter(j,h.line+1,function(a){return a==f.maxLine?(i=!0,!0):void 0})),Nd(e,b,c,d,A(a)),a.options.lineWrapping||(e.iter(j,g.line+b.text.length,function(a){var b=G(e,a);b>f.maxLineLength&&(f.maxLine=a,f.maxLineLength=b,f.maxLineChanged=!0,i=!1)}),i&&(a.curOp.updateMaxLine=!0)),e.frontier=Math.min(e.frontier,g.line),_(a,400);var k=b.text.length-(h.line-g.line)-1;if(yb(a,g.line,h.line+1,k),Ae(a,"change")){var l={from:g,to:h,text:b.text,origin:b.origin};if(a.curOp.textChanged){for(var m=a.curOp.textChanged;m.next;m=m.next);m.next=l}else a.curOp.textChanged=l}}function nc(a,b,c,d,e){if(d||(d=c),qc(d,c)){var f=d;d=c,c=f}"string"==typeof b&&(b=bf(b)),hc(a,{from:c,to:d,text:b,origin:e},null)}function oc(a,b){return this instanceof oc?(this.line=a,this.ch=b,void 0):new oc(a,b)}function pc(a,b){return a.line==b.line&&a.ch==b.ch}function qc(a,b){return a.linec?oc(c,Wd(a,c).text.length):uc(b,Wd(a,b.line).text.length)}function uc(a,b){var c=a.ch;return null==c||c>b?oc(a.line,b):0>c?oc(a.line,0):a}function vc(a,b){return b>=a.first&&b=f.ch:k.to>f.ch))){if(d&&l.clearOnEnter){(i||(i=[])).push(l);continue}if(!l.atomic)continue;var m=l.find()[0>g?"from":"to"];if(pc(m,f)&&(m.ch+=g,m.ch<0?m=m.line>a.first?tc(a,oc(m.line-1)):null:m.ch>h.text.length&&(m=m.line(window.innerHeight||document.documentElement.clientHeight)&&(e=!1),null!=e&&!m){var f="none"==c.cursor.style.display;f&&(c.cursor.style.display="",c.cursor.style.left=b.left+"px",c.cursor.style.top=b.top-c.viewOffset+"px"),c.cursor.scrollIntoView(e),f&&(c.cursor.style.display="none")}}}function Cc(a,b){for(;;){var c=!1,d=lb(a,b),e=Ec(a,d.left,d.top,d.left,d.bottom),f=a.doc.scrollTop,g=a.doc.scrollLeft;if(null!=e.scrollTop&&(Ob(a,e.scrollTop),Math.abs(a.doc.scrollTop-f)>1&&(c=!0)),null!=e.scrollLeft&&(Pb(a,e.scrollLeft),Math.abs(a.doc.scrollLeft-g)>1&&(c=!0)),!c)return d}}function Dc(a,b,c,d,e){var f=Ec(a,b,c,d,e);null!=f.scrollTop&&Ob(a,f.scrollTop),null!=f.scrollLeft&&Pb(a,f.scrollLeft)}function Ec(a,b,c,d,e){var f=a.display,g=db(f);c+=g,e+=g;var h=f.scroller.clientHeight-Be,i=f.scroller.scrollTop,j={},k=a.doc.height+2*g,l=g+10>c,m=e+g>k-10;i>c?j.scrollTop=l?0:Math.max(0,c):e>i+h&&(j.scrollTop=(m?k:e)-h);var n=f.scroller.clientWidth-Be,o=f.scroller.scrollLeft;b+=f.gutters.offsetWidth,d+=f.gutters.offsetWidth;var p=f.gutters.offsetWidth,q=p+10>b;return o+p>b||q?(q&&(b=0),j.scrollLeft=Math.max(0,b-10-p)):d>n+o-3&&(j.scrollLeft=d+10-n),j}function Fc(a,b,c,d){var e=a.doc;if(c||(c="add"),"smart"==c)if(a.doc.mode.indent)var f=cb(a,b);else c="prev";var k,g=a.options.tabSize,h=Wd(e,b),i=Ee(h.text,null,g),j=h.text.match(/^\s*/)[0];if("smart"==c&&(k=a.doc.mode.indent(f,h.text.slice(j.length),h.text),k==Ce)){if(!d)return;c="prev"}"prev"==c?k=b>e.first?Ee(Wd(e,b-1).text,null,g):0:"add"==c?k=i+a.options.indentUnit:"subtract"==c&&(k=i-a.options.indentUnit),k=Math.max(0,k);var l="",m=0;if(a.options.indentWithTabs)for(var n=Math.floor(k/g);n;--n)m+=g,l+=" ";k>m&&(l+=Ge(k-m)),l!=j&&nc(a.doc,l,oc(b,0),oc(b,j.length),"+input"),h.stateAfter=null}function Gc(a,b,c){var d=b,e=b,f=a.doc;return"number"==typeof b?e=Wd(f,sc(f,b)):d=$d(b),null==d?null:c(e,d)?(yb(a,d,d+1),e):null}function Hc(a,b,c,d,e){function j(){var b=f+c;return b=a.first+a.size?i=!1:(f=b,h=Wd(a,b))}function k(a){var b=(e?nf:of)(h,g,c,!0);if(null==b){if(a||!j())return i=!1;g=e?(0>c?kf:jf)(h):0>c?h.text.length:0}else g=b;return!0}var f=b.line,g=b.ch,h=Wd(a,f),i=!0;if("char"==d)k();else if("column"==d)k(!0);else if("word"==d)for(var l=!1;!(0>c)||k();){if(Pe(h.text.charAt(g)))l=!0;else if(l){0>c&&(c=1,k());break}if(c>0&&!k())break}var m=Ac(a,oc(f,g),c,!0);return i||(m.hitSide=!0),m}function Ic(a,b,c,d){var g,e=a.doc,f=b.left;if("page"==d){var h=Math.min(a.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight);g=b.top+c*h}else"line"==d&&(g=c>0?b.bottom+3:b.top-3);for(;;){var i=nb(a,f,g);if(!i.outside)break;if(0>c?0>=g:g>=e.height){i.hitSide=!0;break}g+=5*c}return i}function Jc(a,b){var c=b.ch,d=b.ch;if(a){b.after===!1||d==a.length?--c:++d;for(var e=a.charAt(c),f=Pe(e)?Pe:/\s/.test(e)?function(a){return/\s/.test(a)}:function(a){return!/\s/.test(a)&&!Pe(a)};c>0&&f(a.charAt(c-1));)--c;for(;dg;++g){var i=d(f[g]);if(i)return i}return!1}for(var e=0;e=b:f.to>b);(e||(e=[])).push({from:f.from,to:i?null:f.to,marker:g})}}return e}function id(a,b,c){if(a)for(var e,d=0;d=b:f.to>b);if(h||"bookmark"==g.type&&f.from==b&&(!c||f.marker.insertLeft)){var i=null==f.from||(g.inclusiveLeft?f.from<=b:f.from0&&h)for(var l=0;ll;++l)o.push(q);o.push(i)}return o}function kd(a,b){var c=he(a,b),d=jd(a,b);if(!c)return d;if(!d)return c;for(var e=0;eb)&&(!d||d.width5e3&&(f=!1,i.pos=Math.min(b.length,i.start+5e4),j=null);var k=i.current();i.start=i.pos,f&&h==j?g+=k:(g&&e(g,h),g=k,h=j)}g&&e(g,h)}function Cd(a,b,c){var d=[a.state.modeGen];Bd(a,b.text,a.doc.mode,c,function(a,b){d.push(a,b)});for(var e=0;e=i?e-=i:(d.splice(g,1,h.slice(0,e),d[g+1],h.slice(e)),e=0),g+=2}if(b)if(f.opaque)d.splice(c,g-c,a,b),g=c+2;else for(;g>c;c+=2){var h=d[c+1];d[c+1]=h?h+" "+b:b}})}return d}function Dd(a,b){return b.styles&&b.styles[0]==a.state.modeGen||(b.styles=Cd(a,b,b.stateAfter=cb(a,$d(b)))),b.styles}function Ed(a,b,c){var d=a.doc.mode,e=new _c(b.text,a.options.tabSize);for(""==b.text&&d.blankLine&&d.blankLine(c);!e.eol()&&e.pos<=5e3;)d.token(e,c),e.start=e.pos}function Gd(a){return a?Fd[a]||(Fd[a]="cm-"+a.replace(/ +/g," cm-")):null}function Hd(a,c,d){for(var e,g,h,f=c,i=!0;e=nd(f);)i=!1,f=Wd(a.doc,e.find().from.line),g||(g=f);var j={pre:Se("pre"),col:0,pos:0,display:!d,measure:null,addedOne:!1,cm:a};f.textClass&&(j.pre.className=f.textClass);do{j.measure=f==c&&d,j.pos=0,j.addToken=j.measure?Kd:Jd,d&&h&&f!=c&&!j.addedOne&&(d[0]=j.pre.appendChild(af(a.display.measure)),j.addedOne=!0);var k=Md(f,j,Dd(a,f));h=f==g,k&&(f=Wd(a.doc,k.to.line),i=!1)}while(k);d&&!j.addedOne&&(d[0]=j.pre.appendChild(i?Se("span","\xa0"):af(a.display.measure))),j.pre.firstChild||qd(a.doc,c)||j.pre.appendChild(document.createTextNode("\xa0"));var l;if(d&&b&&(l=be(f))){var m=l.length-1;l[m].from==l[m].to&&--m;var n=l[m],o=l[m-1];if(n.from+1==n.to&&o&&n.level="\ud800"&&"\udbff">g&&fh)?(null!=r.to&&k>r.to&&(k=r.to,m=""),s.className&&(l+=" "+s.className),s.startStyle&&r.from==h&&(n+=" "+s.startStyle),s.endStyle&&r.to==k&&(m+=" "+s.endStyle),s.collapsed&&(!o||o.marker.widthh&&k>r.from&&(k=r.from),"bookmark"==s.type&&r.from==h&&s.replacedWith&&(p=s.replacedWith)}if(o&&(o.from||0)==h&&(Ld(b,(null==o.to?g:o.to)-h,null!=o.from&&o.marker.replacedWith),null==o.to))return o.marker.find();p&&!o&&Ld(b,0,p)}if(h>=g)break;for(var t=Math.min(g,k);;){if(i){var u=h+i.length;if(!o){var v=u>t?i.slice(0,t-h):i;b.addToken(b,v,j?j+l:l,n,h+v.length==k?m:"")}if(u>=t){i=i.slice(t-h),h=t;break}h=u,n=""}i=c[e++],j=Gd(c[e++])}}else for(var e=1;eo;++o)q.push(yd(i[o],f(o),e));zd(k,k.text,m,e),n&&a.remove(g.line,n),q.length&&a.insert(g.line,q)}else if(j==k)if(1==i.length)zd(j,j.text.slice(0,g.ch)+l+j.text.slice(h.ch),m,e);else{for(var q=[],o=1,p=i.length-1;p>o;++o)q.push(yd(i[o],f(o),e));q.push(yd(l+j.text.slice(h.ch),m,e)),zd(j,j.text.slice(0,g.ch)+i[0],f(0),e),a.insert(g.line+1,q)}else if(1==i.length)zd(j,j.text.slice(0,g.ch)+i[0]+k.text.slice(h.ch),f(0),e),a.remove(g.line+1,n);else{zd(j,j.text.slice(0,g.ch)+i[0],f(0),e),zd(k,l+k.text.slice(h.ch),m,e);for(var o=1,p=i.length-1,q=[];p>o;++o)q.push(yd(i[o],f(o),e));n>1&&a.remove(g.line+1,n-1),a.insert(g.line+1,q)}ye(a,"change",a,b),yc(a,d.anchor,d.head,null,!0)}function Od(a){this.lines=a,this.parent=null;for(var b=0,c=a.length,d=0;c>b;++b)a[b].parent=this,d+=a[b].height;this.height=d}function Pd(a){this.children=a;for(var b=0,c=0,d=0,e=a.length;e>d;++d){var f=a[d];b+=f.chunkSize(),c+=f.height,f.parent=this}this.size=b,this.height=c,this.parent=null}function Ud(a,b,c){function d(a,e,f){if(a.linked)for(var g=0;gb){a=d;break}b-=e}return a.lines[b]}function Xd(a,b,c){var d=[],e=b.line;return a.iter(b.line,c.line+1,function(a){var f=a.text;e==c.line&&(f=f.slice(0,c.ch)),e==b.line&&(f=f.slice(b.ch)),d.push(f),++e}),d}function Yd(a,b,c){var d=[];return a.iter(b,c,function(a){d.push(a.text)}),d}function Zd(a,b){for(var c=b-a.height,d=a;d;d=d.parent)d.height+=c}function $d(a){if(null==a.parent)return null;for(var b=a.parent,c=Je(b.lines,a),d=b.parent;d;b=d,d=d.parent)for(var e=0;d.children[e]!=b;++e)c+=d.children[e].chunkSize();return c+b.first}function _d(a,b){var c=a.first;a:do{for(var d=0,e=a.children.length;e>d;++d){var f=a.children[d],g=f.height;if(g>b){a=f;continue a}b-=g,c+=f.chunkSize()}return c}while(!a.lines);for(var d=0,e=a.lines.length;e>d;++d){var h=a.lines[d],i=h.height;if(i>b)break;b-=i}return c+d}function ae(a,b){b=pd(a.doc,b);for(var c=0,d=b.parent,e=0;ef-600||"*"==b.origin.charAt(0)))){var h=He(g.changes);pc(b.from,b.to)&&pc(b.from,h.to)?h.to=dc(b):g.changes.push(ee(a,b)),g.anchorAfter=c.anchor,g.headAfter=c.head}else{for(g={changes:[ee(a,b)],anchorBefore:a.sel.anchor,headBefore:a.sel.head,anchorAfter:c.anchor,headAfter:c.head},e.done.push(g);e.done.length>e.undoDepth;)e.done.shift();e.dirtyCounter<0?e.dirtyCounter=0/0:e.dirtyCounter++}e.lastTime=f,e.lastOp=d,e.lastOrigin=b.origin}function ge(a){if(!a)return null;for(var c,b=0;b-1&&(He(g)[k]=i[k],delete i[k])}}return d}function je(a,b,c,d){c0}function De(){this.id=null}function Ee(a,b,c){null==b&&(b=a.search(/[^\s\u00a0]/),-1==b&&(b=a.length));for(var d=0,e=0;b>d;++d)" "==a.charAt(d)?e+=c-e%c:++e;return e}function Ge(a){for(;Fe.length<=a;)Fe.push(He(Fe)+" ");return Fe[a]}function He(a){return a[a.length-1]}function Ie(a){n?(a.selectionStart=0,a.selectionEnd=a.value.length):a.select()}function Je(a,b){if(a.indexOf)return a.indexOf(b);for(var c=0,d=a.length;d>c;++c)if(a[c]==b)return c;return-1}function Ke(a,b){function c(){}c.prototype=a;var d=new c;return b&&Le(b,d),d}function Le(a,b){b||(b={});for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b}function Me(a){for(var b=[],c=0;a>c;++c)b.push(void 0);return b}function Ne(a){var b=Array.prototype.slice.call(arguments,1);return function(){return a.apply(null,b)}}function Pe(a){return/\w/.test(a)||a>"\x80"&&(a.toUpperCase()!=a.toLowerCase()||Oe.test(a))}function Qe(a){for(var b in a)if(a.hasOwnProperty(b)&&a[b])return!1;
3 | return!0}function Se(a,b,c,d){var e=document.createElement(a);if(c&&(e.className=c),d&&(e.style.cssText=d),"string"==typeof b)Ve(e,b);else if(b)for(var f=0;f2&&!c)}return _e?Se("span","\u200b"):Se("span","\xa0",null,"display: inline-block; width: 1px; margin-right: -1px")}function ff(a,b,c,d){if(!a)return d(b,c,"ltr");for(var e=0;eb||b==c&&f.to==b)&&d(Math.max(f.from,b),Math.min(f.to,c),1==f.level?"rtl":"ltr")}}function gf(a){return a.level%2?a.to:a.from}function hf(a){return a.level%2?a.from:a.to}function jf(a){var b=be(a);return b?gf(b[0]):0}function kf(a){var b=be(a);return b?hf(He(b)):a.text.length}function lf(a,b){var c=Wd(a.doc,b),d=pd(a.doc,c);d!=c&&(b=$d(d));var e=be(d),f=e?e[0].level%2?kf(d):jf(d):0;return oc(b,f)}function mf(a,b){for(var c,d;c=od(d=Wd(a.doc,b));)b=c.find().to.line;var e=be(d),f=e?e[0].level%2?jf(d):kf(d):d.text.length;return oc(b,f)}function nf(a,b,c,d){var e=be(a);if(!e)return of(a,b,c,d);for(var f=d?function(b,c){do b+=c;while(b>0&&Re.test(a.text.charAt(b)));return b}:function(a,b){return a+b},g=e[0].level,h=0;hb||j&&(i.from==b||i.to==b))break}for(var k=f(b,i.level%2?-c:c);null!=k;)if(i.level%2==g){if(!(ki.to))break;i=e[h+=c],k=i&&(c>0==i.level%2?f(i.to,-1):f(i.from,1))}else if(k==gf(i))i=e[--h],k=i&&hf(i);else{if(k!=hf(i))break;i=e[++h],k=i&&gf(i)}return 0>k||k>a.text.length?null:k}function of(a,b,c,d){var e=b+c;if(d)for(;e>0&&Re.test(a.text.charAt(e));)e+=c;return 0>e||e>a.text.length?null:e}var a=/gecko\/\d/i.test(navigator.userAgent),b=/MSIE \d/.test(navigator.userAgent),c=b&&(null==document.documentMode||document.documentMode<8),d=b&&(null==document.documentMode||document.documentMode<9),e=/WebKit\//.test(navigator.userAgent),f=e&&/Qt\/\d+\.\d+/.test(navigator.userAgent),g=/Chrome\//.test(navigator.userAgent),h=/Opera\//.test(navigator.userAgent),i=/Apple Computer/.test(navigator.vendor),j=/KHTML\//.test(navigator.userAgent),k=/Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent),l=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent),m=/PhantomJS/.test(navigator.userAgent),n=/AppleWebKit/.test(navigator.userAgent)&&/Mobile\/\w+/.test(navigator.userAgent),o=n||/Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent),p=n||/Mac/.test(navigator.platform),q=/windows/i.test(navigator.platform),r=h&&navigator.userAgent.match(/Version\/(\d*\.\d*)/);r&&(r=Number(r[1]));var pb,Ib,Jb,s=p&&(f||h&&(null==r||12.11>r)),t=a||b&&!d,u=!1,v=!1,sb=0,Qb=0,Rb=null;b?Rb=-.53:a?Rb=15:g?Rb=-.7:i&&(Rb=-1/3);var Vb,bc,Yb=null;w.Pos=oc,w.prototype={focus:function(){window.focus(),Db(this),_b(this),Ab(this)},setOption:function(a,b){var c=this.options,d=c[a];(c[a]!=b||"mode"==a)&&(c[a]=b,Lc.hasOwnProperty(a)&&vb(this,Lc[a])(this,b,d))},getOption:function(a){return this.options[a]},getDoc:function(){return this.doc},addKeyMap:function(a){this.state.keyMaps.push(a)},removeKeyMap:function(a){for(var b=this.state.keyMaps,c=0;c=d;++d)Fc(this,d,a)}),getTokenAt:function(a){var b=this.doc;a=tc(b,a);for(var c=cb(this,a.line),d=this.doc.mode,e=Wd(b,a.line),f=new _c(e.text,this.options.tabSize);f.posi)&&a.top>b.offsetHeight?g=a.top-b.offsetHeight:a.bottom+b.offsetHeight<=i&&(g=a.bottom),h+b.offsetWidth>j&&(h=j-b.offsetWidth)}b.style.top=g+db(f)+"px",b.style.left=b.style.right="","right"==e?(h=f.sizer.clientWidth-b.offsetWidth,b.style.right="0px"):("left"==e?h=0:"middle"==e&&(h=(f.sizer.clientWidth-b.offsetWidth)/2),b.style.left=h+"px"),c&&Dc(this,h,g,h+b.offsetWidth,g+b.offsetHeight)},triggerOnKeyDown:vb(null,Zb),execCommand:function(a){return Vc[a](this)},findPosH:function(a,b,c,d){var e=1;0>b&&(e=-1,b=-b);for(var f=0,g=tc(this.doc,a);b>f&&(g=Hc(this.doc,g,e,c,d),!g.hitSide);++f);return g},moveH:vb(null,function(a,b){var d,c=this.doc.sel;d=c.shift||c.extend||pc(c.from,c.to)?Hc(this.doc,c.head,a,b,this.options.rtlMoveVisually):0>a?c.from:c.to,wc(this.doc,d,d,a)}),deleteH:vb(null,function(a,b){var c=this.doc.sel;pc(c.from,c.to)?nc(this.doc,"",c.from,Hc(this.doc,c.head,a,b,!1),"+delete"):nc(this.doc,"",c.from,c.to,"+delete"),this.curOp.userSelChange=!0}),findPosV:function(a,b,c,d){var e=1,f=d;0>b&&(e=-1,b=-b);for(var g=0,h=tc(this.doc,a);b>g;++g){var i=lb(this,h,"div");if(null==f?f=i.left:i.left=f,h=Ic(this,i,e,c),h.hitSide)break}return h},moveV:vb(null,function(a,b){var c=this.doc.sel,d=lb(this,c.head,"div");null!=c.goalColumn&&(d.left=c.goalColumn);var e=Ic(this,d,a,b);"page"==b&&(this.display.scrollbarV.scrollTop+=kb(this,e,"div").top-d.top),wc(this.doc,e,e,a),c.goalColumn=d.left}),toggleOverwrite:function(){(this.state.overwrite=!this.state.overwrite)?this.display.cursor.className+=" CodeMirror-overwrite":this.display.cursor.className=this.display.cursor.className.replace(" CodeMirror-overwrite","")},scrollTo:vb(null,function(a,b){this.curOp.updateScrollPos={scrollLeft:a,scrollTop:b}}),getScrollInfo:function(){var a=this.display.scroller,b=Be;return{left:a.scrollLeft,top:a.scrollTop,height:a.scrollHeight-b,width:a.scrollWidth-b,clientHeight:a.clientHeight-b,clientWidth:a.clientWidth-b}},scrollIntoView:function(a){"number"==typeof a&&(a=oc(a,0)),a&&null==a.line?Dc(this,a.left,a.top,a.right,a.bottom):(a=a?tc(this.doc,a):this.doc.sel.head,Cc(this,a))},setSize:function(a,b){function c(a){return"number"==typeof a||/^\d+$/.test(String(a))?a+"px":a}null!=a&&(this.display.wrapper.style.width=c(a)),null!=b&&(this.display.wrapper.style.height=c(b)),this.refresh()},on:function(a,b){te(this,a,b)},off:function(a,b){ue(this,a,b)},operation:function(a){return xb(this,a)},refresh:vb(null,function(){ib(this),this.curOp.updateScrollPos={scrollTop:this.doc.scrollTop,scrollLeft:this.doc.scrollLeft},yb(this)}),swapDoc:vb(null,function(a){var b=this.doc;return b.cm=null,Vd(this,a),ib(this),this.curOp.updateScrollPos={scrollTop:a.scrollTop,scrollLeft:a.scrollLeft},b}),getInputField:function(){return this.display.input},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}};var Lc=w.optionHandlers={},Mc=w.defaults={},Oc=w.Init={toString:function(){return"CodeMirror.Init"}};Nc("value","",function(a,b){a.setValue(b)},!0),Nc("mode",null,function(a,b){a.doc.modeOption=b,y(a)},!0),Nc("indentUnit",2,y,!0),Nc("indentWithTabs",!1),Nc("smartIndent",!0),Nc("tabSize",4,function(a){y(a),ib(a),yb(a)},!0),Nc("electricChars",!0),Nc("rtlMoveVisually",!q),Nc("theme","default",function(a){D(a),E(a)},!0),Nc("keyMap","default",C),Nc("extraKeys",null),Nc("onKeyEvent",null),Nc("onDragEvent",null),Nc("lineWrapping",!1,z,!0),Nc("gutters",[],function(a){I(a.options),E(a)},!0),Nc("fixedGutter",!0,function(a,b){a.display.gutters.style.left=b?O(a.display)+"px":"0",a.refresh()},!0),Nc("lineNumbers",!1,function(a){I(a.options),E(a)},!0),Nc("firstLineNumber",1,E,!0),Nc("lineNumberFormatter",function(a){return a},E,!0),Nc("showCursorWhenSelecting",!1,X,!0),Nc("readOnly",!1,function(a,b){"nocursor"==b?(ac(a),a.display.input.blur()):b||Cb(a,!0)}),Nc("dragDrop",!0),Nc("cursorBlinkRate",530),Nc("cursorHeight",1),Nc("workTime",100),Nc("workDelay",100),Nc("flattenSpans",!0),Nc("pollInterval",100),Nc("undoDepth",40,function(a,b){a.doc.history.undoDepth=b}),Nc("viewportMargin",10,function(a){a.refresh()},!0),Nc("tabindex",null,function(a,b){a.display.input.tabIndex=b||""}),Nc("autofocus",null);var Pc=w.modes={},Qc=w.mimeModes={};w.defineMode=function(a,b){if(w.defaults.mode||"null"==a||(w.defaults.mode=a),arguments.length>2){b.dependencies=[];for(var c=2;c0&&b.ch=this.string.length},sol:function(){return 0==this.pos},peek:function(){return this.string.charAt(this.pos)||void 0},next:function(){return this.posb},eatSpace:function(){for(var a=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>a},skipToEnd:function(){this.pos=this.string.length},skipTo:function(a){var b=this.string.indexOf(a,this.pos);return b>-1?(this.pos=b,!0):void 0},backUp:function(a){this.pos-=a},column:function(){return Ee(this.string,this.start,this.tabSize)},indentation:function(){return Ee(this.string,null,this.tabSize)},match:function(a,b,c){if("string"!=typeof a){var e=this.string.slice(this.pos).match(a);return e&&e.index>0?null:(e&&b!==!1&&(this.pos+=e[0].length),e)}var d=function(a){return c?a.toLowerCase():a};return d(this.string).indexOf(d(a),this.pos)==this.pos?(b!==!1&&(this.pos+=a.length),!0):void 0},current:function(){return this.string.slice(this.start,this.pos)}},w.StringStream=_c,w.TextMarker=ad,ad.prototype.clear=function(){if(!this.explicitlyCleared){var a=this.doc.cm,b=a&&!a.curOp;b&&tb(a);for(var c=null,d=null,e=0;ea.display.maxLineLength&&(a.display.maxLine=h,a.display.maxLineLength=i,a.display.maxLineChanged=!0)}null!=c&&a&&yb(a,c,d+1),this.lines.length=0,this.explicitlyCleared=!0,this.collapsed&&this.doc.cantEdit&&(this.doc.cantEdit=!1,a&&zc(a)),b&&ub(a),ye(this,"clear")}},ad.prototype.find=function(){for(var a,b,c=0;cc;++c){var e=this.lines[c];this.height-=e.height,Ad(e),ye(e,"delete")}this.lines.splice(a,b)},collapse:function(a){a.splice.apply(a,[a.length,0].concat(this.lines))},insertInner:function(a,b,c){this.height+=c,this.lines=this.lines.slice(0,a).concat(b).concat(this.lines.slice(a));for(var d=0,e=b.length;e>d;++d)b[d].parent=this},iterN:function(a,b,c){for(var d=a+b;d>a;++a)if(c(this.lines[a]))return!0}},Pd.prototype={chunkSize:function(){return this.size},removeInner:function(a,b){this.size-=b;for(var c=0;ca){var f=Math.min(b,e-a),g=d.height;if(d.removeInner(a,f),this.height-=g-d.height,e==f&&(this.children.splice(c--,1),d.parent=null),0==(b-=f))break;a=0}else a-=e}if(this.size-b<25){var h=[];this.collapse(h),this.children=[new Od(h)],this.children[0].parent=this}},collapse:function(a){for(var b=0,c=this.children.length;c>b;++b)this.children[b].collapse(a)},insertInner:function(a,b,c){this.size+=b.length,this.height+=c;for(var d=0,e=this.children.length;e>d;++d){var f=this.children[d],g=f.chunkSize();if(g>=a){if(f.insertInner(a,b,c),f.lines&&f.lines.length>50){for(;f.lines.length>50;){var h=f.lines.splice(f.lines.length-25,25),i=new Od(h);f.height-=i.height,this.children.splice(d+1,0,i),i.parent=this}this.maybeSpill()}break}a-=g}},maybeSpill:function(){if(!(this.children.length<=10)){var a=this;do{var b=a.children.splice(a.children.length-5,5),c=new Pd(b);if(a.parent){a.size-=c.size,a.height-=c.height;var e=Je(a.parent.children,a);a.parent.children.splice(e+1,0,c)}else{var d=new Pd(a.children);d.parent=a,a.children=[d,c],a=d}c.parent=a.parent}while(a.children.length>10);a.parent.maybeSpill()}},iterN:function(a,b,c){for(var d=0,e=this.children.length;e>d;++d){var f=this.children[d],g=f.chunkSize();if(g>a){var h=Math.min(b,g-a);if(f.iterN(a,h,c))return!0;if(0==(b-=h))break;a=0}else a-=g}}};var Qd=0,Rd=w.Doc=function(a,b,c){if(!(this instanceof Rd))return new Rd(a,b,c);null==c&&(c=0),Pd.call(this,[new Od([yd("",null)])]),this.first=c,this.scrollTop=this.scrollLeft=0,this.cantEdit=!1,this.history=ce(),this.frontier=c;var d=oc(c,0);this.sel={from:d,to:d,head:d,anchor:d,shift:!1,extend:!1,goalColumn:null},this.id=++Qd,this.modeOption=b,"string"==typeof a&&(a=bf(a)),Nd(this,{from:d,to:d,text:a},null,{head:d,anchor:d})};Rd.prototype=Ke(Pd.prototype,{iter:function(a,b,c){c?this.iterN(a-this.first,b-a,c):this.iterN(this.first,this.first+this.size,a)},insert:function(a,b){for(var c=0,d=0,e=b.length;e>d;++d)c+=b[d].height;this.insertInner(a-this.first,b,c)},remove:function(a,b){this.removeInner(a-this.first,b)},getValue:function(a){var b=Yd(this,this.first,this.first+this.size);return a===!1?b:b.join(a||"\n")},setValue:function(a){var b=oc(this.first,0),c=this.first+this.size-1;hc(this,{from:b,to:oc(c,Wd(this,c).text.length),text:bf(a),origin:"setValue"},{head:b,anchor:b},!0)},replaceRange:function(a,b,c,d){b=tc(this,b),c=c?tc(this,c):b,nc(this,a,b,c,d)},getRange:function(a,b,c){var d=Xd(this,tc(this,a),tc(this,b));return c===!1?d:d.join(c||"\n")},getLine:function(a){var b=this.getLineHandle(a);return b&&b.text},setLine:function(a,b){vc(this,a)&&nc(this,b,oc(a,0),tc(this,oc(a)))},removeLine:function(a){vc(this,a)&&nc(this,"",oc(a,0),tc(this,oc(a+1,0)))},getLineHandle:function(a){return vc(this,a)?Wd(this,a):void 0},getLineNumber:function(a){return $d(a)},lineCount:function(){return this.size},firstLine:function(){return this.first},lastLine:function(){return this.first+this.size-1},clipPos:function(a){return tc(this,a)},getCursor:function(a){var c,b=this.sel;return c=null==a||"head"==a?b.head:"anchor"==a?b.anchor:"end"==a||a===!1?b.to:b.from,rc(c)},somethingSelected:function(){return!pc(this.sel.head,this.sel.anchor)},setCursor:wb(function(a,b,c){var d=tc(this,"number"==typeof a?oc(a,b||0):a);c?wc(this,d):yc(this,d,d)}),setSelection:wb(function(a,b){yc(this,tc(this,a),tc(this,b||a))}),extendSelection:wb(function(a,b){wc(this,tc(this,a),b&&tc(this,b))}),getSelection:function(a){return this.getRange(this.sel.from,this.sel.to,a)},replaceSelection:function(a,b,c){hc(this,{from:this.sel.from,to:this.sel.to,text:bf(a),origin:c},b||"around")},undo:wb(function(){jc(this,"undo")}),redo:wb(function(){jc(this,"redo")}),setExtending:function(a){this.sel.extend=a},historySize:function(){var a=this.history;return{undo:a.done.length,redo:a.undone.length}},clearHistory:function(){this.history=ce()},markClean:function(){this.history.dirtyCounter=0,this.history.lastOp=this.history.lastOrigin=null},isClean:function(){return 0==this.history.dirtyCounter},getHistory:function(){return{done:ie(this.history.done),undone:ie(this.history.undone)}},setHistory:function(a){var b=this.history=ce();b.done=a.done.slice(0),b.undone=a.undone.slice(0)},markText:function(a,b,c){return bd(this,tc(this,a),tc(this,b),c,"range")},setBookmark:function(a,b){var c={replacedWith:b&&(null==b.nodeType?b.widget:b),insertLeft:b&&b.insertLeft};return a=tc(this,a),bd(this,a,a,c,"bookmark")},findMarksAt:function(a){a=tc(this,a);var b=[],c=Wd(this,a.line).markedSpans;if(c)for(var d=0;d=a.ch)&&b.push(e.marker.parent||e.marker)}return b},getAllMarks:function(){var a=[];return this.iter(function(b){var c=b.markedSpans;if(c)for(var d=0;da?(b=a,!0):(a-=e,++c,void 0)}),tc(this,oc(c,b))},indexFromPos:function(a){a=tc(this,a);var b=a.ch;return a.lineb&&(b=a.from),null!=a.to&&a.to\]|\}~][\(\{\[<]|\$'/);var Ze,_e,bf=3!="\n\nb".split(/\n/).length?function(a){for(var b=0,c=[],d=a.length;d>=b;){var e=a.indexOf("\n",b);-1==e&&(e=a.length);var f=a.slice(b,"\r"==a.charAt(e-1)?e-1:e),g=f.indexOf("\r");-1!=g?(c.push(f.slice(0,g)),b+=g+1):(c.push(f),b=e+1)}return c}:function(a){return a.split(/\r\n?|\n/)};w.splitLines=bf;var cf=window.getSelection?function(a){try{return a.selectionStart!=a.selectionEnd}catch(b){return!1}}:function(a){try{var b=a.ownerDocument.selection.createRange()}catch(c){}return b&&b.parentElement()==a?0!=b.compareEndPoints("StartToEnd",b):!1},df=function(){var a=Se("div");return"oncopy"in a?!0:(a.setAttribute("oncopy","return;"),"function"==typeof a.oncopy)}(),ef={3:"Enter",8:"Backspace",9:"Tab",13:"Enter",16:"Shift",17:"Ctrl",18:"Alt",19:"Pause",20:"CapsLock",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"PrintScrn",45:"Insert",46:"Delete",59:";",91:"Mod",92:"Mod",93:"Mod",109:"-",107:"=",127:"Delete",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",63276:"PageUp",63277:"PageDown",63275:"End",63273:"Home",63234:"Left",63232:"Up",63235:"Right",63233:"Down",63302:"Insert",63272:"Delete"};w.keyNames=ef,function(){for(var a=0;10>a;a++)ef[a+48]=String(a);for(var a=65;90>=a;a++)ef[a]=String.fromCharCode(a);for(var a=1;12>=a;a++)ef[a+111]=ef[a+63235]="F"+a}();var pf=function(){function c(c){return 255>=c?a.charAt(c):c>=1424&&1524>=c?"R":c>=1536&&1791>=c?b.charAt(c-1536):c>=1792&&2220>=c?"r":"L"}var a="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL",b="rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmmrrrrrrrrrrrrrrrrrr",d=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,e=/[stwN]/,f=/[LRr]/,g=/[Lb1n]/,h=/[1n]/,i="L";return function(a){if(!d.test(a))return!1;for(var l,b=a.length,j=[],k=0;b>k;++k)j.push(l=c(a.charCodeAt(k)));for(var k=0,m=i;b>k;++k){var l=j[k];"m"==l?j[k]=m:m=l}for(var k=0,n=i;b>k;++k){var l=j[k];
4 | "1"==l&&"r"==n?j[k]="n":f.test(l)&&(n=l,"r"==l&&(j[k]="R"))}for(var k=1,m=j[0];b-1>k;++k){var l=j[k];"+"==l&&"1"==m&&"1"==j[k+1]?j[k]="1":","!=l||m!=j[k+1]||"1"!=m&&"n"!=m||(j[k]=m),m=l}for(var k=0;b>k;++k){var l=j[k];if(","==l)j[k]="N";else if("%"==l){for(var o=k+1;b>o&&"%"==j[o];++o);for(var p=k&&"!"==j[k-1]||b-1>o&&"1"==j[o]?"1":"N",q=k;o>q;++q)j[q]=p;k=o-1}}for(var k=0,n=i;b>k;++k){var l=j[k];"L"==n&&"1"==l?j[k]="L":f.test(l)&&(n=l)}for(var k=0;b>k;++k)if(e.test(j[k])){for(var o=k+1;b>o&&e.test(j[o]);++o);for(var r="L"==(k?j[k-1]:i),s="L"==(b-1>o?j[o]:i),p=r||s?"L":"R",q=k;o>q;++q)j[q]=p;k=o-1}for(var u,t=[],k=0;b>k;)if(g.test(j[k])){var v=k;for(++k;b>k&&g.test(j[k]);++k);t.push({from:v,to:k,level:0})}else{var w=k,x=t.length;for(++k;b>k&&"L"!=j[k];++k);for(var q=w;k>q;)if(h.test(j[q])){q>w&&t.splice(x,0,{from:w,to:q,level:1});var y=q;for(++q;k>q&&h.test(j[q]);++q);t.splice(x,0,{from:y,to:q,level:2}),w=q}else++q;k>w&&t.splice(x,0,{from:w,to:k,level:1})}return 1==t[0].level&&(u=a.match(/^\s+/))&&(t[0].from=u[0].length,t.unshift({from:0,to:u[0].length,level:0})),1==He(t).level&&(u=a.match(/\s+$/))&&(He(t).to-=u[0].length,t.push({from:b-u[0].length,to:b,level:0})),t[0].level!=He(t).level&&t.push({from:b,to:b,level:t[0].level}),t}}();return w.version="3.1",w}();
--------------------------------------------------------------------------------
/lib/mergely.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2014 by Jamie Peabody, http://www.mergely.com
3 | * All rights reserved.
4 | * Version: 3.3.7 2014-08-17
5 | */
6 |
7 | /* required */
8 | .mergely-column textarea { width: 80px; height: 200px; }
9 | .mergely-column { float: left; }
10 | .mergely-margin { float: left; }
11 | .mergely-canvas { float: left; width: 28px; }
12 |
13 | /* resizeable */
14 | .mergely-resizer { width: 100%; height: 100%; }
15 |
16 | /* style configuration */
17 | .mergely-column { border: 1px solid #ccc; }
18 | .mergely-active { border: 1px solid #a3d1ff; }
19 |
20 | .mergely.a.rhs.start { border-top: 1px solid #a3d1ff; }
21 | .mergely.a.lhs.start.end,
22 | .mergely.a.rhs.end { border-bottom: 1px solid #a3d1ff; }
23 | .mergely.a.rhs { background-color: #ddeeff; }
24 | .mergely.a.lhs.start.end.first { border-bottom: 0; border-top: 1px solid #a3d1ff; }
25 |
26 | .mergely.d.lhs { background-color: #edc0c0; }
27 | .mergely.d.lhs.end,
28 | .mergely.d.rhs.start.end { border-bottom: 1px solid #ff7f7f; }
29 | .mergely.d.rhs.start.end.first { border-bottom: 0; border-top: 1px solid #ff7f7f; }
30 | .mergely.d.lhs.start { border-top: 1px solid #ff7f7f; }
31 |
32 | .mergely.c.lhs,
33 | .mergely.c.rhs { background-color: #fafafa; }
34 | .mergely.c.lhs.start,
35 | .mergely.c.rhs.start { border-top: 1px solid #a3a3a3; }
36 | .mergely.c.lhs.end,
37 | .mergely.c.rhs.end { border-bottom: 1px solid #a3a3a3; }
38 |
39 | .mergely.ch.a.rhs { background-color: #ddeeff; }
40 | .mergely.ch.d.lhs { background-color: #edc0c0; text-decoration: line-through; color: #888; }
41 |
--------------------------------------------------------------------------------
/lib/mergely.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2014 by Jamie Peabody, http://www.mergely.com
3 | * All rights reserved.
4 | * Version: 3.3.7 2014-08-17
5 | */
6 | Mgly = {};
7 |
8 | Mgly.Timer = function(){
9 | var self = this;
10 | self.start = function() { self.t0 = new Date().getTime(); }
11 | self.stop = function() {
12 | var t1 = new Date().getTime();
13 | var d = t1 - self.t0;
14 | self.t0 = t1;
15 | return d;
16 | }
17 | self.start();
18 | }
19 |
20 | Mgly.ChangeExpression = new RegExp(/(^(?![><-])*\d+(?:,\d+)?)([acd])(\d+(?:,\d+)?)/);
21 |
22 | Mgly.DiffParser = function(diff) {
23 | var changes = [];
24 | var change_id = 0;
25 | // parse diff
26 | var diff_lines = diff.split(/\n/);
27 | for (var i = 0; i < diff_lines.length; ++i) {
28 | if (diff_lines[i].length == 0) continue;
29 | var change = {};
30 | var test = Mgly.ChangeExpression.exec(diff_lines[i]);
31 | if (test == null) continue;
32 | // lines are zero-based
33 | var fr = test[1].split(',');
34 | change['lhs-line-from'] = fr[0] - 1;
35 | if (fr.length == 1) change['lhs-line-to'] = fr[0] - 1;
36 | else change['lhs-line-to'] = fr[1] - 1;
37 | var to = test[3].split(',');
38 | change['rhs-line-from'] = to[0] - 1;
39 | if (to.length == 1) change['rhs-line-to'] = to[0] - 1;
40 | else change['rhs-line-to'] = to[1] - 1;
41 | change['op'] = test[2];
42 | changes[change_id++] = change;
43 | }
44 | return changes;
45 | }
46 |
47 | Mgly.sizeOf = function(obj) {
48 | var size = 0, key;
49 | for (key in obj) {
50 | if (obj.hasOwnProperty(key)) size++;
51 | }
52 | return size;
53 | }
54 |
55 | Mgly.LCS = function(x, y) {
56 | this.x = x.replace(/[ ]{1}/g, '\n');
57 | this.y = y.replace(/[ ]{1}/g, '\n');
58 | }
59 | jQuery.extend(Mgly.LCS.prototype, {
60 | clear: function() { this.ready = 0; },
61 | diff: function(added, removed) {
62 | var d = new Mgly.diff(this.x, this.y, {ignorews: false});
63 | var changes = Mgly.DiffParser(d.normal_form());
64 | var li = 0, lj = 0;
65 | for (var i = 0; i < changes.length; ++i) {
66 | var change = changes[i];
67 | if (change.op != 'a') {
68 | // find the starting index of the line
69 | li = d.getLines('lhs').slice(0, change['lhs-line-from']).join(' ').length;
70 | // get the index of the the span of the change
71 | lj = change['lhs-line-to'] + 1;
72 | // get the changed text
73 | var lchange = d.getLines('lhs').slice(change['lhs-line-from'], lj).join(' ');
74 | if (change.op == 'd') lchange += ' ';// include the leading space
75 | else if (li > 0 && change.op == 'c') li += 1; // ignore leading space if not first word
76 | // output the changed index and text
77 | removed(li, li + lchange.length);
78 | }
79 | if (change.op != 'd') {
80 | // find the starting index of the line
81 | li = d.getLines('rhs').slice(0, change['rhs-line-from']).join(' ').length;
82 | // get the index of the the span of the change
83 | lj = change['rhs-line-to'] + 1;
84 | // get the changed text
85 | var rchange = d.getLines('rhs').slice(change['rhs-line-from'], lj).join(' ');
86 | if (change.op == 'a') rchange += ' ';// include the leading space
87 | else if (li > 0 && change.op == 'c') li += 1; // ignore leading space if not first word
88 | // output the changed index and text
89 | added(li, li + rchange.length);
90 | }
91 | }
92 | }
93 | });
94 |
95 | Mgly.CodeifyText = function(settings) {
96 | this._max_code = 0;
97 | this._diff_codes = {};
98 | this.ctxs = {};
99 | this.options = {ignorews: false};
100 | jQuery.extend(this, settings);
101 | this.lhs = settings.lhs.split('\n');
102 | this.rhs = settings.rhs.split('\n');
103 | }
104 |
105 | jQuery.extend(Mgly.CodeifyText.prototype, {
106 | getCodes: function(side) {
107 | if (!this.ctxs.hasOwnProperty(side)) {
108 | var ctx = this._diff_ctx(this[side]);
109 | this.ctxs[side] = ctx;
110 | ctx.codes.length = Object.keys(ctx.codes).length;
111 | }
112 | return this.ctxs[side].codes;
113 | },
114 | getLines: function(side) {
115 | return this.ctxs[side].lines;
116 | },
117 | _diff_ctx: function(lines) {
118 | var ctx = {i: 0, codes: {}, lines: lines};
119 | this._codeify(lines, ctx);
120 | return ctx;
121 | },
122 | _codeify: function(lines, ctx) {
123 | var code = this._max_code;
124 | for (var i = 0; i < lines.length; ++i) {
125 | var line = lines[i];
126 | if (this.options.ignorews) {
127 | line = line.replace(/\s+/g, '');
128 | }
129 | var aCode = this._diff_codes[line];
130 | if (aCode != undefined) {
131 | ctx.codes[i] = aCode;
132 | }
133 | else {
134 | this._max_code++;
135 | this._diff_codes[line] = this._max_code;
136 | ctx.codes[i] = this._max_code;
137 | }
138 | }
139 | }
140 | });
141 |
142 | Mgly.diff = function(lhs, rhs, options) {
143 | var opts = jQuery.extend({ignorews: false}, options);
144 | this.codeify = new Mgly.CodeifyText({
145 | lhs: lhs,
146 | rhs: rhs,
147 | options: opts
148 | });
149 | var lhs_ctx = {
150 | codes: this.codeify.getCodes('lhs'),
151 | modified: {}
152 | };
153 | var rhs_ctx = {
154 | codes: this.codeify.getCodes('rhs'),
155 | modified: {}
156 | };
157 | var max = (lhs_ctx.codes.length + rhs_ctx.codes.length + 1);
158 | var vector_d = Array( 2 * max + 2 );
159 | var vector_u = Array( 2 * max + 2 );
160 | this._lcs(lhs_ctx, 0, lhs_ctx.codes.length, rhs_ctx, 0, rhs_ctx.codes.length, vector_u, vector_d);
161 | this._optimize(lhs_ctx);
162 | this._optimize(rhs_ctx);
163 | this.items = this._create_diffs(lhs_ctx, rhs_ctx);
164 | };
165 |
166 | jQuery.extend(Mgly.diff.prototype, {
167 | changes: function() { return this.items; },
168 | getLines: function(side) {
169 | return this.codeify.getLines(side);
170 | },
171 | normal_form: function() {
172 | var nf = '';
173 | for (var index = 0; index < this.items.length; ++index) {
174 | var item = this.items[index];
175 | var lhs_str = '';
176 | var rhs_str = '';
177 | var change = 'c';
178 | if (item.lhs_deleted_count == 0 && item.rhs_inserted_count > 0) change = 'a';
179 | else if (item.lhs_deleted_count > 0 && item.rhs_inserted_count == 0) change = 'd';
180 |
181 | if (item.lhs_deleted_count == 1) lhs_str = item.lhs_start + 1;
182 | else if (item.lhs_deleted_count == 0) lhs_str = item.lhs_start;
183 | else lhs_str = (item.lhs_start + 1) + ',' + (item.lhs_start + item.lhs_deleted_count);
184 |
185 | if (item.rhs_inserted_count == 1) rhs_str = item.rhs_start + 1;
186 | else if (item.rhs_inserted_count == 0) rhs_str = item.rhs_start;
187 | else rhs_str = (item.rhs_start + 1) + ',' + (item.rhs_start + item.rhs_inserted_count);
188 | nf += lhs_str + change + rhs_str + '\n';
189 |
190 | var lhs_lines = this.getLines('lhs');
191 | var rhs_lines = this.getLines('rhs');
192 | if (rhs_lines && lhs_lines) {
193 | // if rhs/lhs lines have been retained, output contextual diff
194 | for (var i = item.lhs_start; i < item.lhs_start + item.lhs_deleted_count; ++i) {
195 | nf += '< ' + lhs_lines[i] + '\n';
196 | }
197 | if (item.rhs_inserted_count && item.lhs_deleted_count) nf += '---\n';
198 | for (var i = item.rhs_start; i < item.rhs_start + item.rhs_inserted_count; ++i) {
199 | nf += '> ' + rhs_lines[i] + '\n';
200 | }
201 | }
202 | }
203 | return nf;
204 | },
205 | _lcs: function(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d) {
206 | while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs_ctx.codes[lhs_lower] == rhs_ctx.codes[rhs_lower]) ) {
207 | ++lhs_lower;
208 | ++rhs_lower;
209 | }
210 | while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs_ctx.codes[lhs_upper - 1] == rhs_ctx.codes[rhs_upper - 1]) ) {
211 | --lhs_upper;
212 | --rhs_upper;
213 | }
214 | if (lhs_lower == lhs_upper) {
215 | while (rhs_lower < rhs_upper) {
216 | rhs_ctx.modified[ rhs_lower++ ] = true;
217 | }
218 | }
219 | else if (rhs_lower == rhs_upper) {
220 | while (lhs_lower < lhs_upper) {
221 | lhs_ctx.modified[ lhs_lower++ ] = true;
222 | }
223 | }
224 | else {
225 | var sms = this._sms(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d);
226 | this._lcs(lhs_ctx, lhs_lower, sms.x, rhs_ctx, rhs_lower, sms.y, vector_u, vector_d);
227 | this._lcs(lhs_ctx, sms.x, lhs_upper, rhs_ctx, sms.y, rhs_upper, vector_u, vector_d);
228 | }
229 | },
230 | _sms: function(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d) {
231 | var max = lhs_ctx.codes.length + rhs_ctx.codes.length + 1;
232 | var kdown = lhs_lower - rhs_lower;
233 | var kup = lhs_upper - rhs_upper;
234 | var delta = (lhs_upper - lhs_lower) - (rhs_upper - rhs_lower);
235 | var odd = (delta & 1) != 0;
236 | var offset_down = max - kdown;
237 | var offset_up = max - kup;
238 | var maxd = ((lhs_upper - lhs_lower + rhs_upper - rhs_lower) / 2) + 1;
239 | vector_d[ offset_down + kdown + 1 ] = lhs_lower;
240 | vector_u[ offset_up + kup - 1 ] = lhs_upper;
241 | var ret = {x:0,y:0};
242 | for (var d = 0; d <= maxd; ++d) {
243 | for (var k = kdown - d; k <= kdown + d; k += 2) {
244 | var x, y;
245 | if (k == kdown - d) {
246 | x = vector_d[ offset_down + k + 1 ];//down
247 | }
248 | else {
249 | x = vector_d[ offset_down + k - 1 ] + 1;//right
250 | if ((k < (kdown + d)) && (vector_d[ offset_down + k + 1 ] >= x)) {
251 | x = vector_d[ offset_down + k + 1 ];//down
252 | }
253 | }
254 | y = x - k;
255 | // find the end of the furthest reaching forward D-path in diagonal k.
256 | while ((x < lhs_upper) && (y < rhs_upper) && (lhs_ctx.codes[x] == rhs_ctx.codes[y])) {
257 | x++; y++;
258 | }
259 | vector_d[ offset_down + k ] = x;
260 | // overlap ?
261 | if (odd && (kup - d < k) && (k < kup + d)) {
262 | if (vector_u[offset_up + k] <= vector_d[offset_down + k]) {
263 | ret.x = vector_d[offset_down + k];
264 | ret.y = vector_d[offset_down + k] - k;
265 | return (ret);
266 | }
267 | }
268 | }
269 | // Extend the reverse path.
270 | for (var k = kup - d; k <= kup + d; k += 2) {
271 | // find the only or better starting point
272 | var x, y;
273 | if (k == kup + d) {
274 | x = vector_u[offset_up + k - 1]; // up
275 | } else {
276 | x = vector_u[offset_up + k + 1] - 1; // left
277 | if ((k > kup - d) && (vector_u[offset_up + k - 1] < x))
278 | x = vector_u[offset_up + k - 1]; // up
279 | }
280 | y = x - k;
281 | while ((x > lhs_lower) && (y > rhs_lower) && (lhs_ctx.codes[x - 1] == rhs_ctx.codes[y - 1])) {
282 | // diagonal
283 | x--;
284 | y--;
285 | }
286 | vector_u[offset_up + k] = x;
287 | // overlap ?
288 | if (!odd && (kdown - d <= k) && (k <= kdown + d)) {
289 | if (vector_u[offset_up + k] <= vector_d[offset_down + k]) {
290 | ret.x = vector_d[offset_down + k];
291 | ret.y = vector_d[offset_down + k] - k;
292 | return (ret);
293 | }
294 | }
295 | }
296 | }
297 | throw "the algorithm should never come here.";
298 | },
299 | _optimize: function(ctx) {
300 | var start = 0, end = 0;
301 | while (start < ctx.length) {
302 | while ((start < ctx.length) && (ctx.modified[start] == undefined || ctx.modified[start] == false)) {
303 | start++;
304 | }
305 | end = start;
306 | while ((end < ctx.length) && (ctx.modified[end] == true)) {
307 | end++;
308 | }
309 | if ((end < ctx.length) && (ctx.ctx[start] == ctx.codes[end])) {
310 | ctx.modified[start] = false;
311 | ctx.modified[end] = true;
312 | }
313 | else {
314 | start = end;
315 | }
316 | }
317 | },
318 | _create_diffs: function(lhs_ctx, rhs_ctx) {
319 | var items = [];
320 | var lhs_start = 0, rhs_start = 0;
321 | var lhs_line = 0, rhs_line = 0;
322 |
323 | while (lhs_line < lhs_ctx.codes.length || rhs_line < rhs_ctx.codes.length) {
324 | if ((lhs_line < lhs_ctx.codes.length) && (!lhs_ctx.modified[lhs_line])
325 | && (rhs_line < rhs_ctx.codes.length) && (!rhs_ctx.modified[rhs_line])) {
326 | // equal lines
327 | lhs_line++;
328 | rhs_line++;
329 | }
330 | else {
331 | // maybe deleted and/or inserted lines
332 | lhs_start = lhs_line;
333 | rhs_start = rhs_line;
334 |
335 | while (lhs_line < lhs_ctx.codes.length && (rhs_line >= rhs_ctx.codes.length || lhs_ctx.modified[lhs_line]))
336 | lhs_line++;
337 |
338 | while (rhs_line < rhs_ctx.codes.length && (lhs_line >= lhs_ctx.codes.length || rhs_ctx.modified[rhs_line]))
339 | rhs_line++;
340 |
341 | if ((lhs_start < lhs_line) || (rhs_start < rhs_line)) {
342 | // store a new difference-item
343 | items.push({
344 | lhs_start: lhs_start,
345 | rhs_start: rhs_start,
346 | lhs_deleted_count: lhs_line - lhs_start,
347 | rhs_inserted_count: rhs_line - rhs_start
348 | });
349 | }
350 | }
351 | }
352 | return items;
353 | }
354 | });
355 |
356 | Mgly.mergely = function(el, options) {
357 | if (el) {
358 | this.init(el, options);
359 | }
360 | };
361 |
362 | jQuery.extend(Mgly.mergely.prototype, {
363 | name: 'mergely',
364 | //http://jupiterjs.com/news/writing-the-perfect-jquery-plugin
365 | init: function(el, options) {
366 | this.diffView = new Mgly.CodeMirrorDiffView(el, options);
367 | this.bind(el);
368 | },
369 | bind: function(el) {
370 | this.diffView.bind(el);
371 | }
372 | });
373 |
374 | Mgly.CodeMirrorDiffView = function(el, options) {
375 | CodeMirror.defineExtension('centerOnCursor', function() {
376 | var coords = this.cursorCoords(null, 'local');
377 | this.scrollTo(null,
378 | (coords.y + coords.yBot) / 2 - (this.getScrollerElement().clientHeight / 2));
379 | });
380 | this.init(el, options);
381 | };
382 |
383 | jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
384 | init: function(el, options) {
385 | this.settings = {
386 | autoupdate: true,
387 | autoresize: true,
388 | rhs_margin: 'right',
389 | lcs: true,
390 | sidebar: true,
391 | viewport: false,
392 | ignorews: false,
393 | fadein: 'fast',
394 | editor_width: '650px',
395 | editor_height: '400px',
396 | resize_timeout: 500,
397 | change_timeout: 150,
398 | fgcolor: {a:'#4ba3fa',c:'#a3a3a3',d:'#ff7f7f', // color for differences (soft color)
399 | ca:'#4b73ff',cc:'#434343',cd:'#ff4f4f'}, // color for currently active difference (bright color)
400 | bgcolor: '#eee',
401 | vpcolor: 'rgba(0, 0, 200, 0.5)',
402 | lhs: function(setValue) { },
403 | rhs: function(setValue) { },
404 | loaded: function() { },
405 | _auto_width: function(w) { return w; },
406 | resize: function(init) {
407 | var scrollbar = init ? 16 : 0;
408 | var w = jQuery(el).parent().width() + scrollbar;
409 | if (this.width == 'auto') {
410 | w = this._auto_width(w);
411 | }
412 | else {
413 | w = this.width;
414 | this.editor_width = w;
415 | }
416 | if (this.height == 'auto') {
417 | //h = this._auto_height(h);
418 | h = jQuery(el).parent().height();
419 | }
420 | else {
421 | h = this.height;
422 | this.editor_height = h;
423 | }
424 | var content_width = w / 2.0 - 2 * 8 - 8;
425 | var content_height = h;
426 | var self = jQuery(el);
427 | self.find('.mergely-column').css({ width: content_width + 'px' });
428 | self.find('.mergely-column, .mergely-canvas, .mergely-margin, .mergely-column textarea, .CodeMirror-scroll, .cm-s-default').css({ height: content_height + 'px' });
429 | self.find('.mergely-canvas').css({ height: content_height + 'px' });
430 | self.find('.mergely-column textarea').css({ width: content_width + 'px' });
431 | self.css({ width: w, height: h, clear: 'both' });
432 | if (self.css('display') == 'none') {
433 | if (this.fadein != false) self.fadeIn(this.fadein);
434 | else self.show();
435 | if (this.loaded) this.loaded();
436 | }
437 | if (this.resized) this.resized();
438 | },
439 | _debug: '', //scroll,draw,calc,diff,markup,change
440 | resized: function() { }
441 | };
442 | var cmsettings = {
443 | mode: 'text/plain',
444 | readOnly: false,
445 | lineWrapping: false,
446 | lineNumbers: true,
447 | gutters: ['merge', 'CodeMirror-linenumbers']
448 | }
449 | this.lhs_cmsettings = {};
450 | this.rhs_cmsettings = {};
451 |
452 | // save this element for faster queries
453 | this.element = jQuery(el);
454 |
455 | // save options if there are any
456 | if (options && options.cmsettings) jQuery.extend(this.lhs_cmsettings, cmsettings, options.cmsettings, options.lhs_cmsettings);
457 | if (options && options.cmsettings) jQuery.extend(this.rhs_cmsettings, cmsettings, options.cmsettings, options.rhs_cmsettings);
458 | if (options) jQuery.extend(this.settings, options);
459 |
460 | // bind if the element is destroyed
461 | this.element.bind('destroyed', jQuery.proxy(this.teardown, this));
462 |
463 | // save this instance in jQuery data, binding this view to the node
464 | jQuery.data(el, 'mergely', this);
465 | },
466 | unbind: function() {
467 | if (this.changed_timeout != null) clearTimeout(this.changed_timeout);
468 | this.editor[this.id + '-lhs'].toTextArea();
469 | this.editor[this.id + '-rhs'].toTextArea();
470 | },
471 | destroy: function() {
472 | this.element.unbind('destroyed', this.teardown);
473 | this.teardown();
474 | },
475 | teardown: function() {
476 | this.unbind();
477 | },
478 | lhs: function(text) {
479 | this.editor[this.id + '-lhs'].setValue(text);
480 | },
481 | rhs: function(text) {
482 | this.editor[this.id + '-rhs'].setValue(text);
483 | },
484 | update: function() {
485 | this._changing(this.id + '-lhs', this.id + '-rhs');
486 | },
487 | unmarkup: function() {
488 | this._clear();
489 | },
490 | scrollToDiff: function(direction) {
491 | if (!this.changes.length) return;
492 | if (direction == 'next') {
493 | this._current_diff = Math.min(++this._current_diff, this.changes.length - 1);
494 | }
495 | else {
496 | this._current_diff = Math.max(--this._current_diff, 0);
497 | }
498 | this._scroll_to_change(this.changes[this._current_diff]);
499 | this._changed(this.id + '-lhs', this.id + '-rhs');
500 | },
501 | mergeCurrentChange: function(side) {
502 | if (!this.changes.length) return;
503 | if (side == 'lhs' && !this.lhs_cmsettings.readOnly) {
504 | this._merge_change(this.changes[this._current_diff], 'rhs', 'lhs');
505 | }
506 | else if (side == 'rhs' && !this.rhs_cmsettings.readOnly) {
507 | this._merge_change(this.changes[this._current_diff], 'lhs', 'rhs');
508 | }
509 | },
510 | scrollTo: function(side, num) {
511 | var le = this.editor[this.id + '-lhs'];
512 | var re = this.editor[this.id + '-rhs'];
513 | if (side == 'lhs') {
514 | le.setCursor(num);
515 | le.centerOnCursor();
516 | }
517 | else {
518 | re.setCursor(num);
519 | re.centerOnCursor();
520 | }
521 | },
522 | options: function(opts) {
523 | if (opts) {
524 | jQuery.extend(this.settings, opts);
525 | if (this.settings.autoresize) this.resize();
526 | if (this.settings.autoupdate) this.update();
527 | if (this.settings.hasOwnProperty('rhs_margin')) {
528 | // dynamically swap the margin
529 | if (this.settings.rhs_margin == 'left') {
530 | this.element.find('.mergely-margin:last-child').insertAfter(
531 | this.element.find('.mergely-canvas'));
532 | }
533 | else {
534 | var target = this.element.find('.mergely-margin').last();
535 | target.appendTo(target.parent());
536 | }
537 | }
538 | if (this.settings.hasOwnProperty('sidebar')) {
539 | // dynamically enable sidebars
540 | if (this.settings.sidebar) {
541 | jQuery(this.element).find('.mergely-margin').css({display: 'block'});
542 | }
543 | else {
544 | jQuery(this.element).find('.mergely-margin').css({display: 'none'});
545 | }
546 | }
547 | }
548 | else {
549 | return this.settings;
550 | }
551 | },
552 | swap: function() {
553 | if (this.lhs_cmsettings.readOnly || this.rhs_cmsettings.readOnly) return;
554 | var le = this.editor[this.id + '-lhs'];
555 | var re = this.editor[this.id + '-rhs'];
556 | var tmp = re.getValue();
557 | re.setValue(le.getValue());
558 | le.setValue(tmp);
559 | },
560 | merge: function(side) {
561 | var le = this.editor[this.id + '-lhs'];
562 | var re = this.editor[this.id + '-rhs'];
563 | if (side == 'lhs' && !this.lhs_cmsettings.readOnly) le.setValue(re.getValue());
564 | else if (!this.rhs_cmsettings.readOnly) re.setValue(le.getValue());
565 | },
566 | get: function(side) {
567 | var ed = this.editor[this.id + '-' + side];
568 | var t = ed.getValue();
569 | if (t == undefined) return '';
570 | return t;
571 | },
572 | clear: function(side) {
573 | if (side == 'lhs' && this.lhs_cmsettings.readOnly) return;
574 | if (side == 'rhs' && this.rhs_cmsettings.readOnly) return;
575 | var ed = this.editor[this.id + '-' + side];
576 | ed.setValue('');
577 | },
578 | cm: function(side) {
579 | return this.editor[this.id + '-' + side];
580 | },
581 | search: function(side, query, direction) {
582 | var le = this.editor[this.id + '-lhs'];
583 | var re = this.editor[this.id + '-rhs'];
584 | var editor;
585 | if (side == 'lhs') editor = le;
586 | else editor = re;
587 | direction = (direction == 'prev') ? 'findPrevious' : 'findNext';
588 | if ((editor.getSelection().length == 0) || (this.prev_query[side] != query)) {
589 | this.cursor[this.id] = editor.getSearchCursor(query, { line: 0, ch: 0 }, false);
590 | this.prev_query[side] = query;
591 | }
592 | var cursor = this.cursor[this.id];
593 |
594 | if (cursor[direction]()) {
595 | editor.setSelection(cursor.from(), cursor.to());
596 | }
597 | else {
598 | cursor = editor.getSearchCursor(query, { line: 0, ch: 0 }, false);
599 | }
600 | },
601 | resize: function() {
602 | this.settings.resize();
603 | this._changing(this.id + '-lhs', this.id + '-rhs');
604 | this._set_top_offset(this.id + '-lhs');
605 | },
606 | diff: function() {
607 | var lhs = this.editor[this.id + '-lhs'].getValue();
608 | var rhs = this.editor[this.id + '-rhs'].getValue();
609 | var d = new Mgly.diff(lhs, rhs, this.settings);
610 | return d.normal_form();
611 | },
612 | bind: function(el) {
613 | jQuery(this.element).hide();//hide
614 | this.id = jQuery(el).attr('id');
615 | var height = this.settings.editor_height;
616 | var width = this.settings.editor_width;
617 | this.changed_timeout = null;
618 | this.chfns = {};
619 | this.chfns[this.id + '-lhs'] = [];
620 | this.chfns[this.id + '-rhs'] = [];
621 | this.prev_query = [];
622 | this.cursor = [];
623 | this._skipscroll = {};
624 | this.change_exp = new RegExp(/(\d+(?:,\d+)?)([acd])(\d+(?:,\d+)?)/);
625 | var merge_lhs_button;
626 | var merge_rhs_button;
627 | if (jQuery.button != undefined) {
628 | //jquery ui
629 | merge_lhs_button = '';
630 | merge_rhs_button = '';
631 | }
632 | else {
633 | // homebrew
634 | var style = 'opacity:0.4;width:10px;height:15px;background-color:#888;cursor:pointer;text-align:center;color:#eee;border:1px solid: #222;margin-right:5px;margin-top: -2px;';
635 | merge_lhs_button = '<
';
636 | merge_rhs_button = '>
';
637 | }
638 | this.merge_rhs_button = jQuery(merge_rhs_button);
639 | this.merge_lhs_button = jQuery(merge_lhs_button);
640 |
641 | // create the textarea and canvas elements
642 | jQuery(this.element).append(jQuery(''));
643 | jQuery(this.element).append(jQuery(''));
644 | jQuery(this.element).append(jQuery(''));
645 | var rmargin = jQuery('');
646 | if (!this.settings.sidebar) {
647 | jQuery(this.element).find('.mergely-margin').css({display: 'none'});
648 | }
649 | if (this.settings.rhs_margin == 'left') {
650 | jQuery(this.element).append(rmargin);
651 | }
652 | jQuery(this.element).append(jQuery(''));
653 | if (this.settings.rhs_margin != 'left') {
654 | jQuery(this.element).append(rmargin);
655 | }
656 | //codemirror
657 | var cmstyle = '#' + this.id + ' .CodeMirror-gutter-text { padding: 5px 0 0 0; }' +
658 | '#' + this.id + ' .CodeMirror-lines pre, ' + '#' + this.id + ' .CodeMirror-gutter-text pre { line-height: 18px; }' +
659 | '.CodeMirror-linewidget { overflow: hidden; };';
660 | if (this.settings.autoresize) {
661 | cmstyle += this.id + ' .CodeMirror-scroll { height: 100%; overflow: auto; }';
662 | }
663 | // adjust the margin line height
664 | cmstyle += '\n.CodeMirror { line-height: 18px; }';
665 | jQuery('').appendTo('head');
666 |
667 | //bind
668 | var rhstx = jQuery('#' + this.id + '-rhs').get(0);
669 | if (!rhstx) {
670 | console.error('rhs textarea not defined - Mergely not initialized properly');
671 | return;
672 | }
673 | var lhstx = jQuery('#' + this.id + '-lhs').get(0);
674 | if (!rhstx) {
675 | console.error('lhs textarea not defined - Mergely not initialized properly');
676 | return;
677 | }
678 | var self = this;
679 | this.editor = [];
680 | this.editor[this.id + '-lhs'] = CodeMirror.fromTextArea(lhstx, this.lhs_cmsettings);
681 | this.editor[this.id + '-rhs'] = CodeMirror.fromTextArea(rhstx, this.rhs_cmsettings);
682 | this.editor[this.id + '-lhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); });
683 | this.editor[this.id + '-lhs'].on('scroll', function(){ self._scrolling(self.id + '-lhs'); });
684 | this.editor[this.id + '-rhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); });
685 | this.editor[this.id + '-rhs'].on('scroll', function(){ self._scrolling(self.id + '-rhs'); });
686 | // resize
687 | if (this.settings.autoresize) {
688 | var sz_timeout1 = null;
689 | var sz = function(init) {
690 | //self.em_height = null; //recalculate
691 | if (self.settings.resize) self.settings.resize(init);
692 | self.editor[self.id + '-lhs'].refresh();
693 | self.editor[self.id + '-rhs'].refresh();
694 | if (self.settings.autoupdate) {
695 | self._changing(self.id + '-lhs', self.id + '-rhs');
696 | }
697 | }
698 | jQuery(window).resize(
699 | function () {
700 | if (sz_timeout1) clearTimeout(sz_timeout1);
701 | sz_timeout1 = setTimeout(sz, self.settings.resize_timeout);
702 | }
703 | );
704 | sz(true);
705 | }
706 | //bind
707 |
708 | if (this.settings.lhs) {
709 | var setv = this.editor[this.id + '-lhs'].getDoc().setValue;
710 | this.settings.lhs(setv.bind(this.editor[this.id + '-lhs'].getDoc()));
711 | }
712 | if (this.settings.rhs) {
713 | var setv = this.editor[this.id + '-rhs'].getDoc().setValue;
714 | this.settings.rhs(setv.bind(this.editor[this.id + '-rhs'].getDoc()));
715 | }
716 | },
717 |
718 | _scroll_to_change : function(change) {
719 | if (!change) return;
720 | var self = this;
721 | var led = self.editor[self.id+'-lhs'];
722 | var red = self.editor[self.id+'-rhs'];
723 |
724 | var yref = led.getScrollerElement().offsetHeight * 1/2; // center between >0 and 1/2
725 |
726 | // set cursors
727 | led.setCursor(Math.max(change["lhs-line-from"],0), 0); // use led.getCursor().ch ?
728 | red.setCursor(Math.max(change["rhs-line-from"],0), 0);
729 |
730 | // using directly CodeMirror breaks canvas alignment
731 | // var ly = led.charCoords({line: Math.max(change["lhs-line-from"],0), ch: 0}, "local").top;
732 |
733 | // calculate scroll offset for current change. Warning: returns relative y position so we scroll to 0 first.
734 | led.scrollTo(null, 0);
735 | red.scrollTo(null, 0);
736 | self._calculate_offsets(self.id+'-lhs', self.id+'-rhs', [change]);
737 | led.scrollTo(null, Math.max(change["lhs-y-start"]-yref, 0));
738 | red.scrollTo(null, Math.max(change["rhs-y-start"]-yref, 0));
739 | // right pane should simply follows
740 | },
741 |
742 | _scrolling: function(editor_name) {
743 | if (this._skipscroll[editor_name] === true) {
744 | // scrolling one side causes the other to event - ignore it
745 | this._skipscroll[editor_name] = false;
746 | return;
747 | }
748 | var scroller = jQuery(this.editor[editor_name].getScrollerElement());
749 | if (this.midway == undefined) {
750 | this.midway = (scroller.height() / 2.0 + scroller.offset().top).toFixed(2);
751 | }
752 | // balance-line
753 | var midline = this.editor[editor_name].coordsChar({left:0, top:this.midway});
754 | var top_to = scroller.scrollTop();
755 | var left_to = scroller.scrollLeft();
756 |
757 | this.trace('scroll', 'side', editor_name);
758 | this.trace('scroll', 'midway', this.midway);
759 | this.trace('scroll', 'midline', midline);
760 | this.trace('scroll', 'top_to', top_to);
761 | this.trace('scroll', 'left_to', left_to);
762 |
763 | var editor_name1 = this.id + '-lhs';
764 | var editor_name2 = this.id + '-rhs';
765 |
766 | for (var name in this.editor) {
767 | if (!this.editor.hasOwnProperty(name)) continue;
768 | if (editor_name == name) continue; //same editor
769 | var this_side = editor_name.replace(this.id + '-', '');
770 | var other_side = name.replace(this.id + '-', '');
771 | var top_adjust = 0;
772 |
773 | // find the last change that is less than or within the midway point
774 | // do not move the rhs until the lhs end point is >= the rhs end point.
775 | var last_change = null;
776 | var force_scroll = false;
777 | for (var i = 0; i < this.changes.length; ++i) {
778 | var change = this.changes[i];
779 | if ((midline.line >= change[this_side+'-line-from'])) {
780 | last_change = change;
781 | if (midline.line >= last_change[this_side+'-line-to']) {
782 | if (!change.hasOwnProperty(this_side+'-y-start') ||
783 | !change.hasOwnProperty(this_side+'-y-end') ||
784 | !change.hasOwnProperty(other_side+'-y-start') ||
785 | !change.hasOwnProperty(other_side+'-y-end')){
786 | // change outside of viewport
787 | force_scroll = true;
788 | }
789 | else {
790 | top_adjust +=
791 | (change[this_side+'-y-end'] - change[this_side+'-y-start']) -
792 | (change[other_side+'-y-end'] - change[other_side+'-y-start']);
793 | }
794 | }
795 | }
796 | }
797 |
798 | var vp = this.editor[name].getViewport();
799 | var scroll = true;
800 | if (last_change) {
801 | this.trace('scroll', 'last change before midline', last_change);
802 | if (midline.line >= vp.from && midline <= vp.to) {
803 | scroll = false;
804 | }
805 | }
806 | this.trace('scroll', 'scroll', scroll);
807 | if (scroll || force_scroll) {
808 | // scroll the other side
809 | this.trace('scroll', 'scrolling other side', top_to - top_adjust);
810 | var scroller = jQuery(this.editor[name].getScrollerElement());
811 | this._skipscroll[name] = true;//disable next event
812 | scroller.scrollTop(top_to - top_adjust).scrollLeft(left_to);
813 | }
814 | else this.trace('scroll', 'not scrolling other side');
815 |
816 | if (this.settings.autoupdate) {
817 | var timer = new Mgly.Timer();
818 | this._calculate_offsets(editor_name1, editor_name2, this.changes);
819 | this.trace('change', 'offsets time', timer.stop());
820 | this._markup_changes(editor_name1, editor_name2, this.changes);
821 | this.trace('change', 'markup time', timer.stop());
822 | this._draw_diff(editor_name1, editor_name2, this.changes);
823 | this.trace('change', 'draw time', timer.stop());
824 | }
825 | this.trace('scroll', 'scrolled');
826 | }
827 | },
828 | _changing: function(editor_name1, editor_name2) {
829 | this.trace('change', 'changing-timeout', this.changed_timeout);
830 | var self = this;
831 | if (this.changed_timeout != null) clearTimeout(this.changed_timeout);
832 | this.changed_timeout = setTimeout(function(){
833 | var timer = new Mgly.Timer();
834 | self._changed(editor_name1, editor_name2);
835 | self.trace('change', 'total time', timer.stop());
836 | }, this.settings.change_timeout);
837 | },
838 | _changed: function(editor_name1, editor_name2) {
839 | this._clear();
840 | this._diff(editor_name1, editor_name2);
841 | },
842 | _clear: function() {
843 | var self = this;
844 | for (var name in this.editor) {
845 | if (!this.editor.hasOwnProperty(name)) continue;
846 | var editor = this.editor[name];
847 | var fns = self.chfns[name];
848 | // clear editor changes
849 | editor.operation(function() {
850 | var timer = new Mgly.Timer();
851 | for (var i = 0, l = editor.lineCount(); i < l; ++i) {
852 | editor.removeLineClass(i, 'background');
853 | }
854 | for (var i = 0; i < fns.length; ++i) {
855 | //var edid = editor.getDoc().id;
856 | var change = fns[i];
857 | //if (change.doc.id != edid) continue;
858 | if (change.lines.length) {
859 | self.trace('change', 'clear text', change.lines[0].text);
860 | }
861 | change.clear();
862 | }
863 | editor.clearGutter('merge');
864 | self.trace('change', 'clear time', timer.stop());
865 | });
866 | }
867 | self.chfns[name] = [];
868 |
869 | var ex = this._draw_info(this.id + '-lhs', this.id + '-rhs');
870 | var ctx_lhs = ex.clhs.get(0).getContext('2d');
871 | var ctx_rhs = ex.crhs.get(0).getContext('2d');
872 | var ctx = ex.dcanvas.getContext('2d');
873 |
874 | ctx_lhs.beginPath();
875 | ctx_lhs.fillStyle = this.settings.bgcolor;
876 | ctx_lhs.strokeStyle = '#888';
877 | ctx_lhs.fillRect(0, 0, 6.5, ex.visible_page_height);
878 | ctx_lhs.strokeRect(0, 0, 6.5, ex.visible_page_height);
879 |
880 | ctx_rhs.beginPath();
881 | ctx_rhs.fillStyle = this.settings.bgcolor;
882 | ctx_rhs.strokeStyle = '#888';
883 | ctx_rhs.fillRect(0, 0, 6.5, ex.visible_page_height);
884 | ctx_rhs.strokeRect(0, 0, 6.5, ex.visible_page_height);
885 |
886 | ctx.beginPath();
887 | ctx.fillStyle = '#fff';
888 | ctx.fillRect(0, 0, this.draw_mid_width, ex.visible_page_height);
889 | },
890 | _diff: function(editor_name1, editor_name2) {
891 | var lhs = this.editor[editor_name1].getValue();
892 | var rhs = this.editor[editor_name2].getValue();
893 | var timer = new Mgly.Timer();
894 | var d = new Mgly.diff(lhs, rhs, this.settings);
895 | this.trace('change', 'diff time', timer.stop());
896 | this.changes = Mgly.DiffParser(d.normal_form());
897 | this.trace('change', 'parse time', timer.stop());
898 | if (this._current_diff === undefined) {
899 | // go to first difference on start-up
900 | this._current_diff = 0;
901 | this._scroll_to_change(this.changes[0]);
902 | }
903 | this.trace('change', 'scroll_to_change time', timer.stop());
904 | this._calculate_offsets(editor_name1, editor_name2, this.changes);
905 | this.trace('change', 'offsets time', timer.stop());
906 | this._markup_changes(editor_name1, editor_name2, this.changes);
907 | this.trace('change', 'markup time', timer.stop());
908 | this._draw_diff(editor_name1, editor_name2, this.changes);
909 | this.trace('change', 'draw time', timer.stop());
910 | },
911 | _parse_diff: function (editor_name1, editor_name2, diff) {
912 | this.trace('diff', 'diff results:\n', diff);
913 | var changes = [];
914 | var change_id = 0;
915 | // parse diff
916 | var diff_lines = diff.split(/\n/);
917 | for (var i = 0; i < diff_lines.length; ++i) {
918 | if (diff_lines[i].length == 0) continue;
919 | var change = {};
920 | var test = this.change_exp.exec(diff_lines[i]);
921 | if (test == null) continue;
922 | // lines are zero-based
923 | var fr = test[1].split(',');
924 | change['lhs-line-from'] = fr[0] - 1;
925 | if (fr.length == 1) change['lhs-line-to'] = fr[0] - 1;
926 | else change['lhs-line-to'] = fr[1] - 1;
927 | var to = test[3].split(',');
928 | change['rhs-line-from'] = to[0] - 1;
929 | if (to.length == 1) change['rhs-line-to'] = to[0] - 1;
930 | else change['rhs-line-to'] = to[1] - 1;
931 | // TODO: optimize for changes that are adds/removes
932 | if (change['lhs-line-from'] < 0) change['lhs-line-from'] = 0;
933 | if (change['lhs-line-to'] < 0) change['lhs-line-to'] = 0;
934 | if (change['rhs-line-from'] < 0) change['rhs-line-from'] = 0;
935 | if (change['rhs-line-to'] < 0) change['rhs-line-to'] = 0;
936 | change['op'] = test[2];
937 | changes[change_id++] = change;
938 | this.trace('diff', 'change', change);
939 | }
940 | return changes;
941 | },
942 | _get_viewport: function(editor_name1, editor_name2) {
943 | var lhsvp = this.editor[editor_name1].getViewport();
944 | var rhsvp = this.editor[editor_name2].getViewport();
945 | return {from: Math.min(lhsvp.from, rhsvp.from), to: Math.max(lhsvp.to, rhsvp.to)};
946 | },
947 | _is_change_in_view: function(vp, change) {
948 | if (!this.settings.viewport) return true;
949 | if ((change['lhs-line-from'] < vp.from && change['lhs-line-to'] < vp.to) ||
950 | (change['lhs-line-from'] > vp.from && change['lhs-line-to'] > vp.to) ||
951 | (change['rhs-line-from'] < vp.from && change['rhs-line-to'] < vp.to) ||
952 | (change['rhs-line-from'] > vp.from && change['rhs-line-to'] > vp.to)) {
953 | // if the change is outside the viewport, skip
954 | return false;
955 | }
956 | return true;
957 | },
958 | _set_top_offset: function (editor_name1) {
959 | // save the current scroll position of the editor
960 | var saveY = this.editor[editor_name1].getScrollInfo().top;
961 | // temporarily scroll to top
962 | this.editor[editor_name1].scrollTo(null, 0);
963 |
964 | // this is the distance from the top of the screen to the top of the
965 | // content of the first codemirror editor
966 | var topnode = jQuery('#' + this.id + ' .CodeMirror-measure').first();
967 | var top_offset = topnode.offset().top - 4;
968 | if(!top_offset) return false;
969 |
970 | // restore editor's scroll position
971 | this.editor[editor_name1].scrollTo(null, saveY);
972 |
973 | this.draw_top_offset = 0.5 - top_offset;
974 | return true;
975 | },
976 | _calculate_offsets: function (editor_name1, editor_name2, changes) {
977 | if (this.em_height == null) {
978 | if(!this._set_top_offset(editor_name1)) return; //try again
979 | this.em_height = this.editor[editor_name1].defaultTextHeight();
980 | if (!this.em_height) {
981 | console.warn('Failed to calculate offsets, using 18 by default');
982 | this.em_height = 18;
983 | }
984 | this.draw_lhs_min = 0.5;
985 | var c = jQuery('#' + editor_name1 + '-' + editor_name2 + '-canvas');
986 | if (!c.length) {
987 | console.error('failed to find canvas', '#' + editor_name1 + '-' + editor_name2 + '-canvas');
988 | }
989 | if (!c.width()) {
990 | console.error('canvas width is 0');
991 | return;
992 | }
993 | this.draw_mid_width = jQuery('#' + editor_name1 + '-' + editor_name2 + '-canvas').width();
994 | this.draw_rhs_max = this.draw_mid_width - 0.5; //24.5;
995 | this.draw_lhs_width = 5;
996 | this.draw_rhs_width = 5;
997 | this.trace('calc', 'change offsets calculated', {top_offset: this.draw_top_offset, lhs_min: this.draw_lhs_min, rhs_max: this.draw_rhs_max, lhs_width: this.draw_lhs_width, rhs_width: this.draw_rhs_width});
998 | }
999 | var lhschc = this.editor[editor_name1].charCoords({line: 0});
1000 | var rhschc = this.editor[editor_name2].charCoords({line: 0});
1001 | var vp = this._get_viewport(editor_name1, editor_name2);
1002 |
1003 | for (var i = 0; i < changes.length; ++i) {
1004 | var change = changes[i];
1005 |
1006 | if (!this.settings.sidebar && !this._is_change_in_view(vp, change)) {
1007 | // if the change is outside the viewport, skip
1008 | delete change['lhs-y-start'];
1009 | delete change['lhs-y-end'];
1010 | delete change['rhs-y-start'];
1011 | delete change['rhs-y-end'];
1012 | continue;
1013 | }
1014 | var llf = change['lhs-line-from'] >= 0 ? change['lhs-line-from'] : 0;
1015 | var llt = change['lhs-line-to'] >= 0 ? change['lhs-line-to'] : 0;
1016 | var rlf = change['rhs-line-from'] >= 0 ? change['rhs-line-from'] : 0;
1017 | var rlt = change['rhs-line-to'] >= 0 ? change['rhs-line-to'] : 0;
1018 |
1019 | var ls, le, rs, re;
1020 | if (this.editor[editor_name1].getOption('lineWrapping') || this.editor[editor_name1].getOption('lineWrapping')) {
1021 | // If using line-wrapping, we must get the height of the line
1022 | var tls = this.editor[editor_name1].cursorCoords({line: llf, ch: 0}, 'page');
1023 | var lhssh = this.editor[editor_name1].getLineHandle(llf);
1024 | ls = { top: tls.top, bottom: tls.top + lhssh.height };
1025 |
1026 | var tle = this.editor[editor_name1].cursorCoords({line: llt, ch: 0}, 'page');
1027 | var lhseh = this.editor[editor_name1].getLineHandle(llt);
1028 | le = { top: tle.top, bottom: tle.top + lhseh.height };
1029 |
1030 | var tls = this.editor[editor_name2].cursorCoords({line: rlf, ch: 0}, 'page');
1031 | var rhssh = this.editor[editor_name2].getLineHandle(rlf);
1032 | rs = { top: tls.top, bottom: tls.top + rhssh.height };
1033 |
1034 | var tle = this.editor[editor_name2].cursorCoords({line: rlt, ch: 0}, 'page');
1035 | var rhseh = this.editor[editor_name2].getLineHandle(rlt);
1036 | re = { top: tle.top, bottom: tle.top + rhseh.height };
1037 | }
1038 | else {
1039 | // If not using line-wrapping, we can calculate the line position
1040 | ls = {
1041 | top: lhschc.top + llf * this.em_height,
1042 | bottom: lhschc.bottom + llf * this.em_height + 2
1043 | };
1044 | le = {
1045 | top: lhschc.top + llt * this.em_height,
1046 | bottom: lhschc.bottom + llt * this.em_height + 2
1047 | };
1048 | rs = {
1049 | top: rhschc.top + rlf * this.em_height,
1050 | bottom: rhschc.bottom + rlf * this.em_height + 2
1051 | };
1052 | re = {
1053 | top: rhschc.top + rlt * this.em_height,
1054 | bottom: rhschc.bottom + rlt * this.em_height + 2
1055 | };
1056 | }
1057 |
1058 | if (change['op'] == 'a') {
1059 | // adds (right), normally start from the end of the lhs,
1060 | // except for the case when the start of the rhs is 0
1061 | if (rlf > 0) {
1062 | ls.top = ls.bottom;
1063 | ls.bottom += this.em_height;
1064 | le = ls;
1065 | }
1066 | }
1067 | else if (change['op'] == 'd') {
1068 | // deletes (left) normally finish from the end of the rhs,
1069 | // except for the case when the start of the lhs is 0
1070 | if (llf > 0) {
1071 | rs.top = rs.bottom;
1072 | rs.bottom += this.em_height;
1073 | re = rs;
1074 | }
1075 | }
1076 | change['lhs-y-start'] = this.draw_top_offset + ls.top;
1077 | if (change['op'] == 'c' || change['op'] == 'd') {
1078 | change['lhs-y-end'] = this.draw_top_offset + le.bottom;
1079 | }
1080 | else {
1081 | change['lhs-y-end'] = this.draw_top_offset + le.top;
1082 | }
1083 | change['rhs-y-start'] = this.draw_top_offset + rs.top;
1084 | if (change['op'] == 'c' || change['op'] == 'a') {
1085 | change['rhs-y-end'] = this.draw_top_offset + re.bottom;
1086 | }
1087 | else {
1088 | change['rhs-y-end'] = this.draw_top_offset + re.top;
1089 | }
1090 | this.trace('calc', 'change calculated', i, change);
1091 | }
1092 | return changes;
1093 | },
1094 | _markup_changes: function (editor_name1, editor_name2, changes) {
1095 | jQuery('.merge-button').remove(); // clear
1096 |
1097 | var self = this;
1098 | var led = this.editor[editor_name1];
1099 | var red = this.editor[editor_name2];
1100 |
1101 | var timer = new Mgly.Timer();
1102 | led.operation(function() {
1103 | for (var i = 0; i < changes.length; ++i) {
1104 | var change = changes[i];
1105 | var llf = change['lhs-line-from'] >= 0 ? change['lhs-line-from'] : 0;
1106 | var llt = change['lhs-line-to'] >= 0 ? change['lhs-line-to'] : 0;
1107 | var rlf = change['rhs-line-from'] >= 0 ? change['rhs-line-from'] : 0;
1108 | var rlt = change['rhs-line-to'] >= 0 ? change['rhs-line-to'] : 0;
1109 |
1110 | var clazz = ['mergely', 'lhs', change['op'], 'cid-' + i];
1111 | led.addLineClass(llf, 'background', 'start');
1112 | led.addLineClass(llt, 'background', 'end');
1113 |
1114 | if (llf == 0 && llt == 0 && rlf == 0) {
1115 | led.addLineClass(llf, 'background', clazz.join(' '));
1116 | led.addLineClass(llf, 'background', 'first');
1117 | }
1118 | else {
1119 | // apply change for each line in-between the changed lines
1120 | for (var j = llf; j <= llt; ++j) {
1121 | led.addLineClass(j, 'background', clazz.join(' '));
1122 | led.addLineClass(j, 'background', clazz.join(' '));
1123 | }
1124 | }
1125 |
1126 | if (!red.getOption('readOnly')) {
1127 | // add widgets to lhs, if rhs is not read only
1128 | var rhs_button = self.merge_rhs_button.clone();
1129 | if (rhs_button.button) {
1130 | //jquery-ui support
1131 | rhs_button.button({icons: {primary: 'ui-icon-triangle-1-e'}, text: false});
1132 | }
1133 | rhs_button.addClass('merge-button');
1134 | rhs_button.attr('id', 'merge-rhs-' + i);
1135 | led.setGutterMarker(llf, 'merge', rhs_button.get(0));
1136 | }
1137 | }
1138 | });
1139 |
1140 | var vp = this._get_viewport(editor_name1, editor_name2);
1141 |
1142 | this.trace('change', 'markup lhs-editor time', timer.stop());
1143 | red.operation(function() {
1144 | for (var i = 0; i < changes.length; ++i) {
1145 | var change = changes[i];
1146 | var llf = change['lhs-line-from'] >= 0 ? change['lhs-line-from'] : 0;
1147 | var llt = change['lhs-line-to'] >= 0 ? change['lhs-line-to'] : 0;
1148 | var rlf = change['rhs-line-from'] >= 0 ? change['rhs-line-from'] : 0;
1149 | var rlt = change['rhs-line-to'] >= 0 ? change['rhs-line-to'] : 0;
1150 |
1151 | if (!self._is_change_in_view(vp, change)) {
1152 | // if the change is outside the viewport, skip
1153 | continue;
1154 | }
1155 |
1156 | var clazz = ['mergely', 'rhs', change['op'], 'cid-' + i];
1157 | red.addLineClass(rlf, 'background', 'start');
1158 | red.addLineClass(rlt, 'background', 'end');
1159 |
1160 | if (rlf == 0 && rlt == 0 && llf == 0) {
1161 | red.addLineClass(rlf, 'background', clazz.join(' '));
1162 | red.addLineClass(rlf, 'background', 'first');
1163 | }
1164 | else {
1165 | // apply change for each line in-between the changed lines
1166 | for (var j = rlf; j <= rlt; ++j) {
1167 | red.addLineClass(j, 'background', clazz.join(' '));
1168 | red.addLineClass(j, 'background', clazz.join(' '));
1169 | }
1170 | }
1171 |
1172 | if (!led.getOption('readOnly')) {
1173 | // add widgets to rhs, if lhs is not read only
1174 | var lhs_button = self.merge_lhs_button.clone();
1175 | if (lhs_button.button) {
1176 | //jquery-ui support
1177 | lhs_button.button({icons: {primary: 'ui-icon-triangle-1-w'}, text: false});
1178 | }
1179 | lhs_button.addClass('merge-button');
1180 | lhs_button.attr('id', 'merge-lhs-' + i);
1181 | red.setGutterMarker(rlf, 'merge', lhs_button.get(0));
1182 | }
1183 | }
1184 | });
1185 | this.trace('change', 'markup rhs-editor time', timer.stop());
1186 |
1187 | // mark text deleted, LCS changes
1188 | var marktext = [];
1189 | for (var i = 0; this.settings.lcs && i < changes.length; ++i) {
1190 | var change = changes[i];
1191 | var llf = change['lhs-line-from'] >= 0 ? change['lhs-line-from'] : 0;
1192 | var llt = change['lhs-line-to'] >= 0 ? change['lhs-line-to'] : 0;
1193 | var rlf = change['rhs-line-from'] >= 0 ? change['rhs-line-from'] : 0;
1194 | var rlt = change['rhs-line-to'] >= 0 ? change['rhs-line-to'] : 0;
1195 |
1196 | if (!this._is_change_in_view(vp, change)) {
1197 | // if the change is outside the viewport, skip
1198 | continue;
1199 | }
1200 | if (change['op'] == 'd') {
1201 | // apply delete to cross-out (left-hand side only)
1202 | var from = llf;
1203 | var to = llt;
1204 | var to_ln = led.lineInfo(to);
1205 | if (to_ln) {
1206 | marktext.push([led, {line:from, ch:0}, {line:to, ch:to_ln.text.length}, {className: 'mergely ch d lhs'}]);
1207 | }
1208 | }
1209 | else if (change['op'] == 'c') {
1210 | // apply LCS changes to each line
1211 | for (var j = llf, k = rlf, p = 0;
1212 | ((j >= 0) && (j <= llt)) || ((k >= 0) && (k <= rlt));
1213 | ++j, ++k) {
1214 | if (k + p > rlt) {
1215 | // lhs continues past rhs, mark lhs as deleted
1216 | var lhs_line = led.getLine( j );
1217 | marktext.push([led, {line:j, ch:0}, {line:j, ch:lhs_line.length}, {className: 'mergely ch d lhs'}]);
1218 | continue;
1219 | }
1220 | if (j + p > llt) {
1221 | // rhs continues past lhs, mark rhs as added
1222 | var rhs_line = red.getLine( k );
1223 | marktext.push([red, {line:k, ch:0}, {line:k, ch:rhs_line.length}, {className: 'mergely ch a rhs'}]);
1224 | continue;
1225 | }
1226 | var lhs_line = led.getLine( j );
1227 | var rhs_line = red.getLine( k );
1228 | var lhs_start = { line: -1, ch: -1 };
1229 | var lhs_stop = { line: -1, ch: -1 };
1230 | var rhs_start = { line: -1, ch: -1 };
1231 | var rhs_stop = { line: -1, ch: -1 };
1232 |
1233 | var lcs = new Mgly.LCS(lhs_line, rhs_line);
1234 | lcs.diff(
1235 | function (from, to) {//added
1236 | marktext.push([red, {line:k, ch:from}, {line:k, ch:to}, {className: 'mergely ch a rhs'}]);
1237 | },
1238 | removed = function (from, to) {//removed
1239 | marktext.push([led, {line:j, ch:from}, {line:j, ch:to}, {className: 'mergely ch d lhs'}]);
1240 | }
1241 | );
1242 | }
1243 | }
1244 | }
1245 | this.trace('change', 'LCS marktext time', timer.stop());
1246 |
1247 | // mark changes outside closure
1248 | led.operation(function() {
1249 | // apply lhs markup
1250 | for (var i = 0; i < marktext.length; ++i) {
1251 | var m = marktext[i];
1252 | if (m[0].doc.id != led.getDoc().id) continue;
1253 | self.chfns[self.id + '-lhs'].push(m[0].markText(m[1], m[2], m[3]));
1254 | }
1255 | });
1256 | red.operation(function() {
1257 | // apply lhs markup
1258 | for (var i = 0; i < marktext.length; ++i) {
1259 | var m = marktext[i];
1260 | if (m[0].doc.id != red.getDoc().id) continue;
1261 | self.chfns[self.id + '-rhs'].push(m[0].markText(m[1], m[2], m[3]));
1262 | }
1263 | });
1264 | this.trace('change', 'LCS markup time', timer.stop());
1265 |
1266 | // merge buttons
1267 | var ed = {lhs:led, rhs:red};
1268 | jQuery('.merge-button').on('click', function(ev){
1269 | // side of mouseenter
1270 | var side = 'rhs';
1271 | var oside = 'lhs';
1272 | var parent = jQuery(this).parents('#' + self.id + '-editor-lhs');
1273 | if (parent.length) {
1274 | side = 'lhs';
1275 | oside = 'rhs';
1276 | }
1277 | var pos = ed[side].coordsChar({left:ev.pageX, top:ev.pageY});
1278 |
1279 | // get the change id
1280 | var cid = null;
1281 | var info = ed[side].lineInfo(pos.line);
1282 | jQuery.each(info.bgClass.split(' '), function(i, clazz) {
1283 | if (clazz.indexOf('cid-') == 0) {
1284 | cid = parseInt(clazz.split('-')[1], 10);
1285 | return false;
1286 | }
1287 | });
1288 | var change = self.changes[cid];
1289 | self._merge_change(change, side, oside);
1290 | return false;
1291 | });
1292 | this.trace('change', 'markup buttons time', timer.stop());
1293 | },
1294 | _merge_change : function(change, side, oside) {
1295 | if (!change) return;
1296 | var led = this.editor[this.id+'-lhs'];
1297 | var red = this.editor[this.id+'-rhs'];
1298 | var ed = {lhs:led, rhs:red};
1299 |
1300 |
1301 | var text = ed[side].getRange(
1302 | CodeMirror.Pos(change[side + '-line-from'], 0),
1303 | CodeMirror.Pos(change[side + '-line-to'] + 1, 0));
1304 |
1305 | if (change['op'] == 'c') {
1306 | ed[oside].replaceRange(text,
1307 | CodeMirror.Pos(change[oside + '-line-from'], 0),
1308 | CodeMirror.Pos(change[oside + '-line-to'] + 1, 0));
1309 | }
1310 | else if (side == 'rhs') {
1311 | if (change['op'] == 'a') {
1312 | ed[oside].replaceRange(text,
1313 | CodeMirror.Pos(change[oside + '-line-from'] + 1, 0),
1314 | CodeMirror.Pos(change[oside + '-line-to'] + 1, 0));
1315 | }
1316 | else {// 'd'
1317 | var from = parseInt(change[oside + '-line-from']);
1318 | var to = parseInt(change[oside + '-line-to']);
1319 | for (var i = to; i >= from; --i) {
1320 | ed[oside].removeLine(i);
1321 | }
1322 | }
1323 | }
1324 | else if (side == 'lhs') {
1325 | if (change['op'] == 'a') {
1326 | var from = parseInt(change[oside + '-line-from']);
1327 | var to = parseInt(change[oside + '-line-to']);
1328 | for (var i = to; i >= from; --i) {
1329 | ed[oside].removeLine(i);
1330 | }
1331 | }
1332 | else {// 'd'
1333 | ed[oside].replaceRange( text,
1334 | CodeMirror.Pos(change[oside + '-line-from'] + 1, 0));
1335 | }
1336 | }
1337 | //reset
1338 | ed['lhs'].setValue(ed['lhs'].getValue());
1339 | ed['rhs'].setValue(ed['rhs'].getValue());
1340 |
1341 | this._scroll_to_change(change)
1342 | },
1343 | _draw_info: function(editor_name1, editor_name2) {
1344 | var visible_page_height = jQuery(this.editor[editor_name1].getScrollerElement()).height();
1345 | var gutter_height = jQuery(this.editor[editor_name1].getScrollerElement()).children(':first-child').height();
1346 | var dcanvas = document.getElementById(editor_name1 + '-' + editor_name2 + '-canvas');
1347 | if (dcanvas == undefined) throw 'Failed to find: ' + editor_name1 + '-' + editor_name2 + '-canvas';
1348 | var clhs = jQuery('#' + this.id + '-lhs-margin');
1349 | var crhs = jQuery('#' + this.id + '-rhs-margin');
1350 | return {
1351 | visible_page_height: visible_page_height,
1352 | gutter_height: gutter_height,
1353 | visible_page_ratio: (visible_page_height / gutter_height),
1354 | margin_ratio: (visible_page_height / gutter_height),
1355 | lhs_scroller: jQuery(this.editor[editor_name1].getScrollerElement()),
1356 | rhs_scroller: jQuery(this.editor[editor_name2].getScrollerElement()),
1357 | lhs_lines: this.editor[editor_name1].lineCount(),
1358 | rhs_lines: this.editor[editor_name2].lineCount(),
1359 | dcanvas: dcanvas,
1360 | clhs: clhs,
1361 | crhs: crhs,
1362 | lhs_xyoffset: jQuery(clhs).offset(),
1363 | rhs_xyoffset: jQuery(crhs).offset()
1364 | };
1365 | },
1366 | _draw_diff: function(editor_name1, editor_name2, changes) {
1367 | var ex = this._draw_info(editor_name1, editor_name2);
1368 | var mcanvas_lhs = ex.clhs.get(0);
1369 | var mcanvas_rhs = ex.crhs.get(0);
1370 | var ctx = ex.dcanvas.getContext('2d');
1371 | var ctx_lhs = mcanvas_lhs.getContext('2d');
1372 | var ctx_rhs = mcanvas_rhs.getContext('2d');
1373 |
1374 | this.trace('draw', 'visible_page_height', ex.visible_page_height);
1375 | this.trace('draw', 'gutter_height', ex.gutter_height);
1376 | this.trace('draw', 'visible_page_ratio', ex.visible_page_ratio);
1377 | this.trace('draw', 'lhs-scroller-top', ex.lhs_scroller.scrollTop());
1378 | this.trace('draw', 'rhs-scroller-top', ex.rhs_scroller.scrollTop());
1379 |
1380 | jQuery.each(jQuery.find('#' + this.id + ' canvas'), function () {
1381 | jQuery(this).get(0).height = ex.visible_page_height;
1382 | });
1383 |
1384 | ex.clhs.unbind('click');
1385 | ex.crhs.unbind('click');
1386 |
1387 | ctx_lhs.beginPath();
1388 | ctx_lhs.fillStyle = this.settings.bgcolor;
1389 | ctx_lhs.strokeStyle = '#888';
1390 | ctx_lhs.fillRect(0, 0, 6.5, ex.visible_page_height);
1391 | ctx_lhs.strokeRect(0, 0, 6.5, ex.visible_page_height);
1392 |
1393 | ctx_rhs.beginPath();
1394 | ctx_rhs.fillStyle = this.settings.bgcolor;
1395 | ctx_rhs.strokeStyle = '#888';
1396 | ctx_rhs.fillRect(0, 0, 6.5, ex.visible_page_height);
1397 | ctx_rhs.strokeRect(0, 0, 6.5, ex.visible_page_height);
1398 |
1399 | var vp = this._get_viewport(editor_name1, editor_name2);
1400 | for (var i = 0; i < changes.length; ++i) {
1401 | var change = changes[i];
1402 |
1403 | this.trace('draw', change);
1404 | // margin indicators
1405 | var lhs_y_start = ((change['lhs-y-start'] + ex.lhs_scroller.scrollTop()) * ex.visible_page_ratio);
1406 | var lhs_y_end = ((change['lhs-y-end'] + ex.lhs_scroller.scrollTop()) * ex.visible_page_ratio) + 1;
1407 | var rhs_y_start = ((change['rhs-y-start'] + ex.rhs_scroller.scrollTop()) * ex.visible_page_ratio);
1408 | var rhs_y_end = ((change['rhs-y-end'] + ex.rhs_scroller.scrollTop()) * ex.visible_page_ratio) + 1;
1409 | this.trace('draw', 'marker calculated', lhs_y_start, lhs_y_end, rhs_y_start, rhs_y_end);
1410 |
1411 | ctx_lhs.beginPath();
1412 | ctx_lhs.fillStyle = this.settings.fgcolor[(this._current_diff==i?'c':'')+change['op']];
1413 | ctx_lhs.strokeStyle = '#000';
1414 | ctx_lhs.lineWidth = 0.5;
1415 | ctx_lhs.fillRect(1.5, lhs_y_start, 4.5, Math.max(lhs_y_end - lhs_y_start, 5));
1416 | ctx_lhs.strokeRect(1.5, lhs_y_start, 4.5, Math.max(lhs_y_end - lhs_y_start, 5));
1417 |
1418 | ctx_rhs.beginPath();
1419 | ctx_rhs.fillStyle = this.settings.fgcolor[(this._current_diff==i?'c':'')+change['op']];
1420 | ctx_rhs.strokeStyle = '#000';
1421 | ctx_rhs.lineWidth = 0.5;
1422 | ctx_rhs.fillRect(1.5, rhs_y_start, 4.5, Math.max(rhs_y_end - rhs_y_start, 5));
1423 | ctx_rhs.strokeRect(1.5, rhs_y_start, 4.5, Math.max(rhs_y_end - rhs_y_start, 5));
1424 |
1425 | if (!this._is_change_in_view(vp, change)) {
1426 | continue;
1427 | }
1428 |
1429 | lhs_y_start = change['lhs-y-start'];
1430 | lhs_y_end = change['lhs-y-end'];
1431 | rhs_y_start = change['rhs-y-start'];
1432 | rhs_y_end = change['rhs-y-end'];
1433 |
1434 | var radius = 3;
1435 |
1436 | // draw left box
1437 | ctx.beginPath();
1438 | ctx.strokeStyle = this.settings.fgcolor[(this._current_diff==i?'c':'')+change['op']];
1439 | ctx.lineWidth = (this._current_diff==i) ? 1.5 : 1;
1440 |
1441 | var rectWidth = this.draw_lhs_width;
1442 | var rectHeight = lhs_y_end - lhs_y_start - 1;
1443 | var rectX = this.draw_lhs_min;
1444 | var rectY = lhs_y_start;
1445 | // top and top top-right corner
1446 |
1447 | // draw left box
1448 | ctx.moveTo(rectX, rectY);
1449 | if (navigator.appName == 'Microsoft Internet Explorer') {
1450 | // IE arcs look awful
1451 | ctx.lineTo(this.draw_lhs_min + this.draw_lhs_width, lhs_y_start);
1452 | ctx.lineTo(this.draw_lhs_min + this.draw_lhs_width, lhs_y_end + 1);
1453 | ctx.lineTo(this.draw_lhs_min, lhs_y_end + 1);
1454 | }
1455 | else {
1456 | if (rectHeight <= 0) {
1457 | ctx.lineTo(rectX + rectWidth, rectY);
1458 | }
1459 | else {
1460 | ctx.arcTo(rectX + rectWidth, rectY, rectX + rectWidth, rectY + radius, radius);
1461 | ctx.arcTo(rectX + rectWidth, rectY + rectHeight, rectX + rectWidth - radius, rectY + rectHeight, radius);
1462 | }
1463 | // bottom line
1464 | ctx.lineTo(rectX, rectY + rectHeight);
1465 | }
1466 | ctx.stroke();
1467 |
1468 | rectWidth = this.draw_rhs_width;
1469 | rectHeight = rhs_y_end - rhs_y_start - 1;
1470 | rectX = this.draw_rhs_max;
1471 | rectY = rhs_y_start;
1472 |
1473 | // draw right box
1474 | ctx.moveTo(rectX, rectY);
1475 | if (navigator.appName == 'Microsoft Internet Explorer') {
1476 | ctx.lineTo(this.draw_rhs_max - this.draw_rhs_width, rhs_y_start);
1477 | ctx.lineTo(this.draw_rhs_max - this.draw_rhs_width, rhs_y_end + 1);
1478 | ctx.lineTo(this.draw_rhs_max, rhs_y_end + 1);
1479 | }
1480 | else {
1481 | if (rectHeight <= 0) {
1482 | ctx.lineTo(rectX - rectWidth, rectY);
1483 | }
1484 | else {
1485 | ctx.arcTo(rectX - rectWidth, rectY, rectX - rectWidth, rectY + radius, radius);
1486 | ctx.arcTo(rectX - rectWidth, rectY + rectHeight, rectX - radius, rectY + rectHeight, radius);
1487 | }
1488 | ctx.lineTo(rectX, rectY + rectHeight);
1489 | }
1490 | ctx.stroke();
1491 |
1492 | // connect boxes
1493 | var cx = this.draw_lhs_min + this.draw_lhs_width;
1494 | var cy = lhs_y_start + (lhs_y_end + 1 - lhs_y_start) / 2.0;
1495 | var dx = this.draw_rhs_max - this.draw_rhs_width;
1496 | var dy = rhs_y_start + (rhs_y_end + 1 - rhs_y_start) / 2.0;
1497 | ctx.moveTo(cx, cy);
1498 | if (cy == dy) {
1499 | ctx.lineTo(dx, dy);
1500 | }
1501 | else {
1502 | // fancy!
1503 | ctx.bezierCurveTo(
1504 | cx + 12, cy - 3, // control-1 X,Y
1505 | dx - 12, dy - 3, // control-2 X,Y
1506 | dx, dy);
1507 | }
1508 | ctx.stroke();
1509 | }
1510 |
1511 | // visible window feedback
1512 | ctx_lhs.fillStyle = this.settings.vpcolor;
1513 | ctx_rhs.fillStyle = this.settings.vpcolor;
1514 |
1515 | var lto = ex.clhs.height() * ex.visible_page_ratio;
1516 | var lfrom = (ex.lhs_scroller.scrollTop() / ex.gutter_height) * ex.clhs.height();
1517 | var rto = ex.crhs.height() * ex.visible_page_ratio;
1518 | var rfrom = (ex.rhs_scroller.scrollTop() / ex.gutter_height) * ex.crhs.height();
1519 | this.trace('draw', 'cls.height', ex.clhs.height());
1520 | this.trace('draw', 'lhs_scroller.scrollTop()', ex.lhs_scroller.scrollTop());
1521 | this.trace('draw', 'gutter_height', ex.gutter_height);
1522 | this.trace('draw', 'visible_page_ratio', ex.visible_page_ratio);
1523 | this.trace('draw', 'lhs from', lfrom, 'lhs to', lto);
1524 | this.trace('draw', 'rhs from', rfrom, 'rhs to', rto);
1525 |
1526 | ctx_lhs.fillRect(1.5, lfrom, 4.5, lto);
1527 | ctx_rhs.fillRect(1.5, rfrom, 4.5, rto);
1528 |
1529 | ex.clhs.click(function (ev) {
1530 | var y = ev.pageY - ex.lhs_xyoffset.top - (lto / 2);
1531 | var sto = Math.max(0, (y / mcanvas_lhs.height) * ex.lhs_scroller.get(0).scrollHeight);
1532 | ex.lhs_scroller.scrollTop(sto);
1533 | });
1534 | ex.crhs.click(function (ev) {
1535 | var y = ev.pageY - ex.rhs_xyoffset.top - (rto / 2);
1536 | var sto = Math.max(0, (y / mcanvas_rhs.height) * ex.rhs_scroller.get(0).scrollHeight);
1537 | ex.rhs_scroller.scrollTop(sto);
1538 | });
1539 | },
1540 | trace: function(name) {
1541 | if(this.settings._debug.indexOf(name) >= 0) {
1542 | arguments[0] = name+':';
1543 | console.log([].slice.apply(arguments));
1544 | }
1545 | }
1546 | });
1547 |
1548 | jQuery.pluginMaker = function(plugin) {
1549 | // add the plugin function as a jQuery plugin
1550 | jQuery.fn[plugin.prototype.name] = function(options) {
1551 | // get the arguments
1552 | var args = jQuery.makeArray(arguments),
1553 | after = args.slice(1);
1554 | var rc = undefined;
1555 | this.each(function() {
1556 | // see if we have an instance
1557 | var instance = jQuery.data(this, plugin.prototype.name);
1558 | if (instance) {
1559 | // call a method on the instance
1560 | if (typeof options == "string") {
1561 | rc = instance[options].apply(instance, after);
1562 | } else if (instance.update) {
1563 | // call update on the instance
1564 | return instance.update.apply(instance, args);
1565 | }
1566 | } else {
1567 | // create the plugin
1568 | new plugin(this, options);
1569 | }
1570 | });
1571 | if (rc != undefined) return rc;
1572 | };
1573 | };
1574 |
1575 | // make the mergely widget
1576 | jQuery.pluginMaker(Mgly.mergely);
1577 |
--------------------------------------------------------------------------------
/lib/mergely.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2014 by Jamie Peabody, http://www.mergely.com
3 | * All rights reserved.
4 | * Version: 3.3.7 2014-08-17
5 | */
6 | Mgly={},Mgly.Timer=function(){var a=this;a.start=function(){a.t0=(new Date).getTime()},a.stop=function(){var b=(new Date).getTime(),c=b-a.t0;return a.t0=b,c},a.start()},Mgly.ChangeExpression=new RegExp(/(^(?![><-])*\d+(?:,\d+)?)([acd])(\d+(?:,\d+)?)/),Mgly.DiffParser=function(a){for(var b=[],c=0,d=a.split(/\n/),e=0;e0&&"c"==h.op&&(e+=1),b(e,e+i.length)}if("d"!=h.op){e=c.getLines("rhs").slice(0,h["rhs-line-from"]).join(" ").length,f=h["rhs-line-to"]+1;var j=c.getLines("rhs").slice(h["rhs-line-from"],f).join(" ");"a"==h.op?j+=" ":e>0&&"c"==h.op&&(e+=1),a(e,e+j.length)}}}}),Mgly.CodeifyText=function(a){this._max_code=0,this._diff_codes={},this.ctxs={},this.options={ignorews:!1},jQuery.extend(this,a),this.lhs=a.lhs.split("\n"),this.rhs=a.rhs.split("\n")},jQuery.extend(Mgly.CodeifyText.prototype,{getCodes:function(a){if(!this.ctxs.hasOwnProperty(a)){var b=this._diff_ctx(this[a]);this.ctxs[a]=b,b.codes.length=Object.keys(b.codes).length}return this.ctxs[a].codes},getLines:function(a){return this.ctxs[a].lines},_diff_ctx:function(a){var b={i:0,codes:{},lines:a};return this._codeify(a,b),b},_codeify:function(a,b){this._max_code;for(var d=0;d0?f="a":c.lhs_deleted_count>0&&0==c.rhs_inserted_count&&(f="d"),d=1==c.lhs_deleted_count?c.lhs_start+1:0==c.lhs_deleted_count?c.lhs_start:c.lhs_start+1+","+(c.lhs_start+c.lhs_deleted_count),e=1==c.rhs_inserted_count?c.rhs_start+1:0==c.rhs_inserted_count?c.rhs_start:c.rhs_start+1+","+(c.rhs_start+c.rhs_inserted_count),a+=d+f+e+"\n";var g=this.getLines("lhs"),h=this.getLines("rhs");if(h&&g){for(var i=c.lhs_start;i "+h[i]+"\n"}}return a},_lcs:function(a,b,c,d,e,f,g,h){for(;c>b&&f>e&&a.codes[b]==d.codes[e];)++b,++e;for(;c>b&&f>e&&a.codes[c-1]==d.codes[f-1];)--c,--f;if(b==c)for(;f>e;)d.modified[e++]=!0;else if(e==f)for(;c>b;)a.modified[b++]=!0;else{var i=this._sms(a,b,c,d,e,f,g,h);this._lcs(a,b,i.x,d,e,i.y,g,h),this._lcs(a,i.x,c,d,i.y,f,g,h)}},_sms:function(a,b,c,d,e,f,g,h){var i=a.codes.length+d.codes.length+1,j=b-e,k=c-f,l=c-b-(f-e),m=0!=(1&l),n=i-j,o=i-k,p=(c-b+f-e)/2+1;h[n+j+1]=b,g[o+k-1]=c;for(var q={x:0,y:0},r=0;p>=r;++r){for(var s=j-r;j+r>=s;s+=2){var t,u;for(s==j-r?t=h[n+s+1]:(t=h[n+s-1]+1,j+r>s&&h[n+s+1]>=t&&(t=h[n+s+1])),u=t-s;c>t&&f>u&&a.codes[t]==d.codes[u];)t++,u++;if(h[n+s]=t,m&&s>k-r&&k+r>s&&g[o+s]<=h[n+s])return q.x=h[n+s],q.y=h[n+s]-s,q}for(var s=k-r;k+r>=s;s+=2){var t,u;for(s==k+r?t=g[o+s-1]:(t=g[o+s+1]-1,s>k-r&&g[o+s-1]b&&u>e&&a.codes[t-1]==d.codes[u-1];)t--,u--;if(g[o+s]=t,!m&&s>=j-r&&j+r>=s&&g[o+s]<=h[n+s])return q.x=h[n+s],q.y=h[n+s]-s,q}}throw"the algorithm should never come here."},_optimize:function(a){for(var b=0,c=0;b=b.codes.length||a.modified[f]);)f++;for(;g=a.codes.length||b.modified[g]);)g++;(f>d||g>e)&&c.push({lhs_start:d,rhs_start:e,lhs_deleted_count:f-d,rhs_inserted_count:g-e})}return c}}),Mgly.mergely=function(a,b){a&&this.init(a,b)},jQuery.extend(Mgly.mergely.prototype,{name:"mergely",init:function(a,b){this.diffView=new Mgly.CodeMirrorDiffView(a,b),this.bind(a)},bind:function(a){this.diffView.bind(a)}}),Mgly.CodeMirrorDiffView=function(a,b){CodeMirror.defineExtension("centerOnCursor",function(){var a=this.cursorCoords(null,"local");this.scrollTo(null,(a.y+a.yBot)/2-this.getScrollerElement().clientHeight/2)}),this.init(a,b)},jQuery.extend(Mgly.CodeMirrorDiffView.prototype,{init:function(a,b){this.settings={autoupdate:!0,autoresize:!0,rhs_margin:"right",lcs:!0,sidebar:!0,viewport:!1,ignorews:!1,fadein:"fast",editor_width:"650px",editor_height:"400px",resize_timeout:500,change_timeout:150,fgcolor:{a:"#4ba3fa",c:"#a3a3a3",d:"#ff7f7f",ca:"#4b73ff",cc:"#434343",cd:"#ff4f4f"},bgcolor:"#eee",vpcolor:"rgba(0, 0, 200, 0.5)",lhs:function(){},rhs:function(){},loaded:function(){},_auto_width:function(a){return a},resize:function(b){var c=b?16:0,d=jQuery(a).parent().width()+c;"auto"==this.width?d=this._auto_width(d):(d=this.width,this.editor_width=d),"auto"==this.height?h=jQuery(a).parent().height():(h=this.height,this.editor_height=h);var e=d/2-16-8,f=h,g=jQuery(a);g.find(".mergely-column").css({width:e+"px"}),g.find(".mergely-column, .mergely-canvas, .mergely-margin, .mergely-column textarea, .CodeMirror-scroll, .cm-s-default").css({height:f+"px"}),g.find(".mergely-canvas").css({height:f+"px"}),g.find(".mergely-column textarea").css({width:e+"px"}),g.css({width:d,height:h,clear:"both"}),"none"==g.css("display")&&(0!=this.fadein?g.fadeIn(this.fadein):g.show(),this.loaded&&this.loaded()),this.resized&&this.resized()},_debug:"",resized:function(){}};var c={mode:"text/plain",readOnly:!1,lineWrapping:!1,lineNumbers:!0,gutters:["merge","CodeMirror-linenumbers"]};this.lhs_cmsettings={},this.rhs_cmsettings={},this.element=jQuery(a),b&&b.cmsettings&&jQuery.extend(this.lhs_cmsettings,c,b.cmsettings,b.lhs_cmsettings),b&&b.cmsettings&&jQuery.extend(this.rhs_cmsettings,c,b.cmsettings,b.rhs_cmsettings),b&&jQuery.extend(this.settings,b),this.element.bind("destroyed",jQuery.proxy(this.teardown,this)),jQuery.data(a,"mergely",this)},unbind:function(){null!=this.changed_timeout&&clearTimeout(this.changed_timeout),this.editor[this.id+"-lhs"].toTextArea(),this.editor[this.id+"-rhs"].toTextArea()},destroy:function(){this.element.unbind("destroyed",this.teardown),this.teardown()},teardown:function(){this.unbind()},lhs:function(a){this.editor[this.id+"-lhs"].setValue(a)},rhs:function(a){this.editor[this.id+"-rhs"].setValue(a)},update:function(){this._changing(this.id+"-lhs",this.id+"-rhs")},unmarkup:function(){this._clear()},scrollToDiff:function(a){this.changes.length&&(this._current_diff="next"==a?Math.min(++this._current_diff,this.changes.length-1):Math.max(--this._current_diff,0),this._scroll_to_change(this.changes[this._current_diff]),this._changed(this.id+"-lhs",this.id+"-rhs"))},mergeCurrentChange:function(a){this.changes.length&&("lhs"!=a||this.lhs_cmsettings.readOnly?"rhs"!=a||this.rhs_cmsettings.readOnly||this._merge_change(this.changes[this._current_diff],"lhs","rhs"):this._merge_change(this.changes[this._current_diff],"rhs","lhs"))},scrollTo:function(a,b){var c=this.editor[this.id+"-lhs"],d=this.editor[this.id+"-rhs"];"lhs"==a?(c.setCursor(b),c.centerOnCursor()):(d.setCursor(b),d.centerOnCursor())},options:function(a){if(!a)return this.settings;if(jQuery.extend(this.settings,a),this.settings.autoresize&&this.resize(),this.settings.autoupdate&&this.update(),this.settings.hasOwnProperty("rhs_margin"))if("left"==this.settings.rhs_margin)this.element.find(".mergely-margin:last-child").insertAfter(this.element.find(".mergely-canvas"));else{var b=this.element.find(".mergely-margin").last();b.appendTo(b.parent())}this.settings.hasOwnProperty("sidebar")&&(this.settings.sidebar?jQuery(this.element).find(".mergely-margin").css({display:"block"}):jQuery(this.element).find(".mergely-margin").css({display:"none"}))},swap:function(){if(!this.lhs_cmsettings.readOnly&&!this.rhs_cmsettings.readOnly){var a=this.editor[this.id+"-lhs"],b=this.editor[this.id+"-rhs"],c=b.getValue();b.setValue(a.getValue()),a.setValue(c)}},merge:function(a){var b=this.editor[this.id+"-lhs"],c=this.editor[this.id+"-rhs"];"lhs"!=a||this.lhs_cmsettings.readOnly?this.rhs_cmsettings.readOnly||c.setValue(b.getValue()):b.setValue(c.getValue())},get:function(a){var b=this.editor[this.id+"-"+a],c=b.getValue();return void 0==c?"":c},clear:function(a){if(!("lhs"==a&&this.lhs_cmsettings.readOnly||"rhs"==a&&this.rhs_cmsettings.readOnly)){var b=this.editor[this.id+"-"+a];b.setValue("")}},cm:function(a){return this.editor[this.id+"-"+a]},search:function(a,b,c){var f,d=this.editor[this.id+"-lhs"],e=this.editor[this.id+"-rhs"];f="lhs"==a?d:e,c="prev"==c?"findPrevious":"findNext",(0==f.getSelection().length||this.prev_query[a]!=b)&&(this.cursor[this.id]=f.getSearchCursor(b,{line:0,ch:0},!1),this.prev_query[a]=b);var g=this.cursor[this.id];g[c]()?f.setSelection(g.from(),g.to()):g=f.getSearchCursor(b,{line:0,ch:0},!1)},resize:function(){this.settings.resize(),this._changing(this.id+"-lhs",this.id+"-rhs"),this._set_top_offset(this.id+"-lhs")},diff:function(){var a=this.editor[this.id+"-lhs"].getValue(),b=this.editor[this.id+"-rhs"].getValue(),c=new Mgly.diff(a,b,this.settings);return c.normal_form()},bind:function(a){jQuery(this.element).hide(),this.id=jQuery(a).attr("id");var b=this.settings.editor_height,c=this.settings.editor_width;this.changed_timeout=null,this.chfns={},this.chfns[this.id+"-lhs"]=[],this.chfns[this.id+"-rhs"]=[],this.prev_query=[],this.cursor=[],this._skipscroll={},this.change_exp=new RegExp(/(\d+(?:,\d+)?)([acd])(\d+(?:,\d+)?)/);var d,e;if(void 0!=jQuery.button)d='',e='';else{var f="opacity:0.4;width:10px;height:15px;background-color:#888;cursor:pointer;text-align:center;color:#eee;border:1px solid: #222;margin-right:5px;margin-top: -2px;";d='<
',e='>
'}this.merge_rhs_button=jQuery(e),this.merge_lhs_button=jQuery(d),jQuery(this.element).append(jQuery('')),jQuery(this.element).append(jQuery('')),jQuery(this.element).append(jQuery(''));var g=jQuery('');this.settings.sidebar||jQuery(this.element).find(".mergely-margin").css({display:"none"}),"left"==this.settings.rhs_margin&&jQuery(this.element).append(g),jQuery(this.element).append(jQuery('')),"left"!=this.settings.rhs_margin&&jQuery(this.element).append(g);var h="#"+this.id+" .CodeMirror-gutter-text { padding: 5px 0 0 0; }"+"#"+this.id+" .CodeMirror-lines pre, "+"#"+this.id+" .CodeMirror-gutter-text pre { line-height: 18px; }"+".CodeMirror-linewidget { overflow: hidden; };";this.settings.autoresize&&(h+=this.id+" .CodeMirror-scroll { height: 100%; overflow: auto; }"),h+="\n.CodeMirror { line-height: 18px; }",jQuery('").appendTo("head");var i=jQuery("#"+this.id+"-rhs").get(0);if(!i)return console.error("rhs textarea not defined - Mergely not initialized properly"),void 0;var j=jQuery("#"+this.id+"-lhs").get(0);if(!i)return console.error("lhs textarea not defined - Mergely not initialized properly"),void 0;var k=this;if(this.editor=[],this.editor[this.id+"-lhs"]=CodeMirror.fromTextArea(j,this.lhs_cmsettings),this.editor[this.id+"-rhs"]=CodeMirror.fromTextArea(i,this.rhs_cmsettings),this.editor[this.id+"-lhs"].on("change",function(){k.settings.autoupdate&&k._changing(k.id+"-lhs",k.id+"-rhs")}),this.editor[this.id+"-lhs"].on("scroll",function(){k._scrolling(k.id+"-lhs")}),this.editor[this.id+"-rhs"].on("change",function(){k.settings.autoupdate&&k._changing(k.id+"-lhs",k.id+"-rhs")}),this.editor[this.id+"-rhs"].on("scroll",function(){k._scrolling(k.id+"-rhs")}),this.settings.autoresize){var l=null,m=function(a){k.settings.resize&&k.settings.resize(a),k.editor[k.id+"-lhs"].refresh(),k.editor[k.id+"-rhs"].refresh(),k.settings.autoupdate&&k._changing(k.id+"-lhs",k.id+"-rhs")};jQuery(window).resize(function(){l&&clearTimeout(l),l=setTimeout(m,k.settings.resize_timeout)}),m(!0)}if(this.settings.lhs){var n=this.editor[this.id+"-lhs"].getDoc().setValue;this.settings.lhs(n.bind(this.editor[this.id+"-lhs"].getDoc()))}if(this.settings.rhs){var n=this.editor[this.id+"-rhs"].getDoc().setValue;this.settings.rhs(n.bind(this.editor[this.id+"-rhs"].getDoc()))}},_scroll_to_change:function(a){if(a){var b=this,c=b.editor[b.id+"-lhs"],d=b.editor[b.id+"-rhs"],e=1*c.getScrollerElement().offsetHeight/2;c.setCursor(Math.max(a["lhs-line-from"],0),0),d.setCursor(Math.max(a["rhs-line-from"],0),0),c.scrollTo(null,0),d.scrollTo(null,0),b._calculate_offsets(b.id+"-lhs",b.id+"-rhs",[a]),c.scrollTo(null,Math.max(a["lhs-y-start"]-e,0)),d.scrollTo(null,Math.max(a["rhs-y-start"]-e,0))}},_scrolling:function(a){if(this._skipscroll[a]===!0)return this._skipscroll[a]=!1,void 0;var b=jQuery(this.editor[a].getScrollerElement());void 0==this.midway&&(this.midway=(b.height()/2+b.offset().top).toFixed(2));var c=this.editor[a].coordsChar({left:0,top:this.midway}),d=b.scrollTop(),e=b.scrollLeft();this.trace("scroll","side",a),this.trace("scroll","midway",this.midway),this.trace("scroll","midline",c),this.trace("scroll","top_to",d),this.trace("scroll","left_to",e);var f=this.id+"-lhs",g=this.id+"-rhs";for(var h in this.editor)if(this.editor.hasOwnProperty(h)&&a!=h){for(var i=a.replace(this.id+"-",""),j=h.replace(this.id+"-",""),k=0,l=null,m=!1,n=0;n=o[i+"-line-from"]&&(l=o,c.line>=l[i+"-line-to"]&&(o.hasOwnProperty(i+"-y-start")&&o.hasOwnProperty(i+"-y-end")&&o.hasOwnProperty(j+"-y-start")&&o.hasOwnProperty(j+"-y-end")?k+=o[i+"-y-end"]-o[i+"-y-start"]-(o[j+"-y-end"]-o[j+"-y-start"]):m=!0))}var p=this.editor[h].getViewport(),q=!0;if(l&&(this.trace("scroll","last change before midline",l),c.line>=p.from&&c<=p.to&&(q=!1)),this.trace("scroll","scroll",q),q||m){this.trace("scroll","scrolling other side",d-k);var b=jQuery(this.editor[h].getScrollerElement());this._skipscroll[h]=!0,b.scrollTop(d-k).scrollLeft(e)}else this.trace("scroll","not scrolling other side");if(this.settings.autoupdate){var r=new Mgly.Timer;this._calculate_offsets(f,g,this.changes),this.trace("change","offsets time",r.stop()),this._markup_changes(f,g,this.changes),this.trace("change","markup time",r.stop()),this._draw_diff(f,g,this.changes),this.trace("change","draw time",r.stop())}this.trace("scroll","scrolled")}},_changing:function(a,b){this.trace("change","changing-timeout",this.changed_timeout);var c=this;null!=this.changed_timeout&&clearTimeout(this.changed_timeout),this.changed_timeout=setTimeout(function(){var d=new Mgly.Timer;c._changed(a,b),c.trace("change","total time",d.stop())},this.settings.change_timeout)},_changed:function(a,b){this._clear(),this._diff(a,b)},_clear:function(){var a=this;for(var b in this.editor)if(this.editor.hasOwnProperty(b)){var c=this.editor[b],d=a.chfns[b];c.operation(function(){for(var b=new Mgly.Timer,e=0,f=c.lineCount();f>e;++e)c.removeLineClass(e,"background");for(var e=0;ea.from&&b["lhs-line-to"]>a.to||b["rhs-line-from"]a.from&&b["rhs-line-to"]>a.to?!1:!0:!0},_set_top_offset:function(a){var b=this.editor[a].getScrollInfo().top;this.editor[a].scrollTo(null,0);var c=jQuery("#"+this.id+" .CodeMirror-measure").first(),d=c.offset().top-4;return d?(this.editor[a].scrollTo(null,b),this.draw_top_offset=.5-d,!0):!1},_calculate_offsets:function(a,b,c){if(null==this.em_height){if(!this._set_top_offset(a))return;this.em_height=this.editor[a].defaultTextHeight(),this.em_height||(console.warn("Failed to calculate offsets, using 18 by default"),this.em_height=18),this.draw_lhs_min=.5;var d=jQuery("#"+a+"-"+b+"-canvas");if(d.length||console.error("failed to find canvas","#"+a+"-"+b+"-canvas"),!d.width())return console.error("canvas width is 0"),void 0;this.draw_mid_width=jQuery("#"+a+"-"+b+"-canvas").width(),this.draw_rhs_max=this.draw_mid_width-.5,this.draw_lhs_width=5,this.draw_rhs_width=5,this.trace("calc","change offsets calculated",{top_offset:this.draw_top_offset,lhs_min:this.draw_lhs_min,rhs_max:this.draw_rhs_max,lhs_width:this.draw_lhs_width,rhs_width:this.draw_rhs_width})}for(var e=this.editor[a].charCoords({line:0}),f=this.editor[b].charCoords({line:0}),g=this._get_viewport(a,b),h=0;h=0?i["lhs-line-from"]:0,k=i["lhs-line-to"]>=0?i["lhs-line-to"]:0,l=i["rhs-line-from"]>=0?i["rhs-line-from"]:0,m=i["rhs-line-to"]>=0?i["rhs-line-to"]:0;if(this.editor[a].getOption("lineWrapping")||this.editor[a].getOption("lineWrapping")){var r=this.editor[a].cursorCoords({line:j,ch:0},"page"),s=this.editor[a].getLineHandle(j);n={top:r.top,bottom:r.top+s.height};var t=this.editor[a].cursorCoords({line:k,ch:0},"page"),u=this.editor[a].getLineHandle(k);o={top:t.top,bottom:t.top+u.height};var r=this.editor[b].cursorCoords({line:l,ch:0},"page"),v=this.editor[b].getLineHandle(l);p={top:r.top,bottom:r.top+v.height};var t=this.editor[b].cursorCoords({line:m,ch:0},"page"),w=this.editor[b].getLineHandle(m);q={top:t.top,bottom:t.top+w.height}}else n={top:e.top+j*this.em_height,bottom:e.bottom+j*this.em_height+2},o={top:e.top+k*this.em_height,bottom:e.bottom+k*this.em_height+2},p={top:f.top+l*this.em_height,bottom:f.bottom+l*this.em_height+2},q={top:f.top+m*this.em_height,bottom:f.bottom+m*this.em_height+2};"a"==i.op?l>0&&(n.top=n.bottom,n.bottom+=this.em_height,o=n):"d"==i.op&&j>0&&(p.top=p.bottom,p.bottom+=this.em_height,q=p),i["lhs-y-start"]=this.draw_top_offset+n.top,i["lhs-y-end"]="c"==i.op||"d"==i.op?this.draw_top_offset+o.bottom:this.draw_top_offset+o.top,i["rhs-y-start"]=this.draw_top_offset+p.top,i["rhs-y-end"]="c"==i.op||"a"==i.op?this.draw_top_offset+q.bottom:this.draw_top_offset+q.top,this.trace("calc","change calculated",h,i)}else delete i["lhs-y-start"],delete i["lhs-y-end"],delete i["rhs-y-start"],delete i["rhs-y-end"]}return c},_markup_changes:function(a,b,c){jQuery(".merge-button").remove();var d=this,e=this.editor[a],f=this.editor[b],g=new Mgly.Timer;e.operation(function(){for(var a=0;a=0?b["lhs-line-from"]:0,h=b["lhs-line-to"]>=0?b["lhs-line-to"]:0,i=b["rhs-line-from"]>=0?b["rhs-line-from"]:0;b["rhs-line-to"]>=0?b["rhs-line-to"]:0;var k=["mergely","lhs",b.op,"cid-"+a];if(e.addLineClass(g,"background","start"),e.addLineClass(h,"background","end"),0==g&&0==h&&0==i)e.addLineClass(g,"background",k.join(" ")),e.addLineClass(g,"background","first");else for(var l=g;h>=l;++l)e.addLineClass(l,"background",k.join(" ")),e.addLineClass(l,"background",k.join(" "));if(!f.getOption("readOnly")){var m=d.merge_rhs_button.clone();m.button&&m.button({icons:{primary:"ui-icon-triangle-1-e"},text:!1}),m.addClass("merge-button"),m.attr("id","merge-rhs-"+a),e.setGutterMarker(g,"merge",m.get(0))}}});var h=this._get_viewport(a,b);this.trace("change","markup lhs-editor time",g.stop()),f.operation(function(){for(var a=0;a=0?b["lhs-line-from"]:0;b["lhs-line-to"]>=0?b["lhs-line-to"]:0;var j=b["rhs-line-from"]>=0?b["rhs-line-from"]:0,k=b["rhs-line-to"]>=0?b["rhs-line-to"]:0;if(d._is_change_in_view(h,b)){var l=["mergely","rhs",b.op,"cid-"+a];if(f.addLineClass(j,"background","start"),f.addLineClass(k,"background","end"),0==j&&0==k&&0==g)f.addLineClass(j,"background",l.join(" ")),f.addLineClass(j,"background","first");else for(var m=j;k>=m;++m)f.addLineClass(m,"background",l.join(" ")),f.addLineClass(m,"background",l.join(" "));if(!e.getOption("readOnly")){var n=d.merge_lhs_button.clone();n.button&&n.button({icons:{primary:"ui-icon-triangle-1-w"},text:!1}),n.addClass("merge-button"),n.attr("id","merge-lhs-"+a),f.setGutterMarker(j,"merge",n.get(0))}}}}),this.trace("change","markup rhs-editor time",g.stop());for(var i=[],j=0;this.settings.lcs&&j=0?k["lhs-line-from"]:0,m=k["lhs-line-to"]>=0?k["lhs-line-to"]:0,n=k["rhs-line-from"]>=0?k["rhs-line-from"]:0,o=k["rhs-line-to"]>=0?k["rhs-line-to"]:0;if(this._is_change_in_view(h,k))if("d"==k.op){var p=l,q=m,r=e.lineInfo(q);r&&i.push([e,{line:p,ch:0},{line:q,ch:r.text.length},{className:"mergely ch d lhs"}])}else if("c"==k.op)for(var s=l,t=n,u=0;s>=0&&m>=s||t>=0&&o>=t;++s,++t)if(t+u>o){var v=e.getLine(s);i.push([e,{line:s,ch:0},{line:s,ch:v.length},{className:"mergely ch d lhs"}])}else if(s+u>m){var w=f.getLine(t);i.push([f,{line:t,ch:0},{line:t,ch:w.length},{className:"mergely ch a rhs"}])}else{var v=e.getLine(s),w=f.getLine(t),B=new Mgly.LCS(v,w);B.diff(function(a,b){i.push([f,{line:t,ch:a},{line:t,ch:b},{className:"mergely ch a rhs"}])},removed=function(a,b){i.push([e,{line:s,ch:a},{line:s,ch:b},{className:"mergely ch d lhs"}])})}}this.trace("change","LCS marktext time",g.stop()),e.operation(function(){for(var a=0;a=h;--j)f[c].removeLine(j);else if("lhs"==b)if("a"==a.op)for(var h=parseInt(a[c+"-line-from"]),i=parseInt(a[c+"-line-to"]),j=i;j>=h;--j)f[c].removeLine(j);else f[c].replaceRange(g,CodeMirror.Pos(a[c+"-line-from"]+1,0));f.lhs.setValue(f.lhs.getValue()),f.rhs.setValue(f.rhs.getValue()),this._scroll_to_change(a)}},_draw_info:function(a,b){var c=jQuery(this.editor[a].getScrollerElement()).height(),d=jQuery(this.editor[a].getScrollerElement()).children(":first-child").height(),e=document.getElementById(a+"-"+b+"-canvas");if(void 0==e)throw"Failed to find: "+a+"-"+b+"-canvas";var f=jQuery("#"+this.id+"-lhs-margin"),g=jQuery("#"+this.id+"-rhs-margin");return{visible_page_height:c,gutter_height:d,visible_page_ratio:c/d,margin_ratio:c/d,lhs_scroller:jQuery(this.editor[a].getScrollerElement()),rhs_scroller:jQuery(this.editor[b].getScrollerElement()),lhs_lines:this.editor[a].lineCount(),rhs_lines:this.editor[b].lineCount(),dcanvas:e,clhs:f,crhs:g,lhs_xyoffset:jQuery(f).offset(),rhs_xyoffset:jQuery(g).offset()}},_draw_diff:function(a,b,c){var d=this._draw_info(a,b),e=d.clhs.get(0),f=d.crhs.get(0),g=d.dcanvas.getContext("2d"),h=e.getContext("2d"),i=f.getContext("2d");this.trace("draw","visible_page_height",d.visible_page_height),this.trace("draw","gutter_height",d.gutter_height),this.trace("draw","visible_page_ratio",d.visible_page_ratio),this.trace("draw","lhs-scroller-top",d.lhs_scroller.scrollTop()),this.trace("draw","rhs-scroller-top",d.rhs_scroller.scrollTop()),jQuery.each(jQuery.find("#"+this.id+" canvas"),function(){jQuery(this).get(0).height=d.visible_page_height}),d.clhs.unbind("click"),d.crhs.unbind("click"),h.beginPath(),h.fillStyle=this.settings.bgcolor,h.strokeStyle="#888",h.fillRect(0,0,6.5,d.visible_page_height),h.strokeRect(0,0,6.5,d.visible_page_height),i.beginPath(),i.fillStyle=this.settings.bgcolor,i.strokeStyle="#888",i.fillRect(0,0,6.5,d.visible_page_height),i.strokeRect(0,0,6.5,d.visible_page_height);for(var j=this._get_viewport(a,b),k=0;k=s?g.lineTo(t+r,u):(g.arcTo(t+r,u,t+r,u+q,q),g.arcTo(t+r,u+s,t+r-q,u+s,q)),g.lineTo(t,u+s)),g.stroke(),r=this.draw_rhs_width,s=p-o-1,t=this.draw_rhs_max,u=o,g.moveTo(t,u),"Microsoft Internet Explorer"==navigator.appName?(g.lineTo(this.draw_rhs_max-this.draw_rhs_width,o),g.lineTo(this.draw_rhs_max-this.draw_rhs_width,p+1),g.lineTo(this.draw_rhs_max,p+1)):(0>=s?g.lineTo(t-r,u):(g.arcTo(t-r,u,t-r,u+q,q),g.arcTo(t-r,u+s,t-q,u+s,q)),g.lineTo(t,u+s)),g.stroke();var v=this.draw_lhs_min+this.draw_lhs_width,w=m+(n+1-m)/2,x=this.draw_rhs_max-this.draw_rhs_width,y=o+(p+1-o)/2;g.moveTo(v,w),w==y?g.lineTo(x,y):g.bezierCurveTo(v+12,w-3,x-12,y-3,x,y),g.stroke()}}h.fillStyle=this.settings.vpcolor,i.fillStyle=this.settings.vpcolor;var z=d.clhs.height()*d.visible_page_ratio,A=d.lhs_scroller.scrollTop()/d.gutter_height*d.clhs.height(),B=d.crhs.height()*d.visible_page_ratio,C=d.rhs_scroller.scrollTop()/d.gutter_height*d.crhs.height();this.trace("draw","cls.height",d.clhs.height()),this.trace("draw","lhs_scroller.scrollTop()",d.lhs_scroller.scrollTop()),this.trace("draw","gutter_height",d.gutter_height),this.trace("draw","visible_page_ratio",d.visible_page_ratio),this.trace("draw","lhs from",A,"lhs to",z),this.trace("draw","rhs from",C,"rhs to",B),h.fillRect(1.5,A,4.5,z),i.fillRect(1.5,C,4.5,B),d.clhs.click(function(a){var b=a.pageY-d.lhs_xyoffset.top-z/2,c=Math.max(0,b/e.height*d.lhs_scroller.get(0).scrollHeight);d.lhs_scroller.scrollTop(c)}),d.crhs.click(function(a){var b=a.pageY-d.rhs_xyoffset.top-B/2,c=Math.max(0,b/f.height*d.rhs_scroller.get(0).scrollHeight);d.rhs_scroller.scrollTop(c)})},trace:function(a){this.settings._debug.indexOf(a)>=0&&(arguments[0]=a+":",console.log([].slice.apply(arguments)))}}),jQuery.pluginMaker=function(a){jQuery.fn[a.prototype.name]=function(b){var c=jQuery.makeArray(arguments),d=c.slice(1),e=void 0;return this.each(function(){var f=jQuery.data(this,a.prototype.name);if(f){if("string"==typeof b)e=f[b].apply(f,d);else if(f.update)return f.update.apply(f,c)}else new a(this,b)}),void 0!=e?e:void 0}},jQuery.pluginMaker(Mgly.mergely);
--------------------------------------------------------------------------------
/lib/searchcursor.js:
--------------------------------------------------------------------------------
1 | (function(){
2 | var Pos = CodeMirror.Pos;
3 |
4 | function SearchCursor(cm, query, pos, caseFold) {
5 | this.atOccurrence = false; this.cm = cm;
6 | if (caseFold == null && typeof query == "string") caseFold = false;
7 |
8 | pos = pos ? cm.clipPos(pos) : Pos(0, 0);
9 | this.pos = {from: pos, to: pos};
10 |
11 | // The matches method is filled in based on the type of query.
12 | // It takes a position and a direction, and returns an object
13 | // describing the next occurrence of the query, or null if no
14 | // more matches were found.
15 | if (typeof query != "string") { // Regexp match
16 | if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g");
17 | this.matches = function(reverse, pos) {
18 | if (reverse) {
19 | query.lastIndex = 0;
20 | var line = cm.getLine(pos.line).slice(0, pos.ch), match = query.exec(line), start = 0;
21 | while (match) {
22 | start += match.index + 1;
23 | line = line.slice(start);
24 | query.lastIndex = 0;
25 | var newmatch = query.exec(line);
26 | if (newmatch) match = newmatch;
27 | else break;
28 | }
29 | start--;
30 | } else {
31 | query.lastIndex = pos.ch;
32 | var line = cm.getLine(pos.line), match = query.exec(line),
33 | start = match && match.index;
34 | }
35 | if (match && match[0])
36 | return {from: Pos(pos.line, start),
37 | to: Pos(pos.line, start + match[0].length),
38 | match: match};
39 | };
40 | } else { // String query
41 | if (caseFold) query = query.toLowerCase();
42 | var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
43 | var target = query.split("\n");
44 | // Different methods for single-line and multi-line queries
45 | if (target.length == 1) {
46 | if (!query.length) {
47 | // Empty string would match anything and never progress, so
48 | // we define it to match nothing instead.
49 | this.matches = function() {};
50 | } else {
51 | this.matches = function(reverse, pos) {
52 | var line = fold(cm.getLine(pos.line)), len = query.length, match;
53 | if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
54 | : (match = line.indexOf(query, pos.ch)) != -1)
55 | return {from: Pos(pos.line, match),
56 | to: Pos(pos.line, match + len)};
57 | };
58 | }
59 | } else {
60 | this.matches = function(reverse, pos) {
61 | var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(cm.getLine(ln));
62 | var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
63 | if (reverse ? offsetA >= pos.ch || offsetA != match.length
64 | : offsetA <= pos.ch || offsetA != line.length - match.length)
65 | return;
66 | for (;;) {
67 | if (reverse ? !ln : ln == cm.lineCount() - 1) return;
68 | line = fold(cm.getLine(ln += reverse ? -1 : 1));
69 | match = target[reverse ? --idx : ++idx];
70 | if (idx > 0 && idx < target.length - 1) {
71 | if (line != match) return;
72 | else continue;
73 | }
74 | var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
75 | if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
76 | return;
77 | var start = Pos(pos.line, offsetA), end = Pos(ln, offsetB);
78 | return {from: reverse ? end : start, to: reverse ? start : end};
79 | }
80 | };
81 | }
82 | }
83 | }
84 |
85 | SearchCursor.prototype = {
86 | findNext: function() {return this.find(false);},
87 | findPrevious: function() {return this.find(true);},
88 |
89 | find: function(reverse) {
90 | var self = this, pos = this.cm.clipPos(reverse ? this.pos.from : this.pos.to);
91 | function savePosAndFail(line) {
92 | var pos = Pos(line, 0);
93 | self.pos = {from: pos, to: pos};
94 | self.atOccurrence = false;
95 | return false;
96 | }
97 |
98 | for (;;) {
99 | if (this.pos = this.matches(reverse, pos)) {
100 | if (!this.pos.from || !this.pos.to) { console.log(this.matches, this.pos); }
101 | this.atOccurrence = true;
102 | return this.pos.match || true;
103 | }
104 | if (reverse) {
105 | if (!pos.line) return savePosAndFail(0);
106 | pos = Pos(pos.line-1, this.cm.getLine(pos.line-1).length);
107 | }
108 | else {
109 | var maxLine = this.cm.lineCount();
110 | if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
111 | pos = Pos(pos.line + 1, 0);
112 | }
113 | }
114 | },
115 |
116 | from: function() {if (this.atOccurrence) return this.pos.from;},
117 | to: function() {if (this.atOccurrence) return this.pos.to;},
118 |
119 | replace: function(newText) {
120 | if (!this.atOccurrence) return;
121 | var lines = CodeMirror.splitLines(newText);
122 | this.cm.replaceRange(lines, this.pos.from, this.pos.to);
123 | this.pos.to = Pos(this.pos.from.line + lines.length - 1,
124 | lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
125 | }
126 | };
127 |
128 | CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
129 | return new SearchCursor(this, query, pos, caseFold);
130 | });
131 | })();
--------------------------------------------------------------------------------