lakelib 0.1.2 → 0.1.4

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.
package/lib/lake.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { Base64 } from 'js-base64';
2
2
  import EventEmitter from 'eventemitter3';
3
+ import { i18nObject as i18nObject$1 } from 'typesafe-i18n';
3
4
  import debounce from 'lodash/debounce';
4
5
  import isEqual from 'lodash/isEqual';
5
6
  import md5 from 'blueimp-md5';
6
7
  import { createKeybindingsHandler } from 'tinykeys';
7
- import { i18nObject as i18nObject$1 } from 'typesafe-i18n';
8
8
  import 'photoswipe/style.css';
9
9
  import PhotoSwipeLightbox from 'photoswipe/lightbox';
10
10
  import PhotoSwipe from 'photoswipe';
@@ -2862,6 +2862,7 @@ class Box {
2862
2862
  container.off('mouseleave');
2863
2863
  container.off('click');
2864
2864
  }
2865
+ // fix: should not activate box when clicking box
2865
2866
  container.on('mousedown', event => {
2866
2867
  event.preventDefault();
2867
2868
  });
@@ -4060,489 +4061,802 @@ class Button {
4060
4061
  }
4061
4062
  }
4062
4063
 
4063
- class Dropdown {
4064
- constructor(config) {
4065
- this.documentClickListener = (event) => {
4066
- const targetNode = new Nodes(event.target);
4067
- const titleNode = this.node.find('.lake-dropdown-title');
4068
- const menuNode = this.node.find('.lake-dropdown-menu');
4069
- if (targetNode.closest('.lake-dropdown-title').get(0) === titleNode.get(0)) {
4070
- return;
4071
- }
4072
- menuNode.hide();
4073
- document.removeEventListener('click', this.documentClickListener);
4074
- };
4075
- this.config = config;
4076
- this.root = config.root;
4077
- this.node = query(safeTemplate `
4078
- <div class="lake-dropdown lake-${config.menuType}-dropdown" name="${config.name}">
4079
- <button type="button" name="${config.name}" class="lake-dropdown-title">
4080
- <div class="lake-dropdown-${config.icon ? 'icon' : 'text'}"></div>
4081
- <div class="lake-dropdown-down-icon"></div>
4082
- </button>
4083
- </div>
4084
- `);
4085
- if (config.tabIndex !== undefined) {
4086
- const titleNode = this.node.find('.lake-dropdown-title');
4087
- titleNode.attr('tabindex', config.tabIndex.toString());
4088
- }
4089
- }
4090
- // Returns the value of the node.
4091
- static getValue(node) {
4092
- const value = node.attr('value');
4093
- if (value === '') {
4094
- return [];
4095
- }
4096
- return JSON.parse(Base64.decode(value));
4097
- }
4098
- // Updates the value of the node.
4099
- static setValue(node, value) {
4100
- node.attr('value', Base64.encode(JSON.stringify(value)));
4101
- }
4102
- static getMenuMap(menuItems) {
4103
- const menuMap = new Map();
4104
- for (const menuItem of menuItems) {
4105
- // remove HTML tags
4106
- const text = menuItem.text.replace(/<[^>]*>/g, '');
4107
- menuMap.set(menuItem.value, text);
4108
- }
4109
- return menuMap;
4110
- }
4111
- updateColorAccent(titleNode, value) {
4112
- const svgNode = titleNode.find('.lake-dropdown-icon svg').eq(1);
4113
- const lineNode = svgNode.find('line');
4114
- if (lineNode.length > 0) {
4115
- lineNode.attr('stroke', value);
4116
- }
4117
- else {
4118
- svgNode.find('path').attr('fill', value);
4119
- }
4120
- }
4121
- apppendMenuItems(menuNode) {
4122
- const config = this.config;
4123
- for (const menuItem of config.menuItems) {
4124
- const listContent = template `
4125
- <li value="${encode(menuItem.value)}">
4126
- <div class="lake-dropdown-menu-text">${menuItem.text}</div>
4127
- </li>
4128
- `;
4129
- const listNode = query(listContent);
4130
- menuNode.append(listNode);
4131
- if (config.menuType === 'color') {
4132
- listNode.attr('title', menuItem.text);
4133
- listNode.find('.lake-dropdown-menu-text').css('background-color', menuItem.value);
4134
- }
4135
- if (menuItem.icon) {
4136
- const menuIconNode = query('<div class="lake-dropdown-menu-icon"></div>');
4137
- menuIconNode.append(menuItem.icon);
4138
- listNode.prepend(menuIconNode);
4139
- }
4140
- const checkIcon = icons.get('check');
4141
- if (checkIcon) {
4142
- const checkNode = query('<div class="lake-dropdown-menu-check"></div>');
4143
- checkNode.append(checkIcon);
4144
- listNode.prepend(checkNode);
4145
- }
4146
- }
4147
- }
4148
- showMenu() {
4149
- const config = this.config;
4150
- const dropdownNode = this.node;
4151
- const menuNode = dropdownNode.find('.lake-dropdown-menu');
4152
- if (dropdownNode.attr('disabled')) {
4153
- return;
4154
- }
4155
- const currentValues = Dropdown.getValue(dropdownNode);
4156
- menuNode.find('.lake-dropdown-menu-check').css('visibility', 'hidden');
4157
- menuNode.find('li').each(node => {
4158
- const listNode = query(node);
4159
- listNode.on('mouseenter', () => {
4160
- if (listNode.hasClass('lake-dropdown-item-selected')) {
4161
- return;
4162
- }
4163
- listNode.addClass('lake-dropdown-item-hovered');
4164
- });
4165
- listNode.on('mouseleave', () => {
4166
- listNode.removeClass('lake-dropdown-item-hovered');
4167
- });
4168
- if (currentValues.indexOf(listNode.attr('value')) >= 0) {
4169
- listNode.find('.lake-dropdown-menu-check').css('visibility', 'visible');
4170
- }
4171
- });
4172
- menuNode.css('visibility', 'hidden');
4173
- menuNode.show(config.menuType === 'color' ? 'flex' : 'block');
4174
- const dropdownNativeNode = dropdownNode.get(0);
4175
- const dropdownRect = dropdownNativeNode.getBoundingClientRect();
4176
- if (dropdownRect.x + menuNode.width() + 50 > window.innerWidth) {
4177
- menuNode.css('left', 'auto');
4178
- menuNode.css('right', '0');
4179
- }
4180
- else {
4181
- menuNode.css('left', '');
4182
- menuNode.css('right', '');
4183
- }
4184
- menuNode.css('visibility', '');
4185
- document.addEventListener('click', this.documentClickListener);
4186
- }
4187
- bindEvents() {
4188
- const config = this.config;
4189
- const dropdownNode = this.node;
4190
- const titleNode = dropdownNode.find('.lake-dropdown-title');
4191
- const textNode = titleNode.find('.lake-dropdown-text');
4192
- const iconNode = titleNode.find('.lake-dropdown-icon');
4193
- const downIconNode = titleNode.find('.lake-dropdown-down-icon');
4194
- const menuNode = dropdownNode.find('.lake-dropdown-menu');
4195
- if (config.menuType === 'color') {
4196
- iconNode.on('mouseenter', () => {
4197
- if (dropdownNode.attr('disabled')) {
4198
- return;
4199
- }
4200
- iconNode.addClass('lake-dropdown-icon-hovered');
4201
- });
4202
- iconNode.on('mouseleave', () => {
4203
- iconNode.removeClass('lake-dropdown-icon-hovered');
4204
- });
4205
- downIconNode.on('mouseenter', () => {
4206
- if (dropdownNode.attr('disabled')) {
4207
- return;
4208
- }
4209
- downIconNode.addClass('lake-dropdown-down-icon-hovered');
4210
- });
4211
- downIconNode.on('mouseleave', () => {
4212
- downIconNode.removeClass('lake-dropdown-down-icon-hovered');
4213
- });
4214
- }
4215
- else {
4216
- titleNode.on('mouseenter', () => {
4217
- if (dropdownNode.attr('disabled')) {
4218
- return;
4219
- }
4220
- titleNode.addClass('lake-dropdown-title-hovered');
4221
- });
4222
- titleNode.on('mouseleave', () => {
4223
- titleNode.removeClass('lake-dropdown-title-hovered');
4224
- });
4225
- }
4226
- if (config.menuType === 'color') {
4227
- iconNode.on('click', event => {
4228
- event.preventDefault();
4229
- if (dropdownNode.attr('disabled')) {
4230
- return;
4231
- }
4232
- const value = dropdownNode.attr('color') || config.defaultValue;
4233
- config.onSelect(value);
4234
- });
4235
- }
4236
- const triggerNode = (config.menuType === 'color' && downIconNode) ? downIconNode : titleNode;
4237
- triggerNode.on('click', event => {
4238
- event.preventDefault();
4239
- this.showMenu();
4240
- });
4241
- menuNode.on('click', event => {
4242
- event.preventDefault();
4243
- const listItem = query(event.target).closest('li');
4244
- const value = listItem.attr('value');
4245
- Dropdown.setValue(dropdownNode, [value]);
4246
- if (textNode.length > 0) {
4247
- textNode.text(listItem.text());
4248
- }
4249
- if (config.menuType === 'color' && value !== '') {
4250
- dropdownNode.attr('color', value);
4251
- this.updateColorAccent(titleNode, value);
4252
- }
4253
- config.onSelect(value);
4254
- menuNode.hide();
4255
- document.removeEventListener('click', this.documentClickListener);
4256
- });
4257
- }
4258
- render() {
4259
- var _a;
4260
- const config = this.config;
4261
- const dropdownNode = this.node;
4262
- const titleNode = dropdownNode.find('.lake-dropdown-title');
4263
- if (!config.downIcon) {
4264
- titleNode.addClass('lake-dropdown-title-no-down');
4265
- }
4266
- titleNode.css('width', config.width);
4267
- titleNode.attr('title', config.tooltip);
4268
- const textNode = titleNode.find('.lake-dropdown-text');
4269
- const iconNode = titleNode.find('.lake-dropdown-icon');
4270
- if (config.icon) {
4271
- iconNode.append(config.icon);
4272
- }
4273
- if (config.accentIcon) {
4274
- iconNode.append(config.accentIcon);
4275
- }
4276
- const downIconNode = titleNode.find('.lake-dropdown-down-icon');
4277
- if (config.downIcon) {
4278
- downIconNode.append(config.downIcon);
4279
- }
4280
- const menuNode = query('<ul class="lake-dropdown-menu" />');
4281
- menuNode.addClass(`lake-${config.menuType}-dropdown-menu`);
4282
- Dropdown.setValue(dropdownNode, [config.defaultValue]);
4283
- if (textNode.length > 0) {
4284
- const menuMap = Dropdown.getMenuMap(config.menuItems);
4285
- textNode.text((_a = menuMap.get(config.defaultValue)) !== null && _a !== void 0 ? _a : config.defaultValue);
4286
- }
4287
- if (config.menuType === 'color') {
4288
- this.updateColorAccent(titleNode, config.defaultValue);
4289
- }
4290
- this.apppendMenuItems(menuNode);
4291
- dropdownNode.append(titleNode);
4292
- dropdownNode.append(menuNode);
4293
- this.root.append(dropdownNode);
4294
- this.bindEvents();
4295
- }
4296
- unmount() {
4297
- this.node.remove();
4298
- document.removeEventListener('click', this.documentClickListener);
4299
- }
4300
- }
4301
-
4302
- var version = "0.1.2";
4303
-
4304
- // Inserts a box into the specified range.
4305
- function insertBox(range, boxName, boxValue) {
4306
- if (range.commonAncestor.isOutside) {
4307
- return null;
4308
- }
4309
- const box = new Box(boxName);
4310
- if (boxValue) {
4311
- box.value = boxValue;
4312
- }
4313
- const fragment = document.createDocumentFragment();
4314
- fragment.appendChild(box.node.get(0));
4315
- // inline box
4316
- if (box.type === 'inline') {
4317
- insertFragment(range, fragment);
4318
- box.render();
4319
- range.selectBoxEnd(box.node);
4320
- return box;
4321
- }
4322
- // block box
4323
- const parts = splitBlock$1(range);
4324
- if (parts.start) {
4325
- range.setEndAfter(parts.start);
4326
- range.collapseToEnd();
4327
- }
4328
- if (parts.end && parts.end.isEmpty) {
4329
- parts.end.remove();
4330
- }
4331
- insertFragment(range, fragment);
4332
- box.render();
4333
- range.selectBoxEnd(box.node);
4334
- if (parts.start && parts.start.isEmpty) {
4335
- parts.start.remove();
4336
- }
4337
- return box;
4338
- }
4064
+ var enUS = {
4065
+ toolbar: {
4066
+ undo: `Undo (${modifierText('mod+Z')})`,
4067
+ redo: `Redo (${modifierText('mod+Y')})`,
4068
+ selectAll: `Select all (${modifierText('mod+A')})`,
4069
+ paragraph: 'Paragraph',
4070
+ blockQuote: 'Block quotation',
4071
+ numberedList: 'Numbered list',
4072
+ bulletedList: 'Bulleted list',
4073
+ checklist: 'Checklist',
4074
+ alignLeft: 'Align left',
4075
+ alignCenter: 'Align center',
4076
+ alignRight: 'Align right',
4077
+ alignJustify: 'Align justify',
4078
+ increaseIndent: 'Increase indent',
4079
+ decreaseIndent: 'Decrease indent',
4080
+ bold: `Bold (${modifierText('mod+B')})`,
4081
+ italic: `Italic (${modifierText('mod+I')})`,
4082
+ underline: `Underline (${modifierText('mod+U')})`,
4083
+ strikethrough: 'Strikethrough',
4084
+ superscript: 'Superscript',
4085
+ subscript: 'Subscript',
4086
+ code: 'Inline code',
4087
+ removeFormat: 'Remove format',
4088
+ formatPainter: 'Format painter',
4089
+ link: 'Link',
4090
+ hr: 'Horizontal line',
4091
+ codeBlock: 'Code block',
4092
+ heading: 'Heading',
4093
+ heading1: 'Heading 1',
4094
+ heading2: 'Heading 2',
4095
+ heading3: 'Heading 3',
4096
+ heading4: 'Heading 4',
4097
+ heading5: 'Heading 5',
4098
+ heading6: 'Heading 6',
4099
+ list: 'List',
4100
+ align: 'Alignment',
4101
+ indent: 'Indent',
4102
+ fontFamily: 'Font family',
4103
+ fontSize: 'Font size',
4104
+ moreStyle: 'More style',
4105
+ fontColor: 'Font color',
4106
+ highlight: 'Highlight',
4107
+ image: 'Image',
4108
+ removeColor: 'Remove color',
4109
+ },
4110
+ link: {
4111
+ newLink: 'New link',
4112
+ url: 'Link URL',
4113
+ title: 'Link title',
4114
+ copy: 'Copy link to clipboard',
4115
+ open: 'Open link in new tab',
4116
+ save: 'Save',
4117
+ unlink: 'Remove link',
4118
+ },
4119
+ image: {
4120
+ view: 'Full screen',
4121
+ remove: 'Delete',
4122
+ previous: 'Previous',
4123
+ next: 'Next',
4124
+ close: 'Close (Esc)',
4125
+ loadingError: 'The image cannot be loaded',
4126
+ zoomOut: 'Zoom out',
4127
+ zoomIn: 'Zoom in',
4128
+ },
4129
+ codeBlock: {
4130
+ langType: 'Select language',
4131
+ },
4132
+ };
4339
4133
 
4340
- function removeBox(range) {
4341
- if (range.commonAncestor.isOutside) {
4342
- return null;
4343
- }
4344
- const boxNode = range.commonAncestor.closest('lake-box');
4345
- if (boxNode.length === 0) {
4346
- return null;
4347
- }
4348
- const box = new Box(boxNode);
4349
- if (box.type === 'block') {
4350
- const paragraph = query('<p><br /></p>');
4351
- boxNode.before(paragraph);
4352
- range.shrinkAfter(paragraph);
4353
- box.unmount();
4354
- boxNode.remove();
4355
- return box;
4356
- }
4357
- range.setStartBefore(boxNode);
4358
- range.collapseToStart();
4359
- const parentNode = boxNode.parent();
4360
- box.unmount();
4361
- boxNode.remove();
4362
- if (parentNode.isEmpty) {
4363
- appendDeepest(parentNode, query('<br />'));
4364
- range.shrinkAfter(parentNode);
4365
- }
4366
- return box;
4367
- }
4134
+ var zhCN = {
4135
+ toolbar: {
4136
+ undo: `撤消 (${modifierText('mod+Z')})`,
4137
+ redo: `重做 (${modifierText('mod+Y')})`,
4138
+ selectAll: `全选 (${modifierText('mod+A')})`,
4139
+ paragraph: '正文',
4140
+ blockQuote: '引用',
4141
+ numberedList: '编号',
4142
+ bulletedList: '项目符号',
4143
+ checklist: '任务列表',
4144
+ alignLeft: '左对齐',
4145
+ alignCenter: '居中',
4146
+ alignRight: '右对齐',
4147
+ alignJustify: '两端对齐',
4148
+ increaseIndent: '增加缩进',
4149
+ decreaseIndent: '减少缩进',
4150
+ bold: `粗体 (${modifierText('mod+B')})`,
4151
+ italic: `斜体 (${modifierText('mod+I')})`,
4152
+ underline: `下划线 (${modifierText('mod+U')})`,
4153
+ strikethrough: '删除线',
4154
+ superscript: '上标',
4155
+ subscript: '下标',
4156
+ code: '行内代码',
4157
+ removeFormat: '清除格式',
4158
+ formatPainter: '格式刷',
4159
+ link: '链接',
4160
+ hr: '分割线',
4161
+ codeBlock: '代码块',
4162
+ heading: '标题',
4163
+ heading1: '标题 1',
4164
+ heading2: '标题 2',
4165
+ heading3: '标题 3',
4166
+ heading4: '标题 4',
4167
+ heading5: '标题 5',
4168
+ heading6: '标题 6',
4169
+ list: '列表',
4170
+ align: '对齐方式',
4171
+ indent: '缩进',
4172
+ fontFamily: '字体',
4173
+ fontSize: '文字大小',
4174
+ moreStyle: '更多样式',
4175
+ fontColor: '文字颜色',
4176
+ highlight: '文字背景',
4177
+ image: '图片',
4178
+ removeColor: '默认',
4179
+ },
4180
+ link: {
4181
+ newLink: '新链接',
4182
+ url: '链接 URL',
4183
+ title: '链接文本',
4184
+ copy: '复制到剪贴板',
4185
+ open: '打开链接',
4186
+ save: '确定',
4187
+ unlink: '取消链接',
4188
+ },
4189
+ image: {
4190
+ view: '查看大图',
4191
+ remove: '删除',
4192
+ previous: '上一张',
4193
+ next: '下一张',
4194
+ close: '关闭 (Esc)',
4195
+ loadingError: '图片加载失败',
4196
+ zoomOut: '缩小',
4197
+ zoomIn: '放大',
4198
+ },
4199
+ codeBlock: {
4200
+ langType: '选择代码语言',
4201
+ },
4202
+ };
4368
4203
 
4369
- // Returns the attributes of the element as an key-value object.
4370
- function getAttributes(node) {
4371
- const nativeNode = node.get(0);
4372
- const attributes = {};
4373
- if (nativeNode.hasAttributes()) {
4374
- for (const attr of nativeNode.attributes) {
4375
- attributes[attr.name] = attr.value;
4376
- }
4377
- }
4378
- return attributes;
4379
- }
4380
- function pushAncestralNodes(appliedItems, range) {
4381
- let parentNode = range.startNode;
4382
- if (parentNode.isText) {
4383
- parentNode = parentNode.parent();
4384
- }
4385
- while (parentNode.length > 0) {
4386
- if (!parentNode.isInside) {
4387
- break;
4388
- }
4389
- appliedItems.push({
4390
- node: parentNode,
4391
- name: parentNode.name,
4392
- attributes: getAttributes(parentNode),
4393
- styles: parseStyle(parentNode.attr('style')),
4394
- });
4395
- parentNode = parentNode.parent();
4396
- }
4397
- }
4398
- function pushNextNestedNodes(appliedItems, range) {
4399
- const startNode = range.startNode;
4400
- let nextNode;
4401
- if (startNode.isText && startNode.text().length === range.startOffset) {
4402
- const node = startNode.next();
4403
- if (node.length > 0 && node.isElement) {
4404
- nextNode = node;
4405
- }
4406
- }
4407
- if (startNode.isElement) {
4408
- const children = startNode.children();
4409
- if (children.length > 0) {
4410
- const node = children[range.startOffset];
4411
- if (node && node.isElement) {
4412
- nextNode = node;
4413
- }
4414
- }
4415
- }
4416
- if (nextNode) {
4417
- let child = nextNode;
4418
- while (child.length > 0) {
4419
- if (child.isElement) {
4420
- appliedItems.push({
4421
- node: child,
4422
- name: child.name,
4423
- attributes: getAttributes(child),
4424
- styles: parseStyle(child.attr('style')),
4425
- });
4426
- }
4427
- child = child.first();
4428
- }
4429
- }
4430
- }
4431
- class Selection {
4432
- constructor(container) {
4433
- const selection = window.getSelection();
4434
- // When called on an <iframe> that is not displayed (e.g., where 'display: none' is set) Firefox will return null,
4435
- // whereas other browsers will return a selection object with Selection.type set to None.
4436
- if (!selection) {
4437
- throw new Error('Selection object is null.');
4438
- }
4439
- this.selection = selection;
4440
- this.container = container;
4441
- this.range = this.getRangeFromNativeSelection();
4442
- }
4443
- // Returns the current selected range from the native selection.
4444
- getRangeFromNativeSelection() {
4445
- if (this.selection.rangeCount > 0) {
4446
- const range = this.selection.getRangeAt(0);
4447
- return new Range(range);
4448
- }
4449
- return new Range();
4450
- }
4451
- // Adds the saved range to the native selection.
4452
- addRangeToNativeSelection() {
4453
- this.selection.removeAllRanges();
4454
- this.selection.addRange(this.range.get());
4204
+ var ja = {
4205
+ toolbar: {
4206
+ undo: `元に戻す (${modifierText('mod+Z')})`,
4207
+ redo: `やり直し (${modifierText('mod+Y')})`,
4208
+ selectAll: `すべて選択 (${modifierText('mod+A')})`,
4209
+ paragraph: 'テキスト',
4210
+ blockQuote: 'ブロック引用',
4211
+ numberedList: '番号付きリスト',
4212
+ bulletedList: '箇条書きリスト',
4213
+ checklist: 'タスクリスト',
4214
+ alignLeft: '左揃え',
4215
+ alignCenter: '中心揃え',
4216
+ alignRight: '右揃え',
4217
+ alignJustify: '左右に並べ替え',
4218
+ increaseIndent: 'インデントを増やす',
4219
+ decreaseIndent: 'インデントを減らす',
4220
+ bold: `太字 (${modifierText('mod+B')})`,
4221
+ italic: `斜体 (${modifierText('mod+I')})`,
4222
+ underline: `下線 (${modifierText('mod+U')})`,
4223
+ strikethrough: '取り消し線',
4224
+ superscript: '上付き文字',
4225
+ subscript: '下付き文字',
4226
+ code: 'インラインコード',
4227
+ removeFormat: '形式を削除',
4228
+ formatPainter: '形式ペインタ',
4229
+ link: 'リンク',
4230
+ hr: '区切り線',
4231
+ codeBlock: 'コードブロック',
4232
+ heading: 'タイトル',
4233
+ heading1: 'タイトル 1',
4234
+ heading2: 'タイトル 2',
4235
+ heading3: 'タイトル 3',
4236
+ heading4: 'タイトル 4',
4237
+ heading5: 'タイトル 5',
4238
+ heading6: 'タイトル 6',
4239
+ list: 'リスト',
4240
+ align: '文字揃え',
4241
+ indent: 'インデント',
4242
+ fontFamily: 'フォント',
4243
+ fontSize: '文字サイズ',
4244
+ moreStyle: 'その他のスタイル',
4245
+ fontColor: '文字色',
4246
+ highlight: '文字の背景',
4247
+ image: '画像',
4248
+ removeColor: 'デフォルト',
4249
+ },
4250
+ link: {
4251
+ newLink: '新しいリンク',
4252
+ url: 'リンク URL',
4253
+ title: 'リンク文字',
4254
+ copy: 'クリップボードにコピー',
4255
+ open: 'リンクを開く',
4256
+ save: '確認',
4257
+ unlink: 'リンクを削除',
4258
+ },
4259
+ image: {
4260
+ view: '大きな画像を見る',
4261
+ remove: '削除',
4262
+ previous: '前の画像',
4263
+ next: '次の画像',
4264
+ close: '閉じる (Esc)',
4265
+ loadingError: '画像を読み込めません',
4266
+ zoomOut: '縮小',
4267
+ zoomIn: '拡大',
4268
+ },
4269
+ codeBlock: {
4270
+ langType: 'コード言語を選択',
4271
+ },
4272
+ };
4273
+
4274
+ var ko = {
4275
+ toolbar: {
4276
+ undo: `작업취소 (${modifierText('mod+Z')})`,
4277
+ redo: `작업재개 (${modifierText('mod+Y')})`,
4278
+ selectAll: `전체 선택 (${modifierText('mod+A')})`,
4279
+ paragraph: '텍스트',
4280
+ blockQuote: '인용문',
4281
+ numberedList: '순서 목록',
4282
+ bulletedList: '비순서 목록',
4283
+ checklist: '체크리스트',
4284
+ alignLeft: '왼쪽 정렬',
4285
+ alignCenter: '가운데 정렬',
4286
+ alignRight: '오른쪽 정렬',
4287
+ alignJustify: '좌우로 정렬',
4288
+ increaseIndent: '들여쓰기 증가',
4289
+ decreaseIndent: '들여쓰기 줄이기',
4290
+ bold: `굵게 (${modifierText('mod+B')})`,
4291
+ italic: `기울임꼴 (${modifierText('mod+I')})`,
4292
+ underline: `밑줄 (${modifierText('mod+U')})`,
4293
+ strikethrough: '취소선',
4294
+ superscript: '위첨자',
4295
+ subscript: '아래 첨자',
4296
+ code: '인라인 코드',
4297
+ removeFormat: '형식 지우기',
4298
+ formatPainter: '형식 페인터',
4299
+ link: '링크',
4300
+ hr: '구분선',
4301
+ codeBlock: '코드 블록',
4302
+ heading: '제목',
4303
+ heading1: '제목 1',
4304
+ heading2: '제목 2',
4305
+ heading3: '제목 3',
4306
+ heading4: '제목 4',
4307
+ heading5: '제목 5',
4308
+ heading6: '제목 6',
4309
+ list: '목록',
4310
+ align: '정렬',
4311
+ indent: '들여쓰기',
4312
+ fontFamily: '글꼴',
4313
+ fontSize: '글자 크기',
4314
+ moreStyle: '더 많은 스타일',
4315
+ fontColor: '글자 색상',
4316
+ highlight: '글자 배경',
4317
+ image: '이미지',
4318
+ removeColor: '기본색',
4319
+ },
4320
+ link: {
4321
+ newLink: '새 링크',
4322
+ url: '링크 URL',
4323
+ title: '링크 텍스트',
4324
+ copy: '클립보드에 복사',
4325
+ open: '링크 열기',
4326
+ save: '확인',
4327
+ unlink: '링크 제거',
4328
+ },
4329
+ image: {
4330
+ view: '큰 이미지 보기',
4331
+ remove: '삭제',
4332
+ previous: '이전 이미지',
4333
+ next: '다음 이미지',
4334
+ close: '닫기 (Esc)',
4335
+ loadingError: '이미지를 로드할 수 없습니다',
4336
+ zoomOut: '축소',
4337
+ zoomIn: '확대',
4338
+ },
4339
+ codeBlock: {
4340
+ langType: '코드언어 선택',
4341
+ },
4342
+ };
4343
+
4344
+ const localeTranslations = {
4345
+ 'en-US': enUS,
4346
+ 'zh-CN': zhCN,
4347
+ ja,
4348
+ ko,
4349
+ };
4350
+ const locales = Object.keys(localeTranslations);
4351
+ const loadedLocales = {};
4352
+ const loadedFormatters = {};
4353
+ const initFormatters = () => {
4354
+ const formatters = {
4355
+ // add your formatter functions here
4356
+ };
4357
+ return formatters;
4358
+ };
4359
+ const loadFormatters = (locale) => {
4360
+ loadedFormatters[locale] = initFormatters();
4361
+ };
4362
+ const loadLocale = (locale) => {
4363
+ if (loadedLocales[locale]) {
4364
+ return;
4455
4365
  }
4456
- // Synchronizes the saved range with the range of the native selection.
4457
- syncByRange() {
4458
- const newRange = this.getRangeFromNativeSelection();
4459
- if (this.range.get() === newRange.get()) {
4460
- return;
4366
+ loadedLocales[locale] = localeTranslations[locale];
4367
+ loadFormatters(locale);
4368
+ };
4369
+ const loadAllLocales = () => locales.forEach(loadLocale);
4370
+ const i18nObject = (locale) => i18nObject$1(locale, loadedLocales[locale], loadedFormatters[locale]);
4371
+ loadAllLocales();
4372
+
4373
+ class Dropdown {
4374
+ constructor(config) {
4375
+ this.documentClickListener = (event) => {
4376
+ const targetNode = new Nodes(event.target);
4377
+ const titleNode = this.node.find('.lake-dropdown-title');
4378
+ const menuNode = this.node.find('.lake-dropdown-menu');
4379
+ if (targetNode.closest('.lake-dropdown-title').get(0) === titleNode.get(0)) {
4380
+ return;
4381
+ }
4382
+ menuNode.hide();
4383
+ document.removeEventListener('click', this.documentClickListener);
4384
+ };
4385
+ this.config = config;
4386
+ this.root = config.root;
4387
+ this.locale = config.locale || i18nObject('en-US');
4388
+ this.node = query(safeTemplate `
4389
+ <div class="lake-dropdown lake-${config.menuType}-dropdown" name="${config.name}">
4390
+ <button type="button" name="${config.name}" class="lake-dropdown-title">
4391
+ <div class="lake-dropdown-${config.icon ? 'icon' : 'text'}"></div>
4392
+ <div class="lake-dropdown-down-icon"></div>
4393
+ </button>
4394
+ </div>
4395
+ `);
4396
+ if (config.tabIndex !== undefined) {
4397
+ const titleNode = this.node.find('.lake-dropdown-title');
4398
+ titleNode.attr('tabindex', config.tabIndex.toString());
4461
4399
  }
4462
- this.range = newRange;
4463
4400
  }
4464
- // Synchronizes the saved range with the range represented by the bookmark.
4465
- synByBookmark() {
4466
- const range = this.range;
4467
- const container = this.container;
4468
- const boxFocus = container.find('lake-box[focus]');
4469
- if (boxFocus.length > 0) {
4470
- toBookmark(range, {
4471
- anchor: new Nodes(),
4472
- focus: boxFocus,
4473
- });
4474
- this.addRangeToNativeSelection();
4475
- return;
4401
+ // Returns the value of the node.
4402
+ static getValue(node) {
4403
+ const value = node.attr('value');
4404
+ if (value === '') {
4405
+ return [];
4476
4406
  }
4477
- const anchor = container.find('lake-bookmark[type="anchor"]');
4478
- const focus = container.find('lake-bookmark[type="focus"]');
4479
- toBookmark(range, {
4480
- anchor,
4481
- focus,
4482
- });
4483
- this.addRangeToNativeSelection();
4484
- }
4485
- getAppliedItems() {
4486
- const appliedItems = [];
4487
- pushAncestralNodes(appliedItems, this.range);
4488
- pushNextNestedNodes(appliedItems, this.range);
4489
- return appliedItems;
4407
+ return JSON.parse(Base64.decode(value));
4490
4408
  }
4491
- insertBookmark() {
4492
- return insertBookmark(this.range);
4409
+ // Updates the value of the node.
4410
+ static setValue(node, value) {
4411
+ node.attr('value', Base64.encode(JSON.stringify(value)));
4493
4412
  }
4494
- toBookmark(bookmark) {
4495
- return toBookmark(this.range, bookmark);
4413
+ static getMenuMap(menuItems, locale) {
4414
+ const menuMap = new Map();
4415
+ for (const menuItem of menuItems) {
4416
+ // remove HTML tags
4417
+ let text = typeof menuItem.text === 'string' ? menuItem.text : menuItem.text(locale);
4418
+ text = text.replace(/<[^>]*>/g, '');
4419
+ menuMap.set(menuItem.value, text);
4420
+ }
4421
+ return menuMap;
4496
4422
  }
4497
- insertNode(node) {
4498
- return insertNode(this.range, node);
4423
+ updateColorAccent(titleNode, value) {
4424
+ const svgNode = titleNode.find('.lake-dropdown-icon svg').eq(1);
4425
+ const lineNode = svgNode.find('line');
4426
+ if (lineNode.length > 0) {
4427
+ lineNode.attr('stroke', value);
4428
+ }
4429
+ else {
4430
+ svgNode.find('path').attr('fill', value);
4431
+ }
4499
4432
  }
4500
- insertFragment(fragment) {
4501
- return insertFragment(this.range, fragment);
4433
+ apppendMenuItems(menuNode) {
4434
+ const config = this.config;
4435
+ for (const menuItem of config.menuItems) {
4436
+ const menuText = typeof menuItem.text === 'string' ? menuItem.text : menuItem.text(this.locale);
4437
+ const listContent = template `
4438
+ <li value="${encode(menuItem.value)}">
4439
+ <div class="lake-dropdown-menu-text">${menuText}</div>
4440
+ </li>
4441
+ `;
4442
+ const listNode = query(listContent);
4443
+ menuNode.append(listNode);
4444
+ if (config.menuType === 'color') {
4445
+ listNode.attr('title', menuText);
4446
+ listNode.find('.lake-dropdown-menu-text').css('background-color', menuItem.value);
4447
+ }
4448
+ if (menuItem.icon) {
4449
+ const menuIconNode = query('<div class="lake-dropdown-menu-icon"></div>');
4450
+ menuIconNode.append(menuItem.icon);
4451
+ listNode.prepend(menuIconNode);
4452
+ }
4453
+ const checkIcon = icons.get('check');
4454
+ if (checkIcon) {
4455
+ const checkNode = query('<div class="lake-dropdown-menu-check"></div>');
4456
+ checkNode.append(checkIcon);
4457
+ listNode.prepend(checkNode);
4458
+ }
4459
+ }
4502
4460
  }
4503
- insertContents(value) {
4504
- return insertContents(this.range, value);
4461
+ showMenu() {
4462
+ const config = this.config;
4463
+ const dropdownNode = this.node;
4464
+ const menuNode = dropdownNode.find('.lake-dropdown-menu');
4465
+ if (dropdownNode.attr('disabled')) {
4466
+ return;
4467
+ }
4468
+ const currentValues = Dropdown.getValue(dropdownNode);
4469
+ menuNode.find('.lake-dropdown-menu-check').css('visibility', 'hidden');
4470
+ menuNode.find('li').each(node => {
4471
+ const listNode = query(node);
4472
+ listNode.on('mouseenter', () => {
4473
+ if (listNode.hasClass('lake-dropdown-item-selected')) {
4474
+ return;
4475
+ }
4476
+ listNode.addClass('lake-dropdown-item-hovered');
4477
+ });
4478
+ listNode.on('mouseleave', () => {
4479
+ listNode.removeClass('lake-dropdown-item-hovered');
4480
+ });
4481
+ if (currentValues.indexOf(listNode.attr('value')) >= 0) {
4482
+ listNode.find('.lake-dropdown-menu-check').css('visibility', 'visible');
4483
+ }
4484
+ });
4485
+ menuNode.css('visibility', 'hidden');
4486
+ menuNode.show(config.menuType === 'color' ? 'flex' : 'block');
4487
+ const dropdownNativeNode = dropdownNode.get(0);
4488
+ const dropdownRect = dropdownNativeNode.getBoundingClientRect();
4489
+ if (dropdownRect.x + menuNode.width() + 50 > window.innerWidth) {
4490
+ menuNode.css('left', 'auto');
4491
+ menuNode.css('right', '0');
4492
+ }
4493
+ else {
4494
+ menuNode.css('left', '');
4495
+ menuNode.css('right', '');
4496
+ }
4497
+ menuNode.css('visibility', '');
4498
+ document.addEventListener('click', this.documentClickListener);
4505
4499
  }
4506
- deleteContents() {
4507
- return deleteContents(this.range);
4500
+ bindEvents() {
4501
+ const config = this.config;
4502
+ const dropdownNode = this.node;
4503
+ const titleNode = dropdownNode.find('.lake-dropdown-title');
4504
+ const textNode = titleNode.find('.lake-dropdown-text');
4505
+ const iconNode = titleNode.find('.lake-dropdown-icon');
4506
+ const downIconNode = titleNode.find('.lake-dropdown-down-icon');
4507
+ const menuNode = dropdownNode.find('.lake-dropdown-menu');
4508
+ if (config.menuType === 'color') {
4509
+ iconNode.on('mouseenter', () => {
4510
+ if (dropdownNode.attr('disabled')) {
4511
+ return;
4512
+ }
4513
+ iconNode.addClass('lake-dropdown-icon-hovered');
4514
+ });
4515
+ iconNode.on('mouseleave', () => {
4516
+ iconNode.removeClass('lake-dropdown-icon-hovered');
4517
+ });
4518
+ downIconNode.on('mouseenter', () => {
4519
+ if (dropdownNode.attr('disabled')) {
4520
+ return;
4521
+ }
4522
+ downIconNode.addClass('lake-dropdown-down-icon-hovered');
4523
+ });
4524
+ downIconNode.on('mouseleave', () => {
4525
+ downIconNode.removeClass('lake-dropdown-down-icon-hovered');
4526
+ });
4527
+ }
4528
+ else {
4529
+ titleNode.on('mouseenter', () => {
4530
+ if (dropdownNode.attr('disabled')) {
4531
+ return;
4532
+ }
4533
+ titleNode.addClass('lake-dropdown-title-hovered');
4534
+ });
4535
+ titleNode.on('mouseleave', () => {
4536
+ titleNode.removeClass('lake-dropdown-title-hovered');
4537
+ });
4538
+ }
4539
+ if (config.menuType === 'color') {
4540
+ iconNode.on('click', event => {
4541
+ event.preventDefault();
4542
+ if (dropdownNode.attr('disabled')) {
4543
+ return;
4544
+ }
4545
+ const value = dropdownNode.attr('color') || config.defaultValue;
4546
+ config.onSelect(value);
4547
+ });
4548
+ }
4549
+ const triggerNode = (config.menuType === 'color' && downIconNode) ? downIconNode : titleNode;
4550
+ triggerNode.on('click', event => {
4551
+ event.preventDefault();
4552
+ this.showMenu();
4553
+ });
4554
+ menuNode.on('click', event => {
4555
+ event.preventDefault();
4556
+ const listItem = query(event.target).closest('li');
4557
+ const value = listItem.attr('value');
4558
+ Dropdown.setValue(dropdownNode, [value]);
4559
+ if (textNode.length > 0) {
4560
+ textNode.text(listItem.text());
4561
+ }
4562
+ if (config.menuType === 'color' && value !== '') {
4563
+ dropdownNode.attr('color', value);
4564
+ this.updateColorAccent(titleNode, value);
4565
+ }
4566
+ config.onSelect(value);
4567
+ menuNode.hide();
4568
+ document.removeEventListener('click', this.documentClickListener);
4569
+ });
4508
4570
  }
4509
- setBlocks(value) {
4510
- return setBlocks(this.range, value);
4571
+ render() {
4572
+ var _a;
4573
+ const config = this.config;
4574
+ const dropdownNode = this.node;
4575
+ const titleNode = dropdownNode.find('.lake-dropdown-title');
4576
+ if (!config.downIcon) {
4577
+ titleNode.addClass('lake-dropdown-title-no-down');
4578
+ }
4579
+ titleNode.css('width', config.width);
4580
+ const tooltip = typeof config.tooltip === 'string' ? config.tooltip : config.tooltip(this.locale);
4581
+ titleNode.attr('title', tooltip);
4582
+ const textNode = titleNode.find('.lake-dropdown-text');
4583
+ const iconNode = titleNode.find('.lake-dropdown-icon');
4584
+ if (config.icon) {
4585
+ iconNode.append(config.icon);
4586
+ }
4587
+ if (config.accentIcon) {
4588
+ iconNode.append(config.accentIcon);
4589
+ }
4590
+ const downIconNode = titleNode.find('.lake-dropdown-down-icon');
4591
+ if (config.downIcon) {
4592
+ downIconNode.append(config.downIcon);
4593
+ }
4594
+ const menuNode = query('<ul class="lake-dropdown-menu" />');
4595
+ menuNode.addClass(`lake-${config.menuType}-dropdown-menu`);
4596
+ Dropdown.setValue(dropdownNode, [config.defaultValue]);
4597
+ if (textNode.length > 0) {
4598
+ const menuMap = Dropdown.getMenuMap(config.menuItems, this.locale);
4599
+ textNode.text((_a = menuMap.get(config.defaultValue)) !== null && _a !== void 0 ? _a : config.defaultValue);
4600
+ }
4601
+ if (config.menuType === 'color') {
4602
+ this.updateColorAccent(titleNode, config.defaultValue);
4603
+ }
4604
+ this.apppendMenuItems(menuNode);
4605
+ dropdownNode.append(titleNode);
4606
+ dropdownNode.append(menuNode);
4607
+ this.root.append(dropdownNode);
4608
+ this.bindEvents();
4511
4609
  }
4512
- splitBlock() {
4513
- return splitBlock$1(this.range);
4610
+ unmount() {
4611
+ this.node.remove();
4612
+ document.removeEventListener('click', this.documentClickListener);
4514
4613
  }
4515
- splitMarks(removeEmptyMark) {
4516
- return splitMarks(this.range, removeEmptyMark);
4614
+ }
4615
+
4616
+ var version = "0.1.4";
4617
+
4618
+ // Inserts a box into the specified range.
4619
+ function insertBox(range, boxName, boxValue) {
4620
+ if (range.commonAncestor.isOutside) {
4621
+ return null;
4517
4622
  }
4518
- addMark(value) {
4519
- return addMark(this.range, value);
4623
+ const box = new Box(boxName);
4624
+ if (boxValue) {
4625
+ box.value = boxValue;
4520
4626
  }
4521
- removeMark(value) {
4522
- return removeMark(this.range, value);
4627
+ const fragment = document.createDocumentFragment();
4628
+ fragment.appendChild(box.node.get(0));
4629
+ // inline box
4630
+ if (box.type === 'inline') {
4631
+ insertFragment(range, fragment);
4632
+ box.render();
4633
+ range.selectBoxEnd(box.node);
4634
+ return box;
4523
4635
  }
4524
- fixList() {
4525
- return fixList(this.range);
4636
+ // block box
4637
+ const parts = splitBlock$1(range);
4638
+ if (parts.start) {
4639
+ range.setEndAfter(parts.start);
4640
+ range.collapseToEnd();
4526
4641
  }
4527
- insertLink(value) {
4528
- return insertLink(this.range, value);
4642
+ if (parts.end && parts.end.isEmpty) {
4643
+ parts.end.remove();
4529
4644
  }
4645
+ insertFragment(range, fragment);
4646
+ box.render();
4647
+ range.selectBoxEnd(box.node);
4648
+ if (parts.start && parts.start.isEmpty) {
4649
+ parts.start.remove();
4650
+ }
4651
+ return box;
4530
4652
  }
4531
4653
 
4532
- class Command {
4533
- constructor(selection) {
4534
- this.commandMap = new Map();
4535
- this.event = new EventEmitter();
4536
- this.selection = selection;
4654
+ function removeBox(range) {
4655
+ if (range.commonAncestor.isOutside) {
4656
+ return null;
4537
4657
  }
4538
- add(name, commandItem) {
4539
- this.commandMap.set(name, commandItem);
4658
+ const boxNode = range.commonAncestor.closest('lake-box');
4659
+ if (boxNode.length === 0) {
4660
+ return null;
4540
4661
  }
4541
- delete(name) {
4542
- this.commandMap.delete(name);
4662
+ const box = new Box(boxNode);
4663
+ if (box.type === 'block') {
4664
+ const paragraph = query('<p><br /></p>');
4665
+ boxNode.before(paragraph);
4666
+ range.shrinkAfter(paragraph);
4667
+ box.unmount();
4668
+ boxNode.remove();
4669
+ return box;
4543
4670
  }
4544
- getNames() {
4545
- return Array.from(this.commandMap.keys());
4671
+ range.setStartBefore(boxNode);
4672
+ range.collapseToStart();
4673
+ const parentNode = boxNode.parent();
4674
+ box.unmount();
4675
+ boxNode.remove();
4676
+ if (parentNode.isEmpty) {
4677
+ appendDeepest(parentNode, query('<br />'));
4678
+ range.shrinkAfter(parentNode);
4679
+ }
4680
+ return box;
4681
+ }
4682
+
4683
+ // Returns the attributes of the element as an key-value object.
4684
+ function getAttributes(node) {
4685
+ const nativeNode = node.get(0);
4686
+ const attributes = {};
4687
+ if (nativeNode.hasAttributes()) {
4688
+ for (const attr of nativeNode.attributes) {
4689
+ attributes[attr.name] = attr.value;
4690
+ }
4691
+ }
4692
+ return attributes;
4693
+ }
4694
+ function pushAncestralNodes(appliedItems, range) {
4695
+ let parentNode = range.startNode;
4696
+ if (parentNode.isText) {
4697
+ parentNode = parentNode.parent();
4698
+ }
4699
+ while (parentNode.length > 0) {
4700
+ if (!parentNode.isInside) {
4701
+ break;
4702
+ }
4703
+ appliedItems.push({
4704
+ node: parentNode,
4705
+ name: parentNode.name,
4706
+ attributes: getAttributes(parentNode),
4707
+ styles: parseStyle(parentNode.attr('style')),
4708
+ });
4709
+ parentNode = parentNode.parent();
4710
+ }
4711
+ }
4712
+ function pushNextNestedNodes(appliedItems, range) {
4713
+ const startNode = range.startNode;
4714
+ let nextNode;
4715
+ if (startNode.isText && startNode.text().length === range.startOffset) {
4716
+ const node = startNode.next();
4717
+ if (node.length > 0 && node.isElement) {
4718
+ nextNode = node;
4719
+ }
4720
+ }
4721
+ if (startNode.isElement) {
4722
+ const children = startNode.children();
4723
+ if (children.length > 0) {
4724
+ const node = children[range.startOffset];
4725
+ if (node && node.isElement) {
4726
+ nextNode = node;
4727
+ }
4728
+ }
4729
+ }
4730
+ if (nextNode) {
4731
+ let child = nextNode;
4732
+ while (child.length > 0) {
4733
+ if (child.isElement) {
4734
+ appliedItems.push({
4735
+ node: child,
4736
+ name: child.name,
4737
+ attributes: getAttributes(child),
4738
+ styles: parseStyle(child.attr('style')),
4739
+ });
4740
+ }
4741
+ child = child.first();
4742
+ }
4743
+ }
4744
+ }
4745
+ class Selection {
4746
+ constructor(container) {
4747
+ const selection = window.getSelection();
4748
+ // When called on an <iframe> that is not displayed (e.g., where 'display: none' is set) Firefox will return null,
4749
+ // whereas other browsers will return a selection object with Selection.type set to None.
4750
+ if (!selection) {
4751
+ throw new Error('Selection object is null.');
4752
+ }
4753
+ this.selection = selection;
4754
+ this.container = container;
4755
+ this.range = this.getRangeFromNativeSelection();
4756
+ }
4757
+ // Returns the current selected range from the native selection.
4758
+ getRangeFromNativeSelection() {
4759
+ if (this.selection.rangeCount > 0) {
4760
+ const range = this.selection.getRangeAt(0);
4761
+ return new Range(range);
4762
+ }
4763
+ return new Range();
4764
+ }
4765
+ // Adds the saved range to the native selection.
4766
+ addRangeToNativeSelection() {
4767
+ this.selection.removeAllRanges();
4768
+ this.selection.addRange(this.range.get());
4769
+ }
4770
+ // Synchronizes the saved range with the range of the native selection.
4771
+ syncByRange() {
4772
+ const newRange = this.getRangeFromNativeSelection();
4773
+ if (this.range.get() === newRange.get()) {
4774
+ return;
4775
+ }
4776
+ this.range = newRange;
4777
+ }
4778
+ // Synchronizes the saved range with the range represented by the bookmark.
4779
+ synByBookmark() {
4780
+ const range = this.range;
4781
+ const container = this.container;
4782
+ const boxFocus = container.find('lake-box[focus]');
4783
+ if (boxFocus.length > 0) {
4784
+ toBookmark(range, {
4785
+ anchor: new Nodes(),
4786
+ focus: boxFocus,
4787
+ });
4788
+ this.addRangeToNativeSelection();
4789
+ return;
4790
+ }
4791
+ const anchor = container.find('lake-bookmark[type="anchor"]');
4792
+ const focus = container.find('lake-bookmark[type="focus"]');
4793
+ toBookmark(range, {
4794
+ anchor,
4795
+ focus,
4796
+ });
4797
+ this.addRangeToNativeSelection();
4798
+ }
4799
+ getAppliedItems() {
4800
+ const appliedItems = [];
4801
+ pushAncestralNodes(appliedItems, this.range);
4802
+ pushNextNestedNodes(appliedItems, this.range);
4803
+ return appliedItems;
4804
+ }
4805
+ insertBookmark() {
4806
+ return insertBookmark(this.range);
4807
+ }
4808
+ toBookmark(bookmark) {
4809
+ return toBookmark(this.range, bookmark);
4810
+ }
4811
+ insertNode(node) {
4812
+ return insertNode(this.range, node);
4813
+ }
4814
+ insertFragment(fragment) {
4815
+ return insertFragment(this.range, fragment);
4816
+ }
4817
+ insertContents(value) {
4818
+ return insertContents(this.range, value);
4819
+ }
4820
+ deleteContents() {
4821
+ return deleteContents(this.range);
4822
+ }
4823
+ setBlocks(value) {
4824
+ return setBlocks(this.range, value);
4825
+ }
4826
+ splitBlock() {
4827
+ return splitBlock$1(this.range);
4828
+ }
4829
+ splitMarks(removeEmptyMark) {
4830
+ return splitMarks(this.range, removeEmptyMark);
4831
+ }
4832
+ addMark(value) {
4833
+ return addMark(this.range, value);
4834
+ }
4835
+ removeMark(value) {
4836
+ return removeMark(this.range, value);
4837
+ }
4838
+ fixList() {
4839
+ return fixList(this.range);
4840
+ }
4841
+ insertLink(value) {
4842
+ return insertLink(this.range, value);
4843
+ }
4844
+ }
4845
+
4846
+ class Command {
4847
+ constructor(selection) {
4848
+ this.commandMap = new Map();
4849
+ this.event = new EventEmitter();
4850
+ this.selection = selection;
4851
+ }
4852
+ add(name, commandItem) {
4853
+ this.commandMap.set(name, commandItem);
4854
+ }
4855
+ delete(name) {
4856
+ this.commandMap.delete(name);
4857
+ }
4858
+ getNames() {
4859
+ return Array.from(this.commandMap.keys());
4546
4860
  }
4547
4861
  has(name) {
4548
4862
  return this.commandMap.get(name) !== undefined;
@@ -4825,880 +5139,573 @@ class Keystroke {
4825
5139
  // Executes the keyup shortcuts.
4826
5140
  keyup(type) {
4827
5141
  type = this.normalizeType(type);
4828
- for (const item of this.keyupEventList) {
4829
- if (item.type === type) {
4830
- if (item.listener(new Event(type)) === false) {
4831
- break;
4832
- }
4833
- }
4834
- }
4835
- }
4836
- }
4837
-
4838
- class BoxManager {
4839
- add(component) {
4840
- boxes.set(component.name, component);
4841
- }
4842
- remove(name) {
4843
- boxes.delete(name);
4844
- }
4845
- getNames() {
4846
- return Array.from(boxes.keys());
4847
- }
4848
- getInstances(editor) {
4849
- let instanceMap = boxInstances.get(editor.container.id);
4850
- if (!instanceMap) {
4851
- instanceMap = new Map();
4852
- boxInstances.set(editor.container.id, instanceMap);
4853
- return instanceMap;
4854
- }
4855
- return instanceMap;
4856
- }
4857
- rectifyInstances(editor) {
4858
- const instanceMap = this.getInstances(editor);
4859
- for (const box of instanceMap.values()) {
4860
- if (!box.node.get(0).isConnected) {
4861
- box.unmount();
4862
- instanceMap.delete(box.node.id);
4863
- }
4864
- }
4865
- }
4866
- findAll(editor) {
4867
- return editor.container.find('lake-box');
4868
- }
4869
- renderAll(editor) {
4870
- this.rectifyInstances(editor);
4871
- const instanceMap = this.getInstances(editor);
4872
- this.findAll(editor).each(boxNativeNode => {
4873
- const boxNode = new Nodes(boxNativeNode);
4874
- if (instanceMap.get(boxNode.id)) {
4875
- return;
4876
- }
4877
- const box = new Box(boxNode);
4878
- box.render();
4879
- instanceMap.set(box.node.id, box);
4880
- });
4881
- }
4882
- }
4883
-
4884
- class Plugin {
4885
- constructor() {
4886
- this.pluginList = [];
4887
- }
4888
- add(plugin) {
4889
- this.pluginList.push(plugin);
4890
- }
4891
- loadAll(editor) {
4892
- this.pluginList.forEach(plugin => {
4893
- plugin(editor);
4894
- });
4895
- }
4896
- }
4897
-
4898
- const defaultConfig = {
4899
- value: '<p><br /><focus /></p>',
4900
- readonly: false,
4901
- spellcheck: false,
4902
- tabIndex: 0,
4903
- indentWithTab: true,
4904
- minChangeSize: 5,
4905
- };
4906
- class Editor {
4907
- constructor(config) {
4908
- this.unsavedInputData = '';
4909
- this.stateData = {
4910
- appliedItems: [],
4911
- disabledNameMap: new Map(),
4912
- selectedNameMap: new Map(),
4913
- selectedValuesMap: new Map(),
4914
- };
4915
- this.isComposing = false;
4916
- this.event = new EventEmitter();
4917
- this.box = Editor.box;
4918
- this.beforeunloadListener = () => {
4919
- this.history.save();
4920
- };
4921
- this.selectionchangeListener = () => {
4922
- this.selection.syncByRange();
4923
- this.updateBoxSelectionStyle();
4924
- this.emitStateChangeEvent();
4925
- };
4926
- this.clickListener = event => {
4927
- const targetNode = new Nodes(event.target);
4928
- if (targetNode.closest('.lake-popup').length > 0) {
4929
- return;
4930
- }
4931
- this.event.emit('click', targetNode);
4932
- };
4933
- this.resizeListener = () => {
4934
- this.event.emit('resize');
4935
- };
4936
- this.updateBoxSelectionStyle = debounce(() => {
4937
- // The editor has been unmounted.
4938
- if (this.root.first().length === 0) {
4939
- return;
4940
- }
4941
- const range = this.selection.range;
4942
- const clonedRange = range.clone();
4943
- clonedRange.adaptBox();
4944
- this.box.findAll(this).each(boxNode => {
4945
- const box = new Box(boxNode);
4946
- const boxContainer = box.getContainer();
4947
- if (boxContainer.length === 0) {
4948
- return;
4949
- }
4950
- if (range.compareBeforeNode(boxContainer) < 0 && range.compareAfterNode(boxContainer) > 0) {
4951
- if (!(range.isCollapsed && range.startNode.get(0) === boxContainer.get(0) && range.startOffset === 0)) {
4952
- boxContainer.removeClass('lake-box-hovered');
4953
- boxContainer.removeClass('lake-box-selected');
4954
- boxContainer.removeClass('lake-box-focused');
4955
- boxContainer.addClass('lake-box-activated');
4956
- return;
4957
- }
4958
- }
4959
- if (clonedRange.intersectsNode(box.node)) {
4960
- boxContainer.removeClass('lake-box-activated');
4961
- if (range.isCollapsed) {
4962
- boxContainer.removeClass('lake-box-hovered');
4963
- boxContainer.removeClass('lake-box-selected');
4964
- boxContainer.addClass('lake-box-focused');
4965
- }
4966
- else {
4967
- boxContainer.removeClass('lake-box-focused');
4968
- boxContainer.addClass('lake-box-selected');
4969
- }
4970
- return;
4971
- }
4972
- boxContainer.removeClass('lake-box-activated');
4973
- boxContainer.removeClass('lake-box-focused');
4974
- boxContainer.removeClass('lake-box-selected');
4975
- });
4976
- this.event.emit('boxselectionstylechange');
4977
- }, 50, {
4978
- leading: false,
4979
- trailing: true,
4980
- maxWait: 50,
4981
- });
4982
- this.emitStateChangeEvent = debounce(() => {
4983
- const commandNames = this.command.getNames();
4984
- let appliedItems = this.selection.getAppliedItems();
4985
- if (appliedItems.length > 0 &&
4986
- appliedItems[0].node.closestContainer().get(0) !== this.container.get(0)) {
4987
- appliedItems = [];
4988
- }
4989
- const disabledNameMap = new Map();
4990
- const selectedNameMap = new Map();
4991
- const selectedValuesMap = new Map();
4992
- if (appliedItems.length > 0) {
4993
- for (const name of commandNames) {
4994
- const commandItem = this.command.getItem(name);
4995
- if (commandItem.isDisabled && commandItem.isDisabled(appliedItems)) {
4996
- disabledNameMap.set(name, true);
4997
- }
4998
- if (commandItem.isSelected && commandItem.isSelected(appliedItems)) {
4999
- selectedNameMap.set(name, true);
5000
- }
5001
- if (commandItem.selectedValues) {
5002
- const values = commandItem.selectedValues(appliedItems);
5003
- if (values.length > 0) {
5004
- selectedValuesMap.set(name, values);
5005
- }
5006
- }
5007
- }
5008
- }
5009
- const stateData = {
5010
- appliedItems,
5011
- disabledNameMap,
5012
- selectedNameMap,
5013
- selectedValuesMap,
5014
- };
5015
- if (isEqual(stateData, this.stateData)) {
5016
- return;
5017
- }
5018
- if (this.toolbar) {
5019
- this.toolbar.updateState(stateData);
5020
- }
5021
- this.event.emit('statechange', stateData);
5022
- this.stateData = stateData;
5023
- }, 100, {
5024
- leading: false,
5025
- trailing: true,
5026
- maxWait: 100,
5027
- });
5028
- this.emitChangeEvent = (value) => {
5029
- this.rectifyContent();
5030
- this.emitStateChangeEvent();
5031
- this.event.emit('change', value);
5032
- };
5033
- if (!config.root) {
5034
- throw new Error('The root of the config must be specified.');
5035
- }
5036
- this.root = query(config.root);
5037
- this.toolbar = config.toolbar;
5038
- this.config = Object.assign({}, defaultConfig);
5039
- for (const key of Object.keys(config)) {
5040
- this.config[key] = config[key];
5041
- }
5042
- this.containerWrapper = query('<div class="lake-container-wrapper" />');
5043
- this.container = query('<div class="lake-container" />');
5044
- this.overlayContainer = query('<div class="lake-overlay" />');
5045
- this.popupContainer = query('<div class="lake-popup lake-custom-properties" />');
5046
- this.readonly = this.config.readonly;
5047
- this.root.addClass('lake-custom-properties');
5048
- this.container.attr({
5049
- contenteditable: this.readonly ? 'false' : 'true',
5050
- spellcheck: this.config.spellcheck ? 'true' : 'false',
5051
- tabindex: this.config.tabIndex.toString(),
5052
- });
5053
- this.selection = new Selection(this.container);
5054
- this.command = new Command(this.selection);
5055
- this.history = new History(this.selection);
5056
- this.keystroke = new Keystroke(this.container);
5057
- editors.set(this.container.id, this);
5058
- }
5059
- inputInBoxStrip() {
5060
- const selection = this.selection;
5061
- const range = selection.range;
5062
- const stripNode = range.startNode.closest('.lake-box-strip');
5063
- const boxNode = stripNode.closest('lake-box');
5064
- const box = new Box(boxNode);
5065
- if (box.type === 'inline') {
5066
- if (range.isBoxStart) {
5067
- range.setStartBefore(boxNode);
5068
- range.collapseToStart();
5069
- }
5070
- else {
5071
- range.setStartAfter(boxNode);
5072
- range.collapseToStart();
5073
- }
5074
- }
5075
- else {
5076
- const paragraph = query('<p />');
5077
- if (range.isBoxStart) {
5078
- boxNode.before(paragraph);
5079
- }
5080
- else {
5081
- boxNode.after(paragraph);
5082
- }
5083
- range.shrinkAfter(paragraph);
5084
- }
5085
- const text = stripNode.text();
5086
- stripNode.html('<br />');
5087
- selection.insertNode(document.createTextNode(text));
5088
- }
5089
- bindInputEvents() {
5090
- this.container.on('compositionstart', () => {
5091
- this.isComposing = true;
5092
- });
5093
- this.container.on('compositionend', () => {
5094
- this.isComposing = false;
5095
- });
5096
- this.container.on('beforeinput', event => {
5097
- const inputEvent = event;
5098
- const range = this.selection.range;
5099
- if (range.isBoxStart || range.isBoxEnd) {
5100
- this.commitUnsavedInputData();
5101
- return;
5102
- }
5103
- if (inputEvent.inputType === 'insertText' ||
5104
- inputEvent.inputType === 'insertCompositionText') {
5105
- return;
5106
- }
5107
- this.commitUnsavedInputData();
5108
- });
5109
- this.container.on('input', event => {
5110
- const inputEvent = event;
5111
- // Here setTimeout is necessary because isComposing is not false after ending composition.
5112
- window.setTimeout(() => {
5113
- var _a;
5114
- const range = this.selection.range;
5115
- if (range.isInsideBox) {
5116
- return;
5117
- }
5118
- // isComposing is false after ending composition because compositionend event has been emitted.
5119
- if (this.isComposing) {
5120
- this.event.emit('input', inputEvent);
5121
- return;
5122
- }
5123
- if (range.isBoxStart || range.isBoxEnd) {
5124
- this.inputInBoxStrip();
5125
- this.history.save();
5126
- this.event.emit('input', inputEvent);
5127
- return;
5128
- }
5129
- if (inputEvent.inputType === 'insertText' ||
5130
- inputEvent.inputType === 'insertCompositionText') {
5131
- this.unsavedInputData += (_a = inputEvent.data) !== null && _a !== void 0 ? _a : '';
5132
- if (this.unsavedInputData.length < this.config.minChangeSize) {
5133
- this.event.emit('input', inputEvent);
5134
- this.emitChangeEvent(this.getValue());
5135
- return;
5136
- }
5137
- }
5138
- this.history.save();
5139
- this.event.emit('input', inputEvent);
5140
- }, 0);
5141
- });
5142
- this.command.event.on('beforeexecute', () => this.commitUnsavedInputData());
5143
- }
5144
- bindHistoryEvents() {
5145
- this.history.event.on('undo', value => {
5146
- this.box.renderAll(this);
5147
- this.emitChangeEvent(value);
5148
- });
5149
- this.history.event.on('redo', value => {
5150
- this.box.renderAll(this);
5151
- this.emitChangeEvent(value);
5152
- });
5153
- this.history.event.on('save', value => {
5154
- this.box.rectifyInstances(this);
5155
- this.emitChangeEvent(value);
5156
- });
5157
- }
5158
- bindFocusEvents() {
5159
- this.container.on('focus', () => {
5160
- this.root.addClass('lake-root-focused');
5161
- });
5162
- this.container.on('blur', () => {
5163
- this.root.removeClass('lake-root-focused');
5164
- });
5165
- }
5166
- // Fixes wrong content, especially empty tag.
5167
- rectifyContent() {
5168
- let children = this.container.children();
5169
- for (const child of children) {
5170
- if ((child.isBlock || child.isMark) && child.html() === '') {
5171
- child.remove();
5172
- debug('Rectifying content: empty tag was removed');
5173
- }
5174
- }
5175
- children = this.container.children();
5176
- if (children.length === 0) {
5177
- this.container.html('<p><br /></p>');
5178
- this.selection.range.shrinkAfter(this.container);
5179
- debug('Rectifying content: default paragraph was added');
5180
- return;
5181
- }
5182
- if (children.length === 1) {
5183
- const child = children[0];
5184
- if (child.isVoid) {
5185
- const paragraph = query('<p />');
5186
- child.before(paragraph);
5187
- paragraph.append(child);
5188
- this.selection.range.shrinkAfter(paragraph);
5189
- debug('Rectifying content: void element was wrapped in paragraph');
5190
- }
5191
- }
5192
- }
5193
- // Saves the input data which is unsaved.
5194
- commitUnsavedInputData() {
5195
- if (this.unsavedInputData.length > 0) {
5196
- this.history.save(false);
5197
- this.unsavedInputData = '';
5198
- }
5199
- }
5200
- // Updates some state before custom modifications.
5201
- prepareOperation() {
5202
- this.commitUnsavedInputData();
5203
- this.history.pause();
5204
- }
5205
- // Saves custom modifications to the history.
5206
- commitOperation() {
5207
- this.history.continue();
5208
- this.history.save();
5209
- }
5210
- // Sets default config for a plugin.
5211
- setPluginConfig(pluginName, pluginConfig) {
5212
- if (!this.config[pluginName]) {
5213
- this.config[pluginName] = {};
5214
- }
5215
- for (const key of Object.keys(pluginConfig)) {
5216
- if (this.config[pluginName][key] === undefined) {
5217
- this.config[pluginName][key] = pluginConfig[key];
5218
- }
5219
- }
5220
- }
5221
- // Sets focus on the editor area.
5222
- focus() {
5223
- this.container.focus();
5224
- }
5225
- // Removes focus from the editor area.
5226
- blur() {
5227
- this.container.blur();
5228
- }
5229
- // Sets the specified HTML string to the editor area.
5230
- setValue(value) {
5231
- value = normalizeValue(value);
5232
- const htmlParser = new HTMLParser(value);
5233
- const fragment = htmlParser.getFragment();
5234
- this.container.empty();
5235
- this.container.append(fragment);
5236
- Editor.box.renderAll(this);
5237
- this.selection.synByBookmark();
5238
- }
5239
- // Returns the contents from the editor.
5240
- getValue() {
5241
- const bookmark = this.selection.insertBookmark();
5242
- let value = new HTMLParser(this.container).getHTML();
5243
- value = denormalizeValue(value);
5244
- this.selection.toBookmark(bookmark);
5245
- return value;
5246
- }
5247
- // Inserts a box into the position of the selection.
5248
- insertBox(boxName, boxValue) {
5249
- const box = insertBox(this.selection.range, boxName, boxValue);
5250
- if (!box) {
5251
- throw new Error(`Box '${boxName}' cannot be inserted outside the editor.`);
5252
- }
5253
- const instanceMap = this.box.getInstances(this);
5254
- instanceMap.set(box.node.id, box);
5255
- return box;
5256
- }
5257
- // Removes the selected box.
5258
- removeBox() {
5259
- const box = removeBox(this.selection.range);
5260
- if (box) {
5261
- const instanceMap = this.box.getInstances(this);
5262
- instanceMap.delete(box.node.id);
5263
- }
5264
- return box;
5265
- }
5266
- // Renders an editor area and set default value to it.
5267
- render() {
5268
- const value = normalizeValue(this.config.value);
5269
- const htmlParser = new HTMLParser(value);
5270
- const fragment = htmlParser.getFragment();
5271
- this.root.empty();
5272
- this.root.append(this.containerWrapper);
5273
- this.containerWrapper.append(this.container);
5274
- this.containerWrapper.append(this.overlayContainer);
5275
- query(document.body).append(this.popupContainer);
5276
- this.container.append(fragment);
5277
- Editor.plugin.loadAll(this);
5278
- if (!this.readonly) {
5279
- this.bindFocusEvents();
5280
- this.selection.synByBookmark();
5281
- this.history.save();
5282
- }
5283
- Editor.box.renderAll(this);
5284
- if (this.toolbar) {
5285
- this.toolbar.render(this);
5286
- }
5287
- if (!this.readonly) {
5288
- window.addEventListener('beforeunload', this.beforeunloadListener);
5289
- document.addEventListener('selectionchange', this.selectionchangeListener);
5290
- document.addEventListener('click', this.clickListener);
5291
- window.addEventListener('resize', this.resizeListener);
5292
- this.bindInputEvents();
5293
- this.bindHistoryEvents();
5294
- }
5295
- }
5296
- // Destroys a rendered editor.
5297
- unmount() {
5298
- this.root.empty();
5299
- this.popupContainer.remove();
5300
- if (!this.readonly) {
5301
- window.removeEventListener('beforeunload', this.beforeunloadListener);
5302
- document.removeEventListener('selectionchange', this.selectionchangeListener);
5303
- document.removeEventListener('click', this.clickListener);
5304
- window.removeEventListener('resize', this.resizeListener);
5305
- }
5306
- }
5307
- }
5308
- Editor.version = version;
5309
- Editor.box = new BoxManager();
5310
- Editor.plugin = new Plugin();
5311
-
5312
- var enUS = {
5313
- toolbar: {
5314
- undo: `Undo (${modifierText('mod+Z')})`,
5315
- redo: `Redo (${modifierText('mod+Y')})`,
5316
- selectAll: `Select all (${modifierText('mod+A')})`,
5317
- paragraph: 'Paragraph',
5318
- blockQuote: 'Block quotation',
5319
- numberedList: 'Numbered list',
5320
- bulletedList: 'Bulleted list',
5321
- checklist: 'Checklist',
5322
- alignLeft: 'Align left',
5323
- alignCenter: 'Align center',
5324
- alignRight: 'Align right',
5325
- alignJustify: 'Align justify',
5326
- increaseIndent: 'Increase indent',
5327
- decreaseIndent: 'Decrease indent',
5328
- bold: `Bold (${modifierText('mod+B')})`,
5329
- italic: `Italic (${modifierText('mod+I')})`,
5330
- underline: `Underline (${modifierText('mod+U')})`,
5331
- strikethrough: 'Strikethrough',
5332
- superscript: 'Superscript',
5333
- subscript: 'Subscript',
5334
- code: 'Inline code',
5335
- removeFormat: 'Remove format',
5336
- formatPainter: 'Format painter',
5337
- link: 'Link',
5338
- hr: 'Horizontal line',
5339
- codeBlock: 'Code block',
5340
- heading: 'Heading',
5341
- heading1: 'Heading 1',
5342
- heading2: 'Heading 2',
5343
- heading3: 'Heading 3',
5344
- heading4: 'Heading 4',
5345
- heading5: 'Heading 5',
5346
- heading6: 'Heading 6',
5347
- list: 'List',
5348
- align: 'Alignment',
5349
- indent: 'Indent',
5350
- fontFamily: 'Font family',
5351
- fontSize: 'Font size',
5352
- moreStyle: 'More style',
5353
- fontColor: 'Font color',
5354
- highlight: 'Highlight',
5355
- image: 'Image',
5356
- removeColor: 'Remove color',
5357
- },
5358
- link: {
5359
- newLink: 'New link',
5360
- url: 'Link URL',
5361
- title: 'Link title',
5362
- copy: 'Copy link to clipboard',
5363
- open: 'Open link in new tab',
5364
- save: 'Save',
5365
- unlink: 'Remove link',
5366
- },
5367
- image: {
5368
- view: 'Full screen',
5369
- remove: 'Delete',
5370
- previous: 'Previous',
5371
- next: 'Next',
5372
- close: 'Close (Esc)',
5373
- loadingError: 'The image cannot be loaded',
5374
- zoomOut: 'Zoom out',
5375
- zoomIn: 'Zoom in',
5376
- },
5377
- codeBlock: {
5378
- langType: 'Select language',
5379
- },
5380
- };
5381
-
5382
- var zhCN = {
5383
- toolbar: {
5384
- undo: `撤消 (${modifierText('mod+Z')})`,
5385
- redo: `重做 (${modifierText('mod+Y')})`,
5386
- selectAll: `全选 (${modifierText('mod+A')})`,
5387
- paragraph: '正文',
5388
- blockQuote: '引用',
5389
- numberedList: '编号',
5390
- bulletedList: '项目符号',
5391
- checklist: '任务列表',
5392
- alignLeft: '左对齐',
5393
- alignCenter: '居中',
5394
- alignRight: '右对齐',
5395
- alignJustify: '两端对齐',
5396
- increaseIndent: '增加缩进',
5397
- decreaseIndent: '减少缩进',
5398
- bold: `粗体 (${modifierText('mod+B')})`,
5399
- italic: `斜体 (${modifierText('mod+I')})`,
5400
- underline: `下划线 (${modifierText('mod+U')})`,
5401
- strikethrough: '删除线',
5402
- superscript: '上标',
5403
- subscript: '下标',
5404
- code: '行内代码',
5405
- removeFormat: '清除格式',
5406
- formatPainter: '格式刷',
5407
- link: '链接',
5408
- hr: '分割线',
5409
- codeBlock: '代码块',
5410
- heading: '标题',
5411
- heading1: '标题 1',
5412
- heading2: '标题 2',
5413
- heading3: '标题 3',
5414
- heading4: '标题 4',
5415
- heading5: '标题 5',
5416
- heading6: '标题 6',
5417
- list: '列表',
5418
- align: '对齐方式',
5419
- indent: '缩进',
5420
- fontFamily: '字体',
5421
- fontSize: '文字大小',
5422
- moreStyle: '更多样式',
5423
- fontColor: '文字颜色',
5424
- highlight: '文字背景',
5425
- image: '图片',
5426
- removeColor: '默认',
5427
- },
5428
- link: {
5429
- newLink: '新链接',
5430
- url: '链接 URL',
5431
- title: '链接文本',
5432
- copy: '复制到剪贴板',
5433
- open: '打开链接',
5434
- save: '确定',
5435
- unlink: '取消链接',
5436
- },
5437
- image: {
5438
- view: '查看大图',
5439
- remove: '删除',
5440
- previous: '上一张',
5441
- next: '下一张',
5442
- close: '关闭 (Esc)',
5443
- loadingError: '图片加载失败',
5444
- zoomOut: '缩小',
5445
- zoomIn: '放大',
5446
- },
5447
- codeBlock: {
5448
- langType: '选择代码语言',
5449
- },
5450
- };
5451
-
5452
- var ja = {
5453
- toolbar: {
5454
- undo: `元に戻す (${modifierText('mod+Z')})`,
5455
- redo: `やり直し (${modifierText('mod+Y')})`,
5456
- selectAll: `すべて選択 (${modifierText('mod+A')})`,
5457
- paragraph: 'テキスト',
5458
- blockQuote: 'ブロック引用',
5459
- numberedList: '番号付きリスト',
5460
- bulletedList: '箇条書きリスト',
5461
- checklist: 'タスクリスト',
5462
- alignLeft: '左揃え',
5463
- alignCenter: '中心揃え',
5464
- alignRight: '右揃え',
5465
- alignJustify: '左右に並べ替え',
5466
- increaseIndent: 'インデントを増やす',
5467
- decreaseIndent: 'インデントを減らす',
5468
- bold: `太字 (${modifierText('mod+B')})`,
5469
- italic: `斜体 (${modifierText('mod+I')})`,
5470
- underline: `下線 (${modifierText('mod+U')})`,
5471
- strikethrough: '取り消し線',
5472
- superscript: '上付き文字',
5473
- subscript: '下付き文字',
5474
- code: 'インラインコード',
5475
- removeFormat: '形式を削除',
5476
- formatPainter: '形式ペインタ',
5477
- link: 'リンク',
5478
- hr: '区切り線',
5479
- codeBlock: 'コードブロック',
5480
- heading: 'タイトル',
5481
- heading1: 'タイトル 1',
5482
- heading2: 'タイトル 2',
5483
- heading3: 'タイトル 3',
5484
- heading4: 'タイトル 4',
5485
- heading5: 'タイトル 5',
5486
- heading6: 'タイトル 6',
5487
- list: 'リスト',
5488
- align: '文字揃え',
5489
- indent: 'インデント',
5490
- fontFamily: 'フォント',
5491
- fontSize: '文字サイズ',
5492
- moreStyle: 'その他のスタイル',
5493
- fontColor: '文字色',
5494
- highlight: '文字の背景',
5495
- image: '画像',
5496
- removeColor: 'デフォルト',
5497
- },
5498
- link: {
5499
- newLink: '新しいリンク',
5500
- url: 'リンク URL',
5501
- title: 'リンク文字',
5502
- copy: 'クリップボードにコピー',
5503
- open: 'リンクを開く',
5504
- save: '確認',
5505
- unlink: 'リンクを削除',
5506
- },
5507
- image: {
5508
- view: '大きな画像を見る',
5509
- remove: '削除',
5510
- previous: '前の画像',
5511
- next: '次の画像',
5512
- close: '閉じる (Esc)',
5513
- loadingError: '画像を読み込めません',
5514
- zoomOut: '縮小',
5515
- zoomIn: '拡大',
5516
- },
5517
- codeBlock: {
5518
- langType: 'コード言語を選択',
5519
- },
5520
- };
5521
-
5522
- var ko = {
5523
- toolbar: {
5524
- undo: `작업취소 (${modifierText('mod+Z')})`,
5525
- redo: `작업재개 (${modifierText('mod+Y')})`,
5526
- selectAll: `전체 선택 (${modifierText('mod+A')})`,
5527
- paragraph: '텍스트',
5528
- blockQuote: '인용문',
5529
- numberedList: '순서 목록',
5530
- bulletedList: '비순서 목록',
5531
- checklist: '체크리스트',
5532
- alignLeft: '왼쪽 정렬',
5533
- alignCenter: '가운데 정렬',
5534
- alignRight: '오른쪽 정렬',
5535
- alignJustify: '좌우로 정렬',
5536
- increaseIndent: '들여쓰기 증가',
5537
- decreaseIndent: '들여쓰기 줄이기',
5538
- bold: `굵게 (${modifierText('mod+B')})`,
5539
- italic: `기울임꼴 (${modifierText('mod+I')})`,
5540
- underline: `밑줄 (${modifierText('mod+U')})`,
5541
- strikethrough: '취소선',
5542
- superscript: '위첨자',
5543
- subscript: '아래 첨자',
5544
- code: '인라인 코드',
5545
- removeFormat: '형식 지우기',
5546
- formatPainter: '형식 페인터',
5547
- link: '링크',
5548
- hr: '구분선',
5549
- codeBlock: '코드 블록',
5550
- heading: '제목',
5551
- heading1: '제목 1',
5552
- heading2: '제목 2',
5553
- heading3: '제목 3',
5554
- heading4: '제목 4',
5555
- heading5: '제목 5',
5556
- heading6: '제목 6',
5557
- list: '목록',
5558
- align: '정렬',
5559
- indent: '들여쓰기',
5560
- fontFamily: '글꼴',
5561
- fontSize: '글자 크기',
5562
- moreStyle: '더 많은 스타일',
5563
- fontColor: '글자 색상',
5564
- highlight: '글자 배경',
5565
- image: '이미지',
5566
- removeColor: '기본색',
5567
- },
5568
- link: {
5569
- newLink: '새 링크',
5570
- url: '링크 URL',
5571
- title: '링크 텍스트',
5572
- copy: '클립보드에 복사',
5573
- open: '링크 열기',
5574
- save: '확인',
5575
- unlink: '링크 제거',
5576
- },
5577
- image: {
5578
- view: '큰 이미지 보기',
5579
- remove: '삭제',
5580
- previous: '이전 이미지',
5581
- next: '다음 이미지',
5582
- close: '닫기 (Esc)',
5583
- loadingError: '이미지를 로드할 수 없습니다',
5584
- zoomOut: '축소',
5585
- zoomIn: '확대',
5586
- },
5587
- codeBlock: {
5588
- langType: '코드언어 선택',
5589
- },
5590
- };
5142
+ for (const item of this.keyupEventList) {
5143
+ if (item.type === type) {
5144
+ if (item.listener(new Event(type)) === false) {
5145
+ break;
5146
+ }
5147
+ }
5148
+ }
5149
+ }
5150
+ }
5591
5151
 
5592
- const localeTranslations = {
5593
- 'en-US': enUS,
5594
- 'zh-CN': zhCN,
5595
- ja,
5596
- ko,
5597
- };
5598
- const locales = Object.keys(localeTranslations);
5599
- const loadedLocales = {};
5600
- const loadedFormatters = {};
5601
- const initFormatters = () => {
5602
- const formatters = {
5603
- // add your formatter functions here
5604
- };
5605
- return formatters;
5606
- };
5607
- const loadFormatters = (locale) => {
5608
- loadedFormatters[locale] = initFormatters();
5152
+ class BoxManager {
5153
+ add(component) {
5154
+ boxes.set(component.name, component);
5155
+ }
5156
+ remove(name) {
5157
+ boxes.delete(name);
5158
+ }
5159
+ getNames() {
5160
+ return Array.from(boxes.keys());
5161
+ }
5162
+ getInstances(editor) {
5163
+ let instanceMap = boxInstances.get(editor.container.id);
5164
+ if (!instanceMap) {
5165
+ instanceMap = new Map();
5166
+ boxInstances.set(editor.container.id, instanceMap);
5167
+ return instanceMap;
5168
+ }
5169
+ return instanceMap;
5170
+ }
5171
+ rectifyInstances(editor) {
5172
+ const instanceMap = this.getInstances(editor);
5173
+ for (const box of instanceMap.values()) {
5174
+ if (!box.node.get(0).isConnected) {
5175
+ box.unmount();
5176
+ instanceMap.delete(box.node.id);
5177
+ }
5178
+ }
5179
+ }
5180
+ findAll(editor) {
5181
+ return editor.container.find('lake-box');
5182
+ }
5183
+ renderAll(editor) {
5184
+ this.rectifyInstances(editor);
5185
+ const instanceMap = this.getInstances(editor);
5186
+ this.findAll(editor).each(boxNativeNode => {
5187
+ const boxNode = new Nodes(boxNativeNode);
5188
+ if (instanceMap.get(boxNode.id)) {
5189
+ return;
5190
+ }
5191
+ const box = new Box(boxNode);
5192
+ box.render();
5193
+ instanceMap.set(box.node.id, box);
5194
+ });
5195
+ }
5196
+ }
5197
+
5198
+ class Plugin {
5199
+ constructor() {
5200
+ this.pluginList = [];
5201
+ }
5202
+ add(plugin) {
5203
+ this.pluginList.push(plugin);
5204
+ }
5205
+ loadAll(editor) {
5206
+ this.pluginList.forEach(plugin => {
5207
+ plugin(editor);
5208
+ });
5209
+ }
5210
+ }
5211
+
5212
+ const defaultConfig = {
5213
+ value: '<p><br /><focus /></p>',
5214
+ readonly: false,
5215
+ spellcheck: false,
5216
+ tabIndex: 0,
5217
+ indentWithTab: true,
5218
+ lang: 'en-US',
5219
+ minChangeSize: 5,
5609
5220
  };
5610
- const loadLocale = (locale) => {
5611
- if (loadedLocales[locale]) {
5612
- return;
5221
+ class Editor {
5222
+ constructor(config) {
5223
+ this.unsavedInputData = '';
5224
+ this.stateData = {
5225
+ appliedItems: [],
5226
+ disabledNameMap: new Map(),
5227
+ selectedNameMap: new Map(),
5228
+ selectedValuesMap: new Map(),
5229
+ };
5230
+ this.isComposing = false;
5231
+ this.event = new EventEmitter();
5232
+ this.box = Editor.box;
5233
+ this.beforeunloadListener = () => {
5234
+ this.history.save();
5235
+ };
5236
+ this.selectionchangeListener = () => {
5237
+ this.selection.syncByRange();
5238
+ this.updateBoxSelectionStyle();
5239
+ this.emitStateChangeEvent();
5240
+ };
5241
+ this.clickListener = event => {
5242
+ const targetNode = new Nodes(event.target);
5243
+ if (targetNode.closest('.lake-popup').length > 0) {
5244
+ return;
5245
+ }
5246
+ this.event.emit('click', targetNode);
5247
+ };
5248
+ this.resizeListener = () => {
5249
+ this.event.emit('resize');
5250
+ };
5251
+ this.updateBoxSelectionStyle = debounce(() => {
5252
+ // The editor has been unmounted.
5253
+ if (this.root.first().length === 0) {
5254
+ return;
5255
+ }
5256
+ const range = this.selection.range;
5257
+ const clonedRange = range.clone();
5258
+ clonedRange.adaptBox();
5259
+ this.box.findAll(this).each(boxNode => {
5260
+ const box = new Box(boxNode);
5261
+ const boxContainer = box.getContainer();
5262
+ if (boxContainer.length === 0) {
5263
+ return;
5264
+ }
5265
+ if (range.compareBeforeNode(boxContainer) < 0 && range.compareAfterNode(boxContainer) > 0) {
5266
+ if (!(range.isCollapsed && range.startNode.get(0) === boxContainer.get(0) && range.startOffset === 0)) {
5267
+ boxContainer.removeClass('lake-box-hovered');
5268
+ boxContainer.removeClass('lake-box-selected');
5269
+ boxContainer.removeClass('lake-box-focused');
5270
+ boxContainer.addClass('lake-box-activated');
5271
+ return;
5272
+ }
5273
+ }
5274
+ if (clonedRange.intersectsNode(box.node)) {
5275
+ boxContainer.removeClass('lake-box-activated');
5276
+ if (range.isCollapsed) {
5277
+ boxContainer.removeClass('lake-box-hovered');
5278
+ boxContainer.removeClass('lake-box-selected');
5279
+ boxContainer.addClass('lake-box-focused');
5280
+ }
5281
+ else {
5282
+ boxContainer.removeClass('lake-box-focused');
5283
+ boxContainer.addClass('lake-box-selected');
5284
+ }
5285
+ return;
5286
+ }
5287
+ boxContainer.removeClass('lake-box-activated');
5288
+ boxContainer.removeClass('lake-box-focused');
5289
+ boxContainer.removeClass('lake-box-selected');
5290
+ });
5291
+ this.event.emit('boxselectionstylechange');
5292
+ }, 50, {
5293
+ leading: false,
5294
+ trailing: true,
5295
+ maxWait: 50,
5296
+ });
5297
+ this.emitStateChangeEvent = debounce(() => {
5298
+ const commandNames = this.command.getNames();
5299
+ let appliedItems = this.selection.getAppliedItems();
5300
+ if (appliedItems.length > 0 &&
5301
+ appliedItems[0].node.closestContainer().get(0) !== this.container.get(0)) {
5302
+ appliedItems = [];
5303
+ }
5304
+ const disabledNameMap = new Map();
5305
+ const selectedNameMap = new Map();
5306
+ const selectedValuesMap = new Map();
5307
+ if (appliedItems.length > 0) {
5308
+ for (const name of commandNames) {
5309
+ const commandItem = this.command.getItem(name);
5310
+ if (commandItem.isDisabled && commandItem.isDisabled(appliedItems)) {
5311
+ disabledNameMap.set(name, true);
5312
+ }
5313
+ if (commandItem.isSelected && commandItem.isSelected(appliedItems)) {
5314
+ selectedNameMap.set(name, true);
5315
+ }
5316
+ if (commandItem.selectedValues) {
5317
+ const values = commandItem.selectedValues(appliedItems);
5318
+ if (values.length > 0) {
5319
+ selectedValuesMap.set(name, values);
5320
+ }
5321
+ }
5322
+ }
5323
+ }
5324
+ const stateData = {
5325
+ appliedItems,
5326
+ disabledNameMap,
5327
+ selectedNameMap,
5328
+ selectedValuesMap,
5329
+ };
5330
+ if (isEqual(stateData, this.stateData)) {
5331
+ return;
5332
+ }
5333
+ if (this.toolbar) {
5334
+ this.toolbar.updateState(stateData);
5335
+ }
5336
+ this.event.emit('statechange', stateData);
5337
+ this.stateData = stateData;
5338
+ }, 100, {
5339
+ leading: false,
5340
+ trailing: true,
5341
+ maxWait: 100,
5342
+ });
5343
+ this.emitChangeEvent = (value) => {
5344
+ this.rectifyContent();
5345
+ this.emitStateChangeEvent();
5346
+ this.event.emit('change', value);
5347
+ };
5348
+ if (!config.root) {
5349
+ throw new Error('The root of the config must be specified.');
5350
+ }
5351
+ this.root = query(config.root);
5352
+ this.toolbar = config.toolbar;
5353
+ this.config = Object.assign({}, defaultConfig);
5354
+ for (const key of Object.keys(config)) {
5355
+ this.config[key] = config[key];
5356
+ }
5357
+ this.containerWrapper = query('<div class="lake-container-wrapper" />');
5358
+ this.container = query('<div class="lake-container" />');
5359
+ this.overlayContainer = query('<div class="lake-overlay" />');
5360
+ this.popupContainer = query('<div class="lake-popup lake-custom-properties" />');
5361
+ this.readonly = this.config.readonly;
5362
+ this.root.addClass('lake-custom-properties');
5363
+ this.container.attr({
5364
+ contenteditable: this.readonly ? 'false' : 'true',
5365
+ spellcheck: this.config.spellcheck ? 'true' : 'false',
5366
+ tabindex: this.config.tabIndex.toString(),
5367
+ });
5368
+ this.selection = new Selection(this.container);
5369
+ this.command = new Command(this.selection);
5370
+ this.history = new History(this.selection);
5371
+ this.keystroke = new Keystroke(this.container);
5372
+ editors.set(this.container.id, this);
5373
+ }
5374
+ inputInBoxStrip() {
5375
+ const selection = this.selection;
5376
+ const range = selection.range;
5377
+ const stripNode = range.startNode.closest('.lake-box-strip');
5378
+ const boxNode = stripNode.closest('lake-box');
5379
+ const box = new Box(boxNode);
5380
+ if (box.type === 'inline') {
5381
+ if (range.isBoxStart) {
5382
+ range.setStartBefore(boxNode);
5383
+ range.collapseToStart();
5384
+ }
5385
+ else {
5386
+ range.setStartAfter(boxNode);
5387
+ range.collapseToStart();
5388
+ }
5389
+ }
5390
+ else {
5391
+ const paragraph = query('<p />');
5392
+ if (range.isBoxStart) {
5393
+ boxNode.before(paragraph);
5394
+ }
5395
+ else {
5396
+ boxNode.after(paragraph);
5397
+ }
5398
+ range.shrinkAfter(paragraph);
5399
+ }
5400
+ const text = stripNode.text();
5401
+ stripNode.html('<br />');
5402
+ selection.insertNode(document.createTextNode(text));
5613
5403
  }
5614
- loadedLocales[locale] = localeTranslations[locale];
5615
- loadFormatters(locale);
5616
- };
5617
- const loadAllLocales = () => locales.forEach(loadLocale);
5618
- const i18nObject = (locale) => i18nObject$1(locale, loadedLocales[locale], loadedFormatters[locale]);
5619
- loadAllLocales();
5620
- const language = locales.indexOf(window.LAKE_LANGUAGE) >= 0 ? window.LAKE_LANGUAGE : 'en-US';
5621
- const locale = i18nObject(language);
5404
+ bindInputEvents() {
5405
+ this.container.on('compositionstart', () => {
5406
+ this.isComposing = true;
5407
+ });
5408
+ this.container.on('compositionend', () => {
5409
+ this.isComposing = false;
5410
+ });
5411
+ this.container.on('beforeinput', event => {
5412
+ const inputEvent = event;
5413
+ const range = this.selection.range;
5414
+ if (range.isBoxStart || range.isBoxEnd) {
5415
+ this.commitUnsavedInputData();
5416
+ return;
5417
+ }
5418
+ if (inputEvent.inputType === 'insertText' ||
5419
+ inputEvent.inputType === 'insertCompositionText') {
5420
+ return;
5421
+ }
5422
+ this.commitUnsavedInputData();
5423
+ });
5424
+ this.container.on('input', event => {
5425
+ const inputEvent = event;
5426
+ // Here setTimeout is necessary because isComposing is not false after ending composition.
5427
+ window.setTimeout(() => {
5428
+ var _a;
5429
+ const range = this.selection.range;
5430
+ if (range.isInsideBox) {
5431
+ return;
5432
+ }
5433
+ // isComposing is false after ending composition because compositionend event has been emitted.
5434
+ if (this.isComposing) {
5435
+ this.event.emit('input', inputEvent);
5436
+ return;
5437
+ }
5438
+ if (range.isBoxStart || range.isBoxEnd) {
5439
+ this.inputInBoxStrip();
5440
+ this.history.save();
5441
+ this.event.emit('input', inputEvent);
5442
+ return;
5443
+ }
5444
+ if (inputEvent.inputType === 'insertText' ||
5445
+ inputEvent.inputType === 'insertCompositionText') {
5446
+ this.unsavedInputData += (_a = inputEvent.data) !== null && _a !== void 0 ? _a : '';
5447
+ if (this.unsavedInputData.length < this.config.minChangeSize) {
5448
+ this.event.emit('input', inputEvent);
5449
+ this.emitChangeEvent(this.getValue());
5450
+ return;
5451
+ }
5452
+ }
5453
+ this.history.save();
5454
+ this.event.emit('input', inputEvent);
5455
+ }, 0);
5456
+ });
5457
+ this.command.event.on('beforeexecute', () => this.commitUnsavedInputData());
5458
+ }
5459
+ bindHistoryEvents() {
5460
+ this.history.event.on('undo', value => {
5461
+ this.box.renderAll(this);
5462
+ this.emitChangeEvent(value);
5463
+ });
5464
+ this.history.event.on('redo', value => {
5465
+ this.box.renderAll(this);
5466
+ this.emitChangeEvent(value);
5467
+ });
5468
+ this.history.event.on('save', value => {
5469
+ this.box.rectifyInstances(this);
5470
+ this.emitChangeEvent(value);
5471
+ });
5472
+ }
5473
+ // Returns a boolean value indicating whether the editor has focus.
5474
+ get hasFocus() {
5475
+ const activeElement = document.activeElement;
5476
+ if (!activeElement) {
5477
+ return false;
5478
+ }
5479
+ return query(activeElement).closest('.lake-container').get(0) === this.container.get(0);
5480
+ }
5481
+ // Returns translation functions by the specified lang.
5482
+ get locale() {
5483
+ return i18nObject(this.config.lang);
5484
+ }
5485
+ // Fixes wrong content, especially empty tag.
5486
+ rectifyContent() {
5487
+ let children = this.container.children();
5488
+ for (const child of children) {
5489
+ if ((child.isBlock || child.isMark) && child.html() === '') {
5490
+ child.remove();
5491
+ debug('Rectifying content: empty tag was removed');
5492
+ }
5493
+ }
5494
+ children = this.container.children();
5495
+ if (children.length === 0) {
5496
+ this.container.html('<p><br /></p>');
5497
+ this.selection.range.shrinkAfter(this.container);
5498
+ debug('Rectifying content: default paragraph was added');
5499
+ return;
5500
+ }
5501
+ if (children.length === 1) {
5502
+ const child = children[0];
5503
+ if (child.isVoid) {
5504
+ const paragraph = query('<p />');
5505
+ child.before(paragraph);
5506
+ paragraph.append(child);
5507
+ this.selection.range.shrinkAfter(paragraph);
5508
+ debug('Rectifying content: void element was wrapped in paragraph');
5509
+ }
5510
+ }
5511
+ }
5512
+ // Saves the input data which is unsaved.
5513
+ commitUnsavedInputData() {
5514
+ if (this.unsavedInputData.length > 0) {
5515
+ this.history.save(false);
5516
+ this.unsavedInputData = '';
5517
+ }
5518
+ }
5519
+ // Updates some state before custom modifications.
5520
+ prepareOperation() {
5521
+ this.commitUnsavedInputData();
5522
+ this.history.pause();
5523
+ }
5524
+ // Saves custom modifications to the history.
5525
+ commitOperation() {
5526
+ this.history.continue();
5527
+ this.history.save();
5528
+ }
5529
+ // Sets default config for a plugin.
5530
+ setPluginConfig(pluginName, pluginConfig) {
5531
+ if (!this.config[pluginName]) {
5532
+ this.config[pluginName] = {};
5533
+ }
5534
+ for (const key of Object.keys(pluginConfig)) {
5535
+ if (this.config[pluginName][key] === undefined) {
5536
+ this.config[pluginName][key] = pluginConfig[key];
5537
+ }
5538
+ }
5539
+ }
5540
+ // Sets focus on the editor area.
5541
+ focus() {
5542
+ this.container.focus();
5543
+ }
5544
+ // Removes focus from the editor area.
5545
+ blur() {
5546
+ this.container.blur();
5547
+ }
5548
+ // Sets the specified HTML string to the editor area.
5549
+ setValue(value) {
5550
+ value = normalizeValue(value);
5551
+ const htmlParser = new HTMLParser(value);
5552
+ const fragment = htmlParser.getFragment();
5553
+ this.container.empty();
5554
+ this.container.append(fragment);
5555
+ Editor.box.renderAll(this);
5556
+ this.selection.synByBookmark();
5557
+ }
5558
+ // Returns the contents from the editor.
5559
+ getValue() {
5560
+ const bookmark = this.selection.insertBookmark();
5561
+ let value = new HTMLParser(this.container).getHTML();
5562
+ value = denormalizeValue(value);
5563
+ this.selection.toBookmark(bookmark);
5564
+ return value;
5565
+ }
5566
+ // Inserts a box into the position of the selection.
5567
+ insertBox(boxName, boxValue) {
5568
+ const box = insertBox(this.selection.range, boxName, boxValue);
5569
+ if (!box) {
5570
+ throw new Error(`Box '${boxName}' cannot be inserted outside the editor.`);
5571
+ }
5572
+ const instanceMap = this.box.getInstances(this);
5573
+ instanceMap.set(box.node.id, box);
5574
+ return box;
5575
+ }
5576
+ // Removes the selected box.
5577
+ removeBox() {
5578
+ const box = removeBox(this.selection.range);
5579
+ if (box) {
5580
+ const instanceMap = this.box.getInstances(this);
5581
+ instanceMap.delete(box.node.id);
5582
+ }
5583
+ return box;
5584
+ }
5585
+ // Renders an editor area and set default value to it.
5586
+ render() {
5587
+ const value = normalizeValue(this.config.value);
5588
+ const htmlParser = new HTMLParser(value);
5589
+ const fragment = htmlParser.getFragment();
5590
+ this.root.empty();
5591
+ this.root.append(this.containerWrapper);
5592
+ this.containerWrapper.append(this.container);
5593
+ this.containerWrapper.append(this.overlayContainer);
5594
+ query(document.body).append(this.popupContainer);
5595
+ this.container.append(fragment);
5596
+ Editor.plugin.loadAll(this);
5597
+ if (!this.readonly) {
5598
+ this.selection.synByBookmark();
5599
+ this.history.save();
5600
+ }
5601
+ Editor.box.renderAll(this);
5602
+ if (this.toolbar) {
5603
+ this.toolbar.render(this);
5604
+ }
5605
+ if (!this.readonly) {
5606
+ window.addEventListener('beforeunload', this.beforeunloadListener);
5607
+ document.addEventListener('selectionchange', this.selectionchangeListener);
5608
+ document.addEventListener('click', this.clickListener);
5609
+ window.addEventListener('resize', this.resizeListener);
5610
+ this.bindInputEvents();
5611
+ this.bindHistoryEvents();
5612
+ }
5613
+ }
5614
+ // Destroys a rendered editor.
5615
+ unmount() {
5616
+ this.root.empty();
5617
+ this.popupContainer.remove();
5618
+ if (!this.readonly) {
5619
+ window.removeEventListener('beforeunload', this.beforeunloadListener);
5620
+ document.removeEventListener('selectionchange', this.selectionchangeListener);
5621
+ document.removeEventListener('click', this.clickListener);
5622
+ window.removeEventListener('resize', this.resizeListener);
5623
+ }
5624
+ }
5625
+ }
5626
+ Editor.version = version;
5627
+ Editor.box = new BoxManager();
5628
+ Editor.plugin = new Plugin();
5622
5629
 
5623
5630
  const headingMenuItems = [
5624
5631
  {
5625
5632
  value: 'h1',
5626
- text: `<span style="font-weight: bold; font-size: 26px;">${locale.toolbar.heading1()}</span>`,
5633
+ text: locale => `<span style="font-weight: bold; font-size: 26px;">${locale.toolbar.heading1()}</span>`,
5627
5634
  },
5628
5635
  {
5629
5636
  value: 'h2',
5630
- text: `<span style="font-weight: bold; font-size: 24px;">${locale.toolbar.heading2()}</span>`,
5637
+ text: locale => `<span style="font-weight: bold; font-size: 24px;">${locale.toolbar.heading2()}</span>`,
5631
5638
  },
5632
5639
  {
5633
5640
  value: 'h3',
5634
- text: `<span style="font-weight: bold; font-size: 22px;">${locale.toolbar.heading3()}</span>`,
5641
+ text: locale => `<span style="font-weight: bold; font-size: 22px;">${locale.toolbar.heading3()}</span>`,
5635
5642
  },
5636
5643
  {
5637
5644
  value: 'h4',
5638
- text: `<span style="font-weight: bold; font-size: 20px;">${locale.toolbar.heading4()}</span>`,
5645
+ text: locale => `<span style="font-weight: bold; font-size: 20px;">${locale.toolbar.heading4()}</span>`,
5639
5646
  },
5640
5647
  {
5641
5648
  value: 'h5',
5642
- text: `<span style="font-weight: bold; font-size: 18px;">${locale.toolbar.heading5()}</span>`,
5649
+ text: locale => `<span style="font-weight: bold; font-size: 18px;">${locale.toolbar.heading5()}</span>`,
5643
5650
  },
5644
5651
  {
5645
5652
  value: 'h6',
5646
- text: `<span style="font-weight: bold; font-size: 16px;">${locale.toolbar.heading6()}</span>`,
5653
+ text: locale => `<span style="font-weight: bold; font-size: 16px;">${locale.toolbar.heading6()}</span>`,
5647
5654
  },
5648
5655
  {
5649
5656
  value: 'p',
5650
- text: locale.toolbar.paragraph(),
5657
+ text: locale => locale.toolbar.paragraph(),
5651
5658
  },
5652
5659
  ];
5653
5660
  const listMenuItems = [
5654
5661
  {
5655
5662
  icon: icons.get('numberedList'),
5656
5663
  value: 'numbered',
5657
- text: locale.toolbar.numberedList(),
5664
+ text: locale => locale.toolbar.numberedList(),
5658
5665
  },
5659
5666
  {
5660
5667
  icon: icons.get('bulletedList'),
5661
5668
  value: 'bulleted',
5662
- text: locale.toolbar.bulletedList(),
5669
+ text: locale => locale.toolbar.bulletedList(),
5663
5670
  },
5664
5671
  {
5665
5672
  icon: icons.get('checklist'),
5666
5673
  value: 'checklist',
5667
- text: locale.toolbar.checklist(),
5674
+ text: locale => locale.toolbar.checklist(),
5668
5675
  },
5669
5676
  ];
5670
5677
  const alignMenuItems = [
5671
5678
  {
5672
5679
  icon: icons.get('alignLeft'),
5673
5680
  value: 'left',
5674
- text: locale.toolbar.alignLeft(),
5681
+ text: locale => locale.toolbar.alignLeft(),
5675
5682
  },
5676
5683
  {
5677
5684
  icon: icons.get('alignCenter'),
5678
5685
  value: 'center',
5679
- text: locale.toolbar.alignCenter(),
5686
+ text: locale => locale.toolbar.alignCenter(),
5680
5687
  },
5681
5688
  {
5682
5689
  icon: icons.get('alignRight'),
5683
5690
  value: 'right',
5684
- text: locale.toolbar.alignRight(),
5691
+ text: locale => locale.toolbar.alignRight(),
5685
5692
  },
5686
5693
  {
5687
5694
  icon: icons.get('alignJustify'),
5688
5695
  value: 'justify',
5689
- text: locale.toolbar.alignJustify(),
5696
+ text: locale => locale.toolbar.alignJustify(),
5690
5697
  },
5691
5698
  ];
5692
5699
  const indentMenuItems = [
5693
5700
  {
5694
5701
  icon: icons.get('increaseIndent'),
5695
5702
  value: 'increase',
5696
- text: locale.toolbar.increaseIndent(),
5703
+ text: locale => locale.toolbar.increaseIndent(),
5697
5704
  },
5698
5705
  {
5699
5706
  icon: icons.get('decreaseIndent'),
5700
5707
  value: 'decrease',
5701
- text: locale.toolbar.decreaseIndent(),
5708
+ text: locale => locale.toolbar.decreaseIndent(),
5702
5709
  },
5703
5710
  ];
5704
5711
  const fontFamilyMenuItems = [
@@ -5785,32 +5792,32 @@ const moreStyleMenuItems = [
5785
5792
  {
5786
5793
  icon: icons.get('italic'),
5787
5794
  value: 'italic',
5788
- text: locale.toolbar.italic(),
5795
+ text: locale => locale.toolbar.italic(),
5789
5796
  },
5790
5797
  {
5791
5798
  icon: icons.get('underline'),
5792
5799
  value: 'underline',
5793
- text: locale.toolbar.underline(),
5800
+ text: locale => locale.toolbar.underline(),
5794
5801
  },
5795
5802
  {
5796
5803
  icon: icons.get('strikethrough'),
5797
5804
  value: 'strikethrough',
5798
- text: locale.toolbar.strikethrough(),
5805
+ text: locale => locale.toolbar.strikethrough(),
5799
5806
  },
5800
5807
  {
5801
5808
  icon: icons.get('superscript'),
5802
5809
  value: 'superscript',
5803
- text: locale.toolbar.superscript(),
5810
+ text: locale => locale.toolbar.superscript(),
5804
5811
  },
5805
5812
  {
5806
5813
  icon: icons.get('subscript'),
5807
5814
  value: 'subscript',
5808
- text: locale.toolbar.subscript(),
5815
+ text: locale => locale.toolbar.subscript(),
5809
5816
  },
5810
5817
  {
5811
5818
  icon: icons.get('code'),
5812
5819
  value: 'code',
5813
- text: locale.toolbar.code(),
5820
+ text: locale => locale.toolbar.code(),
5814
5821
  },
5815
5822
  ];
5816
5823
  // These colors are from Ant Design (https://ant.design/docs/spec/colors)
@@ -5833,7 +5840,7 @@ const colorMenuItems = [
5833
5840
  {
5834
5841
  icon: icons.get('removeFormat'),
5835
5842
  value: '',
5836
- text: locale.toolbar.removeColor(),
5843
+ text: locale => locale.toolbar.removeColor(),
5837
5844
  },
5838
5845
  ];
5839
5846
  for (const color of colors) {
@@ -5858,7 +5865,7 @@ const toolbarItems = [
5858
5865
  name: 'undo',
5859
5866
  type: 'button',
5860
5867
  icon: icons.get('undo'),
5861
- tooltip: locale.toolbar.undo(),
5868
+ tooltip: locale => locale.toolbar.undo(),
5862
5869
  onClick: (editor, value) => {
5863
5870
  editor.command.execute(value);
5864
5871
  },
@@ -5867,7 +5874,7 @@ const toolbarItems = [
5867
5874
  name: 'redo',
5868
5875
  type: 'button',
5869
5876
  icon: icons.get('redo'),
5870
- tooltip: locale.toolbar.redo(),
5877
+ tooltip: locale => locale.toolbar.redo(),
5871
5878
  onClick: (editor, value) => {
5872
5879
  editor.command.execute(value);
5873
5880
  },
@@ -5876,7 +5883,7 @@ const toolbarItems = [
5876
5883
  name: 'selectAll',
5877
5884
  type: 'button',
5878
5885
  icon: icons.get('selectAll'),
5879
- tooltip: locale.toolbar.selectAll(),
5886
+ tooltip: locale => locale.toolbar.selectAll(),
5880
5887
  onClick: (editor, value) => {
5881
5888
  editor.command.execute(value);
5882
5889
  },
@@ -5885,7 +5892,7 @@ const toolbarItems = [
5885
5892
  name: 'paragraph',
5886
5893
  type: 'button',
5887
5894
  icon: icons.get('paragraph'),
5888
- tooltip: locale.toolbar.paragraph(),
5895
+ tooltip: locale => locale.toolbar.paragraph(),
5889
5896
  isSelected: appliedItems => !!appliedItems.find(item => item.name === 'p'),
5890
5897
  onClick: editor => {
5891
5898
  editor.command.execute('heading', 'p');
@@ -5895,7 +5902,7 @@ const toolbarItems = [
5895
5902
  name: 'blockQuote',
5896
5903
  type: 'button',
5897
5904
  icon: icons.get('blockQuote'),
5898
- tooltip: locale.toolbar.blockQuote(),
5905
+ tooltip: locale => locale.toolbar.blockQuote(),
5899
5906
  onClick: (editor, value) => {
5900
5907
  editor.command.execute(value);
5901
5908
  },
@@ -5904,7 +5911,7 @@ const toolbarItems = [
5904
5911
  name: 'numberedList',
5905
5912
  type: 'button',
5906
5913
  icon: icons.get('numberedList'),
5907
- tooltip: locale.toolbar.numberedList(),
5914
+ tooltip: locale => locale.toolbar.numberedList(),
5908
5915
  isSelected: appliedItems => !!appliedItems.find(item => item.name === 'ol'),
5909
5916
  onClick: editor => {
5910
5917
  editor.command.execute('list', 'numbered');
@@ -5914,7 +5921,7 @@ const toolbarItems = [
5914
5921
  name: 'bulletedList',
5915
5922
  type: 'button',
5916
5923
  icon: icons.get('bulletedList'),
5917
- tooltip: locale.toolbar.bulletedList(),
5924
+ tooltip: locale => locale.toolbar.bulletedList(),
5918
5925
  isSelected: appliedItems => !!appliedItems.find(item => item.name === 'ul' && !item.node.hasAttr('type')),
5919
5926
  onClick: editor => {
5920
5927
  editor.command.execute('list', 'bulleted');
@@ -5924,7 +5931,7 @@ const toolbarItems = [
5924
5931
  name: 'checklist',
5925
5932
  type: 'button',
5926
5933
  icon: icons.get('checklist'),
5927
- tooltip: locale.toolbar.checklist(),
5934
+ tooltip: locale => locale.toolbar.checklist(),
5928
5935
  isSelected: appliedItems => !!appliedItems.find(item => item.name === 'ul' && item.node.attr('type') === 'checklist'),
5929
5936
  onClick: editor => {
5930
5937
  editor.command.execute('list', 'checklist');
@@ -5934,7 +5941,7 @@ const toolbarItems = [
5934
5941
  name: 'alignLeft',
5935
5942
  type: 'button',
5936
5943
  icon: icons.get('alignLeft'),
5937
- tooltip: locale.toolbar.alignLeft(),
5944
+ tooltip: locale => locale.toolbar.alignLeft(),
5938
5945
  isSelected: appliedItems => !!appliedItems.find(item => item.node.isBlock && item.node.css('text-align') === 'left'),
5939
5946
  onClick: editor => {
5940
5947
  editor.command.execute('align', 'left');
@@ -5944,7 +5951,7 @@ const toolbarItems = [
5944
5951
  name: 'alignCenter',
5945
5952
  type: 'button',
5946
5953
  icon: icons.get('alignCenter'),
5947
- tooltip: locale.toolbar.alignCenter(),
5954
+ tooltip: locale => locale.toolbar.alignCenter(),
5948
5955
  isSelected: appliedItems => !!appliedItems.find(item => item.node.isBlock && item.node.css('text-align') === 'center'),
5949
5956
  onClick: editor => {
5950
5957
  editor.command.execute('align', 'center');
@@ -5954,7 +5961,7 @@ const toolbarItems = [
5954
5961
  name: 'alignRight',
5955
5962
  type: 'button',
5956
5963
  icon: icons.get('alignRight'),
5957
- tooltip: locale.toolbar.alignRight(),
5964
+ tooltip: locale => locale.toolbar.alignRight(),
5958
5965
  isSelected: appliedItems => !!appliedItems.find(item => item.node.isBlock && item.node.css('text-align') === 'right'),
5959
5966
  onClick: editor => {
5960
5967
  editor.command.execute('align', 'right');
@@ -5964,7 +5971,7 @@ const toolbarItems = [
5964
5971
  name: 'alignJustify',
5965
5972
  type: 'button',
5966
5973
  icon: icons.get('alignJustify'),
5967
- tooltip: locale.toolbar.alignJustify(),
5974
+ tooltip: locale => locale.toolbar.alignJustify(),
5968
5975
  isSelected: appliedItems => !!appliedItems.find(item => item.node.isBlock && item.node.css('text-align') === 'justify'),
5969
5976
  onClick: editor => {
5970
5977
  editor.command.execute('align', 'justify');
@@ -5974,7 +5981,7 @@ const toolbarItems = [
5974
5981
  name: 'increaseIndent',
5975
5982
  type: 'button',
5976
5983
  icon: icons.get('increaseIndent'),
5977
- tooltip: locale.toolbar.increaseIndent(),
5984
+ tooltip: locale => locale.toolbar.increaseIndent(),
5978
5985
  onClick: editor => {
5979
5986
  editor.command.execute('indent', 'increase');
5980
5987
  },
@@ -5983,7 +5990,7 @@ const toolbarItems = [
5983
5990
  name: 'decreaseIndent',
5984
5991
  type: 'button',
5985
5992
  icon: icons.get('decreaseIndent'),
5986
- tooltip: locale.toolbar.decreaseIndent(),
5993
+ tooltip: locale => locale.toolbar.decreaseIndent(),
5987
5994
  onClick: editor => {
5988
5995
  editor.command.execute('indent', 'decrease');
5989
5996
  },
@@ -5992,7 +5999,7 @@ const toolbarItems = [
5992
5999
  name: 'bold',
5993
6000
  type: 'button',
5994
6001
  icon: icons.get('bold'),
5995
- tooltip: locale.toolbar.bold(),
6002
+ tooltip: locale => locale.toolbar.bold(),
5996
6003
  onClick: (editor, value) => {
5997
6004
  editor.command.execute(value);
5998
6005
  },
@@ -6001,7 +6008,7 @@ const toolbarItems = [
6001
6008
  name: 'italic',
6002
6009
  type: 'button',
6003
6010
  icon: icons.get('italic'),
6004
- tooltip: locale.toolbar.italic(),
6011
+ tooltip: locale => locale.toolbar.italic(),
6005
6012
  onClick: (editor, value) => {
6006
6013
  editor.command.execute(value);
6007
6014
  },
@@ -6010,7 +6017,7 @@ const toolbarItems = [
6010
6017
  name: 'underline',
6011
6018
  type: 'button',
6012
6019
  icon: icons.get('underline'),
6013
- tooltip: locale.toolbar.underline(),
6020
+ tooltip: locale => locale.toolbar.underline(),
6014
6021
  onClick: (editor, value) => {
6015
6022
  editor.command.execute(value);
6016
6023
  },
@@ -6019,7 +6026,7 @@ const toolbarItems = [
6019
6026
  name: 'strikethrough',
6020
6027
  type: 'button',
6021
6028
  icon: icons.get('strikethrough'),
6022
- tooltip: locale.toolbar.strikethrough(),
6029
+ tooltip: locale => locale.toolbar.strikethrough(),
6023
6030
  onClick: (editor, value) => {
6024
6031
  editor.command.execute(value);
6025
6032
  },
@@ -6028,7 +6035,7 @@ const toolbarItems = [
6028
6035
  name: 'superscript',
6029
6036
  type: 'button',
6030
6037
  icon: icons.get('superscript'),
6031
- tooltip: locale.toolbar.superscript(),
6038
+ tooltip: locale => locale.toolbar.superscript(),
6032
6039
  onClick: (editor, value) => {
6033
6040
  editor.command.execute(value);
6034
6041
  },
@@ -6037,7 +6044,7 @@ const toolbarItems = [
6037
6044
  name: 'subscript',
6038
6045
  type: 'button',
6039
6046
  icon: icons.get('subscript'),
6040
- tooltip: locale.toolbar.subscript(),
6047
+ tooltip: locale => locale.toolbar.subscript(),
6041
6048
  onClick: (editor, value) => {
6042
6049
  editor.command.execute(value);
6043
6050
  },
@@ -6046,7 +6053,7 @@ const toolbarItems = [
6046
6053
  name: 'code',
6047
6054
  type: 'button',
6048
6055
  icon: icons.get('code'),
6049
- tooltip: locale.toolbar.code(),
6056
+ tooltip: locale => locale.toolbar.code(),
6050
6057
  onClick: (editor, value) => {
6051
6058
  editor.command.execute(value);
6052
6059
  },
@@ -6055,7 +6062,7 @@ const toolbarItems = [
6055
6062
  name: 'removeFormat',
6056
6063
  type: 'button',
6057
6064
  icon: icons.get('removeFormat'),
6058
- tooltip: locale.toolbar.removeFormat(),
6065
+ tooltip: locale => locale.toolbar.removeFormat(),
6059
6066
  onClick: (editor, value) => {
6060
6067
  editor.command.execute(value);
6061
6068
  },
@@ -6064,7 +6071,7 @@ const toolbarItems = [
6064
6071
  name: 'formatPainter',
6065
6072
  type: 'button',
6066
6073
  icon: icons.get('formatPainter'),
6067
- tooltip: locale.toolbar.formatPainter(),
6074
+ tooltip: locale => locale.toolbar.formatPainter(),
6068
6075
  onClick: (editor, value) => {
6069
6076
  editor.command.execute(value);
6070
6077
  },
@@ -6073,7 +6080,7 @@ const toolbarItems = [
6073
6080
  name: 'link',
6074
6081
  type: 'button',
6075
6082
  icon: icons.get('link'),
6076
- tooltip: locale.toolbar.link(),
6083
+ tooltip: locale => locale.toolbar.link(),
6077
6084
  onClick: (editor, value) => {
6078
6085
  editor.command.execute(value);
6079
6086
  },
@@ -6082,7 +6089,7 @@ const toolbarItems = [
6082
6089
  name: 'hr',
6083
6090
  type: 'button',
6084
6091
  icon: icons.get('hr'),
6085
- tooltip: locale.toolbar.hr(),
6092
+ tooltip: locale => locale.toolbar.hr(),
6086
6093
  onClick: (editor, value) => {
6087
6094
  editor.command.execute(value);
6088
6095
  },
@@ -6091,7 +6098,7 @@ const toolbarItems = [
6091
6098
  name: 'codeBlock',
6092
6099
  type: 'button',
6093
6100
  icon: icons.get('codeBlock'),
6094
- tooltip: locale.toolbar.codeBlock(),
6101
+ tooltip: locale => locale.toolbar.codeBlock(),
6095
6102
  onClick: (editor, value) => {
6096
6103
  editor.command.execute(value);
6097
6104
  },
@@ -6101,7 +6108,7 @@ const toolbarItems = [
6101
6108
  type: 'dropdown',
6102
6109
  downIcon: icons.get('down'),
6103
6110
  defaultValue: 'p',
6104
- tooltip: locale.toolbar.heading(),
6111
+ tooltip: locale => locale.toolbar.heading(),
6105
6112
  width: '100px',
6106
6113
  menuType: 'list',
6107
6114
  menuItems: headingMenuItems,
@@ -6115,7 +6122,7 @@ const toolbarItems = [
6115
6122
  downIcon: icons.get('down'),
6116
6123
  icon: icons.get('list'),
6117
6124
  defaultValue: '',
6118
- tooltip: locale.toolbar.list(),
6125
+ tooltip: locale => locale.toolbar.list(),
6119
6126
  width: 'auto',
6120
6127
  menuType: 'list',
6121
6128
  menuItems: listMenuItems,
@@ -6129,7 +6136,7 @@ const toolbarItems = [
6129
6136
  downIcon: icons.get('down'),
6130
6137
  icon: icons.get('alignLeft'),
6131
6138
  defaultValue: '',
6132
- tooltip: locale.toolbar.align(),
6139
+ tooltip: locale => locale.toolbar.align(),
6133
6140
  width: 'auto',
6134
6141
  menuType: 'list',
6135
6142
  menuItems: alignMenuItems,
@@ -6143,7 +6150,7 @@ const toolbarItems = [
6143
6150
  downIcon: icons.get('down'),
6144
6151
  icon: icons.get('increaseIndent'),
6145
6152
  defaultValue: '',
6146
- tooltip: locale.toolbar.indent(),
6153
+ tooltip: locale => locale.toolbar.indent(),
6147
6154
  width: 'auto',
6148
6155
  menuType: 'list',
6149
6156
  menuItems: indentMenuItems,
@@ -6156,7 +6163,7 @@ const toolbarItems = [
6156
6163
  type: 'dropdown',
6157
6164
  downIcon: icons.get('down'),
6158
6165
  defaultValue: 'Segoe UI',
6159
- tooltip: locale.toolbar.fontFamily(),
6166
+ tooltip: locale => locale.toolbar.fontFamily(),
6160
6167
  width: '100px',
6161
6168
  menuType: 'list',
6162
6169
  menuItems: fontFamilyMenuItems,
@@ -6169,7 +6176,7 @@ const toolbarItems = [
6169
6176
  type: 'dropdown',
6170
6177
  downIcon: icons.get('down'),
6171
6178
  defaultValue: '16px',
6172
- tooltip: locale.toolbar.fontSize(),
6179
+ tooltip: locale => locale.toolbar.fontSize(),
6173
6180
  width: '65px',
6174
6181
  menuType: 'list',
6175
6182
  menuItems: fontSizeMenuItems,
@@ -6182,7 +6189,7 @@ const toolbarItems = [
6182
6189
  type: 'dropdown',
6183
6190
  icon: icons.get('more'),
6184
6191
  defaultValue: '',
6185
- tooltip: locale.toolbar.moreStyle(),
6192
+ tooltip: locale => locale.toolbar.moreStyle(),
6186
6193
  width: 'auto',
6187
6194
  menuType: 'list',
6188
6195
  menuItems: moreStyleMenuItems,
@@ -6208,7 +6215,7 @@ const toolbarItems = [
6208
6215
  icon: icons.get('fontColor'),
6209
6216
  accentIcon: icons.get('fontColorAccent'),
6210
6217
  defaultValue: '#f5222d',
6211
- tooltip: locale.toolbar.fontColor(),
6218
+ tooltip: locale => locale.toolbar.fontColor(),
6212
6219
  width: 'auto',
6213
6220
  menuType: 'color',
6214
6221
  menuItems: colorMenuItems,
@@ -6223,7 +6230,7 @@ const toolbarItems = [
6223
6230
  icon: icons.get('highlight'),
6224
6231
  accentIcon: icons.get('highlightAccent'),
6225
6232
  defaultValue: '#fadb14',
6226
- tooltip: locale.toolbar.highlight(),
6233
+ tooltip: locale => locale.toolbar.highlight(),
6227
6234
  width: 'auto',
6228
6235
  menuType: 'color',
6229
6236
  menuItems: colorMenuItems,
@@ -6235,7 +6242,7 @@ const toolbarItems = [
6235
6242
  name: 'image',
6236
6243
  type: 'upload',
6237
6244
  icon: icons.get('image'),
6238
- tooltip: locale.toolbar.image(),
6245
+ tooltip: locale => locale.toolbar.image(),
6239
6246
  accept: 'image/*',
6240
6247
  multiple: true,
6241
6248
  },
@@ -6339,7 +6346,7 @@ class Toolbar {
6339
6346
  root: this.container,
6340
6347
  name: item.name,
6341
6348
  icon: item.icon,
6342
- tooltip: item.tooltip,
6349
+ tooltip: typeof item.tooltip === 'string' ? item.tooltip : item.tooltip(editor.locale),
6343
6350
  tabIndex: -1,
6344
6351
  onClick: () => {
6345
6352
  editor.focus();
@@ -6351,6 +6358,7 @@ class Toolbar {
6351
6358
  appendDropdown(editor, item) {
6352
6359
  const dropdown = new Dropdown({
6353
6360
  root: this.container,
6361
+ locale: editor.locale,
6354
6362
  name: item.name,
6355
6363
  icon: item.icon,
6356
6364
  accentIcon: item.accentIcon,
@@ -6386,7 +6394,7 @@ class Toolbar {
6386
6394
  root: uploadNode,
6387
6395
  name: item.name,
6388
6396
  icon: item.icon,
6389
- tooltip: item.tooltip,
6397
+ tooltip: typeof item.tooltip === 'string' ? item.tooltip : item.tooltip(editor.locale),
6390
6398
  tabIndex: -1,
6391
6399
  onClick: () => {
6392
6400
  editor.focus();
@@ -6491,7 +6499,7 @@ class Toolbar {
6491
6499
  return;
6492
6500
  }
6493
6501
  if (item.type === 'dropdown') {
6494
- this.allMenuMap.set(item.name, Dropdown.getMenuMap(item.menuItems));
6502
+ this.allMenuMap.set(item.name, Dropdown.getMenuMap(item.menuItems, editor.locale));
6495
6503
  this.dropdownItemList.push(item);
6496
6504
  this.appendDropdown(editor, item);
6497
6505
  return;
@@ -6683,10 +6691,10 @@ function openFullScreen(box) {
6683
6691
  arrowPrevSVG: icons.get('left'),
6684
6692
  arrowNextSVG: icons.get('right'),
6685
6693
  closeSVG: icons.get('close'),
6686
- arrowPrevTitle: locale.image.previous(),
6687
- arrowNextTitle: locale.image.next(),
6688
- closeTitle: locale.image.close(),
6689
- errorMsg: locale.image.loadingError(),
6694
+ arrowPrevTitle: editor.locale.image.previous(),
6695
+ arrowNextTitle: editor.locale.image.next(),
6696
+ closeTitle: editor.locale.image.close(),
6697
+ errorMsg: editor.locale.image.loadingError(),
6690
6698
  });
6691
6699
  lightbox.on('uiRegister', () => {
6692
6700
  const pswp = lightbox.pswp;
@@ -6694,7 +6702,7 @@ function openFullScreen(box) {
6694
6702
  name: 'zoom-out-button',
6695
6703
  order: 8,
6696
6704
  isButton: true,
6697
- title: locale.image.zoomOut(),
6705
+ title: editor.locale.image.zoomOut(),
6698
6706
  html: icons.get('zoomOut'),
6699
6707
  onClick: () => {
6700
6708
  const currSlide = pswp.currSlide;
@@ -6707,7 +6715,7 @@ function openFullScreen(box) {
6707
6715
  name: 'zoom-in-button',
6708
6716
  order: 9,
6709
6717
  isButton: true,
6710
- title: locale.image.zoomIn(),
6718
+ title: editor.locale.image.zoomIn(),
6711
6719
  html: icons.get('zoomIn'),
6712
6720
  onClick: () => {
6713
6721
  const currSlide = pswp.currSlide;
@@ -6759,6 +6767,10 @@ function removeImageBox(box) {
6759
6767
  // Displays error icon and filename.
6760
6768
  function renderError(imageNode, box) {
6761
6769
  return __awaiter(this, void 0, void 0, function* () {
6770
+ const editor = box.getEditor();
6771
+ if (!editor) {
6772
+ return;
6773
+ }
6762
6774
  const value = box.value;
6763
6775
  box.getContainer().css({
6764
6776
  width: '',
@@ -6766,7 +6778,7 @@ function renderError(imageNode, box) {
6766
6778
  });
6767
6779
  const buttonGroupNode = query(safeTemplate `
6768
6780
  <div class="lake-button-group">
6769
- <button type="button" tabindex="-1" class="lake-button-remove" title="${locale.image.remove()}"></button>
6781
+ <button type="button" tabindex="-1" class="lake-button-remove" title="${editor.locale.image.remove()}"></button>
6770
6782
  </div>
6771
6783
  `);
6772
6784
  const removeButton = buttonGroupNode.find('.lake-button-remove');
@@ -6816,7 +6828,7 @@ function renderUploading(imageNode, box) {
6816
6828
  });
6817
6829
  const buttonGroupNode = query(safeTemplate `
6818
6830
  <div class="lake-button-group">
6819
- <button type="button" tabindex="-1" class="lake-button-remove" title="${locale.image.remove()}"></button>
6831
+ <button type="button" tabindex="-1" class="lake-button-remove" title="${editor.locale.image.remove()}"></button>
6820
6832
  </div>
6821
6833
  `);
6822
6834
  const removeButton = buttonGroupNode.find('.lake-button-remove');
@@ -6878,8 +6890,8 @@ function renderDone(imageNode, box) {
6878
6890
  });
6879
6891
  const buttonGroupNode = query(safeTemplate `
6880
6892
  <div class="lake-button-group">
6881
- <button type="button" tabindex="-1" class="lake-button-view" title="${locale.image.view()}"></button>
6882
- <button type="button" tabindex="-1" class="lake-button-remove" title="${locale.image.remove()}"></button>
6893
+ <button type="button" tabindex="-1" class="lake-button-view" title="${editor.locale.image.view()}"></button>
6894
+ <button type="button" tabindex="-1" class="lake-button-remove" title="${editor.locale.image.remove()}"></button>
6883
6895
  </div>
6884
6896
  `);
6885
6897
  const viewButton = buttonGroupNode.find('.lake-button-view');
@@ -7130,6 +7142,7 @@ const codeBlockBox = {
7130
7142
  doc: (_a = boxValue.code) !== null && _a !== void 0 ? _a : '',
7131
7143
  extensions: [
7132
7144
  EditorState.readOnly.of(editor.readonly),
7145
+ EditorView.editable.of(!editor.readonly),
7133
7146
  history(),
7134
7147
  keymap.of([
7135
7148
  ...defaultKeymap,
@@ -7147,7 +7160,7 @@ const codeBlockBox = {
7147
7160
  name: 'langType',
7148
7161
  downIcon: icons.get('down'),
7149
7162
  defaultValue: langItem ? boxValue.lang : codeBlockConfig.defaultLang,
7150
- tooltip: locale.codeBlock.langType(),
7163
+ tooltip: editor.locale.codeBlock.langType(),
7151
7164
  width: 'auto',
7152
7165
  menuType: 'list',
7153
7166
  menuItems: langItems.map((item) => ({
@@ -7505,9 +7518,7 @@ var heading = (editor) => {
7505
7518
  const typeList = [
7506
7519
  'info',
7507
7520
  'tip',
7508
- 'success',
7509
7521
  'warning',
7510
- 'error',
7511
7522
  'danger',
7512
7523
  ];
7513
7524
  var blockQuote = (editor) => {
@@ -7975,17 +7986,18 @@ var formatPainter = (editor) => {
7975
7986
  };
7976
7987
 
7977
7988
  class LinkPopup {
7978
- constructor(root) {
7989
+ constructor(config) {
7979
7990
  this.linkNode = null;
7980
7991
  this.event = new EventEmitter();
7981
- this.root = root;
7992
+ this.root = config.root;
7993
+ this.locale = config.locale || i18nObject('en-US');
7982
7994
  this.container = query(safeTemplate `
7983
7995
  <div class="lake-link-popup">
7984
- <div class="lake-row">${locale.link.url()}</div>
7996
+ <div class="lake-row">${this.locale.link.url()}</div>
7985
7997
  <div class="lake-row lake-url-row">
7986
7998
  <input type="text" name="url" />
7987
7999
  </div>
7988
- <div class="lake-row">${locale.link.title()}</div>
8000
+ <div class="lake-row">${this.locale.link.title()}</div>
7989
8001
  <div class="lake-row">
7990
8002
  <input type="text" name="title" />
7991
8003
  </div>
@@ -8020,7 +8032,7 @@ class LinkPopup {
8020
8032
  root: this.container.find('.lake-url-row'),
8021
8033
  name: 'copy',
8022
8034
  icon: icons.get('copy'),
8023
- tooltip: locale.link.copy(),
8035
+ tooltip: this.locale.link.copy(),
8024
8036
  onClick: () => {
8025
8037
  if (!this.linkNode) {
8026
8038
  return;
@@ -8062,7 +8074,7 @@ class LinkPopup {
8062
8074
  root: this.container.find('.lake-url-row'),
8063
8075
  name: 'open',
8064
8076
  icon: icons.get('open'),
8065
- tooltip: locale.link.open(),
8077
+ tooltip: this.locale.link.open(),
8066
8078
  onClick: () => {
8067
8079
  if (!this.linkNode) {
8068
8080
  return;
@@ -8079,7 +8091,7 @@ class LinkPopup {
8079
8091
  root: this.container.find('.lake-button-row'),
8080
8092
  name: 'save',
8081
8093
  icon: icons.get('check'),
8082
- text: locale.link.save(),
8094
+ text: this.locale.link.save(),
8083
8095
  onClick: () => {
8084
8096
  if (!this.linkNode) {
8085
8097
  return;
@@ -8098,7 +8110,7 @@ class LinkPopup {
8098
8110
  root: this.container.find('.lake-button-row'),
8099
8111
  name: 'unlink',
8100
8112
  icon: icons.get('unlink'),
8101
- text: locale.link.unlink(),
8113
+ text: this.locale.link.unlink(),
8102
8114
  onClick: () => {
8103
8115
  if (!this.linkNode) {
8104
8116
  return;
@@ -8204,7 +8216,10 @@ var link = (editor) => {
8204
8216
  if (editor.readonly) {
8205
8217
  return;
8206
8218
  }
8207
- const popup = new LinkPopup(editor.popupContainer);
8219
+ const popup = new LinkPopup({
8220
+ root: editor.popupContainer,
8221
+ locale: editor.locale,
8222
+ });
8208
8223
  popup.event.on('save', node => {
8209
8224
  const range = editor.selection.range;
8210
8225
  range.setStartAfter(node);
@@ -8244,7 +8259,7 @@ var link = (editor) => {
8244
8259
  });
8245
8260
  editor.command.add('link', {
8246
8261
  execute: () => {
8247
- const linkNode = editor.selection.insertLink(`<a href="">${locale.link.newLink()}</a>`);
8262
+ const linkNode = editor.selection.insertLink(`<a href="">${editor.locale.link.newLink()}</a>`);
8248
8263
  if (!linkNode) {
8249
8264
  return;
8250
8265
  }
@@ -8357,6 +8372,12 @@ const headingTypeMap = new Map([
8357
8372
  ['#####', 'h5'],
8358
8373
  ['######', 'h6'],
8359
8374
  ]);
8375
+ const shortLangTypeMap = new Map([
8376
+ ['js', 'javascript'],
8377
+ ['ts', 'typescript'],
8378
+ ['md', 'markdown'],
8379
+ ['htm', 'html'],
8380
+ ]);
8360
8381
  const markItemList = [
8361
8382
  {
8362
8383
  re: /\*\*(.+?)\*\*$/,
@@ -8475,6 +8496,7 @@ const blockItemListForEnterKey = [
8475
8496
  {
8476
8497
  re: /^`+([a-z]*)$/i,
8477
8498
  getParameters: (results) => {
8499
+ var _a;
8478
8500
  if (!results[1]) {
8479
8501
  return [
8480
8502
  'codeBlock',
@@ -8483,7 +8505,7 @@ const blockItemListForEnterKey = [
8483
8505
  return [
8484
8506
  'codeBlock',
8485
8507
  {
8486
- lang: results[1],
8508
+ lang: (_a = shortLangTypeMap.get(results[1])) !== null && _a !== void 0 ? _a : results[1],
8487
8509
  },
8488
8510
  ];
8489
8511
  },
@@ -9232,7 +9254,7 @@ var escapeKey = (editor) => {
9232
9254
  selection.addRangeToNativeSelection();
9233
9255
  return;
9234
9256
  }
9235
- if (editor.root.hasClass('lake-root-focused')) {
9257
+ if (editor.hasFocus) {
9236
9258
  event.preventDefault();
9237
9259
  editor.blur();
9238
9260
  }