@seafile/sdoc-editor 0.1.59 → 0.1.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/basic-sdk/editor.js +6 -2
- package/dist/basic-sdk/extension/constants/index.js +8 -0
- package/dist/basic-sdk/extension/core/utils/index.js +7 -4
- package/dist/basic-sdk/extension/menu/menu.css +2 -1
- package/dist/basic-sdk/extension/plugins/code-block/helpers.js +6 -3
- package/dist/basic-sdk/extension/plugins/code-block/render-elem.js +2 -1
- package/dist/basic-sdk/extension/plugins/table/constants/index.js +0 -2
- package/dist/basic-sdk/extension/plugins/table/helpers.js +10 -10
- package/dist/basic-sdk/extension/plugins/table/render/render-cell.js +1 -0
- package/dist/basic-sdk/extension/plugins/table/render/table-root.js +15 -10
- package/dist/basic-sdk/extension/plugins/text-align/menu/index.js +0 -1
- package/dist/basic-sdk/extension/plugins/text-align/menu/style.css +1 -0
- package/dist/basic-sdk/extension/plugins/text-style/render-elem.js +13 -8
- package/dist/basic-sdk/utils/diff-text.js +255 -0
- package/dist/basic-sdk/utils/diff.js +229 -142
- package/dist/basic-sdk/utils/document-utils.js +18 -0
- package/dist/basic-sdk/viewer.js +48 -66
- package/dist/pages/diff-viewer/diff-viewer.js +43 -114
- package/dist/pages/diff-viewer/history-version-viewer.js +6 -1
- package/package.json +2 -2
- package/public/media/sdoc-editor-font/iconfont.eot +0 -0
- package/public/media/sdoc-editor-font/iconfont.svg +2 -2
- package/public/media/sdoc-editor-font/iconfont.ttf +0 -0
- package/public/media/sdoc-editor-font/iconfont.woff +0 -0
- package/public/media/sdoc-editor-font/iconfont.woff2 +0 -0
- package/public/media/sdoc-editor-font.css +10 -10
package/dist/basic-sdk/editor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
2
|
-
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react';
|
|
3
3
|
import { Node } from '@seafile/slate';
|
|
4
4
|
import { Editable, Slate, ReactEditor } from '@seafile/slate-react';
|
|
5
5
|
import defaultEditor, { renderLeaf, renderElement, Toolbar, ContextMenu } from './extension';
|
|
@@ -19,6 +19,8 @@ import './assets/css/sdoc-editor-plugins.css';
|
|
|
19
19
|
var SDocEditor = function SDocEditor(_ref) {
|
|
20
20
|
var document = _ref.document,
|
|
21
21
|
config = _ref.config;
|
|
22
|
+
var articleRef = useRef(null);
|
|
23
|
+
|
|
22
24
|
// init editor
|
|
23
25
|
var editor = useMemo(function () {
|
|
24
26
|
var newEditor = withNodeId(withSocketIO(defaultEditor, {
|
|
@@ -57,6 +59,7 @@ var SDocEditor = function SDocEditor(_ref) {
|
|
|
57
59
|
// useMount: init socket connection
|
|
58
60
|
useEffect(function () {
|
|
59
61
|
editor.openConnection();
|
|
62
|
+
editor.width = articleRef.current.children[0].clientWidth;
|
|
60
63
|
return function () {
|
|
61
64
|
editor.closeConnection();
|
|
62
65
|
};
|
|
@@ -111,7 +114,8 @@ var SDocEditor = function SDocEditor(_ref) {
|
|
|
111
114
|
value: slateValue,
|
|
112
115
|
onChange: onChange
|
|
113
116
|
}, /*#__PURE__*/React.createElement("div", {
|
|
114
|
-
className: "article"
|
|
117
|
+
className: "article",
|
|
118
|
+
ref: articleRef
|
|
115
119
|
}, /*#__PURE__*/React.createElement(SetNodeToDecorations, null), /*#__PURE__*/React.createElement(Editable, {
|
|
116
120
|
renderElement: renderElement,
|
|
117
121
|
renderLeaf: renderLeaf,
|
|
@@ -113,4 +113,12 @@ export var TABLE_ELEMENT_POSITION = {
|
|
|
113
113
|
AFTER: 'after',
|
|
114
114
|
BEFORE: 'before'
|
|
115
115
|
};
|
|
116
|
+
export var DELETED_STYLE = {
|
|
117
|
+
background_color: '#ffeef0',
|
|
118
|
+
color: 'rgb(165, 32, 21)'
|
|
119
|
+
};
|
|
120
|
+
export var ADDED_STYLE = {
|
|
121
|
+
background_color: '#e6ffed',
|
|
122
|
+
color: 'rgb(137, 181, 66)'
|
|
123
|
+
};
|
|
116
124
|
export { BLOCKQUOTE, HEADER, HEADER1, HEADER2, HEADER3, HEADER4, HEADER5, HEADER6, PARAGRAPH, BOLD, ITALIC, UNDERLINE, STRIKETHROUGH, ORDERED_LIST, UNORDERED_LIST, LIST_ITEM, LIST_LIC, CHECK_LIST, CHECK_LIST_ITEM, LINK, HTML, CODE_BLOCK, CODE_LINE, IMAGE, TABLE, TABLE_CELL, TABLE_ROW, FORMULA, COLUMN, TEXT_STYLE, BOLD_ITALIC, TEXT_ALIGN, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ELEMENT_TYPE, KEYBOARD };
|
|
@@ -18,13 +18,16 @@ export var match = function match(node, path, predicate) {
|
|
|
18
18
|
}
|
|
19
19
|
return predicate(node, path);
|
|
20
20
|
};
|
|
21
|
+
export var generateDefaultText = function generateDefaultText() {
|
|
22
|
+
return {
|
|
23
|
+
id: slugid.nice(),
|
|
24
|
+
text: ''
|
|
25
|
+
};
|
|
26
|
+
};
|
|
21
27
|
export var generateEmptyElement = function generateEmptyElement(type) {
|
|
22
28
|
return {
|
|
23
29
|
type: type,
|
|
24
|
-
children: [
|
|
25
|
-
id: slugid.nice(),
|
|
26
|
-
text: ''
|
|
27
|
-
}]
|
|
30
|
+
children: [generateDefaultText()]
|
|
28
31
|
};
|
|
29
32
|
};
|
|
30
33
|
export function Placeholder(props) {
|
|
@@ -68,7 +68,8 @@ export var changeToCodeBlock = function changeToCodeBlock(editor, language) {
|
|
|
68
68
|
id: slugid.nice(),
|
|
69
69
|
type: CODE_LINE,
|
|
70
70
|
children: [{
|
|
71
|
-
text: strArr.join('\n')
|
|
71
|
+
text: strArr.join('\n'),
|
|
72
|
+
id: slugid.nice()
|
|
72
73
|
} // Select the plain text of the node
|
|
73
74
|
]
|
|
74
75
|
}]
|
|
@@ -95,8 +96,10 @@ export var changeToPlainText = function changeToPlainText(editor) {
|
|
|
95
96
|
return {
|
|
96
97
|
type: 'paragraph',
|
|
97
98
|
children: [{
|
|
98
|
-
text: s
|
|
99
|
-
|
|
99
|
+
text: s,
|
|
100
|
+
id: slugid.nice()
|
|
101
|
+
}],
|
|
102
|
+
id: elem.id
|
|
100
103
|
};
|
|
101
104
|
});
|
|
102
105
|
Transforms.insertNodes(editor, pList, {
|
|
@@ -99,7 +99,8 @@ var CodeBlock = function CodeBlock(_ref) {
|
|
|
99
99
|
document.getElementById('sdoc-editor-article-container').removeEventListener('scroll', onScroll);
|
|
100
100
|
}
|
|
101
101
|
return function () {
|
|
102
|
-
document.getElementById('sdoc-editor-article-container')
|
|
102
|
+
var articleContainer = document.getElementById('sdoc-editor-article-container');
|
|
103
|
+
articleContainer && articleContainer.removeEventListener('scroll', onScroll);
|
|
103
104
|
};
|
|
104
105
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
105
106
|
}, [showHoverMenu]);
|
|
@@ -6,7 +6,5 @@ export var EMPTY_SELECTED_RANGE = {
|
|
|
6
6
|
minColIndex: -1,
|
|
7
7
|
maxColIndex: -1
|
|
8
8
|
};
|
|
9
|
-
export var TABLE_MAX_WIDTH = 672; // 673 = 794 - 2[borderLeft + borderRight] - 120[paddingLeft + paddingRight]
|
|
10
|
-
|
|
11
9
|
export var TABLE_ROW_MIN_HEIGHT = 42;
|
|
12
10
|
export var TABLE_CELL_MIN_WIDTH = 35;
|
|
@@ -5,7 +5,7 @@ import slugid from 'slugid';
|
|
|
5
5
|
import { Editor, Range, Transforms } from '@seafile/slate';
|
|
6
6
|
import { getNodeType, getParentNode, getSelectedNodeByType, isTextNode, getSelectedElems, focusEditor, getNode, findPath } from '../../core';
|
|
7
7
|
import { ELEMENT_TYPE, TABLE_ELEMENT, TABLE_ELEMENT_POSITION } from '../../constants';
|
|
8
|
-
import { TABLE_MAX_ROWS, TABLE_MAX_COLUMNS, EMPTY_SELECTED_RANGE, TABLE_ROW_MIN_HEIGHT, TABLE_CELL_MIN_WIDTH
|
|
8
|
+
import { TABLE_MAX_ROWS, TABLE_MAX_COLUMNS, EMPTY_SELECTED_RANGE, TABLE_ROW_MIN_HEIGHT, TABLE_CELL_MIN_WIDTH } from './constants';
|
|
9
9
|
import EventBus from '../../../utils/event-bus';
|
|
10
10
|
import { EXTERNAL_EVENT } from '../../../../constants';
|
|
11
11
|
import ObjectUtils from '../../../utils/object-utils';
|
|
@@ -65,8 +65,8 @@ export var generateTableRow = function generateTableRow(colsCount) {
|
|
|
65
65
|
}
|
|
66
66
|
};
|
|
67
67
|
};
|
|
68
|
-
export var generateEmptyTable = function generateEmptyTable() {
|
|
69
|
-
var size = arguments.length >
|
|
68
|
+
export var generateEmptyTable = function generateEmptyTable(editor) {
|
|
69
|
+
var size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [0, 0];
|
|
70
70
|
var rowsCount = size[0];
|
|
71
71
|
var colsCount = size[1];
|
|
72
72
|
var children = [];
|
|
@@ -74,7 +74,7 @@ export var generateEmptyTable = function generateEmptyTable() {
|
|
|
74
74
|
var tableRow = generateTableRow(colsCount);
|
|
75
75
|
children.push(tableRow);
|
|
76
76
|
}
|
|
77
|
-
var columnWidth = Math.max(TABLE_CELL_MIN_WIDTH, parseInt(
|
|
77
|
+
var columnWidth = Math.max(TABLE_CELL_MIN_WIDTH, parseInt(editor.width / colsCount));
|
|
78
78
|
var columns = [];
|
|
79
79
|
for (var _i = 0; _i < colsCount; _i++) {
|
|
80
80
|
columns.push({
|
|
@@ -91,7 +91,7 @@ export var generateEmptyTable = function generateEmptyTable() {
|
|
|
91
91
|
export var insertTable = function insertTable(editor, size, selection) {
|
|
92
92
|
if (!size) return;
|
|
93
93
|
if (isTableMenuDisabled(editor)) return;
|
|
94
|
-
var tableNode = generateEmptyTable(size);
|
|
94
|
+
var tableNode = generateEmptyTable(editor, size);
|
|
95
95
|
Transforms.insertNodes(editor, tableNode, {
|
|
96
96
|
at: selection
|
|
97
97
|
});
|
|
@@ -351,7 +351,7 @@ export var getTableColumnsAfterInsertColumn = function getTableColumnsAfterInser
|
|
|
351
351
|
var targetInsertColumnsWidth = targetColumn.width * insertColumnCount;
|
|
352
352
|
|
|
353
353
|
// Currently in scrolling state, insert directly
|
|
354
|
-
if (totalColumnsWidth >
|
|
354
|
+
if (totalColumnsWidth > editor.width) {
|
|
355
355
|
for (var i = 0; i < insertColumnCount; i++) {
|
|
356
356
|
newColumns.splice(targetColumnIndex, 0, targetColumn);
|
|
357
357
|
}
|
|
@@ -360,7 +360,7 @@ export var getTableColumnsAfterInsertColumn = function getTableColumnsAfterInser
|
|
|
360
360
|
|
|
361
361
|
// Not currently scrolling
|
|
362
362
|
// It is not a scroll state after inserting a new column
|
|
363
|
-
if (totalColumnsWidth + targetInsertColumnsWidth <
|
|
363
|
+
if (totalColumnsWidth + targetInsertColumnsWidth < editor.width) {
|
|
364
364
|
for (var _i5 = 0; _i5 < insertColumnCount; _i5++) {
|
|
365
365
|
newColumns.push(targetColumn);
|
|
366
366
|
}
|
|
@@ -372,7 +372,7 @@ export var getTableColumnsAfterInsertColumn = function getTableColumnsAfterInser
|
|
|
372
372
|
totalColumnsWidth += targetColumn.width;
|
|
373
373
|
newColumns.splice(targetColumnIndex, 0, targetColumn);
|
|
374
374
|
}
|
|
375
|
-
var proportion = totalColumnsWidth / (
|
|
375
|
+
var proportion = totalColumnsWidth / (editor.width - 1);
|
|
376
376
|
return newColumns.map(function (column) {
|
|
377
377
|
return _objectSpread(_objectSpread({}, column), {}, {
|
|
378
378
|
width: Math.max(parseInt(column.width / proportion), TABLE_CELL_MIN_WIDTH)
|
|
@@ -395,7 +395,7 @@ export var getTableColumns = function getTableColumns(editor, element) {
|
|
|
395
395
|
var initColumns = [];
|
|
396
396
|
for (var i = 0; i < columnsCount; i++) {
|
|
397
397
|
var column = {
|
|
398
|
-
width: Math.max(TABLE_CELL_MIN_WIDTH, parseInt(
|
|
398
|
+
width: Math.max(TABLE_CELL_MIN_WIDTH, parseInt(editor.width / columnsCount))
|
|
399
399
|
};
|
|
400
400
|
initColumns.push(column);
|
|
401
401
|
}
|
|
@@ -418,7 +418,7 @@ export var getCellColumn = function getCellColumn(editor, cellElement) {
|
|
|
418
418
|
} else {
|
|
419
419
|
var columnsCount = tableElement.children[0].children.length;
|
|
420
420
|
column = {
|
|
421
|
-
width: Math.max(TABLE_CELL_MIN_WIDTH, parseInt(
|
|
421
|
+
width: Math.max(TABLE_CELL_MIN_WIDTH, parseInt(editor.width / columnsCount))
|
|
422
422
|
};
|
|
423
423
|
}
|
|
424
424
|
return column;
|
|
@@ -74,6 +74,7 @@ function renderTableCell(props) {
|
|
|
74
74
|
var width = column.width;
|
|
75
75
|
return /*#__PURE__*/React.createElement("div", Object.assign({}, attributes, {
|
|
76
76
|
style: _objectSpread(_objectSpread(_objectSpread({}, style), element.style), {}, {
|
|
77
|
+
minWidth: width,
|
|
77
78
|
width: width
|
|
78
79
|
}),
|
|
79
80
|
className: classnames('table-cell', attributes.className),
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
1
2
|
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
2
|
-
import React, { useState, useRef } from 'react';
|
|
3
|
+
import React, { useState, useRef, useCallback } from 'react';
|
|
3
4
|
import classnames from 'classnames';
|
|
4
|
-
import {
|
|
5
|
+
import { useSlateStatic } from '@seafile/slate-react';
|
|
5
6
|
import { TableRootContext } from './hooks';
|
|
6
7
|
var TableRoot = function TableRoot(_ref) {
|
|
7
8
|
var attributes = _ref.attributes,
|
|
8
9
|
_ref$columns = _ref.columns,
|
|
9
10
|
columns = _ref$columns === void 0 ? [] : _ref$columns,
|
|
10
11
|
children = _ref.children;
|
|
12
|
+
var editor = useSlateStatic();
|
|
11
13
|
var tableScrollWrapper = useRef(null);
|
|
12
14
|
var _useState = useState(0),
|
|
13
15
|
_useState2 = _slicedToArray(_useState, 2),
|
|
@@ -16,19 +18,22 @@ var TableRoot = function TableRoot(_ref) {
|
|
|
16
18
|
var allWidth = columns.reduce(function (pre, cur) {
|
|
17
19
|
return pre + cur.width;
|
|
18
20
|
}, 0);
|
|
19
|
-
var onScroll = function
|
|
21
|
+
var onScroll = useCallback(function (event) {
|
|
20
22
|
setScrollLeft(event.target.scrollLeft);
|
|
21
|
-
};
|
|
23
|
+
}, []);
|
|
22
24
|
return /*#__PURE__*/React.createElement(TableRootContext.Provider, {
|
|
23
25
|
value: tableScrollWrapper.current
|
|
24
|
-
}, /*#__PURE__*/React.createElement("div", Object.assign({
|
|
25
|
-
className: classnames('sdoc-table-wrapper', {
|
|
26
|
-
'scroll position-relative': allWidth >
|
|
26
|
+
}, /*#__PURE__*/React.createElement("div", Object.assign({}, attributes, {
|
|
27
|
+
className: classnames('sdoc-table-wrapper', attributes.className, {
|
|
28
|
+
'scroll position-relative': allWidth > editor.width
|
|
29
|
+
}),
|
|
30
|
+
style: _objectSpread(_objectSpread({}, attributes.style), {}, {
|
|
31
|
+
maxWidth: editor.width
|
|
27
32
|
})
|
|
28
|
-
}
|
|
33
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
29
34
|
className: classnames('sdoc-table-scroll-wrapper', {
|
|
30
|
-
'scroll-at-center': scrollLeft +
|
|
31
|
-
'scroll-at-right': scrollLeft +
|
|
35
|
+
'scroll-at-center': scrollLeft + editor.width !== allWidth && scrollLeft > 0,
|
|
36
|
+
'scroll-at-right': scrollLeft + editor.width === allWidth,
|
|
32
37
|
'scroll-at-left': scrollLeft === 0
|
|
33
38
|
}),
|
|
34
39
|
ref: tableScrollWrapper,
|
|
@@ -70,7 +70,6 @@ var TextAlignMenu = /*#__PURE__*/function (_React$Component) {
|
|
|
70
70
|
key: "render",
|
|
71
71
|
value: function render() {
|
|
72
72
|
var _this2 = this;
|
|
73
|
-
var t = this.props.t;
|
|
74
73
|
var isDropdownMenuOpen = this.state.isDropdownMenuOpen;
|
|
75
74
|
var caretIconClass = "caret-icon sdocfont sdoc-".concat(isDropdownMenuOpen ? 'caret-up' : 'drop-down');
|
|
76
75
|
var curType = this.getCurrentType();
|
|
@@ -9,6 +9,18 @@ var renderText = function renderText(props, editor) {
|
|
|
9
9
|
var text = leaf.text,
|
|
10
10
|
rest = _objectWithoutProperties(leaf, _excluded);
|
|
11
11
|
var markedChildren = React.cloneElement(children);
|
|
12
|
+
var style = {};
|
|
13
|
+
if (leaf.isCaret) {
|
|
14
|
+
style['position'] = 'relative';
|
|
15
|
+
style['display'] = 'inline-block';
|
|
16
|
+
style['minWidth'] = '2px';
|
|
17
|
+
}
|
|
18
|
+
if (leaf.background_color) {
|
|
19
|
+
style['backgroundColor'] = leaf.background_color;
|
|
20
|
+
}
|
|
21
|
+
if (leaf.color) {
|
|
22
|
+
style['color'] = leaf.color;
|
|
23
|
+
}
|
|
12
24
|
if (leaf.BOLD) {
|
|
13
25
|
markedChildren = /*#__PURE__*/React.createElement("strong", null, markedChildren);
|
|
14
26
|
}
|
|
@@ -36,20 +48,13 @@ var renderText = function renderText(props, editor) {
|
|
|
36
48
|
markedChildren = /*#__PURE__*/React.createElement("del", null, markedChildren);
|
|
37
49
|
}
|
|
38
50
|
if (leaf.ADD) {
|
|
39
|
-
markedChildren = /*#__PURE__*/React.createElement("
|
|
51
|
+
markedChildren = /*#__PURE__*/React.createElement("span", null, markedChildren);
|
|
40
52
|
}
|
|
41
53
|
if (leaf.decoration) {
|
|
42
54
|
markedChildren = /*#__PURE__*/React.createElement("span", {
|
|
43
55
|
className: "token ".concat(leaf.type)
|
|
44
56
|
}, markedChildren);
|
|
45
57
|
}
|
|
46
|
-
var style = {
|
|
47
|
-
position: 'relative'
|
|
48
|
-
};
|
|
49
|
-
if (leaf.isCaret) {
|
|
50
|
-
style['display'] = 'inline-block';
|
|
51
|
-
style['minWidth'] = '2px';
|
|
52
|
-
}
|
|
53
58
|
return /*#__PURE__*/React.createElement("span", Object.assign({
|
|
54
59
|
"data-id": leaf.id
|
|
55
60
|
}, attributes, {
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import _createClass from "@babel/runtime/helpers/esm/createClass";
|
|
2
|
+
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
|
3
|
+
import ObjectUtils from './object-utils';
|
|
4
|
+
var buildValues = function buildValues(diff, components, newString, oldString, valueType, useLongestToken) {
|
|
5
|
+
var componentPos = 0;
|
|
6
|
+
var componentLen = components.length;
|
|
7
|
+
var newPos = 0;
|
|
8
|
+
var oldPos = 0;
|
|
9
|
+
for (; componentPos < componentLen; componentPos++) {
|
|
10
|
+
var component = components[componentPos];
|
|
11
|
+
if (!component.removed) {
|
|
12
|
+
if (!component.added && useLongestToken) {
|
|
13
|
+
var value = newString.slice(newPos, newPos + component.count);
|
|
14
|
+
// eslint-disable-next-line no-loop-func
|
|
15
|
+
value = value.map(function (value, i) {
|
|
16
|
+
var oldValue = oldString[oldPos + i];
|
|
17
|
+
return oldValue.length > value.length ? oldValue : value;
|
|
18
|
+
});
|
|
19
|
+
component.value = diff.join(value, valueType);
|
|
20
|
+
} else {
|
|
21
|
+
component.value = diff.join(newString.slice(newPos, newPos + component.count), valueType);
|
|
22
|
+
}
|
|
23
|
+
newPos += component.count;
|
|
24
|
+
|
|
25
|
+
// Common case
|
|
26
|
+
if (!component.added) {
|
|
27
|
+
oldPos += component.count;
|
|
28
|
+
}
|
|
29
|
+
} else {
|
|
30
|
+
component.value = diff.join(oldString.slice(oldPos, oldPos + component.count), valueType);
|
|
31
|
+
oldPos += component.count;
|
|
32
|
+
|
|
33
|
+
// Reverse add and remove so removes are output first to match common convention
|
|
34
|
+
// The diffing algorithm is tied to add then remove output and this is the simplest
|
|
35
|
+
// route to get the desired output with minimal overhead.
|
|
36
|
+
if (componentPos && components[componentPos - 1].added) {
|
|
37
|
+
var tmp = components[componentPos - 1];
|
|
38
|
+
components[componentPos - 1] = components[componentPos];
|
|
39
|
+
components[componentPos] = tmp;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Special case handle for when one terminal is ignored (i.e. whitespace).
|
|
45
|
+
// For this case we merge the terminal into the prior string and drop the change.
|
|
46
|
+
// This is only available for string mode.
|
|
47
|
+
var lastComponent = components[componentLen - 1];
|
|
48
|
+
if (componentLen > 1 && typeof lastComponent.value === 'string' && (lastComponent.added || lastComponent.removed) && diff.equals('', lastComponent.value)) {
|
|
49
|
+
components[componentLen - 2].value += lastComponent.value;
|
|
50
|
+
components.pop();
|
|
51
|
+
}
|
|
52
|
+
return components;
|
|
53
|
+
};
|
|
54
|
+
var clonePath = function clonePath(path) {
|
|
55
|
+
return {
|
|
56
|
+
newPos: path.newPos,
|
|
57
|
+
components: path.components.slice(0)
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
var DiffText = /*#__PURE__*/_createClass(function DiffText(oldValue, newValue) {
|
|
61
|
+
var _this = this;
|
|
62
|
+
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
63
|
+
_classCallCheck(this, DiffText);
|
|
64
|
+
this.done = function (value) {
|
|
65
|
+
if (_this.callback) {
|
|
66
|
+
setTimeout(function () {
|
|
67
|
+
this.callback(undefined, value);
|
|
68
|
+
}, 0);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
};
|
|
73
|
+
// Main worker method. checks all permutations of a given edit length for acceptance.
|
|
74
|
+
this.execCompareLength = function (bestPath) {
|
|
75
|
+
for (var diagonalPath = -1 * _this.comparePath; diagonalPath <= _this.comparePath; diagonalPath += 2) {
|
|
76
|
+
var basePath = void 0;
|
|
77
|
+
var addPath = bestPath[diagonalPath - 1];
|
|
78
|
+
var removePath = bestPath[diagonalPath + 1];
|
|
79
|
+
var oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;
|
|
80
|
+
if (addPath) {
|
|
81
|
+
// No one else is going to attempt to use this value, clear it
|
|
82
|
+
bestPath[diagonalPath - 1] = undefined;
|
|
83
|
+
}
|
|
84
|
+
var canAdd = addPath && addPath.newPos + 1 < _this.newLen;
|
|
85
|
+
var canRemove = removePath && 0 <= oldPos && oldPos < _this.oldLen;
|
|
86
|
+
if (!canAdd && !canRemove) {
|
|
87
|
+
// If this path is a terminal then prune
|
|
88
|
+
bestPath[diagonalPath] = undefined;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Select the diagonal that we want to branch from. We select the prior
|
|
93
|
+
// path whose position in the new string is the farthest from the origin
|
|
94
|
+
// and does not pass the bounds of the diff graph
|
|
95
|
+
if (!canAdd || canRemove && addPath.newPos < removePath.newPos) {
|
|
96
|
+
basePath = clonePath(removePath);
|
|
97
|
+
_this.pushComponent(basePath.components, undefined, true);
|
|
98
|
+
} else {
|
|
99
|
+
basePath = addPath; // No need to clone, we've pulled it from the list
|
|
100
|
+
basePath.newPos++;
|
|
101
|
+
_this.pushComponent(basePath.components, true, undefined);
|
|
102
|
+
}
|
|
103
|
+
oldPos = _this.extractCommon(basePath, _this.newValue, _this.oldValue, diagonalPath);
|
|
104
|
+
|
|
105
|
+
// If we have hit the end of both strings, then we are done
|
|
106
|
+
if (basePath.newPos + 1 >= _this.newLen && oldPos + 1 >= _this.oldLen) {
|
|
107
|
+
return _this.done(buildValues(_this, basePath.components, _this.newValue, _this.oldValue, _this.valueType, _this.useLongestToken));
|
|
108
|
+
} else {
|
|
109
|
+
// Otherwise track this path as a potential candidate and continue.
|
|
110
|
+
bestPath[diagonalPath] = basePath;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
_this.comparePath++;
|
|
114
|
+
};
|
|
115
|
+
this.exec = function (bestPath) {
|
|
116
|
+
setTimeout(function () {
|
|
117
|
+
if (this.comparePath > this.maxEditLength) {
|
|
118
|
+
return this.callback();
|
|
119
|
+
}
|
|
120
|
+
if (!this.execCompareLength(bestPath)) {
|
|
121
|
+
this.exec(bestPath);
|
|
122
|
+
}
|
|
123
|
+
}, 0);
|
|
124
|
+
};
|
|
125
|
+
this.pushComponent = function (components, added, removed) {
|
|
126
|
+
var last = components[components.length - 1];
|
|
127
|
+
if (last && last.added === added && last.removed === removed) {
|
|
128
|
+
// We need to clone here as the component clone operation is just
|
|
129
|
+
// as shallow array clone
|
|
130
|
+
components[components.length - 1] = {
|
|
131
|
+
count: last.count + 1,
|
|
132
|
+
added: added,
|
|
133
|
+
removed: removed
|
|
134
|
+
};
|
|
135
|
+
} else {
|
|
136
|
+
components.push({
|
|
137
|
+
count: 1,
|
|
138
|
+
added: added,
|
|
139
|
+
removed: removed
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
this.extractCommon = function (basePath, newString, oldString, diagonalPath) {
|
|
144
|
+
var newLen = newString.length;
|
|
145
|
+
var oldLen = oldString.length;
|
|
146
|
+
var newPos = basePath.newPos;
|
|
147
|
+
var oldPos = newPos - diagonalPath;
|
|
148
|
+
var commonCount = 0;
|
|
149
|
+
while (newPos + 1 < newLen && oldPos + 1 < oldLen && _this.equals(newString[newPos + 1], oldString[oldPos + 1])) {
|
|
150
|
+
newPos++;
|
|
151
|
+
oldPos++;
|
|
152
|
+
commonCount++;
|
|
153
|
+
}
|
|
154
|
+
if (commonCount) {
|
|
155
|
+
basePath.components.push({
|
|
156
|
+
count: commonCount
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
basePath.newPos = newPos;
|
|
160
|
+
return oldPos;
|
|
161
|
+
};
|
|
162
|
+
this.equals = function (left, right) {
|
|
163
|
+
if (_this.options.comparator) {
|
|
164
|
+
return _this.options.comparator(left, right);
|
|
165
|
+
} else {
|
|
166
|
+
return left === right || _this.options.ignoreCase && left.toLowerCase() === right.toLowerCase();
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
this.removeEmpty = function (array, type) {
|
|
170
|
+
if (type === 'Array') return array;
|
|
171
|
+
var ret = [];
|
|
172
|
+
for (var i = 0; i < array.length; i++) {
|
|
173
|
+
if (array[i]) {
|
|
174
|
+
ret.push(array[i]);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return ret;
|
|
178
|
+
};
|
|
179
|
+
this.tokenize = function (value, valueType) {
|
|
180
|
+
if (valueType === 'Array') return value.slice();
|
|
181
|
+
return value.split('');
|
|
182
|
+
};
|
|
183
|
+
this.join = function (value, valueType) {
|
|
184
|
+
if (valueType === 'Array') return value;
|
|
185
|
+
return value.join('');
|
|
186
|
+
};
|
|
187
|
+
this.getDiffs = function () {
|
|
188
|
+
if (!_this.canCompare) {
|
|
189
|
+
return [{
|
|
190
|
+
value: _this.oldValue,
|
|
191
|
+
removed: true
|
|
192
|
+
}, {
|
|
193
|
+
value: _this.newValue,
|
|
194
|
+
added: true
|
|
195
|
+
}];
|
|
196
|
+
}
|
|
197
|
+
var bestPath = [{
|
|
198
|
+
newPos: -1,
|
|
199
|
+
components: []
|
|
200
|
+
}];
|
|
201
|
+
|
|
202
|
+
// Seed editLength = 0, i.e. the content starts with the same values
|
|
203
|
+
var oldPos = _this.extractCommon(bestPath[0], _this.newValue, _this.oldValue, 0);
|
|
204
|
+
if (bestPath[0].newPos + 1 >= _this.newLen && oldPos + 1 >= _this.oldLen) {
|
|
205
|
+
// Identity per the equality and tokenizer
|
|
206
|
+
return _this.done([{
|
|
207
|
+
value: _this.join(_this.newValue, _this.valueType),
|
|
208
|
+
count: _this.oldValue.length
|
|
209
|
+
}]);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Performs the length of edit iteration. Is a bit fugly as this has to support the
|
|
213
|
+
// sync and async mode which is never fun. Loops over execCompareLength until a value
|
|
214
|
+
// is produced, or until the edit length exceeds options.maxEditLength (if given),
|
|
215
|
+
// in which case it will return undefined.
|
|
216
|
+
if (_this.callback) {
|
|
217
|
+
_this.exec(bestPath);
|
|
218
|
+
} else {
|
|
219
|
+
while (_this.comparePath <= _this.maxEditLength) {
|
|
220
|
+
var ret = _this.execCompareLength(bestPath);
|
|
221
|
+
if (ret) {
|
|
222
|
+
return ret;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
this.oldValue = oldValue;
|
|
228
|
+
this.newValue = newValue;
|
|
229
|
+
var oldValueType = ObjectUtils.getDataType(oldValue);
|
|
230
|
+
var newValueType = ObjectUtils.getDataType(newValue);
|
|
231
|
+
this.canCompare = true;
|
|
232
|
+
if (oldValueType !== newValueType) {
|
|
233
|
+
this.canCompare = false;
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
this.valueType = newValueType;
|
|
237
|
+
this.callback = options.callback;
|
|
238
|
+
var optionsType = ObjectUtils.getDataType(options);
|
|
239
|
+
if (optionsType === 'function') {
|
|
240
|
+
this.callback = options;
|
|
241
|
+
this.options = {};
|
|
242
|
+
} else {
|
|
243
|
+
this.options = {};
|
|
244
|
+
}
|
|
245
|
+
this.comparePath = 1;
|
|
246
|
+
this.oldValue = this.removeEmpty(this.tokenize(oldValue, oldValueType), oldValueType);
|
|
247
|
+
this.oldLen = this.oldValue.length;
|
|
248
|
+
this.newValue = this.removeEmpty(this.tokenize(newValue, newValueType), newValueType);
|
|
249
|
+
this.newLen = this.newValue.length;
|
|
250
|
+
this.maxEditLength = this.newLen + this.oldLen;
|
|
251
|
+
if (this.options.maxEditLength) {
|
|
252
|
+
this.maxEditLength = Math.min(this.maxEditLength, this.options.maxEditLength);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
export default DiffText;
|