lakelib 0.1.22 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +4 -4
  2. package/dist/lake.css +45 -36
  3. package/dist/lake.min.js +37 -29
  4. package/dist/lake.min.js.map +1 -1
  5. package/lib/lake.css +45 -36
  6. package/lib/lake.js +927 -227
  7. package/lib/lake.js.map +1 -1
  8. package/lib/types/boxes/code-block.d.ts +2 -1
  9. package/lib/types/boxes/emoji.d.ts +2 -1
  10. package/lib/types/boxes/equation.d.ts +2 -1
  11. package/lib/types/boxes/file.d.ts +2 -1
  12. package/lib/types/boxes/hr.d.ts +2 -1
  13. package/lib/types/boxes/image.d.ts +2 -1
  14. package/lib/types/boxes/video.d.ts +2 -1
  15. package/lib/types/config/slash-items.d.ts +2 -0
  16. package/lib/types/css/index.d.ts +1 -1
  17. package/lib/types/editor.d.ts +2 -0
  18. package/lib/types/i18n/en-US/index.d.ts +36 -0
  19. package/lib/types/i18n/ja/index.d.ts +36 -0
  20. package/lib/types/i18n/ko/index.d.ts +36 -0
  21. package/lib/types/i18n/types.d.ts +278 -2
  22. package/lib/types/i18n/zh-CN/index.d.ts +36 -0
  23. package/lib/types/index.d.ts +3 -2
  24. package/lib/types/managers/keystroke.d.ts +0 -1
  25. package/lib/types/managers/plugin.d.ts +4 -5
  26. package/lib/types/managers/selection.d.ts +1 -1
  27. package/lib/types/models/box.d.ts +1 -1
  28. package/lib/types/models/nodes.d.ts +2 -0
  29. package/lib/types/plugins/slash.d.ts +3 -0
  30. package/lib/types/types/plugin.d.ts +3 -0
  31. package/lib/types/types/{commands.d.ts → slash.d.ts} +4 -4
  32. package/lib/types/ui/box-toolbar.d.ts +2 -1
  33. package/lib/types/ui/dropdown.d.ts +1 -0
  34. package/lib/types/ui/link-popup.d.ts +2 -3
  35. package/lib/types/ui/slash-popup.d.ts +34 -0
  36. package/lib/types/ui/toolbar.d.ts +5 -3
  37. package/lib/types/utils/index.d.ts +2 -1
  38. package/lib/types/utils/{node-and-view.d.ts → node-position.d.ts} +1 -1
  39. package/lib/types/utils/scroll-to-node.d.ts +2 -0
  40. package/package.json +1 -1
  41. package/lib/types/ui/commands-popup.d.ts +0 -24
package/lib/lake.js CHANGED
@@ -1098,6 +1098,15 @@ class Nodes {
1098
1098
  element.innerText = value;
1099
1099
  });
1100
1100
  }
1101
+ value(value) {
1102
+ if (value === undefined) {
1103
+ const inputElement = this.get(0);
1104
+ return inputElement.value;
1105
+ }
1106
+ return this.eachElement(element => {
1107
+ element.value = value;
1108
+ });
1109
+ }
1101
1110
  outerHTML() {
1102
1111
  const element = this.get(0);
1103
1112
  return element.outerHTML;
@@ -1506,7 +1515,7 @@ class Range {
1506
1515
  selectBox(boxNode) {
1507
1516
  const boxContainer = boxNode.find('.lake-box-container');
1508
1517
  if (boxContainer.length === 0) {
1509
- throw new Error(`The box cannot be selected because the box "${boxNode.attr('name')}" (id=${boxNode.id}) has not been rendered yet.`);
1518
+ throw new Error(`The box "${boxNode.attr('name')}" (id=${boxNode.id}) cannot be selected because it has not been rendered yet.`);
1510
1519
  }
1511
1520
  this.setStart(boxContainer, 0);
1512
1521
  this.collapseToStart();
@@ -1515,7 +1524,7 @@ class Range {
1515
1524
  selectBoxStart(boxNode) {
1516
1525
  const boxStrip = boxNode.find('.lake-box-strip');
1517
1526
  if (boxStrip.length === 0) {
1518
- throw new Error(`The box cannot be selected because the box "${boxNode.attr('name')}" (id=${boxNode.id}) has not been rendered yet.`);
1527
+ throw new Error(`The box "${boxNode.attr('name')}" (id=${boxNode.id}) cannot be selected because it has not been rendered yet.`);
1519
1528
  }
1520
1529
  this.selectNodeContents(boxStrip.eq(0));
1521
1530
  this.collapseToStart();
@@ -1524,7 +1533,7 @@ class Range {
1524
1533
  selectBoxEnd(boxNode) {
1525
1534
  const boxStrip = boxNode.find('.lake-box-strip');
1526
1535
  if (boxStrip.length === 0) {
1527
- throw new Error(`The box cannot be selected because the box "${boxNode.attr('name')}" (id=${boxNode.id}) has not been rendered yet.`);
1536
+ throw new Error(`The box "${boxNode.attr('name')}" (id=${boxNode.id}) cannot be selected because it has not been rendered yet.`);
1528
1537
  }
1529
1538
  this.selectNodeContents(boxStrip.eq(1));
1530
1539
  this.collapseToStart();
@@ -2770,7 +2779,7 @@ function morph(node, otherNode, config = {}) {
2770
2779
  }
2771
2780
 
2772
2781
  // Returns an object that indicates the specified node's position relative to the viewport.
2773
- function nodeAndView(node) {
2782
+ function nodePosition(node) {
2774
2783
  const nativeNode = node.get(0);
2775
2784
  const rect = nativeNode.getBoundingClientRect();
2776
2785
  let left = rect.left;
@@ -2801,6 +2810,15 @@ function nodeAndView(node) {
2801
2810
  return position;
2802
2811
  }
2803
2812
 
2813
+ // If a node is not visible, scrolls the container that contains this node to its position to make it visible.
2814
+ // If the node is visible, then scrolling takes place.
2815
+ function scrollToNode(node, options) {
2816
+ const position = nodePosition(node);
2817
+ if (position.left < 0 || position.right < 0 || position.top < 0 || position.bottom < 0) {
2818
+ node.get(0).scrollIntoView(options);
2819
+ }
2820
+ }
2821
+
2804
2822
  const boxInstances = new Map();
2805
2823
  function getInstanceMap(id) {
2806
2824
  let instanceMap = boxInstances.get(id);
@@ -2916,6 +2934,42 @@ var enUS = {
2916
2934
  equation: 'Equation',
2917
2935
  removeColor: 'Remove color',
2918
2936
  },
2937
+ slash: {
2938
+ heading1: 'Heading 1',
2939
+ heading1Desc: 'Create a heading level 1',
2940
+ heading2: 'Heading 2',
2941
+ heading2Desc: 'Create a heading level 2',
2942
+ heading3: 'Heading 3',
2943
+ heading3Desc: 'Create a heading level 3',
2944
+ heading4: 'Heading 4',
2945
+ heading4Desc: 'Create a heading level 4',
2946
+ heading5: 'Heading 5',
2947
+ heading5Desc: 'Create a heading level 5',
2948
+ heading6: 'Heading 6',
2949
+ heading6Desc: 'Create a heading level 6',
2950
+ paragraph: 'Paragraph',
2951
+ paragraphDesc: 'Create a paragraph',
2952
+ blockQuote: 'Block quotation',
2953
+ blockQuoteDesc: 'Create a block quotation',
2954
+ numberedList: 'Numbered list',
2955
+ numberedListDesc: 'Create a numbered list',
2956
+ bulletedList: 'Bulleted list',
2957
+ bulletedListDesc: 'Create a bulleted list',
2958
+ checklist: 'Checklist',
2959
+ checklistDesc: 'Create a checklist',
2960
+ hr: 'Horizontal line',
2961
+ hrDesc: 'Insert a horizontal line',
2962
+ codeBlock: 'Code block',
2963
+ codeBlockDesc: 'Insert a code block',
2964
+ video: 'Video',
2965
+ videoDesc: 'Insert a video from YouTube',
2966
+ equation: 'Equation',
2967
+ equationDesc: 'Insert TeX expression in text',
2968
+ image: 'Image',
2969
+ imageDesc: 'Upload an image',
2970
+ file: 'File',
2971
+ fileDesc: 'Upload a file',
2972
+ },
2919
2973
  link: {
2920
2974
  newLink: 'New link',
2921
2975
  url: 'Link URL',
@@ -3005,6 +3059,42 @@ var zhCN = {
3005
3059
  equation: '公式',
3006
3060
  removeColor: '默认',
3007
3061
  },
3062
+ slash: {
3063
+ heading1: '标题 1',
3064
+ heading1Desc: '创建标题 1',
3065
+ heading2: '标题 2',
3066
+ heading2Desc: '创建标题 2',
3067
+ heading3: '标题 3',
3068
+ heading3Desc: '创建标题 3',
3069
+ heading4: '标题 4',
3070
+ heading4Desc: '创建标题 4',
3071
+ heading5: '标题 5',
3072
+ heading5Desc: '创建标题 5',
3073
+ heading6: '标题 6',
3074
+ heading6Desc: '创建标题 6',
3075
+ paragraph: '正文',
3076
+ paragraphDesc: '把当前段落改成正文',
3077
+ blockQuote: '引用',
3078
+ blockQuoteDesc: '创建引用',
3079
+ numberedList: '编号',
3080
+ numberedListDesc: '创建编号列表',
3081
+ bulletedList: '项目符号',
3082
+ bulletedListDesc: '创建项目符号列表',
3083
+ checklist: '任务列表',
3084
+ checklistDesc: '创建任务列表',
3085
+ hr: '分割线',
3086
+ hrDesc: '插入分割线',
3087
+ codeBlock: '代码块',
3088
+ codeBlockDesc: '插入代码块',
3089
+ video: '视频',
3090
+ videoDesc: '插入 YouTube 视频',
3091
+ equation: '公式',
3092
+ equationDesc: '支持 TeX 语法',
3093
+ image: '图片',
3094
+ imageDesc: '上传图片',
3095
+ file: '文件',
3096
+ fileDesc: '上传文件',
3097
+ },
3008
3098
  link: {
3009
3099
  newLink: '新链接',
3010
3100
  url: '链接 URL',
@@ -3050,7 +3140,7 @@ var ja = {
3050
3140
  redo: `やり直し (${modifierText('mod+Y')})`,
3051
3141
  selectAll: `すべて選択 (${modifierText('mod+A')})`,
3052
3142
  paragraph: 'テキスト',
3053
- blockQuote: 'ブロック引用',
3143
+ blockQuote: '引用ブロック',
3054
3144
  numberedList: '番号付きリスト',
3055
3145
  bulletedList: '箇条書きリスト',
3056
3146
  checklist: 'タスクリスト',
@@ -3094,6 +3184,42 @@ var ja = {
3094
3184
  equation: '公式',
3095
3185
  removeColor: 'デフォルト',
3096
3186
  },
3187
+ slash: {
3188
+ heading1: 'タイトル 1',
3189
+ heading1Desc: 'レベル 1 のタイトルを作成',
3190
+ heading2: 'タイトル 2',
3191
+ heading2Desc: 'レベル 2 のタイトルを作成',
3192
+ heading3: 'タイトル 3',
3193
+ heading3Desc: 'レベル 3 のタイトルを作成',
3194
+ heading4: 'タイトル 4',
3195
+ heading4Desc: 'レベル 4 のタイトルを作成',
3196
+ heading5: 'タイトル 5',
3197
+ heading5Desc: 'レベル 5 のタイトルを作成',
3198
+ heading6: 'タイトル 6',
3199
+ heading6Desc: 'レベル 6 のタイトルを作成',
3200
+ paragraph: 'テキスト',
3201
+ paragraphDesc: '段落を作成',
3202
+ blockQuote: '引用ブロック',
3203
+ blockQuoteDesc: '引用ブロックを作成',
3204
+ numberedList: '番号付きリスト',
3205
+ numberedListDesc: '番号付きリストを作成',
3206
+ bulletedList: '箇条書きリスト',
3207
+ bulletedListDesc: '箇条書きリストを作成',
3208
+ checklist: 'タスクリスト',
3209
+ checklistDesc: 'タスクリストを作成',
3210
+ hr: '区切り線',
3211
+ hrDesc: '水平線を挿入',
3212
+ codeBlock: 'コードブロック',
3213
+ codeBlockDesc: 'コードブロックを挿入',
3214
+ video: '動画',
3215
+ videoDesc: 'YouTube から動画を挿入',
3216
+ equation: '公式',
3217
+ equationDesc: 'TeX 式を挿入',
3218
+ image: '画像',
3219
+ imageDesc: '画像をアップロード',
3220
+ file: 'ファイル',
3221
+ fileDesc: 'ファイルをアップロード',
3222
+ },
3097
3223
  link: {
3098
3224
  newLink: '新しいリンク',
3099
3225
  url: 'リンク URL',
@@ -3183,6 +3309,42 @@ var ko = {
3183
3309
  equation: '수식',
3184
3310
  removeColor: '기본색',
3185
3311
  },
3312
+ slash: {
3313
+ heading1: '제목 1',
3314
+ heading1Desc: '1 단계 제목을 작성',
3315
+ heading2: '제목 2',
3316
+ heading2Desc: '2 단계 제목을 작성',
3317
+ heading3: '제목 3',
3318
+ heading3Desc: '3 단계 제목을 작성',
3319
+ heading4: '제목 4',
3320
+ heading4Desc: '4 단계 제목을 작성',
3321
+ heading5: '제목 5',
3322
+ heading5Desc: '5 단계 제목을 작성',
3323
+ heading6: '제목 6',
3324
+ heading6Desc: '6 단계 제목을 작성',
3325
+ paragraph: '텍스트',
3326
+ paragraphDesc: '단락을 작성',
3327
+ blockQuote: '인용문',
3328
+ blockQuoteDesc: '인용문을 작성',
3329
+ numberedList: '순서 목록',
3330
+ numberedListDesc: '순서 목록을 작성',
3331
+ bulletedList: '비순서 목록',
3332
+ bulletedListDesc: '비순서 목록을 작성',
3333
+ checklist: '체크리스트',
3334
+ checklistDesc: '체크리스트를 작성',
3335
+ hr: '구분선',
3336
+ hrDesc: '구분선을 삽입',
3337
+ codeBlock: '코드 블록',
3338
+ codeBlockDesc: '코드 블록을 삽입',
3339
+ video: '동영상',
3340
+ videoDesc: '유튜브 동영상을 삽입',
3341
+ equation: '수식',
3342
+ equationDesc: '텍스 표현식을 삽입',
3343
+ image: '이미지',
3344
+ imageDesc: '이미지를 업로드',
3345
+ file: '파일',
3346
+ fileDesc: '파일을 업로드',
3347
+ },
3186
3348
  link: {
3187
3349
  newLink: '새 링크',
3188
3350
  url: '링크 URL',
@@ -3256,12 +3418,10 @@ class Dropdown {
3256
3418
  this.documentClickListener = (event) => {
3257
3419
  const targetNode = new Nodes(event.target);
3258
3420
  const titleNode = this.node.find('.lake-dropdown-title');
3259
- const menuNode = this.node.find('.lake-dropdown-menu');
3260
3421
  if (targetNode.closest('.lake-dropdown-title').get(0) === titleNode.get(0)) {
3261
3422
  return;
3262
3423
  }
3263
- menuNode.hide();
3264
- document.removeEventListener('click', this.documentClickListener);
3424
+ this.hideMenu();
3265
3425
  };
3266
3426
  this.config = config;
3267
3427
  this.root = config.root;
@@ -3323,6 +3483,15 @@ class Dropdown {
3323
3483
  `;
3324
3484
  const listNode = query(listContent);
3325
3485
  menuNode.append(listNode);
3486
+ listNode.on('mouseenter', () => {
3487
+ if (listNode.hasClass('lake-dropdown-item-selected')) {
3488
+ return;
3489
+ }
3490
+ listNode.addClass('lake-dropdown-item-hovered');
3491
+ });
3492
+ listNode.on('mouseleave', () => {
3493
+ listNode.removeClass('lake-dropdown-item-hovered');
3494
+ });
3326
3495
  if (config.menuType === 'character') {
3327
3496
  listNode.attr('title', menuText);
3328
3497
  listNode.find('.lake-dropdown-menu-text').text(menuItem.value);
@@ -3355,15 +3524,6 @@ class Dropdown {
3355
3524
  menuNode.find('.lake-dropdown-menu-check').css('visibility', 'hidden');
3356
3525
  menuNode.find('li').each(node => {
3357
3526
  const listNode = query(node);
3358
- listNode.on('mouseenter', () => {
3359
- if (listNode.hasClass('lake-dropdown-item-selected')) {
3360
- return;
3361
- }
3362
- listNode.addClass('lake-dropdown-item-hovered');
3363
- });
3364
- listNode.on('mouseleave', () => {
3365
- listNode.removeClass('lake-dropdown-item-hovered');
3366
- });
3367
3527
  if (currentValues.indexOf(listNode.attr('value')) >= 0) {
3368
3528
  listNode.find('.lake-dropdown-menu-check').css('visibility', 'visible');
3369
3529
  }
@@ -3387,6 +3547,12 @@ class Dropdown {
3387
3547
  menuNode.css('visibility', '');
3388
3548
  document.addEventListener('click', this.documentClickListener);
3389
3549
  }
3550
+ hideMenu() {
3551
+ const dropdownNode = this.node;
3552
+ const menuNode = dropdownNode.find('.lake-dropdown-menu');
3553
+ menuNode.hide();
3554
+ document.removeEventListener('click', this.documentClickListener);
3555
+ }
3390
3556
  bindEvents() {
3391
3557
  const config = this.config;
3392
3558
  const dropdownNode = this.node;
@@ -3458,8 +3624,7 @@ class Dropdown {
3458
3624
  this.updateColorAccent(titleNode, value);
3459
3625
  }
3460
3626
  config.onSelect(value);
3461
- menuNode.hide();
3462
- document.removeEventListener('click', this.documentClickListener);
3627
+ this.hideMenu();
3463
3628
  });
3464
3629
  }
3465
3630
  render() {
@@ -3512,8 +3677,8 @@ class Dropdown {
3512
3677
  this.bindEvents();
3513
3678
  }
3514
3679
  unmount() {
3680
+ this.hideMenu();
3515
3681
  this.node.remove();
3516
- document.removeEventListener('click', this.documentClickListener);
3517
3682
  }
3518
3683
  }
3519
3684
 
@@ -3521,13 +3686,13 @@ class BoxToolbar {
3521
3686
  constructor(config) {
3522
3687
  this.buttonItemList = [];
3523
3688
  this.dropdownItemList = [];
3689
+ this.dropdownList = [];
3524
3690
  this.root = query(config.root);
3525
3691
  this.box = config.box;
3526
3692
  this.items = config.items;
3527
3693
  this.locale = config.locale || i18nObject('en-US');
3528
3694
  this.placement = config.placement || 'top';
3529
3695
  this.container = query('<div class="lake-box-toolbar" />');
3530
- this.root.addClass('lake-custom-properties');
3531
3696
  }
3532
3697
  appendDivider() {
3533
3698
  this.container.append('<div class="lake-toolbar-divider" />');
@@ -3565,12 +3730,13 @@ class BoxToolbar {
3565
3730
  },
3566
3731
  });
3567
3732
  dropdown.render();
3733
+ this.dropdownList.push(dropdown);
3568
3734
  }
3569
- updatePosition() {
3735
+ position() {
3570
3736
  const boxNode = this.box.node;
3571
3737
  const boxNativeNode = boxNode.get(0);
3572
3738
  const boxRect = boxNativeNode.getBoundingClientRect();
3573
- const position = nodeAndView(boxNode);
3739
+ const position = nodePosition(boxNode);
3574
3740
  if (position.top < 0 || position.bottom + boxRect.height < 0) {
3575
3741
  this.container.hide();
3576
3742
  return;
@@ -3601,9 +3767,13 @@ class BoxToolbar {
3601
3767
  this.appendDropdown(item);
3602
3768
  }
3603
3769
  }
3604
- this.updatePosition();
3770
+ this.position();
3605
3771
  }
3772
+ // Destroys the toolbar.
3606
3773
  unmount() {
3774
+ for (const dropdown of this.dropdownList) {
3775
+ dropdown.unmount();
3776
+ }
3607
3777
  this.container.remove();
3608
3778
  }
3609
3779
  }
@@ -3705,7 +3875,11 @@ class Box {
3705
3875
  // Returns an instance of the editor that includes the box.
3706
3876
  getEditor() {
3707
3877
  const container = this.node.closest('div[contenteditable]');
3708
- return container.length > 0 ? editors.get(container.id) : undefined;
3878
+ const editor = container.length > 0 ? editors.get(container.id) : undefined;
3879
+ if (!editor) {
3880
+ throw new Error(`The box "${this.name}" (id=${this.node.id}) is not rendered in the editor.`);
3881
+ }
3882
+ return editor;
3709
3883
  }
3710
3884
  // Returns the container node of the box.
3711
3885
  getContainer() {
@@ -3713,11 +3887,15 @@ class Box {
3713
3887
  }
3714
3888
  // Sets a popup toolbar for the box.
3715
3889
  setToolbar(items) {
3716
- const editor = this.getEditor();
3890
+ let editor;
3891
+ try {
3892
+ editor = this.getEditor();
3893
+ }
3894
+ catch ( /* empty */_a) { /* empty */ }
3717
3895
  let toolbar = null;
3718
3896
  const scrollListener = () => {
3719
3897
  if (toolbar) {
3720
- toolbar.updatePosition();
3898
+ toolbar.position();
3721
3899
  }
3722
3900
  };
3723
3901
  this.event.on('focus', () => {
@@ -3859,7 +4037,7 @@ function getBody(xhr) {
3859
4037
  try {
3860
4038
  return JSON.parse(text);
3861
4039
  }
3862
- catch (e) {
4040
+ catch (_a) {
3863
4041
  return text;
3864
4042
  }
3865
4043
  }
@@ -4021,7 +4199,7 @@ var index = /*#__PURE__*/Object.freeze({
4021
4199
  mergeNodes: mergeNodes,
4022
4200
  modifierText: modifierText,
4023
4201
  morph: morph,
4024
- nodeAndView: nodeAndView,
4202
+ nodePosition: nodePosition,
4025
4203
  normalizeValue: normalizeValue,
4026
4204
  parseStyle: parseStyle,
4027
4205
  query: query,
@@ -4029,6 +4207,7 @@ var index = /*#__PURE__*/Object.freeze({
4029
4207
  removeZWS: removeZWS,
4030
4208
  request: request,
4031
4209
  safeTemplate: safeTemplate,
4210
+ scrollToNode: scrollToNode,
4032
4211
  setBlockIndent: setBlockIndent,
4033
4212
  splitNodes: splitNodes,
4034
4213
  template: template,
@@ -5173,7 +5352,7 @@ function removeBox(range) {
5173
5352
  return box;
5174
5353
  }
5175
5354
 
5176
- var version = "0.1.22";
5355
+ var version = "0.1.24";
5177
5356
 
5178
5357
  // Returns the attributes of the element as an key-value object.
5179
5358
  function getAttributes(node) {
@@ -5247,10 +5426,10 @@ class Selection {
5247
5426
  }
5248
5427
  this.selection = selection;
5249
5428
  this.container = container;
5250
- this.range = this.getRangeFromNativeSelection();
5429
+ this.range = this.getCurrentRange();
5251
5430
  }
5252
- // Returns the current selected range from the native selection.
5253
- getRangeFromNativeSelection() {
5431
+ // Returns a range object currently selected.
5432
+ getCurrentRange() {
5254
5433
  if (this.selection.rangeCount > 0) {
5255
5434
  const range = this.selection.getRangeAt(0);
5256
5435
  return new Range(range);
@@ -5259,12 +5438,15 @@ class Selection {
5259
5438
  }
5260
5439
  // Adds the saved range to the native selection.
5261
5440
  sync() {
5441
+ if (!this.container.contains(this.range.commonAncestor)) {
5442
+ return;
5443
+ }
5262
5444
  this.selection.removeAllRanges();
5263
5445
  this.selection.addRange(this.range.get());
5264
5446
  }
5265
5447
  // Updates the saved range with the range of the native selection.
5266
5448
  updateByRange() {
5267
- const newRange = this.getRangeFromNativeSelection();
5449
+ const newRange = this.getCurrentRange();
5268
5450
  if (!this.container.contains(newRange.commonAncestor)) {
5269
5451
  return;
5270
5452
  }
@@ -5416,6 +5598,11 @@ class Command {
5416
5598
  return commandItem.selectedValues(appliedItems);
5417
5599
  }
5418
5600
  execute(name, ...data) {
5601
+ const container = this.selection.container;
5602
+ const range = this.selection.range;
5603
+ if (!container.contains(range.commonAncestor)) {
5604
+ range.shrinkAfter(container);
5605
+ }
5419
5606
  const commandItem = this.getItem(name);
5420
5607
  commandItem.execute.apply(this, data);
5421
5608
  debug(`Command "${name}" executed`);
@@ -5614,12 +5801,6 @@ class History {
5614
5801
  }
5615
5802
  }
5616
5803
 
5617
- const aliasMap = new Map([
5618
- ['arrow-left', 'left'],
5619
- ['arrow-right', 'right'],
5620
- ['arrow-up', 'up'],
5621
- ['arrow-down', 'down'],
5622
- ]);
5623
5804
  class Keystroke {
5624
5805
  constructor(container) {
5625
5806
  this.keydownEventList = [];
@@ -5630,6 +5811,9 @@ class Keystroke {
5630
5811
  if (keyboardEvent.isComposing) {
5631
5812
  return;
5632
5813
  }
5814
+ if (keyboardEvent.defaultPrevented) {
5815
+ return;
5816
+ }
5633
5817
  for (const item of this.keydownEventList) {
5634
5818
  if (isKeyHotkey(item.type, keyboardEvent)) {
5635
5819
  if (item.listener(keyboardEvent) === false) {
@@ -5643,6 +5827,9 @@ class Keystroke {
5643
5827
  if (keyboardEvent.isComposing) {
5644
5828
  return;
5645
5829
  }
5830
+ if (keyboardEvent.defaultPrevented) {
5831
+ return;
5832
+ }
5646
5833
  for (const item of this.keyupEventList) {
5647
5834
  if (isKeyHotkey(item.type, keyboardEvent)) {
5648
5835
  if (item.listener(keyboardEvent) === false) {
@@ -5652,14 +5839,8 @@ class Keystroke {
5652
5839
  }
5653
5840
  });
5654
5841
  }
5655
- normalizeType(type) {
5656
- var _a;
5657
- type = (_a = aliasMap.get(type)) !== null && _a !== void 0 ? _a : type;
5658
- return type;
5659
- }
5660
5842
  // Sets a keydown shortcut.
5661
5843
  setKeydown(type, listener) {
5662
- type = this.normalizeType(type);
5663
5844
  this.keydownEventList.push({
5664
5845
  type,
5665
5846
  listener,
@@ -5667,7 +5848,6 @@ class Keystroke {
5667
5848
  }
5668
5849
  // Sets a keyup shortcut.
5669
5850
  setKeyup(type, listener) {
5670
- type = this.normalizeType(type);
5671
5851
  this.keyupEventList.push({
5672
5852
  type,
5673
5853
  listener,
@@ -5675,7 +5855,6 @@ class Keystroke {
5675
5855
  }
5676
5856
  // Executes the keydown shortcuts.
5677
5857
  keydown(type) {
5678
- type = this.normalizeType(type);
5679
5858
  for (const item of this.keydownEventList) {
5680
5859
  if (item.type === type) {
5681
5860
  if (item.listener(new KeyboardEvent(type)) === false) {
@@ -5686,7 +5865,6 @@ class Keystroke {
5686
5865
  }
5687
5866
  // Executes the keyup shortcuts.
5688
5867
  keyup(type) {
5689
- type = this.normalizeType(type);
5690
5868
  for (const item of this.keyupEventList) {
5691
5869
  if (item.type === type) {
5692
5870
  if (item.listener(new KeyboardEvent(type)) === false) {
@@ -5711,15 +5889,26 @@ class BoxManager {
5711
5889
 
5712
5890
  class Plugin {
5713
5891
  constructor() {
5714
- this.pluginList = [];
5892
+ this.pluginMap = new Map();
5715
5893
  }
5716
- add(plugin) {
5717
- this.pluginList.push(plugin);
5894
+ add(name, plugin) {
5895
+ if (this.pluginMap.get(name)) {
5896
+ throw new Error(`Plugin "${name}" is already defined.`);
5897
+ }
5898
+ this.pluginMap.set(name, plugin);
5718
5899
  }
5719
5900
  loadAll(editor) {
5720
- for (const plugin of this.pluginList) {
5721
- plugin(editor);
5901
+ const unmountPluginMap = new Map();
5902
+ for (const name of this.pluginMap.keys()) {
5903
+ const plugin = this.pluginMap.get(name);
5904
+ if (plugin && editor.config[name] !== false) {
5905
+ const result = plugin(editor);
5906
+ if (result) {
5907
+ unmountPluginMap.set(name, result);
5908
+ }
5909
+ }
5722
5910
  }
5911
+ return unmountPluginMap;
5723
5912
  }
5724
5913
  }
5725
5914
 
@@ -5749,6 +5938,7 @@ const defaultConfig = {
5749
5938
  console.error(message);
5750
5939
  }
5751
5940
  },
5941
+ slash: false,
5752
5942
  };
5753
5943
  class Editor {
5754
5944
  constructor(config) {
@@ -5760,25 +5950,26 @@ class Editor {
5760
5950
  selectedNameMap: new Map(),
5761
5951
  selectedValuesMap: new Map(),
5762
5952
  };
5953
+ this.unmountPluginMap = new Map();
5763
5954
  this.isComposing = false;
5764
5955
  this.event = new EventEmitter();
5765
5956
  this.box = Editor.box;
5766
5957
  this.copyListener = event => {
5767
- const range = this.selection.range;
5958
+ const range = this.selection.getCurrentRange();
5768
5959
  if (!this.container.contains(range.commonAncestor)) {
5769
5960
  return;
5770
5961
  }
5771
5962
  this.event.emit('copy', event);
5772
5963
  };
5773
5964
  this.cutListener = event => {
5774
- const range = this.selection.range;
5965
+ const range = this.selection.getCurrentRange();
5775
5966
  if (!this.container.contains(range.commonAncestor)) {
5776
5967
  return;
5777
5968
  }
5778
5969
  this.event.emit('cut', event);
5779
5970
  };
5780
5971
  this.pasteListener = event => {
5781
- const range = this.selection.range;
5972
+ const range = this.selection.getCurrentRange();
5782
5973
  if (!this.container.contains(range.commonAncestor)) {
5783
5974
  return;
5784
5975
  }
@@ -5791,7 +5982,7 @@ class Editor {
5791
5982
  };
5792
5983
  this.clickListener = event => {
5793
5984
  const targetNode = new Nodes(event.target);
5794
- if (!targetNode.get(0).isConnected || targetNode.closest('.lake-popup').length > 0) {
5985
+ if (!targetNode.get(0).isConnected) {
5795
5986
  return;
5796
5987
  }
5797
5988
  this.event.emit('click', targetNode);
@@ -5799,6 +5990,9 @@ class Editor {
5799
5990
  this.resizeListener = () => {
5800
5991
  this.event.emit('resize');
5801
5992
  };
5993
+ this.scrollListener = () => {
5994
+ this.event.emit('scroll');
5995
+ };
5802
5996
  this.updateSelectionRange = debounce(() => {
5803
5997
  this.selection.updateByRange();
5804
5998
  }, 1, {
@@ -6116,7 +6310,7 @@ class Editor {
6116
6310
  }
6117
6311
  // Sets default config for a plugin.
6118
6312
  setPluginConfig(name, config) {
6119
- if (!this.config[name]) {
6313
+ if (typeof this.config[name] !== 'object') {
6120
6314
  this.config[name] = {};
6121
6315
  }
6122
6316
  for (const key of Object.keys(config)) {
@@ -6183,17 +6377,11 @@ class Editor {
6183
6377
  });
6184
6378
  this.overlayContainer.find('.lake-artificial-caret').remove();
6185
6379
  this.overlayContainer.append(artificialCaret);
6186
- const position = nodeAndView(artificialCaret);
6187
- // Scrolls the artificial caret element into the visible area of the browser window
6188
- // if it's not already within the visible area of the browser window.
6189
- // If the element is already within the visibposition.rightle area of the browser window, then no scrolling takes place.
6190
- if (position.left < 0 || position.right < 0 || position.top < 0 || position.bottom < 0) {
6191
- artificialCaret.get(0).scrollIntoView({
6192
- behavior: 'instant',
6193
- block: 'center',
6194
- inline: 'nearest',
6195
- });
6196
- }
6380
+ scrollToNode(artificialCaret, {
6381
+ behavior: 'instant',
6382
+ block: 'center',
6383
+ inline: 'nearest',
6384
+ });
6197
6385
  artificialCaret.remove();
6198
6386
  }
6199
6387
  // Sets the specified value to the editor.
@@ -6226,7 +6414,7 @@ class Editor {
6226
6414
  query(document.body).append(this.popupContainer);
6227
6415
  this.togglePlaceholderClass(htmlParser.getHTML());
6228
6416
  this.container.append(fragment);
6229
- Editor.plugin.loadAll(this);
6417
+ this.unmountPluginMap = Editor.plugin.loadAll(this);
6230
6418
  if (!this.readonly) {
6231
6419
  this.selection.updateByBookmark();
6232
6420
  this.history.save({
@@ -6237,30 +6425,53 @@ class Editor {
6237
6425
  if (this.toolbar) {
6238
6426
  this.toolbar.render(this);
6239
6427
  }
6428
+ this.root.on('scroll', this.scrollListener);
6240
6429
  document.addEventListener('copy', this.copyListener);
6430
+ window.addEventListener('resize', this.resizeListener);
6241
6431
  if (!this.readonly) {
6242
6432
  document.addEventListener('cut', this.cutListener);
6243
6433
  document.addEventListener('paste', this.pasteListener);
6244
6434
  document.addEventListener('selectionchange', this.selectionchangeListener);
6245
6435
  document.addEventListener('click', this.clickListener);
6246
- window.addEventListener('resize', this.resizeListener);
6247
6436
  this.bindInputEvents();
6248
6437
  this.bindHistoryEvents();
6249
6438
  }
6250
6439
  }
6251
- // Destroys the rendered editor.
6440
+ // Destroys the editor.
6252
6441
  unmount() {
6442
+ // Executes delayed executions immediately.
6443
+ this.updateSelectionRange.flush();
6444
+ this.updateBoxSelectionStyle.flush();
6445
+ this.emitStateChangeEvent.flush();
6446
+ for (const name of this.unmountPluginMap.keys()) {
6447
+ const unmountPlugin = this.unmountPluginMap.get(name);
6448
+ if (unmountPlugin) {
6449
+ unmountPlugin();
6450
+ debug(`The plugin "${name}" unmounted`);
6451
+ }
6452
+ }
6453
+ if (this.toolbar) {
6454
+ this.toolbar.unmount();
6455
+ }
6456
+ this.removeBoxGarbage();
6457
+ this.container.find('lake-box').each(boxNativeNode => {
6458
+ const boxNode = query(boxNativeNode);
6459
+ const box = getBox(boxNode);
6460
+ box.unmount();
6461
+ });
6253
6462
  this.event.removeAllListeners();
6254
6463
  this.history.event.removeAllListeners();
6464
+ this.root.off();
6465
+ this.root.removeClass('lake-custom-properties');
6255
6466
  this.root.empty();
6256
6467
  this.popupContainer.remove();
6257
6468
  document.removeEventListener('copy', this.copyListener);
6469
+ window.removeEventListener('resize', this.resizeListener);
6258
6470
  if (!this.readonly) {
6259
6471
  document.removeEventListener('cut', this.cutListener);
6260
6472
  document.removeEventListener('paste', this.pasteListener);
6261
6473
  document.removeEventListener('selectionchange', this.selectionchangeListener);
6262
6474
  document.removeEventListener('click', this.clickListener);
6263
- window.removeEventListener('resize', this.resizeListener);
6264
6475
  }
6265
6476
  }
6266
6477
  }
@@ -6907,7 +7118,7 @@ const toolbarItems = [
6907
7118
  },
6908
7119
  ];
6909
7120
 
6910
- const defaultItems = [
7121
+ const defaultItems$1 = [
6911
7122
  'undo',
6912
7123
  'redo',
6913
7124
  '|',
@@ -6938,8 +7149,9 @@ class Toolbar {
6938
7149
  this.allMenuMap = new Map();
6939
7150
  this.buttonItemList = [];
6940
7151
  this.dropdownItemList = [];
7152
+ this.dropdownList = [];
6941
7153
  this.root = query(config.root);
6942
- this.items = config.items || defaultItems;
7154
+ this.items = config.items || defaultItems$1;
6943
7155
  if (config.placement) {
6944
7156
  this.placement = config.placement;
6945
7157
  }
@@ -6949,7 +7161,7 @@ class Toolbar {
6949
7161
  appendDivider() {
6950
7162
  this.container.append('<div class="lake-toolbar-divider" />');
6951
7163
  }
6952
- appendButton(editor, item) {
7164
+ appendNormalButton(editor, item) {
6953
7165
  const button = new Button({
6954
7166
  root: this.container,
6955
7167
  name: item.name,
@@ -6986,8 +7198,9 @@ class Toolbar {
6986
7198
  },
6987
7199
  });
6988
7200
  dropdown.render();
7201
+ this.dropdownList.push(dropdown);
6989
7202
  }
6990
- appendUpload(editor, item) {
7203
+ appendUploadButton(editor, item) {
6991
7204
  const uploadNode = query(safeTemplate `
6992
7205
  <div class="lake-upload" name="${item.name}">
6993
7206
  <input type="file" />
@@ -7089,7 +7302,6 @@ class Toolbar {
7089
7302
  }
7090
7303
  // Renders a toolbar for the specified editor.
7091
7304
  render(editor) {
7092
- this.root.empty();
7093
7305
  this.root.append(this.container);
7094
7306
  for (const name of this.items) {
7095
7307
  if (name === '|') {
@@ -7108,7 +7320,7 @@ class Toolbar {
7108
7320
  }
7109
7321
  if (item.type === 'button') {
7110
7322
  this.buttonItemList.push(item);
7111
- this.appendButton(editor, item);
7323
+ this.appendNormalButton(editor, item);
7112
7324
  }
7113
7325
  else if (item.type === 'dropdown') {
7114
7326
  this.allMenuMap.set(item.name, Dropdown.getMenuMap(item.menuItems, editor.locale));
@@ -7116,21 +7328,26 @@ class Toolbar {
7116
7328
  this.appendDropdown(editor, item);
7117
7329
  }
7118
7330
  else if (item.type === 'upload') {
7119
- this.appendUpload(editor, item);
7331
+ this.appendUploadButton(editor, item);
7120
7332
  }
7121
7333
  }
7122
7334
  }
7123
7335
  }
7336
+ // Destroys the toolbar.
7337
+ unmount() {
7338
+ for (const dropdown of this.dropdownList) {
7339
+ dropdown.unmount();
7340
+ }
7341
+ this.root.removeClass('lake-custom-properties');
7342
+ this.container.remove();
7343
+ }
7124
7344
  }
7125
7345
 
7126
- const hrBox = {
7346
+ var hrBox = {
7127
7347
  type: 'block',
7128
7348
  name: 'hr',
7129
7349
  render: box => {
7130
7350
  const editor = box.getEditor();
7131
- if (!editor) {
7132
- return;
7133
- }
7134
7351
  const boxContainer = box.getContainer();
7135
7352
  const rootNode = query('<div class="lake-hr"><hr /></div>');
7136
7353
  boxContainer.empty();
@@ -7219,15 +7436,12 @@ function getHighlightStyle(CodeMirror) {
7219
7436
  { tag: [tags.special(tags.variableName)], color: config.special },
7220
7437
  ]);
7221
7438
  }
7222
- const codeBlockBox = {
7439
+ var codeBlockBox = {
7223
7440
  type: 'block',
7224
7441
  name: 'codeBlock',
7225
7442
  render: box => {
7226
7443
  var _a;
7227
7444
  const editor = box.getEditor();
7228
- if (!editor) {
7229
- return;
7230
- }
7231
7445
  const rootNode = query('<div class="lake-code-block" />');
7232
7446
  const boxContainer = box.getContainer();
7233
7447
  boxContainer.css('width', `${editor.container.innerWidth() - 2}px`);
@@ -7334,6 +7548,7 @@ const codeBlockBox = {
7334
7548
  codeEditor.focus();
7335
7549
  });
7336
7550
  box.event.on('beforeunmount', () => {
7551
+ dropdown.unmount();
7337
7552
  codeEditor.destroy();
7338
7553
  editor.event.off('resize', resizeListener);
7339
7554
  debug('CodeMirror destroyed');
@@ -7411,7 +7626,11 @@ class BoxResizer {
7411
7626
  const pointerNativeNode = pointerNode.get(0);
7412
7627
  // The capture will be implicitly released after a pointerup or pointercancel event.
7413
7628
  // https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture
7414
- pointerNativeNode.setPointerCapture(pointerEvent.pointerId);
7629
+ try {
7630
+ // Test case throws an exception on Firefox.
7631
+ pointerNativeNode.setPointerCapture(pointerEvent.pointerId);
7632
+ }
7633
+ catch ( /* empty */_a) { /* empty */ }
7415
7634
  clientX = pointerEvent.clientX;
7416
7635
  width = boxContainer.width();
7417
7636
  infoNode.show();
@@ -7491,9 +7710,6 @@ function getImageInfo(url) {
7491
7710
  // Opens full screen view.
7492
7711
  function openFullScreen(box) {
7493
7712
  const editor = box.getEditor();
7494
- if (!editor) {
7495
- return;
7496
- }
7497
7713
  const dataSource = [];
7498
7714
  let currentIndex = 0;
7499
7715
  const allImageBox = editor.container.find('lake-box[name="image"]');
@@ -7584,9 +7800,6 @@ function openFullScreen(box) {
7584
7800
  function renderError$1(rootNode, box) {
7585
7801
  return __awaiter(this, void 0, void 0, function* () {
7586
7802
  const editor = box.getEditor();
7587
- if (!editor) {
7588
- return;
7589
- }
7590
7803
  const value = box.value;
7591
7804
  box.getContainer().css({
7592
7805
  width: '',
@@ -7620,9 +7833,6 @@ function renderError$1(rootNode, box) {
7620
7833
  function renderUploading(rootNode, box) {
7621
7834
  return __awaiter(this, void 0, void 0, function* () {
7622
7835
  const editor = box.getEditor();
7623
- if (!editor) {
7624
- return;
7625
- }
7626
7836
  const value = box.value;
7627
7837
  const imageInfo = yield getImageInfo(value.url);
7628
7838
  if (!imageInfo.width || !imageInfo.height) {
@@ -7680,9 +7890,6 @@ function renderUploading(rootNode, box) {
7680
7890
  function renderDone(rootNode, box) {
7681
7891
  return __awaiter(this, void 0, void 0, function* () {
7682
7892
  const editor = box.getEditor();
7683
- if (!editor) {
7684
- return;
7685
- }
7686
7893
  const boxContainer = box.getContainer();
7687
7894
  const value = box.value;
7688
7895
  const imageInfo = yield getImageInfo(value.url);
@@ -7750,14 +7957,11 @@ function renderDone(rootNode, box) {
7750
7957
  rootNode.append(imgNode);
7751
7958
  });
7752
7959
  }
7753
- const imageBox = {
7960
+ var imageBox = {
7754
7961
  type: 'inline',
7755
7962
  name: 'image',
7756
7963
  render: box => {
7757
7964
  const editor = box.getEditor();
7758
- if (!editor) {
7759
- return;
7760
- }
7761
7965
  const value = box.value;
7762
7966
  if (editor.readonly && ['uploading', 'loading', 'error'].indexOf(value.status) >= 0) {
7763
7967
  box.node.hide();
@@ -7830,16 +8034,8 @@ function getVideoId(url) {
7830
8034
  const result = /\w+$/i.exec(url || '');
7831
8035
  return result ? result[0] : '';
7832
8036
  }
7833
- function getInputValue(videoNode, name) {
7834
- const inputElement = videoNode.find(`input[name="${name}"]`);
7835
- const nativeInputElement = inputElement.get(0);
7836
- return nativeInputElement.value;
7837
- }
7838
8037
  function appendButtonGroup(box) {
7839
8038
  const editor = box.getEditor();
7840
- if (!editor) {
7841
- return;
7842
- }
7843
8039
  const boxContainer = box.getContainer();
7844
8040
  const videoNode = boxContainer.find('.lake-video');
7845
8041
  const buttonGroupNode = query(safeTemplate `
@@ -7861,9 +8057,6 @@ function appendButtonGroup(box) {
7861
8057
  }
7862
8058
  function showVideo(box) {
7863
8059
  const editor = box.getEditor();
7864
- if (!editor) {
7865
- return;
7866
- }
7867
8060
  const boxContainer = box.getContainer();
7868
8061
  const value = box.value;
7869
8062
  const width = value.width || 560;
@@ -7912,14 +8105,11 @@ function showVideo(box) {
7912
8105
  }
7913
8106
  rootNode.append(iframeNode);
7914
8107
  }
7915
- const videoBox = {
8108
+ var videoBox = {
7916
8109
  type: 'inline',
7917
8110
  name: 'video',
7918
8111
  render: box => {
7919
8112
  const editor = box.getEditor();
7920
- if (!editor) {
7921
- return;
7922
- }
7923
8113
  const locale = editor.locale;
7924
8114
  const value = box.value;
7925
8115
  const boxContainer = box.getContainer();
@@ -7951,7 +8141,7 @@ const videoBox = {
7951
8141
  type: 'primary',
7952
8142
  text: locale.video.embed(),
7953
8143
  onClick: () => {
7954
- const url = getInputValue(formNode, 'url');
8144
+ const url = formNode.find('input[name="url"]').value();
7955
8145
  if (url.indexOf('https://www.youtube.com/') < 0 || getVideoId(url) === '') {
7956
8146
  editor.config.onMessage('error', locale.video.urlError());
7957
8147
  return;
@@ -7995,9 +8185,6 @@ const boxToolbarItems = [
7995
8185
  tooltip: locale => locale.file.remove(),
7996
8186
  onClick: box => {
7997
8187
  const editor = box.getEditor();
7998
- if (!editor) {
7999
- return;
8000
- }
8001
8188
  editor.selection.removeBox(box);
8002
8189
  editor.history.save();
8003
8190
  },
@@ -8005,10 +8192,6 @@ const boxToolbarItems = [
8005
8192
  ];
8006
8193
  function appendContent(rootNode, box) {
8007
8194
  return __awaiter(this, void 0, void 0, function* () {
8008
- const editor = box.getEditor();
8009
- if (!editor) {
8010
- return;
8011
- }
8012
8195
  const value = box.value;
8013
8196
  const infoNode = query(safeTemplate `
8014
8197
  <div class="lake-file-info">
@@ -8039,14 +8222,11 @@ function appendContent(rootNode, box) {
8039
8222
  rootNode.append(infoNode);
8040
8223
  });
8041
8224
  }
8042
- const fileBox = {
8225
+ var fileBox = {
8043
8226
  type: 'inline',
8044
8227
  name: 'file',
8045
8228
  render: box => {
8046
8229
  const editor = box.getEditor();
8047
- if (!editor) {
8048
- return;
8049
- }
8050
8230
  const value = box.value;
8051
8231
  if (editor.readonly && ['uploading', 'error'].indexOf(value.status) >= 0) {
8052
8232
  box.node.hide();
@@ -8073,14 +8253,11 @@ const fileBox = {
8073
8253
  },
8074
8254
  };
8075
8255
 
8076
- const emojiBox = {
8256
+ var emojiBox = {
8077
8257
  type: 'inline',
8078
8258
  name: 'emoji',
8079
8259
  render: box => {
8080
8260
  const editor = box.getEditor();
8081
- if (!editor) {
8082
- return;
8083
- }
8084
8261
  const value = box.value;
8085
8262
  const boxContainer = box.getContainer();
8086
8263
  const rootNode = query(safeTemplate `
@@ -8097,9 +8274,6 @@ const emojiBox = {
8097
8274
  const defaultExpression = String.raw `\sqrt{x}`;
8098
8275
  function renderError(box) {
8099
8276
  const editor = box.getEditor();
8100
- if (!editor) {
8101
- return;
8102
- }
8103
8277
  if (editor.readonly) {
8104
8278
  box.node.hide();
8105
8279
  return;
@@ -8116,14 +8290,11 @@ function renderError(box) {
8116
8290
  Please check if the "katex" library is added to this page.
8117
8291
  `.trim());
8118
8292
  }
8119
- const equationBox = {
8293
+ var equationBox = {
8120
8294
  type: 'inline',
8121
8295
  name: 'equation',
8122
8296
  render: box => {
8123
8297
  const editor = box.getEditor();
8124
- if (!editor) {
8125
- return;
8126
- }
8127
8298
  const rootNode = query('<div class="lake-equation" />');
8128
8299
  const boxContainer = box.getContainer();
8129
8300
  boxContainer.empty();
@@ -8152,10 +8323,9 @@ const equationBox = {
8152
8323
  `);
8153
8324
  rootNode.append(formNode);
8154
8325
  const textareaNode = formNode.find('textarea');
8155
- const textareaNativeNode = textareaNode.get(0);
8156
- textareaNativeNode.value = defaultCode;
8326
+ textareaNode.value(defaultCode);
8157
8327
  textareaNode.on('input', () => {
8158
- const code = textareaNativeNode.value.trim();
8328
+ const code = textareaNode.value().trim();
8159
8329
  viewNode.html(window.katex.renderToString(code || defaultExpression, {
8160
8330
  throwOnError: false,
8161
8331
  }));
@@ -9137,8 +9307,7 @@ var formatPainter = (editor) => {
9137
9307
  if (editor.container.contains(targetNode)) {
9138
9308
  return;
9139
9309
  }
9140
- const buttonNode = targetNode.closest('button[name="formatPainter"]');
9141
- if (buttonNode.length > 0) {
9310
+ if (targetNode.closest('button[name="formatPainter"]').length > 0) {
9142
9311
  return;
9143
9312
  }
9144
9313
  editor.container.removeClass(formatPainterClassName);
@@ -9199,7 +9368,7 @@ class LinkPopup {
9199
9368
  if (!this.linkNode) {
9200
9369
  return;
9201
9370
  }
9202
- const url = this.getInputValue('url');
9371
+ const url = this.container.find('input[name="url"]').value();
9203
9372
  this.writeClipboardText(url).then((error) => {
9204
9373
  const svgNode = this.container.find('button[name="copy"] svg');
9205
9374
  svgNode.hide();
@@ -9245,7 +9414,7 @@ class LinkPopup {
9245
9414
  if (!this.linkNode) {
9246
9415
  return;
9247
9416
  }
9248
- const url = this.getInputValue('url');
9417
+ const url = this.container.find('input[name="url"]').value();
9249
9418
  window.open(url);
9250
9419
  },
9251
9420
  });
@@ -9305,22 +9474,15 @@ class LinkPopup {
9305
9474
  });
9306
9475
  button.render();
9307
9476
  }
9308
- getInputValue(name) {
9309
- const inputElement = this.container.find(`input[name="${name}"]`);
9310
- const nativeInputElement = inputElement.get(0);
9311
- return nativeInputElement.value;
9312
- }
9313
- setInputValue(name, value) {
9314
- const inputElement = this.container.find(`input[name="${name}"]`);
9315
- const nativeInputElement = inputElement.get(0);
9316
- nativeInputElement.value = value;
9477
+ get visible() {
9478
+ return this.container.get(0).isConnected && this.container.computedCSS('display') !== 'none';
9317
9479
  }
9318
9480
  save() {
9319
9481
  if (!this.linkNode) {
9320
9482
  return;
9321
9483
  }
9322
- const url = this.getInputValue('url');
9323
- let title = this.getInputValue('title');
9484
+ const url = this.container.find('input[name="url"]').value();
9485
+ let title = this.container.find('input[name="title"]').value();
9324
9486
  if (url === '' && title === '') {
9325
9487
  this.linkNode.remove();
9326
9488
  return;
@@ -9331,32 +9493,27 @@ class LinkPopup {
9331
9493
  this.linkNode.attr('href', url);
9332
9494
  this.linkNode.text(title);
9333
9495
  }
9334
- updatePosition() {
9496
+ position() {
9335
9497
  if (!this.linkNode) {
9336
9498
  return;
9337
9499
  }
9338
- const position = nodeAndView(this.linkNode);
9500
+ const position = nodePosition(this.linkNode);
9339
9501
  if (position.left < 0 || position.right < 0 || position.top < 0 || position.bottom < 0) {
9340
9502
  this.container.css('visibility', 'hidden');
9341
9503
  return;
9342
9504
  }
9343
9505
  this.container.css('visibility', '');
9344
9506
  const linkNativeNode = this.linkNode.get(0);
9345
- // Returns a DOMRect object providing information about the size of an element and its position relative to the viewport.
9346
9507
  const linkRect = linkNativeNode.getBoundingClientRect();
9347
9508
  const linkX = linkRect.x + window.scrollX;
9348
9509
  const linkY = linkRect.y + window.scrollY;
9349
- // link.x + popup.width > window.width
9350
9510
  if (linkRect.x + this.container.width() > window.innerWidth) {
9351
- // link.x + window.scrollX - (popup.width - link.width)
9352
9511
  this.container.css('left', `${linkX - this.container.width() + linkRect.width}px`);
9353
9512
  }
9354
9513
  else {
9355
9514
  this.container.css('left', `${linkX}px`);
9356
9515
  }
9357
- // link.y + link.height + popup.height > window.height
9358
9516
  if (linkRect.y + linkRect.height + this.container.height() > window.innerHeight) {
9359
- // link.y + window.scrollY - popup.height
9360
9517
  this.container.css('top', `${linkY - this.container.height()}px`);
9361
9518
  }
9362
9519
  else {
@@ -9380,13 +9537,13 @@ class LinkPopup {
9380
9537
  this.linkNode = linkNode;
9381
9538
  const url = linkNode.attr('href');
9382
9539
  const title = linkNode.text();
9383
- this.setInputValue('url', url);
9540
+ this.container.find('input[name="url"]').value(url);
9384
9541
  if (title !== url) {
9385
- this.setInputValue('title', title);
9542
+ this.container.find('input[name="title"]').value(title);
9386
9543
  }
9387
9544
  this.container.css('visibility', 'hidden');
9388
9545
  this.container.show();
9389
- this.updatePosition();
9546
+ this.position();
9390
9547
  this.container.css('visibility', '');
9391
9548
  this.container.find('input[name="url"]').focus();
9392
9549
  }
@@ -9407,31 +9564,38 @@ var link = (editor) => {
9407
9564
  const range = editor.selection.range;
9408
9565
  range.setStartAfter(node);
9409
9566
  range.collapseToStart();
9567
+ editor.selection.sync();
9410
9568
  editor.history.save();
9411
9569
  },
9412
9570
  onRemove: node => {
9413
9571
  const range = editor.selection.range;
9414
9572
  range.setStartAfter(node);
9415
9573
  range.collapseToStart();
9574
+ editor.selection.sync();
9416
9575
  editor.history.save();
9417
9576
  },
9418
9577
  });
9419
- editor.root.on('scroll', () => {
9420
- popup.updatePosition();
9578
+ editor.event.on('scroll', () => {
9579
+ popup.position();
9421
9580
  });
9422
9581
  editor.event.on('resize', () => {
9423
- popup.updatePosition();
9582
+ popup.position();
9424
9583
  });
9425
9584
  editor.event.on('click', (targetNode) => {
9426
- if (targetNode.closest('button[name="link"]').length > 0) {
9585
+ if (popup.container.contains(targetNode)) {
9427
9586
  return;
9428
9587
  }
9429
- const linkNode = targetNode.closest('a');
9430
- if (linkNode.length === 0) {
9431
- popup.hide();
9588
+ if (targetNode.closest('button[name="link"]').length > 0) {
9432
9589
  return;
9433
9590
  }
9434
- if (!editor.container.contains(linkNode) || linkNode.closest('lake-box').length > 0) {
9591
+ const linkNode = targetNode.closest('a');
9592
+ if (linkNode.length === 0 ||
9593
+ !editor.container.contains(linkNode) ||
9594
+ linkNode.closest('lake-box').length > 0) {
9595
+ if (!popup.visible) {
9596
+ return;
9597
+ }
9598
+ editor.selection.sync();
9435
9599
  popup.hide();
9436
9600
  return;
9437
9601
  }
@@ -9613,8 +9777,10 @@ var equation = (editor) => {
9613
9777
  editor.command.add('equation', {
9614
9778
  execute: (value) => {
9615
9779
  const box = editor.selection.insertBox('equation', value);
9616
- editor.selection.selectBox(box);
9617
9780
  editor.history.save();
9781
+ const boxContainer = box.getContainer();
9782
+ boxContainer.addClass('lake-box-activated');
9783
+ boxContainer.find('textarea').focus();
9618
9784
  },
9619
9785
  });
9620
9786
  };
@@ -10435,7 +10601,7 @@ var arrowKeys = (editor) => {
10435
10601
  if (editor.readonly) {
10436
10602
  return;
10437
10603
  }
10438
- editor.keystroke.setKeydown('arrow-left', event => {
10604
+ editor.keystroke.setKeydown('left', event => {
10439
10605
  const range = editor.selection.range;
10440
10606
  if (range.isInsideBox) {
10441
10607
  return;
@@ -10475,7 +10641,7 @@ var arrowKeys = (editor) => {
10475
10641
  range.selectBox(prevNode);
10476
10642
  }
10477
10643
  });
10478
- editor.keystroke.setKeydown('arrow-right', event => {
10644
+ editor.keystroke.setKeydown('right', event => {
10479
10645
  const range = editor.selection.range;
10480
10646
  if (range.isInsideBox) {
10481
10647
  return;
@@ -10515,7 +10681,7 @@ var arrowKeys = (editor) => {
10515
10681
  range.selectBox(nextNode);
10516
10682
  }
10517
10683
  });
10518
- editor.keystroke.setKeydown('arrow-up', event => {
10684
+ editor.keystroke.setKeydown('up', event => {
10519
10685
  const range = editor.selection.range;
10520
10686
  if (range.isInsideBox) {
10521
10687
  return;
@@ -10534,7 +10700,7 @@ var arrowKeys = (editor) => {
10534
10700
  range.collapseToStart();
10535
10701
  }
10536
10702
  });
10537
- editor.keystroke.setKeydown('arrow-down', event => {
10703
+ editor.keystroke.setKeydown('down', event => {
10538
10704
  const range = editor.selection.range;
10539
10705
  if (range.isInsideBox) {
10540
10706
  return;
@@ -10576,6 +10742,539 @@ var escapeKey = (editor) => {
10576
10742
  });
10577
10743
  };
10578
10744
 
10745
+ const slashItems = [
10746
+ {
10747
+ name: 'heading1',
10748
+ type: 'button',
10749
+ icon: icons.get('heading1'),
10750
+ title: locale => locale.slash.heading1(),
10751
+ description: locale => locale.slash.heading1Desc(),
10752
+ onClick: editor => {
10753
+ editor.command.execute('heading', 'h1');
10754
+ },
10755
+ },
10756
+ {
10757
+ name: 'heading2',
10758
+ type: 'button',
10759
+ icon: icons.get('heading2'),
10760
+ title: locale => locale.slash.heading2(),
10761
+ description: locale => locale.slash.heading2Desc(),
10762
+ onClick: editor => {
10763
+ editor.command.execute('heading', 'h2');
10764
+ },
10765
+ },
10766
+ {
10767
+ name: 'heading3',
10768
+ type: 'button',
10769
+ icon: icons.get('heading3'),
10770
+ title: locale => locale.slash.heading3(),
10771
+ description: locale => locale.slash.heading3Desc(),
10772
+ onClick: editor => {
10773
+ editor.command.execute('heading', 'h3');
10774
+ },
10775
+ },
10776
+ {
10777
+ name: 'heading4',
10778
+ type: 'button',
10779
+ icon: icons.get('heading4'),
10780
+ title: locale => locale.slash.heading4(),
10781
+ description: locale => locale.slash.heading4Desc(),
10782
+ onClick: editor => {
10783
+ editor.command.execute('heading', 'h4');
10784
+ },
10785
+ },
10786
+ {
10787
+ name: 'heading5',
10788
+ type: 'button',
10789
+ icon: icons.get('heading5'),
10790
+ title: locale => locale.slash.heading5(),
10791
+ description: locale => locale.slash.heading5Desc(),
10792
+ onClick: editor => {
10793
+ editor.command.execute('heading', 'h5');
10794
+ },
10795
+ },
10796
+ {
10797
+ name: 'heading6',
10798
+ type: 'button',
10799
+ icon: icons.get('heading6'),
10800
+ title: locale => locale.slash.heading6(),
10801
+ description: locale => locale.slash.heading6Desc(),
10802
+ onClick: editor => {
10803
+ editor.command.execute('heading', 'h6');
10804
+ },
10805
+ },
10806
+ {
10807
+ name: 'paragraph',
10808
+ type: 'button',
10809
+ icon: icons.get('paragraph'),
10810
+ title: locale => locale.slash.paragraph(),
10811
+ description: locale => locale.slash.paragraphDesc(),
10812
+ onClick: editor => {
10813
+ editor.command.execute('heading', 'p');
10814
+ },
10815
+ },
10816
+ {
10817
+ name: 'blockQuote',
10818
+ type: 'button',
10819
+ icon: icons.get('blockQuote'),
10820
+ title: locale => locale.slash.blockQuote(),
10821
+ description: locale => locale.slash.blockQuoteDesc(),
10822
+ onClick: (editor, value) => {
10823
+ editor.command.execute(value);
10824
+ },
10825
+ },
10826
+ {
10827
+ name: 'numberedList',
10828
+ type: 'button',
10829
+ icon: icons.get('numberedList'),
10830
+ title: locale => locale.slash.numberedList(),
10831
+ description: locale => locale.slash.numberedListDesc(),
10832
+ onClick: editor => {
10833
+ editor.command.execute('list', 'numbered');
10834
+ },
10835
+ },
10836
+ {
10837
+ name: 'bulletedList',
10838
+ type: 'button',
10839
+ icon: icons.get('bulletedList'),
10840
+ title: locale => locale.slash.bulletedList(),
10841
+ description: locale => locale.slash.bulletedListDesc(),
10842
+ onClick: editor => {
10843
+ editor.command.execute('list', 'bulleted');
10844
+ },
10845
+ },
10846
+ {
10847
+ name: 'checklist',
10848
+ type: 'button',
10849
+ icon: icons.get('checklist'),
10850
+ title: locale => locale.slash.checklist(),
10851
+ description: locale => locale.slash.checklistDesc(),
10852
+ onClick: editor => {
10853
+ editor.command.execute('list', 'checklist');
10854
+ },
10855
+ },
10856
+ {
10857
+ name: 'hr',
10858
+ type: 'button',
10859
+ icon: icons.get('hr'),
10860
+ title: locale => locale.slash.hr(),
10861
+ description: locale => locale.slash.hrDesc(),
10862
+ onClick: (editor, value) => {
10863
+ editor.command.execute(value);
10864
+ },
10865
+ },
10866
+ {
10867
+ name: 'codeBlock',
10868
+ type: 'button',
10869
+ icon: icons.get('codeBlock'),
10870
+ title: locale => locale.slash.codeBlock(),
10871
+ description: locale => locale.slash.codeBlockDesc(),
10872
+ onClick: (editor, value) => {
10873
+ editor.command.execute(value);
10874
+ },
10875
+ },
10876
+ {
10877
+ name: 'video',
10878
+ type: 'button',
10879
+ icon: icons.get('video'),
10880
+ title: locale => locale.slash.video(),
10881
+ description: locale => locale.slash.videoDesc(),
10882
+ onClick: (editor, value) => {
10883
+ editor.command.execute(value);
10884
+ },
10885
+ },
10886
+ {
10887
+ name: 'equation',
10888
+ type: 'button',
10889
+ icon: icons.get('equation'),
10890
+ title: locale => locale.slash.equation(),
10891
+ description: locale => locale.slash.equationDesc(),
10892
+ onClick: (editor, value) => {
10893
+ editor.command.execute(value);
10894
+ },
10895
+ },
10896
+ {
10897
+ name: 'image',
10898
+ type: 'upload',
10899
+ icon: icons.get('image'),
10900
+ title: locale => locale.slash.image(),
10901
+ description: locale => locale.slash.imageDesc(),
10902
+ accept: 'image/*',
10903
+ multiple: true,
10904
+ },
10905
+ {
10906
+ name: 'file',
10907
+ type: 'upload',
10908
+ icon: icons.get('attachment'),
10909
+ title: locale => locale.slash.file(),
10910
+ description: locale => locale.slash.fileDesc(),
10911
+ accept: '*',
10912
+ multiple: true,
10913
+ },
10914
+ ];
10915
+
10916
+ const slashItemMap = new Map();
10917
+ for (const item of slashItems) {
10918
+ slashItemMap.set(item.name, item);
10919
+ }
10920
+ class SlashPopup {
10921
+ constructor(config) {
10922
+ this.range = null;
10923
+ this.noMouseEvent = false;
10924
+ this.keyword = null;
10925
+ this.keydownListener = (event) => {
10926
+ if (isKeyHotkey('escape', event)) {
10927
+ event.preventDefault();
10928
+ this.hide();
10929
+ return;
10930
+ }
10931
+ const isDownKey = isKeyHotkey('down', event);
10932
+ const isUpKey = isKeyHotkey('up', event);
10933
+ const isEnterKey = isKeyHotkey('enter', event);
10934
+ if (!isDownKey && !isUpKey && !isEnterKey) {
10935
+ return;
10936
+ }
10937
+ const selectedItemNode = this.container.find('.lake-slash-item-selected');
10938
+ if (selectedItemNode.length === 0) {
10939
+ const firstItem = this.container.find('.lake-slash-item').eq(0);
10940
+ scrollToNode(firstItem, {
10941
+ behavior: 'instant',
10942
+ block: 'start',
10943
+ });
10944
+ firstItem.addClass('lake-slash-item-selected');
10945
+ return;
10946
+ }
10947
+ this.noMouseEvent = true;
10948
+ if (isDownKey) {
10949
+ event.preventDefault();
10950
+ let nextItemNode = selectedItemNode.next();
10951
+ if (nextItemNode.length === 0) {
10952
+ nextItemNode = this.container.find('.lake-slash-item').eq(0);
10953
+ }
10954
+ scrollToNode(nextItemNode, {
10955
+ behavior: 'instant',
10956
+ block: 'end',
10957
+ });
10958
+ this.container.find('.lake-slash-item').removeClass('lake-slash-item-selected');
10959
+ nextItemNode.addClass('lake-slash-item-selected');
10960
+ }
10961
+ else if (isUpKey) {
10962
+ event.preventDefault();
10963
+ let prevItemNode = selectedItemNode.prev();
10964
+ if (prevItemNode.length === 0) {
10965
+ const itemNode = this.container.find('.lake-slash-item');
10966
+ prevItemNode = itemNode.eq(itemNode.length - 1);
10967
+ }
10968
+ scrollToNode(prevItemNode, {
10969
+ behavior: 'instant',
10970
+ block: 'start',
10971
+ });
10972
+ this.container.find('.lake-slash-item').removeClass('lake-slash-item-selected');
10973
+ prevItemNode.addClass('lake-slash-item-selected');
10974
+ }
10975
+ else if (isEnterKey) {
10976
+ event.preventDefault();
10977
+ selectedItemNode.emit('click');
10978
+ }
10979
+ window.setTimeout(() => {
10980
+ this.noMouseEvent = false;
10981
+ }, 50);
10982
+ };
10983
+ this.clickListener = (targetNode) => {
10984
+ if (this.container.contains(targetNode)) {
10985
+ return;
10986
+ }
10987
+ this.hide();
10988
+ };
10989
+ this.scrollListener = () => this.position();
10990
+ this.resizeListener = () => this.position();
10991
+ this.editor = config.editor;
10992
+ this.items = config.items;
10993
+ this.root = config.editor.popupContainer;
10994
+ this.container = query('<ul class="lake-slash-popup" />');
10995
+ }
10996
+ getItem(name) {
10997
+ if (typeof name !== 'string') {
10998
+ return name;
10999
+ }
11000
+ const item = slashItemMap.get(name);
11001
+ if (!item) {
11002
+ throw new Error(`SlashItem "${name}" has not been defined yet.`);
11003
+ }
11004
+ return item;
11005
+ }
11006
+ emptyBlock() {
11007
+ const range = this.editor.selection.range;
11008
+ const block = range.commonAncestor.closestBlock();
11009
+ this.hide();
11010
+ block.empty();
11011
+ appendBreak(block);
11012
+ range.shrinkBefore(block);
11013
+ }
11014
+ appendItem(item) {
11015
+ const editor = this.editor;
11016
+ const itemTitle = typeof item.title === 'string' ? item.title : item.title(editor.locale);
11017
+ const itemDescription = typeof item.description === 'string' ? item.description : item.description(editor.locale);
11018
+ const itemNode = query(safeTemplate `
11019
+ <li class="lake-slash-item" name="${item.name}">
11020
+ <div class="lake-slash-icon"></div>
11021
+ <div class="lake-slash-text">
11022
+ <div class="lake-slash-title">${itemTitle}</div>
11023
+ <div class="lake-slash-description">${itemDescription}</div>
11024
+ </div>
11025
+ </li>
11026
+ `);
11027
+ const icon = item.icon;
11028
+ if (icon) {
11029
+ itemNode.find('.lake-slash-icon').append(icon);
11030
+ }
11031
+ this.container.append(itemNode);
11032
+ itemNode.on('mouseenter', () => {
11033
+ if (this.noMouseEvent) {
11034
+ return;
11035
+ }
11036
+ this.container.find('.lake-slash-item').removeClass('lake-slash-item-selected');
11037
+ itemNode.addClass('lake-slash-item-selected');
11038
+ });
11039
+ itemNode.on('mouseleave', () => {
11040
+ if (this.noMouseEvent) {
11041
+ return;
11042
+ }
11043
+ itemNode.removeClass('lake-slash-item-selected');
11044
+ });
11045
+ if (item.type === 'upload') {
11046
+ itemNode.append('<input type="file" />');
11047
+ const fileNode = itemNode.find('input[type="file"]');
11048
+ const fileNativeNode = fileNode.get(0);
11049
+ if (item.accept) {
11050
+ fileNode.attr('accept', item.accept);
11051
+ }
11052
+ if (item.multiple === true) {
11053
+ fileNode.attr('multiple', 'true');
11054
+ }
11055
+ fileNode.on('click', event => event.stopPropagation());
11056
+ fileNode.on('change', event => {
11057
+ editor.focus();
11058
+ this.emptyBlock();
11059
+ const target = event.target;
11060
+ const files = target.files || [];
11061
+ for (const file of files) {
11062
+ uploadFile({
11063
+ editor,
11064
+ name: item.name,
11065
+ file,
11066
+ onError: error => editor.config.onMessage('error', error),
11067
+ });
11068
+ }
11069
+ });
11070
+ itemNode.on('click', () => {
11071
+ fileNativeNode.click();
11072
+ });
11073
+ }
11074
+ else {
11075
+ itemNode.on('click', () => {
11076
+ editor.focus();
11077
+ this.emptyBlock();
11078
+ item.onClick(editor, item.name);
11079
+ });
11080
+ }
11081
+ }
11082
+ get visible() {
11083
+ return this.container.get(0).isConnected && this.container.computedCSS('display') !== 'none';
11084
+ }
11085
+ search(keyword) {
11086
+ const editor = this.editor;
11087
+ const localeEnglish = i18nObject('en-US');
11088
+ keyword = keyword.toLowerCase();
11089
+ const items = [];
11090
+ for (const name of this.items) {
11091
+ const item = this.getItem(name);
11092
+ let itemTitle = typeof item.title === 'string' ? item.title : item.title(editor.locale);
11093
+ itemTitle = itemTitle.toLowerCase();
11094
+ let itemTitleEnglish = typeof item.title === 'string' ? item.title : item.title(localeEnglish);
11095
+ itemTitleEnglish = itemTitleEnglish.toLowerCase();
11096
+ if (itemTitle.indexOf(keyword) >= 0 ||
11097
+ itemTitle.replace(/\s+/g, '').indexOf(keyword) >= 0 ||
11098
+ itemTitleEnglish.indexOf(keyword) >= 0 ||
11099
+ itemTitleEnglish.replace(/\s+/g, '').indexOf(keyword) >= 0) {
11100
+ items.push(typeof name === 'string' ? item.name : name);
11101
+ }
11102
+ }
11103
+ return items;
11104
+ }
11105
+ position() {
11106
+ if (!this.range) {
11107
+ return;
11108
+ }
11109
+ this.container.css('visibility', '');
11110
+ const rangeRect = this.range.get().getBoundingClientRect();
11111
+ const rangeX = rangeRect.x + window.scrollX;
11112
+ const rangeY = rangeRect.y + window.scrollY;
11113
+ if (rangeRect.x + this.container.width() > window.innerWidth) {
11114
+ this.container.css('left', `${rangeX - this.container.width() + rangeRect.width}px`);
11115
+ }
11116
+ else {
11117
+ this.container.css('left', `${rangeX}px`);
11118
+ }
11119
+ if (rangeRect.y + rangeRect.height + this.container.height() > window.innerHeight) {
11120
+ this.container.css('top', `${rangeY - this.container.height() - 5}px`);
11121
+ }
11122
+ else {
11123
+ this.container.css('top', `${rangeY + rangeRect.height + 5}px`);
11124
+ }
11125
+ }
11126
+ render() {
11127
+ this.root.append(this.container);
11128
+ this.update();
11129
+ }
11130
+ update(keyword = null) {
11131
+ if (keyword !== null && this.keyword === keyword) {
11132
+ return;
11133
+ }
11134
+ const items = keyword !== null ? this.search(keyword) : this.items;
11135
+ if (items.length === 0) {
11136
+ this.hide();
11137
+ return;
11138
+ }
11139
+ this.keyword = keyword;
11140
+ this.container.empty();
11141
+ for (const name of items) {
11142
+ const item = this.getItem(name);
11143
+ this.appendItem(item);
11144
+ }
11145
+ const selectedItemNode = this.container.find('.lake-slash-item-selected');
11146
+ if (selectedItemNode.length === 0) {
11147
+ this.container.find('.lake-slash-item').eq(0).addClass('lake-slash-item-selected');
11148
+ }
11149
+ this.position();
11150
+ }
11151
+ show(range, keyword) {
11152
+ const editor = this.editor;
11153
+ if (this.root.find('.lake-slash-popup').length === 0) {
11154
+ this.render();
11155
+ }
11156
+ else {
11157
+ this.update();
11158
+ }
11159
+ this.range = range;
11160
+ this.container.css('visibility', 'hidden');
11161
+ this.container.show();
11162
+ this.position();
11163
+ // for fixing the container's width
11164
+ this.container.css('width', '');
11165
+ this.container.css('width', `${this.container.width()}px`);
11166
+ if (keyword) {
11167
+ this.update(keyword);
11168
+ }
11169
+ this.container.css('visibility', '');
11170
+ document.addEventListener('keydown', this.keydownListener, true);
11171
+ editor.event.on('click', this.clickListener);
11172
+ editor.event.on('scroll', this.scrollListener);
11173
+ editor.event.on('resize', this.resizeListener);
11174
+ }
11175
+ hide() {
11176
+ const editor = this.editor;
11177
+ this.range = null;
11178
+ this.container.hide();
11179
+ document.removeEventListener('keydown', this.keydownListener, true);
11180
+ editor.event.off('click', this.clickListener);
11181
+ editor.event.off('scroll', this.scrollListener);
11182
+ editor.event.off('resize', this.resizeListener);
11183
+ }
11184
+ unmount() {
11185
+ this.hide();
11186
+ this.container.remove();
11187
+ }
11188
+ }
11189
+
11190
+ const defaultItems = [
11191
+ 'heading1',
11192
+ 'heading2',
11193
+ 'heading3',
11194
+ 'heading4',
11195
+ 'heading5',
11196
+ 'heading6',
11197
+ 'paragraph',
11198
+ 'blockQuote',
11199
+ 'numberedList',
11200
+ 'bulletedList',
11201
+ 'checklist',
11202
+ 'hr',
11203
+ ];
11204
+ function getKeyword(block) {
11205
+ let text = block.text().trim();
11206
+ text = text.replace(/[\u200B\u2060]/g, '');
11207
+ if (!/^\//.test(text)) {
11208
+ return null;
11209
+ }
11210
+ return text.substring(1);
11211
+ }
11212
+ function showPopup(editor, popup) {
11213
+ const range = editor.selection.range;
11214
+ if (!range.isCollapsed) {
11215
+ return;
11216
+ }
11217
+ const block = range.getBlocks()[0];
11218
+ if (!block) {
11219
+ return;
11220
+ }
11221
+ if (block.find('lake-box').length > 0) {
11222
+ return;
11223
+ }
11224
+ const keyword = getKeyword(block);
11225
+ if (keyword === null) {
11226
+ return;
11227
+ }
11228
+ const slashRange = range.clone();
11229
+ slashRange.selectNodeContents(block);
11230
+ popup.show(slashRange, keyword);
11231
+ }
11232
+ var slash = (editor) => {
11233
+ editor.setPluginConfig('slash', {
11234
+ items: defaultItems,
11235
+ });
11236
+ if (editor.readonly) {
11237
+ return;
11238
+ }
11239
+ const popup = new SlashPopup({
11240
+ editor,
11241
+ items: editor.config.slash.items,
11242
+ });
11243
+ editor.container.on('keyup', event => {
11244
+ if (editor.isComposing) {
11245
+ return;
11246
+ }
11247
+ const keyboardEvent = event;
11248
+ if (isKeyHotkey(['down', 'up', 'enter'], keyboardEvent)) {
11249
+ return;
11250
+ }
11251
+ if (!popup.visible) {
11252
+ if (isKeyHotkey('/', keyboardEvent)) {
11253
+ showPopup(editor, popup);
11254
+ return;
11255
+ }
11256
+ if (isKeyHotkey(['backspace', 'delete'], keyboardEvent)) {
11257
+ showPopup(editor, popup);
11258
+ }
11259
+ else {
11260
+ return;
11261
+ }
11262
+ }
11263
+ const range = editor.selection.range;
11264
+ const block = range.getBlocks()[0];
11265
+ if (!block) {
11266
+ return;
11267
+ }
11268
+ const keyword = getKeyword(block);
11269
+ if (keyword === null) {
11270
+ popup.hide();
11271
+ return;
11272
+ }
11273
+ popup.update(keyword);
11274
+ });
11275
+ return () => popup.unmount();
11276
+ };
11277
+
10579
11278
  Editor.box.add(hrBox);
10580
11279
  Editor.box.add(codeBlockBox);
10581
11280
  Editor.box.add(imageBox);
@@ -10583,48 +11282,49 @@ Editor.box.add(videoBox);
10583
11282
  Editor.box.add(fileBox);
10584
11283
  Editor.box.add(emojiBox);
10585
11284
  Editor.box.add(equationBox);
10586
- Editor.plugin.add(copy);
10587
- Editor.plugin.add(cut);
10588
- Editor.plugin.add(paste);
10589
- Editor.plugin.add(drop);
10590
- Editor.plugin.add(undo);
10591
- Editor.plugin.add(redo);
10592
- Editor.plugin.add(selectAll);
10593
- Editor.plugin.add(heading);
10594
- Editor.plugin.add(blockQuote);
10595
- Editor.plugin.add(list);
10596
- Editor.plugin.add(align);
10597
- Editor.plugin.add(indent);
10598
- Editor.plugin.add(bold);
10599
- Editor.plugin.add(italic);
10600
- Editor.plugin.add(underline);
10601
- Editor.plugin.add(strikethrough);
10602
- Editor.plugin.add(subscript);
10603
- Editor.plugin.add(superscript);
10604
- Editor.plugin.add(code);
10605
- Editor.plugin.add(fontFamily);
10606
- Editor.plugin.add(fontSize);
10607
- Editor.plugin.add(fontColor);
10608
- Editor.plugin.add(highlight);
10609
- Editor.plugin.add(removeFormat);
10610
- Editor.plugin.add(formatPainter);
10611
- Editor.plugin.add(link);
10612
- Editor.plugin.add(hr);
10613
- Editor.plugin.add(codeBlock);
10614
- Editor.plugin.add(image);
10615
- Editor.plugin.add(video);
10616
- Editor.plugin.add(file);
10617
- Editor.plugin.add(emoji);
10618
- Editor.plugin.add(equation);
10619
- Editor.plugin.add(specialCharacter);
10620
- Editor.plugin.add(markdown);
10621
- Editor.plugin.add(enterKey);
10622
- Editor.plugin.add(shiftEnterKey);
10623
- Editor.plugin.add(backspaceKey);
10624
- Editor.plugin.add(deleteKey);
10625
- Editor.plugin.add(tabKey);
10626
- Editor.plugin.add(arrowKeys);
10627
- Editor.plugin.add(escapeKey);
11285
+ Editor.plugin.add('copy', copy);
11286
+ Editor.plugin.add('cut', cut);
11287
+ Editor.plugin.add('paste', paste);
11288
+ Editor.plugin.add('drop', drop);
11289
+ Editor.plugin.add('undo', undo);
11290
+ Editor.plugin.add('redo', redo);
11291
+ Editor.plugin.add('selectAll', selectAll);
11292
+ Editor.plugin.add('heading', heading);
11293
+ Editor.plugin.add('blockQuote', blockQuote);
11294
+ Editor.plugin.add('list', list);
11295
+ Editor.plugin.add('align', align);
11296
+ Editor.plugin.add('indent', indent);
11297
+ Editor.plugin.add('bold', bold);
11298
+ Editor.plugin.add('italic', italic);
11299
+ Editor.plugin.add('underline', underline);
11300
+ Editor.plugin.add('strikethrough', strikethrough);
11301
+ Editor.plugin.add('subscript', subscript);
11302
+ Editor.plugin.add('superscript', superscript);
11303
+ Editor.plugin.add('code', code);
11304
+ Editor.plugin.add('fontFamily', fontFamily);
11305
+ Editor.plugin.add('fontSize', fontSize);
11306
+ Editor.plugin.add('fontColor', fontColor);
11307
+ Editor.plugin.add('highlight', highlight);
11308
+ Editor.plugin.add('removeFormat', removeFormat);
11309
+ Editor.plugin.add('formatPainter', formatPainter);
11310
+ Editor.plugin.add('link', link);
11311
+ Editor.plugin.add('hr', hr);
11312
+ Editor.plugin.add('codeBlock', codeBlock);
11313
+ Editor.plugin.add('image', image);
11314
+ Editor.plugin.add('video', video);
11315
+ Editor.plugin.add('file', file);
11316
+ Editor.plugin.add('emoji', emoji);
11317
+ Editor.plugin.add('equation', equation);
11318
+ Editor.plugin.add('specialCharacter', specialCharacter);
11319
+ Editor.plugin.add('markdown', markdown);
11320
+ Editor.plugin.add('enterKey', enterKey);
11321
+ Editor.plugin.add('shiftEnterKey', shiftEnterKey);
11322
+ Editor.plugin.add('backspaceKey', backspaceKey);
11323
+ Editor.plugin.add('deleteKey', deleteKey);
11324
+ Editor.plugin.add('tabKey', tabKey);
11325
+ Editor.plugin.add('arrowKeys', arrowKeys);
11326
+ Editor.plugin.add('escapeKey', escapeKey);
11327
+ Editor.plugin.add('slash', slash);
10628
11328
 
10629
11329
  export { Box, Button, Dropdown, Editor, Fragment, HTMLParser, Nodes, Range, TextParser, Toolbar, index as Utils, addMark, deleteContents, fixList, icons, insertBookmark, insertBox, insertFragment, insertLink, insertNode, removeBox, removeMark, setBlocks, splitBlock$1 as splitBlock, splitMarks, toBookmark };
10630
11330
  //# sourceMappingURL=lake.js.map