lakelib 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/lake.js CHANGED
@@ -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 = "lake-lib";
3995
- var description = "Rich text editor based on the browser";
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
+
3996
4294
  var version = "0.0.2";
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
- };
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');
@@ -5731,306 +6273,136 @@ class Toolbar {
5731
6273
  this.items = config.items || defaultItems;
5732
6274
  this.editor = config.editor;
5733
6275
  this.root = query(config.root);
5734
- this.event = new EventEmitter();
5735
- }
5736
- // Returns the value of the node.
5737
- getValue(node) {
5738
- const value = node.attr('value');
5739
- if (value === '') {
5740
- return [];
5741
- }
5742
- return JSON.parse(Base64.decode(value));
5743
- }
5744
- // Updates the value of the node.
5745
- setValue(node, value) {
5746
- node.attr('value', Base64.encode(JSON.stringify(value)));
6276
+ this.container = query('<div class="lake-toolbar" />');
6277
+ this.root.addClass('lake-custom-properties');
5747
6278
  }
5748
6279
  appendDivider() {
5749
- this.root.append('<div class="lake-toolbar-divider" />');
6280
+ this.container.append('<div class="lake-toolbar-divider" />');
5750
6281
  }
5751
6282
  appendButton(item) {
5752
6283
  const editor = this.editor;
5753
- const buttonNode = query('<button type="button" class="lake-toolbar-button" />');
5754
- buttonNode.attr('name', item.name);
5755
- buttonNode.attr('title', item.tooltip);
5756
- if (item.icon) {
5757
- buttonNode.append(item.icon);
5758
- }
5759
- this.root.append(buttonNode);
5760
- buttonNode.on('mouseenter', () => {
5761
- if (buttonNode.attr('disabled')) {
5762
- return;
5763
- }
5764
- buttonNode.addClass('lake-toolbar-button-hovered');
5765
- });
5766
- buttonNode.on('mouseleave', () => {
5767
- if (buttonNode.attr('disabled')) {
5768
- return;
5769
- }
5770
- buttonNode.removeClass('lake-toolbar-button-hovered');
5771
- });
5772
- buttonNode.on('click', event => {
5773
- event.preventDefault();
5774
- editor.focus();
5775
- 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
+ },
5776
6294
  });
6295
+ button.render();
5777
6296
  }
5778
- getMenuMap(item) {
5779
- const menuMap = new Map();
5780
- if (!item.menuItems) {
5781
- return menuMap;
5782
- }
5783
- for (const menuItem of item.menuItems) {
5784
- // remove HTML tags
5785
- const text = menuItem.text.replace(/<[^>]*>/g, '');
5786
- menuMap.set(menuItem.value, text);
5787
- }
5788
- 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();
5789
6317
  }
5790
- updateColorAccent(titleNode, value) {
5791
- const svgNode = titleNode.find('.lake-dropdown-icon svg').eq(1);
5792
- const lineNode = svgNode.find('line');
5793
- if (lineNode.length > 0) {
5794
- 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);
5795
6329
  }
5796
- else {
5797
- svgNode.find('path').attr('fill', value);
6330
+ if (item.multiple === true) {
6331
+ fileNode.attr('multiple', 'true');
5798
6332
  }
5799
- }
5800
- addDropdownMenu(menuNode, item) {
5801
- for (const menuItem of item.menuItems) {
5802
- const listContent = template `
5803
- <li value="${menuItem.value}">
5804
- <div class="lake-dropdown-menu-text">${menuItem.text}</div>
5805
- </li>
5806
- `;
5807
- const listNode = query(listContent);
5808
- menuNode.append(listNode);
5809
- if (item.menuType === 'color') {
5810
- listNode.attr('title', menuItem.text);
5811
- listNode.find('.lake-dropdown-menu-text').css('background-color', menuItem.value);
5812
- }
5813
- if (menuItem.icon) {
5814
- const menuIconNode = query('<div class="lake-dropdown-menu-icon"></div>');
5815
- menuIconNode.append(menuItem.icon);
5816
- listNode.prepend(menuIconNode);
5817
- }
5818
- const checkIcon = icons.get('check');
5819
- if (checkIcon) {
5820
- const checkNode = query('<div class="lake-dropdown-menu-check"></div>');
5821
- checkNode.append(checkIcon);
5822
- 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
+ });
5823
6355
  }
5824
- }
6356
+ });
5825
6357
  }
5826
- bindDropdownEvents(dropdownNode, item) {
6358
+ // Renders a toolbar for the specified editor.
6359
+ render() {
5827
6360
  const editor = this.editor;
5828
- const titleNode = dropdownNode.find('.lake-dropdown-title');
5829
- const textNode = titleNode.find('.lake-dropdown-text');
5830
- const iconNode = titleNode.find('.lake-dropdown-icon');
5831
- const downIconNode = titleNode.find('.lake-dropdown-down-icon');
5832
- const menuNode = dropdownNode.find('.lake-dropdown-menu');
5833
- if (item.menuType === 'color') {
5834
- iconNode.on('mouseenter', () => {
5835
- if (dropdownNode.attr('disabled')) {
5836
- return;
5837
- }
5838
- iconNode.addClass('lake-dropdown-icon-hovered');
5839
- });
5840
- iconNode.on('mouseleave', () => {
5841
- iconNode.removeClass('lake-dropdown-icon-hovered');
5842
- });
5843
- downIconNode.on('mouseenter', () => {
5844
- if (dropdownNode.attr('disabled')) {
5845
- return;
5846
- }
5847
- downIconNode.addClass('lake-dropdown-down-icon-hovered');
5848
- });
5849
- downIconNode.on('mouseleave', () => {
5850
- downIconNode.removeClass('lake-dropdown-down-icon-hovered');
5851
- });
5852
- }
5853
- else {
5854
- titleNode.on('mouseenter', () => {
5855
- if (dropdownNode.attr('disabled')) {
5856
- return;
5857
- }
5858
- titleNode.addClass('lake-dropdown-title-hovered');
5859
- });
5860
- titleNode.on('mouseleave', () => {
5861
- titleNode.removeClass('lake-dropdown-title-hovered');
5862
- });
5863
- }
5864
- if (item.menuType === 'color') {
5865
- iconNode.on('click', event => {
5866
- event.preventDefault();
5867
- if (dropdownNode.attr('disabled')) {
5868
- return;
5869
- }
5870
- editor.focus();
5871
- const value = dropdownNode.attr('color') || item.defaultValue;
5872
- item.onSelect(editor, value);
5873
- });
5874
- }
5875
- const triggerNode = (item.menuType === 'color' && downIconNode) ? downIconNode : titleNode;
5876
- triggerNode.on('click', event => {
5877
- event.preventDefault();
5878
- 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();
5879
6369
  return;
5880
6370
  }
5881
- const currentValues = this.getValue(dropdownNode);
5882
- menuNode.find('.lake-dropdown-menu-check').css('visibility', 'hidden');
5883
- menuNode.find('li').each(node => {
5884
- const listNode = query(node);
5885
- if (currentValues.indexOf(listNode.attr('value')) >= 0) {
5886
- 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;
5887
6376
  }
5888
- });
5889
- menuNode.css('visibility', 'hidden');
5890
- menuNode.show(item.menuType === 'color' ? 'flex' : 'block');
5891
- const dropdownNativeNode = dropdownNode.get(0);
5892
- const dropdownRect = dropdownNativeNode.getBoundingClientRect();
5893
- if (dropdownRect.x + menuNode.width() > window.innerWidth) {
5894
- menuNode.css('left', 'auto');
5895
- menuNode.css('right', '0');
5896
6377
  }
5897
6378
  else {
5898
- menuNode.css('left', '');
5899
- menuNode.css('right', '');
5900
- }
5901
- menuNode.css('visibility', '');
5902
- });
5903
- menuNode.on('click', event => {
5904
- event.preventDefault();
5905
- editor.focus();
5906
- const listItem = query(event.target).closest('li');
5907
- const value = listItem.attr('value');
5908
- if (textNode.length > 0) {
5909
- textNode.text(listItem.text());
6379
+ item = name;
5910
6380
  }
5911
- if (item.menuType === 'color' && value !== '') {
5912
- dropdownNode.attr('color', value);
5913
- this.updateColorAccent(titleNode, value);
6381
+ if (item.type === 'button') {
6382
+ buttonItemList.push(item);
6383
+ this.appendButton(item);
6384
+ return;
5914
6385
  }
5915
- item.onSelect(editor, value);
5916
- });
5917
- editor.event.on('click', target => {
5918
- 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);
5919
6390
  return;
5920
6391
  }
5921
- menuNode.hide();
5922
- });
5923
- }
5924
- appendDropdown(item) {
5925
- var _a;
5926
- const menuMap = this.getMenuMap(item);
5927
- const dropdownNode = item.icon ? query(safeTemplate `
5928
- <div class="lake-dropdown">
5929
- <button type="button" class="lake-dropdown-title">
5930
- <div class="lake-dropdown-icon"></div>
5931
- <div class="lake-dropdown-down-icon"></div>
5932
- </button>
5933
- </div>
5934
- `) : query(safeTemplate `
5935
- <div class="lake-dropdown">
5936
- <button type="button" class="lake-dropdown-title">
5937
- <div class="lake-dropdown-text"></div>
5938
- <div class="lake-dropdown-down-icon"></div>
5939
- </button>
5940
- </div>
5941
- `);
5942
- dropdownNode.attr('name', item.name);
5943
- dropdownNode.addClass(`lake-dropdown-${item.menuType}`);
5944
- const titleNode = dropdownNode.find('.lake-dropdown-title');
5945
- if (!item.downIcon) {
5946
- titleNode.addClass('lake-dropdown-title-no-down');
5947
- }
5948
- titleNode.css('width', item.width);
5949
- titleNode.attr('title', item.tooltip);
5950
- const textNode = titleNode.find('.lake-dropdown-text');
5951
- const iconNode = titleNode.find('.lake-dropdown-icon');
5952
- if (item.icon) {
5953
- iconNode.append(item.icon);
5954
- }
5955
- if (item.accentIcon) {
5956
- iconNode.append(item.accentIcon);
5957
- }
5958
- const downIconNode = titleNode.find('.lake-dropdown-down-icon');
5959
- if (item.downIcon) {
5960
- downIconNode.append(item.downIcon);
5961
- }
5962
- const menuNode = query('<ul class="lake-dropdown-menu" />');
5963
- menuNode.addClass(`lake-dropdown-${item.menuType}-menu`);
5964
- if (textNode.length > 0) {
5965
- textNode.text((_a = menuMap.get(item.defaultValue)) !== null && _a !== void 0 ? _a : item.defaultValue);
5966
- }
5967
- if (item.menuType === 'color') {
5968
- this.updateColorAccent(titleNode, item.defaultValue);
5969
- }
5970
- this.addDropdownMenu(menuNode, item);
5971
- dropdownNode.append(titleNode);
5972
- dropdownNode.append(menuNode);
5973
- this.root.append(dropdownNode);
5974
- this.bindDropdownEvents(dropdownNode, item);
5975
- }
5976
- appendUpload(item) {
5977
- const editor = this.editor;
5978
- const uploadNode = query(safeTemplate `
5979
- <div class="lake-upload">
5980
- <input type="file" />
5981
- <button type="button" class="lake-toolbar-button" />
5982
- </div>
5983
- `);
5984
- const fileNode = uploadNode.find('input[type="file"]');
5985
- const fileNativeNode = fileNode.get(0);
5986
- if (item.accept) {
5987
- fileNode.attr('accept', item.accept);
5988
- }
5989
- if (item.multiple === true) {
5990
- fileNode.attr('multiple', 'true');
5991
- }
5992
- const buttonNode = uploadNode.find('button');
5993
- buttonNode.attr('name', item.name);
5994
- buttonNode.attr('title', item.tooltip);
5995
- if (item.icon) {
5996
- buttonNode.append(item.icon);
5997
- }
5998
- this.root.append(uploadNode);
5999
- buttonNode.on('mouseenter', () => {
6000
- buttonNode.addClass('lake-toolbar-button-hovered');
6001
- });
6002
- buttonNode.on('mouseleave', () => {
6003
- buttonNode.removeClass('lake-toolbar-button-hovered');
6004
- });
6005
- buttonNode.on('click', event => {
6006
- event.preventDefault();
6007
- fileNativeNode.click();
6008
- });
6009
- fileNode.on('click', event => event.stopPropagation());
6010
- fileNode.on('change', event => {
6011
- const target = event.target;
6012
- const files = target.files || [];
6013
- for (const file of files) {
6014
- uploadImage({
6015
- editor,
6016
- file,
6017
- });
6392
+ if (item.type === 'upload') {
6393
+ this.appendUpload(item);
6018
6394
  }
6019
6395
  });
6020
- }
6021
- getUpdateStateHandler(config) {
6022
- const { editor, allMenuMap, buttonItemList, dropdownItemList } = config;
6023
- return debounce(() => {
6396
+ editor.event.on('statechange', data => {
6024
6397
  var _a;
6025
- let appliedItems = editor.selection.appliedItems;
6026
- if (appliedItems.length > 0 &&
6027
- appliedItems[0].node.closestContainer().get(0) !== editor.container.get(0)) {
6028
- appliedItems = [];
6029
- }
6398
+ const { appliedItems, disabledNameMap, selectedNameMap, selectedValuesMap } = data;
6030
6399
  for (const item of buttonItemList) {
6031
- const selectedClass = 'lake-toolbar-button-selected';
6032
- const buttonNode = this.root.find(`button[name="${item.name}"]`);
6033
- const isDisabled = item.isDisabled && appliedItems.length > 0 ? item.isDisabled(appliedItems, editor) : false;
6400
+ const selectedClass = 'lake-button-selected';
6401
+ const buttonNode = this.container.find(`button[name="${item.name}"]`);
6402
+ let isDisabled = disabledNameMap.get(item.name);
6403
+ if (isDisabled === undefined) {
6404
+ isDisabled = item.isDisabled && appliedItems.length > 0 ? item.isDisabled(appliedItems) : false;
6405
+ }
6034
6406
  if (isDisabled) {
6035
6407
  buttonNode.attr('disabled', 'true');
6036
6408
  buttonNode.removeClass(selectedClass);
@@ -6039,7 +6411,10 @@ class Toolbar {
6039
6411
  buttonNode.removeAttr('disabled');
6040
6412
  }
6041
6413
  if (!isDisabled) {
6042
- 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
+ }
6043
6418
  if (isSelected) {
6044
6419
  buttonNode.addClass(selectedClass);
6045
6420
  }
@@ -6049,9 +6424,15 @@ class Toolbar {
6049
6424
  }
6050
6425
  }
6051
6426
  for (const item of dropdownItemList) {
6052
- const selectedValues = item.selectedValues && appliedItems.length > 0 ? item.selectedValues(appliedItems, editor) : [];
6053
- const dropdownNode = this.root.find(`div.lake-dropdown[name="${item.name}"]`);
6054
- const isDisabled = item.isDisabled && appliedItems.length > 0 ? item.isDisabled(appliedItems, editor) : false;
6427
+ let selectedValues = selectedValuesMap.get(item.name);
6428
+ if (selectedValues === undefined) {
6429
+ selectedValues = item.selectedValues && appliedItems.length > 0 ? item.selectedValues(appliedItems) : [];
6430
+ }
6431
+ const dropdownNode = this.container.find(`div.lake-dropdown[name="${item.name}"]`);
6432
+ let isDisabled = disabledNameMap.get(item.name);
6433
+ if (isDisabled === undefined) {
6434
+ isDisabled = item.isDisabled && appliedItems.length > 0 ? item.isDisabled(appliedItems) : false;
6435
+ }
6055
6436
  if (isDisabled) {
6056
6437
  dropdownNode.attr('disabled', 'true');
6057
6438
  }
@@ -6059,7 +6440,7 @@ class Toolbar {
6059
6440
  dropdownNode.removeAttr('disabled');
6060
6441
  }
6061
6442
  if (!isDisabled) {
6062
- this.setValue(dropdownNode, selectedValues);
6443
+ Dropdown.setValue(dropdownNode, selectedValues);
6063
6444
  const textNode = dropdownNode.find('.lake-dropdown-text');
6064
6445
  if (textNode.length > 0) {
6065
6446
  const key = selectedValues[0] || item.defaultValue;
@@ -6069,57 +6450,7 @@ class Toolbar {
6069
6450
  }
6070
6451
  }
6071
6452
  }
6072
- this.event.emit('updatestate');
6073
- }, 100, {
6074
- leading: false,
6075
- trailing: true,
6076
- maxWait: 100,
6077
- });
6078
- }
6079
- render() {
6080
- const editor = this.editor;
6081
- this.root.addClass('lake-custom-properties');
6082
- const allMenuMap = new Map();
6083
- const buttonItemList = [];
6084
- const dropdownItemList = [];
6085
- this.items.forEach(name => {
6086
- if (name === '|') {
6087
- this.appendDivider();
6088
- return;
6089
- }
6090
- let item;
6091
- if (typeof name === 'string') {
6092
- item = toolbarItemMap.get(name);
6093
- if (!item) {
6094
- return;
6095
- }
6096
- }
6097
- else {
6098
- item = name;
6099
- }
6100
- if (item.type === 'button') {
6101
- buttonItemList.push(item);
6102
- this.appendButton(item);
6103
- return;
6104
- }
6105
- if (item.type === 'dropdown') {
6106
- allMenuMap.set(item.name, this.getMenuMap(item));
6107
- dropdownItemList.push(item);
6108
- this.appendDropdown(item);
6109
- return;
6110
- }
6111
- if (item.type === 'upload') {
6112
- this.appendUpload(item);
6113
- }
6114
6453
  });
6115
- const updateStateHandler = this.getUpdateStateHandler({
6116
- editor,
6117
- allMenuMap,
6118
- buttonItemList,
6119
- dropdownItemList,
6120
- });
6121
- editor.event.on('selectionchange', updateStateHandler);
6122
- editor.event.on('change', updateStateHandler);
6123
6454
  }
6124
6455
  }
6125
6456
 
@@ -6132,8 +6463,8 @@ const hrBox = {
6132
6463
  return;
6133
6464
  }
6134
6465
  box.useEffect(() => {
6135
- const root = box.getContainer().find('.lake-hr');
6136
- root.on('click', () => {
6466
+ const hrNode = box.getContainer().find('.lake-hr');
6467
+ hrNode.on('click', () => {
6137
6468
  editor.selection.range.selectBox(box.node);
6138
6469
  });
6139
6470
  });
@@ -6302,10 +6633,10 @@ function openFullScreen(box) {
6302
6633
  arrowPrevSVG: icons.get('left'),
6303
6634
  arrowNextSVG: icons.get('right'),
6304
6635
  closeSVG: icons.get('close'),
6305
- arrowPrevTitle: 'Previous',
6306
- arrowNextTitle: 'Next',
6307
- closeTitle: 'Close (Esc)',
6308
- 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(),
6309
6640
  });
6310
6641
  lightbox.on('uiRegister', () => {
6311
6642
  const pswp = lightbox.pswp;
@@ -6313,7 +6644,7 @@ function openFullScreen(box) {
6313
6644
  name: 'zoom-out-button',
6314
6645
  order: 8,
6315
6646
  isButton: true,
6316
- title: 'Zoom out',
6647
+ title: locale.image.zoomOut(),
6317
6648
  html: icons.get('zoomOut'),
6318
6649
  onClick: () => {
6319
6650
  const currSlide = pswp.currSlide;
@@ -6326,7 +6657,7 @@ function openFullScreen(box) {
6326
6657
  name: 'zoom-in-button',
6327
6658
  order: 9,
6328
6659
  isButton: true,
6329
- title: 'Zoom in',
6660
+ title: locale.image.zoomIn(),
6330
6661
  html: icons.get('zoomIn'),
6331
6662
  onClick: () => {
6332
6663
  const currSlide = pswp.currSlide;
@@ -6371,7 +6702,7 @@ function removeImageBox(box) {
6371
6702
  editor.history.save();
6372
6703
  }
6373
6704
  // Displays error icon and filename.
6374
- function renderError(root, box) {
6705
+ function renderError(imageNode, box) {
6375
6706
  return __awaiter(this, void 0, void 0, function* () {
6376
6707
  const value = box.value;
6377
6708
  box.getContainer().css({
@@ -6380,7 +6711,7 @@ function renderError(root, box) {
6380
6711
  });
6381
6712
  const buttonGroupNode = query(safeTemplate `
6382
6713
  <div class="lake-button-group">
6383
- <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>
6384
6715
  </div>
6385
6716
  `);
6386
6717
  const removeButton = buttonGroupNode.find('.lake-button-remove');
@@ -6398,12 +6729,12 @@ function renderError(root, box) {
6398
6729
  if (imageIcon) {
6399
6730
  errorNode.find('.lake-error-icon').append(imageIcon);
6400
6731
  }
6401
- root.append(buttonGroupNode);
6402
- root.append(errorNode);
6732
+ imageNode.append(buttonGroupNode);
6733
+ imageNode.append(errorNode);
6403
6734
  });
6404
6735
  }
6405
6736
  // Displays an image with uplaoding progress.
6406
- function renderUploading(root, box) {
6737
+ function renderUploading(imageNode, box) {
6407
6738
  return __awaiter(this, void 0, void 0, function* () {
6408
6739
  const editor = box.getEditor();
6409
6740
  if (!editor) {
@@ -6412,10 +6743,10 @@ function renderUploading(root, box) {
6412
6743
  const value = box.value;
6413
6744
  const imageInfo = yield getImageInfo(value.url);
6414
6745
  if (!imageInfo.width || !imageInfo.height) {
6415
- yield renderError(root, box);
6746
+ yield renderError(imageNode, box);
6416
6747
  return;
6417
6748
  }
6418
- const maxWidth = editor.innerWidth() - 2;
6749
+ const maxWidth = editor.container.innerWidth() - 2;
6419
6750
  const width = imageInfo.width < maxWidth ? imageInfo.width : maxWidth;
6420
6751
  const height = Math.round(width * imageInfo.height / imageInfo.width);
6421
6752
  box.updateValue({
@@ -6430,7 +6761,7 @@ function renderUploading(root, box) {
6430
6761
  });
6431
6762
  const buttonGroupNode = query(safeTemplate `
6432
6763
  <div class="lake-button-group">
6433
- <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>
6434
6765
  </div>
6435
6766
  `);
6436
6767
  const removeButton = buttonGroupNode.find('.lake-button-remove');
@@ -6457,13 +6788,13 @@ function renderUploading(root, box) {
6457
6788
  draggable: 'false',
6458
6789
  alt: value.name,
6459
6790
  });
6460
- root.append(buttonGroupNode);
6461
- root.append(progressNode);
6462
- root.append(imgNode);
6791
+ imageNode.append(buttonGroupNode);
6792
+ imageNode.append(progressNode);
6793
+ imageNode.append(imgNode);
6463
6794
  });
6464
6795
  }
6465
6796
  // Displays an image that can be previewed or removed.
6466
- function renderDone(root, box) {
6797
+ function renderDone(imageNode, box) {
6467
6798
  return __awaiter(this, void 0, void 0, function* () {
6468
6799
  const editor = box.getEditor();
6469
6800
  if (!editor) {
@@ -6472,13 +6803,13 @@ function renderDone(root, box) {
6472
6803
  const value = box.value;
6473
6804
  const imageInfo = yield getImageInfo(value.url);
6474
6805
  if (!imageInfo.width || !imageInfo.height) {
6475
- yield renderError(root, box);
6806
+ yield renderError(imageNode, box);
6476
6807
  return;
6477
6808
  }
6478
6809
  let width = value.width;
6479
6810
  let height = value.height;
6480
6811
  if (!width || !height) {
6481
- const maxWidth = editor.innerWidth() - 2;
6812
+ const maxWidth = editor.container.innerWidth() - 2;
6482
6813
  width = Math.round(imageInfo.width < maxWidth ? imageInfo.width : maxWidth);
6483
6814
  height = Math.round(width * imageInfo.height / imageInfo.width);
6484
6815
  box.updateValue({
@@ -6492,8 +6823,8 @@ function renderDone(root, box) {
6492
6823
  });
6493
6824
  const buttonGroupNode = query(safeTemplate `
6494
6825
  <div class="lake-button-group">
6495
- <button type="button" class="lake-button-view" title="Full screen"></button>
6496
- <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>
6497
6828
  </div>
6498
6829
  `);
6499
6830
  const viewButton = buttonGroupNode.find('.lake-button-view');
@@ -6501,7 +6832,7 @@ function renderDone(root, box) {
6501
6832
  if (maximizeIcon) {
6502
6833
  viewButton.append(maximizeIcon);
6503
6834
  }
6504
- if (width < 80) {
6835
+ if (width < 80 || PhotoSwipeLightbox === null) {
6505
6836
  viewButton.hide();
6506
6837
  }
6507
6838
  const removeButton = buttonGroupNode.find('.lake-button-remove');
@@ -6528,9 +6859,9 @@ function renderDone(root, box) {
6528
6859
  bindResizerEvents(resizerNode.find('.lake-resizer-top-right'), box);
6529
6860
  bindResizerEvents(resizerNode.find('.lake-resizer-bottom-left'), box);
6530
6861
  bindResizerEvents(resizerNode.find('.lake-resizer-bottom-right'), box);
6531
- root.append(buttonGroupNode);
6532
- root.append(resizerNode);
6533
- root.append(imgNode);
6862
+ imageNode.append(buttonGroupNode);
6863
+ imageNode.append(resizerNode);
6864
+ imageNode.append(imgNode);
6534
6865
  });
6535
6866
  }
6536
6867
  const imageBox = {
@@ -6567,29 +6898,29 @@ const imageBox = {
6567
6898
  if (value.status === 'loading') {
6568
6899
  return;
6569
6900
  }
6570
- const root = query('<div class="lake-image" />');
6571
- root.addClass(`lake-image-${value.status}`);
6901
+ const imageNode = query('<div class="lake-image" />');
6902
+ imageNode.addClass(`lake-image-${value.status}`);
6572
6903
  let promise;
6573
6904
  if (value.status === 'uploading') {
6574
- promise = renderUploading(root, box);
6905
+ promise = renderUploading(imageNode, box);
6575
6906
  }
6576
6907
  else if (value.status === 'error') {
6577
- promise = renderError(root, box);
6908
+ promise = renderError(imageNode, box);
6578
6909
  }
6579
6910
  else {
6580
- promise = renderDone(root, box);
6911
+ promise = renderDone(imageNode, box);
6581
6912
  }
6582
6913
  promise.then(() => {
6583
6914
  container.empty();
6584
- container.append(root);
6585
- root.find('.lake-button-view').on('click', () => openFullScreen(box));
6586
- 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 => {
6587
6918
  event.stopPropagation();
6588
6919
  removeImageBox(box);
6589
6920
  });
6590
6921
  box.event.emit('render');
6591
6922
  });
6592
- root.on('click', () => {
6923
+ imageNode.on('click', () => {
6593
6924
  editor.selection.range.selectBox(box.node);
6594
6925
  });
6595
6926
  },
@@ -6599,25 +6930,51 @@ const imageBox = {
6599
6930
  },
6600
6931
  };
6601
6932
 
6602
- function CodeMirror (config) {
6603
- const updateListener = (update) => {
6604
- if (!update.docChanged) {
6605
- return;
6606
- }
6607
- config.onChange(update.state.doc.toString());
6608
- };
6609
- return new EditorView({
6610
- doc: config.value,
6611
- extensions: [
6612
- basicSetup,
6613
- keymap.of([indentWithTab]),
6614
- javascript(),
6615
- EditorView.updateListener.of(updateListener),
6616
- ],
6617
- parent: config.parent,
6618
- });
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
+ ]);
6619
6977
  }
6620
-
6621
6978
  const codeBlockBox = {
6622
6979
  type: 'block',
6623
6980
  name: 'codeBlock',
@@ -6627,17 +6984,34 @@ const codeBlockBox = {
6627
6984
  if (!editor) {
6628
6985
  return;
6629
6986
  }
6630
- const width = editor.innerWidth() - 2;
6631
- const root = query('<div class="lake-code-block" />');
6632
- root.css('width', `${width}px`);
6987
+ const codeBlockNode = query('<div class="lake-code-block" />');
6633
6988
  const container = box.getContainer();
6634
6989
  container.empty();
6635
- container.append(root);
6636
- const parent = root.get(0);
6637
- 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
+ });
6638
7003
  return;
6639
7004
  }
6640
- 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) => {
6641
7015
  // Here setTimeout is necessary because isComposing is not false after ending composition.
6642
7016
  window.setTimeout(() => {
6643
7017
  if (editor.isComposing) {
@@ -6647,12 +7021,58 @@ const codeBlockBox = {
6647
7021
  editor.history.save();
6648
7022
  }, 0);
6649
7023
  };
6650
- const codeEditor = CodeMirror({
6651
- parent: root.get(0),
6652
- value: (_a = box.value.code) !== null && _a !== void 0 ? _a : '',
6653
- 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
+ },
6654
7069
  });
7070
+ dropdown.render();
6655
7071
  box.setData('codeEditor', codeEditor);
7072
+ box.useEffect(() => () => {
7073
+ codeEditor.destroy();
7074
+ debug('CodeMirror destroyed');
7075
+ });
6656
7076
  },
6657
7077
  };
6658
7078
 
@@ -6907,8 +7327,10 @@ var paste = (editor) => {
6907
7327
  };
6908
7328
 
6909
7329
  var undo = (editor) => {
6910
- editor.command.add('undo', () => {
6911
- editor.history.undo();
7330
+ editor.command.add('undo', {
7331
+ execute: () => {
7332
+ editor.history.undo();
7333
+ },
6912
7334
  });
6913
7335
  editor.keystroke.setKeydown('mod+z', event => {
6914
7336
  const range = editor.selection.range;
@@ -6921,38 +7343,53 @@ var undo = (editor) => {
6921
7343
  };
6922
7344
 
6923
7345
  var redo = (editor) => {
6924
- editor.command.add('redo', () => {
6925
- editor.history.redo();
7346
+ editor.command.add('redo', {
7347
+ execute: () => {
7348
+ editor.history.redo();
7349
+ },
6926
7350
  });
6927
- editor.keystroke.setKeydown('mod+y', event => {
7351
+ const redoHandler = (event) => {
6928
7352
  const range = editor.selection.range;
6929
7353
  if (range.isInsideBox) {
6930
7354
  return;
6931
7355
  }
6932
7356
  event.preventDefault();
6933
7357
  editor.command.execute('redo');
6934
- });
7358
+ };
7359
+ editor.keystroke.setKeydown('mod+y', redoHandler);
7360
+ editor.keystroke.setKeydown('mod+shift+z', redoHandler);
6935
7361
  };
6936
7362
 
6937
7363
  var selectAll = (editor) => {
6938
- editor.command.add('selectAll', () => {
6939
- const range = editor.selection.range;
6940
- range.selectNodeContents(editor.container);
6941
- range.shrink();
7364
+ editor.command.add('selectAll', {
7365
+ execute: () => {
7366
+ const range = editor.selection.range;
7367
+ range.selectNodeContents(editor.container);
7368
+ range.shrink();
7369
+ },
6942
7370
  });
6943
7371
  };
6944
7372
 
6945
7373
  var heading = (editor) => {
6946
- editor.command.add('heading', (type) => {
6947
- editor.selection.setBlocks(`<${type} />`);
6948
- 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
+ },
6949
7383
  });
6950
7384
  };
6951
7385
 
6952
7386
  var blockQuote = (editor) => {
6953
- editor.command.add('blockQuote', () => {
6954
- editor.selection.setBlocks('<blockquote />');
6955
- 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
+ },
6956
7393
  });
6957
7394
  };
6958
7395
 
@@ -6969,73 +7406,90 @@ function setChecklist(editor, value) {
6969
7406
  editor.selection.setBlocks(`<ul type="checklist"><li value="${value}"></li></ul>`);
6970
7407
  }
6971
7408
  var list = (editor) => {
6972
- editor.command.add('list', (type, value = false) => {
6973
- const blocks = editor.selection.range.getBlocks();
6974
- let isNumberedList = false;
6975
- let isBulletedList = false;
6976
- let isChecklist = false;
6977
- for (const block of blocks) {
6978
- if (!isNumberedList && block.name === 'ol') {
6979
- isNumberedList = true;
6980
- }
6981
- if (!isBulletedList && block.name === 'ul' && !block.hasAttr('type')) {
6982
- isBulletedList = true;
6983
- }
6984
- if (!isChecklist && block.name === 'ul' && block.attr('type') === 'checklist') {
6985
- 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
+ }
6986
7425
  }
6987
- }
6988
- if (isNumberedList) {
6989
- if (type === 'numbered') {
6990
- 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
+ }
6991
7443
  }
6992
- if (type === 'bulleted') {
6993
- 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
+ }
6994
7454
  }
6995
- if (type === 'checklist') {
6996
- 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
+ }
6997
7465
  }
6998
- }
6999
- else if (isBulletedList) {
7000
- if (type === 'numbered') {
7001
- setNumberedList(editor);
7002
- }
7003
- if (type === 'bulleted') {
7004
- setParagraph(editor);
7005
- }
7006
- if (type === 'checklist') {
7007
- setChecklist(editor, value);
7008
- }
7009
- }
7010
- else if (isChecklist) {
7011
- if (type === 'numbered') {
7012
- setNumberedList(editor);
7013
- }
7014
- if (type === 'bulleted') {
7015
- setBulletedList(editor);
7016
- }
7017
- if (type === 'checklist') {
7018
- setParagraph(editor);
7019
- }
7020
- }
7021
- else {
7022
- if (type === 'numbered') {
7023
- setNumberedList(editor);
7024
- }
7025
- if (type === 'bulleted') {
7026
- 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
+ }
7027
7476
  }
7028
- if (type === 'checklist') {
7029
- 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
+ }
7030
7487
  }
7031
- }
7032
- editor.history.save();
7488
+ editor.history.save();
7489
+ },
7033
7490
  });
7034
7491
  editor.container.on('click', event => {
7035
7492
  const mouseEvent = event;
7036
- if (editor.readonly) {
7037
- return;
7038
- }
7039
7493
  if (!mouseEvent.target) {
7040
7494
  return;
7041
7495
  }
@@ -7047,36 +7501,60 @@ var list = (editor) => {
7047
7501
  });
7048
7502
  };
7049
7503
 
7504
+ const alignValueMap = {
7505
+ start: 'left',
7506
+ end: 'right',
7507
+ };
7050
7508
  var align = (editor) => {
7051
- editor.command.add('align', (type) => {
7052
- editor.selection.setBlocks({
7053
- 'text-align': type,
7054
- });
7055
- 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
+ },
7056
7529
  });
7057
7530
  };
7058
7531
 
7059
7532
  var indent = (editor) => {
7060
- editor.command.add('indent', (type) => {
7061
- const blocks = editor.selection.range.getBlocks();
7062
- for (const block of blocks) {
7063
- setBlockIndent(block, type);
7064
- }
7065
- 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
+ },
7066
7541
  });
7067
7542
  };
7068
7543
 
7069
7544
  const tagName$6 = 'strong';
7070
7545
  var bold = (editor) => {
7071
- editor.command.add('bold', () => {
7072
- const appliedItems = editor.selection.getAppliedItems();
7073
- if (appliedItems.find(item => item.name === tagName$6)) {
7074
- editor.selection.removeMark(`<${tagName$6} />`);
7075
- }
7076
- else {
7077
- editor.selection.addMark(`<${tagName$6} />`);
7078
- }
7079
- 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
+ },
7080
7558
  });
7081
7559
  editor.keystroke.setKeydown('mod+b', event => {
7082
7560
  event.preventDefault();
@@ -7086,15 +7564,17 @@ var bold = (editor) => {
7086
7564
 
7087
7565
  const tagName$5 = 'i';
7088
7566
  var italic = (editor) => {
7089
- editor.command.add('italic', () => {
7090
- const appliedItems = editor.selection.getAppliedItems();
7091
- if (appliedItems.find(item => item.name === tagName$5)) {
7092
- editor.selection.removeMark(`<${tagName$5} />`);
7093
- }
7094
- else {
7095
- editor.selection.addMark(`<${tagName$5} />`);
7096
- }
7097
- 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
+ },
7098
7578
  });
7099
7579
  editor.keystroke.setKeydown('mod+i', event => {
7100
7580
  event.preventDefault();
@@ -7104,15 +7584,17 @@ var italic = (editor) => {
7104
7584
 
7105
7585
  const tagName$4 = 'u';
7106
7586
  var underline = (editor) => {
7107
- editor.command.add('underline', () => {
7108
- const appliedItems = editor.selection.getAppliedItems();
7109
- if (appliedItems.find(item => item.name === tagName$4)) {
7110
- editor.selection.removeMark(`<${tagName$4} />`);
7111
- }
7112
- else {
7113
- editor.selection.addMark(`<${tagName$4} />`);
7114
- }
7115
- 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
+ },
7116
7598
  });
7117
7599
  editor.keystroke.setKeydown('mod+u', event => {
7118
7600
  event.preventDefault();
@@ -7122,15 +7604,17 @@ var underline = (editor) => {
7122
7604
 
7123
7605
  const tagName$3 = 's';
7124
7606
  var strikethrough = (editor) => {
7125
- editor.command.add('strikethrough', () => {
7126
- const appliedItems = editor.selection.getAppliedItems();
7127
- if (appliedItems.find(item => item.name === tagName$3)) {
7128
- editor.selection.removeMark(`<${tagName$3} />`);
7129
- }
7130
- else {
7131
- editor.selection.addMark(`<${tagName$3} />`);
7132
- }
7133
- 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
+ },
7134
7618
  });
7135
7619
  editor.keystroke.setKeydown('mod+shift+x', event => {
7136
7620
  event.preventDefault();
@@ -7140,93 +7624,148 @@ var strikethrough = (editor) => {
7140
7624
 
7141
7625
  const tagName$2 = 'sub';
7142
7626
  var subscript = (editor) => {
7143
- editor.command.add('subscript', () => {
7144
- const appliedItems = editor.selection.getAppliedItems();
7145
- if (appliedItems.find(item => item.name === tagName$2)) {
7146
- editor.selection.removeMark(`<${tagName$2} />`);
7147
- }
7148
- else {
7149
- editor.selection.addMark(`<${tagName$2} />`);
7150
- }
7151
- 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
+ },
7152
7638
  });
7153
7639
  };
7154
7640
 
7155
7641
  const tagName$1 = 'sup';
7156
7642
  var superscript = (editor) => {
7157
- editor.command.add('superscript', () => {
7158
- const appliedItems = editor.selection.getAppliedItems();
7159
- if (appliedItems.find(item => item.name === tagName$1)) {
7160
- editor.selection.removeMark(`<${tagName$1} />`);
7161
- }
7162
- else {
7163
- editor.selection.addMark(`<${tagName$1} />`);
7164
- }
7165
- 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
+ },
7166
7654
  });
7167
7655
  };
7168
7656
 
7169
7657
  const tagName = 'code';
7170
7658
  var code = (editor) => {
7171
- editor.command.add('code', () => {
7172
- const appliedItems = editor.selection.getAppliedItems();
7173
- if (appliedItems.find(item => item.name === tagName)) {
7174
- editor.selection.removeMark(`<${tagName} />`);
7175
- }
7176
- else {
7177
- editor.selection.addMark(`<${tagName} />`);
7178
- }
7179
- 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
+ },
7180
7670
  });
7181
7671
  };
7182
7672
 
7183
7673
  var fontFamily = (editor) => {
7184
- editor.command.add('fontFamily', (value) => {
7185
- editor.selection.addMark(`<span style="font-family: ${value};" />`);
7186
- 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
+ },
7187
7688
  });
7188
7689
  };
7189
7690
 
7190
7691
  var fontSize = (editor) => {
7191
- editor.command.add('fontSize', (value) => {
7192
- editor.selection.addMark(`<span style="font-size: ${value};" />`);
7193
- 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
+ },
7194
7707
  });
7195
7708
  };
7196
7709
 
7197
7710
  var fontColor = (editor) => {
7198
- editor.command.add('fontColor', (value) => {
7199
- editor.selection.addMark(`<span style="color: ${value};" />`);
7200
- 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
+ },
7201
7725
  });
7202
7726
  };
7203
7727
 
7204
7728
  var highlight = (editor) => {
7205
- editor.command.add('highlight', (value) => {
7206
- editor.selection.addMark(`<span style="background-color: ${value};" />`);
7207
- 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
+ },
7208
7743
  });
7209
7744
  };
7210
7745
 
7211
7746
  var removeFormat = (editor) => {
7212
- editor.command.add('removeFormat', () => {
7213
- editor.selection.removeMark();
7214
- editor.history.save();
7747
+ editor.command.add('removeFormat', {
7748
+ execute: () => {
7749
+ editor.selection.removeMark();
7750
+ editor.history.save();
7751
+ },
7215
7752
  });
7216
7753
  };
7217
7754
 
7218
7755
  let markList = [];
7219
7756
  const formatPainterClassName = 'lake-format-painter';
7220
7757
  var formatPainter = (editor) => {
7221
- editor.command.add('formatPainter', () => {
7222
- editor.container.addClass(formatPainterClassName);
7223
- const appliedItems = editor.selection.getAppliedItems();
7224
- for (const item of appliedItems) {
7225
- const node = item.node.clone();
7226
- if (node.isMark && node.name !== 'a') {
7227
- 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
+ }
7228
7767
  }
7229
- }
7768
+ },
7230
7769
  });
7231
7770
  editor.container.on('click', () => {
7232
7771
  editor.container.removeClass(formatPainterClassName);
@@ -7243,8 +7782,8 @@ var formatPainter = (editor) => {
7243
7782
  if (tagetNode.isInside) {
7244
7783
  return;
7245
7784
  }
7246
- const buttonNode = tagetNode.closest('.lake-toolbar-button');
7247
- if (buttonNode.length > 0 && buttonNode.attr('name') === 'formatPainter') {
7785
+ const buttonNode = tagetNode.closest('button[name="formatPainter"]');
7786
+ if (buttonNode.length > 0) {
7248
7787
  return;
7249
7788
  }
7250
7789
  editor.container.removeClass(formatPainterClassName);
@@ -7253,123 +7792,147 @@ var formatPainter = (editor) => {
7253
7792
  };
7254
7793
 
7255
7794
  class LinkPopup {
7256
- constructor(target) {
7795
+ constructor(root) {
7257
7796
  this.linkNode = null;
7258
7797
  this.event = new EventEmitter();
7259
- this.root = query(safeTemplate `
7798
+ this.root = root;
7799
+ this.container = query(safeTemplate `
7260
7800
  <div class="lake-link-popup">
7261
- <div class="lake-row">URL</div>
7801
+ <div class="lake-row">${locale.link.url()}</div>
7262
7802
  <div class="lake-row lake-url-row">
7263
7803
  <input type="text" name="url" />
7264
- <button type="button" class="lake-button-copy" title="Copy link to clipboard"></button>
7265
- <button type="button" class="lake-button-open" title="Open link in new tab"></button>
7266
7804
  </div>
7267
- <div class="lake-row">Link title</div>
7805
+ <div class="lake-row">${locale.link.title()}</div>
7268
7806
  <div class="lake-row">
7269
7807
  <input type="text" name="title" />
7270
7808
  </div>
7271
- <div class="lake-row">
7272
- <button type="button" class="lake-button-save"><span>Save</span></button>
7273
- <button type="button" class="lake-button-unlink"><span>Remove link</span></button>
7274
- </div>
7809
+ <div class="lake-row lake-button-row"></div>
7275
7810
  </div>
7276
7811
  `);
7277
- const openIcon = icons.get('open');
7278
- if (openIcon) {
7279
- this.root.find('.lake-button-open').append(openIcon);
7280
- }
7281
- const copyButton = this.root.find('.lake-button-copy');
7282
- const copyIcon = icons.get('copy');
7283
- if (copyIcon) {
7284
- copyButton.append(copyIcon);
7285
- }
7286
- const copyDoneIcon = icons.get('checkCircle');
7287
- if (copyDoneIcon) {
7288
- copyButton.append(copyDoneIcon);
7289
- }
7290
- const copyErrorIcon = icons.get('warningCircle');
7291
- if (copyErrorIcon) {
7292
- copyButton.append(copyErrorIcon);
7293
- }
7294
- const saveIcon = icons.get('check');
7295
- if (saveIcon) {
7296
- this.root.find('.lake-button-save').prepend(saveIcon);
7297
- }
7298
- const unlinkIcon = icons.get('unlink');
7299
- if (unlinkIcon) {
7300
- this.root.find('.lake-button-unlink').prepend(unlinkIcon);
7301
- }
7302
- target.append(this.root);
7303
- this.bindEvents();
7304
7812
  }
7305
- writeClipboardText(text, errorCallback) {
7813
+ // Writes the specified text to the system clipboard
7814
+ writeClipboardText(text) {
7306
7815
  return __awaiter(this, void 0, void 0, function* () {
7816
+ let error = false;
7307
7817
  try {
7308
- 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
+ }
7309
7824
  }
7310
7825
  catch (_a) {
7311
- errorCallback();
7826
+ error = true;
7312
7827
  }
7828
+ return new Promise(resolve => {
7829
+ resolve(error);
7830
+ });
7313
7831
  });
7314
7832
  }
7315
- bindEvents() {
7316
- // Copy link to clipboard
7833
+ // Copy link to clipboard
7834
+ appendCopyButton() {
7317
7835
  let timeoutId = null;
7318
- this.root.find('.lake-button-copy').on('click', () => {
7319
- if (!this.linkNode) {
7320
- return;
7321
- }
7322
- const url = this.getInputValue('url');
7323
- this.writeClipboardText(url, () => {
7324
- const svgNode = this.root.find('.lake-button-copy svg');
7325
- svgNode.hide();
7326
- svgNode.eq(2).show('inline');
7327
- });
7328
- const svgNode = this.root.find('.lake-button-copy svg');
7329
- svgNode.hide();
7330
- svgNode.eq(1).show('inline');
7331
- if (timeoutId) {
7332
- window.clearTimeout(timeoutId);
7333
- }
7334
- timeoutId = window.setTimeout(() => {
7335
- svgNode.hide();
7336
- svgNode.eq(0).show('inline');
7337
- }, 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
+ },
7338
7865
  });
7339
- // Open link in new tab
7340
- this.root.find('.lake-button-open').on('click', () => {
7341
- if (!this.linkNode) {
7342
- return;
7343
- }
7344
- const url = this.getInputValue('url');
7345
- 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
+ },
7346
7890
  });
7347
- // Save link
7348
- this.root.find('.lake-button-save').on('click', () => {
7349
- if (!this.linkNode) {
7350
- return;
7351
- }
7352
- this.save();
7353
- this.hide();
7354
- 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
+ },
7355
7908
  });
7356
- // Remove link
7357
- this.root.find('.lake-button-unlink').on('click', () => {
7358
- if (!this.linkNode) {
7359
- return;
7360
- }
7361
- this.linkNode.remove(true);
7362
- this.hide();
7363
- 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
+ },
7364
7926
  });
7927
+ button.render();
7365
7928
  }
7366
7929
  getInputValue(name) {
7367
- const inputElement = this.root.find(`input[name="${name}"]`);
7930
+ const inputElement = this.container.find(`input[name="${name}"]`);
7368
7931
  const nativeInputElement = inputElement.get(0);
7369
7932
  return nativeInputElement.value;
7370
7933
  }
7371
7934
  setInputValue(name, value) {
7372
- const inputElement = this.root.find(`input[name="${name}"]`);
7935
+ const inputElement = this.container.find(`input[name="${name}"]`);
7373
7936
  const nativeInputElement = inputElement.get(0);
7374
7937
  nativeInputElement.value = value;
7375
7938
  }
@@ -7379,8 +7942,12 @@ class LinkPopup {
7379
7942
  }
7380
7943
  const url = this.getInputValue('url');
7381
7944
  let title = this.getInputValue('title');
7945
+ if (url === '' && title === '') {
7946
+ this.linkNode.remove();
7947
+ return;
7948
+ }
7382
7949
  if (title === '') {
7383
- title = 'Link';
7950
+ title = url;
7384
7951
  }
7385
7952
  this.linkNode.attr('href', url);
7386
7953
  this.linkNode.text(title);
@@ -7399,90 +7966,93 @@ class LinkPopup {
7399
7966
  return;
7400
7967
  }
7401
7968
  // link.x + popup.width > window.width
7402
- if (linkRect.x + this.root.width() > window.innerWidth) {
7969
+ if (linkRect.x + this.container.width() > window.innerWidth) {
7403
7970
  // link.x + window.scrollX - (popup.width - link.width)
7404
- this.root.css('left', `${linkX - this.root.width() + linkRect.width}px`);
7971
+ this.container.css('left', `${linkX - this.container.width() + linkRect.width}px`);
7405
7972
  }
7406
7973
  else {
7407
- this.root.css('left', `${linkX}px`);
7974
+ this.container.css('left', `${linkX}px`);
7408
7975
  }
7409
7976
  // link.y + link.height + popup.height > window.height
7410
- if (linkRect.y + linkRect.height + this.root.height() > window.innerHeight) {
7977
+ if (linkRect.y + linkRect.height + this.container.height() > window.innerHeight) {
7411
7978
  // link.y + window.scrollY - popup.height
7412
- this.root.css('top', `${linkY - this.root.height()}px`);
7979
+ this.container.css('top', `${linkY - this.container.height()}px`);
7413
7980
  }
7414
7981
  else {
7415
- this.root.css('top', `${linkY + linkRect.height}px`);
7982
+ this.container.css('top', `${linkY + linkRect.height}px`);
7416
7983
  }
7417
7984
  }
7985
+ render() {
7986
+ this.appendCopyButton();
7987
+ this.appendOpenButton();
7988
+ this.appendSaveButton();
7989
+ this.appendUnlinkButton();
7990
+ this.root.append(this.container);
7991
+ }
7418
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
+ }
7419
7999
  this.linkNode = linkNode;
7420
8000
  const url = linkNode.attr('href');
7421
8001
  const title = linkNode.text();
7422
8002
  this.setInputValue('url', url);
7423
- this.setInputValue('title', title);
7424
- this.root.css('visibility', 'hidden');
7425
- this.root.show();
8003
+ if (title !== url) {
8004
+ this.setInputValue('title', title);
8005
+ }
8006
+ this.container.css('visibility', 'hidden');
8007
+ this.container.show();
7426
8008
  this.updatePosition();
7427
- this.root.css('visibility', '');
8009
+ this.container.css('visibility', '');
8010
+ this.container.find('input[name="url"]').focus();
7428
8011
  }
7429
8012
  hide() {
7430
8013
  this.linkNode = null;
7431
- this.root.hide();
8014
+ this.container.hide();
7432
8015
  }
7433
8016
  }
7434
8017
 
7435
8018
  var link = (editor) => {
7436
- let popup;
7437
- const showPopup = (lineNode) => {
7438
- if (popup) {
7439
- popup.show(lineNode);
7440
- return;
7441
- }
7442
- popup = new LinkPopup(editor.popupContainer);
7443
- popup.event.on('save', () => {
7444
- editor.history.save();
7445
- });
7446
- popup.event.on('remove', () => {
7447
- editor.history.save();
7448
- });
7449
- popup.show(lineNode);
7450
- };
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
+ });
7451
8026
  editor.root.on('scroll', () => {
7452
- if (!popup) {
7453
- return;
7454
- }
7455
8027
  popup.updatePosition();
7456
8028
  });
7457
8029
  editor.event.on('resize', () => {
7458
- if (!popup) {
7459
- return;
7460
- }
7461
8030
  popup.updatePosition();
7462
8031
  });
7463
8032
  editor.event.on('click', (targetNode) => {
7464
- if (targetNode.isOutside) {
7465
- return;
7466
- }
7467
- if (targetNode.closest('lake-box').length > 0) {
8033
+ if (targetNode.closest('button[name="link"]').length > 0) {
7468
8034
  return;
7469
8035
  }
7470
8036
  const linkNode = targetNode.closest('a');
7471
8037
  if (linkNode.length === 0) {
7472
- if (popup) {
7473
- popup.hide();
7474
- }
8038
+ popup.hide();
7475
8039
  return;
7476
8040
  }
7477
- showPopup(linkNode);
7478
- });
7479
- editor.command.add('link', () => {
7480
- const linkNode = editor.selection.insertLink('<a href="">New link</a>');
7481
- if (!linkNode) {
8041
+ if (linkNode.isOutside ||
8042
+ linkNode.closest('lake-box').length > 0) {
7482
8043
  return;
7483
8044
  }
7484
- editor.history.save();
7485
- 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
+ },
7486
8056
  });
7487
8057
  };
7488
8058
 
@@ -7495,9 +8065,11 @@ var hr = (editor) => {
7495
8065
  node.replaceWith(box.node);
7496
8066
  });
7497
8067
  });
7498
- editor.command.add('hr', () => {
7499
- editor.insertBox('hr');
7500
- editor.history.save();
8068
+ editor.command.add('hr', {
8069
+ execute: () => {
8070
+ editor.insertBox('hr');
8071
+ editor.history.save();
8072
+ },
7501
8073
  });
7502
8074
  };
7503
8075
 
@@ -7520,21 +8092,314 @@ var image = (editor) => {
7520
8092
  node.replaceWith(box.node);
7521
8093
  });
7522
8094
  });
7523
- editor.command.add('image', (value) => {
7524
- editor.insertBox('image', value);
7525
- 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
+ }
7526
8377
  });
7527
- };
7528
-
7529
- var codeBlock = (editor) => {
7530
- editor.command.add('codeBlock', () => {
7531
- const box = editor.insertBox('codeBlock');
7532
- if (!box) {
8378
+ editor.keystroke.setKeydown('enter', event => {
8379
+ const selection = editor.selection;
8380
+ const range = selection.range;
8381
+ if (range.isBox) {
7533
8382
  return;
7534
8383
  }
7535
- editor.history.save();
7536
- const codeEditor = box.getData('codeEditor');
7537
- 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
+ }
7538
8403
  });
7539
8404
  };
7540
8405
 
@@ -7595,6 +8460,7 @@ var enterKey = (editor) => {
7595
8460
  return;
7596
8461
  }
7597
8462
  event.preventDefault();
8463
+ editor.rectifyContent();
7598
8464
  if (range.isBox) {
7599
8465
  addBlockOrSplitBlockForBox(editor);
7600
8466
  editor.history.save();
@@ -7636,7 +8502,7 @@ function addLineBreak(editor) {
7636
8502
  return;
7637
8503
  }
7638
8504
  }
7639
- editor.selection.insertContents('<br />');
8505
+ editor.selection.insertNode(query('<br />'));
7640
8506
  }
7641
8507
  function addBlockOrLineBreakForBox(editor) {
7642
8508
  const range = editor.selection.range;
@@ -7676,6 +8542,7 @@ var shiftEnterKey = (editor) => {
7676
8542
  if (range.isInsideBox) {
7677
8543
  return;
7678
8544
  }
8545
+ editor.rectifyContent();
7679
8546
  event.preventDefault();
7680
8547
  if (range.isBox) {
7681
8548
  addBlockOrLineBreakForBox(editor);
@@ -7737,6 +8604,7 @@ var backspaceKey = (editor) => {
7737
8604
  if (range.isInsideBox) {
7738
8605
  return;
7739
8606
  }
8607
+ editor.rectifyContent();
7740
8608
  if (range.isBoxLeft) {
7741
8609
  const boxNode = range.startNode.closest('lake-box');
7742
8610
  const prevNode = boxNode.prev();
@@ -7787,6 +8655,14 @@ var backspaceKey = (editor) => {
7787
8655
  editor.history.save();
7788
8656
  return;
7789
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
+ }
7790
8666
  const leftText = range.getLeftText();
7791
8667
  if (leftText === '') {
7792
8668
  event.preventDefault();
@@ -7809,14 +8685,6 @@ var backspaceKey = (editor) => {
7809
8685
  }
7810
8686
  mergeWithPreviousBlock(editor, block);
7811
8687
  editor.history.save();
7812
- return;
7813
- }
7814
- if (prevNode.name === 'br') {
7815
- event.preventDefault();
7816
- range.setStartBefore(prevNode);
7817
- range.collapseToStart();
7818
- prevNode.remove();
7819
- editor.history.save();
7820
8688
  }
7821
8689
  });
7822
8690
  };
@@ -7853,6 +8721,7 @@ var deleteKey = (editor) => {
7853
8721
  if (range.isInsideBox) {
7854
8722
  return;
7855
8723
  }
8724
+ editor.rectifyContent();
7856
8725
  if (range.isBoxRight) {
7857
8726
  const boxNode = range.startNode.closest('lake-box');
7858
8727
  const nextNode = boxNode.next();
@@ -7903,6 +8772,13 @@ var deleteKey = (editor) => {
7903
8772
  editor.history.save();
7904
8773
  return;
7905
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
+ }
7906
8782
  const rightText = range.getRightText();
7907
8783
  if (rightText === '') {
7908
8784
  event.preventDefault();
@@ -7913,20 +8789,15 @@ var deleteKey = (editor) => {
7913
8789
  }
7914
8790
  mergeWithNextBlock(editor, block);
7915
8791
  editor.history.save();
7916
- return;
7917
- }
7918
- if (nextNode.name === 'br') {
7919
- event.preventDefault();
7920
- range.setStartBefore(nextNode);
7921
- range.collapseToStart();
7922
- nextNode.remove();
7923
- editor.history.save();
7924
8792
  }
7925
8793
  });
7926
8794
  };
7927
8795
 
7928
8796
  var tabKey = (editor) => {
7929
8797
  editor.keystroke.setKeydown('tab', event => {
8798
+ if (editor.config.indentWithTab === false) {
8799
+ return;
8800
+ }
7930
8801
  event.preventDefault();
7931
8802
  const blocks = editor.selection.range.getBlocks();
7932
8803
  blocks.forEach(block => {
@@ -8061,218 +8932,6 @@ var arrowKeys = (editor) => {
8061
8932
  });
8062
8933
  };
8063
8934
 
8064
- const headingTypeMap = new Map([
8065
- ['#', 'h1'],
8066
- ['##', 'h2'],
8067
- ['###', 'h3'],
8068
- ['####', 'h4'],
8069
- ['#####', 'h5'],
8070
- ['######', 'h6'],
8071
- ]);
8072
- const markItemList = [
8073
- {
8074
- re: /\*\*(.+?)\*\*$/,
8075
- getParameters: () => [
8076
- 'bold',
8077
- ],
8078
- },
8079
- {
8080
- re: /__(.+?)__$/,
8081
- getParameters: () => [
8082
- 'bold',
8083
- ],
8084
- },
8085
- {
8086
- re: /_(.+?)_$/,
8087
- getParameters: () => [
8088
- 'italic',
8089
- ],
8090
- },
8091
- {
8092
- re: /\*(.+?)\*$/,
8093
- getParameters: () => [
8094
- 'italic',
8095
- ],
8096
- },
8097
- {
8098
- re: /==(.+?)==$/,
8099
- getParameters: () => [
8100
- 'highlight',
8101
- '#fff566', // yellow-4, from https://ant.design/docs/spec/colors
8102
- ],
8103
- },
8104
- {
8105
- re: /~~(.+?)~~$/,
8106
- getParameters: () => [
8107
- 'strikethrough',
8108
- ],
8109
- },
8110
- {
8111
- re: /`(.+?)`$/,
8112
- getParameters: () => [
8113
- 'code',
8114
- ],
8115
- },
8116
- ];
8117
- const blockItemList = [
8118
- {
8119
- re: /^#+$/,
8120
- getParameters: (text) => {
8121
- var _a;
8122
- return [
8123
- 'heading',
8124
- (_a = headingTypeMap.get(text)) !== null && _a !== void 0 ? _a : 'h6',
8125
- ];
8126
- },
8127
- },
8128
- {
8129
- re: /^\d+\.$/,
8130
- getParameters: () => [
8131
- 'list',
8132
- 'numbered',
8133
- ],
8134
- },
8135
- {
8136
- re: /^[*\-+]$/,
8137
- getParameters: () => [
8138
- 'list',
8139
- 'bulleted',
8140
- ],
8141
- },
8142
- {
8143
- re: /^\[\s?\]$/,
8144
- getParameters: () => [
8145
- 'list',
8146
- 'checklist',
8147
- false,
8148
- ],
8149
- },
8150
- {
8151
- re: /^\[x\]$/i,
8152
- getParameters: () => [
8153
- 'list',
8154
- 'checklist',
8155
- true,
8156
- ],
8157
- },
8158
- {
8159
- re: /^>$/,
8160
- getParameters: () => [
8161
- 'blockQuote',
8162
- ],
8163
- },
8164
- ];
8165
- function getMarkdownPoint(editor) {
8166
- const selection = editor.selection;
8167
- const range = selection.range;
8168
- let node = range.startNode;
8169
- let offset = range.startOffset;
8170
- if (offset === 0) {
8171
- return;
8172
- }
8173
- if (node.isElement) {
8174
- const child = node.children()[offset - 1];
8175
- if (!child || !child.isText) {
8176
- return;
8177
- }
8178
- node = child;
8179
- offset = node.text().length;
8180
- }
8181
- if (offset < 1) {
8182
- return;
8183
- }
8184
- return {
8185
- node,
8186
- offset,
8187
- };
8188
- }
8189
- // case 1: <p></p> to <p><br /></p>
8190
- // case 2: <p><focus /></p> to <p><br /><focus /></p>
8191
- function fixEmptyBlock(block) {
8192
- const newBlock = block.clone(true);
8193
- newBlock.find('lake-bookmark').remove();
8194
- if (newBlock.html() !== '') {
8195
- return;
8196
- }
8197
- block.prepend('<br />');
8198
- }
8199
- function executeMarkCommand(editor, point) {
8200
- const selection = editor.selection;
8201
- const range = selection.range;
8202
- const offset = point.offset;
8203
- const text = point.node.text().slice(0, offset);
8204
- for (const item of markItemList) {
8205
- const result = item.re.exec(text);
8206
- if (result !== null) {
8207
- // <p>foo**bold**<focus /></p>, offset = 11
8208
- // to
8209
- // <p>foobold\u200B<focus /></p>,
8210
- // to
8211
- // <p>foo[bold]\u200B<focus /></p>, startOffset = 3, endOffset = 7
8212
- editor.prepareOperation();
8213
- const bookmark = selection.insertBookmark();
8214
- const node = bookmark.focus.prev();
8215
- const oldValue = node.text();
8216
- const newValue = `${oldValue.replace(item.re, '$1')}\u200B`;
8217
- node.get(0).nodeValue = newValue;
8218
- range.setStart(node, offset - result[0].length);
8219
- range.setEnd(node, offset - (oldValue.length - newValue.length) - 1);
8220
- const parameters = item.getParameters();
8221
- editor.command.execute(parameters.shift(), ...parameters);
8222
- selection.toBookmark(bookmark);
8223
- editor.commitOperation();
8224
- return true;
8225
- }
8226
- }
8227
- return false;
8228
- }
8229
- function executeBlockCommand(editor, point) {
8230
- const selection = editor.selection;
8231
- const offset = point.offset;
8232
- let text = point.node.text().slice(0, offset);
8233
- text = text.replace(/[\u200B\u2060]/g, '');
8234
- for (const item of blockItemList) {
8235
- if (item.re.test(text)) {
8236
- // <p>#<focus />foo</p>
8237
- // to
8238
- // <h1><focus />foo</h1>
8239
- editor.prepareOperation();
8240
- const bookmark = selection.insertBookmark();
8241
- const node = bookmark.focus.prev();
8242
- node.remove();
8243
- const block = bookmark.focus.closestBlock();
8244
- fixEmptyBlock(block);
8245
- selection.range.shrinkAfter(block);
8246
- const parameters = item.getParameters(text);
8247
- editor.command.execute(parameters.shift(), ...parameters);
8248
- selection.toBookmark(bookmark);
8249
- editor.commitOperation();
8250
- return true;
8251
- }
8252
- }
8253
- return false;
8254
- }
8255
- var markdown = (editor) => {
8256
- editor.keystroke.setKeydown('space', event => {
8257
- const selection = editor.selection;
8258
- const point = getMarkdownPoint(editor);
8259
- if (!point) {
8260
- return;
8261
- }
8262
- if (executeMarkCommand(editor, point)) {
8263
- event.preventDefault();
8264
- return;
8265
- }
8266
- const block = selection.range.getBlocks()[0];
8267
- if (block && !(block.isHeading || block.name === 'p')) {
8268
- return;
8269
- }
8270
- if (executeBlockCommand(editor, point)) {
8271
- event.preventDefault();
8272
- }
8273
- });
8274
- };
8275
-
8276
8935
  Editor.box.add(hrBox);
8277
8936
  Editor.box.add(imageBox);
8278
8937
  Editor.box.add(codeBlockBox);
@@ -8304,12 +8963,13 @@ Editor.plugin.add(link);
8304
8963
  Editor.plugin.add(hr);
8305
8964
  Editor.plugin.add(image);
8306
8965
  Editor.plugin.add(codeBlock);
8966
+ Editor.plugin.add(markdown);
8307
8967
  Editor.plugin.add(enterKey);
8308
8968
  Editor.plugin.add(shiftEnterKey);
8309
8969
  Editor.plugin.add(backspaceKey);
8310
8970
  Editor.plugin.add(deleteKey);
8311
8971
  Editor.plugin.add(tabKey);
8312
8972
  Editor.plugin.add(arrowKeys);
8313
- Editor.plugin.add(markdown);
8314
8973
 
8315
- 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