UNPKG

@atlaskit/editor-plugin-show-diff

Version:

ShowDiff plugin for @atlaskit/editor-core

242 lines (240 loc) 13.1 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.calculateDiffDecorations = void 0; var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _isEqual = _interopRequireDefault(require("lodash/isEqual")); var _memoizeOne = _interopRequireDefault(require("memoize-one")); var _prosemirrorChangeset = require("prosemirror-changeset"); var _document = require("@atlaskit/editor-common/utils/document"); var _view = require("@atlaskit/editor-prosemirror/view"); var _platformFeatureFlags = require("@atlaskit/platform-feature-flags"); var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals"); var _areDocsEqualByBlockStructureAndText = require("../areDocsEqualByBlockStructureAndText"); var _createBlockChangedDecoration = require("../decorations/createBlockChangedDecoration"); var _createInlineChangedDecoration = require("../decorations/createInlineChangedDecoration"); var _createNodeChangedDecorationWidget = require("../decorations/createNodeChangedDecorationWidget"); var _getAttrChangeRanges = require("../decorations/utils/getAttrChangeRanges"); var _getMarkChangeRanges = require("../decorations/utils/getMarkChangeRanges"); var _groupChangesByBlock = require("./groupChangesByBlock"); var _optimizeChanges = require("./optimizeChanges"); var _simplifySteps = require("./simplifySteps"); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } // eslint-disable-next-line @atlassian/tangerine/import/entry-points var getChanges = function getChanges(_ref) { var changeset = _ref.changeset, originalDoc = _ref.originalDoc, steppedDoc = _ref.steppedDoc, diffType = _ref.diffType, tr = _ref.tr; if (diffType === 'block' && (0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true)) { return (0, _groupChangesByBlock.groupChangesByBlock)(changeset.changes, originalDoc, steppedDoc); } var changes = (0, _prosemirrorChangeset.simplifyChanges)(changeset.changes, tr.doc); return (0, _optimizeChanges.optimizeChanges)(changes); }; var calculateNodesForBlockDecoration = function calculateNodesForBlockDecoration(_ref2) { var doc = _ref2.doc, from = _ref2.from, to = _ref2.to, colorScheme = _ref2.colorScheme, _ref2$isInserted = _ref2.isInserted, isInserted = _ref2$isInserted === void 0 ? true : _ref2$isInserted, activeIndexPos = _ref2.activeIndexPos; var decorations = []; // Iterate over the document nodes within the range doc.nodesBetween(from, to, function (node, pos) { if (node.isBlock && (!(0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true) || pos + node.nodeSize <= to)) { var nodeEnd = pos + node.nodeSize; var isActive = activeIndexPos && pos === activeIndexPos.from && nodeEnd === activeIndexPos.to; var decoration = (0, _createBlockChangedDecoration.createBlockChangedDecoration)({ change: { from: pos, to: nodeEnd, name: node.type.name }, colorScheme: colorScheme, isInserted: isInserted, isActive: isActive }); if (decoration) { decorations.push(decoration); } } }); return decorations; }; var calculateDiffDecorationsInner = function calculateDiffDecorationsInner(_ref3) { var state = _ref3.state, pluginState = _ref3.pluginState, nodeViewSerializer = _ref3.nodeViewSerializer, colorScheme = _ref3.colorScheme, intl = _ref3.intl, activeIndexPos = _ref3.activeIndexPos, api = _ref3.api, _ref3$isInverted = _ref3.isInverted, isInverted = _ref3$isInverted === void 0 ? false : _ref3$isInverted, _ref3$diffType = _ref3.diffType, diffType = _ref3$diffType === void 0 ? 'inline' : _ref3$diffType; var originalDoc = pluginState.originalDoc, steps = pluginState.steps; if (!originalDoc || !pluginState.isDisplayingChanges) { return _view.DecorationSet.empty; } var tr = state.tr; var steppedDoc = originalDoc; var attrSteps = []; var simplifiedSteps = (0, _simplifySteps.simplifySteps)(steps, originalDoc); var stepMaps = []; var _iterator = _createForOfIteratorHelper(simplifiedSteps), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var step = _step.value; var result = step.apply(steppedDoc); if (result.failed === null && result.doc) { if ((0, _getAttrChangeRanges.stepIsValidAttrChange)(step, steppedDoc, result.doc)) { attrSteps.push(step); } stepMaps.push(step.getMap()); steppedDoc = result.doc; } } // Rather than using .eq() we use a custom function that only checks for structural // changes and ignores differences in attributes which don't affect decoration positions } catch (err) { _iterator.e(err); } finally { _iterator.f(); } if (!(0, _document.areNodesEqualIgnoreAttrs)(steppedDoc, tr.doc)) { var recoveredViaContentEquality = (0, _platformFeatureFlags.fg)('platform_editor_show_diff_equality_fallback') ? (0, _areDocsEqualByBlockStructureAndText.areDocsEqualByBlockStructureAndText)(steppedDoc, tr.doc) : undefined; if ((0, _expValEquals.expValEquals)('platform_editor_are_nodes_equal_ignore_mark_order', 'isEnabled', true)) { var _api$analytics; api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.fireAnalyticsEvent({ eventType: 'track', action: 'nodesNotEqual', actionSubject: 'showDiff', attributes: { docSizeEqual: steppedDoc.nodeSize === tr.doc.nodeSize, colorScheme: colorScheme, recoveredViaContentEquality: recoveredViaContentEquality } }); } if ((0, _platformFeatureFlags.fg)('platform_editor_show_diff_equality_fallback')) { if (!recoveredViaContentEquality) { return _view.DecorationSet.empty; } } else { return _view.DecorationSet.empty; } } var changeset = _prosemirrorChangeset.ChangeSet.create(originalDoc).addSteps(steppedDoc, stepMaps, tr.doc); var changes = getChanges({ changeset: changeset, originalDoc: originalDoc, steppedDoc: steppedDoc, diffType: diffType, tr: tr }); var decorations = []; changes.forEach(function (change) { var isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to; // Our default operations are insertions, so it should match the opposite of isInverted. var isInserted = !isInverted; if (change.inserted.length > 0) { decorations.push((0, _createInlineChangedDecoration.createInlineChangedDecoration)(_objectSpread({ change: change, colorScheme: colorScheme, isActive: isActive }, (0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true) && { isInserted: isInserted }))); decorations.push.apply(decorations, (0, _toConsumableArray2.default)(calculateNodesForBlockDecoration(_objectSpread(_objectSpread({ doc: tr.doc, from: change.fromB, to: change.toB, colorScheme: colorScheme }, (0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true) && { isInserted: isInserted }), {}, { activeIndexPos: activeIndexPos, intl: intl })))); } if (change.deleted.length > 0) { var decoration = (0, _createNodeChangedDecorationWidget.createNodeChangedDecorationWidget)(_objectSpread({ change: change, doc: originalDoc, nodeViewSerializer: nodeViewSerializer, colorScheme: colorScheme, newDoc: tr.doc, intl: intl, activeIndexPos: activeIndexPos }, (0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true) && { isInserted: !isInserted })); if (decoration) { decorations.push.apply(decorations, (0, _toConsumableArray2.default)(decoration)); } } }); (0, _getMarkChangeRanges.getMarkChangeRanges)(steps).forEach(function (change) { var isActive = activeIndexPos && change.fromB === activeIndexPos.from && change.toB === activeIndexPos.to; decorations.push((0, _createInlineChangedDecoration.createInlineChangedDecoration)({ change: change, colorScheme: colorScheme, isActive: isActive, isInserted: true })); }); (0, _getAttrChangeRanges.getAttrChangeRanges)(tr.doc, attrSteps).forEach(function (change) { decorations.push.apply(decorations, (0, _toConsumableArray2.default)(calculateNodesForBlockDecoration({ doc: tr.doc, from: change.fromB, to: change.toB, colorScheme: colorScheme, isInserted: true, activeIndexPos: activeIndexPos, intl: intl }))); }); return _view.DecorationSet.empty.add(tr.doc, decorations); }; var calculateDiffDecorations = exports.calculateDiffDecorations = (0, _memoizeOne.default)(calculateDiffDecorationsInner, // Cache results unless relevant inputs change function (_ref4, _ref5) { var _ref9; var _ref6 = (0, _slicedToArray2.default)(_ref4, 1), _ref6$ = _ref6[0], pluginState = _ref6$.pluginState, state = _ref6$.state, colorScheme = _ref6$.colorScheme, intl = _ref6$.intl, activeIndexPos = _ref6$.activeIndexPos, isInverted = _ref6$.isInverted, diffType = _ref6$.diffType; var _ref7 = (0, _slicedToArray2.default)(_ref5, 1), _ref7$ = _ref7[0], lastPluginState = _ref7$.pluginState, lastState = _ref7$.state, lastColorScheme = _ref7$.colorScheme, lastIntl = _ref7$.intl, lastActiveIndexPos = _ref7$.activeIndexPos, lastIsInverted = _ref7$.isInverted, lastDiffType = _ref7$.diffType; var originalDocIsSame = lastPluginState.originalDoc && pluginState.originalDoc && pluginState.originalDoc.eq(lastPluginState.originalDoc); if ((0, _expValEquals.expValEquals)('platform_editor_diff_plugin_extended', 'isEnabled', true)) { var _ref8; return (_ref8 = colorScheme === lastColorScheme && intl.locale === lastIntl.locale && isInverted === lastIsInverted && diffType === lastDiffType && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos) && originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && state.doc.eq(lastState.doc)) !== null && _ref8 !== void 0 ? _ref8 : false; } return (_ref9 = originalDocIsSame && (0, _isEqual.default)(pluginState.steps, lastPluginState.steps) && state.doc.eq(lastState.doc) && colorScheme === lastColorScheme && intl.locale === lastIntl.locale && (0, _isEqual.default)(activeIndexPos, lastActiveIndexPos)) !== null && _ref9 !== void 0 ? _ref9 : false; });