UNPKG

@atlaskit/editor-core

Version:

A package contains Atlassian editor core functionality

133 lines (123 loc) • 8.28 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.outsideProsemirrorEditorClickHandler = exports.clickAreaClickHandler = exports.checkForModal = void 0; var _collab = require("@atlaskit/editor-common/collab"); var _commands = require("@atlaskit/editor-common/commands"); var _selection = require("@atlaskit/editor-common/selection"); var _utils = require("@atlaskit/editor-common/utils"); var _contentComponentWrapper = require("./ClickAreaBlock/contentComponentWrapper"); // we ignore all of the clicks made inside <div class="ak-editor-content-area" /> (but not clicks on the node itself) var insideContentArea = function insideContentArea(ref) { while (ref) { if (ref.classList && ref.classList.contains('ak-editor-content-area')) { return true; } // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting ref = ref.parentNode; } return false; }; var insideProseMirrorEditableArea = function insideProseMirrorEditableArea(ref) { return Boolean(ref === null || ref === void 0 ? void 0 : ref.closest('.ProseMirror')); }; /** * @see ED-14699 - check if editor is inside a modal to continue to bring cursor to input when * any part of the editor container is clicked * * Handles two cases when a click event is fired: * * 1. if editor (e.g. comment inside of Jira ticket view) is inside modal then ensure focus and cursor is brought to the input * 2. if another modal is open (e.g. delete confirmation modal for confluence table) then ignore clicks as they shouldn't influence editor state */ var checkForModal = exports.checkForModal = function checkForModal(target) { var modalDialog = target === null || target === void 0 ? void 0 : target.closest('[role=dialog]'); if (modalDialog) { // return false if not an editor inside modal, otherwise return true return !!(modalDialog !== null && modalDialog !== void 0 && modalDialog.querySelector('.akEditor')); } // no modal present so we can return true return true; }; var clickAreaClickHandler = exports.clickAreaClickHandler = function clickAreaClickHandler(view, event) { var _view$hasFocus, _target$parentElement, _event$currentTarget, _event$currentTarget2; var isEditorFocused = !!(view !== null && view !== void 0 && (_view$hasFocus = view.hasFocus) !== null && _view$hasFocus !== void 0 && _view$hasFocus.call(view)); if (!(event.target instanceof HTMLElement)) { return; } // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting var target = event.target; var isTargetContentArea = target === null || target === void 0 ? void 0 : target.classList.contains('ak-editor-content-area'); var isTargetChildOfContentArea = insideContentArea((target === null || target === void 0 ? void 0 : target.parentNode) instanceof HTMLElement ? target === null || target === void 0 ? void 0 : target.parentNode : null); var isTargetInsideEditableArea = insideProseMirrorEditableArea(target); // Any click inside ProseMirror should be managed by ProseMirror if (isTargetInsideEditableArea) { return false; } var isEventComingFromContentArea = Boolean(event.currentTarget.querySelector('.ak-editor-content-area')); // @see https://product-fabric.atlassian.net/browse/ED-4287 // click event gets triggered twice on a checkbox (on <label> first and then on <input>) // by the time it gets triggered on input, PM already re-renders nodeView and detaches it from DOM // which doesn't pass the check !contentArea.contains(event.target) var isInputClicked = (target === null || target === void 0 ? void 0 : target.nodeName) === 'INPUT'; // @see ED-5126 var isPopupClicked = !!(0, _utils.closestElement)(target, '[data-editor-popup]'); // Fixes issue when using a textarea for editor title in full page editor doesn't let user focus it. var isTextAreaClicked = (target === null || target === void 0 ? void 0 : target.nodeName) === 'TEXTAREA'; var isBreadcrumbClicked = !!(0, _utils.closestElement)(target, 'nav[aria-label="Breadcrumbs"]'); var selection = window.getSelection(); var isEditorPopupTextSelected = (selection === null || selection === void 0 ? void 0 : selection.type) === 'Range' && // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting (0, _utils.closestElement)(selection === null || selection === void 0 ? void 0 : selection.anchorNode, '[data-editor-popup]'); // For clicks directly on the content component -- they should not be ignored var isContentComponent = target === null || target === void 0 || (_target$parentElement = target.parentElement) === null || _target$parentElement === void 0 ? void 0 : _target$parentElement.closest("[".concat(_contentComponentWrapper.ignoreAttribute, "]")); // This is a super workaround to find when events are coming from Confluence InlineComment modal // We don't own those components, so we can't change them var isEventComingFromInlineCommentPopup = Boolean((0, _utils.closestElement)(event.currentTarget, 'div[offset]')) || Boolean((0, _utils.closestElement)(target, 'div[offset]')); var isAnchorButtonClicked = Boolean((0, _utils.closestElement)(event.currentTarget, 'a')) || Boolean((0, _utils.closestElement)(target, 'a')) || ((_event$currentTarget = event.currentTarget) === null || _event$currentTarget === void 0 ? void 0 : _event$currentTarget.nodeName) === 'A' || (target === null || target === void 0 ? void 0 : target.nodeName) === 'A'; var isButtonClicked = Boolean((0, _utils.closestElement)(event.currentTarget, 'button')) || Boolean((0, _utils.closestElement)(target, 'button')) || ((_event$currentTarget2 = event.currentTarget) === null || _event$currentTarget2 === void 0 ? void 0 : _event$currentTarget2.nodeName) === 'BUTTON' || (target === null || target === void 0 ? void 0 : target.nodeName) === 'BUTTON' || isAnchorButtonClicked; var isTargetInsideContentArea = Boolean(isTargetChildOfContentArea); var isBetweenContentAreaAndEditableContent = isTargetInsideContentArea && !isTargetInsideEditableArea; // Column Picker dropdown in Datasources table var isDatasourcePopupClicked = !!(target !== null && target !== void 0 && target.closest('#column-picker-popup')); var edgeCaseScenario1 = (isBetweenContentAreaAndEditableContent || !isEventComingFromContentArea) && !isEditorFocused; var edgeCaseScenario2 = !isTargetInsideContentArea && isEditorFocused; var edgeCaseScenario3 = isTargetContentArea && !isTargetInsideContentArea && !isEditorFocused; var edgeCaseScenario4 = isEventComingFromContentArea && !isTargetContentArea && !isTargetInsideContentArea && !isEditorFocused; var edgeCases = edgeCaseScenario1 || edgeCaseScenario2 || edgeCaseScenario3 || edgeCaseScenario4; var isClickOutsideEditor = edgeCases && !isDatasourcePopupClicked && !isEventComingFromInlineCommentPopup && !isButtonClicked && !isInputClicked && !isTextAreaClicked && !isPopupClicked && !isBreadcrumbClicked && !isEditorPopupTextSelected && !isContentComponent && checkForModal(target); // click was within editor container and focus should be brought to input if (isClickOutsideEditor && view) { outsideProsemirrorEditorClickHandler(view, event); } }; var outsideProsemirrorEditorClickHandler = exports.outsideProsemirrorEditorClickHandler = function outsideProsemirrorEditorClickHandler(view, event) { var _view$hasFocus2; var dispatch = view.dispatch, dom = view.dom, state = view.state; var tr = state.tr; var isEditorFocused = !!(view !== null && view !== void 0 && (_view$hasFocus2 = view.hasFocus) !== null && _view$hasFocus2 !== void 0 && _view$hasFocus2.call(view)); var isBottomAreaClicked = event.clientY > dom.getBoundingClientRect().bottom; if (isBottomAreaClicked) { tr.setMeta('outsideProsemirrorEditorClicked', true); (0, _commands.addParagraphAtEnd)(tr); } (0, _selection.setSelectionTopLevelBlocks)(tr, event, // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting dom, view.posAtCoords.bind(view), isEditorFocused); (0, _collab.tintDirtyTransaction)(tr); if (!tr.docChanged && !tr.selectionSet) { return; } if (dispatch) { dispatch(tr); } view.focus(); event.preventDefault(); };