├── .eslintrc ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── assets └── screenshot.png ├── dist ├── gallery.mjs └── gallery.umd.js ├── package.json ├── postcss.config.js ├── src ├── index.js ├── index.pcss ├── svg │ ├── fit.svg │ ├── slider.svg │ └── toolbox.svg ├── tunes.js ├── ui.js └── uploader.js ├── vite.config.js └── yarn.lock /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "codex" 4 | ], 5 | "globals": { 6 | "fetch": true, 7 | "ImageConfig": true, 8 | "ImageToolData": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | npm-debug.log 3 | .idea/ 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | dev/ 3 | src/ 4 | .babelrc 5 | .eslintrc 6 | vite.config.js 7 | postcss.config.js 8 | yarn.lock 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 СodeX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://badgen.net/badge/Editor.js/v2.0/blue) 2 | 3 | # Gallery block for Editor.js 4 | 5 | Loader based on [editor-js/image](https://github.com/editor-js/image). 6 | 7 | ### Preview 8 | ![Preview image](https://raw.githubusercontent.com/VolgaIgor/editorjs-gallery/master/assets/screenshot.png) 9 | 10 | ### Features 11 | * Multiple downloads 12 | * Sorting uploaded images (providing by [SortableJS](https://github.com/SortableJS/Sortable)) 13 | * Limit the number of images 14 | * Two view selector (slider and fit) 15 | 16 | ## Installation 17 | ### Install via NPM 18 | Get the package 19 | 20 | ```shell 21 | $ npm i @kiberpro/editorjs-gallery 22 | ``` 23 | 24 | Include module at your application 25 | 26 | ```javascript 27 | import ImageGallery from '@kiberpro/editorjs-gallery'; 28 | ``` 29 | 30 | ### Load from CDN 31 | 32 | You can load a specific version of the package from jsDelivr CDN. 33 | 34 | Require this script on a page with Editor.js. 35 | 36 | ```html 37 | 38 | ``` 39 | 40 | ### Download to your project's source dir 41 | 42 | 1. Upload folder `dist` from repository 43 | 2. Add `dist/gallery.umd.js` file to your page. 44 | 45 | ### Enable sorting 46 | To enable sorting, include the SortableJS library and send it to the configuration: 47 | ```shell 48 | $ npm i sortablejs 49 | ``` 50 | ```javascript 51 | import Sortable from 'sortablejs'; 52 | ``` 53 | 54 | ## Usage 55 | ```javascript 56 | var editor = EditorJS({ 57 | // ... 58 | tools: { 59 | // ... 60 | gallery: { 61 | class: ImageGallery, 62 | config: { 63 | sortableJs: Sortable, 64 | endpoints: { 65 | byFile: 'http://localhost:8008/uploadFile', 66 | } 67 | }, 68 | }, 69 | } 70 | // ... 71 | }); 72 | ``` 73 | 74 | ## Config Params 75 | 76 | Gallery block supports these configuration parameters: 77 | 78 | | Field | Type | Description | 79 | | ----- | -------- | ------------------ | 80 | | sortableJs | `object` | SortableJS library | 81 | | maxElementCount | `int` | (default: `undefined`) Maximum allowed number of images | 82 | | buttonContent | `string` | (default: `Select an Image`) Label for upload button | 83 | | uploader | `{{uploadByFile: function}}` | Optional custom uploading method. [See details](https://github.com/editor-js/image#providing-custom-uploading-methods). | 84 | | actions | `[{name: string, icon: string, title: string}]` | Array with custom switches | 85 | | [And others from the original ](https://github.com/editor-js/image#config-params) | 86 | 87 | Also you can add a localized string: 88 | ```javascript 89 | new Editorjs({ 90 | // ... 91 | tools: { 92 | gallery: ImageGallery 93 | }, 94 | i18n: { 95 | tools: { 96 | gallery: { 97 | 'Select an Image': 'Выберите изображение', 98 | 'Delete': 'Удалить', 99 | 'Gallery caption': 'Подпись' 100 | } 101 | } 102 | }, 103 | }) 104 | ``` 105 | 106 | ## Output data 107 | 108 | This Tool returns `data` with following format 109 | 110 | | Field | Type | Description | 111 | | -------------- | --------- | -------------------------------- | 112 | | files | `object[]` | Uploaded file datas. Any data got from backend uploader. Always contain the `url` property | 113 | | source | `string` | image's source | 114 | | style | `string` | (`fit` of `slider`) gallery view | 115 | -------------------------------------------------------------------------------- /assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VolgaIgor/editorjs-gallery/7050929faebe4e6acfcf57ae575e770e6170053d/assets/screenshot.png -------------------------------------------------------------------------------- /dist/gallery.mjs: -------------------------------------------------------------------------------- 1 | (function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode('.image-gallery{--bg-color: #cdd1e0;--front-color: #388ae5;--border-color: #e8e8eb}.image-gallery__container{background:black;margin-bottom:10px;padding:5px}.image-gallery__controls{display:flex;gap:10px;padding:8px 2px 3px}.image-gallery__items{display:grid;gap:10px;grid-template-columns:1fr 1fr 1fr;padding:10px;background-color:#222}.image-gallery__items:empty{display:none}.image-gallery__preloaders{display:flex;flex-grow:1;flex-wrap:nowrap;padding:5px;gap:8px;overflow:hidden}.image-gallery__preloader{min-width:30px;height:30px;border-radius:50%;background-size:cover;position:relative;background-color:var(--bg-color);background-position:center center}.image-gallery__preloader:after{content:"";position:absolute;z-index:3;width:30px;height:30px;border-radius:50%;border:2px solid var(--bg-color);border-top-color:var(--front-color);left:50%;top:50%;margin-top:-15px;margin-left:-15px;animation:image-preloader-spin 2s infinite linear;box-sizing:border-box}.sortable .image-gallery__image{cursor:move}.image-gallery__image{position:relative;overflow:hidden;aspect-ratio:16 / 9;-webkit-user-select:none;user-select:none;background-color:#000;border-radius:3px;padding:5px}.image-gallery__image.sortable-ghost{opacity:.75}.image-gallery__image--empty,.image-gallery__image--loading{display:none}.image-gallery__image-picture{border-radius:3px;max-width:100%;height:100%;display:block;margin:auto;object-fit:cover;pointer-events:none}.image-gallery__image-trash{position:absolute;top:3px;right:3px;cursor:pointer;color:#fff;font-size:18px;background-color:#00000040;line-height:1;padding:6px 8px;border-radius:3px;transition:background-color .1s}.image-gallery__image-trash:hover{background-color:#00000080}.image-gallery__counter{display:flex;align-items:center;color:gray;font-size:14px;margin-right:6px}.image-gallery__caption[contentEditable=true][data-placeholder]:before{position:absolute!important;content:attr(data-placeholder);color:#707684;font-weight:400;display:none}.image-gallery__caption[contentEditable=true][data-placeholder]:empty:before{display:block}.image-gallery__caption[contentEditable=true][data-placeholder]:empty:focus:before{display:none}.image-gallery__caption{margin-bottom:10px}.image-gallery .cdx-button{height:40px;display:flex;align-items:center;justify-content:center;padding:12px;gap:5px;white-space:nowrap}.image-gallery__tune-wrapper{display:flex;gap:6px;margin:6px 0}.image-gallery__tune-wrapper:first-child{margin-top:0}.image-gallery__tune-wrapper:last-child{margin-bottom:0}.image-gallery__tune{flex-grow:1;padding:6px;color:var(--color-text-primary);display:flex;align-items:center;justify-content:center}.image-gallery__tune.active{background:var(--color-background-icon-active);color:var(--color-text-icon-active);border-color:var(--color-text-icon-active)}.image-gallery__tune svg{width:24px;height:24px}@keyframes image-preloader-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}')),document.head.appendChild(e)}}catch(a){console.error("vite-plugin-css-injected-by-js",a)}})(); 2 | const L = '', I = ''; 3 | class T { 4 | /** 5 | * @param {object} ui - image tool Ui module 6 | * @param {object} ui.api - Editor.js API 7 | * @param {ImageConfig} ui.config - user config 8 | * @param {Function} ui.onSelectFile - callback for clicks on Select file button 9 | * @param {boolean} ui.readOnly - read-only mode flag 10 | */ 11 | constructor({ api: o, config: s, onSelectFile: d, onDeleteFile: r, onMoveFile: i, readOnly: t }) { 12 | this.api = o, this.config = s, this.onSelectFile = d, this.onDeleteFile = r, this.onMoveFile = i, this.readOnly = t, this.nodes = { 13 | wrapper: x("div", [this.CSS.baseClass, this.CSS.wrapper]), 14 | fileButton: this.createFileButton(), 15 | container: x("div", this.CSS.container), 16 | itemsContainer: x("div", this.CSS.itemsContainer), 17 | controls: x("div", this.CSS.controls), 18 | preloaderContainer: x("div", this.CSS.preloaderContainer), 19 | caption: x("div", [this.CSS.input, this.CSS.caption], { 20 | contentEditable: !this.readOnly 21 | }) 22 | }, this.nodes.caption.dataset.placeholder = this.api.i18n.t("Gallery caption"), this.readOnly || (this.nodes.controls.appendChild(this.nodes.preloaderContainer), this.config.maxElementCount && (this.nodes.limitCounter = x("div", this.CSS.limitCounter), this.nodes.controls.appendChild(this.nodes.limitCounter)), this.nodes.controls.appendChild(this.nodes.fileButton)), this.nodes.container.appendChild(this.nodes.itemsContainer), this.readOnly || this.nodes.container.appendChild(this.nodes.controls), this.nodes.wrapper.appendChild(this.nodes.container), this.readOnly || this.nodes.wrapper.appendChild(this.nodes.caption), ["dragenter", "dragover", "dragleave", "drop"].forEach((c) => { 23 | this.nodes.itemsContainer.addEventListener(c, function(g) { 24 | g.preventDefault(), g.stopPropagation(); 25 | }, !1); 26 | }); 27 | } 28 | /** 29 | * CSS classes 30 | * 31 | * @returns {object} 32 | */ 33 | get CSS() { 34 | return { 35 | baseClass: this.api.styles.block, 36 | loading: this.api.styles.loader, 37 | input: this.api.styles.input, 38 | button: this.api.styles.button, 39 | /** 40 | * Tool's classes 41 | */ 42 | wrapper: "image-gallery", 43 | container: "image-gallery__container", 44 | controls: "image-gallery__controls", 45 | limitCounter: "image-gallery__counter", 46 | itemsContainer: "image-gallery__items", 47 | imageContainer: "image-gallery__image", 48 | preloaderContainer: "image-gallery__preloaders", 49 | imagePreloader: "image-gallery__preloader", 50 | imageEl: "image-gallery__image-picture", 51 | trashButton: "image-gallery__image-trash", 52 | caption: "image-gallery__caption" 53 | }; 54 | } 55 | /** 56 | * Ui statuses: 57 | * - empty 58 | * - uploading 59 | * - filled 60 | * 61 | * @returns {{EMPTY: string, UPLOADING: string, FILLED: string}} 62 | */ 63 | static get status() { 64 | return { 65 | EMPTY: "empty", 66 | UPLOADING: "loading", 67 | FILLED: "filled" 68 | }; 69 | } 70 | /** 71 | * Renders tool UI 72 | * 73 | * @param {ImageGalleryData} toolData - saved tool data 74 | * @returns {Element} 75 | */ 76 | render(o) { 77 | return this.nodes.wrapper; 78 | } 79 | onRendered() { 80 | !this.readOnly && !this.sortable && (this.sortable = new this.config.sortableJs(this.nodes.itemsContainer, { 81 | handle: `.${this.CSS.imageContainer}`, 82 | filter: `.${this.CSS.trashButton}`, 83 | onStart: () => { 84 | this.nodes.itemsContainer.classList.add(`${this.CSS.itemsContainer}--drag`); 85 | }, 86 | onEnd: (o) => { 87 | this.nodes.itemsContainer.classList.remove(`${this.CSS.itemsContainer}--drag`), o.oldIndex !== o.newIndex && this.onMoveFile(o.oldIndex, o.newIndex); 88 | } 89 | }), this.nodes.itemsContainer.classList.add("sortable")); 90 | } 91 | /** 92 | * Creates upload-file button 93 | * 94 | * @returns {Element} 95 | */ 96 | createFileButton() { 97 | const o = x("div", [this.CSS.button]); 98 | return o.innerHTML = this.config.buttonContent || `${L} ${this.api.i18n.t("Select an Image")}`, o.addEventListener("click", () => { 99 | this.onSelectFile(); 100 | }), o; 101 | } 102 | /** 103 | * Shows uploading button 104 | * 105 | * @returns {void} 106 | */ 107 | showFileButton() { 108 | this.nodes.fileButton.style.display = ""; 109 | } 110 | /** 111 | * Hide uploading button 112 | * 113 | * @returns {void} 114 | */ 115 | hideFileButton() { 116 | this.nodes.fileButton.style.display = "none"; 117 | } 118 | getPreloader(o) { 119 | let s = x("div", this.CSS.imagePreloader); 120 | this.nodes.preloaderContainer.append(s); 121 | const d = new FileReader(); 122 | return d.readAsDataURL(o), d.onload = (r) => { 123 | s.style.backgroundImage = `url(${r.target.result})`; 124 | }, s; 125 | } 126 | removePreloader(o) { 127 | o.remove(); 128 | } 129 | /** 130 | * Shows an image 131 | * 132 | * @param {ImageGalleryDataFile} file - image file object 133 | * @returns {void} 134 | */ 135 | appendImage(o) { 136 | let s = o.url; 137 | const d = /\.mp4$/.test(s) ? "VIDEO" : "IMG", r = { 138 | src: s 139 | }; 140 | let i = "load"; 141 | d === "VIDEO" && (r.autoplay = !1, r.muted = !0, r.playsinline = !0, i = "loadeddata"); 142 | let t = x("div", [this.CSS.imageContainer]), c = x(d, this.CSS.imageEl, r); 143 | c.addEventListener(i, () => { 144 | this.toggleStatus(t, T.status.FILLED); 145 | }), t.appendChild(c); 146 | const g = this.api.i18n.t("Delete"); 147 | if (!this.readOnly) { 148 | let a = x("div", [this.CSS.trashButton], { 149 | innerHTML: I, 150 | title: g 151 | }); 152 | this.api.tooltip.onHover(a, g, { 153 | placement: "top" 154 | }), a.addEventListener("click", () => { 155 | this.api.tooltip.hide(); 156 | let p = Array.prototype.slice.call(this.nodes.itemsContainer.children).indexOf(t); 157 | p !== -1 && (this.nodes.itemsContainer.removeChild(t), this.onDeleteFile(p)); 158 | }), t.appendChild(a); 159 | } 160 | this.nodes.itemsContainer.append(t); 161 | } 162 | /** 163 | * Shows caption input 164 | * 165 | * @param {string} text - caption text 166 | * @returns {void} 167 | */ 168 | fillCaption(o) { 169 | this.nodes.caption && (this.nodes.caption.innerHTML = o); 170 | } 171 | /** 172 | * Changes UI status 173 | * 174 | * @param {Element} elem 175 | * @param {string} status - see {@link Ui.status} constants 176 | * @returns {void} 177 | */ 178 | toggleStatus(o, s) { 179 | for (const d in T.status) 180 | Object.prototype.hasOwnProperty.call(T.status, d) && o.classList.toggle(`${this.CSS.imageContainer}--${T.status[d]}`, s === T.status[d]); 181 | } 182 | /** 183 | * @param {int} imageCount 184 | * @param {int|null} limitCounter 185 | * @returns {void} 186 | */ 187 | updateLimitCounter(o, s) { 188 | s && this.nodes.limitCounter && (o === 0 ? this.nodes.limitCounter.style.display = "none" : (this.nodes.limitCounter.style.display = null, this.nodes.limitCounter.innerText = `${o} / ${s}`)); 189 | } 190 | } 191 | const x = function(o, s = null, d = {}) { 192 | const r = document.createElement(o); 193 | Array.isArray(s) ? r.classList.add(...s) : s && r.classList.add(s); 194 | for (const i in d) 195 | r[i] = d[i]; 196 | return r; 197 | }, q = '', P = ''; 198 | class O { 199 | /** 200 | * @param {object} tune - image tool Tunes managers 201 | * @param {object} tune.api - Editor API 202 | * @param {object} tune.actions - list of user defined tunes 203 | * @param {Function} tune.onChange - tune toggling callback 204 | */ 205 | constructor({ api: o, actions: s, onChange: d }) { 206 | this.api = o, this.actions = s, this.onChange = d, this.buttons = []; 207 | } 208 | /** 209 | * Available Image tunes 210 | * 211 | * @returns {{name: string, icon: string, title: string}[]} 212 | */ 213 | static get tunes() { 214 | return [ 215 | { 216 | name: "slider", 217 | icon: q, 218 | title: "Slider" 219 | }, 220 | { 221 | name: "fit", 222 | icon: P, 223 | title: "Fit" 224 | } 225 | ]; 226 | } 227 | /** 228 | * Styles 229 | * 230 | * @returns {{wrapper: string, buttonBase: *, button: string, buttonActive: *}} 231 | */ 232 | get CSS() { 233 | return { 234 | wrapper: "image-gallery__tune-wrapper", 235 | buttonBase: this.api.styles.button, 236 | button: "image-gallery__tune", 237 | buttonActive: "active" 238 | }; 239 | } 240 | /** 241 | * Makes buttons with tunes 242 | * 243 | * @param {ImageGalleryData} toolData - generate Elements of tunes 244 | * @returns {Element} 245 | */ 246 | render(o) { 247 | const s = x("div", this.CSS.wrapper), d = this.actions ?? O.tunes; 248 | return this.buttons = [], d.forEach((r) => { 249 | const i = this.api.i18n.t(r.title), t = x("div", [this.CSS.buttonBase, this.CSS.button], { 250 | innerHTML: r.icon, 251 | title: i 252 | }); 253 | t.addEventListener("click", () => { 254 | this.tuneClicked(r.name, r.action); 255 | }), t.dataset.tune = r.name, t.classList.toggle(this.CSS.buttonActive, o.style === r.name), this.buttons.push(t), this.api.tooltip.onHover(t, i, { 256 | placement: "top" 257 | }), s.appendChild(t); 258 | }), s; 259 | } 260 | /** 261 | * Clicks to one of the tunes 262 | * 263 | * @param {string} tuneName - clicked tune name 264 | * @param {Function} customFunction - function to execute on click 265 | */ 266 | tuneClicked(o, s) { 267 | if (typeof s == "function" && !s(o)) 268 | return !1; 269 | this.buttons.forEach((d) => { 270 | d.classList.toggle(this.CSS.buttonActive, d.dataset.tune === o); 271 | }), this.onChange(o); 272 | } 273 | } 274 | const D = ''; 275 | function H(E) { 276 | return E && E.__esModule && Object.prototype.hasOwnProperty.call(E, "default") ? E.default : E; 277 | } 278 | var j = { exports: {} }; 279 | (function(E, o) { 280 | (function(s, d) { 281 | E.exports = d(); 282 | })(window, function() { 283 | return function(s) { 284 | var d = {}; 285 | function r(i) { 286 | if (d[i]) 287 | return d[i].exports; 288 | var t = d[i] = { i, l: !1, exports: {} }; 289 | return s[i].call(t.exports, t, t.exports, r), t.l = !0, t.exports; 290 | } 291 | return r.m = s, r.c = d, r.d = function(i, t, c) { 292 | r.o(i, t) || Object.defineProperty(i, t, { enumerable: !0, get: c }); 293 | }, r.r = function(i) { 294 | typeof Symbol < "u" && Symbol.toStringTag && Object.defineProperty(i, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(i, "__esModule", { value: !0 }); 295 | }, r.t = function(i, t) { 296 | if (1 & t && (i = r(i)), 8 & t || 4 & t && typeof i == "object" && i && i.__esModule) 297 | return i; 298 | var c = /* @__PURE__ */ Object.create(null); 299 | if (r.r(c), Object.defineProperty(c, "default", { enumerable: !0, value: i }), 2 & t && typeof i != "string") 300 | for (var g in i) 301 | r.d(c, g, (function(a) { 302 | return i[a]; 303 | }).bind(null, g)); 304 | return c; 305 | }, r.n = function(i) { 306 | var t = i && i.__esModule ? function() { 307 | return i.default; 308 | } : function() { 309 | return i; 310 | }; 311 | return r.d(t, "a", t), t; 312 | }, r.o = function(i, t) { 313 | return Object.prototype.hasOwnProperty.call(i, t); 314 | }, r.p = "", r(r.s = 3); 315 | }([function(s, d) { 316 | var r; 317 | r = function() { 318 | return this; 319 | }(); 320 | try { 321 | r = r || new Function("return this")(); 322 | } catch { 323 | typeof window == "object" && (r = window); 324 | } 325 | s.exports = r; 326 | }, function(s, d, r) { 327 | (function(i) { 328 | var t = r(2), c = setTimeout; 329 | function g() { 330 | } 331 | function a(n) { 332 | if (!(this instanceof a)) 333 | throw new TypeError("Promises must be constructed via new"); 334 | if (typeof n != "function") 335 | throw new TypeError("not a function"); 336 | this._state = 0, this._handled = !1, this._value = void 0, this._deferreds = [], e(n, this); 337 | } 338 | function h(n, u) { 339 | for (; n._state === 3; ) 340 | n = n._value; 341 | n._state !== 0 ? (n._handled = !0, a._immediateFn(function() { 342 | var l = n._state === 1 ? u.onFulfilled : u.onRejected; 343 | if (l !== null) { 344 | var y; 345 | try { 346 | y = l(n._value); 347 | } catch (m) { 348 | return void v(u.promise, m); 349 | } 350 | p(u.promise, y); 351 | } else 352 | (n._state === 1 ? p : v)(u.promise, n._value); 353 | })) : n._deferreds.push(u); 354 | } 355 | function p(n, u) { 356 | try { 357 | if (u === n) 358 | throw new TypeError("A promise cannot be resolved with itself."); 359 | if (u && (typeof u == "object" || typeof u == "function")) { 360 | var l = u.then; 361 | if (u instanceof a) 362 | return n._state = 3, n._value = u, void b(n); 363 | if (typeof l == "function") 364 | return void e((y = l, m = u, function() { 365 | y.apply(m, arguments); 366 | }), n); 367 | } 368 | n._state = 1, n._value = u, b(n); 369 | } catch (f) { 370 | v(n, f); 371 | } 372 | var y, m; 373 | } 374 | function v(n, u) { 375 | n._state = 2, n._value = u, b(n); 376 | } 377 | function b(n) { 378 | n._state === 2 && n._deferreds.length === 0 && a._immediateFn(function() { 379 | n._handled || a._unhandledRejectionFn(n._value); 380 | }); 381 | for (var u = 0, l = n._deferreds.length; u < l; u++) 382 | h(n, n._deferreds[u]); 383 | n._deferreds = null; 384 | } 385 | function w(n, u, l) { 386 | this.onFulfilled = typeof n == "function" ? n : null, this.onRejected = typeof u == "function" ? u : null, this.promise = l; 387 | } 388 | function e(n, u) { 389 | var l = !1; 390 | try { 391 | n(function(y) { 392 | l || (l = !0, p(u, y)); 393 | }, function(y) { 394 | l || (l = !0, v(u, y)); 395 | }); 396 | } catch (y) { 397 | if (l) 398 | return; 399 | l = !0, v(u, y); 400 | } 401 | } 402 | a.prototype.catch = function(n) { 403 | return this.then(null, n); 404 | }, a.prototype.then = function(n, u) { 405 | var l = new this.constructor(g); 406 | return h(this, new w(n, u, l)), l; 407 | }, a.prototype.finally = t.a, a.all = function(n) { 408 | return new a(function(u, l) { 409 | if (!n || n.length === void 0) 410 | throw new TypeError("Promise.all accepts an array"); 411 | var y = Array.prototype.slice.call(n); 412 | if (y.length === 0) 413 | return u([]); 414 | var m = y.length; 415 | function f(S, C) { 416 | try { 417 | if (C && (typeof C == "object" || typeof C == "function")) { 418 | var k = C.then; 419 | if (typeof k == "function") 420 | return void k.call(C, function(F) { 421 | f(S, F); 422 | }, l); 423 | } 424 | y[S] = C, --m == 0 && u(y); 425 | } catch (F) { 426 | l(F); 427 | } 428 | } 429 | for (var _ = 0; _ < y.length; _++) 430 | f(_, y[_]); 431 | }); 432 | }, a.resolve = function(n) { 433 | return n && typeof n == "object" && n.constructor === a ? n : new a(function(u) { 434 | u(n); 435 | }); 436 | }, a.reject = function(n) { 437 | return new a(function(u, l) { 438 | l(n); 439 | }); 440 | }, a.race = function(n) { 441 | return new a(function(u, l) { 442 | for (var y = 0, m = n.length; y < m; y++) 443 | n[y].then(u, l); 444 | }); 445 | }, a._immediateFn = typeof i == "function" && function(n) { 446 | i(n); 447 | } || function(n) { 448 | c(n, 0); 449 | }, a._unhandledRejectionFn = function(n) { 450 | typeof console < "u" && console && console.warn("Possible Unhandled Promise Rejection:", n); 451 | }, d.a = a; 452 | }).call(this, r(5).setImmediate); 453 | }, function(s, d, r) { 454 | d.a = function(i) { 455 | var t = this.constructor; 456 | return this.then(function(c) { 457 | return t.resolve(i()).then(function() { 458 | return c; 459 | }); 460 | }, function(c) { 461 | return t.resolve(i()).then(function() { 462 | return t.reject(c); 463 | }); 464 | }); 465 | }; 466 | }, function(s, d, r) { 467 | function i(e) { 468 | return (i = typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? function(n) { 469 | return typeof n; 470 | } : function(n) { 471 | return n && typeof Symbol == "function" && n.constructor === Symbol && n !== Symbol.prototype ? "symbol" : typeof n; 472 | })(e); 473 | } 474 | r(4); 475 | var t, c, g, a, h, p, v, b = r(8), w = (c = function(e) { 476 | return new Promise(function(n, u) { 477 | e = a(e), (e = h(e)).beforeSend && e.beforeSend(); 478 | var l = window.XMLHttpRequest ? new window.XMLHttpRequest() : new window.ActiveXObject("Microsoft.XMLHTTP"); 479 | l.open(e.method, e.url), l.setRequestHeader("X-Requested-With", "XMLHttpRequest"), Object.keys(e.headers).forEach(function(m) { 480 | var f = e.headers[m]; 481 | l.setRequestHeader(m, f); 482 | }); 483 | var y = e.ratio; 484 | l.upload.addEventListener("progress", function(m) { 485 | var f = Math.round(m.loaded / m.total * 100), _ = Math.ceil(f * y / 100); 486 | e.progress(Math.min(_, 100)); 487 | }, !1), l.addEventListener("progress", function(m) { 488 | var f = Math.round(m.loaded / m.total * 100), _ = Math.ceil(f * (100 - y) / 100) + y; 489 | e.progress(Math.min(_, 100)); 490 | }, !1), l.onreadystatechange = function() { 491 | if (l.readyState === 4) { 492 | var m = l.response; 493 | try { 494 | m = JSON.parse(m); 495 | } catch { 496 | } 497 | var f = b.parseHeaders(l.getAllResponseHeaders()), _ = { body: m, code: l.status, headers: f }; 498 | v(l.status) ? n(_) : u(_); 499 | } 500 | }, l.send(e.data); 501 | }); 502 | }, g = function(e) { 503 | return e.method = "POST", c(e); 504 | }, a = function() { 505 | var e = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}; 506 | if (e.url && typeof e.url != "string") 507 | throw new Error("Url must be a string"); 508 | if (e.url = e.url || "", e.method && typeof e.method != "string") 509 | throw new Error("`method` must be a string or null"); 510 | if (e.method = e.method ? e.method.toUpperCase() : "GET", e.headers && i(e.headers) !== "object") 511 | throw new Error("`headers` must be an object or null"); 512 | if (e.headers = e.headers || {}, e.type && (typeof e.type != "string" || !Object.values(t).includes(e.type))) 513 | throw new Error("`type` must be taken from module's «contentType» library"); 514 | if (e.progress && typeof e.progress != "function") 515 | throw new Error("`progress` must be a function or null"); 516 | if (e.progress = e.progress || function(n) { 517 | }, e.beforeSend = e.beforeSend || function(n) { 518 | }, e.ratio && typeof e.ratio != "number") 519 | throw new Error("`ratio` must be a number"); 520 | if (e.ratio < 0 || e.ratio > 100) 521 | throw new Error("`ratio` must be in a 0-100 interval"); 522 | if (e.ratio = e.ratio || 90, e.accept && typeof e.accept != "string") 523 | throw new Error("`accept` must be a string with a list of allowed mime-types"); 524 | if (e.accept = e.accept || "*/*", e.multiple && typeof e.multiple != "boolean") 525 | throw new Error("`multiple` must be a true or false"); 526 | if (e.multiple = e.multiple || !1, e.fieldName && typeof e.fieldName != "string") 527 | throw new Error("`fieldName` must be a string"); 528 | return e.fieldName = e.fieldName || "files", e; 529 | }, h = function(e) { 530 | switch (e.method) { 531 | case "GET": 532 | var n = p(e.data, t.URLENCODED); 533 | delete e.data, e.url = /\?/.test(e.url) ? e.url + "&" + n : e.url + "?" + n; 534 | break; 535 | case "POST": 536 | case "PUT": 537 | case "DELETE": 538 | case "UPDATE": 539 | var u = function() { 540 | return (arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}).type || t.JSON; 541 | }(e); 542 | (b.isFormData(e.data) || b.isFormElement(e.data)) && (u = t.FORM), e.data = p(e.data, u), u !== w.contentType.FORM && (e.headers["content-type"] = u); 543 | } 544 | return e; 545 | }, p = function() { 546 | var e = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}; 547 | switch (arguments.length > 1 ? arguments[1] : void 0) { 548 | case t.URLENCODED: 549 | return b.urlEncode(e); 550 | case t.JSON: 551 | return b.jsonEncode(e); 552 | case t.FORM: 553 | return b.formEncode(e); 554 | default: 555 | return e; 556 | } 557 | }, v = function(e) { 558 | return e >= 200 && e < 300; 559 | }, { contentType: t = { URLENCODED: "application/x-www-form-urlencoded; charset=utf-8", FORM: "multipart/form-data", JSON: "application/json; charset=utf-8" }, request: c, get: function(e) { 560 | return e.method = "GET", c(e); 561 | }, post: g, transport: function(e) { 562 | return e = a(e), b.selectFiles(e).then(function(n) { 563 | for (var u = new FormData(), l = 0; l < n.length; l++) 564 | u.append(e.fieldName, n[l], n[l].name); 565 | b.isObject(e.data) && Object.keys(e.data).forEach(function(m) { 566 | var f = e.data[m]; 567 | u.append(m, f); 568 | }); 569 | var y = e.beforeSend; 570 | return e.beforeSend = function() { 571 | return y(n); 572 | }, e.data = u, g(e); 573 | }); 574 | }, selectFiles: function(e) { 575 | return delete (e = a(e)).beforeSend, b.selectFiles(e); 576 | } }); 577 | s.exports = w; 578 | }, function(s, d, r) { 579 | r.r(d); 580 | var i = r(1); 581 | window.Promise = window.Promise || i.a; 582 | }, function(s, d, r) { 583 | (function(i) { 584 | var t = i !== void 0 && i || typeof self < "u" && self || window, c = Function.prototype.apply; 585 | function g(a, h) { 586 | this._id = a, this._clearFn = h; 587 | } 588 | d.setTimeout = function() { 589 | return new g(c.call(setTimeout, t, arguments), clearTimeout); 590 | }, d.setInterval = function() { 591 | return new g(c.call(setInterval, t, arguments), clearInterval); 592 | }, d.clearTimeout = d.clearInterval = function(a) { 593 | a && a.close(); 594 | }, g.prototype.unref = g.prototype.ref = function() { 595 | }, g.prototype.close = function() { 596 | this._clearFn.call(t, this._id); 597 | }, d.enroll = function(a, h) { 598 | clearTimeout(a._idleTimeoutId), a._idleTimeout = h; 599 | }, d.unenroll = function(a) { 600 | clearTimeout(a._idleTimeoutId), a._idleTimeout = -1; 601 | }, d._unrefActive = d.active = function(a) { 602 | clearTimeout(a._idleTimeoutId); 603 | var h = a._idleTimeout; 604 | h >= 0 && (a._idleTimeoutId = setTimeout(function() { 605 | a._onTimeout && a._onTimeout(); 606 | }, h)); 607 | }, r(6), d.setImmediate = typeof self < "u" && self.setImmediate || i !== void 0 && i.setImmediate || this && this.setImmediate, d.clearImmediate = typeof self < "u" && self.clearImmediate || i !== void 0 && i.clearImmediate || this && this.clearImmediate; 608 | }).call(this, r(0)); 609 | }, function(s, d, r) { 610 | (function(i, t) { 611 | (function(c, g) { 612 | if (!c.setImmediate) { 613 | var a, h, p, v, b, w = 1, e = {}, n = !1, u = c.document, l = Object.getPrototypeOf && Object.getPrototypeOf(c); 614 | l = l && l.setTimeout ? l : c, {}.toString.call(c.process) === "[object process]" ? a = function(f) { 615 | t.nextTick(function() { 616 | m(f); 617 | }); 618 | } : function() { 619 | if (c.postMessage && !c.importScripts) { 620 | var f = !0, _ = c.onmessage; 621 | return c.onmessage = function() { 622 | f = !1; 623 | }, c.postMessage("", "*"), c.onmessage = _, f; 624 | } 625 | }() ? (v = "setImmediate$" + Math.random() + "$", b = function(f) { 626 | f.source === c && typeof f.data == "string" && f.data.indexOf(v) === 0 && m(+f.data.slice(v.length)); 627 | }, c.addEventListener ? c.addEventListener("message", b, !1) : c.attachEvent("onmessage", b), a = function(f) { 628 | c.postMessage(v + f, "*"); 629 | }) : c.MessageChannel ? ((p = new MessageChannel()).port1.onmessage = function(f) { 630 | m(f.data); 631 | }, a = function(f) { 632 | p.port2.postMessage(f); 633 | }) : u && "onreadystatechange" in u.createElement("script") ? (h = u.documentElement, a = function(f) { 634 | var _ = u.createElement("script"); 635 | _.onreadystatechange = function() { 636 | m(f), _.onreadystatechange = null, h.removeChild(_), _ = null; 637 | }, h.appendChild(_); 638 | }) : a = function(f) { 639 | setTimeout(m, 0, f); 640 | }, l.setImmediate = function(f) { 641 | typeof f != "function" && (f = new Function("" + f)); 642 | for (var _ = new Array(arguments.length - 1), S = 0; S < _.length; S++) 643 | _[S] = arguments[S + 1]; 644 | var C = { callback: f, args: _ }; 645 | return e[w] = C, a(w), w++; 646 | }, l.clearImmediate = y; 647 | } 648 | function y(f) { 649 | delete e[f]; 650 | } 651 | function m(f) { 652 | if (n) 653 | setTimeout(m, 0, f); 654 | else { 655 | var _ = e[f]; 656 | if (_) { 657 | n = !0; 658 | try { 659 | (function(S) { 660 | var C = S.callback, k = S.args; 661 | switch (k.length) { 662 | case 0: 663 | C(); 664 | break; 665 | case 1: 666 | C(k[0]); 667 | break; 668 | case 2: 669 | C(k[0], k[1]); 670 | break; 671 | case 3: 672 | C(k[0], k[1], k[2]); 673 | break; 674 | default: 675 | C.apply(g, k); 676 | } 677 | })(_); 678 | } finally { 679 | y(f), n = !1; 680 | } 681 | } 682 | } 683 | } 684 | })(typeof self > "u" ? i === void 0 ? this : i : self); 685 | }).call(this, r(0), r(7)); 686 | }, function(s, d) { 687 | var r, i, t = s.exports = {}; 688 | function c() { 689 | throw new Error("setTimeout has not been defined"); 690 | } 691 | function g() { 692 | throw new Error("clearTimeout has not been defined"); 693 | } 694 | function a(l) { 695 | if (r === setTimeout) 696 | return setTimeout(l, 0); 697 | if ((r === c || !r) && setTimeout) 698 | return r = setTimeout, setTimeout(l, 0); 699 | try { 700 | return r(l, 0); 701 | } catch { 702 | try { 703 | return r.call(null, l, 0); 704 | } catch { 705 | return r.call(this, l, 0); 706 | } 707 | } 708 | } 709 | (function() { 710 | try { 711 | r = typeof setTimeout == "function" ? setTimeout : c; 712 | } catch { 713 | r = c; 714 | } 715 | try { 716 | i = typeof clearTimeout == "function" ? clearTimeout : g; 717 | } catch { 718 | i = g; 719 | } 720 | })(); 721 | var h, p = [], v = !1, b = -1; 722 | function w() { 723 | v && h && (v = !1, h.length ? p = h.concat(p) : b = -1, p.length && e()); 724 | } 725 | function e() { 726 | if (!v) { 727 | var l = a(w); 728 | v = !0; 729 | for (var y = p.length; y; ) { 730 | for (h = p, p = []; ++b < y; ) 731 | h && h[b].run(); 732 | b = -1, y = p.length; 733 | } 734 | h = null, v = !1, function(m) { 735 | if (i === clearTimeout) 736 | return clearTimeout(m); 737 | if ((i === g || !i) && clearTimeout) 738 | return i = clearTimeout, clearTimeout(m); 739 | try { 740 | i(m); 741 | } catch { 742 | try { 743 | return i.call(null, m); 744 | } catch { 745 | return i.call(this, m); 746 | } 747 | } 748 | }(l); 749 | } 750 | } 751 | function n(l, y) { 752 | this.fun = l, this.array = y; 753 | } 754 | function u() { 755 | } 756 | t.nextTick = function(l) { 757 | var y = new Array(arguments.length - 1); 758 | if (arguments.length > 1) 759 | for (var m = 1; m < arguments.length; m++) 760 | y[m - 1] = arguments[m]; 761 | p.push(new n(l, y)), p.length !== 1 || v || a(e); 762 | }, n.prototype.run = function() { 763 | this.fun.apply(null, this.array); 764 | }, t.title = "browser", t.browser = !0, t.env = {}, t.argv = [], t.version = "", t.versions = {}, t.on = u, t.addListener = u, t.once = u, t.off = u, t.removeListener = u, t.removeAllListeners = u, t.emit = u, t.prependListener = u, t.prependOnceListener = u, t.listeners = function(l) { 765 | return []; 766 | }, t.binding = function(l) { 767 | throw new Error("process.binding is not supported"); 768 | }, t.cwd = function() { 769 | return "/"; 770 | }, t.chdir = function(l) { 771 | throw new Error("process.chdir is not supported"); 772 | }, t.umask = function() { 773 | return 0; 774 | }; 775 | }, function(s, d, r) { 776 | function i(c, g) { 777 | for (var a = 0; a < g.length; a++) { 778 | var h = g[a]; 779 | h.enumerable = h.enumerable || !1, h.configurable = !0, "value" in h && (h.writable = !0), Object.defineProperty(c, h.key, h); 780 | } 781 | } 782 | var t = r(9); 783 | s.exports = function() { 784 | function c() { 785 | (function(p, v) { 786 | if (!(p instanceof v)) 787 | throw new TypeError("Cannot call a class as a function"); 788 | })(this, c); 789 | } 790 | var g, a, h; 791 | return g = c, h = [{ key: "urlEncode", value: function(p) { 792 | return t(p); 793 | } }, { key: "jsonEncode", value: function(p) { 794 | return JSON.stringify(p); 795 | } }, { key: "formEncode", value: function(p) { 796 | if (this.isFormData(p)) 797 | return p; 798 | if (this.isFormElement(p)) 799 | return new FormData(p); 800 | if (this.isObject(p)) { 801 | var v = new FormData(); 802 | return Object.keys(p).forEach(function(b) { 803 | var w = p[b]; 804 | v.append(b, w); 805 | }), v; 806 | } 807 | throw new Error("`data` must be an instance of Object, FormData or
HTMLElement"); 808 | } }, { key: "isObject", value: function(p) { 809 | return Object.prototype.toString.call(p) === "[object Object]"; 810 | } }, { key: "isFormData", value: function(p) { 811 | return p instanceof FormData; 812 | } }, { key: "isFormElement", value: function(p) { 813 | return p instanceof HTMLFormElement; 814 | } }, { key: "selectFiles", value: function() { 815 | var p = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}; 816 | return new Promise(function(v, b) { 817 | var w = document.createElement("INPUT"); 818 | w.type = "file", p.multiple && w.setAttribute("multiple", "multiple"), p.accept && w.setAttribute("accept", p.accept), w.style.display = "none", document.body.appendChild(w), w.addEventListener("change", function(e) { 819 | var n = e.target.files; 820 | v(n), document.body.removeChild(w); 821 | }, !1), w.click(); 822 | }); 823 | } }, { key: "parseHeaders", value: function(p) { 824 | var v = p.trim().split(/[\r\n]+/), b = {}; 825 | return v.forEach(function(w) { 826 | var e = w.split(": "), n = e.shift(), u = e.join(": "); 827 | n && (b[n] = u); 828 | }), b; 829 | } }], (a = null) && i(g.prototype, a), h && i(g, h), c; 830 | }(); 831 | }, function(s, d) { 832 | var r = function(t) { 833 | return encodeURIComponent(t).replace(/[!'()*]/g, escape).replace(/%20/g, "+"); 834 | }, i = function(t, c, g, a) { 835 | return c = c || null, g = g || "&", a = a || null, t ? function(h) { 836 | for (var p = new Array(), v = 0; v < h.length; v++) 837 | h[v] && p.push(h[v]); 838 | return p; 839 | }(Object.keys(t).map(function(h) { 840 | var p, v, b = h; 841 | if (a && (b = a + "[" + b + "]"), typeof t[h] == "object" && t[h] !== null) 842 | p = i(t[h], null, g, b); 843 | else { 844 | c && (v = b, b = !isNaN(parseFloat(v)) && isFinite(v) ? c + Number(b) : b); 845 | var w = t[h]; 846 | w = (w = (w = (w = w === !0 ? "1" : w) === !1 ? "0" : w) === 0 ? "0" : w) || "", p = r(b) + "=" + r(w); 847 | } 848 | return p; 849 | })).join(g).replace(/[!'()*]/g, "") : ""; 850 | }; 851 | s.exports = i; 852 | }]); 853 | }); 854 | })(j); 855 | var R = j.exports; 856 | const M = /* @__PURE__ */ H(R); 857 | class B { 858 | /** 859 | * @param {object} params - uploader module params 860 | * @param {ImageConfig} params.config - image tool config 861 | */ 862 | constructor({ config: o }) { 863 | this.config = o; 864 | } 865 | /** 866 | * Handle clicks on the upload file button 867 | */ 868 | uploadSelectedFiles(o, { onPreview: s, onUpload: d, onError: r }) { 869 | M.selectFiles({ 870 | accept: this.config.types, 871 | multiple: !0 872 | }).then((i) => { 873 | let t = 0; 874 | for (var c = 0; c < i.length && !(o !== null && t == o); c++) { 875 | t++; 876 | let g = i[c], a = s(g), h; 877 | if (this.config.uploader && typeof this.config.uploader.uploadByFile == "function") { 878 | const p = this.config.uploader.uploadByFile(g); 879 | A(p) || console.warn("Custom uploader method uploadByFile should return a Promise"), h = p; 880 | } else 881 | h = this.uploadByFile(g); 882 | h.then((p) => { 883 | d(p, a); 884 | }).catch((p) => { 885 | r(p, a); 886 | }); 887 | } 888 | }); 889 | } 890 | /** 891 | * Default file uploader 892 | * Fires ajax.post() 893 | * 894 | * @param {File} file - file pasted by drag-n-drop 895 | */ 896 | uploadByFile(o) { 897 | const s = new FormData(); 898 | return s.append(this.config.field, o), this.config.additionalRequestData && Object.keys(this.config.additionalRequestData).length && Object.entries(this.config.additionalRequestData).forEach(([d, r]) => { 899 | s.append(d, r); 900 | }), M.post({ 901 | url: this.config.endpoints.byFile, 902 | data: s, 903 | type: M.contentType.JSON, 904 | headers: this.config.additionalRequestHeaders 905 | }).then((d) => d.body); 906 | } 907 | } 908 | function A(E) { 909 | return E && typeof E.then == "function"; 910 | } 911 | /** 912 | * Image Gallery Tool for the Editor.js 913 | * 914 | * @author Igor Shuvalov «VolgaIgor» 915 | * @license MIT 916 | * @see {@link https://github.com/VolgaIgor/editorjs-gallery} 917 | * 918 | * To developers. 919 | * To simplify Tool structure, we split it to 4 parts: 920 | * 1) index.js — main Tool's interface, public API and methods for working with data 921 | * 2) uploader.js — module that has methods for sending files via AJAX: from device, by URL or File pasting 922 | * 3) ui.js — module for UI manipulations: render, showing preloader, etc 923 | * 4) tunes.js — working with Block Tunes: render buttons, handle clicks 924 | * 925 | * For debug purposes there is a testing server 926 | * that can save uploaded files and return a Response {@link UploadResponseFormat} 927 | * 928 | * $ node dev/server.js 929 | * 930 | * It will expose 8008 port, so you can pass http://localhost:8008 with the Tools config: 931 | * 932 | * gallery: { 933 | * class: ImageGallery, 934 | * config: { 935 | * endpoints: { 936 | * byFile: 'http://localhost:8008/uploadFile', 937 | * } 938 | * }, 939 | * }, 940 | */ 941 | class Z { 942 | /** 943 | * Notify core that read-only mode is supported 944 | * 945 | * @returns {boolean} 946 | */ 947 | static get isReadOnlySupported() { 948 | return !0; 949 | } 950 | /** 951 | * Get Tool toolbox settings 952 | * icon - Tool icon's SVG 953 | * title - title to show in toolbox 954 | * 955 | * @returns {{icon: string, title: string}} 956 | */ 957 | static get toolbox() { 958 | return { 959 | icon: D, 960 | title: "Gallery" 961 | }; 962 | } 963 | /** 964 | * @param {object} tool - tool properties got from editor.js 965 | * @param {ImageGalleryData} tool.data - previously saved data 966 | * @param {ImageConfig} tool.config - user config for Tool 967 | * @param {object} tool.api - Editor.js API 968 | * @param {boolean} tool.readOnly - read-only mode flag 969 | */ 970 | constructor({ data: o, config: s, api: d, readOnly: r }) { 971 | this.api = d, this.readOnly = r, this.config = { 972 | endpoints: s.endpoints || "", 973 | additionalRequestData: s.additionalRequestData || {}, 974 | additionalRequestHeaders: s.additionalRequestHeaders || {}, 975 | field: s.field || "image", 976 | types: s.types || "image/*", 977 | buttonContent: s.buttonContent || "", 978 | uploader: s.uploader || void 0, 979 | actions: s.actions || void 0, 980 | maxElementCount: s.maxElementCount || void 0, 981 | sortableJs: s.sortableJs 982 | }, this.uploader = new B({ 983 | config: this.config 984 | }), this.ui = new T({ 985 | api: d, 986 | config: this.config, 987 | onSelectFile: () => { 988 | let i = this.config.maxElementCount ? this.config.maxElementCount - this._data.files.length : null; 989 | this.uploader.uploadSelectedFiles(i, { 990 | onPreview: (t) => this.ui.getPreloader(t), 991 | onUpload: (t, c) => { 992 | this.onUpload(t, c); 993 | }, 994 | onError: (t, c) => { 995 | this.uploadingFailed(t, c); 996 | } 997 | }); 998 | }, 999 | onDeleteFile: (i) => { 1000 | this.deleteImage(i); 1001 | }, 1002 | onMoveFile: (i, t) => { 1003 | this.moveImage(i, t); 1004 | }, 1005 | readOnly: r 1006 | }), this.tunes = new O({ 1007 | api: d, 1008 | actions: this.config.actions, 1009 | onChange: (i) => this.styleToggled(i) 1010 | }), this._data = {}, this.data = o; 1011 | } 1012 | /** 1013 | * Renders Block content 1014 | * 1015 | * @public 1016 | * 1017 | * @returns {HTMLDivElement} 1018 | */ 1019 | render() { 1020 | return this.ui.render(this.data); 1021 | } 1022 | rendered() { 1023 | return this.checkMaxElemCount(), this.ui.onRendered(); 1024 | } 1025 | /** 1026 | * Validate data: check if Image exists 1027 | * 1028 | * @param {ImageGalleryData} savedData — data received after saving 1029 | * @returns {boolean} false if saved data is not correct, otherwise true 1030 | * @public 1031 | */ 1032 | validate(o) { 1033 | return !(!o.files || !o.files.length); 1034 | } 1035 | /** 1036 | * Return Block data 1037 | * 1038 | * @public 1039 | * 1040 | * @returns {ImageGalleryData} 1041 | */ 1042 | save() { 1043 | const o = this.ui.nodes.caption; 1044 | return this._data.caption = o.innerHTML, this.data; 1045 | } 1046 | /** 1047 | * Makes buttons with tunes 1048 | * 1049 | * @public 1050 | * 1051 | * @returns {Element} 1052 | */ 1053 | renderSettings() { 1054 | return this.tunes.render(this.data); 1055 | } 1056 | /** 1057 | * Set new image file 1058 | * 1059 | * @private 1060 | * 1061 | * @param {ImageGalleryDataFile} file - uploaded file data 1062 | */ 1063 | appendImage(o) { 1064 | if (o && o.url) { 1065 | if (this.config.maxElementCount && this._data.files.length >= this.config.maxElementCount) 1066 | return; 1067 | this._data.files.push(o), this.ui.appendImage(o), this.checkMaxElemCount(); 1068 | } 1069 | } 1070 | /** 1071 | * Move image file 1072 | * 1073 | * @private 1074 | * 1075 | * @param {integer} from - target image old index 1076 | * @param {integer} to - target image new index 1077 | */ 1078 | moveImage(o, s) { 1079 | s >= this._data.files.length && (s = this._data.files.length - 1), this._data.files.splice(s, 0, this._data.files.splice(o, 1)[0]); 1080 | } 1081 | /** 1082 | * Delete image file 1083 | * 1084 | * @private 1085 | * 1086 | * @param {integer} id - image index 1087 | */ 1088 | deleteImage(o) { 1089 | this._data.files[o] !== void 0 && (this._data.files.splice(o, 1), this.checkMaxElemCount()); 1090 | } 1091 | /** 1092 | * Private methods 1093 | * ̿̿ ̿̿ ̿̿ ̿'̿'\̵͇̿̿\з= ( ▀ ͜͞ʖ▀) =ε/̵͇̿̿/’̿’̿ ̿ ̿̿ ̿̿ ̿̿ 1094 | */ 1095 | /** 1096 | * Stores all Tool's data 1097 | * 1098 | * @private 1099 | * 1100 | * @param {ImageGalleryData} data - data in Image Tool format 1101 | */ 1102 | set data(o) { 1103 | this._data.files = [], o.files && o.files.forEach((d) => { 1104 | this.appendImage(d); 1105 | }), this._data.caption = o.caption || "", this.ui.fillCaption(this._data.caption); 1106 | let s = o.style || ""; 1107 | this.styleToggled(s); 1108 | } 1109 | /** 1110 | * Return Tool data 1111 | * 1112 | * @private 1113 | * 1114 | * @returns {ImageGalleryData} 1115 | */ 1116 | get data() { 1117 | return this._data; 1118 | } 1119 | /** 1120 | * File uploading callback 1121 | * 1122 | * @private 1123 | * 1124 | * @param {UploadResponseFormat} response - uploading server response 1125 | * @returns {void} 1126 | */ 1127 | onUpload(o, s) { 1128 | this.ui.removePreloader(s), o.success && o.file ? this.appendImage(o.file) : this.uploadingFailed("incorrect response: " + JSON.stringify(o)); 1129 | } 1130 | /** 1131 | * Handle uploader errors 1132 | * 1133 | * @private 1134 | * @param {string} errorText - uploading error text 1135 | * @returns {void} 1136 | */ 1137 | uploadingFailed(o, s) { 1138 | this.ui.removePreloader(s), console.log("Image Tool: uploading failed because of", o), this.api.notifier.show({ 1139 | message: this.api.i18n.t("Couldn’t upload image. Please try another."), 1140 | style: "error" 1141 | }); 1142 | } 1143 | /** 1144 | * Callback fired when Block Tune is activated 1145 | * 1146 | * @private 1147 | * 1148 | * @param {string} tuneName - tune that has been clicked 1149 | * @returns {void} 1150 | */ 1151 | styleToggled(o) { 1152 | o === "fit" ? this._data.style = "fit" : this._data.style = "slider"; 1153 | } 1154 | checkMaxElemCount() { 1155 | this.ui.updateLimitCounter(this._data.files.length, this.config.maxElementCount), this.config.maxElementCount && this._data.files.length >= this.config.maxElementCount ? this.ui.hideFileButton() : this.ui.showFileButton(); 1156 | } 1157 | } 1158 | export { 1159 | Z as default 1160 | }; 1161 | -------------------------------------------------------------------------------- /dist/gallery.umd.js: -------------------------------------------------------------------------------- 1 | (function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode('.image-gallery{--bg-color: #cdd1e0;--front-color: #388ae5;--border-color: #e8e8eb}.image-gallery__container{background:black;margin-bottom:10px;padding:5px}.image-gallery__controls{display:flex;gap:10px;padding:8px 2px 3px}.image-gallery__items{display:grid;gap:10px;grid-template-columns:1fr 1fr 1fr;padding:10px;background-color:#222}.image-gallery__items:empty{display:none}.image-gallery__preloaders{display:flex;flex-grow:1;flex-wrap:nowrap;padding:5px;gap:8px;overflow:hidden}.image-gallery__preloader{min-width:30px;height:30px;border-radius:50%;background-size:cover;position:relative;background-color:var(--bg-color);background-position:center center}.image-gallery__preloader:after{content:"";position:absolute;z-index:3;width:30px;height:30px;border-radius:50%;border:2px solid var(--bg-color);border-top-color:var(--front-color);left:50%;top:50%;margin-top:-15px;margin-left:-15px;animation:image-preloader-spin 2s infinite linear;box-sizing:border-box}.sortable .image-gallery__image{cursor:move}.image-gallery__image{position:relative;overflow:hidden;aspect-ratio:16 / 9;-webkit-user-select:none;user-select:none;background-color:#000;border-radius:3px;padding:5px}.image-gallery__image.sortable-ghost{opacity:.75}.image-gallery__image--empty,.image-gallery__image--loading{display:none}.image-gallery__image-picture{border-radius:3px;max-width:100%;height:100%;display:block;margin:auto;object-fit:cover;pointer-events:none}.image-gallery__image-trash{position:absolute;top:3px;right:3px;cursor:pointer;color:#fff;font-size:18px;background-color:#00000040;line-height:1;padding:6px 8px;border-radius:3px;transition:background-color .1s}.image-gallery__image-trash:hover{background-color:#00000080}.image-gallery__counter{display:flex;align-items:center;color:gray;font-size:14px;margin-right:6px}.image-gallery__caption[contentEditable=true][data-placeholder]:before{position:absolute!important;content:attr(data-placeholder);color:#707684;font-weight:400;display:none}.image-gallery__caption[contentEditable=true][data-placeholder]:empty:before{display:block}.image-gallery__caption[contentEditable=true][data-placeholder]:empty:focus:before{display:none}.image-gallery__caption{margin-bottom:10px}.image-gallery .cdx-button{height:40px;display:flex;align-items:center;justify-content:center;padding:12px;gap:5px;white-space:nowrap}.image-gallery__tune-wrapper{display:flex;gap:6px;margin:6px 0}.image-gallery__tune-wrapper:first-child{margin-top:0}.image-gallery__tune-wrapper:last-child{margin-bottom:0}.image-gallery__tune{flex-grow:1;padding:6px;color:var(--color-text-primary);display:flex;align-items:center;justify-content:center}.image-gallery__tune.active{background:var(--color-background-icon-active);color:var(--color-text-icon-active);border-color:var(--color-text-icon-active)}.image-gallery__tune svg{width:24px;height:24px}@keyframes image-preloader-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}')),document.head.appendChild(e)}}catch(a){console.error("vite-plugin-css-injected-by-js",a)}})(); 2 | (function(M,F){typeof exports=="object"&&typeof module<"u"?module.exports=F():typeof define=="function"&&define.amd?define(F):(M=typeof globalThis<"u"?globalThis:M||self,M.ImageGallery=F())})(this,function(){"use strict";const M=`.image-gallery{--bg-color: #cdd1e0;--front-color: #388ae5;--border-color: #e8e8eb}.image-gallery__container{background:black;margin-bottom:10px;padding:5px}.image-gallery__controls{display:flex;gap:10px;padding:8px 2px 3px}.image-gallery__items{display:grid;gap:10px;grid-template-columns:1fr 1fr 1fr;padding:10px;background-color:#222}.image-gallery__items:empty{display:none}.image-gallery__preloaders{display:flex;flex-grow:1;flex-wrap:nowrap;padding:5px;gap:8px;overflow:hidden}.image-gallery__preloader{min-width:30px;height:30px;border-radius:50%;background-size:cover;position:relative;background-color:var(--bg-color);background-position:center center}.image-gallery__preloader:after{content:"";position:absolute;z-index:3;width:30px;height:30px;border-radius:50%;border:2px solid var(--bg-color);border-top-color:var(--front-color);left:50%;top:50%;margin-top:-15px;margin-left:-15px;animation:image-preloader-spin 2s infinite linear;box-sizing:border-box}.sortable .image-gallery__image{cursor:move}.image-gallery__image{position:relative;overflow:hidden;aspect-ratio:16 / 9;-webkit-user-select:none;user-select:none;background-color:#000;border-radius:3px;padding:5px}.image-gallery__image.sortable-ghost{opacity:.75}.image-gallery__image--empty,.image-gallery__image--loading{display:none}.image-gallery__image-picture{border-radius:3px;max-width:100%;height:100%;display:block;margin:auto;object-fit:cover;pointer-events:none}.image-gallery__image-trash{position:absolute;top:3px;right:3px;cursor:pointer;color:#fff;font-size:18px;background-color:#00000040;line-height:1;padding:6px 8px;border-radius:3px;transition:background-color .1s}.image-gallery__image-trash:hover{background-color:#00000080}.image-gallery__counter{display:flex;align-items:center;color:gray;font-size:14px;margin-right:6px}.image-gallery__caption[contentEditable=true][data-placeholder]:before{position:absolute!important;content:attr(data-placeholder);color:#707684;font-weight:400;display:none}.image-gallery__caption[contentEditable=true][data-placeholder]:empty:before{display:block}.image-gallery__caption[contentEditable=true][data-placeholder]:empty:focus:before{display:none}.image-gallery__caption{margin-bottom:10px}.image-gallery .cdx-button{height:40px;display:flex;align-items:center;justify-content:center;padding:12px;gap:5px;white-space:nowrap}.image-gallery__tune-wrapper{display:flex;gap:6px;margin:6px 0}.image-gallery__tune-wrapper:first-child{margin-top:0}.image-gallery__tune-wrapper:last-child{margin-bottom:0}.image-gallery__tune{flex-grow:1;padding:6px;color:var(--color-text-primary);display:flex;align-items:center;justify-content:center}.image-gallery__tune.active{background:var(--color-background-icon-active);color:var(--color-text-icon-active);border-color:var(--color-text-icon-active)}.image-gallery__tune svg{width:24px;height:24px}@keyframes image-preloader-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}} 3 | `,F='',q='';class k{constructor({api:r,config:s,onSelectFile:d,onDeleteFile:o,onMoveFile:i,readOnly:t}){this.api=r,this.config=s,this.onSelectFile=d,this.onDeleteFile=o,this.onMoveFile=i,this.readOnly=t,this.nodes={wrapper:C("div",[this.CSS.baseClass,this.CSS.wrapper]),fileButton:this.createFileButton(),container:C("div",this.CSS.container),itemsContainer:C("div",this.CSS.itemsContainer),controls:C("div",this.CSS.controls),preloaderContainer:C("div",this.CSS.preloaderContainer),caption:C("div",[this.CSS.input,this.CSS.caption],{contentEditable:!this.readOnly})},this.nodes.caption.dataset.placeholder=this.api.i18n.t("Gallery caption"),this.readOnly||(this.nodes.controls.appendChild(this.nodes.preloaderContainer),this.config.maxElementCount&&(this.nodes.limitCounter=C("div",this.CSS.limitCounter),this.nodes.controls.appendChild(this.nodes.limitCounter)),this.nodes.controls.appendChild(this.nodes.fileButton)),this.nodes.container.appendChild(this.nodes.itemsContainer),this.readOnly||this.nodes.container.appendChild(this.nodes.controls),this.nodes.wrapper.appendChild(this.nodes.container),this.readOnly||this.nodes.wrapper.appendChild(this.nodes.caption),["dragenter","dragover","dragleave","drop"].forEach(c=>{this.nodes.itemsContainer.addEventListener(c,function(g){g.preventDefault(),g.stopPropagation()},!1)})}get CSS(){return{baseClass:this.api.styles.block,loading:this.api.styles.loader,input:this.api.styles.input,button:this.api.styles.button,wrapper:"image-gallery",container:"image-gallery__container",controls:"image-gallery__controls",limitCounter:"image-gallery__counter",itemsContainer:"image-gallery__items",imageContainer:"image-gallery__image",preloaderContainer:"image-gallery__preloaders",imagePreloader:"image-gallery__preloader",imageEl:"image-gallery__image-picture",trashButton:"image-gallery__image-trash",caption:"image-gallery__caption"}}static get status(){return{EMPTY:"empty",UPLOADING:"loading",FILLED:"filled"}}render(r){return this.nodes.wrapper}onRendered(){!this.readOnly&&!this.sortable&&(this.sortable=new this.config.sortableJs(this.nodes.itemsContainer,{handle:`.${this.CSS.imageContainer}`,filter:`.${this.CSS.trashButton}`,onStart:()=>{this.nodes.itemsContainer.classList.add(`${this.CSS.itemsContainer}--drag`)},onEnd:r=>{this.nodes.itemsContainer.classList.remove(`${this.CSS.itemsContainer}--drag`),r.oldIndex!==r.newIndex&&this.onMoveFile(r.oldIndex,r.newIndex)}}),this.nodes.itemsContainer.classList.add("sortable"))}createFileButton(){const r=C("div",[this.CSS.button]);return r.innerHTML=this.config.buttonContent||`${F} ${this.api.i18n.t("Select an Image")}`,r.addEventListener("click",()=>{this.onSelectFile()}),r}showFileButton(){this.nodes.fileButton.style.display=""}hideFileButton(){this.nodes.fileButton.style.display="none"}getPreloader(r){let s=C("div",this.CSS.imagePreloader);this.nodes.preloaderContainer.append(s);const d=new FileReader;return d.readAsDataURL(r),d.onload=o=>{s.style.backgroundImage=`url(${o.target.result})`},s}removePreloader(r){r.remove()}appendImage(r){let s=r.url;const d=/\.mp4$/.test(s)?"VIDEO":"IMG",o={src:s};let i="load";d==="VIDEO"&&(o.autoplay=!1,o.muted=!0,o.playsinline=!0,i="loadeddata");let t=C("div",[this.CSS.imageContainer]),c=C(d,this.CSS.imageEl,o);c.addEventListener(i,()=>{this.toggleStatus(t,k.status.FILLED)}),t.appendChild(c);const g=this.api.i18n.t("Delete");if(!this.readOnly){let a=C("div",[this.CSS.trashButton],{innerHTML:q,title:g});this.api.tooltip.onHover(a,g,{placement:"top"}),a.addEventListener("click",()=>{this.api.tooltip.hide();let p=Array.prototype.slice.call(this.nodes.itemsContainer.children).indexOf(t);p!==-1&&(this.nodes.itemsContainer.removeChild(t),this.onDeleteFile(p))}),t.appendChild(a)}this.nodes.itemsContainer.append(t)}fillCaption(r){this.nodes.caption&&(this.nodes.caption.innerHTML=r)}toggleStatus(r,s){for(const d in k.status)Object.prototype.hasOwnProperty.call(k.status,d)&&r.classList.toggle(`${this.CSS.imageContainer}--${k.status[d]}`,s===k.status[d])}updateLimitCounter(r,s){s&&this.nodes.limitCounter&&(r===0?this.nodes.limitCounter.style.display="none":(this.nodes.limitCounter.style.display=null,this.nodes.limitCounter.innerText=`${r} / ${s}`))}}const C=function(r,s=null,d={}){const o=document.createElement(r);Array.isArray(s)?o.classList.add(...s):s&&o.classList.add(s);for(const i in d)o[i]=d[i];return o},P='',D='';class O{constructor({api:r,actions:s,onChange:d}){this.api=r,this.actions=s,this.onChange=d,this.buttons=[]}static get tunes(){return[{name:"slider",icon:P,title:"Slider"},{name:"fit",icon:D,title:"Fit"}]}get CSS(){return{wrapper:"image-gallery__tune-wrapper",buttonBase:this.api.styles.button,button:"image-gallery__tune",buttonActive:"active"}}render(r){const s=C("div",this.CSS.wrapper),d=this.actions??O.tunes;return this.buttons=[],d.forEach(o=>{const i=this.api.i18n.t(o.title),t=C("div",[this.CSS.buttonBase,this.CSS.button],{innerHTML:o.icon,title:i});t.addEventListener("click",()=>{this.tuneClicked(o.name,o.action)}),t.dataset.tune=o.name,t.classList.toggle(this.CSS.buttonActive,r.style===o.name),this.buttons.push(t),this.api.tooltip.onHover(t,i,{placement:"top"}),s.appendChild(t)}),s}tuneClicked(r,s){if(typeof s=="function"&&!s(r))return!1;this.buttons.forEach(d=>{d.classList.toggle(this.CSS.buttonActive,d.dataset.tune===r)}),this.onChange(r)}}const H='';function R(E){return E&&E.__esModule&&Object.prototype.hasOwnProperty.call(E,"default")?E.default:E}var I={exports:{}};(function(E,r){(function(s,d){E.exports=d()})(window,function(){return function(s){var d={};function o(i){if(d[i])return d[i].exports;var t=d[i]={i,l:!1,exports:{}};return s[i].call(t.exports,t,t.exports,o),t.l=!0,t.exports}return o.m=s,o.c=d,o.d=function(i,t,c){o.o(i,t)||Object.defineProperty(i,t,{enumerable:!0,get:c})},o.r=function(i){typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(i,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(i,"__esModule",{value:!0})},o.t=function(i,t){if(1&t&&(i=o(i)),8&t||4&t&&typeof i=="object"&&i&&i.__esModule)return i;var c=Object.create(null);if(o.r(c),Object.defineProperty(c,"default",{enumerable:!0,value:i}),2&t&&typeof i!="string")for(var g in i)o.d(c,g,(function(a){return i[a]}).bind(null,g));return c},o.n=function(i){var t=i&&i.__esModule?function(){return i.default}:function(){return i};return o.d(t,"a",t),t},o.o=function(i,t){return Object.prototype.hasOwnProperty.call(i,t)},o.p="",o(o.s=3)}([function(s,d){var o;o=function(){return this}();try{o=o||new Function("return this")()}catch{typeof window=="object"&&(o=window)}s.exports=o},function(s,d,o){(function(i){var t=o(2),c=setTimeout;function g(){}function a(n){if(!(this instanceof a))throw new TypeError("Promises must be constructed via new");if(typeof n!="function")throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],e(n,this)}function h(n,u){for(;n._state===3;)n=n._value;n._state!==0?(n._handled=!0,a._immediateFn(function(){var l=n._state===1?u.onFulfilled:u.onRejected;if(l!==null){var y;try{y=l(n._value)}catch(m){return void v(u.promise,m)}p(u.promise,y)}else(n._state===1?p:v)(u.promise,n._value)})):n._deferreds.push(u)}function p(n,u){try{if(u===n)throw new TypeError("A promise cannot be resolved with itself.");if(u&&(typeof u=="object"||typeof u=="function")){var l=u.then;if(u instanceof a)return n._state=3,n._value=u,void b(n);if(typeof l=="function")return void e((y=l,m=u,function(){y.apply(m,arguments)}),n)}n._state=1,n._value=u,b(n)}catch(f){v(n,f)}var y,m}function v(n,u){n._state=2,n._value=u,b(n)}function b(n){n._state===2&&n._deferreds.length===0&&a._immediateFn(function(){n._handled||a._unhandledRejectionFn(n._value)});for(var u=0,l=n._deferreds.length;u0&&arguments[0]!==void 0?arguments[0]:{};if(e.url&&typeof e.url!="string")throw new Error("Url must be a string");if(e.url=e.url||"",e.method&&typeof e.method!="string")throw new Error("`method` must be a string or null");if(e.method=e.method?e.method.toUpperCase():"GET",e.headers&&i(e.headers)!=="object")throw new Error("`headers` must be an object or null");if(e.headers=e.headers||{},e.type&&(typeof e.type!="string"||!Object.values(t).includes(e.type)))throw new Error("`type` must be taken from module's «contentType» library");if(e.progress&&typeof e.progress!="function")throw new Error("`progress` must be a function or null");if(e.progress=e.progress||function(n){},e.beforeSend=e.beforeSend||function(n){},e.ratio&&typeof e.ratio!="number")throw new Error("`ratio` must be a number");if(e.ratio<0||e.ratio>100)throw new Error("`ratio` must be in a 0-100 interval");if(e.ratio=e.ratio||90,e.accept&&typeof e.accept!="string")throw new Error("`accept` must be a string with a list of allowed mime-types");if(e.accept=e.accept||"*/*",e.multiple&&typeof e.multiple!="boolean")throw new Error("`multiple` must be a true or false");if(e.multiple=e.multiple||!1,e.fieldName&&typeof e.fieldName!="string")throw new Error("`fieldName` must be a string");return e.fieldName=e.fieldName||"files",e},h=function(e){switch(e.method){case"GET":var n=p(e.data,t.URLENCODED);delete e.data,e.url=/\?/.test(e.url)?e.url+"&"+n:e.url+"?"+n;break;case"POST":case"PUT":case"DELETE":case"UPDATE":var u=function(){return(arguments.length>0&&arguments[0]!==void 0?arguments[0]:{}).type||t.JSON}(e);(b.isFormData(e.data)||b.isFormElement(e.data))&&(u=t.FORM),e.data=p(e.data,u),u!==w.contentType.FORM&&(e.headers["content-type"]=u)}return e},p=function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};switch(arguments.length>1?arguments[1]:void 0){case t.URLENCODED:return b.urlEncode(e);case t.JSON:return b.jsonEncode(e);case t.FORM:return b.formEncode(e);default:return e}},v=function(e){return e>=200&&e<300},{contentType:t={URLENCODED:"application/x-www-form-urlencoded; charset=utf-8",FORM:"multipart/form-data",JSON:"application/json; charset=utf-8"},request:c,get:function(e){return e.method="GET",c(e)},post:g,transport:function(e){return e=a(e),b.selectFiles(e).then(function(n){for(var u=new FormData,l=0;l=0&&(a._idleTimeoutId=setTimeout(function(){a._onTimeout&&a._onTimeout()},h))},o(6),d.setImmediate=typeof self<"u"&&self.setImmediate||i!==void 0&&i.setImmediate||this&&this.setImmediate,d.clearImmediate=typeof self<"u"&&self.clearImmediate||i!==void 0&&i.clearImmediate||this&&this.clearImmediate}).call(this,o(0))},function(s,d,o){(function(i,t){(function(c,g){if(!c.setImmediate){var a,h,p,v,b,w=1,e={},n=!1,u=c.document,l=Object.getPrototypeOf&&Object.getPrototypeOf(c);l=l&&l.setTimeout?l:c,{}.toString.call(c.process)==="[object process]"?a=function(f){t.nextTick(function(){m(f)})}:function(){if(c.postMessage&&!c.importScripts){var f=!0,_=c.onmessage;return c.onmessage=function(){f=!1},c.postMessage("","*"),c.onmessage=_,f}}()?(v="setImmediate$"+Math.random()+"$",b=function(f){f.source===c&&typeof f.data=="string"&&f.data.indexOf(v)===0&&m(+f.data.slice(v.length))},c.addEventListener?c.addEventListener("message",b,!1):c.attachEvent("onmessage",b),a=function(f){c.postMessage(v+f,"*")}):c.MessageChannel?((p=new MessageChannel).port1.onmessage=function(f){m(f.data)},a=function(f){p.port2.postMessage(f)}):u&&"onreadystatechange"in u.createElement("script")?(h=u.documentElement,a=function(f){var _=u.createElement("script");_.onreadystatechange=function(){m(f),_.onreadystatechange=null,h.removeChild(_),_=null},h.appendChild(_)}):a=function(f){setTimeout(m,0,f)},l.setImmediate=function(f){typeof f!="function"&&(f=new Function(""+f));for(var _=new Array(arguments.length-1),S=0;S<_.length;S++)_[S]=arguments[S+1];var x={callback:f,args:_};return e[w]=x,a(w),w++},l.clearImmediate=y}function y(f){delete e[f]}function m(f){if(n)setTimeout(m,0,f);else{var _=e[f];if(_){n=!0;try{(function(S){var x=S.callback,T=S.args;switch(T.length){case 0:x();break;case 1:x(T[0]);break;case 2:x(T[0],T[1]);break;case 3:x(T[0],T[1],T[2]);break;default:x.apply(g,T)}})(_)}finally{y(f),n=!1}}}}})(typeof self>"u"?i===void 0?this:i:self)}).call(this,o(0),o(7))},function(s,d){var o,i,t=s.exports={};function c(){throw new Error("setTimeout has not been defined")}function g(){throw new Error("clearTimeout has not been defined")}function a(l){if(o===setTimeout)return setTimeout(l,0);if((o===c||!o)&&setTimeout)return o=setTimeout,setTimeout(l,0);try{return o(l,0)}catch{try{return o.call(null,l,0)}catch{return o.call(this,l,0)}}}(function(){try{o=typeof setTimeout=="function"?setTimeout:c}catch{o=c}try{i=typeof clearTimeout=="function"?clearTimeout:g}catch{i=g}})();var h,p=[],v=!1,b=-1;function w(){v&&h&&(v=!1,h.length?p=h.concat(p):b=-1,p.length&&e())}function e(){if(!v){var l=a(w);v=!0;for(var y=p.length;y;){for(h=p,p=[];++b1)for(var m=1;m HTMLElement")}},{key:"isObject",value:function(p){return Object.prototype.toString.call(p)==="[object Object]"}},{key:"isFormData",value:function(p){return p instanceof FormData}},{key:"isFormElement",value:function(p){return p instanceof HTMLFormElement}},{key:"selectFiles",value:function(){var p=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};return new Promise(function(v,b){var w=document.createElement("INPUT");w.type="file",p.multiple&&w.setAttribute("multiple","multiple"),p.accept&&w.setAttribute("accept",p.accept),w.style.display="none",document.body.appendChild(w),w.addEventListener("change",function(e){var n=e.target.files;v(n),document.body.removeChild(w)},!1),w.click()})}},{key:"parseHeaders",value:function(p){var v=p.trim().split(/[\r\n]+/),b={};return v.forEach(function(w){var e=w.split(": "),n=e.shift(),u=e.join(": ");n&&(b[n]=u)}),b}}],(a=null)&&i(g.prototype,a),h&&i(g,h),c}()},function(s,d){var o=function(t){return encodeURIComponent(t).replace(/[!'()*]/g,escape).replace(/%20/g,"+")},i=function(t,c,g,a){return c=c||null,g=g||"&",a=a||null,t?function(h){for(var p=new Array,v=0;v{let t=0;for(var c=0;c{d(p,a)}).catch(p=>{o(p,a)})}})}uploadByFile(r){const s=new FormData;return s.append(this.config.field,r),this.config.additionalRequestData&&Object.keys(this.config.additionalRequestData).length&&Object.entries(this.config.additionalRequestData).forEach(([d,o])=>{s.append(d,o)}),j.post({url:this.config.endpoints.byFile,data:s,type:j.contentType.JSON,headers:this.config.additionalRequestHeaders}).then(d=>d.body)}}function Z(E){return E&&typeof E.then=="function"}/** 4 | * Image Gallery Tool for the Editor.js 5 | * 6 | * @author Igor Shuvalov «VolgaIgor» 7 | * @license MIT 8 | * @see {@link https://github.com/VolgaIgor/editorjs-gallery} 9 | * 10 | * To developers. 11 | * To simplify Tool structure, we split it to 4 parts: 12 | * 1) index.js — main Tool's interface, public API and methods for working with data 13 | * 2) uploader.js — module that has methods for sending files via AJAX: from device, by URL or File pasting 14 | * 3) ui.js — module for UI manipulations: render, showing preloader, etc 15 | * 4) tunes.js — working with Block Tunes: render buttons, handle clicks 16 | * 17 | * For debug purposes there is a testing server 18 | * that can save uploaded files and return a Response {@link UploadResponseFormat} 19 | * 20 | * $ node dev/server.js 21 | * 22 | * It will expose 8008 port, so you can pass http://localhost:8008 with the Tools config: 23 | * 24 | * gallery: { 25 | * class: ImageGallery, 26 | * config: { 27 | * endpoints: { 28 | * byFile: 'http://localhost:8008/uploadFile', 29 | * } 30 | * }, 31 | * }, 32 | */class N{static get isReadOnlySupported(){return!0}static get toolbox(){return{icon:H,title:"Gallery"}}constructor({data:r,config:s,api:d,readOnly:o}){this.api=d,this.readOnly=o,this.config={endpoints:s.endpoints||"",additionalRequestData:s.additionalRequestData||{},additionalRequestHeaders:s.additionalRequestHeaders||{},field:s.field||"image",types:s.types||"image/*",buttonContent:s.buttonContent||"",uploader:s.uploader||void 0,actions:s.actions||void 0,maxElementCount:s.maxElementCount||void 0,sortableJs:s.sortableJs},this.uploader=new A({config:this.config}),this.ui=new k({api:d,config:this.config,onSelectFile:()=>{let i=this.config.maxElementCount?this.config.maxElementCount-this._data.files.length:null;this.uploader.uploadSelectedFiles(i,{onPreview:t=>this.ui.getPreloader(t),onUpload:(t,c)=>{this.onUpload(t,c)},onError:(t,c)=>{this.uploadingFailed(t,c)}})},onDeleteFile:i=>{this.deleteImage(i)},onMoveFile:(i,t)=>{this.moveImage(i,t)},readOnly:o}),this.tunes=new O({api:d,actions:this.config.actions,onChange:i=>this.styleToggled(i)}),this._data={},this.data=r}render(){return this.ui.render(this.data)}rendered(){return this.checkMaxElemCount(),this.ui.onRendered()}validate(r){return!(!r.files||!r.files.length)}save(){const r=this.ui.nodes.caption;return this._data.caption=r.innerHTML,this.data}renderSettings(){return this.tunes.render(this.data)}appendImage(r){if(r&&r.url){if(this.config.maxElementCount&&this._data.files.length>=this.config.maxElementCount)return;this._data.files.push(r),this.ui.appendImage(r),this.checkMaxElemCount()}}moveImage(r,s){s>=this._data.files.length&&(s=this._data.files.length-1),this._data.files.splice(s,0,this._data.files.splice(r,1)[0])}deleteImage(r){this._data.files[r]!==void 0&&(this._data.files.splice(r,1),this.checkMaxElemCount())}set data(r){this._data.files=[],r.files&&r.files.forEach(d=>{this.appendImage(d)}),this._data.caption=r.caption||"",this.ui.fillCaption(this._data.caption);let s=r.style||"";this.styleToggled(s)}get data(){return this._data}onUpload(r,s){this.ui.removePreloader(s),r.success&&r.file?this.appendImage(r.file):this.uploadingFailed("incorrect response: "+JSON.stringify(r))}uploadingFailed(r,s){this.ui.removePreloader(s),console.log("Image Tool: uploading failed because of",r),this.api.notifier.show({message:this.api.i18n.t("Couldn’t upload image. Please try another."),style:"error"})}styleToggled(r){r==="fit"?this._data.style="fit":this._data.style="slider"}checkMaxElemCount(){this.ui.updateLimitCounter(this._data.files.length,this.config.maxElementCount),this.config.maxElementCount&&this._data.files.length>=this.config.maxElementCount?this.ui.hideFileButton():this.ui.showFileButton()}}return N}); 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@kiberpro/editorjs-gallery", 3 | "version": "1.3.0", 4 | "keywords": [ 5 | "codex editor", 6 | "tool", 7 | "image", 8 | "gallery", 9 | "editor.js", 10 | "editorjs" 11 | ], 12 | "description": "Image Gallery Tool with source field for Editor.js", 13 | "license": "MIT", 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/VolgaIgor/editorjs-gallery.git" 17 | }, 18 | "files": [ 19 | "dist" 20 | ], 21 | "main": "./dist/gallery.umd.js", 22 | "module": "./dist/gallery.mjs", 23 | "exports": { 24 | ".": { 25 | "import": "./dist/gallery.mjs", 26 | "require": "./dist/gallery.umd.js" 27 | } 28 | }, 29 | "scripts": { 30 | "dev": "vite", 31 | "build": "vite build", 32 | "lint": "eslint src/ --ext .js", 33 | "lint:errors": "eslint src/ --ext .js --quiet", 34 | "lint:fix": "eslint src/ --ext .js --fix" 35 | }, 36 | "author": "Igor Shuvalov «VolgaIgor» & CodeX", 37 | "devDependencies": { 38 | "@codexteam/ajax": "^4.2.0", 39 | "eslint": "^6.8.0", 40 | "eslint-config-codex": "^1.3.3", 41 | "eslint-loader": "^4.0.0", 42 | "formidable": "^1.2.1", 43 | "postcss-nested": "^4.1.0", 44 | "postcss-nested-ancestors": "^2.0.0", 45 | "request": "^2.88.0", 46 | "vite": "^4.5.0", 47 | "vite-plugin-css-injected-by-js": "^3.3.0" 48 | }, 49 | "dependencies": { 50 | "@codexteam/icons": "^0.0.6" 51 | }, 52 | "bugs": { 53 | "url": "https://github.com/VolgaIgor/editorjs-gallery/issues" 54 | }, 55 | "homepage": "https://github.com/VolgaIgor/editorjs-gallery#readme" 56 | } 57 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-nested-ancestors'), 4 | require('postcss-nested'), 5 | ], 6 | }; 7 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Image Gallery Tool for the Editor.js 3 | * 4 | * @author Igor Shuvalov «VolgaIgor» 5 | * @license MIT 6 | * @see {@link https://github.com/VolgaIgor/editorjs-gallery} 7 | * 8 | * To developers. 9 | * To simplify Tool structure, we split it to 4 parts: 10 | * 1) index.js — main Tool's interface, public API and methods for working with data 11 | * 2) uploader.js — module that has methods for sending files via AJAX: from device, by URL or File pasting 12 | * 3) ui.js — module for UI manipulations: render, showing preloader, etc 13 | * 4) tunes.js — working with Block Tunes: render buttons, handle clicks 14 | * 15 | * For debug purposes there is a testing server 16 | * that can save uploaded files and return a Response {@link UploadResponseFormat} 17 | * 18 | * $ node dev/server.js 19 | * 20 | * It will expose 8008 port, so you can pass http://localhost:8008 with the Tools config: 21 | * 22 | * gallery: { 23 | * class: ImageGallery, 24 | * config: { 25 | * endpoints: { 26 | * byFile: 'http://localhost:8008/uploadFile', 27 | * } 28 | * }, 29 | * }, 30 | */ 31 | 32 | /** 33 | * @typedef {object} ImageGalleryDataFile 34 | * @description Image Gallery Tool's files data format 35 | * @property {string} url — image URL 36 | */ 37 | 38 | /** 39 | * @typedef {object} ImageGalleryData 40 | * @description Image Tool's input and output data format 41 | * @property {boolean} style - slider or fit 42 | * @property {string} caption — gallery caption 43 | * @property {ImageGalleryDataFile[]} files — Image file data returned from backend 44 | */ 45 | 46 | // eslint-disable-next-line 47 | import css from './index.pcss'; 48 | import Ui from './ui'; 49 | import Tunes from './tunes'; 50 | import ToolboxIcon from './svg/toolbox.svg?raw'; 51 | import Uploader from './uploader'; 52 | 53 | /** 54 | * @typedef {object} ImageConfig 55 | * @description Config supported by Tool 56 | * @property {object} endpoints - upload endpoints 57 | * @property {string} endpoints.byFile - upload by file 58 | * @property {string} field - field name for uploaded image 59 | * @property {string} types - available mime-types 60 | * @property {object} additionalRequestData - any data to send with requests 61 | * @property {object} additionalRequestHeaders - allows to pass custom headers with Request 62 | * @property {string} buttonContent - overrides for Select File button 63 | * @property {object} [uploader] - optional custom uploader 64 | * @property {function(File): Promise.} [uploader.uploadByFile] - method that upload image by File 65 | */ 66 | 67 | /** 68 | * @typedef {object} UploadResponseFormat 69 | * @description This format expected from backend on file uploading 70 | * @property {number} success - 1 for successful uploading, 0 for failure 71 | * @property {object} file - Object with file data. 72 | * 'url' is required, 73 | * also can contain any additional data that will be saved and passed back 74 | * @property {string} file.url - [Required] image source URL 75 | */ 76 | export default class ImageGallery { 77 | /** 78 | * Notify core that read-only mode is supported 79 | * 80 | * @returns {boolean} 81 | */ 82 | static get isReadOnlySupported() { 83 | return true; 84 | } 85 | 86 | /** 87 | * Get Tool toolbox settings 88 | * icon - Tool icon's SVG 89 | * title - title to show in toolbox 90 | * 91 | * @returns {{icon: string, title: string}} 92 | */ 93 | static get toolbox() { 94 | return { 95 | icon: ToolboxIcon, 96 | title: 'Gallery', 97 | }; 98 | } 99 | 100 | /** 101 | * @param {object} tool - tool properties got from editor.js 102 | * @param {ImageGalleryData} tool.data - previously saved data 103 | * @param {ImageConfig} tool.config - user config for Tool 104 | * @param {object} tool.api - Editor.js API 105 | * @param {boolean} tool.readOnly - read-only mode flag 106 | */ 107 | constructor({ data, config, api, readOnly }) { 108 | this.api = api; 109 | this.readOnly = readOnly; 110 | 111 | /** 112 | * Tool's initial config 113 | */ 114 | this.config = { 115 | endpoints: config.endpoints || '', 116 | additionalRequestData: config.additionalRequestData || {}, 117 | additionalRequestHeaders: config.additionalRequestHeaders || {}, 118 | field: config.field || 'image', 119 | types: config.types || 'image/*', 120 | buttonContent: config.buttonContent || '', 121 | uploader: config.uploader || undefined, 122 | actions: config.actions || undefined, 123 | maxElementCount: config.maxElementCount || undefined, 124 | sortableJs: config.sortableJs, 125 | }; 126 | 127 | /** 128 | * Module for file uploading 129 | */ 130 | this.uploader = new Uploader({ 131 | config: this.config, 132 | }); 133 | 134 | /** 135 | * Module for working with UI 136 | */ 137 | this.ui = new Ui({ 138 | api, 139 | config: this.config, 140 | onSelectFile: () => { 141 | let maxElementCount = (this.config.maxElementCount) ? this.config.maxElementCount - this._data.files.length : null; 142 | this.uploader.uploadSelectedFiles(maxElementCount, { 143 | onPreview: (file) => { 144 | return this.ui.getPreloader(file); 145 | }, 146 | onUpload: (response, previewElem) => { 147 | this.onUpload(response, previewElem); 148 | }, 149 | onError: (error, previewElem) => { 150 | this.uploadingFailed(error, previewElem); 151 | }, 152 | }); 153 | }, 154 | onDeleteFile: (id) => { 155 | this.deleteImage(id); 156 | }, 157 | onMoveFile: (oldId, newId) => { 158 | this.moveImage(oldId, newId); 159 | }, 160 | readOnly, 161 | }); 162 | 163 | /** 164 | * Module for working with tunes 165 | */ 166 | this.tunes = new Tunes({ 167 | api, 168 | actions: this.config.actions, 169 | onChange: (styleName) => this.styleToggled(styleName), 170 | }); 171 | 172 | /** 173 | * Set saved state 174 | */ 175 | this._data = {}; 176 | this.data = data; 177 | } 178 | 179 | /** 180 | * Renders Block content 181 | * 182 | * @public 183 | * 184 | * @returns {HTMLDivElement} 185 | */ 186 | render() { 187 | return this.ui.render(this.data); 188 | } 189 | 190 | rendered() { 191 | this.checkMaxElemCount(); 192 | 193 | return this.ui.onRendered(); 194 | } 195 | 196 | /** 197 | * Validate data: check if Image exists 198 | * 199 | * @param {ImageGalleryData} savedData — data received after saving 200 | * @returns {boolean} false if saved data is not correct, otherwise true 201 | * @public 202 | */ 203 | validate(savedData) { 204 | if (!savedData.files || !savedData.files.length) { 205 | return false; 206 | } 207 | 208 | return true; 209 | } 210 | 211 | /** 212 | * Return Block data 213 | * 214 | * @public 215 | * 216 | * @returns {ImageGalleryData} 217 | */ 218 | save() { 219 | const caption = this.ui.nodes.caption; 220 | 221 | this._data.caption = caption.innerHTML; 222 | 223 | return this.data; 224 | } 225 | 226 | /** 227 | * Makes buttons with tunes 228 | * 229 | * @public 230 | * 231 | * @returns {Element} 232 | */ 233 | renderSettings() { 234 | return this.tunes.render(this.data); 235 | } 236 | 237 | /** 238 | * Set new image file 239 | * 240 | * @private 241 | * 242 | * @param {ImageGalleryDataFile} file - uploaded file data 243 | */ 244 | appendImage(file) { 245 | if (file && file.url) { 246 | if (this.config.maxElementCount && this._data.files.length >= this.config.maxElementCount) { 247 | return; 248 | } 249 | 250 | this._data.files.push(file); 251 | this.ui.appendImage(file); 252 | 253 | this.checkMaxElemCount(); 254 | } 255 | } 256 | 257 | /** 258 | * Move image file 259 | * 260 | * @private 261 | * 262 | * @param {integer} from - target image old index 263 | * @param {integer} to - target image new index 264 | */ 265 | moveImage(from, to) { 266 | if (to >= this._data.files.length) { 267 | to = this._data.files.length - 1; 268 | } 269 | this._data.files.splice(to, 0, this._data.files.splice(from, 1)[0]); 270 | } 271 | 272 | /** 273 | * Delete image file 274 | * 275 | * @private 276 | * 277 | * @param {integer} id - image index 278 | */ 279 | deleteImage(id) { 280 | if (this._data.files[id] !== undefined) { 281 | this._data.files.splice(id, 1); 282 | 283 | this.checkMaxElemCount(); 284 | } 285 | } 286 | 287 | /** 288 | * Private methods 289 | * ̿̿ ̿̿ ̿̿ ̿'̿'\̵͇̿̿\з= ( ▀ ͜͞ʖ▀) =ε/̵͇̿̿/’̿’̿ ̿ ̿̿ ̿̿ ̿̿ 290 | */ 291 | 292 | /** 293 | * Stores all Tool's data 294 | * 295 | * @private 296 | * 297 | * @param {ImageGalleryData} data - data in Image Tool format 298 | */ 299 | set data(data) { 300 | this._data.files = []; 301 | if (data.files) { 302 | data.files.forEach(file => { 303 | this.appendImage(file); 304 | }); 305 | } 306 | 307 | this._data.caption = data.caption || ''; 308 | this.ui.fillCaption(this._data.caption); 309 | 310 | let style = data.style || ''; 311 | this.styleToggled(style); 312 | } 313 | 314 | /** 315 | * Return Tool data 316 | * 317 | * @private 318 | * 319 | * @returns {ImageGalleryData} 320 | */ 321 | get data() { 322 | return this._data; 323 | } 324 | 325 | /** 326 | * File uploading callback 327 | * 328 | * @private 329 | * 330 | * @param {UploadResponseFormat} response - uploading server response 331 | * @returns {void} 332 | */ 333 | onUpload(response, previewElem) { 334 | this.ui.removePreloader(previewElem); 335 | if (response.success && response.file) { 336 | this.appendImage(response.file); 337 | } else { 338 | this.uploadingFailed('incorrect response: ' + JSON.stringify(response)); 339 | } 340 | } 341 | 342 | /** 343 | * Handle uploader errors 344 | * 345 | * @private 346 | * @param {string} errorText - uploading error text 347 | * @returns {void} 348 | */ 349 | uploadingFailed(errorText, previewElem) { 350 | this.ui.removePreloader(previewElem); 351 | 352 | console.log('Image Tool: uploading failed because of', errorText); 353 | 354 | this.api.notifier.show({ 355 | message: this.api.i18n.t('Couldn’t upload image. Please try another.'), 356 | style: 'error', 357 | }); 358 | } 359 | 360 | /** 361 | * Callback fired when Block Tune is activated 362 | * 363 | * @private 364 | * 365 | * @param {string} tuneName - tune that has been clicked 366 | * @returns {void} 367 | */ 368 | styleToggled(tuneName) { 369 | if (tuneName === 'fit') { 370 | this._data.style = 'fit'; 371 | } else { 372 | this._data.style = 'slider'; 373 | } 374 | } 375 | 376 | checkMaxElemCount() { 377 | this.ui.updateLimitCounter(this._data.files.length, this.config.maxElementCount); 378 | 379 | if (this.config.maxElementCount && this._data.files.length >= this.config.maxElementCount) { 380 | this.ui.hideFileButton(); 381 | } else { 382 | this.ui.showFileButton(); 383 | } 384 | } 385 | } 386 | -------------------------------------------------------------------------------- /src/index.pcss: -------------------------------------------------------------------------------- 1 | .image-gallery { 2 | --bg-color: #cdd1e0; 3 | --front-color: #388ae5; 4 | --border-color: #e8e8eb; 5 | 6 | &__container { 7 | background: black; 8 | margin-bottom: 10px; 9 | padding: 5px; 10 | } 11 | 12 | &__controls { 13 | display: flex; 14 | gap: 10px; 15 | padding: 8px 2px 3px; 16 | } 17 | 18 | &__items { 19 | display: grid; 20 | gap: 10px; 21 | grid-template-columns: 1fr 1fr 1fr; 22 | padding: 10px; 23 | background-color: #222222; 24 | } 25 | 26 | &__items:empty { 27 | display: none; 28 | } 29 | 30 | &__preloaders { 31 | display: flex; 32 | flex-grow: 1; 33 | flex-wrap: nowrap; 34 | padding: 5px; 35 | gap: 8px; 36 | overflow: hidden; 37 | } 38 | 39 | &__preloader { 40 | min-width: 30px; 41 | height: 30px; 42 | border-radius: 50%; 43 | background-size: cover; 44 | position: relative; 45 | background-color: var(--bg-color); 46 | background-position: center center; 47 | 48 | &::after { 49 | content: ""; 50 | position: absolute; 51 | z-index: 3; 52 | width: 30px; 53 | height: 30px; 54 | border-radius: 50%; 55 | border: 2px solid var(--bg-color); 56 | border-top-color: var(--front-color); 57 | left: 50%; 58 | top: 50%; 59 | margin-top: -15px; 60 | margin-left: -15px; 61 | animation: image-preloader-spin 2s infinite linear; 62 | box-sizing: border-box; 63 | } 64 | } 65 | 66 | .sortable &__image { 67 | cursor: move; 68 | } 69 | 70 | &__image { 71 | position: relative; 72 | overflow: hidden; 73 | aspect-ratio: 16 / 9; 74 | user-select: none; 75 | background-color: black; 76 | border-radius: 3px; 77 | padding: 5px; 78 | 79 | &.sortable-ghost { 80 | opacity: .75; 81 | } 82 | 83 | &--empty, 84 | &--loading { 85 | display: none; 86 | } 87 | 88 | &-picture { 89 | border-radius: 3px; 90 | max-width: 100%; 91 | height: 100%; 92 | display: block; 93 | margin: auto; 94 | object-fit: cover; 95 | pointer-events: none; 96 | } 97 | 98 | &-trash { 99 | position: absolute; 100 | top: 3px; 101 | right: 3px; 102 | cursor: pointer; 103 | color: #fff; 104 | font-size: 18px; 105 | background-color: rgba(0, 0, 0, .25); 106 | line-height: 1; 107 | padding: 6px 8px; 108 | border-radius: 3px; 109 | transition: background-color .1s; 110 | 111 | &:hover { 112 | background-color: rgba(0, 0, 0, .5); 113 | } 114 | } 115 | } 116 | 117 | &__counter { 118 | display: flex; 119 | align-items: center; 120 | color: gray; 121 | font-size: 14px; 122 | margin-right: 6px; 123 | } 124 | 125 | &__caption { 126 | &[contentEditable="true"][data-placeholder]::before { 127 | position: absolute !important; 128 | content: attr(data-placeholder); 129 | color: #707684; 130 | font-weight: normal; 131 | display: none; 132 | } 133 | 134 | &[contentEditable="true"][data-placeholder]:empty { 135 | &::before { 136 | display: block; 137 | } 138 | 139 | &:focus::before { 140 | display: none; 141 | } 142 | } 143 | } 144 | 145 | &__caption { 146 | margin-bottom: 10px; 147 | } 148 | 149 | .cdx-button { 150 | height: 40px; 151 | display: flex; 152 | align-items: center; 153 | justify-content: center; 154 | padding: 12px; 155 | gap: 5px; 156 | white-space: nowrap; 157 | } 158 | 159 | /** 160 | * Tunes 161 | * ---------------- 162 | */ 163 | 164 | &__tune-wrapper { 165 | display: flex; 166 | gap: 6px; 167 | margin: 6px 0; 168 | 169 | &:first-child { 170 | margin-top: 0; 171 | } 172 | 173 | &:last-child { 174 | margin-bottom: 0; 175 | } 176 | } 177 | 178 | &__tune { 179 | flex-grow: 1; 180 | padding: 6px; 181 | color: var(--color-text-primary); 182 | display: flex; 183 | align-items: center; 184 | justify-content: center; 185 | 186 | &.active { 187 | background: var(--color-background-icon-active); 188 | color: var(--color-text-icon-active); 189 | border-color: var(--color-text-icon-active); 190 | } 191 | 192 | & svg { 193 | width: 24px; 194 | height: 24px; 195 | } 196 | } 197 | } 198 | 199 | @keyframes image-preloader-spin { 200 | 0% { 201 | transform: rotate(0deg); 202 | } 203 | 204 | 100% { 205 | transform: rotate(360deg); 206 | } 207 | } -------------------------------------------------------------------------------- /src/svg/fit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/svg/slider.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/svg/toolbox.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/tunes.js: -------------------------------------------------------------------------------- 1 | import { make } from './ui'; 2 | import sliderIcon from './svg/slider.svg?raw'; 3 | import fitIcon from './svg/fit.svg?raw'; 4 | 5 | /** 6 | * Working with Block Tunes 7 | */ 8 | export default class Tunes { 9 | /** 10 | * @param {object} tune - image tool Tunes managers 11 | * @param {object} tune.api - Editor API 12 | * @param {object} tune.actions - list of user defined tunes 13 | * @param {Function} tune.onChange - tune toggling callback 14 | */ 15 | constructor({ api, actions, onChange }) { 16 | this.api = api; 17 | this.actions = actions; 18 | this.onChange = onChange; 19 | this.buttons = []; 20 | } 21 | 22 | /** 23 | * Available Image tunes 24 | * 25 | * @returns {{name: string, icon: string, title: string}[]} 26 | */ 27 | static get tunes() { 28 | return [ 29 | { 30 | name: 'slider', 31 | icon: sliderIcon, 32 | title: 'Slider', 33 | }, 34 | { 35 | name: 'fit', 36 | icon: fitIcon, 37 | title: 'Fit', 38 | }, 39 | ]; 40 | } 41 | 42 | /** 43 | * Styles 44 | * 45 | * @returns {{wrapper: string, buttonBase: *, button: string, buttonActive: *}} 46 | */ 47 | get CSS() { 48 | return { 49 | wrapper: 'image-gallery__tune-wrapper', 50 | buttonBase: this.api.styles.button, 51 | button: 'image-gallery__tune', 52 | buttonActive: 'active', 53 | }; 54 | } 55 | 56 | /** 57 | * Makes buttons with tunes 58 | * 59 | * @param {ImageGalleryData} toolData - generate Elements of tunes 60 | * @returns {Element} 61 | */ 62 | render(toolData) { 63 | const wrapper = make('div', this.CSS.wrapper); 64 | 65 | const tunes = this.actions ?? Tunes.tunes; 66 | 67 | this.buttons = []; 68 | 69 | tunes.forEach(tune => { 70 | const title = this.api.i18n.t(tune.title); 71 | const el = make('div', [this.CSS.buttonBase, this.CSS.button], { 72 | innerHTML: tune.icon, 73 | title, 74 | }); 75 | 76 | el.addEventListener('click', () => { 77 | this.tuneClicked(tune.name, tune.action); 78 | }); 79 | 80 | el.dataset.tune = tune.name; 81 | el.classList.toggle(this.CSS.buttonActive, toolData.style === tune.name); 82 | 83 | this.buttons.push(el); 84 | 85 | this.api.tooltip.onHover(el, title, { 86 | placement: 'top', 87 | }); 88 | 89 | wrapper.appendChild(el); 90 | }); 91 | 92 | return wrapper; 93 | } 94 | 95 | /** 96 | * Clicks to one of the tunes 97 | * 98 | * @param {string} tuneName - clicked tune name 99 | * @param {Function} customFunction - function to execute on click 100 | */ 101 | tuneClicked(tuneName, customFunction) { 102 | if (typeof customFunction === 'function') { 103 | if (!customFunction(tuneName)) { 104 | return false; 105 | } 106 | } 107 | 108 | this.buttons.forEach(button => { 109 | button.classList.toggle(this.CSS.buttonActive, button.dataset.tune === tuneName); 110 | }); 111 | 112 | this.onChange(tuneName); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/ui.js: -------------------------------------------------------------------------------- 1 | import { IconPicture, IconTrash } from '@codexteam/icons' 2 | 3 | /** 4 | * Class for working with UI: 5 | * - rendering base structure 6 | * - show/hide preview 7 | * - apply tune view 8 | */ 9 | export default class Ui { 10 | /** 11 | * @param {object} ui - image tool Ui module 12 | * @param {object} ui.api - Editor.js API 13 | * @param {ImageConfig} ui.config - user config 14 | * @param {Function} ui.onSelectFile - callback for clicks on Select file button 15 | * @param {boolean} ui.readOnly - read-only mode flag 16 | */ 17 | constructor({ api, config, onSelectFile, onDeleteFile, onMoveFile, readOnly }) { 18 | this.api = api; 19 | this.config = config; 20 | this.onSelectFile = onSelectFile; 21 | this.onDeleteFile = onDeleteFile; 22 | this.onMoveFile = onMoveFile; 23 | this.readOnly = readOnly; 24 | this.nodes = { 25 | wrapper: make('div', [this.CSS.baseClass, this.CSS.wrapper]), 26 | fileButton: this.createFileButton(), 27 | container: make('div', this.CSS.container), 28 | itemsContainer: make('div', this.CSS.itemsContainer), 29 | controls: make('div', this.CSS.controls), 30 | preloaderContainer: make('div', this.CSS.preloaderContainer), 31 | caption: make('div', [this.CSS.input, this.CSS.caption], { 32 | contentEditable: !this.readOnly, 33 | }), 34 | }; 35 | 36 | /** 37 | * Create base structure 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | */ 52 | this.nodes.caption.dataset.placeholder = this.api.i18n.t('Gallery caption'); 53 | 54 | if (!this.readOnly) { 55 | this.nodes.controls.appendChild(this.nodes.preloaderContainer); 56 | if (this.config.maxElementCount) { 57 | this.nodes.limitCounter = make('div', this.CSS.limitCounter); 58 | this.nodes.controls.appendChild(this.nodes.limitCounter); 59 | } 60 | this.nodes.controls.appendChild(this.nodes.fileButton); 61 | } 62 | 63 | this.nodes.container.appendChild(this.nodes.itemsContainer); 64 | if (!this.readOnly) { 65 | this.nodes.container.appendChild(this.nodes.controls); 66 | } 67 | 68 | this.nodes.wrapper.appendChild(this.nodes.container); 69 | 70 | if (!this.readOnly) { 71 | this.nodes.wrapper.appendChild(this.nodes.caption); 72 | } 73 | 74 | ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { 75 | this.nodes.itemsContainer.addEventListener(eventName, function (e) { 76 | e.preventDefault(); 77 | e.stopPropagation(); 78 | }, false); 79 | }); 80 | } 81 | 82 | /** 83 | * CSS classes 84 | * 85 | * @returns {object} 86 | */ 87 | get CSS() { 88 | return { 89 | baseClass: this.api.styles.block, 90 | loading: this.api.styles.loader, 91 | input: this.api.styles.input, 92 | button: this.api.styles.button, 93 | 94 | /** 95 | * Tool's classes 96 | */ 97 | wrapper: 'image-gallery', 98 | container: 'image-gallery__container', 99 | controls: 'image-gallery__controls', 100 | limitCounter: 'image-gallery__counter', 101 | itemsContainer: 'image-gallery__items', 102 | imageContainer: 'image-gallery__image', 103 | preloaderContainer: 'image-gallery__preloaders', 104 | imagePreloader: 'image-gallery__preloader', 105 | imageEl: 'image-gallery__image-picture', 106 | trashButton: 'image-gallery__image-trash', 107 | caption: 'image-gallery__caption', 108 | }; 109 | }; 110 | 111 | /** 112 | * Ui statuses: 113 | * - empty 114 | * - uploading 115 | * - filled 116 | * 117 | * @returns {{EMPTY: string, UPLOADING: string, FILLED: string}} 118 | */ 119 | static get status() { 120 | return { 121 | EMPTY: 'empty', 122 | UPLOADING: 'loading', 123 | FILLED: 'filled', 124 | }; 125 | } 126 | 127 | /** 128 | * Renders tool UI 129 | * 130 | * @param {ImageGalleryData} toolData - saved tool data 131 | * @returns {Element} 132 | */ 133 | render(toolData) { 134 | return this.nodes.wrapper; 135 | } 136 | 137 | onRendered() { 138 | if (!this.readOnly && !this.sortable) { 139 | this.sortable = new this.config.sortableJs(this.nodes.itemsContainer, { 140 | handle: `.${this.CSS.imageContainer}`, 141 | filter: `.${this.CSS.trashButton}`, 142 | onStart: () => { 143 | this.nodes.itemsContainer.classList.add(`${this.CSS.itemsContainer}--drag`); 144 | }, 145 | onEnd: (evt) => { 146 | this.nodes.itemsContainer.classList.remove(`${this.CSS.itemsContainer}--drag`); 147 | 148 | if (evt.oldIndex !== evt.newIndex) { 149 | this.onMoveFile(evt.oldIndex, evt.newIndex); 150 | } 151 | } 152 | }); 153 | 154 | this.nodes.itemsContainer.classList.add('sortable') 155 | } 156 | } 157 | 158 | /** 159 | * Creates upload-file button 160 | * 161 | * @returns {Element} 162 | */ 163 | createFileButton() { 164 | const button = make('div', [this.CSS.button]); 165 | 166 | button.innerHTML = this.config.buttonContent || `${IconPicture} ${this.api.i18n.t('Select an Image')}`; 167 | 168 | button.addEventListener('click', () => { 169 | this.onSelectFile(); 170 | }); 171 | 172 | return button; 173 | } 174 | 175 | /** 176 | * Shows uploading button 177 | * 178 | * @returns {void} 179 | */ 180 | showFileButton() { 181 | this.nodes.fileButton.style.display = ''; 182 | } 183 | 184 | /** 185 | * Hide uploading button 186 | * 187 | * @returns {void} 188 | */ 189 | hideFileButton() { 190 | this.nodes.fileButton.style.display = 'none'; 191 | } 192 | 193 | getPreloader(file) { 194 | /** 195 | * @type {HTMLElement} 196 | */ 197 | let preloader = make('div', this.CSS.imagePreloader); 198 | 199 | this.nodes.preloaderContainer.append(preloader); 200 | 201 | const reader = new FileReader(); 202 | reader.readAsDataURL(file); 203 | reader.onload = (e) => { 204 | preloader.style.backgroundImage = `url(${e.target.result})`; 205 | }; 206 | 207 | return preloader; 208 | } 209 | 210 | removePreloader(preloader) { 211 | preloader.remove(); 212 | } 213 | 214 | /** 215 | * Shows an image 216 | * 217 | * @param {ImageGalleryDataFile} file - image file object 218 | * @returns {void} 219 | */ 220 | appendImage(file) { 221 | let url = file.url; 222 | 223 | /** 224 | * Check for a source extension to compose element correctly: video tag for mp4, img — for others 225 | */ 226 | const tag = /\.mp4$/.test(url) ? 'VIDEO' : 'IMG'; 227 | 228 | const attributes = { 229 | src: url 230 | }; 231 | 232 | /** 233 | * We use eventName variable because IMG and VIDEO tags have different event to be called on source load 234 | * - IMG: load 235 | * - VIDEO: loadeddata 236 | * 237 | * @type {string} 238 | */ 239 | let eventName = 'load'; 240 | 241 | /** 242 | * Update attributes and eventName if source is a mp4 video 243 | */ 244 | if (tag === 'VIDEO') { 245 | /** 246 | * Add attributes for playing muted mp4 as a gif 247 | * 248 | * @type {boolean} 249 | */ 250 | attributes.autoplay = false; 251 | attributes.muted = true; 252 | attributes.playsinline = true; 253 | 254 | /** 255 | * Change event to be listened 256 | * 257 | * @type {string} 258 | */ 259 | eventName = 'loadeddata'; 260 | } 261 | 262 | /** 263 | * @type {Element} 264 | */ 265 | let imageContainer = make('div', [this.CSS.imageContainer]); 266 | 267 | /** 268 | * Compose tag with defined attributes 269 | * 270 | * @type {Element} 271 | */ 272 | let imageEl = make(tag, this.CSS.imageEl, attributes); 273 | 274 | /** 275 | * Add load event listener 276 | */ 277 | imageEl.addEventListener(eventName, () => { 278 | this.toggleStatus(imageContainer, Ui.status.FILLED); 279 | }); 280 | 281 | imageContainer.appendChild(imageEl); 282 | 283 | const title = this.api.i18n.t('Delete'); 284 | 285 | if (!this.readOnly) { 286 | /** 287 | * @type {Element} 288 | */ 289 | let imageTrash = make('div', [this.CSS.trashButton], { 290 | innerHTML: IconTrash, 291 | title, 292 | }); 293 | 294 | this.api.tooltip.onHover(imageTrash, title, { 295 | placement: 'top', 296 | }); 297 | 298 | imageTrash.addEventListener('click', () => { 299 | this.api.tooltip.hide(); 300 | 301 | let arrayChild = Array.prototype.slice.call(this.nodes.itemsContainer.children); 302 | let elIndex = arrayChild.indexOf(imageContainer); 303 | 304 | if (elIndex !== -1) { 305 | this.nodes.itemsContainer.removeChild(imageContainer); 306 | 307 | this.onDeleteFile(elIndex); 308 | } 309 | }); 310 | 311 | imageContainer.appendChild(imageTrash); 312 | } 313 | 314 | this.nodes.itemsContainer.append(imageContainer); 315 | } 316 | 317 | /** 318 | * Shows caption input 319 | * 320 | * @param {string} text - caption text 321 | * @returns {void} 322 | */ 323 | fillCaption(text) { 324 | if (this.nodes.caption) { 325 | this.nodes.caption.innerHTML = text; 326 | } 327 | } 328 | 329 | /** 330 | * Changes UI status 331 | * 332 | * @param {Element} elem 333 | * @param {string} status - see {@link Ui.status} constants 334 | * @returns {void} 335 | */ 336 | toggleStatus(elem, status) { 337 | for (const statusType in Ui.status) { 338 | if (Object.prototype.hasOwnProperty.call(Ui.status, statusType)) { 339 | elem.classList.toggle(`${this.CSS.imageContainer}--${Ui.status[statusType]}`, status === Ui.status[statusType]); 340 | } 341 | } 342 | } 343 | 344 | /** 345 | * @param {int} imageCount 346 | * @param {int|null} limitCounter 347 | * @returns {void} 348 | */ 349 | updateLimitCounter(imageCount, limitCounter) { 350 | if (limitCounter && this.nodes.limitCounter) { 351 | if (imageCount === 0) { 352 | this.nodes.limitCounter.style.display = 'none'; 353 | } else { 354 | this.nodes.limitCounter.style.display = null; 355 | this.nodes.limitCounter.innerText = `${imageCount} / ${limitCounter}`; 356 | } 357 | } 358 | } 359 | } 360 | 361 | /** 362 | * Helper for making Elements with attributes 363 | * 364 | * @param {string} tagName - new Element tag name 365 | * @param {Array|string} classNames - list or name of CSS class 366 | * @param {object} attributes - any attributes 367 | * @returns {Element} 368 | */ 369 | export const make = function make(tagName, classNames = null, attributes = {}) { 370 | const el = document.createElement(tagName); 371 | 372 | if (Array.isArray(classNames)) { 373 | el.classList.add(...classNames); 374 | } else if (classNames) { 375 | el.classList.add(classNames); 376 | } 377 | 378 | for (const attrName in attributes) { 379 | el[attrName] = attributes[attrName]; 380 | } 381 | 382 | return el; 383 | }; 384 | -------------------------------------------------------------------------------- /src/uploader.js: -------------------------------------------------------------------------------- 1 | import ajax from '@codexteam/ajax'; 2 | 3 | /** 4 | * Module for file uploading. Handle 3 scenarios: 5 | * 1. Select file from device and upload 6 | * 2. Upload by pasting URL 7 | * 3. Upload by pasting file from Clipboard or by Drag'n'Drop 8 | */ 9 | export default class Uploader { 10 | /** 11 | * @param {object} params - uploader module params 12 | * @param {ImageConfig} params.config - image tool config 13 | */ 14 | constructor({ config }) { 15 | this.config = config; 16 | } 17 | 18 | /** 19 | * Handle clicks on the upload file button 20 | */ 21 | uploadSelectedFiles(maxElementCount, { onPreview, onUpload, onError }) { 22 | ajax.selectFiles({ 23 | accept: this.config.types, 24 | multiple: true 25 | }).then((files) => { 26 | let loadedFiles = 0; 27 | for (var i = 0; i < files.length; i++) { 28 | if (maxElementCount !== null && loadedFiles == maxElementCount) { 29 | break; 30 | } else { 31 | loadedFiles++; 32 | } 33 | 34 | let file = files[i]; 35 | let previewElem = onPreview(file); 36 | 37 | let uploader; 38 | 39 | if (this.config.uploader && typeof this.config.uploader.uploadByFile === 'function') { 40 | const customUpload = this.config.uploader.uploadByFile(file); 41 | 42 | if (!isPromise(customUpload)) { 43 | console.warn('Custom uploader method uploadByFile should return a Promise'); 44 | } 45 | 46 | uploader = customUpload; 47 | } else { 48 | uploader = this.uploadByFile(file); 49 | } 50 | 51 | uploader.then((response) => { 52 | onUpload(response, previewElem); 53 | }).catch((error) => { 54 | onError(error, previewElem); 55 | }); 56 | } 57 | }); 58 | } 59 | 60 | /** 61 | * Default file uploader 62 | * Fires ajax.post() 63 | * 64 | * @param {File} file - file pasted by drag-n-drop 65 | */ 66 | uploadByFile(file) { 67 | const formData = new FormData(); 68 | 69 | formData.append(this.config.field, file); 70 | 71 | if (this.config.additionalRequestData && Object.keys(this.config.additionalRequestData).length) { 72 | Object.entries(this.config.additionalRequestData).forEach(([name, value]) => { 73 | formData.append(name, value); 74 | }); 75 | } 76 | 77 | return ajax.post({ 78 | url: this.config.endpoints.byFile, 79 | data: formData, 80 | type: ajax.contentType.JSON, 81 | headers: this.config.additionalRequestHeaders, 82 | }).then(response => response.body); 83 | } 84 | } 85 | 86 | /** 87 | * Check if passed object is a Promise 88 | * 89 | * @param {*} object - object to check 90 | * @returns {boolean} 91 | */ 92 | function isPromise(object) { 93 | return object && typeof object.then === "function"; 94 | } 95 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js"; 3 | import * as pkg from "./package.json"; 4 | 5 | const NODE_ENV = process.argv.mode || "development"; 6 | const VERSION = pkg.version; 7 | 8 | export default { 9 | build: { 10 | copyPublicDir: false, 11 | lib: { 12 | entry: path.resolve(__dirname, "src", "index.js"), 13 | name: "ImageGallery", 14 | fileName: "gallery", 15 | }, 16 | }, 17 | define: { 18 | NODE_ENV: JSON.stringify(NODE_ENV), 19 | VERSION: JSON.stringify(VERSION), 20 | }, 21 | 22 | plugins: [cssInjectedByJsPlugin()], 23 | }; 24 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.0.0": 6 | version "7.8.3" 7 | resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz" 8 | dependencies: 9 | "@babel/highlight" "^7.8.3" 10 | 11 | "@babel/helper-validator-identifier@^7.9.0": 12 | version "7.9.5" 13 | resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz" 14 | 15 | "@babel/highlight@^7.8.3": 16 | version "7.9.0" 17 | resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz" 18 | dependencies: 19 | "@babel/helper-validator-identifier" "^7.9.0" 20 | chalk "^2.0.0" 21 | js-tokens "^4.0.0" 22 | 23 | "@codexteam/ajax@^4.2.0": 24 | version "4.2.0" 25 | resolved "https://registry.npmjs.org/@codexteam/ajax/-/ajax-4.2.0.tgz" 26 | 27 | "@codexteam/icons@^0.0.6": 28 | version "0.0.6" 29 | resolved "https://registry.npmjs.org/@codexteam/icons/-/icons-0.0.6.tgz" 30 | 31 | "@esbuild/android-arm64@0.18.20": 32 | version "0.18.20" 33 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" 34 | integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== 35 | 36 | "@esbuild/android-arm@0.18.20": 37 | version "0.18.20" 38 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" 39 | integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== 40 | 41 | "@esbuild/android-x64@0.18.20": 42 | version "0.18.20" 43 | resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" 44 | integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== 45 | 46 | "@esbuild/darwin-arm64@0.18.20": 47 | version "0.18.20" 48 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" 49 | integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== 50 | 51 | "@esbuild/darwin-x64@0.18.20": 52 | version "0.18.20" 53 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" 54 | integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== 55 | 56 | "@esbuild/freebsd-arm64@0.18.20": 57 | version "0.18.20" 58 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" 59 | integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== 60 | 61 | "@esbuild/freebsd-x64@0.18.20": 62 | version "0.18.20" 63 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" 64 | integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== 65 | 66 | "@esbuild/linux-arm64@0.18.20": 67 | version "0.18.20" 68 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" 69 | integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== 70 | 71 | "@esbuild/linux-arm@0.18.20": 72 | version "0.18.20" 73 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" 74 | integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== 75 | 76 | "@esbuild/linux-ia32@0.18.20": 77 | version "0.18.20" 78 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" 79 | integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== 80 | 81 | "@esbuild/linux-loong64@0.18.20": 82 | version "0.18.20" 83 | resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" 84 | integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== 85 | 86 | "@esbuild/linux-mips64el@0.18.20": 87 | version "0.18.20" 88 | resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" 89 | integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== 90 | 91 | "@esbuild/linux-ppc64@0.18.20": 92 | version "0.18.20" 93 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" 94 | integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== 95 | 96 | "@esbuild/linux-riscv64@0.18.20": 97 | version "0.18.20" 98 | resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" 99 | integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== 100 | 101 | "@esbuild/linux-s390x@0.18.20": 102 | version "0.18.20" 103 | resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" 104 | integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== 105 | 106 | "@esbuild/linux-x64@0.18.20": 107 | version "0.18.20" 108 | resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" 109 | integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== 110 | 111 | "@esbuild/netbsd-x64@0.18.20": 112 | version "0.18.20" 113 | resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" 114 | integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== 115 | 116 | "@esbuild/openbsd-x64@0.18.20": 117 | version "0.18.20" 118 | resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" 119 | integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== 120 | 121 | "@esbuild/sunos-x64@0.18.20": 122 | version "0.18.20" 123 | resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" 124 | integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== 125 | 126 | "@esbuild/win32-arm64@0.18.20": 127 | version "0.18.20" 128 | resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" 129 | integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== 130 | 131 | "@esbuild/win32-ia32@0.18.20": 132 | version "0.18.20" 133 | resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" 134 | integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== 135 | 136 | "@esbuild/win32-x64@0.18.20": 137 | version "0.18.20" 138 | resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz" 139 | integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== 140 | 141 | "@types/color-name@^1.1.1": 142 | version "1.1.1" 143 | resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz" 144 | 145 | "@types/eslint-visitor-keys@^1.0.0": 146 | version "1.0.0" 147 | resolved "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz" 148 | 149 | "@types/json-schema@^7.0.3": 150 | version "7.0.15" 151 | resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" 152 | integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== 153 | 154 | "@typescript-eslint/eslint-plugin@^2.12.0": 155 | version "2.29.0" 156 | resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.29.0.tgz" 157 | dependencies: 158 | "@typescript-eslint/experimental-utils" "2.29.0" 159 | functional-red-black-tree "^1.0.1" 160 | regexpp "^3.0.0" 161 | tsutils "^3.17.1" 162 | 163 | "@typescript-eslint/experimental-utils@2.29.0": 164 | version "2.29.0" 165 | resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.29.0.tgz" 166 | dependencies: 167 | "@types/json-schema" "^7.0.3" 168 | "@typescript-eslint/typescript-estree" "2.29.0" 169 | eslint-scope "^5.0.0" 170 | eslint-utils "^2.0.0" 171 | 172 | "@typescript-eslint/parser@^2.12.0": 173 | version "2.29.0" 174 | resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.29.0.tgz" 175 | dependencies: 176 | "@types/eslint-visitor-keys" "^1.0.0" 177 | "@typescript-eslint/experimental-utils" "2.29.0" 178 | "@typescript-eslint/typescript-estree" "2.29.0" 179 | eslint-visitor-keys "^1.1.0" 180 | 181 | "@typescript-eslint/typescript-estree@2.29.0": 182 | version "2.29.0" 183 | resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.29.0.tgz" 184 | dependencies: 185 | debug "^4.1.1" 186 | eslint-visitor-keys "^1.1.0" 187 | glob "^7.1.6" 188 | is-glob "^4.0.1" 189 | lodash "^4.17.15" 190 | semver "^6.3.0" 191 | tsutils "^3.17.1" 192 | 193 | acorn-jsx@^5.2.0: 194 | version "5.2.0" 195 | resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz" 196 | 197 | acorn@^7.1.1: 198 | version "7.1.1" 199 | resolved "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz" 200 | 201 | ajv-keywords@^3.4.1: 202 | version "3.5.2" 203 | resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" 204 | integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== 205 | 206 | ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.5.5: 207 | version "6.12.6" 208 | resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" 209 | integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== 210 | dependencies: 211 | fast-deep-equal "^3.1.1" 212 | fast-json-stable-stringify "^2.0.0" 213 | json-schema-traverse "^0.4.1" 214 | uri-js "^4.2.2" 215 | 216 | ansi-escapes@^4.2.1: 217 | version "4.3.1" 218 | resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz" 219 | dependencies: 220 | type-fest "^0.11.0" 221 | 222 | ansi-regex@^4.1.0: 223 | version "4.1.0" 224 | resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz" 225 | 226 | ansi-regex@^5.0.0: 227 | version "5.0.0" 228 | resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz" 229 | 230 | ansi-styles@^3.2.0, ansi-styles@^3.2.1: 231 | version "3.2.1" 232 | resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" 233 | dependencies: 234 | color-convert "^1.9.0" 235 | 236 | ansi-styles@^4.1.0: 237 | version "4.2.1" 238 | resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz" 239 | dependencies: 240 | "@types/color-name" "^1.1.1" 241 | color-convert "^2.0.1" 242 | 243 | argparse@^1.0.7: 244 | version "1.0.10" 245 | resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" 246 | dependencies: 247 | sprintf-js "~1.0.2" 248 | 249 | array-includes@^3.0.3: 250 | version "3.1.1" 251 | resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz" 252 | dependencies: 253 | define-properties "^1.1.3" 254 | es-abstract "^1.17.0" 255 | is-string "^1.0.5" 256 | 257 | array.prototype.flat@^1.2.1: 258 | version "1.2.3" 259 | resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz" 260 | dependencies: 261 | define-properties "^1.1.3" 262 | es-abstract "^1.17.0-next.1" 263 | 264 | asn1@~0.2.3: 265 | version "0.2.4" 266 | resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz" 267 | dependencies: 268 | safer-buffer "~2.1.0" 269 | 270 | assert-plus@1.0.0, assert-plus@^1.0.0: 271 | version "1.0.0" 272 | resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" 273 | 274 | astral-regex@^1.0.0: 275 | version "1.0.0" 276 | resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz" 277 | 278 | asynckit@^0.4.0: 279 | version "0.4.0" 280 | resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" 281 | 282 | at-least-node@^1.0.0: 283 | version "1.0.0" 284 | resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz" 285 | 286 | aws-sign2@~0.7.0: 287 | version "0.7.0" 288 | resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz" 289 | 290 | aws4@^1.8.0: 291 | version "1.9.1" 292 | resolved "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz" 293 | 294 | balanced-match@^1.0.0: 295 | version "1.0.0" 296 | resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz" 297 | 298 | bcrypt-pbkdf@^1.0.0: 299 | version "1.0.2" 300 | resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz" 301 | dependencies: 302 | tweetnacl "^0.14.3" 303 | 304 | big.js@^5.2.2: 305 | version "5.2.2" 306 | resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz" 307 | 308 | brace-expansion@^1.1.7: 309 | version "1.1.11" 310 | resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" 311 | dependencies: 312 | balanced-match "^1.0.0" 313 | concat-map "0.0.1" 314 | 315 | callsites@^3.0.0: 316 | version "3.1.0" 317 | resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" 318 | 319 | caseless@~0.12.0: 320 | version "0.12.0" 321 | resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" 322 | 323 | chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: 324 | version "2.4.2" 325 | resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" 326 | dependencies: 327 | ansi-styles "^3.2.1" 328 | escape-string-regexp "^1.0.5" 329 | supports-color "^5.3.0" 330 | 331 | chalk@^3.0.0: 332 | version "3.0.0" 333 | resolved "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz" 334 | dependencies: 335 | ansi-styles "^4.1.0" 336 | supports-color "^7.1.0" 337 | 338 | chardet@^0.7.0: 339 | version "0.7.0" 340 | resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" 341 | 342 | cli-cursor@^3.1.0: 343 | version "3.1.0" 344 | resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz" 345 | dependencies: 346 | restore-cursor "^3.1.0" 347 | 348 | cli-width@^2.0.0: 349 | version "2.2.1" 350 | resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz" 351 | 352 | color-convert@^1.9.0: 353 | version "1.9.3" 354 | resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" 355 | dependencies: 356 | color-name "1.1.3" 357 | 358 | color-convert@^2.0.1: 359 | version "2.0.1" 360 | resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" 361 | dependencies: 362 | color-name "~1.1.4" 363 | 364 | color-name@1.1.3: 365 | version "1.1.3" 366 | resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" 367 | 368 | color-name@~1.1.4: 369 | version "1.1.4" 370 | resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" 371 | 372 | combined-stream@^1.0.6, combined-stream@~1.0.6: 373 | version "1.0.8" 374 | resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" 375 | dependencies: 376 | delayed-stream "~1.0.0" 377 | 378 | comment-parser@^0.7.2: 379 | version "0.7.2" 380 | resolved "https://registry.npmjs.org/comment-parser/-/comment-parser-0.7.2.tgz" 381 | 382 | commondir@^1.0.1: 383 | version "1.0.1" 384 | resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" 385 | 386 | concat-map@0.0.1: 387 | version "0.0.1" 388 | resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" 389 | 390 | contains-path@^0.1.0: 391 | version "0.1.0" 392 | resolved "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz" 393 | 394 | core-util-is@1.0.2: 395 | version "1.0.2" 396 | resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" 397 | 398 | cross-spawn@^6.0.5: 399 | version "6.0.5" 400 | resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz" 401 | dependencies: 402 | nice-try "^1.0.4" 403 | path-key "^2.0.1" 404 | semver "^5.5.0" 405 | shebang-command "^1.2.0" 406 | which "^1.2.9" 407 | 408 | cssesc@^3.0.0: 409 | version "3.0.0" 410 | resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" 411 | 412 | dashdash@^1.12.0: 413 | version "1.14.1" 414 | resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz" 415 | dependencies: 416 | assert-plus "^1.0.0" 417 | 418 | debug@^2.6.9: 419 | version "2.6.9" 420 | resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" 421 | dependencies: 422 | ms "2.0.0" 423 | 424 | debug@^4.0.1, debug@^4.1.1: 425 | version "4.1.1" 426 | resolved "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz" 427 | dependencies: 428 | ms "^2.1.1" 429 | 430 | deep-is@~0.1.3: 431 | version "0.1.3" 432 | resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" 433 | 434 | define-properties@^1.1.2, define-properties@^1.1.3: 435 | version "1.1.3" 436 | resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz" 437 | dependencies: 438 | object-keys "^1.0.12" 439 | 440 | delayed-stream@~1.0.0: 441 | version "1.0.0" 442 | resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" 443 | 444 | doctrine@1.5.0: 445 | version "1.5.0" 446 | resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz" 447 | dependencies: 448 | esutils "^2.0.2" 449 | isarray "^1.0.0" 450 | 451 | doctrine@^3.0.0: 452 | version "3.0.0" 453 | resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" 454 | dependencies: 455 | esutils "^2.0.2" 456 | 457 | ecc-jsbn@~0.1.1: 458 | version "0.1.2" 459 | resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz" 460 | dependencies: 461 | jsbn "~0.1.0" 462 | safer-buffer "^2.1.0" 463 | 464 | emoji-regex@^7.0.1: 465 | version "7.0.3" 466 | resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz" 467 | 468 | emoji-regex@^8.0.0: 469 | version "8.0.0" 470 | resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" 471 | 472 | emojis-list@^3.0.0: 473 | version "3.0.0" 474 | resolved "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz" 475 | 476 | error-ex@^1.2.0: 477 | version "1.3.2" 478 | resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" 479 | dependencies: 480 | is-arrayish "^0.2.1" 481 | 482 | es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: 483 | version "1.17.5" 484 | resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz" 485 | dependencies: 486 | es-to-primitive "^1.2.1" 487 | function-bind "^1.1.1" 488 | has "^1.0.3" 489 | has-symbols "^1.0.1" 490 | is-callable "^1.1.5" 491 | is-regex "^1.0.5" 492 | object-inspect "^1.7.0" 493 | object-keys "^1.1.1" 494 | object.assign "^4.1.0" 495 | string.prototype.trimleft "^2.1.1" 496 | string.prototype.trimright "^2.1.1" 497 | 498 | es-to-primitive@^1.2.1: 499 | version "1.2.1" 500 | resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" 501 | dependencies: 502 | is-callable "^1.1.4" 503 | is-date-object "^1.0.1" 504 | is-symbol "^1.0.2" 505 | 506 | esbuild@^0.18.10: 507 | version "0.18.20" 508 | resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz" 509 | integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== 510 | optionalDependencies: 511 | "@esbuild/android-arm" "0.18.20" 512 | "@esbuild/android-arm64" "0.18.20" 513 | "@esbuild/android-x64" "0.18.20" 514 | "@esbuild/darwin-arm64" "0.18.20" 515 | "@esbuild/darwin-x64" "0.18.20" 516 | "@esbuild/freebsd-arm64" "0.18.20" 517 | "@esbuild/freebsd-x64" "0.18.20" 518 | "@esbuild/linux-arm" "0.18.20" 519 | "@esbuild/linux-arm64" "0.18.20" 520 | "@esbuild/linux-ia32" "0.18.20" 521 | "@esbuild/linux-loong64" "0.18.20" 522 | "@esbuild/linux-mips64el" "0.18.20" 523 | "@esbuild/linux-ppc64" "0.18.20" 524 | "@esbuild/linux-riscv64" "0.18.20" 525 | "@esbuild/linux-s390x" "0.18.20" 526 | "@esbuild/linux-x64" "0.18.20" 527 | "@esbuild/netbsd-x64" "0.18.20" 528 | "@esbuild/openbsd-x64" "0.18.20" 529 | "@esbuild/sunos-x64" "0.18.20" 530 | "@esbuild/win32-arm64" "0.18.20" 531 | "@esbuild/win32-ia32" "0.18.20" 532 | "@esbuild/win32-x64" "0.18.20" 533 | 534 | escape-string-regexp@^1.0.5: 535 | version "1.0.5" 536 | resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" 537 | 538 | eslint-config-codex@^1.3.3: 539 | version "1.3.3" 540 | resolved "https://registry.npmjs.org/eslint-config-codex/-/eslint-config-codex-1.3.3.tgz" 541 | dependencies: 542 | "@typescript-eslint/eslint-plugin" "^2.12.0" 543 | "@typescript-eslint/parser" "^2.12.0" 544 | eslint-config-standard "14.1.0" 545 | eslint-plugin-import "2.19.1" 546 | eslint-plugin-jsdoc "^22.1.0" 547 | eslint-plugin-node "10.0.0" 548 | eslint-plugin-promise "4.2.1" 549 | eslint-plugin-standard "4.0.1" 550 | typescript "^3.7.3" 551 | 552 | eslint-config-standard@14.1.0: 553 | version "14.1.0" 554 | resolved "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-14.1.0.tgz" 555 | 556 | eslint-import-resolver-node@^0.3.2: 557 | version "0.3.3" 558 | resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz" 559 | dependencies: 560 | debug "^2.6.9" 561 | resolve "^1.13.1" 562 | 563 | eslint-loader@^4.0.0: 564 | version "4.0.0" 565 | resolved "https://registry.npmjs.org/eslint-loader/-/eslint-loader-4.0.0.tgz" 566 | dependencies: 567 | fs-extra "^9.0.0" 568 | loader-fs-cache "^1.0.3" 569 | loader-utils "^2.0.0" 570 | object-hash "^2.0.3" 571 | schema-utils "^2.6.5" 572 | 573 | eslint-module-utils@^2.4.1: 574 | version "2.6.0" 575 | resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz" 576 | dependencies: 577 | debug "^2.6.9" 578 | pkg-dir "^2.0.0" 579 | 580 | eslint-plugin-es@^2.0.0: 581 | version "2.0.0" 582 | resolved "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-2.0.0.tgz" 583 | dependencies: 584 | eslint-utils "^1.4.2" 585 | regexpp "^3.0.0" 586 | 587 | eslint-plugin-import@2.19.1: 588 | version "2.19.1" 589 | resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.19.1.tgz" 590 | dependencies: 591 | array-includes "^3.0.3" 592 | array.prototype.flat "^1.2.1" 593 | contains-path "^0.1.0" 594 | debug "^2.6.9" 595 | doctrine "1.5.0" 596 | eslint-import-resolver-node "^0.3.2" 597 | eslint-module-utils "^2.4.1" 598 | has "^1.0.3" 599 | minimatch "^3.0.4" 600 | object.values "^1.1.0" 601 | read-pkg-up "^2.0.0" 602 | resolve "^1.12.0" 603 | 604 | eslint-plugin-jsdoc@^22.1.0: 605 | version "22.2.0" 606 | resolved "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-22.2.0.tgz" 607 | dependencies: 608 | comment-parser "^0.7.2" 609 | debug "^4.1.1" 610 | jsdoctypeparser "^6.1.0" 611 | lodash "^4.17.15" 612 | regextras "^0.7.0" 613 | semver "^6.3.0" 614 | spdx-expression-parse "^3.0.0" 615 | 616 | eslint-plugin-node@10.0.0: 617 | version "10.0.0" 618 | resolved "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-10.0.0.tgz" 619 | dependencies: 620 | eslint-plugin-es "^2.0.0" 621 | eslint-utils "^1.4.2" 622 | ignore "^5.1.1" 623 | minimatch "^3.0.4" 624 | resolve "^1.10.1" 625 | semver "^6.1.0" 626 | 627 | eslint-plugin-promise@4.2.1: 628 | version "4.2.1" 629 | resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz" 630 | 631 | eslint-plugin-standard@4.0.1: 632 | version "4.0.1" 633 | resolved "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz" 634 | 635 | eslint-scope@^5.0.0: 636 | version "5.1.1" 637 | resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" 638 | integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== 639 | dependencies: 640 | esrecurse "^4.3.0" 641 | estraverse "^4.1.1" 642 | 643 | eslint-utils@^1.4.2, eslint-utils@^1.4.3: 644 | version "1.4.3" 645 | resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz" 646 | dependencies: 647 | eslint-visitor-keys "^1.1.0" 648 | 649 | eslint-utils@^2.0.0: 650 | version "2.0.0" 651 | resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz" 652 | dependencies: 653 | eslint-visitor-keys "^1.1.0" 654 | 655 | eslint-visitor-keys@^1.1.0: 656 | version "1.1.0" 657 | resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz" 658 | 659 | eslint@^6.8.0: 660 | version "6.8.0" 661 | resolved "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz" 662 | dependencies: 663 | "@babel/code-frame" "^7.0.0" 664 | ajv "^6.10.0" 665 | chalk "^2.1.0" 666 | cross-spawn "^6.0.5" 667 | debug "^4.0.1" 668 | doctrine "^3.0.0" 669 | eslint-scope "^5.0.0" 670 | eslint-utils "^1.4.3" 671 | eslint-visitor-keys "^1.1.0" 672 | espree "^6.1.2" 673 | esquery "^1.0.1" 674 | esutils "^2.0.2" 675 | file-entry-cache "^5.0.1" 676 | functional-red-black-tree "^1.0.1" 677 | glob-parent "^5.0.0" 678 | globals "^12.1.0" 679 | ignore "^4.0.6" 680 | import-fresh "^3.0.0" 681 | imurmurhash "^0.1.4" 682 | inquirer "^7.0.0" 683 | is-glob "^4.0.0" 684 | js-yaml "^3.13.1" 685 | json-stable-stringify-without-jsonify "^1.0.1" 686 | levn "^0.3.0" 687 | lodash "^4.17.14" 688 | minimatch "^3.0.4" 689 | mkdirp "^0.5.1" 690 | natural-compare "^1.4.0" 691 | optionator "^0.8.3" 692 | progress "^2.0.0" 693 | regexpp "^2.0.1" 694 | semver "^6.1.2" 695 | strip-ansi "^5.2.0" 696 | strip-json-comments "^3.0.1" 697 | table "^5.2.3" 698 | text-table "^0.2.0" 699 | v8-compile-cache "^2.0.3" 700 | 701 | espree@^6.1.2: 702 | version "6.2.1" 703 | resolved "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz" 704 | dependencies: 705 | acorn "^7.1.1" 706 | acorn-jsx "^5.2.0" 707 | eslint-visitor-keys "^1.1.0" 708 | 709 | esprima@^4.0.0: 710 | version "4.0.1" 711 | resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" 712 | 713 | esquery@^1.0.1: 714 | version "1.3.1" 715 | resolved "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz" 716 | dependencies: 717 | estraverse "^5.1.0" 718 | 719 | esrecurse@^4.3.0: 720 | version "4.3.0" 721 | resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" 722 | integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== 723 | dependencies: 724 | estraverse "^5.2.0" 725 | 726 | estraverse@^4.1.1: 727 | version "4.3.0" 728 | resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" 729 | integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== 730 | 731 | estraverse@^5.1.0: 732 | version "5.1.0" 733 | resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz" 734 | 735 | estraverse@^5.2.0: 736 | version "5.3.0" 737 | resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" 738 | integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== 739 | 740 | esutils@^2.0.2: 741 | version "2.0.3" 742 | resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" 743 | 744 | extend@~3.0.2: 745 | version "3.0.2" 746 | resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" 747 | 748 | external-editor@^3.0.3: 749 | version "3.1.0" 750 | resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz" 751 | dependencies: 752 | chardet "^0.7.0" 753 | iconv-lite "^0.4.24" 754 | tmp "^0.0.33" 755 | 756 | extsprintf@1.3.0: 757 | version "1.3.0" 758 | resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz" 759 | 760 | extsprintf@^1.2.0: 761 | version "1.4.0" 762 | resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz" 763 | 764 | fast-deep-equal@^3.1.1: 765 | version "3.1.1" 766 | resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz" 767 | 768 | fast-json-stable-stringify@^2.0.0: 769 | version "2.1.0" 770 | resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" 771 | 772 | fast-levenshtein@~2.0.6: 773 | version "2.0.6" 774 | resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" 775 | 776 | figures@^3.0.0: 777 | version "3.2.0" 778 | resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz" 779 | dependencies: 780 | escape-string-regexp "^1.0.5" 781 | 782 | file-entry-cache@^5.0.1: 783 | version "5.0.1" 784 | resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz" 785 | dependencies: 786 | flat-cache "^2.0.1" 787 | 788 | find-cache-dir@^0.1.1: 789 | version "0.1.1" 790 | resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz" 791 | dependencies: 792 | commondir "^1.0.1" 793 | mkdirp "^0.5.1" 794 | pkg-dir "^1.0.0" 795 | 796 | find-up@^1.0.0: 797 | version "1.1.2" 798 | resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz" 799 | dependencies: 800 | path-exists "^2.0.0" 801 | pinkie-promise "^2.0.0" 802 | 803 | find-up@^2.0.0, find-up@^2.1.0: 804 | version "2.1.0" 805 | resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz" 806 | dependencies: 807 | locate-path "^2.0.0" 808 | 809 | flat-cache@^2.0.1: 810 | version "2.0.1" 811 | resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz" 812 | dependencies: 813 | flatted "^2.0.0" 814 | rimraf "2.6.3" 815 | write "1.0.3" 816 | 817 | flatted@^2.0.0: 818 | version "2.0.2" 819 | resolved "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz" 820 | 821 | forever-agent@~0.6.1: 822 | version "0.6.1" 823 | resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" 824 | 825 | form-data@~2.3.2: 826 | version "2.3.3" 827 | resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz" 828 | dependencies: 829 | asynckit "^0.4.0" 830 | combined-stream "^1.0.6" 831 | mime-types "^2.1.12" 832 | 833 | formidable@^1.2.1: 834 | version "1.2.2" 835 | resolved "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz" 836 | 837 | fs-extra@^9.0.0: 838 | version "9.0.0" 839 | resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz" 840 | dependencies: 841 | at-least-node "^1.0.0" 842 | graceful-fs "^4.2.0" 843 | jsonfile "^6.0.1" 844 | universalify "^1.0.0" 845 | 846 | fs.realpath@^1.0.0: 847 | version "1.0.0" 848 | resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" 849 | 850 | fsevents@~2.3.2: 851 | version "2.3.3" 852 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" 853 | integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== 854 | 855 | function-bind@^1.1.1: 856 | version "1.1.1" 857 | resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" 858 | 859 | functional-red-black-tree@^1.0.1: 860 | version "1.0.1" 861 | resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" 862 | 863 | getpass@^0.1.1: 864 | version "0.1.7" 865 | resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz" 866 | dependencies: 867 | assert-plus "^1.0.0" 868 | 869 | glob-parent@^5.0.0: 870 | version "5.1.1" 871 | resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz" 872 | dependencies: 873 | is-glob "^4.0.1" 874 | 875 | glob@^7.1.3, glob@^7.1.6: 876 | version "7.1.6" 877 | resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz" 878 | dependencies: 879 | fs.realpath "^1.0.0" 880 | inflight "^1.0.4" 881 | inherits "2" 882 | minimatch "^3.0.4" 883 | once "^1.3.0" 884 | path-is-absolute "^1.0.0" 885 | 886 | globals@^12.1.0: 887 | version "12.4.0" 888 | resolved "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz" 889 | dependencies: 890 | type-fest "^0.8.1" 891 | 892 | graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: 893 | version "4.2.11" 894 | resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" 895 | integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== 896 | 897 | har-schema@^2.0.0: 898 | version "2.0.0" 899 | resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz" 900 | 901 | har-validator@~5.1.3: 902 | version "5.1.3" 903 | resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz" 904 | dependencies: 905 | ajv "^6.5.5" 906 | har-schema "^2.0.0" 907 | 908 | has-flag@^3.0.0: 909 | version "3.0.0" 910 | resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" 911 | 912 | has-flag@^4.0.0: 913 | version "4.0.0" 914 | resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" 915 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 916 | 917 | has-symbols@^1.0.0, has-symbols@^1.0.1: 918 | version "1.0.1" 919 | resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz" 920 | 921 | has@^1.0.3: 922 | version "1.0.3" 923 | resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" 924 | dependencies: 925 | function-bind "^1.1.1" 926 | 927 | hosted-git-info@^2.1.4: 928 | version "2.8.9" 929 | resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz" 930 | 931 | http-signature@~1.2.0: 932 | version "1.2.0" 933 | resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz" 934 | dependencies: 935 | assert-plus "^1.0.0" 936 | jsprim "^1.2.2" 937 | sshpk "^1.7.0" 938 | 939 | iconv-lite@^0.4.24: 940 | version "0.4.24" 941 | resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" 942 | dependencies: 943 | safer-buffer ">= 2.1.2 < 3" 944 | 945 | ignore@^4.0.6: 946 | version "4.0.6" 947 | resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" 948 | 949 | ignore@^5.1.1: 950 | version "5.1.4" 951 | resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz" 952 | 953 | import-fresh@^3.0.0: 954 | version "3.2.1" 955 | resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz" 956 | dependencies: 957 | parent-module "^1.0.0" 958 | resolve-from "^4.0.0" 959 | 960 | imurmurhash@^0.1.4: 961 | version "0.1.4" 962 | resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" 963 | 964 | indexes-of@^1.0.1: 965 | version "1.0.1" 966 | resolved "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz" 967 | 968 | inflight@^1.0.4: 969 | version "1.0.6" 970 | resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" 971 | dependencies: 972 | once "^1.3.0" 973 | wrappy "1" 974 | 975 | inherits@2: 976 | version "2.0.4" 977 | resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" 978 | 979 | inquirer@^7.0.0: 980 | version "7.1.0" 981 | resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz" 982 | dependencies: 983 | ansi-escapes "^4.2.1" 984 | chalk "^3.0.0" 985 | cli-cursor "^3.1.0" 986 | cli-width "^2.0.0" 987 | external-editor "^3.0.3" 988 | figures "^3.0.0" 989 | lodash "^4.17.15" 990 | mute-stream "0.0.8" 991 | run-async "^2.4.0" 992 | rxjs "^6.5.3" 993 | string-width "^4.1.0" 994 | strip-ansi "^6.0.0" 995 | through "^2.3.6" 996 | 997 | is-arrayish@^0.2.1: 998 | version "0.2.1" 999 | resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" 1000 | 1001 | is-callable@^1.1.4, is-callable@^1.1.5: 1002 | version "1.1.5" 1003 | resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz" 1004 | 1005 | is-date-object@^1.0.1: 1006 | version "1.0.2" 1007 | resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz" 1008 | 1009 | is-extglob@^2.1.1: 1010 | version "2.1.1" 1011 | resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" 1012 | 1013 | is-fullwidth-code-point@^2.0.0: 1014 | version "2.0.0" 1015 | resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz" 1016 | 1017 | is-fullwidth-code-point@^3.0.0: 1018 | version "3.0.0" 1019 | resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" 1020 | 1021 | is-glob@^4.0.0, is-glob@^4.0.1: 1022 | version "4.0.1" 1023 | resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz" 1024 | dependencies: 1025 | is-extglob "^2.1.1" 1026 | 1027 | is-promise@^2.1.0: 1028 | version "2.1.0" 1029 | resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz" 1030 | 1031 | is-regex@^1.0.5: 1032 | version "1.0.5" 1033 | resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz" 1034 | dependencies: 1035 | has "^1.0.3" 1036 | 1037 | is-string@^1.0.5: 1038 | version "1.0.5" 1039 | resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz" 1040 | 1041 | is-symbol@^1.0.2: 1042 | version "1.0.3" 1043 | resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz" 1044 | dependencies: 1045 | has-symbols "^1.0.1" 1046 | 1047 | is-typedarray@~1.0.0: 1048 | version "1.0.0" 1049 | resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" 1050 | 1051 | isarray@^1.0.0: 1052 | version "1.0.0" 1053 | resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" 1054 | 1055 | isexe@^2.0.0: 1056 | version "2.0.0" 1057 | resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" 1058 | 1059 | isstream@~0.1.2: 1060 | version "0.1.2" 1061 | resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" 1062 | 1063 | js-tokens@^4.0.0: 1064 | version "4.0.0" 1065 | resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" 1066 | 1067 | js-yaml@^3.13.1: 1068 | version "3.13.1" 1069 | resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz" 1070 | dependencies: 1071 | argparse "^1.0.7" 1072 | esprima "^4.0.0" 1073 | 1074 | jsbn@~0.1.0: 1075 | version "0.1.1" 1076 | resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz" 1077 | 1078 | jsdoctypeparser@^6.1.0: 1079 | version "6.1.0" 1080 | resolved "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-6.1.0.tgz" 1081 | 1082 | json-schema-traverse@^0.4.1: 1083 | version "0.4.1" 1084 | resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" 1085 | 1086 | json-schema@0.2.3: 1087 | version "0.2.3" 1088 | resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz" 1089 | 1090 | json-stable-stringify-without-jsonify@^1.0.1: 1091 | version "1.0.1" 1092 | resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" 1093 | 1094 | json-stringify-safe@~5.0.1: 1095 | version "5.0.1" 1096 | resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" 1097 | 1098 | json5@^2.1.2: 1099 | version "2.1.3" 1100 | resolved "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz" 1101 | dependencies: 1102 | minimist "^1.2.5" 1103 | 1104 | jsonfile@^6.0.1: 1105 | version "6.0.1" 1106 | resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz" 1107 | dependencies: 1108 | universalify "^1.0.0" 1109 | optionalDependencies: 1110 | graceful-fs "^4.1.6" 1111 | 1112 | jsprim@^1.2.2: 1113 | version "1.4.1" 1114 | resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz" 1115 | dependencies: 1116 | assert-plus "1.0.0" 1117 | extsprintf "1.3.0" 1118 | json-schema "0.2.3" 1119 | verror "1.10.0" 1120 | 1121 | levn@^0.3.0, levn@~0.3.0: 1122 | version "0.3.0" 1123 | resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" 1124 | dependencies: 1125 | prelude-ls "~1.1.2" 1126 | type-check "~0.3.2" 1127 | 1128 | load-json-file@^2.0.0: 1129 | version "2.0.0" 1130 | resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz" 1131 | dependencies: 1132 | graceful-fs "^4.1.2" 1133 | parse-json "^2.2.0" 1134 | pify "^2.0.0" 1135 | strip-bom "^3.0.0" 1136 | 1137 | loader-fs-cache@^1.0.3: 1138 | version "1.0.3" 1139 | resolved "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz" 1140 | dependencies: 1141 | find-cache-dir "^0.1.1" 1142 | mkdirp "^0.5.1" 1143 | 1144 | loader-utils@^2.0.0: 1145 | version "2.0.0" 1146 | resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz" 1147 | dependencies: 1148 | big.js "^5.2.2" 1149 | emojis-list "^3.0.0" 1150 | json5 "^2.1.2" 1151 | 1152 | locate-path@^2.0.0: 1153 | version "2.0.0" 1154 | resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz" 1155 | dependencies: 1156 | p-locate "^2.0.0" 1157 | path-exists "^3.0.0" 1158 | 1159 | lodash@^4.17.14, lodash@^4.17.15: 1160 | version "4.17.21" 1161 | resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" 1162 | 1163 | mime-db@1.52.0: 1164 | version "1.52.0" 1165 | resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" 1166 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 1167 | 1168 | mime-types@^2.1.12, mime-types@~2.1.19: 1169 | version "2.1.35" 1170 | resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" 1171 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 1172 | dependencies: 1173 | mime-db "1.52.0" 1174 | 1175 | mimic-fn@^2.1.0: 1176 | version "2.1.0" 1177 | resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" 1178 | 1179 | minimatch@^3.0.4: 1180 | version "3.0.4" 1181 | resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz" 1182 | dependencies: 1183 | brace-expansion "^1.1.7" 1184 | 1185 | minimist@^1.2.5: 1186 | version "1.2.5" 1187 | resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz" 1188 | 1189 | mkdirp@^0.5.1: 1190 | version "0.5.5" 1191 | resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz" 1192 | dependencies: 1193 | minimist "^1.2.5" 1194 | 1195 | ms@2.0.0: 1196 | version "2.0.0" 1197 | resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" 1198 | 1199 | ms@^2.1.1: 1200 | version "2.1.2" 1201 | resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" 1202 | 1203 | mute-stream@0.0.8: 1204 | version "0.0.8" 1205 | resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz" 1206 | 1207 | nanoid@^3.3.6: 1208 | version "3.3.7" 1209 | resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz" 1210 | integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== 1211 | 1212 | natural-compare@^1.4.0: 1213 | version "1.4.0" 1214 | resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" 1215 | 1216 | nice-try@^1.0.4: 1217 | version "1.0.5" 1218 | resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz" 1219 | 1220 | normalize-package-data@^2.3.2: 1221 | version "2.5.0" 1222 | resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" 1223 | dependencies: 1224 | hosted-git-info "^2.1.4" 1225 | resolve "^1.10.0" 1226 | semver "2 || 3 || 4 || 5" 1227 | validate-npm-package-license "^3.0.1" 1228 | 1229 | oauth-sign@~0.9.0: 1230 | version "0.9.0" 1231 | resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz" 1232 | 1233 | object-hash@^2.0.3: 1234 | version "2.0.3" 1235 | resolved "https://registry.npmjs.org/object-hash/-/object-hash-2.0.3.tgz" 1236 | 1237 | object-inspect@^1.7.0: 1238 | version "1.7.0" 1239 | resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz" 1240 | 1241 | object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: 1242 | version "1.1.1" 1243 | resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" 1244 | 1245 | object.assign@^4.1.0: 1246 | version "4.1.0" 1247 | resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz" 1248 | dependencies: 1249 | define-properties "^1.1.2" 1250 | function-bind "^1.1.1" 1251 | has-symbols "^1.0.0" 1252 | object-keys "^1.0.11" 1253 | 1254 | object.values@^1.1.0: 1255 | version "1.1.1" 1256 | resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz" 1257 | dependencies: 1258 | define-properties "^1.1.3" 1259 | es-abstract "^1.17.0-next.1" 1260 | function-bind "^1.1.1" 1261 | has "^1.0.3" 1262 | 1263 | once@^1.3.0: 1264 | version "1.4.0" 1265 | resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" 1266 | dependencies: 1267 | wrappy "1" 1268 | 1269 | onetime@^5.1.0: 1270 | version "5.1.0" 1271 | resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz" 1272 | dependencies: 1273 | mimic-fn "^2.1.0" 1274 | 1275 | optionator@^0.8.3: 1276 | version "0.8.3" 1277 | resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" 1278 | dependencies: 1279 | deep-is "~0.1.3" 1280 | fast-levenshtein "~2.0.6" 1281 | levn "~0.3.0" 1282 | prelude-ls "~1.1.2" 1283 | type-check "~0.3.2" 1284 | word-wrap "~1.2.3" 1285 | 1286 | os-tmpdir@~1.0.2: 1287 | version "1.0.2" 1288 | resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" 1289 | 1290 | p-limit@^1.1.0: 1291 | version "1.3.0" 1292 | resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz" 1293 | dependencies: 1294 | p-try "^1.0.0" 1295 | 1296 | p-locate@^2.0.0: 1297 | version "2.0.0" 1298 | resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz" 1299 | dependencies: 1300 | p-limit "^1.1.0" 1301 | 1302 | p-try@^1.0.0: 1303 | version "1.0.0" 1304 | resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz" 1305 | 1306 | parent-module@^1.0.0: 1307 | version "1.0.1" 1308 | resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" 1309 | dependencies: 1310 | callsites "^3.0.0" 1311 | 1312 | parse-json@^2.2.0: 1313 | version "2.2.0" 1314 | resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz" 1315 | dependencies: 1316 | error-ex "^1.2.0" 1317 | 1318 | path-exists@^2.0.0: 1319 | version "2.1.0" 1320 | resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz" 1321 | dependencies: 1322 | pinkie-promise "^2.0.0" 1323 | 1324 | path-exists@^3.0.0: 1325 | version "3.0.0" 1326 | resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" 1327 | 1328 | path-is-absolute@^1.0.0: 1329 | version "1.0.1" 1330 | resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" 1331 | 1332 | path-key@^2.0.1: 1333 | version "2.0.1" 1334 | resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" 1335 | 1336 | path-parse@^1.0.6: 1337 | version "1.0.7" 1338 | resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" 1339 | 1340 | path-type@^2.0.0: 1341 | version "2.0.0" 1342 | resolved "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz" 1343 | dependencies: 1344 | pify "^2.0.0" 1345 | 1346 | performance-now@^2.1.0: 1347 | version "2.1.0" 1348 | resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" 1349 | 1350 | picocolors@^1.0.0: 1351 | version "1.0.1" 1352 | resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz" 1353 | integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== 1354 | 1355 | pify@^2.0.0: 1356 | version "2.3.0" 1357 | resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" 1358 | 1359 | pinkie-promise@^2.0.0: 1360 | version "2.0.1" 1361 | resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" 1362 | dependencies: 1363 | pinkie "^2.0.0" 1364 | 1365 | pinkie@^2.0.0: 1366 | version "2.0.4" 1367 | resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" 1368 | 1369 | pkg-dir@^1.0.0: 1370 | version "1.0.0" 1371 | resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz" 1372 | dependencies: 1373 | find-up "^1.0.0" 1374 | 1375 | pkg-dir@^2.0.0: 1376 | version "2.0.0" 1377 | resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz" 1378 | dependencies: 1379 | find-up "^2.1.0" 1380 | 1381 | postcss-nested-ancestors@^2.0.0: 1382 | version "2.0.0" 1383 | resolved "https://registry.npmjs.org/postcss-nested-ancestors/-/postcss-nested-ancestors-2.0.0.tgz" 1384 | dependencies: 1385 | escape-string-regexp "^1.0.5" 1386 | postcss "^6.0.0" 1387 | postcss-resolve-nested-selector "^0.1.1" 1388 | 1389 | postcss-nested@^4.1.0: 1390 | version "4.2.1" 1391 | resolved "https://registry.npmjs.org/postcss-nested/-/postcss-nested-4.2.1.tgz" 1392 | dependencies: 1393 | postcss "^7.0.21" 1394 | postcss-selector-parser "^6.0.2" 1395 | 1396 | postcss-resolve-nested-selector@^0.1.1: 1397 | version "0.1.1" 1398 | resolved "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz" 1399 | 1400 | postcss-selector-parser@^6.0.2: 1401 | version "6.0.2" 1402 | resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz" 1403 | dependencies: 1404 | cssesc "^3.0.0" 1405 | indexes-of "^1.0.1" 1406 | uniq "^1.0.1" 1407 | 1408 | postcss@^6.0.0: 1409 | version "6.0.23" 1410 | resolved "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz" 1411 | dependencies: 1412 | chalk "^2.4.1" 1413 | source-map "^0.6.1" 1414 | supports-color "^5.4.0" 1415 | 1416 | postcss@^7.0.21: 1417 | version "7.0.27" 1418 | resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz" 1419 | dependencies: 1420 | chalk "^2.4.2" 1421 | source-map "^0.6.1" 1422 | supports-color "^6.1.0" 1423 | 1424 | postcss@^8.4.27: 1425 | version "8.4.31" 1426 | resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz" 1427 | integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== 1428 | dependencies: 1429 | nanoid "^3.3.6" 1430 | picocolors "^1.0.0" 1431 | source-map-js "^1.0.2" 1432 | 1433 | prelude-ls@~1.1.2: 1434 | version "1.1.2" 1435 | resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" 1436 | 1437 | progress@^2.0.0: 1438 | version "2.0.3" 1439 | resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" 1440 | 1441 | psl@^1.1.28: 1442 | version "1.8.0" 1443 | resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz" 1444 | 1445 | punycode@^2.1.0, punycode@^2.1.1: 1446 | version "2.1.1" 1447 | resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" 1448 | 1449 | qs@~6.5.2: 1450 | version "6.5.2" 1451 | resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz" 1452 | 1453 | read-pkg-up@^2.0.0: 1454 | version "2.0.0" 1455 | resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz" 1456 | dependencies: 1457 | find-up "^2.0.0" 1458 | read-pkg "^2.0.0" 1459 | 1460 | read-pkg@^2.0.0: 1461 | version "2.0.0" 1462 | resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz" 1463 | dependencies: 1464 | load-json-file "^2.0.0" 1465 | normalize-package-data "^2.3.2" 1466 | path-type "^2.0.0" 1467 | 1468 | regexpp@^2.0.1: 1469 | version "2.0.1" 1470 | resolved "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz" 1471 | 1472 | regexpp@^3.0.0: 1473 | version "3.1.0" 1474 | resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz" 1475 | 1476 | regextras@^0.7.0: 1477 | version "0.7.0" 1478 | resolved "https://registry.npmjs.org/regextras/-/regextras-0.7.0.tgz" 1479 | 1480 | request@^2.88.0: 1481 | version "2.88.2" 1482 | resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz" 1483 | dependencies: 1484 | aws-sign2 "~0.7.0" 1485 | aws4 "^1.8.0" 1486 | caseless "~0.12.0" 1487 | combined-stream "~1.0.6" 1488 | extend "~3.0.2" 1489 | forever-agent "~0.6.1" 1490 | form-data "~2.3.2" 1491 | har-validator "~5.1.3" 1492 | http-signature "~1.2.0" 1493 | is-typedarray "~1.0.0" 1494 | isstream "~0.1.2" 1495 | json-stringify-safe "~5.0.1" 1496 | mime-types "~2.1.19" 1497 | oauth-sign "~0.9.0" 1498 | performance-now "^2.1.0" 1499 | qs "~6.5.2" 1500 | safe-buffer "^5.1.2" 1501 | tough-cookie "~2.5.0" 1502 | tunnel-agent "^0.6.0" 1503 | uuid "^3.3.2" 1504 | 1505 | resolve-from@^4.0.0: 1506 | version "4.0.0" 1507 | resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" 1508 | 1509 | resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1: 1510 | version "1.16.1" 1511 | resolved "https://registry.npmjs.org/resolve/-/resolve-1.16.1.tgz" 1512 | dependencies: 1513 | path-parse "^1.0.6" 1514 | 1515 | restore-cursor@^3.1.0: 1516 | version "3.1.0" 1517 | resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz" 1518 | dependencies: 1519 | onetime "^5.1.0" 1520 | signal-exit "^3.0.2" 1521 | 1522 | rimraf@2.6.3: 1523 | version "2.6.3" 1524 | resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz" 1525 | dependencies: 1526 | glob "^7.1.3" 1527 | 1528 | rollup@^3.27.1: 1529 | version "3.29.4" 1530 | resolved "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz" 1531 | integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== 1532 | optionalDependencies: 1533 | fsevents "~2.3.2" 1534 | 1535 | run-async@^2.4.0: 1536 | version "2.4.0" 1537 | resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz" 1538 | dependencies: 1539 | is-promise "^2.1.0" 1540 | 1541 | rxjs@^6.5.3: 1542 | version "6.5.5" 1543 | resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz" 1544 | dependencies: 1545 | tslib "^1.9.0" 1546 | 1547 | safe-buffer@^5.0.1, safe-buffer@^5.1.2: 1548 | version "5.2.0" 1549 | resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz" 1550 | 1551 | "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: 1552 | version "2.1.2" 1553 | resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" 1554 | 1555 | schema-utils@^2.6.5: 1556 | version "2.6.6" 1557 | resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.6.tgz" 1558 | dependencies: 1559 | ajv "^6.12.0" 1560 | ajv-keywords "^3.4.1" 1561 | 1562 | "semver@2 || 3 || 4 || 5", semver@^5.5.0: 1563 | version "5.7.1" 1564 | resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" 1565 | 1566 | semver@^6.1.0, semver@^6.1.2, semver@^6.3.0: 1567 | version "6.3.0" 1568 | resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" 1569 | 1570 | shebang-command@^1.2.0: 1571 | version "1.2.0" 1572 | resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" 1573 | dependencies: 1574 | shebang-regex "^1.0.0" 1575 | 1576 | shebang-regex@^1.0.0: 1577 | version "1.0.0" 1578 | resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" 1579 | 1580 | signal-exit@^3.0.2: 1581 | version "3.0.3" 1582 | resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz" 1583 | 1584 | slice-ansi@^2.1.0: 1585 | version "2.1.0" 1586 | resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz" 1587 | dependencies: 1588 | ansi-styles "^3.2.0" 1589 | astral-regex "^1.0.0" 1590 | is-fullwidth-code-point "^2.0.0" 1591 | 1592 | source-map-js@^1.0.2: 1593 | version "1.2.0" 1594 | resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz" 1595 | integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== 1596 | 1597 | source-map@^0.6.1: 1598 | version "0.6.1" 1599 | resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" 1600 | 1601 | spdx-correct@^3.0.0: 1602 | version "3.1.0" 1603 | resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz" 1604 | dependencies: 1605 | spdx-expression-parse "^3.0.0" 1606 | spdx-license-ids "^3.0.0" 1607 | 1608 | spdx-exceptions@^2.1.0: 1609 | version "2.3.0" 1610 | resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz" 1611 | 1612 | spdx-expression-parse@^3.0.0: 1613 | version "3.0.0" 1614 | resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz" 1615 | dependencies: 1616 | spdx-exceptions "^2.1.0" 1617 | spdx-license-ids "^3.0.0" 1618 | 1619 | spdx-license-ids@^3.0.0: 1620 | version "3.0.5" 1621 | resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz" 1622 | 1623 | sprintf-js@~1.0.2: 1624 | version "1.0.3" 1625 | resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" 1626 | 1627 | sshpk@^1.7.0: 1628 | version "1.16.1" 1629 | resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz" 1630 | dependencies: 1631 | asn1 "~0.2.3" 1632 | assert-plus "^1.0.0" 1633 | bcrypt-pbkdf "^1.0.0" 1634 | dashdash "^1.12.0" 1635 | ecc-jsbn "~0.1.1" 1636 | getpass "^0.1.1" 1637 | jsbn "~0.1.0" 1638 | safer-buffer "^2.0.2" 1639 | tweetnacl "~0.14.0" 1640 | 1641 | string-width@^3.0.0: 1642 | version "3.1.0" 1643 | resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz" 1644 | dependencies: 1645 | emoji-regex "^7.0.1" 1646 | is-fullwidth-code-point "^2.0.0" 1647 | strip-ansi "^5.1.0" 1648 | 1649 | string-width@^4.1.0: 1650 | version "4.2.0" 1651 | resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz" 1652 | dependencies: 1653 | emoji-regex "^8.0.0" 1654 | is-fullwidth-code-point "^3.0.0" 1655 | strip-ansi "^6.0.0" 1656 | 1657 | string.prototype.trimend@^1.0.0: 1658 | version "1.0.1" 1659 | resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz" 1660 | dependencies: 1661 | define-properties "^1.1.3" 1662 | es-abstract "^1.17.5" 1663 | 1664 | string.prototype.trimleft@^2.1.1: 1665 | version "2.1.2" 1666 | resolved "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz" 1667 | dependencies: 1668 | define-properties "^1.1.3" 1669 | es-abstract "^1.17.5" 1670 | string.prototype.trimstart "^1.0.0" 1671 | 1672 | string.prototype.trimright@^2.1.1: 1673 | version "2.1.2" 1674 | resolved "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz" 1675 | dependencies: 1676 | define-properties "^1.1.3" 1677 | es-abstract "^1.17.5" 1678 | string.prototype.trimend "^1.0.0" 1679 | 1680 | string.prototype.trimstart@^1.0.0: 1681 | version "1.0.1" 1682 | resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz" 1683 | dependencies: 1684 | define-properties "^1.1.3" 1685 | es-abstract "^1.17.5" 1686 | 1687 | strip-ansi@^5.1.0, strip-ansi@^5.2.0: 1688 | version "5.2.0" 1689 | resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz" 1690 | dependencies: 1691 | ansi-regex "^4.1.0" 1692 | 1693 | strip-ansi@^6.0.0: 1694 | version "6.0.0" 1695 | resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz" 1696 | dependencies: 1697 | ansi-regex "^5.0.0" 1698 | 1699 | strip-bom@^3.0.0: 1700 | version "3.0.0" 1701 | resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" 1702 | 1703 | strip-json-comments@^3.0.1: 1704 | version "3.1.0" 1705 | resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz" 1706 | 1707 | supports-color@^5.3.0, supports-color@^5.4.0: 1708 | version "5.5.0" 1709 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" 1710 | dependencies: 1711 | has-flag "^3.0.0" 1712 | 1713 | supports-color@^6.1.0: 1714 | version "6.1.0" 1715 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz" 1716 | dependencies: 1717 | has-flag "^3.0.0" 1718 | 1719 | supports-color@^7.1.0: 1720 | version "7.1.0" 1721 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz" 1722 | dependencies: 1723 | has-flag "^4.0.0" 1724 | 1725 | table@^5.2.3: 1726 | version "5.4.6" 1727 | resolved "https://registry.npmjs.org/table/-/table-5.4.6.tgz" 1728 | dependencies: 1729 | ajv "^6.10.2" 1730 | lodash "^4.17.14" 1731 | slice-ansi "^2.1.0" 1732 | string-width "^3.0.0" 1733 | 1734 | text-table@^0.2.0: 1735 | version "0.2.0" 1736 | resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" 1737 | 1738 | through@^2.3.6: 1739 | version "2.3.8" 1740 | resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" 1741 | 1742 | tmp@^0.0.33: 1743 | version "0.0.33" 1744 | resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz" 1745 | dependencies: 1746 | os-tmpdir "~1.0.2" 1747 | 1748 | tough-cookie@~2.5.0: 1749 | version "2.5.0" 1750 | resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz" 1751 | dependencies: 1752 | psl "^1.1.28" 1753 | punycode "^2.1.1" 1754 | 1755 | tslib@^1.8.1, tslib@^1.9.0: 1756 | version "1.11.1" 1757 | resolved "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz" 1758 | 1759 | tsutils@^3.17.1: 1760 | version "3.17.1" 1761 | resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz" 1762 | dependencies: 1763 | tslib "^1.8.1" 1764 | 1765 | tunnel-agent@^0.6.0: 1766 | version "0.6.0" 1767 | resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" 1768 | dependencies: 1769 | safe-buffer "^5.0.1" 1770 | 1771 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 1772 | version "0.14.5" 1773 | resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" 1774 | 1775 | type-check@~0.3.2: 1776 | version "0.3.2" 1777 | resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" 1778 | dependencies: 1779 | prelude-ls "~1.1.2" 1780 | 1781 | type-fest@^0.11.0: 1782 | version "0.11.0" 1783 | resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz" 1784 | 1785 | type-fest@^0.8.1: 1786 | version "0.8.1" 1787 | resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" 1788 | 1789 | typescript@^3.7.3: 1790 | version "3.8.3" 1791 | resolved "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz" 1792 | 1793 | uniq@^1.0.1: 1794 | version "1.0.1" 1795 | resolved "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz" 1796 | 1797 | universalify@^1.0.0: 1798 | version "1.0.0" 1799 | resolved "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz" 1800 | 1801 | uri-js@^4.2.2: 1802 | version "4.2.2" 1803 | resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz" 1804 | dependencies: 1805 | punycode "^2.1.0" 1806 | 1807 | uuid@^3.3.2: 1808 | version "3.4.0" 1809 | resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" 1810 | 1811 | v8-compile-cache@^2.0.3: 1812 | version "2.1.0" 1813 | resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz" 1814 | 1815 | validate-npm-package-license@^3.0.1: 1816 | version "3.0.4" 1817 | resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz" 1818 | dependencies: 1819 | spdx-correct "^3.0.0" 1820 | spdx-expression-parse "^3.0.0" 1821 | 1822 | verror@1.10.0: 1823 | version "1.10.0" 1824 | resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz" 1825 | dependencies: 1826 | assert-plus "^1.0.0" 1827 | core-util-is "1.0.2" 1828 | extsprintf "^1.2.0" 1829 | 1830 | vite-plugin-css-injected-by-js@^3.3.0: 1831 | version "3.3.0" 1832 | resolved "https://registry.npmjs.org/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.3.0.tgz" 1833 | integrity sha512-xG+jyHNCmUqi/TXp6q88wTJGeAOrNLSyUUTp4qEQ9QZLGcHWQQsCsSSKa59rPMQr8sOzfzmWDd8enGqfH/dBew== 1834 | 1835 | vite@^4.5.0: 1836 | version "4.5.0" 1837 | resolved "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz" 1838 | integrity sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw== 1839 | dependencies: 1840 | esbuild "^0.18.10" 1841 | postcss "^8.4.27" 1842 | rollup "^3.27.1" 1843 | optionalDependencies: 1844 | fsevents "~2.3.2" 1845 | 1846 | which@^1.2.9: 1847 | version "1.3.1" 1848 | resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" 1849 | dependencies: 1850 | isexe "^2.0.0" 1851 | 1852 | word-wrap@~1.2.3: 1853 | version "1.2.3" 1854 | resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" 1855 | 1856 | wrappy@1: 1857 | version "1.0.2" 1858 | resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" 1859 | 1860 | write@1.0.3: 1861 | version "1.0.3" 1862 | resolved "https://registry.npmjs.org/write/-/write-1.0.3.tgz" 1863 | dependencies: 1864 | mkdirp "^0.5.1" 1865 | --------------------------------------------------------------------------------