You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					645 lines
				
				21 KiB
			
		
		
			
		
	
	
					645 lines
				
				21 KiB
			| 
											8 months ago
										 | const e = (() => { | ||
|  |     if ("undefined" == typeof self) return !1; | ||
|  |     if ("top" in self && self !== top) try { | ||
|  |       top.window.document._ = 0; | ||
|  |     } catch (e) { | ||
|  |       return !1; | ||
|  |     } | ||
|  |     return "showOpenFilePicker" in self; | ||
|  |   })(), | ||
|  |   t = e ? Promise.resolve().then(function () { | ||
|  |     return l; | ||
|  |   }) : Promise.resolve().then(function () { | ||
|  |     return v; | ||
|  |   }); | ||
|  | async function n() { | ||
|  |   return (await t).default(...arguments); | ||
|  | } | ||
|  | e ? Promise.resolve().then(function () { | ||
|  |   return y; | ||
|  | }) : Promise.resolve().then(function () { | ||
|  |   return b; | ||
|  | }); | ||
|  | const a = e ? Promise.resolve().then(function () { | ||
|  |   return m; | ||
|  | }) : Promise.resolve().then(function () { | ||
|  |   return k; | ||
|  | }); | ||
|  | async function o() { | ||
|  |   return (await a).default(...arguments); | ||
|  | } | ||
|  | const s = async e => { | ||
|  |   const t = await e.getFile(); | ||
|  |   return t.handle = e, t; | ||
|  | }; | ||
|  | var c = async function () { | ||
|  |     let e = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [{}]; | ||
|  |     Array.isArray(e) || (e = [e]); | ||
|  |     const t = []; | ||
|  |     e.forEach((e, n) => { | ||
|  |       t[n] = { | ||
|  |         description: e.description || "Files", | ||
|  |         accept: {} | ||
|  |       }, e.mimeTypes ? e.mimeTypes.map(r => { | ||
|  |         t[n].accept[r] = e.extensions || []; | ||
|  |       }) : t[n].accept["*/*"] = e.extensions || []; | ||
|  |     }); | ||
|  |     const n = await window.showOpenFilePicker({ | ||
|  |         id: e[0].id, | ||
|  |         startIn: e[0].startIn, | ||
|  |         types: t, | ||
|  |         multiple: e[0].multiple || !1, | ||
|  |         excludeAcceptAllOption: e[0].excludeAcceptAllOption || !1 | ||
|  |       }), | ||
|  |       r = await Promise.all(n.map(s)); | ||
|  |     return e[0].multiple ? r : r[0]; | ||
|  |   }, | ||
|  |   l = { | ||
|  |     __proto__: null, | ||
|  |     default: c | ||
|  |   }; | ||
|  | function u(e) { | ||
|  |   function t(e) { | ||
|  |     if (Object(e) !== e) return Promise.reject(new TypeError(e + " is not an object.")); | ||
|  |     var t = e.done; | ||
|  |     return Promise.resolve(e.value).then(function (e) { | ||
|  |       return { | ||
|  |         value: e, | ||
|  |         done: t | ||
|  |       }; | ||
|  |     }); | ||
|  |   } | ||
|  |   return u = function (e) { | ||
|  |     this.s = e, this.n = e.next; | ||
|  |   }, u.prototype = { | ||
|  |     s: null, | ||
|  |     n: null, | ||
|  |     next: function () { | ||
|  |       return t(this.n.apply(this.s, arguments)); | ||
|  |     }, | ||
|  |     return: function (e) { | ||
|  |       var n = this.s.return; | ||
|  |       return void 0 === n ? Promise.resolve({ | ||
|  |         value: e, | ||
|  |         done: !0 | ||
|  |       }) : t(n.apply(this.s, arguments)); | ||
|  |     }, | ||
|  |     throw: function (e) { | ||
|  |       var n = this.s.return; | ||
|  |       return void 0 === n ? Promise.reject(e) : t(n.apply(this.s, arguments)); | ||
|  |     } | ||
|  |   }, new u(e); | ||
|  | } | ||
|  | const p = async function (e, t) { | ||
|  |   let n = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : e.name; | ||
|  |   let r = arguments.length > 3 ? arguments[3] : undefined; | ||
|  |   const i = [], | ||
|  |     a = []; | ||
|  |   var o, | ||
|  |     s = !1, | ||
|  |     c = !1; | ||
|  |   try { | ||
|  |     for (var l, d = function (e) { | ||
|  |         var t, | ||
|  |           n, | ||
|  |           r, | ||
|  |           i = 2; | ||
|  |         for ("undefined" != typeof Symbol && (n = Symbol.asyncIterator, r = Symbol.iterator); i--;) { | ||
|  |           if (n && null != (t = e[n])) return t.call(e); | ||
|  |           if (r && null != (t = e[r])) return new u(t.call(e)); | ||
|  |           n = "@@asyncIterator", r = "@@iterator"; | ||
|  |         } | ||
|  |         throw new TypeError("Object is not async iterable"); | ||
|  |       }(e.values()); s = !(l = await d.next()).done; s = !1) { | ||
|  |       const o = l.value, | ||
|  |         s = `${n}/${o.name}`; | ||
|  |       "file" === o.kind ? a.push(o.getFile().then(t => (t.directoryHandle = e, t.handle = o, Object.defineProperty(t, "webkitRelativePath", { | ||
|  |         configurable: !0, | ||
|  |         enumerable: !0, | ||
|  |         get: () => s | ||
|  |       })))) : "directory" !== o.kind || !t || r && r(o) || i.push(p(o, t, s, r)); | ||
|  |     } | ||
|  |   } catch (e) { | ||
|  |     c = !0, o = e; | ||
|  |   } finally { | ||
|  |     try { | ||
|  |       s && null != d.return && (await d.return()); | ||
|  |     } finally { | ||
|  |       if (c) throw o; | ||
|  |     } | ||
|  |   } | ||
|  |   return [...(await Promise.all(i)).flat(), ...(await Promise.all(a))]; | ||
|  | }; | ||
|  | var d = async function () { | ||
|  |     let e = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
|  |     e.recursive = e.recursive || !1, e.mode = e.mode || "read"; | ||
|  |     const t = await window.showDirectoryPicker({ | ||
|  |       id: e.id, | ||
|  |       startIn: e.startIn, | ||
|  |       mode: e.mode | ||
|  |     }); | ||
|  |     return (await (await t.values()).next()).done ? [t] : p(t, e.recursive, void 0, e.skipDirectory); | ||
|  |   }, | ||
|  |   y = { | ||
|  |     __proto__: null, | ||
|  |     default: d | ||
|  |   }, | ||
|  |   f = async function (e) { | ||
|  |     let t = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [{}]; | ||
|  |     let n = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
|  |     let r = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : !1; | ||
|  |     let i = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null; | ||
|  |     Array.isArray(t) || (t = [t]), t[0].fileName = t[0].fileName || "Untitled"; | ||
|  |     const a = []; | ||
|  |     let o = null; | ||
|  |     if (e instanceof Blob && e.type ? o = e.type : e.headers && e.headers.get("content-type") && (o = e.headers.get("content-type")), t.forEach((e, t) => { | ||
|  |       a[t] = { | ||
|  |         description: e.description || "Files", | ||
|  |         accept: {} | ||
|  |       }, e.mimeTypes ? (0 === t && o && e.mimeTypes.push(o), e.mimeTypes.map(n => { | ||
|  |         a[t].accept[n] = e.extensions || []; | ||
|  |       })) : o ? a[t].accept[o] = e.extensions || [] : a[t].accept["*/*"] = e.extensions || []; | ||
|  |     }), n) try { | ||
|  |       await n.getFile(); | ||
|  |     } catch (e) { | ||
|  |       if (n = null, r) throw e; | ||
|  |     } | ||
|  |     const s = n || (await window.showSaveFilePicker({ | ||
|  |       suggestedName: t[0].fileName, | ||
|  |       id: t[0].id, | ||
|  |       startIn: t[0].startIn, | ||
|  |       types: a, | ||
|  |       excludeAcceptAllOption: t[0].excludeAcceptAllOption || !1 | ||
|  |     })); | ||
|  |     !n && i && i(s); | ||
|  |     const c = await s.createWritable(); | ||
|  |     if ("stream" in e) { | ||
|  |       const t = e.stream(); | ||
|  |       return await t.pipeTo(c), s; | ||
|  |     } | ||
|  |     return "body" in e ? (await e.body.pipeTo(c), s) : (await c.write(await e), await c.close(), s); | ||
|  |   }, | ||
|  |   m = { | ||
|  |     __proto__: null, | ||
|  |     default: f | ||
|  |   }, | ||
|  |   w = async function () { | ||
|  |     let e = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [{}]; | ||
|  |     return Array.isArray(e) || (e = [e]), new Promise((t, n) => { | ||
|  |       const r = document.createElement("input"); | ||
|  |       r.type = "file"; | ||
|  |       const i = [...e.map(e => e.mimeTypes || []), ...e.map(e => e.extensions || [])].join(); | ||
|  |       r.multiple = e[0].multiple || !1, r.accept = i || "", r.style.display = "none", document.body.append(r); | ||
|  |       const a = e => { | ||
|  |           "function" == typeof o && o(), t(e); | ||
|  |         }, | ||
|  |         o = e[0].legacySetup && e[0].legacySetup(a, () => o(n), r), | ||
|  |         s = () => { | ||
|  |           window.removeEventListener("focus", s), r.remove(); | ||
|  |         }; | ||
|  |       r.addEventListener("click", () => { | ||
|  |         window.addEventListener("focus", s); | ||
|  |       }), r.addEventListener("change", () => { | ||
|  |         window.removeEventListener("focus", s), r.remove(), a(r.multiple ? Array.from(r.files) : r.files[0]); | ||
|  |       }), "showPicker" in HTMLInputElement.prototype ? r.showPicker() : r.click(); | ||
|  |     }); | ||
|  |   }, | ||
|  |   v = { | ||
|  |     __proto__: null, | ||
|  |     default: w | ||
|  |   }, | ||
|  |   h = async function () { | ||
|  |     let e = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [{}]; | ||
|  |     return Array.isArray(e) || (e = [e]), e[0].recursive = e[0].recursive || !1, new Promise((t, n) => { | ||
|  |       const r = document.createElement("input"); | ||
|  |       r.type = "file", r.webkitdirectory = !0; | ||
|  |       const i = e => { | ||
|  |           "function" == typeof a && a(), t(e); | ||
|  |         }, | ||
|  |         a = e[0].legacySetup && e[0].legacySetup(i, () => a(n), r); | ||
|  |       r.addEventListener("change", () => { | ||
|  |         let t = Array.from(r.files); | ||
|  |         e[0].recursive ? e[0].recursive && e[0].skipDirectory && (t = t.filter(t => t.webkitRelativePath.split("/").every(t => !e[0].skipDirectory({ | ||
|  |           name: t, | ||
|  |           kind: "directory" | ||
|  |         })))) : t = t.filter(e => 2 === e.webkitRelativePath.split("/").length), i(t); | ||
|  |       }), "showPicker" in HTMLInputElement.prototype ? r.showPicker() : r.click(); | ||
|  |     }); | ||
|  |   }, | ||
|  |   b = { | ||
|  |     __proto__: null, | ||
|  |     default: h | ||
|  |   }, | ||
|  |   P = async function (e) { | ||
|  |     let t = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
|  |     Array.isArray(t) && (t = t[0]); | ||
|  |     const n = document.createElement("a"); | ||
|  |     let r = e; | ||
|  |     "body" in e && (r = await async function (e, t) { | ||
|  |       const n = e.getReader(), | ||
|  |         r = new ReadableStream({ | ||
|  |           start: e => async function t() { | ||
|  |             return n.read().then(_ref => { | ||
|  |               let { | ||
|  |                 done: n, | ||
|  |                 value: r | ||
|  |               } = _ref; | ||
|  |               if (!n) return e.enqueue(r), t(); | ||
|  |               e.close(); | ||
|  |             }); | ||
|  |           }() | ||
|  |         }), | ||
|  |         i = new Response(r), | ||
|  |         a = await i.blob(); | ||
|  |       return n.releaseLock(), new Blob([a], { | ||
|  |         type: t | ||
|  |       }); | ||
|  |     }(e.body, e.headers.get("content-type"))), n.download = t.fileName || "Untitled", n.href = URL.createObjectURL(await r); | ||
|  |     const i = () => { | ||
|  |         "function" == typeof a && a(); | ||
|  |       }, | ||
|  |       a = t.legacySetup && t.legacySetup(i, () => a(), n); | ||
|  |     return n.addEventListener("click", () => { | ||
|  |       setTimeout(() => URL.revokeObjectURL(n.href), 3e4), i(); | ||
|  |     }), n.click(), null; | ||
|  |   }, | ||
|  |   k = { | ||
|  |     __proto__: null, | ||
|  |     default: P | ||
|  |   }; | ||
|  | 
 | ||
|  | function __variableDynamicImportRuntime0__(path) { | ||
|  |   switch (path) { | ||
|  |     case './locale/en.js': | ||
|  |       return Promise.resolve().then(function () { return en$1; }); | ||
|  |     case './locale/fr.js': | ||
|  |       return Promise.resolve().then(function () { return fr$1; }); | ||
|  |     case './locale/sv.js': | ||
|  |       return Promise.resolve().then(function () { return sv$1; }); | ||
|  |     case './locale/tr.js': | ||
|  |       return Promise.resolve().then(function () { return tr$1; }); | ||
|  |     case './locale/uk.js': | ||
|  |       return Promise.resolve().then(function () { return uk$1; }); | ||
|  |     case './locale/zh-CN.js': | ||
|  |       return Promise.resolve().then(function () { return zhCN$1; }); | ||
|  |     default: | ||
|  |       return new Promise(function (resolve, reject) { | ||
|  |         (typeof queueMicrotask === 'function' ? queueMicrotask : setTimeout)(reject.bind(null, new Error("Unknown variable dynamic import: " + path))); | ||
|  |       }); | ||
|  |   } | ||
|  | } | ||
|  | const name = 'opensave'; | ||
|  | let handle = null; | ||
|  | const loadExtensionTranslation = async function (svgEditor) { | ||
|  |   let translationModule; | ||
|  |   const lang = svgEditor.configObj.pref('lang'); | ||
|  |   try { | ||
|  |     translationModule = await __variableDynamicImportRuntime0__(`./locale/${lang}.js`); | ||
|  |   } catch (_error) { | ||
|  |     console.warn(`Missing translation (${lang}) for ${name} - using 'en'`); | ||
|  |     translationModule = await Promise.resolve().then(function () { return en$1; }); | ||
|  |   } | ||
|  |   svgEditor.i18next.addResourceBundle(lang, 'translation', translationModule.default, true, true); | ||
|  | }; | ||
|  | var extOpensave = { | ||
|  |   name, | ||
|  |   async init(_S) { | ||
|  |     const svgEditor = this; | ||
|  |     const { | ||
|  |       svgCanvas | ||
|  |     } = svgEditor; | ||
|  |     const { | ||
|  |       $id, | ||
|  |       $click | ||
|  |     } = svgCanvas; | ||
|  |     await loadExtensionTranslation(svgEditor); | ||
|  |     /** | ||
|  |     * @param {Event} e | ||
|  |     * @returns {void} | ||
|  |     */ | ||
|  |     const importImage = e => { | ||
|  |       $id('se-prompt-dialog').title = this.i18next.t('notification.loadingImage'); | ||
|  |       $id('se-prompt-dialog').setAttribute('close', false); | ||
|  |       e.stopPropagation(); | ||
|  |       e.preventDefault(); | ||
|  |       const file = e.type === 'drop' ? e.dataTransfer.files[0] : e.currentTarget.files[0]; | ||
|  |       if (!file) { | ||
|  |         $id('se-prompt-dialog').setAttribute('close', true); | ||
|  |         return; | ||
|  |       } | ||
|  |       if (!file.type.includes('image')) { | ||
|  |         return; | ||
|  |       } | ||
|  |       // Detected an image
 | ||
|  |       // svg handling
 | ||
|  |       let reader; | ||
|  |       if (file.type.includes('svg')) { | ||
|  |         reader = new FileReader(); | ||
|  |         reader.onloadend = ev => { | ||
|  |           // imgImport.shiftKey (shift key pressed or not) will determine if import should preserve dimension)
 | ||
|  |           const newElement = this.svgCanvas.importSvgString(ev.target.result, imgImport.shiftKey); | ||
|  |           this.svgCanvas.alignSelectedElements('m', 'page'); | ||
|  |           this.svgCanvas.alignSelectedElements('c', 'page'); | ||
|  |           // highlight imported element, otherwise we get strange empty selectbox
 | ||
|  |           this.svgCanvas.selectOnly([newElement]); | ||
|  |           $id('se-prompt-dialog').setAttribute('close', true); | ||
|  |         }; | ||
|  |         reader.readAsText(file); | ||
|  |       } else { | ||
|  |         // bitmap handling
 | ||
|  |         reader = new FileReader(); | ||
|  |         reader.onloadend = _ref => { | ||
|  |           let { | ||
|  |             target: { | ||
|  |               result | ||
|  |             } | ||
|  |           } = _ref; | ||
|  |           /** | ||
|  |               * Insert the new image until we know its dimensions. | ||
|  |               * @param {Float} imageWidth | ||
|  |               * @param {Float} imageHeight | ||
|  |               * @returns {void} | ||
|  |               */ | ||
|  |           const insertNewImage = (imageWidth, imageHeight) => { | ||
|  |             const newImage = this.svgCanvas.addSVGElementsFromJson({ | ||
|  |               element: 'image', | ||
|  |               attr: { | ||
|  |                 x: 0, | ||
|  |                 y: 0, | ||
|  |                 width: imageWidth, | ||
|  |                 height: imageHeight, | ||
|  |                 id: this.svgCanvas.getNextId(), | ||
|  |                 style: 'pointer-events:inherit' | ||
|  |               } | ||
|  |             }); | ||
|  |             this.svgCanvas.setHref(newImage, result); | ||
|  |             this.svgCanvas.selectOnly([newImage]); | ||
|  |             this.svgCanvas.alignSelectedElements('m', 'page'); | ||
|  |             this.svgCanvas.alignSelectedElements('c', 'page'); | ||
|  |             this.topPanel.updateContextPanel(); | ||
|  |             $id('se-prompt-dialog').setAttribute('close', true); | ||
|  |           }; | ||
|  |           // create dummy img so we know the default dimensions
 | ||
|  |           let imgWidth = 100; | ||
|  |           let imgHeight = 100; | ||
|  |           const img = new Image(); | ||
|  |           img.style.opacity = 0; | ||
|  |           img.addEventListener('load', () => { | ||
|  |             imgWidth = img.offsetWidth || img.naturalWidth || img.width; | ||
|  |             imgHeight = img.offsetHeight || img.naturalHeight || img.height; | ||
|  |             insertNewImage(imgWidth, imgHeight); | ||
|  |           }); | ||
|  |           img.src = result; | ||
|  |         }; | ||
|  |         reader.readAsDataURL(file); | ||
|  |       } | ||
|  |     }; | ||
|  |     // create an input with type file to open the filesystem dialog
 | ||
|  |     const imgImport = document.createElement('input'); | ||
|  |     imgImport.type = 'file'; | ||
|  |     imgImport.addEventListener('change', importImage); | ||
|  |     // dropping a svg file will import it in the svg as well
 | ||
|  |     this.workarea.addEventListener('drop', importImage); | ||
|  |     const clickClear = async function () { | ||
|  |       const [x, y] = svgEditor.configObj.curConfig.dimensions; | ||
|  |       const ok = await seConfirm(svgEditor.i18next.t('notification.QwantToClear')); | ||
|  |       if (ok === 'Cancel') { | ||
|  |         return; | ||
|  |       } | ||
|  |       svgEditor.leftPanel.clickSelect(); | ||
|  |       svgEditor.svgCanvas.clear(); | ||
|  |       svgEditor.svgCanvas.setResolution(x, y); | ||
|  |       svgEditor.updateCanvas(true); | ||
|  |       svgEditor.zoomImage(); | ||
|  |       svgEditor.layersPanel.populateLayers(); | ||
|  |       svgEditor.topPanel.updateContextPanel(); | ||
|  |       svgEditor.topPanel.updateTitle('untitled.svg'); | ||
|  |     }; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * By default,  this.editor.svgCanvas.open() is a no-op. It is up to an extension | ||
|  |      *  mechanism (opera widget, etc.) to call `setCustomHandlers()` which | ||
|  |      *  will make it do something. | ||
|  |      * @returns {void} | ||
|  |      */ | ||
|  |     const clickOpen = async function () { | ||
|  |       // ask user before clearing an unsaved SVG
 | ||
|  |       const response = await svgEditor.openPrep(); | ||
|  |       if (response === 'Cancel') { | ||
|  |         return; | ||
|  |       } | ||
|  |       svgCanvas.clear(); | ||
|  |       try { | ||
|  |         const blob = await n({ | ||
|  |           mimeTypes: ['image/*'] | ||
|  |         }); | ||
|  |         const svgContent = await blob.text(); | ||
|  |         await svgEditor.loadSvgString(svgContent); | ||
|  |         svgEditor.updateCanvas(); | ||
|  |         handle = blob.handle; | ||
|  |         svgEditor.topPanel.updateTitle(blob.name); | ||
|  |         svgEditor.svgCanvas.runExtensions('onOpenedDocument', { | ||
|  |           name: blob.name, | ||
|  |           lastModified: blob.lastModified, | ||
|  |           size: blob.size, | ||
|  |           type: blob.type | ||
|  |         }); | ||
|  |       } catch (err) { | ||
|  |         if (err.name !== 'AbortError') { | ||
|  |           return console.error(err); | ||
|  |         } | ||
|  |       } | ||
|  |     }; | ||
|  |     const b64toBlob = function (b64Data) { | ||
|  |       let contentType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; | ||
|  |       let sliceSize = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 512; | ||
|  |       const byteCharacters = atob(b64Data); | ||
|  |       const byteArrays = []; | ||
|  |       for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) { | ||
|  |         const slice = byteCharacters.slice(offset, offset + sliceSize); | ||
|  |         const byteNumbers = new Array(slice.length); | ||
|  |         for (let i = 0; i < slice.length; i++) { | ||
|  |           byteNumbers[i] = slice.charCodeAt(i); | ||
|  |         } | ||
|  |         const byteArray = new Uint8Array(byteNumbers); | ||
|  |         byteArrays.push(byteArray); | ||
|  |       } | ||
|  |       const blob = new Blob(byteArrays, { | ||
|  |         type: contentType | ||
|  |       }); | ||
|  |       return blob; | ||
|  |     }; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * | ||
|  |      * @returns {void} | ||
|  |      */ | ||
|  |     const clickSave = async function (type) { | ||
|  |       const $editorDialog = $id('se-svg-editor-dialog'); | ||
|  |       const editingsource = $editorDialog.getAttribute('dialog') === 'open'; | ||
|  |       if (editingsource) { | ||
|  |         svgEditor.saveSourceEditor(); | ||
|  |       } else { | ||
|  |         // In the future, more options can be provided here
 | ||
|  |         const saveOpts = { | ||
|  |           images: svgEditor.configObj.pref('img_save'), | ||
|  |           round_digits: 2 | ||
|  |         }; | ||
|  |         // remove the selected outline before serializing
 | ||
|  |         svgCanvas.clearSelection(); | ||
|  |         // Update save options if provided
 | ||
|  |         if (saveOpts) { | ||
|  |           const saveOptions = svgCanvas.mergeDeep(svgCanvas.getSvgOption(), saveOpts); | ||
|  |           for (const [key, value] of Object.entries(saveOptions)) { | ||
|  |             svgCanvas.setSvgOption(key, value); | ||
|  |           } | ||
|  |         } | ||
|  |         svgCanvas.setSvgOption('apply', true); | ||
|  | 
 | ||
|  |         // no need for doctype, see https://jwatt.org/svg/authoring/#doctype-declaration
 | ||
|  |         const svg = '<?xml version="1.0"?>\n' + svgCanvas.svgCanvasToString(); | ||
|  |         const b64Data = svgCanvas.encode64(svg); | ||
|  |         const blob = b64toBlob(b64Data, 'image/svg+xml'); | ||
|  |         try { | ||
|  |           if (type === 'save' && handle !== null) { | ||
|  |             const throwIfExistingHandleNotGood = false; | ||
|  |             handle = await o(blob, { | ||
|  |               fileName: 'untitled.svg', | ||
|  |               extensions: ['.svg'] | ||
|  |             }, handle, throwIfExistingHandleNotGood); | ||
|  |           } else { | ||
|  |             handle = await o(blob, { | ||
|  |               fileName: svgEditor.title, | ||
|  |               extensions: ['.svg'] | ||
|  |             }); | ||
|  |           } | ||
|  |           svgEditor.topPanel.updateTitle(handle.name); | ||
|  |           svgCanvas.runExtensions('onSavedDocument', { | ||
|  |             name: handle.name, | ||
|  |             kind: handle.kind | ||
|  |           }); | ||
|  |         } catch (err) { | ||
|  |           if (err.name !== 'AbortError') { | ||
|  |             return console.error(err); | ||
|  |           } | ||
|  |         } | ||
|  |       } | ||
|  |     }; | ||
|  |     return { | ||
|  |       name: svgEditor.i18next.t(`${name}:name`), | ||
|  |       // The callback should be used to load the DOM with the appropriate UI items
 | ||
|  |       callback() { | ||
|  |         const buttonTemplate = `
 | ||
|  |         <se-menu-item id="tool_clear" label="opensave.new_doc" shortcut="N" src="new.svg"></se-menu-item>`; | ||
|  |         svgCanvas.insertChildAtIndex($id('main_button'), buttonTemplate, 0); | ||
|  |         const openButtonTemplate = '<se-menu-item id="tool_open" label="opensave.open_image_doc" src="open.svg"></se-menu-item>'; | ||
|  |         svgCanvas.insertChildAtIndex($id('main_button'), openButtonTemplate, 1); | ||
|  |         const saveButtonTemplate = '<se-menu-item id="tool_save" label="opensave.save_doc" shortcut="S" src="saveImg.svg"></se-menu-item>'; | ||
|  |         svgCanvas.insertChildAtIndex($id('main_button'), saveButtonTemplate, 2); | ||
|  |         const saveAsButtonTemplate = '<se-menu-item id="tool_save_as" label="opensave.save_as_doc" src="saveImg.svg"></se-menu-item>'; | ||
|  |         svgCanvas.insertChildAtIndex($id('main_button'), saveAsButtonTemplate, 3); | ||
|  |         const importButtonTemplate = '<se-menu-item id="tool_import" label="tools.import_doc" src="importImg.svg"></se-menu-item>'; | ||
|  |         svgCanvas.insertChildAtIndex($id('main_button'), importButtonTemplate, 4); | ||
|  | 
 | ||
|  |         // handler
 | ||
|  |         $click($id('tool_clear'), clickClear.bind(this)); | ||
|  |         $click($id('tool_open'), clickOpen.bind(this)); | ||
|  |         $click($id('tool_save'), clickSave.bind(this, 'save')); | ||
|  |         $click($id('tool_save_as'), clickSave.bind(this, 'saveas')); | ||
|  |         // tool_import pressed with shiftKey will not scale the SVG
 | ||
|  |         $click($id('tool_import'), ev => { | ||
|  |           imgImport.shiftKey = ev.shiftKey; | ||
|  |           imgImport.click(); | ||
|  |         }); | ||
|  |       } | ||
|  |     }; | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | var en = { | ||
|  |   opensave: { | ||
|  |     new_doc: 'New Image', | ||
|  |     open_image_doc: 'Open SVG', | ||
|  |     save_doc: 'Save SVG', | ||
|  |     save_as_doc: 'Save as SVG' | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | var en$1 = /*#__PURE__*/Object.freeze({ | ||
|  |   __proto__: null, | ||
|  |   default: en | ||
|  | }); | ||
|  | 
 | ||
|  | var fr = { | ||
|  |   opensave: { | ||
|  |     new_doc: 'Nouvelle image', | ||
|  |     open_image_doc: 'Ouvrir le SVG', | ||
|  |     save_doc: 'Enregistrer l\'image', | ||
|  |     save_as_doc: 'Enregistrer en tant qu\'image' | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | var fr$1 = /*#__PURE__*/Object.freeze({ | ||
|  |   __proto__: null, | ||
|  |   default: fr | ||
|  | }); | ||
|  | 
 | ||
|  | var sv = { | ||
|  |   opensave: { | ||
|  |     new_doc: 'Ny bild', | ||
|  |     open_image_doc: 'Öppna SVG', | ||
|  |     save_doc: 'Spara SVG', | ||
|  |     save_as_doc: 'Spara som SVG' | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | var sv$1 = /*#__PURE__*/Object.freeze({ | ||
|  |   __proto__: null, | ||
|  |   default: sv | ||
|  | }); | ||
|  | 
 | ||
|  | var tr = { | ||
|  |   opensave: { | ||
|  |     new_doc: 'Yeni Resim', | ||
|  |     open_image_doc: 'SVG Aç', | ||
|  |     save_doc: 'SVG Kaydet', | ||
|  |     save_as_doc: 'SVG olarak Kaydet' | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | var tr$1 = /*#__PURE__*/Object.freeze({ | ||
|  |   __proto__: null, | ||
|  |   default: tr | ||
|  | }); | ||
|  | 
 | ||
|  | var uk = { | ||
|  |   opensave: { | ||
|  |     new_doc: 'Нове Зображення', | ||
|  |     open_image_doc: 'Відкрити SVG', | ||
|  |     save_doc: 'Зберегти SVG', | ||
|  |     save_as_doc: 'Зберегти SVG як' | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | var uk$1 = /*#__PURE__*/Object.freeze({ | ||
|  |   __proto__: null, | ||
|  |   default: uk | ||
|  | }); | ||
|  | 
 | ||
|  | var zhCN = { | ||
|  |   opensave: { | ||
|  |     new_doc: '新图片', | ||
|  |     open_image_doc: '打开 SVG', | ||
|  |     save_doc: '保存图像', | ||
|  |     save_as_doc: '另存为图像' | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | var zhCN$1 = /*#__PURE__*/Object.freeze({ | ||
|  |   __proto__: null, | ||
|  |   default: zhCN | ||
|  | }); | ||
|  | 
 | ||
|  | export { extOpensave as default }; | ||
|  | //# sourceMappingURL=ext-opensave.js.map
 |