UNPKG

@atlaskit/editor-plugin-card

Version:

Card plugin for @atlaskit/editor-core

303 lines (297 loc) 17.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.createPlugin = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _rafSchd = _interopRequireDefault(require("raf-schd")); var _reactNodeView = require("@atlaskit/editor-common/react-node-view"); var _safePlugin = require("@atlaskit/editor-common/safe-plugin"); var _styles = require("@atlaskit/editor-common/styles"); var _state = require("@atlaskit/editor-prosemirror/state"); var _utils = require("@atlaskit/editor-prosemirror/utils"); var _linkingCommon = require("@atlaskit/linking-common"); var _platformFeatureFlags = require("@atlaskit/platform-feature-flags"); var _inlineCard = require("../nodeviews/inlineCard"); var _lazyBlockCard = require("../nodeviews/lazy-block-card"); var _lazyEmbedCard = require("../nodeviews/lazy-embed-card"); var _lazyInlineCard = require("../nodeviews/lazy-inline-card"); var _eventsFromTr = require("../ui/analytics/events-from-tr"); var _utils2 = require("../ui/LayoutButton/utils"); var _localStorage = require("../ui/local-storage"); var _actions = require("./actions"); var _pluginKey = require("./plugin-key"); var _reducers = _interopRequireDefault(require("./reducers")); var _resolve = require("./util/resolve"); var _state2 = require("./util/state"); var _utils3 = require("./utils"); 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 LOCAL_STORAGE_DISCOVERY_KEY_SMART_LINK = 'smart-link-upgrade-pulse'; // Only the first resolved inline smart link is needed for PO spotlight targeting var MAX_RESOLVED_INLINE_SMART_LINKS = 1; var handleAwarenessOverlay = function handleAwarenessOverlay(view) { var currentState = (0, _state2.getPluginState)(view.state); var overlayCandidatePos = currentState === null || currentState === void 0 ? void 0 : currentState.overlayCandidatePosition; if (overlayCandidatePos) { var _currentState$removeO; (_currentState$removeO = currentState.removeOverlay) === null || _currentState$removeO === void 0 || _currentState$removeO.call(currentState); var tr = view.state.tr; (0, _actions.clearOverlayCandidate)(tr); view.dispatch(tr); } }; var createPlugin = exports.createPlugin = function createPlugin(options, pluginInjectionApi) { return function (pmPluginFactoryParams) { var editorAppearance = options.editorAppearance, allowResizing = options.allowResizing, useAlternativePreloader = options.useAlternativePreloader, fullWidthMode = options.fullWidthMode, actionOptions = options.actionOptions, cardPluginEvents = options.cardPluginEvents, showUpgradeDiscoverability = options.showUpgradeDiscoverability, allowEmbeds = options.allowEmbeds, allowBlockCards = options.allowBlockCards, onClickCallback = options.onClickCallback, isPageSSRed = options.isPageSSRed, provider = options.provider, CompetitorPrompt = options.CompetitorPrompt, embedCardTransformers = options.embedCardTransformers; var enableInlineUpgradeFeatures = !!showUpgradeDiscoverability; var inlineCardViewProducer = (0, _reactNodeView.getInlineNodeViewProducer)({ pmPluginFactoryParams: pmPluginFactoryParams, Component: _inlineCard.InlineCardNodeView, extraComponentProps: { useAlternativePreloader: useAlternativePreloader, actionOptions: actionOptions, enableInlineUpgradeFeatures: enableInlineUpgradeFeatures, allowEmbeds: allowEmbeds, allowBlockCards: allowBlockCards, pluginInjectionApi: pluginInjectionApi, onClickCallback: onClickCallback, isPageSSRed: isPageSSRed, provider: provider, CompetitorPrompt: CompetitorPrompt } }); return new _safePlugin.SafePlugin({ state: { init: function init() { return { requests: [], provider: null, cards: [], datasourceStash: {}, resolvedToolbarAttributesByUrl: {}, showLinkingToolbar: false, smartLinkEvents: undefined, editorAppearance: editorAppearance, embedCardTransformers: embedCardTransformers, showDatasourceModal: false, datasourceModalType: undefined, datasourceTableRef: undefined, layout: undefined }; }, apply: function apply(tr, pluginState, prevEditorState) { var _pluginState$requests, _pluginState$requests2; // Update all the positions of outstanding requests and // cards in the plugin state. var pluginStateWithUpdatedPos = (0, _state2.getPluginStateWithUpdatedPos)(pluginState, tr); // apply any actions var meta = tr.getMeta(_pluginKey.pluginKey); if (cardPluginEvents) { var events = (0, _eventsFromTr.eventsFromTransaction)(tr, prevEditorState); cardPluginEvents.push.apply(cardPluginEvents, (0, _toConsumableArray2.default)(events)); } if (!meta) { if (pluginState.datasourceTableRef) { if (!(tr.selection instanceof _state.NodeSelection) || !tr.selection.node.attrs.datasource) { // disable resize button when switching from datasource to block card return _objectSpread(_objectSpread({}, pluginStateWithUpdatedPos), {}, { datasourceTableRef: undefined }); } } } if (!meta) { return pluginStateWithUpdatedPos; } var newState = (0, _reducers.default)(pluginStateWithUpdatedPos, meta); // Track the first resolved inline smart link for PO spotlight DOM targeting if (meta.type === 'RESOLVE' && pluginState !== null && pluginState !== void 0 && (_pluginState$requests = pluginState.requests) !== null && _pluginState$requests !== void 0 && _pluginState$requests.length && (0, _platformFeatureFlags.fg)('cc_dnd_smart_link_changeboard_po_template_gate')) { var resolvedRequest = pluginState.requests.find(function (req) { return req.url === meta.url; }); if ((resolvedRequest === null || resolvedRequest === void 0 ? void 0 : resolvedRequest.appearance) === 'inline') { var _newState$resolvedInl, _newState$resolvedInl2; if (((_newState$resolvedInl = (_newState$resolvedInl2 = newState.resolvedInlineSmartLinks) === null || _newState$resolvedInl2 === void 0 ? void 0 : _newState$resolvedInl2.length) !== null && _newState$resolvedInl !== void 0 ? _newState$resolvedInl : 0) < MAX_RESOLVED_INLINE_SMART_LINKS) { var _newState$resolvedInl3; newState.resolvedInlineSmartLinks = [].concat((0, _toConsumableArray2.default)((_newState$resolvedInl3 = newState.resolvedInlineSmartLinks) !== null && _newState$resolvedInl3 !== void 0 ? _newState$resolvedInl3 : []), [{ pos: resolvedRequest.pos, url: resolvedRequest.url, source: resolvedRequest.source }]); } } } if (!enableInlineUpgradeFeatures) { return newState; } // the code below is related to the "Inline Switcher" project, for more information pls see EDM-7984 var isSingleInlineLink = (pluginState === null || pluginState === void 0 || (_pluginState$requests2 = pluginState.requests) === null || _pluginState$requests2 === void 0 ? void 0 : _pluginState$requests2.length) === 1 && pluginState.requests[0].appearance === 'inline'; var isSmartLinkPulseDiscovered = (0, _localStorage.isLocalStorageKeyDiscovered)(LOCAL_STORAGE_DISCOVERY_KEY_SMART_LINK); if (meta.type !== 'RESOLVE' || !isSingleInlineLink) { return newState; } var linkPosition = pluginState.requests[0].pos; var canBeUpgradedToBlock = allowBlockCards && (0, _utils3.isBlockSupportedAtPosition)(linkPosition, prevEditorState, 'inline'); var canBeUpgradedToEmbed = allowEmbeds && (0, _utils3.isEmbedSupportedAtPosition)(linkPosition, prevEditorState, 'inline'); if (canBeUpgradedToBlock || canBeUpgradedToEmbed) { newState.overlayCandidatePosition = linkPosition; } if (!isSmartLinkPulseDiscovered && canBeUpgradedToEmbed) { newState.inlineCardAwarenessCandidatePosition = linkPosition; } return newState; } }, filterTransaction: function filterTransaction(tr) { var isOutsideClicked = tr.getMeta('outsideProsemirrorEditorClicked'); if (isOutsideClicked) { var isInlineEditingActive = document.getElementById('sllv-active-inline-edit'); if (isInlineEditingActive) { return false; } } return true; }, view: function view(_view) { var domAtPos = _view.domAtPos.bind(_view); var rafCancellationCallbacks = []; if (options.provider) { (0, _resolve.handleProvider)('cardProvider', options.provider, _view); } return { update: function update(view, prevState) { var _selection$node; var currentState = (0, _state2.getPluginState)(view.state); var oldState = (0, _state2.getPluginState)(prevState); var state = view.state, dispatch = view.dispatch; var selection = state.selection, tr = state.tr, schema = state.schema; var isBlockCardSelected = selection instanceof _state.NodeSelection && ((_selection$node = selection.node) === null || _selection$node === void 0 ? void 0 : _selection$node.type) === schema.nodes.blockCard; if (isBlockCardSelected) { var _findDomRefAtPos, _node$attrs; // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting var datasourceTableRef = // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting (_findDomRefAtPos = (0, _utils.findDomRefAtPos)(selection.from, domAtPos)) === null || _findDomRefAtPos === void 0 ? void 0 : _findDomRefAtPos.querySelector(".".concat(_styles.DATASOURCE_INNER_CONTAINER_CLASSNAME)); var node = selection.node; var isDatasource = !!(node !== null && node !== void 0 && (_node$attrs = node.attrs) !== null && _node$attrs !== void 0 && _node$attrs.datasource); var shouldUpdateTableRef = datasourceTableRef && (currentState === null || currentState === void 0 ? void 0 : currentState.datasourceTableRef) !== datasourceTableRef; if (isDatasource && shouldUpdateTableRef) { // since we use the plugin state, which is a shared state, we need to update the datasourceTableRef, layout on each selection var layout = (0, _utils2.isDatasourceTableLayout)(node.attrs.layout) ? node.attrs.layout : _linkingCommon.DATASOURCE_DEFAULT_LAYOUT; var isNested = selection.$anchor.depth > 0; // we want to disable resize button when datasource table is nested by not setting then datasourceTableRef on selection if (!isNested) { // we use cardAction to set the same meta, hence, we will need to combine both layout+datasourceTableRef in one transaction dispatch((0, _actions.setCardLayoutAndDatasourceTableRef)({ datasourceTableRef: datasourceTableRef, layout: layout })(tr)); } } } else { if (currentState !== null && currentState !== void 0 && currentState.datasourceTableRef) { dispatch((0, _actions.setDatasourceTableRef)(undefined)(tr)); } } if (currentState && currentState.provider) { // Find requests in this state that weren't in the old one. var newRequests = (0, _state2.getNewRequests)(oldState, currentState); // Ask the CardProvider to resolve all new requests. var _provider = currentState.provider; newRequests.forEach(function (request) { /** * Queue each asynchronous resolve request on separate frames. * --- * NB: The promise for each request is queued to take place on separate animation frames. This avoids * the scenario debugged and discovered in EDM-668, wherein the queuing of too many promises in quick succession * leads to the browser's macrotask queue being overwhelmed, locking interactivity of the browser tab. * By using this approach, the browser is free to schedule the resolution of the promises below in between rendering/network/ * other tasks as per common implementations of the JavaScript event loop in browsers. */ var invoke = (0, _rafSchd.default)(function () { var _pluginInjectionApi$a, _pluginInjectionApi$a2, _pluginInjectionApi$a3, _currentState$embedCa; return (0, _resolve.resolveWithProvider)(view, _provider, request, options, pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions, (_pluginInjectionApi$a2 = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a3 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a3 === void 0 || (_pluginInjectionApi$a3 = _pluginInjectionApi$a3.sharedState.currentState()) === null || _pluginInjectionApi$a3 === void 0 ? void 0 : _pluginInjectionApi$a3.createAnalyticsEvent) !== null && _pluginInjectionApi$a2 !== void 0 ? _pluginInjectionApi$a2 : undefined, currentState === null || currentState === void 0 || (_currentState$embedCa = currentState.embedCardTransformers) === null || _currentState$embedCa === void 0 ? void 0 : _currentState$embedCa.embedCardNodeTransformer); }); rafCancellationCallbacks.push(invoke.cancel); invoke(); }); } /** * If there have been any events queued, flush them * so subscribers can now be notified and dispatch * analytics events */ cardPluginEvents === null || cardPluginEvents === void 0 || cardPluginEvents.flush(); }, destroy: function destroy() { // Cancel any outstanding raf callbacks. rafCancellationCallbacks.forEach(function (cancellationCallback) { return cancellationCallback(); }); } }; }, props: _objectSpread({ nodeViews: { inlineCard: (0, _lazyInlineCard.lazyInlineCardView)({ inlineCardViewProducer: inlineCardViewProducer, isPageSSRed: isPageSSRed // no need provider here, it's in the inlineCardViewProducer.extraComponentProps }), blockCard: (0, _lazyBlockCard.lazyBlockCardView)({ pmPluginFactoryParams: pmPluginFactoryParams, actionOptions: actionOptions, pluginInjectionApi: pluginInjectionApi, onClickCallback: onClickCallback, allowDatasource: options.allowDatasource, inlineCardViewProducer: inlineCardViewProducer, isPageSSRed: isPageSSRed, provider: provider, CompetitorPrompt: options.CompetitorPrompt }), embedCard: (0, _lazyEmbedCard.lazyEmbedCardView)({ allowResizing: allowResizing, fullWidthMode: fullWidthMode, pmPluginFactoryParams: pmPluginFactoryParams, pluginInjectionApi: pluginInjectionApi, actionOptions: actionOptions, onClickCallback: options.onClickCallback, isPageSSRed: isPageSSRed, provider: provider, CompetitorPrompt: options.CompetitorPrompt }) } }, enableInlineUpgradeFeatures && { handleKeyDown: function handleKeyDown(view) { handleAwarenessOverlay(view); return false; }, handleClick: function handleClick(view) { handleAwarenessOverlay(view); return false; } }), key: _pluginKey.pluginKey }); }; };