1
0
mirror of synced 2025-12-11 00:38:02 +08:00

Compare commits

..

8 Commits

Author SHA1 Message Date
Jamie Peabody
88f21e2bc7 chore(ci): package-lock.json 2023-04-22 16:01:38 +01:00
Jamie Peabody
4160ab4f6e chore(ci): test 2023-04-22 15:59:44 +01:00
Jamie Peabody
16f1d2016d chore(ci): alpha, beta, next branches 2023-04-22 15:57:48 +01:00
Jamie Peabody
347a3f56ff chore(ci): updated webpack 2023-04-22 14:41:21 +01:00
Jamie Peabody
88d4a62a04 chore: updated examples 2023-04-22 14:40:58 +01:00
Jamie Peabody
b3e7b48d11 feat: dark mode 2023-04-22 14:13:30 +01:00
Jamie Peabody
fcea4efe2f chore: tweaked no-start/end styles 2023-04-22 13:44:33 +01:00
Jamie Peabody
080b8fd7b5 feat: v5
BREAKING CHANGE: Mergely is no longer a jQuery plugin.

BREAKING CHANGE: Removed `options.autoresize`

BREAKING CHANGE: Removed `options.editor_width`

BREAKING CHANGE: Removed `options.editor_height`

BREAKING CHANGE: Removed `options.fadein`

BREAKING CHANGE: Removed `options.fgcolor`

BREAKING CHANGE: Removed `options.resize`

BREAKING CHANGE: Removed `options.width`

BREAKING CHANGE: Removed `options.height`

BREAKING CHANGE: Removed `options.loaded` callback

BREAKING CHANGE: Removed `options.resized` callback

BREAKING CHANGE: Removed styles `.mergely-resizer`, `.mergely-full-screen-0`, and `.mergely-full-screen-8`

BREAKING CHANGE: Changed default for `options.change_timeout` changed from `150` to `50`.

BREAKING CHANGE: No longer automatically scrolls to first change.

feat: CodeMirror is now an explicit dependency.

feat: No longer necessary to separately require codemirror/addon/search/searchcursor

feat: No longer necessary to separately require codemirror/addon/selection/mark-selection

feat: `mergely.js` is now unminimized, and added new minimized version `mergely.min.js`

feat: Gutter click now scrolls to any line

feat: Mergely now emits `resize` event on resize

feat: The UI is now non-blocking as diff now runs in background

feat: Added support to provide `options.lhs` and `options.rhs` as strings

feat: #16 added titles to editor.mergely.com

fix: #165 block of changes at end of file are now distinguishable

fix: #140 fixed performance issue with large files

fix: Fixed issue where canvas markup was not rendered when `viewport` enabled

fix: Fixed timing issue where swap sides may not work as expected.

fix: Fixed issue where unmarkup did not emit an updated event.

fix: Fixed documentation issue where `merge` incorrectly stated: from the specified `side` to the opposite side.

fix: Fixed performance issue scrolling

fix: Fixed issue where initial render scrolled to first change, showing it at the bottom (as opposed to middle as expected)

fix: Fixed issue where line-diffs failed to diff non-alphanumeric characters
2023-04-22 12:41:12 +01:00
14 changed files with 43 additions and 257 deletions

View File

@@ -3,10 +3,7 @@ name: Run tests (branch)
on:
push:
branches-ignore:
- master
- alpha
- beta
- next
- 'master'
tags-ignore:
- 'v*'

View File

@@ -1,11 +0,0 @@
branches:
- master
- name: alpha
prerelease: true
plugins:
- "@semantic-release/commit-analyzer"
- "@semantic-release/release-notes-generator"
- "@semantic-release/changelog"
- "@semantic-release/npm"
- "@semantic-release/git"
- "@semantic-release/github"

View File

@@ -1,55 +1,7 @@
## [5.0.4](https://github.com/wickedest/Mergely/compare/v5.0.3...v5.0.4) (2023-08-27)
### Bug Fixes
* updated CDN example ([dec1e95](https://github.com/wickedest/Mergely/commit/dec1e9509d94811914e77cbc33dc1aaedf154f7c))
## [5.0.3](https://github.com/wickedest/Mergely/compare/v5.0.2...v5.0.3) (2023-08-27)
### Bug Fixes
* Updated docs with CDN example ([254adf1](https://github.com/wickedest/Mergely/commit/254adf15ab09fe9c5c3dff542d0a7f62ce2c9782))
## [5.0.2](https://github.com/wickedest/Mergely/compare/v5.0.1...v5.0.2) (2023-04-24)
### Bug Fixes
* **scroll:** fixed issue where first rhs scroll was unlinked ([7b2040c](https://github.com/wickedest/Mergely/commit/7b2040c6ad17ea70a09720f54d9a255cdc57cd67))
## [5.0.1](https://github.com/wickedest/Mergely/compare/v5.0.0...v5.0.1) (2023-04-23)
### Bug Fixes
* update release ([a8b497b](https://github.com/wickedest/Mergely/commit/a8b497bc9b68beb5d8265106d9f010aa9489dd17))
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [5.0.0](https://github.com/wickedest/Mergely/compare/v4.3.9...v5.0.0) (2023-04-23)
### BREAKING CHANGES
- Mergely is no longer a jQuery plugin.
- Removed options.autoresize
- Removed options.editor_width
- Removed options.editor_height
- Removed options.fadein
- Removed options.fgcolor
- Removed options.resize
- Removed options.width
- Removed options.height
- Removed options.loaded callback
- Removed options.resized callback
- Removed styles .mergely-resizer, .mergely-full-screen-0, and .mergely-full-screen-8
- Changed default for options.change_timeout changed from 150 to 50.
- No longer automatically scrolls to first change.
### 4.3.9 (2022-01-19)

View File

@@ -4,7 +4,7 @@
https://mergely.com
Mergely is a JavaScript component for differencing and merging files interactively in a browser (diff/merge). It provides a rich API that enables you to easily integrate Mergely into your existing web application. It is suitable for comparing text files online, such as .txt, .html, .xml, .c, .cpp, .java, .js, etc.
Mergely is a JavaScript component for differencing and merging files interactively in a browser (diff/merge). It provides a 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 has a JavaScript implementation of the Longest Common Subsequence (LCS) diff algorithm, and a customizable markup engine. It computes the diff within the browser.
@@ -36,11 +36,11 @@ rm -rf .git
### Usage via CDN
Add the following to the `<head>` of your target HTML source file. Note that `codemirror` is bundled.
Unpack mergely.tgz into a folder, for example, `./lib`, and add the following to the `<head>` of your target HTML source file.
```html
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mergely/5.0.0/mergely.min.js"></script>
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/mergely/5.0.0/mergely.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/mergely/5.0.0/mergely.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mergely/5.0.0/mergely.css"></script>
```
### Synchronous initialization

View File

@@ -1,38 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Mergely - Example full page editor</title>
<meta http-equiv="X-UA-Compatible" content="chrome=1, IE=edge">
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<meta name="description" content="" />
<meta name="keywords" content="mergely,diff,merge,compare" />
<meta name="author" content="Jamie Peabody" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<!-- Mergely -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mergely/5.0.0/mergely.min.js"></script>
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/mergely/5.0.0/mergely.css" />
<style type="text/css">
html, body {
height: 100%;
margin: 0;
}
#compare {
height: inherit;
}
</style>
</head>
<body>
<div id="compare"></div>
<script>
const mergely = new Mergely('#compare');
mergely.once('updated', () => {
mergely.lhs('the quick red fox\njumped over the hairy dog');
mergely.rhs('the quick brown fox\njumped over the lazy dog');
});
</script>
</body>
</html>

View File

@@ -21,9 +21,6 @@ This example demonstrates the minimum amount of code required to use Mergely.
<h1>Examples</h1>
<dl>
<dt><a href="cdn.html">cdn.html</a></dt>
<dd>Demonstrates how to use Mergely with CDN.</dd>
<dt><a href="editor.html">editor.html</a></dt>
<dd>An example editor showcasing some of Mergely's API features.</dd>

View File

@@ -22,7 +22,6 @@
"changelog" : {
"commitTypes": [
"docs",
"feat",
"fix",
"perf",

102
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "mergely",
"version": "5.0.4",
"version": "5.0.0-rc0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mergely",
"version": "5.0.4",
"version": "5.0.0-rc0",
"license": "(GPL-3.0 OR LGPL-3.0 OR MPL-1.1 OR SEE LICENSE IN LICENSE)",
"devDependencies": {
"@babel/core": "^7.1.6",
@@ -14,8 +14,6 @@
"@commitlint/cli": "^17.6.1",
"@commitlint/config-conventional": "^15.0.0",
"@commitlint/prompt-cli": "^15.0.0",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"babel-loader": "^8.2.3",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"chai": "^4.3.4",
@@ -3498,59 +3496,6 @@
"node": ">=12"
}
},
"node_modules/@semantic-release/changelog": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/@semantic-release/changelog/-/changelog-6.0.3.tgz",
"integrity": "sha512-dZuR5qByyfe3Y03TpmCvAxCyTnp7r5XwtHRf/8vD9EAn4ZWbavUX8adMtXYzE86EVh0gyLA7lm5yW4IV30XUag==",
"dev": true,
"dependencies": {
"@semantic-release/error": "^3.0.0",
"aggregate-error": "^3.0.0",
"fs-extra": "^11.0.0",
"lodash": "^4.17.4"
},
"engines": {
"node": ">=14.17"
},
"peerDependencies": {
"semantic-release": ">=18.0.0"
}
},
"node_modules/@semantic-release/changelog/node_modules/fs-extra": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz",
"integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==",
"dev": true,
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
},
"engines": {
"node": ">=14.14"
}
},
"node_modules/@semantic-release/changelog/node_modules/jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true,
"dependencies": {
"universalify": "^2.0.0"
},
"optionalDependencies": {
"graceful-fs": "^4.1.6"
}
},
"node_modules/@semantic-release/changelog/node_modules/universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
"dev": true,
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/@semantic-release/commit-analyzer": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-9.0.2.tgz",
@@ -3581,37 +3526,6 @@
"node": ">=14.17"
}
},
"node_modules/@semantic-release/git": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/@semantic-release/git/-/git-10.0.1.tgz",
"integrity": "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==",
"dev": true,
"dependencies": {
"@semantic-release/error": "^3.0.0",
"aggregate-error": "^3.0.0",
"debug": "^4.0.0",
"dir-glob": "^3.0.0",
"execa": "^5.0.0",
"lodash": "^4.17.4",
"micromatch": "^4.0.0",
"p-reduce": "^2.0.0"
},
"engines": {
"node": ">=14.17"
},
"peerDependencies": {
"semantic-release": ">=18.0.0"
}
},
"node_modules/@semantic-release/git/node_modules/p-reduce": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz",
"integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/@semantic-release/github": {
"version": "8.0.7",
"resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-8.0.7.tgz",
@@ -6899,9 +6813,9 @@
}
},
"node_modules/engine.io": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz",
"integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==",
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.1.tgz",
"integrity": "sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==",
"dev": true,
"dependencies": {
"@types/cookie": "^0.4.1",
@@ -16564,9 +16478,9 @@
}
},
"node_modules/socket.io-parser": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.3.tgz",
"integrity": "sha512-JMafRntWVO2DCJimKsRTh/wnqVvO4hrfwOqtO7f+uzwsQMuxO6VwImtYxaQ+ieoyshWOTJyV0fA21lccEXRPpQ==",
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz",
"integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==",
"dev": true,
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",

View File

@@ -1,6 +1,6 @@
{
"name": "mergely",
"version": "5.0.4",
"version": "5.0.0-rc0",
"description": "A javascript UI for diff/merge",
"license": "(GPL-3.0 OR LGPL-3.0 OR MPL-1.1 OR SEE LICENSE IN LICENSE)",
"author": {
@@ -14,7 +14,7 @@
},
"repository": {
"type": "git",
"url": "git@github.com:wickedest/Mergely.git"
"url": "git+https://github.com/wickedest/Mergely.git"
},
"main": "lib/mergely.js",
"files": [
@@ -36,8 +36,6 @@
"@commitlint/cli": "^17.6.1",
"@commitlint/config-conventional": "^15.0.0",
"@commitlint/prompt-cli": "^15.0.0",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"babel-loader": "^8.2.3",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"chai": "^4.3.4",

View File

@@ -44,8 +44,7 @@ CodeMirrorDiffView.prototype.init = function(el, options = {}) {
lineNumbers: this.settings.line_numbers,
gutters: (this.settings.line_numbers && [ 'merge', 'CodeMirror-linenumbers' ]) || [],
};
this._vdoc = new VDoc({ _debug: this.settings._debug });
this._linkedScrollTimeout = {};
this._vdoc = new VDoc();
};
CodeMirrorDiffView.prototype.unbind = function() {
@@ -291,6 +290,11 @@ CodeMirrorDiffView.prototype.bind = function(container) {
className: container.className
};
const el = dom.getMergelyContainer({ clazz: container.className });
// const found = document.getElementById(container.id);
// if (!found) {
// console.error(`Failed to find mergely: #${container.id}`);
// return;
// }
const computedStyle = window.getComputedStyle(container);
if (!computedStyle.height || computedStyle.height === '0px') {
throw new Error(
@@ -436,10 +440,7 @@ CodeMirrorDiffView.prototype.bind = function(container) {
trace('event#lhs-scroll');
}
}
// firefox scroll-linked effect render issue
setTimeout(() => {
this._scrolling({ side: 'lhs' });
}, 1);
this._scrolling({ side: 'lhs' });
});
this.editor.rhs.on('change', (instance, ev) => {
if (this.settings._debug) {
@@ -458,10 +459,7 @@ CodeMirrorDiffView.prototype.bind = function(container) {
trace('event#rhs-scroll');
}
}
// firefox scroll-linked effect render issue
setTimeout(() => {
this._scrolling({ side: 'rhs' });
}, 1);
this._scrolling({ side: 'rhs' });
});
// resize event handeler
@@ -562,7 +560,7 @@ CodeMirrorDiffView.prototype._clearMarkup = function () {
traceTimeStart('draw#_clearMarkup');
}
this._vdoc.clear();
this._vdoc = new VDoc({ _debug: this.settings._debug });
this._vdoc = new VDoc();
if (this.settings._debug) {
traceTimeEnd('draw#_clearMarkup');
}
@@ -636,10 +634,7 @@ CodeMirrorDiffView.prototype._scrolling = function({ side }) {
const scroller = this.editor[side].getScrollerElement();
const { top } = scroller.getBoundingClientRect();
let height;
if (scroller.offsetParent === null) {
return;
}
if (this.midway == undefined) {
if (true || this.midway == undefined) {
height = scroller.clientHeight
- (scroller.offsetHeight - scroller.offsetParent.offsetHeight);
this.midway = (height / 2.0 + top).toFixed(2);
@@ -702,14 +697,11 @@ CodeMirrorDiffView.prototype._scrolling = function({ side }) {
// coming in 2s, so this will "link" scrolling the other editor to
// this editor until this editor stops scrolling and times out.
this._skipscroll[oside] = true;
trace('scroll#set oside skip set:', oside, this._skipscroll);
if (this._linkedScrollTimeout[oside]) {
clearTimeout(this._linkedScrollTimeout[oside]);
trace('scroll#clearing timeout:', this._skipscroll);
if (this._linkedScrollTimeout) {
clearTimeout(this._linkedScrollTimeout);
}
this._linkedScrollTimeout[oside] = setTimeout(() => {
this._linkedScrollTimeout = setTimeout(() => {
this._skipscroll[oside] = false;
trace('scroll#set oside skip unset:', oside, this._skipscroll);
}, 100);
const top = top_to - top_adjust;
@@ -999,10 +991,14 @@ CodeMirrorDiffView.prototype._markupLineChanges = function (changes) {
}
}
led.operation(() => {
vdoc.update('lhs', led, lhsvp);
for (let i = 0; i < changes.length; ++i) {
vdoc.update('lhs', i, led, lhsvp);
}
});
red.operation(() => {
vdoc.update('rhs', red, rhsvp);
for (let i = 0; i < changes.length; ++i) {
vdoc.update('rhs', i, red, rhsvp);
}
});
if (this.settings._debug) {
traceTimeEnd('draw#_markupLineChanges');

View File

@@ -67,7 +67,7 @@ function getColors(el) {
function getMergelyContainer({ clazz = '' }) {
const classes = [ 'mergely-editor', clazz ]
return htmlToElement(`\
<div class="${classes.join(' ')}" style="display:flex;height:100%;position:relative;overflow:hidden;"></div>`);
<div class="${classes.join(' ')}" style="display:flex;height:100%;position:relative;"></div>`);
}
function getMarginTemplate({ id }) {

View File

@@ -17,7 +17,7 @@
}
.mergely-editor .CodeMirror-selected {
background: #0f73ff47;
background: #ffcb0f;
}
.mergely-splash {
@@ -52,6 +52,8 @@
.mergely-editor .merge-button {
height: 18px;
cursor: pointer;
width: 26px;
padding-left: 3px;
}
/* common stles */

View File

@@ -114,7 +114,7 @@ class Mergely {
_setOptions(options) {
if (this._options && this._options._debug) {
trace('api#options');
trace('api#options', opts);
}
const colors = dom.getColors(this.el);
this._options = {
@@ -186,7 +186,7 @@ class Mergely {
diff() {
if (this._options._debug) {
trace('api#diff');
trace('api#diff', side);
}
const lhs_text = this.get('lhs');
const rhs_text = this.get('rhs');

View File

@@ -1,10 +1,7 @@
const diff = require('./diff');
const trace = console.log;
class VDoc {
constructor(options) {
this.options = options;
constructor() {
this._lines = {
lhs: {},
rhs: {}
@@ -16,9 +13,6 @@ class VDoc {
}
addRender(side, change, changeId, options) {
if (this.options._debug) {
trace('vdoc#addRender', side, changeId, change);
}
const {
isCurrent,
lineDiff,
@@ -29,9 +23,6 @@ class VDoc {
const alreadyRendered = !!this._rendered[side][changeId];
if (alreadyRendered) {
if (this.options._debug) {
trace('vdoc#addRender (already rendered)', side, changeId, change);
}
return;
}
@@ -125,9 +116,6 @@ class VDoc {
}
addInlineDiff(change, changeId, { getText, ignorews, ignoreaccents, ignorecase }) {
if (this.options._debug) {
trace('vdoc#addInlineDiff', changeId, change);
}
const { lf, lt, olf, olt } = getExtents('lhs', change);
const vdoc = this;
@@ -181,9 +169,6 @@ class VDoc {
}
_setRenderedChange(side, changeId) {
if (this.options._debug) {
trace('vdoc#_setRenderedChange', side, changeId);
}
return this._rendered[side][changeId] = true;
}
@@ -197,10 +182,8 @@ class VDoc {
return line;
}
update(side, editor, viewport) {
if (this.options._debug) {
trace('vdoc#update', side, editor, viewport);
}
update(side, changeId, editor, viewport) {
this._setRenderedChange(side, changeId);
const lines = Object.keys(this._lines[side]);
for (let i = 0; i < lines.length; ++i) {
const id = lines[i];
@@ -217,9 +200,6 @@ class VDoc {
}
clear() {
if (this.options._debug) {
trace('vdoc#clear');
}
for (const lineId in this._lines.lhs) {
this._lines.lhs[lineId].clear();
}