├── .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 |  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 |  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