Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d44470103 | ||
|
|
2c8f6cd340 | ||
|
|
6716096215 | ||
|
|
217674cd07 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
/node_modules
|
/node_modules
|
||||||
/lib
|
/lib
|
||||||
mergely-*.tgz
|
mergely-*.tgz
|
||||||
|
package-lock.json
|
||||||
|
|||||||
15
CHANGES.md
15
CHANGES.md
@@ -1,5 +1,20 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
|
## 4.0.7
|
||||||
|
* chore: updated documentation
|
||||||
|
|
||||||
|
## 4.0.6
|
||||||
|
|
||||||
|
* #89: fixes missing merge buttons
|
||||||
|
|
||||||
|
## 4.0.5
|
||||||
|
|
||||||
|
* #85: fixes XSS vulnerability with DOM id
|
||||||
|
|
||||||
|
## 4.0.2
|
||||||
|
|
||||||
|
* #83: fixes poor rendering performance
|
||||||
|
|
||||||
## 4.0.0
|
## 4.0.0
|
||||||
|
|
||||||
### Breaking changes
|
### Breaking changes
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ Mergely is a javascript component to diff/merge files interactively in a browser
|
|||||||
### Installation via webpack
|
### Installation via webpack
|
||||||
The recommended way to install mergely is to use npm and [webpack](https://webpack.js.org/) to install mergely and its dependencies. It is highly recommended that you start by cloning [mergely-webpack](https://github.com/wickedest/mergely-webpack). It has everything that you need to get started.
|
The recommended way to install mergely is to use npm and [webpack](https://webpack.js.org/) to install mergely and its dependencies. It is highly recommended that you start by cloning [mergely-webpack](https://github.com/wickedest/mergely-webpack). It has everything that you need to get started.
|
||||||
|
|
||||||
|
### Angular 6.1.1
|
||||||
|
You can also use mergely within angular. You can start by cloning [mergely-angular](https://github.com/wickedest/mergely-angular).
|
||||||
|
|
||||||
### Installation via .tgz
|
### Installation via .tgz
|
||||||
|
|
||||||
Unpack mergely.tgz into a folder, e.g. `./lib`, and then add the following to the `<head>` of your target html source file.
|
Unpack mergely.tgz into a folder, e.g. `./lib`, and then add the following to the `<head>` of your target html source file.
|
||||||
@@ -46,9 +49,6 @@ The following example can be used to set the `lhs` and `rhs` editors synchronous
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
// initialize mergely
|
|
||||||
$('#mergely').mergely();
|
|
||||||
|
|
||||||
// set editor content
|
// set editor content
|
||||||
$('#mergely').mergely({
|
$('#mergely').mergely({
|
||||||
lhs: function(setValue) {
|
lhs: function(setValue) {
|
||||||
|
|||||||
2
package.json
Normal file → Executable file
2
package.json
Normal file → Executable file
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mergely",
|
"name": "mergely",
|
||||||
"version": "4.0.4",
|
"version": "4.0.7",
|
||||||
"description": "A javascript UI for diff/merge",
|
"description": "A javascript UI for diff/merge",
|
||||||
"directories": {
|
"directories": {
|
||||||
"doc": "doc",
|
"doc": "doc",
|
||||||
|
|||||||
@@ -461,11 +461,11 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
lineNumbers: this.settings.line_numbers
|
lineNumbers: this.settings.line_numbers
|
||||||
};
|
};
|
||||||
var lhs_gutters = [];
|
var lhs_gutters = [];
|
||||||
if (this.lhs_cmsettings.line_numbers) {
|
if (this.lhs_cmsettings.lineNumbers) {
|
||||||
lhs_gutters = ['merge', 'CodeMirror-linenumbers']
|
lhs_gutters = ['merge', 'CodeMirror-linenumbers']
|
||||||
}
|
}
|
||||||
var rhs_gutters = [];
|
var rhs_gutters = [];
|
||||||
if (this.rhs_cmsettings.line_numbers) {
|
if (this.rhs_cmsettings.lineNumbers) {
|
||||||
rhs_gutters = ['merge', 'CodeMirror-linenumbers']
|
rhs_gutters = ['merge', 'CodeMirror-linenumbers']
|
||||||
}
|
}
|
||||||
jQuery.extend(true, this.lhs_cmsettings, this.settings.cmsettings, { gutters: lhs_gutters }, this.settings);
|
jQuery.extend(true, this.lhs_cmsettings, this.settings.cmsettings, { gutters: lhs_gutters }, this.settings);
|
||||||
@@ -659,6 +659,13 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
bind: function(el) {
|
bind: function(el) {
|
||||||
this.element.hide();
|
this.element.hide();
|
||||||
this.id = jQuery(el).attr('id');
|
this.id = jQuery(el).attr('id');
|
||||||
|
try {
|
||||||
|
// ensure the id is valid for jQuery
|
||||||
|
jQuery(`#${this.id}`);
|
||||||
|
} catch (ex) {
|
||||||
|
console.error(`jQuery failed to find mergely: #${this.id}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.changed_timeout = null;
|
this.changed_timeout = null;
|
||||||
this.chfns = {};
|
this.chfns = {};
|
||||||
this.chfns[this.id + '-lhs'] = [];
|
this.chfns[this.id + '-lhs'] = [];
|
||||||
@@ -676,7 +683,7 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// homebrew
|
// homebrew
|
||||||
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;';
|
var style = 'opacity:0.6;height:16px;background-color:#bfbfbf;cursor:pointer;text-align:center;color:#eee;border:1px solid #848484;margin-right:5px;margin-top:-2px;';
|
||||||
merge_lhs_button = '<div style="' + style + '" title="Merge left"><</div>';
|
merge_lhs_button = '<div style="' + style + '" title="Merge left"><</div>';
|
||||||
merge_rhs_button = '<div style="' + style + '" title="Merge right">></div>';
|
merge_rhs_button = '<div style="' + style + '" title="Merge right">></div>';
|
||||||
}
|
}
|
||||||
@@ -749,32 +756,42 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check initialization
|
||||||
|
var rhstx;
|
||||||
|
try {
|
||||||
|
rhstx = this.element.find(`#${this.id}-rhs`).get(0);
|
||||||
|
} catch (ex) {
|
||||||
|
}
|
||||||
|
if (!rhstx) {
|
||||||
|
console.error('rhs textarea not defined - Mergely not initialized properly');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var lhstx;
|
||||||
|
try {
|
||||||
|
lhstx = this.element.find(`#${this.id}-lhs`).get(0);
|
||||||
|
} catch (ex) {
|
||||||
|
}
|
||||||
|
if (!lhstx) {
|
||||||
|
console.error('lhs textarea not defined - Mergely not initialized properly');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// get current diff border color
|
// get current diff border color
|
||||||
var color = jQuery('<div style="display:none" class="mergely current start" />').appendTo('body').css('border-top-color');
|
var color = jQuery('<div style="display:none" class="mergely current start" />').appendTo('body').css('border-top-color');
|
||||||
this.current_diff_color = color;
|
this.current_diff_color = color;
|
||||||
|
|
||||||
// codemirror
|
// codemirror
|
||||||
var cmstyle = '#' + this.id + ' .CodeMirror-gutter-text { padding: 5px 0 0 0; }' +
|
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; };';
|
'.CodeMirror-linewidget { overflow: hidden; };`;
|
||||||
if (this.settings.autoresize) {
|
if (this.settings.autoresize) {
|
||||||
cmstyle += this.id + ' .CodeMirror-scroll { height: 100%; overflow: auto; }';
|
cmstyle += `${this.id} .CodeMirror-scroll { height: 100%; overflow: auto; }`;
|
||||||
}
|
}
|
||||||
// adjust the margin line height
|
// adjust the margin line height
|
||||||
cmstyle += '\n.CodeMirror { line-height: 18px; }';
|
cmstyle += '\n.CodeMirror { line-height: 18px; }';
|
||||||
jQuery('<style type="text/css">' + cmstyle + '</style>').appendTo('head');
|
jQuery(`<style type="text/css">${cmstyle}</style>`).appendTo('head');
|
||||||
|
|
||||||
//bind
|
// bind
|
||||||
var rhstx = this.element.find('#' + this.id + '-rhs').get(0);
|
|
||||||
if (!rhstx) {
|
|
||||||
console.error('rhs textarea not defined - Mergely not initialized properly');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var lhstx = this.element.find('#' + this.id + '-lhs').get(0);
|
|
||||||
if (!rhstx) {
|
|
||||||
console.error('lhs textarea not defined - Mergely not initialized properly');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var self = this;
|
var self = this;
|
||||||
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);
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ describe('mergely', function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
$('#mergely').mergely('unbind');
|
const mergely = $('#mergely');
|
||||||
$('#mergely').mergelyUnregister();
|
mergely.mergely('unbind');
|
||||||
$('#mergely').remove();
|
mergely.mergelyUnregister();
|
||||||
|
mergely.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('initialization', () => {
|
describe('initialization', () => {
|
||||||
@@ -401,6 +402,7 @@ describe('mergely', function () {
|
|||||||
for (let i = 0; i < opt.next; ++i) {
|
for (let i = 0; i < opt.next; ++i) {
|
||||||
$('#mergely').mergely('scrollToDiff', 'next');
|
$('#mergely').mergely('scrollToDiff', 'next');
|
||||||
}
|
}
|
||||||
|
expect($('.merge-button').length > 0).to.be.true;
|
||||||
$('#mergely').mergely('mergeCurrentChange', opt.dir);
|
$('#mergely').mergely('mergeCurrentChange', opt.dir);
|
||||||
if (opt.dir === 'lhs') {
|
if (opt.dir === 'lhs') {
|
||||||
expect($('#mergely').mergely('get', 'lhs')).to.equal(opt.expect || opt.rhs);
|
expect($('#mergely').mergely('get', 'lhs')).to.equal(opt.expect || opt.rhs);
|
||||||
@@ -525,13 +527,11 @@ describe('mergely', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.only('should not be vulnerable to XSS', function (done) {
|
it('should not be vulnerable to XSS', function (done) {
|
||||||
function initXSS(options) {
|
function initXSS(options) {
|
||||||
// $('body').css({'margin': '0px'}).append("<div id='mergely<script>alert(123)</script>' />");
|
$('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');
|
||||||
$('body').get(0).innerHTML = "<div id='mergely\"<script id='injected'>alert(123)</script>'></div>";
|
editor = $(divs[0]);
|
||||||
|
|
||||||
const editor = $('#mergely');
|
|
||||||
editor.mergely(options);
|
editor.mergely(options);
|
||||||
return editor;
|
return editor;
|
||||||
};
|
};
|
||||||
@@ -544,14 +544,10 @@ describe('mergely', function () {
|
|||||||
lhs: (setValue) => setValue(macbeth),
|
lhs: (setValue) => setValue(macbeth),
|
||||||
rhs: (setValue) => setValue(macbeth)
|
rhs: (setValue) => setValue(macbeth)
|
||||||
});
|
});
|
||||||
const { mergely } = $('#mergely');
|
expect($('body').find('#injected')).to.have.length(0, 'expected no div with id injected');
|
||||||
// console.log('HERE', $('body').html());
|
const divs = document.getElementsByTagName('div');
|
||||||
// const { mergely } = $('#mergely"<script>alert(123)</script>');
|
expect(divs).to.have.length(1);
|
||||||
// expect($('#mergely<script>alert(123)</script>').mergely('_is_change_in_view', 'lhs', {from: 10, to: 20}, {
|
expect(divs[0].id).to.equal('mergely<script id="injected">alert(123)</script>');
|
||||||
// 'lhs-line-from': 0,
|
|
||||||
// 'lhs-line-to': 25
|
|
||||||
// })).to.be.true;
|
|
||||||
expect($('body').find('#injected')).to.have.length(0);
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user