@atlaskit/editor-core
Version:
A package contains Atlassian editor core functionality
133 lines (123 loc) • 8.28 kB
JavaScript
"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();
};