UNPKG

braft-extensions

Version:

Extensions for Braft Editor

1,387 lines (1,127 loc) 80.6 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("react"), require("draft-js"), require("immutable")); else if(typeof define === 'function' && define.amd) define(["react", "draft-js", "immutable"], factory); else { var a = typeof exports === 'object' ? factory(require("react"), require("draft-js"), require("immutable")) : factory(root["react"], root["draft-js"], root["immutable"]); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } })(window, function(__WEBPACK_EXTERNAL_MODULE__1__, __WEBPACK_EXTERNAL_MODULE__3__, __WEBPACK_EXTERNAL_MODULE__4__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = "/"; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 52); /******/ }) /************************************************************************/ /******/ ([ /* 0 */, /* 1 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__1__; /***/ }), /* 2 */ /***/ (function(module, exports) { function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } module.exports = _defineProperty; /***/ }), /* 3 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__3__; /***/ }), /* 4 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__4__; /***/ }), /* 5 */ /***/ (function(module, exports, __webpack_require__) { var defineProperty = __webpack_require__(2); function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? Object(arguments[i]) : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { defineProperty(target, key, source[key]); }); } return target; } module.exports = _objectSpread; /***/ }), /* 6 */, /* 7 */, /* 8 */, /* 9 */, /* 10 */, /* 11 */, /* 12 */, /* 13 */, /* 14 */, /* 15 */ /***/ (function(module, exports, __webpack_require__) { var objectWithoutPropertiesLoose = __webpack_require__(22); function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } module.exports = _objectWithoutProperties; /***/ }), /* 16 */ /***/ (function(module, exports, __webpack_require__) { var arrayWithoutHoles = __webpack_require__(26); var iterableToArray = __webpack_require__(27); var nonIterableSpread = __webpack_require__(28); function _toConsumableArray(arr) { return arrayWithoutHoles(arr) || iterableToArray(arr) || nonIterableSpread(); } module.exports = _toConsumableArray; /***/ }), /* 17 */, /* 18 */, /* 19 */ /***/ (function(module, exports) { var g; // This works in non-strict mode g = (function() { return this; })(); try { // This works if eval is allowed (see CSP) g = g || new Function("return this")(); } catch (e) { // This works if the window reference is available if (typeof window === "object") g = window; } // g can still be undefined, but nothing to do about it... // We return undefined, instead of nothing here, so it's // easier to handle this case. if(!global) { ...} module.exports = g; /***/ }), /* 20 */, /* 21 */, /* 22 */ /***/ (function(module, exports) { function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } module.exports = _objectWithoutPropertiesLoose; /***/ }), /* 23 */, /* 24 */, /* 25 */, /* 26 */ /***/ (function(module, exports) { function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } module.exports = _arrayWithoutHoles; /***/ }), /* 27 */ /***/ (function(module, exports) { function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } module.exports = _iterableToArray; /***/ }), /* 28 */ /***/ (function(module, exports) { function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } module.exports = _nonIterableSpread; /***/ }), /* 29 */ /***/ (function(module, exports, __webpack_require__) { var root = __webpack_require__(59); /** Built-in value references. */ var Symbol = root.Symbol; module.exports = Symbol; /***/ }), /* 30 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.defaultSuggestionsFilter = exports.defaultTheme = exports.MentionSuggestions = undefined; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; // eslint-disable-line import/no-named-as-default var _MentionSuggestions = __webpack_require__(54); Object.defineProperty(exports, 'MentionSuggestions', { enumerable: true, get: function get() { return _interopRequireDefault(_MentionSuggestions).default; } }); var _react = __webpack_require__(1); var _react2 = _interopRequireDefault(_react); var _immutable = __webpack_require__(4); var _Mention = __webpack_require__(74); var _Mention2 = _interopRequireDefault(_Mention); var _MentionSuggestions2 = _interopRequireDefault(_MentionSuggestions); var _MentionSuggestionsPortal = __webpack_require__(76); var _MentionSuggestionsPortal2 = _interopRequireDefault(_MentionSuggestionsPortal); var _defaultRegExp = __webpack_require__(77); var _defaultRegExp2 = _interopRequireDefault(_defaultRegExp); var _mentionStrategy = __webpack_require__(78); var _mentionStrategy2 = _interopRequireDefault(_mentionStrategy); var _mentionSuggestionsStrategy = __webpack_require__(79); var _mentionSuggestionsStrategy2 = _interopRequireDefault(_mentionSuggestionsStrategy); var _mentionStyles = { "mention": "draftJsMentionPlugin__mention__29BEd" }; var _mentionStyles2 = _interopRequireDefault(_mentionStyles); var _mentionSuggestionsStyles = { "mentionSuggestions": "draftJsMentionPlugin__mentionSuggestions__2DWjA" }; var _mentionSuggestionsStyles2 = _interopRequireDefault(_mentionSuggestionsStyles); var _mentionSuggestionsEntryStyles = { "mentionSuggestionsEntry": "draftJsMentionPlugin__mentionSuggestionsEntry__3mSwm", "mentionSuggestionsEntryFocused": "draftJsMentionPlugin__mentionSuggestionsEntryFocused__3LcTd draftJsMentionPlugin__mentionSuggestionsEntry__3mSwm", "mentionSuggestionsEntryText": "draftJsMentionPlugin__mentionSuggestionsEntryText__3Jobq", "mentionSuggestionsEntryAvatar": "draftJsMentionPlugin__mentionSuggestionsEntryAvatar__1xgA9" }; var _mentionSuggestionsEntryStyles2 = _interopRequireDefault(_mentionSuggestionsEntryStyles); var _defaultSuggestionsFilter = __webpack_require__(80); var _defaultSuggestionsFilter2 = _interopRequireDefault(_defaultSuggestionsFilter); var _positionSuggestions = __webpack_require__(81); var _positionSuggestions2 = _interopRequireDefault(_positionSuggestions); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var defaultTheme = exports.defaultTheme = { // CSS class for mention text mention: _mentionStyles2.default.mention, // CSS class for suggestions component mentionSuggestions: _mentionSuggestionsStyles2.default.mentionSuggestions, // CSS classes for an entry in the suggestions component mentionSuggestionsEntry: _mentionSuggestionsEntryStyles2.default.mentionSuggestionsEntry, mentionSuggestionsEntryFocused: _mentionSuggestionsEntryStyles2.default.mentionSuggestionsEntryFocused, mentionSuggestionsEntryText: _mentionSuggestionsEntryStyles2.default.mentionSuggestionsEntryText, mentionSuggestionsEntryAvatar: _mentionSuggestionsEntryStyles2.default.mentionSuggestionsEntryAvatar }; exports.default = function () { var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var callbacks = { keyBindingFn: undefined, handleKeyCommand: undefined, handleReturn: undefined, onChange: undefined }; var ariaProps = { ariaHasPopup: 'false', ariaExpanded: false, ariaOwneeID: undefined, ariaActiveDescendantID: undefined }; var searches = (0, _immutable.Map)(); var escapedSearch = void 0; var clientRectFunctions = (0, _immutable.Map)(); var isOpened = void 0; var store = { getEditorState: undefined, setEditorState: undefined, getPortalClientRect: function getPortalClientRect(offsetKey) { return clientRectFunctions.get(offsetKey)(); }, getAllSearches: function getAllSearches() { return searches; }, isEscaped: function isEscaped(offsetKey) { return escapedSearch === offsetKey; }, escapeSearch: function escapeSearch(offsetKey) { escapedSearch = offsetKey; }, resetEscapedSearch: function resetEscapedSearch() { escapedSearch = undefined; }, register: function register(offsetKey) { searches = searches.set(offsetKey, offsetKey); }, updatePortalClientRect: function updatePortalClientRect(offsetKey, func) { clientRectFunctions = clientRectFunctions.set(offsetKey, func); }, unregister: function unregister(offsetKey) { searches = searches.delete(offsetKey); clientRectFunctions = clientRectFunctions.delete(offsetKey); }, getIsOpened: function getIsOpened() { return isOpened; }, setIsOpened: function setIsOpened(nextIsOpened) { isOpened = nextIsOpened; } }; // Styles are overwritten instead of merged as merging causes a lot of confusion. // // Why? Because when merging a developer needs to know all of the underlying // styles which needs a deep dive into the code. Merging also makes it prone to // errors when upgrading as basically every styling change would become a major // breaking change. 1px of an increased padding can break a whole layout. var _config$mentionPrefix = config.mentionPrefix, mentionPrefix = _config$mentionPrefix === undefined ? '' : _config$mentionPrefix, _config$theme = config.theme, theme = _config$theme === undefined ? defaultTheme : _config$theme, _config$positionSugge = config.positionSuggestions, positionSuggestions = _config$positionSugge === undefined ? _positionSuggestions2.default : _config$positionSugge, mentionComponent = config.mentionComponent, _config$mentionSugges = config.mentionSuggestionsComponent, MentionSuggestionsComponent = _config$mentionSugges === undefined ? _MentionSuggestions2.default : _config$mentionSugges, _config$entityMutabil = config.entityMutability, entityMutability = _config$entityMutabil === undefined ? 'SEGMENTED' : _config$entityMutabil, _config$mentionTrigge = config.mentionTrigger, mentionTrigger = _config$mentionTrigge === undefined ? '@' : _config$mentionTrigge, _config$mentionRegExp = config.mentionRegExp, mentionRegExp = _config$mentionRegExp === undefined ? _defaultRegExp2.default : _config$mentionRegExp, _config$supportWhites = config.supportWhitespace, supportWhitespace = _config$supportWhites === undefined ? false : _config$supportWhites; var mentionSearchProps = { ariaProps: ariaProps, callbacks: callbacks, theme: theme, store: store, entityMutability: entityMutability, positionSuggestions: positionSuggestions, mentionTrigger: mentionTrigger, mentionPrefix: mentionPrefix }; var DecoratedMentionSuggestionsComponent = function DecoratedMentionSuggestionsComponent(props) { return _react2.default.createElement(MentionSuggestionsComponent, _extends({}, props, mentionSearchProps)); }; var DecoratedMention = function DecoratedMention(props) { return _react2.default.createElement(_Mention2.default, _extends({}, props, { theme: theme, mentionComponent: mentionComponent })); }; var DecoratedMentionSuggestionsPortal = function DecoratedMentionSuggestionsPortal(props) { return _react2.default.createElement(_MentionSuggestionsPortal2.default, _extends({}, props, { store: store })); }; return { MentionSuggestions: DecoratedMentionSuggestionsComponent, decorators: [{ strategy: (0, _mentionStrategy2.default)(mentionTrigger), component: DecoratedMention }, { strategy: (0, _mentionSuggestionsStrategy2.default)(mentionTrigger, supportWhitespace, mentionRegExp), component: DecoratedMentionSuggestionsPortal }], getAccessibilityProps: function getAccessibilityProps() { return { role: 'combobox', ariaAutoComplete: 'list', ariaHasPopup: ariaProps.ariaHasPopup, ariaExpanded: ariaProps.ariaExpanded, ariaActiveDescendantID: ariaProps.ariaActiveDescendantID, ariaOwneeID: ariaProps.ariaOwneeID }; }, initialize: function initialize(_ref) { var getEditorState = _ref.getEditorState, setEditorState = _ref.setEditorState; store.getEditorState = getEditorState; store.setEditorState = setEditorState; }, keyBindingFn: function keyBindingFn(keyboardEvent) { return callbacks.keyBindingFn && callbacks.keyBindingFn(keyboardEvent); }, handleReturn: function handleReturn(keyboardEvent) { return callbacks.handleReturn && callbacks.handleReturn(keyboardEvent); }, onChange: function onChange(editorState) { if (callbacks.onChange) return callbacks.onChange(editorState); return editorState; } }; }; var defaultSuggestionsFilter = exports.defaultSuggestionsFilter = _defaultSuggestionsFilter2.default; /***/ }), /* 31 */, /* 32 */ /***/ (function(module, exports, __webpack_require__) { /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ if (false) { var throwOnDirectAccess, isValidElement, REACT_ELEMENT_TYPE; } else { // By explicitly using `prop-types` you are opting into new production behavior. // http://fb.me/prop-types-in-prod module.exports = __webpack_require__(55)(); } /***/ }), /* 33 */ /***/ (function(module, exports, __webpack_require__) { var toString = __webpack_require__(57); /** * Used to match `RegExp` * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). */ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, reHasRegExpChar = RegExp(reRegExpChar.source); /** * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. * * @static * @memberOf _ * @since 3.0.0 * @category String * @param {string} [string=''] The string to escape. * @returns {string} Returns the escaped string. * @example * * _.escapeRegExp('[lodash](https://lodash.com/)'); * // => '\[lodash\]\(https://lodash\.com/\)' */ function escapeRegExp(string) { string = toString(string); return (string && reHasRegExpChar.test(string)) ? string.replace(reRegExpChar, '\\$&') : string; } module.exports = escapeRegExp; /***/ }), /* 34 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _getSearchTextAt = __webpack_require__(70); var _getSearchTextAt2 = _interopRequireDefault(_getSearchTextAt); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } exports.default = function (editorState, selection, trigger) { var anchorKey = selection.getAnchorKey(); var anchorOffset = selection.getAnchorOffset(); var currentContent = editorState.getCurrentContent(); var currentBlock = currentContent.getBlockForKey(anchorKey); var blockText = currentBlock.getText(); return (0, _getSearchTextAt2.default)(blockText, anchorOffset, trigger); }; /***/ }), /* 35 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var getTypeByTrigger = function getTypeByTrigger(trigger) { return trigger === '@' ? 'mention' : trigger + 'mention'; }; exports.default = getTypeByTrigger; /***/ }), /* 36 */, /* 37 */, /* 38 */, /* 39 */, /* 40 */, /* 41 */, /* 42 */, /* 43 */, /* 44 */, /* 45 */, /* 46 */, /* 47 */, /* 48 */, /* 49 */, /* 50 */, /* 51 */, /* 52 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var _babel_runtime_helpers_defineProperty__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); /* harmony import */ var _babel_runtime_helpers_defineProperty__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_defineProperty__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _babel_runtime_helpers_objectSpread__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); /* harmony import */ var _babel_runtime_helpers_objectSpread__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_objectSpread__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _babel_runtime_helpers_toConsumableArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(16); /* harmony import */ var _babel_runtime_helpers_toConsumableArray__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_toConsumableArray__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _babel_runtime_helpers_objectWithoutProperties__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(15); /* harmony import */ var _babel_runtime_helpers_objectWithoutProperties__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_objectWithoutProperties__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var draft_js_mention_plugin_lib_plugin_css__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(53); /* harmony import */ var draft_js_mention_plugin_lib_plugin_css__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(draft_js_mention_plugin_lib_plugin_css__WEBPACK_IMPORTED_MODULE_4__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(1); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_5__); /* harmony import */ var draft_js_mention_plugin__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(30); /* harmony import */ var draft_js_mention_plugin__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(draft_js_mention_plugin__WEBPACK_IMPORTED_MODULE_6__); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "defaultSuggestionsFilter", function() { return draft_js_mention_plugin__WEBPACK_IMPORTED_MODULE_6__["defaultSuggestionsFilter"]; }); /** * 基于 draft-js-mention-plugin 的 mention 扩展 * 除了 includeEditors 和 excludeEditors 外 * 其他属性将会传递给 draft-js-mention-plugin * 参考 https://www.draft-js-plugins.com/plugin/mention */ /* harmony default export */ __webpack_exports__["default"] = (function () { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var includeEditors = options.includeEditors, excludeEditors = options.excludeEditors, mentionPluginOptions = _babel_runtime_helpers_objectWithoutProperties__WEBPACK_IMPORTED_MODULE_3___default()(options, ["includeEditors", "excludeEditors"]); var mentionPlugin = draft_js_mention_plugin__WEBPACK_IMPORTED_MODULE_6___default()(mentionPluginOptions); // MentionSuggestions 是一个 React Component 用来定制 mention 的数据 var MentionSuggestions = mentionPlugin.MentionSuggestions, draftEditorPlugin = _babel_runtime_helpers_objectWithoutProperties__WEBPACK_IMPORTED_MODULE_3___default()(mentionPlugin, ["MentionSuggestions"]); /** * draft-js-plugin 为每个 plugin 的很多地方都注入了 get 和 set * 在 braft-editor 里面 由于 在 useExtension 里面并拿不到 editor 的实例 * 只能在 prop-interception 的时候 有机会拿到 因此先用一个 对象引用起来 再传递 */ var getAndSetState = { getEditorState: function getEditorState() { throw new Error('can\'t use get state'); }, setEditorState: function setEditorState(state) { throw new Error("can't use set state ".concat(state)); } }; return [[{ type: 'prop-interception', interceptor: function interceptor(editorProps, editor) { // hack // 没有地方可以有 init 的时机,属性拦截器这里会把编辑器的实例传过来 // 所以在这里初始化插件 getAndSetState.getEditorState = editor.getValue.bind(editor); getAndSetState.setEditorState = editor.setValue.bind(editor); if (draftEditorPlugin.initialize) { // 这里 mention 插件 只用了 get/setEditor State 所以其他可以不传 draftEditorPlugin.initialize(getAndSetState); } // mention 的 plugin 需要 hack editor 的 onChange // 如果有更好的办法请告知 var hackOnChange = editor.onChange; if (hackOnChange) { editor.onChange = function (editorState, callback) { hackOnChange.call(editor, editorState, callback); if (draftEditorPlugin.onChange) { draftEditorPlugin.onChange(editorState, getAndSetState); } }; } // 应该是 draft-js 和 draft-js-mention-plugin 之间的磨合除了问题 // mention 需要处理 以下几个键盘事件 但是 draft-js 对这几个事件有特殊处理 // 仅仅调用了 props 传递进去的 而不会通过 keyBindingFn 调用 // 所以这里额外处理,并通过 prop-interception 传递给 draftProps // bug 可在 https://stackblitz.com/edit/draft-js-mention?file=index.tsx 使用 DraftEditor 复现 var passSomeKeyEventToKeyBindingFn = function passSomeKeyEventToKeyBindingFn(props) { var handleName = ['onUpArrow', 'onRightArrow', 'onDownArrow', 'onLeftArrow', 'onEscape', 'onTab']; return handleName.reduce(function (acc, name) { var hackHandle = props[name]; var handler = function handler(event) { if (typeof hackHandle === 'function') { hackHandle(event); } draftEditorPlugin.keyBindingFn(event, getAndSetState); }; return _babel_runtime_helpers_objectSpread__WEBPACK_IMPORTED_MODULE_1___default()({}, acc, _babel_runtime_helpers_defineProperty__WEBPACK_IMPORTED_MODULE_0___default()({}, name, handler)); }, {}); }; return _babel_runtime_helpers_objectSpread__WEBPACK_IMPORTED_MODULE_1___default()({}, editorProps, { draftProps: _babel_runtime_helpers_objectSpread__WEBPACK_IMPORTED_MODULE_1___default()({}, editorProps.draftProps, draftEditorPlugin.getAccessibilityProps(), passSomeKeyEventToKeyBindingFn(editorProps.draftProps || {})), keyBindingFn: function keyBindingFn(event) { // 先处理前面插件的 keyBindingFn // 暂时没有发现 mention 必须优先处理的必要性 var originHandler = editorProps.keyBindingFn; var ret = null; if (typeof originHandler === 'function') { ret = originHandler(event); } return ret != null ? ret : draftEditorPlugin.keyBindingFn(event, getAndSetState); }, handleReturn: function handleReturn(event, editorState, editor) { var originHandler = editorProps.handleReturn; // 这里 mention 要优于其他的插件处理 回车 事件 // 因为在 mention 弹出 suggestion 时 有「确认选择」的功能 if (draftEditorPlugin.handleReturn(event, editorState, getAndSetState) === 'handled') { return 'handled'; } return originHandler ? originHandler(event, editorState, editor) : 'not-handled'; } }); } }].concat(_babel_runtime_helpers_toConsumableArray__WEBPACK_IMPORTED_MODULE_2___default()((draftEditorPlugin.decorators || []).map(function (decorate) { return { type: 'decorator', includeEditors: includeEditors, excludeEditors: excludeEditors, decorator: _babel_runtime_helpers_objectSpread__WEBPACK_IMPORTED_MODULE_1___default()({}, decorate, { component: function component(props) { // 这里需要注入 getAndSet 是因为平时 draft-js-plugin 里面 对所有的非自定义类型的装饰器进行了注入 // 所以这里也要模仿 // see draft-js-plugins/packages/editor/src/Editor/resolveDecorators.ts return react__WEBPACK_IMPORTED_MODULE_5___default.a.createElement(decorate.component, _babel_runtime_helpers_objectSpread__WEBPACK_IMPORTED_MODULE_1___default()({}, props, getAndSetState)); } }) }; }))), MentionSuggestions]; }); /***/ }), /* 53 */ /***/ (function(module, exports, __webpack_require__) { // extracted by mini-css-extract-plugin /***/ }), /* 54 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MentionSuggestions = undefined; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _react = __webpack_require__(1); var _react2 = _interopRequireDefault(_react); var _propTypes = __webpack_require__(32); var _propTypes2 = _interopRequireDefault(_propTypes); var _draftJs = __webpack_require__(3); var _escapeRegExp = __webpack_require__(33); var _escapeRegExp2 = _interopRequireDefault(_escapeRegExp); var _Entry = __webpack_require__(68); var _Entry2 = _interopRequireDefault(_Entry); var _addMention = __webpack_require__(69); var _addMention2 = _interopRequireDefault(_addMention); var _decodeOffsetKey = __webpack_require__(71); var _decodeOffsetKey2 = _interopRequireDefault(_decodeOffsetKey); var _getSearchText2 = __webpack_require__(34); var _getSearchText3 = _interopRequireDefault(_getSearchText2); var _defaultEntryComponent = __webpack_require__(72); var _defaultEntryComponent2 = _interopRequireDefault(_defaultEntryComponent); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var MentionSuggestions = exports.MentionSuggestions = function (_Component) { _inherits(MentionSuggestions, _Component); function MentionSuggestions() { var _ref; var _temp, _this, _ret; _classCallCheck(this, MentionSuggestions); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = MentionSuggestions.__proto__ || Object.getPrototypeOf(MentionSuggestions)).call.apply(_ref, [this].concat(args))), _this), _this.state = { isActive: false, focusedOptionIndex: 0 }, _this.componentDidUpdate = function (prevProps, prevState) { if (_this.popover) { // In case the list shrinks there should be still an option focused. // Note: this might run multiple times and deduct 1 until the condition is // not fullfilled anymore. var size = _this.props.suggestions.length; if (size > 0 && _this.state.focusedOptionIndex >= size) { _this.setState({ focusedOptionIndex: size - 1 }); } // Note: this is a simple protection for the error when componentDidUpdate // try to get new getPortalClientRect, but the key already was deleted by // previous action. (right now, it only can happened when set the mention // trigger to be multi-characters which not supported anyway!) if (!_this.props.store.getAllSearches().has(_this.activeOffsetKey)) { return; } var decoratorRect = _this.props.store.getPortalClientRect(_this.activeOffsetKey); var newStyles = _this.props.positionSuggestions({ decoratorRect: decoratorRect, prevProps: prevProps, prevState: prevState, props: _this.props, state: _this.state, popover: _this.popover }); Object.keys(newStyles).forEach(function (key) { _this.popover.style[key] = newStyles[key]; }); } }, _this.componentWillUnmount = function () { _this.props.callbacks.onChange = undefined; }, _this.onEditorStateChange = function (editorState) { var searches = _this.props.store.getAllSearches(); // if no search portal is active there is no need to show the popover if (searches.size === 0) { return editorState; } var removeList = function removeList() { _this.props.store.resetEscapedSearch(); _this.closeDropdown(); return editorState; }; // get the current selection var selection = editorState.getSelection(); var anchorKey = selection.getAnchorKey(); var anchorOffset = selection.getAnchorOffset(); // the list should not be visible if a range is selected or the editor has no focus if (!selection.isCollapsed() || !selection.getHasFocus()) return removeList(); // identify the start & end positon of each search-text var offsetDetails = searches.map(function (offsetKey) { return (0, _decodeOffsetKey2.default)(offsetKey); }); // a leave can be empty when it is removed due e.g. using backspace // do not check leaves, use full decorated portal text var leaves = offsetDetails.filter(function (_ref2) { var blockKey = _ref2.blockKey; return blockKey === anchorKey; }).map(function (_ref3) { var blockKey = _ref3.blockKey, decoratorKey = _ref3.decoratorKey; return editorState.getBlockTree(blockKey).getIn([decoratorKey]); }); // if all leaves are undefined the popover should be removed if (leaves.every(function (leave) { return leave === undefined; })) { return removeList(); } // Checks that the cursor is after the @ character but still somewhere in // the word (search term). Setting it to allow the cursor to be left of // the @ causes troubles due selection confusion. var plainText = editorState.getCurrentContent().getPlainText(); var selectionIsInsideWord = leaves.filter(function (leave) { return leave !== undefined; }).map(function (_ref4) { var start = _ref4.start, end = _ref4.end; return start === 0 && anchorOffset === _this.props.mentionTrigger.length && plainText.charAt(anchorOffset) !== _this.props.mentionTrigger && new RegExp(String.raw({ raw: '' + (0, _escapeRegExp2.default)(_this.props.mentionTrigger) }), 'g').test(plainText) && anchorOffset <= end || // @ is the first character anchorOffset > start + _this.props.mentionTrigger.length && anchorOffset <= end; } // @ is in the text or at the end ); if (selectionIsInsideWord.every(function (isInside) { return isInside === false; })) return removeList(); var lastActiveOffsetKey = _this.activeOffsetKey; _this.activeOffsetKey = selectionIsInsideWord.filter(function (value) { return value === true; }).keySeq().first(); _this.onSearchChange(editorState, selection, _this.activeOffsetKey, lastActiveOffsetKey); // make sure the escaped search is reseted in the cursor since the user // already switched to another mention search if (!_this.props.store.isEscaped(_this.activeOffsetKey)) { _this.props.store.resetEscapedSearch(); } // If none of the above triggered to close the window, it's safe to assume // the dropdown should be open. This is useful when a user focuses on another // input field and then comes back: the dropdown will show again. if (!_this.state.isActive && !_this.props.store.isEscaped(_this.activeOffsetKey) && _this.props.suggestions.length > 0) { _this.openDropdown(); } // makes sure the focused index is reseted every time a new selection opens // or the selection was moved to another mention search if (_this.lastSelectionIsInsideWord === undefined || !selectionIsInsideWord.equals(_this.lastSelectionIsInsideWord)) { _this.setState({ focusedOptionIndex: 0 }); } _this.lastSelectionIsInsideWord = selectionIsInsideWord; return editorState; }, _this.onSearchChange = function (editorState, selection, activeOffsetKey, lastActiveOffsetKey) { var _getSearchText = (0, _getSearchText3.default)(editorState, selection, _this.props.mentionTrigger), searchValue = _getSearchText.matchingString; if (_this.lastSearchValue !== searchValue || activeOffsetKey !== lastActiveOffsetKey) { _this.lastSearchValue = searchValue; _this.props.onSearchChange({ value: searchValue }); } }, _this.onDownArrow = function (keyboardEvent) { keyboardEvent.preventDefault(); var newIndex = _this.state.focusedOptionIndex + 1; _this.onMentionFocus(newIndex >= _this.props.suggestions.length ? 0 : newIndex); }, _this.onTab = function (keyboardEvent) { keyboardEvent.preventDefault(); _this.commitSelection(); }, _this.onUpArrow = function (keyboardEvent) { keyboardEvent.preventDefault(); if (_this.props.suggestions.length > 0) { var newIndex = _this.state.focusedOptionIndex - 1; _this.onMentionFocus(newIndex < 0 ? _this.props.suggestions.length - 1 : newIndex); } }, _this.onEscape = function (keyboardEvent) { keyboardEvent.preventDefault(); var activeOffsetKey = _this.lastSelectionIsInsideWord.filter(function (value) { return value === true; }).keySeq().first(); _this.props.store.escapeSearch(activeOffsetKey); _this.closeDropdown(); // to force a re-render of the outer component to change the aria props _this.props.store.setEditorState(_this.props.store.getEditorState()); }, _this.onMentionSelect = function (mention) { // Note: This can happen in case a user typed @xxx (invalid mention) and // then hit Enter. Then the mention will be undefined. if (!mention) { return; } if (_this.props.onAddMention) { _this.props.onAddMention(mention); } _this.closeDropdown(); var newEditorState = (0, _addMention2.default)(_this.props.store.getEditorState(), mention, _this.props.mentionPrefix, _this.props.mentionTrigger, _this.props.entityMutability); _this.props.store.setEditorState(newEditorState); }, _this.onMentionFocus = function (index) { var descendant = 'mention-option-' + _this.key + '-' + index; _this.props.ariaProps.ariaActiveDescendantID = descendant; _this.setState({ focusedOptionIndex: index }); // to force a re-render of the outer component to change the aria props _this.props.store.setEditorState(_this.props.store.getEditorState()); }, _this.commitSelection = function () { if (!_this.props.store.getIsOpened()) { return 'not-handled'; } _this.onMentionSelect(_this.props.suggestions[_this.state.focusedOptionIndex]); return 'handled'; }, _this.openDropdown = function () { // This is a really nasty way of attaching & releasing the key related functions. // It assumes that the keyFunctions object will not loose its reference and // by this we can replace inner parameters spread over different modules. // This better be some registering & unregistering logic. PRs are welcome :) _this.props.callbacks.handleReturn = _this.commitSelection; _this.props.callbacks.keyBindingFn = function (keyboardEvent) { // arrow down if (keyboardEvent.keyCode === 40) { _this.onDownArrow(keyboardEvent); } // arrow up if (keyboardEvent.keyCode === 38) { _this.onUpArrow(keyboardEvent); } // escape if (keyboardEvent.keyCode === 27) { _this.onEscape(keyboardEvent); } // tab if (keyboardEvent.keyCode === 9) { _this.onTab(keyboardEvent); } }; var descendant = 'mention-option-' + _this.key + '-' + _this.state.focusedOptionIndex; _this.props.ariaProps.ariaActiveDescendantID = descendant; _this.props.ariaProps.ariaOwneeID = 'mentions-list-' + _this.key; _this.props.ariaProps.ariaHasPopup = 'true'; _this.props.ariaProps.ariaExpanded = true; _this.setState({ isActive: true }); if (_this.props.onOpen) { _this.props.onOpen(); } }, _this.closeDropdown = function () { // make sure none of these callbacks are triggered _this.props.callbacks.handleReturn = undefined; _this.props.callbacks.keyBindingFn = undefined; _this.props.ariaProps.ariaHasPopup = 'false'; _this.props.ariaProps.ariaExpanded = false; _this.props.ariaProps.ariaActiveDescendantID = undefined; _this.props.ariaProps.ariaOwneeID = undefined; _this.setState({ isActive: false }); if (_this.props.onClose) { _this.props.onClose(); } }, _temp), _possibleConstructorReturn(_this, _ret); } _createClass(MentionSuggestions, [{ key: 'componentWillMount', value: function componentWillMount() { this.key = (0, _draftJs.genKey)(); this.props.callbacks.onChange = this.onEditorStateChange; } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (nextProps.suggestions.length === 0 && this.state.isActive) { this.closeDropdown(); } else if (nextProps.suggestions.length > 0 && nextProps.suggestions !== this.props.suggestions && !this.state.isActive) { this.openDropdown(); } } }, { key: 'render', value: function render() { var _this2 = this; if (!this.state.isActive) { return null; } var _props = this.props, entryComponent = _props.entryComponent, _props$popoverCompone = _props.popoverComponent, popoverComponent = _props$popoverCompone === undefined ? _react2.default.createElement('div', null) : _props$popoverCompone, onClose = _props.onClose, onOpen = _props.onOpen, onAddMention = _props.onAddMention, onSearchChange = _props.onSearchChange, suggestions = _props.suggestions, ariaProps = _props.ariaProps, callbacks = _props.callbacks, _props$theme = _props.theme, theme = _props$theme === undefined ? {} : _props$theme, store = _props.store, entityMutability = _props.entityMutability, positionSuggestions = _props.positionSuggestions, mentionTrigger = _props.mentionTrigger, mentionPrefix = _props.mentionPrefix, elementProps = _objectWithoutProperties(_props, ['entryComponent', 'popoverComponent', 'onClose', 'onOpen', 'onAddMention', 'onSearchChange', 'suggestions', 'ariaProps', 'callbacks', 'theme', 'store', 'entityMutability', 'positionSuggestions', 'mentionTrigger', 'mentionPrefix']); return _react2.default.cloneElement(popoverComponent, _extends({}, elementProps, { className: theme.mentionSuggestions, role: 'listbox', id: 'mentions-list-' + this.key, ref: function ref(element) { _this2.popover = element; } }), this.props.suggestions.map(function (mention, index) { return _react2.default.createElement(_Entry2.default, { key: mention.id != null ? mention.id : mention.name, onMentionSelect: _this2.onMentionSelect, onMentionFocus: _this2.onMentionFocus, isFocused: _this2.state.focusedOptionIndex === index, mention: mention, index: index, id: 'mention-option-' + _this2.key + '-' + index, theme: theme, searchValue: _this2.lastSearchValue, entryComponent: entryComponent || _defaultEntryComponent2.default }); })); } }]); return MentionSuggestions; }(_react.Component); MentionSuggestions.propTypes = { entityMutability: _propTypes2.default.oneOf(['SEGMENTED', 'IMMUTABLE', 'MUTABLE']), entryComponent: _propTypes2.default.func, onAddMention: _propTypes2.default.func, suggestions: _propTypes2.default.array }; exports.default = MentionSuggestions; /***/ }), /* 55 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var ReactPropTypesSecret = __webpack_require__(56); function emptyFunction() {} module.exports = function() { function shim(props, propName, componentName, location, propFullName, secret) { if (secret === ReactPropTypesSecret) { // It is still safe when called from React. return; } var err = new Error( 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + 'Use PropTypes.checkPropTypes() to call them. ' + 'Read more at http://fb.me/use-check-prop-types' ); err.name = 'Invariant Violation'; throw err; }; shim.isRequired = shim; function getShim() { return shim; }; // Important! // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`. var ReactPropTypes = { array: shim, bool: shim, func: shim, number: shim, object: shim, string: shim, symbol: shim, any: shim, arrayOf: getShim, element: shim, instanceOf: getShim, node: shim, objectOf: getShim, oneOf: getShim, oneOfType: getShim, shape: getShim, exact: getShim }; ReactPropTypes.checkPropTypes = emptyFunction; ReactPropTypes.PropTypes = ReactPropTypes; return ReactPropTypes; }; /***/ }), /* 56 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; module.exports = ReactPropTypesSecret; /***/ }), /* 57 */ /***/ (function(module, exports, __webpack_require__) { var baseToString = __webpack_require__(58); /** * Converts `value` to a string. An empty string is returned for `null` * and `undefined` values. The sign of `-0` is preserved. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to convert. * @returns {string} Returns the converted string. * @example * * _.toString(null); * // => '' * * _.toString(-0); * // => '-0' * * _.toString([1, 2, 3]); * // => '1,2,3' */ function toString(value) { return value == null ? '' : baseToString(value); } module.exports = toString; /***/ }), /* 58 */ /***/ (function(module, exports, __webpack_require__) { var Symbol = __webpack_require__(29), arrayMap = __webpack_require__(61), isArray = __webpack_require__(62), isSymbol = __webpack_require__(63); /** Used as references for various `Number` constants. */ var INFINITY = 1 / 0; /** Used to convert symbols to primitives and strings. */ var symbolProto = Symbol ? Symbol.prototype : undefined, symbolToString = symbolProto ? symbolProto.toString : undefined; /** * The base implementation of `_.toString` which doesn't convert nullish * values to empty strings. * * @private * @param {*} value The value to process. * @returns {string} Returns the string. */ function baseToString(value) { // Exit early for strings to avoid a performance hit in some environments. if (typeof value == 'string') {