Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3830cff687 | ||
|
|
e38cd50037 | ||
|
|
85b02add89 | ||
|
|
5a0cd15ddd | ||
|
|
577a324d01 | ||
|
|
e38468b2c2 | ||
|
|
bd659adcfd | ||
|
|
ddeb16ef8b | ||
|
|
fd09b9761d | ||
|
|
b3f417e9af | ||
|
|
827c9ed8ef | ||
|
|
06189782de |
29
CHANGES.md
29
CHANGES.md
@@ -1,5 +1,34 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
|
## 4.2.2:
|
||||||
|
* patch: fixes issue where initial change was not being set causing next/prev and merge actions to not work as expected.
|
||||||
|
|
||||||
|
## 4.2.1:
|
||||||
|
* chore: updated dependencies, cleared security issues
|
||||||
|
|
||||||
|
## 4.2.0:
|
||||||
|
* minor: added new option `ignoreaccents` to ignore accented characters.
|
||||||
|
|
||||||
|
## 4.1.2:
|
||||||
|
* patch: fixes issue #134 where the readme had broken links.
|
||||||
|
|
||||||
|
## 4.1.1:
|
||||||
|
* patch: fixes issue #95 where cursor was not focusing correctly on init.
|
||||||
|
|
||||||
|
## 4.1.0:
|
||||||
|
* minor: emits 'updated' event after every change.
|
||||||
|
* patch: fixes `scrollTo` that no longer functioned after a codemirror update.
|
||||||
|
* patch: fixes `loaded` being called prematurely and after every resize, and is now is called once, after the 'updated' event.
|
||||||
|
|
||||||
|
## 4.0.16:
|
||||||
|
* patch: fixes rendering beyond change constraint
|
||||||
|
|
||||||
|
## 4.0.15
|
||||||
|
* patch: removed unnecessary addon mark-selected
|
||||||
|
|
||||||
|
## 4.0.14
|
||||||
|
* patch: fixes issue #104 where diff text conflicted with selected text
|
||||||
|
|
||||||
## 4.0.13
|
## 4.0.13
|
||||||
* patch: fixed issue where `lhs_cmsettings` and `lhs_cmsettings` were ignored
|
* patch: fixed issue where `lhs_cmsettings` and `lhs_cmsettings` were ignored
|
||||||
* patch: updated documentation
|
* patch: updated documentation
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -1,6 +1,6 @@
|
|||||||
# Mergely
|
# Mergely
|
||||||
|
|
||||||
http://mergely.com
|
https://mergely.com
|
||||||
|
|
||||||
Mergely is a JavaScript component for differencing and merging files interactively in a browser (diff/merge), providing rich API that enables you to easily integrate Mergely into your existing web application. It is suitable for comparing text files online, for example, .txt, .html, .xml, .c, .cpp, .java, etc.
|
Mergely is a JavaScript component for differencing and merging files interactively in a browser (diff/merge), providing rich API that enables you to easily integrate Mergely into your existing web application. It is suitable for comparing text files online, for example, .txt, .html, .xml, .c, .cpp, .java, etc.
|
||||||
|
|
||||||
@@ -93,19 +93,20 @@ $(document).ready(function () {
|
|||||||
|<a name="autoupdate"></a>autoupdate|boolean|`true`|Enables/disables the auto-updating of the editor when changes are made.|
|
|<a name="autoupdate"></a>autoupdate|boolean|`true`|Enables/disables the auto-updating of the editor when changes are made.|
|
||||||
|<a name="bgcolor"></a>bgcolor|string|`#eeeeee`|The background color that mergely fills the margin canvas with.|
|
|<a name="bgcolor"></a>bgcolor|string|`#eeeeee`|The background color that mergely fills the margin canvas with.|
|
||||||
|<a name="change_timeout"></a>change_timeout|number|`500`|The timeout, after a text change, before Mergely calculates a diff. Only used when `readonly` is enabled.|
|
|<a name="change_timeout"></a>change_timeout|number|`500`|The timeout, after a text change, before Mergely calculates a diff. Only used when `readonly` is enabled.|
|
||||||
|<a name="cmsettings"></a>cmsettings|object|`{mode: 'text/plain', readOnly: false}`|CodeMirror settings (see [CodeMirror](http://codemirror.net])) that are combined with `lhs_cmsettings` and `rhs_cmsettings`.|
|
|<a name="cmsettings"></a>cmsettings|object|`{mode: 'text/plain', readOnly: false}`|CodeMirror settings (see [CodeMirror](https://codemirror.net)) that are combined with `lhs_cmsettings` and `rhs_cmsettings`.|
|
||||||
|<a name="editor_width"></a>editor_width|string|`400px`|Starting width.|
|
|<a name="editor_width"></a>editor_width|string|`400px`|Starting width.|
|
||||||
|<a name="editor_height"></a>editor_height|string|`400px`|Starting height.|
|
|<a name="editor_height"></a>editor_height|string|`400px`|Starting height.|
|
||||||
|<a name="fadein"></a>fadein|string|`fast`|A jQuery [fadein](http://api.jquery.com/fadein) value to enable the editor to fade in. Set to empty string to disable.|
|
|<a name="fadein"></a>fadein|string|`fast`|A jQuery [fadein](http://api.jquery.com/fadein) value to enable the editor to fade in. Set to empty string to disable.|
|
||||||
|<a name="fgcolor"></a>fgcolor|string\|number\|object|`{a:'#4ba3fa', c:'#a3a3a3', d:'#ff7f7f', ca:'#4b73ff', cc:'#434343', cd:'#ff4f4f'}`|The foreground color that mergely marks changes with on the canvas. The value **a** is additions, **c** changes, **d** deletions, and the prefix *c* indicates current/active change (e.g. **cd** current delection).|
|
|<a name="fgcolor"></a>fgcolor|string\|number\|object|`{a:'#4ba3fa', c:'#a3a3a3', d:'#ff7f7f', ca:'#4b73ff', cc:'#434343', cd:'#ff4f4f'}`|The foreground color that mergely marks changes with on the canvas. The value **a** is additions, **c** changes, **d** deletions, and the prefix *c* indicates current/active change (e.g. **cd** current delection).|
|
||||||
|<a name="ignorews"></a>ignorews|boolean|`false`|Ignores white-space.|
|
|<a name="ignorews"></a>ignorews|boolean|`false`|Ignores white-space.|
|
||||||
|<a name="ignorecase"></a>ignorecase|boolean|`false`|Ignores case when differientiating.
|
|<a name="ignorecase"></a>ignorecase|boolean|`false`|Ignores case when differientiating.|
|
||||||
|
|<a name="ignoreaccents"></a>ignorews|boolean|`false`|Ignores accented characters.|
|
||||||
|<a name="lcs"></a>lcs|boolean|`true`|Enables/disables LCS computation for paragraphs (word-by-word changes). Disabling can give a performance gain for large documents.|
|
|<a name="lcs"></a>lcs|boolean|`true`|Enables/disables LCS computation for paragraphs (word-by-word changes). Disabling can give a performance gain for large documents.|
|
||||||
|<a name="license"></a>license|string|`lgpl`|The choice of license to use with Mergely. Valid values are: `lgpl`, `gpl`, `mpl` or `lgpl-separate-notice`, `gpl-separate-notice`, `mpl-separate-notice` (the license requirements are met in a separate notice file).|
|
|<a name="license"></a>license|string|`lgpl`|The choice of license to use with Mergely. Valid values are: `lgpl`, `gpl`, `mpl` or `lgpl-separate-notice`, `gpl-separate-notice`, `mpl-separate-notice` (the license requirements are met in a separate notice file).|
|
||||||
|<a name="line_numbers"></a>line_numbers|boolean|`true`|Enables/disables line numbers. Enabling line numbers will toggle the visibility of the line number margins.|
|
|<a name="line_numbers"></a>line_numbers|boolean|`true`|Enables/disables line numbers. Enabling line numbers will toggle the visibility of the line number margins.|
|
||||||
|<a name="lhs_cmsettings"></a>lhs_cmsettings|object|`{}`|The CodeMirror settings (see [CodeMirror](http://codemirror.net])) for the left-hand side editor.|
|
|<a name="lhs_cmsettings"></a>lhs_cmsettings|object|`{}`|The CodeMirror settings (see [CodeMirror](https://codemirror.net)) for the left-hand side editor.|
|
||||||
|<a name="resize_timeout"></a>resize_timeout|number|`500`|The timeout, after a resize, before Mergely auto-resizes. Only used when autoresize enabled.|
|
|<a name="resize_timeout"></a>resize_timeout|number|`500`|The timeout, after a resize, before Mergely auto-resizes. Only used when autoresize enabled.|
|
||||||
|<a name="rhs_cmsettings"></a>rhs_cmsettings|object|`{}`|The CodeMirror settings (see [CodeMirror](http://codemirror.net])) for the right-hand side editor.|
|
|<a name="rhs_cmsettings"></a>rhs_cmsettings|object|`{}`|The CodeMirror settings (see [CodeMirror](https://codemirror.net)) for the right-hand side editor.|
|
||||||
|<a name="rhs_margin"></a>rhs_margin|string|`right`|Location for the rhs markup margin. Possible values: right, left.|
|
|<a name="rhs_margin"></a>rhs_margin|string|`right`|Location for the rhs markup margin. Possible values: right, left.|
|
||||||
|<a name="sidebar"></a>sidebar|boolean|`true`|Enables/disables sidebar markers. Disabling can give a performance gain for large documents.|
|
|<a name="sidebar"></a>sidebar|boolean|`true`|Enables/disables sidebar markers. Disabling can give a performance gain for large documents.|
|
||||||
|<a name="vpcolor"></a>vpcolor|string|`rgba(0, 0, 200, 0.5)`|The margin/viewport indicator color.|
|
|<a name="vpcolor"></a>vpcolor|string|`rgba(0, 0, 200, 0.5)`|The margin/viewport indicator color.|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
require('codemirror/addon/selection/mark-selection.js');
|
||||||
require('codemirror/lib/codemirror.css');
|
require('codemirror/lib/codemirror.css');
|
||||||
require('../src/mergely.css');
|
require('../src/mergely.css');
|
||||||
|
|
||||||
|
|||||||
@@ -53,11 +53,13 @@ module.exports = function(config) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new CopyWebpackPlugin([{
|
new CopyWebpackPlugin({
|
||||||
from: 'src/mergely.css',
|
patterns: [{
|
||||||
to: 'mergely.css',
|
from: 'src/mergely.css',
|
||||||
toType: 'file'
|
to: 'mergely.css',
|
||||||
}])
|
toType: 'file'
|
||||||
|
}]
|
||||||
|
})
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
webpackServer: {
|
webpackServer: {
|
||||||
|
|||||||
39
package.json
39
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mergely",
|
"name": "mergely",
|
||||||
"version": "4.0.13",
|
"version": "4.2.2",
|
||||||
"description": "A javascript UI for diff/merge",
|
"description": "A javascript UI for diff/merge",
|
||||||
"directories": {
|
"directories": {
|
||||||
"doc": "doc",
|
"doc": "doc",
|
||||||
@@ -36,34 +36,33 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.1.6",
|
"@babel/core": "^7.1.6",
|
||||||
"@babel/preset-env": "^7.1.6",
|
"@babel/preset-env": "^7.1.6",
|
||||||
"@webpack-cli/init": "^0.1.2",
|
"@webpack-cli/init": "^1.0.1",
|
||||||
"babel-loader": "^8.0.4",
|
"babel-loader": "^8.0.4",
|
||||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||||
"chai": "^4.1.2",
|
"chai": "^4.1.2",
|
||||||
"codemirror": "^5.32.0",
|
"codemirror": "^5.50.2",
|
||||||
"copy-webpack-plugin": "^4.6.0",
|
"copy-webpack-plugin": "^6.2.1",
|
||||||
"css-loader": "^0.28.11",
|
"css-loader": "^5.0.0",
|
||||||
"file-loader": "^1.1.5",
|
"file-loader": "^6.1.1",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^4.5.0",
|
||||||
"image-webpack-loader": "^3.4.2",
|
"image-webpack-loader": "^7.0.1",
|
||||||
"jquery": "^3.2.1",
|
"jquery": "^3.5.1",
|
||||||
"karma": "^3.1.1",
|
"karma": "^5.2.3",
|
||||||
"karma-chai": "^0.1.0",
|
"karma-chai": "^0.1.0",
|
||||||
"karma-chrome-launcher": "^2.2.0",
|
"karma-chrome-launcher": "^3.1.0",
|
||||||
"karma-coverage-istanbul-reporter": "^1.3.0",
|
"karma-coverage-istanbul-reporter": "^1.3.0",
|
||||||
"karma-mocha": "^1.3.0",
|
"karma-mocha": "^2.0.1",
|
||||||
"karma-mocha-reporter": "^2.2.5",
|
"karma-mocha-reporter": "^2.2.5",
|
||||||
"karma-webpack": "^2.0.9",
|
"karma-webpack": "^4.0.2",
|
||||||
"mocha": "^4.0.1",
|
"mocha": "^8.1.3",
|
||||||
"style-loader": "^0.23.0",
|
"style-loader": "^2.0.0",
|
||||||
"uglifyjs-webpack-plugin": "^2.0.1",
|
"webpack": "^4.44.2",
|
||||||
"webpack": "^4.20.2",
|
"webpack-cli": "^4.0.0",
|
||||||
"webpack-cli": "^3.1.2",
|
"webpack-dev-server": "^3.11.0"
|
||||||
"webpack-dev-server": "^3.1.9"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rm -rf lib && webpack --config ./webpack.prod.js",
|
"build": "rm -rf lib && webpack --config ./webpack.prod.js",
|
||||||
"start": "webpack-dev-server -w --debug --progress --colors --config ./webpack.dev.js --content-base ./dist --inline --hot --host 0.0.0.0",
|
"start": "webpack serve --config webpack.dev.js",
|
||||||
"test": "karma start",
|
"test": "karma start",
|
||||||
"test:chrome": "karma start --browsers Chrome --singleRun=false"
|
"test:chrome": "karma start --browsers Chrome --singleRun=false"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,3 +48,4 @@
|
|||||||
.mergely.current.CodeMirror-linenumber { color: #F9F9F9; font-weight: bold; background-color: #777; }
|
.mergely.current.CodeMirror-linenumber { color: #F9F9F9; font-weight: bold; background-color: #777; }
|
||||||
.CodeMirror-linenumber { cursor: pointer; }
|
.CodeMirror-linenumber { cursor: pointer; }
|
||||||
.CodeMirror-code { color: #717171; }
|
.CodeMirror-code { color: #717171; }
|
||||||
|
span.CodeMirror-selectedtext { background: none !important; }
|
||||||
|
|||||||
@@ -41,15 +41,19 @@ Mgly.sizeOf = function(obj) {
|
|||||||
return size;
|
return size;
|
||||||
};
|
};
|
||||||
|
|
||||||
Mgly.LCS = function(x, y) {
|
Mgly.LCS = function(x, y, options) {
|
||||||
this.x = (x && x.replace(/[ ]{1}/g, '\n')) || '';
|
this.x = (x && x.replace(/[ ]{1}/g, '\n')) || '';
|
||||||
this.y = (y && y.replace(/[ ]{1}/g, '\n')) || '';
|
this.y = (y && y.replace(/[ ]{1}/g, '\n')) || '';
|
||||||
|
this.options = options;
|
||||||
};
|
};
|
||||||
|
|
||||||
jQuery.extend(Mgly.LCS.prototype, {
|
jQuery.extend(Mgly.LCS.prototype, {
|
||||||
clear: function() { this.ready = 0; },
|
clear: function() { this.ready = 0; },
|
||||||
diff: function(added, removed) {
|
diff: function(added, removed) {
|
||||||
var d = new Mgly.diff(this.x, this.y, {ignorews: false});
|
var d = new Mgly.diff(this.x, this.y, {
|
||||||
|
ignorews: false,
|
||||||
|
ignoreaccents: !!this.options.ignoreaccents
|
||||||
|
});
|
||||||
var changes = Mgly.DiffParser(d.normal_form());
|
var changes = Mgly.DiffParser(d.normal_form());
|
||||||
var li = 0, lj = 0;
|
var li = 0, lj = 0;
|
||||||
for (var i = 0; i < changes.length; ++i) {
|
for (var i = 0; i < changes.length; ++i) {
|
||||||
@@ -86,7 +90,6 @@ Mgly.CodeifyText = function(settings) {
|
|||||||
this._max_code = 0;
|
this._max_code = 0;
|
||||||
this._diff_codes = {};
|
this._diff_codes = {};
|
||||||
this.ctxs = {};
|
this.ctxs = {};
|
||||||
this.options = {ignorews: false};
|
|
||||||
jQuery.extend(this, settings);
|
jQuery.extend(this, settings);
|
||||||
this.lhs = settings.lhs.split('\n');
|
this.lhs = settings.lhs.split('\n');
|
||||||
this.rhs = settings.rhs.split('\n');
|
this.rhs = settings.rhs.split('\n');
|
||||||
@@ -119,6 +122,9 @@ jQuery.extend(Mgly.CodeifyText.prototype, {
|
|||||||
if (this.options.ignorecase) {
|
if (this.options.ignorecase) {
|
||||||
line = line.toLowerCase();
|
line = line.toLowerCase();
|
||||||
}
|
}
|
||||||
|
if (this.options.ignoreaccents) {
|
||||||
|
line = line.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
||||||
|
}
|
||||||
var aCode = this._diff_codes[line];
|
var aCode = this._diff_codes[line];
|
||||||
if (aCode != undefined) {
|
if (aCode != undefined) {
|
||||||
ctx.codes[i] = aCode;
|
ctx.codes[i] = aCode;
|
||||||
@@ -133,7 +139,7 @@ jQuery.extend(Mgly.CodeifyText.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Mgly.diff = function(lhs, rhs, options) {
|
Mgly.diff = function(lhs, rhs, options) {
|
||||||
var opts = jQuery.extend({ignorews: false}, options);
|
var opts = jQuery.extend({ignorews: false, ignoreaccents: false}, options);
|
||||||
this.codeify = new Mgly.CodeifyText({
|
this.codeify = new Mgly.CodeifyText({
|
||||||
lhs: lhs,
|
lhs: lhs,
|
||||||
rhs: rhs,
|
rhs: rhs,
|
||||||
@@ -367,7 +373,7 @@ Mgly.CodeMirrorDiffView = function(el, options) {
|
|||||||
CodeMirror.defineExtension('centerOnCursor', function() {
|
CodeMirror.defineExtension('centerOnCursor', function() {
|
||||||
var coords = this.cursorCoords(null, 'local');
|
var coords = this.cursorCoords(null, 'local');
|
||||||
this.scrollTo(null,
|
this.scrollTo(null,
|
||||||
(coords.y + coords.yBot) / 2 - (this.getScrollerElement().clientHeight / 2));
|
(coords.top + coords.bottom) / 2 - (this.getScrollerElement().clientHeight / 2));
|
||||||
});
|
});
|
||||||
this.init(el, options);
|
this.init(el, options);
|
||||||
};
|
};
|
||||||
@@ -385,6 +391,7 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
viewport: false,
|
viewport: false,
|
||||||
ignorews: false,
|
ignorews: false,
|
||||||
ignorecase: false,
|
ignorecase: false,
|
||||||
|
ignoreaccents: false,
|
||||||
fadein: 'fast',
|
fadein: 'fast',
|
||||||
resize_timeout: 500,
|
resize_timeout: 500,
|
||||||
change_timeout: 150,
|
change_timeout: 150,
|
||||||
@@ -395,6 +402,9 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
license: '',
|
license: '',
|
||||||
width: 'auto',
|
width: 'auto',
|
||||||
height: 'auto',
|
height: 'auto',
|
||||||
|
cmsettings: {
|
||||||
|
styleSelectedText: true
|
||||||
|
},
|
||||||
lhs: function(setValue) { },
|
lhs: function(setValue) { },
|
||||||
rhs: function(setValue) { },
|
rhs: function(setValue) { },
|
||||||
loaded: function() { },
|
loaded: function() { },
|
||||||
@@ -429,14 +439,12 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
else {
|
else {
|
||||||
self.show();
|
self.show();
|
||||||
}
|
}
|
||||||
if (this.loaded) this.loaded();
|
|
||||||
}
|
}
|
||||||
if (this.resized) this.resized();
|
if (this.resized) this.resized();
|
||||||
},
|
},
|
||||||
_debug: '', //scroll,draw,calc,diff,markup,change
|
_debug: '', //scroll,draw,calc,diff,markup,change,init
|
||||||
resized: function() { }
|
resized: function() { }
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
// save this element for faster queries
|
// save this element for faster queries
|
||||||
this.element = jQuery(el);
|
this.element = jQuery(el);
|
||||||
|
|
||||||
@@ -497,7 +505,7 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
scrollToDiff: function(direction) {
|
scrollToDiff: function(direction) {
|
||||||
if (!this.changes.length) return;
|
if (!this.changes.length) return;
|
||||||
if (direction == 'next') {
|
if (direction == 'next') {
|
||||||
if (this._current_diff == this.changes.length -1) {
|
if (this._current_diff == this.changes.length - 1) {
|
||||||
this._current_diff = 0;
|
this._current_diff = 0;
|
||||||
} else {
|
} else {
|
||||||
this._current_diff = Math.min(++this._current_diff, this.changes.length - 1);
|
this._current_diff = Math.min(++this._current_diff, this.changes.length - 1);
|
||||||
@@ -645,6 +653,7 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
return d.normal_form();
|
return d.normal_form();
|
||||||
},
|
},
|
||||||
bind: function(el) {
|
bind: function(el) {
|
||||||
|
this.trace('init', 'bind');
|
||||||
this.element.hide();
|
this.element.hide();
|
||||||
this.id = jQuery(el).attr('id');
|
this.id = jQuery(el).attr('id');
|
||||||
try {
|
try {
|
||||||
@@ -781,6 +790,7 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
|
|
||||||
// bind
|
// bind
|
||||||
var self = this;
|
var self = this;
|
||||||
|
self.trace('init', 'binding event listeners');
|
||||||
this.editor = [];
|
this.editor = [];
|
||||||
this.editor[this.id + '-lhs'] = CodeMirror.fromTextArea(lhstx, this.lhs_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 + '-rhs'] = CodeMirror.fromTextArea(rhstx, this.rhs_cmsettings);
|
||||||
@@ -795,9 +805,6 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
if (self.settings.resize) self.settings.resize(init);
|
if (self.settings.resize) self.settings.resize(init);
|
||||||
self.editor[self.id + '-lhs'].refresh();
|
self.editor[self.id + '-lhs'].refresh();
|
||||||
self.editor[self.id + '-rhs'].refresh();
|
self.editor[self.id + '-rhs'].refresh();
|
||||||
if (self.settings.autoupdate) {
|
|
||||||
self._changing(self.id + '-lhs', self.id + '-rhs');
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
jQuery(window).on('resize.mergely',
|
jQuery(window).on('resize.mergely',
|
||||||
function () {
|
function () {
|
||||||
@@ -839,19 +846,34 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
gutterClicked.call(this, 'rhs', n, ev);
|
gutterClicked.call(this, 'rhs', n, ev);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
//bind
|
// if `lhs` and `rhs` are passed in, this sets the values in each editor
|
||||||
|
// and kicks off the whole change pipeline.
|
||||||
var setv;
|
var setv;
|
||||||
if (this.settings.lhs) {
|
if (this.settings.lhs) {
|
||||||
setv = this.editor[this.id + '-lhs'].getDoc().setValue;
|
self.trace('init', 'setting lhs value');
|
||||||
this.settings.lhs(setv.bind(this.editor[this.id + '-lhs'].getDoc()));
|
this.settings.lhs(function setValue(value) {
|
||||||
|
this._initializing = true;
|
||||||
|
this.editor[this.id + '-lhs'].getDoc().setValue(value);
|
||||||
|
}.bind(this));
|
||||||
}
|
}
|
||||||
if (this.settings.rhs) {
|
if (this.settings.rhs) {
|
||||||
setv = this.editor[this.id + '-rhs'].getDoc().setValue;
|
self.trace('init', 'setting rhs value');
|
||||||
this.settings.rhs(setv.bind(this.editor[this.id + '-rhs'].getDoc()));
|
this.settings.rhs(function setValue(value) {
|
||||||
|
this._initializing = true;
|
||||||
|
this.editor[this.id + '-rhs'].getDoc().setValue(value);
|
||||||
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
this.element.one('updated', () => {
|
||||||
|
this._initializing = false;
|
||||||
|
if (self.settings.loaded) {
|
||||||
|
self.settings.loaded();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.trace('init', 'bound');
|
||||||
|
this.editor[this.id + '-lhs'].focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
_scroll_to_change : function(change) {
|
_scroll_to_change: function(change) {
|
||||||
if (!change) return;
|
if (!change) return;
|
||||||
var self = this;
|
var self = this;
|
||||||
var led = self.editor[self.id+'-lhs'];
|
var led = self.editor[self.id+'-lhs'];
|
||||||
@@ -862,6 +884,7 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
if (change["lhs-line-to"] >= 0) {
|
if (change["lhs-line-to"] >= 0) {
|
||||||
led.scrollIntoView({line: change["lhs-line-to"]});
|
led.scrollIntoView({line: change["lhs-line-to"]});
|
||||||
}
|
}
|
||||||
|
led.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
_scrolling: function(editor_name) {
|
_scrolling: function(editor_name) {
|
||||||
@@ -870,6 +893,11 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
this._skipscroll[editor_name] = false;
|
this._skipscroll[editor_name] = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!this.changes) {
|
||||||
|
// pasting a wide line can trigger scroll before changes
|
||||||
|
// are calculated
|
||||||
|
return;
|
||||||
|
}
|
||||||
var scroller = jQuery(this.editor[editor_name].getScrollerElement());
|
var scroller = jQuery(this.editor[editor_name].getScrollerElement());
|
||||||
if (this.midway == undefined) {
|
if (this.midway == undefined) {
|
||||||
this.midway = (scroller.height() / 2.0 + scroller.offset().top).toFixed(2);
|
this.midway = (scroller.height() / 2.0 + scroller.offset().top).toFixed(2);
|
||||||
@@ -1023,9 +1051,12 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
this.changes = Mgly.DiffParser(d.normal_form());
|
this.changes = Mgly.DiffParser(d.normal_form());
|
||||||
this.trace('change', 'parse time', Timer.stop());
|
this.trace('change', 'parse time', Timer.stop());
|
||||||
if (this._current_diff === undefined && this.changes.length) {
|
if (this._current_diff === undefined && this.changes.length) {
|
||||||
// go to first difference on start-up
|
// go to first difference on start-up where values are provided in
|
||||||
|
// settings.
|
||||||
this._current_diff = 0;
|
this._current_diff = 0;
|
||||||
this._scroll_to_change(this.changes[0]);
|
if (this._initializing) {
|
||||||
|
this._scroll_to_change(this.changes[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.trace('change', 'scroll_to_change time', Timer.stop());
|
this.trace('change', 'scroll_to_change time', Timer.stop());
|
||||||
this._calculate_offsets(editor_name1, editor_name2, this.changes);
|
this._calculate_offsets(editor_name1, editor_name2, this.changes);
|
||||||
@@ -1034,6 +1065,7 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
this.trace('change', 'markup time', Timer.stop());
|
this.trace('change', 'markup time', Timer.stop());
|
||||||
this._draw_diff(editor_name1, editor_name2, this.changes);
|
this._draw_diff(editor_name1, editor_name2, this.changes);
|
||||||
this.trace('change', 'draw time', Timer.stop());
|
this.trace('change', 'draw time', Timer.stop());
|
||||||
|
this.element.trigger('updated');
|
||||||
},
|
},
|
||||||
_parse_diff: function (editor_name1, editor_name2, diff) {
|
_parse_diff: function (editor_name1, editor_name2, diff) {
|
||||||
this.trace('diff', 'diff results:\n', diff);
|
this.trace('diff', 'diff results:\n', diff);
|
||||||
@@ -1354,17 +1386,17 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
}
|
}
|
||||||
else if (change['op'] == 'c') {
|
else if (change['op'] == 'c') {
|
||||||
// apply LCS changes to each line
|
// apply LCS changes to each line
|
||||||
for (j = llf, k = rlf, p = 0;
|
for (j = llf, k = rlf;
|
||||||
((j >= 0) && (j <= llt)) || ((k >= 0) && (k <= rlt));
|
((j >= 0) && (j <= llt)) || ((k >= 0) && (k <= rlt));
|
||||||
++j, ++k) {
|
++j, ++k) {
|
||||||
var lhs_line, rhs_line;
|
var lhs_line, rhs_line;
|
||||||
if (k + p > rlt && this._is_change_in_view('lhs', lhsvp, change)) {
|
if (k > rlt) {
|
||||||
// lhs continues past rhs, mark lhs as deleted
|
// lhs continues past rhs, mark lhs as deleted
|
||||||
lhs_line = led.getLine( j );
|
lhs_line = led.getLine( j );
|
||||||
marktext.push([led, {line:j, ch:0}, {line:j, ch:lhs_line.length}, {className: 'mergely ch d lhs'}]);
|
marktext.push([led, {line:j, ch:0}, {line:j, ch:lhs_line.length}, {className: 'mergely ch d lhs'}]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (j + p > llt && this._is_change_in_view('rhs', rhsvp, change)) {
|
if (j > llt) {
|
||||||
// rhs continues past lhs, mark rhs as added
|
// rhs continues past lhs, mark rhs as added
|
||||||
rhs_line = red.getLine( k );
|
rhs_line = red.getLine( k );
|
||||||
marktext.push([red, {line:k, ch:0}, {line:k, ch:rhs_line.length}, {className: 'mergely ch a rhs'}]);
|
marktext.push([red, {line:k, ch:0}, {line:k, ch:rhs_line.length}, {className: 'mergely ch a rhs'}]);
|
||||||
@@ -1372,7 +1404,9 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
}
|
}
|
||||||
lhs_line = led.getLine( j );
|
lhs_line = led.getLine( j );
|
||||||
rhs_line = red.getLine( k );
|
rhs_line = red.getLine( k );
|
||||||
var lcs = new Mgly.LCS(lhs_line, rhs_line);
|
var lcs = new Mgly.LCS(lhs_line, rhs_line, {
|
||||||
|
ignoreaccents: !!this.settings.ignoreaccents
|
||||||
|
});
|
||||||
lcs.diff(
|
lcs.diff(
|
||||||
function added (from, to) {
|
function added (from, to) {
|
||||||
if (self._is_change_in_view('rhs', rhsvp, change)) {
|
if (self._is_change_in_view('rhs', rhsvp, change)) {
|
||||||
|
|||||||
@@ -586,28 +586,48 @@ describe('mergely', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should not be vulnerable to XSS', function (done) {
|
it('should not be vulnerable to XSS', function (done) {
|
||||||
function initXSS(options) {
|
function initXSS(options) {
|
||||||
$('body').get(0).innerHTML = "<!DOCTYPE html><html lang=\"en\"><body><div id='mergely<script id=\"injected\">alert(123)</script>'></div></body></html>";
|
$('body').get(0).innerHTML = "<!DOCTYPE html><html lang=\"en\"><body><div id='mergely<script id=\"injected\">alert(123)</script>'></div></body></html>";
|
||||||
const divs = document.getElementsByTagName('div');
|
const divs = document.getElementsByTagName('div');
|
||||||
editor = $(divs[0]);
|
editor = $(divs[0]);
|
||||||
editor.mergely(options);
|
editor.mergely(options);
|
||||||
return editor;
|
return editor;
|
||||||
};
|
};
|
||||||
|
|
||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
const editor = initXSS({
|
const editor = initXSS({
|
||||||
height: 100,
|
height: 100,
|
||||||
viewport: true,
|
viewport: true,
|
||||||
license: 'lgpl-separate-notice',
|
license: 'lgpl-separate-notice',
|
||||||
lhs: (setValue) => setValue(macbeth),
|
lhs: (setValue) => setValue(macbeth),
|
||||||
rhs: (setValue) => setValue(macbeth)
|
rhs: (setValue) => setValue(macbeth)
|
||||||
});
|
});
|
||||||
expect($('body').find('#injected')).to.have.length(0, 'expected no div with id injected');
|
expect($('body').find('#injected')).to.have.length(0, 'expected no div with id injected');
|
||||||
const divs = document.getElementsByTagName('div');
|
const divs = document.getElementsByTagName('div');
|
||||||
expect(divs).to.have.length(1);
|
expect(divs).to.have.length(1);
|
||||||
expect(divs[0].id).to.equal('mergely<script id="injected">alert(123)</script>');
|
expect(divs[0].id).to.equal('mergely<script id="injected">alert(123)</script>');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore accented characters', function (done) {
|
||||||
|
$(document).ready(() => {
|
||||||
|
const editor = init({
|
||||||
|
height: 100,
|
||||||
|
license: 'lgpl-separate-notice',
|
||||||
|
ignoreaccents: true,
|
||||||
|
lhs: (setValue) => setValue('comunicação'),
|
||||||
|
rhs: (setValue) => setValue('comunicacao')
|
||||||
|
});
|
||||||
|
const { mergely } = $('#mergely');
|
||||||
|
|
||||||
|
$('#mergely').on('updated', () => {
|
||||||
|
console.log('updated');
|
||||||
|
const diff = $('#mergely').mergely('diff');;
|
||||||
|
expect(diff).to.equal('');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,10 +19,7 @@ module.exports = {
|
|||||||
}, {
|
}, {
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
use: [{
|
use: [{
|
||||||
loader: 'style-loader',
|
loader: 'style-loader'
|
||||||
options: {
|
|
||||||
sourceMap: true
|
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
loader: 'css-loader'
|
loader: 'css-loader'
|
||||||
}]
|
}]
|
||||||
@@ -39,8 +36,7 @@ module.exports = {
|
|||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: 'examples/app.html',
|
template: path.join(__dirname, 'examples', 'app.html')
|
||||||
filename: 'mergely.html'
|
|
||||||
}),
|
}),
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
$: 'jquery',
|
$: 'jquery',
|
||||||
@@ -70,11 +66,9 @@ module.exports = {
|
|||||||
test: /[\\/]node_modules[\\/]/
|
test: /[\\/]node_modules[\\/]/
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
chunks: 'async',
|
chunks: 'async',
|
||||||
minChunks: 1,
|
minChunks: 1,
|
||||||
minSize: 30000,
|
minSize: 30000
|
||||||
name: true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,10 +29,12 @@ module.exports = {
|
|||||||
CodeMirror: 'CodeMirror'
|
CodeMirror: 'CodeMirror'
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new CopyWebpackPlugin([{
|
new CopyWebpackPlugin({
|
||||||
from: 'src/mergely.css',
|
patterns: [{
|
||||||
to: 'mergely.css',
|
from: 'src/mergely.css',
|
||||||
toType: 'file'
|
to: 'mergely.css',
|
||||||
}])
|
toType: 'file'
|
||||||
|
}]
|
||||||
|
})
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user