mentions.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. /**
  2. * DevExtreme (ui/html_editor/modules/mentions.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. function _typeof(obj) {
  11. "@babel/helpers - typeof";
  12. return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) {
  13. return typeof obj
  14. } : function(obj) {
  15. return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj
  16. }, _typeof(obj)
  17. }
  18. Object.defineProperty(exports, "__esModule", {
  19. value: true
  20. });
  21. var _renderer = require("../../../core/renderer");
  22. var _renderer2 = _interopRequireDefault(_renderer);
  23. var _data = require("../../../core/utils/data");
  24. var _type = require("../../../core/utils/type");
  25. var _extend = require("../../../core/utils/extend");
  26. var _dom = require("../../../core/utils/dom");
  27. var _events = require("../../../events");
  28. var _popup = require("./popup");
  29. var _popup2 = _interopRequireDefault(_popup);
  30. var _mention = require("../formats/mention");
  31. var _mention2 = _interopRequireDefault(_mention);
  32. function _interopRequireDefault(obj) {
  33. return obj && obj.__esModule ? obj : {
  34. "default": obj
  35. }
  36. }
  37. function _classCallCheck(instance, Constructor) {
  38. if (!(instance instanceof Constructor)) {
  39. throw new TypeError("Cannot call a class as a function")
  40. }
  41. }
  42. function _defineProperties(target, props) {
  43. for (var i = 0; i < props.length; i++) {
  44. var descriptor = props[i];
  45. descriptor.enumerable = descriptor.enumerable || false;
  46. descriptor.configurable = true;
  47. if ("value" in descriptor) {
  48. descriptor.writable = true
  49. }
  50. Object.defineProperty(target, descriptor.key, descriptor)
  51. }
  52. }
  53. function _createClass(Constructor, protoProps, staticProps) {
  54. if (protoProps) {
  55. _defineProperties(Constructor.prototype, protoProps)
  56. }
  57. if (staticProps) {
  58. _defineProperties(Constructor, staticProps)
  59. }
  60. Object.defineProperty(Constructor, "prototype", {
  61. writable: false
  62. });
  63. return Constructor
  64. }
  65. function _inherits(subClass, superClass) {
  66. if ("function" !== typeof superClass && null !== superClass) {
  67. throw new TypeError("Super expression must either be null or a function")
  68. }
  69. subClass.prototype = Object.create(superClass && superClass.prototype, {
  70. constructor: {
  71. value: subClass,
  72. writable: true,
  73. configurable: true
  74. }
  75. });
  76. Object.defineProperty(subClass, "prototype", {
  77. writable: false
  78. });
  79. if (superClass) {
  80. _setPrototypeOf(subClass, superClass)
  81. }
  82. }
  83. function _setPrototypeOf(o, p) {
  84. _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function(o, p) {
  85. o.__proto__ = p;
  86. return o
  87. };
  88. return _setPrototypeOf(o, p)
  89. }
  90. function _createSuper(Derived) {
  91. var hasNativeReflectConstruct = _isNativeReflectConstruct();
  92. return function() {
  93. var result, Super = _getPrototypeOf(Derived);
  94. if (hasNativeReflectConstruct) {
  95. var NewTarget = _getPrototypeOf(this).constructor;
  96. result = Reflect.construct(Super, arguments, NewTarget)
  97. } else {
  98. result = Super.apply(this, arguments)
  99. }
  100. return _possibleConstructorReturn(this, result)
  101. }
  102. }
  103. function _possibleConstructorReturn(self, call) {
  104. if (call && ("object" === _typeof(call) || "function" === typeof call)) {
  105. return call
  106. } else {
  107. if (void 0 !== call) {
  108. throw new TypeError("Derived constructors may only return object or undefined")
  109. }
  110. }
  111. return _assertThisInitialized(self)
  112. }
  113. function _assertThisInitialized(self) {
  114. if (void 0 === self) {
  115. throw new ReferenceError("this hasn't been initialised - super() hasn't been called")
  116. }
  117. return self
  118. }
  119. function _isNativeReflectConstruct() {
  120. if ("undefined" === typeof Reflect || !Reflect.construct) {
  121. return false
  122. }
  123. if (Reflect.construct.sham) {
  124. return false
  125. }
  126. if ("function" === typeof Proxy) {
  127. return true
  128. }
  129. try {
  130. Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
  131. return true
  132. } catch (e) {
  133. return false
  134. }
  135. }
  136. function _get() {
  137. if ("undefined" !== typeof Reflect && Reflect.get) {
  138. _get = Reflect.get.bind()
  139. } else {
  140. _get = function(target, property, receiver) {
  141. var base = _superPropBase(target, property);
  142. if (!base) {
  143. return
  144. }
  145. var desc = Object.getOwnPropertyDescriptor(base, property);
  146. if (desc.get) {
  147. return desc.get.call(arguments.length < 3 ? target : receiver)
  148. }
  149. return desc.value
  150. }
  151. }
  152. return _get.apply(this, arguments)
  153. }
  154. function _superPropBase(object, property) {
  155. while (!Object.prototype.hasOwnProperty.call(object, property)) {
  156. object = _getPrototypeOf(object);
  157. if (null === object) {
  158. break
  159. }
  160. }
  161. return object
  162. }
  163. function _getPrototypeOf(o) {
  164. _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function(o) {
  165. return o.__proto__ || Object.getPrototypeOf(o)
  166. };
  167. return _getPrototypeOf(o)
  168. }
  169. var USER_ACTION = "user";
  170. var SILENT_ACTION = "silent";
  171. var DEFAULT_MARKER = "@";
  172. var KEY_CODES = {
  173. ARROW_UP: 38,
  174. ARROW_DOWN: 40,
  175. ARROW_LEFT: 37,
  176. ARROW_RIGHT: 39,
  177. ENTER: 13,
  178. ESCAPE: 27,
  179. SPACE: 32,
  180. PAGE_UP: 33,
  181. PAGE_DOWN: 34,
  182. END: 35,
  183. HOME: 36
  184. };
  185. 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];
  186. var ALLOWED_PREFIX_CHARS = [" ", "\n"];
  187. var DISABLED_STATE_CLASS = "dx-state-disabled";
  188. var MentionModule = function(_PopupModule) {
  189. _inherits(MentionModule, _PopupModule);
  190. var _super = _createSuper(MentionModule);
  191. function MentionModule(quill, options) {
  192. var _this;
  193. _classCallCheck(this, MentionModule);
  194. _this = _super.call(this, quill, options);
  195. _this._mentions = {};
  196. _this.editorInstance = options.editorInstance;
  197. options.mentions.forEach(function(item) {
  198. var marker = item.marker;
  199. if (!marker) {
  200. item.marker = marker = DEFAULT_MARKER
  201. }
  202. var template = item.template;
  203. if (template) {
  204. var preparedTemplate = _this.editorInstance._getTemplate(template);
  205. preparedTemplate && _mention2.default.addTemplate(marker, preparedTemplate)
  206. }
  207. _this._mentions[marker] = (0, _extend.extend)({}, _this._getDefaultOptions(), item)
  208. });
  209. _this._attachKeyboardHandlers();
  210. _this.editorInstance.addCleanCallback(_this.clean.bind(_assertThisInitialized(_this)));
  211. _this.quill.on("text-change", _this.onTextChange.bind(_assertThisInitialized(_this)));
  212. return _this
  213. }
  214. _createClass(MentionModule, [{
  215. key: "_getDefaultOptions",
  216. value: function() {
  217. var baseConfig = _get(_getPrototypeOf(MentionModule.prototype), "_getDefaultOptions", this).call(this);
  218. return (0, _extend.extend)(baseConfig, {
  219. itemTemplate: "item",
  220. valueExpr: "this",
  221. displayExpr: "this",
  222. template: null,
  223. searchExpr: null,
  224. searchTimeout: 500,
  225. minSearchLength: 0
  226. })
  227. }
  228. }, {
  229. key: "_attachKeyboardHandlers",
  230. value: function() {
  231. var _this2 = this;
  232. this.quill.keyboard.addBinding({
  233. key: KEY_CODES.ARROW_UP
  234. }, this._moveToItem.bind(this, "prev"));
  235. this.quill.keyboard.addBinding({
  236. key: KEY_CODES.ARROW_DOWN
  237. }, this._moveToItem.bind(this, "next"));
  238. this.quill.keyboard.addBinding({
  239. key: KEY_CODES.ENTER
  240. }, this._selectItemHandler.bind(this));
  241. var enterBindings = this.quill.keyboard.bindings[KEY_CODES.ENTER];
  242. enterBindings.unshift(enterBindings.pop());
  243. this.quill.keyboard.addBinding({
  244. key: KEY_CODES.ESCAPE
  245. }, this._escapeKeyHandler.bind(this));
  246. this.quill.keyboard.addBinding({
  247. key: KEY_CODES.SPACE
  248. }, this._selectItemHandler.bind(this));
  249. this.quill.keyboard.addBinding({
  250. key: KEY_CODES.ARROW_LEFT,
  251. shiftKey: true
  252. }, this._ignoreKeyHandler.bind(this));
  253. this.quill.keyboard.addBinding({
  254. key: KEY_CODES.ARROW_RIGHT,
  255. shiftKey: true
  256. }, this._ignoreKeyHandler.bind(this));
  257. NAVIGATION_KEYS.forEach(function(key) {
  258. _this2.quill.keyboard.addBinding({
  259. key: key
  260. }, _this2._ignoreKeyHandler.bind(_this2))
  261. })
  262. }
  263. }, {
  264. key: "_moveToItem",
  265. value: function(direction) {
  266. var dataSource = this._list.getDataSource();
  267. if (this._isMentionActive && !dataSource.isLoading()) {
  268. var $focusedItem = (0, _renderer2.default)(this._list.option("focusedElement"));
  269. var defaultItemPosition = "next" === direction ? "first" : "last";
  270. var $nextItem = $focusedItem[direction]();
  271. $nextItem = $nextItem.length ? $nextItem : this._activeListItems[defaultItemPosition]();
  272. this._list.option("focusedElement", (0, _dom.getPublicElement)($nextItem));
  273. this._list.scrollToItem($nextItem)
  274. }
  275. return !this._isMentionActive
  276. }
  277. }, {
  278. key: "_ignoreKeyHandler",
  279. value: function() {
  280. return !this._isMentionActive
  281. }
  282. }, {
  283. key: "_fitIntoRange",
  284. value: function(value, start, end) {
  285. if (value > end) {
  286. return start
  287. }
  288. if (value < start) {
  289. return end
  290. }
  291. return value
  292. }
  293. }, {
  294. key: "_selectItemHandler",
  295. value: function() {
  296. if (this._isMentionActive) {
  297. this._list.selectItem(this._list.option("focusedElement"))
  298. }
  299. return !this._isMentionActive
  300. }
  301. }, {
  302. key: "_escapeKeyHandler",
  303. value: function() {
  304. if (this._isMentionActive) {
  305. this._popup.hide()
  306. }
  307. return !this._isMentionActive
  308. }
  309. }, {
  310. key: "renderList",
  311. value: function($container, options) {
  312. this.compileGetters(this.options);
  313. _get(_getPrototypeOf(MentionModule.prototype), "renderList", this).call(this, $container, options)
  314. }
  315. }, {
  316. key: "compileGetters",
  317. value: function(_ref) {
  318. var displayExpr = _ref.displayExpr,
  319. valueExpr = _ref.valueExpr;
  320. this._valueGetter = (0, _data.compileGetter)(displayExpr);
  321. this._idGetter = (0, _data.compileGetter)(valueExpr)
  322. }
  323. }, {
  324. key: "_getListConfig",
  325. value: function(options) {
  326. var _this3 = this;
  327. var baseConfig = _get(_getPrototypeOf(MentionModule.prototype), "_getListConfig", this).call(this, options);
  328. return (0, _extend.extend)(baseConfig, {
  329. itemTemplate: this.options.itemTemplate,
  330. onContentReady: function() {
  331. if (_this3._hasSearch) {
  332. _this3._popup.repaint();
  333. _this3._focusFirstElement();
  334. _this3._hasSearch = false
  335. }
  336. }
  337. })
  338. }
  339. }, {
  340. key: "insertEmbedContent",
  341. value: function() {
  342. var markerLength = this._activeMentionConfig.marker.length;
  343. var textLength = markerLength + this._searchValue.length;
  344. var caretPosition = this.getPosition();
  345. var startIndex = Math.max(0, caretPosition - markerLength);
  346. var selectedItem = this._list.option("selectedItem");
  347. var value = {
  348. value: this._valueGetter(selectedItem),
  349. id: this._idGetter(selectedItem),
  350. marker: this._activeMentionConfig.marker
  351. };
  352. setTimeout(function() {
  353. this.quill.insertText(startIndex, " ", SILENT_ACTION);
  354. this.quill.deleteText(startIndex + 1, textLength, SILENT_ACTION);
  355. this.quill.insertEmbed(startIndex, "mention", value);
  356. this.quill.setSelection(startIndex + 2)
  357. }.bind(this))
  358. }
  359. }, {
  360. key: "_getLastInsertOperation",
  361. value: function(ops) {
  362. var lastOperation = ops[ops.length - 1];
  363. var isLastOperationInsert = "insert" in lastOperation;
  364. if (isLastOperationInsert) {
  365. return lastOperation
  366. }
  367. var isLastOperationDelete = "delete" in lastOperation;
  368. if (isLastOperationDelete && ops.length >= 2) {
  369. var penultOperation = ops[ops.length - 2];
  370. var isPenultOperationInsert = "insert" in penultOperation;
  371. var isSelectionReplacing = isLastOperationDelete && isPenultOperationInsert;
  372. if (isSelectionReplacing) {
  373. return penultOperation
  374. }
  375. }
  376. return null
  377. }
  378. }, {
  379. key: "onTextChange",
  380. value: function(newDelta, oldDelta, source) {
  381. if (source === USER_ACTION) {
  382. var lastOperation = newDelta.ops[newDelta.ops.length - 1];
  383. if (this._isMentionActive) {
  384. this._processSearchValue(lastOperation) && this._filterList(this._searchValue)
  385. } else {
  386. var ops = newDelta.ops;
  387. var lastInsertOperation = this._getLastInsertOperation(ops);
  388. if (lastInsertOperation) {
  389. this.checkMentionRequest(lastInsertOperation, ops)
  390. }
  391. }
  392. }
  393. }
  394. }, {
  395. key: "_processSearchValue",
  396. value: function(operation) {
  397. var isInsertOperation = "insert" in operation;
  398. if (isInsertOperation) {
  399. this._searchValue += operation.insert
  400. } else {
  401. if (!this._searchValue.length) {
  402. this._popup.hide();
  403. return false
  404. } else {
  405. this._searchValue = this._searchValue.slice(0, -1)
  406. }
  407. }
  408. return true
  409. }
  410. }, {
  411. key: "checkMentionRequest",
  412. value: function(_ref2, ops) {
  413. var insert = _ref2.insert;
  414. var caret = this.quill.getSelection();
  415. if (!insert || !(0, _type.isString)(insert) || !caret || this._isMarkerPartOfText(ops[0].retain)) {
  416. return
  417. }
  418. this._activeMentionConfig = this._mentions[insert];
  419. if (this._activeMentionConfig) {
  420. this._updateList(this._activeMentionConfig);
  421. this.savePosition(caret.index);
  422. this._popup.option("position", this._popupPosition);
  423. this._searchValue = "";
  424. this._popup.show()
  425. }
  426. }
  427. }, {
  428. key: "_isMarkerPartOfText",
  429. value: function(retain) {
  430. if (!retain || ALLOWED_PREFIX_CHARS.indexOf(this._getCharByIndex(retain - 1)) !== -1) {
  431. return false
  432. }
  433. return true
  434. }
  435. }, {
  436. key: "_getCharByIndex",
  437. value: function(index) {
  438. return this.quill.getContents(index, 1).ops[0].insert
  439. }
  440. }, {
  441. key: "_updateList",
  442. value: function(_ref3) {
  443. var dataSource = _ref3.dataSource,
  444. displayExpr = _ref3.displayExpr,
  445. valueExpr = _ref3.valueExpr,
  446. itemTemplate = _ref3.itemTemplate,
  447. searchExpr = _ref3.searchExpr;
  448. this.compileGetters({
  449. displayExpr: displayExpr,
  450. valueExpr: valueExpr
  451. });
  452. this._list.unselectAll();
  453. this._list.option({
  454. dataSource: dataSource,
  455. displayExpr: displayExpr,
  456. itemTemplate: itemTemplate,
  457. searchExpr: searchExpr
  458. })
  459. }
  460. }, {
  461. key: "_filterList",
  462. value: function(searchValue) {
  463. var _this4 = this;
  464. if (!this._isMinSearchLengthExceeded(searchValue)) {
  465. this._resetFilter();
  466. return
  467. }
  468. var searchTimeout = this._activeMentionConfig.searchTimeout;
  469. if (searchTimeout) {
  470. clearTimeout(this._searchTimer);
  471. this._searchTimer = setTimeout(function() {
  472. _this4._search(searchValue)
  473. }, searchTimeout)
  474. } else {
  475. this._search(searchValue)
  476. }
  477. }
  478. }, {
  479. key: "_isMinSearchLengthExceeded",
  480. value: function(searchValue) {
  481. return searchValue.length >= this._activeMentionConfig.minSearchLength
  482. }
  483. }, {
  484. key: "_resetFilter",
  485. value: function() {
  486. clearTimeout(this._searchTimer);
  487. this._search(null)
  488. }
  489. }, {
  490. key: "_search",
  491. value: function(searchValue) {
  492. this._hasSearch = true;
  493. this._list.option("searchValue", searchValue)
  494. }
  495. }, {
  496. key: "_focusFirstElement",
  497. value: function() {
  498. if (!this._list) {
  499. return
  500. }
  501. var $firstItem = this._activeListItems.first();
  502. this._list.option("focusedElement", (0, _dom.getPublicElement)($firstItem));
  503. this._list.scrollToItem($firstItem)
  504. }
  505. }, {
  506. key: "_popupPosition",
  507. get: function() {
  508. var position = this.getPosition();
  509. var _this$quill$getBounds = this.quill.getBounds(position ? position - 1 : position),
  510. mentionLeft = _this$quill$getBounds.left,
  511. mentionTop = _this$quill$getBounds.top,
  512. mentionHeight = _this$quill$getBounds.height;
  513. var _$$offset = (0, _renderer2.default)(this.quill.root).offset(),
  514. leftOffset = _$$offset.left,
  515. topOffset = _$$offset.top;
  516. var positionEvent = (0, _events.Event)("positionEvent", {
  517. pageX: leftOffset + mentionLeft,
  518. pageY: topOffset + mentionTop
  519. });
  520. return {
  521. of: positionEvent,
  522. offset: {
  523. v: mentionHeight
  524. },
  525. my: "top left",
  526. at: "top left",
  527. collision: {
  528. y: "flip",
  529. x: "flipfit"
  530. }
  531. }
  532. }
  533. }, {
  534. key: "_getPopupConfig",
  535. value: function() {
  536. var _this5 = this;
  537. return (0, _extend.extend)(_get(_getPrototypeOf(MentionModule.prototype), "_getPopupConfig", this).call(this), {
  538. closeOnTargetScroll: false,
  539. onShown: function() {
  540. _this5._isMentionActive = true;
  541. _this5._hasSearch = false;
  542. _this5._focusFirstElement()
  543. },
  544. onHidden: function() {
  545. _this5._list.unselectAll();
  546. _this5._list.option("focusedElement", null);
  547. _this5._isMentionActive = false;
  548. _this5._search(null)
  549. },
  550. focusStateEnabled: false
  551. })
  552. }
  553. }, {
  554. key: "_activeListItems",
  555. get: function() {
  556. return this._list.itemElements().filter(":not(.".concat(DISABLED_STATE_CLASS, ")"))
  557. }
  558. }, {
  559. key: "clean",
  560. value: function() {
  561. var _this6 = this;
  562. Object.keys(this._mentions).forEach(function(marker) {
  563. if (_this6._mentions[marker].template) {
  564. _mention2.default.removeTemplate(marker)
  565. }
  566. })
  567. }
  568. }]);
  569. return MentionModule
  570. }(_popup2.default);
  571. exports.default = MentionModule;