lakelib 0.1.2 → 0.1.3

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.3";
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;
@@ -4831,874 +5145,568 @@ class Keystroke {
4831
5145
  break;
4832
5146
  }
4833
5147
  }
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
- };
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
+ bindFocusEvents() {
5474
+ this.container.on('focus', () => {
5475
+ this.root.addClass('lake-root-focused');
5476
+ });
5477
+ this.container.on('blur', () => {
5478
+ this.root.removeClass('lake-root-focused');
5479
+ });
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.bindFocusEvents();
5599
+ this.selection.synByBookmark();
5600
+ this.history.save();
5601
+ }
5602
+ Editor.box.renderAll(this);
5603
+ if (this.toolbar) {
5604
+ this.toolbar.render(this);
5605
+ }
5606
+ if (!this.readonly) {
5607
+ window.addEventListener('beforeunload', this.beforeunloadListener);
5608
+ document.addEventListener('selectionchange', this.selectionchangeListener);
5609
+ document.addEventListener('click', this.clickListener);
5610
+ window.addEventListener('resize', this.resizeListener);
5611
+ this.bindInputEvents();
5612
+ this.bindHistoryEvents();
5613
+ }
5614
+ }
5615
+ // Destroys a rendered editor.
5616
+ unmount() {
5617
+ this.root.empty();
5618
+ this.popupContainer.remove();
5619
+ if (!this.readonly) {
5620
+ window.removeEventListener('beforeunload', this.beforeunloadListener);
5621
+ document.removeEventListener('selectionchange', this.selectionchangeListener);
5622
+ document.removeEventListener('click', this.clickListener);
5623
+ window.removeEventListener('resize', this.resizeListener);
5624
+ }
5625
+ }
5626
+ }
5627
+ Editor.version = version;
5628
+ Editor.box = new BoxManager();
5629
+ Editor.plugin = new Plugin();
5622
5630
 
5623
5631
  const headingMenuItems = [
5624
5632
  {
5625
5633
  value: 'h1',
5626
- text: `<span style="font-weight: bold; font-size: 26px;">${locale.toolbar.heading1()}</span>`,
5634
+ text: locale => `<span style="font-weight: bold; font-size: 26px;">${locale.toolbar.heading1()}</span>`,
5627
5635
  },
5628
5636
  {
5629
5637
  value: 'h2',
5630
- text: `<span style="font-weight: bold; font-size: 24px;">${locale.toolbar.heading2()}</span>`,
5638
+ text: locale => `<span style="font-weight: bold; font-size: 24px;">${locale.toolbar.heading2()}</span>`,
5631
5639
  },
5632
5640
  {
5633
5641
  value: 'h3',
5634
- text: `<span style="font-weight: bold; font-size: 22px;">${locale.toolbar.heading3()}</span>`,
5642
+ text: locale => `<span style="font-weight: bold; font-size: 22px;">${locale.toolbar.heading3()}</span>`,
5635
5643
  },
5636
5644
  {
5637
5645
  value: 'h4',
5638
- text: `<span style="font-weight: bold; font-size: 20px;">${locale.toolbar.heading4()}</span>`,
5646
+ text: locale => `<span style="font-weight: bold; font-size: 20px;">${locale.toolbar.heading4()}</span>`,
5639
5647
  },
5640
5648
  {
5641
5649
  value: 'h5',
5642
- text: `<span style="font-weight: bold; font-size: 18px;">${locale.toolbar.heading5()}</span>`,
5650
+ text: locale => `<span style="font-weight: bold; font-size: 18px;">${locale.toolbar.heading5()}</span>`,
5643
5651
  },
5644
5652
  {
5645
5653
  value: 'h6',
5646
- text: `<span style="font-weight: bold; font-size: 16px;">${locale.toolbar.heading6()}</span>`,
5654
+ text: locale => `<span style="font-weight: bold; font-size: 16px;">${locale.toolbar.heading6()}</span>`,
5647
5655
  },
5648
5656
  {
5649
5657
  value: 'p',
5650
- text: locale.toolbar.paragraph(),
5658
+ text: locale => locale.toolbar.paragraph(),
5651
5659
  },
5652
5660
  ];
5653
5661
  const listMenuItems = [
5654
5662
  {
5655
5663
  icon: icons.get('numberedList'),
5656
5664
  value: 'numbered',
5657
- text: locale.toolbar.numberedList(),
5665
+ text: locale => locale.toolbar.numberedList(),
5658
5666
  },
5659
5667
  {
5660
5668
  icon: icons.get('bulletedList'),
5661
5669
  value: 'bulleted',
5662
- text: locale.toolbar.bulletedList(),
5670
+ text: locale => locale.toolbar.bulletedList(),
5663
5671
  },
5664
5672
  {
5665
5673
  icon: icons.get('checklist'),
5666
5674
  value: 'checklist',
5667
- text: locale.toolbar.checklist(),
5675
+ text: locale => locale.toolbar.checklist(),
5668
5676
  },
5669
5677
  ];
5670
5678
  const alignMenuItems = [
5671
5679
  {
5672
5680
  icon: icons.get('alignLeft'),
5673
5681
  value: 'left',
5674
- text: locale.toolbar.alignLeft(),
5682
+ text: locale => locale.toolbar.alignLeft(),
5675
5683
  },
5676
5684
  {
5677
5685
  icon: icons.get('alignCenter'),
5678
5686
  value: 'center',
5679
- text: locale.toolbar.alignCenter(),
5687
+ text: locale => locale.toolbar.alignCenter(),
5680
5688
  },
5681
5689
  {
5682
5690
  icon: icons.get('alignRight'),
5683
5691
  value: 'right',
5684
- text: locale.toolbar.alignRight(),
5692
+ text: locale => locale.toolbar.alignRight(),
5685
5693
  },
5686
5694
  {
5687
5695
  icon: icons.get('alignJustify'),
5688
5696
  value: 'justify',
5689
- text: locale.toolbar.alignJustify(),
5697
+ text: locale => locale.toolbar.alignJustify(),
5690
5698
  },
5691
5699
  ];
5692
5700
  const indentMenuItems = [
5693
5701
  {
5694
5702
  icon: icons.get('increaseIndent'),
5695
5703
  value: 'increase',
5696
- text: locale.toolbar.increaseIndent(),
5704
+ text: locale => locale.toolbar.increaseIndent(),
5697
5705
  },
5698
5706
  {
5699
5707
  icon: icons.get('decreaseIndent'),
5700
5708
  value: 'decrease',
5701
- text: locale.toolbar.decreaseIndent(),
5709
+ text: locale => locale.toolbar.decreaseIndent(),
5702
5710
  },
5703
5711
  ];
5704
5712
  const fontFamilyMenuItems = [
@@ -5785,32 +5793,32 @@ const moreStyleMenuItems = [
5785
5793
  {
5786
5794
  icon: icons.get('italic'),
5787
5795
  value: 'italic',
5788
- text: locale.toolbar.italic(),
5796
+ text: locale => locale.toolbar.italic(),
5789
5797
  },
5790
5798
  {
5791
5799
  icon: icons.get('underline'),
5792
5800
  value: 'underline',
5793
- text: locale.toolbar.underline(),
5801
+ text: locale => locale.toolbar.underline(),
5794
5802
  },
5795
5803
  {
5796
5804
  icon: icons.get('strikethrough'),
5797
5805
  value: 'strikethrough',
5798
- text: locale.toolbar.strikethrough(),
5806
+ text: locale => locale.toolbar.strikethrough(),
5799
5807
  },
5800
5808
  {
5801
5809
  icon: icons.get('superscript'),
5802
5810
  value: 'superscript',
5803
- text: locale.toolbar.superscript(),
5811
+ text: locale => locale.toolbar.superscript(),
5804
5812
  },
5805
5813
  {
5806
5814
  icon: icons.get('subscript'),
5807
5815
  value: 'subscript',
5808
- text: locale.toolbar.subscript(),
5816
+ text: locale => locale.toolbar.subscript(),
5809
5817
  },
5810
5818
  {
5811
5819
  icon: icons.get('code'),
5812
5820
  value: 'code',
5813
- text: locale.toolbar.code(),
5821
+ text: locale => locale.toolbar.code(),
5814
5822
  },
5815
5823
  ];
5816
5824
  // These colors are from Ant Design (https://ant.design/docs/spec/colors)
@@ -5833,7 +5841,7 @@ const colorMenuItems = [
5833
5841
  {
5834
5842
  icon: icons.get('removeFormat'),
5835
5843
  value: '',
5836
- text: locale.toolbar.removeColor(),
5844
+ text: locale => locale.toolbar.removeColor(),
5837
5845
  },
5838
5846
  ];
5839
5847
  for (const color of colors) {
@@ -5858,7 +5866,7 @@ const toolbarItems = [
5858
5866
  name: 'undo',
5859
5867
  type: 'button',
5860
5868
  icon: icons.get('undo'),
5861
- tooltip: locale.toolbar.undo(),
5869
+ tooltip: locale => locale.toolbar.undo(),
5862
5870
  onClick: (editor, value) => {
5863
5871
  editor.command.execute(value);
5864
5872
  },
@@ -5867,7 +5875,7 @@ const toolbarItems = [
5867
5875
  name: 'redo',
5868
5876
  type: 'button',
5869
5877
  icon: icons.get('redo'),
5870
- tooltip: locale.toolbar.redo(),
5878
+ tooltip: locale => locale.toolbar.redo(),
5871
5879
  onClick: (editor, value) => {
5872
5880
  editor.command.execute(value);
5873
5881
  },
@@ -5876,7 +5884,7 @@ const toolbarItems = [
5876
5884
  name: 'selectAll',
5877
5885
  type: 'button',
5878
5886
  icon: icons.get('selectAll'),
5879
- tooltip: locale.toolbar.selectAll(),
5887
+ tooltip: locale => locale.toolbar.selectAll(),
5880
5888
  onClick: (editor, value) => {
5881
5889
  editor.command.execute(value);
5882
5890
  },
@@ -5885,7 +5893,7 @@ const toolbarItems = [
5885
5893
  name: 'paragraph',
5886
5894
  type: 'button',
5887
5895
  icon: icons.get('paragraph'),
5888
- tooltip: locale.toolbar.paragraph(),
5896
+ tooltip: locale => locale.toolbar.paragraph(),
5889
5897
  isSelected: appliedItems => !!appliedItems.find(item => item.name === 'p'),
5890
5898
  onClick: editor => {
5891
5899
  editor.command.execute('heading', 'p');
@@ -5895,7 +5903,7 @@ const toolbarItems = [
5895
5903
  name: 'blockQuote',
5896
5904
  type: 'button',
5897
5905
  icon: icons.get('blockQuote'),
5898
- tooltip: locale.toolbar.blockQuote(),
5906
+ tooltip: locale => locale.toolbar.blockQuote(),
5899
5907
  onClick: (editor, value) => {
5900
5908
  editor.command.execute(value);
5901
5909
  },
@@ -5904,7 +5912,7 @@ const toolbarItems = [
5904
5912
  name: 'numberedList',
5905
5913
  type: 'button',
5906
5914
  icon: icons.get('numberedList'),
5907
- tooltip: locale.toolbar.numberedList(),
5915
+ tooltip: locale => locale.toolbar.numberedList(),
5908
5916
  isSelected: appliedItems => !!appliedItems.find(item => item.name === 'ol'),
5909
5917
  onClick: editor => {
5910
5918
  editor.command.execute('list', 'numbered');
@@ -5914,7 +5922,7 @@ const toolbarItems = [
5914
5922
  name: 'bulletedList',
5915
5923
  type: 'button',
5916
5924
  icon: icons.get('bulletedList'),
5917
- tooltip: locale.toolbar.bulletedList(),
5925
+ tooltip: locale => locale.toolbar.bulletedList(),
5918
5926
  isSelected: appliedItems => !!appliedItems.find(item => item.name === 'ul' && !item.node.hasAttr('type')),
5919
5927
  onClick: editor => {
5920
5928
  editor.command.execute('list', 'bulleted');
@@ -5924,7 +5932,7 @@ const toolbarItems = [
5924
5932
  name: 'checklist',
5925
5933
  type: 'button',
5926
5934
  icon: icons.get('checklist'),
5927
- tooltip: locale.toolbar.checklist(),
5935
+ tooltip: locale => locale.toolbar.checklist(),
5928
5936
  isSelected: appliedItems => !!appliedItems.find(item => item.name === 'ul' && item.node.attr('type') === 'checklist'),
5929
5937
  onClick: editor => {
5930
5938
  editor.command.execute('list', 'checklist');
@@ -5934,7 +5942,7 @@ const toolbarItems = [
5934
5942
  name: 'alignLeft',
5935
5943
  type: 'button',
5936
5944
  icon: icons.get('alignLeft'),
5937
- tooltip: locale.toolbar.alignLeft(),
5945
+ tooltip: locale => locale.toolbar.alignLeft(),
5938
5946
  isSelected: appliedItems => !!appliedItems.find(item => item.node.isBlock && item.node.css('text-align') === 'left'),
5939
5947
  onClick: editor => {
5940
5948
  editor.command.execute('align', 'left');
@@ -5944,7 +5952,7 @@ const toolbarItems = [
5944
5952
  name: 'alignCenter',
5945
5953
  type: 'button',
5946
5954
  icon: icons.get('alignCenter'),
5947
- tooltip: locale.toolbar.alignCenter(),
5955
+ tooltip: locale => locale.toolbar.alignCenter(),
5948
5956
  isSelected: appliedItems => !!appliedItems.find(item => item.node.isBlock && item.node.css('text-align') === 'center'),
5949
5957
  onClick: editor => {
5950
5958
  editor.command.execute('align', 'center');
@@ -5954,7 +5962,7 @@ const toolbarItems = [
5954
5962
  name: 'alignRight',
5955
5963
  type: 'button',
5956
5964
  icon: icons.get('alignRight'),
5957
- tooltip: locale.toolbar.alignRight(),
5965
+ tooltip: locale => locale.toolbar.alignRight(),
5958
5966
  isSelected: appliedItems => !!appliedItems.find(item => item.node.isBlock && item.node.css('text-align') === 'right'),
5959
5967
  onClick: editor => {
5960
5968
  editor.command.execute('align', 'right');
@@ -5964,7 +5972,7 @@ const toolbarItems = [
5964
5972
  name: 'alignJustify',
5965
5973
  type: 'button',
5966
5974
  icon: icons.get('alignJustify'),
5967
- tooltip: locale.toolbar.alignJustify(),
5975
+ tooltip: locale => locale.toolbar.alignJustify(),
5968
5976
  isSelected: appliedItems => !!appliedItems.find(item => item.node.isBlock && item.node.css('text-align') === 'justify'),
5969
5977
  onClick: editor => {
5970
5978
  editor.command.execute('align', 'justify');
@@ -5974,7 +5982,7 @@ const toolbarItems = [
5974
5982
  name: 'increaseIndent',
5975
5983
  type: 'button',
5976
5984
  icon: icons.get('increaseIndent'),
5977
- tooltip: locale.toolbar.increaseIndent(),
5985
+ tooltip: locale => locale.toolbar.increaseIndent(),
5978
5986
  onClick: editor => {
5979
5987
  editor.command.execute('indent', 'increase');
5980
5988
  },
@@ -5983,7 +5991,7 @@ const toolbarItems = [
5983
5991
  name: 'decreaseIndent',
5984
5992
  type: 'button',
5985
5993
  icon: icons.get('decreaseIndent'),
5986
- tooltip: locale.toolbar.decreaseIndent(),
5994
+ tooltip: locale => locale.toolbar.decreaseIndent(),
5987
5995
  onClick: editor => {
5988
5996
  editor.command.execute('indent', 'decrease');
5989
5997
  },
@@ -5992,7 +6000,7 @@ const toolbarItems = [
5992
6000
  name: 'bold',
5993
6001
  type: 'button',
5994
6002
  icon: icons.get('bold'),
5995
- tooltip: locale.toolbar.bold(),
6003
+ tooltip: locale => locale.toolbar.bold(),
5996
6004
  onClick: (editor, value) => {
5997
6005
  editor.command.execute(value);
5998
6006
  },
@@ -6001,7 +6009,7 @@ const toolbarItems = [
6001
6009
  name: 'italic',
6002
6010
  type: 'button',
6003
6011
  icon: icons.get('italic'),
6004
- tooltip: locale.toolbar.italic(),
6012
+ tooltip: locale => locale.toolbar.italic(),
6005
6013
  onClick: (editor, value) => {
6006
6014
  editor.command.execute(value);
6007
6015
  },
@@ -6010,7 +6018,7 @@ const toolbarItems = [
6010
6018
  name: 'underline',
6011
6019
  type: 'button',
6012
6020
  icon: icons.get('underline'),
6013
- tooltip: locale.toolbar.underline(),
6021
+ tooltip: locale => locale.toolbar.underline(),
6014
6022
  onClick: (editor, value) => {
6015
6023
  editor.command.execute(value);
6016
6024
  },
@@ -6019,7 +6027,7 @@ const toolbarItems = [
6019
6027
  name: 'strikethrough',
6020
6028
  type: 'button',
6021
6029
  icon: icons.get('strikethrough'),
6022
- tooltip: locale.toolbar.strikethrough(),
6030
+ tooltip: locale => locale.toolbar.strikethrough(),
6023
6031
  onClick: (editor, value) => {
6024
6032
  editor.command.execute(value);
6025
6033
  },
@@ -6028,7 +6036,7 @@ const toolbarItems = [
6028
6036
  name: 'superscript',
6029
6037
  type: 'button',
6030
6038
  icon: icons.get('superscript'),
6031
- tooltip: locale.toolbar.superscript(),
6039
+ tooltip: locale => locale.toolbar.superscript(),
6032
6040
  onClick: (editor, value) => {
6033
6041
  editor.command.execute(value);
6034
6042
  },
@@ -6037,7 +6045,7 @@ const toolbarItems = [
6037
6045
  name: 'subscript',
6038
6046
  type: 'button',
6039
6047
  icon: icons.get('subscript'),
6040
- tooltip: locale.toolbar.subscript(),
6048
+ tooltip: locale => locale.toolbar.subscript(),
6041
6049
  onClick: (editor, value) => {
6042
6050
  editor.command.execute(value);
6043
6051
  },
@@ -6046,7 +6054,7 @@ const toolbarItems = [
6046
6054
  name: 'code',
6047
6055
  type: 'button',
6048
6056
  icon: icons.get('code'),
6049
- tooltip: locale.toolbar.code(),
6057
+ tooltip: locale => locale.toolbar.code(),
6050
6058
  onClick: (editor, value) => {
6051
6059
  editor.command.execute(value);
6052
6060
  },
@@ -6055,7 +6063,7 @@ const toolbarItems = [
6055
6063
  name: 'removeFormat',
6056
6064
  type: 'button',
6057
6065
  icon: icons.get('removeFormat'),
6058
- tooltip: locale.toolbar.removeFormat(),
6066
+ tooltip: locale => locale.toolbar.removeFormat(),
6059
6067
  onClick: (editor, value) => {
6060
6068
  editor.command.execute(value);
6061
6069
  },
@@ -6064,7 +6072,7 @@ const toolbarItems = [
6064
6072
  name: 'formatPainter',
6065
6073
  type: 'button',
6066
6074
  icon: icons.get('formatPainter'),
6067
- tooltip: locale.toolbar.formatPainter(),
6075
+ tooltip: locale => locale.toolbar.formatPainter(),
6068
6076
  onClick: (editor, value) => {
6069
6077
  editor.command.execute(value);
6070
6078
  },
@@ -6073,7 +6081,7 @@ const toolbarItems = [
6073
6081
  name: 'link',
6074
6082
  type: 'button',
6075
6083
  icon: icons.get('link'),
6076
- tooltip: locale.toolbar.link(),
6084
+ tooltip: locale => locale.toolbar.link(),
6077
6085
  onClick: (editor, value) => {
6078
6086
  editor.command.execute(value);
6079
6087
  },
@@ -6082,7 +6090,7 @@ const toolbarItems = [
6082
6090
  name: 'hr',
6083
6091
  type: 'button',
6084
6092
  icon: icons.get('hr'),
6085
- tooltip: locale.toolbar.hr(),
6093
+ tooltip: locale => locale.toolbar.hr(),
6086
6094
  onClick: (editor, value) => {
6087
6095
  editor.command.execute(value);
6088
6096
  },
@@ -6091,7 +6099,7 @@ const toolbarItems = [
6091
6099
  name: 'codeBlock',
6092
6100
  type: 'button',
6093
6101
  icon: icons.get('codeBlock'),
6094
- tooltip: locale.toolbar.codeBlock(),
6102
+ tooltip: locale => locale.toolbar.codeBlock(),
6095
6103
  onClick: (editor, value) => {
6096
6104
  editor.command.execute(value);
6097
6105
  },
@@ -6101,7 +6109,7 @@ const toolbarItems = [
6101
6109
  type: 'dropdown',
6102
6110
  downIcon: icons.get('down'),
6103
6111
  defaultValue: 'p',
6104
- tooltip: locale.toolbar.heading(),
6112
+ tooltip: locale => locale.toolbar.heading(),
6105
6113
  width: '100px',
6106
6114
  menuType: 'list',
6107
6115
  menuItems: headingMenuItems,
@@ -6115,7 +6123,7 @@ const toolbarItems = [
6115
6123
  downIcon: icons.get('down'),
6116
6124
  icon: icons.get('list'),
6117
6125
  defaultValue: '',
6118
- tooltip: locale.toolbar.list(),
6126
+ tooltip: locale => locale.toolbar.list(),
6119
6127
  width: 'auto',
6120
6128
  menuType: 'list',
6121
6129
  menuItems: listMenuItems,
@@ -6129,7 +6137,7 @@ const toolbarItems = [
6129
6137
  downIcon: icons.get('down'),
6130
6138
  icon: icons.get('alignLeft'),
6131
6139
  defaultValue: '',
6132
- tooltip: locale.toolbar.align(),
6140
+ tooltip: locale => locale.toolbar.align(),
6133
6141
  width: 'auto',
6134
6142
  menuType: 'list',
6135
6143
  menuItems: alignMenuItems,
@@ -6143,7 +6151,7 @@ const toolbarItems = [
6143
6151
  downIcon: icons.get('down'),
6144
6152
  icon: icons.get('increaseIndent'),
6145
6153
  defaultValue: '',
6146
- tooltip: locale.toolbar.indent(),
6154
+ tooltip: locale => locale.toolbar.indent(),
6147
6155
  width: 'auto',
6148
6156
  menuType: 'list',
6149
6157
  menuItems: indentMenuItems,
@@ -6156,7 +6164,7 @@ const toolbarItems = [
6156
6164
  type: 'dropdown',
6157
6165
  downIcon: icons.get('down'),
6158
6166
  defaultValue: 'Segoe UI',
6159
- tooltip: locale.toolbar.fontFamily(),
6167
+ tooltip: locale => locale.toolbar.fontFamily(),
6160
6168
  width: '100px',
6161
6169
  menuType: 'list',
6162
6170
  menuItems: fontFamilyMenuItems,
@@ -6169,7 +6177,7 @@ const toolbarItems = [
6169
6177
  type: 'dropdown',
6170
6178
  downIcon: icons.get('down'),
6171
6179
  defaultValue: '16px',
6172
- tooltip: locale.toolbar.fontSize(),
6180
+ tooltip: locale => locale.toolbar.fontSize(),
6173
6181
  width: '65px',
6174
6182
  menuType: 'list',
6175
6183
  menuItems: fontSizeMenuItems,
@@ -6182,7 +6190,7 @@ const toolbarItems = [
6182
6190
  type: 'dropdown',
6183
6191
  icon: icons.get('more'),
6184
6192
  defaultValue: '',
6185
- tooltip: locale.toolbar.moreStyle(),
6193
+ tooltip: locale => locale.toolbar.moreStyle(),
6186
6194
  width: 'auto',
6187
6195
  menuType: 'list',
6188
6196
  menuItems: moreStyleMenuItems,
@@ -6208,7 +6216,7 @@ const toolbarItems = [
6208
6216
  icon: icons.get('fontColor'),
6209
6217
  accentIcon: icons.get('fontColorAccent'),
6210
6218
  defaultValue: '#f5222d',
6211
- tooltip: locale.toolbar.fontColor(),
6219
+ tooltip: locale => locale.toolbar.fontColor(),
6212
6220
  width: 'auto',
6213
6221
  menuType: 'color',
6214
6222
  menuItems: colorMenuItems,
@@ -6223,7 +6231,7 @@ const toolbarItems = [
6223
6231
  icon: icons.get('highlight'),
6224
6232
  accentIcon: icons.get('highlightAccent'),
6225
6233
  defaultValue: '#fadb14',
6226
- tooltip: locale.toolbar.highlight(),
6234
+ tooltip: locale => locale.toolbar.highlight(),
6227
6235
  width: 'auto',
6228
6236
  menuType: 'color',
6229
6237
  menuItems: colorMenuItems,
@@ -6235,7 +6243,7 @@ const toolbarItems = [
6235
6243
  name: 'image',
6236
6244
  type: 'upload',
6237
6245
  icon: icons.get('image'),
6238
- tooltip: locale.toolbar.image(),
6246
+ tooltip: locale => locale.toolbar.image(),
6239
6247
  accept: 'image/*',
6240
6248
  multiple: true,
6241
6249
  },
@@ -6339,7 +6347,7 @@ class Toolbar {
6339
6347
  root: this.container,
6340
6348
  name: item.name,
6341
6349
  icon: item.icon,
6342
- tooltip: item.tooltip,
6350
+ tooltip: typeof item.tooltip === 'string' ? item.tooltip : item.tooltip(editor.locale),
6343
6351
  tabIndex: -1,
6344
6352
  onClick: () => {
6345
6353
  editor.focus();
@@ -6351,6 +6359,7 @@ class Toolbar {
6351
6359
  appendDropdown(editor, item) {
6352
6360
  const dropdown = new Dropdown({
6353
6361
  root: this.container,
6362
+ locale: editor.locale,
6354
6363
  name: item.name,
6355
6364
  icon: item.icon,
6356
6365
  accentIcon: item.accentIcon,
@@ -6386,7 +6395,7 @@ class Toolbar {
6386
6395
  root: uploadNode,
6387
6396
  name: item.name,
6388
6397
  icon: item.icon,
6389
- tooltip: item.tooltip,
6398
+ tooltip: typeof item.tooltip === 'string' ? item.tooltip : item.tooltip(editor.locale),
6390
6399
  tabIndex: -1,
6391
6400
  onClick: () => {
6392
6401
  editor.focus();
@@ -6491,7 +6500,7 @@ class Toolbar {
6491
6500
  return;
6492
6501
  }
6493
6502
  if (item.type === 'dropdown') {
6494
- this.allMenuMap.set(item.name, Dropdown.getMenuMap(item.menuItems));
6503
+ this.allMenuMap.set(item.name, Dropdown.getMenuMap(item.menuItems, editor.locale));
6495
6504
  this.dropdownItemList.push(item);
6496
6505
  this.appendDropdown(editor, item);
6497
6506
  return;
@@ -6683,10 +6692,10 @@ function openFullScreen(box) {
6683
6692
  arrowPrevSVG: icons.get('left'),
6684
6693
  arrowNextSVG: icons.get('right'),
6685
6694
  closeSVG: icons.get('close'),
6686
- arrowPrevTitle: locale.image.previous(),
6687
- arrowNextTitle: locale.image.next(),
6688
- closeTitle: locale.image.close(),
6689
- errorMsg: locale.image.loadingError(),
6695
+ arrowPrevTitle: editor.locale.image.previous(),
6696
+ arrowNextTitle: editor.locale.image.next(),
6697
+ closeTitle: editor.locale.image.close(),
6698
+ errorMsg: editor.locale.image.loadingError(),
6690
6699
  });
6691
6700
  lightbox.on('uiRegister', () => {
6692
6701
  const pswp = lightbox.pswp;
@@ -6694,7 +6703,7 @@ function openFullScreen(box) {
6694
6703
  name: 'zoom-out-button',
6695
6704
  order: 8,
6696
6705
  isButton: true,
6697
- title: locale.image.zoomOut(),
6706
+ title: editor.locale.image.zoomOut(),
6698
6707
  html: icons.get('zoomOut'),
6699
6708
  onClick: () => {
6700
6709
  const currSlide = pswp.currSlide;
@@ -6707,7 +6716,7 @@ function openFullScreen(box) {
6707
6716
  name: 'zoom-in-button',
6708
6717
  order: 9,
6709
6718
  isButton: true,
6710
- title: locale.image.zoomIn(),
6719
+ title: editor.locale.image.zoomIn(),
6711
6720
  html: icons.get('zoomIn'),
6712
6721
  onClick: () => {
6713
6722
  const currSlide = pswp.currSlide;
@@ -6759,6 +6768,10 @@ function removeImageBox(box) {
6759
6768
  // Displays error icon and filename.
6760
6769
  function renderError(imageNode, box) {
6761
6770
  return __awaiter(this, void 0, void 0, function* () {
6771
+ const editor = box.getEditor();
6772
+ if (!editor) {
6773
+ return;
6774
+ }
6762
6775
  const value = box.value;
6763
6776
  box.getContainer().css({
6764
6777
  width: '',
@@ -6766,7 +6779,7 @@ function renderError(imageNode, box) {
6766
6779
  });
6767
6780
  const buttonGroupNode = query(safeTemplate `
6768
6781
  <div class="lake-button-group">
6769
- <button type="button" tabindex="-1" class="lake-button-remove" title="${locale.image.remove()}"></button>
6782
+ <button type="button" tabindex="-1" class="lake-button-remove" title="${editor.locale.image.remove()}"></button>
6770
6783
  </div>
6771
6784
  `);
6772
6785
  const removeButton = buttonGroupNode.find('.lake-button-remove');
@@ -6816,7 +6829,7 @@ function renderUploading(imageNode, box) {
6816
6829
  });
6817
6830
  const buttonGroupNode = query(safeTemplate `
6818
6831
  <div class="lake-button-group">
6819
- <button type="button" tabindex="-1" class="lake-button-remove" title="${locale.image.remove()}"></button>
6832
+ <button type="button" tabindex="-1" class="lake-button-remove" title="${editor.locale.image.remove()}"></button>
6820
6833
  </div>
6821
6834
  `);
6822
6835
  const removeButton = buttonGroupNode.find('.lake-button-remove');
@@ -6878,8 +6891,8 @@ function renderDone(imageNode, box) {
6878
6891
  });
6879
6892
  const buttonGroupNode = query(safeTemplate `
6880
6893
  <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>
6894
+ <button type="button" tabindex="-1" class="lake-button-view" title="${editor.locale.image.view()}"></button>
6895
+ <button type="button" tabindex="-1" class="lake-button-remove" title="${editor.locale.image.remove()}"></button>
6883
6896
  </div>
6884
6897
  `);
6885
6898
  const viewButton = buttonGroupNode.find('.lake-button-view');
@@ -7130,6 +7143,7 @@ const codeBlockBox = {
7130
7143
  doc: (_a = boxValue.code) !== null && _a !== void 0 ? _a : '',
7131
7144
  extensions: [
7132
7145
  EditorState.readOnly.of(editor.readonly),
7146
+ EditorView.editable.of(!editor.readonly),
7133
7147
  history(),
7134
7148
  keymap.of([
7135
7149
  ...defaultKeymap,
@@ -7147,7 +7161,7 @@ const codeBlockBox = {
7147
7161
  name: 'langType',
7148
7162
  downIcon: icons.get('down'),
7149
7163
  defaultValue: langItem ? boxValue.lang : codeBlockConfig.defaultLang,
7150
- tooltip: locale.codeBlock.langType(),
7164
+ tooltip: editor.locale.codeBlock.langType(),
7151
7165
  width: 'auto',
7152
7166
  menuType: 'list',
7153
7167
  menuItems: langItems.map((item) => ({
@@ -7505,9 +7519,7 @@ var heading = (editor) => {
7505
7519
  const typeList = [
7506
7520
  'info',
7507
7521
  'tip',
7508
- 'success',
7509
7522
  'warning',
7510
- 'error',
7511
7523
  'danger',
7512
7524
  ];
7513
7525
  var blockQuote = (editor) => {
@@ -7975,17 +7987,18 @@ var formatPainter = (editor) => {
7975
7987
  };
7976
7988
 
7977
7989
  class LinkPopup {
7978
- constructor(root) {
7990
+ constructor(config) {
7979
7991
  this.linkNode = null;
7980
7992
  this.event = new EventEmitter();
7981
- this.root = root;
7993
+ this.root = config.root;
7994
+ this.locale = config.locale || i18nObject('en-US');
7982
7995
  this.container = query(safeTemplate `
7983
7996
  <div class="lake-link-popup">
7984
- <div class="lake-row">${locale.link.url()}</div>
7997
+ <div class="lake-row">${this.locale.link.url()}</div>
7985
7998
  <div class="lake-row lake-url-row">
7986
7999
  <input type="text" name="url" />
7987
8000
  </div>
7988
- <div class="lake-row">${locale.link.title()}</div>
8001
+ <div class="lake-row">${this.locale.link.title()}</div>
7989
8002
  <div class="lake-row">
7990
8003
  <input type="text" name="title" />
7991
8004
  </div>
@@ -8020,7 +8033,7 @@ class LinkPopup {
8020
8033
  root: this.container.find('.lake-url-row'),
8021
8034
  name: 'copy',
8022
8035
  icon: icons.get('copy'),
8023
- tooltip: locale.link.copy(),
8036
+ tooltip: this.locale.link.copy(),
8024
8037
  onClick: () => {
8025
8038
  if (!this.linkNode) {
8026
8039
  return;
@@ -8062,7 +8075,7 @@ class LinkPopup {
8062
8075
  root: this.container.find('.lake-url-row'),
8063
8076
  name: 'open',
8064
8077
  icon: icons.get('open'),
8065
- tooltip: locale.link.open(),
8078
+ tooltip: this.locale.link.open(),
8066
8079
  onClick: () => {
8067
8080
  if (!this.linkNode) {
8068
8081
  return;
@@ -8079,7 +8092,7 @@ class LinkPopup {
8079
8092
  root: this.container.find('.lake-button-row'),
8080
8093
  name: 'save',
8081
8094
  icon: icons.get('check'),
8082
- text: locale.link.save(),
8095
+ text: this.locale.link.save(),
8083
8096
  onClick: () => {
8084
8097
  if (!this.linkNode) {
8085
8098
  return;
@@ -8098,7 +8111,7 @@ class LinkPopup {
8098
8111
  root: this.container.find('.lake-button-row'),
8099
8112
  name: 'unlink',
8100
8113
  icon: icons.get('unlink'),
8101
- text: locale.link.unlink(),
8114
+ text: this.locale.link.unlink(),
8102
8115
  onClick: () => {
8103
8116
  if (!this.linkNode) {
8104
8117
  return;
@@ -8204,7 +8217,10 @@ var link = (editor) => {
8204
8217
  if (editor.readonly) {
8205
8218
  return;
8206
8219
  }
8207
- const popup = new LinkPopup(editor.popupContainer);
8220
+ const popup = new LinkPopup({
8221
+ root: editor.popupContainer,
8222
+ locale: editor.locale,
8223
+ });
8208
8224
  popup.event.on('save', node => {
8209
8225
  const range = editor.selection.range;
8210
8226
  range.setStartAfter(node);
@@ -8244,7 +8260,7 @@ var link = (editor) => {
8244
8260
  });
8245
8261
  editor.command.add('link', {
8246
8262
  execute: () => {
8247
- const linkNode = editor.selection.insertLink(`<a href="">${locale.link.newLink()}</a>`);
8263
+ const linkNode = editor.selection.insertLink(`<a href="">${editor.locale.link.newLink()}</a>`);
8248
8264
  if (!linkNode) {
8249
8265
  return;
8250
8266
  }
@@ -8357,6 +8373,12 @@ const headingTypeMap = new Map([
8357
8373
  ['#####', 'h5'],
8358
8374
  ['######', 'h6'],
8359
8375
  ]);
8376
+ const shortLangTypeMap = new Map([
8377
+ ['js', 'javascript'],
8378
+ ['ts', 'typescript'],
8379
+ ['md', 'markdown'],
8380
+ ['htm', 'html'],
8381
+ ]);
8360
8382
  const markItemList = [
8361
8383
  {
8362
8384
  re: /\*\*(.+?)\*\*$/,
@@ -8475,6 +8497,7 @@ const blockItemListForEnterKey = [
8475
8497
  {
8476
8498
  re: /^`+([a-z]*)$/i,
8477
8499
  getParameters: (results) => {
8500
+ var _a;
8478
8501
  if (!results[1]) {
8479
8502
  return [
8480
8503
  'codeBlock',
@@ -8483,7 +8506,7 @@ const blockItemListForEnterKey = [
8483
8506
  return [
8484
8507
  'codeBlock',
8485
8508
  {
8486
- lang: results[1],
8509
+ lang: (_a = shortLangTypeMap.get(results[1])) !== null && _a !== void 0 ? _a : results[1],
8487
8510
  },
8488
8511
  ];
8489
8512
  },