UNPKG

@atlaskit/editor-plugin-show-diff

Version:

ShowDiff plugin for @atlaskit/editor-core

200 lines (188 loc) 7.55 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.NodeViewSerializer = void 0; exports.isEditorViewWithNodeViews = isEditorViewWithNodeViews; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _model = require("@atlaskit/editor-prosemirror/model"); /** * Utilities for working with ProseMirror node views and DOM serialization within the * Show Diff editor plugin. * * This module centralizes: * - Access to the editor's `nodeViews` registry (when available on `EditorView`) * - Safe attempts to instantiate a node view for a given node, with a blocklist to * avoid node types that are known to be problematic in this context (e.g. tables) * - Schema-driven serialization of nodes and fragments to DOM via `DOMSerializer` * * The Show Diff decorations leverage this to either render nodes using their * corresponding node view implementation, or fall back to DOM serialization. */ /** * Narrowed `EditorView` that exposes the internal `nodeViews` registry. * Many editor instances provide this, but it's not part of the base type. */ /** * Type guard to detect whether an `EditorView` exposes a `nodeViews` map. */ function isEditorViewWithNodeViews(view) { // eslint-disable-next-line @typescript-eslint/no-explicit-any return view.nodeViews !== undefined; } /** * Encapsulates DOM serialization and node view access/creation. * * Responsible for: * - Creating a `DOMSerializer` from the provided schema * - Reading `nodeViews` from an `EditorView` (if present) or using an explicit mapping * - Preventing node view creation for blocklisted node types */ var NodeViewSerializer = exports.NodeViewSerializer = /*#__PURE__*/function () { function NodeViewSerializer(params) { var _params$blocklist; (0, _classCallCheck2.default)(this, NodeViewSerializer); if (params !== null && params !== void 0 && params.editorView) { this.init({ editorView: params.editorView }); } this.nodeViewBlocklist = new Set((_params$blocklist = params.blocklist) !== null && _params$blocklist !== void 0 ? _params$blocklist : ['paragraph']); } /** * Initializes or reinitializes the NodeViewSerializer with a new EditorView. * This allows the same serializer instance to be reused across different editor states. */ return (0, _createClass2.default)(NodeViewSerializer, [{ key: "init", value: function init(params) { var _params$editorView, _ref, _this$editorView; this.serializer = _model.DOMSerializer.fromSchema(params.editorView.state.schema); if (isEditorViewWithNodeViews(params.editorView)) { this.editorView = params.editorView; } var nodeViews = // eslint-disable-next-line @typescript-eslint/no-explicit-any ((_params$editorView = params.editorView) === null || _params$editorView === void 0 ? void 0 : _params$editorView.nodeViews) || {}; this.nodeViews = (_ref = nodeViews !== null && nodeViews !== void 0 ? nodeViews : (_this$editorView = this.editorView) === null || _this$editorView === void 0 ? void 0 : _this$editorView.nodeViews) !== null && _ref !== void 0 ? _ref : {}; } /** * Appends serialized child nodes to the given contentDOM element. */ }, { key: "appendChildNodes", value: function appendChildNodes(children, contentDOM) { var _this = this; children.forEach(function (child) { var childNode = _this.tryCreateNodeView(child) || _this.serializeNode(child); if (childNode) { contentDOM === null || contentDOM === void 0 || contentDOM.append(childNode); } }); } /** * Attempts to create a node view for the given node. * * Returns `null` when there is no `EditorView`, no constructor for the node type, * or the node type is blocklisted. Otherwise returns the constructed node view instance. */ }, { key: "tryCreateNodeView", value: function tryCreateNodeView(targetNode) { var _this$nodeViews; if (!this.editorView) { return null; } var constructor = (_this$nodeViews = this.nodeViews) === null || _this$nodeViews === void 0 ? void 0 : _this$nodeViews[targetNode.type.name]; if (this.nodeViewBlocklist.has(targetNode.type.name)) { return null; } try { if (!constructor) { var _targetNode$type$spec, _targetNode$type$spec2; if (targetNode.isInline) { return null; } var toDOMResult = (_targetNode$type$spec = (_targetNode$type$spec2 = targetNode.type.spec).toDOM) === null || _targetNode$type$spec === void 0 ? void 0 : _targetNode$type$spec.call(_targetNode$type$spec2, targetNode); if (!toDOMResult) { return null; } var _DOMSerializer$render = _model.DOMSerializer.renderSpec(document, toDOMResult), _dom = _DOMSerializer$render.dom, _contentDOM = _DOMSerializer$render.contentDOM; if (_dom instanceof HTMLElement) { if (targetNode.type.name === 'paragraph' && targetNode.children.length === 1) { return this.serializeFragment(targetNode.content); } // Iteratively populate children this.appendChildNodes(targetNode.children, _contentDOM); } return _dom; } var _constructor = constructor(targetNode, this.editorView, function () { return 0; }, [], {}), dom = _constructor.dom, contentDOM = _constructor.contentDOM; // Iteratively populate children this.appendChildNodes(targetNode.children, contentDOM); return dom; } catch (e) { return null; } } /** * Serializes a node to a DOM `Node` using the schema's `DOMSerializer`. */ }, { key: "serializeNode", value: function serializeNode(node) { if (!this.serializer) { throw new Error('NodeViewSerializer must be initialized with init() before use'); } try { return this.serializer.serializeNode(node); } catch (e) { return null; } } /** * Serializes a fragment to a `DocumentFragment` using the schema's `DOMSerializer`. */ }, { key: "serializeFragment", value: function serializeFragment(fragment) { if (!this.serializer) { throw new Error('NodeViewSerializer must be initialized with init() before use'); } try { return this.serializer.serializeFragment(fragment); } catch (e) { return null; } } /** * Returns a copy of the current node view blocklist. */ }, { key: "getNodeViewBlocklist", value: function getNodeViewBlocklist() { return new Set(this.nodeViewBlocklist); } /** * Returns a filtered copy of the node view blocklist, excluding specified node types. * @param excludeTypes - Array of node type names to exclude from the blocklist */ }, { key: "getFilteredNodeViewBlocklist", value: function getFilteredNodeViewBlocklist(excludeTypes) { var filtered = new Set(this.nodeViewBlocklist); excludeTypes.forEach(function (type) { return filtered.delete(type); }); return filtered; } }]); }();