UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

597 lines (581 loc) • 23.3 kB
/** * DevExtreme (ui/html_editor/modules/mentions.js) * Version: 20.1.7 * Build date: Tue Aug 25 2020 * * Copyright (c) 2012 - 2020 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _renderer = require("../../../core/renderer"); var _renderer2 = _interopRequireDefault(_renderer); var _quill = require("quill"); var _quill2 = _interopRequireDefault(_quill); var _data = require("../../../core/utils/data"); var _type = require("../../../core/utils/type"); var _extend = require("../../../core/utils/extend"); var _dom = require("../../../core/utils/dom"); var _events_engine = require("../../../events/core/events_engine"); var _popup = require("./popup"); var _popup2 = _interopRequireDefault(_popup); var _mention = require("../formats/mention"); var _mention2 = _interopRequireDefault(_mention); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj } } function _typeof(obj) { "@babel/helpers - typeof"; if ("function" === typeof Symbol && "symbol" === typeof Symbol.iterator) { _typeof = function(obj) { return typeof obj } } else { _typeof = function(obj) { return obj && "function" === typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj } } return _typeof(obj) } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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) } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) { _defineProperties(Constructor.prototype, protoProps) } if (staticProps) { _defineProperties(Constructor, staticProps) } return Constructor } function _inherits(subClass, superClass) { if ("function" !== typeof superClass && null !== superClass) { throw new TypeError("Super expression must either be null or a function") } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) { _setPrototypeOf(subClass, superClass) } } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function(o, p) { o.__proto__ = p; return o }; return _setPrototypeOf(o, p) } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function() { var result, Super = _getPrototypeOf(Derived); if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget) } else { result = Super.apply(this, arguments) } return _possibleConstructorReturn(this, result) } } function _possibleConstructorReturn(self, call) { if (call && ("object" === _typeof(call) || "function" === typeof call)) { return call } return _assertThisInitialized(self) } function _assertThisInitialized(self) { if (void 0 === self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called") } return self } function _isNativeReflectConstruct() { if ("undefined" === typeof Reflect || !Reflect.construct) { return false } if (Reflect.construct.sham) { return false } if ("function" === typeof Proxy) { return true } try { Date.prototype.toString.call(Reflect.construct(Date, [], function() {})); return true } catch (e) { return false } } function _get(target, property, receiver) { if ("undefined" !== typeof Reflect && Reflect.get) { _get = Reflect.get } else { _get = function(target, property, receiver) { var base = _superPropBase(target, property); if (!base) { return } var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver) } return desc.value } } return _get(target, property, receiver || target) } function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (null === object) { break } } return object } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function(o) { return o.__proto__ || Object.getPrototypeOf(o) }; return _getPrototypeOf(o) } var MentionModule = {}; if (_quill2.default) { var USER_ACTION = "user"; var SILENT_ACTION = "silent"; var DEFAULT_MARKER = "@"; var KEY_CODES = { ARROW_UP: 38, ARROW_DOWN: 40, ARROW_LEFT: 37, ARROW_RIGHT: 39, ENTER: 13, ESCAPE: 27, SPACE: 32, PAGE_UP: 33, PAGE_DOWN: 34, END: 35, HOME: 36 }; var NAVIGATION_KEYS = [KEY_CODES.ARROW_LEFT, KEY_CODES.ARROW_RIGHT, KEY_CODES.PAGE_UP, KEY_CODES.PAGE_DOWN, KEY_CODES.END, KEY_CODES.HOME]; var ALLOWED_PREFIX_CHARS = [" ", "\n"]; var DISABLED_STATE_CLASS = "dx-state-disabled"; _quill2.default.register({ "formats/mention": _mention2.default }, true); MentionModule = function(_PopupModule) { _inherits(MentionModule, _PopupModule); var _super = _createSuper(MentionModule); _createClass(MentionModule, [{ key: "_getDefaultOptions", value: function() { var baseConfig = _get(_getPrototypeOf(MentionModule.prototype), "_getDefaultOptions", this).call(this); return (0, _extend.extend)(baseConfig, { itemTemplate: "item", valueExpr: "this", displayExpr: "this", template: null, searchExpr: null, searchTimeout: 500, minSearchLength: 0 }) } }]); function MentionModule(quill, options) { var _this; _classCallCheck(this, MentionModule); _this = _super.call(this, quill, options); _this._mentions = {}; _this.editorInstance = options.editorInstance; options.mentions.forEach(function(item) { var marker = item.marker; if (!marker) { item.marker = marker = DEFAULT_MARKER } var template = item.template; if (template) { var preparedTemplate = _this.editorInstance._getTemplate(template); preparedTemplate && _mention2.default.addTemplate(marker, preparedTemplate) } _this._mentions[marker] = (0, _extend.extend)({}, _this._getDefaultOptions(), item) }); _this._attachKeyboardHandlers(); _this.editorInstance.addCleanCallback(_this.clean.bind(_assertThisInitialized(_this))); _this.quill.on("text-change", _this.onTextChange.bind(_assertThisInitialized(_this))); return _this } _createClass(MentionModule, [{ key: "_attachKeyboardHandlers", value: function() { var _this2 = this; this.quill.keyboard.addBinding({ key: KEY_CODES.ARROW_UP }, this._moveToItem.bind(this, "prev")); this.quill.keyboard.addBinding({ key: KEY_CODES.ARROW_DOWN }, this._moveToItem.bind(this, "next")); this.quill.keyboard.addBinding({ key: KEY_CODES.ENTER }, this._selectItemHandler.bind(this)); var enterBindings = this.quill.keyboard.bindings[KEY_CODES.ENTER]; enterBindings.unshift(enterBindings.pop()); this.quill.keyboard.addBinding({ key: KEY_CODES.ESCAPE }, this._escapeKeyHandler.bind(this)); this.quill.keyboard.addBinding({ key: KEY_CODES.SPACE }, this._selectItemHandler.bind(this)); this.quill.keyboard.addBinding({ key: KEY_CODES.ARROW_LEFT, shiftKey: true }, this._ignoreKeyHandler.bind(this)); this.quill.keyboard.addBinding({ key: KEY_CODES.ARROW_RIGHT, shiftKey: true }, this._ignoreKeyHandler.bind(this)); NAVIGATION_KEYS.forEach(function(key) { _this2.quill.keyboard.addBinding({ key: key }, _this2._ignoreKeyHandler.bind(_this2)) }) } }, { key: "_moveToItem", value: function(direction) { var dataSource = this._list.getDataSource(); if (this._isMentionActive && !dataSource.isLoading()) { var $focusedItem = (0, _renderer2.default)(this._list.option("focusedElement")); var defaultItemPosition = "next" === direction ? "first" : "last"; var $nextItem = $focusedItem[direction](); $nextItem = $nextItem.length ? $nextItem : this._activeListItems[defaultItemPosition](); this._list.option("focusedElement", (0, _dom.getPublicElement)($nextItem)); this._list.scrollToItem($nextItem) } return !this._isMentionActive } }, { key: "_ignoreKeyHandler", value: function() { return !this._isMentionActive } }, { key: "_fitIntoRange", value: function(value, start, end) { if (value > end) { return start } if (value < start) { return end } return value } }, { key: "_selectItemHandler", value: function() { if (this._isMentionActive) { this._list.selectItem(this._list.option("focusedElement")) } return !this._isMentionActive } }, { key: "_escapeKeyHandler", value: function() { if (this._isMentionActive) { this._popup.hide() } return !this._isMentionActive } }, { key: "renderList", value: function($container, options) { this.compileGetters(this.options); _get(_getPrototypeOf(MentionModule.prototype), "renderList", this).call(this, $container, options) } }, { key: "compileGetters", value: function(_ref) { var displayExpr = _ref.displayExpr, valueExpr = _ref.valueExpr; this._valueGetter = (0, _data.compileGetter)(displayExpr); this._idGetter = (0, _data.compileGetter)(valueExpr) } }, { key: "_getListConfig", value: function(options) { var _this3 = this; var baseConfig = _get(_getPrototypeOf(MentionModule.prototype), "_getListConfig", this).call(this, options); return (0, _extend.extend)(baseConfig, { itemTemplate: this.options.itemTemplate, onContentReady: function() { if (_this3._hasSearch) { _this3._popup.repaint(); _this3._focusFirstElement(); _this3._hasSearch = false } } }) } }, { key: "insertEmbedContent", value: function() { var markerLength = this._activeMentionConfig.marker.length; var textLength = markerLength + this._searchValue.length; var caretPosition = this.getPosition(); var startIndex = Math.max(0, caretPosition - markerLength); var selectedItem = this._list.option("selectedItem"); var value = { value: this._valueGetter(selectedItem), id: this._idGetter(selectedItem), marker: this._activeMentionConfig.marker }; setTimeout(function() { this.quill.insertText(startIndex, " ", SILENT_ACTION); this.quill.deleteText(startIndex + 1, textLength, SILENT_ACTION); this.quill.insertEmbed(startIndex, "mention", value); this.quill.setSelection(startIndex + 2) }.bind(this)) } }, { key: "_getLastInsertOperation", value: function(ops) { var lastOperation = ops[ops.length - 1]; var isLastOperationInsert = "insert" in lastOperation; if (isLastOperationInsert) { return lastOperation } var isLastOperationDelete = "delete" in lastOperation; if (isLastOperationDelete && ops.length >= 2) { var penultOperation = ops[ops.length - 2]; var isPenultOperationInsert = "insert" in penultOperation; var isSelectionReplacing = isLastOperationDelete && isPenultOperationInsert; if (isSelectionReplacing) { return penultOperation } } return null } }, { key: "onTextChange", value: function(newDelta, oldDelta, source) { if (source === USER_ACTION) { var lastOperation = newDelta.ops[newDelta.ops.length - 1]; if (this._isMentionActive && this._isPopupVisible) { this._processSearchValue(lastOperation) && this._filterList(this._searchValue) } else { var ops = newDelta.ops; var lastInsertOperation = this._getLastInsertOperation(ops); if (lastInsertOperation) { this.checkMentionRequest(lastInsertOperation, ops) } } } } }, { key: "_processSearchValue", value: function(operation) { var isInsertOperation = "insert" in operation; if (isInsertOperation) { this._searchValue += operation.insert } else { if (!this._searchValue.length || operation.delete > 1) { this._popup.hide(); return false } else { this._searchValue = this._searchValue.slice(0, -1) } } return true } }, { key: "checkMentionRequest", value: function(_ref2, ops) { var insert = _ref2.insert; var caret = this.quill.getSelection(); if (!insert || !(0, _type.isString)(insert) || !caret || this._isMarkerPartOfText(ops[0].retain)) { return } this._activeMentionConfig = this._mentions[insert]; if (this._activeMentionConfig) { this._updateList(this._activeMentionConfig); this.savePosition(caret.index); this._popup.option("position", this._popupPosition); this._searchValue = ""; this._popup.show() } } }, { key: "_isMarkerPartOfText", value: function(retain) { if (!retain || ALLOWED_PREFIX_CHARS.indexOf(this._getCharByIndex(retain - 1)) !== -1) { return false } return true } }, { key: "_getCharByIndex", value: function(index) { return this.quill.getContents(index, 1).ops[0].insert } }, { key: "_updateList", value: function(_ref3) { var dataSource = _ref3.dataSource, displayExpr = _ref3.displayExpr, valueExpr = _ref3.valueExpr, itemTemplate = _ref3.itemTemplate, searchExpr = _ref3.searchExpr; this.compileGetters({ displayExpr: displayExpr, valueExpr: valueExpr }); this._list.unselectAll(); this._list.option({ dataSource: dataSource, displayExpr: displayExpr, itemTemplate: itemTemplate, searchExpr: searchExpr }) } }, { key: "_filterList", value: function(searchValue) { var _this4 = this; if (!this._isMinSearchLengthExceeded(searchValue)) { this._resetFilter(); return } var searchTimeout = this._activeMentionConfig.searchTimeout; if (searchTimeout) { clearTimeout(this._searchTimer); this._searchTimer = setTimeout(function() { _this4._search(searchValue) }, searchTimeout) } else { this._search(searchValue) } } }, { key: "_isMinSearchLengthExceeded", value: function(searchValue) { return searchValue.length >= this._activeMentionConfig.minSearchLength } }, { key: "_resetFilter", value: function() { clearTimeout(this._searchTimer); this._search(null) } }, { key: "_search", value: function(searchValue) { this._hasSearch = true; this._list.option("searchValue", searchValue) } }, { key: "_focusFirstElement", value: function() { if (!this._list) { return } var $firstItem = this._activeListItems.first(); this._list.option("focusedElement", (0, _dom.getPublicElement)($firstItem)); this._list.scrollToItem($firstItem) } }, { key: "_getPopupConfig", value: function() { var _this5 = this; return (0, _extend.extend)(_get(_getPrototypeOf(MentionModule.prototype), "_getPopupConfig", this).call(this), { closeOnTargetScroll: false, onShown: function() { _this5._isMentionActive = true; _this5._hasSearch = false; _this5._focusFirstElement() }, onHidden: function() { _this5._list.unselectAll(); _this5._list.option("focusedElement", null); _this5._isMentionActive = false; _this5._search(null) }, focusStateEnabled: false }) } }, { key: "clean", value: function() { var _this6 = this; Object.keys(this._mentions).forEach(function(marker) { if (_this6._mentions[marker].template) { _mention2.default.removeTemplate(marker) } }) } }, { key: "_isPopupVisible", get: function() { var _this$_popup; return null === (_this$_popup = this._popup) || void 0 === _this$_popup ? void 0 : _this$_popup.option("visible") } }, { key: "_popupPosition", get: function() { var position = this.getPosition(); var _this$quill$getBounds = this.quill.getBounds(position ? position - 1 : position), mentionLeft = _this$quill$getBounds.left, mentionTop = _this$quill$getBounds.top, mentionHeight = _this$quill$getBounds.height; var _$$offset = (0, _renderer2.default)(this.quill.root).offset(), leftOffset = _$$offset.left, topOffset = _$$offset.top; var positionEvent = (0, _events_engine.Event)("positionEvent", { pageX: leftOffset + mentionLeft, pageY: topOffset + mentionTop }); return { of: positionEvent, offset: { v: mentionHeight }, my: "top left", at: "top left", collision: { y: "flip", x: "flipfit" } } } }, { key: "_activeListItems", get: function() { return this._list.itemElements().filter(":not(.".concat(DISABLED_STATE_CLASS, ")")) } }]); return MentionModule }(_popup2.default) } exports.default = MentionModule;