lakelib 0.1.13 → 0.1.15
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 +4 -4
- package/dist/lake.css +268 -218
- package/dist/lake.min.js +40 -38
- package/dist/lake.min.js.map +1 -1
- package/lib/lake.css +268 -218
- package/lib/lake.js +727 -677
- package/lib/lake.js.map +1 -1
- package/lib/types/boxes/emoji.d.ts +2 -0
- package/lib/types/css/index.d.ts +5 -5
- package/lib/types/editor.d.ts +7 -9
- 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/command.d.ts +0 -2
- package/lib/types/managers/history.d.ts +11 -5
- 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/operations/insert-fragment.d.ts +2 -1
- package/lib/types/plugins/emoji.d.ts +3 -0
- package/lib/types/types/dropdown.d.ts +4 -3
- package/lib/types/utils/index.d.ts +1 -0
- package/package.json +1 -1
- 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
|
@@ -135,17 +135,19 @@ var unlink = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32
|
|
|
135
135
|
|
|
136
136
|
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
137
|
|
|
138
|
+
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>";
|
|
139
|
+
|
|
138
140
|
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
141
|
|
|
140
142
|
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
143
|
|
|
142
144
|
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
145
|
|
|
144
|
-
var
|
|
146
|
+
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
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,11 @@ 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],
|
|
224
227
|
['table', table],
|
|
225
228
|
]);
|
|
226
229
|
|
|
@@ -269,9 +272,10 @@ function safeTemplate(strings, ...keys) {
|
|
|
269
272
|
function camelCase(value) {
|
|
270
273
|
const valueList = value.split('-');
|
|
271
274
|
let camelString = '';
|
|
272
|
-
valueList.
|
|
273
|
-
|
|
274
|
-
|
|
275
|
+
for (let i = 0; i < valueList.length; i++) {
|
|
276
|
+
const val = valueList[i];
|
|
277
|
+
camelString += (i > 0) ? val.charAt(0).toUpperCase() + val.substring(1) : val;
|
|
278
|
+
}
|
|
275
279
|
return camelString;
|
|
276
280
|
}
|
|
277
281
|
|
|
@@ -876,15 +880,16 @@ class Nodes {
|
|
|
876
880
|
var _a;
|
|
877
881
|
const elementId = element.lakeId;
|
|
878
882
|
const eventItems = (_a = eventData[elementId]) !== null && _a !== void 0 ? _a : [];
|
|
879
|
-
eventItems.
|
|
883
|
+
for (let i = 0; i < eventItems.length; i++) {
|
|
884
|
+
const item = eventItems[i];
|
|
880
885
|
if (!type || type === item.type && (!listener || listener === item.listener)) {
|
|
881
886
|
element.removeEventListener(item.type, item.listener, false);
|
|
882
|
-
eventItems[
|
|
887
|
+
eventItems[i] = {
|
|
883
888
|
type: '',
|
|
884
889
|
listener: () => { },
|
|
885
890
|
};
|
|
886
891
|
}
|
|
887
|
-
}
|
|
892
|
+
}
|
|
888
893
|
eventData[elementId] = eventItems.filter((item) => item.type !== '');
|
|
889
894
|
});
|
|
890
895
|
}
|
|
@@ -893,11 +898,11 @@ class Nodes {
|
|
|
893
898
|
return this.eachElement(element => {
|
|
894
899
|
const elementId = element.lakeId;
|
|
895
900
|
const eventItems = eventData[elementId];
|
|
896
|
-
|
|
901
|
+
for (const item of eventItems) {
|
|
897
902
|
if (item.type === type) {
|
|
898
903
|
item.listener(event !== null && event !== void 0 ? event : new Event(type));
|
|
899
904
|
}
|
|
900
|
-
}
|
|
905
|
+
}
|
|
901
906
|
});
|
|
902
907
|
}
|
|
903
908
|
// Gets all event listeners attached to the Nodes object.
|
|
@@ -953,9 +958,9 @@ class Nodes {
|
|
|
953
958
|
}
|
|
954
959
|
addClass(className) {
|
|
955
960
|
if (Array.isArray(className)) {
|
|
956
|
-
|
|
961
|
+
for (const name of className) {
|
|
957
962
|
this.addClass(name);
|
|
958
|
-
}
|
|
963
|
+
}
|
|
959
964
|
return this;
|
|
960
965
|
}
|
|
961
966
|
return this.eachElement(element => {
|
|
@@ -967,9 +972,9 @@ class Nodes {
|
|
|
967
972
|
}
|
|
968
973
|
removeClass(className) {
|
|
969
974
|
if (Array.isArray(className)) {
|
|
970
|
-
|
|
975
|
+
for (const name of className) {
|
|
971
976
|
this.removeClass(name);
|
|
972
|
-
}
|
|
977
|
+
}
|
|
973
978
|
return this;
|
|
974
979
|
}
|
|
975
980
|
return this.eachElement(element => {
|
|
@@ -1061,22 +1066,21 @@ class Nodes {
|
|
|
1061
1066
|
this.html('');
|
|
1062
1067
|
return this;
|
|
1063
1068
|
}
|
|
1064
|
-
// Inserts the specified content
|
|
1069
|
+
// Inserts the specified content to the beginning of the first element.
|
|
1065
1070
|
prepend(content) {
|
|
1071
|
+
const element = this.get(0);
|
|
1066
1072
|
if (typeof content === 'string') {
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
});
|
|
1073
|
+
const list = toNodeList(content).reverse();
|
|
1074
|
+
for (const node of list) {
|
|
1075
|
+
if (element.firstChild) {
|
|
1076
|
+
element.insertBefore(node, element.firstChild);
|
|
1077
|
+
}
|
|
1078
|
+
else {
|
|
1079
|
+
element.appendChild(node);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
return this;
|
|
1078
1083
|
}
|
|
1079
|
-
const element = this.get(0);
|
|
1080
1084
|
if (content instanceof Nodes) {
|
|
1081
1085
|
content = content.get(0);
|
|
1082
1086
|
}
|
|
@@ -1088,71 +1092,62 @@ class Nodes {
|
|
|
1088
1092
|
}
|
|
1089
1093
|
return this;
|
|
1090
1094
|
}
|
|
1091
|
-
// Inserts the specified content
|
|
1095
|
+
// Inserts the specified content to the end of the first element.
|
|
1092
1096
|
append(content) {
|
|
1097
|
+
const element = this.get(0);
|
|
1093
1098
|
if (typeof content === 'string') {
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
});
|
|
1099
|
+
const list = toNodeList(content);
|
|
1100
|
+
for (const node of list) {
|
|
1101
|
+
element.appendChild(node);
|
|
1102
|
+
}
|
|
1103
|
+
return this;
|
|
1100
1104
|
}
|
|
1101
|
-
const element = this.get(0);
|
|
1102
1105
|
if (content instanceof Nodes) {
|
|
1103
1106
|
content = content.get(0);
|
|
1104
1107
|
}
|
|
1105
1108
|
element.appendChild(content);
|
|
1106
1109
|
return this;
|
|
1107
1110
|
}
|
|
1108
|
-
// Inserts the specified content before
|
|
1111
|
+
// Inserts the specified content before the first node.
|
|
1109
1112
|
before(content) {
|
|
1113
|
+
const node = this.get(0);
|
|
1114
|
+
if (!node.parentNode) {
|
|
1115
|
+
return this;
|
|
1116
|
+
}
|
|
1110
1117
|
if (typeof content === 'string') {
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
}
|
|
1117
|
-
node.parentNode.insertBefore(target, node);
|
|
1118
|
-
});
|
|
1119
|
-
});
|
|
1118
|
+
const list = toNodeList(content);
|
|
1119
|
+
for (const target of list) {
|
|
1120
|
+
node.parentNode.insertBefore(target, node);
|
|
1121
|
+
}
|
|
1122
|
+
return this;
|
|
1120
1123
|
}
|
|
1121
|
-
const node = this.get(0);
|
|
1122
1124
|
if (content instanceof Nodes) {
|
|
1123
1125
|
content = content.get(0);
|
|
1124
1126
|
}
|
|
1125
|
-
if (!node.parentNode) {
|
|
1126
|
-
return this;
|
|
1127
|
-
}
|
|
1128
1127
|
node.parentNode.insertBefore(content, node);
|
|
1129
1128
|
return this;
|
|
1130
1129
|
}
|
|
1131
|
-
// Inserts the specified content after
|
|
1130
|
+
// Inserts the specified content after the first node.
|
|
1132
1131
|
after(content) {
|
|
1132
|
+
const node = this.get(0);
|
|
1133
|
+
if (!node.parentNode) {
|
|
1134
|
+
return this;
|
|
1135
|
+
}
|
|
1133
1136
|
if (typeof content === 'string') {
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
node.parentNode.appendChild(target);
|
|
1145
|
-
}
|
|
1146
|
-
});
|
|
1147
|
-
});
|
|
1137
|
+
const list = toNodeList(content).reverse();
|
|
1138
|
+
for (const target of list) {
|
|
1139
|
+
if (node.nextSibling) {
|
|
1140
|
+
node.parentNode.insertBefore(target, node.nextSibling);
|
|
1141
|
+
}
|
|
1142
|
+
else {
|
|
1143
|
+
node.parentNode.appendChild(target);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
return this;
|
|
1148
1147
|
}
|
|
1149
|
-
const node = this.get(0);
|
|
1150
1148
|
if (content instanceof Nodes) {
|
|
1151
1149
|
content = content.get(0);
|
|
1152
1150
|
}
|
|
1153
|
-
if (!node.parentNode) {
|
|
1154
|
-
return this;
|
|
1155
|
-
}
|
|
1156
1151
|
if (node.nextSibling) {
|
|
1157
1152
|
node.parentNode.insertBefore(content, node.nextSibling);
|
|
1158
1153
|
}
|
|
@@ -1161,21 +1156,21 @@ class Nodes {
|
|
|
1161
1156
|
}
|
|
1162
1157
|
return this;
|
|
1163
1158
|
}
|
|
1164
|
-
// Replaces
|
|
1159
|
+
// Replaces the first node with the provided new content.
|
|
1165
1160
|
replaceWith(newContent) {
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1161
|
+
const node = this.get(0);
|
|
1162
|
+
if (!node.parentNode) {
|
|
1163
|
+
return this;
|
|
1164
|
+
}
|
|
1165
|
+
let target;
|
|
1166
|
+
if (newContent instanceof Nodes) {
|
|
1167
|
+
target = newContent.get(0);
|
|
1168
|
+
}
|
|
1169
|
+
else {
|
|
1170
|
+
target = toNodeList(newContent)[0];
|
|
1171
|
+
}
|
|
1172
|
+
node.parentNode.replaceChild(target, node);
|
|
1173
|
+
return this;
|
|
1179
1174
|
}
|
|
1180
1175
|
// Removes each node from the DOM.
|
|
1181
1176
|
// keepChildren parameter:
|
|
@@ -1470,7 +1465,7 @@ class Range {
|
|
|
1470
1465
|
selectBox(boxNode) {
|
|
1471
1466
|
const boxContainer = boxNode.find('.lake-box-container');
|
|
1472
1467
|
if (boxContainer.length === 0) {
|
|
1473
|
-
throw new Error(`The box cannot be selected because the box
|
|
1468
|
+
throw new Error(`The box cannot be selected because the box "${boxNode.attr('name')}" (id=${boxNode.id}) has not been rendered yet.`);
|
|
1474
1469
|
}
|
|
1475
1470
|
this.setStart(boxContainer, 0);
|
|
1476
1471
|
this.collapseToStart();
|
|
@@ -1479,7 +1474,7 @@ class Range {
|
|
|
1479
1474
|
selectBoxStart(boxNode) {
|
|
1480
1475
|
const boxStrip = boxNode.find('.lake-box-strip');
|
|
1481
1476
|
if (boxStrip.length === 0) {
|
|
1482
|
-
throw new Error(`The box cannot be selected because the box
|
|
1477
|
+
throw new Error(`The box cannot be selected because the box "${boxNode.attr('name')}" (id=${boxNode.id}) has not been rendered yet.`);
|
|
1483
1478
|
}
|
|
1484
1479
|
this.selectNodeContents(boxStrip.eq(0));
|
|
1485
1480
|
this.collapseToStart();
|
|
@@ -1488,7 +1483,7 @@ class Range {
|
|
|
1488
1483
|
selectBoxEnd(boxNode) {
|
|
1489
1484
|
const boxStrip = boxNode.find('.lake-box-strip');
|
|
1490
1485
|
if (boxStrip.length === 0) {
|
|
1491
|
-
throw new Error(`The box cannot be selected because the box
|
|
1486
|
+
throw new Error(`The box cannot be selected because the box "${boxNode.attr('name')}" (id=${boxNode.id}) has not been rendered yet.`);
|
|
1492
1487
|
}
|
|
1493
1488
|
this.selectNodeContents(boxStrip.eq(1));
|
|
1494
1489
|
this.collapseToStart();
|
|
@@ -2020,19 +2015,24 @@ function wrapNodeList(nodeList, wrapper) {
|
|
|
2020
2015
|
wrapper = wrapper.clone(true);
|
|
2021
2016
|
const deepestElement = getDeepest(wrapper);
|
|
2022
2017
|
nodeList[0].before(wrapper);
|
|
2023
|
-
|
|
2018
|
+
for (const node of nodeList) {
|
|
2024
2019
|
deepestElement.append(node);
|
|
2025
|
-
}
|
|
2020
|
+
}
|
|
2026
2021
|
return wrapper;
|
|
2027
2022
|
}
|
|
2028
2023
|
|
|
2029
2024
|
// Removes Zero-width spaces that are dependent on some other text nodes.
|
|
2030
2025
|
function removeZWS(node) {
|
|
2031
2026
|
for (const child of node.getWalker()) {
|
|
2032
|
-
if (child.isText
|
|
2033
|
-
const
|
|
2034
|
-
if (
|
|
2035
|
-
child.
|
|
2027
|
+
if (child.isText) {
|
|
2028
|
+
const text = child.text();
|
|
2029
|
+
if (text === '') {
|
|
2030
|
+
child.remove();
|
|
2031
|
+
}
|
|
2032
|
+
else if (text.length > 1) {
|
|
2033
|
+
if (/\u200B/.test(text)) {
|
|
2034
|
+
child.get(0).nodeValue = text.replace(/\u200B/g, '');
|
|
2035
|
+
}
|
|
2036
2036
|
}
|
|
2037
2037
|
}
|
|
2038
2038
|
}
|
|
@@ -2850,6 +2850,7 @@ var enUS = {
|
|
|
2850
2850
|
highlight: 'Highlight',
|
|
2851
2851
|
image: 'Image',
|
|
2852
2852
|
file: 'File',
|
|
2853
|
+
emoji: 'Emoji',
|
|
2853
2854
|
removeColor: 'Remove color',
|
|
2854
2855
|
},
|
|
2855
2856
|
link: {
|
|
@@ -2933,6 +2934,7 @@ var zhCN = {
|
|
|
2933
2934
|
highlight: '文字背景',
|
|
2934
2935
|
image: '图片',
|
|
2935
2936
|
file: '文件',
|
|
2937
|
+
emoji: '表情',
|
|
2936
2938
|
removeColor: '默认',
|
|
2937
2939
|
},
|
|
2938
2940
|
link: {
|
|
@@ -3016,6 +3018,7 @@ var ja = {
|
|
|
3016
3018
|
highlight: '文字の背景',
|
|
3017
3019
|
image: '画像',
|
|
3018
3020
|
file: 'ファイル',
|
|
3021
|
+
emoji: '絵文字',
|
|
3019
3022
|
removeColor: 'デフォルト',
|
|
3020
3023
|
},
|
|
3021
3024
|
link: {
|
|
@@ -3099,6 +3102,7 @@ var ko = {
|
|
|
3099
3102
|
highlight: '글자 배경',
|
|
3100
3103
|
image: '이미지',
|
|
3101
3104
|
file: '파일',
|
|
3105
|
+
emoji: '이모지',
|
|
3102
3106
|
removeColor: '기본색',
|
|
3103
3107
|
},
|
|
3104
3108
|
link: {
|
|
@@ -3279,7 +3283,7 @@ class Dropdown {
|
|
|
3279
3283
|
}
|
|
3280
3284
|
});
|
|
3281
3285
|
menuNode.css('visibility', 'hidden');
|
|
3282
|
-
menuNode.show(config.menuType === '
|
|
3286
|
+
menuNode.show(config.menuType === 'list' ? 'block' : 'flex');
|
|
3283
3287
|
const dropdownNativeNode = dropdownNode.get(0);
|
|
3284
3288
|
const dropdownRect = dropdownNativeNode.getBoundingClientRect();
|
|
3285
3289
|
// A overflow width on the left side, greater than 0 indicates an overflow.
|
|
@@ -3342,7 +3346,7 @@ class Dropdown {
|
|
|
3342
3346
|
if (dropdownNode.attr('disabled')) {
|
|
3343
3347
|
return;
|
|
3344
3348
|
}
|
|
3345
|
-
const value = dropdownNode.attr('color') || config.defaultValue;
|
|
3349
|
+
const value = dropdownNode.attr('color') || config.defaultValue || '';
|
|
3346
3350
|
config.onSelect(value);
|
|
3347
3351
|
});
|
|
3348
3352
|
}
|
|
@@ -3369,14 +3373,17 @@ class Dropdown {
|
|
|
3369
3373
|
});
|
|
3370
3374
|
}
|
|
3371
3375
|
render() {
|
|
3372
|
-
var _a;
|
|
3376
|
+
var _a, _b;
|
|
3373
3377
|
const config = this.config;
|
|
3378
|
+
const defaultValue = (_a = config.defaultValue) !== null && _a !== void 0 ? _a : '';
|
|
3374
3379
|
const dropdownNode = this.node;
|
|
3375
3380
|
const titleNode = dropdownNode.find('.lake-dropdown-title');
|
|
3376
3381
|
if (!config.downIcon) {
|
|
3377
3382
|
titleNode.addClass('lake-dropdown-title-no-down');
|
|
3378
3383
|
}
|
|
3379
|
-
|
|
3384
|
+
if (config.width) {
|
|
3385
|
+
titleNode.css('width', config.width);
|
|
3386
|
+
}
|
|
3380
3387
|
const tooltip = typeof config.tooltip === 'string' ? config.tooltip : config.tooltip(this.locale);
|
|
3381
3388
|
titleNode.attr('title', tooltip);
|
|
3382
3389
|
const textNode = titleNode.find('.lake-dropdown-text');
|
|
@@ -3393,13 +3400,16 @@ class Dropdown {
|
|
|
3393
3400
|
}
|
|
3394
3401
|
const menuNode = query('<ul class="lake-dropdown-menu" />');
|
|
3395
3402
|
menuNode.addClass(`lake-${config.menuType}-dropdown-menu`);
|
|
3396
|
-
|
|
3403
|
+
if (config.menuWidth) {
|
|
3404
|
+
menuNode.css('width', config.menuWidth);
|
|
3405
|
+
}
|
|
3406
|
+
Dropdown.setValue(dropdownNode, [defaultValue]);
|
|
3397
3407
|
if (textNode.length > 0) {
|
|
3398
3408
|
const menuMap = Dropdown.getMenuMap(config.menuItems, this.locale);
|
|
3399
|
-
textNode.text((
|
|
3409
|
+
textNode.text((_b = menuMap.get(defaultValue)) !== null && _b !== void 0 ? _b : defaultValue);
|
|
3400
3410
|
}
|
|
3401
3411
|
if (config.menuType === 'color') {
|
|
3402
|
-
this.updateColorAccent(titleNode,
|
|
3412
|
+
this.updateColorAccent(titleNode, defaultValue);
|
|
3403
3413
|
}
|
|
3404
3414
|
this.apppendMenuItems(menuNode);
|
|
3405
3415
|
dropdownNode.append(titleNode);
|
|
@@ -3484,21 +3494,19 @@ class BoxToolbar {
|
|
|
3484
3494
|
// Renders a toolbar for the specified box.
|
|
3485
3495
|
render() {
|
|
3486
3496
|
this.root.append(this.container);
|
|
3487
|
-
this.items
|
|
3497
|
+
for (const item of this.items) {
|
|
3488
3498
|
if (item === '|') {
|
|
3489
3499
|
this.appendDivider();
|
|
3490
|
-
return;
|
|
3491
3500
|
}
|
|
3492
|
-
if (item.type === 'button') {
|
|
3501
|
+
else if (item.type === 'button') {
|
|
3493
3502
|
this.buttonItemList.push(item);
|
|
3494
3503
|
this.appendButton(item);
|
|
3495
|
-
return;
|
|
3496
3504
|
}
|
|
3497
|
-
if (item.type === 'dropdown') {
|
|
3505
|
+
else if (item.type === 'dropdown') {
|
|
3498
3506
|
this.dropdownItemList.push(item);
|
|
3499
3507
|
this.appendDropdown(item);
|
|
3500
3508
|
}
|
|
3501
|
-
}
|
|
3509
|
+
}
|
|
3502
3510
|
this.updatePosition();
|
|
3503
3511
|
}
|
|
3504
3512
|
unmount() {
|
|
@@ -3506,8 +3514,6 @@ class BoxToolbar {
|
|
|
3506
3514
|
}
|
|
3507
3515
|
}
|
|
3508
3516
|
|
|
3509
|
-
// A key-value object for storing data about box.
|
|
3510
|
-
const boxData = {};
|
|
3511
3517
|
const framework = safeTemplate `
|
|
3512
3518
|
<span class="lake-box-strip"><br /></span>
|
|
3513
3519
|
<div class="lake-box-container" contenteditable="false"></div>
|
|
@@ -3519,7 +3525,7 @@ class Box {
|
|
|
3519
3525
|
if (typeof node === 'string') {
|
|
3520
3526
|
const component = boxes.get(node);
|
|
3521
3527
|
if (component === undefined) {
|
|
3522
|
-
throw new Error(`Box
|
|
3528
|
+
throw new Error(`Box "${node}" has not been defined yet.`);
|
|
3523
3529
|
}
|
|
3524
3530
|
const type = encode(component.type);
|
|
3525
3531
|
const name = encode(component.name);
|
|
@@ -3532,15 +3538,12 @@ class Box {
|
|
|
3532
3538
|
this.node = query(node);
|
|
3533
3539
|
const component = boxes.get(this.name);
|
|
3534
3540
|
if (component === undefined) {
|
|
3535
|
-
throw new Error(`Box
|
|
3541
|
+
throw new Error(`Box "${this.name}" has not been defined yet.`);
|
|
3536
3542
|
}
|
|
3537
3543
|
if (component.value && !this.node.hasAttr('value')) {
|
|
3538
3544
|
this.value = component.value;
|
|
3539
3545
|
}
|
|
3540
3546
|
}
|
|
3541
|
-
if (!boxData[this.node.id]) {
|
|
3542
|
-
boxData[this.node.id] = {};
|
|
3543
|
-
}
|
|
3544
3547
|
}
|
|
3545
3548
|
// Adds the framework of the box.
|
|
3546
3549
|
addFramework() {
|
|
@@ -3566,7 +3569,7 @@ class Box {
|
|
|
3566
3569
|
container.removeClass('lake-box-hovered');
|
|
3567
3570
|
});
|
|
3568
3571
|
container.on('click', () => {
|
|
3569
|
-
debug(`Box
|
|
3572
|
+
debug(`Box "${this.name}" (id = ${this.node.id}) value:`);
|
|
3570
3573
|
debug(this.value);
|
|
3571
3574
|
});
|
|
3572
3575
|
if (this.type === 'block' && this.node.isContentEditable) {
|
|
@@ -3605,14 +3608,6 @@ class Box {
|
|
|
3605
3608
|
}
|
|
3606
3609
|
this.value = value;
|
|
3607
3610
|
}
|
|
3608
|
-
// Returns data of the box.
|
|
3609
|
-
getData(key) {
|
|
3610
|
-
return boxData[this.node.id][key];
|
|
3611
|
-
}
|
|
3612
|
-
// Updates data of the box.
|
|
3613
|
-
setData(key, value) {
|
|
3614
|
-
boxData[this.node.id][key] = value;
|
|
3615
|
-
}
|
|
3616
3611
|
// Returns the editor instance of the box.
|
|
3617
3612
|
getEditor() {
|
|
3618
3613
|
const container = this.node.closest('div[contenteditable]');
|
|
@@ -3667,16 +3662,15 @@ class Box {
|
|
|
3667
3662
|
newContainer.append(content);
|
|
3668
3663
|
morph(container, newContainer);
|
|
3669
3664
|
}
|
|
3670
|
-
debug(`Box
|
|
3665
|
+
debug(`Box "${this.name}" (id: ${this.node.id}) rendered`);
|
|
3671
3666
|
}
|
|
3672
3667
|
// Destroys a rendered box.
|
|
3673
3668
|
unmount() {
|
|
3674
3669
|
this.event.emit('blur');
|
|
3675
3670
|
this.event.emit('beforeunmount');
|
|
3676
|
-
boxData[this.node.id] = {};
|
|
3677
3671
|
this.event.removeAllListeners();
|
|
3678
3672
|
this.node.empty();
|
|
3679
|
-
debug(`Box
|
|
3673
|
+
debug(`Box "${this.name}" (id: ${this.node.id}) unmounted`);
|
|
3680
3674
|
}
|
|
3681
3675
|
// Returns a HTML string of the box.
|
|
3682
3676
|
getHTML() {
|
|
@@ -3847,6 +3841,71 @@ function request(option) {
|
|
|
3847
3841
|
return xhr;
|
|
3848
3842
|
}
|
|
3849
3843
|
|
|
3844
|
+
function uploadFile(config) {
|
|
3845
|
+
const { editor, name, file, onError, onSuccess } = config;
|
|
3846
|
+
const { requestMethod, requestAction, requestTypes } = editor.config[name];
|
|
3847
|
+
if (requestTypes.indexOf(file.type) < 0) {
|
|
3848
|
+
if (onError) {
|
|
3849
|
+
onError(`File "${file.name}" is not allowed for uploading.`);
|
|
3850
|
+
}
|
|
3851
|
+
throw new Error(`Cannot upload file "${file.name}" because its type "${file.type}" is not found in ['${requestTypes.join('\', \'')}'].`);
|
|
3852
|
+
}
|
|
3853
|
+
const box = editor.selection.insertBox(name, {
|
|
3854
|
+
url: URL.createObjectURL(file),
|
|
3855
|
+
status: 'uploading',
|
|
3856
|
+
name: file.name,
|
|
3857
|
+
size: file.size,
|
|
3858
|
+
type: file.type,
|
|
3859
|
+
lastModified: file.lastModified,
|
|
3860
|
+
});
|
|
3861
|
+
let xhr = request({
|
|
3862
|
+
onProgress: e => {
|
|
3863
|
+
const percentNode = box.node.find('.lake-percent');
|
|
3864
|
+
const percent = Math.round(e.percent);
|
|
3865
|
+
percentNode.text(`${percent < 100 ? percent : 99} %`);
|
|
3866
|
+
},
|
|
3867
|
+
onError: (error, body) => {
|
|
3868
|
+
xhr = null;
|
|
3869
|
+
debug(error.toString(), body);
|
|
3870
|
+
box.updateValue('status', 'error');
|
|
3871
|
+
box.render();
|
|
3872
|
+
if (onError) {
|
|
3873
|
+
onError(error.toString());
|
|
3874
|
+
}
|
|
3875
|
+
},
|
|
3876
|
+
onSuccess: body => {
|
|
3877
|
+
xhr = null;
|
|
3878
|
+
if (!body.url) {
|
|
3879
|
+
box.updateValue('status', 'error');
|
|
3880
|
+
box.render();
|
|
3881
|
+
if (onError) {
|
|
3882
|
+
onError('Cannot find the url field.');
|
|
3883
|
+
}
|
|
3884
|
+
return;
|
|
3885
|
+
}
|
|
3886
|
+
box.updateValue({
|
|
3887
|
+
status: 'done',
|
|
3888
|
+
url: body.url,
|
|
3889
|
+
});
|
|
3890
|
+
box.render();
|
|
3891
|
+
editor.history.save();
|
|
3892
|
+
if (onSuccess) {
|
|
3893
|
+
onSuccess();
|
|
3894
|
+
}
|
|
3895
|
+
},
|
|
3896
|
+
file,
|
|
3897
|
+
action: requestAction,
|
|
3898
|
+
method: requestMethod,
|
|
3899
|
+
});
|
|
3900
|
+
box.event.on('beforeunmount', () => {
|
|
3901
|
+
if (xhr) {
|
|
3902
|
+
xhr.abort();
|
|
3903
|
+
debug('Upload canceled');
|
|
3904
|
+
}
|
|
3905
|
+
});
|
|
3906
|
+
return box;
|
|
3907
|
+
}
|
|
3908
|
+
|
|
3850
3909
|
// String
|
|
3851
3910
|
|
|
3852
3911
|
var index = /*#__PURE__*/Object.freeze({
|
|
@@ -3879,6 +3938,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
3879
3938
|
template: template,
|
|
3880
3939
|
toHex: toHex,
|
|
3881
3940
|
toNodeList: toNodeList,
|
|
3941
|
+
uploadFile: uploadFile,
|
|
3882
3942
|
wrapNodeList: wrapNodeList
|
|
3883
3943
|
});
|
|
3884
3944
|
|
|
@@ -3886,6 +3946,10 @@ class Fragment {
|
|
|
3886
3946
|
constructor(fragment) {
|
|
3887
3947
|
this.fragment = fragment !== null && fragment !== void 0 ? fragment : document.createDocumentFragment();
|
|
3888
3948
|
}
|
|
3949
|
+
// Gets a native fragment.
|
|
3950
|
+
get() {
|
|
3951
|
+
return this.fragment;
|
|
3952
|
+
}
|
|
3889
3953
|
// Returns the descendants of the fragment which are selected by the specified CSS selector.
|
|
3890
3954
|
find(selector) {
|
|
3891
3955
|
const nodeList = [];
|
|
@@ -3905,7 +3969,7 @@ class Fragment {
|
|
|
3905
3969
|
}
|
|
3906
3970
|
// Inserts the specified node as the last child.
|
|
3907
3971
|
append(node) {
|
|
3908
|
-
node.each(nativeNode => {
|
|
3972
|
+
query(node).each(nativeNode => {
|
|
3909
3973
|
this.fragment.appendChild(nativeNode);
|
|
3910
3974
|
});
|
|
3911
3975
|
}
|
|
@@ -4287,9 +4351,8 @@ function insertBookmark(range) {
|
|
|
4287
4351
|
function removeAndNormalizeNode(node, range) {
|
|
4288
4352
|
const previousNode = node.prev();
|
|
4289
4353
|
const nextNode = node.next();
|
|
4290
|
-
if (previousNode.isText
|
|
4354
|
+
if (previousNode.isText || nextNode.isText) {
|
|
4291
4355
|
const parentNode = node.parent();
|
|
4292
|
-
removeZWS(parentNode);
|
|
4293
4356
|
node.remove();
|
|
4294
4357
|
parentNode.get(0).normalize();
|
|
4295
4358
|
}
|
|
@@ -4407,6 +4470,9 @@ function deleteContents(range) {
|
|
|
4407
4470
|
|
|
4408
4471
|
// Inserts a DocumentFragment object into the specified range.
|
|
4409
4472
|
function insertFragment(range, fragment) {
|
|
4473
|
+
if (fragment instanceof Fragment) {
|
|
4474
|
+
fragment = fragment.get();
|
|
4475
|
+
}
|
|
4410
4476
|
if (range.commonAncestor.isOutside) {
|
|
4411
4477
|
return;
|
|
4412
4478
|
}
|
|
@@ -4424,16 +4490,6 @@ function insertFragment(range, fragment) {
|
|
|
4424
4490
|
range.adjustBlock();
|
|
4425
4491
|
}
|
|
4426
4492
|
|
|
4427
|
-
// Inserts a HTML string into the specified range.
|
|
4428
|
-
function insertContents(range, value) {
|
|
4429
|
-
const nodes = query(value);
|
|
4430
|
-
const fragment = document.createDocumentFragment();
|
|
4431
|
-
nodes.each(nativeNode => {
|
|
4432
|
-
fragment.appendChild(nativeNode);
|
|
4433
|
-
});
|
|
4434
|
-
insertFragment(range, fragment);
|
|
4435
|
-
}
|
|
4436
|
-
|
|
4437
4493
|
function getTopNonBlockNodes(range) {
|
|
4438
4494
|
const container = range.commonAncestor.closest('div[contenteditable="true"],td');
|
|
4439
4495
|
let nodeList = [];
|
|
@@ -4495,7 +4551,7 @@ function setBlocks(range, value) {
|
|
|
4495
4551
|
}
|
|
4496
4552
|
else {
|
|
4497
4553
|
const block = valueNode.clone(true);
|
|
4498
|
-
if (node.isList && node.attr('indent') !== '') {
|
|
4554
|
+
if (block.isList && node.isList && node.attr('indent') !== '') {
|
|
4499
4555
|
block.attr('indent', node.attr('indent'));
|
|
4500
4556
|
}
|
|
4501
4557
|
const deepestBlock = getDeepest(block);
|
|
@@ -4593,7 +4649,7 @@ function splitBlock$1(range) {
|
|
|
4593
4649
|
}
|
|
4594
4650
|
|
|
4595
4651
|
// Removes empty marks that contain no content.
|
|
4596
|
-
function removeEmptyMarks$
|
|
4652
|
+
function removeEmptyMarks$2(node) {
|
|
4597
4653
|
if (node.isMark && node.isEmpty) {
|
|
4598
4654
|
node.remove();
|
|
4599
4655
|
return;
|
|
@@ -4615,8 +4671,8 @@ function splitMarksAtPoint(node, offset, removeEmptyMark) {
|
|
|
4615
4671
|
const parts = splitNodes(node, offset, limitBlock);
|
|
4616
4672
|
if (parts) {
|
|
4617
4673
|
if (removeEmptyMark) {
|
|
4618
|
-
removeEmptyMarks$
|
|
4619
|
-
removeEmptyMarks$
|
|
4674
|
+
removeEmptyMarks$2(parts.start);
|
|
4675
|
+
removeEmptyMarks$2(parts.end);
|
|
4620
4676
|
if (!parts.start.isEmpty) {
|
|
4621
4677
|
start = parts.start;
|
|
4622
4678
|
}
|
|
@@ -4802,7 +4858,7 @@ function addMark(range, value) {
|
|
|
4802
4858
|
}
|
|
4803
4859
|
|
|
4804
4860
|
// Removes empty marks that contain no content.
|
|
4805
|
-
function removeEmptyMarks(node) {
|
|
4861
|
+
function removeEmptyMarks$1(node) {
|
|
4806
4862
|
if (node.isMark && node.isEmpty) {
|
|
4807
4863
|
node.remove();
|
|
4808
4864
|
return;
|
|
@@ -4860,13 +4916,13 @@ function removeMark(range, value) {
|
|
|
4860
4916
|
return;
|
|
4861
4917
|
}
|
|
4862
4918
|
if (parts.end) {
|
|
4863
|
-
removeEmptyMarks(parts.end);
|
|
4919
|
+
removeEmptyMarks$1(parts.end);
|
|
4864
4920
|
}
|
|
4865
4921
|
const zeroWidthSpace = new Nodes(document.createTextNode('\u200B'));
|
|
4866
4922
|
const newMark = copyNestedMarks(parts.start, tagName);
|
|
4867
4923
|
if (!newMark) {
|
|
4868
4924
|
parts.start.after(zeroWidthSpace);
|
|
4869
|
-
removeEmptyMarks(parts.start);
|
|
4925
|
+
removeEmptyMarks$1(parts.start);
|
|
4870
4926
|
if (zeroWidthSpace.prev().isText) {
|
|
4871
4927
|
range.setStartAfter(zeroWidthSpace.prev());
|
|
4872
4928
|
range.collapseToStart();
|
|
@@ -4879,7 +4935,7 @@ function removeMark(range, value) {
|
|
|
4879
4935
|
}
|
|
4880
4936
|
appendDeepest(newMark, zeroWidthSpace);
|
|
4881
4937
|
parts.start.after(newMark);
|
|
4882
|
-
removeEmptyMarks(parts.start);
|
|
4938
|
+
removeEmptyMarks$1(parts.start);
|
|
4883
4939
|
range.shrinkAfter(newMark);
|
|
4884
4940
|
return;
|
|
4885
4941
|
}
|
|
@@ -4947,8 +5003,6 @@ function insertLink(range, value) {
|
|
|
4947
5003
|
return linkNode;
|
|
4948
5004
|
}
|
|
4949
5005
|
|
|
4950
|
-
var version = "0.1.13";
|
|
4951
|
-
|
|
4952
5006
|
// Inserts a box into the specified range.
|
|
4953
5007
|
function insertBox(range, boxName, boxValue) {
|
|
4954
5008
|
if (range.commonAncestor.isOutside) {
|
|
@@ -5026,6 +5080,8 @@ function removeBox(range) {
|
|
|
5026
5080
|
return box;
|
|
5027
5081
|
}
|
|
5028
5082
|
|
|
5083
|
+
var version = "0.1.15";
|
|
5084
|
+
|
|
5029
5085
|
// Returns the attributes of the element as an key-value object.
|
|
5030
5086
|
function getAttributes(node) {
|
|
5031
5087
|
const nativeNode = node.get(0);
|
|
@@ -5116,7 +5172,10 @@ class Selection {
|
|
|
5116
5172
|
// Updates the saved range with the range of the native selection.
|
|
5117
5173
|
updateByRange() {
|
|
5118
5174
|
const newRange = this.getRangeFromNativeSelection();
|
|
5119
|
-
if (this.range.get() === newRange.get()
|
|
5175
|
+
if (this.range.startNode.get(0) === newRange.startNode.get(0) &&
|
|
5176
|
+
this.range.startOffset === newRange.startOffset &&
|
|
5177
|
+
this.range.endNode.get(0) === newRange.endNode.get(0) &&
|
|
5178
|
+
this.range.endOffset === newRange.endOffset) {
|
|
5120
5179
|
return;
|
|
5121
5180
|
}
|
|
5122
5181
|
this.range = newRange;
|
|
@@ -5160,9 +5219,6 @@ class Selection {
|
|
|
5160
5219
|
insertFragment(fragment) {
|
|
5161
5220
|
return insertFragment(this.range, fragment);
|
|
5162
5221
|
}
|
|
5163
|
-
insertContents(value) {
|
|
5164
|
-
return insertContents(this.range, value);
|
|
5165
|
-
}
|
|
5166
5222
|
deleteContents() {
|
|
5167
5223
|
return deleteContents(this.range);
|
|
5168
5224
|
}
|
|
@@ -5202,7 +5258,7 @@ class Selection {
|
|
|
5202
5258
|
insertBox(boxName, boxValue) {
|
|
5203
5259
|
const box = insertBox(this.range, boxName, boxValue);
|
|
5204
5260
|
if (!box) {
|
|
5205
|
-
throw new Error(`Box
|
|
5261
|
+
throw new Error(`Box "${boxName}" cannot be inserted outside the editor.`);
|
|
5206
5262
|
}
|
|
5207
5263
|
return box;
|
|
5208
5264
|
}
|
|
@@ -5218,7 +5274,6 @@ class Selection {
|
|
|
5218
5274
|
class Command {
|
|
5219
5275
|
constructor(selection) {
|
|
5220
5276
|
this.commandMap = new Map();
|
|
5221
|
-
this.event = new EventEmitter();
|
|
5222
5277
|
this.selection = selection;
|
|
5223
5278
|
}
|
|
5224
5279
|
add(name, commandItem) {
|
|
@@ -5236,7 +5291,7 @@ class Command {
|
|
|
5236
5291
|
getItem(name) {
|
|
5237
5292
|
const commandItem = this.commandMap.get(name);
|
|
5238
5293
|
if (commandItem === undefined) {
|
|
5239
|
-
throw new Error(`Command
|
|
5294
|
+
throw new Error(`Command "${name}" has not been defined yet.`);
|
|
5240
5295
|
}
|
|
5241
5296
|
return commandItem;
|
|
5242
5297
|
}
|
|
@@ -5266,10 +5321,8 @@ class Command {
|
|
|
5266
5321
|
}
|
|
5267
5322
|
execute(name, ...data) {
|
|
5268
5323
|
const commandItem = this.getItem(name);
|
|
5269
|
-
this.event.emit('beforeexecute', name);
|
|
5270
5324
|
commandItem.execute.apply(this, data);
|
|
5271
|
-
|
|
5272
|
-
debug(`Command '${name}' executed`);
|
|
5325
|
+
debug(`Command "${name}" executed`);
|
|
5273
5326
|
}
|
|
5274
5327
|
}
|
|
5275
5328
|
|
|
@@ -5287,11 +5340,11 @@ class Command {
|
|
|
5287
5340
|
// inputs 'e': value: 'abe', list: ['a', 'ab', 'abe'], index: 3, canRedo: false
|
|
5288
5341
|
class History {
|
|
5289
5342
|
constructor(selection) {
|
|
5343
|
+
this.canSave = true;
|
|
5290
5344
|
// an array for storing the history items
|
|
5291
5345
|
this.list = [];
|
|
5292
5346
|
// the next index of the list
|
|
5293
5347
|
this.index = 0;
|
|
5294
|
-
this.canSave = true;
|
|
5295
5348
|
this.limit = 100;
|
|
5296
5349
|
this.event = new EventEmitter();
|
|
5297
5350
|
this.selection = selection;
|
|
@@ -5343,6 +5396,12 @@ class History {
|
|
|
5343
5396
|
this.removeIdfromBoxes(container);
|
|
5344
5397
|
this.removeIdfromBoxes(otherContainer);
|
|
5345
5398
|
}
|
|
5399
|
+
get canUndo() {
|
|
5400
|
+
return this.index > 1 && !!this.list[this.index - 1];
|
|
5401
|
+
}
|
|
5402
|
+
get canRedo() {
|
|
5403
|
+
return !!this.list[this.index];
|
|
5404
|
+
}
|
|
5346
5405
|
cloneContainer() {
|
|
5347
5406
|
const range = this.selection.range;
|
|
5348
5407
|
const newContainer = this.container.clone(true);
|
|
@@ -5354,6 +5413,12 @@ class History {
|
|
|
5354
5413
|
return newContainer;
|
|
5355
5414
|
}
|
|
5356
5415
|
if (range.isInsideBox) {
|
|
5416
|
+
const boxNode = range.commonAncestor.closest('lake-box');
|
|
5417
|
+
const boxNodePath = boxNode.path();
|
|
5418
|
+
const newBoxNode = newContainer.find(boxNodePath);
|
|
5419
|
+
const newRange = range.clone();
|
|
5420
|
+
newRange.selectBox(newBoxNode);
|
|
5421
|
+
insertBookmark(newRange);
|
|
5357
5422
|
return newContainer;
|
|
5358
5423
|
}
|
|
5359
5424
|
const startNodePath = range.startNode.path();
|
|
@@ -5366,23 +5431,14 @@ class History {
|
|
|
5366
5431
|
insertBookmark(newRange);
|
|
5367
5432
|
return newContainer;
|
|
5368
5433
|
}
|
|
5369
|
-
get count() {
|
|
5370
|
-
return this.list.length;
|
|
5371
|
-
}
|
|
5372
|
-
get canUndo() {
|
|
5373
|
-
return this.index > 1 && !!this.list[this.index - 1];
|
|
5374
|
-
}
|
|
5375
|
-
get canRedo() {
|
|
5376
|
-
return !!this.list[this.index];
|
|
5377
|
-
}
|
|
5378
5434
|
undo() {
|
|
5379
|
-
if (!this.list[this.index -
|
|
5435
|
+
if (!this.list[this.index - 2]) {
|
|
5380
5436
|
return;
|
|
5381
5437
|
}
|
|
5382
5438
|
this.selection.insertBookmark();
|
|
5383
5439
|
const value = this.getValue(this.container);
|
|
5384
|
-
while (this.index >
|
|
5385
|
-
const prevItem = this.list[this.index -
|
|
5440
|
+
while (this.index > 1) {
|
|
5441
|
+
const prevItem = this.list[this.index - 2];
|
|
5386
5442
|
if (!prevItem) {
|
|
5387
5443
|
break;
|
|
5388
5444
|
}
|
|
@@ -5394,9 +5450,6 @@ class History {
|
|
|
5394
5450
|
break;
|
|
5395
5451
|
}
|
|
5396
5452
|
}
|
|
5397
|
-
if (this.index < 1) {
|
|
5398
|
-
this.index = 1;
|
|
5399
|
-
}
|
|
5400
5453
|
this.selection.updateByBookmark();
|
|
5401
5454
|
debug(`History undone (index: ${this.index})`);
|
|
5402
5455
|
}
|
|
@@ -5428,7 +5481,11 @@ class History {
|
|
|
5428
5481
|
pause() {
|
|
5429
5482
|
this.canSave = false;
|
|
5430
5483
|
}
|
|
5431
|
-
save(
|
|
5484
|
+
save(options = {}) {
|
|
5485
|
+
var _a, _b, _c;
|
|
5486
|
+
const inputType = (_a = options.inputType) !== null && _a !== void 0 ? _a : '';
|
|
5487
|
+
const update = (_b = options.update) !== null && _b !== void 0 ? _b : false;
|
|
5488
|
+
const emitEvent = (_c = options.emitEvent) !== null && _c !== void 0 ? _c : true;
|
|
5432
5489
|
if (!this.canSave) {
|
|
5433
5490
|
return;
|
|
5434
5491
|
}
|
|
@@ -5438,16 +5495,25 @@ class History {
|
|
|
5438
5495
|
this.removeBookmark(this.getValue(this.list[this.index - 1])) === this.removeBookmark(value)) {
|
|
5439
5496
|
return;
|
|
5440
5497
|
}
|
|
5441
|
-
|
|
5442
|
-
|
|
5498
|
+
if (update) {
|
|
5499
|
+
this.list.splice(this.index - 1, Infinity, item);
|
|
5500
|
+
}
|
|
5501
|
+
else {
|
|
5502
|
+
this.list.splice(this.index, Infinity, item);
|
|
5503
|
+
this.index++;
|
|
5504
|
+
}
|
|
5443
5505
|
if (this.list.length > this.limit) {
|
|
5444
5506
|
this.list.shift();
|
|
5445
5507
|
this.index = this.list.length;
|
|
5446
5508
|
}
|
|
5447
|
-
|
|
5448
|
-
|
|
5509
|
+
debug(`History saved (index: ${this.index}, inputType: "${inputType}", update: ${update}, emitEvent: ${emitEvent})`);
|
|
5510
|
+
if (emitEvent) {
|
|
5511
|
+
this.event.emit('save', denormalizeValue(value), {
|
|
5512
|
+
inputType,
|
|
5513
|
+
update,
|
|
5514
|
+
emitEvent,
|
|
5515
|
+
});
|
|
5449
5516
|
}
|
|
5450
|
-
debug(`History saved (index: ${this.index})`);
|
|
5451
5517
|
}
|
|
5452
5518
|
}
|
|
5453
5519
|
|
|
@@ -5536,9 +5602,9 @@ class Plugin {
|
|
|
5536
5602
|
this.pluginList.push(plugin);
|
|
5537
5603
|
}
|
|
5538
5604
|
loadAll(editor) {
|
|
5539
|
-
this.pluginList
|
|
5605
|
+
for (const plugin of this.pluginList) {
|
|
5540
5606
|
plugin(editor);
|
|
5541
|
-
}
|
|
5607
|
+
}
|
|
5542
5608
|
}
|
|
5543
5609
|
}
|
|
5544
5610
|
|
|
@@ -5551,6 +5617,7 @@ const defaultConfig = {
|
|
|
5551
5617
|
indentWithTab: true,
|
|
5552
5618
|
lang: 'en-US',
|
|
5553
5619
|
minChangeSize: 5,
|
|
5620
|
+
historySize: 100,
|
|
5554
5621
|
onMessage: (type, message) => {
|
|
5555
5622
|
if (type === 'success') {
|
|
5556
5623
|
// eslint-disable-next-line no-console
|
|
@@ -5571,6 +5638,7 @@ const defaultConfig = {
|
|
|
5571
5638
|
class Editor {
|
|
5572
5639
|
constructor(config) {
|
|
5573
5640
|
this.unsavedInputData = '';
|
|
5641
|
+
this.unsavedInputCount = 0;
|
|
5574
5642
|
this.state = {
|
|
5575
5643
|
appliedItems: [],
|
|
5576
5644
|
disabledNameMap: new Map(),
|
|
@@ -5601,9 +5669,6 @@ class Editor {
|
|
|
5601
5669
|
}
|
|
5602
5670
|
this.event.emit('paste', event);
|
|
5603
5671
|
};
|
|
5604
|
-
this.beforeunloadListener = () => {
|
|
5605
|
-
this.history.save();
|
|
5606
|
-
};
|
|
5607
5672
|
this.selectionchangeListener = () => {
|
|
5608
5673
|
this.selection.updateByRange();
|
|
5609
5674
|
this.updateBoxSelectionStyle();
|
|
@@ -5619,6 +5684,7 @@ class Editor {
|
|
|
5619
5684
|
this.resizeListener = () => {
|
|
5620
5685
|
this.event.emit('resize');
|
|
5621
5686
|
};
|
|
5687
|
+
// Updates the classes of all boxes when the current selection of the editor is changed.
|
|
5622
5688
|
this.updateBoxSelectionStyle = debounce(() => {
|
|
5623
5689
|
// The editor has been unmounted.
|
|
5624
5690
|
if (this.root.first().length === 0) {
|
|
@@ -5663,12 +5729,12 @@ class Editor {
|
|
|
5663
5729
|
boxContainer.removeClass('lake-box-selected');
|
|
5664
5730
|
box.event.emit('blur');
|
|
5665
5731
|
});
|
|
5666
|
-
this.event.emit('boxselectionstylechange');
|
|
5667
5732
|
}, 50, {
|
|
5668
5733
|
leading: false,
|
|
5669
5734
|
trailing: true,
|
|
5670
5735
|
maxWait: 50,
|
|
5671
5736
|
});
|
|
5737
|
+
// Triggers the statechange event when the current selection of the editor is changed.
|
|
5672
5738
|
this.emitStateChangeEvent = debounce(() => {
|
|
5673
5739
|
const commandNames = this.command.getNames();
|
|
5674
5740
|
let appliedItems = this.selection.getAppliedItems();
|
|
@@ -5715,13 +5781,6 @@ class Editor {
|
|
|
5715
5781
|
trailing: true,
|
|
5716
5782
|
maxWait: 100,
|
|
5717
5783
|
});
|
|
5718
|
-
this.emitChangeEvent = (value) => {
|
|
5719
|
-
this.fixContent();
|
|
5720
|
-
this.emitStateChangeEvent();
|
|
5721
|
-
this.togglePlaceholderClass(value);
|
|
5722
|
-
this.scrollToCaret();
|
|
5723
|
-
this.event.emit('change', value);
|
|
5724
|
-
};
|
|
5725
5784
|
if (!config.root) {
|
|
5726
5785
|
throw new Error('The root of the config must be specified.');
|
|
5727
5786
|
}
|
|
@@ -5748,9 +5807,11 @@ class Editor {
|
|
|
5748
5807
|
this.selection = new Selection(this.container);
|
|
5749
5808
|
this.command = new Command(this.selection);
|
|
5750
5809
|
this.history = new History(this.selection);
|
|
5810
|
+
this.history.limit = this.config.historySize;
|
|
5751
5811
|
this.keystroke = new Keystroke(this.container);
|
|
5752
5812
|
editors.set(this.container.id, this);
|
|
5753
5813
|
}
|
|
5814
|
+
// Adds or Removes a placeholder class.
|
|
5754
5815
|
togglePlaceholderClass(value) {
|
|
5755
5816
|
value = denormalizeValue(value);
|
|
5756
5817
|
const className = 'lake-show-placeholder';
|
|
@@ -5761,7 +5822,8 @@ class Editor {
|
|
|
5761
5822
|
this.container.removeClass(className);
|
|
5762
5823
|
}
|
|
5763
5824
|
}
|
|
5764
|
-
|
|
5825
|
+
// Moves the input text from box strip to normal position.
|
|
5826
|
+
moveBoxStripText() {
|
|
5765
5827
|
const selection = this.selection;
|
|
5766
5828
|
const range = selection.range;
|
|
5767
5829
|
const stripNode = range.startNode.closest('.lake-box-strip');
|
|
@@ -5791,6 +5853,12 @@ class Editor {
|
|
|
5791
5853
|
stripNode.html('<br />');
|
|
5792
5854
|
selection.insertNode(document.createTextNode(text));
|
|
5793
5855
|
}
|
|
5856
|
+
// Resets the value of unsaved input property.
|
|
5857
|
+
resetUnsavedInputData() {
|
|
5858
|
+
this.unsavedInputData = '';
|
|
5859
|
+
this.unsavedInputCount = 0;
|
|
5860
|
+
}
|
|
5861
|
+
// Binds events about input.
|
|
5794
5862
|
bindInputEvents() {
|
|
5795
5863
|
this.container.on('compositionstart', () => {
|
|
5796
5864
|
this.isComposing = true;
|
|
@@ -5798,19 +5866,6 @@ class Editor {
|
|
|
5798
5866
|
this.container.on('compositionend', () => {
|
|
5799
5867
|
this.isComposing = false;
|
|
5800
5868
|
});
|
|
5801
|
-
this.container.on('beforeinput', event => {
|
|
5802
|
-
const inputEvent = event;
|
|
5803
|
-
const range = this.selection.range;
|
|
5804
|
-
if (range.isBoxStart || range.isBoxEnd) {
|
|
5805
|
-
this.commitUnsavedInputData();
|
|
5806
|
-
return;
|
|
5807
|
-
}
|
|
5808
|
-
if (inputEvent.inputType === 'insertText' ||
|
|
5809
|
-
inputEvent.inputType === 'insertCompositionText') {
|
|
5810
|
-
return;
|
|
5811
|
-
}
|
|
5812
|
-
this.commitUnsavedInputData();
|
|
5813
|
-
});
|
|
5814
5869
|
this.container.on('input', event => {
|
|
5815
5870
|
const inputEvent = event;
|
|
5816
5871
|
// Here setTimeout is necessary because isComposing is not false after ending composition.
|
|
@@ -5826,7 +5881,7 @@ class Editor {
|
|
|
5826
5881
|
return;
|
|
5827
5882
|
}
|
|
5828
5883
|
if (range.isBoxStart || range.isBoxEnd) {
|
|
5829
|
-
this.
|
|
5884
|
+
this.moveBoxStripText();
|
|
5830
5885
|
this.history.save();
|
|
5831
5886
|
this.event.emit('input', inputEvent);
|
|
5832
5887
|
return;
|
|
@@ -5834,30 +5889,60 @@ class Editor {
|
|
|
5834
5889
|
if (inputEvent.inputType === 'insertText' ||
|
|
5835
5890
|
inputEvent.inputType === 'insertCompositionText') {
|
|
5836
5891
|
this.unsavedInputData += (_a = inputEvent.data) !== null && _a !== void 0 ? _a : '';
|
|
5892
|
+
this.unsavedInputCount++;
|
|
5837
5893
|
if (this.unsavedInputData.length < this.config.minChangeSize) {
|
|
5838
|
-
this.
|
|
5839
|
-
|
|
5840
|
-
|
|
5894
|
+
this.history.save({
|
|
5895
|
+
inputType: 'insertText',
|
|
5896
|
+
update: this.unsavedInputCount > 1,
|
|
5897
|
+
});
|
|
5898
|
+
}
|
|
5899
|
+
else {
|
|
5900
|
+
this.history.save({
|
|
5901
|
+
inputType: 'insertText',
|
|
5902
|
+
update: true,
|
|
5903
|
+
});
|
|
5904
|
+
this.resetUnsavedInputData();
|
|
5841
5905
|
}
|
|
5906
|
+
this.event.emit('input', inputEvent);
|
|
5907
|
+
return;
|
|
5842
5908
|
}
|
|
5843
5909
|
this.history.save();
|
|
5844
5910
|
this.event.emit('input', inputEvent);
|
|
5845
5911
|
}, 0);
|
|
5846
5912
|
});
|
|
5847
|
-
this.command.event.on('beforeexecute', () => this.commitUnsavedInputData());
|
|
5848
5913
|
}
|
|
5914
|
+
// Binds events about history.
|
|
5849
5915
|
bindHistoryEvents() {
|
|
5916
|
+
const executeCommonMethods = (value) => {
|
|
5917
|
+
if (this.fixContent()) {
|
|
5918
|
+
this.history.save({
|
|
5919
|
+
update: true,
|
|
5920
|
+
emitEvent: false,
|
|
5921
|
+
});
|
|
5922
|
+
value = this.getValue();
|
|
5923
|
+
}
|
|
5924
|
+
this.emitStateChangeEvent();
|
|
5925
|
+
this.togglePlaceholderClass(value);
|
|
5926
|
+
this.scrollToCaret();
|
|
5927
|
+
this.event.emit('change', value);
|
|
5928
|
+
};
|
|
5850
5929
|
this.history.event.on('undo', value => {
|
|
5851
5930
|
this.renderBoxes();
|
|
5852
|
-
|
|
5931
|
+
executeCommonMethods(value);
|
|
5932
|
+
this.resetUnsavedInputData();
|
|
5853
5933
|
});
|
|
5854
5934
|
this.history.event.on('redo', value => {
|
|
5855
5935
|
this.renderBoxes();
|
|
5856
|
-
|
|
5936
|
+
executeCommonMethods(value);
|
|
5937
|
+
this.resetUnsavedInputData();
|
|
5857
5938
|
});
|
|
5858
|
-
this.history.event.on('save', value => {
|
|
5939
|
+
this.history.event.on('save', (value, options) => {
|
|
5859
5940
|
this.removeBoxGarbage();
|
|
5860
|
-
|
|
5941
|
+
executeCommonMethods(value);
|
|
5942
|
+
this.selection.sync();
|
|
5943
|
+
if (options.inputType !== 'insertText') {
|
|
5944
|
+
this.resetUnsavedInputData();
|
|
5945
|
+
}
|
|
5861
5946
|
});
|
|
5862
5947
|
}
|
|
5863
5948
|
// Returns a boolean value indicating whether the editor has focus.
|
|
@@ -5874,47 +5959,34 @@ class Editor {
|
|
|
5874
5959
|
}
|
|
5875
5960
|
// Fixes wrong content, especially empty tag.
|
|
5876
5961
|
fixContent() {
|
|
5962
|
+
let changed = false;
|
|
5877
5963
|
let children = this.container.children();
|
|
5878
5964
|
for (const child of children) {
|
|
5879
5965
|
if ((child.isBlock || child.isMark) && child.html() === '') {
|
|
5880
5966
|
child.remove();
|
|
5881
|
-
|
|
5967
|
+
changed = true;
|
|
5968
|
+
debug(`Content fixed: empty tag "${child.name}" was removed`);
|
|
5882
5969
|
}
|
|
5883
5970
|
}
|
|
5884
5971
|
children = this.container.children();
|
|
5885
5972
|
if (children.length === 0) {
|
|
5886
5973
|
this.container.html('<p><br /></p>');
|
|
5887
5974
|
this.selection.range.shrinkAfter(this.container);
|
|
5888
|
-
|
|
5889
|
-
|
|
5975
|
+
changed = true;
|
|
5976
|
+
debug('Content fixed: default paragraph was added');
|
|
5890
5977
|
}
|
|
5891
|
-
if (children.length === 1) {
|
|
5978
|
+
else if (children.length === 1) {
|
|
5892
5979
|
const child = children[0];
|
|
5893
5980
|
if (child.isVoid) {
|
|
5894
5981
|
const paragraph = query('<p />');
|
|
5895
5982
|
child.before(paragraph);
|
|
5896
5983
|
paragraph.append(child);
|
|
5897
5984
|
this.selection.range.shrinkAfter(paragraph);
|
|
5898
|
-
|
|
5985
|
+
changed = true;
|
|
5986
|
+
debug(`Content fixed: void element "${child.name}" was wrapped in paragraph`);
|
|
5899
5987
|
}
|
|
5900
5988
|
}
|
|
5901
|
-
|
|
5902
|
-
// Saves the input data which is unsaved.
|
|
5903
|
-
commitUnsavedInputData() {
|
|
5904
|
-
if (this.unsavedInputData.length > 0) {
|
|
5905
|
-
this.history.save(false);
|
|
5906
|
-
this.unsavedInputData = '';
|
|
5907
|
-
}
|
|
5908
|
-
}
|
|
5909
|
-
// Updates some state before custom modifications.
|
|
5910
|
-
prepareOperation() {
|
|
5911
|
-
this.commitUnsavedInputData();
|
|
5912
|
-
this.history.pause();
|
|
5913
|
-
}
|
|
5914
|
-
// Saves custom modifications to the history.
|
|
5915
|
-
commitOperation() {
|
|
5916
|
-
this.history.continue();
|
|
5917
|
-
this.history.save();
|
|
5989
|
+
return changed;
|
|
5918
5990
|
}
|
|
5919
5991
|
// Sets default config for a plugin.
|
|
5920
5992
|
setPluginConfig(name, config) {
|
|
@@ -5951,11 +6023,11 @@ class Editor {
|
|
|
5951
6023
|
box.render();
|
|
5952
6024
|
});
|
|
5953
6025
|
}
|
|
5954
|
-
// Sets focus on the editor
|
|
6026
|
+
// Sets focus on the editor.
|
|
5955
6027
|
focus() {
|
|
5956
6028
|
this.container.focus();
|
|
5957
6029
|
}
|
|
5958
|
-
// Removes focus from the editor
|
|
6030
|
+
// Removes focus from the editor.
|
|
5959
6031
|
blur() {
|
|
5960
6032
|
this.container.blur();
|
|
5961
6033
|
}
|
|
@@ -5963,6 +6035,9 @@ class Editor {
|
|
|
5963
6035
|
scrollToCaret() {
|
|
5964
6036
|
// Creates an artificial caret that is the same size as the caret at the current caret position.
|
|
5965
6037
|
const rangeRect = this.selection.range.getRect();
|
|
6038
|
+
if (rangeRect.x === 0 || rangeRect.y === 0) {
|
|
6039
|
+
return;
|
|
6040
|
+
}
|
|
5966
6041
|
const containerRect = this.container.get(0).getBoundingClientRect();
|
|
5967
6042
|
const artificialCaret = query('<div class="lake-artificial-caret" />');
|
|
5968
6043
|
const left = rangeRect.x - containerRect.x;
|
|
@@ -5991,7 +6066,7 @@ class Editor {
|
|
|
5991
6066
|
}
|
|
5992
6067
|
artificialCaret.remove();
|
|
5993
6068
|
}
|
|
5994
|
-
// Sets the specified
|
|
6069
|
+
// Sets the specified value to the editor.
|
|
5995
6070
|
setValue(value) {
|
|
5996
6071
|
value = normalizeValue(value);
|
|
5997
6072
|
const htmlParser = new HTMLParser(value);
|
|
@@ -6002,15 +6077,14 @@ class Editor {
|
|
|
6002
6077
|
this.renderBoxes();
|
|
6003
6078
|
this.selection.updateByBookmark();
|
|
6004
6079
|
}
|
|
6005
|
-
// Returns the
|
|
6080
|
+
// Returns the value of the editor.
|
|
6006
6081
|
getValue() {
|
|
6007
|
-
const
|
|
6008
|
-
let value = new HTMLParser(
|
|
6082
|
+
const item = this.history.cloneContainer();
|
|
6083
|
+
let value = new HTMLParser(item).getHTML();
|
|
6009
6084
|
value = denormalizeValue(value);
|
|
6010
|
-
this.selection.toBookmark(bookmark);
|
|
6011
6085
|
return value;
|
|
6012
6086
|
}
|
|
6013
|
-
// Renders an editor area and
|
|
6087
|
+
// Renders an editor area and sets default value to it.
|
|
6014
6088
|
render() {
|
|
6015
6089
|
const value = normalizeValue(this.config.value);
|
|
6016
6090
|
const htmlParser = new HTMLParser(value);
|
|
@@ -6025,7 +6099,9 @@ class Editor {
|
|
|
6025
6099
|
Editor.plugin.loadAll(this);
|
|
6026
6100
|
if (!this.readonly) {
|
|
6027
6101
|
this.selection.updateByBookmark();
|
|
6028
|
-
this.history.save(
|
|
6102
|
+
this.history.save({
|
|
6103
|
+
emitEvent: false,
|
|
6104
|
+
});
|
|
6029
6105
|
}
|
|
6030
6106
|
this.renderBoxes();
|
|
6031
6107
|
if (this.toolbar) {
|
|
@@ -6035,7 +6111,6 @@ class Editor {
|
|
|
6035
6111
|
if (!this.readonly) {
|
|
6036
6112
|
document.addEventListener('cut', this.cutListener);
|
|
6037
6113
|
document.addEventListener('paste', this.pasteListener);
|
|
6038
|
-
window.addEventListener('beforeunload', this.beforeunloadListener);
|
|
6039
6114
|
document.addEventListener('selectionchange', this.selectionchangeListener);
|
|
6040
6115
|
document.addEventListener('click', this.clickListener);
|
|
6041
6116
|
window.addEventListener('resize', this.resizeListener);
|
|
@@ -6043,10 +6118,9 @@ class Editor {
|
|
|
6043
6118
|
this.bindHistoryEvents();
|
|
6044
6119
|
}
|
|
6045
6120
|
}
|
|
6046
|
-
// Destroys
|
|
6121
|
+
// Destroys the rendered editor.
|
|
6047
6122
|
unmount() {
|
|
6048
6123
|
this.event.removeAllListeners();
|
|
6049
|
-
this.command.event.removeAllListeners();
|
|
6050
6124
|
this.history.event.removeAllListeners();
|
|
6051
6125
|
this.root.empty();
|
|
6052
6126
|
this.popupContainer.remove();
|
|
@@ -6054,7 +6128,6 @@ class Editor {
|
|
|
6054
6128
|
if (!this.readonly) {
|
|
6055
6129
|
document.removeEventListener('cut', this.cutListener);
|
|
6056
6130
|
document.removeEventListener('paste', this.pasteListener);
|
|
6057
|
-
window.removeEventListener('beforeunload', this.beforeunloadListener);
|
|
6058
6131
|
document.removeEventListener('selectionchange', this.selectionchangeListener);
|
|
6059
6132
|
document.removeEventListener('click', this.clickListener);
|
|
6060
6133
|
window.removeEventListener('resize', this.resizeListener);
|
|
@@ -6258,7 +6331,7 @@ const moreStyleMenuItems = [
|
|
|
6258
6331
|
text: locale => locale.toolbar.code(),
|
|
6259
6332
|
},
|
|
6260
6333
|
];
|
|
6261
|
-
// These colors are from Ant Design (https://ant.design/docs/spec/colors)
|
|
6334
|
+
// These colors are sourced from Ant Design (https://ant.design/docs/spec/colors)
|
|
6262
6335
|
const colors = [
|
|
6263
6336
|
// Dust Red, Volcano, Sunset Orange, Calendula Gold, Sunrise Yellow, Lime, Polar Green, Cyan, Daybreak Blue, Geek Blue, Golden Purple, Magenta
|
|
6264
6337
|
'#f5222d', '#fa541c', '#fa8c16', '#faad14', '#fadb14', '#a0d911', '#52c41a', '#13c2c2', '#1677ff', '#2f54eb', '#722ed1', '#eb2f96', // color 6
|
|
@@ -6533,19 +6606,19 @@ const toolbarItems = [
|
|
|
6533
6606
|
},
|
|
6534
6607
|
},
|
|
6535
6608
|
{
|
|
6536
|
-
name: '
|
|
6609
|
+
name: 'codeBlock',
|
|
6537
6610
|
type: 'button',
|
|
6538
|
-
icon: icons.get('
|
|
6539
|
-
tooltip: locale => locale.toolbar.
|
|
6611
|
+
icon: icons.get('codeBlock'),
|
|
6612
|
+
tooltip: locale => locale.toolbar.codeBlock(),
|
|
6540
6613
|
onClick: (editor, value) => {
|
|
6541
6614
|
editor.command.execute(value);
|
|
6542
6615
|
},
|
|
6543
6616
|
},
|
|
6544
6617
|
{
|
|
6545
|
-
name: '
|
|
6618
|
+
name: 'video',
|
|
6546
6619
|
type: 'button',
|
|
6547
|
-
icon: icons.get('
|
|
6548
|
-
tooltip: locale => locale.toolbar.
|
|
6620
|
+
icon: icons.get('video'),
|
|
6621
|
+
tooltip: locale => locale.toolbar.video(),
|
|
6549
6622
|
onClick: (editor, value) => {
|
|
6550
6623
|
editor.command.execute(value);
|
|
6551
6624
|
},
|
|
@@ -6568,9 +6641,7 @@ const toolbarItems = [
|
|
|
6568
6641
|
type: 'dropdown',
|
|
6569
6642
|
downIcon: icons.get('down'),
|
|
6570
6643
|
icon: icons.get('list'),
|
|
6571
|
-
defaultValue: '',
|
|
6572
6644
|
tooltip: locale => locale.toolbar.list(),
|
|
6573
|
-
width: 'auto',
|
|
6574
6645
|
menuType: 'list',
|
|
6575
6646
|
menuItems: listMenuItems,
|
|
6576
6647
|
onSelect: (editor, value) => {
|
|
@@ -6582,9 +6653,7 @@ const toolbarItems = [
|
|
|
6582
6653
|
type: 'dropdown',
|
|
6583
6654
|
downIcon: icons.get('down'),
|
|
6584
6655
|
icon: icons.get('alignLeft'),
|
|
6585
|
-
defaultValue: '',
|
|
6586
6656
|
tooltip: locale => locale.toolbar.align(),
|
|
6587
|
-
width: 'auto',
|
|
6588
6657
|
menuType: 'list',
|
|
6589
6658
|
menuItems: alignMenuItems,
|
|
6590
6659
|
onSelect: (editor, value) => {
|
|
@@ -6596,9 +6665,7 @@ const toolbarItems = [
|
|
|
6596
6665
|
type: 'dropdown',
|
|
6597
6666
|
downIcon: icons.get('down'),
|
|
6598
6667
|
icon: icons.get('increaseIndent'),
|
|
6599
|
-
defaultValue: '',
|
|
6600
6668
|
tooltip: locale => locale.toolbar.indent(),
|
|
6601
|
-
width: 'auto',
|
|
6602
6669
|
menuType: 'list',
|
|
6603
6670
|
menuItems: indentMenuItems,
|
|
6604
6671
|
onSelect: (editor, value) => {
|
|
@@ -6635,9 +6702,7 @@ const toolbarItems = [
|
|
|
6635
6702
|
name: 'moreStyle',
|
|
6636
6703
|
type: 'dropdown',
|
|
6637
6704
|
icon: icons.get('more'),
|
|
6638
|
-
defaultValue: '',
|
|
6639
6705
|
tooltip: locale => locale.toolbar.moreStyle(),
|
|
6640
|
-
width: 'auto',
|
|
6641
6706
|
menuType: 'list',
|
|
6642
6707
|
menuItems: moreStyleMenuItems,
|
|
6643
6708
|
selectedValues: appliedItems => {
|
|
@@ -6663,9 +6728,9 @@ const toolbarItems = [
|
|
|
6663
6728
|
accentIcon: icons.get('fontColorAccent'),
|
|
6664
6729
|
defaultValue: '#f5222d',
|
|
6665
6730
|
tooltip: locale => locale.toolbar.fontColor(),
|
|
6666
|
-
width: 'auto',
|
|
6667
6731
|
menuType: 'color',
|
|
6668
6732
|
menuItems: colorMenuItems,
|
|
6733
|
+
menuWidth: '296px',
|
|
6669
6734
|
onSelect: (editor, value) => {
|
|
6670
6735
|
editor.command.execute('fontColor', value);
|
|
6671
6736
|
},
|
|
@@ -6678,9 +6743,9 @@ const toolbarItems = [
|
|
|
6678
6743
|
accentIcon: icons.get('highlightAccent'),
|
|
6679
6744
|
defaultValue: '#fadb14',
|
|
6680
6745
|
tooltip: locale => locale.toolbar.highlight(),
|
|
6681
|
-
width: 'auto',
|
|
6682
6746
|
menuType: 'color',
|
|
6683
6747
|
menuItems: colorMenuItems,
|
|
6748
|
+
menuWidth: '296px',
|
|
6684
6749
|
onSelect: (editor, value) => {
|
|
6685
6750
|
editor.command.execute('highlight', value);
|
|
6686
6751
|
},
|
|
@@ -6703,64 +6768,6 @@ const toolbarItems = [
|
|
|
6703
6768
|
},
|
|
6704
6769
|
];
|
|
6705
6770
|
|
|
6706
|
-
function uploadFile(config) {
|
|
6707
|
-
const { editor, name, file, onError, onSuccess } = config;
|
|
6708
|
-
const { requestMethod, requestAction, requestTypes } = editor.config[name];
|
|
6709
|
-
if (requestTypes.indexOf(file.type) < 0) {
|
|
6710
|
-
if (onError) {
|
|
6711
|
-
onError(`File '${file.name}' is not allowed for uploading.`);
|
|
6712
|
-
}
|
|
6713
|
-
throw new Error(`Cannot upload file '${file.name}' because its type '${file.type}' is not found in ['${requestTypes.join('\', \'')}'].`);
|
|
6714
|
-
}
|
|
6715
|
-
const box = editor.selection.insertBox(name, {
|
|
6716
|
-
url: URL.createObjectURL(file),
|
|
6717
|
-
status: 'uploading',
|
|
6718
|
-
name: file.name,
|
|
6719
|
-
size: file.size,
|
|
6720
|
-
type: file.type,
|
|
6721
|
-
lastModified: file.lastModified,
|
|
6722
|
-
});
|
|
6723
|
-
const xhr = request({
|
|
6724
|
-
onProgress: e => {
|
|
6725
|
-
const percentNode = box.node.find('.lake-percent');
|
|
6726
|
-
const percent = Math.round(e.percent);
|
|
6727
|
-
percentNode.text(`${percent < 100 ? percent : 99} %`);
|
|
6728
|
-
},
|
|
6729
|
-
onError: (error, body) => {
|
|
6730
|
-
debug(error.toString(), body);
|
|
6731
|
-
box.updateValue('status', 'error');
|
|
6732
|
-
box.render();
|
|
6733
|
-
if (onError) {
|
|
6734
|
-
onError(error.toString());
|
|
6735
|
-
}
|
|
6736
|
-
},
|
|
6737
|
-
onSuccess: body => {
|
|
6738
|
-
if (!body.url) {
|
|
6739
|
-
box.updateValue('status', 'error');
|
|
6740
|
-
box.render();
|
|
6741
|
-
if (onError) {
|
|
6742
|
-
onError('Cannot find the url field.');
|
|
6743
|
-
}
|
|
6744
|
-
return;
|
|
6745
|
-
}
|
|
6746
|
-
box.updateValue({
|
|
6747
|
-
status: 'done',
|
|
6748
|
-
url: body.url,
|
|
6749
|
-
});
|
|
6750
|
-
box.render();
|
|
6751
|
-
editor.history.save();
|
|
6752
|
-
if (onSuccess) {
|
|
6753
|
-
onSuccess();
|
|
6754
|
-
}
|
|
6755
|
-
},
|
|
6756
|
-
file,
|
|
6757
|
-
action: requestAction,
|
|
6758
|
-
method: requestMethod,
|
|
6759
|
-
});
|
|
6760
|
-
box.setData('xhr', xhr);
|
|
6761
|
-
return box;
|
|
6762
|
-
}
|
|
6763
|
-
|
|
6764
6771
|
const defaultItems = [
|
|
6765
6772
|
'undo',
|
|
6766
6773
|
'redo',
|
|
@@ -6783,9 +6790,9 @@ const defaultItems = [
|
|
|
6783
6790
|
'hr',
|
|
6784
6791
|
];
|
|
6785
6792
|
const toolbarItemMap = new Map();
|
|
6786
|
-
|
|
6793
|
+
for (const item of toolbarItems) {
|
|
6787
6794
|
toolbarItemMap.set(item.name, item);
|
|
6788
|
-
}
|
|
6795
|
+
}
|
|
6789
6796
|
class Toolbar {
|
|
6790
6797
|
constructor(config) {
|
|
6791
6798
|
this.placement = 'top';
|
|
@@ -6830,6 +6837,7 @@ class Toolbar {
|
|
|
6830
6837
|
width: item.width,
|
|
6831
6838
|
menuType: item.menuType,
|
|
6832
6839
|
menuItems: item.menuItems,
|
|
6840
|
+
menuWidth: item.menuWidth,
|
|
6833
6841
|
tabIndex: -1,
|
|
6834
6842
|
placement: this.placement === 'top' ? 'bottom' : 'top',
|
|
6835
6843
|
onSelect: value => {
|
|
@@ -6931,7 +6939,7 @@ class Toolbar {
|
|
|
6931
6939
|
Dropdown.setValue(dropdownNode, selectedValues);
|
|
6932
6940
|
const textNode = dropdownNode.find('.lake-dropdown-text');
|
|
6933
6941
|
if (textNode.length > 0) {
|
|
6934
|
-
const key = selectedValues[0] || item.defaultValue;
|
|
6942
|
+
const key = selectedValues[0] || item.defaultValue || '';
|
|
6935
6943
|
const menuMap = this.allMenuMap.get(item.name);
|
|
6936
6944
|
const text = (_a = (menuMap && menuMap.get(key))) !== null && _a !== void 0 ? _a : key;
|
|
6937
6945
|
textNode.text(text);
|
|
@@ -6943,36 +6951,35 @@ class Toolbar {
|
|
|
6943
6951
|
render(editor) {
|
|
6944
6952
|
this.root.empty();
|
|
6945
6953
|
this.root.append(this.container);
|
|
6946
|
-
this.items
|
|
6954
|
+
for (const name of this.items) {
|
|
6947
6955
|
if (name === '|') {
|
|
6948
6956
|
this.appendDivider();
|
|
6949
|
-
return;
|
|
6950
|
-
}
|
|
6951
|
-
let item;
|
|
6952
|
-
if (typeof name === 'string') {
|
|
6953
|
-
item = toolbarItemMap.get(name);
|
|
6954
|
-
if (!item) {
|
|
6955
|
-
return;
|
|
6956
|
-
}
|
|
6957
6957
|
}
|
|
6958
6958
|
else {
|
|
6959
|
-
item
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6959
|
+
let item;
|
|
6960
|
+
if (typeof name === 'string') {
|
|
6961
|
+
item = toolbarItemMap.get(name);
|
|
6962
|
+
if (!item) {
|
|
6963
|
+
throw new Error(`ToolbarItem "${name}" has not been defined yet.`);
|
|
6964
|
+
}
|
|
6965
|
+
}
|
|
6966
|
+
else {
|
|
6967
|
+
item = name;
|
|
6968
|
+
}
|
|
6969
|
+
if (item.type === 'button') {
|
|
6970
|
+
this.buttonItemList.push(item);
|
|
6971
|
+
this.appendButton(editor, item);
|
|
6972
|
+
}
|
|
6973
|
+
else if (item.type === 'dropdown') {
|
|
6974
|
+
this.allMenuMap.set(item.name, Dropdown.getMenuMap(item.menuItems, editor.locale));
|
|
6975
|
+
this.dropdownItemList.push(item);
|
|
6976
|
+
this.appendDropdown(editor, item);
|
|
6977
|
+
}
|
|
6978
|
+
else if (item.type === 'upload') {
|
|
6979
|
+
this.appendUpload(editor, item);
|
|
6980
|
+
}
|
|
6974
6981
|
}
|
|
6975
|
-
}
|
|
6982
|
+
}
|
|
6976
6983
|
}
|
|
6977
6984
|
}
|
|
6978
6985
|
|
|
@@ -6984,248 +6991,15 @@ const hrBox = {
|
|
|
6984
6991
|
if (!editor) {
|
|
6985
6992
|
return;
|
|
6986
6993
|
}
|
|
6987
|
-
const
|
|
6988
|
-
box.getContainer().append(
|
|
6989
|
-
|
|
6994
|
+
const rootNode = query('<div class="lake-hr"><hr /></div>');
|
|
6995
|
+
box.getContainer().append(rootNode);
|
|
6996
|
+
rootNode.on('click', () => {
|
|
6990
6997
|
editor.selection.selectBox(box);
|
|
6991
6998
|
});
|
|
6992
6999
|
},
|
|
6993
7000
|
html: () => '<hr />',
|
|
6994
7001
|
};
|
|
6995
7002
|
|
|
6996
|
-
class BoxResizer {
|
|
6997
|
-
constructor(config) {
|
|
6998
|
-
this.config = config;
|
|
6999
|
-
this.root = config.root;
|
|
7000
|
-
this.box = config.box;
|
|
7001
|
-
}
|
|
7002
|
-
bindEvents(pointerNode) {
|
|
7003
|
-
const box = this.box;
|
|
7004
|
-
const boxContainer = box.getContainer();
|
|
7005
|
-
const resizerNode = pointerNode.closest('.lake-resizer');
|
|
7006
|
-
const infoNode = resizerNode.find('.lake-resizer-info');
|
|
7007
|
-
const isPlus = pointerNode.attr('class').indexOf('-right') >= 0;
|
|
7008
|
-
const initialWidth = boxContainer.width();
|
|
7009
|
-
const initialHeight = boxContainer.height();
|
|
7010
|
-
const rate = initialHeight / initialWidth;
|
|
7011
|
-
let clientX = 0;
|
|
7012
|
-
let width = 0;
|
|
7013
|
-
// resizing box
|
|
7014
|
-
const pointermoveListener = (event) => {
|
|
7015
|
-
const pointerEvent = event;
|
|
7016
|
-
const diffX = pointerEvent.clientX - clientX;
|
|
7017
|
-
const newWidth = Math.round(isPlus ? width + diffX : width - diffX);
|
|
7018
|
-
const newHeight = Math.round(rate * newWidth);
|
|
7019
|
-
infoNode.text(`${newWidth} x ${newHeight}`);
|
|
7020
|
-
boxContainer.css({
|
|
7021
|
-
width: `${newWidth}px`,
|
|
7022
|
-
height: `${newHeight}px`,
|
|
7023
|
-
});
|
|
7024
|
-
if (this.config.onResize) {
|
|
7025
|
-
this.config.onResize(newWidth, newHeight);
|
|
7026
|
-
}
|
|
7027
|
-
};
|
|
7028
|
-
// start resizing
|
|
7029
|
-
const pointerdownListener = (event) => {
|
|
7030
|
-
const pointerEvent = event;
|
|
7031
|
-
const pointerNativeNode = pointerNode.get(0);
|
|
7032
|
-
// The capture will be implicitly released after a pointerup or pointercancel event.
|
|
7033
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture
|
|
7034
|
-
pointerNativeNode.setPointerCapture(pointerEvent.pointerId);
|
|
7035
|
-
clientX = pointerEvent.clientX;
|
|
7036
|
-
width = boxContainer.width();
|
|
7037
|
-
infoNode.show();
|
|
7038
|
-
pointerNode.on('pointermove', pointermoveListener);
|
|
7039
|
-
};
|
|
7040
|
-
// stop resizing
|
|
7041
|
-
const pointerupListner = () => {
|
|
7042
|
-
pointerNode.off('pointermove');
|
|
7043
|
-
infoNode.hide();
|
|
7044
|
-
width = box.getContainer().width();
|
|
7045
|
-
const height = Math.round(rate * width);
|
|
7046
|
-
this.config.onStop(width, height);
|
|
7047
|
-
};
|
|
7048
|
-
// cancel resizing
|
|
7049
|
-
const pointercancelListner = () => {
|
|
7050
|
-
pointerNode.off('pointermove');
|
|
7051
|
-
infoNode.hide();
|
|
7052
|
-
};
|
|
7053
|
-
pointerNode.on('pointerdown', pointerdownListener);
|
|
7054
|
-
pointerNode.on('pointerup', pointerupListner);
|
|
7055
|
-
pointerNode.on('pointercancel', pointercancelListner);
|
|
7056
|
-
}
|
|
7057
|
-
render() {
|
|
7058
|
-
const { width, height } = this.config;
|
|
7059
|
-
const resizerNode = query(safeTemplate `
|
|
7060
|
-
<div class="lake-resizer">
|
|
7061
|
-
<div class="lake-resizer-top-left"></div>
|
|
7062
|
-
<div class="lake-resizer-top-right"></div>
|
|
7063
|
-
<div class="lake-resizer-bottom-left"></div>
|
|
7064
|
-
<div class="lake-resizer-bottom-right"></div>
|
|
7065
|
-
<div class="lake-resizer-info">${width} x ${height}</div>
|
|
7066
|
-
</div>
|
|
7067
|
-
`);
|
|
7068
|
-
this.bindEvents(resizerNode.find('.lake-resizer-top-left'));
|
|
7069
|
-
this.bindEvents(resizerNode.find('.lake-resizer-top-right'));
|
|
7070
|
-
this.bindEvents(resizerNode.find('.lake-resizer-bottom-left'));
|
|
7071
|
-
this.bindEvents(resizerNode.find('.lake-resizer-bottom-right'));
|
|
7072
|
-
this.root.append(resizerNode);
|
|
7073
|
-
}
|
|
7074
|
-
}
|
|
7075
|
-
|
|
7076
|
-
function getVideoId(url) {
|
|
7077
|
-
const result = /\w+$/i.exec(url || '');
|
|
7078
|
-
return result ? result[0] : '';
|
|
7079
|
-
}
|
|
7080
|
-
function getInputValue(videoNode, name) {
|
|
7081
|
-
const inputElement = videoNode.find(`input[name="${name}"]`);
|
|
7082
|
-
const nativeInputElement = inputElement.get(0);
|
|
7083
|
-
return nativeInputElement.value;
|
|
7084
|
-
}
|
|
7085
|
-
function appendButtonGroup(box) {
|
|
7086
|
-
const editor = box.getEditor();
|
|
7087
|
-
if (!editor) {
|
|
7088
|
-
return;
|
|
7089
|
-
}
|
|
7090
|
-
const boxContainer = box.getContainer();
|
|
7091
|
-
const videoNode = boxContainer.find('.lake-video');
|
|
7092
|
-
const buttonGroupNode = query(safeTemplate `
|
|
7093
|
-
<div class="lake-button-group">
|
|
7094
|
-
<button type="button" tabindex="-1" class="lake-button-remove" title="${editor.locale.video.remove()}"></button>
|
|
7095
|
-
</div>
|
|
7096
|
-
`);
|
|
7097
|
-
const removeButton = buttonGroupNode.find('.lake-button-remove');
|
|
7098
|
-
const removeIcon = icons.get('remove');
|
|
7099
|
-
if (removeIcon) {
|
|
7100
|
-
removeButton.append(removeIcon);
|
|
7101
|
-
}
|
|
7102
|
-
buttonGroupNode.find('.lake-button-remove').on('click', event => {
|
|
7103
|
-
event.stopPropagation();
|
|
7104
|
-
editor.selection.removeBox(box);
|
|
7105
|
-
editor.history.save();
|
|
7106
|
-
editor.selection.sync();
|
|
7107
|
-
});
|
|
7108
|
-
videoNode.append(buttonGroupNode);
|
|
7109
|
-
}
|
|
7110
|
-
function showVideo(box) {
|
|
7111
|
-
const editor = box.getEditor();
|
|
7112
|
-
if (!editor) {
|
|
7113
|
-
return;
|
|
7114
|
-
}
|
|
7115
|
-
const boxContainer = box.getContainer();
|
|
7116
|
-
const value = box.value;
|
|
7117
|
-
const width = value.width || 560;
|
|
7118
|
-
const height = value.height || 315;
|
|
7119
|
-
boxContainer.css({
|
|
7120
|
-
width: `${width}px`,
|
|
7121
|
-
height: `${height}px`,
|
|
7122
|
-
});
|
|
7123
|
-
const videoId = getVideoId(value.url);
|
|
7124
|
-
if (videoId === '') {
|
|
7125
|
-
throw new Error(`Invalid link: ${value.url}`);
|
|
7126
|
-
}
|
|
7127
|
-
// YouTube URL: https://www.youtube.com/watch?v=5sMBhDv4sik
|
|
7128
|
-
// The script for embedding YouTube:
|
|
7129
|
-
// <iframe width="560" height="315" src="https://www.youtube.com/embed/5sMBhDv4sik" title="YouTube video player"
|
|
7130
|
-
// frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
|
7131
|
-
// referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
|
7132
|
-
const iframeNode = query(safeTemplate `
|
|
7133
|
-
<iframe width="100%" height="${height}" src="https://www.youtube.com/embed/${videoId}" title="YouTube video player"
|
|
7134
|
-
frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
|
7135
|
-
referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
|
7136
|
-
`);
|
|
7137
|
-
const videoNode = boxContainer.find('.lake-video');
|
|
7138
|
-
if (!editor.readonly) {
|
|
7139
|
-
iframeNode.on('load', () => {
|
|
7140
|
-
appendButtonGroup(box);
|
|
7141
|
-
new BoxResizer({
|
|
7142
|
-
root: videoNode,
|
|
7143
|
-
box,
|
|
7144
|
-
width,
|
|
7145
|
-
height,
|
|
7146
|
-
onResize: (newWidth, newHeight) => {
|
|
7147
|
-
iframeNode.attr({
|
|
7148
|
-
height: newHeight.toString(),
|
|
7149
|
-
});
|
|
7150
|
-
},
|
|
7151
|
-
onStop: (newWidth, newHeight) => {
|
|
7152
|
-
box.updateValue({
|
|
7153
|
-
width: newWidth,
|
|
7154
|
-
height: newHeight,
|
|
7155
|
-
});
|
|
7156
|
-
editor.history.save();
|
|
7157
|
-
},
|
|
7158
|
-
}).render();
|
|
7159
|
-
});
|
|
7160
|
-
}
|
|
7161
|
-
videoNode.append(iframeNode);
|
|
7162
|
-
}
|
|
7163
|
-
const videoBox = {
|
|
7164
|
-
type: 'inline',
|
|
7165
|
-
name: 'video',
|
|
7166
|
-
render: box => {
|
|
7167
|
-
const editor = box.getEditor();
|
|
7168
|
-
if (!editor) {
|
|
7169
|
-
return;
|
|
7170
|
-
}
|
|
7171
|
-
const locale = editor.locale;
|
|
7172
|
-
const value = box.value;
|
|
7173
|
-
const boxContainer = box.getContainer();
|
|
7174
|
-
const videoNode = query('<div class="lake-video" />');
|
|
7175
|
-
boxContainer.empty();
|
|
7176
|
-
boxContainer.css({
|
|
7177
|
-
width: '',
|
|
7178
|
-
height: '',
|
|
7179
|
-
});
|
|
7180
|
-
boxContainer.append(videoNode);
|
|
7181
|
-
if (!value.url) {
|
|
7182
|
-
if (editor.readonly) {
|
|
7183
|
-
box.node.hide();
|
|
7184
|
-
return;
|
|
7185
|
-
}
|
|
7186
|
-
const formNode = query(safeTemplate `
|
|
7187
|
-
<div class="lake-video-form">
|
|
7188
|
-
<div class="lake-row lake-desc-row">${locale.video.description()}</div>
|
|
7189
|
-
<div class="lake-row">${locale.video.url()}</div>
|
|
7190
|
-
<div class="lake-row">
|
|
7191
|
-
<input type="text" name="url" placeholder="https://www.youtube.com/watch?v=..." />
|
|
7192
|
-
</div>
|
|
7193
|
-
<div class="lake-row lake-button-row"></div>
|
|
7194
|
-
</div>
|
|
7195
|
-
`);
|
|
7196
|
-
const button = new Button({
|
|
7197
|
-
root: formNode.find('.lake-button-row'),
|
|
7198
|
-
name: 'embed',
|
|
7199
|
-
type: 'primary',
|
|
7200
|
-
text: locale.video.embed(),
|
|
7201
|
-
onClick: () => {
|
|
7202
|
-
const url = getInputValue(formNode, 'url');
|
|
7203
|
-
if (url.indexOf('https://www.youtube.com/') < 0 || getVideoId(url) === '') {
|
|
7204
|
-
editor.config.onMessage('error', locale.video.urlError());
|
|
7205
|
-
return;
|
|
7206
|
-
}
|
|
7207
|
-
box.updateValue('url', url);
|
|
7208
|
-
editor.history.save();
|
|
7209
|
-
formNode.remove();
|
|
7210
|
-
showVideo(box);
|
|
7211
|
-
},
|
|
7212
|
-
});
|
|
7213
|
-
formNode.find('input[name="url"]').on('keydown', createKeybindingsHandler({
|
|
7214
|
-
'Enter': event => {
|
|
7215
|
-
event.preventDefault();
|
|
7216
|
-
button.node.emit('click');
|
|
7217
|
-
},
|
|
7218
|
-
}));
|
|
7219
|
-
button.render();
|
|
7220
|
-
videoNode.append(formNode);
|
|
7221
|
-
appendButtonGroup(box);
|
|
7222
|
-
}
|
|
7223
|
-
else {
|
|
7224
|
-
showVideo(box);
|
|
7225
|
-
}
|
|
7226
|
-
},
|
|
7227
|
-
};
|
|
7228
|
-
|
|
7229
7003
|
const config = {
|
|
7230
7004
|
comment: '#57606a',
|
|
7231
7005
|
name: '#444d56',
|
|
@@ -7312,12 +7086,12 @@ const codeBlockBox = {
|
|
|
7312
7086
|
if (!editor) {
|
|
7313
7087
|
return;
|
|
7314
7088
|
}
|
|
7315
|
-
const
|
|
7089
|
+
const rootNode = query('<div class="lake-code-block" />');
|
|
7316
7090
|
const container = box.getContainer();
|
|
7317
7091
|
container.css('width', `${editor.container.innerWidth() - 2}px`);
|
|
7318
7092
|
container.empty();
|
|
7319
|
-
container.append(
|
|
7320
|
-
const codeBlockNativeNode =
|
|
7093
|
+
container.append(rootNode);
|
|
7094
|
+
const codeBlockNativeNode = rootNode.get(0);
|
|
7321
7095
|
if (!codeBlockNativeNode) {
|
|
7322
7096
|
return;
|
|
7323
7097
|
}
|
|
@@ -7328,12 +7102,12 @@ const codeBlockBox = {
|
|
|
7328
7102
|
box.node.hide();
|
|
7329
7103
|
return;
|
|
7330
7104
|
}
|
|
7331
|
-
|
|
7332
|
-
|
|
7105
|
+
rootNode.addClass('lake-code-block-error');
|
|
7106
|
+
rootNode.text(`
|
|
7333
7107
|
The code cannot be displayed because window.LakeCodeMirror is not found.
|
|
7334
7108
|
Please check if the "lake-codemirror" library is added to this page.
|
|
7335
7109
|
`.trim());
|
|
7336
|
-
|
|
7110
|
+
rootNode.on('click', () => {
|
|
7337
7111
|
editor.selection.selectBox(box);
|
|
7338
7112
|
});
|
|
7339
7113
|
return;
|
|
@@ -7383,14 +7157,13 @@ const codeBlockBox = {
|
|
|
7383
7157
|
updateListener,
|
|
7384
7158
|
],
|
|
7385
7159
|
});
|
|
7386
|
-
|
|
7160
|
+
rootNode.find('[contenteditable="true"]').attr('tabindex', '-1');
|
|
7387
7161
|
const dropdown = new Dropdown({
|
|
7388
|
-
root:
|
|
7162
|
+
root: rootNode,
|
|
7389
7163
|
name: 'langType',
|
|
7390
7164
|
downIcon: icons.get('down'),
|
|
7391
7165
|
defaultValue: langItem ? boxValue.lang : codeBlockConfig.defaultLang,
|
|
7392
7166
|
tooltip: editor.locale.codeBlock.langType(),
|
|
7393
|
-
width: 'auto',
|
|
7394
7167
|
menuType: 'list',
|
|
7395
7168
|
menuItems: langItems.map((item) => ({
|
|
7396
7169
|
value: item.value,
|
|
@@ -7408,11 +7181,16 @@ const codeBlockBox = {
|
|
|
7408
7181
|
},
|
|
7409
7182
|
});
|
|
7410
7183
|
dropdown.render();
|
|
7411
|
-
box.setData('codeEditor', codeEditor);
|
|
7412
7184
|
const resizeListener = () => {
|
|
7413
7185
|
container.css('width', `${editor.container.innerWidth() - 2}px`);
|
|
7414
7186
|
};
|
|
7415
7187
|
editor.event.on('resize', resizeListener);
|
|
7188
|
+
rootNode.on('click', () => {
|
|
7189
|
+
if (codeEditor.hasFocus) {
|
|
7190
|
+
return;
|
|
7191
|
+
}
|
|
7192
|
+
codeEditor.focus();
|
|
7193
|
+
});
|
|
7416
7194
|
box.event.on('beforeunmount', () => {
|
|
7417
7195
|
codeEditor.destroy();
|
|
7418
7196
|
editor.event.off('resize', resizeListener);
|
|
@@ -7453,6 +7231,86 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
7453
7231
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
7454
7232
|
};
|
|
7455
7233
|
|
|
7234
|
+
class BoxResizer {
|
|
7235
|
+
constructor(config) {
|
|
7236
|
+
this.config = config;
|
|
7237
|
+
this.root = config.root;
|
|
7238
|
+
this.box = config.box;
|
|
7239
|
+
}
|
|
7240
|
+
bindEvents(pointerNode) {
|
|
7241
|
+
const box = this.box;
|
|
7242
|
+
const boxContainer = box.getContainer();
|
|
7243
|
+
const resizerNode = pointerNode.closest('.lake-resizer');
|
|
7244
|
+
const infoNode = resizerNode.find('.lake-resizer-info');
|
|
7245
|
+
const isPlus = pointerNode.attr('class').indexOf('-right') >= 0;
|
|
7246
|
+
const initialWidth = boxContainer.width();
|
|
7247
|
+
const initialHeight = boxContainer.height();
|
|
7248
|
+
const rate = initialHeight / initialWidth;
|
|
7249
|
+
let clientX = 0;
|
|
7250
|
+
let width = 0;
|
|
7251
|
+
// resizing box
|
|
7252
|
+
const pointermoveListener = (event) => {
|
|
7253
|
+
const pointerEvent = event;
|
|
7254
|
+
const diffX = pointerEvent.clientX - clientX;
|
|
7255
|
+
const newWidth = Math.round(isPlus ? width + diffX : width - diffX);
|
|
7256
|
+
const newHeight = Math.round(rate * newWidth);
|
|
7257
|
+
infoNode.text(`${newWidth} x ${newHeight}`);
|
|
7258
|
+
boxContainer.css({
|
|
7259
|
+
width: `${newWidth}px`,
|
|
7260
|
+
height: `${newHeight}px`,
|
|
7261
|
+
});
|
|
7262
|
+
if (this.config.onResize) {
|
|
7263
|
+
this.config.onResize(newWidth, newHeight);
|
|
7264
|
+
}
|
|
7265
|
+
};
|
|
7266
|
+
// start resizing
|
|
7267
|
+
const pointerdownListener = (event) => {
|
|
7268
|
+
const pointerEvent = event;
|
|
7269
|
+
const pointerNativeNode = pointerNode.get(0);
|
|
7270
|
+
// The capture will be implicitly released after a pointerup or pointercancel event.
|
|
7271
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture
|
|
7272
|
+
pointerNativeNode.setPointerCapture(pointerEvent.pointerId);
|
|
7273
|
+
clientX = pointerEvent.clientX;
|
|
7274
|
+
width = boxContainer.width();
|
|
7275
|
+
infoNode.show();
|
|
7276
|
+
pointerNode.on('pointermove', pointermoveListener);
|
|
7277
|
+
};
|
|
7278
|
+
// stop resizing
|
|
7279
|
+
const pointerupListner = () => {
|
|
7280
|
+
pointerNode.off('pointermove');
|
|
7281
|
+
infoNode.hide();
|
|
7282
|
+
width = box.getContainer().width();
|
|
7283
|
+
const height = Math.round(rate * width);
|
|
7284
|
+
this.config.onStop(width, height);
|
|
7285
|
+
};
|
|
7286
|
+
// cancel resizing
|
|
7287
|
+
const pointercancelListner = () => {
|
|
7288
|
+
pointerNode.off('pointermove');
|
|
7289
|
+
infoNode.hide();
|
|
7290
|
+
};
|
|
7291
|
+
pointerNode.on('pointerdown', pointerdownListener);
|
|
7292
|
+
pointerNode.on('pointerup', pointerupListner);
|
|
7293
|
+
pointerNode.on('pointercancel', pointercancelListner);
|
|
7294
|
+
}
|
|
7295
|
+
render() {
|
|
7296
|
+
const { width, height } = this.config;
|
|
7297
|
+
const resizerNode = query(safeTemplate `
|
|
7298
|
+
<div class="lake-resizer">
|
|
7299
|
+
<div class="lake-resizer-top-left"></div>
|
|
7300
|
+
<div class="lake-resizer-top-right"></div>
|
|
7301
|
+
<div class="lake-resizer-bottom-left"></div>
|
|
7302
|
+
<div class="lake-resizer-bottom-right"></div>
|
|
7303
|
+
<div class="lake-resizer-info">${width} x ${height}</div>
|
|
7304
|
+
</div>
|
|
7305
|
+
`);
|
|
7306
|
+
this.bindEvents(resizerNode.find('.lake-resizer-top-left'));
|
|
7307
|
+
this.bindEvents(resizerNode.find('.lake-resizer-top-right'));
|
|
7308
|
+
this.bindEvents(resizerNode.find('.lake-resizer-bottom-left'));
|
|
7309
|
+
this.bindEvents(resizerNode.find('.lake-resizer-bottom-right'));
|
|
7310
|
+
this.root.append(resizerNode);
|
|
7311
|
+
}
|
|
7312
|
+
}
|
|
7313
|
+
|
|
7456
7314
|
// Loads an image and get its width and height.
|
|
7457
7315
|
function getImageInfo(url) {
|
|
7458
7316
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -7590,7 +7448,7 @@ function openFullScreen(box) {
|
|
|
7590
7448
|
lightbox.loadAndOpen(currentIndex);
|
|
7591
7449
|
}
|
|
7592
7450
|
// Displays error icon and filename.
|
|
7593
|
-
function renderError(
|
|
7451
|
+
function renderError(rootNode, box) {
|
|
7594
7452
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7595
7453
|
const editor = box.getEditor();
|
|
7596
7454
|
if (!editor) {
|
|
@@ -7621,12 +7479,12 @@ function renderError(imageNode, box) {
|
|
|
7621
7479
|
if (imageIcon) {
|
|
7622
7480
|
errorNode.find('.lake-error-icon').append(imageIcon);
|
|
7623
7481
|
}
|
|
7624
|
-
|
|
7625
|
-
|
|
7482
|
+
rootNode.append(buttonGroupNode);
|
|
7483
|
+
rootNode.append(errorNode);
|
|
7626
7484
|
});
|
|
7627
7485
|
}
|
|
7628
7486
|
// Displays an image with uplaoding progress.
|
|
7629
|
-
function renderUploading(
|
|
7487
|
+
function renderUploading(rootNode, box) {
|
|
7630
7488
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7631
7489
|
const editor = box.getEditor();
|
|
7632
7490
|
if (!editor) {
|
|
@@ -7635,7 +7493,7 @@ function renderUploading(imageNode, box) {
|
|
|
7635
7493
|
const value = box.value;
|
|
7636
7494
|
const imageInfo = yield getImageInfo(value.url);
|
|
7637
7495
|
if (!imageInfo.width || !imageInfo.height) {
|
|
7638
|
-
yield renderError(
|
|
7496
|
+
yield renderError(rootNode, box);
|
|
7639
7497
|
return;
|
|
7640
7498
|
}
|
|
7641
7499
|
const maxWidth = editor.container.innerWidth() - 2;
|
|
@@ -7680,13 +7538,13 @@ function renderUploading(imageNode, box) {
|
|
|
7680
7538
|
draggable: 'false',
|
|
7681
7539
|
alt: value.name,
|
|
7682
7540
|
});
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7541
|
+
rootNode.append(buttonGroupNode);
|
|
7542
|
+
rootNode.append(progressNode);
|
|
7543
|
+
rootNode.append(imgNode);
|
|
7686
7544
|
});
|
|
7687
7545
|
}
|
|
7688
7546
|
// Displays an image that can be previewed or removed.
|
|
7689
|
-
function renderDone(
|
|
7547
|
+
function renderDone(rootNode, box) {
|
|
7690
7548
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7691
7549
|
const editor = box.getEditor();
|
|
7692
7550
|
if (!editor) {
|
|
@@ -7699,7 +7557,7 @@ function renderDone(imageNode, box) {
|
|
|
7699
7557
|
return;
|
|
7700
7558
|
}
|
|
7701
7559
|
if (!imageInfo.width || !imageInfo.height) {
|
|
7702
|
-
yield renderError(
|
|
7560
|
+
yield renderError(rootNode, box);
|
|
7703
7561
|
return;
|
|
7704
7562
|
}
|
|
7705
7563
|
let width = value.width;
|
|
@@ -7742,9 +7600,9 @@ function renderDone(imageNode, box) {
|
|
|
7742
7600
|
draggable: 'false',
|
|
7743
7601
|
alt: value.name,
|
|
7744
7602
|
});
|
|
7745
|
-
|
|
7603
|
+
rootNode.append(buttonGroupNode);
|
|
7746
7604
|
new BoxResizer({
|
|
7747
|
-
root:
|
|
7605
|
+
root: rootNode,
|
|
7748
7606
|
box,
|
|
7749
7607
|
width,
|
|
7750
7608
|
height,
|
|
@@ -7756,7 +7614,7 @@ function renderDone(imageNode, box) {
|
|
|
7756
7614
|
editor.history.save();
|
|
7757
7615
|
},
|
|
7758
7616
|
}).render();
|
|
7759
|
-
|
|
7617
|
+
rootNode.append(imgNode);
|
|
7760
7618
|
});
|
|
7761
7619
|
}
|
|
7762
7620
|
const imageBox = {
|
|
@@ -7797,46 +7655,193 @@ const imageBox = {
|
|
|
7797
7655
|
if (value.status === 'loading') {
|
|
7798
7656
|
return;
|
|
7799
7657
|
}
|
|
7800
|
-
const
|
|
7801
|
-
|
|
7658
|
+
const rootNode = query('<div class="lake-image" />');
|
|
7659
|
+
rootNode.addClass(`lake-image-${value.status}`);
|
|
7802
7660
|
let promise;
|
|
7803
7661
|
if (value.status === 'uploading') {
|
|
7804
|
-
promise = renderUploading(
|
|
7662
|
+
promise = renderUploading(rootNode, box);
|
|
7805
7663
|
}
|
|
7806
7664
|
else if (value.status === 'error') {
|
|
7807
|
-
promise = renderError(
|
|
7665
|
+
promise = renderError(rootNode, box);
|
|
7808
7666
|
}
|
|
7809
7667
|
else {
|
|
7810
|
-
promise = renderDone(
|
|
7668
|
+
promise = renderDone(rootNode, box);
|
|
7811
7669
|
}
|
|
7812
7670
|
promise.then(() => {
|
|
7813
7671
|
container.empty();
|
|
7814
|
-
container.append(
|
|
7815
|
-
|
|
7672
|
+
container.append(rootNode);
|
|
7673
|
+
rootNode.find('.lake-button-view').on('click', () => openFullScreen(box));
|
|
7816
7674
|
if (editor.readonly) {
|
|
7817
|
-
|
|
7675
|
+
rootNode.find('.lake-button-remove').hide();
|
|
7818
7676
|
}
|
|
7819
7677
|
else {
|
|
7820
|
-
|
|
7678
|
+
rootNode.find('.lake-button-remove').on('click', event => {
|
|
7821
7679
|
event.stopPropagation();
|
|
7822
|
-
const xhr = box.getData('xhr');
|
|
7823
|
-
if (xhr) {
|
|
7824
|
-
xhr.abort();
|
|
7825
|
-
}
|
|
7826
7680
|
editor.selection.removeBox(box);
|
|
7827
7681
|
editor.history.save();
|
|
7828
|
-
editor.selection.sync();
|
|
7829
7682
|
});
|
|
7830
7683
|
}
|
|
7831
7684
|
box.event.emit('render');
|
|
7832
7685
|
});
|
|
7833
|
-
|
|
7686
|
+
rootNode.on('click', () => {
|
|
7834
7687
|
editor.selection.selectBox(box);
|
|
7835
7688
|
});
|
|
7836
7689
|
},
|
|
7837
7690
|
html: box => {
|
|
7838
|
-
const
|
|
7839
|
-
return safeTemplate `<img src="${box.value.url}" data-lake-value="${
|
|
7691
|
+
const rawValue = box.node.attr('value');
|
|
7692
|
+
return safeTemplate `<img src="${box.value.url}" data-lake-value="${rawValue}" />`;
|
|
7693
|
+
},
|
|
7694
|
+
};
|
|
7695
|
+
|
|
7696
|
+
function getVideoId(url) {
|
|
7697
|
+
const result = /\w+$/i.exec(url || '');
|
|
7698
|
+
return result ? result[0] : '';
|
|
7699
|
+
}
|
|
7700
|
+
function getInputValue(videoNode, name) {
|
|
7701
|
+
const inputElement = videoNode.find(`input[name="${name}"]`);
|
|
7702
|
+
const nativeInputElement = inputElement.get(0);
|
|
7703
|
+
return nativeInputElement.value;
|
|
7704
|
+
}
|
|
7705
|
+
function appendButtonGroup(box) {
|
|
7706
|
+
const editor = box.getEditor();
|
|
7707
|
+
if (!editor) {
|
|
7708
|
+
return;
|
|
7709
|
+
}
|
|
7710
|
+
const boxContainer = box.getContainer();
|
|
7711
|
+
const videoNode = boxContainer.find('.lake-video');
|
|
7712
|
+
const buttonGroupNode = query(safeTemplate `
|
|
7713
|
+
<div class="lake-button-group">
|
|
7714
|
+
<button type="button" tabindex="-1" class="lake-button-remove" title="${editor.locale.video.remove()}"></button>
|
|
7715
|
+
</div>
|
|
7716
|
+
`);
|
|
7717
|
+
const removeButton = buttonGroupNode.find('.lake-button-remove');
|
|
7718
|
+
const removeIcon = icons.get('remove');
|
|
7719
|
+
if (removeIcon) {
|
|
7720
|
+
removeButton.append(removeIcon);
|
|
7721
|
+
}
|
|
7722
|
+
buttonGroupNode.find('.lake-button-remove').on('click', event => {
|
|
7723
|
+
event.stopPropagation();
|
|
7724
|
+
editor.selection.removeBox(box);
|
|
7725
|
+
editor.history.save();
|
|
7726
|
+
});
|
|
7727
|
+
videoNode.append(buttonGroupNode);
|
|
7728
|
+
}
|
|
7729
|
+
function showVideo(box) {
|
|
7730
|
+
const editor = box.getEditor();
|
|
7731
|
+
if (!editor) {
|
|
7732
|
+
return;
|
|
7733
|
+
}
|
|
7734
|
+
const boxContainer = box.getContainer();
|
|
7735
|
+
const value = box.value;
|
|
7736
|
+
const width = value.width || 560;
|
|
7737
|
+
const height = value.height || 315;
|
|
7738
|
+
boxContainer.css({
|
|
7739
|
+
width: `${width}px`,
|
|
7740
|
+
height: `${height}px`,
|
|
7741
|
+
});
|
|
7742
|
+
const videoId = getVideoId(value.url);
|
|
7743
|
+
if (videoId === '') {
|
|
7744
|
+
throw new Error(`Invalid link: ${value.url}`);
|
|
7745
|
+
}
|
|
7746
|
+
// YouTube URL: https://www.youtube.com/watch?v=5sMBhDv4sik
|
|
7747
|
+
// The script for embedding YouTube:
|
|
7748
|
+
// <iframe width="560" height="315" src="https://www.youtube.com/embed/5sMBhDv4sik" title="YouTube video player"
|
|
7749
|
+
// frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
|
7750
|
+
// referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
|
7751
|
+
const iframeNode = query(safeTemplate `
|
|
7752
|
+
<iframe width="100%" height="${height}" src="https://www.youtube.com/embed/${videoId}" title="YouTube video player"
|
|
7753
|
+
frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
|
7754
|
+
referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
|
7755
|
+
`);
|
|
7756
|
+
const rootNode = boxContainer.find('.lake-video');
|
|
7757
|
+
if (!editor.readonly) {
|
|
7758
|
+
iframeNode.on('load', () => {
|
|
7759
|
+
appendButtonGroup(box);
|
|
7760
|
+
new BoxResizer({
|
|
7761
|
+
root: rootNode,
|
|
7762
|
+
box,
|
|
7763
|
+
width,
|
|
7764
|
+
height,
|
|
7765
|
+
onResize: (newWidth, newHeight) => {
|
|
7766
|
+
iframeNode.attr({
|
|
7767
|
+
height: newHeight.toString(),
|
|
7768
|
+
});
|
|
7769
|
+
},
|
|
7770
|
+
onStop: (newWidth, newHeight) => {
|
|
7771
|
+
box.updateValue({
|
|
7772
|
+
width: newWidth,
|
|
7773
|
+
height: newHeight,
|
|
7774
|
+
});
|
|
7775
|
+
editor.history.save();
|
|
7776
|
+
},
|
|
7777
|
+
}).render();
|
|
7778
|
+
});
|
|
7779
|
+
}
|
|
7780
|
+
rootNode.append(iframeNode);
|
|
7781
|
+
}
|
|
7782
|
+
const videoBox = {
|
|
7783
|
+
type: 'inline',
|
|
7784
|
+
name: 'video',
|
|
7785
|
+
render: box => {
|
|
7786
|
+
const editor = box.getEditor();
|
|
7787
|
+
if (!editor) {
|
|
7788
|
+
return;
|
|
7789
|
+
}
|
|
7790
|
+
const locale = editor.locale;
|
|
7791
|
+
const value = box.value;
|
|
7792
|
+
const boxContainer = box.getContainer();
|
|
7793
|
+
const rootNode = query('<div class="lake-video" />');
|
|
7794
|
+
boxContainer.empty();
|
|
7795
|
+
boxContainer.css({
|
|
7796
|
+
width: '',
|
|
7797
|
+
height: '',
|
|
7798
|
+
});
|
|
7799
|
+
boxContainer.append(rootNode);
|
|
7800
|
+
if (!value.url) {
|
|
7801
|
+
if (editor.readonly) {
|
|
7802
|
+
box.node.hide();
|
|
7803
|
+
return;
|
|
7804
|
+
}
|
|
7805
|
+
const formNode = query(safeTemplate `
|
|
7806
|
+
<div class="lake-video-form">
|
|
7807
|
+
<div class="lake-row lake-desc-row">${locale.video.description()}</div>
|
|
7808
|
+
<div class="lake-row">${locale.video.url()}</div>
|
|
7809
|
+
<div class="lake-row">
|
|
7810
|
+
<input type="text" name="url" placeholder="https://www.youtube.com/watch?v=..." />
|
|
7811
|
+
</div>
|
|
7812
|
+
<div class="lake-row lake-button-row"></div>
|
|
7813
|
+
</div>
|
|
7814
|
+
`);
|
|
7815
|
+
const button = new Button({
|
|
7816
|
+
root: formNode.find('.lake-button-row'),
|
|
7817
|
+
name: 'embed',
|
|
7818
|
+
type: 'primary',
|
|
7819
|
+
text: locale.video.embed(),
|
|
7820
|
+
onClick: () => {
|
|
7821
|
+
const url = getInputValue(formNode, 'url');
|
|
7822
|
+
if (url.indexOf('https://www.youtube.com/') < 0 || getVideoId(url) === '') {
|
|
7823
|
+
editor.config.onMessage('error', locale.video.urlError());
|
|
7824
|
+
return;
|
|
7825
|
+
}
|
|
7826
|
+
box.updateValue('url', url);
|
|
7827
|
+
editor.history.save();
|
|
7828
|
+
formNode.remove();
|
|
7829
|
+
showVideo(box);
|
|
7830
|
+
},
|
|
7831
|
+
});
|
|
7832
|
+
formNode.find('input[name="url"]').on('keydown', createKeybindingsHandler({
|
|
7833
|
+
'Enter': event => {
|
|
7834
|
+
event.preventDefault();
|
|
7835
|
+
button.node.emit('click');
|
|
7836
|
+
},
|
|
7837
|
+
}));
|
|
7838
|
+
button.render();
|
|
7839
|
+
rootNode.append(formNode);
|
|
7840
|
+
appendButtonGroup(box);
|
|
7841
|
+
}
|
|
7842
|
+
else {
|
|
7843
|
+
showVideo(box);
|
|
7844
|
+
}
|
|
7840
7845
|
},
|
|
7841
7846
|
};
|
|
7842
7847
|
|
|
@@ -7862,11 +7867,10 @@ const boxToolbarItems = [
|
|
|
7862
7867
|
}
|
|
7863
7868
|
editor.selection.removeBox(box);
|
|
7864
7869
|
editor.history.save();
|
|
7865
|
-
editor.selection.sync();
|
|
7866
7870
|
},
|
|
7867
7871
|
},
|
|
7868
7872
|
];
|
|
7869
|
-
function appendContent(
|
|
7873
|
+
function appendContent(rootNode, box) {
|
|
7870
7874
|
return __awaiter(this, void 0, void 0, function* () {
|
|
7871
7875
|
const editor = box.getEditor();
|
|
7872
7876
|
if (!editor) {
|
|
@@ -7899,7 +7903,7 @@ function appendContent(fileNode, box) {
|
|
|
7899
7903
|
typeNode.append(fileIcon);
|
|
7900
7904
|
}
|
|
7901
7905
|
}
|
|
7902
|
-
|
|
7906
|
+
rootNode.append(infoNode);
|
|
7903
7907
|
});
|
|
7904
7908
|
}
|
|
7905
7909
|
const fileBox = {
|
|
@@ -7916,26 +7920,45 @@ const fileBox = {
|
|
|
7916
7920
|
return;
|
|
7917
7921
|
}
|
|
7918
7922
|
const container = box.getContainer();
|
|
7919
|
-
const
|
|
7920
|
-
|
|
7921
|
-
appendContent(
|
|
7923
|
+
const rootNode = query('<div class="lake-file" />');
|
|
7924
|
+
rootNode.addClass(`lake-file-${value.status}`);
|
|
7925
|
+
appendContent(rootNode, box);
|
|
7922
7926
|
container.empty();
|
|
7923
|
-
container.append(
|
|
7927
|
+
container.append(rootNode);
|
|
7924
7928
|
if (!editor.readonly) {
|
|
7925
|
-
|
|
7929
|
+
rootNode.on('click', () => {
|
|
7926
7930
|
editor.selection.selectBox(box);
|
|
7927
7931
|
});
|
|
7928
7932
|
const items = value.status === 'done' ? boxToolbarItems : boxToolbarItems.filter(item => item.name === 'remove');
|
|
7929
7933
|
box.setToolbar(items);
|
|
7930
7934
|
}
|
|
7931
7935
|
else {
|
|
7932
|
-
|
|
7936
|
+
rootNode.on('click', () => {
|
|
7933
7937
|
window.open(value.url);
|
|
7934
7938
|
});
|
|
7935
7939
|
}
|
|
7936
7940
|
},
|
|
7937
7941
|
};
|
|
7938
7942
|
|
|
7943
|
+
const emojiBox = {
|
|
7944
|
+
type: 'inline',
|
|
7945
|
+
name: 'emoji',
|
|
7946
|
+
render: box => {
|
|
7947
|
+
const editor = box.getEditor();
|
|
7948
|
+
if (!editor) {
|
|
7949
|
+
return;
|
|
7950
|
+
}
|
|
7951
|
+
const value = box.value;
|
|
7952
|
+
const rootNode = query(safeTemplate `
|
|
7953
|
+
<div class="lake-emoji"><img src="${value.url}" title="${value.title}" /></div>
|
|
7954
|
+
`);
|
|
7955
|
+
box.getContainer().append(rootNode);
|
|
7956
|
+
rootNode.on('click', () => {
|
|
7957
|
+
editor.selection.selectBox(box);
|
|
7958
|
+
});
|
|
7959
|
+
},
|
|
7960
|
+
};
|
|
7961
|
+
|
|
7939
7962
|
var copy = (editor) => {
|
|
7940
7963
|
editor.event.on('copy', event => {
|
|
7941
7964
|
const range = editor.selection.range;
|
|
@@ -8554,7 +8577,6 @@ var list = (editor) => {
|
|
|
8554
8577
|
}
|
|
8555
8578
|
}
|
|
8556
8579
|
editor.history.save();
|
|
8557
|
-
editor.selection.sync();
|
|
8558
8580
|
},
|
|
8559
8581
|
});
|
|
8560
8582
|
editor.container.on('click', event => {
|
|
@@ -9166,14 +9188,12 @@ var link = (editor) => {
|
|
|
9166
9188
|
const range = editor.selection.range;
|
|
9167
9189
|
range.setStartAfter(node);
|
|
9168
9190
|
range.collapseToStart();
|
|
9169
|
-
editor.selection.sync();
|
|
9170
9191
|
editor.history.save();
|
|
9171
9192
|
},
|
|
9172
9193
|
onRemove: node => {
|
|
9173
9194
|
const range = editor.selection.range;
|
|
9174
9195
|
range.setStartAfter(node);
|
|
9175
9196
|
range.collapseToStart();
|
|
9176
|
-
editor.selection.sync();
|
|
9177
9197
|
editor.history.save();
|
|
9178
9198
|
},
|
|
9179
9199
|
});
|
|
@@ -9232,21 +9252,6 @@ var hr = (editor) => {
|
|
|
9232
9252
|
});
|
|
9233
9253
|
};
|
|
9234
9254
|
|
|
9235
|
-
var video = (editor) => {
|
|
9236
|
-
if (editor.readonly) {
|
|
9237
|
-
return;
|
|
9238
|
-
}
|
|
9239
|
-
editor.command.add('video', {
|
|
9240
|
-
execute: (value) => {
|
|
9241
|
-
const box = editor.selection.insertBox('video', value);
|
|
9242
|
-
editor.history.save();
|
|
9243
|
-
if (box) {
|
|
9244
|
-
box.getContainer().find('input[name="url"]').focus();
|
|
9245
|
-
}
|
|
9246
|
-
},
|
|
9247
|
-
});
|
|
9248
|
-
};
|
|
9249
|
-
|
|
9250
9255
|
const langList = [
|
|
9251
9256
|
'text',
|
|
9252
9257
|
'c',
|
|
@@ -9282,8 +9287,7 @@ var codeBlock = (editor) => {
|
|
|
9282
9287
|
execute: (value) => {
|
|
9283
9288
|
const box = editor.selection.insertBox('codeBlock', value);
|
|
9284
9289
|
editor.history.save();
|
|
9285
|
-
|
|
9286
|
-
codeEditor.focus();
|
|
9290
|
+
box.getContainer().find('.lake-code-block').emit('click');
|
|
9287
9291
|
},
|
|
9288
9292
|
});
|
|
9289
9293
|
};
|
|
@@ -9322,6 +9326,21 @@ var image = (editor) => {
|
|
|
9322
9326
|
});
|
|
9323
9327
|
};
|
|
9324
9328
|
|
|
9329
|
+
var video = (editor) => {
|
|
9330
|
+
if (editor.readonly) {
|
|
9331
|
+
return;
|
|
9332
|
+
}
|
|
9333
|
+
editor.command.add('video', {
|
|
9334
|
+
execute: (value) => {
|
|
9335
|
+
const box = editor.selection.insertBox('video', value);
|
|
9336
|
+
editor.history.save();
|
|
9337
|
+
if (box) {
|
|
9338
|
+
box.getContainer().find('input[name="url"]').focus();
|
|
9339
|
+
}
|
|
9340
|
+
},
|
|
9341
|
+
});
|
|
9342
|
+
};
|
|
9343
|
+
|
|
9325
9344
|
var file = (editor) => {
|
|
9326
9345
|
editor.setPluginConfig('file', {
|
|
9327
9346
|
requestMethod: 'POST',
|
|
@@ -9355,6 +9374,18 @@ var file = (editor) => {
|
|
|
9355
9374
|
});
|
|
9356
9375
|
};
|
|
9357
9376
|
|
|
9377
|
+
var emoji = (editor) => {
|
|
9378
|
+
if (editor.readonly) {
|
|
9379
|
+
return;
|
|
9380
|
+
}
|
|
9381
|
+
editor.command.add('emoji', {
|
|
9382
|
+
execute: (value) => {
|
|
9383
|
+
editor.selection.insertBox('emoji', value);
|
|
9384
|
+
editor.history.save();
|
|
9385
|
+
},
|
|
9386
|
+
});
|
|
9387
|
+
};
|
|
9388
|
+
|
|
9358
9389
|
const headingTypeMap = new Map([
|
|
9359
9390
|
['#', 'h1'],
|
|
9360
9391
|
['##', 'h2'],
|
|
@@ -9554,7 +9585,7 @@ function executeMarkCommand(editor, point) {
|
|
|
9554
9585
|
// <p>foobold\u200B<focus /></p>,
|
|
9555
9586
|
// to
|
|
9556
9587
|
// <p>foo[bold]\u200B<focus /></p>, startOffset = 3, endOffset = 7
|
|
9557
|
-
editor.
|
|
9588
|
+
editor.history.pause();
|
|
9558
9589
|
const bookmark = selection.insertBookmark();
|
|
9559
9590
|
const node = bookmark.focus.prev();
|
|
9560
9591
|
const oldValue = node.text();
|
|
@@ -9564,7 +9595,8 @@ function executeMarkCommand(editor, point) {
|
|
|
9564
9595
|
range.setEnd(node, offset - (oldValue.length - newValue.length) - 1);
|
|
9565
9596
|
editor.command.execute(commandName, ...parameters);
|
|
9566
9597
|
selection.toBookmark(bookmark);
|
|
9567
|
-
editor.
|
|
9598
|
+
editor.history.continue();
|
|
9599
|
+
editor.history.save();
|
|
9568
9600
|
return true;
|
|
9569
9601
|
}
|
|
9570
9602
|
}
|
|
@@ -9586,16 +9618,14 @@ function spaceKeyExecutesBlockCommand(editor, point) {
|
|
|
9586
9618
|
// <p>#<focus />foo</p>
|
|
9587
9619
|
// to
|
|
9588
9620
|
// <h1><focus />foo</h1>
|
|
9589
|
-
editor.prepareOperation();
|
|
9590
9621
|
const bookmark = selection.insertBookmark();
|
|
9591
9622
|
const node = bookmark.focus.prev();
|
|
9592
9623
|
node.remove();
|
|
9593
9624
|
const block = bookmark.focus.closestBlock();
|
|
9594
9625
|
fixEmptyBlock(block);
|
|
9595
9626
|
selection.range.shrinkAfter(block);
|
|
9596
|
-
editor.command.execute(commandName, ...parameters);
|
|
9597
9627
|
selection.toBookmark(bookmark);
|
|
9598
|
-
editor.
|
|
9628
|
+
editor.command.execute(commandName, ...parameters);
|
|
9599
9629
|
return true;
|
|
9600
9630
|
}
|
|
9601
9631
|
}
|
|
@@ -9616,12 +9646,10 @@ function enterKeyExecutesBlockCommand(editor, block) {
|
|
|
9616
9646
|
// <p>---<focus /></p>
|
|
9617
9647
|
// to
|
|
9618
9648
|
// <lake-box type="block" name="hr" focus="end"></lake-box>
|
|
9619
|
-
editor.prepareOperation();
|
|
9620
9649
|
block.empty();
|
|
9621
9650
|
fixEmptyBlock(block);
|
|
9622
9651
|
selection.range.shrinkAfter(block);
|
|
9623
9652
|
editor.command.execute(commandName, ...parameters);
|
|
9624
|
-
editor.commitOperation();
|
|
9625
9653
|
return true;
|
|
9626
9654
|
}
|
|
9627
9655
|
}
|
|
@@ -9700,7 +9728,7 @@ function splitBlock(editor, block) {
|
|
|
9700
9728
|
block.find('li').attr('value', 'false');
|
|
9701
9729
|
}
|
|
9702
9730
|
}
|
|
9703
|
-
function
|
|
9731
|
+
function addOrSplitBlockForBox(editor) {
|
|
9704
9732
|
const range = editor.selection.range;
|
|
9705
9733
|
const boxNode = range.startNode.closest('lake-box');
|
|
9706
9734
|
const block = boxNode.closestBlock();
|
|
@@ -9744,7 +9772,7 @@ var enterKey = (editor) => {
|
|
|
9744
9772
|
event.preventDefault();
|
|
9745
9773
|
editor.fixContent();
|
|
9746
9774
|
if (range.isBox) {
|
|
9747
|
-
|
|
9775
|
+
addOrSplitBlockForBox(editor);
|
|
9748
9776
|
editor.history.save();
|
|
9749
9777
|
return;
|
|
9750
9778
|
}
|
|
@@ -9753,7 +9781,7 @@ var enterKey = (editor) => {
|
|
|
9753
9781
|
return;
|
|
9754
9782
|
}
|
|
9755
9783
|
if (range.isBox) {
|
|
9756
|
-
|
|
9784
|
+
addOrSplitBlockForBox(editor);
|
|
9757
9785
|
editor.history.save();
|
|
9758
9786
|
return;
|
|
9759
9787
|
}
|
|
@@ -9779,7 +9807,9 @@ function addLineBreak(editor) {
|
|
|
9779
9807
|
const prevNode = range.getPrevNode();
|
|
9780
9808
|
const endText = range.getEndText();
|
|
9781
9809
|
if (prevNode.name !== 'br' && endText === '') {
|
|
9782
|
-
|
|
9810
|
+
const fragment = new Fragment();
|
|
9811
|
+
fragment.append('<br /><br />');
|
|
9812
|
+
editor.selection.insertFragment(fragment);
|
|
9783
9813
|
editor.history.save();
|
|
9784
9814
|
return;
|
|
9785
9815
|
}
|
|
@@ -9848,6 +9878,14 @@ var shiftEnterKey = (editor) => {
|
|
|
9848
9878
|
});
|
|
9849
9879
|
};
|
|
9850
9880
|
|
|
9881
|
+
function removeEmptyMarks(range) {
|
|
9882
|
+
const block = range.getBlocks()[0];
|
|
9883
|
+
if (block && block.isEmpty && block.first().name !== 'br') {
|
|
9884
|
+
block.empty();
|
|
9885
|
+
appendDeepest(block, query('<br />'));
|
|
9886
|
+
range.shrinkAfter(block);
|
|
9887
|
+
}
|
|
9888
|
+
}
|
|
9851
9889
|
function mergeWithPreviousBlock(editor, block) {
|
|
9852
9890
|
const range = editor.selection.range;
|
|
9853
9891
|
let prevBlock = block.prev();
|
|
@@ -9878,6 +9916,7 @@ function mergeWithPreviousBlock(editor, block) {
|
|
|
9878
9916
|
prevBlock.remove();
|
|
9879
9917
|
return;
|
|
9880
9918
|
}
|
|
9919
|
+
removeEmptyMarks(range);
|
|
9881
9920
|
const bookmark = editor.selection.insertBookmark();
|
|
9882
9921
|
mergeNodes(prevBlock, block);
|
|
9883
9922
|
editor.selection.toBookmark(bookmark);
|
|
@@ -9890,6 +9929,14 @@ var backspaceKey = (editor) => {
|
|
|
9890
9929
|
editor.keystroke.setKeydown('backspace', event => {
|
|
9891
9930
|
const range = editor.selection.range;
|
|
9892
9931
|
if (range.isInsideBox) {
|
|
9932
|
+
const boxNode = range.commonAncestor.closest('lake-box');
|
|
9933
|
+
const box = getBox(boxNode);
|
|
9934
|
+
const boxValue = box.value;
|
|
9935
|
+
if (box.name === 'codeBlock' && (boxValue.code === undefined || boxValue.code === '')) {
|
|
9936
|
+
event.preventDefault();
|
|
9937
|
+
editor.selection.removeBox(box);
|
|
9938
|
+
editor.history.save();
|
|
9939
|
+
}
|
|
9893
9940
|
return;
|
|
9894
9941
|
}
|
|
9895
9942
|
editor.fixContent();
|
|
@@ -9948,7 +9995,7 @@ var backspaceKey = (editor) => {
|
|
|
9948
9995
|
editor.history.save();
|
|
9949
9996
|
return;
|
|
9950
9997
|
}
|
|
9951
|
-
if (prevNode.isText && prevNode.text().length === 1) {
|
|
9998
|
+
if (prevNode.isText && prevNode.text().length === 1 && prevNode.parent().isBlock) {
|
|
9952
9999
|
event.preventDefault();
|
|
9953
10000
|
const block = prevNode.closestBlock();
|
|
9954
10001
|
range.setStartBefore(prevNode);
|
|
@@ -10111,13 +10158,14 @@ var tabKey = (editor) => {
|
|
|
10111
10158
|
}
|
|
10112
10159
|
event.preventDefault();
|
|
10113
10160
|
const blocks = editor.selection.range.getBlocks();
|
|
10114
|
-
|
|
10161
|
+
for (const block of blocks) {
|
|
10115
10162
|
if (block.name !== 'p' || block.css('text-indent') === '2em') {
|
|
10116
10163
|
setBlockIndent(block, 'increase');
|
|
10117
|
-
return;
|
|
10118
10164
|
}
|
|
10119
|
-
|
|
10120
|
-
|
|
10165
|
+
else {
|
|
10166
|
+
block.css('text-indent', '2em');
|
|
10167
|
+
}
|
|
10168
|
+
}
|
|
10121
10169
|
editor.history.save();
|
|
10122
10170
|
});
|
|
10123
10171
|
};
|
|
@@ -10268,10 +10316,11 @@ var escapeKey = (editor) => {
|
|
|
10268
10316
|
};
|
|
10269
10317
|
|
|
10270
10318
|
Editor.box.add(hrBox);
|
|
10271
|
-
Editor.box.add(videoBox);
|
|
10272
10319
|
Editor.box.add(codeBlockBox);
|
|
10273
10320
|
Editor.box.add(imageBox);
|
|
10321
|
+
Editor.box.add(videoBox);
|
|
10274
10322
|
Editor.box.add(fileBox);
|
|
10323
|
+
Editor.box.add(emojiBox);
|
|
10275
10324
|
Editor.plugin.add(copy);
|
|
10276
10325
|
Editor.plugin.add(cut);
|
|
10277
10326
|
Editor.plugin.add(paste);
|
|
@@ -10299,10 +10348,11 @@ Editor.plugin.add(removeFormat);
|
|
|
10299
10348
|
Editor.plugin.add(formatPainter);
|
|
10300
10349
|
Editor.plugin.add(link);
|
|
10301
10350
|
Editor.plugin.add(hr);
|
|
10302
|
-
Editor.plugin.add(video);
|
|
10303
10351
|
Editor.plugin.add(codeBlock);
|
|
10304
10352
|
Editor.plugin.add(image);
|
|
10353
|
+
Editor.plugin.add(video);
|
|
10305
10354
|
Editor.plugin.add(file);
|
|
10355
|
+
Editor.plugin.add(emoji);
|
|
10306
10356
|
Editor.plugin.add(markdown);
|
|
10307
10357
|
Editor.plugin.add(enterKey);
|
|
10308
10358
|
Editor.plugin.add(shiftEnterKey);
|
|
@@ -10312,5 +10362,5 @@ Editor.plugin.add(tabKey);
|
|
|
10312
10362
|
Editor.plugin.add(arrowKeys);
|
|
10313
10363
|
Editor.plugin.add(escapeKey);
|
|
10314
10364
|
|
|
10315
|
-
export { Box, Button, Dropdown, Editor, Fragment, HTMLParser, Nodes, Range, TextParser, Toolbar, index as Utils, addMark, deleteContents, fixList, icons, insertBookmark,
|
|
10365
|
+
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 };
|
|
10316
10366
|
//# sourceMappingURL=lake.js.map
|