lakelib 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/lake.js CHANGED
@@ -37,8 +37,12 @@ var checkCircle = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height
37
37
 
38
38
  var warningCircle = "<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,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z\"></path></svg>";
39
39
 
40
+ var file$1 = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M213.66,82.34l-56-56A8,8,0,0,0,152,24H56A16,16,0,0,0,40,40V216a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V88A8,8,0,0,0,213.66,82.34ZM160,51.31,188.69,80H160ZM200,216H56V40h88V88a8,8,0,0,0,8,8h48V216Z\"></path></svg>";
41
+
40
42
  var open = "<svg width=\"24\" height=\"24\" fill=\"none\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M6.25 4.5A1.75 1.75 0 0 0 4.5 6.25v11.5c0 .966.783 1.75 1.75 1.75h11.5a1.75 1.75 0 0 0 1.75-1.75v-4a.75.75 0 0 1 1.5 0v4A3.25 3.25 0 0 1 17.75 21H6.25A3.25 3.25 0 0 1 3 17.75V6.25A3.25 3.25 0 0 1 6.25 3h4a.75.75 0 0 1 0 1.5h-4ZM13 3.75a.75.75 0 0 1 .75-.75h6.5a.75.75 0 0 1 .75.75v6.5a.75.75 0 0 1-1.5 0V5.56l-5.22 5.22a.75.75 0 0 1-1.06-1.06l5.22-5.22h-4.69a.75.75 0 0 1-.75-.75Z\" fill=\"#000000\"/></svg>";
41
43
 
44
+ var download = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M224,144v64a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V144a8,8,0,0,1,16,0v56H208V144a8,8,0,0,1,16,0Zm-101.66,5.66a8,8,0,0,0,11.32,0l40-40a8,8,0,0,0-11.32-11.32L136,124.69V32a8,8,0,0,0-16,0v92.69L93.66,98.34a8,8,0,0,0-11.32,11.32Z\"></path></svg>";
45
+
42
46
  var copy$1 = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M216,32H88a8,8,0,0,0-8,8V80H40a8,8,0,0,0-8,8V216a8,8,0,0,0,8,8H168a8,8,0,0,0,8-8V176h40a8,8,0,0,0,8-8V40A8,8,0,0,0,216,32ZM160,208H48V96H160Zm48-48H176V88a8,8,0,0,0-8-8H96V48H208Z\"></path></svg>";
43
47
 
44
48
  var remove = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z\"></path></svg>";
@@ -133,6 +137,8 @@ var hr$1 = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\"
133
137
 
134
138
  var image$1 = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,16V158.75l-26.07-26.06a16,16,0,0,0-22.63,0l-20,20-44-44a16,16,0,0,0-22.62,0L40,149.37V56ZM40,172l52-52,80,80H40Zm176,28H194.63l-36-36,20-20L216,181.38V200ZM144,100a12,12,0,1,1,12,12A12,12,0,0,1,144,100Z\"></path></svg>";
135
139
 
140
+ 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>";
141
+
136
142
  var codeBlock$1 = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"#000000\" viewBox=\"0 0 256 256\"><path d=\"M58.34,101.66l-32-32a8,8,0,0,1,0-11.32l32-32A8,8,0,0,1,69.66,37.66L43.31,64,69.66,90.34a8,8,0,0,1-11.32,11.32Zm40,0a8,8,0,0,0,11.32,0l32-32a8,8,0,0,0,0-11.32l-32-32A8,8,0,0,0,98.34,37.66L124.69,64,98.34,90.34A8,8,0,0,0,98.34,101.66ZM200,40H176a8,8,0,0,0,0,16h24V200H56V136a8,8,0,0,0-16,0v64a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V56A16,16,0,0,0,200,40Z\"></path></svg>";
137
143
 
138
144
  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>";
@@ -160,7 +166,9 @@ const icons = new Map([
160
166
  ['check', check],
161
167
  ['checkCircle', checkCircle],
162
168
  ['warningCircle', warningCircle],
169
+ ['file', file$1],
163
170
  ['open', open],
171
+ ['download', download],
164
172
  ['copy', copy$1],
165
173
  ['remove', remove],
166
174
  ['maximize', maximize],
@@ -208,6 +216,7 @@ const icons = new Map([
208
216
  ['unlink', unlink],
209
217
  ['hr', hr$1],
210
218
  ['image', image$1],
219
+ ['attachment', attachment],
211
220
  ['codeBlock', codeBlock$1],
212
221
  ['table', table],
213
222
  ]);
@@ -324,12 +333,29 @@ function denormalizeValue(value) {
324
333
  // Mac: mod+Z returns ⌘+Z
325
334
  // Windows / Linux: mod+Z returns Ctrl+Z
326
335
  function modifierText(value, userAgent) {
336
+ // for generating i18n files
337
+ if (typeof window === 'undefined') {
338
+ return value;
339
+ }
327
340
  userAgent = userAgent !== null && userAgent !== void 0 ? userAgent : navigator.userAgent;
328
341
  const isMac = userAgent.indexOf('Mac OS X') >= 0;
329
342
  const modText = isMac ? '⌘' : 'Ctrl';
330
343
  return value.replace(/(^|\+|\s)mod(\+|\s|$)/g, `$1${modText}$2`);
331
344
  }
332
345
 
346
+ // Returns a human-readable file size string from a number.
347
+ function fileSize(size) {
348
+ const units = ['KB', 'MB', 'GB'];
349
+ let i = 0;
350
+ size /= 1024;
351
+ while (size > 1024 && i < 2) {
352
+ size /= 1024;
353
+ i++;
354
+ }
355
+ const sizeString = size > 0 ? Math.max(size, 0.1).toFixed(1) : 0;
356
+ return `${sizeString} ${units[i]}`;
357
+ }
358
+
333
359
  // Returns a property value of all CSS properties of an element
334
360
  function getCSS(element, propertyName) {
335
361
  const camelPropertyName = camelCase(propertyName);
@@ -2678,184 +2704,46 @@ function morph(node, otherNode, config = {}) {
2678
2704
  morphNormalizedContent(node.get(0), normalizedContent, ctx);
2679
2705
  }
2680
2706
 
2681
- /**
2682
- The MIT License (MIT)
2683
-
2684
- Copyright (c) 2016-present react-component
2685
-
2686
- Permission is hereby granted, free of charge, to any person obtaining a copy
2687
- of this software and associated documentation files (the "Software"), to deal
2688
- in the Software without restriction, including without limitation the rights
2689
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2690
- copies of the Software, and to permit persons to whom the Software is
2691
- furnished to do so, subject to the following conditions:
2692
-
2693
- The above copyright notice and this permission notice shall be included in
2694
- all copies or substantial portions of the Software.
2695
-
2696
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2697
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2698
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2699
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
2700
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2701
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2702
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2703
-
2704
- Repository: https://github.com/react-component/upload
2705
- */
2706
- function getError(option, xhr) {
2707
- const msg = `Cannot ${option.method} ${option.action} ${xhr.status}'`;
2708
- const err = new Error(msg);
2709
- err.status = xhr.status;
2710
- err.method = option.method;
2711
- err.url = option.action;
2712
- return err;
2713
- }
2714
- function getBody(xhr) {
2715
- const text = xhr.responseText || xhr.response;
2716
- if (!text) {
2717
- return text;
2718
- }
2719
- try {
2720
- return JSON.parse(text);
2721
- }
2722
- catch (e) {
2723
- return text;
2724
- }
2725
- }
2726
- function request(option) {
2727
- const xhr = new XMLHttpRequest();
2728
- if (option.onProgress && xhr.upload) {
2729
- xhr.upload.onprogress = (e) => {
2730
- if (e.total > 0) {
2731
- e.percent = (e.loaded / e.total) * 100;
2732
- }
2733
- if (option.onProgress) {
2734
- option.onProgress(e);
2707
+ // Returns an object that indicates the specified node's position relative to the viewport.
2708
+ function nodeAndView(node) {
2709
+ const nativeNode = node.get(0);
2710
+ const rect = nativeNode.getBoundingClientRect();
2711
+ let left = rect.left;
2712
+ let right = rect.right;
2713
+ let top = rect.top;
2714
+ let bottom = rect.bottom;
2715
+ let viewportWidth = window.innerWidth;
2716
+ let viewportHeight = window.innerHeight;
2717
+ const container = node.closestContainer();
2718
+ if (container.length > 0) {
2719
+ const viewport = container.closestScroller();
2720
+ if (viewport.length > 0) {
2721
+ const containerWrapper = container.parent();
2722
+ if (containerWrapper.length > 0) {
2723
+ const nativeContainerWrapper = containerWrapper.get(0);
2724
+ const offsetLeft = nativeContainerWrapper.offsetLeft - window.scrollX;
2725
+ const offsetTop = nativeContainerWrapper.offsetTop - window.scrollY;
2726
+ left -= offsetLeft;
2727
+ right -= offsetLeft;
2728
+ top -= offsetTop;
2729
+ bottom -= offsetTop;
2735
2730
  }
2736
- };
2737
- }
2738
- const formData = new FormData();
2739
- const data = option.data || {};
2740
- Object.keys(data).forEach(key => {
2741
- const value = data[key];
2742
- // support key-value array data
2743
- if (Array.isArray(value)) {
2744
- value.forEach(item => {
2745
- // { list: [ 11, 22 ] }
2746
- // formData.append('list[]', 11);
2747
- formData.append(`${key}[]`, item);
2748
- });
2749
- return;
2731
+ const nativeViewport = viewport.get(0);
2732
+ const viewportRect = nativeViewport.getBoundingClientRect();
2733
+ viewportWidth = viewportRect.width;
2734
+ viewportHeight = viewportRect.height;
2750
2735
  }
2751
- formData.append(key, value);
2752
- });
2753
- const filename = option.filename || 'file';
2754
- if (option.file instanceof Blob) {
2755
- formData.append(filename, option.file, option.file.name);
2756
- }
2757
- else {
2758
- formData.append(filename, option.file);
2759
2736
  }
2760
- xhr.onerror = (e) => {
2761
- if (option.onError) {
2762
- option.onError(e);
2763
- }
2737
+ const position = {
2738
+ left,
2739
+ right: viewportWidth - right,
2740
+ top,
2741
+ bottom: viewportHeight - bottom,
2764
2742
  };
2765
- xhr.onload = () => {
2766
- // allow success when 2xx status
2767
- // see https://github.com/react-component/upload/issues/34
2768
- if (xhr.status < 200 || xhr.status >= 300) {
2769
- if (!option.onError) {
2770
- return;
2771
- }
2772
- return option.onError(getError(option, xhr), getBody(xhr));
2773
- }
2774
- if (!option.onSuccess) {
2775
- return;
2776
- }
2777
- return option.onSuccess(getBody(xhr), xhr);
2778
- };
2779
- xhr.open(option.method, option.action, true);
2780
- // Has to be after `.open()`. See https://github.com/enyo/dropzone/issues/179
2781
- if (option.withCredentials && 'withCredentials' in xhr) {
2782
- xhr.withCredentials = true;
2783
- }
2784
- const headers = option.headers || {};
2785
- // when set headers['X-Requested-With'] = null , can close default XHR header
2786
- // see https://github.com/react-component/upload/issues/33
2787
- if (headers['X-Requested-With'] !== null) {
2788
- xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
2789
- }
2790
- Object.keys(headers).forEach(h => {
2791
- if (headers[h] !== null) {
2792
- xhr.setRequestHeader(h, headers[h]);
2793
- }
2794
- });
2795
- xhr.send(formData);
2796
- return xhr;
2743
+ return position;
2797
2744
  }
2798
2745
 
2799
- // String
2800
-
2801
- var index = /*#__PURE__*/Object.freeze({
2802
- __proto__: null,
2803
- appendDeepest: appendDeepest,
2804
- camelCase: camelCase,
2805
- changeTagName: changeTagName,
2806
- debug: debug,
2807
- denormalizeValue: denormalizeValue,
2808
- encode: encode,
2809
- fixNumberedList: fixNumberedList,
2810
- getCSS: getCSS,
2811
- getDeepest: getDeepest,
2812
- inString: inString,
2813
- mergeNodes: mergeNodes,
2814
- modifierText: modifierText,
2815
- morph: morph,
2816
- normalizeValue: normalizeValue,
2817
- parseStyle: parseStyle,
2818
- query: query,
2819
- removeBr: removeBr,
2820
- removeZWS: removeZWS,
2821
- request: request,
2822
- safeTemplate: safeTemplate,
2823
- setBlockIndent: setBlockIndent,
2824
- splitNodes: splitNodes,
2825
- template: template,
2826
- toHex: toHex,
2827
- toNodeList: toNodeList,
2828
- wrapNodeList: wrapNodeList
2829
- });
2830
-
2831
- class Fragment {
2832
- constructor(fragment) {
2833
- this.fragment = fragment !== null && fragment !== void 0 ? fragment : document.createDocumentFragment();
2834
- }
2835
- // Returns the descendants of the fragment which are selected by the specified CSS selector.
2836
- find(selector) {
2837
- const nodeList = [];
2838
- let child = new Nodes(this.fragment.firstChild);
2839
- while (child.length > 0) {
2840
- if (child.matches(selector)) {
2841
- nodeList.push(child.get(0));
2842
- }
2843
- else if (child.isElement) {
2844
- child.find(selector).each(node => {
2845
- nodeList.push(node);
2846
- });
2847
- }
2848
- child = child.next();
2849
- }
2850
- return new Nodes(nodeList);
2851
- }
2852
- // Inserts the specified node as the last child.
2853
- append(node) {
2854
- node.each(nativeNode => {
2855
- this.fragment.appendChild(nativeNode);
2856
- });
2857
- }
2858
- }
2746
+ const boxInstances = new Map();
2859
2747
 
2860
2748
  const boxes = new Map();
2861
2749
 
@@ -2867,7 +2755,7 @@ const boxData = {};
2867
2755
  const effectData = {};
2868
2756
  const framework = safeTemplate `
2869
2757
  <span class="lake-box-strip"><br /></span>
2870
- <div class="lake-box-container" contenteditable="false" draggable="true"></div>
2758
+ <div class="lake-box-container" contenteditable="false"></div>
2871
2759
  <span class="lake-box-strip"><br /></span>
2872
2760
  `;
2873
2761
  class Box {
@@ -2932,6 +2820,9 @@ class Box {
2932
2820
  debug(`Box '${this.name}' (id = ${this.node.id}) value:`);
2933
2821
  debug(this.value);
2934
2822
  });
2823
+ if (this.type === 'block') {
2824
+ container.attr('draggable', 'true');
2825
+ }
2935
2826
  }
2936
2827
  // Returns the type of the box.
2937
2828
  get type() {
@@ -3009,28 +2900,235 @@ class Box {
3009
2900
  }
3010
2901
  debug(`Box '${this.name}' (id = ${this.node.id}) rendered`);
3011
2902
  }
3012
- // Destroys a rendered box.
3013
- unmount() {
3014
- for (const cleanup of effectData[this.node.id].cleanup) {
3015
- cleanup();
2903
+ // Destroys a rendered box.
2904
+ unmount() {
2905
+ this.event.emit('blur');
2906
+ for (const cleanup of effectData[this.node.id].cleanup) {
2907
+ cleanup();
2908
+ }
2909
+ boxData[this.node.id] = {};
2910
+ effectData[this.node.id].setup = [];
2911
+ effectData[this.node.id].cleanup = [];
2912
+ this.event.removeAllListeners();
2913
+ this.node.empty();
2914
+ debug(`Box '${this.name}' (id = ${this.node.id}) unmounted`);
2915
+ }
2916
+ // Returns a HTML string of the box.
2917
+ getHTML() {
2918
+ const component = boxes.get(this.name);
2919
+ if (component === undefined) {
2920
+ return '';
2921
+ }
2922
+ if (component.html === undefined) {
2923
+ return this.node.outerHTML();
2924
+ }
2925
+ return component.html(this);
2926
+ }
2927
+ }
2928
+
2929
+ // Returns an already generated box instance or generates a new instance if it does not exist.
2930
+ function getBox(boxNode) {
2931
+ if (typeof boxNode === 'string') {
2932
+ return new Box(boxNode);
2933
+ }
2934
+ boxNode = query(boxNode);
2935
+ const container = boxNode.closestContainer();
2936
+ if (container.length === 0) {
2937
+ return new Box(boxNode);
2938
+ }
2939
+ let instanceMap = boxInstances.get(container.id);
2940
+ if (!instanceMap) {
2941
+ instanceMap = new Map();
2942
+ boxInstances.set(container.id, instanceMap);
2943
+ }
2944
+ let box = instanceMap.get(boxNode.id);
2945
+ if (box) {
2946
+ return box;
2947
+ }
2948
+ box = new Box(boxNode);
2949
+ instanceMap.set(box.node.id, box);
2950
+ return box;
2951
+ }
2952
+
2953
+ /**
2954
+ The MIT License (MIT)
2955
+
2956
+ Copyright (c) 2016-present react-component
2957
+
2958
+ Permission is hereby granted, free of charge, to any person obtaining a copy
2959
+ of this software and associated documentation files (the "Software"), to deal
2960
+ in the Software without restriction, including without limitation the rights
2961
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2962
+ copies of the Software, and to permit persons to whom the Software is
2963
+ furnished to do so, subject to the following conditions:
2964
+
2965
+ The above copyright notice and this permission notice shall be included in
2966
+ all copies or substantial portions of the Software.
2967
+
2968
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2969
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2970
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2971
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
2972
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2973
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2974
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2975
+
2976
+ Repository: https://github.com/react-component/upload
2977
+ */
2978
+ function getError(option, xhr) {
2979
+ const msg = `Cannot ${option.method} ${option.action} ${xhr.status}'`;
2980
+ const err = new Error(msg);
2981
+ err.status = xhr.status;
2982
+ err.method = option.method;
2983
+ err.url = option.action;
2984
+ return err;
2985
+ }
2986
+ function getBody(xhr) {
2987
+ const text = xhr.responseText || xhr.response;
2988
+ if (!text) {
2989
+ return text;
2990
+ }
2991
+ try {
2992
+ return JSON.parse(text);
2993
+ }
2994
+ catch (e) {
2995
+ return text;
2996
+ }
2997
+ }
2998
+ function request(option) {
2999
+ const xhr = new XMLHttpRequest();
3000
+ if (option.onProgress && xhr.upload) {
3001
+ xhr.upload.onprogress = (e) => {
3002
+ if (e.total > 0) {
3003
+ e.percent = (e.loaded / e.total) * 100;
3004
+ }
3005
+ if (option.onProgress) {
3006
+ option.onProgress(e);
3007
+ }
3008
+ };
3009
+ }
3010
+ const formData = new FormData();
3011
+ const data = option.data || {};
3012
+ Object.keys(data).forEach(key => {
3013
+ const value = data[key];
3014
+ // support key-value array data
3015
+ if (Array.isArray(value)) {
3016
+ value.forEach(item => {
3017
+ // { list: [ 11, 22 ] }
3018
+ // formData.append('list[]', 11);
3019
+ formData.append(`${key}[]`, item);
3020
+ });
3021
+ return;
3022
+ }
3023
+ formData.append(key, value);
3024
+ });
3025
+ const filename = option.filename || 'file';
3026
+ if (option.file instanceof Blob) {
3027
+ formData.append(filename, option.file, option.file.name);
3028
+ }
3029
+ else {
3030
+ formData.append(filename, option.file);
3031
+ }
3032
+ xhr.onerror = (e) => {
3033
+ if (option.onError) {
3034
+ option.onError(e);
3035
+ }
3036
+ };
3037
+ xhr.onload = () => {
3038
+ // allow success when 2xx status
3039
+ // see https://github.com/react-component/upload/issues/34
3040
+ if (xhr.status < 200 || xhr.status >= 300) {
3041
+ if (!option.onError) {
3042
+ return;
3043
+ }
3044
+ return option.onError(getError(option, xhr), getBody(xhr));
3045
+ }
3046
+ if (!option.onSuccess) {
3047
+ return;
3048
+ }
3049
+ return option.onSuccess(getBody(xhr), xhr);
3050
+ };
3051
+ xhr.open(option.method, option.action, true);
3052
+ // Has to be after `.open()`. See https://github.com/enyo/dropzone/issues/179
3053
+ if (option.withCredentials && 'withCredentials' in xhr) {
3054
+ xhr.withCredentials = true;
3055
+ }
3056
+ const headers = option.headers || {};
3057
+ // when set headers['X-Requested-With'] = null , can close default XHR header
3058
+ // see https://github.com/react-component/upload/issues/33
3059
+ if (headers['X-Requested-With'] !== null) {
3060
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
3061
+ }
3062
+ Object.keys(headers).forEach(h => {
3063
+ if (headers[h] !== null) {
3064
+ xhr.setRequestHeader(h, headers[h]);
3065
+ }
3066
+ });
3067
+ xhr.send(formData);
3068
+ return xhr;
3069
+ }
3070
+
3071
+ // String
3072
+
3073
+ var index = /*#__PURE__*/Object.freeze({
3074
+ __proto__: null,
3075
+ appendDeepest: appendDeepest,
3076
+ camelCase: camelCase,
3077
+ changeTagName: changeTagName,
3078
+ debug: debug,
3079
+ denormalizeValue: denormalizeValue,
3080
+ encode: encode,
3081
+ fileSize: fileSize,
3082
+ fixNumberedList: fixNumberedList,
3083
+ getBox: getBox,
3084
+ getCSS: getCSS,
3085
+ getDeepest: getDeepest,
3086
+ inString: inString,
3087
+ mergeNodes: mergeNodes,
3088
+ modifierText: modifierText,
3089
+ morph: morph,
3090
+ nodeAndView: nodeAndView,
3091
+ normalizeValue: normalizeValue,
3092
+ parseStyle: parseStyle,
3093
+ query: query,
3094
+ removeBr: removeBr,
3095
+ removeZWS: removeZWS,
3096
+ request: request,
3097
+ safeTemplate: safeTemplate,
3098
+ setBlockIndent: setBlockIndent,
3099
+ splitNodes: splitNodes,
3100
+ template: template,
3101
+ toHex: toHex,
3102
+ toNodeList: toNodeList,
3103
+ wrapNodeList: wrapNodeList
3104
+ });
3105
+
3106
+ class Fragment {
3107
+ constructor(fragment) {
3108
+ this.fragment = fragment !== null && fragment !== void 0 ? fragment : document.createDocumentFragment();
3109
+ }
3110
+ // Returns the descendants of the fragment which are selected by the specified CSS selector.
3111
+ find(selector) {
3112
+ const nodeList = [];
3113
+ let child = new Nodes(this.fragment.firstChild);
3114
+ while (child.length > 0) {
3115
+ if (child.matches(selector)) {
3116
+ nodeList.push(child.get(0));
3117
+ }
3118
+ else if (child.isElement) {
3119
+ child.find(selector).each(node => {
3120
+ nodeList.push(node);
3121
+ });
3122
+ }
3123
+ child = child.next();
3016
3124
  }
3017
- boxData[this.node.id] = {};
3018
- effectData[this.node.id].setup = [];
3019
- effectData[this.node.id].cleanup = [];
3020
- this.event.removeAllListeners();
3021
- this.node.empty();
3022
- debug(`Box '${this.name}' (id = ${this.node.id}) unmounted`);
3125
+ return new Nodes(nodeList);
3023
3126
  }
3024
- // Returns a HTML string of the box.
3025
- getHTML() {
3026
- const component = boxes.get(this.name);
3027
- if (component === undefined) {
3028
- return '';
3029
- }
3030
- if (component.html === undefined) {
3031
- return this.node.outerHTML();
3032
- }
3033
- return component.html(this);
3127
+ // Inserts the specified node as the last child.
3128
+ append(node) {
3129
+ node.each(nativeNode => {
3130
+ this.fragment.appendChild(nativeNode);
3131
+ });
3034
3132
  }
3035
3133
  }
3036
3134
 
@@ -3440,7 +3538,7 @@ function toBookmark(range, bookmark) {
3440
3538
  }
3441
3539
  if (focus.length > 0 && anchor.length === 0) {
3442
3540
  if (focus.isBox) {
3443
- const box = new Box(focus);
3541
+ const box = getBox(focus);
3444
3542
  if (box.getContainer().length === 0) {
3445
3543
  box.render();
3446
3544
  }
@@ -3861,7 +3959,7 @@ function addMark(range, value) {
3861
3959
  if (range.isCollapsed) {
3862
3960
  if (range.isBox) {
3863
3961
  const boxNode = range.startNode.closest('lake-box');
3864
- const box = new Box(boxNode);
3962
+ const box = getBox(boxNode);
3865
3963
  if (box.type === 'block') {
3866
3964
  const newBlock = query('<p><br /></p>');
3867
3965
  if (range.isBoxStart) {
@@ -4160,6 +4258,7 @@ var enUS = {
4160
4258
  fontColor: 'Font color',
4161
4259
  highlight: 'Highlight',
4162
4260
  image: 'Image',
4261
+ file: 'File',
4163
4262
  removeColor: 'Remove color',
4164
4263
  },
4165
4264
  link: {
@@ -4181,6 +4280,10 @@ var enUS = {
4181
4280
  zoomOut: 'Zoom out',
4182
4281
  zoomIn: 'Zoom in',
4183
4282
  },
4283
+ file: {
4284
+ download: 'Download',
4285
+ remove: 'Delete',
4286
+ },
4184
4287
  codeBlock: {
4185
4288
  langType: 'Select language',
4186
4289
  },
@@ -4230,6 +4333,7 @@ var zhCN = {
4230
4333
  fontColor: '文字颜色',
4231
4334
  highlight: '文字背景',
4232
4335
  image: '图片',
4336
+ file: '文件',
4233
4337
  removeColor: '默认',
4234
4338
  },
4235
4339
  link: {
@@ -4251,6 +4355,10 @@ var zhCN = {
4251
4355
  zoomOut: '缩小',
4252
4356
  zoomIn: '放大',
4253
4357
  },
4358
+ file: {
4359
+ download: '下载',
4360
+ remove: '删除',
4361
+ },
4254
4362
  codeBlock: {
4255
4363
  langType: '选择代码语言',
4256
4364
  },
@@ -4300,6 +4408,7 @@ var ja = {
4300
4408
  fontColor: '文字色',
4301
4409
  highlight: '文字の背景',
4302
4410
  image: '画像',
4411
+ file: 'ファイル',
4303
4412
  removeColor: 'デフォルト',
4304
4413
  },
4305
4414
  link: {
@@ -4321,6 +4430,10 @@ var ja = {
4321
4430
  zoomOut: '縮小',
4322
4431
  zoomIn: '拡大',
4323
4432
  },
4433
+ file: {
4434
+ download: 'ダウンロード',
4435
+ remove: '削除',
4436
+ },
4324
4437
  codeBlock: {
4325
4438
  langType: 'コード言語を選択',
4326
4439
  },
@@ -4370,6 +4483,7 @@ var ko = {
4370
4483
  fontColor: '글자 색상',
4371
4484
  highlight: '글자 배경',
4372
4485
  image: '이미지',
4486
+ file: '파일',
4373
4487
  removeColor: '기본색',
4374
4488
  },
4375
4489
  link: {
@@ -4391,6 +4505,10 @@ var ko = {
4391
4505
  zoomOut: '축소',
4392
4506
  zoomIn: '확대',
4393
4507
  },
4508
+ file: {
4509
+ download: '다운로드',
4510
+ remove: '삭제',
4511
+ },
4394
4512
  codeBlock: {
4395
4513
  langType: '코드언어 선택',
4396
4514
  },
@@ -4673,14 +4791,14 @@ class Dropdown {
4673
4791
  }
4674
4792
  }
4675
4793
 
4676
- var version = "0.1.8";
4794
+ var version = "0.1.9";
4677
4795
 
4678
4796
  // Inserts a box into the specified range.
4679
4797
  function insertBox(range, boxName, boxValue) {
4680
4798
  if (range.commonAncestor.isOutside) {
4681
4799
  return null;
4682
4800
  }
4683
- const box = new Box(boxName);
4801
+ const box = getBox(boxName);
4684
4802
  if (boxValue) {
4685
4803
  box.value = boxValue;
4686
4804
  }
@@ -4719,7 +4837,7 @@ function removeBox(range) {
4719
4837
  if (boxNode.length === 0) {
4720
4838
  return null;
4721
4839
  }
4722
- const box = new Box(boxNode);
4840
+ const box = getBox(boxNode);
4723
4841
  if (box.type === 'block') {
4724
4842
  const paragraph = query('<p><br /></p>');
4725
4843
  boxNode.before(paragraph);
@@ -4823,20 +4941,20 @@ class Selection {
4823
4941
  return new Range();
4824
4942
  }
4825
4943
  // Adds the saved range to the native selection.
4826
- addRangeToNativeSelection() {
4944
+ sync() {
4827
4945
  this.selection.removeAllRanges();
4828
4946
  this.selection.addRange(this.range.get());
4829
4947
  }
4830
- // Synchronizes the saved range with the range of the native selection.
4831
- syncByRange() {
4948
+ // Updates the saved range with the range of the native selection.
4949
+ updateByRange() {
4832
4950
  const newRange = this.getRangeFromNativeSelection();
4833
4951
  if (this.range.get() === newRange.get()) {
4834
4952
  return;
4835
4953
  }
4836
4954
  this.range = newRange;
4837
4955
  }
4838
- // Synchronizes the saved range with the range represented by the bookmark.
4839
- synByBookmark() {
4956
+ // Updates the saved range with the range represented by the bookmark.
4957
+ updateByBookmark() {
4840
4958
  const range = this.range;
4841
4959
  const container = this.container;
4842
4960
  const boxFocus = container.find('lake-box[focus]');
@@ -4845,7 +4963,7 @@ class Selection {
4845
4963
  anchor: new Nodes(),
4846
4964
  focus: boxFocus,
4847
4965
  });
4848
- this.addRangeToNativeSelection();
4966
+ this.sync();
4849
4967
  return;
4850
4968
  }
4851
4969
  const anchor = container.find('lake-bookmark[type="anchor"]');
@@ -4854,7 +4972,7 @@ class Selection {
4854
4972
  anchor,
4855
4973
  focus,
4856
4974
  });
4857
- this.addRangeToNativeSelection();
4975
+ this.sync();
4858
4976
  }
4859
4977
  getAppliedItems() {
4860
4978
  const appliedItems = [];
@@ -4961,8 +5079,6 @@ class Command {
4961
5079
  }
4962
5080
  }
4963
5081
 
4964
- const boxInstances = new Map();
4965
-
4966
5082
  // Saves and controls the history of the value of the editor.
4967
5083
  // Example:
4968
5084
  // before initialization: value: 'a', list: [], index: 0, canUndo: false
@@ -5040,7 +5156,7 @@ class History {
5040
5156
  const range = this.selection.range;
5041
5157
  const newContainer = this.container.clone(true);
5042
5158
  newContainer.find('lake-box').each(nativeNode => {
5043
- const box = new Box(nativeNode);
5159
+ const box = getBox(nativeNode);
5044
5160
  box.getContainer().empty();
5045
5161
  });
5046
5162
  if (range.commonAncestor.isOutside) {
@@ -5090,7 +5206,7 @@ class History {
5090
5206
  }
5091
5207
  this.index--;
5092
5208
  }
5093
- this.selection.synByBookmark();
5209
+ this.selection.updateByBookmark();
5094
5210
  debug(`History undone, the last index is ${this.index}`);
5095
5211
  }
5096
5212
  redo() {
@@ -5112,7 +5228,7 @@ class History {
5112
5228
  break;
5113
5229
  }
5114
5230
  }
5115
- this.selection.synByBookmark();
5231
+ this.selection.updateByBookmark();
5116
5232
  debug(`History redone, the last index is ${this.index}`);
5117
5233
  }
5118
5234
  continue() {
@@ -5219,17 +5335,17 @@ class BoxManager {
5219
5335
  getNames() {
5220
5336
  return Array.from(boxes.keys());
5221
5337
  }
5222
- getInstances(editor) {
5223
- let instanceMap = boxInstances.get(editor.container.id);
5338
+ getInstances(container) {
5339
+ let instanceMap = boxInstances.get(container.id);
5224
5340
  if (!instanceMap) {
5225
5341
  instanceMap = new Map();
5226
- boxInstances.set(editor.container.id, instanceMap);
5342
+ boxInstances.set(container.id, instanceMap);
5227
5343
  return instanceMap;
5228
5344
  }
5229
5345
  return instanceMap;
5230
5346
  }
5231
- rectifyInstances(editor) {
5232
- const instanceMap = this.getInstances(editor);
5347
+ rectifyInstances(container) {
5348
+ const instanceMap = this.getInstances(container);
5233
5349
  for (const box of instanceMap.values()) {
5234
5350
  if (!box.node.get(0).isConnected) {
5235
5351
  box.unmount();
@@ -5237,20 +5353,16 @@ class BoxManager {
5237
5353
  }
5238
5354
  }
5239
5355
  }
5240
- findAll(editor) {
5241
- return editor.container.find('lake-box');
5242
- }
5243
- renderAll(editor) {
5244
- this.rectifyInstances(editor);
5245
- const instanceMap = this.getInstances(editor);
5246
- this.findAll(editor).each(boxNativeNode => {
5247
- const boxNode = new Nodes(boxNativeNode);
5356
+ renderAll(container) {
5357
+ this.rectifyInstances(container);
5358
+ const instanceMap = this.getInstances(container);
5359
+ container.find('lake-box').each(boxNativeNode => {
5360
+ const boxNode = query(boxNativeNode);
5248
5361
  if (instanceMap.get(boxNode.id)) {
5249
5362
  return;
5250
5363
  }
5251
- const box = new Box(boxNode);
5364
+ const box = getBox(boxNode);
5252
5365
  box.render();
5253
- instanceMap.set(box.node.id, box);
5254
5366
  });
5255
5367
  }
5256
5368
  }
@@ -5278,6 +5390,22 @@ const defaultConfig = {
5278
5390
  indentWithTab: true,
5279
5391
  lang: 'en-US',
5280
5392
  minChangeSize: 5,
5393
+ onMessage: (type, message) => {
5394
+ if (type === 'success') {
5395
+ // eslint-disable-next-line no-console
5396
+ console.log(message);
5397
+ return;
5398
+ }
5399
+ if (type === 'warning') {
5400
+ // eslint-disable-next-line no-console
5401
+ console.warn(message);
5402
+ return;
5403
+ }
5404
+ if (type === 'error') {
5405
+ // eslint-disable-next-line no-console
5406
+ console.error(message);
5407
+ }
5408
+ },
5281
5409
  };
5282
5410
  class Editor {
5283
5411
  constructor(config) {
@@ -5316,13 +5444,13 @@ class Editor {
5316
5444
  this.history.save();
5317
5445
  };
5318
5446
  this.selectionchangeListener = () => {
5319
- this.selection.syncByRange();
5447
+ this.selection.updateByRange();
5320
5448
  this.updateBoxSelectionStyle();
5321
5449
  this.emitStateChangeEvent();
5322
5450
  };
5323
5451
  this.clickListener = event => {
5324
5452
  const targetNode = new Nodes(event.target);
5325
- if (targetNode.closest('.lake-popup').length > 0) {
5453
+ if (!targetNode.get(0).isConnected || targetNode.closest('.lake-popup').length > 0) {
5326
5454
  return;
5327
5455
  }
5328
5456
  this.event.emit('click', targetNode);
@@ -5338,8 +5466,8 @@ class Editor {
5338
5466
  const range = this.selection.range;
5339
5467
  const clonedRange = range.clone();
5340
5468
  clonedRange.adaptBox();
5341
- this.box.findAll(this).each(boxNode => {
5342
- const box = new Box(boxNode);
5469
+ this.container.find('lake-box').each(boxNativeNode => {
5470
+ const box = getBox(boxNativeNode);
5343
5471
  const boxContainer = box.getContainer();
5344
5472
  if (boxContainer.length === 0) {
5345
5473
  return;
@@ -5350,6 +5478,7 @@ class Editor {
5350
5478
  boxContainer.removeClass('lake-box-selected');
5351
5479
  boxContainer.removeClass('lake-box-focused');
5352
5480
  boxContainer.addClass('lake-box-activated');
5481
+ box.event.emit('focus');
5353
5482
  return;
5354
5483
  }
5355
5484
  }
@@ -5359,16 +5488,19 @@ class Editor {
5359
5488
  boxContainer.removeClass('lake-box-hovered');
5360
5489
  boxContainer.removeClass('lake-box-selected');
5361
5490
  boxContainer.addClass('lake-box-focused');
5491
+ box.event.emit('focus');
5362
5492
  }
5363
5493
  else {
5364
5494
  boxContainer.removeClass('lake-box-focused');
5365
5495
  boxContainer.addClass('lake-box-selected');
5496
+ box.event.emit('blur');
5366
5497
  }
5367
5498
  return;
5368
5499
  }
5369
5500
  boxContainer.removeClass('lake-box-activated');
5370
5501
  boxContainer.removeClass('lake-box-focused');
5371
5502
  boxContainer.removeClass('lake-box-selected');
5503
+ box.event.emit('blur');
5372
5504
  });
5373
5505
  this.event.emit('boxselectionstylechange');
5374
5506
  }, 50, {
@@ -5473,7 +5605,7 @@ class Editor {
5473
5605
  const range = selection.range;
5474
5606
  const stripNode = range.startNode.closest('.lake-box-strip');
5475
5607
  const boxNode = stripNode.closest('lake-box');
5476
- const box = new Box(boxNode);
5608
+ const box = getBox(boxNode);
5477
5609
  if (box.type === 'inline') {
5478
5610
  if (range.isBoxStart) {
5479
5611
  range.setStartBefore(boxNode);
@@ -5555,15 +5687,15 @@ class Editor {
5555
5687
  }
5556
5688
  bindHistoryEvents() {
5557
5689
  this.history.event.on('undo', value => {
5558
- this.box.renderAll(this);
5690
+ this.box.renderAll(this.container);
5559
5691
  this.emitChangeEvent(value);
5560
5692
  });
5561
5693
  this.history.event.on('redo', value => {
5562
- this.box.renderAll(this);
5694
+ this.box.renderAll(this.container);
5563
5695
  this.emitChangeEvent(value);
5564
5696
  });
5565
5697
  this.history.event.on('save', value => {
5566
- this.box.rectifyInstances(this);
5698
+ this.box.rectifyInstances(this.container);
5567
5699
  this.emitChangeEvent(value);
5568
5700
  });
5569
5701
  }
@@ -5710,8 +5842,8 @@ class Editor {
5710
5842
  this.container.empty();
5711
5843
  this.togglePlaceholderClass(htmlParser.getHTML());
5712
5844
  this.container.append(fragment);
5713
- Editor.box.renderAll(this);
5714
- this.selection.synByBookmark();
5845
+ Editor.box.renderAll(this.container);
5846
+ this.selection.updateByBookmark();
5715
5847
  }
5716
5848
  // Returns the contents from the editor.
5717
5849
  getValue() {
@@ -5721,21 +5853,35 @@ class Editor {
5721
5853
  this.selection.toBookmark(bookmark);
5722
5854
  return value;
5723
5855
  }
5856
+ // Sets the current range to the center position of the box.
5857
+ selectBox(box) {
5858
+ let boxNode = box;
5859
+ if (box instanceof Box) {
5860
+ boxNode = box.node;
5861
+ }
5862
+ else {
5863
+ boxNode = box;
5864
+ }
5865
+ this.selection.range.selectBox(boxNode);
5866
+ }
5724
5867
  // Inserts a box into the position of the selection.
5725
5868
  insertBox(boxName, boxValue) {
5726
5869
  const box = insertBox(this.selection.range, boxName, boxValue);
5727
5870
  if (!box) {
5728
5871
  throw new Error(`Box '${boxName}' cannot be inserted outside the editor.`);
5729
5872
  }
5730
- const instanceMap = this.box.getInstances(this);
5873
+ const instanceMap = this.box.getInstances(this.container);
5731
5874
  instanceMap.set(box.node.id, box);
5732
5875
  return box;
5733
5876
  }
5734
5877
  // Removes the selected box.
5735
- removeBox() {
5736
- const box = removeBox(this.selection.range);
5878
+ removeBox(box = null) {
5879
+ if (box) {
5880
+ this.selectBox(box);
5881
+ }
5882
+ box = removeBox(this.selection.range);
5737
5883
  if (box) {
5738
- const instanceMap = this.box.getInstances(this);
5884
+ const instanceMap = this.box.getInstances(this.container);
5739
5885
  instanceMap.delete(box.node.id);
5740
5886
  }
5741
5887
  return box;
@@ -5754,10 +5900,10 @@ class Editor {
5754
5900
  this.container.append(fragment);
5755
5901
  Editor.plugin.loadAll(this);
5756
5902
  if (!this.readonly) {
5757
- this.selection.synByBookmark();
5903
+ this.selection.updateByBookmark();
5758
5904
  this.history.save();
5759
5905
  }
5760
- Editor.box.renderAll(this);
5906
+ Editor.box.renderAll(this.container);
5761
5907
  if (this.toolbar) {
5762
5908
  this.toolbar.render(this);
5763
5909
  }
@@ -6414,15 +6560,26 @@ const toolbarItems = [
6414
6560
  accept: 'image/*',
6415
6561
  multiple: true,
6416
6562
  },
6563
+ {
6564
+ name: 'file',
6565
+ type: 'upload',
6566
+ icon: icons.get('attachment'),
6567
+ tooltip: locale => locale.toolbar.file(),
6568
+ accept: '*',
6569
+ multiple: true,
6570
+ },
6417
6571
  ];
6418
6572
 
6419
- function uploadImage(config) {
6420
- const { editor, file, onError, onSuccess } = config;
6421
- const { requestMethod, requestAction, requestTypes } = editor.config.image;
6573
+ function uploadFile(config) {
6574
+ const { editor, name, file, onError, onSuccess } = config;
6575
+ const { requestMethod, requestAction, requestTypes } = editor.config[name];
6422
6576
  if (requestTypes.indexOf(file.type) < 0) {
6423
- throw new Error(`Cannot upload file because its type '${file.type}' is not found in ['${requestTypes.join('\', \'')}'].`);
6577
+ if (onError) {
6578
+ onError(`File '${file.name}' is not allowed for uploading.`);
6579
+ }
6580
+ throw new Error(`Cannot upload file '${file.name}' because its type '${file.type}' is not found in ['${requestTypes.join('\', \'')}'].`);
6424
6581
  }
6425
- const box = editor.insertBox('image', {
6582
+ const box = editor.insertBox(name, {
6426
6583
  url: URL.createObjectURL(file),
6427
6584
  status: 'uploading',
6428
6585
  name: file.name,
@@ -6441,7 +6598,7 @@ function uploadImage(config) {
6441
6598
  box.updateValue('status', 'error');
6442
6599
  box.render();
6443
6600
  if (onError) {
6444
- onError();
6601
+ onError(error.toString());
6445
6602
  }
6446
6603
  },
6447
6604
  onSuccess: body => {
@@ -6449,7 +6606,7 @@ function uploadImage(config) {
6449
6606
  box.updateValue('status', 'error');
6450
6607
  box.render();
6451
6608
  if (onError) {
6452
- onError();
6609
+ onError('Cannot find the url field.');
6453
6610
  }
6454
6611
  return;
6455
6612
  }
@@ -6492,9 +6649,9 @@ const defaultItems = [
6492
6649
  'blockQuote',
6493
6650
  'hr',
6494
6651
  ];
6495
- const toolbarItemMap = new Map();
6652
+ const toolbarItemMap$1 = new Map();
6496
6653
  toolbarItems.forEach(item => {
6497
- toolbarItemMap.set(item.name, item);
6654
+ toolbarItemMap$1.set(item.name, item);
6498
6655
  });
6499
6656
  class Toolbar {
6500
6657
  constructor(config) {
@@ -6581,9 +6738,11 @@ class Toolbar {
6581
6738
  const target = event.target;
6582
6739
  const files = target.files || [];
6583
6740
  for (const file of files) {
6584
- uploadImage({
6741
+ uploadFile({
6585
6742
  editor,
6743
+ name: item.name,
6586
6744
  file,
6745
+ onError: error => editor.config.onMessage('error', error),
6587
6746
  });
6588
6747
  }
6589
6748
  });
@@ -6658,7 +6817,7 @@ class Toolbar {
6658
6817
  }
6659
6818
  let item;
6660
6819
  if (typeof name === 'string') {
6661
- item = toolbarItemMap.get(name);
6820
+ item = toolbarItemMap$1.get(name);
6662
6821
  if (!item) {
6663
6822
  return;
6664
6823
  }
@@ -6695,7 +6854,7 @@ const hrBox = {
6695
6854
  box.useEffect(() => {
6696
6855
  const hrNode = box.getContainer().find('.lake-hr');
6697
6856
  hrNode.on('click', () => {
6698
- editor.selection.range.selectBox(box.node);
6857
+ editor.selectBox(box);
6699
6858
  });
6700
6859
  });
6701
6860
  return '<div class="lake-hr"><hr /></div>';
@@ -6839,7 +6998,7 @@ function openFullScreen(box) {
6839
6998
  let currentIndex = 0;
6840
6999
  const allImageBox = editor.container.find('lake-box[name="image"]');
6841
7000
  allImageBox.each((node, index) => {
6842
- const imageBox = new Box(node);
7001
+ const imageBox = getBox(node);
6843
7002
  const imageValue = imageBox.value;
6844
7003
  if (imageValue.status !== 'done') {
6845
7004
  return;
@@ -6922,7 +7081,7 @@ function openFullScreen(box) {
6922
7081
  if (savedRange) {
6923
7082
  // fix(image): lose focus when zooming in the iOS
6924
7083
  editor.selection.range = savedRange;
6925
- editor.selection.addRangeToNativeSelection();
7084
+ editor.selection.sync();
6926
7085
  }
6927
7086
  box.event.emit('closefullscreen');
6928
7087
  }, 0);
@@ -6930,20 +7089,6 @@ function openFullScreen(box) {
6930
7089
  lightbox.init();
6931
7090
  lightbox.loadAndOpen(currentIndex);
6932
7091
  }
6933
- // Removes current box.
6934
- function removeImageBox(box) {
6935
- const editor = box.getEditor();
6936
- if (!editor) {
6937
- return;
6938
- }
6939
- const xhr = box.getData('xhr');
6940
- if (xhr) {
6941
- xhr.abort();
6942
- }
6943
- editor.selection.range.selectBox(box.node);
6944
- editor.removeBox();
6945
- editor.history.save();
6946
- }
6947
7092
  // Displays error icon and filename.
6948
7093
  function renderError(imageNode, box) {
6949
7094
  return __awaiter(this, void 0, void 0, function* () {
@@ -7167,13 +7312,19 @@ const imageBox = {
7167
7312
  else {
7168
7313
  imageNode.find('.lake-button-remove').on('click', event => {
7169
7314
  event.stopPropagation();
7170
- removeImageBox(box);
7315
+ const xhr = box.getData('xhr');
7316
+ if (xhr) {
7317
+ xhr.abort();
7318
+ }
7319
+ editor.removeBox(box);
7320
+ editor.history.save();
7321
+ editor.selection.sync();
7171
7322
  });
7172
7323
  }
7173
7324
  box.event.emit('render');
7174
7325
  });
7175
7326
  imageNode.on('click', () => {
7176
- editor.selection.range.selectBox(box.node);
7327
+ editor.selectBox(box);
7177
7328
  });
7178
7329
  },
7179
7330
  html: box => {
@@ -7182,6 +7333,232 @@ const imageBox = {
7182
7333
  },
7183
7334
  };
7184
7335
 
7336
+ const toolbarItemMap = new Map();
7337
+ class BoxToolbar {
7338
+ constructor(config) {
7339
+ this.placement = 'top';
7340
+ this.buttonItemList = [];
7341
+ this.dropdownItemList = [];
7342
+ this.root = query(config.root);
7343
+ this.editor = config.editor;
7344
+ this.box = config.box;
7345
+ this.items = config.items;
7346
+ if (config.placement) {
7347
+ this.placement = config.placement;
7348
+ }
7349
+ this.container = query('<div class="lake-box-toolbar" />');
7350
+ this.root.addClass('lake-custom-properties');
7351
+ }
7352
+ appendDivider() {
7353
+ this.container.append('<div class="lake-box-toolbar-divider" />');
7354
+ }
7355
+ appendButton(item) {
7356
+ const button = new Button({
7357
+ root: this.container,
7358
+ name: item.name,
7359
+ icon: item.icon,
7360
+ tooltip: typeof item.tooltip === 'string' ? item.tooltip : item.tooltip(this.editor.locale),
7361
+ tabIndex: -1,
7362
+ onClick: () => {
7363
+ item.onClick(this.box, item.name);
7364
+ },
7365
+ });
7366
+ button.render();
7367
+ }
7368
+ appendDropdown(item) {
7369
+ const dropdown = new Dropdown({
7370
+ root: this.container,
7371
+ locale: this.editor.locale,
7372
+ name: item.name,
7373
+ icon: item.icon,
7374
+ accentIcon: item.accentIcon,
7375
+ downIcon: item.downIcon,
7376
+ defaultValue: item.defaultValue,
7377
+ tooltip: item.tooltip,
7378
+ width: item.width,
7379
+ menuType: item.menuType,
7380
+ menuItems: item.menuItems,
7381
+ tabIndex: -1,
7382
+ placement: this.placement === 'top' ? 'bottom' : 'top',
7383
+ onSelect: value => {
7384
+ item.onSelect(this.box, value);
7385
+ },
7386
+ });
7387
+ dropdown.render();
7388
+ }
7389
+ updatePosition() {
7390
+ const boxNode = this.box.node;
7391
+ const position = nodeAndView(boxNode);
7392
+ if (position.left < 0 || position.right < 0 || position.top < 0 || position.bottom < 0) {
7393
+ this.container.hide();
7394
+ return;
7395
+ }
7396
+ this.container.show('flex');
7397
+ const boxNativeNode = this.box.node.get(0);
7398
+ const boxRect = boxNativeNode.getBoundingClientRect();
7399
+ const boxX = boxRect.x + window.scrollX;
7400
+ const boxY = boxRect.y + window.scrollY;
7401
+ const left = (boxX + boxRect.width / 2 - this.container.width() / 2).toFixed(1);
7402
+ const top = (boxY - this.container.height() - 6).toFixed(1);
7403
+ this.container.css({
7404
+ left: `${left}px`,
7405
+ top: `${top}px`,
7406
+ });
7407
+ }
7408
+ // Renders a toolbar for the specified box.
7409
+ render() {
7410
+ this.root.empty();
7411
+ this.root.append(this.container);
7412
+ this.items.forEach(name => {
7413
+ if (name === '|') {
7414
+ this.appendDivider();
7415
+ return;
7416
+ }
7417
+ let item;
7418
+ if (typeof name === 'string') {
7419
+ item = toolbarItemMap.get(name);
7420
+ if (!item) {
7421
+ return;
7422
+ }
7423
+ }
7424
+ else {
7425
+ item = name;
7426
+ }
7427
+ if (item.type === 'button') {
7428
+ this.buttonItemList.push(item);
7429
+ this.appendButton(item);
7430
+ return;
7431
+ }
7432
+ if (item.type === 'dropdown') {
7433
+ this.dropdownItemList.push(item);
7434
+ this.appendDropdown(item);
7435
+ }
7436
+ });
7437
+ this.updatePosition();
7438
+ }
7439
+ unmount() {
7440
+ this.container.remove();
7441
+ }
7442
+ }
7443
+
7444
+ const boxToolbarItems = [
7445
+ {
7446
+ name: 'download',
7447
+ type: 'button',
7448
+ icon: icons.get('download'),
7449
+ tooltip: locale => locale.file.download(),
7450
+ onClick: box => {
7451
+ window.open(box.value.url);
7452
+ },
7453
+ },
7454
+ {
7455
+ name: 'remove',
7456
+ type: 'button',
7457
+ icon: icons.get('remove'),
7458
+ tooltip: locale => locale.file.remove(),
7459
+ onClick: box => {
7460
+ const editor = box.getEditor();
7461
+ if (!editor) {
7462
+ return;
7463
+ }
7464
+ editor.removeBox(box);
7465
+ editor.history.save();
7466
+ editor.selection.sync();
7467
+ },
7468
+ },
7469
+ ];
7470
+ function appendContent(fileNode, box) {
7471
+ return __awaiter(this, void 0, void 0, function* () {
7472
+ const editor = box.getEditor();
7473
+ if (!editor) {
7474
+ return;
7475
+ }
7476
+ const value = box.value;
7477
+ const infoNode = query(safeTemplate `
7478
+ <div class="lake-file-info">
7479
+ <div class="lake-file-type"></div>
7480
+ <div class="lake-file-name">${value.name} (${fileSize(value.size)})</div>
7481
+ </div>
7482
+ `);
7483
+ const typeNode = infoNode.find('.lake-file-type');
7484
+ if (value.status === 'uploading') {
7485
+ const percent = Math.round(value.percent || 0);
7486
+ const progressNode = query(safeTemplate `
7487
+ <div class="lake-progress">
7488
+ <div class="lake-percent">${percent} %</div>
7489
+ </div>
7490
+ `);
7491
+ const circleNotchIcon = icons.get('circleNotch');
7492
+ if (circleNotchIcon) {
7493
+ progressNode.prepend(circleNotchIcon);
7494
+ }
7495
+ typeNode.replaceWith(progressNode);
7496
+ }
7497
+ else {
7498
+ const fileIcon = value.status === 'error' ? icons.get('warningCircle') : icons.get('file');
7499
+ if (fileIcon) {
7500
+ typeNode.append(fileIcon);
7501
+ }
7502
+ }
7503
+ fileNode.append(infoNode);
7504
+ });
7505
+ }
7506
+ const fileBox = {
7507
+ type: 'inline',
7508
+ name: 'file',
7509
+ render: box => {
7510
+ const editor = box.getEditor();
7511
+ if (!editor) {
7512
+ return;
7513
+ }
7514
+ const value = box.value;
7515
+ const container = box.getContainer();
7516
+ const fileNode = query('<div class="lake-file" />');
7517
+ fileNode.addClass(`lake-file-${value.status}`);
7518
+ if (editor.readonly) {
7519
+ fileNode.addClass('lake-file-readonly');
7520
+ }
7521
+ appendContent(fileNode, box);
7522
+ container.empty();
7523
+ container.append(fileNode);
7524
+ if (!editor.readonly) {
7525
+ fileNode.on('click', () => {
7526
+ editor.selectBox(box);
7527
+ });
7528
+ let toolbar = null;
7529
+ const scrollListener = () => {
7530
+ if (toolbar) {
7531
+ toolbar.updatePosition();
7532
+ }
7533
+ };
7534
+ box.event.on('focus', () => {
7535
+ const items = value.status === 'done' ? boxToolbarItems : boxToolbarItems.filter(item => item.name === 'remove');
7536
+ toolbar = new BoxToolbar({
7537
+ root: editor.popupContainer,
7538
+ editor,
7539
+ box,
7540
+ items,
7541
+ });
7542
+ toolbar.render();
7543
+ editor.root.on('scroll', scrollListener);
7544
+ });
7545
+ box.event.on('blur', () => {
7546
+ if (toolbar) {
7547
+ toolbar.unmount();
7548
+ toolbar = null;
7549
+ }
7550
+ editor.root.off('scroll', scrollListener);
7551
+ });
7552
+ }
7553
+ else {
7554
+ fileNode.on('click', () => {
7555
+ window.open(value.url);
7556
+ });
7557
+ }
7558
+ box.event.emit('render');
7559
+ },
7560
+ };
7561
+
7185
7562
  const config = {
7186
7563
  comment: '#57606a',
7187
7564
  name: '#444d56',
@@ -7286,7 +7663,7 @@ const codeBlockBox = {
7286
7663
  Please check if the "lake-codemirror" library is added to this page.
7287
7664
  `.trim());
7288
7665
  codeBlockNode.on('click', () => {
7289
- editor.selection.range.selectBox(box.node);
7666
+ editor.selectBox(box);
7290
7667
  });
7291
7668
  return;
7292
7669
  }
@@ -7391,7 +7768,7 @@ var copy = (editor) => {
7391
7768
  if (!dataTransfer) {
7392
7769
  return;
7393
7770
  }
7394
- const box = new Box(boxNode);
7771
+ const box = getBox(boxNode);
7395
7772
  const content = box.getHTML();
7396
7773
  dataTransfer.setData('text/html', content);
7397
7774
  });
@@ -7418,7 +7795,7 @@ var cut = (editor) => {
7418
7795
  if (!dataTransfer) {
7419
7796
  return;
7420
7797
  }
7421
- const box = new Box(boxNode);
7798
+ const box = getBox(boxNode);
7422
7799
  const content = box.getHTML();
7423
7800
  dataTransfer.setData('text/html', content);
7424
7801
  editor.removeBox();
@@ -7484,7 +7861,7 @@ function insertFirstNode(editor, otherNode) {
7484
7861
  const range = editor.selection.range;
7485
7862
  const boxNode = range.startNode.closest('lake-box');
7486
7863
  if (boxNode.length > 0) {
7487
- const box = new Box(boxNode);
7864
+ const box = getBox(boxNode);
7488
7865
  if (box.type === 'inline') {
7489
7866
  if (range.isBoxStart) {
7490
7867
  range.setStartBefore(boxNode);
@@ -7515,7 +7892,7 @@ function insertFirstNode(editor, otherNode) {
7515
7892
  }
7516
7893
  const block = range.startNode.closestBlock();
7517
7894
  if (otherNode.isBlockBox) {
7518
- const box = new Box(otherNode);
7895
+ const box = getBox(otherNode);
7519
7896
  const value = otherNode.attr('value') !== '' ? box.value : undefined;
7520
7897
  editor.insertBox(box.name, value);
7521
7898
  otherNode.remove();
@@ -7527,7 +7904,7 @@ function insertFirstNode(editor, otherNode) {
7527
7904
  if (block.isEmpty && block.name === 'p') {
7528
7905
  block.replaceWith(otherNode);
7529
7906
  otherNode.find('lake-box').each(node => {
7530
- new Box(node).render();
7907
+ getBox(node).render();
7531
7908
  });
7532
7909
  range.shrinkAfter(otherNode);
7533
7910
  return;
@@ -7601,9 +7978,11 @@ var paste = (editor) => {
7601
7978
  if (dataTransfer.files.length > 0) {
7602
7979
  for (const file of dataTransfer.files) {
7603
7980
  if (requestTypes.indexOf(file.type) >= 0) {
7604
- uploadImage({
7981
+ uploadFile({
7605
7982
  editor,
7983
+ name: file.type.indexOf('image/') === 0 ? 'image' : 'file',
7606
7984
  file,
7985
+ onError: error => editor.config.onMessage('error', error),
7607
7986
  });
7608
7987
  }
7609
7988
  }
@@ -7626,7 +8005,7 @@ var paste = (editor) => {
7626
8005
  editor.event.emit('beforepaste', fragment);
7627
8006
  fixClipboardData(fragment);
7628
8007
  pasteFragment(editor, fragment);
7629
- editor.box.renderAll(editor);
8008
+ editor.box.renderAll(editor.container);
7630
8009
  });
7631
8010
  };
7632
8011
 
@@ -7654,7 +8033,7 @@ var drop = (editor) => {
7654
8033
  dragEvent.preventDefault();
7655
8034
  return;
7656
8035
  }
7657
- const box = new Box(boxNode);
8036
+ const box = getBox(boxNode);
7658
8037
  if (box.type === 'inline') {
7659
8038
  dragEvent.preventDefault();
7660
8039
  return;
@@ -7752,7 +8131,7 @@ var drop = (editor) => {
7752
8131
  return;
7753
8132
  }
7754
8133
  dragEvent.preventDefault();
7755
- const draggedBox = new Box(draggedNode);
8134
+ const draggedBox = getBox(draggedNode);
7756
8135
  const range = editor.selection.range;
7757
8136
  if (targetBlock.isBox) {
7758
8137
  if (dropPosition === 'top') {
@@ -8494,15 +8873,17 @@ class LinkPopup {
8494
8873
  if (!this.linkNode) {
8495
8874
  return;
8496
8875
  }
8876
+ const position = nodeAndView(this.linkNode);
8877
+ if (position.left < 0 || position.right < 0 || position.top < 0 || position.bottom < 0) {
8878
+ this.container.css('visibility', 'hidden');
8879
+ return;
8880
+ }
8881
+ this.container.css('visibility', '');
8497
8882
  const linkNativeNode = this.linkNode.get(0);
8498
8883
  // Returns a DOMRect object providing information about the size of an element and its position relative to the viewport.
8499
8884
  const linkRect = linkNativeNode.getBoundingClientRect();
8500
8885
  const linkX = linkRect.x + window.scrollX;
8501
8886
  const linkY = linkRect.y + window.scrollY;
8502
- if (linkX < 0 || linkY < 0) {
8503
- this.hide();
8504
- return;
8505
- }
8506
8887
  // link.x + popup.width > window.width
8507
8888
  if (linkRect.x + this.container.width() > window.innerWidth) {
8508
8889
  // link.x + window.scrollX - (popup.width - link.width)
@@ -8564,14 +8945,14 @@ var link = (editor) => {
8564
8945
  const range = editor.selection.range;
8565
8946
  range.setStartAfter(node);
8566
8947
  range.collapseToStart();
8567
- editor.selection.addRangeToNativeSelection();
8948
+ editor.selection.sync();
8568
8949
  editor.history.save();
8569
8950
  },
8570
8951
  onRemove: node => {
8571
8952
  const range = editor.selection.range;
8572
8953
  range.setStartAfter(node);
8573
8954
  range.collapseToStart();
8574
- editor.selection.addRangeToNativeSelection();
8955
+ editor.selection.sync();
8575
8956
  editor.history.save();
8576
8957
  },
8577
8958
  });
@@ -8618,7 +8999,7 @@ var hr = (editor) => {
8618
8999
  const fragment = new Fragment(nativeFragment);
8619
9000
  fragment.find('hr').each(nativeNode => {
8620
9001
  const node = query(nativeNode);
8621
- const box = new Box('hr');
9002
+ const box = getBox('hr');
8622
9003
  node.replaceWith(box.node);
8623
9004
  });
8624
9005
  });
@@ -8642,7 +9023,7 @@ var image = (editor) => {
8642
9023
  const fragment = new Fragment(nativeFragment);
8643
9024
  fragment.find('img').each(nativeNode => {
8644
9025
  const node = query(nativeNode);
8645
- const box = new Box('image');
9026
+ const box = getBox('image');
8646
9027
  const value = node.attr('data-lake-value');
8647
9028
  if (value === '') {
8648
9029
  box.value = {
@@ -8664,6 +9045,39 @@ var image = (editor) => {
8664
9045
  });
8665
9046
  };
8666
9047
 
9048
+ var file = (editor) => {
9049
+ editor.setPluginConfig('file', {
9050
+ requestMethod: 'POST',
9051
+ requestTypes: [
9052
+ 'application/zip',
9053
+ 'application/x-zip-compressed',
9054
+ 'application/vnd.rar',
9055
+ 'image/gif',
9056
+ 'image/jpeg',
9057
+ 'image/png',
9058
+ 'image/svg+xml',
9059
+ 'text/plain',
9060
+ 'text/html',
9061
+ 'application/pdf',
9062
+ 'application/msword',
9063
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
9064
+ 'application/vnd.ms-excel',
9065
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
9066
+ 'application/vnd.ms-powerpoint',
9067
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
9068
+ ],
9069
+ });
9070
+ if (editor.readonly) {
9071
+ return;
9072
+ }
9073
+ editor.command.add('file', {
9074
+ execute: (value) => {
9075
+ editor.insertBox('file', value);
9076
+ editor.history.save();
9077
+ },
9078
+ });
9079
+ };
9080
+
8667
9081
  const langList = [
8668
9082
  'text',
8669
9083
  'c',
@@ -9288,8 +9702,7 @@ var backspaceKey = (editor) => {
9288
9702
  const prevNode = range.getPrevNode();
9289
9703
  if (prevNode.isBox) {
9290
9704
  event.preventDefault();
9291
- range.selectBox(prevNode);
9292
- editor.removeBox();
9705
+ editor.removeBox(prevNode);
9293
9706
  editor.history.save();
9294
9707
  return;
9295
9708
  }
@@ -9408,8 +9821,7 @@ var deleteKey = (editor) => {
9408
9821
  const nextNode = range.getNextNode();
9409
9822
  if (nextNode.isBox) {
9410
9823
  event.preventDefault();
9411
- range.selectBox(nextNode);
9412
- editor.removeBox();
9824
+ editor.removeBox(nextNode);
9413
9825
  editor.history.save();
9414
9826
  return;
9415
9827
  }
@@ -9590,7 +10002,7 @@ var escapeKey = (editor) => {
9590
10002
  event.preventDefault();
9591
10003
  const boxNode = range.commonAncestor.closest('lake-box');
9592
10004
  range.selectBoxEnd(boxNode);
9593
- selection.addRangeToNativeSelection();
10005
+ selection.sync();
9594
10006
  return;
9595
10007
  }
9596
10008
  if (editor.hasFocus) {
@@ -9602,6 +10014,7 @@ var escapeKey = (editor) => {
9602
10014
 
9603
10015
  Editor.box.add(hrBox);
9604
10016
  Editor.box.add(imageBox);
10017
+ Editor.box.add(fileBox);
9605
10018
  Editor.box.add(codeBlockBox);
9606
10019
  Editor.plugin.add(copy);
9607
10020
  Editor.plugin.add(cut);
@@ -9631,6 +10044,7 @@ Editor.plugin.add(formatPainter);
9631
10044
  Editor.plugin.add(link);
9632
10045
  Editor.plugin.add(hr);
9633
10046
  Editor.plugin.add(image);
10047
+ Editor.plugin.add(file);
9634
10048
  Editor.plugin.add(codeBlock);
9635
10049
  Editor.plugin.add(markdown);
9636
10050
  Editor.plugin.add(enterKey);