lakelib 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/lake.js CHANGED
@@ -3,13 +3,10 @@ import EventEmitter from 'eventemitter3';
3
3
  import debounce from 'lodash/debounce';
4
4
  import md5 from 'blueimp-md5';
5
5
  import { createKeybindingsHandler } from 'tinykeys';
6
+ import { i18nObject as i18nObject$1 } from 'typesafe-i18n';
6
7
  import 'photoswipe/style.css';
7
8
  import PhotoSwipeLightbox from 'photoswipe/lightbox';
8
9
  import PhotoSwipe from 'photoswipe';
9
- import { basicSetup } from 'codemirror';
10
- import { EditorView, keymap } from '@codemirror/view';
11
- import { indentWithTab } from '@codemirror/commands';
12
- import { javascript } from '@codemirror/lang-javascript';
13
10
 
14
11
  class BoxElement extends HTMLElement {
15
12
  }
@@ -318,6 +315,16 @@ function denormalizeValue(value) {
318
315
  replace(/<lake-bookmark\s+type="focus">\s*<\/lake-bookmark>/ig, '<focus />');
319
316
  }
320
317
 
318
+ // Returns the text of keyboard shortcuts used for a tooltip or help.
319
+ // Mac: mod+Z returns ⌘+Z
320
+ // Windows / Linux: mod+Z returns Ctrl+Z
321
+ function modifierText(value, userAgent) {
322
+ userAgent = userAgent !== null && userAgent !== void 0 ? userAgent : navigator.userAgent;
323
+ const isMac = userAgent.indexOf('Mac OS X') >= 0;
324
+ const modText = isMac ? '⌘' : 'Ctrl';
325
+ return value.replace(/(^|\+|\s)mod(\+|\s|$)/g, `$1${modText}$2`);
326
+ }
327
+
321
328
  function forEach(map, callback) {
322
329
  for (const key in map) {
323
330
  if (callback(key, map[key]) === false) {
@@ -437,7 +444,7 @@ const tableTagNames = new Set([
437
444
 
438
445
  /* eslint no-console: "off" */
439
446
  function debug(...data) {
440
- if (window.DEBUG) {
447
+ if (window.LAKE_DEBUG) {
441
448
  console.log.apply(console.log, data);
442
449
  }
443
450
  }
@@ -965,6 +972,12 @@ class Nodes {
965
972
  const element = this.get(0);
966
973
  return element.offsetWidth;
967
974
  }
975
+ // Returns the interior width of the first element, which does not include padding.
976
+ innerWidth() {
977
+ const paddingLeft = parseInt(this.computedCSS('padding-left'), 10) || 0;
978
+ const paddingRight = parseInt(this.computedCSS('padding-right'), 10) || 0;
979
+ return this.width() - paddingLeft - paddingRight;
980
+ }
968
981
  // Returns the height of of the first element.
969
982
  height() {
970
983
  const element = this.get(0);
@@ -2738,6 +2751,7 @@ var index = /*#__PURE__*/Object.freeze({
2738
2751
  getDeepest: getDeepest,
2739
2752
  inString: inString,
2740
2753
  mergeNodes: mergeNodes,
2754
+ modifierText: modifierText,
2741
2755
  morph: morph,
2742
2756
  normalizeValue: normalizeValue,
2743
2757
  parseStyle: parseStyle,
@@ -2901,7 +2915,7 @@ class Box {
2901
2915
  }
2902
2916
  // Returns the editor instance of the box.
2903
2917
  getEditor() {
2904
- const container = this.node.closestContainer();
2918
+ const container = this.node.closest('div[contenteditable]');
2905
2919
  return container.length > 0 ? editors.get(container.id) : undefined;
2906
2920
  }
2907
2921
  // Returns the container node of the box.
@@ -2963,7 +2977,7 @@ const blockAttributeRules = {
2963
2977
  id: /^[\w-]+$/,
2964
2978
  class: /^[\w-]+$/,
2965
2979
  style: {
2966
- 'text-align': ['left', 'center', 'right', 'justify'],
2980
+ 'text-align': ['left', 'center', 'right', 'justify', 'start', 'end'],
2967
2981
  'margin-left': /^-?\d+px$/i,
2968
2982
  'text-indent': /^-?\d+em$/i,
2969
2983
  },
@@ -3991,102 +4005,293 @@ function insertLink(range, value) {
3991
4005
  return linkNode;
3992
4006
  }
3993
4007
 
3994
- var name = "lakelib";
3995
- var description = "Rich text editor based on the browser";
3996
- var version = "0.0.1";
3997
- var author = "Luo Longhao <luolonghao@gmail.com>";
3998
- var license = "MIT";
3999
- var homepage = "http://lakejs.com";
4000
- var repository = {
4001
- type: "git",
4002
- url: "git+https://github.com/lakejs/lake.git"
4003
- };
4004
- var main = "./lib/lake";
4005
- var files = [
4006
- "dist",
4007
- "lib"
4008
- ];
4009
- var keywords = [
4010
- "rich text",
4011
- "wysiwyg",
4012
- "editor"
4013
- ];
4014
- var bugs = {
4015
- url: "https://github.com/lakejs/lake/issues"
4016
- };
4017
- var dependencies = {
4018
- "@codemirror/commands": "^6.3.3",
4019
- "@codemirror/lang-javascript": "^6.2.2",
4020
- "@codemirror/view": "^6.26.0",
4021
- "@types/blueimp-md5": "^2.18.2",
4022
- "@types/lodash": "^4.14.202",
4023
- "blueimp-md5": "^2.19.0",
4024
- codemirror: "^6.0.1",
4025
- eventemitter3: "^4.0.7",
4026
- "js-base64": "^3.7.6",
4027
- lodash: "^4.17.21",
4028
- photoswipe: "^5.4.3",
4029
- tinykeys: "^2.1.0"
4030
- };
4031
- var devDependencies = {
4032
- "@rollup/plugin-commonjs": "^25.0.7",
4033
- "@rollup/plugin-json": "^6.1.0",
4034
- "@rollup/plugin-node-resolve": "^15.2.3",
4035
- "@rollup/plugin-terser": "^0.4.4",
4036
- "@rollup/plugin-typescript": "^11.1.6",
4037
- "@types/chai": "^4.3.11",
4038
- "@types/mocha": "^10.0.6",
4039
- "@types/sinon": "^17.0.3",
4040
- "@typescript-eslint/eslint-plugin": "^6.21.0",
4041
- "@typescript-eslint/parser": "^6.21.0",
4042
- chai: "^4.4.1",
4043
- eslint: "^8.56.0",
4044
- "eslint-config-airbnb-base": "^15.0.0",
4045
- "eslint-config-prettier": "^8.10.0",
4046
- express: "^4.18.2",
4047
- mocha: "^10.3.0",
4048
- multer: "1.4.5-lts.1",
4049
- "npm-run-all": "^4.1.5",
4050
- puppeteer: "^22.6.1",
4051
- rimraf: "^5.0.5",
4052
- rollup: "^3.29.4",
4053
- "rollup-plugin-import-css": "^3.4.0",
4054
- "rollup-plugin-svg-import": "^3.0.0",
4055
- "simple-git-hooks": "^2.9.0",
4056
- sinon: "^17.0.1",
4057
- tslib: "^2.6.2",
4058
- typescript: "^5.3.3"
4059
- };
4060
- var scripts = {
4061
- start: "npm-run-all --parallel --print-label express watch",
4062
- express: "node ./scripts/start-server.mjs",
4063
- watch: "rollup --watch --config rollup.config.mjs",
4064
- build: "rimraf ./dist ./lib & rollup --config rollup.config.mjs",
4065
- lint: "eslint . --config .eslintrc.cjs --ext \".ts,.js,.cjs,.mjs\"",
4066
- test: "node ./scripts/run-tests.mjs",
4067
- clean: "rimraf ./dist ./lib ./temp"
4068
- };
4069
- var packageManager = "pnpm@8.7.5";
4070
- var pkg = {
4071
- name: name,
4072
- description: description,
4073
- version: version,
4074
- author: author,
4075
- license: license,
4076
- homepage: homepage,
4077
- repository: repository,
4078
- main: main,
4079
- files: files,
4080
- keywords: keywords,
4081
- bugs: bugs,
4082
- dependencies: dependencies,
4083
- devDependencies: devDependencies,
4084
- scripts: scripts,
4085
- "simple-git-hooks": {
4086
- "pre-commit": "pnpm lint"
4087
- },
4088
- packageManager: packageManager
4089
- };
4008
+ class Button {
4009
+ constructor(config) {
4010
+ this.config = config;
4011
+ this.root = config.root;
4012
+ this.node = query(safeTemplate `
4013
+ <button type="button" name="${config.name}" class="lake-button" />
4014
+ `);
4015
+ if (config.tabIndex !== undefined) {
4016
+ this.node.attr('tabindex', config.tabIndex.toString());
4017
+ }
4018
+ }
4019
+ render() {
4020
+ const config = this.config;
4021
+ const buttonNode = this.node;
4022
+ buttonNode.addClass(`lake-${config.text ? 'text' : 'icon'}-button`);
4023
+ if (config.tooltip) {
4024
+ buttonNode.attr('title', config.tooltip);
4025
+ }
4026
+ if (config.icon) {
4027
+ buttonNode.append(config.icon);
4028
+ }
4029
+ if (config.text) {
4030
+ buttonNode.append(`<span>${config.text}</span>`);
4031
+ }
4032
+ this.root.append(buttonNode);
4033
+ buttonNode.on('mouseenter', () => {
4034
+ if (buttonNode.attr('disabled')) {
4035
+ return;
4036
+ }
4037
+ if (buttonNode.hasClass('lake-button-selected')) {
4038
+ return;
4039
+ }
4040
+ buttonNode.addClass('lake-button-hovered');
4041
+ });
4042
+ buttonNode.on('mouseleave', () => {
4043
+ if (buttonNode.attr('disabled')) {
4044
+ return;
4045
+ }
4046
+ buttonNode.removeClass('lake-button-hovered');
4047
+ });
4048
+ buttonNode.on('click', event => {
4049
+ event.preventDefault();
4050
+ config.onClick();
4051
+ });
4052
+ }
4053
+ }
4054
+
4055
+ class Dropdown {
4056
+ constructor(config) {
4057
+ this.documentClickListener = (event) => {
4058
+ const targetNode = new Nodes(event.target);
4059
+ const titleNode = this.node.find('.lake-dropdown-title');
4060
+ const menuNode = this.node.find('.lake-dropdown-menu');
4061
+ if (targetNode.closest('.lake-dropdown-title').get(0) === titleNode.get(0)) {
4062
+ return;
4063
+ }
4064
+ menuNode.hide();
4065
+ document.removeEventListener('click', this.documentClickListener);
4066
+ };
4067
+ this.config = config;
4068
+ this.root = config.root;
4069
+ this.node = query(safeTemplate `
4070
+ <div class="lake-dropdown lake-${config.menuType}-dropdown" name="${config.name}">
4071
+ <button type="button" name="${config.name}" class="lake-dropdown-title">
4072
+ <div class="lake-dropdown-${config.icon ? 'icon' : 'text'}"></div>
4073
+ <div class="lake-dropdown-down-icon"></div>
4074
+ </button>
4075
+ </div>
4076
+ `);
4077
+ if (config.tabIndex !== undefined) {
4078
+ const titleNode = this.node.find('.lake-dropdown-title');
4079
+ titleNode.attr('tabindex', config.tabIndex.toString());
4080
+ }
4081
+ }
4082
+ // Returns the value of the node.
4083
+ static getValue(node) {
4084
+ const value = node.attr('value');
4085
+ if (value === '') {
4086
+ return [];
4087
+ }
4088
+ return JSON.parse(Base64.decode(value));
4089
+ }
4090
+ // Updates the value of the node.
4091
+ static setValue(node, value) {
4092
+ node.attr('value', Base64.encode(JSON.stringify(value)));
4093
+ }
4094
+ static getMenuMap(menuItems) {
4095
+ const menuMap = new Map();
4096
+ for (const menuItem of menuItems) {
4097
+ // remove HTML tags
4098
+ const text = menuItem.text.replace(/<[^>]*>/g, '');
4099
+ menuMap.set(menuItem.value, text);
4100
+ }
4101
+ return menuMap;
4102
+ }
4103
+ updateColorAccent(titleNode, value) {
4104
+ const svgNode = titleNode.find('.lake-dropdown-icon svg').eq(1);
4105
+ const lineNode = svgNode.find('line');
4106
+ if (lineNode.length > 0) {
4107
+ lineNode.attr('stroke', value);
4108
+ }
4109
+ else {
4110
+ svgNode.find('path').attr('fill', value);
4111
+ }
4112
+ }
4113
+ apppendMenuItems(menuNode) {
4114
+ const config = this.config;
4115
+ for (const menuItem of config.menuItems) {
4116
+ const listContent = template `
4117
+ <li value="${encode(menuItem.value)}">
4118
+ <div class="lake-dropdown-menu-text">${menuItem.text}</div>
4119
+ </li>
4120
+ `;
4121
+ const listNode = query(listContent);
4122
+ menuNode.append(listNode);
4123
+ if (config.menuType === 'color') {
4124
+ listNode.attr('title', menuItem.text);
4125
+ listNode.find('.lake-dropdown-menu-text').css('background-color', menuItem.value);
4126
+ }
4127
+ if (menuItem.icon) {
4128
+ const menuIconNode = query('<div class="lake-dropdown-menu-icon"></div>');
4129
+ menuIconNode.append(menuItem.icon);
4130
+ listNode.prepend(menuIconNode);
4131
+ }
4132
+ const checkIcon = icons.get('check');
4133
+ if (checkIcon) {
4134
+ const checkNode = query('<div class="lake-dropdown-menu-check"></div>');
4135
+ checkNode.append(checkIcon);
4136
+ listNode.prepend(checkNode);
4137
+ }
4138
+ }
4139
+ }
4140
+ showMenu() {
4141
+ const config = this.config;
4142
+ const dropdownNode = this.node;
4143
+ const menuNode = dropdownNode.find('.lake-dropdown-menu');
4144
+ if (dropdownNode.attr('disabled')) {
4145
+ return;
4146
+ }
4147
+ const currentValues = Dropdown.getValue(dropdownNode);
4148
+ menuNode.find('.lake-dropdown-menu-check').css('visibility', 'hidden');
4149
+ menuNode.find('li').each(node => {
4150
+ const listNode = query(node);
4151
+ listNode.on('mouseenter', () => {
4152
+ if (listNode.hasClass('lake-dropdown-item-selected')) {
4153
+ return;
4154
+ }
4155
+ listNode.addClass('lake-dropdown-item-hovered');
4156
+ });
4157
+ listNode.on('mouseleave', () => {
4158
+ listNode.removeClass('lake-dropdown-item-hovered');
4159
+ });
4160
+ if (currentValues.indexOf(listNode.attr('value')) >= 0) {
4161
+ listNode.find('.lake-dropdown-menu-check').css('visibility', 'visible');
4162
+ }
4163
+ });
4164
+ menuNode.css('visibility', 'hidden');
4165
+ menuNode.show(config.menuType === 'color' ? 'flex' : 'block');
4166
+ const dropdownNativeNode = dropdownNode.get(0);
4167
+ const dropdownRect = dropdownNativeNode.getBoundingClientRect();
4168
+ if (dropdownRect.x + menuNode.width() + 50 > window.innerWidth) {
4169
+ menuNode.css('left', 'auto');
4170
+ menuNode.css('right', '0');
4171
+ }
4172
+ else {
4173
+ menuNode.css('left', '');
4174
+ menuNode.css('right', '');
4175
+ }
4176
+ menuNode.css('visibility', '');
4177
+ document.addEventListener('click', this.documentClickListener);
4178
+ }
4179
+ bindEvents() {
4180
+ const config = this.config;
4181
+ const dropdownNode = this.node;
4182
+ const titleNode = dropdownNode.find('.lake-dropdown-title');
4183
+ const textNode = titleNode.find('.lake-dropdown-text');
4184
+ const iconNode = titleNode.find('.lake-dropdown-icon');
4185
+ const downIconNode = titleNode.find('.lake-dropdown-down-icon');
4186
+ const menuNode = dropdownNode.find('.lake-dropdown-menu');
4187
+ if (config.menuType === 'color') {
4188
+ iconNode.on('mouseenter', () => {
4189
+ if (dropdownNode.attr('disabled')) {
4190
+ return;
4191
+ }
4192
+ iconNode.addClass('lake-dropdown-icon-hovered');
4193
+ });
4194
+ iconNode.on('mouseleave', () => {
4195
+ iconNode.removeClass('lake-dropdown-icon-hovered');
4196
+ });
4197
+ downIconNode.on('mouseenter', () => {
4198
+ if (dropdownNode.attr('disabled')) {
4199
+ return;
4200
+ }
4201
+ downIconNode.addClass('lake-dropdown-down-icon-hovered');
4202
+ });
4203
+ downIconNode.on('mouseleave', () => {
4204
+ downIconNode.removeClass('lake-dropdown-down-icon-hovered');
4205
+ });
4206
+ }
4207
+ else {
4208
+ titleNode.on('mouseenter', () => {
4209
+ if (dropdownNode.attr('disabled')) {
4210
+ return;
4211
+ }
4212
+ titleNode.addClass('lake-dropdown-title-hovered');
4213
+ });
4214
+ titleNode.on('mouseleave', () => {
4215
+ titleNode.removeClass('lake-dropdown-title-hovered');
4216
+ });
4217
+ }
4218
+ if (config.menuType === 'color') {
4219
+ iconNode.on('click', event => {
4220
+ event.preventDefault();
4221
+ if (dropdownNode.attr('disabled')) {
4222
+ return;
4223
+ }
4224
+ const value = dropdownNode.attr('color') || config.defaultValue;
4225
+ config.onSelect(value);
4226
+ });
4227
+ }
4228
+ const triggerNode = (config.menuType === 'color' && downIconNode) ? downIconNode : titleNode;
4229
+ triggerNode.on('click', event => {
4230
+ event.preventDefault();
4231
+ this.showMenu();
4232
+ });
4233
+ menuNode.on('click', event => {
4234
+ event.preventDefault();
4235
+ const listItem = query(event.target).closest('li');
4236
+ const value = listItem.attr('value');
4237
+ Dropdown.setValue(dropdownNode, [value]);
4238
+ if (textNode.length > 0) {
4239
+ textNode.text(listItem.text());
4240
+ }
4241
+ if (config.menuType === 'color' && value !== '') {
4242
+ dropdownNode.attr('color', value);
4243
+ this.updateColorAccent(titleNode, value);
4244
+ }
4245
+ config.onSelect(value);
4246
+ menuNode.hide();
4247
+ document.removeEventListener('click', this.documentClickListener);
4248
+ });
4249
+ }
4250
+ render() {
4251
+ var _a;
4252
+ const config = this.config;
4253
+ const dropdownNode = this.node;
4254
+ const titleNode = dropdownNode.find('.lake-dropdown-title');
4255
+ if (!config.downIcon) {
4256
+ titleNode.addClass('lake-dropdown-title-no-down');
4257
+ }
4258
+ titleNode.css('width', config.width);
4259
+ titleNode.attr('title', config.tooltip);
4260
+ const textNode = titleNode.find('.lake-dropdown-text');
4261
+ const iconNode = titleNode.find('.lake-dropdown-icon');
4262
+ if (config.icon) {
4263
+ iconNode.append(config.icon);
4264
+ }
4265
+ if (config.accentIcon) {
4266
+ iconNode.append(config.accentIcon);
4267
+ }
4268
+ const downIconNode = titleNode.find('.lake-dropdown-down-icon');
4269
+ if (config.downIcon) {
4270
+ downIconNode.append(config.downIcon);
4271
+ }
4272
+ const menuNode = query('<ul class="lake-dropdown-menu" />');
4273
+ menuNode.addClass(`lake-${config.menuType}-dropdown-menu`);
4274
+ Dropdown.setValue(dropdownNode, [config.defaultValue]);
4275
+ if (textNode.length > 0) {
4276
+ const menuMap = Dropdown.getMenuMap(config.menuItems);
4277
+ textNode.text((_a = menuMap.get(config.defaultValue)) !== null && _a !== void 0 ? _a : config.defaultValue);
4278
+ }
4279
+ if (config.menuType === 'color') {
4280
+ this.updateColorAccent(titleNode, config.defaultValue);
4281
+ }
4282
+ this.apppendMenuItems(menuNode);
4283
+ dropdownNode.append(titleNode);
4284
+ dropdownNode.append(menuNode);
4285
+ this.root.append(dropdownNode);
4286
+ this.bindEvents();
4287
+ }
4288
+ unmount() {
4289
+ this.node.remove();
4290
+ document.removeEventListener('click', this.documentClickListener);
4291
+ }
4292
+ }
4293
+
4294
+ var version = "0.0.2";
4090
4295
 
4091
4296
  // Inserts a box into the specified range.
4092
4297
  function insertBox(range, boxName, boxValue) {
@@ -4226,7 +4431,6 @@ class Selection {
4226
4431
  this.selection = selection;
4227
4432
  this.container = container;
4228
4433
  this.range = this.getRangeFromNativeSelection();
4229
- this.appliedItems = [];
4230
4434
  }
4231
4435
  // Returns the current selected range from the native selection.
4232
4436
  getRangeFromNativeSelection() {
@@ -4318,9 +4522,10 @@ class Selection {
4318
4522
  }
4319
4523
 
4320
4524
  class Command {
4321
- constructor() {
4525
+ constructor(selection) {
4322
4526
  this.commandMap = new Map();
4323
4527
  this.event = new EventEmitter();
4528
+ this.selection = selection;
4324
4529
  }
4325
4530
  add(name, handler) {
4326
4531
  this.commandMap.set(name, handler);
@@ -4328,13 +4533,41 @@ class Command {
4328
4533
  getNames() {
4329
4534
  return Array.from(this.commandMap.keys());
4330
4535
  }
4331
- execute(name, ...data) {
4332
- const handler = this.commandMap.get(name);
4333
- if (handler === undefined) {
4536
+ getItem(name) {
4537
+ const commandItem = this.commandMap.get(name);
4538
+ if (commandItem === undefined) {
4334
4539
  throw new Error(`Command '${name}' does not exist.`);
4335
4540
  }
4541
+ return commandItem;
4542
+ }
4543
+ isDisabled(name) {
4544
+ const commandItem = this.getItem(name);
4545
+ if (!commandItem.isDisabled) {
4546
+ return false;
4547
+ }
4548
+ const appliedItems = this.selection.getAppliedItems();
4549
+ return commandItem.isDisabled(appliedItems);
4550
+ }
4551
+ isSelected(name) {
4552
+ const commandItem = this.getItem(name);
4553
+ if (!commandItem.isSelected) {
4554
+ return false;
4555
+ }
4556
+ const appliedItems = this.selection.getAppliedItems();
4557
+ return commandItem.isSelected(appliedItems);
4558
+ }
4559
+ selectedValues(name) {
4560
+ const commandItem = this.getItem(name);
4561
+ if (!commandItem.selectedValues) {
4562
+ return [];
4563
+ }
4564
+ const appliedItems = this.selection.getAppliedItems();
4565
+ return commandItem.selectedValues(appliedItems);
4566
+ }
4567
+ execute(name, ...data) {
4568
+ const commandItem = this.getItem(name);
4336
4569
  this.event.emit('beforeexecute', name);
4337
- handler.apply(this, data);
4570
+ commandItem.execute.apply(this, data);
4338
4571
  this.event.emit('execute', name);
4339
4572
  debug(`Command '${name}' executed`);
4340
4573
  }
@@ -4356,13 +4589,15 @@ const boxInstances = new Map();
4356
4589
  // inputs 'e': value: 'abe', list: ['a', 'ab', 'abe'], index: 3, canRedo: false
4357
4590
  class History {
4358
4591
  constructor(selection) {
4359
- this.selection = selection;
4360
- this.container = selection.container;
4592
+ // an array for storing the history items
4361
4593
  this.list = [];
4594
+ // the next index of the list
4362
4595
  this.index = 0;
4363
4596
  this.canSave = true;
4364
4597
  this.limit = 100;
4365
4598
  this.event = new EventEmitter();
4599
+ this.selection = selection;
4600
+ this.container = selection.container;
4366
4601
  }
4367
4602
  removeBookmark(value) {
4368
4603
  return value.replace(/(<lake-box[^>]+)\s+focus="\w+"([^>]*>)/ig, '$1$2').
@@ -4524,9 +4759,9 @@ const shortenedTypeMap = new Map([
4524
4759
  ]);
4525
4760
  class Keystroke {
4526
4761
  constructor(container) {
4527
- this.container = container;
4528
4762
  this.keydownEventList = [];
4529
4763
  this.keyupEventList = [];
4764
+ this.container = container;
4530
4765
  }
4531
4766
  normalizeType(type) {
4532
4767
  var _a;
@@ -4565,7 +4800,9 @@ class Keystroke {
4565
4800
  type = this.normalizeType(type);
4566
4801
  for (const item of this.keydownEventList) {
4567
4802
  if (item.type === type) {
4568
- item.listener(new Event(type));
4803
+ if (item.listener(new Event(type)) === false) {
4804
+ break;
4805
+ }
4569
4806
  }
4570
4807
  }
4571
4808
  }
@@ -4574,7 +4811,9 @@ class Keystroke {
4574
4811
  type = this.normalizeType(type);
4575
4812
  for (const item of this.keyupEventList) {
4576
4813
  if (item.type === type) {
4577
- item.listener(new Event(type));
4814
+ if (item.listener(new Event(type)) === false) {
4815
+ break;
4816
+ }
4578
4817
  }
4579
4818
  }
4580
4819
  }
@@ -4644,6 +4883,8 @@ const defaultConfig = {
4644
4883
  value: '<p><br /><focus /></p>',
4645
4884
  readonly: false,
4646
4885
  spellcheck: false,
4886
+ tabIndex: 0,
4887
+ indentWithTab: true,
4647
4888
  minChangeSize: 5,
4648
4889
  imageRequestMethod: 'POST',
4649
4890
  imageRequestAction: '/upload',
@@ -4651,34 +4892,29 @@ const defaultConfig = {
4651
4892
  };
4652
4893
  class Editor {
4653
4894
  constructor(config) {
4654
- if (!config.root) {
4655
- throw new Error('The root of the config must be specified.');
4656
- }
4657
- this.root = query(config.root);
4658
- this.config = Object.assign(Object.assign({}, defaultConfig), config);
4659
- this.containerWrapper = query('<div class="lake-container-wrapper" />');
4660
- this.container = query('<div class="lake-container" />');
4661
- this.overlayContainer = query('<div class="lake-overlay" />');
4662
- this.popupContainer = query('<div class="lake-popup lake-custom-properties" />');
4895
+ this.unsavedInputData = '';
4663
4896
  this.isComposing = false;
4664
- this.readonly = this.config.readonly;
4665
- this.root.addClass('lake-custom-properties');
4666
- this.container.attr({
4667
- contenteditable: this.readonly ? 'false' : 'true',
4668
- spellcheck: this.config.spellcheck ? 'true' : 'false',
4669
- });
4670
4897
  this.event = new EventEmitter();
4671
- this.selection = new Selection(this.container);
4672
- this.command = new Command();
4673
- this.history = new History(this.selection);
4674
- this.keystroke = new Keystroke(this.container);
4675
4898
  this.box = Editor.box;
4676
- this.unsavedInputData = '';
4677
- editors.set(this.container.id, this);
4678
4899
  this.beforeunloadListener = () => {
4679
4900
  this.commitUnsavedInputData();
4680
4901
  };
4681
- const updateBoxSelectionStyleHandler = debounce(() => {
4902
+ this.selectionchangeListener = () => {
4903
+ this.selection.syncByRange();
4904
+ this.updateBoxSelectionStyle();
4905
+ this.emitStateChangeEvent();
4906
+ };
4907
+ this.clickListener = event => {
4908
+ const targetNode = new Nodes(event.target);
4909
+ if (targetNode.closest('.lake-popup').length > 0) {
4910
+ return;
4911
+ }
4912
+ this.event.emit('click', targetNode);
4913
+ };
4914
+ this.resizeListener = () => {
4915
+ this.event.emit('resize');
4916
+ };
4917
+ this.updateBoxSelectionStyle = debounce(() => {
4682
4918
  // The editor has been unmounted.
4683
4919
  if (this.root.first().length === 0) {
4684
4920
  return;
@@ -4716,28 +4952,76 @@ class Editor {
4716
4952
  boxContainer.removeClass('lake-box-focused');
4717
4953
  boxContainer.removeClass('lake-box-selected');
4718
4954
  });
4955
+ this.event.emit('boxselectionstylechange');
4719
4956
  }, 50, {
4720
4957
  leading: false,
4721
4958
  trailing: true,
4722
4959
  maxWait: 50,
4723
4960
  });
4724
- this.selectionchangeListener = () => {
4725
- this.selection.syncByRange();
4726
- this.selection.appliedItems = this.selection.getAppliedItems();
4727
- updateBoxSelectionStyleHandler();
4728
- this.event.emit('selectionchange');
4729
- };
4730
- this.clickListener = event => {
4731
- const targetNode = new Nodes(event.target);
4732
- this.event.emit('click', targetNode);
4733
- };
4734
- this.mouseoverListener = event => {
4735
- const targetNode = new Nodes(event.target);
4736
- this.event.emit('mouseover', targetNode);
4737
- };
4738
- this.resizeListener = () => {
4739
- this.event.emit('resize');
4961
+ this.emitStateChangeEvent = debounce(() => {
4962
+ const commandNames = this.command.getNames();
4963
+ let appliedItems = this.selection.getAppliedItems();
4964
+ if (appliedItems.length > 0 &&
4965
+ appliedItems[0].node.closestContainer().get(0) !== this.container.get(0)) {
4966
+ appliedItems = [];
4967
+ }
4968
+ const disabledNameMap = new Map();
4969
+ const selectedNameMap = new Map();
4970
+ const selectedValuesMap = new Map();
4971
+ if (appliedItems.length > 0) {
4972
+ for (const name of commandNames) {
4973
+ const commandItem = this.command.getItem(name);
4974
+ if (commandItem.isDisabled && commandItem.isDisabled(appliedItems)) {
4975
+ disabledNameMap.set(name, true);
4976
+ }
4977
+ if (commandItem.isSelected && commandItem.isSelected(appliedItems)) {
4978
+ selectedNameMap.set(name, true);
4979
+ }
4980
+ if (commandItem.selectedValues) {
4981
+ const values = commandItem.selectedValues(appliedItems);
4982
+ if (values.length > 0) {
4983
+ selectedValuesMap.set(name, values);
4984
+ }
4985
+ }
4986
+ }
4987
+ }
4988
+ this.event.emit('statechange', {
4989
+ appliedItems,
4990
+ disabledNameMap,
4991
+ selectedNameMap,
4992
+ selectedValuesMap,
4993
+ });
4994
+ }, 100, {
4995
+ leading: false,
4996
+ trailing: true,
4997
+ maxWait: 100,
4998
+ });
4999
+ this.emitChangeEvent = (value) => {
5000
+ this.rectifyContent();
5001
+ this.emitStateChangeEvent();
5002
+ this.event.emit('change', value);
4740
5003
  };
5004
+ if (!config.root) {
5005
+ throw new Error('The root of the config must be specified.');
5006
+ }
5007
+ this.root = query(config.root);
5008
+ this.config = Object.assign(Object.assign({}, defaultConfig), config);
5009
+ this.containerWrapper = query('<div class="lake-container-wrapper" />');
5010
+ this.container = query('<div class="lake-container" />');
5011
+ this.overlayContainer = query('<div class="lake-overlay" />');
5012
+ this.popupContainer = query('<div class="lake-popup lake-custom-properties" />');
5013
+ this.readonly = this.config.readonly;
5014
+ this.root.addClass('lake-custom-properties');
5015
+ this.container.attr({
5016
+ contenteditable: this.readonly ? 'false' : 'true',
5017
+ spellcheck: this.config.spellcheck ? 'true' : 'false',
5018
+ tabindex: this.config.tabIndex.toString(),
5019
+ });
5020
+ this.selection = new Selection(this.container);
5021
+ this.command = new Command(this.selection);
5022
+ this.history = new History(this.selection);
5023
+ this.keystroke = new Keystroke(this.container);
5024
+ editors.set(this.container.id, this);
4741
5025
  }
4742
5026
  inputInBoxStrip() {
4743
5027
  const selection = this.selection;
@@ -4819,17 +5103,52 @@ class Editor {
4819
5103
  bindHistoryEvents() {
4820
5104
  this.history.event.on('undo', value => {
4821
5105
  this.box.renderAll(this);
4822
- this.event.emit('change', value);
5106
+ this.emitChangeEvent(value);
4823
5107
  });
4824
5108
  this.history.event.on('redo', value => {
4825
5109
  this.box.renderAll(this);
4826
- this.event.emit('change', value);
5110
+ this.emitChangeEvent(value);
4827
5111
  });
4828
5112
  this.history.event.on('save', value => {
4829
5113
  this.box.rectifyInstances(this);
4830
- this.event.emit('change', value);
5114
+ this.emitChangeEvent(value);
5115
+ });
5116
+ }
5117
+ bindFocusEvents() {
5118
+ this.container.on('focus', () => {
5119
+ this.root.addClass('lake-root-focused');
5120
+ });
5121
+ this.container.on('blur', () => {
5122
+ this.root.removeClass('lake-root-focused');
4831
5123
  });
4832
5124
  }
5125
+ // Fixes wrong content, especially empty tag.
5126
+ rectifyContent() {
5127
+ let children = this.container.children();
5128
+ for (const child of children) {
5129
+ if ((child.isBlock || child.isMark) && child.html() === '') {
5130
+ child.remove();
5131
+ debug('Rectifying content: empty tag was removed');
5132
+ }
5133
+ }
5134
+ children = this.container.children();
5135
+ if (children.length === 0) {
5136
+ this.container.html('<p><br /></p>');
5137
+ this.selection.range.shrinkAfter(this.container);
5138
+ debug('Rectifying content: default paragraph was added');
5139
+ return;
5140
+ }
5141
+ if (children.length === 1) {
5142
+ const child = children[0];
5143
+ if (child.isVoid) {
5144
+ const paragraph = query('<p />');
5145
+ child.before(paragraph);
5146
+ paragraph.append(child);
5147
+ this.selection.range.shrinkAfter(paragraph);
5148
+ debug('Rectifying content: void element was wrapped in paragraph');
5149
+ }
5150
+ }
5151
+ }
4833
5152
  // Saves the input data which is unsaved.
4834
5153
  commitUnsavedInputData() {
4835
5154
  if (this.unsavedInputData.length > 0) {
@@ -4877,7 +5196,7 @@ class Editor {
4877
5196
  insertBox(boxName, boxValue) {
4878
5197
  const box = insertBox(this.selection.range, boxName, boxValue);
4879
5198
  if (!box) {
4880
- return box;
5199
+ throw new Error(`Box '${boxName}' cannot be inserted outside the editor.`);
4881
5200
  }
4882
5201
  const instanceMap = this.box.getInstances(this);
4883
5202
  instanceMap.set(box.node.id, box);
@@ -4892,12 +5211,6 @@ class Editor {
4892
5211
  }
4893
5212
  return box;
4894
5213
  }
4895
- // Returns the interior width of the editor area, which does not include padding.
4896
- innerWidth() {
4897
- const paddingLeft = parseInt(this.container.computedCSS('padding-left'), 10) || 0;
4898
- const paddingRight = parseInt(this.container.computedCSS('padding-right'), 10) || 0;
4899
- return this.container.width() - paddingLeft - paddingRight;
4900
- }
4901
5214
  // Renders an editor area and set default value to it.
4902
5215
  render() {
4903
5216
  const value = normalizeValue(this.config.value);
@@ -4910,11 +5223,12 @@ class Editor {
4910
5223
  query(document.body).append(this.popupContainer);
4911
5224
  this.container.append(fragment);
4912
5225
  if (!this.readonly) {
5226
+ this.bindFocusEvents();
4913
5227
  this.focus();
4914
5228
  this.selection.synByBookmark();
4915
5229
  this.history.save();
5230
+ Editor.plugin.loadAll(this);
4916
5231
  }
4917
- Editor.plugin.loadAll(this);
4918
5232
  Editor.box.renderAll(this);
4919
5233
  if (!this.readonly) {
4920
5234
  window.addEventListener('beforeunload', this.beforeunloadListener);
@@ -4923,7 +5237,6 @@ class Editor {
4923
5237
  this.bindHistoryEvents();
4924
5238
  }
4925
5239
  document.addEventListener('click', this.clickListener);
4926
- document.addEventListener('mouseover', this.mouseoverListener);
4927
5240
  window.addEventListener('resize', this.resizeListener);
4928
5241
  }
4929
5242
  // Destroys a rendered editor.
@@ -4935,93 +5248,403 @@ class Editor {
4935
5248
  document.removeEventListener('selectionchange', this.selectionchangeListener);
4936
5249
  }
4937
5250
  document.removeEventListener('click', this.clickListener);
4938
- document.removeEventListener('mouseover', this.mouseoverListener);
4939
5251
  window.removeEventListener('resize', this.resizeListener);
4940
5252
  }
4941
5253
  }
4942
- Editor.version = pkg.version;
5254
+ Editor.version = version;
4943
5255
  Editor.box = new BoxManager();
4944
5256
  Editor.plugin = new Plugin();
4945
5257
 
5258
+ var enUS = {
5259
+ toolbar: {
5260
+ undo: `Undo (${modifierText('mod+Z')})`,
5261
+ redo: `Redo (${modifierText('mod+Y')})`,
5262
+ selectAll: `Select all (${modifierText('mod+A')})`,
5263
+ paragraph: 'Paragraph',
5264
+ blockQuote: 'Block quotation',
5265
+ numberedList: 'Numbered list',
5266
+ bulletedList: 'Bulleted list',
5267
+ checklist: 'Checklist',
5268
+ alignLeft: 'Align left',
5269
+ alignCenter: 'Align center',
5270
+ alignRight: 'Align right',
5271
+ alignJustify: 'Align justify',
5272
+ increaseIndent: 'Increase indent',
5273
+ decreaseIndent: 'Decrease indent',
5274
+ bold: `Bold (${modifierText('mod+B')})`,
5275
+ italic: `Italic (${modifierText('mod+I')})`,
5276
+ underline: `Underline (${modifierText('mod+U')})`,
5277
+ strikethrough: 'Strikethrough',
5278
+ superscript: 'Superscript',
5279
+ subscript: 'Subscript',
5280
+ code: 'Inline code',
5281
+ removeFormat: 'Remove format',
5282
+ formatPainter: 'Format painter',
5283
+ link: 'Link',
5284
+ hr: 'Horizontal line',
5285
+ codeBlock: 'Code block',
5286
+ heading: 'Heading',
5287
+ heading1: 'Heading 1',
5288
+ heading2: 'Heading 2',
5289
+ heading3: 'Heading 3',
5290
+ heading4: 'Heading 4',
5291
+ heading5: 'Heading 5',
5292
+ heading6: 'Heading 6',
5293
+ list: 'List',
5294
+ align: 'Alignment',
5295
+ indent: 'Indent',
5296
+ fontFamily: 'Font family',
5297
+ fontSize: 'Font size',
5298
+ moreStyle: 'More style',
5299
+ fontColor: 'Font color',
5300
+ highlight: 'Highlight',
5301
+ image: 'Image',
5302
+ removeColor: 'Remove color',
5303
+ },
5304
+ link: {
5305
+ newLink: 'New link',
5306
+ url: 'Link URL',
5307
+ title: 'Link title',
5308
+ copy: 'Copy link to clipboard',
5309
+ open: 'Open link in new tab',
5310
+ save: 'Save',
5311
+ unlink: 'Remove link',
5312
+ },
5313
+ image: {
5314
+ view: 'Full screen',
5315
+ remove: 'Delete',
5316
+ previous: 'Previous',
5317
+ next: 'Next',
5318
+ close: 'Close (Esc)',
5319
+ loadingError: 'The image cannot be loaded',
5320
+ zoomOut: 'Zoom out',
5321
+ zoomIn: 'Zoom in',
5322
+ },
5323
+ codeBlock: {
5324
+ langType: 'Select language',
5325
+ },
5326
+ };
5327
+
5328
+ var zhCN = {
5329
+ toolbar: {
5330
+ undo: `撤消 (${modifierText('mod+Z')})`,
5331
+ redo: `重做 (${modifierText('mod+Y')})`,
5332
+ selectAll: `全选 (${modifierText('mod+A')})`,
5333
+ paragraph: '正文',
5334
+ blockQuote: '引用',
5335
+ numberedList: '编号',
5336
+ bulletedList: '项目符号',
5337
+ checklist: '任务列表',
5338
+ alignLeft: '左对齐',
5339
+ alignCenter: '居中',
5340
+ alignRight: '右对齐',
5341
+ alignJustify: '两端对齐',
5342
+ increaseIndent: '增加缩进',
5343
+ decreaseIndent: '减少缩进',
5344
+ bold: `粗体 (${modifierText('mod+B')})`,
5345
+ italic: `斜体 (${modifierText('mod+I')})`,
5346
+ underline: `下划线 (${modifierText('mod+U')})`,
5347
+ strikethrough: '删除线',
5348
+ superscript: '上标',
5349
+ subscript: '下标',
5350
+ code: '行内代码',
5351
+ removeFormat: '清除格式',
5352
+ formatPainter: '格式刷',
5353
+ link: '链接',
5354
+ hr: '分割线',
5355
+ codeBlock: '代码块',
5356
+ heading: '标题',
5357
+ heading1: '标题 1',
5358
+ heading2: '标题 2',
5359
+ heading3: '标题 3',
5360
+ heading4: '标题 4',
5361
+ heading5: '标题 5',
5362
+ heading6: '标题 6',
5363
+ list: '列表',
5364
+ align: '对齐方式',
5365
+ indent: '缩进',
5366
+ fontFamily: '字体',
5367
+ fontSize: '文字大小',
5368
+ moreStyle: '更多样式',
5369
+ fontColor: '文字颜色',
5370
+ highlight: '文字背景',
5371
+ image: '图片',
5372
+ removeColor: '默认',
5373
+ },
5374
+ link: {
5375
+ newLink: '新链接',
5376
+ url: '链接 URL',
5377
+ title: '链接文本',
5378
+ copy: '复制到剪贴板',
5379
+ open: '打开链接',
5380
+ save: '确定',
5381
+ unlink: '取消链接',
5382
+ },
5383
+ image: {
5384
+ view: '查看大图',
5385
+ remove: '删除',
5386
+ previous: '上一张',
5387
+ next: '下一张',
5388
+ close: '关闭 (Esc)',
5389
+ loadingError: '图片加载失败',
5390
+ zoomOut: '缩小',
5391
+ zoomIn: '放大',
5392
+ },
5393
+ codeBlock: {
5394
+ langType: '选择代码语言',
5395
+ },
5396
+ };
5397
+
5398
+ var ja = {
5399
+ toolbar: {
5400
+ undo: `元に戻す (${modifierText('mod+Z')})`,
5401
+ redo: `やり直し (${modifierText('mod+Y')})`,
5402
+ selectAll: `すべて選択 (${modifierText('mod+A')})`,
5403
+ paragraph: 'テキスト',
5404
+ blockQuote: 'ブロック引用',
5405
+ numberedList: '番号付きリスト',
5406
+ bulletedList: '箇条書きリスト',
5407
+ checklist: 'タスクリスト',
5408
+ alignLeft: '左揃え',
5409
+ alignCenter: '中心揃え',
5410
+ alignRight: '右揃え',
5411
+ alignJustify: '左右に並べ替え',
5412
+ increaseIndent: 'インデントを増やす',
5413
+ decreaseIndent: 'インデントを減らす',
5414
+ bold: `太字 (${modifierText('mod+B')})`,
5415
+ italic: `斜体 (${modifierText('mod+I')})`,
5416
+ underline: `下線 (${modifierText('mod+U')})`,
5417
+ strikethrough: '取り消し線',
5418
+ superscript: '上付き文字',
5419
+ subscript: '下付き文字',
5420
+ code: 'インラインコード',
5421
+ removeFormat: '形式を削除',
5422
+ formatPainter: '形式ペインタ',
5423
+ link: 'リンク',
5424
+ hr: '区切り線',
5425
+ codeBlock: 'コードブロック',
5426
+ heading: 'タイトル',
5427
+ heading1: 'タイトル 1',
5428
+ heading2: 'タイトル 2',
5429
+ heading3: 'タイトル 3',
5430
+ heading4: 'タイトル 4',
5431
+ heading5: 'タイトル 5',
5432
+ heading6: 'タイトル 6',
5433
+ list: 'リスト',
5434
+ align: '文字揃え',
5435
+ indent: 'インデント',
5436
+ fontFamily: 'フォント',
5437
+ fontSize: '文字サイズ',
5438
+ moreStyle: 'その他のスタイル',
5439
+ fontColor: '文字色',
5440
+ highlight: '文字の背景',
5441
+ image: '画像',
5442
+ removeColor: 'デフォルト',
5443
+ },
5444
+ link: {
5445
+ newLink: '新しいリンク',
5446
+ url: 'リンク URL',
5447
+ title: 'リンク文字',
5448
+ copy: 'クリップボードにコピー',
5449
+ open: 'リンクを開く',
5450
+ save: '確認',
5451
+ unlink: 'リンクを削除',
5452
+ },
5453
+ image: {
5454
+ view: '大きな画像を見る',
5455
+ remove: '削除',
5456
+ previous: '前の画像',
5457
+ next: '次の画像',
5458
+ close: '閉じる (Esc)',
5459
+ loadingError: '画像を読み込めません',
5460
+ zoomOut: '縮小',
5461
+ zoomIn: '拡大',
5462
+ },
5463
+ codeBlock: {
5464
+ langType: 'コード言語を選択',
5465
+ },
5466
+ };
5467
+
5468
+ var ko = {
5469
+ toolbar: {
5470
+ undo: `작업취소 (${modifierText('mod+Z')})`,
5471
+ redo: `작업재개 (${modifierText('mod+Y')})`,
5472
+ selectAll: `전체 선택 (${modifierText('mod+A')})`,
5473
+ paragraph: '텍스트',
5474
+ blockQuote: '인용문',
5475
+ numberedList: '순서 목록',
5476
+ bulletedList: '비순서 목록',
5477
+ checklist: '체크리스트',
5478
+ alignLeft: '왼쪽 정렬',
5479
+ alignCenter: '가운데 정렬',
5480
+ alignRight: '오른쪽 정렬',
5481
+ alignJustify: '좌우로 정렬',
5482
+ increaseIndent: '들여쓰기 증가',
5483
+ decreaseIndent: '들여쓰기 줄이기',
5484
+ bold: `굵게 (${modifierText('mod+B')})`,
5485
+ italic: `기울임꼴 (${modifierText('mod+I')})`,
5486
+ underline: `밑줄 (${modifierText('mod+U')})`,
5487
+ strikethrough: '취소선',
5488
+ superscript: '위첨자',
5489
+ subscript: '아래 첨자',
5490
+ code: '인라인 코드',
5491
+ removeFormat: '형식 지우기',
5492
+ formatPainter: '형식 페인터',
5493
+ link: '링크',
5494
+ hr: '구분선',
5495
+ codeBlock: '코드 블록',
5496
+ heading: '제목',
5497
+ heading1: '제목 1',
5498
+ heading2: '제목 2',
5499
+ heading3: '제목 3',
5500
+ heading4: '제목 4',
5501
+ heading5: '제목 5',
5502
+ heading6: '제목 6',
5503
+ list: '목록',
5504
+ align: '정렬',
5505
+ indent: '들여쓰기',
5506
+ fontFamily: '글꼴',
5507
+ fontSize: '글자 크기',
5508
+ moreStyle: '더 많은 스타일',
5509
+ fontColor: '글자 색상',
5510
+ highlight: '글자 배경',
5511
+ image: '이미지',
5512
+ removeColor: '기본색',
5513
+ },
5514
+ link: {
5515
+ newLink: '새 링크',
5516
+ url: '링크 URL',
5517
+ title: '링크 텍스트',
5518
+ copy: '클립보드에 복사',
5519
+ open: '링크 열기',
5520
+ save: '확인',
5521
+ unlink: '링크 제거',
5522
+ },
5523
+ image: {
5524
+ view: '큰 이미지 보기',
5525
+ remove: '삭제',
5526
+ previous: '이전 이미지',
5527
+ next: '다음 이미지',
5528
+ close: '닫기 (Esc)',
5529
+ loadingError: '이미지를 로드할 수 없습니다',
5530
+ zoomOut: '축소',
5531
+ zoomIn: '확대',
5532
+ },
5533
+ codeBlock: {
5534
+ langType: '코드언어 선택',
5535
+ },
5536
+ };
5537
+
5538
+ const localeTranslations = {
5539
+ 'en-US': enUS,
5540
+ 'zh-CN': zhCN,
5541
+ ja,
5542
+ ko,
5543
+ };
5544
+ const locales = Object.keys(localeTranslations);
5545
+ const loadedLocales = {};
5546
+ const loadedFormatters = {};
5547
+ const initFormatters = () => {
5548
+ const formatters = {
5549
+ // add your formatter functions here
5550
+ };
5551
+ return formatters;
5552
+ };
5553
+ const loadFormatters = (locale) => {
5554
+ loadedFormatters[locale] = initFormatters();
5555
+ };
5556
+ const loadLocale = (locale) => {
5557
+ if (loadedLocales[locale]) {
5558
+ return;
5559
+ }
5560
+ loadedLocales[locale] = localeTranslations[locale];
5561
+ loadFormatters(locale);
5562
+ };
5563
+ const loadAllLocales = () => locales.forEach(loadLocale);
5564
+ const i18nObject = (locale) => i18nObject$1(locale, loadedLocales[locale], loadedFormatters[locale]);
5565
+ loadAllLocales();
5566
+ const language = locales.indexOf(window.LAKE_LANGUAGE) >= 0 ? window.LAKE_LANGUAGE : 'en-US';
5567
+ const locale = i18nObject(language);
5568
+
4946
5569
  const headingMenuItems = [
4947
5570
  {
4948
5571
  value: 'h1',
4949
- text: '<span style="font-weight: bold; font-size: 26px;">Heading 1</span>',
5572
+ text: `<span style="font-weight: bold; font-size: 26px;">${locale.toolbar.heading1()}</span>`,
4950
5573
  },
4951
5574
  {
4952
5575
  value: 'h2',
4953
- text: '<span style="font-weight: bold; font-size: 24px;">Heading 2</span>',
5576
+ text: `<span style="font-weight: bold; font-size: 24px;">${locale.toolbar.heading2()}</span>`,
4954
5577
  },
4955
5578
  {
4956
5579
  value: 'h3',
4957
- text: '<span style="font-weight: bold; font-size: 22px;">Heading 3</span>',
5580
+ text: `<span style="font-weight: bold; font-size: 22px;">${locale.toolbar.heading3()}</span>`,
4958
5581
  },
4959
5582
  {
4960
5583
  value: 'h4',
4961
- text: '<span style="font-weight: bold; font-size: 20px;">Heading 4</span>',
5584
+ text: `<span style="font-weight: bold; font-size: 20px;">${locale.toolbar.heading4()}</span>`,
4962
5585
  },
4963
5586
  {
4964
5587
  value: 'h5',
4965
- text: '<span style="font-weight: bold; font-size: 18px;">Heading 5</span>',
5588
+ text: `<span style="font-weight: bold; font-size: 18px;">${locale.toolbar.heading5()}</span>`,
4966
5589
  },
4967
5590
  {
4968
5591
  value: 'h6',
4969
- text: '<span style="font-weight: bold; font-size: 16px;">Heading 6</span>',
5592
+ text: `<span style="font-weight: bold; font-size: 16px;">${locale.toolbar.heading6()}</span>`,
4970
5593
  },
4971
5594
  {
4972
5595
  value: 'p',
4973
- text: 'Paragraph',
5596
+ text: locale.toolbar.paragraph(),
4974
5597
  },
4975
5598
  ];
4976
5599
  const listMenuItems = [
4977
5600
  {
4978
5601
  icon: icons.get('numberedList'),
4979
5602
  value: 'numbered',
4980
- text: 'Numbered list',
5603
+ text: locale.toolbar.numberedList(),
4981
5604
  },
4982
5605
  {
4983
5606
  icon: icons.get('bulletedList'),
4984
5607
  value: 'bulleted',
4985
- text: 'Bulleted list',
5608
+ text: locale.toolbar.bulletedList(),
4986
5609
  },
4987
5610
  {
4988
5611
  icon: icons.get('checklist'),
4989
5612
  value: 'checklist',
4990
- text: 'Checklist',
5613
+ text: locale.toolbar.checklist(),
4991
5614
  },
4992
5615
  ];
4993
5616
  const alignMenuItems = [
4994
5617
  {
4995
5618
  icon: icons.get('alignLeft'),
4996
5619
  value: 'left',
4997
- text: 'Align left',
5620
+ text: locale.toolbar.alignLeft(),
4998
5621
  },
4999
5622
  {
5000
5623
  icon: icons.get('alignCenter'),
5001
5624
  value: 'center',
5002
- text: 'Align center',
5625
+ text: locale.toolbar.alignCenter(),
5003
5626
  },
5004
5627
  {
5005
5628
  icon: icons.get('alignRight'),
5006
5629
  value: 'right',
5007
- text: 'Align right',
5630
+ text: locale.toolbar.alignRight(),
5008
5631
  },
5009
5632
  {
5010
5633
  icon: icons.get('alignJustify'),
5011
5634
  value: 'justify',
5012
- text: 'Align justify',
5635
+ text: locale.toolbar.alignJustify(),
5013
5636
  },
5014
5637
  ];
5015
5638
  const indentMenuItems = [
5016
5639
  {
5017
5640
  icon: icons.get('increaseIndent'),
5018
5641
  value: 'increase',
5019
- text: 'Increase indent',
5642
+ text: locale.toolbar.increaseIndent(),
5020
5643
  },
5021
5644
  {
5022
5645
  icon: icons.get('decreaseIndent'),
5023
5646
  value: 'decrease',
5024
- text: 'Decrease indent',
5647
+ text: locale.toolbar.decreaseIndent(),
5025
5648
  },
5026
5649
  ];
5027
5650
  const fontFamilyMenuItems = [
@@ -5108,32 +5731,32 @@ const moreStyleMenuItems = [
5108
5731
  {
5109
5732
  icon: icons.get('italic'),
5110
5733
  value: 'italic',
5111
- text: 'Italic',
5734
+ text: locale.toolbar.italic(),
5112
5735
  },
5113
5736
  {
5114
5737
  icon: icons.get('underline'),
5115
5738
  value: 'underline',
5116
- text: 'Underline',
5739
+ text: locale.toolbar.underline(),
5117
5740
  },
5118
5741
  {
5119
5742
  icon: icons.get('strikethrough'),
5120
5743
  value: 'strikethrough',
5121
- text: 'Strikethrough',
5744
+ text: locale.toolbar.strikethrough(),
5122
5745
  },
5123
5746
  {
5124
5747
  icon: icons.get('superscript'),
5125
5748
  value: 'superscript',
5126
- text: 'Superscript',
5749
+ text: locale.toolbar.superscript(),
5127
5750
  },
5128
5751
  {
5129
5752
  icon: icons.get('subscript'),
5130
5753
  value: 'subscript',
5131
- text: 'Subscript',
5754
+ text: locale.toolbar.subscript(),
5132
5755
  },
5133
5756
  {
5134
5757
  icon: icons.get('code'),
5135
5758
  value: 'code',
5136
- text: 'Code',
5759
+ text: locale.toolbar.code(),
5137
5760
  },
5138
5761
  ];
5139
5762
  // These colors are from Ant Design (https://ant.design/docs/spec/colors)
@@ -5156,7 +5779,7 @@ const colorMenuItems = [
5156
5779
  {
5157
5780
  icon: icons.get('removeFormat'),
5158
5781
  value: '',
5159
- text: 'Remove color',
5782
+ text: locale.toolbar.removeColor(),
5160
5783
  },
5161
5784
  ];
5162
5785
  for (const color of colors) {
@@ -5181,7 +5804,7 @@ const toolbarItems = [
5181
5804
  name: 'undo',
5182
5805
  type: 'button',
5183
5806
  icon: icons.get('undo'),
5184
- tooltip: 'Undo',
5807
+ tooltip: locale.toolbar.undo(),
5185
5808
  onClick: (editor, value) => {
5186
5809
  editor.command.execute(value);
5187
5810
  },
@@ -5190,7 +5813,7 @@ const toolbarItems = [
5190
5813
  name: 'redo',
5191
5814
  type: 'button',
5192
5815
  icon: icons.get('redo'),
5193
- tooltip: 'Redo',
5816
+ tooltip: locale.toolbar.redo(),
5194
5817
  onClick: (editor, value) => {
5195
5818
  editor.command.execute(value);
5196
5819
  },
@@ -5199,7 +5822,7 @@ const toolbarItems = [
5199
5822
  name: 'selectAll',
5200
5823
  type: 'button',
5201
5824
  icon: icons.get('selectAll'),
5202
- tooltip: 'Select all',
5825
+ tooltip: locale.toolbar.selectAll(),
5203
5826
  onClick: (editor, value) => {
5204
5827
  editor.command.execute(value);
5205
5828
  },
@@ -5208,7 +5831,7 @@ const toolbarItems = [
5208
5831
  name: 'paragraph',
5209
5832
  type: 'button',
5210
5833
  icon: icons.get('paragraph'),
5211
- tooltip: 'Paragraph',
5834
+ tooltip: locale.toolbar.paragraph(),
5212
5835
  isSelected: appliedItems => !!appliedItems.find(item => item.name === 'p'),
5213
5836
  onClick: editor => {
5214
5837
  editor.command.execute('heading', 'p');
@@ -5218,8 +5841,7 @@ const toolbarItems = [
5218
5841
  name: 'blockQuote',
5219
5842
  type: 'button',
5220
5843
  icon: icons.get('blockQuote'),
5221
- tooltip: 'Block quotation',
5222
- isSelected: appliedItems => !!appliedItems.find(item => item.name === 'blockquote'),
5844
+ tooltip: locale.toolbar.blockQuote(),
5223
5845
  onClick: (editor, value) => {
5224
5846
  editor.command.execute(value);
5225
5847
  },
@@ -5228,7 +5850,7 @@ const toolbarItems = [
5228
5850
  name: 'numberedList',
5229
5851
  type: 'button',
5230
5852
  icon: icons.get('numberedList'),
5231
- tooltip: 'Numbered list',
5853
+ tooltip: locale.toolbar.numberedList(),
5232
5854
  isSelected: appliedItems => !!appliedItems.find(item => item.name === 'ol'),
5233
5855
  onClick: editor => {
5234
5856
  editor.command.execute('list', 'numbered');
@@ -5238,7 +5860,7 @@ const toolbarItems = [
5238
5860
  name: 'bulletedList',
5239
5861
  type: 'button',
5240
5862
  icon: icons.get('bulletedList'),
5241
- tooltip: 'Bulleted list',
5863
+ tooltip: locale.toolbar.bulletedList(),
5242
5864
  isSelected: appliedItems => !!appliedItems.find(item => item.name === 'ul' && !item.node.hasAttr('type')),
5243
5865
  onClick: editor => {
5244
5866
  editor.command.execute('list', 'bulleted');
@@ -5248,7 +5870,7 @@ const toolbarItems = [
5248
5870
  name: 'checklist',
5249
5871
  type: 'button',
5250
5872
  icon: icons.get('checklist'),
5251
- tooltip: 'Checklist',
5873
+ tooltip: locale.toolbar.checklist(),
5252
5874
  isSelected: appliedItems => !!appliedItems.find(item => item.name === 'ul' && item.node.attr('type') === 'checklist'),
5253
5875
  onClick: editor => {
5254
5876
  editor.command.execute('list', 'checklist');
@@ -5258,7 +5880,7 @@ const toolbarItems = [
5258
5880
  name: 'alignLeft',
5259
5881
  type: 'button',
5260
5882
  icon: icons.get('alignLeft'),
5261
- tooltip: 'Align left',
5883
+ tooltip: locale.toolbar.alignLeft(),
5262
5884
  isSelected: appliedItems => !!appliedItems.find(item => item.node.isBlock && item.node.css('text-align') === 'left'),
5263
5885
  onClick: editor => {
5264
5886
  editor.command.execute('align', 'left');
@@ -5268,7 +5890,7 @@ const toolbarItems = [
5268
5890
  name: 'alignCenter',
5269
5891
  type: 'button',
5270
5892
  icon: icons.get('alignCenter'),
5271
- tooltip: 'Align center',
5893
+ tooltip: locale.toolbar.alignCenter(),
5272
5894
  isSelected: appliedItems => !!appliedItems.find(item => item.node.isBlock && item.node.css('text-align') === 'center'),
5273
5895
  onClick: editor => {
5274
5896
  editor.command.execute('align', 'center');
@@ -5278,7 +5900,7 @@ const toolbarItems = [
5278
5900
  name: 'alignRight',
5279
5901
  type: 'button',
5280
5902
  icon: icons.get('alignRight'),
5281
- tooltip: 'Align right',
5903
+ tooltip: locale.toolbar.alignRight(),
5282
5904
  isSelected: appliedItems => !!appliedItems.find(item => item.node.isBlock && item.node.css('text-align') === 'right'),
5283
5905
  onClick: editor => {
5284
5906
  editor.command.execute('align', 'right');
@@ -5288,7 +5910,7 @@ const toolbarItems = [
5288
5910
  name: 'alignJustify',
5289
5911
  type: 'button',
5290
5912
  icon: icons.get('alignJustify'),
5291
- tooltip: 'Align justify',
5913
+ tooltip: locale.toolbar.alignJustify(),
5292
5914
  isSelected: appliedItems => !!appliedItems.find(item => item.node.isBlock && item.node.css('text-align') === 'justify'),
5293
5915
  onClick: editor => {
5294
5916
  editor.command.execute('align', 'justify');
@@ -5298,7 +5920,7 @@ const toolbarItems = [
5298
5920
  name: 'increaseIndent',
5299
5921
  type: 'button',
5300
5922
  icon: icons.get('increaseIndent'),
5301
- tooltip: 'Increase indent',
5923
+ tooltip: locale.toolbar.increaseIndent(),
5302
5924
  onClick: editor => {
5303
5925
  editor.command.execute('indent', 'increase');
5304
5926
  },
@@ -5307,7 +5929,7 @@ const toolbarItems = [
5307
5929
  name: 'decreaseIndent',
5308
5930
  type: 'button',
5309
5931
  icon: icons.get('decreaseIndent'),
5310
- tooltip: 'Decrease indent',
5932
+ tooltip: locale.toolbar.decreaseIndent(),
5311
5933
  onClick: editor => {
5312
5934
  editor.command.execute('indent', 'decrease');
5313
5935
  },
@@ -5316,9 +5938,7 @@ const toolbarItems = [
5316
5938
  name: 'bold',
5317
5939
  type: 'button',
5318
5940
  icon: icons.get('bold'),
5319
- tooltip: 'Bold',
5320
- isDisabled: appliedItems => !!appliedItems.find(item => item.node.isHeading),
5321
- isSelected: appliedItems => !!appliedItems.find(item => item.name === 'strong'),
5941
+ tooltip: locale.toolbar.bold(),
5322
5942
  onClick: (editor, value) => {
5323
5943
  editor.command.execute(value);
5324
5944
  },
@@ -5327,8 +5947,7 @@ const toolbarItems = [
5327
5947
  name: 'italic',
5328
5948
  type: 'button',
5329
5949
  icon: icons.get('italic'),
5330
- tooltip: 'Italic',
5331
- isSelected: appliedItems => !!appliedItems.find(item => item.name === 'i'),
5950
+ tooltip: locale.toolbar.italic(),
5332
5951
  onClick: (editor, value) => {
5333
5952
  editor.command.execute(value);
5334
5953
  },
@@ -5337,8 +5956,7 @@ const toolbarItems = [
5337
5956
  name: 'underline',
5338
5957
  type: 'button',
5339
5958
  icon: icons.get('underline'),
5340
- tooltip: 'Underline',
5341
- isSelected: appliedItems => !!appliedItems.find(item => item.name === 'u'),
5959
+ tooltip: locale.toolbar.underline(),
5342
5960
  onClick: (editor, value) => {
5343
5961
  editor.command.execute(value);
5344
5962
  },
@@ -5347,8 +5965,7 @@ const toolbarItems = [
5347
5965
  name: 'strikethrough',
5348
5966
  type: 'button',
5349
5967
  icon: icons.get('strikethrough'),
5350
- tooltip: 'Strikethrough',
5351
- isSelected: appliedItems => !!appliedItems.find(item => item.name === 's'),
5968
+ tooltip: locale.toolbar.strikethrough(),
5352
5969
  onClick: (editor, value) => {
5353
5970
  editor.command.execute(value);
5354
5971
  },
@@ -5357,8 +5974,7 @@ const toolbarItems = [
5357
5974
  name: 'superscript',
5358
5975
  type: 'button',
5359
5976
  icon: icons.get('superscript'),
5360
- tooltip: 'Superscript',
5361
- isSelected: appliedItems => !!appliedItems.find(item => item.name === 'sup'),
5977
+ tooltip: locale.toolbar.superscript(),
5362
5978
  onClick: (editor, value) => {
5363
5979
  editor.command.execute(value);
5364
5980
  },
@@ -5367,8 +5983,7 @@ const toolbarItems = [
5367
5983
  name: 'subscript',
5368
5984
  type: 'button',
5369
5985
  icon: icons.get('subscript'),
5370
- tooltip: 'Subscript',
5371
- isSelected: appliedItems => !!appliedItems.find(item => item.name === 'sub'),
5986
+ tooltip: locale.toolbar.subscript(),
5372
5987
  onClick: (editor, value) => {
5373
5988
  editor.command.execute(value);
5374
5989
  },
@@ -5377,8 +5992,7 @@ const toolbarItems = [
5377
5992
  name: 'code',
5378
5993
  type: 'button',
5379
5994
  icon: icons.get('code'),
5380
- tooltip: 'Inline code',
5381
- isSelected: appliedItems => !!appliedItems.find(item => item.name === 'code'),
5995
+ tooltip: locale.toolbar.code(),
5382
5996
  onClick: (editor, value) => {
5383
5997
  editor.command.execute(value);
5384
5998
  },
@@ -5387,7 +6001,7 @@ const toolbarItems = [
5387
6001
  name: 'removeFormat',
5388
6002
  type: 'button',
5389
6003
  icon: icons.get('removeFormat'),
5390
- tooltip: 'Remove format',
6004
+ tooltip: locale.toolbar.removeFormat(),
5391
6005
  onClick: (editor, value) => {
5392
6006
  editor.command.execute(value);
5393
6007
  },
@@ -5396,7 +6010,7 @@ const toolbarItems = [
5396
6010
  name: 'formatPainter',
5397
6011
  type: 'button',
5398
6012
  icon: icons.get('formatPainter'),
5399
- tooltip: 'Format painter',
6013
+ tooltip: locale.toolbar.formatPainter(),
5400
6014
  onClick: (editor, value) => {
5401
6015
  editor.command.execute(value);
5402
6016
  },
@@ -5405,7 +6019,7 @@ const toolbarItems = [
5405
6019
  name: 'link',
5406
6020
  type: 'button',
5407
6021
  icon: icons.get('link'),
5408
- tooltip: 'Link',
6022
+ tooltip: locale.toolbar.link(),
5409
6023
  onClick: (editor, value) => {
5410
6024
  editor.command.execute(value);
5411
6025
  },
@@ -5414,7 +6028,7 @@ const toolbarItems = [
5414
6028
  name: 'hr',
5415
6029
  type: 'button',
5416
6030
  icon: icons.get('hr'),
5417
- tooltip: 'Horizontal line',
6031
+ tooltip: locale.toolbar.hr(),
5418
6032
  onClick: (editor, value) => {
5419
6033
  editor.command.execute(value);
5420
6034
  },
@@ -5423,7 +6037,7 @@ const toolbarItems = [
5423
6037
  name: 'codeBlock',
5424
6038
  type: 'button',
5425
6039
  icon: icons.get('codeBlock'),
5426
- tooltip: 'Code block',
6040
+ tooltip: locale.toolbar.codeBlock(),
5427
6041
  onClick: (editor, value) => {
5428
6042
  editor.command.execute(value);
5429
6043
  },
@@ -5433,14 +6047,10 @@ const toolbarItems = [
5433
6047
  type: 'dropdown',
5434
6048
  downIcon: icons.get('down'),
5435
6049
  defaultValue: 'p',
5436
- tooltip: 'Heading',
6050
+ tooltip: locale.toolbar.heading(),
5437
6051
  width: '100px',
5438
6052
  menuType: 'list',
5439
6053
  menuItems: headingMenuItems,
5440
- selectedValues: appliedItems => {
5441
- const currentItem = appliedItems.find(item => item.node.isHeading || item.name === 'p');
5442
- return currentItem ? [currentItem.name] : [];
5443
- },
5444
6054
  onSelect: (editor, value) => {
5445
6055
  editor.command.execute('heading', value);
5446
6056
  },
@@ -5451,28 +6061,10 @@ const toolbarItems = [
5451
6061
  downIcon: icons.get('down'),
5452
6062
  icon: icons.get('list'),
5453
6063
  defaultValue: '',
5454
- tooltip: 'List',
6064
+ tooltip: locale.toolbar.list(),
5455
6065
  width: 'auto',
5456
6066
  menuType: 'list',
5457
6067
  menuItems: listMenuItems,
5458
- selectedValues: appliedItems => {
5459
- let currentValue = '';
5460
- for (const item of appliedItems) {
5461
- if (item.name === 'ol') {
5462
- currentValue = 'numbered';
5463
- break;
5464
- }
5465
- if (item.name === 'ul' && !item.node.hasAttr('type')) {
5466
- currentValue = 'bulleted';
5467
- break;
5468
- }
5469
- if (item.name === 'ul' && item.node.attr('type') === 'checklist') {
5470
- currentValue = 'checklist';
5471
- break;
5472
- }
5473
- }
5474
- return [currentValue];
5475
- },
5476
6068
  onSelect: (editor, value) => {
5477
6069
  editor.command.execute('list', value);
5478
6070
  },
@@ -5483,20 +6075,10 @@ const toolbarItems = [
5483
6075
  downIcon: icons.get('down'),
5484
6076
  icon: icons.get('alignLeft'),
5485
6077
  defaultValue: '',
5486
- tooltip: 'Alignment',
6078
+ tooltip: locale.toolbar.align(),
5487
6079
  width: 'auto',
5488
6080
  menuType: 'list',
5489
6081
  menuItems: alignMenuItems,
5490
- selectedValues: appliedItems => {
5491
- let currentValue = '';
5492
- for (const item of appliedItems) {
5493
- if (item.node.isBlock) {
5494
- currentValue = item.node.computedCSS('text-align');
5495
- break;
5496
- }
5497
- }
5498
- return [currentValue];
5499
- },
5500
6082
  onSelect: (editor, value) => {
5501
6083
  editor.command.execute('align', value);
5502
6084
  },
@@ -5507,7 +6089,7 @@ const toolbarItems = [
5507
6089
  downIcon: icons.get('down'),
5508
6090
  icon: icons.get('increaseIndent'),
5509
6091
  defaultValue: '',
5510
- tooltip: 'Indent',
6092
+ tooltip: locale.toolbar.indent(),
5511
6093
  width: 'auto',
5512
6094
  menuType: 'list',
5513
6095
  menuItems: indentMenuItems,
@@ -5520,19 +6102,10 @@ const toolbarItems = [
5520
6102
  type: 'dropdown',
5521
6103
  downIcon: icons.get('down'),
5522
6104
  defaultValue: 'Segoe UI',
5523
- tooltip: 'Font family',
6105
+ tooltip: locale.toolbar.fontFamily(),
5524
6106
  width: '100px',
5525
6107
  menuType: 'list',
5526
6108
  menuItems: fontFamilyMenuItems,
5527
- selectedValues: appliedItems => {
5528
- for (const item of appliedItems) {
5529
- if (item.name === 'span') {
5530
- const currentValue = item.node.css('font-family');
5531
- return [currentValue.replace(/['"]/g, '')];
5532
- }
5533
- }
5534
- return [];
5535
- },
5536
6109
  onSelect: (editor, value) => {
5537
6110
  editor.command.execute('fontFamily', value);
5538
6111
  },
@@ -5542,20 +6115,10 @@ const toolbarItems = [
5542
6115
  type: 'dropdown',
5543
6116
  downIcon: icons.get('down'),
5544
6117
  defaultValue: '16px',
5545
- tooltip: 'Font size',
6118
+ tooltip: locale.toolbar.fontSize(),
5546
6119
  width: '65px',
5547
6120
  menuType: 'list',
5548
6121
  menuItems: fontSizeMenuItems,
5549
- isDisabled: appliedItems => !!appliedItems.find(item => item.node.isHeading),
5550
- selectedValues: appliedItems => {
5551
- for (const item of appliedItems) {
5552
- if (item.name === 'span') {
5553
- const currentValue = item.node.css('font-size');
5554
- return [currentValue.replace(/\.\d+/, '')];
5555
- }
5556
- }
5557
- return [];
5558
- },
5559
6122
  onSelect: (editor, value) => {
5560
6123
  editor.command.execute('fontSize', value);
5561
6124
  },
@@ -5565,7 +6128,7 @@ const toolbarItems = [
5565
6128
  type: 'dropdown',
5566
6129
  icon: icons.get('more'),
5567
6130
  defaultValue: '',
5568
- tooltip: 'More style',
6131
+ tooltip: locale.toolbar.moreStyle(),
5569
6132
  width: 'auto',
5570
6133
  menuType: 'list',
5571
6134
  menuItems: moreStyleMenuItems,
@@ -5591,19 +6154,10 @@ const toolbarItems = [
5591
6154
  icon: icons.get('fontColor'),
5592
6155
  accentIcon: icons.get('fontColorAccent'),
5593
6156
  defaultValue: '#f5222d',
5594
- tooltip: 'Font color',
6157
+ tooltip: locale.toolbar.fontColor(),
5595
6158
  width: 'auto',
5596
6159
  menuType: 'color',
5597
6160
  menuItems: colorMenuItems,
5598
- selectedValues: appliedItems => {
5599
- for (const item of appliedItems) {
5600
- if (item.name === 'span') {
5601
- const currentValue = item.node.computedCSS('color');
5602
- return [toHex(currentValue)];
5603
- }
5604
- }
5605
- return [];
5606
- },
5607
6161
  onSelect: (editor, value) => {
5608
6162
  editor.command.execute('fontColor', value);
5609
6163
  },
@@ -5615,19 +6169,10 @@ const toolbarItems = [
5615
6169
  icon: icons.get('highlight'),
5616
6170
  accentIcon: icons.get('highlightAccent'),
5617
6171
  defaultValue: '#fadb14',
5618
- tooltip: 'Highlight',
6172
+ tooltip: locale.toolbar.highlight(),
5619
6173
  width: 'auto',
5620
6174
  menuType: 'color',
5621
6175
  menuItems: colorMenuItems,
5622
- selectedValues: appliedItems => {
5623
- for (const item of appliedItems) {
5624
- if (item.name === 'span') {
5625
- const currentValue = item.node.computedCSS('background-color');
5626
- return [toHex(currentValue)];
5627
- }
5628
- }
5629
- return [];
5630
- },
5631
6176
  onSelect: (editor, value) => {
5632
6177
  editor.command.execute('highlight', value);
5633
6178
  },
@@ -5636,7 +6181,7 @@ const toolbarItems = [
5636
6181
  name: 'image',
5637
6182
  type: 'upload',
5638
6183
  icon: icons.get('image'),
5639
- tooltip: 'Image',
6184
+ tooltip: locale.toolbar.image(),
5640
6185
  accept: 'image/*',
5641
6186
  multiple: true,
5642
6187
  },
@@ -5656,9 +6201,6 @@ function uploadImage(config) {
5656
6201
  type: file.type,
5657
6202
  lastModified: file.lastModified,
5658
6203
  });
5659
- if (!box) {
5660
- throw new Error('The image box cannot be inserted outside the editor.');
5661
- }
5662
6204
  const xhr = request({
5663
6205
  onProgress: e => {
5664
6206
  const percentNode = box.node.find('.lake-percent');
@@ -5732,307 +6274,135 @@ class Toolbar {
5732
6274
  this.editor = config.editor;
5733
6275
  this.root = query(config.root);
5734
6276
  this.container = query('<div class="lake-toolbar" />');
5735
- this.event = new EventEmitter();
5736
6277
  this.root.addClass('lake-custom-properties');
5737
6278
  }
5738
- // Returns the value of the node.
5739
- getValue(node) {
5740
- const value = node.attr('value');
5741
- if (value === '') {
5742
- return [];
5743
- }
5744
- return JSON.parse(Base64.decode(value));
5745
- }
5746
- // Updates the value of the node.
5747
- setValue(node, value) {
5748
- node.attr('value', Base64.encode(JSON.stringify(value)));
5749
- }
5750
6279
  appendDivider() {
5751
6280
  this.container.append('<div class="lake-toolbar-divider" />');
5752
6281
  }
5753
6282
  appendButton(item) {
5754
6283
  const editor = this.editor;
5755
- const buttonNode = query('<button type="button" class="lake-toolbar-button" />');
5756
- buttonNode.attr('name', item.name);
5757
- buttonNode.attr('title', item.tooltip);
5758
- if (item.icon) {
5759
- buttonNode.append(item.icon);
5760
- }
5761
- this.container.append(buttonNode);
5762
- buttonNode.on('mouseenter', () => {
5763
- if (buttonNode.attr('disabled')) {
5764
- return;
5765
- }
5766
- buttonNode.addClass('lake-toolbar-button-hovered');
5767
- });
5768
- buttonNode.on('mouseleave', () => {
5769
- if (buttonNode.attr('disabled')) {
5770
- return;
5771
- }
5772
- buttonNode.removeClass('lake-toolbar-button-hovered');
5773
- });
5774
- buttonNode.on('click', event => {
5775
- event.preventDefault();
5776
- editor.focus();
5777
- item.onClick(editor, item.name);
6284
+ const button = new Button({
6285
+ root: this.container,
6286
+ name: item.name,
6287
+ icon: item.icon,
6288
+ tooltip: item.tooltip,
6289
+ tabIndex: -1,
6290
+ onClick: () => {
6291
+ editor.focus();
6292
+ item.onClick(editor, item.name);
6293
+ },
5778
6294
  });
6295
+ button.render();
5779
6296
  }
5780
- getMenuMap(item) {
5781
- const menuMap = new Map();
5782
- if (!item.menuItems) {
5783
- return menuMap;
5784
- }
5785
- for (const menuItem of item.menuItems) {
5786
- // remove HTML tags
5787
- const text = menuItem.text.replace(/<[^>]*>/g, '');
5788
- menuMap.set(menuItem.value, text);
5789
- }
5790
- return menuMap;
6297
+ appendDropdown(item) {
6298
+ const editor = this.editor;
6299
+ const dropdown = new Dropdown({
6300
+ root: this.container,
6301
+ name: item.name,
6302
+ icon: item.icon,
6303
+ accentIcon: item.accentIcon,
6304
+ downIcon: item.downIcon,
6305
+ defaultValue: item.defaultValue,
6306
+ tooltip: item.tooltip,
6307
+ width: item.width,
6308
+ menuType: item.menuType,
6309
+ menuItems: item.menuItems,
6310
+ tabIndex: -1,
6311
+ onSelect: value => {
6312
+ editor.focus();
6313
+ item.onSelect(editor, value);
6314
+ },
6315
+ });
6316
+ dropdown.render();
5791
6317
  }
5792
- updateColorAccent(titleNode, value) {
5793
- const svgNode = titleNode.find('.lake-dropdown-icon svg').eq(1);
5794
- const lineNode = svgNode.find('line');
5795
- if (lineNode.length > 0) {
5796
- lineNode.attr('stroke', value);
6318
+ appendUpload(item) {
6319
+ const editor = this.editor;
6320
+ const uploadNode = query(safeTemplate `
6321
+ <div class="lake-upload" name="${item.name}">
6322
+ <input type="file" />
6323
+ </div>
6324
+ `);
6325
+ const fileNode = uploadNode.find('input[type="file"]');
6326
+ const fileNativeNode = fileNode.get(0);
6327
+ if (item.accept) {
6328
+ fileNode.attr('accept', item.accept);
5797
6329
  }
5798
- else {
5799
- svgNode.find('path').attr('fill', value);
6330
+ if (item.multiple === true) {
6331
+ fileNode.attr('multiple', 'true');
5800
6332
  }
5801
- }
5802
- addDropdownMenu(menuNode, item) {
5803
- for (const menuItem of item.menuItems) {
5804
- const listContent = template `
5805
- <li value="${menuItem.value}">
5806
- <div class="lake-dropdown-menu-text">${menuItem.text}</div>
5807
- </li>
5808
- `;
5809
- const listNode = query(listContent);
5810
- menuNode.append(listNode);
5811
- if (item.menuType === 'color') {
5812
- listNode.attr('title', menuItem.text);
5813
- listNode.find('.lake-dropdown-menu-text').css('background-color', menuItem.value);
5814
- }
5815
- if (menuItem.icon) {
5816
- const menuIconNode = query('<div class="lake-dropdown-menu-icon"></div>');
5817
- menuIconNode.append(menuItem.icon);
5818
- listNode.prepend(menuIconNode);
5819
- }
5820
- const checkIcon = icons.get('check');
5821
- if (checkIcon) {
5822
- const checkNode = query('<div class="lake-dropdown-menu-check"></div>');
5823
- checkNode.append(checkIcon);
5824
- listNode.prepend(checkNode);
6333
+ const button = new Button({
6334
+ root: uploadNode,
6335
+ name: item.name,
6336
+ icon: item.icon,
6337
+ tooltip: item.tooltip,
6338
+ tabIndex: -1,
6339
+ onClick: () => {
6340
+ editor.focus();
6341
+ fileNativeNode.click();
6342
+ },
6343
+ });
6344
+ button.render();
6345
+ this.container.append(uploadNode);
6346
+ fileNode.on('click', event => event.stopPropagation());
6347
+ fileNode.on('change', event => {
6348
+ const target = event.target;
6349
+ const files = target.files || [];
6350
+ for (const file of files) {
6351
+ uploadImage({
6352
+ editor,
6353
+ file,
6354
+ });
5825
6355
  }
5826
- }
6356
+ });
5827
6357
  }
5828
- bindDropdownEvents(dropdownNode, item) {
6358
+ // Renders a toolbar for the specified editor.
6359
+ render() {
5829
6360
  const editor = this.editor;
5830
- const titleNode = dropdownNode.find('.lake-dropdown-title');
5831
- const textNode = titleNode.find('.lake-dropdown-text');
5832
- const iconNode = titleNode.find('.lake-dropdown-icon');
5833
- const downIconNode = titleNode.find('.lake-dropdown-down-icon');
5834
- const menuNode = dropdownNode.find('.lake-dropdown-menu');
5835
- if (item.menuType === 'color') {
5836
- iconNode.on('mouseenter', () => {
5837
- if (dropdownNode.attr('disabled')) {
5838
- return;
5839
- }
5840
- iconNode.addClass('lake-dropdown-icon-hovered');
5841
- });
5842
- iconNode.on('mouseleave', () => {
5843
- iconNode.removeClass('lake-dropdown-icon-hovered');
5844
- });
5845
- downIconNode.on('mouseenter', () => {
5846
- if (dropdownNode.attr('disabled')) {
5847
- return;
5848
- }
5849
- downIconNode.addClass('lake-dropdown-down-icon-hovered');
5850
- });
5851
- downIconNode.on('mouseleave', () => {
5852
- downIconNode.removeClass('lake-dropdown-down-icon-hovered');
5853
- });
5854
- }
5855
- else {
5856
- titleNode.on('mouseenter', () => {
5857
- if (dropdownNode.attr('disabled')) {
5858
- return;
5859
- }
5860
- titleNode.addClass('lake-dropdown-title-hovered');
5861
- });
5862
- titleNode.on('mouseleave', () => {
5863
- titleNode.removeClass('lake-dropdown-title-hovered');
5864
- });
5865
- }
5866
- if (item.menuType === 'color') {
5867
- iconNode.on('click', event => {
5868
- event.preventDefault();
5869
- if (dropdownNode.attr('disabled')) {
5870
- return;
5871
- }
5872
- editor.focus();
5873
- const value = dropdownNode.attr('color') || item.defaultValue;
5874
- item.onSelect(editor, value);
5875
- });
5876
- }
5877
- const triggerNode = (item.menuType === 'color' && downIconNode) ? downIconNode : titleNode;
5878
- triggerNode.on('click', event => {
5879
- event.preventDefault();
5880
- if (dropdownNode.attr('disabled')) {
6361
+ this.root.empty();
6362
+ this.root.append(this.container);
6363
+ const allMenuMap = new Map();
6364
+ const buttonItemList = [];
6365
+ const dropdownItemList = [];
6366
+ this.items.forEach(name => {
6367
+ if (name === '|') {
6368
+ this.appendDivider();
5881
6369
  return;
5882
6370
  }
5883
- const currentValues = this.getValue(dropdownNode);
5884
- menuNode.find('.lake-dropdown-menu-check').css('visibility', 'hidden');
5885
- menuNode.find('li').each(node => {
5886
- const listNode = query(node);
5887
- if (currentValues.indexOf(listNode.attr('value')) >= 0) {
5888
- listNode.find('.lake-dropdown-menu-check').css('visibility', 'visible');
6371
+ let item;
6372
+ if (typeof name === 'string') {
6373
+ item = toolbarItemMap.get(name);
6374
+ if (!item) {
6375
+ return;
5889
6376
  }
5890
- });
5891
- menuNode.css('visibility', 'hidden');
5892
- menuNode.show(item.menuType === 'color' ? 'flex' : 'block');
5893
- const dropdownNativeNode = dropdownNode.get(0);
5894
- const dropdownRect = dropdownNativeNode.getBoundingClientRect();
5895
- if (dropdownRect.x + menuNode.width() > window.innerWidth) {
5896
- menuNode.css('left', 'auto');
5897
- menuNode.css('right', '0');
5898
6377
  }
5899
6378
  else {
5900
- menuNode.css('left', '');
5901
- menuNode.css('right', '');
5902
- }
5903
- menuNode.css('visibility', '');
5904
- });
5905
- menuNode.on('click', event => {
5906
- event.preventDefault();
5907
- editor.focus();
5908
- const listItem = query(event.target).closest('li');
5909
- const value = listItem.attr('value');
5910
- if (textNode.length > 0) {
5911
- textNode.text(listItem.text());
6379
+ item = name;
5912
6380
  }
5913
- if (item.menuType === 'color' && value !== '') {
5914
- dropdownNode.attr('color', value);
5915
- this.updateColorAccent(titleNode, value);
6381
+ if (item.type === 'button') {
6382
+ buttonItemList.push(item);
6383
+ this.appendButton(item);
6384
+ return;
5916
6385
  }
5917
- item.onSelect(editor, value);
5918
- });
5919
- editor.event.on('click', target => {
5920
- if (target.closest('.lake-dropdown-title').get(0) === titleNode.get(0)) {
6386
+ if (item.type === 'dropdown') {
6387
+ allMenuMap.set(item.name, Dropdown.getMenuMap(item.menuItems));
6388
+ dropdownItemList.push(item);
6389
+ this.appendDropdown(item);
5921
6390
  return;
5922
6391
  }
5923
- menuNode.hide();
5924
- });
5925
- }
5926
- appendDropdown(item) {
5927
- var _a;
5928
- const menuMap = this.getMenuMap(item);
5929
- const dropdownNode = item.icon ? query(safeTemplate `
5930
- <div class="lake-dropdown">
5931
- <button type="button" class="lake-dropdown-title">
5932
- <div class="lake-dropdown-icon"></div>
5933
- <div class="lake-dropdown-down-icon"></div>
5934
- </button>
5935
- </div>
5936
- `) : query(safeTemplate `
5937
- <div class="lake-dropdown">
5938
- <button type="button" class="lake-dropdown-title">
5939
- <div class="lake-dropdown-text"></div>
5940
- <div class="lake-dropdown-down-icon"></div>
5941
- </button>
5942
- </div>
5943
- `);
5944
- dropdownNode.attr('name', item.name);
5945
- dropdownNode.addClass(`lake-dropdown-${item.menuType}`);
5946
- const titleNode = dropdownNode.find('.lake-dropdown-title');
5947
- if (!item.downIcon) {
5948
- titleNode.addClass('lake-dropdown-title-no-down');
5949
- }
5950
- titleNode.css('width', item.width);
5951
- titleNode.attr('title', item.tooltip);
5952
- const textNode = titleNode.find('.lake-dropdown-text');
5953
- const iconNode = titleNode.find('.lake-dropdown-icon');
5954
- if (item.icon) {
5955
- iconNode.append(item.icon);
5956
- }
5957
- if (item.accentIcon) {
5958
- iconNode.append(item.accentIcon);
5959
- }
5960
- const downIconNode = titleNode.find('.lake-dropdown-down-icon');
5961
- if (item.downIcon) {
5962
- downIconNode.append(item.downIcon);
5963
- }
5964
- const menuNode = query('<ul class="lake-dropdown-menu" />');
5965
- menuNode.addClass(`lake-dropdown-${item.menuType}-menu`);
5966
- if (textNode.length > 0) {
5967
- textNode.text((_a = menuMap.get(item.defaultValue)) !== null && _a !== void 0 ? _a : item.defaultValue);
5968
- }
5969
- if (item.menuType === 'color') {
5970
- this.updateColorAccent(titleNode, item.defaultValue);
5971
- }
5972
- this.addDropdownMenu(menuNode, item);
5973
- dropdownNode.append(titleNode);
5974
- dropdownNode.append(menuNode);
5975
- this.container.append(dropdownNode);
5976
- this.bindDropdownEvents(dropdownNode, item);
5977
- }
5978
- appendUpload(item) {
5979
- const editor = this.editor;
5980
- const uploadNode = query(safeTemplate `
5981
- <div class="lake-upload">
5982
- <input type="file" />
5983
- <button type="button" class="lake-toolbar-button" />
5984
- </div>
5985
- `);
5986
- const fileNode = uploadNode.find('input[type="file"]');
5987
- const fileNativeNode = fileNode.get(0);
5988
- if (item.accept) {
5989
- fileNode.attr('accept', item.accept);
5990
- }
5991
- if (item.multiple === true) {
5992
- fileNode.attr('multiple', 'true');
5993
- }
5994
- const buttonNode = uploadNode.find('button');
5995
- buttonNode.attr('name', item.name);
5996
- buttonNode.attr('title', item.tooltip);
5997
- if (item.icon) {
5998
- buttonNode.append(item.icon);
5999
- }
6000
- this.container.append(uploadNode);
6001
- buttonNode.on('mouseenter', () => {
6002
- buttonNode.addClass('lake-toolbar-button-hovered');
6003
- });
6004
- buttonNode.on('mouseleave', () => {
6005
- buttonNode.removeClass('lake-toolbar-button-hovered');
6006
- });
6007
- buttonNode.on('click', event => {
6008
- event.preventDefault();
6009
- fileNativeNode.click();
6010
- });
6011
- fileNode.on('click', event => event.stopPropagation());
6012
- fileNode.on('change', event => {
6013
- const target = event.target;
6014
- const files = target.files || [];
6015
- for (const file of files) {
6016
- uploadImage({
6017
- editor,
6018
- file,
6019
- });
6392
+ if (item.type === 'upload') {
6393
+ this.appendUpload(item);
6020
6394
  }
6021
6395
  });
6022
- }
6023
- getUpdateStateHandler(config) {
6024
- const { editor, allMenuMap, buttonItemList, dropdownItemList } = config;
6025
- return debounce(() => {
6396
+ editor.event.on('statechange', data => {
6026
6397
  var _a;
6027
- let appliedItems = editor.selection.appliedItems;
6028
- if (appliedItems.length > 0 &&
6029
- appliedItems[0].node.closestContainer().get(0) !== editor.container.get(0)) {
6030
- appliedItems = [];
6031
- }
6398
+ const { appliedItems, disabledNameMap, selectedNameMap, selectedValuesMap } = data;
6032
6399
  for (const item of buttonItemList) {
6033
- const selectedClass = 'lake-toolbar-button-selected';
6400
+ const selectedClass = 'lake-button-selected';
6034
6401
  const buttonNode = this.container.find(`button[name="${item.name}"]`);
6035
- const isDisabled = item.isDisabled && appliedItems.length > 0 ? item.isDisabled(appliedItems, editor) : false;
6402
+ let isDisabled = disabledNameMap.get(item.name);
6403
+ if (isDisabled === undefined) {
6404
+ isDisabled = item.isDisabled && appliedItems.length > 0 ? item.isDisabled(appliedItems) : false;
6405
+ }
6036
6406
  if (isDisabled) {
6037
6407
  buttonNode.attr('disabled', 'true');
6038
6408
  buttonNode.removeClass(selectedClass);
@@ -6041,7 +6411,10 @@ class Toolbar {
6041
6411
  buttonNode.removeAttr('disabled');
6042
6412
  }
6043
6413
  if (!isDisabled) {
6044
- const isSelected = item.isSelected && appliedItems.length > 0 ? item.isSelected(appliedItems, editor) : false;
6414
+ let isSelected = selectedNameMap.get(item.name);
6415
+ if (isSelected === undefined) {
6416
+ isSelected = item.isSelected && appliedItems.length > 0 ? item.isSelected(appliedItems) : false;
6417
+ }
6045
6418
  if (isSelected) {
6046
6419
  buttonNode.addClass(selectedClass);
6047
6420
  }
@@ -6051,9 +6424,15 @@ class Toolbar {
6051
6424
  }
6052
6425
  }
6053
6426
  for (const item of dropdownItemList) {
6054
- const selectedValues = item.selectedValues && appliedItems.length > 0 ? item.selectedValues(appliedItems, editor) : [];
6427
+ let selectedValues = selectedValuesMap.get(item.name);
6428
+ if (selectedValues === undefined) {
6429
+ selectedValues = item.selectedValues && appliedItems.length > 0 ? item.selectedValues(appliedItems) : [];
6430
+ }
6055
6431
  const dropdownNode = this.container.find(`div.lake-dropdown[name="${item.name}"]`);
6056
- const isDisabled = item.isDisabled && appliedItems.length > 0 ? item.isDisabled(appliedItems, editor) : false;
6432
+ let isDisabled = disabledNameMap.get(item.name);
6433
+ if (isDisabled === undefined) {
6434
+ isDisabled = item.isDisabled && appliedItems.length > 0 ? item.isDisabled(appliedItems) : false;
6435
+ }
6057
6436
  if (isDisabled) {
6058
6437
  dropdownNode.attr('disabled', 'true');
6059
6438
  }
@@ -6061,7 +6440,7 @@ class Toolbar {
6061
6440
  dropdownNode.removeAttr('disabled');
6062
6441
  }
6063
6442
  if (!isDisabled) {
6064
- this.setValue(dropdownNode, selectedValues);
6443
+ Dropdown.setValue(dropdownNode, selectedValues);
6065
6444
  const textNode = dropdownNode.find('.lake-dropdown-text');
6066
6445
  if (textNode.length > 0) {
6067
6446
  const key = selectedValues[0] || item.defaultValue;
@@ -6071,59 +6450,7 @@ class Toolbar {
6071
6450
  }
6072
6451
  }
6073
6452
  }
6074
- this.event.emit('updatestate');
6075
- }, 100, {
6076
- leading: false,
6077
- trailing: true,
6078
- maxWait: 100,
6079
- });
6080
- }
6081
- // Renders a toolbar for the specified editor.
6082
- render() {
6083
- const editor = this.editor;
6084
- this.root.empty();
6085
- this.root.append(this.container);
6086
- const allMenuMap = new Map();
6087
- const buttonItemList = [];
6088
- const dropdownItemList = [];
6089
- this.items.forEach(name => {
6090
- if (name === '|') {
6091
- this.appendDivider();
6092
- return;
6093
- }
6094
- let item;
6095
- if (typeof name === 'string') {
6096
- item = toolbarItemMap.get(name);
6097
- if (!item) {
6098
- return;
6099
- }
6100
- }
6101
- else {
6102
- item = name;
6103
- }
6104
- if (item.type === 'button') {
6105
- buttonItemList.push(item);
6106
- this.appendButton(item);
6107
- return;
6108
- }
6109
- if (item.type === 'dropdown') {
6110
- allMenuMap.set(item.name, this.getMenuMap(item));
6111
- dropdownItemList.push(item);
6112
- this.appendDropdown(item);
6113
- return;
6114
- }
6115
- if (item.type === 'upload') {
6116
- this.appendUpload(item);
6117
- }
6118
- });
6119
- const updateStateHandler = this.getUpdateStateHandler({
6120
- editor,
6121
- allMenuMap,
6122
- buttonItemList,
6123
- dropdownItemList,
6124
6453
  });
6125
- editor.event.on('selectionchange', updateStateHandler);
6126
- editor.event.on('change', updateStateHandler);
6127
6454
  }
6128
6455
  }
6129
6456
 
@@ -6136,8 +6463,8 @@ const hrBox = {
6136
6463
  return;
6137
6464
  }
6138
6465
  box.useEffect(() => {
6139
- const root = box.getContainer().find('.lake-hr');
6140
- root.on('click', () => {
6466
+ const hrNode = box.getContainer().find('.lake-hr');
6467
+ hrNode.on('click', () => {
6141
6468
  editor.selection.range.selectBox(box.node);
6142
6469
  });
6143
6470
  });
@@ -6306,10 +6633,10 @@ function openFullScreen(box) {
6306
6633
  arrowPrevSVG: icons.get('left'),
6307
6634
  arrowNextSVG: icons.get('right'),
6308
6635
  closeSVG: icons.get('close'),
6309
- arrowPrevTitle: 'Previous',
6310
- arrowNextTitle: 'Next',
6311
- closeTitle: 'Close (Esc)',
6312
- errorMsg: 'The image cannot be loaded',
6636
+ arrowPrevTitle: locale.image.previous(),
6637
+ arrowNextTitle: locale.image.next(),
6638
+ closeTitle: locale.image.close(),
6639
+ errorMsg: locale.image.loadingError(),
6313
6640
  });
6314
6641
  lightbox.on('uiRegister', () => {
6315
6642
  const pswp = lightbox.pswp;
@@ -6317,7 +6644,7 @@ function openFullScreen(box) {
6317
6644
  name: 'zoom-out-button',
6318
6645
  order: 8,
6319
6646
  isButton: true,
6320
- title: 'Zoom out',
6647
+ title: locale.image.zoomOut(),
6321
6648
  html: icons.get('zoomOut'),
6322
6649
  onClick: () => {
6323
6650
  const currSlide = pswp.currSlide;
@@ -6330,7 +6657,7 @@ function openFullScreen(box) {
6330
6657
  name: 'zoom-in-button',
6331
6658
  order: 9,
6332
6659
  isButton: true,
6333
- title: 'Zoom in',
6660
+ title: locale.image.zoomIn(),
6334
6661
  html: icons.get('zoomIn'),
6335
6662
  onClick: () => {
6336
6663
  const currSlide = pswp.currSlide;
@@ -6375,7 +6702,7 @@ function removeImageBox(box) {
6375
6702
  editor.history.save();
6376
6703
  }
6377
6704
  // Displays error icon and filename.
6378
- function renderError(root, box) {
6705
+ function renderError(imageNode, box) {
6379
6706
  return __awaiter(this, void 0, void 0, function* () {
6380
6707
  const value = box.value;
6381
6708
  box.getContainer().css({
@@ -6384,7 +6711,7 @@ function renderError(root, box) {
6384
6711
  });
6385
6712
  const buttonGroupNode = query(safeTemplate `
6386
6713
  <div class="lake-button-group">
6387
- <button type="button" class="lake-button-remove" title="Delete"></button>
6714
+ <button type="button" tabindex="-1" class="lake-button-remove" title="${locale.image.remove()}"></button>
6388
6715
  </div>
6389
6716
  `);
6390
6717
  const removeButton = buttonGroupNode.find('.lake-button-remove');
@@ -6402,12 +6729,12 @@ function renderError(root, box) {
6402
6729
  if (imageIcon) {
6403
6730
  errorNode.find('.lake-error-icon').append(imageIcon);
6404
6731
  }
6405
- root.append(buttonGroupNode);
6406
- root.append(errorNode);
6732
+ imageNode.append(buttonGroupNode);
6733
+ imageNode.append(errorNode);
6407
6734
  });
6408
6735
  }
6409
6736
  // Displays an image with uplaoding progress.
6410
- function renderUploading(root, box) {
6737
+ function renderUploading(imageNode, box) {
6411
6738
  return __awaiter(this, void 0, void 0, function* () {
6412
6739
  const editor = box.getEditor();
6413
6740
  if (!editor) {
@@ -6416,10 +6743,10 @@ function renderUploading(root, box) {
6416
6743
  const value = box.value;
6417
6744
  const imageInfo = yield getImageInfo(value.url);
6418
6745
  if (!imageInfo.width || !imageInfo.height) {
6419
- yield renderError(root, box);
6746
+ yield renderError(imageNode, box);
6420
6747
  return;
6421
6748
  }
6422
- const maxWidth = editor.innerWidth() - 2;
6749
+ const maxWidth = editor.container.innerWidth() - 2;
6423
6750
  const width = imageInfo.width < maxWidth ? imageInfo.width : maxWidth;
6424
6751
  const height = Math.round(width * imageInfo.height / imageInfo.width);
6425
6752
  box.updateValue({
@@ -6434,7 +6761,7 @@ function renderUploading(root, box) {
6434
6761
  });
6435
6762
  const buttonGroupNode = query(safeTemplate `
6436
6763
  <div class="lake-button-group">
6437
- <button type="button" class="lake-button-remove" title="Delete"></button>
6764
+ <button type="button" tabindex="-1" class="lake-button-remove" title="${locale.image.remove()}"></button>
6438
6765
  </div>
6439
6766
  `);
6440
6767
  const removeButton = buttonGroupNode.find('.lake-button-remove');
@@ -6461,13 +6788,13 @@ function renderUploading(root, box) {
6461
6788
  draggable: 'false',
6462
6789
  alt: value.name,
6463
6790
  });
6464
- root.append(buttonGroupNode);
6465
- root.append(progressNode);
6466
- root.append(imgNode);
6791
+ imageNode.append(buttonGroupNode);
6792
+ imageNode.append(progressNode);
6793
+ imageNode.append(imgNode);
6467
6794
  });
6468
6795
  }
6469
6796
  // Displays an image that can be previewed or removed.
6470
- function renderDone(root, box) {
6797
+ function renderDone(imageNode, box) {
6471
6798
  return __awaiter(this, void 0, void 0, function* () {
6472
6799
  const editor = box.getEditor();
6473
6800
  if (!editor) {
@@ -6476,13 +6803,13 @@ function renderDone(root, box) {
6476
6803
  const value = box.value;
6477
6804
  const imageInfo = yield getImageInfo(value.url);
6478
6805
  if (!imageInfo.width || !imageInfo.height) {
6479
- yield renderError(root, box);
6806
+ yield renderError(imageNode, box);
6480
6807
  return;
6481
6808
  }
6482
6809
  let width = value.width;
6483
6810
  let height = value.height;
6484
6811
  if (!width || !height) {
6485
- const maxWidth = editor.innerWidth() - 2;
6812
+ const maxWidth = editor.container.innerWidth() - 2;
6486
6813
  width = Math.round(imageInfo.width < maxWidth ? imageInfo.width : maxWidth);
6487
6814
  height = Math.round(width * imageInfo.height / imageInfo.width);
6488
6815
  box.updateValue({
@@ -6496,8 +6823,8 @@ function renderDone(root, box) {
6496
6823
  });
6497
6824
  const buttonGroupNode = query(safeTemplate `
6498
6825
  <div class="lake-button-group">
6499
- <button type="button" class="lake-button-view" title="Full screen"></button>
6500
- <button type="button" class="lake-button-remove" title="Delete"></button>
6826
+ <button type="button" tabindex="-1" class="lake-button-view" title="${locale.image.view()}"></button>
6827
+ <button type="button" tabindex="-1" class="lake-button-remove" title="${locale.image.remove()}"></button>
6501
6828
  </div>
6502
6829
  `);
6503
6830
  const viewButton = buttonGroupNode.find('.lake-button-view');
@@ -6505,7 +6832,7 @@ function renderDone(root, box) {
6505
6832
  if (maximizeIcon) {
6506
6833
  viewButton.append(maximizeIcon);
6507
6834
  }
6508
- if (width < 80) {
6835
+ if (width < 80 || PhotoSwipeLightbox === null) {
6509
6836
  viewButton.hide();
6510
6837
  }
6511
6838
  const removeButton = buttonGroupNode.find('.lake-button-remove');
@@ -6532,9 +6859,9 @@ function renderDone(root, box) {
6532
6859
  bindResizerEvents(resizerNode.find('.lake-resizer-top-right'), box);
6533
6860
  bindResizerEvents(resizerNode.find('.lake-resizer-bottom-left'), box);
6534
6861
  bindResizerEvents(resizerNode.find('.lake-resizer-bottom-right'), box);
6535
- root.append(buttonGroupNode);
6536
- root.append(resizerNode);
6537
- root.append(imgNode);
6862
+ imageNode.append(buttonGroupNode);
6863
+ imageNode.append(resizerNode);
6864
+ imageNode.append(imgNode);
6538
6865
  });
6539
6866
  }
6540
6867
  const imageBox = {
@@ -6571,29 +6898,29 @@ const imageBox = {
6571
6898
  if (value.status === 'loading') {
6572
6899
  return;
6573
6900
  }
6574
- const root = query('<div class="lake-image" />');
6575
- root.addClass(`lake-image-${value.status}`);
6901
+ const imageNode = query('<div class="lake-image" />');
6902
+ imageNode.addClass(`lake-image-${value.status}`);
6576
6903
  let promise;
6577
6904
  if (value.status === 'uploading') {
6578
- promise = renderUploading(root, box);
6905
+ promise = renderUploading(imageNode, box);
6579
6906
  }
6580
6907
  else if (value.status === 'error') {
6581
- promise = renderError(root, box);
6908
+ promise = renderError(imageNode, box);
6582
6909
  }
6583
6910
  else {
6584
- promise = renderDone(root, box);
6911
+ promise = renderDone(imageNode, box);
6585
6912
  }
6586
6913
  promise.then(() => {
6587
6914
  container.empty();
6588
- container.append(root);
6589
- root.find('.lake-button-view').on('click', () => openFullScreen(box));
6590
- root.find('.lake-button-remove').on('click', event => {
6915
+ container.append(imageNode);
6916
+ imageNode.find('.lake-button-view').on('click', () => openFullScreen(box));
6917
+ imageNode.find('.lake-button-remove').on('click', event => {
6591
6918
  event.stopPropagation();
6592
6919
  removeImageBox(box);
6593
6920
  });
6594
6921
  box.event.emit('render');
6595
6922
  });
6596
- root.on('click', () => {
6923
+ imageNode.on('click', () => {
6597
6924
  editor.selection.range.selectBox(box.node);
6598
6925
  });
6599
6926
  },
@@ -6603,23 +6930,50 @@ const imageBox = {
6603
6930
  },
6604
6931
  };
6605
6932
 
6606
- function CodeMirror(config) {
6607
- const updateListener = (update) => {
6608
- if (!update.docChanged) {
6609
- return;
6610
- }
6611
- config.onChange(update.state.doc.toString());
6612
- };
6613
- return new EditorView({
6614
- doc: config.value,
6615
- extensions: [
6616
- basicSetup,
6617
- keymap.of([indentWithTab]),
6618
- javascript(),
6619
- EditorView.updateListener.of(updateListener),
6620
- ],
6621
- parent: config.parent,
6622
- });
6933
+ const config = {
6934
+ defaultLang: 'text',
6935
+ background: '#0000000a',
6936
+ foreground: '#444d56',
6937
+ selection: '#1ba2e333',
6938
+ cursor: '#044289',
6939
+ keyword: '#cf222e',
6940
+ variable: '#1f2328',
6941
+ parameter: '#24292e',
6942
+ function: '#005cc5',
6943
+ string: '#0a3069',
6944
+ constant: '#0550ae',
6945
+ type: '#24292f',
6946
+ class: '#24292e',
6947
+ number: '#0550ae',
6948
+ comment: '#57606a',
6949
+ heading: '#0550ae',
6950
+ invalid: '#f6f8fa',
6951
+ regexp: '#116329',
6952
+ };
6953
+ function getHighlightStyle(CodeMirror) {
6954
+ const { HighlightStyle, tags } = CodeMirror;
6955
+ return HighlightStyle.define([
6956
+ { tag: tags.keyword, color: config.keyword },
6957
+ { tag: [tags.name, tags.deleted, tags.character, tags.macroName], color: config.variable },
6958
+ { tag: [tags.propertyName], color: config.function },
6959
+ { tag: [tags.processingInstruction, tags.string, tags.inserted, tags.special(tags.string)], color: config.string },
6960
+ { tag: [tags.function(tags.variableName), tags.labelName], color: config.function },
6961
+ { tag: [tags.color, tags.constant(tags.name), tags.standard(tags.name)], color: config.constant },
6962
+ { tag: [tags.definition(tags.name), tags.separator], color: config.variable },
6963
+ { tag: [tags.className], color: config.class },
6964
+ { tag: [tags.number, tags.changed, tags.annotation, tags.modifier, tags.self, tags.namespace], color: config.number },
6965
+ { tag: [tags.typeName], color: config.type },
6966
+ { tag: [tags.operator, tags.operatorKeyword], color: config.keyword },
6967
+ { tag: [tags.url, tags.escape, tags.regexp, tags.link], color: config.regexp },
6968
+ { tag: [tags.meta, tags.comment], color: config.comment },
6969
+ { tag: tags.strong, fontWeight: 'bold' },
6970
+ { tag: tags.emphasis, fontStyle: 'italic' },
6971
+ { tag: tags.link, textDecoration: 'underline' },
6972
+ { tag: tags.heading, fontWeight: 'bold', color: config.heading },
6973
+ { tag: [tags.atom, tags.bool, tags.special(tags.variableName)], color: config.variable },
6974
+ { tag: tags.invalid, color: config.invalid },
6975
+ { tag: tags.strikethrough, textDecoration: 'line-through' },
6976
+ ]);
6623
6977
  }
6624
6978
  const codeBlockBox = {
6625
6979
  type: 'block',
@@ -6630,17 +6984,34 @@ const codeBlockBox = {
6630
6984
  if (!editor) {
6631
6985
  return;
6632
6986
  }
6633
- const width = editor.innerWidth() - 2;
6634
- const root = query('<div class="lake-code-block" />');
6635
- root.css('width', `${width}px`);
6987
+ const codeBlockNode = query('<div class="lake-code-block" />');
6636
6988
  const container = box.getContainer();
6637
6989
  container.empty();
6638
- container.append(root);
6639
- const parent = root.get(0);
6640
- if (!parent) {
6990
+ container.append(codeBlockNode);
6991
+ const codeBlockNativeNode = codeBlockNode.get(0);
6992
+ if (!codeBlockNativeNode) {
6993
+ return;
6994
+ }
6995
+ // begin to create CodeMirror
6996
+ const CodeMirror = window.CodeMirror;
6997
+ if (!CodeMirror) {
6998
+ codeBlockNode.addClass('lake-code-block-error');
6999
+ codeBlockNode.text('The code cannot be displayed because window.CodeMirror is not found. Please check if the CodeMirror file is added to this page.');
7000
+ codeBlockNode.on('click', () => {
7001
+ editor.selection.range.selectBox(box.node);
7002
+ });
6641
7003
  return;
6642
7004
  }
6643
- const onChangeHandler = (value) => {
7005
+ const { EditorState, Compartment, EditorView, keymap, history, defaultKeymap, historyKeymap, indentWithTab, syntaxHighlighting, langItems, } = CodeMirror;
7006
+ // language menu items
7007
+ const langItemMap = new Map();
7008
+ for (const item of langItems) {
7009
+ langItemMap.set(item.value, item);
7010
+ }
7011
+ const boxValue = box.value;
7012
+ const langItem = langItemMap.get(boxValue.lang);
7013
+ const language = new Compartment();
7014
+ const changeHandler = (value) => {
6644
7015
  // Here setTimeout is necessary because isComposing is not false after ending composition.
6645
7016
  window.setTimeout(() => {
6646
7017
  if (editor.isComposing) {
@@ -6650,12 +7021,58 @@ const codeBlockBox = {
6650
7021
  editor.history.save();
6651
7022
  }, 0);
6652
7023
  };
6653
- const codeEditor = CodeMirror({
6654
- parent: root.get(0),
6655
- value: (_a = box.value.code) !== null && _a !== void 0 ? _a : '',
6656
- onChange: onChangeHandler,
7024
+ const updateListener = EditorView.updateListener.of((update) => {
7025
+ if (!update.docChanged) {
7026
+ return;
7027
+ }
7028
+ changeHandler(update.state.doc.toString());
7029
+ });
7030
+ const codeEditor = new EditorView({
7031
+ parent: codeBlockNativeNode,
7032
+ doc: (_a = boxValue.code) !== null && _a !== void 0 ? _a : '',
7033
+ extensions: [
7034
+ EditorState.readOnly.of(editor.readonly),
7035
+ history(),
7036
+ keymap.of([
7037
+ ...defaultKeymap,
7038
+ ...historyKeymap,
7039
+ indentWithTab,
7040
+ ]),
7041
+ syntaxHighlighting(getHighlightStyle(CodeMirror)),
7042
+ language.of(langItem && langItem.component ? langItem.component() : []),
7043
+ updateListener,
7044
+ ],
7045
+ });
7046
+ codeBlockNode.find('[contenteditable="true"]').attr('tabindex', '-1');
7047
+ const dropdown = new Dropdown({
7048
+ root: codeBlockNode,
7049
+ name: 'langType',
7050
+ downIcon: icons.get('down'),
7051
+ defaultValue: langItem ? boxValue.lang : config.defaultLang,
7052
+ tooltip: locale.codeBlock.langType(),
7053
+ width: 'auto',
7054
+ menuType: 'list',
7055
+ menuItems: langItems.map((item) => ({
7056
+ value: item.value,
7057
+ text: item.text,
7058
+ })),
7059
+ onSelect: value => {
7060
+ const item = langItemMap.get(value);
7061
+ codeEditor.dispatch({
7062
+ effects: language.reconfigure(item && item.component ? item.component() : []),
7063
+ });
7064
+ box.updateValue({
7065
+ lang: value,
7066
+ });
7067
+ editor.history.save();
7068
+ },
6657
7069
  });
7070
+ dropdown.render();
6658
7071
  box.setData('codeEditor', codeEditor);
7072
+ box.useEffect(() => () => {
7073
+ codeEditor.destroy();
7074
+ debug('CodeMirror destroyed');
7075
+ });
6659
7076
  },
6660
7077
  };
6661
7078
 
@@ -6910,8 +7327,10 @@ var paste = (editor) => {
6910
7327
  };
6911
7328
 
6912
7329
  var undo = (editor) => {
6913
- editor.command.add('undo', () => {
6914
- editor.history.undo();
7330
+ editor.command.add('undo', {
7331
+ execute: () => {
7332
+ editor.history.undo();
7333
+ },
6915
7334
  });
6916
7335
  editor.keystroke.setKeydown('mod+z', event => {
6917
7336
  const range = editor.selection.range;
@@ -6924,38 +7343,53 @@ var undo = (editor) => {
6924
7343
  };
6925
7344
 
6926
7345
  var redo = (editor) => {
6927
- editor.command.add('redo', () => {
6928
- editor.history.redo();
7346
+ editor.command.add('redo', {
7347
+ execute: () => {
7348
+ editor.history.redo();
7349
+ },
6929
7350
  });
6930
- editor.keystroke.setKeydown('mod+y', event => {
7351
+ const redoHandler = (event) => {
6931
7352
  const range = editor.selection.range;
6932
7353
  if (range.isInsideBox) {
6933
7354
  return;
6934
7355
  }
6935
7356
  event.preventDefault();
6936
7357
  editor.command.execute('redo');
6937
- });
7358
+ };
7359
+ editor.keystroke.setKeydown('mod+y', redoHandler);
7360
+ editor.keystroke.setKeydown('mod+shift+z', redoHandler);
6938
7361
  };
6939
7362
 
6940
7363
  var selectAll = (editor) => {
6941
- editor.command.add('selectAll', () => {
6942
- const range = editor.selection.range;
6943
- range.selectNodeContents(editor.container);
6944
- range.shrink();
7364
+ editor.command.add('selectAll', {
7365
+ execute: () => {
7366
+ const range = editor.selection.range;
7367
+ range.selectNodeContents(editor.container);
7368
+ range.shrink();
7369
+ },
6945
7370
  });
6946
7371
  };
6947
7372
 
6948
7373
  var heading = (editor) => {
6949
- editor.command.add('heading', (type) => {
6950
- editor.selection.setBlocks(`<${type} />`);
6951
- editor.history.save();
7374
+ editor.command.add('heading', {
7375
+ selectedValues: appliedItems => {
7376
+ const currentItem = appliedItems.find(item => item.node.isHeading || item.name === 'p');
7377
+ return currentItem ? [currentItem.name] : [];
7378
+ },
7379
+ execute: (type) => {
7380
+ editor.selection.setBlocks(`<${type} />`);
7381
+ editor.history.save();
7382
+ },
6952
7383
  });
6953
7384
  };
6954
7385
 
6955
7386
  var blockQuote = (editor) => {
6956
- editor.command.add('blockQuote', () => {
6957
- editor.selection.setBlocks('<blockquote />');
6958
- editor.history.save();
7387
+ editor.command.add('blockQuote', {
7388
+ isSelected: appliedItems => !!appliedItems.find(item => item.name === 'blockquote'),
7389
+ execute: () => {
7390
+ editor.selection.setBlocks('<blockquote />');
7391
+ editor.history.save();
7392
+ },
6959
7393
  });
6960
7394
  };
6961
7395
 
@@ -6972,73 +7406,90 @@ function setChecklist(editor, value) {
6972
7406
  editor.selection.setBlocks(`<ul type="checklist"><li value="${value}"></li></ul>`);
6973
7407
  }
6974
7408
  var list = (editor) => {
6975
- editor.command.add('list', (type, value = false) => {
6976
- const blocks = editor.selection.range.getBlocks();
6977
- let isNumberedList = false;
6978
- let isBulletedList = false;
6979
- let isChecklist = false;
6980
- for (const block of blocks) {
6981
- if (!isNumberedList && block.name === 'ol') {
6982
- isNumberedList = true;
6983
- }
6984
- if (!isBulletedList && block.name === 'ul' && !block.hasAttr('type')) {
6985
- isBulletedList = true;
6986
- }
6987
- if (!isChecklist && block.name === 'ul' && block.attr('type') === 'checklist') {
6988
- isChecklist = true;
7409
+ editor.command.add('list', {
7410
+ selectedValues: appliedItems => {
7411
+ let currentValue;
7412
+ for (const item of appliedItems) {
7413
+ if (item.name === 'ol') {
7414
+ currentValue = 'numbered';
7415
+ break;
7416
+ }
7417
+ if (item.name === 'ul' && !item.node.hasAttr('type')) {
7418
+ currentValue = 'bulleted';
7419
+ break;
7420
+ }
7421
+ if (item.name === 'ul' && item.node.attr('type') === 'checklist') {
7422
+ currentValue = 'checklist';
7423
+ break;
7424
+ }
6989
7425
  }
6990
- }
6991
- if (isNumberedList) {
6992
- if (type === 'numbered') {
6993
- setParagraph(editor);
7426
+ return currentValue ? [currentValue] : [];
7427
+ },
7428
+ execute: (type, value = false) => {
7429
+ const blocks = editor.selection.range.getBlocks();
7430
+ let isNumberedList = false;
7431
+ let isBulletedList = false;
7432
+ let isChecklist = false;
7433
+ for (const block of blocks) {
7434
+ if (!isNumberedList && block.name === 'ol') {
7435
+ isNumberedList = true;
7436
+ }
7437
+ if (!isBulletedList && block.name === 'ul' && !block.hasAttr('type')) {
7438
+ isBulletedList = true;
7439
+ }
7440
+ if (!isChecklist && block.name === 'ul' && block.attr('type') === 'checklist') {
7441
+ isChecklist = true;
7442
+ }
6994
7443
  }
6995
- if (type === 'bulleted') {
6996
- setBulletedList(editor);
7444
+ if (isNumberedList) {
7445
+ if (type === 'numbered') {
7446
+ setParagraph(editor);
7447
+ }
7448
+ if (type === 'bulleted') {
7449
+ setBulletedList(editor);
7450
+ }
7451
+ if (type === 'checklist') {
7452
+ setChecklist(editor, value);
7453
+ }
6997
7454
  }
6998
- if (type === 'checklist') {
6999
- setChecklist(editor, value);
7455
+ else if (isBulletedList) {
7456
+ if (type === 'numbered') {
7457
+ setNumberedList(editor);
7458
+ }
7459
+ if (type === 'bulleted') {
7460
+ setParagraph(editor);
7461
+ }
7462
+ if (type === 'checklist') {
7463
+ setChecklist(editor, value);
7464
+ }
7000
7465
  }
7001
- }
7002
- else if (isBulletedList) {
7003
- if (type === 'numbered') {
7004
- setNumberedList(editor);
7005
- }
7006
- if (type === 'bulleted') {
7007
- setParagraph(editor);
7008
- }
7009
- if (type === 'checklist') {
7010
- setChecklist(editor, value);
7011
- }
7012
- }
7013
- else if (isChecklist) {
7014
- if (type === 'numbered') {
7015
- setNumberedList(editor);
7016
- }
7017
- if (type === 'bulleted') {
7018
- setBulletedList(editor);
7019
- }
7020
- if (type === 'checklist') {
7021
- setParagraph(editor);
7022
- }
7023
- }
7024
- else {
7025
- if (type === 'numbered') {
7026
- setNumberedList(editor);
7027
- }
7028
- if (type === 'bulleted') {
7029
- setBulletedList(editor);
7466
+ else if (isChecklist) {
7467
+ if (type === 'numbered') {
7468
+ setNumberedList(editor);
7469
+ }
7470
+ if (type === 'bulleted') {
7471
+ setBulletedList(editor);
7472
+ }
7473
+ if (type === 'checklist') {
7474
+ setParagraph(editor);
7475
+ }
7030
7476
  }
7031
- if (type === 'checklist') {
7032
- setChecklist(editor, value);
7477
+ else {
7478
+ if (type === 'numbered') {
7479
+ setNumberedList(editor);
7480
+ }
7481
+ if (type === 'bulleted') {
7482
+ setBulletedList(editor);
7483
+ }
7484
+ if (type === 'checklist') {
7485
+ setChecklist(editor, value);
7486
+ }
7033
7487
  }
7034
- }
7035
- editor.history.save();
7488
+ editor.history.save();
7489
+ },
7036
7490
  });
7037
7491
  editor.container.on('click', event => {
7038
7492
  const mouseEvent = event;
7039
- if (editor.readonly) {
7040
- return;
7041
- }
7042
7493
  if (!mouseEvent.target) {
7043
7494
  return;
7044
7495
  }
@@ -7050,36 +7501,60 @@ var list = (editor) => {
7050
7501
  });
7051
7502
  };
7052
7503
 
7504
+ const alignValueMap = {
7505
+ start: 'left',
7506
+ end: 'right',
7507
+ };
7053
7508
  var align = (editor) => {
7054
- editor.command.add('align', (type) => {
7055
- editor.selection.setBlocks({
7056
- 'text-align': type,
7057
- });
7058
- editor.history.save();
7509
+ editor.command.add('align', {
7510
+ selectedValues: appliedItems => {
7511
+ let currentValue;
7512
+ for (const item of appliedItems) {
7513
+ if (item.node.isBlock) {
7514
+ currentValue = item.node.computedCSS('text-align');
7515
+ break;
7516
+ }
7517
+ }
7518
+ if (!currentValue) {
7519
+ return [];
7520
+ }
7521
+ return [alignValueMap[currentValue] || currentValue];
7522
+ },
7523
+ execute: (type) => {
7524
+ editor.selection.setBlocks({
7525
+ 'text-align': type,
7526
+ });
7527
+ editor.history.save();
7528
+ },
7059
7529
  });
7060
7530
  };
7061
7531
 
7062
7532
  var indent = (editor) => {
7063
- editor.command.add('indent', (type) => {
7064
- const blocks = editor.selection.range.getBlocks();
7065
- for (const block of blocks) {
7066
- setBlockIndent(block, type);
7067
- }
7068
- editor.history.save();
7533
+ editor.command.add('indent', {
7534
+ execute: (type) => {
7535
+ const blocks = editor.selection.range.getBlocks();
7536
+ for (const block of blocks) {
7537
+ setBlockIndent(block, type);
7538
+ }
7539
+ editor.history.save();
7540
+ },
7069
7541
  });
7070
7542
  };
7071
7543
 
7072
7544
  const tagName$6 = 'strong';
7073
7545
  var bold = (editor) => {
7074
- editor.command.add('bold', () => {
7075
- const appliedItems = editor.selection.getAppliedItems();
7076
- if (appliedItems.find(item => item.name === tagName$6)) {
7077
- editor.selection.removeMark(`<${tagName$6} />`);
7078
- }
7079
- else {
7080
- editor.selection.addMark(`<${tagName$6} />`);
7081
- }
7082
- editor.history.save();
7546
+ editor.command.add('bold', {
7547
+ isDisabled: appliedItems => !!appliedItems.find(item => item.node.isHeading),
7548
+ isSelected: appliedItems => !!appliedItems.find(item => item.name === tagName$6),
7549
+ execute: () => {
7550
+ if (editor.command.isSelected('bold')) {
7551
+ editor.selection.removeMark(`<${tagName$6} />`);
7552
+ }
7553
+ else {
7554
+ editor.selection.addMark(`<${tagName$6} />`);
7555
+ }
7556
+ editor.history.save();
7557
+ },
7083
7558
  });
7084
7559
  editor.keystroke.setKeydown('mod+b', event => {
7085
7560
  event.preventDefault();
@@ -7089,15 +7564,17 @@ var bold = (editor) => {
7089
7564
 
7090
7565
  const tagName$5 = 'i';
7091
7566
  var italic = (editor) => {
7092
- editor.command.add('italic', () => {
7093
- const appliedItems = editor.selection.getAppliedItems();
7094
- if (appliedItems.find(item => item.name === tagName$5)) {
7095
- editor.selection.removeMark(`<${tagName$5} />`);
7096
- }
7097
- else {
7098
- editor.selection.addMark(`<${tagName$5} />`);
7099
- }
7100
- editor.history.save();
7567
+ editor.command.add('italic', {
7568
+ isSelected: appliedItems => !!appliedItems.find(item => item.name === tagName$5),
7569
+ execute: () => {
7570
+ if (editor.command.isSelected('italic')) {
7571
+ editor.selection.removeMark(`<${tagName$5} />`);
7572
+ }
7573
+ else {
7574
+ editor.selection.addMark(`<${tagName$5} />`);
7575
+ }
7576
+ editor.history.save();
7577
+ },
7101
7578
  });
7102
7579
  editor.keystroke.setKeydown('mod+i', event => {
7103
7580
  event.preventDefault();
@@ -7107,15 +7584,17 @@ var italic = (editor) => {
7107
7584
 
7108
7585
  const tagName$4 = 'u';
7109
7586
  var underline = (editor) => {
7110
- editor.command.add('underline', () => {
7111
- const appliedItems = editor.selection.getAppliedItems();
7112
- if (appliedItems.find(item => item.name === tagName$4)) {
7113
- editor.selection.removeMark(`<${tagName$4} />`);
7114
- }
7115
- else {
7116
- editor.selection.addMark(`<${tagName$4} />`);
7117
- }
7118
- editor.history.save();
7587
+ editor.command.add('underline', {
7588
+ isSelected: appliedItems => !!appliedItems.find(item => item.name === tagName$4),
7589
+ execute: () => {
7590
+ if (editor.command.isSelected('underline')) {
7591
+ editor.selection.removeMark(`<${tagName$4} />`);
7592
+ }
7593
+ else {
7594
+ editor.selection.addMark(`<${tagName$4} />`);
7595
+ }
7596
+ editor.history.save();
7597
+ },
7119
7598
  });
7120
7599
  editor.keystroke.setKeydown('mod+u', event => {
7121
7600
  event.preventDefault();
@@ -7125,15 +7604,17 @@ var underline = (editor) => {
7125
7604
 
7126
7605
  const tagName$3 = 's';
7127
7606
  var strikethrough = (editor) => {
7128
- editor.command.add('strikethrough', () => {
7129
- const appliedItems = editor.selection.getAppliedItems();
7130
- if (appliedItems.find(item => item.name === tagName$3)) {
7131
- editor.selection.removeMark(`<${tagName$3} />`);
7132
- }
7133
- else {
7134
- editor.selection.addMark(`<${tagName$3} />`);
7135
- }
7136
- editor.history.save();
7607
+ editor.command.add('strikethrough', {
7608
+ isSelected: appliedItems => !!appliedItems.find(item => item.name === tagName$3),
7609
+ execute: () => {
7610
+ if (editor.command.isSelected('strikethrough')) {
7611
+ editor.selection.removeMark(`<${tagName$3} />`);
7612
+ }
7613
+ else {
7614
+ editor.selection.addMark(`<${tagName$3} />`);
7615
+ }
7616
+ editor.history.save();
7617
+ },
7137
7618
  });
7138
7619
  editor.keystroke.setKeydown('mod+shift+x', event => {
7139
7620
  event.preventDefault();
@@ -7143,93 +7624,148 @@ var strikethrough = (editor) => {
7143
7624
 
7144
7625
  const tagName$2 = 'sub';
7145
7626
  var subscript = (editor) => {
7146
- editor.command.add('subscript', () => {
7147
- const appliedItems = editor.selection.getAppliedItems();
7148
- if (appliedItems.find(item => item.name === tagName$2)) {
7149
- editor.selection.removeMark(`<${tagName$2} />`);
7150
- }
7151
- else {
7152
- editor.selection.addMark(`<${tagName$2} />`);
7153
- }
7154
- editor.history.save();
7627
+ editor.command.add('subscript', {
7628
+ isSelected: appliedItems => !!appliedItems.find(item => item.name === tagName$2),
7629
+ execute: () => {
7630
+ if (editor.command.isSelected('subscript')) {
7631
+ editor.selection.removeMark(`<${tagName$2} />`);
7632
+ }
7633
+ else {
7634
+ editor.selection.addMark(`<${tagName$2} />`);
7635
+ }
7636
+ editor.history.save();
7637
+ },
7155
7638
  });
7156
7639
  };
7157
7640
 
7158
7641
  const tagName$1 = 'sup';
7159
7642
  var superscript = (editor) => {
7160
- editor.command.add('superscript', () => {
7161
- const appliedItems = editor.selection.getAppliedItems();
7162
- if (appliedItems.find(item => item.name === tagName$1)) {
7163
- editor.selection.removeMark(`<${tagName$1} />`);
7164
- }
7165
- else {
7166
- editor.selection.addMark(`<${tagName$1} />`);
7167
- }
7168
- editor.history.save();
7643
+ editor.command.add('superscript', {
7644
+ isSelected: appliedItems => !!appliedItems.find(item => item.name === tagName$1),
7645
+ execute: () => {
7646
+ if (editor.command.isSelected('superscript')) {
7647
+ editor.selection.removeMark(`<${tagName$1} />`);
7648
+ }
7649
+ else {
7650
+ editor.selection.addMark(`<${tagName$1} />`);
7651
+ }
7652
+ editor.history.save();
7653
+ },
7169
7654
  });
7170
7655
  };
7171
7656
 
7172
7657
  const tagName = 'code';
7173
7658
  var code = (editor) => {
7174
- editor.command.add('code', () => {
7175
- const appliedItems = editor.selection.getAppliedItems();
7176
- if (appliedItems.find(item => item.name === tagName)) {
7177
- editor.selection.removeMark(`<${tagName} />`);
7178
- }
7179
- else {
7180
- editor.selection.addMark(`<${tagName} />`);
7181
- }
7182
- editor.history.save();
7659
+ editor.command.add('code', {
7660
+ isSelected: appliedItems => !!appliedItems.find(item => item.name === tagName),
7661
+ execute: () => {
7662
+ if (editor.command.isSelected('code')) {
7663
+ editor.selection.removeMark(`<${tagName} />`);
7664
+ }
7665
+ else {
7666
+ editor.selection.addMark(`<${tagName} />`);
7667
+ }
7668
+ editor.history.save();
7669
+ },
7183
7670
  });
7184
7671
  };
7185
7672
 
7186
7673
  var fontFamily = (editor) => {
7187
- editor.command.add('fontFamily', (value) => {
7188
- editor.selection.addMark(`<span style="font-family: ${value};" />`);
7189
- editor.history.save();
7674
+ editor.command.add('fontFamily', {
7675
+ selectedValues: appliedItems => {
7676
+ for (const item of appliedItems) {
7677
+ if (item.name === 'span') {
7678
+ const currentValue = item.node.css('font-family');
7679
+ return [currentValue.replace(/['"]/g, '')];
7680
+ }
7681
+ }
7682
+ return [];
7683
+ },
7684
+ execute: (value) => {
7685
+ editor.selection.addMark(`<span style="font-family: ${value};" />`);
7686
+ editor.history.save();
7687
+ },
7190
7688
  });
7191
7689
  };
7192
7690
 
7193
7691
  var fontSize = (editor) => {
7194
- editor.command.add('fontSize', (value) => {
7195
- editor.selection.addMark(`<span style="font-size: ${value};" />`);
7196
- editor.history.save();
7692
+ editor.command.add('fontSize', {
7693
+ isDisabled: appliedItems => !!appliedItems.find(item => item.node.isHeading),
7694
+ selectedValues: appliedItems => {
7695
+ for (const item of appliedItems) {
7696
+ if (item.name === 'span') {
7697
+ const currentValue = item.node.css('font-size');
7698
+ return [currentValue.replace(/\.\d+/, '')];
7699
+ }
7700
+ }
7701
+ return [];
7702
+ },
7703
+ execute: (value) => {
7704
+ editor.selection.addMark(`<span style="font-size: ${value};" />`);
7705
+ editor.history.save();
7706
+ },
7197
7707
  });
7198
7708
  };
7199
7709
 
7200
7710
  var fontColor = (editor) => {
7201
- editor.command.add('fontColor', (value) => {
7202
- editor.selection.addMark(`<span style="color: ${value};" />`);
7203
- editor.history.save();
7711
+ editor.command.add('fontColor', {
7712
+ selectedValues: appliedItems => {
7713
+ for (const item of appliedItems) {
7714
+ if (item.name === 'span') {
7715
+ const currentValue = item.node.computedCSS('color');
7716
+ return [toHex(currentValue)];
7717
+ }
7718
+ }
7719
+ return [];
7720
+ },
7721
+ execute: (value) => {
7722
+ editor.selection.addMark(`<span style="color: ${value};" />`);
7723
+ editor.history.save();
7724
+ },
7204
7725
  });
7205
7726
  };
7206
7727
 
7207
7728
  var highlight = (editor) => {
7208
- editor.command.add('highlight', (value) => {
7209
- editor.selection.addMark(`<span style="background-color: ${value};" />`);
7210
- editor.history.save();
7729
+ editor.command.add('highlight', {
7730
+ selectedValues: appliedItems => {
7731
+ for (const item of appliedItems) {
7732
+ if (item.name === 'span') {
7733
+ const currentValue = item.node.computedCSS('background-color');
7734
+ return [toHex(currentValue)];
7735
+ }
7736
+ }
7737
+ return [];
7738
+ },
7739
+ execute: (value) => {
7740
+ editor.selection.addMark(`<span style="background-color: ${value};" />`);
7741
+ editor.history.save();
7742
+ },
7211
7743
  });
7212
7744
  };
7213
7745
 
7214
7746
  var removeFormat = (editor) => {
7215
- editor.command.add('removeFormat', () => {
7216
- editor.selection.removeMark();
7217
- editor.history.save();
7747
+ editor.command.add('removeFormat', {
7748
+ execute: () => {
7749
+ editor.selection.removeMark();
7750
+ editor.history.save();
7751
+ },
7218
7752
  });
7219
7753
  };
7220
7754
 
7221
7755
  let markList = [];
7222
7756
  const formatPainterClassName = 'lake-format-painter';
7223
7757
  var formatPainter = (editor) => {
7224
- editor.command.add('formatPainter', () => {
7225
- editor.container.addClass(formatPainterClassName);
7226
- const appliedItems = editor.selection.getAppliedItems();
7227
- for (const item of appliedItems) {
7228
- const node = item.node.clone();
7229
- if (node.isMark && node.name !== 'a') {
7230
- markList.push(node);
7758
+ editor.command.add('formatPainter', {
7759
+ execute: () => {
7760
+ editor.container.addClass(formatPainterClassName);
7761
+ const appliedItems = editor.selection.getAppliedItems();
7762
+ for (const item of appliedItems) {
7763
+ const node = item.node.clone();
7764
+ if (node.isMark && node.name !== 'a') {
7765
+ markList.push(node);
7766
+ }
7231
7767
  }
7232
- }
7768
+ },
7233
7769
  });
7234
7770
  editor.container.on('click', () => {
7235
7771
  editor.container.removeClass(formatPainterClassName);
@@ -7246,8 +7782,8 @@ var formatPainter = (editor) => {
7246
7782
  if (tagetNode.isInside) {
7247
7783
  return;
7248
7784
  }
7249
- const buttonNode = tagetNode.closest('.lake-toolbar-button');
7250
- if (buttonNode.length > 0 && buttonNode.attr('name') === 'formatPainter') {
7785
+ const buttonNode = tagetNode.closest('button[name="formatPainter"]');
7786
+ if (buttonNode.length > 0) {
7251
7787
  return;
7252
7788
  }
7253
7789
  editor.container.removeClass(formatPainterClassName);
@@ -7256,123 +7792,147 @@ var formatPainter = (editor) => {
7256
7792
  };
7257
7793
 
7258
7794
  class LinkPopup {
7259
- constructor(target) {
7795
+ constructor(root) {
7260
7796
  this.linkNode = null;
7261
7797
  this.event = new EventEmitter();
7262
- this.root = query(safeTemplate `
7798
+ this.root = root;
7799
+ this.container = query(safeTemplate `
7263
7800
  <div class="lake-link-popup">
7264
- <div class="lake-row">URL</div>
7801
+ <div class="lake-row">${locale.link.url()}</div>
7265
7802
  <div class="lake-row lake-url-row">
7266
7803
  <input type="text" name="url" />
7267
- <button type="button" class="lake-button-copy" title="Copy link to clipboard"></button>
7268
- <button type="button" class="lake-button-open" title="Open link in new tab"></button>
7269
7804
  </div>
7270
- <div class="lake-row">Link title</div>
7805
+ <div class="lake-row">${locale.link.title()}</div>
7271
7806
  <div class="lake-row">
7272
7807
  <input type="text" name="title" />
7273
7808
  </div>
7274
- <div class="lake-row">
7275
- <button type="button" class="lake-button-save"><span>Save</span></button>
7276
- <button type="button" class="lake-button-unlink"><span>Remove link</span></button>
7277
- </div>
7809
+ <div class="lake-row lake-button-row"></div>
7278
7810
  </div>
7279
7811
  `);
7280
- const openIcon = icons.get('open');
7281
- if (openIcon) {
7282
- this.root.find('.lake-button-open').append(openIcon);
7283
- }
7284
- const copyButton = this.root.find('.lake-button-copy');
7285
- const copyIcon = icons.get('copy');
7286
- if (copyIcon) {
7287
- copyButton.append(copyIcon);
7288
- }
7289
- const copyDoneIcon = icons.get('checkCircle');
7290
- if (copyDoneIcon) {
7291
- copyButton.append(copyDoneIcon);
7292
- }
7293
- const copyErrorIcon = icons.get('warningCircle');
7294
- if (copyErrorIcon) {
7295
- copyButton.append(copyErrorIcon);
7296
- }
7297
- const saveIcon = icons.get('check');
7298
- if (saveIcon) {
7299
- this.root.find('.lake-button-save').prepend(saveIcon);
7300
- }
7301
- const unlinkIcon = icons.get('unlink');
7302
- if (unlinkIcon) {
7303
- this.root.find('.lake-button-unlink').prepend(unlinkIcon);
7304
- }
7305
- target.append(this.root);
7306
- this.bindEvents();
7307
7812
  }
7308
- writeClipboardText(text, errorCallback) {
7813
+ // Writes the specified text to the system clipboard
7814
+ writeClipboardText(text) {
7309
7815
  return __awaiter(this, void 0, void 0, function* () {
7816
+ let error = false;
7310
7817
  try {
7311
- yield navigator.clipboard.writeText(text);
7818
+ if (window.LAKE_TEST) {
7819
+ error = window.LAKE_ERROR;
7820
+ }
7821
+ else {
7822
+ yield navigator.clipboard.writeText(text);
7823
+ }
7312
7824
  }
7313
7825
  catch (_a) {
7314
- errorCallback();
7826
+ error = true;
7315
7827
  }
7828
+ return new Promise(resolve => {
7829
+ resolve(error);
7830
+ });
7316
7831
  });
7317
7832
  }
7318
- bindEvents() {
7319
- // Copy link to clipboard
7833
+ // Copy link to clipboard
7834
+ appendCopyButton() {
7320
7835
  let timeoutId = null;
7321
- this.root.find('.lake-button-copy').on('click', () => {
7322
- if (!this.linkNode) {
7323
- return;
7324
- }
7325
- const url = this.getInputValue('url');
7326
- this.writeClipboardText(url, () => {
7327
- const svgNode = this.root.find('.lake-button-copy svg');
7328
- svgNode.hide();
7329
- svgNode.eq(2).show('inline');
7330
- });
7331
- const svgNode = this.root.find('.lake-button-copy svg');
7332
- svgNode.hide();
7333
- svgNode.eq(1).show('inline');
7334
- if (timeoutId) {
7335
- window.clearTimeout(timeoutId);
7336
- }
7337
- timeoutId = window.setTimeout(() => {
7338
- svgNode.hide();
7339
- svgNode.eq(0).show('inline');
7340
- }, 2000);
7836
+ const button = new Button({
7837
+ root: this.container.find('.lake-url-row'),
7838
+ name: 'copy',
7839
+ icon: icons.get('copy'),
7840
+ tooltip: locale.link.copy(),
7841
+ onClick: () => {
7842
+ if (!this.linkNode) {
7843
+ return;
7844
+ }
7845
+ const url = this.getInputValue('url');
7846
+ this.writeClipboardText(url).then((error) => {
7847
+ const svgNode = this.container.find('button[name="copy"] svg');
7848
+ svgNode.hide();
7849
+ if (error) {
7850
+ svgNode.eq(2).show('inline');
7851
+ this.event.emit('copy', error);
7852
+ return;
7853
+ }
7854
+ svgNode.eq(1).show('inline');
7855
+ this.event.emit('copy', error);
7856
+ if (timeoutId) {
7857
+ window.clearTimeout(timeoutId);
7858
+ }
7859
+ timeoutId = window.setTimeout(() => {
7860
+ svgNode.hide();
7861
+ svgNode.eq(0).show('inline');
7862
+ }, 2000);
7863
+ });
7864
+ },
7341
7865
  });
7342
- // Open link in new tab
7343
- this.root.find('.lake-button-open').on('click', () => {
7344
- if (!this.linkNode) {
7345
- return;
7346
- }
7347
- const url = this.getInputValue('url');
7348
- window.open(url);
7866
+ button.render();
7867
+ const copyDoneIcon = icons.get('checkCircle');
7868
+ if (copyDoneIcon) {
7869
+ button.node.append(copyDoneIcon);
7870
+ }
7871
+ const copyErrorIcon = icons.get('warningCircle');
7872
+ if (copyErrorIcon) {
7873
+ button.node.append(copyErrorIcon);
7874
+ }
7875
+ }
7876
+ // Open link in new tab
7877
+ appendOpenButton() {
7878
+ const button = new Button({
7879
+ root: this.container.find('.lake-url-row'),
7880
+ name: 'open',
7881
+ icon: icons.get('open'),
7882
+ tooltip: locale.link.open(),
7883
+ onClick: () => {
7884
+ if (!this.linkNode) {
7885
+ return;
7886
+ }
7887
+ const url = this.getInputValue('url');
7888
+ window.open(url);
7889
+ },
7349
7890
  });
7350
- // Save link
7351
- this.root.find('.lake-button-save').on('click', () => {
7352
- if (!this.linkNode) {
7353
- return;
7354
- }
7355
- this.save();
7356
- this.hide();
7357
- this.event.emit('save');
7891
+ button.render();
7892
+ }
7893
+ // Save link
7894
+ appendSaveButton() {
7895
+ const button = new Button({
7896
+ root: this.container.find('.lake-button-row'),
7897
+ name: 'save',
7898
+ icon: icons.get('check'),
7899
+ text: locale.link.save(),
7900
+ onClick: () => {
7901
+ if (!this.linkNode) {
7902
+ return;
7903
+ }
7904
+ this.save();
7905
+ this.hide();
7906
+ this.event.emit('save');
7907
+ },
7358
7908
  });
7359
- // Remove link
7360
- this.root.find('.lake-button-unlink').on('click', () => {
7361
- if (!this.linkNode) {
7362
- return;
7363
- }
7364
- this.linkNode.remove(true);
7365
- this.hide();
7366
- this.event.emit('remove');
7909
+ button.render();
7910
+ }
7911
+ // Remove link
7912
+ appendUnlinkButton() {
7913
+ const button = new Button({
7914
+ root: this.container.find('.lake-button-row'),
7915
+ name: 'unlink',
7916
+ icon: icons.get('unlink'),
7917
+ text: locale.link.unlink(),
7918
+ onClick: () => {
7919
+ if (!this.linkNode) {
7920
+ return;
7921
+ }
7922
+ this.linkNode.remove(true);
7923
+ this.hide();
7924
+ this.event.emit('remove');
7925
+ },
7367
7926
  });
7927
+ button.render();
7368
7928
  }
7369
7929
  getInputValue(name) {
7370
- const inputElement = this.root.find(`input[name="${name}"]`);
7930
+ const inputElement = this.container.find(`input[name="${name}"]`);
7371
7931
  const nativeInputElement = inputElement.get(0);
7372
7932
  return nativeInputElement.value;
7373
7933
  }
7374
7934
  setInputValue(name, value) {
7375
- const inputElement = this.root.find(`input[name="${name}"]`);
7935
+ const inputElement = this.container.find(`input[name="${name}"]`);
7376
7936
  const nativeInputElement = inputElement.get(0);
7377
7937
  nativeInputElement.value = value;
7378
7938
  }
@@ -7382,8 +7942,12 @@ class LinkPopup {
7382
7942
  }
7383
7943
  const url = this.getInputValue('url');
7384
7944
  let title = this.getInputValue('title');
7945
+ if (url === '' && title === '') {
7946
+ this.linkNode.remove();
7947
+ return;
7948
+ }
7385
7949
  if (title === '') {
7386
- title = 'Link';
7950
+ title = url;
7387
7951
  }
7388
7952
  this.linkNode.attr('href', url);
7389
7953
  this.linkNode.text(title);
@@ -7402,90 +7966,93 @@ class LinkPopup {
7402
7966
  return;
7403
7967
  }
7404
7968
  // link.x + popup.width > window.width
7405
- if (linkRect.x + this.root.width() > window.innerWidth) {
7969
+ if (linkRect.x + this.container.width() > window.innerWidth) {
7406
7970
  // link.x + window.scrollX - (popup.width - link.width)
7407
- this.root.css('left', `${linkX - this.root.width() + linkRect.width}px`);
7971
+ this.container.css('left', `${linkX - this.container.width() + linkRect.width}px`);
7408
7972
  }
7409
7973
  else {
7410
- this.root.css('left', `${linkX}px`);
7974
+ this.container.css('left', `${linkX}px`);
7411
7975
  }
7412
7976
  // link.y + link.height + popup.height > window.height
7413
- if (linkRect.y + linkRect.height + this.root.height() > window.innerHeight) {
7977
+ if (linkRect.y + linkRect.height + this.container.height() > window.innerHeight) {
7414
7978
  // link.y + window.scrollY - popup.height
7415
- this.root.css('top', `${linkY - this.root.height()}px`);
7979
+ this.container.css('top', `${linkY - this.container.height()}px`);
7416
7980
  }
7417
7981
  else {
7418
- this.root.css('top', `${linkY + linkRect.height}px`);
7982
+ this.container.css('top', `${linkY + linkRect.height}px`);
7419
7983
  }
7420
7984
  }
7985
+ render() {
7986
+ this.appendCopyButton();
7987
+ this.appendOpenButton();
7988
+ this.appendSaveButton();
7989
+ this.appendUnlinkButton();
7990
+ this.root.append(this.container);
7991
+ }
7421
7992
  show(linkNode) {
7993
+ if (this.root.find('.lake-link-popup').length === 0) {
7994
+ this.render();
7995
+ }
7996
+ if (this.linkNode && this.linkNode.get(0) === linkNode.get(0)) {
7997
+ return;
7998
+ }
7422
7999
  this.linkNode = linkNode;
7423
8000
  const url = linkNode.attr('href');
7424
8001
  const title = linkNode.text();
7425
8002
  this.setInputValue('url', url);
7426
- this.setInputValue('title', title);
7427
- this.root.css('visibility', 'hidden');
7428
- this.root.show();
8003
+ if (title !== url) {
8004
+ this.setInputValue('title', title);
8005
+ }
8006
+ this.container.css('visibility', 'hidden');
8007
+ this.container.show();
7429
8008
  this.updatePosition();
7430
- this.root.css('visibility', '');
8009
+ this.container.css('visibility', '');
8010
+ this.container.find('input[name="url"]').focus();
7431
8011
  }
7432
8012
  hide() {
7433
8013
  this.linkNode = null;
7434
- this.root.hide();
8014
+ this.container.hide();
7435
8015
  }
7436
8016
  }
7437
8017
 
7438
8018
  var link = (editor) => {
7439
- let popup;
7440
- const showPopup = (lineNode) => {
7441
- if (popup) {
7442
- popup.show(lineNode);
7443
- return;
7444
- }
7445
- popup = new LinkPopup(editor.popupContainer);
7446
- popup.event.on('save', () => {
7447
- editor.history.save();
7448
- });
7449
- popup.event.on('remove', () => {
7450
- editor.history.save();
7451
- });
7452
- popup.show(lineNode);
7453
- };
8019
+ const popup = new LinkPopup(editor.popupContainer);
8020
+ popup.event.on('save', () => {
8021
+ editor.history.save();
8022
+ });
8023
+ popup.event.on('remove', () => {
8024
+ editor.history.save();
8025
+ });
7454
8026
  editor.root.on('scroll', () => {
7455
- if (!popup) {
7456
- return;
7457
- }
7458
8027
  popup.updatePosition();
7459
8028
  });
7460
8029
  editor.event.on('resize', () => {
7461
- if (!popup) {
7462
- return;
7463
- }
7464
8030
  popup.updatePosition();
7465
8031
  });
7466
8032
  editor.event.on('click', (targetNode) => {
7467
- if (targetNode.isOutside) {
7468
- return;
7469
- }
7470
- if (targetNode.closest('lake-box').length > 0) {
8033
+ if (targetNode.closest('button[name="link"]').length > 0) {
7471
8034
  return;
7472
8035
  }
7473
8036
  const linkNode = targetNode.closest('a');
7474
8037
  if (linkNode.length === 0) {
7475
- if (popup) {
7476
- popup.hide();
7477
- }
8038
+ popup.hide();
7478
8039
  return;
7479
8040
  }
7480
- showPopup(linkNode);
7481
- });
7482
- editor.command.add('link', () => {
7483
- const linkNode = editor.selection.insertLink('<a href="">New link</a>');
7484
- if (!linkNode) {
8041
+ if (linkNode.isOutside ||
8042
+ linkNode.closest('lake-box').length > 0) {
7485
8043
  return;
7486
8044
  }
7487
- editor.history.save();
7488
- showPopup(linkNode);
8045
+ popup.show(linkNode);
8046
+ });
8047
+ editor.command.add('link', {
8048
+ execute: () => {
8049
+ const linkNode = editor.selection.insertLink(`<a href="">${locale.link.newLink()}</a>`);
8050
+ if (!linkNode) {
8051
+ return;
8052
+ }
8053
+ editor.history.save();
8054
+ popup.show(linkNode);
8055
+ },
7489
8056
  });
7490
8057
  };
7491
8058
 
@@ -7498,9 +8065,11 @@ var hr = (editor) => {
7498
8065
  node.replaceWith(box.node);
7499
8066
  });
7500
8067
  });
7501
- editor.command.add('hr', () => {
7502
- editor.insertBox('hr');
7503
- editor.history.save();
8068
+ editor.command.add('hr', {
8069
+ execute: () => {
8070
+ editor.insertBox('hr');
8071
+ editor.history.save();
8072
+ },
7504
8073
  });
7505
8074
  };
7506
8075
 
@@ -7523,21 +8092,314 @@ var image = (editor) => {
7523
8092
  node.replaceWith(box.node);
7524
8093
  });
7525
8094
  });
7526
- editor.command.add('image', (value) => {
7527
- editor.insertBox('image', value);
7528
- editor.history.save();
8095
+ editor.command.add('image', {
8096
+ execute: (value) => {
8097
+ editor.insertBox('image', value);
8098
+ editor.history.save();
8099
+ },
8100
+ });
8101
+ };
8102
+
8103
+ var codeBlock = (editor) => {
8104
+ editor.command.add('codeBlock', {
8105
+ execute: (value) => {
8106
+ const box = editor.insertBox('codeBlock', value);
8107
+ editor.history.save();
8108
+ const codeEditor = box.getData('codeEditor');
8109
+ codeEditor.focus();
8110
+ },
8111
+ });
8112
+ };
8113
+
8114
+ const headingTypeMap = new Map([
8115
+ ['#', 'h1'],
8116
+ ['##', 'h2'],
8117
+ ['###', 'h3'],
8118
+ ['####', 'h4'],
8119
+ ['#####', 'h5'],
8120
+ ['######', 'h6'],
8121
+ ]);
8122
+ const markItemList = [
8123
+ {
8124
+ re: /\*\*(.+?)\*\*$/,
8125
+ getParameters: () => [
8126
+ 'bold',
8127
+ ],
8128
+ },
8129
+ {
8130
+ re: /__(.+?)__$/,
8131
+ getParameters: () => [
8132
+ 'bold',
8133
+ ],
8134
+ },
8135
+ {
8136
+ re: /_(.+?)_$/,
8137
+ getParameters: () => [
8138
+ 'italic',
8139
+ ],
8140
+ },
8141
+ {
8142
+ re: /\*(.+?)\*$/,
8143
+ getParameters: () => [
8144
+ 'italic',
8145
+ ],
8146
+ },
8147
+ {
8148
+ re: /==(.+?)==$/,
8149
+ getParameters: () => [
8150
+ 'highlight',
8151
+ '#fff566', // yellow-4, from https://ant.design/docs/spec/colors
8152
+ ],
8153
+ },
8154
+ {
8155
+ re: /~~(.+?)~~$/,
8156
+ getParameters: () => [
8157
+ 'strikethrough',
8158
+ ],
8159
+ },
8160
+ {
8161
+ re: /`(.+?)`$/,
8162
+ getParameters: () => [
8163
+ 'code',
8164
+ ],
8165
+ },
8166
+ ];
8167
+ const blockItemListForSpaceKey = [
8168
+ {
8169
+ re: /^#+$/,
8170
+ getParameters: (results) => {
8171
+ var _a;
8172
+ return [
8173
+ 'heading',
8174
+ (_a = headingTypeMap.get(results[0])) !== null && _a !== void 0 ? _a : 'h6',
8175
+ ];
8176
+ },
8177
+ },
8178
+ {
8179
+ re: /^\d+\.$/,
8180
+ getParameters: () => [
8181
+ 'list',
8182
+ 'numbered',
8183
+ ],
8184
+ },
8185
+ {
8186
+ re: /^[*\-+]$/,
8187
+ getParameters: () => [
8188
+ 'list',
8189
+ 'bulleted',
8190
+ ],
8191
+ },
8192
+ {
8193
+ re: /^\[\s?\]$/,
8194
+ getParameters: () => [
8195
+ 'list',
8196
+ 'checklist',
8197
+ false,
8198
+ ],
8199
+ },
8200
+ {
8201
+ re: /^\[x\]$/i,
8202
+ getParameters: () => [
8203
+ 'list',
8204
+ 'checklist',
8205
+ true,
8206
+ ],
8207
+ },
8208
+ {
8209
+ re: /^>$/,
8210
+ getParameters: () => [
8211
+ 'blockQuote',
8212
+ ],
8213
+ },
8214
+ ];
8215
+ const blockItemListForEnterKey = [
8216
+ {
8217
+ re: /^-+$/,
8218
+ getParameters: () => [
8219
+ 'hr',
8220
+ ],
8221
+ },
8222
+ {
8223
+ re: /^`+([a-z]*)$/i,
8224
+ getParameters: (results) => {
8225
+ if (!results[1]) {
8226
+ return [
8227
+ 'codeBlock',
8228
+ ];
8229
+ }
8230
+ return [
8231
+ 'codeBlock',
8232
+ {
8233
+ lang: results[1],
8234
+ },
8235
+ ];
8236
+ },
8237
+ },
8238
+ ];
8239
+ function getMarkdownPoint(editor) {
8240
+ const selection = editor.selection;
8241
+ const range = selection.range;
8242
+ let node = range.startNode;
8243
+ let offset = range.startOffset;
8244
+ if (offset === 0) {
8245
+ return;
8246
+ }
8247
+ if (node.isElement) {
8248
+ const child = node.children()[offset - 1];
8249
+ if (!child || !child.isText) {
8250
+ return;
8251
+ }
8252
+ node = child;
8253
+ offset = node.text().length;
8254
+ }
8255
+ if (offset < 1) {
8256
+ return;
8257
+ }
8258
+ return {
8259
+ node,
8260
+ offset,
8261
+ };
8262
+ }
8263
+ // case 1: <p></p> to <p><br /></p>
8264
+ // case 2: <p><focus /></p> to <p><br /><focus /></p>
8265
+ function fixEmptyBlock(block) {
8266
+ const newBlock = block.clone(true);
8267
+ newBlock.find('lake-bookmark').remove();
8268
+ if (newBlock.html() !== '') {
8269
+ return;
8270
+ }
8271
+ block.prepend('<br />');
8272
+ }
8273
+ function executeMarkCommand(editor, point) {
8274
+ const selection = editor.selection;
8275
+ const range = selection.range;
8276
+ const offset = point.offset;
8277
+ const text = point.node.text().slice(0, offset);
8278
+ for (const item of markItemList) {
8279
+ const results = item.re.exec(text);
8280
+ if (results !== null) {
8281
+ // <p>foo**bold**<focus /></p>, offset = 11
8282
+ // to
8283
+ // <p>foobold\u200B<focus /></p>,
8284
+ // to
8285
+ // <p>foo[bold]\u200B<focus /></p>, startOffset = 3, endOffset = 7
8286
+ editor.prepareOperation();
8287
+ const bookmark = selection.insertBookmark();
8288
+ const node = bookmark.focus.prev();
8289
+ const oldValue = node.text();
8290
+ const newValue = `${oldValue.replace(item.re, '$1')}\u200B`;
8291
+ node.get(0).nodeValue = newValue;
8292
+ range.setStart(node, offset - results[0].length);
8293
+ range.setEnd(node, offset - (oldValue.length - newValue.length) - 1);
8294
+ const parameters = item.getParameters();
8295
+ editor.command.execute(parameters.shift(), ...parameters);
8296
+ selection.toBookmark(bookmark);
8297
+ editor.commitOperation();
8298
+ return true;
8299
+ }
8300
+ }
8301
+ return false;
8302
+ }
8303
+ function spaceKeyExecutesBlockCommand(editor, point) {
8304
+ const selection = editor.selection;
8305
+ const offset = point.offset;
8306
+ let text = point.node.text().slice(0, offset);
8307
+ text = text.replace(/[\u200B\u2060]/g, '');
8308
+ for (const item of blockItemListForSpaceKey) {
8309
+ const results = item.re.exec(text);
8310
+ if (results !== null) {
8311
+ // <p>#<focus />foo</p>
8312
+ // to
8313
+ // <h1><focus />foo</h1>
8314
+ editor.prepareOperation();
8315
+ const bookmark = selection.insertBookmark();
8316
+ const node = bookmark.focus.prev();
8317
+ node.remove();
8318
+ const block = bookmark.focus.closestBlock();
8319
+ fixEmptyBlock(block);
8320
+ selection.range.shrinkAfter(block);
8321
+ const parameters = item.getParameters(results);
8322
+ editor.command.execute(parameters.shift(), ...parameters);
8323
+ selection.toBookmark(bookmark);
8324
+ editor.commitOperation();
8325
+ return true;
8326
+ }
8327
+ }
8328
+ return false;
8329
+ }
8330
+ function enterKeyExecutesBlockCommand(editor, block) {
8331
+ const selection = editor.selection;
8332
+ let text = block.text();
8333
+ text = text.replace(/[\u200B\u2060]/g, '');
8334
+ for (const item of blockItemListForEnterKey) {
8335
+ const results = item.re.exec(text);
8336
+ if (results !== null) {
8337
+ // <p>---<focus /></p>
8338
+ // to
8339
+ // <lake-box type="block" name="hr" focus="right"></lake-box>
8340
+ editor.prepareOperation();
8341
+ block.empty();
8342
+ fixEmptyBlock(block);
8343
+ selection.range.shrinkAfter(block);
8344
+ const parameters = item.getParameters(results);
8345
+ editor.command.execute(parameters.shift(), ...parameters);
8346
+ editor.commitOperation();
8347
+ return true;
8348
+ }
8349
+ }
8350
+ return false;
8351
+ }
8352
+ var markdown = (editor) => {
8353
+ editor.keystroke.setKeydown('space', event => {
8354
+ const selection = editor.selection;
8355
+ const range = selection.range;
8356
+ if (range.isBox) {
8357
+ return;
8358
+ }
8359
+ const point = getMarkdownPoint(editor);
8360
+ if (!point) {
8361
+ return;
8362
+ }
8363
+ if (executeMarkCommand(editor, point)) {
8364
+ event.preventDefault();
8365
+ return;
8366
+ }
8367
+ const block = range.getBlocks()[0];
8368
+ if (!block) {
8369
+ return;
8370
+ }
8371
+ if (!(block.isHeading || block.name === 'p')) {
8372
+ return;
8373
+ }
8374
+ if (spaceKeyExecutesBlockCommand(editor, point)) {
8375
+ event.preventDefault();
8376
+ }
7529
8377
  });
7530
- };
7531
-
7532
- var codeBlock = (editor) => {
7533
- editor.command.add('codeBlock', () => {
7534
- const box = editor.insertBox('codeBlock');
7535
- if (!box) {
8378
+ editor.keystroke.setKeydown('enter', event => {
8379
+ const selection = editor.selection;
8380
+ const range = selection.range;
8381
+ if (range.isBox) {
7536
8382
  return;
7537
8383
  }
7538
- editor.history.save();
7539
- const codeEditor = box.getData('codeEditor');
7540
- codeEditor.focus();
8384
+ const block = range.getBlocks()[0];
8385
+ if (!block) {
8386
+ return;
8387
+ }
8388
+ if (!(block.isHeading || block.name === 'p')) {
8389
+ return;
8390
+ }
8391
+ if (block.find('lake-box').length > 0) {
8392
+ return;
8393
+ }
8394
+ if (range.getRightText() !== '') {
8395
+ return;
8396
+ }
8397
+ if (enterKeyExecutesBlockCommand(editor, block)) {
8398
+ event.preventDefault();
8399
+ event.stopImmediatePropagation();
8400
+ // returning false is for unit test
8401
+ return false;
8402
+ }
7541
8403
  });
7542
8404
  };
7543
8405
 
@@ -7598,6 +8460,7 @@ var enterKey = (editor) => {
7598
8460
  return;
7599
8461
  }
7600
8462
  event.preventDefault();
8463
+ editor.rectifyContent();
7601
8464
  if (range.isBox) {
7602
8465
  addBlockOrSplitBlockForBox(editor);
7603
8466
  editor.history.save();
@@ -7639,7 +8502,7 @@ function addLineBreak(editor) {
7639
8502
  return;
7640
8503
  }
7641
8504
  }
7642
- editor.selection.insertContents('<br />');
8505
+ editor.selection.insertNode(query('<br />'));
7643
8506
  }
7644
8507
  function addBlockOrLineBreakForBox(editor) {
7645
8508
  const range = editor.selection.range;
@@ -7679,6 +8542,7 @@ var shiftEnterKey = (editor) => {
7679
8542
  if (range.isInsideBox) {
7680
8543
  return;
7681
8544
  }
8545
+ editor.rectifyContent();
7682
8546
  event.preventDefault();
7683
8547
  if (range.isBox) {
7684
8548
  addBlockOrLineBreakForBox(editor);
@@ -7740,6 +8604,7 @@ var backspaceKey = (editor) => {
7740
8604
  if (range.isInsideBox) {
7741
8605
  return;
7742
8606
  }
8607
+ editor.rectifyContent();
7743
8608
  if (range.isBoxLeft) {
7744
8609
  const boxNode = range.startNode.closest('lake-box');
7745
8610
  const prevNode = boxNode.prev();
@@ -7790,6 +8655,14 @@ var backspaceKey = (editor) => {
7790
8655
  editor.history.save();
7791
8656
  return;
7792
8657
  }
8658
+ if (prevNode.name === 'br' && prevNode.prev().length > 0) {
8659
+ event.preventDefault();
8660
+ range.setStartBefore(prevNode);
8661
+ range.collapseToStart();
8662
+ prevNode.remove();
8663
+ editor.history.save();
8664
+ return;
8665
+ }
7793
8666
  const leftText = range.getLeftText();
7794
8667
  if (leftText === '') {
7795
8668
  event.preventDefault();
@@ -7812,14 +8685,6 @@ var backspaceKey = (editor) => {
7812
8685
  }
7813
8686
  mergeWithPreviousBlock(editor, block);
7814
8687
  editor.history.save();
7815
- return;
7816
- }
7817
- if (prevNode.name === 'br') {
7818
- event.preventDefault();
7819
- range.setStartBefore(prevNode);
7820
- range.collapseToStart();
7821
- prevNode.remove();
7822
- editor.history.save();
7823
8688
  }
7824
8689
  });
7825
8690
  };
@@ -7856,6 +8721,7 @@ var deleteKey = (editor) => {
7856
8721
  if (range.isInsideBox) {
7857
8722
  return;
7858
8723
  }
8724
+ editor.rectifyContent();
7859
8725
  if (range.isBoxRight) {
7860
8726
  const boxNode = range.startNode.closest('lake-box');
7861
8727
  const nextNode = boxNode.next();
@@ -7906,6 +8772,13 @@ var deleteKey = (editor) => {
7906
8772
  editor.history.save();
7907
8773
  return;
7908
8774
  }
8775
+ if (nextNode.name === 'br' && nextNode.next().length > 0) {
8776
+ event.preventDefault();
8777
+ range.setStartBefore(nextNode);
8778
+ range.collapseToStart();
8779
+ nextNode.remove();
8780
+ editor.history.save();
8781
+ }
7909
8782
  const rightText = range.getRightText();
7910
8783
  if (rightText === '') {
7911
8784
  event.preventDefault();
@@ -7916,20 +8789,15 @@ var deleteKey = (editor) => {
7916
8789
  }
7917
8790
  mergeWithNextBlock(editor, block);
7918
8791
  editor.history.save();
7919
- return;
7920
- }
7921
- if (nextNode.name === 'br') {
7922
- event.preventDefault();
7923
- range.setStartBefore(nextNode);
7924
- range.collapseToStart();
7925
- nextNode.remove();
7926
- editor.history.save();
7927
8792
  }
7928
8793
  });
7929
8794
  };
7930
8795
 
7931
8796
  var tabKey = (editor) => {
7932
8797
  editor.keystroke.setKeydown('tab', event => {
8798
+ if (editor.config.indentWithTab === false) {
8799
+ return;
8800
+ }
7933
8801
  event.preventDefault();
7934
8802
  const blocks = editor.selection.range.getBlocks();
7935
8803
  blocks.forEach(block => {
@@ -8064,218 +8932,6 @@ var arrowKeys = (editor) => {
8064
8932
  });
8065
8933
  };
8066
8934
 
8067
- const headingTypeMap = new Map([
8068
- ['#', 'h1'],
8069
- ['##', 'h2'],
8070
- ['###', 'h3'],
8071
- ['####', 'h4'],
8072
- ['#####', 'h5'],
8073
- ['######', 'h6'],
8074
- ]);
8075
- const markItemList = [
8076
- {
8077
- re: /\*\*(.+?)\*\*$/,
8078
- getParameters: () => [
8079
- 'bold',
8080
- ],
8081
- },
8082
- {
8083
- re: /__(.+?)__$/,
8084
- getParameters: () => [
8085
- 'bold',
8086
- ],
8087
- },
8088
- {
8089
- re: /_(.+?)_$/,
8090
- getParameters: () => [
8091
- 'italic',
8092
- ],
8093
- },
8094
- {
8095
- re: /\*(.+?)\*$/,
8096
- getParameters: () => [
8097
- 'italic',
8098
- ],
8099
- },
8100
- {
8101
- re: /==(.+?)==$/,
8102
- getParameters: () => [
8103
- 'highlight',
8104
- '#fff566', // yellow-4, from https://ant.design/docs/spec/colors
8105
- ],
8106
- },
8107
- {
8108
- re: /~~(.+?)~~$/,
8109
- getParameters: () => [
8110
- 'strikethrough',
8111
- ],
8112
- },
8113
- {
8114
- re: /`(.+?)`$/,
8115
- getParameters: () => [
8116
- 'code',
8117
- ],
8118
- },
8119
- ];
8120
- const blockItemList = [
8121
- {
8122
- re: /^#+$/,
8123
- getParameters: (text) => {
8124
- var _a;
8125
- return [
8126
- 'heading',
8127
- (_a = headingTypeMap.get(text)) !== null && _a !== void 0 ? _a : 'h6',
8128
- ];
8129
- },
8130
- },
8131
- {
8132
- re: /^\d+\.$/,
8133
- getParameters: () => [
8134
- 'list',
8135
- 'numbered',
8136
- ],
8137
- },
8138
- {
8139
- re: /^[*\-+]$/,
8140
- getParameters: () => [
8141
- 'list',
8142
- 'bulleted',
8143
- ],
8144
- },
8145
- {
8146
- re: /^\[\s?\]$/,
8147
- getParameters: () => [
8148
- 'list',
8149
- 'checklist',
8150
- false,
8151
- ],
8152
- },
8153
- {
8154
- re: /^\[x\]$/i,
8155
- getParameters: () => [
8156
- 'list',
8157
- 'checklist',
8158
- true,
8159
- ],
8160
- },
8161
- {
8162
- re: /^>$/,
8163
- getParameters: () => [
8164
- 'blockQuote',
8165
- ],
8166
- },
8167
- ];
8168
- function getMarkdownPoint(editor) {
8169
- const selection = editor.selection;
8170
- const range = selection.range;
8171
- let node = range.startNode;
8172
- let offset = range.startOffset;
8173
- if (offset === 0) {
8174
- return;
8175
- }
8176
- if (node.isElement) {
8177
- const child = node.children()[offset - 1];
8178
- if (!child || !child.isText) {
8179
- return;
8180
- }
8181
- node = child;
8182
- offset = node.text().length;
8183
- }
8184
- if (offset < 1) {
8185
- return;
8186
- }
8187
- return {
8188
- node,
8189
- offset,
8190
- };
8191
- }
8192
- // case 1: <p></p> to <p><br /></p>
8193
- // case 2: <p><focus /></p> to <p><br /><focus /></p>
8194
- function fixEmptyBlock(block) {
8195
- const newBlock = block.clone(true);
8196
- newBlock.find('lake-bookmark').remove();
8197
- if (newBlock.html() !== '') {
8198
- return;
8199
- }
8200
- block.prepend('<br />');
8201
- }
8202
- function executeMarkCommand(editor, point) {
8203
- const selection = editor.selection;
8204
- const range = selection.range;
8205
- const offset = point.offset;
8206
- const text = point.node.text().slice(0, offset);
8207
- for (const item of markItemList) {
8208
- const result = item.re.exec(text);
8209
- if (result !== null) {
8210
- // <p>foo**bold**<focus /></p>, offset = 11
8211
- // to
8212
- // <p>foobold\u200B<focus /></p>,
8213
- // to
8214
- // <p>foo[bold]\u200B<focus /></p>, startOffset = 3, endOffset = 7
8215
- editor.prepareOperation();
8216
- const bookmark = selection.insertBookmark();
8217
- const node = bookmark.focus.prev();
8218
- const oldValue = node.text();
8219
- const newValue = `${oldValue.replace(item.re, '$1')}\u200B`;
8220
- node.get(0).nodeValue = newValue;
8221
- range.setStart(node, offset - result[0].length);
8222
- range.setEnd(node, offset - (oldValue.length - newValue.length) - 1);
8223
- const parameters = item.getParameters();
8224
- editor.command.execute(parameters.shift(), ...parameters);
8225
- selection.toBookmark(bookmark);
8226
- editor.commitOperation();
8227
- return true;
8228
- }
8229
- }
8230
- return false;
8231
- }
8232
- function executeBlockCommand(editor, point) {
8233
- const selection = editor.selection;
8234
- const offset = point.offset;
8235
- let text = point.node.text().slice(0, offset);
8236
- text = text.replace(/[\u200B\u2060]/g, '');
8237
- for (const item of blockItemList) {
8238
- if (item.re.test(text)) {
8239
- // <p>#<focus />foo</p>
8240
- // to
8241
- // <h1><focus />foo</h1>
8242
- editor.prepareOperation();
8243
- const bookmark = selection.insertBookmark();
8244
- const node = bookmark.focus.prev();
8245
- node.remove();
8246
- const block = bookmark.focus.closestBlock();
8247
- fixEmptyBlock(block);
8248
- selection.range.shrinkAfter(block);
8249
- const parameters = item.getParameters(text);
8250
- editor.command.execute(parameters.shift(), ...parameters);
8251
- selection.toBookmark(bookmark);
8252
- editor.commitOperation();
8253
- return true;
8254
- }
8255
- }
8256
- return false;
8257
- }
8258
- var markdown = (editor) => {
8259
- editor.keystroke.setKeydown('space', event => {
8260
- const selection = editor.selection;
8261
- const point = getMarkdownPoint(editor);
8262
- if (!point) {
8263
- return;
8264
- }
8265
- if (executeMarkCommand(editor, point)) {
8266
- event.preventDefault();
8267
- return;
8268
- }
8269
- const block = selection.range.getBlocks()[0];
8270
- if (block && !(block.isHeading || block.name === 'p')) {
8271
- return;
8272
- }
8273
- if (executeBlockCommand(editor, point)) {
8274
- event.preventDefault();
8275
- }
8276
- });
8277
- };
8278
-
8279
8935
  Editor.box.add(hrBox);
8280
8936
  Editor.box.add(imageBox);
8281
8937
  Editor.box.add(codeBlockBox);
@@ -8307,12 +8963,13 @@ Editor.plugin.add(link);
8307
8963
  Editor.plugin.add(hr);
8308
8964
  Editor.plugin.add(image);
8309
8965
  Editor.plugin.add(codeBlock);
8966
+ Editor.plugin.add(markdown);
8310
8967
  Editor.plugin.add(enterKey);
8311
8968
  Editor.plugin.add(shiftEnterKey);
8312
8969
  Editor.plugin.add(backspaceKey);
8313
8970
  Editor.plugin.add(deleteKey);
8314
8971
  Editor.plugin.add(tabKey);
8315
8972
  Editor.plugin.add(arrowKeys);
8316
- Editor.plugin.add(markdown);
8317
8973
 
8318
- export { Box, Editor, Fragment, HTMLParser, Nodes, Range, TextParser, Toolbar, index as Utils, addMark, deleteContents, fixList, icons, insertBookmark, insertContents, insertFragment, insertLink, insertNode, removeMark, setBlocks, splitBlock$1 as splitBlock, splitMarks, toBookmark };
8974
+ export { Box, Button, Dropdown, Editor, Fragment, HTMLParser, Nodes, Range, TextParser, Toolbar, index as Utils, addMark, deleteContents, fixList, icons, insertBookmark, insertContents, insertFragment, insertLink, insertNode, removeMark, setBlocks, splitBlock$1 as splitBlock, splitMarks, toBookmark };
8975
+ //# sourceMappingURL=lake.js.map