lakelib 0.1.14 → 0.1.16
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/README.md +15 -5
- package/dist/lake.css +135 -56
- package/dist/lake.min.js +45 -43
- package/dist/lake.min.js.map +1 -1
- package/lib/lake.css +135 -56
- package/lib/lake.js +631 -574
- package/lib/lake.js.map +1 -1
- package/lib/types/boxes/emoji.d.ts +2 -0
- package/lib/types/css/index.d.ts +2 -1
- package/lib/types/editor.d.ts +4 -3
- package/lib/types/i18n/en-US/index.d.ts +1 -0
- package/lib/types/i18n/ja/index.d.ts +1 -0
- package/lib/types/i18n/ko/index.d.ts +1 -0
- package/lib/types/i18n/types.d.ts +8 -0
- package/lib/types/i18n/zh-CN/index.d.ts +1 -0
- package/lib/types/index.d.ts +4 -2
- package/lib/types/managers/selection.d.ts +0 -2
- package/lib/types/models/box.d.ts +0 -2
- package/lib/types/models/fragment.d.ts +3 -1
- package/lib/types/models/nodes.d.ts +2 -4
- package/lib/types/operations/insert-fragment.d.ts +2 -1
- package/lib/types/plugins/emoji.d.ts +3 -0
- package/lib/types/types/dropdown.d.ts +5 -3
- package/lib/types/utils/from-base64.d.ts +1 -0
- package/lib/types/utils/index.d.ts +3 -0
- package/lib/types/utils/to-base64.d.ts +1 -0
- package/package.json +17 -19
- package/lib/types/operations/insert-contents.d.ts +0 -2
- /package/lib/types/{ui/upload.d.ts → utils/upload-file.d.ts} +0 -0
package/lib/lake.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { Base64 } from 'js-base64';
|
|
2
1
|
import EventEmitter from 'eventemitter3';
|
|
3
2
|
import { i18nObject as i18nObject$1 } from 'typesafe-i18n';
|
|
4
|
-
import debounce from '
|
|
5
|
-
import isEqual from '
|
|
6
|
-
import md5 from 'blueimp-md5';
|
|
3
|
+
import debounce from 'debounce';
|
|
4
|
+
import isEqual from 'fast-deep-equal/es6';
|
|
7
5
|
import { createKeybindingsHandler } from 'tinykeys';
|
|
8
6
|
import 'photoswipe/style.css';
|
|
9
7
|
import PhotoSwipeLightbox from 'photoswipe/lightbox';
|
|
@@ -135,17 +133,21 @@ var unlink = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32
|
|
|
135
133
|
|
|
136
134
|
var hr$1 = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M224,128a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16H216A8,8,0,0,1,224,128Z\"></path></svg>";
|
|
137
135
|
|
|
136
|
+
var codeBlock$1 = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M58.34,101.66l-32-32a8,8,0,0,1,0-11.32l32-32A8,8,0,0,1,69.66,37.66L43.31,64,69.66,90.34a8,8,0,0,1-11.32,11.32Zm40,0a8,8,0,0,0,11.32,0l32-32a8,8,0,0,0,0-11.32l-32-32A8,8,0,0,0,98.34,37.66L124.69,64,98.34,90.34A8,8,0,0,0,98.34,101.66ZM200,40H176a8,8,0,0,0,0,16h24V200H56V136a8,8,0,0,0-16,0v64a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V56A16,16,0,0,0,200,40Z\"></path></svg>";
|
|
137
|
+
|
|
138
138
|
var image$1 = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,16V158.75l-26.07-26.06a16,16,0,0,0-22.63,0l-20,20-44-44a16,16,0,0,0-22.62,0L40,149.37V56ZM40,172l52-52,80,80H40Zm176,28H194.63l-36-36,20-20L216,181.38V200ZM144,100a12,12,0,1,1,12,12A12,12,0,0,1,144,100Z\"></path></svg>";
|
|
139
139
|
|
|
140
140
|
var video$1 = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M164.44,121.34l-48-32A8,8,0,0,0,104,96v64a8,8,0,0,0,12.44,6.66l48-32a8,8,0,0,0,0-13.32ZM120,145.05V111l25.58,17ZM234.33,69.52a24,24,0,0,0-14.49-16.4C185.56,39.88,131,40,128,40s-57.56-.12-91.84,13.12a24,24,0,0,0-14.49,16.4C19.08,79.5,16,97.74,16,128s3.08,48.5,5.67,58.48a24,24,0,0,0,14.49,16.41C69,215.56,120.4,216,127.34,216h1.32c6.94,0,58.37-.44,91.18-13.11a24,24,0,0,0,14.49-16.41c2.59-10,5.67-28.22,5.67-58.48S236.92,79.5,234.33,69.52Zm-15.49,113a8,8,0,0,1-4.77,5.49c-31.65,12.22-85.48,12-86,12H128c-.54,0-54.33.2-86-12a8,8,0,0,1-4.77-5.49C34.8,173.39,32,156.57,32,128s2.8-45.39,5.16-54.47A8,8,0,0,1,41.93,68c30.52-11.79,81.66-12,85.85-12h.27c.54,0,54.38-.18,86,12a8,8,0,0,1,4.77,5.49C221.2,82.61,224,99.43,224,128S221.2,173.39,218.84,182.47Z\"></path></svg>";
|
|
141
141
|
|
|
142
142
|
var attachment = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M209.66,122.34a8,8,0,0,1,0,11.32l-82.05,82a56,56,0,0,1-79.2-79.21L147.67,35.73a40,40,0,1,1,56.61,56.55L105,193A24,24,0,1,1,71,159L154.3,74.38A8,8,0,1,1,165.7,85.6L82.39,170.31a8,8,0,1,0,11.27,11.36L192.93,81A24,24,0,1,0,159,47L59.76,147.68a40,40,0,1,0,56.53,56.62l82.06-82A8,8,0,0,1,209.66,122.34Z\"></path></svg>";
|
|
143
143
|
|
|
144
|
-
var
|
|
144
|
+
var emoji$1 = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216ZM80,108a12,12,0,1,1,12,12A12,12,0,0,1,80,108Zm96,0a12,12,0,1,1-12-12A12,12,0,0,1,176,108Zm-1.07,48c-10.29,17.79-27.4,28-46.93,28s-36.63-10.2-46.92-28a8,8,0,1,1,13.84-8c7.47,12.91,19.21,20,33.08,20s25.61-7.1,33.07-20a8,8,0,0,1,13.86,8Z\"></path></svg>";
|
|
145
|
+
|
|
146
|
+
var specialCharacter = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 32 32\"><path d=\"M22.7373,25A14.3093,14.3093,0,0,0,27,15C27,8.42,22.58,4,16,4S5,8.42,5,15A14.3093,14.3093,0,0,0,9.2627,25H4v2h8V24.7617A12.5683,12.5683,0,0,1,7,15c0-5.4673,3.5327-9,9-9s9,3.5327,9,9a12.5683,12.5683,0,0,1-5,9.7617V27h8V25Z\"/></svg>";
|
|
145
147
|
|
|
146
148
|
var table = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M224,48H32a8,8,0,0,0-8,8V192a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A8,8,0,0,0,224,48ZM40,112H80v32H40Zm56,0H216v32H96ZM216,64V96H40V64ZM40,160H80v32H40Zm176,32H96V160H216v32Z\"></path></svg>";
|
|
147
149
|
|
|
148
|
-
// These icons are from open source projects.
|
|
150
|
+
// These icons are sourced from open source projects.
|
|
149
151
|
//
|
|
150
152
|
// Fluent Icons by Microsoft (https://fluenticons.co/).
|
|
151
153
|
// - superscript.svg
|
|
@@ -217,10 +219,12 @@ const icons = new Map([
|
|
|
217
219
|
['link', link$1],
|
|
218
220
|
['unlink', unlink],
|
|
219
221
|
['hr', hr$1],
|
|
222
|
+
['codeBlock', codeBlock$1],
|
|
220
223
|
['image', image$1],
|
|
221
224
|
['video', video$1],
|
|
222
225
|
['attachment', attachment],
|
|
223
|
-
['
|
|
226
|
+
['emoji', emoji$1],
|
|
227
|
+
['specialCharacter', specialCharacter],
|
|
224
228
|
['table', table],
|
|
225
229
|
]);
|
|
226
230
|
|
|
@@ -269,9 +273,10 @@ function safeTemplate(strings, ...keys) {
|
|
|
269
273
|
function camelCase(value) {
|
|
270
274
|
const valueList = value.split('-');
|
|
271
275
|
let camelString = '';
|
|
272
|
-
valueList.
|
|
273
|
-
|
|
274
|
-
|
|
276
|
+
for (let i = 0; i < valueList.length; i++) {
|
|
277
|
+
const val = valueList[i];
|
|
278
|
+
camelString += (i > 0) ? val.charAt(0).toUpperCase() + val.substring(1) : val;
|
|
279
|
+
}
|
|
275
280
|
return camelString;
|
|
276
281
|
}
|
|
277
282
|
|
|
@@ -283,6 +288,28 @@ function inString(string, value, delimiter) {
|
|
|
283
288
|
return (delimiter + string + delimiter).indexOf(delimiter + value + delimiter) >= 0;
|
|
284
289
|
}
|
|
285
290
|
|
|
291
|
+
// Creates a Base64-encoded ASCII string from a string.
|
|
292
|
+
function toBase64(value) {
|
|
293
|
+
const encoder = new TextEncoder();
|
|
294
|
+
const byteArray = encoder.encode(value);
|
|
295
|
+
let binaryString = '';
|
|
296
|
+
byteArray.forEach(byte => {
|
|
297
|
+
binaryString += String.fromCharCode(byte);
|
|
298
|
+
});
|
|
299
|
+
return window.btoa(binaryString);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Decodes a string of data which has been encoded using Base64 encoding.
|
|
303
|
+
function fromBase64(value) {
|
|
304
|
+
const binaryString = window.atob(value);
|
|
305
|
+
const byteArray = new Uint8Array(binaryString.length);
|
|
306
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
307
|
+
byteArray[i] = binaryString.charCodeAt(i);
|
|
308
|
+
}
|
|
309
|
+
const decoder = new TextDecoder();
|
|
310
|
+
return decoder.decode(byteArray);
|
|
311
|
+
}
|
|
312
|
+
|
|
286
313
|
// Converts an alpha value to a hex value.
|
|
287
314
|
function alphaToHex(value) {
|
|
288
315
|
const hexString = Math.round(Number.parseFloat(value) * 255).toString(16);
|
|
@@ -876,15 +903,16 @@ class Nodes {
|
|
|
876
903
|
var _a;
|
|
877
904
|
const elementId = element.lakeId;
|
|
878
905
|
const eventItems = (_a = eventData[elementId]) !== null && _a !== void 0 ? _a : [];
|
|
879
|
-
eventItems.
|
|
906
|
+
for (let i = 0; i < eventItems.length; i++) {
|
|
907
|
+
const item = eventItems[i];
|
|
880
908
|
if (!type || type === item.type && (!listener || listener === item.listener)) {
|
|
881
909
|
element.removeEventListener(item.type, item.listener, false);
|
|
882
|
-
eventItems[
|
|
910
|
+
eventItems[i] = {
|
|
883
911
|
type: '',
|
|
884
912
|
listener: () => { },
|
|
885
913
|
};
|
|
886
914
|
}
|
|
887
|
-
}
|
|
915
|
+
}
|
|
888
916
|
eventData[elementId] = eventItems.filter((item) => item.type !== '');
|
|
889
917
|
});
|
|
890
918
|
}
|
|
@@ -893,11 +921,11 @@ class Nodes {
|
|
|
893
921
|
return this.eachElement(element => {
|
|
894
922
|
const elementId = element.lakeId;
|
|
895
923
|
const eventItems = eventData[elementId];
|
|
896
|
-
|
|
924
|
+
for (const item of eventItems) {
|
|
897
925
|
if (item.type === type) {
|
|
898
926
|
item.listener(event !== null && event !== void 0 ? event : new Event(type));
|
|
899
927
|
}
|
|
900
|
-
}
|
|
928
|
+
}
|
|
901
929
|
});
|
|
902
930
|
}
|
|
903
931
|
// Gets all event listeners attached to the Nodes object.
|
|
@@ -953,9 +981,9 @@ class Nodes {
|
|
|
953
981
|
}
|
|
954
982
|
addClass(className) {
|
|
955
983
|
if (Array.isArray(className)) {
|
|
956
|
-
|
|
984
|
+
for (const name of className) {
|
|
957
985
|
this.addClass(name);
|
|
958
|
-
}
|
|
986
|
+
}
|
|
959
987
|
return this;
|
|
960
988
|
}
|
|
961
989
|
return this.eachElement(element => {
|
|
@@ -967,9 +995,9 @@ class Nodes {
|
|
|
967
995
|
}
|
|
968
996
|
removeClass(className) {
|
|
969
997
|
if (Array.isArray(className)) {
|
|
970
|
-
|
|
998
|
+
for (const name of className) {
|
|
971
999
|
this.removeClass(name);
|
|
972
|
-
}
|
|
1000
|
+
}
|
|
973
1001
|
return this;
|
|
974
1002
|
}
|
|
975
1003
|
return this.eachElement(element => {
|
|
@@ -1061,22 +1089,21 @@ class Nodes {
|
|
|
1061
1089
|
this.html('');
|
|
1062
1090
|
return this;
|
|
1063
1091
|
}
|
|
1064
|
-
// Inserts the specified content
|
|
1092
|
+
// Inserts the specified content to the beginning of the first element.
|
|
1065
1093
|
prepend(content) {
|
|
1094
|
+
const element = this.get(0);
|
|
1066
1095
|
if (typeof content === 'string') {
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
});
|
|
1096
|
+
const list = toNodeList(content).reverse();
|
|
1097
|
+
for (const node of list) {
|
|
1098
|
+
if (element.firstChild) {
|
|
1099
|
+
element.insertBefore(node, element.firstChild);
|
|
1100
|
+
}
|
|
1101
|
+
else {
|
|
1102
|
+
element.appendChild(node);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
return this;
|
|
1078
1106
|
}
|
|
1079
|
-
const element = this.get(0);
|
|
1080
1107
|
if (content instanceof Nodes) {
|
|
1081
1108
|
content = content.get(0);
|
|
1082
1109
|
}
|
|
@@ -1088,71 +1115,62 @@ class Nodes {
|
|
|
1088
1115
|
}
|
|
1089
1116
|
return this;
|
|
1090
1117
|
}
|
|
1091
|
-
// Inserts the specified content
|
|
1118
|
+
// Inserts the specified content to the end of the first element.
|
|
1092
1119
|
append(content) {
|
|
1120
|
+
const element = this.get(0);
|
|
1093
1121
|
if (typeof content === 'string') {
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
});
|
|
1122
|
+
const list = toNodeList(content);
|
|
1123
|
+
for (const node of list) {
|
|
1124
|
+
element.appendChild(node);
|
|
1125
|
+
}
|
|
1126
|
+
return this;
|
|
1100
1127
|
}
|
|
1101
|
-
const element = this.get(0);
|
|
1102
1128
|
if (content instanceof Nodes) {
|
|
1103
1129
|
content = content.get(0);
|
|
1104
1130
|
}
|
|
1105
1131
|
element.appendChild(content);
|
|
1106
1132
|
return this;
|
|
1107
1133
|
}
|
|
1108
|
-
// Inserts the specified content before
|
|
1134
|
+
// Inserts the specified content before the first node.
|
|
1109
1135
|
before(content) {
|
|
1136
|
+
const node = this.get(0);
|
|
1137
|
+
if (!node.parentNode) {
|
|
1138
|
+
return this;
|
|
1139
|
+
}
|
|
1110
1140
|
if (typeof content === 'string') {
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
}
|
|
1117
|
-
node.parentNode.insertBefore(target, node);
|
|
1118
|
-
});
|
|
1119
|
-
});
|
|
1141
|
+
const list = toNodeList(content);
|
|
1142
|
+
for (const target of list) {
|
|
1143
|
+
node.parentNode.insertBefore(target, node);
|
|
1144
|
+
}
|
|
1145
|
+
return this;
|
|
1120
1146
|
}
|
|
1121
|
-
const node = this.get(0);
|
|
1122
1147
|
if (content instanceof Nodes) {
|
|
1123
1148
|
content = content.get(0);
|
|
1124
1149
|
}
|
|
1125
|
-
if (!node.parentNode) {
|
|
1126
|
-
return this;
|
|
1127
|
-
}
|
|
1128
1150
|
node.parentNode.insertBefore(content, node);
|
|
1129
1151
|
return this;
|
|
1130
1152
|
}
|
|
1131
|
-
// Inserts the specified content after
|
|
1153
|
+
// Inserts the specified content after the first node.
|
|
1132
1154
|
after(content) {
|
|
1155
|
+
const node = this.get(0);
|
|
1156
|
+
if (!node.parentNode) {
|
|
1157
|
+
return this;
|
|
1158
|
+
}
|
|
1133
1159
|
if (typeof content === 'string') {
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
node.parentNode.appendChild(target);
|
|
1145
|
-
}
|
|
1146
|
-
});
|
|
1147
|
-
});
|
|
1160
|
+
const list = toNodeList(content).reverse();
|
|
1161
|
+
for (const target of list) {
|
|
1162
|
+
if (node.nextSibling) {
|
|
1163
|
+
node.parentNode.insertBefore(target, node.nextSibling);
|
|
1164
|
+
}
|
|
1165
|
+
else {
|
|
1166
|
+
node.parentNode.appendChild(target);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
return this;
|
|
1148
1170
|
}
|
|
1149
|
-
const node = this.get(0);
|
|
1150
1171
|
if (content instanceof Nodes) {
|
|
1151
1172
|
content = content.get(0);
|
|
1152
1173
|
}
|
|
1153
|
-
if (!node.parentNode) {
|
|
1154
|
-
return this;
|
|
1155
|
-
}
|
|
1156
1174
|
if (node.nextSibling) {
|
|
1157
1175
|
node.parentNode.insertBefore(content, node.nextSibling);
|
|
1158
1176
|
}
|
|
@@ -1161,21 +1179,21 @@ class Nodes {
|
|
|
1161
1179
|
}
|
|
1162
1180
|
return this;
|
|
1163
1181
|
}
|
|
1164
|
-
// Replaces
|
|
1182
|
+
// Replaces the first node with the provided new content.
|
|
1165
1183
|
replaceWith(newContent) {
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1184
|
+
const node = this.get(0);
|
|
1185
|
+
if (!node.parentNode) {
|
|
1186
|
+
return this;
|
|
1187
|
+
}
|
|
1188
|
+
let target;
|
|
1189
|
+
if (newContent instanceof Nodes) {
|
|
1190
|
+
target = newContent.get(0);
|
|
1191
|
+
}
|
|
1192
|
+
else {
|
|
1193
|
+
target = toNodeList(newContent)[0];
|
|
1194
|
+
}
|
|
1195
|
+
node.parentNode.replaceChild(target, node);
|
|
1196
|
+
return this;
|
|
1179
1197
|
}
|
|
1180
1198
|
// Removes each node from the DOM.
|
|
1181
1199
|
// keepChildren parameter:
|
|
@@ -1470,7 +1488,7 @@ class Range {
|
|
|
1470
1488
|
selectBox(boxNode) {
|
|
1471
1489
|
const boxContainer = boxNode.find('.lake-box-container');
|
|
1472
1490
|
if (boxContainer.length === 0) {
|
|
1473
|
-
throw new Error(`The box cannot be selected because the box
|
|
1491
|
+
throw new Error(`The box cannot be selected because the box "${boxNode.attr('name')}" (id=${boxNode.id}) has not been rendered yet.`);
|
|
1474
1492
|
}
|
|
1475
1493
|
this.setStart(boxContainer, 0);
|
|
1476
1494
|
this.collapseToStart();
|
|
@@ -1479,7 +1497,7 @@ class Range {
|
|
|
1479
1497
|
selectBoxStart(boxNode) {
|
|
1480
1498
|
const boxStrip = boxNode.find('.lake-box-strip');
|
|
1481
1499
|
if (boxStrip.length === 0) {
|
|
1482
|
-
throw new Error(`The box cannot be selected because the box
|
|
1500
|
+
throw new Error(`The box cannot be selected because the box "${boxNode.attr('name')}" (id=${boxNode.id}) has not been rendered yet.`);
|
|
1483
1501
|
}
|
|
1484
1502
|
this.selectNodeContents(boxStrip.eq(0));
|
|
1485
1503
|
this.collapseToStart();
|
|
@@ -1488,7 +1506,7 @@ class Range {
|
|
|
1488
1506
|
selectBoxEnd(boxNode) {
|
|
1489
1507
|
const boxStrip = boxNode.find('.lake-box-strip');
|
|
1490
1508
|
if (boxStrip.length === 0) {
|
|
1491
|
-
throw new Error(`The box cannot be selected because the box
|
|
1509
|
+
throw new Error(`The box cannot be selected because the box "${boxNode.attr('name')}" (id=${boxNode.id}) has not been rendered yet.`);
|
|
1492
1510
|
}
|
|
1493
1511
|
this.selectNodeContents(boxStrip.eq(1));
|
|
1494
1512
|
this.collapseToStart();
|
|
@@ -2020,9 +2038,9 @@ function wrapNodeList(nodeList, wrapper) {
|
|
|
2020
2038
|
wrapper = wrapper.clone(true);
|
|
2021
2039
|
const deepestElement = getDeepest(wrapper);
|
|
2022
2040
|
nodeList[0].before(wrapper);
|
|
2023
|
-
|
|
2041
|
+
for (const node of nodeList) {
|
|
2024
2042
|
deepestElement.append(node);
|
|
2025
|
-
}
|
|
2043
|
+
}
|
|
2026
2044
|
return wrapper;
|
|
2027
2045
|
}
|
|
2028
2046
|
|
|
@@ -2855,6 +2873,7 @@ var enUS = {
|
|
|
2855
2873
|
highlight: 'Highlight',
|
|
2856
2874
|
image: 'Image',
|
|
2857
2875
|
file: 'File',
|
|
2876
|
+
emoji: 'Emoji',
|
|
2858
2877
|
removeColor: 'Remove color',
|
|
2859
2878
|
},
|
|
2860
2879
|
link: {
|
|
@@ -2938,6 +2957,7 @@ var zhCN = {
|
|
|
2938
2957
|
highlight: '文字背景',
|
|
2939
2958
|
image: '图片',
|
|
2940
2959
|
file: '文件',
|
|
2960
|
+
emoji: '表情',
|
|
2941
2961
|
removeColor: '默认',
|
|
2942
2962
|
},
|
|
2943
2963
|
link: {
|
|
@@ -3021,6 +3041,7 @@ var ja = {
|
|
|
3021
3041
|
highlight: '文字の背景',
|
|
3022
3042
|
image: '画像',
|
|
3023
3043
|
file: 'ファイル',
|
|
3044
|
+
emoji: '絵文字',
|
|
3024
3045
|
removeColor: 'デフォルト',
|
|
3025
3046
|
},
|
|
3026
3047
|
link: {
|
|
@@ -3104,6 +3125,7 @@ var ko = {
|
|
|
3104
3125
|
highlight: '글자 배경',
|
|
3105
3126
|
image: '이미지',
|
|
3106
3127
|
file: '파일',
|
|
3128
|
+
emoji: '이모지',
|
|
3107
3129
|
removeColor: '기본색',
|
|
3108
3130
|
},
|
|
3109
3131
|
link: {
|
|
@@ -3205,11 +3227,11 @@ class Dropdown {
|
|
|
3205
3227
|
if (value === '') {
|
|
3206
3228
|
return [];
|
|
3207
3229
|
}
|
|
3208
|
-
return JSON.parse(
|
|
3230
|
+
return JSON.parse(fromBase64(value));
|
|
3209
3231
|
}
|
|
3210
3232
|
// Updates the value of the node.
|
|
3211
3233
|
static setValue(node, value) {
|
|
3212
|
-
node.attr('value',
|
|
3234
|
+
node.attr('value', toBase64(JSON.stringify(value)));
|
|
3213
3235
|
}
|
|
3214
3236
|
static getMenuMap(menuItems, locale) {
|
|
3215
3237
|
const menuMap = new Map();
|
|
@@ -3242,7 +3264,11 @@ class Dropdown {
|
|
|
3242
3264
|
`;
|
|
3243
3265
|
const listNode = query(listContent);
|
|
3244
3266
|
menuNode.append(listNode);
|
|
3245
|
-
if (config.menuType === '
|
|
3267
|
+
if (config.menuType === 'character') {
|
|
3268
|
+
listNode.attr('title', menuText);
|
|
3269
|
+
listNode.find('.lake-dropdown-menu-text').text(menuItem.value);
|
|
3270
|
+
}
|
|
3271
|
+
else if (config.menuType === 'color') {
|
|
3246
3272
|
listNode.attr('title', menuText);
|
|
3247
3273
|
listNode.find('.lake-dropdown-menu-text').css('background-color', menuItem.value);
|
|
3248
3274
|
}
|
|
@@ -3284,7 +3310,7 @@ class Dropdown {
|
|
|
3284
3310
|
}
|
|
3285
3311
|
});
|
|
3286
3312
|
menuNode.css('visibility', 'hidden');
|
|
3287
|
-
menuNode.show(config.menuType === '
|
|
3313
|
+
menuNode.show(config.menuType === 'list' ? 'block' : 'flex');
|
|
3288
3314
|
const dropdownNativeNode = dropdownNode.get(0);
|
|
3289
3315
|
const dropdownRect = dropdownNativeNode.getBoundingClientRect();
|
|
3290
3316
|
// A overflow width on the left side, greater than 0 indicates an overflow.
|
|
@@ -3347,7 +3373,7 @@ class Dropdown {
|
|
|
3347
3373
|
if (dropdownNode.attr('disabled')) {
|
|
3348
3374
|
return;
|
|
3349
3375
|
}
|
|
3350
|
-
const value = dropdownNode.attr('color') || config.defaultValue;
|
|
3376
|
+
const value = dropdownNode.attr('color') || config.defaultValue || '';
|
|
3351
3377
|
config.onSelect(value);
|
|
3352
3378
|
});
|
|
3353
3379
|
}
|
|
@@ -3358,7 +3384,11 @@ class Dropdown {
|
|
|
3358
3384
|
});
|
|
3359
3385
|
menuNode.on('click', event => {
|
|
3360
3386
|
event.preventDefault();
|
|
3387
|
+
event.stopPropagation();
|
|
3361
3388
|
const listItem = query(event.target).closest('li');
|
|
3389
|
+
if (listItem.length === 0) {
|
|
3390
|
+
return;
|
|
3391
|
+
}
|
|
3362
3392
|
const value = listItem.attr('value');
|
|
3363
3393
|
Dropdown.setValue(dropdownNode, [value]);
|
|
3364
3394
|
if (textNode.length > 0) {
|
|
@@ -3374,14 +3404,17 @@ class Dropdown {
|
|
|
3374
3404
|
});
|
|
3375
3405
|
}
|
|
3376
3406
|
render() {
|
|
3377
|
-
var _a;
|
|
3407
|
+
var _a, _b;
|
|
3378
3408
|
const config = this.config;
|
|
3409
|
+
const defaultValue = (_a = config.defaultValue) !== null && _a !== void 0 ? _a : '';
|
|
3379
3410
|
const dropdownNode = this.node;
|
|
3380
3411
|
const titleNode = dropdownNode.find('.lake-dropdown-title');
|
|
3381
3412
|
if (!config.downIcon) {
|
|
3382
3413
|
titleNode.addClass('lake-dropdown-title-no-down');
|
|
3383
3414
|
}
|
|
3384
|
-
|
|
3415
|
+
if (config.width) {
|
|
3416
|
+
titleNode.css('width', config.width);
|
|
3417
|
+
}
|
|
3385
3418
|
const tooltip = typeof config.tooltip === 'string' ? config.tooltip : config.tooltip(this.locale);
|
|
3386
3419
|
titleNode.attr('title', tooltip);
|
|
3387
3420
|
const textNode = titleNode.find('.lake-dropdown-text');
|
|
@@ -3398,13 +3431,20 @@ class Dropdown {
|
|
|
3398
3431
|
}
|
|
3399
3432
|
const menuNode = query('<ul class="lake-dropdown-menu" />');
|
|
3400
3433
|
menuNode.addClass(`lake-${config.menuType}-dropdown-menu`);
|
|
3401
|
-
|
|
3434
|
+
if (config.menuWidth) {
|
|
3435
|
+
menuNode.css('width', config.menuWidth);
|
|
3436
|
+
}
|
|
3437
|
+
if (config.menuHeight) {
|
|
3438
|
+
menuNode.addClass('lake-dropdown-menu-with-scroll');
|
|
3439
|
+
menuNode.css('height', config.menuHeight);
|
|
3440
|
+
}
|
|
3441
|
+
Dropdown.setValue(dropdownNode, [defaultValue]);
|
|
3402
3442
|
if (textNode.length > 0) {
|
|
3403
3443
|
const menuMap = Dropdown.getMenuMap(config.menuItems, this.locale);
|
|
3404
|
-
textNode.text((
|
|
3444
|
+
textNode.text((_b = menuMap.get(defaultValue)) !== null && _b !== void 0 ? _b : defaultValue);
|
|
3405
3445
|
}
|
|
3406
3446
|
if (config.menuType === 'color') {
|
|
3407
|
-
this.updateColorAccent(titleNode,
|
|
3447
|
+
this.updateColorAccent(titleNode, defaultValue);
|
|
3408
3448
|
}
|
|
3409
3449
|
this.apppendMenuItems(menuNode);
|
|
3410
3450
|
dropdownNode.append(titleNode);
|
|
@@ -3489,21 +3529,19 @@ class BoxToolbar {
|
|
|
3489
3529
|
// Renders a toolbar for the specified box.
|
|
3490
3530
|
render() {
|
|
3491
3531
|
this.root.append(this.container);
|
|
3492
|
-
this.items
|
|
3532
|
+
for (const item of this.items) {
|
|
3493
3533
|
if (item === '|') {
|
|
3494
3534
|
this.appendDivider();
|
|
3495
|
-
return;
|
|
3496
3535
|
}
|
|
3497
|
-
if (item.type === 'button') {
|
|
3536
|
+
else if (item.type === 'button') {
|
|
3498
3537
|
this.buttonItemList.push(item);
|
|
3499
3538
|
this.appendButton(item);
|
|
3500
|
-
return;
|
|
3501
3539
|
}
|
|
3502
|
-
if (item.type === 'dropdown') {
|
|
3540
|
+
else if (item.type === 'dropdown') {
|
|
3503
3541
|
this.dropdownItemList.push(item);
|
|
3504
3542
|
this.appendDropdown(item);
|
|
3505
3543
|
}
|
|
3506
|
-
}
|
|
3544
|
+
}
|
|
3507
3545
|
this.updatePosition();
|
|
3508
3546
|
}
|
|
3509
3547
|
unmount() {
|
|
@@ -3511,8 +3549,6 @@ class BoxToolbar {
|
|
|
3511
3549
|
}
|
|
3512
3550
|
}
|
|
3513
3551
|
|
|
3514
|
-
// A key-value object for storing data about box.
|
|
3515
|
-
const boxData = {};
|
|
3516
3552
|
const framework = safeTemplate `
|
|
3517
3553
|
<span class="lake-box-strip"><br /></span>
|
|
3518
3554
|
<div class="lake-box-container" contenteditable="false"></div>
|
|
@@ -3524,7 +3560,7 @@ class Box {
|
|
|
3524
3560
|
if (typeof node === 'string') {
|
|
3525
3561
|
const component = boxes.get(node);
|
|
3526
3562
|
if (component === undefined) {
|
|
3527
|
-
throw new Error(`Box
|
|
3563
|
+
throw new Error(`Box "${node}" has not been defined yet.`);
|
|
3528
3564
|
}
|
|
3529
3565
|
const type = encode(component.type);
|
|
3530
3566
|
const name = encode(component.name);
|
|
@@ -3537,15 +3573,12 @@ class Box {
|
|
|
3537
3573
|
this.node = query(node);
|
|
3538
3574
|
const component = boxes.get(this.name);
|
|
3539
3575
|
if (component === undefined) {
|
|
3540
|
-
throw new Error(`Box
|
|
3576
|
+
throw new Error(`Box "${this.name}" has not been defined yet.`);
|
|
3541
3577
|
}
|
|
3542
3578
|
if (component.value && !this.node.hasAttr('value')) {
|
|
3543
3579
|
this.value = component.value;
|
|
3544
3580
|
}
|
|
3545
3581
|
}
|
|
3546
|
-
if (!boxData[this.node.id]) {
|
|
3547
|
-
boxData[this.node.id] = {};
|
|
3548
|
-
}
|
|
3549
3582
|
}
|
|
3550
3583
|
// Adds the framework of the box.
|
|
3551
3584
|
addFramework() {
|
|
@@ -3592,11 +3625,11 @@ class Box {
|
|
|
3592
3625
|
if (value === '') {
|
|
3593
3626
|
return {};
|
|
3594
3627
|
}
|
|
3595
|
-
return JSON.parse(
|
|
3628
|
+
return JSON.parse(fromBase64(value));
|
|
3596
3629
|
}
|
|
3597
3630
|
// Sets the value of the box.
|
|
3598
3631
|
set value(value) {
|
|
3599
|
-
this.node.attr('value',
|
|
3632
|
+
this.node.attr('value', toBase64(JSON.stringify(value)));
|
|
3600
3633
|
}
|
|
3601
3634
|
updateValue(valueKey, valueValue) {
|
|
3602
3635
|
const value = this.value;
|
|
@@ -3610,14 +3643,6 @@ class Box {
|
|
|
3610
3643
|
}
|
|
3611
3644
|
this.value = value;
|
|
3612
3645
|
}
|
|
3613
|
-
// Returns data of the box.
|
|
3614
|
-
getData(key) {
|
|
3615
|
-
return boxData[this.node.id][key];
|
|
3616
|
-
}
|
|
3617
|
-
// Updates data of the box.
|
|
3618
|
-
setData(key, value) {
|
|
3619
|
-
boxData[this.node.id][key] = value;
|
|
3620
|
-
}
|
|
3621
3646
|
// Returns the editor instance of the box.
|
|
3622
3647
|
getEditor() {
|
|
3623
3648
|
const container = this.node.closest('div[contenteditable]');
|
|
@@ -3678,7 +3703,6 @@ class Box {
|
|
|
3678
3703
|
unmount() {
|
|
3679
3704
|
this.event.emit('blur');
|
|
3680
3705
|
this.event.emit('beforeunmount');
|
|
3681
|
-
boxData[this.node.id] = {};
|
|
3682
3706
|
this.event.removeAllListeners();
|
|
3683
3707
|
this.node.empty();
|
|
3684
3708
|
debug(`Box "${this.name}" (id: ${this.node.id}) unmounted`);
|
|
@@ -3852,6 +3876,71 @@ function request(option) {
|
|
|
3852
3876
|
return xhr;
|
|
3853
3877
|
}
|
|
3854
3878
|
|
|
3879
|
+
function uploadFile(config) {
|
|
3880
|
+
const { editor, name, file, onError, onSuccess } = config;
|
|
3881
|
+
const { requestMethod, requestAction, requestTypes } = editor.config[name];
|
|
3882
|
+
if (requestTypes.indexOf(file.type) < 0) {
|
|
3883
|
+
if (onError) {
|
|
3884
|
+
onError(`File "${file.name}" is not allowed for uploading.`);
|
|
3885
|
+
}
|
|
3886
|
+
throw new Error(`Cannot upload file "${file.name}" because its type "${file.type}" is not found in ['${requestTypes.join('\', \'')}'].`);
|
|
3887
|
+
}
|
|
3888
|
+
const box = editor.selection.insertBox(name, {
|
|
3889
|
+
url: URL.createObjectURL(file),
|
|
3890
|
+
status: 'uploading',
|
|
3891
|
+
name: file.name,
|
|
3892
|
+
size: file.size,
|
|
3893
|
+
type: file.type,
|
|
3894
|
+
lastModified: file.lastModified,
|
|
3895
|
+
});
|
|
3896
|
+
let xhr = request({
|
|
3897
|
+
onProgress: e => {
|
|
3898
|
+
const percentNode = box.node.find('.lake-percent');
|
|
3899
|
+
const percent = Math.round(e.percent);
|
|
3900
|
+
percentNode.text(`${percent < 100 ? percent : 99} %`);
|
|
3901
|
+
},
|
|
3902
|
+
onError: (error, body) => {
|
|
3903
|
+
xhr = null;
|
|
3904
|
+
debug(error.toString(), body);
|
|
3905
|
+
box.updateValue('status', 'error');
|
|
3906
|
+
box.render();
|
|
3907
|
+
if (onError) {
|
|
3908
|
+
onError(error.toString());
|
|
3909
|
+
}
|
|
3910
|
+
},
|
|
3911
|
+
onSuccess: body => {
|
|
3912
|
+
xhr = null;
|
|
3913
|
+
if (!body.url) {
|
|
3914
|
+
box.updateValue('status', 'error');
|
|
3915
|
+
box.render();
|
|
3916
|
+
if (onError) {
|
|
3917
|
+
onError('Cannot find the url field.');
|
|
3918
|
+
}
|
|
3919
|
+
return;
|
|
3920
|
+
}
|
|
3921
|
+
box.updateValue({
|
|
3922
|
+
status: 'done',
|
|
3923
|
+
url: body.url,
|
|
3924
|
+
});
|
|
3925
|
+
box.render();
|
|
3926
|
+
editor.history.save();
|
|
3927
|
+
if (onSuccess) {
|
|
3928
|
+
onSuccess();
|
|
3929
|
+
}
|
|
3930
|
+
},
|
|
3931
|
+
file,
|
|
3932
|
+
action: requestAction,
|
|
3933
|
+
method: requestMethod,
|
|
3934
|
+
});
|
|
3935
|
+
box.event.on('beforeunmount', () => {
|
|
3936
|
+
if (xhr) {
|
|
3937
|
+
xhr.abort();
|
|
3938
|
+
debug('Upload canceled');
|
|
3939
|
+
}
|
|
3940
|
+
});
|
|
3941
|
+
return box;
|
|
3942
|
+
}
|
|
3943
|
+
|
|
3855
3944
|
// String
|
|
3856
3945
|
|
|
3857
3946
|
var index = /*#__PURE__*/Object.freeze({
|
|
@@ -3864,6 +3953,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
3864
3953
|
encode: encode,
|
|
3865
3954
|
fileSize: fileSize,
|
|
3866
3955
|
fixNumberedList: fixNumberedList,
|
|
3956
|
+
fromBase64: fromBase64,
|
|
3867
3957
|
getBox: getBox,
|
|
3868
3958
|
getCSS: getCSS,
|
|
3869
3959
|
getDeepest: getDeepest,
|
|
@@ -3882,8 +3972,10 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
3882
3972
|
setBlockIndent: setBlockIndent,
|
|
3883
3973
|
splitNodes: splitNodes,
|
|
3884
3974
|
template: template,
|
|
3975
|
+
toBase64: toBase64,
|
|
3885
3976
|
toHex: toHex,
|
|
3886
3977
|
toNodeList: toNodeList,
|
|
3978
|
+
uploadFile: uploadFile,
|
|
3887
3979
|
wrapNodeList: wrapNodeList
|
|
3888
3980
|
});
|
|
3889
3981
|
|
|
@@ -3891,6 +3983,10 @@ class Fragment {
|
|
|
3891
3983
|
constructor(fragment) {
|
|
3892
3984
|
this.fragment = fragment !== null && fragment !== void 0 ? fragment : document.createDocumentFragment();
|
|
3893
3985
|
}
|
|
3986
|
+
// Gets a native fragment.
|
|
3987
|
+
get() {
|
|
3988
|
+
return this.fragment;
|
|
3989
|
+
}
|
|
3894
3990
|
// Returns the descendants of the fragment which are selected by the specified CSS selector.
|
|
3895
3991
|
find(selector) {
|
|
3896
3992
|
const nodeList = [];
|
|
@@ -3910,7 +4006,7 @@ class Fragment {
|
|
|
3910
4006
|
}
|
|
3911
4007
|
// Inserts the specified node as the last child.
|
|
3912
4008
|
append(node) {
|
|
3913
|
-
node.each(nativeNode => {
|
|
4009
|
+
query(node).each(nativeNode => {
|
|
3914
4010
|
this.fragment.appendChild(nativeNode);
|
|
3915
4011
|
});
|
|
3916
4012
|
}
|
|
@@ -4411,6 +4507,9 @@ function deleteContents(range) {
|
|
|
4411
4507
|
|
|
4412
4508
|
// Inserts a DocumentFragment object into the specified range.
|
|
4413
4509
|
function insertFragment(range, fragment) {
|
|
4510
|
+
if (fragment instanceof Fragment) {
|
|
4511
|
+
fragment = fragment.get();
|
|
4512
|
+
}
|
|
4414
4513
|
if (range.commonAncestor.isOutside) {
|
|
4415
4514
|
return;
|
|
4416
4515
|
}
|
|
@@ -4428,16 +4527,6 @@ function insertFragment(range, fragment) {
|
|
|
4428
4527
|
range.adjustBlock();
|
|
4429
4528
|
}
|
|
4430
4529
|
|
|
4431
|
-
// Inserts a HTML string into the specified range.
|
|
4432
|
-
function insertContents(range, value) {
|
|
4433
|
-
const nodes = query(value);
|
|
4434
|
-
const fragment = document.createDocumentFragment();
|
|
4435
|
-
nodes.each(nativeNode => {
|
|
4436
|
-
fragment.appendChild(nativeNode);
|
|
4437
|
-
});
|
|
4438
|
-
insertFragment(range, fragment);
|
|
4439
|
-
}
|
|
4440
|
-
|
|
4441
4530
|
function getTopNonBlockNodes(range) {
|
|
4442
4531
|
const container = range.commonAncestor.closest('div[contenteditable="true"],td');
|
|
4443
4532
|
let nodeList = [];
|
|
@@ -4499,7 +4588,7 @@ function setBlocks(range, value) {
|
|
|
4499
4588
|
}
|
|
4500
4589
|
else {
|
|
4501
4590
|
const block = valueNode.clone(true);
|
|
4502
|
-
if (node.isList && node.attr('indent') !== '') {
|
|
4591
|
+
if (block.isList && node.isList && node.attr('indent') !== '') {
|
|
4503
4592
|
block.attr('indent', node.attr('indent'));
|
|
4504
4593
|
}
|
|
4505
4594
|
const deepestBlock = getDeepest(block);
|
|
@@ -4951,8 +5040,6 @@ function insertLink(range, value) {
|
|
|
4951
5040
|
return linkNode;
|
|
4952
5041
|
}
|
|
4953
5042
|
|
|
4954
|
-
var version = "0.1.14";
|
|
4955
|
-
|
|
4956
5043
|
// Inserts a box into the specified range.
|
|
4957
5044
|
function insertBox(range, boxName, boxValue) {
|
|
4958
5045
|
if (range.commonAncestor.isOutside) {
|
|
@@ -5030,6 +5117,8 @@ function removeBox(range) {
|
|
|
5030
5117
|
return box;
|
|
5031
5118
|
}
|
|
5032
5119
|
|
|
5120
|
+
var version = "0.1.16";
|
|
5121
|
+
|
|
5033
5122
|
// Returns the attributes of the element as an key-value object.
|
|
5034
5123
|
function getAttributes(node) {
|
|
5035
5124
|
const nativeNode = node.get(0);
|
|
@@ -5167,9 +5256,6 @@ class Selection {
|
|
|
5167
5256
|
insertFragment(fragment) {
|
|
5168
5257
|
return insertFragment(this.range, fragment);
|
|
5169
5258
|
}
|
|
5170
|
-
insertContents(value) {
|
|
5171
|
-
return insertContents(this.range, value);
|
|
5172
|
-
}
|
|
5173
5259
|
deleteContents() {
|
|
5174
5260
|
return deleteContents(this.range);
|
|
5175
5261
|
}
|
|
@@ -5209,7 +5295,7 @@ class Selection {
|
|
|
5209
5295
|
insertBox(boxName, boxValue) {
|
|
5210
5296
|
const box = insertBox(this.range, boxName, boxValue);
|
|
5211
5297
|
if (!box) {
|
|
5212
|
-
throw new Error(`Box
|
|
5298
|
+
throw new Error(`Box "${boxName}" cannot be inserted outside the editor.`);
|
|
5213
5299
|
}
|
|
5214
5300
|
return box;
|
|
5215
5301
|
}
|
|
@@ -5242,7 +5328,7 @@ class Command {
|
|
|
5242
5328
|
getItem(name) {
|
|
5243
5329
|
const commandItem = this.commandMap.get(name);
|
|
5244
5330
|
if (commandItem === undefined) {
|
|
5245
|
-
throw new Error(`Command
|
|
5331
|
+
throw new Error(`Command "${name}" has not been defined yet.`);
|
|
5246
5332
|
}
|
|
5247
5333
|
return commandItem;
|
|
5248
5334
|
}
|
|
@@ -5312,7 +5398,7 @@ class History {
|
|
|
5312
5398
|
addIdToBoxes(node) {
|
|
5313
5399
|
node.find('lake-box').each(nativeNode => {
|
|
5314
5400
|
const boxNode = new Nodes(nativeNode);
|
|
5315
|
-
const id =
|
|
5401
|
+
const id = `${boxNode.attr('name')}-${boxNode.attr('value')}`;
|
|
5316
5402
|
boxNode.attr('id', id);
|
|
5317
5403
|
});
|
|
5318
5404
|
}
|
|
@@ -5553,9 +5639,9 @@ class Plugin {
|
|
|
5553
5639
|
this.pluginList.push(plugin);
|
|
5554
5640
|
}
|
|
5555
5641
|
loadAll(editor) {
|
|
5556
|
-
this.pluginList
|
|
5642
|
+
for (const plugin of this.pluginList) {
|
|
5557
5643
|
plugin(editor);
|
|
5558
|
-
}
|
|
5644
|
+
}
|
|
5559
5645
|
}
|
|
5560
5646
|
}
|
|
5561
5647
|
|
|
@@ -5568,6 +5654,7 @@ const defaultConfig = {
|
|
|
5568
5654
|
indentWithTab: true,
|
|
5569
5655
|
lang: 'en-US',
|
|
5570
5656
|
minChangeSize: 5,
|
|
5657
|
+
historySize: 100,
|
|
5571
5658
|
onMessage: (type, message) => {
|
|
5572
5659
|
if (type === 'success') {
|
|
5573
5660
|
// eslint-disable-next-line no-console
|
|
@@ -5679,11 +5766,8 @@ class Editor {
|
|
|
5679
5766
|
boxContainer.removeClass('lake-box-selected');
|
|
5680
5767
|
box.event.emit('blur');
|
|
5681
5768
|
});
|
|
5682
|
-
this.event.emit('boxselectionstylechange');
|
|
5683
5769
|
}, 50, {
|
|
5684
|
-
|
|
5685
|
-
trailing: true,
|
|
5686
|
-
maxWait: 50,
|
|
5770
|
+
immediate: true,
|
|
5687
5771
|
});
|
|
5688
5772
|
// Triggers the statechange event when the current selection of the editor is changed.
|
|
5689
5773
|
this.emitStateChangeEvent = debounce(() => {
|
|
@@ -5727,10 +5811,8 @@ class Editor {
|
|
|
5727
5811
|
}
|
|
5728
5812
|
this.event.emit('statechange', state);
|
|
5729
5813
|
this.state = state;
|
|
5730
|
-
},
|
|
5731
|
-
|
|
5732
|
-
trailing: true,
|
|
5733
|
-
maxWait: 100,
|
|
5814
|
+
}, 50, {
|
|
5815
|
+
immediate: false,
|
|
5734
5816
|
});
|
|
5735
5817
|
if (!config.root) {
|
|
5736
5818
|
throw new Error('The root of the config must be specified.');
|
|
@@ -5758,6 +5840,7 @@ class Editor {
|
|
|
5758
5840
|
this.selection = new Selection(this.container);
|
|
5759
5841
|
this.command = new Command(this.selection);
|
|
5760
5842
|
this.history = new History(this.selection);
|
|
5843
|
+
this.history.limit = this.config.historySize;
|
|
5761
5844
|
this.keystroke = new Keystroke(this.container);
|
|
5762
5845
|
editors.set(this.container.id, this);
|
|
5763
5846
|
}
|
|
@@ -5983,8 +6066,12 @@ class Editor {
|
|
|
5983
6066
|
}
|
|
5984
6067
|
// Scrolls to the caret or the range of the selection.
|
|
5985
6068
|
scrollToCaret() {
|
|
6069
|
+
const range = this.selection.range;
|
|
6070
|
+
if (range.isBox) {
|
|
6071
|
+
return;
|
|
6072
|
+
}
|
|
5986
6073
|
// Creates an artificial caret that is the same size as the caret at the current caret position.
|
|
5987
|
-
const rangeRect =
|
|
6074
|
+
const rangeRect = range.getRect();
|
|
5988
6075
|
if (rangeRect.x === 0 || rangeRect.y === 0) {
|
|
5989
6076
|
return;
|
|
5990
6077
|
}
|
|
@@ -6281,7 +6368,7 @@ const moreStyleMenuItems = [
|
|
|
6281
6368
|
text: locale => locale.toolbar.code(),
|
|
6282
6369
|
},
|
|
6283
6370
|
];
|
|
6284
|
-
// These colors are from Ant Design (https://ant.design/docs/spec/colors)
|
|
6371
|
+
// These colors are sourced from Ant Design (https://ant.design/docs/spec/colors)
|
|
6285
6372
|
const colors = [
|
|
6286
6373
|
// Dust Red, Volcano, Sunset Orange, Calendula Gold, Sunrise Yellow, Lime, Polar Green, Cyan, Daybreak Blue, Geek Blue, Golden Purple, Magenta
|
|
6287
6374
|
'#f5222d', '#fa541c', '#fa8c16', '#faad14', '#fadb14', '#a0d911', '#52c41a', '#13c2c2', '#1677ff', '#2f54eb', '#722ed1', '#eb2f96', // color 6
|
|
@@ -6556,19 +6643,19 @@ const toolbarItems = [
|
|
|
6556
6643
|
},
|
|
6557
6644
|
},
|
|
6558
6645
|
{
|
|
6559
|
-
name: '
|
|
6646
|
+
name: 'codeBlock',
|
|
6560
6647
|
type: 'button',
|
|
6561
|
-
icon: icons.get('
|
|
6562
|
-
tooltip: locale => locale.toolbar.
|
|
6648
|
+
icon: icons.get('codeBlock'),
|
|
6649
|
+
tooltip: locale => locale.toolbar.codeBlock(),
|
|
6563
6650
|
onClick: (editor, value) => {
|
|
6564
6651
|
editor.command.execute(value);
|
|
6565
6652
|
},
|
|
6566
6653
|
},
|
|
6567
6654
|
{
|
|
6568
|
-
name: '
|
|
6655
|
+
name: 'video',
|
|
6569
6656
|
type: 'button',
|
|
6570
|
-
icon: icons.get('
|
|
6571
|
-
tooltip: locale => locale.toolbar.
|
|
6657
|
+
icon: icons.get('video'),
|
|
6658
|
+
tooltip: locale => locale.toolbar.video(),
|
|
6572
6659
|
onClick: (editor, value) => {
|
|
6573
6660
|
editor.command.execute(value);
|
|
6574
6661
|
},
|
|
@@ -6591,9 +6678,7 @@ const toolbarItems = [
|
|
|
6591
6678
|
type: 'dropdown',
|
|
6592
6679
|
downIcon: icons.get('down'),
|
|
6593
6680
|
icon: icons.get('list'),
|
|
6594
|
-
defaultValue: '',
|
|
6595
6681
|
tooltip: locale => locale.toolbar.list(),
|
|
6596
|
-
width: 'auto',
|
|
6597
6682
|
menuType: 'list',
|
|
6598
6683
|
menuItems: listMenuItems,
|
|
6599
6684
|
onSelect: (editor, value) => {
|
|
@@ -6605,9 +6690,7 @@ const toolbarItems = [
|
|
|
6605
6690
|
type: 'dropdown',
|
|
6606
6691
|
downIcon: icons.get('down'),
|
|
6607
6692
|
icon: icons.get('alignLeft'),
|
|
6608
|
-
defaultValue: '',
|
|
6609
6693
|
tooltip: locale => locale.toolbar.align(),
|
|
6610
|
-
width: 'auto',
|
|
6611
6694
|
menuType: 'list',
|
|
6612
6695
|
menuItems: alignMenuItems,
|
|
6613
6696
|
onSelect: (editor, value) => {
|
|
@@ -6619,9 +6702,7 @@ const toolbarItems = [
|
|
|
6619
6702
|
type: 'dropdown',
|
|
6620
6703
|
downIcon: icons.get('down'),
|
|
6621
6704
|
icon: icons.get('increaseIndent'),
|
|
6622
|
-
defaultValue: '',
|
|
6623
6705
|
tooltip: locale => locale.toolbar.indent(),
|
|
6624
|
-
width: 'auto',
|
|
6625
6706
|
menuType: 'list',
|
|
6626
6707
|
menuItems: indentMenuItems,
|
|
6627
6708
|
onSelect: (editor, value) => {
|
|
@@ -6658,9 +6739,7 @@ const toolbarItems = [
|
|
|
6658
6739
|
name: 'moreStyle',
|
|
6659
6740
|
type: 'dropdown',
|
|
6660
6741
|
icon: icons.get('more'),
|
|
6661
|
-
defaultValue: '',
|
|
6662
6742
|
tooltip: locale => locale.toolbar.moreStyle(),
|
|
6663
|
-
width: 'auto',
|
|
6664
6743
|
menuType: 'list',
|
|
6665
6744
|
menuItems: moreStyleMenuItems,
|
|
6666
6745
|
selectedValues: appliedItems => {
|
|
@@ -6686,9 +6765,9 @@ const toolbarItems = [
|
|
|
6686
6765
|
accentIcon: icons.get('fontColorAccent'),
|
|
6687
6766
|
defaultValue: '#f5222d',
|
|
6688
6767
|
tooltip: locale => locale.toolbar.fontColor(),
|
|
6689
|
-
width: 'auto',
|
|
6690
6768
|
menuType: 'color',
|
|
6691
6769
|
menuItems: colorMenuItems,
|
|
6770
|
+
menuWidth: '296px',
|
|
6692
6771
|
onSelect: (editor, value) => {
|
|
6693
6772
|
editor.command.execute('fontColor', value);
|
|
6694
6773
|
},
|
|
@@ -6701,9 +6780,9 @@ const toolbarItems = [
|
|
|
6701
6780
|
accentIcon: icons.get('highlightAccent'),
|
|
6702
6781
|
defaultValue: '#fadb14',
|
|
6703
6782
|
tooltip: locale => locale.toolbar.highlight(),
|
|
6704
|
-
width: 'auto',
|
|
6705
6783
|
menuType: 'color',
|
|
6706
6784
|
menuItems: colorMenuItems,
|
|
6785
|
+
menuWidth: '296px',
|
|
6707
6786
|
onSelect: (editor, value) => {
|
|
6708
6787
|
editor.command.execute('highlight', value);
|
|
6709
6788
|
},
|
|
@@ -6726,64 +6805,6 @@ const toolbarItems = [
|
|
|
6726
6805
|
},
|
|
6727
6806
|
];
|
|
6728
6807
|
|
|
6729
|
-
function uploadFile(config) {
|
|
6730
|
-
const { editor, name, file, onError, onSuccess } = config;
|
|
6731
|
-
const { requestMethod, requestAction, requestTypes } = editor.config[name];
|
|
6732
|
-
if (requestTypes.indexOf(file.type) < 0) {
|
|
6733
|
-
if (onError) {
|
|
6734
|
-
onError(`File '${file.name}' is not allowed for uploading.`);
|
|
6735
|
-
}
|
|
6736
|
-
throw new Error(`Cannot upload file '${file.name}' because its type '${file.type}' is not found in ['${requestTypes.join('\', \'')}'].`);
|
|
6737
|
-
}
|
|
6738
|
-
const box = editor.selection.insertBox(name, {
|
|
6739
|
-
url: URL.createObjectURL(file),
|
|
6740
|
-
status: 'uploading',
|
|
6741
|
-
name: file.name,
|
|
6742
|
-
size: file.size,
|
|
6743
|
-
type: file.type,
|
|
6744
|
-
lastModified: file.lastModified,
|
|
6745
|
-
});
|
|
6746
|
-
const xhr = request({
|
|
6747
|
-
onProgress: e => {
|
|
6748
|
-
const percentNode = box.node.find('.lake-percent');
|
|
6749
|
-
const percent = Math.round(e.percent);
|
|
6750
|
-
percentNode.text(`${percent < 100 ? percent : 99} %`);
|
|
6751
|
-
},
|
|
6752
|
-
onError: (error, body) => {
|
|
6753
|
-
debug(error.toString(), body);
|
|
6754
|
-
box.updateValue('status', 'error');
|
|
6755
|
-
box.render();
|
|
6756
|
-
if (onError) {
|
|
6757
|
-
onError(error.toString());
|
|
6758
|
-
}
|
|
6759
|
-
},
|
|
6760
|
-
onSuccess: body => {
|
|
6761
|
-
if (!body.url) {
|
|
6762
|
-
box.updateValue('status', 'error');
|
|
6763
|
-
box.render();
|
|
6764
|
-
if (onError) {
|
|
6765
|
-
onError('Cannot find the url field.');
|
|
6766
|
-
}
|
|
6767
|
-
return;
|
|
6768
|
-
}
|
|
6769
|
-
box.updateValue({
|
|
6770
|
-
status: 'done',
|
|
6771
|
-
url: body.url,
|
|
6772
|
-
});
|
|
6773
|
-
box.render();
|
|
6774
|
-
editor.history.save();
|
|
6775
|
-
if (onSuccess) {
|
|
6776
|
-
onSuccess();
|
|
6777
|
-
}
|
|
6778
|
-
},
|
|
6779
|
-
file,
|
|
6780
|
-
action: requestAction,
|
|
6781
|
-
method: requestMethod,
|
|
6782
|
-
});
|
|
6783
|
-
box.setData('xhr', xhr);
|
|
6784
|
-
return box;
|
|
6785
|
-
}
|
|
6786
|
-
|
|
6787
6808
|
const defaultItems = [
|
|
6788
6809
|
'undo',
|
|
6789
6810
|
'redo',
|
|
@@ -6806,9 +6827,9 @@ const defaultItems = [
|
|
|
6806
6827
|
'hr',
|
|
6807
6828
|
];
|
|
6808
6829
|
const toolbarItemMap = new Map();
|
|
6809
|
-
|
|
6830
|
+
for (const item of toolbarItems) {
|
|
6810
6831
|
toolbarItemMap.set(item.name, item);
|
|
6811
|
-
}
|
|
6832
|
+
}
|
|
6812
6833
|
class Toolbar {
|
|
6813
6834
|
constructor(config) {
|
|
6814
6835
|
this.placement = 'top';
|
|
@@ -6853,6 +6874,8 @@ class Toolbar {
|
|
|
6853
6874
|
width: item.width,
|
|
6854
6875
|
menuType: item.menuType,
|
|
6855
6876
|
menuItems: item.menuItems,
|
|
6877
|
+
menuWidth: item.menuWidth,
|
|
6878
|
+
menuHeight: item.menuHeight,
|
|
6856
6879
|
tabIndex: -1,
|
|
6857
6880
|
placement: this.placement === 'top' ? 'bottom' : 'top',
|
|
6858
6881
|
onSelect: value => {
|
|
@@ -6954,7 +6977,7 @@ class Toolbar {
|
|
|
6954
6977
|
Dropdown.setValue(dropdownNode, selectedValues);
|
|
6955
6978
|
const textNode = dropdownNode.find('.lake-dropdown-text');
|
|
6956
6979
|
if (textNode.length > 0) {
|
|
6957
|
-
const key = selectedValues[0] || item.defaultValue;
|
|
6980
|
+
const key = selectedValues[0] || item.defaultValue || '';
|
|
6958
6981
|
const menuMap = this.allMenuMap.get(item.name);
|
|
6959
6982
|
const text = (_a = (menuMap && menuMap.get(key))) !== null && _a !== void 0 ? _a : key;
|
|
6960
6983
|
textNode.text(text);
|
|
@@ -6966,36 +6989,35 @@ class Toolbar {
|
|
|
6966
6989
|
render(editor) {
|
|
6967
6990
|
this.root.empty();
|
|
6968
6991
|
this.root.append(this.container);
|
|
6969
|
-
this.items
|
|
6992
|
+
for (const name of this.items) {
|
|
6970
6993
|
if (name === '|') {
|
|
6971
6994
|
this.appendDivider();
|
|
6972
|
-
return;
|
|
6973
|
-
}
|
|
6974
|
-
let item;
|
|
6975
|
-
if (typeof name === 'string') {
|
|
6976
|
-
item = toolbarItemMap.get(name);
|
|
6977
|
-
if (!item) {
|
|
6978
|
-
return;
|
|
6979
|
-
}
|
|
6980
6995
|
}
|
|
6981
6996
|
else {
|
|
6982
|
-
item
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
+
let item;
|
|
6998
|
+
if (typeof name === 'string') {
|
|
6999
|
+
item = toolbarItemMap.get(name);
|
|
7000
|
+
if (!item) {
|
|
7001
|
+
throw new Error(`ToolbarItem "${name}" has not been defined yet.`);
|
|
7002
|
+
}
|
|
7003
|
+
}
|
|
7004
|
+
else {
|
|
7005
|
+
item = name;
|
|
7006
|
+
}
|
|
7007
|
+
if (item.type === 'button') {
|
|
7008
|
+
this.buttonItemList.push(item);
|
|
7009
|
+
this.appendButton(editor, item);
|
|
7010
|
+
}
|
|
7011
|
+
else if (item.type === 'dropdown') {
|
|
7012
|
+
this.allMenuMap.set(item.name, Dropdown.getMenuMap(item.menuItems, editor.locale));
|
|
7013
|
+
this.dropdownItemList.push(item);
|
|
7014
|
+
this.appendDropdown(editor, item);
|
|
7015
|
+
}
|
|
7016
|
+
else if (item.type === 'upload') {
|
|
7017
|
+
this.appendUpload(editor, item);
|
|
7018
|
+
}
|
|
6997
7019
|
}
|
|
6998
|
-
}
|
|
7020
|
+
}
|
|
6999
7021
|
}
|
|
7000
7022
|
}
|
|
7001
7023
|
|
|
@@ -7007,247 +7029,15 @@ const hrBox = {
|
|
|
7007
7029
|
if (!editor) {
|
|
7008
7030
|
return;
|
|
7009
7031
|
}
|
|
7010
|
-
const
|
|
7011
|
-
box.getContainer().append(
|
|
7012
|
-
|
|
7032
|
+
const rootNode = query('<div class="lake-hr"><hr /></div>');
|
|
7033
|
+
box.getContainer().append(rootNode);
|
|
7034
|
+
rootNode.on('click', () => {
|
|
7013
7035
|
editor.selection.selectBox(box);
|
|
7014
7036
|
});
|
|
7015
7037
|
},
|
|
7016
7038
|
html: () => '<hr />',
|
|
7017
7039
|
};
|
|
7018
7040
|
|
|
7019
|
-
class BoxResizer {
|
|
7020
|
-
constructor(config) {
|
|
7021
|
-
this.config = config;
|
|
7022
|
-
this.root = config.root;
|
|
7023
|
-
this.box = config.box;
|
|
7024
|
-
}
|
|
7025
|
-
bindEvents(pointerNode) {
|
|
7026
|
-
const box = this.box;
|
|
7027
|
-
const boxContainer = box.getContainer();
|
|
7028
|
-
const resizerNode = pointerNode.closest('.lake-resizer');
|
|
7029
|
-
const infoNode = resizerNode.find('.lake-resizer-info');
|
|
7030
|
-
const isPlus = pointerNode.attr('class').indexOf('-right') >= 0;
|
|
7031
|
-
const initialWidth = boxContainer.width();
|
|
7032
|
-
const initialHeight = boxContainer.height();
|
|
7033
|
-
const rate = initialHeight / initialWidth;
|
|
7034
|
-
let clientX = 0;
|
|
7035
|
-
let width = 0;
|
|
7036
|
-
// resizing box
|
|
7037
|
-
const pointermoveListener = (event) => {
|
|
7038
|
-
const pointerEvent = event;
|
|
7039
|
-
const diffX = pointerEvent.clientX - clientX;
|
|
7040
|
-
const newWidth = Math.round(isPlus ? width + diffX : width - diffX);
|
|
7041
|
-
const newHeight = Math.round(rate * newWidth);
|
|
7042
|
-
infoNode.text(`${newWidth} x ${newHeight}`);
|
|
7043
|
-
boxContainer.css({
|
|
7044
|
-
width: `${newWidth}px`,
|
|
7045
|
-
height: `${newHeight}px`,
|
|
7046
|
-
});
|
|
7047
|
-
if (this.config.onResize) {
|
|
7048
|
-
this.config.onResize(newWidth, newHeight);
|
|
7049
|
-
}
|
|
7050
|
-
};
|
|
7051
|
-
// start resizing
|
|
7052
|
-
const pointerdownListener = (event) => {
|
|
7053
|
-
const pointerEvent = event;
|
|
7054
|
-
const pointerNativeNode = pointerNode.get(0);
|
|
7055
|
-
// The capture will be implicitly released after a pointerup or pointercancel event.
|
|
7056
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture
|
|
7057
|
-
pointerNativeNode.setPointerCapture(pointerEvent.pointerId);
|
|
7058
|
-
clientX = pointerEvent.clientX;
|
|
7059
|
-
width = boxContainer.width();
|
|
7060
|
-
infoNode.show();
|
|
7061
|
-
pointerNode.on('pointermove', pointermoveListener);
|
|
7062
|
-
};
|
|
7063
|
-
// stop resizing
|
|
7064
|
-
const pointerupListner = () => {
|
|
7065
|
-
pointerNode.off('pointermove');
|
|
7066
|
-
infoNode.hide();
|
|
7067
|
-
width = box.getContainer().width();
|
|
7068
|
-
const height = Math.round(rate * width);
|
|
7069
|
-
this.config.onStop(width, height);
|
|
7070
|
-
};
|
|
7071
|
-
// cancel resizing
|
|
7072
|
-
const pointercancelListner = () => {
|
|
7073
|
-
pointerNode.off('pointermove');
|
|
7074
|
-
infoNode.hide();
|
|
7075
|
-
};
|
|
7076
|
-
pointerNode.on('pointerdown', pointerdownListener);
|
|
7077
|
-
pointerNode.on('pointerup', pointerupListner);
|
|
7078
|
-
pointerNode.on('pointercancel', pointercancelListner);
|
|
7079
|
-
}
|
|
7080
|
-
render() {
|
|
7081
|
-
const { width, height } = this.config;
|
|
7082
|
-
const resizerNode = query(safeTemplate `
|
|
7083
|
-
<div class="lake-resizer">
|
|
7084
|
-
<div class="lake-resizer-top-left"></div>
|
|
7085
|
-
<div class="lake-resizer-top-right"></div>
|
|
7086
|
-
<div class="lake-resizer-bottom-left"></div>
|
|
7087
|
-
<div class="lake-resizer-bottom-right"></div>
|
|
7088
|
-
<div class="lake-resizer-info">${width} x ${height}</div>
|
|
7089
|
-
</div>
|
|
7090
|
-
`);
|
|
7091
|
-
this.bindEvents(resizerNode.find('.lake-resizer-top-left'));
|
|
7092
|
-
this.bindEvents(resizerNode.find('.lake-resizer-top-right'));
|
|
7093
|
-
this.bindEvents(resizerNode.find('.lake-resizer-bottom-left'));
|
|
7094
|
-
this.bindEvents(resizerNode.find('.lake-resizer-bottom-right'));
|
|
7095
|
-
this.root.append(resizerNode);
|
|
7096
|
-
}
|
|
7097
|
-
}
|
|
7098
|
-
|
|
7099
|
-
function getVideoId(url) {
|
|
7100
|
-
const result = /\w+$/i.exec(url || '');
|
|
7101
|
-
return result ? result[0] : '';
|
|
7102
|
-
}
|
|
7103
|
-
function getInputValue(videoNode, name) {
|
|
7104
|
-
const inputElement = videoNode.find(`input[name="${name}"]`);
|
|
7105
|
-
const nativeInputElement = inputElement.get(0);
|
|
7106
|
-
return nativeInputElement.value;
|
|
7107
|
-
}
|
|
7108
|
-
function appendButtonGroup(box) {
|
|
7109
|
-
const editor = box.getEditor();
|
|
7110
|
-
if (!editor) {
|
|
7111
|
-
return;
|
|
7112
|
-
}
|
|
7113
|
-
const boxContainer = box.getContainer();
|
|
7114
|
-
const videoNode = boxContainer.find('.lake-video');
|
|
7115
|
-
const buttonGroupNode = query(safeTemplate `
|
|
7116
|
-
<div class="lake-button-group">
|
|
7117
|
-
<button type="button" tabindex="-1" class="lake-button-remove" title="${editor.locale.video.remove()}"></button>
|
|
7118
|
-
</div>
|
|
7119
|
-
`);
|
|
7120
|
-
const removeButton = buttonGroupNode.find('.lake-button-remove');
|
|
7121
|
-
const removeIcon = icons.get('remove');
|
|
7122
|
-
if (removeIcon) {
|
|
7123
|
-
removeButton.append(removeIcon);
|
|
7124
|
-
}
|
|
7125
|
-
buttonGroupNode.find('.lake-button-remove').on('click', event => {
|
|
7126
|
-
event.stopPropagation();
|
|
7127
|
-
editor.selection.removeBox(box);
|
|
7128
|
-
editor.history.save();
|
|
7129
|
-
});
|
|
7130
|
-
videoNode.append(buttonGroupNode);
|
|
7131
|
-
}
|
|
7132
|
-
function showVideo(box) {
|
|
7133
|
-
const editor = box.getEditor();
|
|
7134
|
-
if (!editor) {
|
|
7135
|
-
return;
|
|
7136
|
-
}
|
|
7137
|
-
const boxContainer = box.getContainer();
|
|
7138
|
-
const value = box.value;
|
|
7139
|
-
const width = value.width || 560;
|
|
7140
|
-
const height = value.height || 315;
|
|
7141
|
-
boxContainer.css({
|
|
7142
|
-
width: `${width}px`,
|
|
7143
|
-
height: `${height}px`,
|
|
7144
|
-
});
|
|
7145
|
-
const videoId = getVideoId(value.url);
|
|
7146
|
-
if (videoId === '') {
|
|
7147
|
-
throw new Error(`Invalid link: ${value.url}`);
|
|
7148
|
-
}
|
|
7149
|
-
// YouTube URL: https://www.youtube.com/watch?v=5sMBhDv4sik
|
|
7150
|
-
// The script for embedding YouTube:
|
|
7151
|
-
// <iframe width="560" height="315" src="https://www.youtube.com/embed/5sMBhDv4sik" title="YouTube video player"
|
|
7152
|
-
// frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
|
7153
|
-
// referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
|
7154
|
-
const iframeNode = query(safeTemplate `
|
|
7155
|
-
<iframe width="100%" height="${height}" src="https://www.youtube.com/embed/${videoId}" title="YouTube video player"
|
|
7156
|
-
frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
|
7157
|
-
referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
|
7158
|
-
`);
|
|
7159
|
-
const videoNode = boxContainer.find('.lake-video');
|
|
7160
|
-
if (!editor.readonly) {
|
|
7161
|
-
iframeNode.on('load', () => {
|
|
7162
|
-
appendButtonGroup(box);
|
|
7163
|
-
new BoxResizer({
|
|
7164
|
-
root: videoNode,
|
|
7165
|
-
box,
|
|
7166
|
-
width,
|
|
7167
|
-
height,
|
|
7168
|
-
onResize: (newWidth, newHeight) => {
|
|
7169
|
-
iframeNode.attr({
|
|
7170
|
-
height: newHeight.toString(),
|
|
7171
|
-
});
|
|
7172
|
-
},
|
|
7173
|
-
onStop: (newWidth, newHeight) => {
|
|
7174
|
-
box.updateValue({
|
|
7175
|
-
width: newWidth,
|
|
7176
|
-
height: newHeight,
|
|
7177
|
-
});
|
|
7178
|
-
editor.history.save();
|
|
7179
|
-
},
|
|
7180
|
-
}).render();
|
|
7181
|
-
});
|
|
7182
|
-
}
|
|
7183
|
-
videoNode.append(iframeNode);
|
|
7184
|
-
}
|
|
7185
|
-
const videoBox = {
|
|
7186
|
-
type: 'inline',
|
|
7187
|
-
name: 'video',
|
|
7188
|
-
render: box => {
|
|
7189
|
-
const editor = box.getEditor();
|
|
7190
|
-
if (!editor) {
|
|
7191
|
-
return;
|
|
7192
|
-
}
|
|
7193
|
-
const locale = editor.locale;
|
|
7194
|
-
const value = box.value;
|
|
7195
|
-
const boxContainer = box.getContainer();
|
|
7196
|
-
const videoNode = query('<div class="lake-video" />');
|
|
7197
|
-
boxContainer.empty();
|
|
7198
|
-
boxContainer.css({
|
|
7199
|
-
width: '',
|
|
7200
|
-
height: '',
|
|
7201
|
-
});
|
|
7202
|
-
boxContainer.append(videoNode);
|
|
7203
|
-
if (!value.url) {
|
|
7204
|
-
if (editor.readonly) {
|
|
7205
|
-
box.node.hide();
|
|
7206
|
-
return;
|
|
7207
|
-
}
|
|
7208
|
-
const formNode = query(safeTemplate `
|
|
7209
|
-
<div class="lake-video-form">
|
|
7210
|
-
<div class="lake-row lake-desc-row">${locale.video.description()}</div>
|
|
7211
|
-
<div class="lake-row">${locale.video.url()}</div>
|
|
7212
|
-
<div class="lake-row">
|
|
7213
|
-
<input type="text" name="url" placeholder="https://www.youtube.com/watch?v=..." />
|
|
7214
|
-
</div>
|
|
7215
|
-
<div class="lake-row lake-button-row"></div>
|
|
7216
|
-
</div>
|
|
7217
|
-
`);
|
|
7218
|
-
const button = new Button({
|
|
7219
|
-
root: formNode.find('.lake-button-row'),
|
|
7220
|
-
name: 'embed',
|
|
7221
|
-
type: 'primary',
|
|
7222
|
-
text: locale.video.embed(),
|
|
7223
|
-
onClick: () => {
|
|
7224
|
-
const url = getInputValue(formNode, 'url');
|
|
7225
|
-
if (url.indexOf('https://www.youtube.com/') < 0 || getVideoId(url) === '') {
|
|
7226
|
-
editor.config.onMessage('error', locale.video.urlError());
|
|
7227
|
-
return;
|
|
7228
|
-
}
|
|
7229
|
-
box.updateValue('url', url);
|
|
7230
|
-
editor.history.save();
|
|
7231
|
-
formNode.remove();
|
|
7232
|
-
showVideo(box);
|
|
7233
|
-
},
|
|
7234
|
-
});
|
|
7235
|
-
formNode.find('input[name="url"]').on('keydown', createKeybindingsHandler({
|
|
7236
|
-
'Enter': event => {
|
|
7237
|
-
event.preventDefault();
|
|
7238
|
-
button.node.emit('click');
|
|
7239
|
-
},
|
|
7240
|
-
}));
|
|
7241
|
-
button.render();
|
|
7242
|
-
videoNode.append(formNode);
|
|
7243
|
-
appendButtonGroup(box);
|
|
7244
|
-
}
|
|
7245
|
-
else {
|
|
7246
|
-
showVideo(box);
|
|
7247
|
-
}
|
|
7248
|
-
},
|
|
7249
|
-
};
|
|
7250
|
-
|
|
7251
7041
|
const config = {
|
|
7252
7042
|
comment: '#57606a',
|
|
7253
7043
|
name: '#444d56',
|
|
@@ -7334,12 +7124,12 @@ const codeBlockBox = {
|
|
|
7334
7124
|
if (!editor) {
|
|
7335
7125
|
return;
|
|
7336
7126
|
}
|
|
7337
|
-
const
|
|
7127
|
+
const rootNode = query('<div class="lake-code-block" />');
|
|
7338
7128
|
const container = box.getContainer();
|
|
7339
7129
|
container.css('width', `${editor.container.innerWidth() - 2}px`);
|
|
7340
7130
|
container.empty();
|
|
7341
|
-
container.append(
|
|
7342
|
-
const codeBlockNativeNode =
|
|
7131
|
+
container.append(rootNode);
|
|
7132
|
+
const codeBlockNativeNode = rootNode.get(0);
|
|
7343
7133
|
if (!codeBlockNativeNode) {
|
|
7344
7134
|
return;
|
|
7345
7135
|
}
|
|
@@ -7350,12 +7140,12 @@ const codeBlockBox = {
|
|
|
7350
7140
|
box.node.hide();
|
|
7351
7141
|
return;
|
|
7352
7142
|
}
|
|
7353
|
-
|
|
7354
|
-
|
|
7143
|
+
rootNode.addClass('lake-code-block-error');
|
|
7144
|
+
rootNode.text(`
|
|
7355
7145
|
The code cannot be displayed because window.LakeCodeMirror is not found.
|
|
7356
7146
|
Please check if the "lake-codemirror" library is added to this page.
|
|
7357
7147
|
`.trim());
|
|
7358
|
-
|
|
7148
|
+
rootNode.on('click', () => {
|
|
7359
7149
|
editor.selection.selectBox(box);
|
|
7360
7150
|
});
|
|
7361
7151
|
return;
|
|
@@ -7405,36 +7195,40 @@ const codeBlockBox = {
|
|
|
7405
7195
|
updateListener,
|
|
7406
7196
|
],
|
|
7407
7197
|
});
|
|
7408
|
-
|
|
7198
|
+
rootNode.find('[contenteditable="true"]').attr('tabindex', '-1');
|
|
7409
7199
|
const dropdown = new Dropdown({
|
|
7410
|
-
root:
|
|
7200
|
+
root: rootNode,
|
|
7411
7201
|
name: 'langType',
|
|
7412
7202
|
downIcon: icons.get('down'),
|
|
7413
7203
|
defaultValue: langItem ? boxValue.lang : codeBlockConfig.defaultLang,
|
|
7414
7204
|
tooltip: editor.locale.codeBlock.langType(),
|
|
7415
|
-
width: 'auto',
|
|
7416
7205
|
menuType: 'list',
|
|
7206
|
+
menuHeight: '200px',
|
|
7417
7207
|
menuItems: langItems.map((item) => ({
|
|
7418
7208
|
value: item.value,
|
|
7419
7209
|
text: item.text,
|
|
7420
7210
|
})),
|
|
7421
7211
|
onSelect: value => {
|
|
7422
|
-
const item = langItemMap.get(value);
|
|
7423
|
-
codeEditor.dispatch({
|
|
7424
|
-
effects: language.reconfigure(item && item.component ? item.component() : []),
|
|
7425
|
-
});
|
|
7426
7212
|
box.updateValue({
|
|
7427
7213
|
lang: value,
|
|
7428
7214
|
});
|
|
7215
|
+
box.unmount();
|
|
7216
|
+
box.render();
|
|
7217
|
+
editor.selection.selectBox(box);
|
|
7429
7218
|
editor.history.save();
|
|
7430
7219
|
},
|
|
7431
7220
|
});
|
|
7432
7221
|
dropdown.render();
|
|
7433
|
-
box.setData('codeEditor', codeEditor);
|
|
7434
7222
|
const resizeListener = () => {
|
|
7435
7223
|
container.css('width', `${editor.container.innerWidth() - 2}px`);
|
|
7436
7224
|
};
|
|
7437
7225
|
editor.event.on('resize', resizeListener);
|
|
7226
|
+
rootNode.on('click', () => {
|
|
7227
|
+
if (codeEditor.hasFocus) {
|
|
7228
|
+
return;
|
|
7229
|
+
}
|
|
7230
|
+
codeEditor.focus();
|
|
7231
|
+
});
|
|
7438
7232
|
box.event.on('beforeunmount', () => {
|
|
7439
7233
|
codeEditor.destroy();
|
|
7440
7234
|
editor.event.off('resize', resizeListener);
|
|
@@ -7475,6 +7269,86 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
7475
7269
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
7476
7270
|
};
|
|
7477
7271
|
|
|
7272
|
+
class BoxResizer {
|
|
7273
|
+
constructor(config) {
|
|
7274
|
+
this.config = config;
|
|
7275
|
+
this.root = config.root;
|
|
7276
|
+
this.box = config.box;
|
|
7277
|
+
}
|
|
7278
|
+
bindEvents(pointerNode) {
|
|
7279
|
+
const box = this.box;
|
|
7280
|
+
const boxContainer = box.getContainer();
|
|
7281
|
+
const resizerNode = pointerNode.closest('.lake-resizer');
|
|
7282
|
+
const infoNode = resizerNode.find('.lake-resizer-info');
|
|
7283
|
+
const isPlus = pointerNode.attr('class').indexOf('-right') >= 0;
|
|
7284
|
+
const initialWidth = boxContainer.width();
|
|
7285
|
+
const initialHeight = boxContainer.height();
|
|
7286
|
+
const rate = initialHeight / initialWidth;
|
|
7287
|
+
let clientX = 0;
|
|
7288
|
+
let width = 0;
|
|
7289
|
+
// resizing box
|
|
7290
|
+
const pointermoveListener = (event) => {
|
|
7291
|
+
const pointerEvent = event;
|
|
7292
|
+
const diffX = pointerEvent.clientX - clientX;
|
|
7293
|
+
const newWidth = Math.round(isPlus ? width + diffX : width - diffX);
|
|
7294
|
+
const newHeight = Math.round(rate * newWidth);
|
|
7295
|
+
infoNode.text(`${newWidth} x ${newHeight}`);
|
|
7296
|
+
boxContainer.css({
|
|
7297
|
+
width: `${newWidth}px`,
|
|
7298
|
+
height: `${newHeight}px`,
|
|
7299
|
+
});
|
|
7300
|
+
if (this.config.onResize) {
|
|
7301
|
+
this.config.onResize(newWidth, newHeight);
|
|
7302
|
+
}
|
|
7303
|
+
};
|
|
7304
|
+
// start resizing
|
|
7305
|
+
const pointerdownListener = (event) => {
|
|
7306
|
+
const pointerEvent = event;
|
|
7307
|
+
const pointerNativeNode = pointerNode.get(0);
|
|
7308
|
+
// The capture will be implicitly released after a pointerup or pointercancel event.
|
|
7309
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture
|
|
7310
|
+
pointerNativeNode.setPointerCapture(pointerEvent.pointerId);
|
|
7311
|
+
clientX = pointerEvent.clientX;
|
|
7312
|
+
width = boxContainer.width();
|
|
7313
|
+
infoNode.show();
|
|
7314
|
+
pointerNode.on('pointermove', pointermoveListener);
|
|
7315
|
+
};
|
|
7316
|
+
// stop resizing
|
|
7317
|
+
const pointerupListner = () => {
|
|
7318
|
+
pointerNode.off('pointermove');
|
|
7319
|
+
infoNode.hide();
|
|
7320
|
+
width = box.getContainer().width();
|
|
7321
|
+
const height = Math.round(rate * width);
|
|
7322
|
+
this.config.onStop(width, height);
|
|
7323
|
+
};
|
|
7324
|
+
// cancel resizing
|
|
7325
|
+
const pointercancelListner = () => {
|
|
7326
|
+
pointerNode.off('pointermove');
|
|
7327
|
+
infoNode.hide();
|
|
7328
|
+
};
|
|
7329
|
+
pointerNode.on('pointerdown', pointerdownListener);
|
|
7330
|
+
pointerNode.on('pointerup', pointerupListner);
|
|
7331
|
+
pointerNode.on('pointercancel', pointercancelListner);
|
|
7332
|
+
}
|
|
7333
|
+
render() {
|
|
7334
|
+
const { width, height } = this.config;
|
|
7335
|
+
const resizerNode = query(safeTemplate `
|
|
7336
|
+
<div class="lake-resizer">
|
|
7337
|
+
<div class="lake-resizer-top-left"></div>
|
|
7338
|
+
<div class="lake-resizer-top-right"></div>
|
|
7339
|
+
<div class="lake-resizer-bottom-left"></div>
|
|
7340
|
+
<div class="lake-resizer-bottom-right"></div>
|
|
7341
|
+
<div class="lake-resizer-info">${width} x ${height}</div>
|
|
7342
|
+
</div>
|
|
7343
|
+
`);
|
|
7344
|
+
this.bindEvents(resizerNode.find('.lake-resizer-top-left'));
|
|
7345
|
+
this.bindEvents(resizerNode.find('.lake-resizer-top-right'));
|
|
7346
|
+
this.bindEvents(resizerNode.find('.lake-resizer-bottom-left'));
|
|
7347
|
+
this.bindEvents(resizerNode.find('.lake-resizer-bottom-right'));
|
|
7348
|
+
this.root.append(resizerNode);
|
|
7349
|
+
}
|
|
7350
|
+
}
|
|
7351
|
+
|
|
7478
7352
|
// Loads an image and get its width and height.
|
|
7479
7353
|
function getImageInfo(url) {
|
|
7480
7354
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -7612,7 +7486,7 @@ function openFullScreen(box) {
|
|
|
7612
7486
|
lightbox.loadAndOpen(currentIndex);
|
|
7613
7487
|
}
|
|
7614
7488
|
// Displays error icon and filename.
|
|
7615
|
-
function renderError(
|
|
7489
|
+
function renderError(rootNode, box) {
|
|
7616
7490
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7617
7491
|
const editor = box.getEditor();
|
|
7618
7492
|
if (!editor) {
|
|
@@ -7643,12 +7517,12 @@ function renderError(imageNode, box) {
|
|
|
7643
7517
|
if (imageIcon) {
|
|
7644
7518
|
errorNode.find('.lake-error-icon').append(imageIcon);
|
|
7645
7519
|
}
|
|
7646
|
-
|
|
7647
|
-
|
|
7520
|
+
rootNode.append(buttonGroupNode);
|
|
7521
|
+
rootNode.append(errorNode);
|
|
7648
7522
|
});
|
|
7649
7523
|
}
|
|
7650
7524
|
// Displays an image with uplaoding progress.
|
|
7651
|
-
function renderUploading(
|
|
7525
|
+
function renderUploading(rootNode, box) {
|
|
7652
7526
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7653
7527
|
const editor = box.getEditor();
|
|
7654
7528
|
if (!editor) {
|
|
@@ -7657,7 +7531,7 @@ function renderUploading(imageNode, box) {
|
|
|
7657
7531
|
const value = box.value;
|
|
7658
7532
|
const imageInfo = yield getImageInfo(value.url);
|
|
7659
7533
|
if (!imageInfo.width || !imageInfo.height) {
|
|
7660
|
-
yield renderError(
|
|
7534
|
+
yield renderError(rootNode, box);
|
|
7661
7535
|
return;
|
|
7662
7536
|
}
|
|
7663
7537
|
const maxWidth = editor.container.innerWidth() - 2;
|
|
@@ -7702,13 +7576,13 @@ function renderUploading(imageNode, box) {
|
|
|
7702
7576
|
draggable: 'false',
|
|
7703
7577
|
alt: value.name,
|
|
7704
7578
|
});
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7579
|
+
rootNode.append(buttonGroupNode);
|
|
7580
|
+
rootNode.append(progressNode);
|
|
7581
|
+
rootNode.append(imgNode);
|
|
7708
7582
|
});
|
|
7709
7583
|
}
|
|
7710
7584
|
// Displays an image that can be previewed or removed.
|
|
7711
|
-
function renderDone(
|
|
7585
|
+
function renderDone(rootNode, box) {
|
|
7712
7586
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7713
7587
|
const editor = box.getEditor();
|
|
7714
7588
|
if (!editor) {
|
|
@@ -7721,7 +7595,7 @@ function renderDone(imageNode, box) {
|
|
|
7721
7595
|
return;
|
|
7722
7596
|
}
|
|
7723
7597
|
if (!imageInfo.width || !imageInfo.height) {
|
|
7724
|
-
yield renderError(
|
|
7598
|
+
yield renderError(rootNode, box);
|
|
7725
7599
|
return;
|
|
7726
7600
|
}
|
|
7727
7601
|
let width = value.width;
|
|
@@ -7764,9 +7638,9 @@ function renderDone(imageNode, box) {
|
|
|
7764
7638
|
draggable: 'false',
|
|
7765
7639
|
alt: value.name,
|
|
7766
7640
|
});
|
|
7767
|
-
|
|
7641
|
+
rootNode.append(buttonGroupNode);
|
|
7768
7642
|
new BoxResizer({
|
|
7769
|
-
root:
|
|
7643
|
+
root: rootNode,
|
|
7770
7644
|
box,
|
|
7771
7645
|
width,
|
|
7772
7646
|
height,
|
|
@@ -7778,7 +7652,7 @@ function renderDone(imageNode, box) {
|
|
|
7778
7652
|
editor.history.save();
|
|
7779
7653
|
},
|
|
7780
7654
|
}).render();
|
|
7781
|
-
|
|
7655
|
+
rootNode.append(imgNode);
|
|
7782
7656
|
});
|
|
7783
7657
|
}
|
|
7784
7658
|
const imageBox = {
|
|
@@ -7819,45 +7693,193 @@ const imageBox = {
|
|
|
7819
7693
|
if (value.status === 'loading') {
|
|
7820
7694
|
return;
|
|
7821
7695
|
}
|
|
7822
|
-
const
|
|
7823
|
-
|
|
7696
|
+
const rootNode = query('<div class="lake-image" />');
|
|
7697
|
+
rootNode.addClass(`lake-image-${value.status}`);
|
|
7824
7698
|
let promise;
|
|
7825
7699
|
if (value.status === 'uploading') {
|
|
7826
|
-
promise = renderUploading(
|
|
7700
|
+
promise = renderUploading(rootNode, box);
|
|
7827
7701
|
}
|
|
7828
7702
|
else if (value.status === 'error') {
|
|
7829
|
-
promise = renderError(
|
|
7703
|
+
promise = renderError(rootNode, box);
|
|
7830
7704
|
}
|
|
7831
7705
|
else {
|
|
7832
|
-
promise = renderDone(
|
|
7706
|
+
promise = renderDone(rootNode, box);
|
|
7833
7707
|
}
|
|
7834
7708
|
promise.then(() => {
|
|
7835
7709
|
container.empty();
|
|
7836
|
-
container.append(
|
|
7837
|
-
|
|
7710
|
+
container.append(rootNode);
|
|
7711
|
+
rootNode.find('.lake-button-view').on('click', () => openFullScreen(box));
|
|
7838
7712
|
if (editor.readonly) {
|
|
7839
|
-
|
|
7713
|
+
rootNode.find('.lake-button-remove').hide();
|
|
7840
7714
|
}
|
|
7841
7715
|
else {
|
|
7842
|
-
|
|
7716
|
+
rootNode.find('.lake-button-remove').on('click', event => {
|
|
7843
7717
|
event.stopPropagation();
|
|
7844
|
-
const xhr = box.getData('xhr');
|
|
7845
|
-
if (xhr) {
|
|
7846
|
-
xhr.abort();
|
|
7847
|
-
}
|
|
7848
7718
|
editor.selection.removeBox(box);
|
|
7849
7719
|
editor.history.save();
|
|
7850
7720
|
});
|
|
7851
7721
|
}
|
|
7852
7722
|
box.event.emit('render');
|
|
7853
7723
|
});
|
|
7854
|
-
|
|
7724
|
+
rootNode.on('click', () => {
|
|
7855
7725
|
editor.selection.selectBox(box);
|
|
7856
7726
|
});
|
|
7857
7727
|
},
|
|
7858
7728
|
html: box => {
|
|
7859
|
-
const
|
|
7860
|
-
return safeTemplate `<img src="${box.value.url}" data-lake-value="${
|
|
7729
|
+
const rawValue = box.node.attr('value');
|
|
7730
|
+
return safeTemplate `<img src="${box.value.url}" data-lake-value="${rawValue}" />`;
|
|
7731
|
+
},
|
|
7732
|
+
};
|
|
7733
|
+
|
|
7734
|
+
function getVideoId(url) {
|
|
7735
|
+
const result = /\w+$/i.exec(url || '');
|
|
7736
|
+
return result ? result[0] : '';
|
|
7737
|
+
}
|
|
7738
|
+
function getInputValue(videoNode, name) {
|
|
7739
|
+
const inputElement = videoNode.find(`input[name="${name}"]`);
|
|
7740
|
+
const nativeInputElement = inputElement.get(0);
|
|
7741
|
+
return nativeInputElement.value;
|
|
7742
|
+
}
|
|
7743
|
+
function appendButtonGroup(box) {
|
|
7744
|
+
const editor = box.getEditor();
|
|
7745
|
+
if (!editor) {
|
|
7746
|
+
return;
|
|
7747
|
+
}
|
|
7748
|
+
const boxContainer = box.getContainer();
|
|
7749
|
+
const videoNode = boxContainer.find('.lake-video');
|
|
7750
|
+
const buttonGroupNode = query(safeTemplate `
|
|
7751
|
+
<div class="lake-button-group">
|
|
7752
|
+
<button type="button" tabindex="-1" class="lake-button-remove" title="${editor.locale.video.remove()}"></button>
|
|
7753
|
+
</div>
|
|
7754
|
+
`);
|
|
7755
|
+
const removeButton = buttonGroupNode.find('.lake-button-remove');
|
|
7756
|
+
const removeIcon = icons.get('remove');
|
|
7757
|
+
if (removeIcon) {
|
|
7758
|
+
removeButton.append(removeIcon);
|
|
7759
|
+
}
|
|
7760
|
+
buttonGroupNode.find('.lake-button-remove').on('click', event => {
|
|
7761
|
+
event.stopPropagation();
|
|
7762
|
+
editor.selection.removeBox(box);
|
|
7763
|
+
editor.history.save();
|
|
7764
|
+
});
|
|
7765
|
+
videoNode.append(buttonGroupNode);
|
|
7766
|
+
}
|
|
7767
|
+
function showVideo(box) {
|
|
7768
|
+
const editor = box.getEditor();
|
|
7769
|
+
if (!editor) {
|
|
7770
|
+
return;
|
|
7771
|
+
}
|
|
7772
|
+
const boxContainer = box.getContainer();
|
|
7773
|
+
const value = box.value;
|
|
7774
|
+
const width = value.width || 560;
|
|
7775
|
+
const height = value.height || 315;
|
|
7776
|
+
boxContainer.css({
|
|
7777
|
+
width: `${width}px`,
|
|
7778
|
+
height: `${height}px`,
|
|
7779
|
+
});
|
|
7780
|
+
const videoId = getVideoId(value.url);
|
|
7781
|
+
if (videoId === '') {
|
|
7782
|
+
throw new Error(`Invalid link: ${value.url}`);
|
|
7783
|
+
}
|
|
7784
|
+
// YouTube URL: https://www.youtube.com/watch?v=5sMBhDv4sik
|
|
7785
|
+
// The script for embedding YouTube:
|
|
7786
|
+
// <iframe width="560" height="315" src="https://www.youtube.com/embed/5sMBhDv4sik" title="YouTube video player"
|
|
7787
|
+
// frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
|
7788
|
+
// referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
|
7789
|
+
const iframeNode = query(safeTemplate `
|
|
7790
|
+
<iframe width="100%" height="${height}" src="https://www.youtube.com/embed/${videoId}" title="YouTube video player"
|
|
7791
|
+
frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
|
7792
|
+
referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
|
7793
|
+
`);
|
|
7794
|
+
const rootNode = boxContainer.find('.lake-video');
|
|
7795
|
+
if (!editor.readonly) {
|
|
7796
|
+
iframeNode.on('load', () => {
|
|
7797
|
+
appendButtonGroup(box);
|
|
7798
|
+
new BoxResizer({
|
|
7799
|
+
root: rootNode,
|
|
7800
|
+
box,
|
|
7801
|
+
width,
|
|
7802
|
+
height,
|
|
7803
|
+
onResize: (newWidth, newHeight) => {
|
|
7804
|
+
iframeNode.attr({
|
|
7805
|
+
height: newHeight.toString(),
|
|
7806
|
+
});
|
|
7807
|
+
},
|
|
7808
|
+
onStop: (newWidth, newHeight) => {
|
|
7809
|
+
box.updateValue({
|
|
7810
|
+
width: newWidth,
|
|
7811
|
+
height: newHeight,
|
|
7812
|
+
});
|
|
7813
|
+
editor.history.save();
|
|
7814
|
+
},
|
|
7815
|
+
}).render();
|
|
7816
|
+
});
|
|
7817
|
+
}
|
|
7818
|
+
rootNode.append(iframeNode);
|
|
7819
|
+
}
|
|
7820
|
+
const videoBox = {
|
|
7821
|
+
type: 'inline',
|
|
7822
|
+
name: 'video',
|
|
7823
|
+
render: box => {
|
|
7824
|
+
const editor = box.getEditor();
|
|
7825
|
+
if (!editor) {
|
|
7826
|
+
return;
|
|
7827
|
+
}
|
|
7828
|
+
const locale = editor.locale;
|
|
7829
|
+
const value = box.value;
|
|
7830
|
+
const boxContainer = box.getContainer();
|
|
7831
|
+
const rootNode = query('<div class="lake-video" />');
|
|
7832
|
+
boxContainer.empty();
|
|
7833
|
+
boxContainer.css({
|
|
7834
|
+
width: '',
|
|
7835
|
+
height: '',
|
|
7836
|
+
});
|
|
7837
|
+
boxContainer.append(rootNode);
|
|
7838
|
+
if (!value.url) {
|
|
7839
|
+
if (editor.readonly) {
|
|
7840
|
+
box.node.hide();
|
|
7841
|
+
return;
|
|
7842
|
+
}
|
|
7843
|
+
const formNode = query(safeTemplate `
|
|
7844
|
+
<div class="lake-video-form">
|
|
7845
|
+
<div class="lake-row lake-desc-row">${locale.video.description()}</div>
|
|
7846
|
+
<div class="lake-row">${locale.video.url()}</div>
|
|
7847
|
+
<div class="lake-row">
|
|
7848
|
+
<input type="text" name="url" placeholder="https://www.youtube.com/watch?v=..." />
|
|
7849
|
+
</div>
|
|
7850
|
+
<div class="lake-row lake-button-row"></div>
|
|
7851
|
+
</div>
|
|
7852
|
+
`);
|
|
7853
|
+
const button = new Button({
|
|
7854
|
+
root: formNode.find('.lake-button-row'),
|
|
7855
|
+
name: 'embed',
|
|
7856
|
+
type: 'primary',
|
|
7857
|
+
text: locale.video.embed(),
|
|
7858
|
+
onClick: () => {
|
|
7859
|
+
const url = getInputValue(formNode, 'url');
|
|
7860
|
+
if (url.indexOf('https://www.youtube.com/') < 0 || getVideoId(url) === '') {
|
|
7861
|
+
editor.config.onMessage('error', locale.video.urlError());
|
|
7862
|
+
return;
|
|
7863
|
+
}
|
|
7864
|
+
box.updateValue('url', url);
|
|
7865
|
+
editor.history.save();
|
|
7866
|
+
formNode.remove();
|
|
7867
|
+
showVideo(box);
|
|
7868
|
+
},
|
|
7869
|
+
});
|
|
7870
|
+
formNode.find('input[name="url"]').on('keydown', createKeybindingsHandler({
|
|
7871
|
+
'Enter': event => {
|
|
7872
|
+
event.preventDefault();
|
|
7873
|
+
button.node.emit('click');
|
|
7874
|
+
},
|
|
7875
|
+
}));
|
|
7876
|
+
button.render();
|
|
7877
|
+
rootNode.append(formNode);
|
|
7878
|
+
appendButtonGroup(box);
|
|
7879
|
+
}
|
|
7880
|
+
else {
|
|
7881
|
+
showVideo(box);
|
|
7882
|
+
}
|
|
7861
7883
|
},
|
|
7862
7884
|
};
|
|
7863
7885
|
|
|
@@ -7886,7 +7908,7 @@ const boxToolbarItems = [
|
|
|
7886
7908
|
},
|
|
7887
7909
|
},
|
|
7888
7910
|
];
|
|
7889
|
-
function appendContent(
|
|
7911
|
+
function appendContent(rootNode, box) {
|
|
7890
7912
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7891
7913
|
const editor = box.getEditor();
|
|
7892
7914
|
if (!editor) {
|
|
@@ -7919,7 +7941,7 @@ function appendContent(fileNode, box) {
|
|
|
7919
7941
|
typeNode.append(fileIcon);
|
|
7920
7942
|
}
|
|
7921
7943
|
}
|
|
7922
|
-
|
|
7944
|
+
rootNode.append(infoNode);
|
|
7923
7945
|
});
|
|
7924
7946
|
}
|
|
7925
7947
|
const fileBox = {
|
|
@@ -7936,26 +7958,45 @@ const fileBox = {
|
|
|
7936
7958
|
return;
|
|
7937
7959
|
}
|
|
7938
7960
|
const container = box.getContainer();
|
|
7939
|
-
const
|
|
7940
|
-
|
|
7941
|
-
appendContent(
|
|
7961
|
+
const rootNode = query('<div class="lake-file" />');
|
|
7962
|
+
rootNode.addClass(`lake-file-${value.status}`);
|
|
7963
|
+
appendContent(rootNode, box);
|
|
7942
7964
|
container.empty();
|
|
7943
|
-
container.append(
|
|
7965
|
+
container.append(rootNode);
|
|
7944
7966
|
if (!editor.readonly) {
|
|
7945
|
-
|
|
7967
|
+
rootNode.on('click', () => {
|
|
7946
7968
|
editor.selection.selectBox(box);
|
|
7947
7969
|
});
|
|
7948
7970
|
const items = value.status === 'done' ? boxToolbarItems : boxToolbarItems.filter(item => item.name === 'remove');
|
|
7949
7971
|
box.setToolbar(items);
|
|
7950
7972
|
}
|
|
7951
7973
|
else {
|
|
7952
|
-
|
|
7974
|
+
rootNode.on('click', () => {
|
|
7953
7975
|
window.open(value.url);
|
|
7954
7976
|
});
|
|
7955
7977
|
}
|
|
7956
7978
|
},
|
|
7957
7979
|
};
|
|
7958
7980
|
|
|
7981
|
+
const emojiBox = {
|
|
7982
|
+
type: 'inline',
|
|
7983
|
+
name: 'emoji',
|
|
7984
|
+
render: box => {
|
|
7985
|
+
const editor = box.getEditor();
|
|
7986
|
+
if (!editor) {
|
|
7987
|
+
return;
|
|
7988
|
+
}
|
|
7989
|
+
const value = box.value;
|
|
7990
|
+
const rootNode = query(safeTemplate `
|
|
7991
|
+
<div class="lake-emoji"><img src="${value.url}" title="${value.title}" /></div>
|
|
7992
|
+
`);
|
|
7993
|
+
box.getContainer().append(rootNode);
|
|
7994
|
+
rootNode.on('click', () => {
|
|
7995
|
+
editor.selection.selectBox(box);
|
|
7996
|
+
});
|
|
7997
|
+
},
|
|
7998
|
+
};
|
|
7999
|
+
|
|
7959
8000
|
var copy = (editor) => {
|
|
7960
8001
|
editor.event.on('copy', event => {
|
|
7961
8002
|
const range = editor.selection.range;
|
|
@@ -9249,21 +9290,6 @@ var hr = (editor) => {
|
|
|
9249
9290
|
});
|
|
9250
9291
|
};
|
|
9251
9292
|
|
|
9252
|
-
var video = (editor) => {
|
|
9253
|
-
if (editor.readonly) {
|
|
9254
|
-
return;
|
|
9255
|
-
}
|
|
9256
|
-
editor.command.add('video', {
|
|
9257
|
-
execute: (value) => {
|
|
9258
|
-
const box = editor.selection.insertBox('video', value);
|
|
9259
|
-
editor.history.save();
|
|
9260
|
-
if (box) {
|
|
9261
|
-
box.getContainer().find('input[name="url"]').focus();
|
|
9262
|
-
}
|
|
9263
|
-
},
|
|
9264
|
-
});
|
|
9265
|
-
};
|
|
9266
|
-
|
|
9267
9293
|
const langList = [
|
|
9268
9294
|
'text',
|
|
9269
9295
|
'c',
|
|
@@ -9299,8 +9325,7 @@ var codeBlock = (editor) => {
|
|
|
9299
9325
|
execute: (value) => {
|
|
9300
9326
|
const box = editor.selection.insertBox('codeBlock', value);
|
|
9301
9327
|
editor.history.save();
|
|
9302
|
-
|
|
9303
|
-
codeEditor.focus();
|
|
9328
|
+
box.getContainer().find('.lake-code-block').emit('click');
|
|
9304
9329
|
},
|
|
9305
9330
|
});
|
|
9306
9331
|
};
|
|
@@ -9339,6 +9364,21 @@ var image = (editor) => {
|
|
|
9339
9364
|
});
|
|
9340
9365
|
};
|
|
9341
9366
|
|
|
9367
|
+
var video = (editor) => {
|
|
9368
|
+
if (editor.readonly) {
|
|
9369
|
+
return;
|
|
9370
|
+
}
|
|
9371
|
+
editor.command.add('video', {
|
|
9372
|
+
execute: (value) => {
|
|
9373
|
+
const box = editor.selection.insertBox('video', value);
|
|
9374
|
+
editor.history.save();
|
|
9375
|
+
if (box) {
|
|
9376
|
+
box.getContainer().find('input[name="url"]').focus();
|
|
9377
|
+
}
|
|
9378
|
+
},
|
|
9379
|
+
});
|
|
9380
|
+
};
|
|
9381
|
+
|
|
9342
9382
|
var file = (editor) => {
|
|
9343
9383
|
editor.setPluginConfig('file', {
|
|
9344
9384
|
requestMethod: 'POST',
|
|
@@ -9372,6 +9412,18 @@ var file = (editor) => {
|
|
|
9372
9412
|
});
|
|
9373
9413
|
};
|
|
9374
9414
|
|
|
9415
|
+
var emoji = (editor) => {
|
|
9416
|
+
if (editor.readonly) {
|
|
9417
|
+
return;
|
|
9418
|
+
}
|
|
9419
|
+
editor.command.add('emoji', {
|
|
9420
|
+
execute: (value) => {
|
|
9421
|
+
editor.selection.insertBox('emoji', value);
|
|
9422
|
+
editor.history.save();
|
|
9423
|
+
},
|
|
9424
|
+
});
|
|
9425
|
+
};
|
|
9426
|
+
|
|
9375
9427
|
const headingTypeMap = new Map([
|
|
9376
9428
|
['#', 'h1'],
|
|
9377
9429
|
['##', 'h2'],
|
|
@@ -9714,7 +9766,7 @@ function splitBlock(editor, block) {
|
|
|
9714
9766
|
block.find('li').attr('value', 'false');
|
|
9715
9767
|
}
|
|
9716
9768
|
}
|
|
9717
|
-
function
|
|
9769
|
+
function addOrSplitBlockForBox(editor) {
|
|
9718
9770
|
const range = editor.selection.range;
|
|
9719
9771
|
const boxNode = range.startNode.closest('lake-box');
|
|
9720
9772
|
const block = boxNode.closestBlock();
|
|
@@ -9758,7 +9810,7 @@ var enterKey = (editor) => {
|
|
|
9758
9810
|
event.preventDefault();
|
|
9759
9811
|
editor.fixContent();
|
|
9760
9812
|
if (range.isBox) {
|
|
9761
|
-
|
|
9813
|
+
addOrSplitBlockForBox(editor);
|
|
9762
9814
|
editor.history.save();
|
|
9763
9815
|
return;
|
|
9764
9816
|
}
|
|
@@ -9767,7 +9819,7 @@ var enterKey = (editor) => {
|
|
|
9767
9819
|
return;
|
|
9768
9820
|
}
|
|
9769
9821
|
if (range.isBox) {
|
|
9770
|
-
|
|
9822
|
+
addOrSplitBlockForBox(editor);
|
|
9771
9823
|
editor.history.save();
|
|
9772
9824
|
return;
|
|
9773
9825
|
}
|
|
@@ -9793,7 +9845,9 @@ function addLineBreak(editor) {
|
|
|
9793
9845
|
const prevNode = range.getPrevNode();
|
|
9794
9846
|
const endText = range.getEndText();
|
|
9795
9847
|
if (prevNode.name !== 'br' && endText === '') {
|
|
9796
|
-
|
|
9848
|
+
const fragment = new Fragment();
|
|
9849
|
+
fragment.append('<br /><br />');
|
|
9850
|
+
editor.selection.insertFragment(fragment);
|
|
9797
9851
|
editor.history.save();
|
|
9798
9852
|
return;
|
|
9799
9853
|
}
|
|
@@ -10142,13 +10196,14 @@ var tabKey = (editor) => {
|
|
|
10142
10196
|
}
|
|
10143
10197
|
event.preventDefault();
|
|
10144
10198
|
const blocks = editor.selection.range.getBlocks();
|
|
10145
|
-
|
|
10199
|
+
for (const block of blocks) {
|
|
10146
10200
|
if (block.name !== 'p' || block.css('text-indent') === '2em') {
|
|
10147
10201
|
setBlockIndent(block, 'increase');
|
|
10148
|
-
return;
|
|
10149
10202
|
}
|
|
10150
|
-
|
|
10151
|
-
|
|
10203
|
+
else {
|
|
10204
|
+
block.css('text-indent', '2em');
|
|
10205
|
+
}
|
|
10206
|
+
}
|
|
10152
10207
|
editor.history.save();
|
|
10153
10208
|
});
|
|
10154
10209
|
};
|
|
@@ -10299,10 +10354,11 @@ var escapeKey = (editor) => {
|
|
|
10299
10354
|
};
|
|
10300
10355
|
|
|
10301
10356
|
Editor.box.add(hrBox);
|
|
10302
|
-
Editor.box.add(videoBox);
|
|
10303
10357
|
Editor.box.add(codeBlockBox);
|
|
10304
10358
|
Editor.box.add(imageBox);
|
|
10359
|
+
Editor.box.add(videoBox);
|
|
10305
10360
|
Editor.box.add(fileBox);
|
|
10361
|
+
Editor.box.add(emojiBox);
|
|
10306
10362
|
Editor.plugin.add(copy);
|
|
10307
10363
|
Editor.plugin.add(cut);
|
|
10308
10364
|
Editor.plugin.add(paste);
|
|
@@ -10330,10 +10386,11 @@ Editor.plugin.add(removeFormat);
|
|
|
10330
10386
|
Editor.plugin.add(formatPainter);
|
|
10331
10387
|
Editor.plugin.add(link);
|
|
10332
10388
|
Editor.plugin.add(hr);
|
|
10333
|
-
Editor.plugin.add(video);
|
|
10334
10389
|
Editor.plugin.add(codeBlock);
|
|
10335
10390
|
Editor.plugin.add(image);
|
|
10391
|
+
Editor.plugin.add(video);
|
|
10336
10392
|
Editor.plugin.add(file);
|
|
10393
|
+
Editor.plugin.add(emoji);
|
|
10337
10394
|
Editor.plugin.add(markdown);
|
|
10338
10395
|
Editor.plugin.add(enterKey);
|
|
10339
10396
|
Editor.plugin.add(shiftEnterKey);
|
|
@@ -10343,5 +10400,5 @@ Editor.plugin.add(tabKey);
|
|
|
10343
10400
|
Editor.plugin.add(arrowKeys);
|
|
10344
10401
|
Editor.plugin.add(escapeKey);
|
|
10345
10402
|
|
|
10346
|
-
export { Box, Button, Dropdown, Editor, Fragment, HTMLParser, Nodes, Range, TextParser, Toolbar, index as Utils, addMark, deleteContents, fixList, icons, insertBookmark,
|
|
10403
|
+
export { Box, Button, Dropdown, Editor, Fragment, HTMLParser, Nodes, Range, TextParser, Toolbar, index as Utils, addMark, deleteContents, fixList, icons, insertBookmark, insertBox, insertFragment, insertLink, insertNode, removeBox, removeMark, setBlocks, splitBlock$1 as splitBlock, splitMarks, toBookmark };
|
|
10347
10404
|
//# sourceMappingURL=lake.js.map
|