1
0
mirror of synced 2025-12-12 17:38:29 +08:00

Major work to update Mergely to work with the head of codemirror git.

This commit is contained in:
Jamie Peabody
2013-02-10 20:19:35 +00:00
parent eaf41856fa
commit 49f57eb72b
6 changed files with 4984 additions and 2833 deletions

36
editor/editor.css Executable file
View File

@@ -0,0 +1,36 @@
body { margin: 0px; font-family: "trebuchet ms"; }
#header { width: 100%; height: 40px; background: #ececec url(/images/banner_bg.png); border-bottom: 1px solid #888; line-height: 40px; }
#compare .ui-button { width: 1em; height: 1em; margin-right: 5px; }
#info { width: 100%; }
#logo { background: transparent url(/images/mergely_sm.png) no-repeat; width: 113px; height:30px; display: inline-block; top: 5px; left: 5px; position: relative; float: left; margin-right: 77px; }
#info h3, #info p { display: none; }
#info button { visibility: hidden; font-size: 0.75em; }
#about, .button-editor, #settings { float: right !important; margin: 6px 5px 0 0; }
#settings { display: inline-block; height: 16px; }
#settings img { display: inline-block; height: 16px; }
.toolbar { display: none; margin: 0px; background: #e2e8ec url(../../images/toolbar_bg.png); border-bottom: 1px solid #A7BCC8; line-height: 14px; }
.title { display: none; font-weight: bold; }
.toolbar .ui-button { width: 1em; }
.toolbar input[type=text] { float: left; border: 1px solid #888; font-size: 12px; font-weight: bold; font-family: tahoma; letter-spacing: 1px; width: 150px; color: #444; margin-right: 2px; }
.toolbar .buttonset { display: inline-block; padding-top:5px; }
.toolbar .buttonset .ui-button { padding: 2px 14px 2px 7px; float: left; }
#share-menu { display: none; background-color:white;border: 3px solid #606060;left:340px;top:33px;position:absolute;width:280px;z-index:50; padding: 5px; height: 40px; }
#share-menu label {font-weight: bold; font-size: .80em; color: #37AFFF; width: 80px; display: inline; padding-right: 5px; }
#share-menu input { width: 200px; border: 1px solid #606060;}
#dialog-confirm { display:none; }
.ui-dialog { font-size:0.75em; }
.toolbar .ui-button { margin-right: 1px; }
#download { font-size: 1.1em; }
.mbutton {
font: normal 0.8em Verdana,Arial,sans-serif; text-decoration: none;
background: url('mergely-theme/images/ui-bg_flat_100_808080_40x100.png') repeat-x scroll 50% 50% #808080;
border: 1px solid #575757; color: #fff; font-weight: normal; display: inline-block; margin-right: 0.1em; overflow: visible; padding: 5px 6px; position: relative;
text-align: center; cursor: pointer; border-radius: 3px;
}
.mbutton:hover { background: url('mergely-theme/images/ui-bg_highlight-soft_25_37afff_1x100.png') repeat-x scroll 50% 50% #808080; }
#dialog-settings { visibility: hidden; }
#dialog-settings label { width: 85px; display: inline-block; font-weight: bold; padding: 5px; }
#dialog-settings input[type=text] { width: 70px; border: 1px solid #444; float:right; }
#dialog-settings label.checkbox { width: auto; }
#dialog-settings fieldset { -webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px; border: 1px solid #ccc; width: 175px; padding-right: 15px; }

View File

@@ -87,8 +87,7 @@ $(document).ready(function () {
},
cmsettings: {
mode: 'text/plain'
},
_debug: ''
}
});
if (key.length == 8) {
$.when(
@@ -257,11 +256,12 @@ $(document).ready(function () {
$('body').append(sa);
$('body').append(sc);
var conf = {
'c-border': {id: '#c-border', defaultColor: '#cccccc', getColor: function() { return sc.css('border-top-color'); } },
'a-border': {id: '#a-border', defaultColor: '#4ba3fa', getColor: function() { return sa.css('border-top-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
'c-border': {id: '#c-border', defaultColor: '#cccccc', getColor: function() { return sc.css('border-top-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
'c-bg': {id: '#c-bg', defaultColor: '#fafafa', getColor: function() { return sc.css('background-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
'a-border': {id: '#a-border', defaultColor: '#a3d1ff', getColor: function() { return sa.css('border-top-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
'd-border': {id: '#d-border', defaultColor: '#ff7f7f', getColor: function() { return sd.css('border-top-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
'a-bg': {id: '#a-bg', defaultColor: '#ddeeff', getColor: function() { return sa.css('background-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
'd-bg': {id: '#d-bg', defaultColor: '#f9e9e9', getColor: function() { return sd.css('background-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
'd-bg': {id: '#d-bg', defaultColor: '#edc0c0', getColor: function() { return sd.css('background-color'); }, setColor: function(color) { $('#'+this.id).val(color) }},
};
$.each(conf, function(key, item){ $(item.id).val(item.getColor()); });

View File

@@ -1,110 +1,52 @@
/* BASICS */
.CodeMirror {
line-height: 1em;
/* Set height, width, borders, and global font properties here */
font-family: monospace;
/* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. */
position: relative;
/* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. */
overflow: hidden;
}
.CodeMirror-scroll {
overflow: auto;
height: 300px;
/* This is needed to prevent an IE[67] bug where the scrolled content
is visible outside of the scrolling box. */
position: relative;
outline: none;
}
.CodeMirror-scroll {
/* Set scrolling behaviour here */
overflow: auto;
}
/* Vertical scrollbar */
.CodeMirror-scrollbar {
position: absolute;
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
z-index: 5;
}
.CodeMirror-scrollbar-inner {
/* This needs to have a nonzero width in order for the scrollbar to appear
in Firefox and IE9. */
width: 1px;
}
.CodeMirror-scrollbar.cm-sb-overlap {
/* Ensure that the scrollbar appears in Lion, and that it overlaps the content
rather than sitting to the right of it. */
position: absolute;
z-index: 1;
float: none;
right: 0;
min-width: 12px;
}
.CodeMirror-scrollbar.cm-sb-nonoverlap {
min-width: 12px;
}
.CodeMirror-scrollbar.cm-sb-ie7 {
min-width: 18px;
}
/* PADDING */
.CodeMirror-gutter {
position: absolute; left: 0; top: 0;
z-index: 10;
background-color: #f7f7f7;
border-right: 1px solid #eee;
min-width: 2em;
height: 100%;
}
.CodeMirror-gutter-text {
color: #aaa;
text-align: right;
padding: .4em .2em .4em .4em;
white-space: pre !important;
cursor: default;
}
.CodeMirror-lines {
padding: .4em;
white-space: pre;
cursor: text;
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre {
-moz-border-radius: 0;
-webkit-border-radius: 0;
-o-border-radius: 0;
border-radius: 0;
border-width: 0; margin: 0; padding: 0; background: transparent;
font-family: inherit;
font-size: inherit;
padding: 0; margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
overflow: visible;
padding: 0 4px; /* Horizontal padding of content */
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden;
.CodeMirror-scrollbar-filler {
background-color: white; /* The little square between H and V scrollbars */
}
.CodeMirror textarea {
outline: none !important;
/* GUTTER */
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: #f7f7f7;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: #999;
}
.CodeMirror pre.CodeMirror-cursor {
z-index: 10;
position: absolute;
visibility: hidden;
/* CURSOR */
.CodeMirror div.CodeMirror-cursor {
border-left: 1px solid black;
border-right: none;
width: 0;
}
.cm-keymap-fat-cursor pre.CodeMirror-cursor {
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
width: auto;
border: 0;
background: transparent;
@@ -112,63 +54,187 @@
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
}
/* Kludge to turn off filter in ie9+, which also accepts rgba */
.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor:not(#nonsense_id) {
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
}
.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
.CodeMirror-focused pre.CodeMirror-cursor {
visibility: visible;
}
/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
div.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused div.CodeMirror-selected { background: #d7d4f0; }
/* DEFAULT THEME */
.CodeMirror-searching {
background: #ffa;
background: rgba(255, 255, 0, .4);
}
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable {color: black;}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
.cm-s-default .cm-property {color: black;}
.cm-s-default .cm-operator {color: black;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-error {color: #f00;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
/* Default theme */
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-emstrong {font-style: italic; font-weight: bold;}
.cm-link {text-decoration: underline;}
.cm-s-default span.cm-keyword {color: #708;}
.cm-s-default span.cm-atom {color: #219;}
.cm-s-default span.cm-number {color: #164;}
.cm-s-default span.cm-def {color: #00f;}
.cm-s-default span.cm-variable {color: black;}
.cm-s-default span.cm-variable-2 {color: #05a;}
.cm-s-default span.cm-variable-3 {color: #085;}
.cm-s-default span.cm-property {color: black;}
.cm-s-default span.cm-operator {color: black;}
.cm-s-default span.cm-comment {color: #a50;}
.cm-s-default span.cm-string {color: #a11;}
.cm-s-default span.cm-string-2 {color: #f50;}
.cm-s-default span.cm-meta {color: #555;}
.cm-s-default span.cm-error {color: #f00;}
.cm-s-default span.cm-qualifier {color: #555;}
.cm-s-default span.cm-builtin {color: #30a;}
.cm-s-default span.cm-bracket {color: #997;}
.cm-s-default span.cm-tag {color: #170;}
.cm-s-default span.cm-attribute {color: #00c;}
.cm-s-default span.cm-header {color: blue;}
.cm-s-default span.cm-quote {color: #090;}
.cm-s-default span.cm-hr {color: #999;}
.cm-s-default span.cm-link {color: #00c;}
span.cm-header, span.cm-strong {font-weight: bold;}
span.cm-em {font-style: italic;}
span.cm-emstrong {font-style: italic; font-weight: bold;}
span.cm-link {text-decoration: underline;}
span.cm-invalidchar {color: #f00;}
.cm-invalidchar {color: #f00;}
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
@media print {
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
.CodeMirror {
line-height: 1;
position: relative;
overflow: hidden;
}
.CodeMirror-scroll {
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror, and the paddings in .CodeMirror-sizer */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px; padding-right: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
}
.CodeMirror-sizer {
position: relative;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actuall scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler {
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
z-index: 6;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
height: 100%;
z-index: 3;
}
.CodeMirror-gutter {
height: 100%;
display: inline-block;
/* Hack to make IE7 behave */
*zoom:1;
*display:inline;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-lines {
cursor: text;
}
.CodeMirror pre {
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; -o-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
overflow: auto;
}
.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden;
}
.CodeMirror-measure {
position: absolute;
width: 100%; height: 0px;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor {
position: absolute;
visibility: hidden;
border-right: none;
width: 0;
}
.CodeMirror-focused div.CodeMirror-cursor {
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.cm-searching {
background: #ffa;
background: rgba(255, 255, 0, .4);
}
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
.CodeMirror span { *vertical-align: text-bottom; }
@media print {
/* Hide the cursor when printing */
.CodeMirror pre.CodeMirror-cursor {
.CodeMirror div.CodeMirror-cursor {
visibility: hidden;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,8 @@
/**
* Copyright (c) 2013 by Jamie Peabody, http://www.mergely.com
* All rights reserved.
* Version: 3.1 2013-01-05
*/
/* required */
.mergely-column textarea { width: 80px; height: 200px; }
.mergely-column { float: left; }
@@ -9,24 +14,25 @@
/* style configuration */
.mergely-column { border: 1px solid #ccc; }
.mergely-active { border: 1px solid #4ba3fa; }
.mergely-active { border: 1px solid #a3d1ff; }
.mergely.a.rhs.start { border-top: 1px solid #4ba3fa; }
.mergely.a.rhs.start { border-top: 1px solid #a3d1ff; }
.mergely.a.lhs.start.end,
.mergely.a.rhs.end { border-bottom: 1px solid #4ba3fa; }
.mergely.a.rhs.end { border-bottom: 1px solid #a3d1ff; }
.mergely.bg.a.rhs { background-color: #ddeeff; }
.mergely.d.lhs { background-color: #f9e9e9; }
.mergely.d.lhs { background-color: #edc0c0; }
.mergely.d.lhs.end,
.mergely.d.rhs.start.end { border-bottom: 1px solid #ff7f7f; }
.mergely.d.rhs.start.end.first { border-bottom: 0; border-top: 1px solid #ff7f7f; }
.mergely.d.lhs.start { border-top: 1px solid #ff7f7f; }
.mergely.c.lhs,
.mergely.c.rhs { background-color: #fcfcfc; }
.mergely.c.rhs { background-color: #fafafa; }
.mergely.c.lhs.start,
.mergely.c.rhs.start { border-top: 1px solid #ccc; }
.mergely.c.lhs.end,
.mergely.c.rhs.end { border-bottom: 1px solid #ccc; }
.mergely.ch.a.rhs { background-color: #ddeeff; }
.mergely.ch.d.lhs { background-color: #f9e9e9; text-decoration: line-through; color: #888; }
.mergely.ch.d.lhs { background-color: #edc0c0; text-decoration: line-through; color: #888; }

View File

@@ -1,5 +1,22 @@
/**
* Copyright (c) 2013 by Jamie Peabody, http://www.mergely.com
* All rights reserved.
* Version: 3.1 2013-01-05
*/
Mgly = {};
Mgly.Timer = function(){
var self = this;
self.start = function() { self.t0 = new Date().getTime(); }
self.stop = function() {
var t1 = new Date().getTime();
var d = t1 - self.t0;
self.t0 = t1;
return d;
}
self.start();
}
Mgly.sizeOf = function(obj) {
var size = 0, key;
for (key in obj) {
@@ -326,8 +343,8 @@ jQuery.extend(Mgly.diff.prototype, {
});
Mgly.mergely = function(el, options) {
CodeMirror.defineExtension("centerOnCursor", function() {
var coords = this.cursorCoords(null, "local");
CodeMirror.defineExtension('centerOnCursor', function() {
var coords = this.cursorCoords(null, 'local');
this.scrollTo(null,
(coords.y + coords.yBot) / 2 - (this.getScrollerElement().clientHeight / 2));
});
@@ -377,7 +394,7 @@ jQuery.extend(Mgly.mergely.prototype, {
}
if (this.resized) this.resized();
},
_debug: '', //scroll,draw,calc,diff,markup
_debug: 'change', //scroll,draw,calc,diff,markup,change
resized: function() { }
};
var cmsettings = {
@@ -399,7 +416,7 @@ jQuery.extend(Mgly.mergely.prototype, {
if (options) jQuery.extend(this.settings, options);
// bind if the element is destroyed
this.element.bind("destroyed", jQuery.proxy(this.teardown, this));
this.element.bind('destroyed', jQuery.proxy(this.teardown, this));
// save this instance in jQuery data
jQuery.data(el, this.name, this);
@@ -420,16 +437,14 @@ jQuery.extend(Mgly.mergely.prototype, {
}
var self = this;
this.editor = [];
var lhs_cmsettings = jQuery.extend({
onChange: function () { if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); },
onScroll: function () { self._scrolling(self.id + '-lhs'); }
}, this.lhs_cmsettings);
this.editor[this.id + '-lhs'] = CodeMirror.fromTextArea(lhstx, lhs_cmsettings);
var rhs_cmsettings = jQuery.extend({
onChange: function () { if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); },
onScroll: function () { self._scrolling(self.id + '-rhs'); }
}, this.rhs_cmsettings);
this.editor[this.id + '-rhs'] = CodeMirror.fromTextArea(rhstx, rhs_cmsettings);
this.editor[this.id + '-lhs'] = CodeMirror.fromTextArea(lhstx, this.lhs_cmsettings);
this.editor[this.id + '-rhs'] = CodeMirror.fromTextArea(rhstx, this.rhs_cmsettings);
this.editor[this.id + '-lhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); });
this.editor[this.id + '-lhs'].on('scroll', function(){ self._scrolling(self.id + '-lhs'); });
this.editor[this.id + '-rhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); });
this.editor[this.id + '-rhs'].on('scroll', function(){ self._scrolling(self.id + '-rhs'); });
// resize
var sz_timeout1 = null;
var sz = function() {
@@ -563,7 +578,7 @@ jQuery.extend(Mgly.mergely.prototype, {
}
else {
// homebrew
var style = 'width:1em;height:1em;background-color:#888;cursor:pointer;text-align:center;color:#eee;border:1px solid: #222;margin-right:5px;border-radius:3px;';
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;';
merge_lhs_button = '<div style="' + style + '" title="Merge left">&lt;</div>';
merge_rhs_button = '<div style="' + style + '" title="Merge right">&gt;</div>';
}
@@ -578,7 +593,8 @@ jQuery.extend(Mgly.mergely.prototype, {
jQuery(this.element).append(jQuery('<div class="mergely-margin" style="height: ' + height + '"><canvas id="' + this.id + '-rhs-margin" width="8px" height="' + height + '"></canvas></div>'));
//codemirror
var cmstyle = '#' + this.id + ' .CodeMirror-gutter-text { padding: 5px 0 0 0; }' +
'#' + this.id + ' .CodeMirror-lines pre, ' + '#' + this.id + ' .CodeMirror-gutter-text pre { line-height: 18px; }';
'#' + this.id + ' .CodeMirror-lines pre, ' + '#' + this.id + ' .CodeMirror-gutter-text pre { line-height: 18px; }' +
'.CodeMirror-linewidget { overflow: hidden; };';
if (this.settings.autoresize) {
cmstyle += this.id + ' .CodeMirror-scroll { height: 100%; overflow: auto; }';
}
@@ -602,7 +618,7 @@ jQuery.extend(Mgly.mergely.prototype, {
this.midway = (scroller.height() / 2.0 + scroller.offset().top).toFixed(2);
}
// balance-line
var midline = this.editor[editor_name].coordsChar({x:0, y:this.midway});
var midline = this.editor[editor_name].coordsChar({left:0, top:this.midway});
var top_to = scroller.scrollTop();
var left_to = scroller.scrollLeft();
@@ -657,39 +673,56 @@ jQuery.extend(Mgly.mergely.prototype, {
}
},
_changing: function(editor_name1, editor_name2) {
this.trace('change', 'changing-timeout', this.changed_timeout);
var self = this;
if (this.changed_timeout != null) clearTimeout(this.changed_timeout);
this.changed_timeout = setTimeout(function(){
var timer = new Mgly.Timer();
self._changed(editor_name1, editor_name2);
self.trace('change', 'total time', timer.stop());
}, this.settings.change_timeout);
},
_changed: function(editor_name1, editor_name2) {
var self = this;
for (var name in this.editor) {
if (!this.editor.hasOwnProperty(name)) continue;
var editor = this.editor[name];
// clear editor changes
editor.operation(function() {
var timer = new Mgly.Timer();
for (var i = 0, l = editor.lineCount(); i < l; ++i) {
editor.clearMarker(i);
editor.setLineClass(i, null, null);
editor.removeLineClass(i, 'background');
}
for (var i = 0; i < self.change_funcs.length; ++i) {
var edid = editor.getDoc().id;
var change = self.change_funcs[i];
if (change.doc.id != edid) continue;
if (change.lines.length) {
self.trace('change', 'clear text', edid, change.lines[0].text);
}
change.clear();
}
editor.clearGutter('merge');
self.trace('change', 'clear time', timer.stop());
});
}
//remove previous markup changes
for (var i = 0; i < this.change_funcs.length; ++i) {
var change = this.change_funcs[i];
if (change.clear != undefined) change.clear();
else change();//prev codemirror
}
self.change_funcs = [];
this._diff(editor_name1, editor_name2);
},
_diff: function(editor_name1, editor_name2) {
var lhs = this.editor[editor_name1].getValue();
var rhs = this.editor[editor_name2].getValue();
var timer = new Mgly.Timer();
var d = new Mgly.diff(lhs, rhs, false, this.settings.ignorews);
this.trace('change', 'diff time', timer.stop());
this.changes = this._parse_diff(editor_name1, editor_name2, d.normal_form());
this.trace('change', 'parse time', timer.stop());
this._calculate_offsets(editor_name1, editor_name2, this.changes);
this.trace('change', 'offsets time', timer.stop());
this._markup_changes(editor_name1, editor_name2, this.changes);
this.trace('change', 'markup time', timer.stop());
this._draw_diff(editor_name1, editor_name2, this.changes);
this.trace('change', 'draw time', timer.stop());
},
_parse_diff: function (editor_name1, editor_name2, diff) {
this.trace('diff', 'diff results:\n', diff);
@@ -732,17 +765,12 @@ jQuery.extend(Mgly.mergely.prototype, {
},
_calculate_offsets: function (editor_name1, editor_name2, changes) {
if (this.em_height == null) {
//var topnode = this.element.find('.CodeMirror-gutter-text pre').first();
//this.em_height = topnode.get(0).offsetHeight;
// this is the distance from the top of the screen
var topnode = jQuery('#' + this.id + '-lhs-margin').first();
var top_offset = topnode.offset().top;
var topnode = jQuery('#' + this.id + ' .CodeMirror-measure').first();
var top_offset = topnode.offset().top - 4;
if (!top_offset) return;//try again
this.draw_top_offset = 0.5 - top_offset;
this.em_height = jQuery('.CodeMirror-lines pre').get(0).offsetHeight
this.em_height = this.editor[editor_name1].defaultTextHeight();
if (!this.em_height) {
console.warn('Failed to calculate offsets, using 18 by default');
this.em_height = 18;
@@ -763,7 +791,6 @@ jQuery.extend(Mgly.mergely.prototype, {
}
for (var i = 0; i < changes.length; ++i) {
var change = changes[i];
var valign = 2;
var ls = this.editor[editor_name1].charCoords({line: change['lhs-line-from']});
var le = this.editor[editor_name1].charCoords({line: change['lhs-line-to']});
var rs = this.editor[editor_name2].charCoords({line: change['rhs-line-from']});
@@ -772,8 +799,8 @@ jQuery.extend(Mgly.mergely.prototype, {
// adds (right), normally start from the end of the lhs,
// except for the case when the start of the rhs is 0
if (change['rhs-line-from'] > 0) {
ls.y = ls.yBot;
ls.yBot += this.em_height;
ls.top = ls.bottom;
ls.bottom += this.em_height;
le = ls;
}
}
@@ -781,24 +808,24 @@ jQuery.extend(Mgly.mergely.prototype, {
// deletes (left) normally finish from the end of the rhs,
// except for the case when the start of the lhs is 0
if (change['lhs-line-from'] > 0) {
rs.y = rs.yBot;
rs.yBot += this.em_height;
rs.top = rs.bottom;
rs.bottom += this.em_height;
re = rs;
}
}
change['lhs-y-start'] = this.draw_top_offset + ls.y;
change['lhs-y-start'] = this.draw_top_offset + ls.top;
if (change['op'] == 'c' || change['op'] == 'd') {
change['lhs-y-end'] = this.draw_top_offset + le.yBot - valign;
change['lhs-y-end'] = this.draw_top_offset + le.bottom;
}
else {
change['lhs-y-end'] = this.draw_top_offset + le.y - valign;
change['lhs-y-end'] = this.draw_top_offset + le.top;
}
change['rhs-y-start'] = this.draw_top_offset + rs.y;
change['rhs-y-start'] = this.draw_top_offset + rs.top;
if (change['op'] == 'c' || change['op'] == 'a') {
change['rhs-y-end'] = this.draw_top_offset + re.yBot - valign;
change['rhs-y-end'] = this.draw_top_offset + re.bottom;
}
else {
change['rhs-y-end'] = this.draw_top_offset + re.y - valign;
change['rhs-y-end'] = this.draw_top_offset + re.top;
}
this.trace('calc', 'change calculated', i, change);
}
@@ -810,158 +837,27 @@ jQuery.extend(Mgly.mergely.prototype, {
var self = this;
var led = this.editor[editor_name1];
var red = this.editor[editor_name2];
var timer = new Mgly.Timer();
led.operation(function() {
for (var i = 0; i < changes.length; ++i) {
var change = changes[i];
var clazz = 'mergely ' + change['op'] + ' cid-' + i + ' ';
// lhs markup
if (change['lhs-line-from'] == change['lhs-line-to']) {
if (change['op'] == 'a') {
// adds (right), normally start from the end of the lhs,
// except for the case when the start of the rhs is 0
if (change['rhs-line-from'] > 0) {
var cl = clazz + 'lhs start end';
led.setLineClass(change['lhs-line-from'], null, cl);
}
else {
var cl = clazz + 'lhs start';
led.setLineClass(change['lhs-line-from'], null, cl);
}
}
else if (change['op'] == 'd') {
var cl = clazz + 'lhs start end';
led.setLineClass(change['lhs-line-from'], null, cl);
}
else if (change['op'] == 'c') {
var cl = clazz + 'lhs start end';
led.setLineClass(change['lhs-line-from'], null, cl);
}
var clazz = ['mergely', 'lhs', change['op'], 'cid-' + i];
led.addLineClass(change['lhs-line-from'], 'background', 'start');
led.addLineClass(change['lhs-line-to'], 'background', 'end');
if (change['lhs-line-from'] == 0 && change['lhs-line-to'] == 0) {
led.addLineClass(change['lhs-line-from'], 'background', clazz.join(' '));
led.addLineClass(change['lhs-line-from'], 'background', 'first');
}
else {
var cl = clazz + 'lhs start';
led.setLineClass(change['lhs-line-from'], null, cl);
cl = clazz + 'lhs end';
led.setLineClass(change['lhs-line-to'], null, cl);
}
if (change['op'] == 'a') {
var cl = clazz + 'rhs start';
red.setLineClass(change['rhs-line-from'], null, cl);
if (change['rhs-line-from'] == change['rhs-line-to']) {
cl += ' end';
red.setLineClass(change['rhs-line-to'], null, cl);
}
else {
cl = clazz + 'rhs end';
red.setLineClass(change['rhs-line-to'], null, cl);
}
}
else if (change['op'] == 'd') {
// apply delete to cross-out
var from = change['lhs-line-from'];
var to = change['lhs-line-to'];
var to_ln = led.lineInfo(to);
if (to_ln) {
var func = led.markText({line:from, ch:0}, {line:to, ch:to_ln.text.length}, 'mergely ch d lhs');
self.change_funcs.push(func);
}
}
else if (change['op'] == 'c') {
// apply LCS changes to each line
for (var j = change['lhs-line-from'], k = change['rhs-line-from'], p = 0;
((j >= 0) && (j <= change['lhs-line-to'])) || ((k >= 0) && (k <= change['rhs-line-to']));
++j, ++k) {
if (k + p > change['rhs-line-to']) {
// lhs continues past rhs, mark lhs as deleted
var lhs_line = led.getLine( j );
var func = led.markText({line:j, ch:0}, {line:j, ch:lhs_line.length}, 'mergely ch d lhs');
self.change_funcs.push(func);
continue;
}
if (j + p > change['lhs-line-to']) {
// rhs continues past lhs, mark rhs as added
var rhs_line = red.getLine( k );
var func = led.markText({line:k, ch:0}, {line:k, ch:lhs_line.length}, 'mergely ch a rhs');
self.change_funcs.push(func);
continue;
}
var lhs_line = led.getLine( j );
var rhs_line = red.getLine( k );
var lhs_start = { 'line': -1, 'ch': -1 };
var lhs_stop = { 'line': -1, 'ch': -1 };
var rhs_start = { 'line': -1, 'ch': -1 };
var rhs_stop = { 'line': -1, 'ch': -1 };
var lcs = new Mgly.LCS(lhs_line, rhs_line);
var max = Math.max(lhs_line.length, rhs_line.length);
if (max == 0) max = 1;
var percent = ((1.0)*lcs.length / max) * 100;
if (percent < 10) lcs.clear();
lcs.diff(
added = function (index, c) {
if (rhs_start.ch < 0) {
rhs_start.line = k;
rhs_start.ch = index;
rhs_stop.line = k;
rhs_stop.ch = index;
}
else if (index == rhs_stop.ch + 1) {
rhs_stop.ch = index;
}
else {
if ((rhs_start.ch >= 0) && (rhs_stop.ch >= rhs_start.ch)) {
rhs_stop.ch += 1;
var func = self.editor[editor_name2].markText(rhs_start, rhs_stop, 'mergely ch a rhs');
self.change_funcs.push(func);
}
//reset
rhs_start.ch = -1;
rhs_stop.ch = -1;
if (c != '\n') this.added(index, c);//call again
}
},
removed = function (index, c) {
if (lhs_start.ch < 0) {
lhs_start.line = j;
lhs_start.ch = index;
lhs_stop.line = j;
lhs_stop.ch = index;
}
else if (index == lhs_stop.ch + 1) {
lhs_stop.ch = index;
}
else {
if ((lhs_start.ch >= 0) && (lhs_stop.ch >= lhs_start.ch)) {
lhs_stop.ch += 1;
var func = self.editor[editor_name1].markText(lhs_start, lhs_stop, 'mergely ch d lhs');
self.change_funcs.push(func);
}
//reset
lhs_start.ch = -1;
lhs_stop.ch = -1;
if (c != '\n') this.removed(index, c);//call again
}
}
);
if ((rhs_start.ch >= 0) && (rhs_stop.ch >= rhs_start.ch)) {
rhs_stop.ch += 1;
var func = red.markText(rhs_start, rhs_stop, 'mergely ch a rhs');
self.change_funcs.push(func);
}
if ((lhs_start.ch >= 0) && (lhs_stop.ch >= lhs_start.ch)) {
lhs_stop.ch += 1;
var func = led.markText(lhs_start, lhs_stop, 'mergely ch d lhs');
self.change_funcs.push(func);
}
// apply change for each line in-between the changed lines
for (var j = change['lhs-line-from']; j <= change['lhs-line-to']; ++j) {
led.addLineClass(j, 'background', clazz.join(' '));
led.addLineClass(j, 'background', clazz.join(' '));
}
}
// for each line in-between the changed lines, from and to, apply 'bg' class
for (var j = change['lhs-line-from'] + 1; j < change['lhs-line-to']; ++j) {
var cl = clazz + 'lhs';
led.setLineClass(j, null, cl);
}
// add widgets
var lhs_button = self.merge_lhs_button.clone();
if (lhs_button.button) {
@@ -970,8 +866,7 @@ jQuery.extend(Mgly.mergely.prototype, {
}
lhs_button.addClass('merge-button');
lhs_button.attr('id', 'merge-lhs-' + i);
red.addWidget(
{'line': change['rhs-line-from'], 'ch': 0}, lhs_button.get(0), false, 'over', 'right');
red.setGutterMarker(change['rhs-line-from'], 'merge', lhs_button.get(0));
var rhs_button = self.merge_rhs_button.clone();
if (rhs_button.button) {
@@ -980,68 +875,154 @@ jQuery.extend(Mgly.mergely.prototype, {
}
rhs_button.addClass('merge-button');
rhs_button.attr('id', 'merge-rhs-' + i);
led.addWidget(
{'line': change['lhs-line-from'], 'ch': 0}, rhs_button.get(0), false, 'over', 'right');
}
});
red.operation(function() {
for (var i = 0; i < changes.length; ++i) {
var change = changes[i];
var clazz = 'mergely ' + change['op'] + ' cid-' + i + ' ';
// rhs markup
if (change['rhs-line-from'] == change['rhs-line-to']) {
if (change['op'] == 'a') {
var cl = clazz + 'bg rhs start end';
red.setLineClass(change['rhs-line-from'], null, cl);
}
else if (change['op'] == 'd'){
if (change['lhs-line-from'] > 0) {
// deletes (left), normally start from the end of the rhs,
// except for the case when the start of the lhs is 0
var cl = clazz + 'rhs start end';
red.setLineClass(change['rhs-line-from'], null, cl);
// this will be sweet if gutters worked the same as lines
//red.setMarker(change['rhs-line-from'], null, cl)
}
else {
// case where there are no lines on the rhs or where the lhs change
// finishes before the rhs change
var cl = clazz + 'rhs start';
red.setLineClass(change['rhs-line-from'], null, cl);
// this will be sweet if gutters worked the same as lines
//red.setMarker(change['rhs-line-from'], null, cl)
}
}
else if (change['op'] == 'c') {
var cl = clazz + 'rhs start end';
red.setLineClass(change['rhs-line-from'], null, cl);
// this will be sweet if gutters worked the same as lines
//red.setMarker(change['rhs-line-from'], null, cl)
}
}
else {
var cl = clazz + 'rhs start';
red.setLineClass(change['rhs-line-from'], null, cl);
cl = clazz + 'rhs end';
red.setLineClass(change['rhs-line-to'], null, cl);
}
for (var i = change['rhs-line-from'] + 1; i <= change['rhs-line-to']; ++i) {
var cl = clazz + 'rhs';
if (change['op'] == 'c') {
// these lines are added
cl = 'mergely a cid-' + i + ' rhs c';
//if (i == change['rhs-line-to']) cl += ' c';
}
if (i == change['rhs-line-to']) cl += ' end';
red.setLineClass(i, '', cl);
}
led.setGutterMarker(change['lhs-line-from'], 'merge', rhs_button.get(0));
}
});
var ed = {lhs:this.editor[this.id + '-lhs'], rhs:this.editor[this.id + '-rhs']};
this.trace('change', 'markup lhs-editor time', timer.stop());
red.operation(function() {
for (var i = 0; i < changes.length; ++i) {
var change = changes[i];
var clazz = ['mergely', 'rhs', change['op'], 'cid-' + i];
red.addLineClass(change['rhs-line-from'], 'background', 'start');
red.addLineClass(change['rhs-line-to'], 'background', 'end');
if (change['rhs-line-from'] == 0 && change['rhs-line-to'] == 0) {
red.addLineClass(change['rhs-line-from'], 'background', clazz.join(' '));
red.addLineClass(change['rhs-line-from'], 'background', 'first');
}
else {
// apply change for each line in-between the changed lines
for (var j = change['rhs-line-from']; j <= change['rhs-line-to']; ++j) {
red.addLineClass(j, 'background', clazz.join(' '));
red.addLineClass(j, 'background', clazz.join(' '));
}
}
}
});
this.trace('change', 'markup rhs-editor time', timer.stop());
// mark text deleted, LCS changes
var marktext = [];
for (var i = 0; i < changes.length; ++i) {
var change = changes[i];
if (change['op'] == 'd') {
// apply delete to cross-out (left-hand side only)
var from = change['lhs-line-from'];
var to = change['lhs-line-to'];
var to_ln = led.lineInfo(to);
if (to_ln) {
marktext.push([led, {line:from, ch:0}, {line:to, ch:to_ln.text.length}, {className: 'mergely ch d lhs'}]);
}
}
else if (change['op'] == 'c') {
// apply LCS changes to each line
for (var j = change['lhs-line-from'], k = change['rhs-line-from'], p = 0;
((j >= 0) && (j <= change['lhs-line-to'])) || ((k >= 0) && (k <= change['rhs-line-to']));
++j, ++k) {
if (k + p > change['rhs-line-to']) {
// lhs continues past rhs, mark lhs as deleted
var lhs_line = led.getLine( j );
marktext.push([led, {line:j, ch:0}, {line:j, ch:lhs_line.length}, {className: 'mergely ch d lhs'}]);
continue;
}
if (j + p > change['lhs-line-to']) {
// rhs continues past lhs, mark rhs as added
var rhs_line = red.getLine( k );
marktext.push([red, {line:k, ch:0}, {line:k, ch:rhs_line.length}, {className: 'mergely ch a rhs'}]);
continue;
}
var lhs_line = led.getLine( j );
var rhs_line = red.getLine( k );
var lhs_start = { 'line': -1, 'ch': -1 };
var lhs_stop = { 'line': -1, 'ch': -1 };
var rhs_start = { 'line': -1, 'ch': -1 };
var rhs_stop = { 'line': -1, 'ch': -1 };
var lcs = new Mgly.LCS(lhs_line, rhs_line);
var max = Math.max(lhs_line.length, rhs_line.length);
if (max == 0) max = 1;
var percent = ((1.0)*lcs.length / max) * 100;
if (percent < 10) lcs.clear();
lcs.diff(
added = function (index, c) {
if (rhs_start.ch < 0) {
rhs_start.line = k;
rhs_start.ch = index;
rhs_stop.line = k;
rhs_stop.ch = index;
}
else if (index == rhs_stop.ch + 1) {
rhs_stop.ch = index;
}
else {
if ((rhs_start.ch >= 0) && (rhs_stop.ch >= rhs_start.ch)) {
rhs_stop.ch += 1;
marktext.push([red, {line:rhs_start.line, ch:rhs_start.ch}, {line:rhs_stop.line, ch:rhs_stop.ch}, {className: 'mergely ch a rhs'}]);
}
//reset
rhs_start.ch = -1;
rhs_stop.ch = -1;
if (c != '\n') this.added(index, c);//call again
}
},
removed = function (index, c) {
if (lhs_start.ch < 0) {
lhs_start.line = j;
lhs_start.ch = index;
lhs_stop.line = j;
lhs_stop.ch = index;
}
else if (index == lhs_stop.ch + 1) {
lhs_stop.ch = index;
}
else {
if ((lhs_start.ch >= 0) && (lhs_stop.ch >= lhs_start.ch)) {
lhs_stop.ch += 1;
marktext.push([led, {line:lhs_start.line, ch:lhs_start.ch}, {line:lhs_stop.line, ch:lhs_stop.ch}, {className: 'mergely ch d lhs'}]);
}
//reset
lhs_start.ch = -1;
lhs_stop.ch = -1;
if (c != '\n') this.removed(index, c);//call again
}
}
);
if ((rhs_start.ch >= 0) && (rhs_stop.ch >= rhs_start.ch)) {
rhs_stop.ch += 1;
marktext.push([red, {line:rhs_start.line, ch:rhs_start.ch}, {line:rhs_stop.line, ch:rhs_stop.ch}, {className: 'mergely ch a rhs'}]);
}
if ((lhs_start.ch >= 0) && (lhs_stop.ch >= lhs_start.ch)) {
lhs_stop.ch += 1;
marktext.push([led, {line:lhs_start.line, ch:lhs_start.ch}, {line:lhs_stop.line, ch:lhs_stop.ch}, {className: 'mergely ch d lhs'}]);
}
}
}
}
// mark changes outside closure
led.operation(function() {
// apply lhs markup
for (var i = 0; i < marktext.length; ++i) {
var m = marktext[i];
if (m[0].doc.id != led.getDoc().id) continue;
self.change_funcs.push(m[0].markText(m[1], m[2], m[3]));
}
});
red.operation(function() {
// apply lhs markup
for (var i = 0; i < marktext.length; ++i) {
var m = marktext[i];
if (m[0].doc.id != red.getDoc().id) continue;
var mark = m[0].markText(m[1], m[2], m[3]);
self.change_funcs.push(m[0].markText(m[1], m[2], m[3]));
}
});
// merge buttons
var ed = {lhs:led, rhs:red};
jQuery('.merge-button').on('click', function(ev){
// side of mouseenter
var side = 'rhs';
@@ -1051,7 +1032,7 @@ jQuery.extend(Mgly.mergely.prototype, {
side = 'lhs';
oside = 'rhs';
}
var pos = ed[side].coordsChar({x:ev.pageX, y:ev.pageY});
var pos = ed[side].coordsChar({left:ev.pageX, top:ev.pageY});
console.log('pos', side, pos);
// get the change id
@@ -1089,7 +1070,7 @@ jQuery.extend(Mgly.mergely.prototype, {
ed['rhs'].setValue(ed['rhs'].getValue());
return false;
});
this.trace('change', 'markup buttons time', timer.stop());
},
_draw_diff: function(editor_name1, editor_name2, changes) {
var visible_page_height = jQuery(this.editor[editor_name1].getScrollerElement()).height();