UNPKG

@atlaskit/editor-plugin-show-diff

Version:

ShowDiff plugin for @atlaskit/editor-core

189 lines (178 loc) 8.93 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.stepIsValidAttrChange = exports.getAttrChangeRanges = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _steps = require("@atlaskit/adf-schema/steps"); var _deprecatedPlatformFeatureExperiments = require("@atlaskit/editor-common/deprecated-platform-feature-experiments"); var _nodeTypeUtils = require("@atlaskit/editor-common/utils/node-type-utils"); var _transform = require("@atlaskit/editor-prosemirror/transform"); var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals"); var _diffableAttrs = require("./diffableAttrs"); 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; } var filterUndefined = function filterUndefined(x) { return !!x; }; // Attr lists sourced from the shared `diffableAttrs` map (shared with the encoder). var mediaAttrs = (0, _diffableAttrs.getRequiredIncludedDiffableAttrs)('media'); var dateAttrs = (0, _diffableAttrs.getRequiredIncludedDiffableAttrs)('date'); var taskItemAttrs = (0, _diffableAttrs.getRequiredIncludedDiffableAttrs)('taskItem'); var panelAttrs = (0, _diffableAttrs.getRequiredIncludedDiffableAttrs)('panel'); var emojiAttrs = (0, _diffableAttrs.getRequiredIncludedDiffableAttrs)('emoji'); var mentionAttrs = (0, _diffableAttrs.getRequiredIncludedDiffableAttrs)('mention'); var statusAttrs = (0, _diffableAttrs.getRequiredIncludedDiffableAttrs)('status'); // Map of node type name → the attrs that represent a meaningful content change for that node var inlineNodeAttrMap = { date: dateAttrs, emoji: emojiAttrs, mention: mentionAttrs, status: statusAttrs }; var isInlineAttrChangeNodeName = function isInlineAttrChangeNodeName(nodeName) { return nodeName in inlineNodeAttrMap; }; // Extension node type names. Their "any attr except localId" exclude rule lives // in the shared `diffableAttrs` map and is applied via `isDiffableAttr` below. var extensionNodeNames = ['extension', 'inlineExtension', 'bodiedExtension']; var getStepAttrs = function getStepAttrs(step) { if (step instanceof _transform.AttrStep) { return [step.attr]; } if (step instanceof _steps.SetAttrsStep && step.attrs) { return Object.keys(step.attrs); } return []; }; var getAttrChangeRanges = exports.getAttrChangeRanges = function getAttrChangeRanges(doc, steps, originalDoc) { return steps.map(function (step) { if (!(step instanceof _transform.AttrStep) && !(step instanceof _steps.SetAttrsStep)) { return undefined; } var stepAttrs = getStepAttrs(step); var $pos = doc.resolve(step.pos); var nodeAtPos = doc.nodeAt(step.pos); // date node: timestamp attribute change — highlight the date node itself (inline) if (stepAttrs.some(function (v) { return dateAttrs.includes(v); }) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'date' && !(0, _deprecatedPlatformFeatureExperiments.isExperimentEnabled)('platform_editor_improve_inline_diffs', function () { return (0, _expValEquals.expValEquals)('platform_editor_improve_inline_diffs', 'isEnabled', true); })) { return { fromB: step.pos, toB: step.pos + nodeAtPos.nodeSize, isInline: true, inlineNodeName: 'date' }; } // The following inline node attr changes are gated behind platform_editor_improve_inline_diffs. // The changeset path (createDecorationsForChange) handles the deletion widget via // prosemirror-changeset; we only need to add the inline insertion highlight here. if ((0, _deprecatedPlatformFeatureExperiments.isExperimentEnabled)('platform_editor_improve_inline_diffs', function () { return (0, _expValEquals.expValEquals)('platform_editor_improve_inline_diffs', 'isEnabled', true); }) && nodeAtPos) { var nodeName = nodeAtPos.type.name; if (isInlineAttrChangeNodeName(nodeName)) { var watchedAttrs = inlineNodeAttrMap[nodeName]; if (stepAttrs.some(function (v) { return watchedAttrs.includes(v); })) { var originalNodeAtPos = originalDoc === null || originalDoc === void 0 ? void 0 : originalDoc.nodeAt(step.pos); return _objectSpread({ fromB: step.pos, toB: step.pos + nodeAtPos.nodeSize, isInline: true, inlineNodeName: nodeName }, originalNodeAtPos && { fromA: step.pos, toA: step.pos + originalNodeAtPos.nodeSize }); } } } // taskItem node: state attribute change — highlight the taskItem node if (stepAttrs.some(function (v) { return taskItemAttrs.includes(v); }) && (nodeAtPos === null || nodeAtPos === void 0 ? void 0 : nodeAtPos.type.name) === 'taskItem') { return { fromB: step.pos, toB: step.pos + nodeAtPos.nodeSize }; } // panel node (incl. variants like panel_c1): type/colour/icon attribute change // (e.g. note -> warning) — highlight the new panel and, when the original node // is resolvable, expose its range (fromA/toA) so the caller can render the old // panel as a "deleted" widget for a before/after comparison. if (stepAttrs.some(function (v) { return panelAttrs.includes(v); }) && nodeAtPos && (0, _nodeTypeUtils.getBaseNodeTypeName)(nodeAtPos.type) === 'panel') { var _originalNodeAtPos = originalDoc === null || originalDoc === void 0 ? void 0 : originalDoc.nodeAt(step.pos); return _objectSpread({ fromB: step.pos, toB: step.pos + nodeAtPos.nodeSize }, _originalNodeAtPos && { fromA: step.pos, toA: step.pos + _originalNodeAtPos.nodeSize }); } // extension nodes: highlight on any diffable attr change (exclude rule in shared map) if (nodeAtPos && extensionNodeNames.includes(nodeAtPos.type.name) && stepAttrs.some(function (v) { return (0, _diffableAttrs.isDiffableAttr)(nodeAtPos.type.name, v); })) { var isInline = nodeAtPos.type.name === 'inlineExtension'; return { fromB: step.pos, toB: step.pos + nodeAtPos.nodeSize, isInline: isInline }; } // media node: id/collection/url attribute change — highlight the mediaSingle parent if (stepAttrs.some(function (v) { return mediaAttrs.includes(v); }) && $pos.parent.type === doc.type.schema.nodes.mediaSingle) { var startPos = $pos.pos + $pos.parentOffset; return { fromB: startPos, toB: startPos + $pos.parent.nodeSize - 1 }; } return undefined; }).filter(filterUndefined) // Deduplicate by node position: multiple AttrSteps on the same node // (e.g. setNodeAttribute(pos, 'text', ...) + setNodeAttribute(pos, 'color', ...)) // should produce only one decoration, not one per step. // Gated behind the same experiment as the inline node attr changes that introduced // the possibility of multiple ranges for the same node position. .filter(function (range, i, arr) { return !(0, _deprecatedPlatformFeatureExperiments.isExperimentEnabled)('platform_editor_improve_inline_diffs', function () { return (0, _expValEquals.expValEquals)('platform_editor_improve_inline_diffs', 'isEnabled', true); }) || arr.findIndex(function (r) { return r.fromB === range.fromB; }) === i; }); }; /** * Check if the step was a valid attr change and affected the doc * * @param step Attr step to test * @param beforeDoc Doc before the step * @param afterDoc Doc after the step * @returns Boolean if the change should show a decoration */ var stepIsValidAttrChange = exports.stepIsValidAttrChange = function stepIsValidAttrChange(step, beforeDoc, afterDoc) { try { if (step instanceof _transform.AttrStep || step instanceof _steps.SetAttrsStep) { var attrStepAfter = afterDoc.nodeAt(step.pos); var attrStepBefore = beforeDoc.nodeAt(step.pos); // The change affected the document if (attrStepAfter && attrStepBefore && !attrStepAfter.eq(attrStepBefore)) { return true; } } return false; } catch (_unused) { return false; } };