UNPKG

@atlaskit/editor-plugin-find-replace

Version:

find replace plugin for @atlaskit/editor-core

304 lines (300 loc) 13.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.toggleMatchCase = exports.replaceAll = exports.replace = exports.removeDecorations = exports.findPrevious = exports.findNext = exports.find = exports.cancelSearch = exports.blur = exports.addDecorations = exports.activate = void 0; var _state = require("@atlaskit/editor-prosemirror/state"); var _view = require("@atlaskit/editor-prosemirror/view"); var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals"); var _actions = require("./actions"); var _pluginFactory = require("./plugin-factory"); var _utils = require("./utils"); var _batchDecorations = _interopRequireDefault(require("./utils/batch-decorations")); var _commands = require("./utils/commands"); var activate = exports.activate = function activate() { return (0, _pluginFactory.createCommand)(function (state) { var selection = state.selection; var findText; var matches; var index; // if user has selected text and hit cmd-f, set that as the keyword if (selection instanceof _state.TextSelection && !selection.empty) { findText = (0, _utils.getSelectedText)(selection); var _getPluginState = (0, _pluginFactory.getPluginState)(state), shouldMatchCase = _getPluginState.shouldMatchCase, getIntl = _getPluginState.getIntl, api = _getPluginState.api; matches = (0, _utils.findMatches)({ content: state.doc, searchText: findText, shouldMatchCase: shouldMatchCase, getIntl: getIntl, api: api }); index = (0, _expValEquals.expValEquals)('platform_editor_find_and_replace_improvements', 'isEnabled', true) ? (0, _utils.findClosestMatch)(selection.from, matches) : (0, _utils.findSearchIndex)(selection.from, matches); } return { type: _actions.FindReplaceActionTypes.ACTIVATE, findText: findText, matches: matches, index: index }; }); }; var find = exports.find = function find(editorView, containerElement, keyword) { return (0, _commands.withScrollIntoView)((0, _pluginFactory.createCommand)(function (state) { var selection = state.selection; var _getPluginState2 = (0, _pluginFactory.getPluginState)(state), shouldMatchCase = _getPluginState2.shouldMatchCase, getIntl = _getPluginState2.getIntl, api = _getPluginState2.api; var matches = keyword !== undefined ? (0, _utils.findMatches)({ content: state.doc, searchText: keyword, shouldMatchCase: shouldMatchCase, getIntl: getIntl, api: api }) : []; var index = (0, _expValEquals.expValEquals)('platform_editor_find_and_replace_improvements', 'isEnabled', true) ? (0, _utils.findClosestMatch)(selection.from, matches) : (0, _utils.findSearchIndex)(selection.from, matches); // we can't just apply all the decorations to highlight the search results at once // as if there are a lot ProseMirror cries :'( _batchDecorations.default.applyAllSearchDecorations(editorView, containerElement, function (decorations) { return addDecorations(decorations)(editorView.state, editorView.dispatch); }, function (decorations) { return removeDecorations(decorations)(editorView.state, editorView.dispatch); }); return { type: _actions.FindReplaceActionTypes.FIND, findText: keyword || '', matches: matches, index: index }; }, function (tr, state) { var selection = state.selection; var _getPluginState3 = (0, _pluginFactory.getPluginState)(state), shouldMatchCase = _getPluginState3.shouldMatchCase, getIntl = _getPluginState3.getIntl, api = _getPluginState3.api; var matches = keyword !== undefined ? (0, _utils.findMatches)({ content: state.doc, searchText: keyword, shouldMatchCase: shouldMatchCase, getIntl: getIntl, api: api }) : []; if (matches.length > 0) { var _api$expand; var index = (0, _expValEquals.expValEquals)('platform_editor_find_and_replace_improvements', 'isEnabled', true) ? (0, _utils.findClosestMatch)(selection.from, matches) : (0, _utils.findSearchIndex)(selection.from, matches); var newSelection = (0, _utils.getSelectionForMatch)(tr.selection, tr.doc, index, matches); api === null || api === void 0 || (_api$expand = api.expand) === null || _api$expand === void 0 || _api$expand.commands.toggleExpandWithMatch(newSelection)({ tr: tr }); return tr.setSelection(newSelection); } return tr; })); }; var findNext = exports.findNext = function findNext(editorView) { return (0, _commands.withScrollIntoView)((0, _pluginFactory.createCommand)(function (state) { return findInDirection(state, 'next'); }, function (tr, state) { var _api$expand2; var _getPluginState4 = (0, _pluginFactory.getPluginState)(state), matches = _getPluginState4.matches, index = _getPluginState4.index, api = _getPluginState4.api; // can't use index from plugin state because if the cursor has moved, it will still be the // OLD index (the find next operation should look for the first match forward starting // from the current cursor position) var searchIndex = (0, _utils.findSearchIndex)(state.selection.from, matches); if (searchIndex === index) { // cursor has not moved, so we just want to find the next in matches array searchIndex = (0, _utils.nextIndex)(searchIndex, matches.length); } var newSelection = (0, _utils.getSelectionForMatch)(tr.selection, tr.doc, searchIndex, matches); api === null || api === void 0 || (_api$expand2 = api.expand) === null || _api$expand2 === void 0 || _api$expand2.commands.toggleExpandWithMatch(newSelection)({ tr: tr }); return tr.setSelection(newSelection); })); }; var findPrevious = exports.findPrevious = function findPrevious(editorView) { return (0, _commands.withScrollIntoView)((0, _pluginFactory.createCommand)(function (state) { return findInDirection(state, 'previous'); }, function (tr, state) { var _api$expand3; var _getPluginState5 = (0, _pluginFactory.getPluginState)(state), matches = _getPluginState5.matches, api = _getPluginState5.api; // can't use index from plugin state because if the cursor has moved, it will still be the // OLD index (the find prev operation should look for the first match backward starting // from the current cursor position) var searchIndex = (0, _utils.findSearchIndex)(state.selection.from, matches, true); var newSelection = (0, _utils.getSelectionForMatch)(tr.selection, tr.doc, searchIndex, matches); api === null || api === void 0 || (_api$expand3 = api.expand) === null || _api$expand3 === void 0 || _api$expand3.commands.toggleExpandWithMatch(newSelection)({ tr: tr }); return tr.setSelection(newSelection); })); }; var findInDirection = function findInDirection(state, dir) { var pluginState = (0, _pluginFactory.getPluginState)(state); var matches = pluginState.matches, findText = pluginState.findText; var decorationSet = pluginState.decorationSet, index = pluginState.index; if (findText) { var searchIndex = (0, _utils.findSearchIndex)(state.selection.from, matches, dir === 'previous'); // compare index from plugin state and index of first match forward from cursor position if (index === searchIndex) { // normal case, cycling through matches index = dir === 'next' ? (0, _utils.nextIndex)(index, matches.length) : (0, _utils.prevIndex)(index, matches.length); } else { // cursor has moved index = searchIndex; } decorationSet = updateSelectedHighlight(state, index); } return { type: dir === 'next' ? _actions.FindReplaceActionTypes.FIND_NEXT : _actions.FindReplaceActionTypes.FIND_PREVIOUS, index: index, decorationSet: decorationSet }; }; var replace = exports.replace = function replace(replaceText) { return (0, _commands.withScrollIntoView)((0, _pluginFactory.createCommand)(function (state) { var pluginState = (0, _pluginFactory.getPluginState)(state); var findText = pluginState.findText, matches = pluginState.matches; var decorationSet = pluginState.decorationSet, index = pluginState.index; decorationSet = updateSelectedHighlight(state, (0, _utils.nextIndex)(index, matches.length)); if (replaceText.toLowerCase().indexOf(findText.toLowerCase()) === -1) { decorationSet = (0, _utils.removeMatchesFromSet)(decorationSet, [matches[index]], state.doc); matches.splice(index, 1); if (index > matches.length - 1) { index = 0; } } else { index = (0, _utils.nextIndex)(index, matches.length); } return { type: _actions.FindReplaceActionTypes.REPLACE, replaceText: replaceText, decorationSet: decorationSet, matches: matches, index: index }; }, function (tr, state) { var _getPluginState6 = (0, _pluginFactory.getPluginState)(state), matches = _getPluginState6.matches, index = _getPluginState6.index, findText = _getPluginState6.findText; if (matches[index]) { if (!matches[index].canReplace && (0, _expValEquals.expValEquals)('platform_editor_find_and_replace_improvements', 'isEnabled', true)) { return tr; } var _matches$index = matches[index], start = _matches$index.start, end = _matches$index.end; var newIndex = (0, _utils.nextIndex)(index, matches.length); tr.insertText(replaceText, start, end).setSelection((0, _utils.getSelectionForMatch)(tr.selection, tr.doc, newIndex, matches, newIndex === 0 ? 0 : replaceText.length - findText.length)); } return tr; })); }; var replaceAll = exports.replaceAll = function replaceAll(replaceText) { return (0, _pluginFactory.createCommand)({ type: _actions.FindReplaceActionTypes.REPLACE_ALL, replaceText: replaceText, decorationSet: _view.DecorationSet.empty, matches: [], index: 0 }, function (tr, state) { var pluginState = (0, _pluginFactory.getPluginState)(state); pluginState.matches.forEach(function (match) { if (!match.canReplace && (0, _expValEquals.expValEquals)('platform_editor_find_and_replace_improvements', 'isEnabled', true)) { return tr; } tr.insertText(replaceText, tr.mapping.map(match.start), tr.mapping.map(match.end)); }); tr.setMeta('scrollIntoView', false); return tr; }); }; var addDecorations = exports.addDecorations = function addDecorations(decorations) { return (0, _pluginFactory.createCommand)(function (state) { var _getPluginState7 = (0, _pluginFactory.getPluginState)(state), decorationSet = _getPluginState7.decorationSet; return { type: _actions.FindReplaceActionTypes.UPDATE_DECORATIONS, decorationSet: decorationSet.add(state.doc, decorations) }; }); }; var removeDecorations = exports.removeDecorations = function removeDecorations(decorations) { return (0, _pluginFactory.createCommand)(function (state) { var _getPluginState8 = (0, _pluginFactory.getPluginState)(state), decorationSet = _getPluginState8.decorationSet; return { type: _actions.FindReplaceActionTypes.UPDATE_DECORATIONS, decorationSet: (0, _utils.removeDecorationsFromSet)(decorationSet, decorations, state.doc) }; }); }; var cancelSearch = exports.cancelSearch = function cancelSearch() { return (0, _pluginFactory.createCommand)(function () { _batchDecorations.default.stop(); return { type: _actions.FindReplaceActionTypes.CANCEL }; }); }; var blur = exports.blur = function blur() { return (0, _pluginFactory.createCommand)({ type: _actions.FindReplaceActionTypes.BLUR }); }; var toggleMatchCase = exports.toggleMatchCase = function toggleMatchCase() { return (0, _pluginFactory.createCommand)({ type: _actions.FindReplaceActionTypes.TOGGLE_MATCH_CASE }); }; var updateSelectedHighlight = function updateSelectedHighlight(state, nextSelectedIndex) { var _getPluginState9 = (0, _pluginFactory.getPluginState)(state), index = _getPluginState9.index, matches = _getPluginState9.matches; var _getPluginState0 = (0, _pluginFactory.getPluginState)(state), decorationSet = _getPluginState0.decorationSet; var currentSelectedMatch = matches[index]; var nextSelectedMatch = matches[nextSelectedIndex]; if (index === nextSelectedIndex) { return decorationSet; } var currentSelectedDecoration = (0, _utils.findDecorationFromMatch)(decorationSet, currentSelectedMatch); var nextSelectedDecoration = (0, _utils.findDecorationFromMatch)(decorationSet, nextSelectedMatch); // Update decorations so the current selected match becomes a normal match // and the next selected gets the selected styling var decorationsToRemove = []; if (currentSelectedDecoration) { decorationsToRemove.push(currentSelectedDecoration); } if (nextSelectedDecoration) { decorationsToRemove.push(nextSelectedDecoration); } if (decorationsToRemove.length > 0) { // removeDecorationsFromSet depends on decorations being pre-sorted decorationsToRemove.sort(function (a, b) { return a.from < b.from ? -1 : 1; }); decorationSet = (0, _utils.removeDecorationsFromSet)(decorationSet, decorationsToRemove, state.doc); } if (currentSelectedMatch) { decorationSet = decorationSet.add(state.doc, [(0, _utils.createDecoration)(currentSelectedMatch)]); } if (nextSelectedMatch) { decorationSet = decorationSet.add(state.doc, [(0, _utils.createDecoration)(nextSelectedMatch, true)]); } return decorationSet; };