@seafile/sdoc-editor 0.1.60 → 0.1.62
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/api/sdoc-server-api.js +52 -0
- package/dist/basic-sdk/assets/css/layout.css +32 -0
- package/dist/basic-sdk/comment/comment-context-provider.js +27 -0
- package/dist/basic-sdk/comment/comment-decorate.js +29 -0
- package/dist/basic-sdk/comment/comment-editor.js +73 -0
- package/dist/basic-sdk/comment/comment-item.js +93 -0
- package/dist/basic-sdk/comment/comment-list.js +128 -0
- package/dist/basic-sdk/comment/comment.js +64 -0
- package/dist/basic-sdk/comment/helper.js +44 -0
- package/dist/basic-sdk/comment/hooks/use-comment-context.js +11 -0
- package/dist/basic-sdk/comment/hooks/use-comment-mount.js +55 -0
- package/dist/basic-sdk/comment/index.js +12 -0
- package/dist/basic-sdk/comment/reducer/comment-reducer.js +82 -0
- package/dist/basic-sdk/comment/style.css +137 -0
- package/dist/basic-sdk/decorates/index.js +21 -0
- package/dist/basic-sdk/editor.js +23 -12
- 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/plugins/code-block/helpers.js +6 -3
- package/dist/basic-sdk/extension/plugins/code-block/render-elem.js +7 -2
- package/dist/basic-sdk/extension/plugins/table/constants/index.js +0 -2
- package/dist/basic-sdk/extension/plugins/table/helpers.js +13 -11
- 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-style/render-elem.js +15 -7
- package/dist/basic-sdk/extension/render/render-element.js +17 -2
- package/dist/basic-sdk/extension/toolbar/index.js +3 -16
- package/dist/basic-sdk/highlight-decorate/index.js +5 -11
- package/dist/basic-sdk/hooks/use-scroll-context.js +10 -0
- package/dist/basic-sdk/hooks/use-selection-element.js +20 -0
- package/dist/basic-sdk/hooks/use-selection-position.js +34 -0
- package/dist/basic-sdk/hooks/use-selection-update.js +18 -0
- 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/constants/index.js +2 -1
- package/dist/context.js +20 -0
- 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
|
@@ -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,
|
|
@@ -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,19 +48,15 @@ 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
|
-
|
|
47
|
-
|
|
48
|
-
};
|
|
49
|
-
if (leaf.isCaret) {
|
|
50
|
-
style['display'] = 'inline-block';
|
|
51
|
-
style['minWidth'] = '2px';
|
|
58
|
+
if (leaf.bg_color) {
|
|
59
|
+
style['backgroundColor'] = leaf.bg_color;
|
|
52
60
|
}
|
|
53
61
|
return /*#__PURE__*/React.createElement("span", Object.assign({
|
|
54
62
|
"data-id": leaf.id
|
|
@@ -136,7 +136,22 @@ var CustomElement = function CustomElement(props) {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
};
|
|
139
|
-
var
|
|
139
|
+
var RenderElement = function RenderElement(props) {
|
|
140
140
|
return /*#__PURE__*/React.createElement(CustomElement, props);
|
|
141
|
+
|
|
142
|
+
// const { element } = props;
|
|
143
|
+
// const editor = useSlateStatic();
|
|
144
|
+
// const comments = editor.comments_map?.[element.id] || [];
|
|
145
|
+
// return (
|
|
146
|
+
// <div className='seafile-block-container'>
|
|
147
|
+
// <CustomElement {...props} />
|
|
148
|
+
// {comments.length > 0 && (
|
|
149
|
+
// <div className='comment-count'>
|
|
150
|
+
// <span className='comment-count__btn'>{comments.length}</span>
|
|
151
|
+
// </div>
|
|
152
|
+
// )}
|
|
153
|
+
// </div>
|
|
154
|
+
// );
|
|
141
155
|
};
|
|
142
|
-
|
|
156
|
+
|
|
157
|
+
export default RenderElement;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import useSelectionUpdate from '../../hooks/use-selection-update';
|
|
3
3
|
import { ORDERED_LIST, UNORDERED_LIST } from '../constants';
|
|
4
4
|
import { MenuGroup } from '../menu';
|
|
5
5
|
import QuoteMenu from '../plugins/blockquote/menu';
|
|
@@ -13,22 +13,9 @@ import CodeBlockMenu from '../plugins/code-block/menu';
|
|
|
13
13
|
import TextAlignMenu from '../plugins/text-align/menu';
|
|
14
14
|
import HistoryMenu from './redo-undo';
|
|
15
15
|
import { TableMenu, ActiveTableMenu } from '../plugins/table/menu';
|
|
16
|
-
import EventBus from '../../utils/event-bus';
|
|
17
16
|
var Toolbar = function Toolbar(_ref) {
|
|
18
17
|
var editor = _ref.editor;
|
|
19
|
-
|
|
20
|
-
_useState2 = _slicedToArray(_useState, 2),
|
|
21
|
-
update = _useState2[1];
|
|
22
|
-
useEffect(function () {
|
|
23
|
-
var onChange = function onChange() {
|
|
24
|
-
return update({});
|
|
25
|
-
};
|
|
26
|
-
var eventBus = EventBus.getInstance();
|
|
27
|
-
var unsubscribe = eventBus.subscribe('change', onChange);
|
|
28
|
-
return function () {
|
|
29
|
-
unsubscribe();
|
|
30
|
-
};
|
|
31
|
-
}, []);
|
|
18
|
+
useSelectionUpdate();
|
|
32
19
|
return /*#__PURE__*/React.createElement("div", {
|
|
33
20
|
className: "sdoc-editor-toolbar"
|
|
34
21
|
}, /*#__PURE__*/React.createElement(MenuGroup, null, /*#__PURE__*/React.createElement(HistoryMenu, {
|
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
2
|
-
import { useCallback } from 'react';
|
|
3
2
|
import { Element } from '@seafile/slate';
|
|
4
3
|
import { CODE_LINE } from '../extension/constants';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
var highlightDecorate = useCallback(function (_ref) {
|
|
4
|
+
export var highlightDecorate = function highlightDecorate(editor) {
|
|
5
|
+
return function (_ref) {
|
|
8
6
|
var _ref2 = _slicedToArray(_ref, 2),
|
|
9
7
|
node = _ref2[0],
|
|
10
8
|
path = _ref2[1];
|
|
9
|
+
var ranges = [];
|
|
11
10
|
if (Element.isElement(node) && node.type === CODE_LINE) {
|
|
12
|
-
|
|
11
|
+
ranges = (editor === null || editor === void 0 ? void 0 : editor.nodeToDecorations.get(node)) || [];
|
|
13
12
|
return ranges;
|
|
14
13
|
}
|
|
15
|
-
return
|
|
16
|
-
},
|
|
17
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
18
|
-
[editor.nodeToDecorations]);
|
|
19
|
-
return {
|
|
20
|
-
highlightDecorate: highlightDecorate
|
|
14
|
+
return ranges;
|
|
21
15
|
};
|
|
22
16
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React, { useContext } from "react";
|
|
2
|
+
export var ScrollContext = React.createContext(null);
|
|
3
|
+
export var useScrollContext = function useScrollContext() {
|
|
4
|
+
var context = useContext(ScrollContext);
|
|
5
|
+
if (!context) {
|
|
6
|
+
throw new Error('The \`useScrollContext\` hook must be used inside the <ScrollContext> component\'s context.');
|
|
7
|
+
}
|
|
8
|
+
var scrollRef = context.scrollRef;
|
|
9
|
+
return scrollRef;
|
|
10
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Editor, Element } from '@seafile/slate';
|
|
2
|
+
import { useSlateStatic } from '@seafile/slate-react';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
export var useSelectionElement = function useSelectionElement() {
|
|
5
|
+
var editor = useSlateStatic();
|
|
6
|
+
var nodeEntry = useMemo(function () {
|
|
7
|
+
var nodeEntry = Editor.above(editor, {
|
|
8
|
+
mode: 'lowest',
|
|
9
|
+
match: function match(n) {
|
|
10
|
+
return Element.isElement(n) && Editor.isBlock(editor, n);
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
return nodeEntry;
|
|
14
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
15
|
+
}, [editor.selection]);
|
|
16
|
+
if (nodeEntry && nodeEntry[0]) {
|
|
17
|
+
return nodeEntry[0];
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ReactEditor, useSlateStatic } from '@seafile/slate-react';
|
|
2
|
+
import { Editor, Element } from '@seafile/slate';
|
|
3
|
+
import { useScrollContext } from './use-scroll-context';
|
|
4
|
+
export var useSelectionPosition = function useSelectionPosition() {
|
|
5
|
+
var editor = useSlateStatic();
|
|
6
|
+
if (!editor.selection) return {
|
|
7
|
+
x: 0,
|
|
8
|
+
y: 0
|
|
9
|
+
};
|
|
10
|
+
var node = Editor.above(editor, {
|
|
11
|
+
mode: 'lowest',
|
|
12
|
+
match: function match(n) {
|
|
13
|
+
return Element.isElement(n) && Editor.isBlock(editor, n);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
var domNode = ReactEditor.toDOMNode(editor, node[0]);
|
|
17
|
+
var rect = domNode.getBoundingClientRect();
|
|
18
|
+
return rect;
|
|
19
|
+
};
|
|
20
|
+
export var useCommentListPosition = function useCommentListPosition() {
|
|
21
|
+
var selectionPosition = useSelectionPosition();
|
|
22
|
+
var headerHeight = 100;
|
|
23
|
+
var scrollRef = useScrollContext();
|
|
24
|
+
var _ref = scrollRef.current || {},
|
|
25
|
+
_ref$scrollTop = _ref.scrollTop,
|
|
26
|
+
scrollTop = _ref$scrollTop === void 0 ? 0 : _ref$scrollTop;
|
|
27
|
+
if (selectionPosition.y !== 0) {
|
|
28
|
+
selectionPosition.y = selectionPosition.y - headerHeight + scrollTop;
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
x: selectionPosition.x,
|
|
32
|
+
y: selectionPosition.y
|
|
33
|
+
};
|
|
34
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import EventBus from '../utils/event-bus';
|
|
4
|
+
export default function useSelectionUpdate() {
|
|
5
|
+
var _useState = useState({}),
|
|
6
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
7
|
+
update = _useState2[1];
|
|
8
|
+
useEffect(function () {
|
|
9
|
+
var onChange = function onChange() {
|
|
10
|
+
return update({});
|
|
11
|
+
};
|
|
12
|
+
var eventBus = EventBus.getInstance();
|
|
13
|
+
var unsubscribe = eventBus.subscribe('change', onChange);
|
|
14
|
+
return function () {
|
|
15
|
+
unsubscribe();
|
|
16
|
+
};
|
|
17
|
+
}, []);
|
|
18
|
+
}
|
|
@@ -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;
|