@ckeditor/ckeditor5-ckbox 0.0.0-nightly-20231204.0 → 0.0.0-nightly-20231206.0
Sign up to get free protection for your applications and to get access to all the features.
- package/build/ckbox.js +1 -1
- package/lang/contexts.json +2 -1
- package/package.json +2 -2
- package/src/ckboxconfig.d.ts +18 -0
- package/src/ckboxediting.d.ts +5 -12
- package/src/ckboxediting.js +7 -55
- package/src/ckboximageedit/ckboximageeditcommand.d.ts +10 -1
- package/src/ckboximageedit/ckboximageeditcommand.js +55 -23
- package/src/ckboximageedit/ckboximageeditediting.d.ts +3 -1
- package/src/ckboximageedit/ckboximageeditediting.js +3 -1
- package/src/ckboximageedit/utils.d.ts +10 -0
- package/src/ckboximageedit/utils.js +48 -0
- package/src/ckboximageedit.d.ts +1 -2
- package/src/ckboximageedit.js +1 -2
- package/src/ckboxui.js +28 -1
- package/src/ckboxuploadadapter.d.ts +0 -5
- package/src/ckboxuploadadapter.js +10 -111
- package/src/ckboxutils.d.ts +51 -0
- package/src/ckboxutils.js +184 -0
- package/src/utils.d.ts +8 -0
- package/src/utils.js +36 -0
- package/theme/icons/ckbox-image-edit.svg +1 -1
package/build/ckbox.js
CHANGED
@@ -2,4 +2,4 @@
|
|
2
2
|
/*!
|
3
3
|
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
4
4
|
* For licensing, see LICENSE.md.
|
5
|
-
*/(()=>{var e={70:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(609),o=n.n(r)()((function(e){return e[1]}));o.push([e.id,':root{--ck-image-processing-highlight-color:#f9fafa;--ck-image-processing-background-color:#e3e5e8}.ck.ck-editor__editable .image.image-processing{position:relative}.ck.ck-editor__editable .image.image-processing:before{animation:ck-image-processing-animation 2s linear infinite;background:linear-gradient(90deg,var(--ck-image-processing-background-color),var(--ck-image-processing-highlight-color),var(--ck-image-processing-background-color));background-size:200% 100%;content:"";height:100%;left:0;position:absolute;top:0;width:100%;z-index:1}.ck.ck-editor__editable .image.image-processing img{height:100%}@keyframes ck-image-processing-animation{0%{background-position:200% 0}to{background-position:-200% 0}}',""]);const i=o},609:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n=e(t);return t[2]?"@media ".concat(t[2]," {").concat(n,"}"):n})).join("")},t.i=function(e,n,r){"string"==typeof e&&(e=[[null,e,""]]);var o={};if(r)for(var i=0;i<this.length;i++){var s=this[i][0];null!=s&&(o[s]=!0)}for(var a=0;a<e.length;a++){var c=[].concat(e[a]);r&&o[c[0]]||(n&&(c[2]?c[2]="".concat(n," and ").concat(c[2]):c[2]=n),t.push(c))}},t}},62:(e,t,n)=>{"use strict";var r,o=function(){return void 0===r&&(r=Boolean(window&&document&&document.all&&!window.atob)),r},i=function(){var e={};return function(t){if(void 0===e[t]){var n=document.querySelector(t);if(window.HTMLIFrameElement&&n instanceof window.HTMLIFrameElement)try{n=n.contentDocument.head}catch(e){n=null}e[t]=n}return e[t]}}(),s=[];function a(e){for(var t=-1,n=0;n<s.length;n++)if(s[n].identifier===e){t=n;break}return t}function c(e,t){for(var n={},r=[],o=0;o<e.length;o++){var i=e[o],c=t.base?i[0]+t.base:i[0],l=n[c]||0,u="".concat(c," ").concat(l);n[c]=l+1;var d=a(u),g={css:i[1],media:i[2],sourceMap:i[3]};-1!==d?(s[d].references++,s[d].updater(g)):s.push({identifier:u,updater:m(g,t),references:1}),r.push(u)}return r}function l(e){var t=document.createElement("style"),r=e.attributes||{};if(void 0===r.nonce){var o=n.nc;o&&(r.nonce=o)}if(Object.keys(r).forEach((function(e){t.setAttribute(e,r[e])})),"function"==typeof e.insert)e.insert(t);else{var s=i(e.insert||"head");if(!s)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");s.appendChild(t)}return t}var u,d=(u=[],function(e,t){return u[e]=t,u.filter(Boolean).join("\n")});function g(e,t,n,r){var o=n?"":r.media?"@media ".concat(r.media," {").concat(r.css,"}"):r.css;if(e.styleSheet)e.styleSheet.cssText=d(t,o);else{var i=document.createTextNode(o),s=e.childNodes;s[t]&&e.removeChild(s[t]),s.length?e.insertBefore(i,s[t]):e.appendChild(i)}}function h(e,t,n){var r=n.css,o=n.media,i=n.sourceMap;if(o?e.setAttribute("media",o):e.removeAttribute("media"),i&&"undefined"!=typeof btoa&&(r+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),e.styleSheet)e.styleSheet.cssText=r;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(r))}}var p=null,f=0;function m(e,t){var n,r,o;if(t.singleton){var i=f++;n=p||(p=l(t)),r=g.bind(null,n,i,!1),o=g.bind(null,n,i,!0)}else n=l(t),r=h.bind(null,n,t),o=function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(n)};return r(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;r(e=t)}else o()}}e.exports=function(e,t){(t=t||{}).singleton||"boolean"==typeof t.singleton||(t.singleton=o());var n=c(e=e||[],t);return function(e){if(e=e||[],"[object Array]"===Object.prototype.toString.call(e)){for(var r=0;r<n.length;r++){var o=a(n[r]);s[o].references--}for(var i=c(e,t),l=0;l<n.length;l++){var u=a(n[l]);0===s[u].references&&(s[u].updater(),s.splice(u,1))}n=i}}}},704:(e,t,n)=>{e.exports=n(79)("./src/core.js")},492:(e,t,n)=>{e.exports=n(79)("./src/engine.js")},273:(e,t,n)=>{e.exports=n(79)("./src/ui.js")},448:(e,t,n)=>{e.exports=n(79)("./src/upload.js")},209:(e,t,n)=>{e.exports=n(79)("./src/utils.js")},79:e=>{"use strict";e.exports=CKEditor5.dll}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var i=t[r]={id:r,exports:{}};return e[r](i,i.exports,n),i.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.nc=void 0;var r={};(()=>{"use strict";n.r(r),n.d(r,{CKBox:()=>P,CKBoxEditing:()=>E,CKBoxImageEdit:()=>jn,CKBoxImageEditEditing:()=>_n,CKBoxImageEditUI:()=>kn,CKBoxUI:()=>o});var e=n(704),t=n(273);class o extends e.Plugin{static get pluginName(){return"CKBoxUI"}afterInit(){const e=this.editor,n=e.commands.get("ckbox");if(!n)return;const r=e.t;e.ui.componentFactory.add("ckbox",(o=>{const i=new t.ButtonView(o);return i.set({label:r("Open file manager"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.627 16.5zm5.873-.196zm0-7.001V8h-13v8.5h4.341c.191.54.457 1.044.785 1.5H2a1.5 1.5 0 0 1-1.5-1.5v-13A1.5 1.5 0 0 1 2 2h4.5a1.5 1.5 0 0 1 1.06.44L9.122 4H16a1.5 1.5 0 0 1 1.5 1.5v1A1.5 1.5 0 0 1 19 8v2.531a6.027 6.027 0 0 0-1.5-1.228zM16 6.5v-1H8.5l-2-2H2v13h1V8a1.5 1.5 0 0 1 1.5-1.5H16z"/><path d="M14.5 19.5a5 5 0 1 1 0-10 5 5 0 0 1 0 10zM15 14v-2h-1v2h-2v1h2v2h1v-2h2v-1h-2z"/></svg>',tooltip:!0}),i.bind("isOn","isEnabled").to(n,"value","isEnabled"),i.on("execute",(()=>{e.execute("ckbox")})),i}))}}var i=n(492),s=n(209),a=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","#","$","%","*","+",",","-",".",":",";","=","?","@","[","]","^","_","{","|","}","~"],c=e=>{let t=0;for(let n=0;n<e.length;n++){let r=e[n];t=83*t+a.indexOf(r)}return t},l=e=>{let t=e/255;return t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)},u=e=>{let t=Math.max(0,Math.min(1,e));return t<=.0031308?Math.trunc(12.92*t*255+.5):Math.trunc(255*(1.055*Math.pow(t,.4166666666666667)-.055)+.5)},d=(e,t)=>(e=>e<0?-1:1)(e)*Math.pow(Math.abs(e),t),g=class extends Error{constructor(e){super(e),this.name="ValidationError",this.message=e}},h=e=>{if(!e||e.length<6)throw new g("The blurhash string must be at least 6 characters");let t=c(e[0]),n=Math.floor(t/9)+1,r=t%9+1;if(e.length!==4+2*r*n)throw new g(`blurhash length mismatch: length is ${e.length} but it should be ${4+2*r*n}`)},p=e=>{let t=e>>8&255,n=255&e;return[l(e>>16),l(t),l(n)]},f=(e,t)=>{let n=Math.floor(e/361),r=Math.floor(e/19)%19,o=e%19;return[d((n-9)/9,2)*t,d((r-9)/9,2)*t,d((o-9)/9,2)*t]},m=(e,t,n,r)=>{h(e),r|=1;let o=c(e[0]),i=Math.floor(o/9)+1,s=o%9+1,a=(c(e[1])+1)/166,l=new Array(s*i);for(let t=0;t<l.length;t++)if(0===t){let n=c(e.substring(2,6));l[t]=p(n)}else{let n=c(e.substring(4+2*t,6+2*t));l[t]=f(n,a*r)}let d=4*t,g=new Uint8ClampedArray(d*n);for(let e=0;e<n;e++)for(let r=0;r<t;r++){let o=0,a=0,c=0;for(let u=0;u<i;u++)for(let i=0;i<s;i++){let d=Math.cos(Math.PI*r*i/t)*Math.cos(Math.PI*e*u/n),g=l[i+u*s];o+=g[0]*d,a+=g[1]*d,c+=g[2]*d}let h=u(o),p=u(a),f=u(c);g[4*r+0+e*d]=h,g[4*r+1+e*d]=p,g[4*r+2+e*d]=f,g[4*r+3+e*d]=255}return g};function b(e){const t=[];let n=0;for(const r in e){const o=parseInt(r,10);isNaN(o)||(o>n&&(n=o),t.push(`${e[r]} ${r}w`))}const r=[{srcset:t.join(","),sizes:`(max-width: ${n}px) 100vw, ${n}px`,type:"image/webp"}];return{imageFallbackUrl:e.default,imageSources:r}}const v=32;function _({url:e,method:t="GET",data:n,onUploadProgress:r,signal:o,authorization:i}){const s=new XMLHttpRequest;s.open(t,e.toString()),s.setRequestHeader("Authorization",i),s.setRequestHeader("CKBox-Version","CKEditor 5"),s.responseType="json";const a=()=>{s.abort()};return new Promise(((e,t)=>{o.throwIfAborted(),o.addEventListener("abort",a),s.addEventListener("loadstart",(()=>{o.addEventListener("abort",a)})),s.addEventListener("loadend",(()=>{o.removeEventListener("abort",a)})),s.addEventListener("error",(()=>{t()})),s.addEventListener("abort",(()=>{t()})),s.addEventListener("load",(()=>{const n=s.response;if(!n||n.statusCode>=400)return t(n&&n.message);e(n)})),r&&s.upload.addEventListener("progress",(e=>{r(e)})),s.send(n)}))}class k extends e.Command{constructor(e){super(e),this._chosenAssets=new Set,this._wrapper=null,this._initListeners()}refresh(){this.value=this._getValue(),this.isEnabled=this._checkEnabled()}execute(){this.fire("ckbox:open")}_getValue(){return null!==this._wrapper}_checkEnabled(){const e=this.editor.commands.get("insertImage"),t=this.editor.commands.get("link");return!(!e.isEnabled&&!t.isEnabled)}_prepareOptions(){const e=this.editor.config.get("ckbox");return{theme:e.theme,language:e.language,tokenUrl:e.tokenUrl,serviceOrigin:e.serviceOrigin,dialog:{onClose:()=>this.fire("ckbox:close")},assets:{onChoose:e=>this.fire("ckbox:choose",e)}}}_initListeners(){const e=this.editor,t=e.model,n=!e.config.get("ckbox.ignoreDataId");this.on("ckbox",(()=>{this.refresh()}),{priority:"low"}),this.on("ckbox:open",(()=>{this.isEnabled&&!this.value&&(this._wrapper=(0,s.createElement)(document,"div",{class:"ck ckbox-wrapper"}),document.body.appendChild(this._wrapper),window.CKBox.mount(this._wrapper,this._prepareOptions()))})),this.on("ckbox:close",(()=>{this.value&&(this._wrapper.remove(),this._wrapper=null,e.editing.view.focus())})),this.on("ckbox:choose",((r,o)=>{if(!this.isEnabled)return;const i=e.commands.get("insertImage"),s=e.commands.get("link"),a=function({assets:e,isImageAllowed:t,isLinkAllowed:n}){return e.map((e=>function(e){const t=e.data.metadata;if(!t)return!1;return t.width&&t.height}(e)?{id:e.data.id,type:"image",attributes:y(e)}:{id:e.data.id,type:"link",attributes:w(e)})).filter((e=>"image"===e.type?t:n))}({assets:o,isImageAllowed:i.isEnabled,isLinkAllowed:s.isEnabled}),c=a.length;0!==c&&(t.change((e=>{for(const t of a){const r=t===a[c-1],o=1===c;this._insertAsset(t,r,e,o),n&&(setTimeout((()=>this._chosenAssets.delete(t)),1e3),this._chosenAssets.add(t))}})),e.editing.view.focus())})),this.listenTo(e,"destroy",(()=>{this.fire("ckbox:close"),this._chosenAssets.clear()}))}_insertAsset(e,t,n,r){const o=this.editor.model.document.selection;n.removeSelectionAttribute("linkHref"),"image"===e.type?this._insertImage(e):this._insertLink(e,n,r),t||n.setSelection(o.getLastPosition())}_insertImage(e){const t=this.editor,{imageFallbackUrl:n,imageSources:r,imageTextAlternative:o,imageWidth:i,imageHeight:s,imagePlaceholder:a}=e.attributes;t.execute("insertImage",{source:{src:n,sources:r,alt:o,width:i,height:s,...a?{placeholder:a}:null}})}_insertLink(e,t,n){const r=this.editor,o=r.model,i=o.document.selection,{linkName:a,linkHref:c}=e.attributes;if(i.isCollapsed){const e=(0,s.toMap)(i.getAttributes()),l=t.createText(a,e);if(!n){const e=i.getLastPosition(),n=e.parent;"paragraph"===n.name&&n.isEmpty||r.execute("insertParagraph",{position:e});const s=o.insertContent(l);return t.setSelection(s),void r.execute("link",c)}const u=o.insertContent(l);t.setSelection(u)}r.execute("link",c)}}function y(e){const{imageFallbackUrl:t,imageSources:n}=b(e.data.imageUrls),{description:r,width:o,height:i,blurHash:s}=e.data.metadata,a=function(e){if(e)try{const t=`${v}px`,n=document.createElement("canvas");n.setAttribute("width",t),n.setAttribute("height",t);const r=n.getContext("2d");if(!r)return;const o=r.createImageData(v,v),i=m(e,v,v);return o.data.set(i),r.putImageData(o,0,0),n.toDataURL()}catch(e){return}}(s);return{imageFallbackUrl:t,imageSources:n,imageTextAlternative:r||"",imageWidth:o,imageHeight:i,...a?{imagePlaceholder:a}:null}}function w(e){return{linkName:e.data.name,linkHref:x(e)}}function x(e){const t=new URL(e.data.url);return t.searchParams.set("download","true"),t.toString()}var I=n(448);class j extends e.Plugin{static get requires(){return["ImageUploadEditing","ImageUploadProgress",I.FileRepository,E]}static get pluginName(){return"CKBoxUploadAdapter"}async afterInit(){const e=this.editor,t=!!e.config.get("ckbox"),n=!!window.CKBox;if(!t&&!n)return;const r=e.plugins.get(I.FileRepository),o=e.plugins.get(E);r.createUploadAdapter=t=>new A(t,o.getToken(),e);const i=!e.config.get("ckbox.ignoreDataId"),s=e.plugins.get("ImageUploadEditing");i&&s.on("uploadComplete",((t,{imageElement:n,data:r})=>{e.model.change((e=>{e.setAttribute("ckboxImageId",r.ckboxImageId,n)}))}))}}class A{constructor(e,t,n){this.loader=e,this.token=t,this.editor=n,this.controller=new AbortController,this.serviceOrigin=n.config.get("ckbox.serviceOrigin")}getWorkspaceId(){const e=(0,this.editor.t)("Cannot access default workspace."),t=this.editor.config.get("ckbox.defaultUploadWorkspaceId"),n=function(e,t){const[,n]=e.value.split("."),r=JSON.parse(atob(n)),o=r.auth&&r.auth.ckbox&&r.auth.ckbox.workspaces||[r.aud];return t?"superadmin"==(r.auth&&r.auth.ckbox&&r.auth.ckbox.role)||o.includes(t)?t:null:o[0]}(this.token,t);if(null==n)throw(0,s.logError)("ckbox-access-default-workspace-error"),e;return n}async getAvailableCategories(e=0){const t=new URL("categories",this.serviceOrigin);return t.searchParams.set("limit",50..toString()),t.searchParams.set("offset",e.toString()),t.searchParams.set("workspaceId",this.getWorkspaceId()),_({url:t,signal:this.controller.signal,authorization:this.token.value}).then((async t=>{if(t.totalCount-(e+50)>0){const n=await this.getAvailableCategories(e+50);return[...t.items,...n]}return t.items})).catch((()=>{this.controller.signal.throwIfAborted(),(0,s.logError)("ckbox-fetch-category-http-error")}))}async getCategoryIdForFile(e){const t=function(e){const t=/\.(?<ext>[^.]+)$/;return e.match(t).groups.ext.toLowerCase()}(e.name),n=await this.getAvailableCategories();if(!n)return null;const r=this.editor.config.get("ckbox.defaultUploadCategories");if(r){const e=Object.keys(r).find((e=>r[e].find((e=>e.toLowerCase()==t))));if(e){const t=n.find((t=>t.id===e||t.name===e));return t?t.id:null}}const o=n.find((e=>e.extensions.find((e=>e.toLowerCase()==t))));return o?o.id:null}async upload(){const e=this.editor.t,t=e("Cannot determine a category for the uploaded file."),n=await this.loader.file,r=await this.getCategoryIdForFile(n);if(!r)return Promise.reject(t);const o=new URL("assets",this.serviceOrigin),i=new FormData;o.searchParams.set("workspaceId",this.getWorkspaceId()),i.append("categoryId",r),i.append("file",n);return _({method:"POST",url:o,data:i,onUploadProgress:e=>{e.lengthComputable&&(this.loader.uploadTotal=e.total,this.loader.uploaded=e.loaded)},signal:this.controller.signal,authorization:this.token.value}).then((async e=>{const t=b(e.imageUrls);return{ckboxImageId:e.id,default:t.imageFallbackUrl,sources:t.imageSources}})).catch((()=>{const t=e("Cannot upload file:")+` ${n.name}.`;return Promise.reject(t)}))}abort(){this.controller.abort()}}class E extends e.Plugin{static get pluginName(){return"CKBoxEditing"}static get requires(){return["CloudServices","LinkEditing","PictureEditing",j]}async init(){const e=this.editor,t=!!e.config.get("ckbox"),n=!!window.CKBox;if(!t&&!n)return;this._initConfig();const r=e.plugins.get("CloudServicesCore"),o=e.config.get("ckbox.tokenUrl");if(o===e.config.get("cloudServices.tokenUrl")){const t=e.plugins.get("CloudServices");this._token=t.token}else this._token=await r.createToken(o).init();e.config.get("ckbox.ignoreDataId")||(this._initSchema(),this._initConversion(),this._initFixers()),n&&e.commands.add("ckbox",new k(e))}getToken(){return this._token}_initConfig(){const e=this.editor;e.config.define("ckbox",{serviceOrigin:"https://api.ckbox.io",defaultUploadCategories:null,ignoreDataId:!1,language:e.locale.uiLanguage,theme:"lark",tokenUrl:e.config.get("cloudServices.tokenUrl")});if(!e.config.get("ckbox.tokenUrl"))throw new s.CKEditorError("ckbox-plugin-missing-token-url",this);e.plugins.has("ImageBlockEditing")||e.plugins.has("ImageInlineEditing")||(0,s.logError)("ckbox-plugin-image-feature-missing",e)}_initSchema(){const e=this.editor.model.schema;e.extend("$text",{allowAttributes:"ckboxLinkId"}),e.isRegistered("imageBlock")&&e.extend("imageBlock",{allowAttributes:["ckboxImageId","ckboxLinkId"]}),e.isRegistered("imageInline")&&e.extend("imageInline",{allowAttributes:["ckboxImageId","ckboxLinkId"]}),e.addAttributeCheck(((e,t)=>{if(!!!e.last.getAttribute("linkHref")&&"ckboxLinkId"===t)return!1}))}_initConversion(){const e=this.editor;e.conversion.for("downcast").add((e=>{e.on("attribute:ckboxLinkId:imageBlock",((e,t,n)=>{const{writer:r,mapper:o,consumable:i}=n;if(!i.consume(t.item,e.name))return;const s=[...o.toViewElement(t.item).getChildren()].find((e=>"a"===e.name));s&&(t.item.hasAttribute("ckboxLinkId")?r.setAttribute("data-ckbox-resource-id",t.item.getAttribute("ckboxLinkId"),s):r.removeAttribute("data-ckbox-resource-id",s))}),{priority:"low"}),e.on("attribute:ckboxLinkId",((e,t,n)=>{const{writer:r,mapper:o,consumable:i}=n;if(i.consume(t.item,e.name)){if(t.attributeOldValue){const e=S(r,t.attributeOldValue);r.unwrap(o.toViewRange(t.range),e)}if(t.attributeNewValue){const e=S(r,t.attributeNewValue);if(t.item.is("selection")){const t=r.document.selection;r.wrap(t.getFirstRange(),e)}else r.wrap(o.toViewRange(t.range),e)}}}),{priority:"low"})})),e.conversion.for("upcast").add((e=>{e.on("element:a",((e,t,n)=>{const{writer:r,consumable:o}=n;if(!t.viewItem.getAttribute("href"))return;if(!o.consume(t.viewItem,{attributes:["data-ckbox-resource-id"]}))return;const i=t.viewItem.getAttribute("data-ckbox-resource-id");if(i)if(t.modelRange)for(let e of t.modelRange.getItems())e.is("$textProxy")&&(e=e.textNode),O(e)&&r.setAttribute("ckboxLinkId",i,e);else{const e=t.modelCursor.nodeBefore||t.modelCursor.parent;r.setAttribute("ckboxLinkId",i,e)}}),{priority:"low"})})),e.conversion.for("downcast").attributeToAttribute({model:"ckboxImageId",view:"data-ckbox-resource-id"}),e.conversion.for("upcast").elementToAttribute({model:{key:"ckboxImageId",value:e=>e.getAttribute("data-ckbox-resource-id")},view:{attributes:{"data-ckbox-resource-id":/[\s\S]+/}}});const t=e.commands.get("replaceImageSource");t&&this.listenTo(t,"cleanupImage",((e,[t,n])=>{t.removeAttribute("ckboxImageId",n)}))}_initFixers(){const e=this.editor,t=e.model,n=t.document.selection;t.document.registerPostFixer(function(e){return t=>{let n=!1;const r=e.model,o=e.commands.get("ckbox");if(!o)return n;for(const e of r.document.differ.getChanges()){if("insert"!==e.type&&"attribute"!==e.type)continue;const r="insert"===e.type?new i.Range(e.position,e.position.getShiftedBy(e.length)):e.range,s="attribute"===e.type&&"linkHref"===e.attributeKey&&null===e.attributeNewValue;for(const e of r.getItems()){if(s&&e.hasAttribute("ckboxLinkId")){t.removeAttribute("ckboxLinkId",e),n=!0;continue}const r=C(e,o._chosenAssets);for(const o of r){const r="image"===o.type?"ckboxImageId":"ckboxLinkId";o.id!==e.getAttribute(r)&&(t.setAttribute(r,o.id,e),n=!0)}}}return n}}(e)),t.document.registerPostFixer(function(e){return t=>!(e.hasAttribute("linkHref")||!e.hasAttribute("ckboxLinkId"))&&(t.removeSelectionAttribute("ckboxLinkId"),!0)}(n))}}function C(e,t){const n=e.is("element","imageInline")||e.is("element","imageBlock"),r=e.hasAttribute("linkHref");return[...t].filter((t=>"image"===t.type&&n?t.attributes.imageFallbackUrl===e.getAttribute("src"):"link"===t.type&&r?t.attributes.linkHref===e.getAttribute("linkHref"):void 0))}function S(e,t){const n=e.createAttributeElement("a",{"data-ckbox-resource-id":t},{priority:5});return e.setCustomProperty("link",!0,n),n}function O(e){return!!e.is("$text")||!(!e.is("element","imageInline")&&!e.is("element","imageBlock"))}class P extends e.Plugin{static get pluginName(){return"CKBox"}static get requires(){return[E,o]}}const L=function(){this.__data__=[],this.size=0};const U=function(e,t){return e===t||e!=e&&t!=t};const T=function(e,t){for(var n=e.length;n--;)if(U(e[n][0],t))return n;return-1};var M=Array.prototype.splice;const B=function(e){var t=this.__data__,n=T(t,e);return!(n<0)&&(n==t.length-1?t.pop():M.call(t,n,1),--this.size,!0)};const z=function(e){var t=this.__data__,n=T(t,e);return n<0?void 0:t[n][1]};const F=function(e){return T(this.__data__,e)>-1};const N=function(e,t){var n=this.__data__,r=T(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this};function K(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t<n;){var r=e[t];this.set(r[0],r[1])}}K.prototype.clear=L,K.prototype.delete=B,K.prototype.get=z,K.prototype.has=F,K.prototype.set=N;const R=K;const V=function(){this.__data__=new R,this.size=0};const H=function(e){var t=this.__data__,n=t.delete(e);return this.size=t.size,n};const $=function(e){return this.__data__.get(e)};const D=function(e){return this.__data__.has(e)};const q="object"==typeof global&&global&&global.Object===Object&&global;var W="object"==typeof self&&self&&self.Object===Object&&self;const Z=q||W||Function("return this")();const G=Z.Symbol;var J=Object.prototype,X=J.hasOwnProperty,Q=J.toString,Y=G?G.toStringTag:void 0;const ee=function(e){var t=X.call(e,Y),n=e[Y];try{e[Y]=void 0;var r=!0}catch(e){}var o=Q.call(e);return r&&(t?e[Y]=n:delete e[Y]),o};var te=Object.prototype.toString;const ne=function(e){return te.call(e)};var re=G?G.toStringTag:void 0;const oe=function(e){return null==e?void 0===e?"[object Undefined]":"[object Null]":re&&re in Object(e)?ee(e):ne(e)};const ie=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)};const se=function(e){if(!ie(e))return!1;var t=oe(e);return"[object Function]"==t||"[object GeneratorFunction]"==t||"[object AsyncFunction]"==t||"[object Proxy]"==t};const ae=Z["__core-js_shared__"];var ce,le=(ce=/[^.]+$/.exec(ae&&ae.keys&&ae.keys.IE_PROTO||""))?"Symbol(src)_1."+ce:"";const ue=function(e){return!!le&&le in e};var de=Function.prototype.toString;const ge=function(e){if(null!=e){try{return de.call(e)}catch(e){}try{return e+""}catch(e){}}return""};var he=/^\[object .+?Constructor\]$/,pe=Function.prototype,fe=Object.prototype,me=pe.toString,be=fe.hasOwnProperty,ve=RegExp("^"+me.call(be).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");const _e=function(e){return!(!ie(e)||ue(e))&&(se(e)?ve:he).test(ge(e))};const ke=function(e,t){return null==e?void 0:e[t]};const ye=function(e,t){var n=ke(e,t);return _e(n)?n:void 0};const we=ye(Z,"Map");const xe=ye(Object,"create");const Ie=function(){this.__data__=xe?xe(null):{},this.size=0};const je=function(e){var t=this.has(e)&&delete this.__data__[e];return this.size-=t?1:0,t};var Ae=Object.prototype.hasOwnProperty;const Ee=function(e){var t=this.__data__;if(xe){var n=t[e];return"__lodash_hash_undefined__"===n?void 0:n}return Ae.call(t,e)?t[e]:void 0};var Ce=Object.prototype.hasOwnProperty;const Se=function(e){var t=this.__data__;return xe?void 0!==t[e]:Ce.call(t,e)};const Oe=function(e,t){var n=this.__data__;return this.size+=this.has(e)?0:1,n[e]=xe&&void 0===t?"__lodash_hash_undefined__":t,this};function Pe(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t<n;){var r=e[t];this.set(r[0],r[1])}}Pe.prototype.clear=Ie,Pe.prototype.delete=je,Pe.prototype.get=Ee,Pe.prototype.has=Se,Pe.prototype.set=Oe;const Le=Pe;const Ue=function(){this.size=0,this.__data__={hash:new Le,map:new(we||R),string:new Le}};const Te=function(e){var t=typeof e;return"string"==t||"number"==t||"symbol"==t||"boolean"==t?"__proto__"!==e:null===e};const Me=function(e,t){var n=e.__data__;return Te(t)?n["string"==typeof t?"string":"hash"]:n.map};const Be=function(e){var t=Me(this,e).delete(e);return this.size-=t?1:0,t};const ze=function(e){return Me(this,e).get(e)};const Fe=function(e){return Me(this,e).has(e)};const Ne=function(e,t){var n=Me(this,e),r=n.size;return n.set(e,t),this.size+=n.size==r?0:1,this};function Ke(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t<n;){var r=e[t];this.set(r[0],r[1])}}Ke.prototype.clear=Ue,Ke.prototype.delete=Be,Ke.prototype.get=ze,Ke.prototype.has=Fe,Ke.prototype.set=Ne;const Re=Ke;const Ve=function(e,t){var n=this.__data__;if(n instanceof R){var r=n.__data__;if(!we||r.length<199)return r.push([e,t]),this.size=++n.size,this;n=this.__data__=new Re(r)}return n.set(e,t),this.size=n.size,this};function He(e){var t=this.__data__=new R(e);this.size=t.size}He.prototype.clear=V,He.prototype.delete=H,He.prototype.get=$,He.prototype.has=D,He.prototype.set=Ve;const $e=He;const De=function(e){return this.__data__.set(e,"__lodash_hash_undefined__"),this};const qe=function(e){return this.__data__.has(e)};function We(e){var t=-1,n=null==e?0:e.length;for(this.__data__=new Re;++t<n;)this.add(e[t])}We.prototype.add=We.prototype.push=De,We.prototype.has=qe;const Ze=We;const Ge=function(e,t){for(var n=-1,r=null==e?0:e.length;++n<r;)if(t(e[n],n,e))return!0;return!1};const Je=function(e,t){return e.has(t)};const Xe=function(e,t,n,r,o,i){var s=1&n,a=e.length,c=t.length;if(a!=c&&!(s&&c>a))return!1;var l=i.get(e),u=i.get(t);if(l&&u)return l==t&&u==e;var d=-1,g=!0,h=2&n?new Ze:void 0;for(i.set(e,t),i.set(t,e);++d<a;){var p=e[d],f=t[d];if(r)var m=s?r(f,p,d,t,e,i):r(p,f,d,e,t,i);if(void 0!==m){if(m)continue;g=!1;break}if(h){if(!Ge(t,(function(e,t){if(!Je(h,t)&&(p===e||o(p,e,n,r,i)))return h.push(t)}))){g=!1;break}}else if(p!==f&&!o(p,f,n,r,i)){g=!1;break}}return i.delete(e),i.delete(t),g};const Qe=Z.Uint8Array;const Ye=function(e){var t=-1,n=Array(e.size);return e.forEach((function(e,r){n[++t]=[r,e]})),n};const et=function(e){var t=-1,n=Array(e.size);return e.forEach((function(e){n[++t]=e})),n};var tt=G?G.prototype:void 0,nt=tt?tt.valueOf:void 0;const rt=function(e,t,n,r,o,i,s){switch(n){case"[object DataView]":if(e.byteLength!=t.byteLength||e.byteOffset!=t.byteOffset)return!1;e=e.buffer,t=t.buffer;case"[object ArrayBuffer]":return!(e.byteLength!=t.byteLength||!i(new Qe(e),new Qe(t)));case"[object Boolean]":case"[object Date]":case"[object Number]":return U(+e,+t);case"[object Error]":return e.name==t.name&&e.message==t.message;case"[object RegExp]":case"[object String]":return e==t+"";case"[object Map]":var a=Ye;case"[object Set]":var c=1&r;if(a||(a=et),e.size!=t.size&&!c)return!1;var l=s.get(e);if(l)return l==t;r|=2,s.set(e,t);var u=Xe(a(e),a(t),r,o,i,s);return s.delete(e),u;case"[object Symbol]":if(nt)return nt.call(e)==nt.call(t)}return!1};const ot=function(e,t){for(var n=-1,r=t.length,o=e.length;++n<r;)e[o+n]=t[n];return e};const it=Array.isArray;const st=function(e,t,n){var r=t(e);return it(e)?r:ot(r,n(e))};const at=function(e,t){for(var n=-1,r=null==e?0:e.length,o=0,i=[];++n<r;){var s=e[n];t(s,n,e)&&(i[o++]=s)}return i};const ct=function(){return[]};var lt=Object.prototype.propertyIsEnumerable,ut=Object.getOwnPropertySymbols;const dt=ut?function(e){return null==e?[]:(e=Object(e),at(ut(e),(function(t){return lt.call(e,t)})))}:ct;const gt=function(e,t){for(var n=-1,r=Array(e);++n<e;)r[n]=t(n);return r};const ht=function(e){return null!=e&&"object"==typeof e};const pt=function(e){return ht(e)&&"[object Arguments]"==oe(e)};var ft=Object.prototype,mt=ft.hasOwnProperty,bt=ft.propertyIsEnumerable;const vt=pt(function(){return arguments}())?pt:function(e){return ht(e)&&mt.call(e,"callee")&&!bt.call(e,"callee")};const _t=function(){return!1};var kt="object"==typeof exports&&exports&&!exports.nodeType&&exports,yt=kt&&"object"==typeof module&&module&&!module.nodeType&&module,wt=yt&&yt.exports===kt?Z.Buffer:void 0;const xt=(wt?wt.isBuffer:void 0)||_t;var It=/^(?:0|[1-9]\d*)$/;const jt=function(e,t){var n=typeof e;return!!(t=null==t?9007199254740991:t)&&("number"==n||"symbol"!=n&&It.test(e))&&e>-1&&e%1==0&&e<t};const At=function(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=9007199254740991};var Et={};Et["[object Float32Array]"]=Et["[object Float64Array]"]=Et["[object Int8Array]"]=Et["[object Int16Array]"]=Et["[object Int32Array]"]=Et["[object Uint8Array]"]=Et["[object Uint8ClampedArray]"]=Et["[object Uint16Array]"]=Et["[object Uint32Array]"]=!0,Et["[object Arguments]"]=Et["[object Array]"]=Et["[object ArrayBuffer]"]=Et["[object Boolean]"]=Et["[object DataView]"]=Et["[object Date]"]=Et["[object Error]"]=Et["[object Function]"]=Et["[object Map]"]=Et["[object Number]"]=Et["[object Object]"]=Et["[object RegExp]"]=Et["[object Set]"]=Et["[object String]"]=Et["[object WeakMap]"]=!1;const Ct=function(e){return ht(e)&&At(e.length)&&!!Et[oe(e)]};const St=function(e){return function(t){return e(t)}};var Ot="object"==typeof exports&&exports&&!exports.nodeType&&exports,Pt=Ot&&"object"==typeof module&&module&&!module.nodeType&&module,Lt=Pt&&Pt.exports===Ot&&q.process,Ut=function(){try{var e=Pt&&Pt.require&&Pt.require("util").types;return e||Lt&&Lt.binding&&Lt.binding("util")}catch(e){}}();var Tt=Ut&&Ut.isTypedArray;const Mt=Tt?St(Tt):Ct;var Bt=Object.prototype.hasOwnProperty;const zt=function(e,t){var n=it(e),r=!n&&vt(e),o=!n&&!r&&xt(e),i=!n&&!r&&!o&&Mt(e),s=n||r||o||i,a=s?gt(e.length,String):[],c=a.length;for(var l in e)!t&&!Bt.call(e,l)||s&&("length"==l||o&&("offset"==l||"parent"==l)||i&&("buffer"==l||"byteLength"==l||"byteOffset"==l)||jt(l,c))||a.push(l);return a};var Ft=Object.prototype;const Nt=function(e){var t=e&&e.constructor;return e===("function"==typeof t&&t.prototype||Ft)};const Kt=function(e,t){return function(n){return e(t(n))}}(Object.keys,Object);var Rt=Object.prototype.hasOwnProperty;const Vt=function(e){if(!Nt(e))return Kt(e);var t=[];for(var n in Object(e))Rt.call(e,n)&&"constructor"!=n&&t.push(n);return t};const Ht=function(e){return null!=e&&At(e.length)&&!se(e)};const $t=function(e){return Ht(e)?zt(e):Vt(e)};const Dt=function(e){return st(e,$t,dt)};var qt=Object.prototype.hasOwnProperty;const Wt=function(e,t,n,r,o,i){var s=1&n,a=Dt(e),c=a.length;if(c!=Dt(t).length&&!s)return!1;for(var l=c;l--;){var u=a[l];if(!(s?u in t:qt.call(t,u)))return!1}var d=i.get(e),g=i.get(t);if(d&&g)return d==t&&g==e;var h=!0;i.set(e,t),i.set(t,e);for(var p=s;++l<c;){var f=e[u=a[l]],m=t[u];if(r)var b=s?r(m,f,u,t,e,i):r(f,m,u,e,t,i);if(!(void 0===b?f===m||o(f,m,n,r,i):b)){h=!1;break}p||(p="constructor"==u)}if(h&&!p){var v=e.constructor,_=t.constructor;v==_||!("constructor"in e)||!("constructor"in t)||"function"==typeof v&&v instanceof v&&"function"==typeof _&&_ instanceof _||(h=!1)}return i.delete(e),i.delete(t),h};const Zt=ye(Z,"DataView");const Gt=ye(Z,"Promise");const Jt=ye(Z,"Set");const Xt=ye(Z,"WeakMap");var Qt="[object Map]",Yt="[object Promise]",en="[object Set]",tn="[object WeakMap]",nn="[object DataView]",rn=ge(Zt),on=ge(we),sn=ge(Gt),an=ge(Jt),cn=ge(Xt),ln=oe;(Zt&&ln(new Zt(new ArrayBuffer(1)))!=nn||we&&ln(new we)!=Qt||Gt&&ln(Gt.resolve())!=Yt||Jt&&ln(new Jt)!=en||Xt&&ln(new Xt)!=tn)&&(ln=function(e){var t=oe(e),n="[object Object]"==t?e.constructor:void 0,r=n?ge(n):"";if(r)switch(r){case rn:return nn;case on:return Qt;case sn:return Yt;case an:return en;case cn:return tn}return t});const un=ln;var dn="[object Arguments]",gn="[object Array]",hn="[object Object]",pn=Object.prototype.hasOwnProperty;const fn=function(e,t,n,r,o,i){var s=it(e),a=it(t),c=s?gn:un(e),l=a?gn:un(t),u=(c=c==dn?hn:c)==hn,d=(l=l==dn?hn:l)==hn,g=c==l;if(g&&xt(e)){if(!xt(t))return!1;s=!0,u=!1}if(g&&!u)return i||(i=new $e),s||Mt(e)?Xe(e,t,n,r,o,i):rt(e,t,c,n,r,o,i);if(!(1&n)){var h=u&&pn.call(e,"__wrapped__"),p=d&&pn.call(t,"__wrapped__");if(h||p){var f=h?e.value():e,m=p?t.value():t;return i||(i=new $e),o(f,m,n,r,i)}}return!!g&&(i||(i=new $e),Wt(e,t,n,r,o,i))};const mn=function e(t,n,r,o,i){return t===n||(null==t||null==n||!ht(t)&&!ht(n)?t!=t&&n!=n:fn(t,n,r,o,e,i))};const bn=function(e,t){return mn(e,t)};class vn extends e.Command{constructor(e){super(e),this._wrapper=null,this._processInProgress=new Map,this.value=!1,this._prepareListeners()}refresh(){const e=this.editor;this.value=this._getValue();const t=e.model.document.selection.getSelectedElement(),n=t&&(t.is("element","imageInline")||t.is("element","imageBlock")),r=Array.from(this._processInProgress.values()).some((({element:e})=>bn(e,t)));n&&t.hasAttribute("ckboxImageId")&&!r?this.isEnabled=!0:this.isEnabled=!1}execute(){if(this._getValue())return;this.value=!0,this._wrapper=(0,s.createElement)(document,"div",{class:"ck ckbox-wrapper"}),document.body.appendChild(this._wrapper);const e=this.editor.model.document.selection.getSelectedElement(),t={ckboxImageId:e.getAttribute("ckboxImageId"),element:e,controller:new AbortController};window.CKBox.mountImageEditor(this._wrapper,this._prepareOptions(t))}destroy(){this._handleImageEditorClose();for(const e of this._processInProgress.values())e.controller.abort();super.destroy()}_getValue(){return null!==this._wrapper}_prepareOptions(e){const t=this.editor.config.get("ckbox");return{assetId:e.ckboxImageId,imageEditing:{allowOverwrite:!1},tokenUrl:t.tokenUrl,onClose:()=>this._handleImageEditorClose(),onSave:t=>this._handleImageEditorSave(e,t)}}_prepareListeners(){this.listenTo(this.editor.model.document,"change:data",(()=>{this._getProcessingStatesOfDeletedImages().forEach((e=>{e.controller.abort()}))}))}_getProcessingStatesOfDeletedImages(){const e=[];for(const t of this._processInProgress.values())"$graveyard"==t.element.root.rootName&&e.push(t);return e}_handleImageEditorClose(){this._wrapper&&(this._wrapper.remove(),this._wrapper=null,this.editor.editing.view.focus())}_handleImageEditorSave(n,r){const o=this.editor.locale.t,i=this.editor.plugins.get(t.Notification),a=this.editor.plugins.get(e.PendingActions),c=a.add(o("Processing the edited image."));this._processInProgress.set(n.ckboxImageId,n),this._showImageProcessingIndicator(n.element,r),this.refresh(),this._waitForAssetProcessed(r.data.id,n.controller.signal).then((e=>{this._replaceImage(n.element,e)}),(e=>{this.editor.editing.reconvertItem(n.element),n.controller.signal.aborted||(!e||e instanceof s.CKEditorError?i.showWarning(o("Server failed to process the image."),{namespace:"ckbox"}):console.error(e))})).finally((()=>{this._processInProgress.delete(n.ckboxImageId),a.remove(c),this.refresh()}))}async _getAssetStatusFromServer(e,t){const n=this.editor.plugins.get(E),r=new URL("assets/"+e,this.editor.config.get("ckbox.serviceOrigin")),o=await _({url:r,signal:t,authorization:n.getToken().value}),i=o.metadata.metadataProcessingStatus;if(!i||"queued"==i)throw new s.CKEditorError("ckbox-image-not-processed");return{data:{...o}}}async _waitForAssetProcessed(e,t){const n=await(0,s.retry)((()=>this._getAssetStatusFromServer(e,t)),{signal:t,maxAttempts:5});if("success"!=n.data.metadata.metadataProcessingStatus)throw new s.CKEditorError("ckbox-image-processing-failed");return n}_showImageProcessingIndicator(e,t){const n=this.editor;n.editing.view.change((r=>{const o=n.editing.mapper.toViewElement(e),i=this.editor.plugins.get("ImageUtils").findViewImgElement(o);r.removeStyle("aspect-ratio",i),r.setAttribute("width",t.data.metadata.width,i),r.setAttribute("height",t.data.metadata.height,i),r.setStyle("width",`${t.data.metadata.width}px`,i),r.setStyle("height",`${t.data.metadata.height}px`,i),r.addClass("image-processing",o)}))}_replaceImage(e,t){const n=this.editor,{imageFallbackUrl:r,imageSources:o,imageWidth:i,imageHeight:s,imagePlaceholder:a}=y(t),c=Array.from(n.model.document.selection.getRanges());n.model.change((l=>{l.setSelection(e,"on"),n.execute("insertImage",{source:{src:r,sources:o,alt:e.getAttribute("alt"),width:i,height:s,...a?{placeholder:a}:null}});const u=e.getChildren();e=n.model.document.selection.getSelectedElement();for(const t of u)l.append(l.cloneElement(t),e);l.setAttribute("ckboxImageId",t.data.id,e),l.setSelection(c)}))}}class _n extends e.Plugin{static get pluginName(){return"CKBoxImageEditEditing"}static get requires(){return[e.PendingActions,t.Notification,"ImageUtils","ImageEditing"]}init(){const{editor:e}=this;e.commands.add("ckboxImageEdit",new vn(e))}}class kn extends e.Plugin{static get pluginName(){return"CKBoxImageEditUI"}init(){const e=this.editor;e.ui.componentFactory.add("ckboxImageEdit",(n=>{const r=e.commands.get("ckboxImageEdit"),o=new t.ButtonView(n),i=n.t;return o.set({label:i("Edit image"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M5.802 8.942a.607.607 0 0 0-.838-.029L1.429 12.8V3.158h12.93v5.25l1.429-1.319V2.758c0-.553-.467-1-1.039-1H1.05c-.582 0-1.049.447-1.049 1v11.281c0 .562.467 1.01 1.039 1.01h6.583v-.228c0-.124.052-.242.143-.326l4.504-4.157-.312-.367a.61.61 0 0 0-.829 0l-2.124 1.962-3.202-2.991Zm3.74-2.578a1.87 1.87 0 1 0 3.707-.486 1.87 1.87 0 0 0-3.707.486Z"/><path d="M8.874 15.926v2.316h2.317l6.836-6.834-2.32-2.32-6.833 6.84v-.002Zm10.944-6.312a.612.612 0 0 0 0-.87L18.372 7.3a.614.614 0 0 0-.87 0l-1.133 1.128 2.32 2.319 1.13-1.133Z"/></svg>',tooltip:!0}),o.bind("isOn").to(r,"value",r,"isEnabled",((e,t)=>e&&t)),o.bind("isEnabled").to(r),this.listenTo(o,"execute",(()=>{e.execute("ckboxImageEdit"),e.editing.view.focus()})),o}))}}var yn=n(62),wn=n.n(yn),xn=n(70),In={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};wn()(xn.Z,In);xn.Z.locals;class jn extends e.Plugin{static get pluginName(){return"CKBoxImageEdit"}static get requires(){return[E,_n,kn]}}})(),(window.CKEditor5=window.CKEditor5||{}).ckbox=r})();
|
5
|
+
*/(()=>{var e={70:(e,t,n)=>{"use strict";n.d(t,{Z:()=>i});var r=n(609),o=n.n(r)()((function(e){return e[1]}));o.push([e.id,':root{--ck-image-processing-highlight-color:#f9fafa;--ck-image-processing-background-color:#e3e5e8}.ck.ck-editor__editable .image.image-processing{position:relative}.ck.ck-editor__editable .image.image-processing:before{animation:ck-image-processing-animation 2s linear infinite;background:linear-gradient(90deg,var(--ck-image-processing-background-color),var(--ck-image-processing-highlight-color),var(--ck-image-processing-background-color));background-size:200% 100%;content:"";height:100%;left:0;position:absolute;top:0;width:100%;z-index:1}.ck.ck-editor__editable .image.image-processing img{height:100%}@keyframes ck-image-processing-animation{0%{background-position:200% 0}to{background-position:-200% 0}}',""]);const i=o},609:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n=e(t);return t[2]?"@media ".concat(t[2]," {").concat(n,"}"):n})).join("")},t.i=function(e,n,r){"string"==typeof e&&(e=[[null,e,""]]);var o={};if(r)for(var i=0;i<this.length;i++){var s=this[i][0];null!=s&&(o[s]=!0)}for(var a=0;a<e.length;a++){var c=[].concat(e[a]);r&&o[c[0]]||(n&&(c[2]?c[2]="".concat(n," and ").concat(c[2]):c[2]=n),t.push(c))}},t}},62:(e,t,n)=>{"use strict";var r,o=function(){return void 0===r&&(r=Boolean(window&&document&&document.all&&!window.atob)),r},i=function(){var e={};return function(t){if(void 0===e[t]){var n=document.querySelector(t);if(window.HTMLIFrameElement&&n instanceof window.HTMLIFrameElement)try{n=n.contentDocument.head}catch(e){n=null}e[t]=n}return e[t]}}(),s=[];function a(e){for(var t=-1,n=0;n<s.length;n++)if(s[n].identifier===e){t=n;break}return t}function c(e,t){for(var n={},r=[],o=0;o<e.length;o++){var i=e[o],c=t.base?i[0]+t.base:i[0],l=n[c]||0,u="".concat(c," ").concat(l);n[c]=l+1;var d=a(u),g={css:i[1],media:i[2],sourceMap:i[3]};-1!==d?(s[d].references++,s[d].updater(g)):s.push({identifier:u,updater:m(g,t),references:1}),r.push(u)}return r}function l(e){var t=document.createElement("style"),r=e.attributes||{};if(void 0===r.nonce){var o=n.nc;o&&(r.nonce=o)}if(Object.keys(r).forEach((function(e){t.setAttribute(e,r[e])})),"function"==typeof e.insert)e.insert(t);else{var s=i(e.insert||"head");if(!s)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");s.appendChild(t)}return t}var u,d=(u=[],function(e,t){return u[e]=t,u.filter(Boolean).join("\n")});function g(e,t,n,r){var o=n?"":r.media?"@media ".concat(r.media," {").concat(r.css,"}"):r.css;if(e.styleSheet)e.styleSheet.cssText=d(t,o);else{var i=document.createTextNode(o),s=e.childNodes;s[t]&&e.removeChild(s[t]),s.length?e.insertBefore(i,s[t]):e.appendChild(i)}}function h(e,t,n){var r=n.css,o=n.media,i=n.sourceMap;if(o?e.setAttribute("media",o):e.removeAttribute("media"),i&&"undefined"!=typeof btoa&&(r+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),e.styleSheet)e.styleSheet.cssText=r;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(r))}}var p=null,f=0;function m(e,t){var n,r,o;if(t.singleton){var i=f++;n=p||(p=l(t)),r=g.bind(null,n,i,!1),o=g.bind(null,n,i,!0)}else n=l(t),r=h.bind(null,n,t),o=function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(n)};return r(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;r(e=t)}else o()}}e.exports=function(e,t){(t=t||{}).singleton||"boolean"==typeof t.singleton||(t.singleton=o());var n=c(e=e||[],t);return function(e){if(e=e||[],"[object Array]"===Object.prototype.toString.call(e)){for(var r=0;r<n.length;r++){var o=a(n[r]);s[o].references--}for(var i=c(e,t),l=0;l<n.length;l++){var u=a(n[l]);0===s[u].references&&(s[u].updater(),s.splice(u,1))}n=i}}}},704:(e,t,n)=>{e.exports=n(79)("./src/core.js")},492:(e,t,n)=>{e.exports=n(79)("./src/engine.js")},273:(e,t,n)=>{e.exports=n(79)("./src/ui.js")},448:(e,t,n)=>{e.exports=n(79)("./src/upload.js")},209:(e,t,n)=>{e.exports=n(79)("./src/utils.js")},79:e=>{"use strict";e.exports=CKEditor5.dll}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var i=t[r]={id:r,exports:{}};return e[r](i,i.exports,n),i.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.nc=void 0;var r={};(()=>{"use strict";n.r(r),n.d(r,{CKBox:()=>U,CKBoxEditing:()=>O,CKBoxImageEdit:()=>Cn,CKBoxImageEditEditing:()=>kn,CKBoxImageEditUI:()=>xn,CKBoxUI:()=>o});var e=n(704),t=n(273);class o extends e.Plugin{static get pluginName(){return"CKBoxUI"}afterInit(){const n=this.editor,r=n.commands.get("ckbox");if(!r)return;const o=n.t;if(n.ui.componentFactory.add("ckbox",(e=>{const i=new t.ButtonView(e);return i.set({label:o("Open file manager"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.627 16.5zm5.873-.196zm0-7.001V8h-13v8.5h4.341c.191.54.457 1.044.785 1.5H2a1.5 1.5 0 0 1-1.5-1.5v-13A1.5 1.5 0 0 1 2 2h4.5a1.5 1.5 0 0 1 1.06.44L9.122 4H16a1.5 1.5 0 0 1 1.5 1.5v1A1.5 1.5 0 0 1 19 8v2.531a6.027 6.027 0 0 0-1.5-1.228zM16 6.5v-1H8.5l-2-2H2v13h1V8a1.5 1.5 0 0 1 1.5-1.5H16z"/><path d="M14.5 19.5a5 5 0 1 1 0-10 5 5 0 0 1 0 10zM15 14v-2h-1v2h-2v1h2v2h1v-2h2v-1h-2z"/></svg>',tooltip:!0}),i.bind("isOn","isEnabled").to(r,"value","isEnabled"),i.on("execute",(()=>{n.execute("ckbox")})),i})),n.plugins.has("ImageInsertUI")){const t=n.plugins.get("ImageInsertUI");t.registerIntegration({name:"assetManager",observable:r,buttonViewCreator:()=>{const n=this.editor.ui.componentFactory.create("ckbox");return n.icon=e.icons.imageAssetManager,n.bind("label").to(t,"isImageSelected",(e=>o(e?"Replace image with file manager":"Insert image with file manager"))),n},formViewCreator:()=>{const n=this.editor.ui.componentFactory.create("ckbox");return n.icon=e.icons.imageAssetManager,n.withText=!0,n.bind("label").to(t,"isImageSelected",(e=>o(e?"Replace with file manager":"Insert with file manager"))),n.on("execute",(()=>{t.dropdownView.isOpen=!1})),n}})}}}var i=n(492),s=n(209),a=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","#","$","%","*","+",",","-",".",":",";","=","?","@","[","]","^","_","{","|","}","~"],c=e=>{let t=0;for(let n=0;n<e.length;n++){let r=e[n];t=83*t+a.indexOf(r)}return t},l=e=>{let t=e/255;return t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)},u=e=>{let t=Math.max(0,Math.min(1,e));return t<=.0031308?Math.trunc(12.92*t*255+.5):Math.trunc(255*(1.055*Math.pow(t,.4166666666666667)-.055)+.5)},d=(e,t)=>(e=>e<0?-1:1)(e)*Math.pow(Math.abs(e),t),g=class extends Error{constructor(e){super(e),this.name="ValidationError",this.message=e}},h=e=>{if(!e||e.length<6)throw new g("The blurhash string must be at least 6 characters");let t=c(e[0]),n=Math.floor(t/9)+1,r=t%9+1;if(e.length!==4+2*r*n)throw new g(`blurhash length mismatch: length is ${e.length} but it should be ${4+2*r*n}`)},p=e=>{let t=e>>8&255,n=255&e;return[l(e>>16),l(t),l(n)]},f=(e,t)=>{let n=Math.floor(e/361),r=Math.floor(e/19)%19,o=e%19;return[d((n-9)/9,2)*t,d((r-9)/9,2)*t,d((o-9)/9,2)*t]},m=(e,t,n,r)=>{h(e),r|=1;let o=c(e[0]),i=Math.floor(o/9)+1,s=o%9+1,a=(c(e[1])+1)/166,l=new Array(s*i);for(let t=0;t<l.length;t++)if(0===t){let n=c(e.substring(2,6));l[t]=p(n)}else{let n=c(e.substring(4+2*t,6+2*t));l[t]=f(n,a*r)}let d=4*t,g=new Uint8ClampedArray(d*n);for(let e=0;e<n;e++)for(let r=0;r<t;r++){let o=0,a=0,c=0;for(let u=0;u<i;u++)for(let i=0;i<s;i++){let d=Math.cos(Math.PI*r*i/t)*Math.cos(Math.PI*e*u/n),g=l[i+u*s];o+=g[0]*d,a+=g[1]*d,c+=g[2]*d}let h=u(o),p=u(a),f=u(c);g[4*r+0+e*d]=h,g[4*r+1+e*d]=p,g[4*r+2+e*d]=f,g[4*r+3+e*d]=255}return g};function b(e){const t=[];let n=0;for(const r in e){const o=parseInt(r,10);isNaN(o)||(o>n&&(n=o),t.push(`${e[r]} ${r}w`))}const r=[{srcset:t.join(","),sizes:`(max-width: ${n}px) 100vw, ${n}px`,type:"image/webp"}];return{imageFallbackUrl:e.default,imageSources:r}}const v=32;function w({url:e,method:t="GET",data:n,onUploadProgress:r,signal:o,authorization:i}){const s=new XMLHttpRequest;s.open(t,e.toString()),s.setRequestHeader("Authorization",i),s.setRequestHeader("CKBox-Version","CKEditor 5"),s.responseType="json";const a=()=>{s.abort()};return new Promise(((e,t)=>{o.throwIfAborted(),o.addEventListener("abort",a),s.addEventListener("loadstart",(()=>{o.addEventListener("abort",a)})),s.addEventListener("loadend",(()=>{o.removeEventListener("abort",a)})),s.addEventListener("error",(()=>{t()})),s.addEventListener("abort",(()=>{t()})),s.addEventListener("load",(()=>{const n=s.response;if(!n||n.statusCode>=400)return t(n&&n.message);e(n)})),r&&s.upload.addEventListener("progress",(e=>{r(e)})),s.send(n)}))}const _={"image/gif":"gif","image/jpeg":"jpg","image/png":"png","image/webp":"webp","image/bmp":"bmp","image/tiff":"tiff"};class y extends e.Command{constructor(e){super(e),this._chosenAssets=new Set,this._wrapper=null,this._initListeners()}refresh(){this.value=this._getValue(),this.isEnabled=this._checkEnabled()}execute(){this.fire("ckbox:open")}_getValue(){return null!==this._wrapper}_checkEnabled(){const e=this.editor.commands.get("insertImage"),t=this.editor.commands.get("link");return!(!e.isEnabled&&!t.isEnabled)}_prepareOptions(){const e=this.editor.config.get("ckbox");return{theme:e.theme,language:e.language,tokenUrl:e.tokenUrl,serviceOrigin:e.serviceOrigin,dialog:{onClose:()=>this.fire("ckbox:close")},assets:{onChoose:e=>this.fire("ckbox:choose",e)}}}_initListeners(){const e=this.editor,t=e.model,n=!e.config.get("ckbox.ignoreDataId");this.on("ckbox",(()=>{this.refresh()}),{priority:"low"}),this.on("ckbox:open",(()=>{this.isEnabled&&!this.value&&(this._wrapper=(0,s.createElement)(document,"div",{class:"ck ckbox-wrapper"}),document.body.appendChild(this._wrapper),window.CKBox.mount(this._wrapper,this._prepareOptions()))})),this.on("ckbox:close",(()=>{this.value&&(this._wrapper.remove(),this._wrapper=null,e.editing.view.focus())})),this.on("ckbox:choose",((r,o)=>{if(!this.isEnabled)return;const i=e.commands.get("insertImage"),s=e.commands.get("link"),a=function({assets:e,isImageAllowed:t,isLinkAllowed:n}){return e.map((e=>function(e){const t=e.data.metadata;if(!t)return!1;return t.width&&t.height}(e)?{id:e.data.id,type:"image",attributes:k(e)}:{id:e.data.id,type:"link",attributes:x(e)})).filter((e=>"image"===e.type?t:n))}({assets:o,isImageAllowed:i.isEnabled,isLinkAllowed:s.isEnabled}),c=a.length;0!==c&&(t.change((e=>{for(const t of a){const r=t===a[c-1],o=1===c;this._insertAsset(t,r,e,o),n&&(setTimeout((()=>this._chosenAssets.delete(t)),1e3),this._chosenAssets.add(t))}})),e.editing.view.focus())})),this.listenTo(e,"destroy",(()=>{this.fire("ckbox:close"),this._chosenAssets.clear()}))}_insertAsset(e,t,n,r){const o=this.editor.model.document.selection;n.removeSelectionAttribute("linkHref"),"image"===e.type?this._insertImage(e):this._insertLink(e,n,r),t||n.setSelection(o.getLastPosition())}_insertImage(e){const t=this.editor,{imageFallbackUrl:n,imageSources:r,imageTextAlternative:o,imageWidth:i,imageHeight:s,imagePlaceholder:a}=e.attributes;t.execute("insertImage",{source:{src:n,sources:r,alt:o,width:i,height:s,...a?{placeholder:a}:null}})}_insertLink(e,t,n){const r=this.editor,o=r.model,i=o.document.selection,{linkName:a,linkHref:c}=e.attributes;if(i.isCollapsed){const e=(0,s.toMap)(i.getAttributes()),l=t.createText(a,e);if(!n){const e=i.getLastPosition(),n=e.parent;"paragraph"===n.name&&n.isEmpty||r.execute("insertParagraph",{position:e});const s=o.insertContent(l);return t.setSelection(s),void r.execute("link",c)}const u=o.insertContent(l);t.setSelection(u)}r.execute("link",c)}}function k(e){const{imageFallbackUrl:t,imageSources:n}=b(e.data.imageUrls),{description:r,width:o,height:i,blurHash:s}=e.data.metadata,a=function(e){if(e)try{const t=`${v}px`,n=document.createElement("canvas");n.setAttribute("width",t),n.setAttribute("height",t);const r=n.getContext("2d");if(!r)return;const o=r.createImageData(v,v),i=m(e,v,v);return o.data.set(i),r.putImageData(o,0,0),n.toDataURL()}catch(e){return}}(s);return{imageFallbackUrl:t,imageSources:n,imageTextAlternative:r||"",imageWidth:o,imageHeight:i,...a?{imagePlaceholder:a}:null}}function x(e){return{linkName:e.data.name,linkHref:I(e)}}function I(e){const t=new URL(e.data.url);return t.searchParams.set("download","true"),t.toString()}var A=n(448);class j extends e.Plugin{static get pluginName(){return"CKBoxUtils"}static get requires(){return["CloudServices"]}async init(){const e=this.editor,t=!!e.config.get("ckbox"),n=!!window.CKBox;if(!t&&!n)return;e.config.define("ckbox",{serviceOrigin:"https://api.ckbox.io",defaultUploadCategories:null,ignoreDataId:!1,language:e.locale.uiLanguage,theme:"lark",tokenUrl:e.config.get("cloudServices.tokenUrl")});const r=e.plugins.get("CloudServices"),o=e.config.get("cloudServices.tokenUrl"),i=e.config.get("ckbox.tokenUrl");if(!i)throw new s.CKEditorError("ckbox-plugin-missing-token-url",this);this._token=i==o?r.token:await r.registerTokenUrl(i)}getToken(){return this._token}getWorkspaceId(){const e=(0,this.editor.t)("Cannot access default workspace."),t=this.editor.config.get("ckbox.defaultUploadWorkspaceId"),n=function(e,t){const[,n]=e.value.split("."),r=JSON.parse(atob(n)),o=r.auth&&r.auth.ckbox&&r.auth.ckbox.workspaces||[r.aud];return t?"superadmin"==(r.auth&&r.auth.ckbox&&r.auth.ckbox.role)||o.includes(t)?t:null:o[0]}(this._token,t);if(null==n)throw(0,s.logError)("ckbox-access-default-workspace-error"),e;return n}async getCategoryIdForFile(e,t){const n=(0,this.editor.t)("Cannot determine a category for the uploaded file."),r=this.editor.config.get("ckbox.defaultUploadCategories"),o=this._getAvailableCategories(t),i="string"==typeof e?(s=await async function(e,t){try{const n=await fetch(e,{method:"HEAD",cache:"force-cache",...t});return n.ok&&n.headers.get("content-type")||""}catch{return""}}(e,t),_[s]):e.name.match(/\.(?<ext>[^.]+)$/).groups.ext.toLowerCase();var s;const a=await o;if(!a)throw n;if(r){const e=Object.keys(r).find((e=>r[e].find((e=>e.toLowerCase()==i))));if(e){const t=a.find((t=>t.id===e||t.name===e));if(!t)throw n;return t.id}}const c=a.find((e=>e.extensions.find((e=>e.toLowerCase()==i))));if(!c)throw n;return c.id}async _getAvailableCategories(e){const t=this.editor,n=this._token,{signal:r}=e,o=t.config.get("ckbox.serviceOrigin"),i=this.getWorkspaceId();try{const e=[];let t,n=0;do{const r=await a(n);e.push(...r.items),t=r.totalCount-(n+50),n+=50}while(t>0);return e}catch{return r.throwIfAborted(),void(0,s.logError)("ckbox-fetch-category-http-error")}function a(e){const t=new URL("categories",o);return t.searchParams.set("limit",50..toString()),t.searchParams.set("offset",e.toString()),t.searchParams.set("workspaceId",i),w({url:t,signal:r,authorization:n.value})}}}class E extends e.Plugin{static get requires(){return["ImageUploadEditing","ImageUploadProgress",A.FileRepository,O]}static get pluginName(){return"CKBoxUploadAdapter"}async afterInit(){const e=this.editor,t=!!e.config.get("ckbox"),n=!!window.CKBox;if(!t&&!n)return;const r=e.plugins.get(A.FileRepository),o=e.plugins.get(j);r.createUploadAdapter=t=>new C(t,e,o);const i=!e.config.get("ckbox.ignoreDataId"),s=e.plugins.get("ImageUploadEditing");i&&s.on("uploadComplete",((t,{imageElement:n,data:r})=>{e.model.change((e=>{e.setAttribute("ckboxImageId",r.ckboxImageId,n)}))}))}}class C{constructor(e,t,n){this.loader=e,this.token=n.getToken(),this.ckboxUtils=n,this.editor=t,this.controller=new AbortController,this.serviceOrigin=t.config.get("ckbox.serviceOrigin")}async upload(){const e=this.ckboxUtils,t=this.editor.t,n=await this.loader.file,r=await e.getCategoryIdForFile(n,{signal:this.controller.signal}),o=new URL("assets",this.serviceOrigin),i=new FormData;o.searchParams.set("workspaceId",e.getWorkspaceId()),i.append("categoryId",r),i.append("file",n);return w({method:"POST",url:o,data:i,onUploadProgress:e=>{e.lengthComputable&&(this.loader.uploadTotal=e.total,this.loader.uploaded=e.loaded)},signal:this.controller.signal,authorization:this.token.value}).then((async e=>{const t=b(e.imageUrls);return{ckboxImageId:e.id,default:t.imageFallbackUrl,sources:t.imageSources}})).catch((()=>{const e=t("Cannot upload file:")+` ${n.name}.`;return Promise.reject(e)}))}abort(){this.controller.abort()}}class O extends e.Plugin{static get pluginName(){return"CKBoxEditing"}static get requires(){return["LinkEditing","PictureEditing",E,j]}init(){const e=this.editor,t=!!e.config.get("ckbox"),n=!!window.CKBox;(t||n)&&(this._checkImagePlugins(),e.config.get("ckbox.ignoreDataId")||(this._initSchema(),this._initConversion(),this._initFixers()),n&&e.commands.add("ckbox",new y(e)))}_checkImagePlugins(){const e=this.editor;e.plugins.has("ImageBlockEditing")||e.plugins.has("ImageInlineEditing")||(0,s.logError)("ckbox-plugin-image-feature-missing",e)}_initSchema(){const e=this.editor.model.schema;e.extend("$text",{allowAttributes:"ckboxLinkId"}),e.isRegistered("imageBlock")&&e.extend("imageBlock",{allowAttributes:["ckboxImageId","ckboxLinkId"]}),e.isRegistered("imageInline")&&e.extend("imageInline",{allowAttributes:["ckboxImageId","ckboxLinkId"]}),e.addAttributeCheck(((e,t)=>{if(!!!e.last.getAttribute("linkHref")&&"ckboxLinkId"===t)return!1}))}_initConversion(){const e=this.editor;e.conversion.for("downcast").add((e=>{e.on("attribute:ckboxLinkId:imageBlock",((e,t,n)=>{const{writer:r,mapper:o,consumable:i}=n;if(!i.consume(t.item,e.name))return;const s=[...o.toViewElement(t.item).getChildren()].find((e=>"a"===e.name));s&&(t.item.hasAttribute("ckboxLinkId")?r.setAttribute("data-ckbox-resource-id",t.item.getAttribute("ckboxLinkId"),s):r.removeAttribute("data-ckbox-resource-id",s))}),{priority:"low"}),e.on("attribute:ckboxLinkId",((e,t,n)=>{const{writer:r,mapper:o,consumable:i}=n;if(i.consume(t.item,e.name)){if(t.attributeOldValue){const e=P(r,t.attributeOldValue);r.unwrap(o.toViewRange(t.range),e)}if(t.attributeNewValue){const e=P(r,t.attributeNewValue);if(t.item.is("selection")){const t=r.document.selection;r.wrap(t.getFirstRange(),e)}else r.wrap(o.toViewRange(t.range),e)}}}),{priority:"low"})})),e.conversion.for("upcast").add((e=>{e.on("element:a",((e,t,n)=>{const{writer:r,consumable:o}=n;if(!t.viewItem.getAttribute("href"))return;if(!o.consume(t.viewItem,{attributes:["data-ckbox-resource-id"]}))return;const i=t.viewItem.getAttribute("data-ckbox-resource-id");if(i)if(t.modelRange)for(let e of t.modelRange.getItems())e.is("$textProxy")&&(e=e.textNode),L(e)&&r.setAttribute("ckboxLinkId",i,e);else{const e=t.modelCursor.nodeBefore||t.modelCursor.parent;r.setAttribute("ckboxLinkId",i,e)}}),{priority:"low"})})),e.conversion.for("downcast").attributeToAttribute({model:"ckboxImageId",view:"data-ckbox-resource-id"}),e.conversion.for("upcast").elementToAttribute({model:{key:"ckboxImageId",value:e=>e.getAttribute("data-ckbox-resource-id")},view:{attributes:{"data-ckbox-resource-id":/[\s\S]+/}}});const t=e.commands.get("replaceImageSource");t&&this.listenTo(t,"cleanupImage",((e,[t,n])=>{t.removeAttribute("ckboxImageId",n)}))}_initFixers(){const e=this.editor,t=e.model,n=t.document.selection;t.document.registerPostFixer(function(e){return t=>{let n=!1;const r=e.model,o=e.commands.get("ckbox");if(!o)return n;for(const e of r.document.differ.getChanges()){if("insert"!==e.type&&"attribute"!==e.type)continue;const r="insert"===e.type?new i.Range(e.position,e.position.getShiftedBy(e.length)):e.range,s="attribute"===e.type&&"linkHref"===e.attributeKey&&null===e.attributeNewValue;for(const e of r.getItems()){if(s&&e.hasAttribute("ckboxLinkId")){t.removeAttribute("ckboxLinkId",e),n=!0;continue}const r=S(e,o._chosenAssets);for(const o of r){const r="image"===o.type?"ckboxImageId":"ckboxLinkId";o.id!==e.getAttribute(r)&&(t.setAttribute(r,o.id,e),n=!0)}}}return n}}(e)),t.document.registerPostFixer(function(e){return t=>!(e.hasAttribute("linkHref")||!e.hasAttribute("ckboxLinkId"))&&(t.removeSelectionAttribute("ckboxLinkId"),!0)}(n))}}function S(e,t){const n=e.is("element","imageInline")||e.is("element","imageBlock"),r=e.hasAttribute("linkHref");return[...t].filter((t=>"image"===t.type&&n?t.attributes.imageFallbackUrl===e.getAttribute("src"):"link"===t.type&&r?t.attributes.linkHref===e.getAttribute("linkHref"):void 0))}function P(e,t){const n=e.createAttributeElement("a",{"data-ckbox-resource-id":t},{priority:5});return e.setCustomProperty("link",!0,n),n}function L(e){return!!e.is("$text")||!(!e.is("element","imageInline")&&!e.is("element","imageBlock"))}class U extends e.Plugin{static get pluginName(){return"CKBox"}static get requires(){return[O,o]}}const B=function(){this.__data__=[],this.size=0};const T=function(e,t){return e===t||e!=e&&t!=t};const M=function(e,t){for(var n=e.length;n--;)if(T(e[n][0],t))return n;return-1};var F=Array.prototype.splice;const z=function(e){var t=this.__data__,n=M(t,e);return!(n<0)&&(n==t.length-1?t.pop():F.call(t,n,1),--this.size,!0)};const N=function(e){var t=this.__data__,n=M(t,e);return n<0?void 0:t[n][1]};const R=function(e){return M(this.__data__,e)>-1};const K=function(e,t){var n=this.__data__,r=M(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this};function V(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t<n;){var r=e[t];this.set(r[0],r[1])}}V.prototype.clear=B,V.prototype.delete=z,V.prototype.get=N,V.prototype.has=R,V.prototype.set=K;const H=V;const $=function(){this.__data__=new H,this.size=0};const D=function(e){var t=this.__data__,n=t.delete(e);return this.size=t.size,n};const q=function(e){return this.__data__.get(e)};const W=function(e){return this.__data__.has(e)};const Z="object"==typeof global&&global&&global.Object===Object&&global;var G="object"==typeof self&&self&&self.Object===Object&&self;const J=Z||G||Function("return this")();const X=J.Symbol;var Q=Object.prototype,Y=Q.hasOwnProperty,ee=Q.toString,te=X?X.toStringTag:void 0;const ne=function(e){var t=Y.call(e,te),n=e[te];try{e[te]=void 0;var r=!0}catch(e){}var o=ee.call(e);return r&&(t?e[te]=n:delete e[te]),o};var re=Object.prototype.toString;const oe=function(e){return re.call(e)};var ie=X?X.toStringTag:void 0;const se=function(e){return null==e?void 0===e?"[object Undefined]":"[object Null]":ie&&ie in Object(e)?ne(e):oe(e)};const ae=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)};const ce=function(e){if(!ae(e))return!1;var t=se(e);return"[object Function]"==t||"[object GeneratorFunction]"==t||"[object AsyncFunction]"==t||"[object Proxy]"==t};const le=J["__core-js_shared__"];var ue,de=(ue=/[^.]+$/.exec(le&&le.keys&&le.keys.IE_PROTO||""))?"Symbol(src)_1."+ue:"";const ge=function(e){return!!de&&de in e};var he=Function.prototype.toString;const pe=function(e){if(null!=e){try{return he.call(e)}catch(e){}try{return e+""}catch(e){}}return""};var fe=/^\[object .+?Constructor\]$/,me=Function.prototype,be=Object.prototype,ve=me.toString,we=be.hasOwnProperty,_e=RegExp("^"+ve.call(we).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");const ye=function(e){return!(!ae(e)||ge(e))&&(ce(e)?_e:fe).test(pe(e))};const ke=function(e,t){return null==e?void 0:e[t]};const xe=function(e,t){var n=ke(e,t);return ye(n)?n:void 0};const Ie=xe(J,"Map");const Ae=xe(Object,"create");const je=function(){this.__data__=Ae?Ae(null):{},this.size=0};const Ee=function(e){var t=this.has(e)&&delete this.__data__[e];return this.size-=t?1:0,t};var Ce=Object.prototype.hasOwnProperty;const Oe=function(e){var t=this.__data__;if(Ae){var n=t[e];return"__lodash_hash_undefined__"===n?void 0:n}return Ce.call(t,e)?t[e]:void 0};var Se=Object.prototype.hasOwnProperty;const Pe=function(e){var t=this.__data__;return Ae?void 0!==t[e]:Se.call(t,e)};const Le=function(e,t){var n=this.__data__;return this.size+=this.has(e)?0:1,n[e]=Ae&&void 0===t?"__lodash_hash_undefined__":t,this};function Ue(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t<n;){var r=e[t];this.set(r[0],r[1])}}Ue.prototype.clear=je,Ue.prototype.delete=Ee,Ue.prototype.get=Oe,Ue.prototype.has=Pe,Ue.prototype.set=Le;const Be=Ue;const Te=function(){this.size=0,this.__data__={hash:new Be,map:new(Ie||H),string:new Be}};const Me=function(e){var t=typeof e;return"string"==t||"number"==t||"symbol"==t||"boolean"==t?"__proto__"!==e:null===e};const Fe=function(e,t){var n=e.__data__;return Me(t)?n["string"==typeof t?"string":"hash"]:n.map};const ze=function(e){var t=Fe(this,e).delete(e);return this.size-=t?1:0,t};const Ne=function(e){return Fe(this,e).get(e)};const Re=function(e){return Fe(this,e).has(e)};const Ke=function(e,t){var n=Fe(this,e),r=n.size;return n.set(e,t),this.size+=n.size==r?0:1,this};function Ve(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t<n;){var r=e[t];this.set(r[0],r[1])}}Ve.prototype.clear=Te,Ve.prototype.delete=ze,Ve.prototype.get=Ne,Ve.prototype.has=Re,Ve.prototype.set=Ke;const He=Ve;const $e=function(e,t){var n=this.__data__;if(n instanceof H){var r=n.__data__;if(!Ie||r.length<199)return r.push([e,t]),this.size=++n.size,this;n=this.__data__=new He(r)}return n.set(e,t),this.size=n.size,this};function De(e){var t=this.__data__=new H(e);this.size=t.size}De.prototype.clear=$,De.prototype.delete=D,De.prototype.get=q,De.prototype.has=W,De.prototype.set=$e;const qe=De;const We=function(e){return this.__data__.set(e,"__lodash_hash_undefined__"),this};const Ze=function(e){return this.__data__.has(e)};function Ge(e){var t=-1,n=null==e?0:e.length;for(this.__data__=new He;++t<n;)this.add(e[t])}Ge.prototype.add=Ge.prototype.push=We,Ge.prototype.has=Ze;const Je=Ge;const Xe=function(e,t){for(var n=-1,r=null==e?0:e.length;++n<r;)if(t(e[n],n,e))return!0;return!1};const Qe=function(e,t){return e.has(t)};const Ye=function(e,t,n,r,o,i){var s=1&n,a=e.length,c=t.length;if(a!=c&&!(s&&c>a))return!1;var l=i.get(e),u=i.get(t);if(l&&u)return l==t&&u==e;var d=-1,g=!0,h=2&n?new Je:void 0;for(i.set(e,t),i.set(t,e);++d<a;){var p=e[d],f=t[d];if(r)var m=s?r(f,p,d,t,e,i):r(p,f,d,e,t,i);if(void 0!==m){if(m)continue;g=!1;break}if(h){if(!Xe(t,(function(e,t){if(!Qe(h,t)&&(p===e||o(p,e,n,r,i)))return h.push(t)}))){g=!1;break}}else if(p!==f&&!o(p,f,n,r,i)){g=!1;break}}return i.delete(e),i.delete(t),g};const et=J.Uint8Array;const tt=function(e){var t=-1,n=Array(e.size);return e.forEach((function(e,r){n[++t]=[r,e]})),n};const nt=function(e){var t=-1,n=Array(e.size);return e.forEach((function(e){n[++t]=e})),n};var rt=X?X.prototype:void 0,ot=rt?rt.valueOf:void 0;const it=function(e,t,n,r,o,i,s){switch(n){case"[object DataView]":if(e.byteLength!=t.byteLength||e.byteOffset!=t.byteOffset)return!1;e=e.buffer,t=t.buffer;case"[object ArrayBuffer]":return!(e.byteLength!=t.byteLength||!i(new et(e),new et(t)));case"[object Boolean]":case"[object Date]":case"[object Number]":return T(+e,+t);case"[object Error]":return e.name==t.name&&e.message==t.message;case"[object RegExp]":case"[object String]":return e==t+"";case"[object Map]":var a=tt;case"[object Set]":var c=1&r;if(a||(a=nt),e.size!=t.size&&!c)return!1;var l=s.get(e);if(l)return l==t;r|=2,s.set(e,t);var u=Ye(a(e),a(t),r,o,i,s);return s.delete(e),u;case"[object Symbol]":if(ot)return ot.call(e)==ot.call(t)}return!1};const st=function(e,t){for(var n=-1,r=t.length,o=e.length;++n<r;)e[o+n]=t[n];return e};const at=Array.isArray;const ct=function(e,t,n){var r=t(e);return at(e)?r:st(r,n(e))};const lt=function(e,t){for(var n=-1,r=null==e?0:e.length,o=0,i=[];++n<r;){var s=e[n];t(s,n,e)&&(i[o++]=s)}return i};const ut=function(){return[]};var dt=Object.prototype.propertyIsEnumerable,gt=Object.getOwnPropertySymbols;const ht=gt?function(e){return null==e?[]:(e=Object(e),lt(gt(e),(function(t){return dt.call(e,t)})))}:ut;const pt=function(e,t){for(var n=-1,r=Array(e);++n<e;)r[n]=t(n);return r};const ft=function(e){return null!=e&&"object"==typeof e};const mt=function(e){return ft(e)&&"[object Arguments]"==se(e)};var bt=Object.prototype,vt=bt.hasOwnProperty,wt=bt.propertyIsEnumerable;const _t=mt(function(){return arguments}())?mt:function(e){return ft(e)&&vt.call(e,"callee")&&!wt.call(e,"callee")};const yt=function(){return!1};var kt="object"==typeof exports&&exports&&!exports.nodeType&&exports,xt=kt&&"object"==typeof module&&module&&!module.nodeType&&module,It=xt&&xt.exports===kt?J.Buffer:void 0;const At=(It?It.isBuffer:void 0)||yt;var jt=/^(?:0|[1-9]\d*)$/;const Et=function(e,t){var n=typeof e;return!!(t=null==t?9007199254740991:t)&&("number"==n||"symbol"!=n&&jt.test(e))&&e>-1&&e%1==0&&e<t};const Ct=function(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=9007199254740991};var Ot={};Ot["[object Float32Array]"]=Ot["[object Float64Array]"]=Ot["[object Int8Array]"]=Ot["[object Int16Array]"]=Ot["[object Int32Array]"]=Ot["[object Uint8Array]"]=Ot["[object Uint8ClampedArray]"]=Ot["[object Uint16Array]"]=Ot["[object Uint32Array]"]=!0,Ot["[object Arguments]"]=Ot["[object Array]"]=Ot["[object ArrayBuffer]"]=Ot["[object Boolean]"]=Ot["[object DataView]"]=Ot["[object Date]"]=Ot["[object Error]"]=Ot["[object Function]"]=Ot["[object Map]"]=Ot["[object Number]"]=Ot["[object Object]"]=Ot["[object RegExp]"]=Ot["[object Set]"]=Ot["[object String]"]=Ot["[object WeakMap]"]=!1;const St=function(e){return ft(e)&&Ct(e.length)&&!!Ot[se(e)]};const Pt=function(e){return function(t){return e(t)}};var Lt="object"==typeof exports&&exports&&!exports.nodeType&&exports,Ut=Lt&&"object"==typeof module&&module&&!module.nodeType&&module,Bt=Ut&&Ut.exports===Lt&&Z.process,Tt=function(){try{var e=Ut&&Ut.require&&Ut.require("util").types;return e||Bt&&Bt.binding&&Bt.binding("util")}catch(e){}}();var Mt=Tt&&Tt.isTypedArray;const Ft=Mt?Pt(Mt):St;var zt=Object.prototype.hasOwnProperty;const Nt=function(e,t){var n=at(e),r=!n&&_t(e),o=!n&&!r&&At(e),i=!n&&!r&&!o&&Ft(e),s=n||r||o||i,a=s?pt(e.length,String):[],c=a.length;for(var l in e)!t&&!zt.call(e,l)||s&&("length"==l||o&&("offset"==l||"parent"==l)||i&&("buffer"==l||"byteLength"==l||"byteOffset"==l)||Et(l,c))||a.push(l);return a};var Rt=Object.prototype;const Kt=function(e){var t=e&&e.constructor;return e===("function"==typeof t&&t.prototype||Rt)};const Vt=function(e,t){return function(n){return e(t(n))}}(Object.keys,Object);var Ht=Object.prototype.hasOwnProperty;const $t=function(e){if(!Kt(e))return Vt(e);var t=[];for(var n in Object(e))Ht.call(e,n)&&"constructor"!=n&&t.push(n);return t};const Dt=function(e){return null!=e&&Ct(e.length)&&!ce(e)};const qt=function(e){return Dt(e)?Nt(e):$t(e)};const Wt=function(e){return ct(e,qt,ht)};var Zt=Object.prototype.hasOwnProperty;const Gt=function(e,t,n,r,o,i){var s=1&n,a=Wt(e),c=a.length;if(c!=Wt(t).length&&!s)return!1;for(var l=c;l--;){var u=a[l];if(!(s?u in t:Zt.call(t,u)))return!1}var d=i.get(e),g=i.get(t);if(d&&g)return d==t&&g==e;var h=!0;i.set(e,t),i.set(t,e);for(var p=s;++l<c;){var f=e[u=a[l]],m=t[u];if(r)var b=s?r(m,f,u,t,e,i):r(f,m,u,e,t,i);if(!(void 0===b?f===m||o(f,m,n,r,i):b)){h=!1;break}p||(p="constructor"==u)}if(h&&!p){var v=e.constructor,w=t.constructor;v==w||!("constructor"in e)||!("constructor"in t)||"function"==typeof v&&v instanceof v&&"function"==typeof w&&w instanceof w||(h=!1)}return i.delete(e),i.delete(t),h};const Jt=xe(J,"DataView");const Xt=xe(J,"Promise");const Qt=xe(J,"Set");const Yt=xe(J,"WeakMap");var en="[object Map]",tn="[object Promise]",nn="[object Set]",rn="[object WeakMap]",on="[object DataView]",sn=pe(Jt),an=pe(Ie),cn=pe(Xt),ln=pe(Qt),un=pe(Yt),dn=se;(Jt&&dn(new Jt(new ArrayBuffer(1)))!=on||Ie&&dn(new Ie)!=en||Xt&&dn(Xt.resolve())!=tn||Qt&&dn(new Qt)!=nn||Yt&&dn(new Yt)!=rn)&&(dn=function(e){var t=se(e),n="[object Object]"==t?e.constructor:void 0,r=n?pe(n):"";if(r)switch(r){case sn:return on;case an:return en;case cn:return tn;case ln:return nn;case un:return rn}return t});const gn=dn;var hn="[object Arguments]",pn="[object Array]",fn="[object Object]",mn=Object.prototype.hasOwnProperty;const bn=function(e,t,n,r,o,i){var s=at(e),a=at(t),c=s?pn:gn(e),l=a?pn:gn(t),u=(c=c==hn?fn:c)==fn,d=(l=l==hn?fn:l)==fn,g=c==l;if(g&&At(e)){if(!At(t))return!1;s=!0,u=!1}if(g&&!u)return i||(i=new qe),s||Ft(e)?Ye(e,t,n,r,o,i):it(e,t,c,n,r,o,i);if(!(1&n)){var h=u&&mn.call(e,"__wrapped__"),p=d&&mn.call(t,"__wrapped__");if(h||p){var f=h?e.value():e,m=p?t.value():t;return i||(i=new qe),o(f,m,n,r,i)}}return!!g&&(i||(i=new qe),Gt(e,t,n,r,o,i))};const vn=function e(t,n,r,o,i){return t===n||(null==t||null==n||!ft(t)&&!ft(n)?t!=t&&n!=n:bn(t,n,r,o,e,i))};const wn=function(e,t){return vn(e,t)};function _n(e){if(Array.isArray(e)){const t=e.map(_n);return e=>t.some((t=>t(e)))}if("origin"==e){const e=s.global.window.location.origin;return t=>t.startsWith(e+"/")}if("function"==typeof e)return e;if(e instanceof RegExp)return t=>!(!t.match(e)&&!t.replace(/^https?:\/\//,"").match(e));return()=>!1}class yn extends e.Command{constructor(e){super(e),this._wrapper=null,this._processInProgress=new Set,this.value=!1,this._canEdit=function(e){const t=_n(e);return e=>!(!e.is("element","imageInline")&&!e.is("element","imageBlock"))&&(!!e.hasAttribute("ckboxImageId")||!!e.hasAttribute("src")&&t(e.getAttribute("src")))}(e.config.get("ckbox.allowExternalImagesEditing")),this._prepareOptions=(0,s.abortableDebounce)(((e,t)=>this._prepareOptionsAbortable(e,t))),this._prepareListeners()}refresh(){const e=this.editor;this.value=this._getValue();const t=e.model.document.selection.getSelectedElement();this.isEnabled=!!t&&this._canEdit(t)&&!this._checkIfElementIsBeingProcessed(t)}execute(){if(this._getValue())return;const e=(0,s.createElement)(document,"div",{class:"ck ckbox-wrapper"});this._wrapper=e,this.value=!0,document.body.appendChild(this._wrapper);const n={element:this.editor.model.document.selection.getSelectedElement(),controller:new AbortController};this._prepareOptions(n).then((t=>window.CKBox.mountImageEditor(e,t)),(e=>{const n=this.editor,r=n.t;n.plugins.get(t.Notification).showWarning(r("Failed to determine category of edited image."),{namespace:"ckbox"}),console.error(e),this._handleImageEditorClose()}))}destroy(){this._handleImageEditorClose(),this._prepareOptions.abort();for(const e of this._processInProgress.values())e.controller.abort();super.destroy()}_getValue(){return null!==this._wrapper}async _prepareOptionsAbortable(e,t){const n=this.editor,r=n.config.get("ckbox"),o=n.plugins.get(j),{element:i}=t;let s;const a=i.getAttribute("ckboxImageId");if(a)s={assetId:a};else{const t=i.getAttribute("src");s={imageUrl:t,uploadCategoryId:await o.getCategoryIdForFile(t,{signal:e})}}return{...s,imageEditing:{allowOverwrite:!1},tokenUrl:r.tokenUrl,onClose:()=>this._handleImageEditorClose(),onSave:e=>this._handleImageEditorSave(t,e)}}_prepareListeners(){this.listenTo(this.editor.model.document,"change:data",(()=>{this._getProcessingStatesOfDeletedImages().forEach((e=>{e.controller.abort()}))}))}_getProcessingStatesOfDeletedImages(){const e=[];for(const t of this._processInProgress.values())"$graveyard"==t.element.root.rootName&&e.push(t);return e}_checkIfElementIsBeingProcessed(e){for(const{element:t}of this._processInProgress)if(wn(t,e))return!0;return!1}_handleImageEditorClose(){this._wrapper&&(this._wrapper.remove(),this._wrapper=null,this.editor.editing.view.focus(),this.refresh())}_handleImageEditorSave(n,r){const o=this.editor.locale.t,i=this.editor.plugins.get(t.Notification),a=this.editor.plugins.get(e.PendingActions),c=a.add(o("Processing the edited image."));this._processInProgress.add(n),this._showImageProcessingIndicator(n.element,r),this.refresh(),this._waitForAssetProcessed(r.data.id,n.controller.signal).then((e=>{this._replaceImage(n.element,e)}),(e=>{this.editor.editing.reconvertItem(n.element),n.controller.signal.aborted||(!e||e instanceof s.CKEditorError?i.showWarning(o("Server failed to process the image."),{namespace:"ckbox"}):console.error(e))})).finally((()=>{this._processInProgress.delete(n),a.remove(c),this.refresh()}))}async _getAssetStatusFromServer(e,t){const n=this.editor.plugins.get(j),r=new URL("assets/"+e,this.editor.config.get("ckbox.serviceOrigin")),o=await w({url:r,signal:t,authorization:n.getToken().value}),i=o.metadata.metadataProcessingStatus;if(!i||"queued"==i)throw new s.CKEditorError("ckbox-image-not-processed");return{data:{...o}}}async _waitForAssetProcessed(e,t){const n=await(0,s.retry)((()=>this._getAssetStatusFromServer(e,t)),{signal:t,maxAttempts:5});if("success"!=n.data.metadata.metadataProcessingStatus)throw new s.CKEditorError("ckbox-image-processing-failed");return n}_showImageProcessingIndicator(e,t){const n=this.editor;n.editing.view.change((r=>{const o=n.editing.mapper.toViewElement(e),i=this.editor.plugins.get("ImageUtils").findViewImgElement(o);r.removeStyle("aspect-ratio",i),r.setAttribute("width",t.data.metadata.width,i),r.setAttribute("height",t.data.metadata.height,i),r.setStyle("width",`${t.data.metadata.width}px`,i),r.setStyle("height",`${t.data.metadata.height}px`,i),r.addClass("image-processing",o)}))}_replaceImage(e,t){const n=this.editor,{imageFallbackUrl:r,imageSources:o,imageWidth:i,imageHeight:s,imagePlaceholder:a}=k(t),c=Array.from(n.model.document.selection.getRanges());n.model.change((l=>{l.setSelection(e,"on"),n.execute("insertImage",{source:{src:r,sources:o,alt:e.getAttribute("alt"),width:i,height:s,...a?{placeholder:a}:null}});const u=e.getChildren();e=n.model.document.selection.getSelectedElement();for(const t of u)l.append(l.cloneElement(t),e);l.setAttribute("ckboxImageId",t.data.id,e),l.setSelection(c)}))}}class kn extends e.Plugin{static get pluginName(){return"CKBoxImageEditEditing"}static get requires(){return[O,j,e.PendingActions,t.Notification,"ImageUtils","ImageEditing"]}init(){const{editor:e}=this;e.commands.add("ckboxImageEdit",new yn(e))}}class xn extends e.Plugin{static get pluginName(){return"CKBoxImageEditUI"}init(){const e=this.editor;e.ui.componentFactory.add("ckboxImageEdit",(n=>{const r=e.commands.get("ckboxImageEdit"),o=new t.ButtonView(n),i=n.t;return o.set({label:i("Edit image"),icon:'<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M1.201 1C.538 1 0 1.47 0 2.1v12.86C0 15.603.534 16 1.186 16H6.45l3.647-3.596-3.48-3.254a.694.694 0 0 0-.958-.033L1.5 13.6V2.5h15v4.59a3.477 3.477 0 0 1 1.5.15V2.1c0-.63-.547-1.1-1.2-1.1H1.202Zm11.723 2.805a2.137 2.137 0 0 0-2.045 2.406 2.13 2.13 0 0 0 4.172.277 2.134 2.134 0 0 0-.76-2.244 2.13 2.13 0 0 0-1.367-.44Z"/><path d="M8.1 17.612V20h2.39l7.046-7.046-2.39-2.39L8.1 17.612Zm11.283-6.506a.638.638 0 0 0 .139-.692.603.603 0 0 0-.139-.206L17.892 8.72a.63.63 0 0 0-.898 0l-1.167 1.163 2.391 2.39 1.165-1.167Z"/></svg>',tooltip:!0}),o.bind("isOn").to(r,"value",r,"isEnabled",((e,t)=>e&&t)),o.bind("isEnabled").to(r),this.listenTo(o,"execute",(()=>{e.execute("ckboxImageEdit"),e.editing.view.focus()})),o}))}}var In=n(62),An=n.n(In),jn=n(70),En={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};An()(jn.Z,En);jn.Z.locals;class Cn extends e.Plugin{static get pluginName(){return"CKBoxImageEdit"}static get requires(){return[kn,xn]}}})(),(window.CKEditor5=window.CKEditor5||{}).ckbox=r})();
|
package/lang/contexts.json
CHANGED
@@ -4,5 +4,6 @@
|
|
4
4
|
"Cannot access default workspace.": "A message is displayed when the user is not authorised to access the CKBox workspace configured as default one.",
|
5
5
|
"Edit image": "Image toolbar button tooltip for opening a dialog to manipulate the image.",
|
6
6
|
"Processing the edited image.": "A message stating that image editing is in progress.",
|
7
|
-
"Server failed to process the image.": "A message is displayed when the server fails to process an image or doesn't respond."
|
7
|
+
"Server failed to process the image.": "A message is displayed when the server fails to process an image or doesn't respond.",
|
8
|
+
"Failed to determine category of edited image.": "A message is displayed when category of the image user wants to edit can't be determined."
|
8
9
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@ckeditor/ckeditor5-ckbox",
|
3
|
-
"version": "0.0.0-nightly-
|
3
|
+
"version": "0.0.0-nightly-20231206.0",
|
4
4
|
"description": "CKBox integration for CKEditor 5.",
|
5
5
|
"keywords": [
|
6
6
|
"ckeditor",
|
@@ -12,7 +12,7 @@
|
|
12
12
|
],
|
13
13
|
"main": "src/index.js",
|
14
14
|
"dependencies": {
|
15
|
-
"ckeditor5": "0.0.0-nightly-
|
15
|
+
"ckeditor5": "0.0.0-nightly-20231206.0",
|
16
16
|
"blurhash": "^2.0.5",
|
17
17
|
"lodash-es": "4.17.21"
|
18
18
|
},
|
package/src/ckboxconfig.d.ts
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
* @module ckbox/ckboxconfig
|
7
7
|
*/
|
8
8
|
import type { TokenUrl } from '@ckeditor/ckeditor5-cloud-services';
|
9
|
+
import type { ArrayOrItem } from 'ckeditor5/src/utils';
|
9
10
|
/**
|
10
11
|
* The configuration of the {@link module:ckbox/ckbox~CKBox CKBox feature}.
|
11
12
|
*
|
@@ -89,6 +90,23 @@ export interface CKBoxConfig {
|
|
89
90
|
* Enforces displaying the "Powered by CKBox" link regardless of the CKBox plan used.
|
90
91
|
*/
|
91
92
|
forceDemoLabel?: boolean;
|
93
|
+
/**
|
94
|
+
* Allows editing images that are not hosted in CKBox service.
|
95
|
+
*
|
96
|
+
* This configuration option should whitelist URL(s) of images that should be editable.
|
97
|
+
* Make sure that allowed image resources have CORS enabled.
|
98
|
+
*
|
99
|
+
* The image is editable if this option is:
|
100
|
+
* * a regular expression and it matches the image URL, or
|
101
|
+
* * a custom function that returns `true` for the image URL, or
|
102
|
+
* * `'origin'` literal and the image URL is from the same origin, or
|
103
|
+
* * an array of the above and the image URL matches one of the array elements.
|
104
|
+
*
|
105
|
+
* Images hosted in CKBox are always editable.
|
106
|
+
*
|
107
|
+
* @default []
|
108
|
+
*/
|
109
|
+
allowExternalImagesEditing?: ArrayOrItem<RegExp | 'origin' | ((src: string) => boolean)>;
|
92
110
|
/**
|
93
111
|
* Inserts the unique asset ID as the `data-ckbox-resource-id` attribute. To disable this behavior, set it to `true`.
|
94
112
|
*
|
package/src/ckboxediting.d.ts
CHANGED
@@ -2,12 +2,9 @@
|
|
2
2
|
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
4
|
*/
|
5
|
-
/**
|
6
|
-
* @module ckbox/ckboxediting
|
7
|
-
*/
|
8
|
-
import type { InitializedToken } from '@ckeditor/ckeditor5-cloud-services';
|
9
5
|
import { Plugin } from 'ckeditor5/src/core';
|
10
6
|
import CKBoxUploadAdapter from './ckboxuploadadapter';
|
7
|
+
import CKBoxUtils from './ckboxutils';
|
11
8
|
/**
|
12
9
|
* The CKBox editing feature. It introduces the {@link module:ckbox/ckboxcommand~CKBoxCommand CKBox command} and
|
13
10
|
* {@link module:ckbox/ckboxuploadadapter~CKBoxUploadAdapter CKBox upload adapter}.
|
@@ -24,19 +21,15 @@ export default class CKBoxEditing extends Plugin {
|
|
24
21
|
/**
|
25
22
|
* @inheritDoc
|
26
23
|
*/
|
27
|
-
static get requires(): readonly ["
|
24
|
+
static get requires(): readonly ["LinkEditing", "PictureEditing", typeof CKBoxUploadAdapter, typeof CKBoxUtils];
|
28
25
|
/**
|
29
26
|
* @inheritDoc
|
30
27
|
*/
|
31
|
-
init():
|
32
|
-
/**
|
33
|
-
* Returns a token used by the CKBox plugin for communication with the CKBox service.
|
34
|
-
*/
|
35
|
-
getToken(): InitializedToken;
|
28
|
+
init(): void;
|
36
29
|
/**
|
37
|
-
*
|
30
|
+
* Checks if the at least one image plugin is loaded.
|
38
31
|
*/
|
39
|
-
private
|
32
|
+
private _checkImagePlugins;
|
40
33
|
/**
|
41
34
|
* Extends the schema to allow the `ckboxImageId` and `ckboxLinkId` attributes for links and images.
|
42
35
|
*/
|
package/src/ckboxediting.js
CHANGED
@@ -4,10 +4,10 @@
|
|
4
4
|
*/
|
5
5
|
import { Plugin } from 'ckeditor5/src/core';
|
6
6
|
import { Range } from 'ckeditor5/src/engine';
|
7
|
-
import {
|
7
|
+
import { logError } from 'ckeditor5/src/utils';
|
8
8
|
import CKBoxCommand from './ckboxcommand';
|
9
9
|
import CKBoxUploadAdapter from './ckboxuploadadapter';
|
10
|
-
|
10
|
+
import CKBoxUtils from './ckboxutils';
|
11
11
|
/**
|
12
12
|
* The CKBox editing feature. It introduces the {@link module:ckbox/ckboxcommand~CKBoxCommand CKBox command} and
|
13
13
|
* {@link module:ckbox/ckboxuploadadapter~CKBoxUploadAdapter CKBox upload adapter}.
|
@@ -23,12 +23,12 @@ export default class CKBoxEditing extends Plugin {
|
|
23
23
|
* @inheritDoc
|
24
24
|
*/
|
25
25
|
static get requires() {
|
26
|
-
return ['
|
26
|
+
return ['LinkEditing', 'PictureEditing', CKBoxUploadAdapter, CKBoxUtils];
|
27
27
|
}
|
28
28
|
/**
|
29
29
|
* @inheritDoc
|
30
30
|
*/
|
31
|
-
|
31
|
+
init() {
|
32
32
|
const editor = this.editor;
|
33
33
|
const hasConfiguration = !!editor.config.get('ckbox');
|
34
34
|
const isLibraryLoaded = !!window.CKBox;
|
@@ -37,20 +37,7 @@ export default class CKBoxEditing extends Plugin {
|
|
37
37
|
if (!hasConfiguration && !isLibraryLoaded) {
|
38
38
|
return;
|
39
39
|
}
|
40
|
-
this.
|
41
|
-
const cloudServicesCore = editor.plugins.get('CloudServicesCore');
|
42
|
-
const ckboxTokenUrl = editor.config.get('ckbox.tokenUrl');
|
43
|
-
const cloudServicesTokenUrl = editor.config.get('cloudServices.tokenUrl');
|
44
|
-
// To avoid fetching the same token twice we need to compare the `ckbox.tokenUrl` and `cloudServices.tokenUrl` values.
|
45
|
-
// If they are equal, it's enough to take the token generated by the `CloudServices` plugin.
|
46
|
-
if (ckboxTokenUrl === cloudServicesTokenUrl) {
|
47
|
-
const cloudServices = editor.plugins.get('CloudServices');
|
48
|
-
this._token = cloudServices.token;
|
49
|
-
}
|
50
|
-
// Otherwise, create a new token manually.
|
51
|
-
else {
|
52
|
-
this._token = await cloudServicesCore.createToken(ckboxTokenUrl).init();
|
53
|
-
}
|
40
|
+
this._checkImagePlugins();
|
54
41
|
// Extending the schema, registering converters and applying fixers only make sense if the configuration option to assign
|
55
42
|
// the assets ID with the model elements is enabled.
|
56
43
|
if (!editor.config.get('ckbox.ignoreDataId')) {
|
@@ -64,45 +51,10 @@ export default class CKBoxEditing extends Plugin {
|
|
64
51
|
}
|
65
52
|
}
|
66
53
|
/**
|
67
|
-
*
|
68
|
-
*/
|
69
|
-
getToken() {
|
70
|
-
return this._token;
|
71
|
-
}
|
72
|
-
/**
|
73
|
-
* Initializes the `ckbox` editor configuration.
|
54
|
+
* Checks if the at least one image plugin is loaded.
|
74
55
|
*/
|
75
|
-
|
56
|
+
_checkImagePlugins() {
|
76
57
|
const editor = this.editor;
|
77
|
-
editor.config.define('ckbox', {
|
78
|
-
serviceOrigin: 'https://api.ckbox.io',
|
79
|
-
defaultUploadCategories: null,
|
80
|
-
ignoreDataId: false,
|
81
|
-
language: editor.locale.uiLanguage,
|
82
|
-
theme: DEFAULT_CKBOX_THEME_NAME,
|
83
|
-
tokenUrl: editor.config.get('cloudServices.tokenUrl')
|
84
|
-
});
|
85
|
-
const tokenUrl = editor.config.get('ckbox.tokenUrl');
|
86
|
-
if (!tokenUrl) {
|
87
|
-
/**
|
88
|
-
* The {@link module:ckbox/ckboxconfig~CKBoxConfig#tokenUrl `config.ckbox.tokenUrl`} or the
|
89
|
-
* {@link module:cloud-services/cloudservicesconfig~CloudServicesConfig#tokenUrl `config.cloudServices.tokenUrl`}
|
90
|
-
* configuration is required for the CKBox plugin.
|
91
|
-
*
|
92
|
-
* ```ts
|
93
|
-
* ClassicEditor.create( document.createElement( 'div' ), {
|
94
|
-
* ckbox: {
|
95
|
-
* tokenUrl: "YOUR_TOKEN_URL"
|
96
|
-
* // ...
|
97
|
-
* }
|
98
|
-
* // ...
|
99
|
-
* } );
|
100
|
-
* ```
|
101
|
-
*
|
102
|
-
* @error ckbox-plugin-missing-token-url
|
103
|
-
*/
|
104
|
-
throw new CKEditorError('ckbox-plugin-missing-token-url', this);
|
105
|
-
}
|
106
58
|
if (!editor.plugins.has('ImageBlockEditing') && !editor.plugins.has('ImageInlineEditing')) {
|
107
59
|
/**
|
108
60
|
* The CKBox feature requires one of the following plugins to be loaded to work correctly:
|
@@ -24,6 +24,14 @@ export default class CKBoxImageEditCommand extends Command {
|
|
24
24
|
* The states of image processing in progress.
|
25
25
|
*/
|
26
26
|
private _processInProgress;
|
27
|
+
/**
|
28
|
+
* Determines if the element can be edited.
|
29
|
+
*/
|
30
|
+
private _canEdit;
|
31
|
+
/**
|
32
|
+
* A wrapper function to prepare mount options. Ensures that at most one preparation is in-flight.
|
33
|
+
*/
|
34
|
+
private _prepareOptions;
|
27
35
|
/**
|
28
36
|
* @inheritDoc
|
29
37
|
*/
|
@@ -47,7 +55,7 @@ export default class CKBoxImageEditCommand extends Command {
|
|
47
55
|
/**
|
48
56
|
* Creates the options object for the CKBox Image Editor dialog.
|
49
57
|
*/
|
50
|
-
private
|
58
|
+
private _prepareOptionsAbortable;
|
51
59
|
/**
|
52
60
|
* Initializes event lister for an event of removing an image.
|
53
61
|
*/
|
@@ -56,6 +64,7 @@ export default class CKBoxImageEditCommand extends Command {
|
|
56
64
|
* Gets processing states of images that have been deleted in the mean time.
|
57
65
|
*/
|
58
66
|
private _getProcessingStatesOfDeletedImages;
|
67
|
+
private _checkIfElementIsBeingProcessed;
|
59
68
|
/**
|
60
69
|
* Closes the CKBox Image Editor dialog.
|
61
70
|
*/
|
@@ -7,12 +7,13 @@
|
|
7
7
|
* @module ckbox/ckboximageedit/ckboximageeditcommand
|
8
8
|
*/
|
9
9
|
import { Command, PendingActions } from 'ckeditor5/src/core';
|
10
|
-
import { CKEditorError, createElement, retry } from 'ckeditor5/src/utils';
|
10
|
+
import { CKEditorError, abortableDebounce, createElement, retry } from 'ckeditor5/src/utils';
|
11
11
|
import { Notification } from 'ckeditor5/src/ui';
|
12
12
|
import { isEqual } from 'lodash-es';
|
13
|
-
import CKBoxEditing from '../ckboxediting';
|
14
13
|
import { sendHttpRequest } from '../utils';
|
15
14
|
import { prepareImageAssetAttributes } from '../ckboxcommand';
|
15
|
+
import { createEditabilityChecker } from './utils';
|
16
|
+
import CKBoxUtils from '../ckboxutils';
|
16
17
|
/**
|
17
18
|
* The CKBox edit image command.
|
18
19
|
*
|
@@ -31,8 +32,10 @@ export default class CKBoxImageEditCommand extends Command {
|
|
31
32
|
/**
|
32
33
|
* The states of image processing in progress.
|
33
34
|
*/
|
34
|
-
this._processInProgress = new
|
35
|
+
this._processInProgress = new Set();
|
35
36
|
this.value = false;
|
37
|
+
this._canEdit = createEditabilityChecker(editor.config.get('ckbox.allowExternalImagesEditing'));
|
38
|
+
this._prepareOptions = abortableDebounce((signal, state) => this._prepareOptionsAbortable(signal, state));
|
36
39
|
this._prepareListeners();
|
37
40
|
}
|
38
41
|
/**
|
@@ -42,16 +45,10 @@ export default class CKBoxImageEditCommand extends Command {
|
|
42
45
|
const editor = this.editor;
|
43
46
|
this.value = this._getValue();
|
44
47
|
const selectedElement = editor.model.document.selection.getSelectedElement();
|
45
|
-
|
46
|
-
selectedElement
|
47
|
-
|
48
|
-
|
49
|
-
if (isImageElement && selectedElement.hasAttribute('ckboxImageId') && !isBeingProcessed) {
|
50
|
-
this.isEnabled = true;
|
51
|
-
}
|
52
|
-
else {
|
53
|
-
this.isEnabled = false;
|
54
|
-
}
|
48
|
+
this.isEnabled =
|
49
|
+
!!selectedElement &&
|
50
|
+
this._canEdit(selectedElement) &&
|
51
|
+
!this._checkIfElementIsBeingProcessed(selectedElement);
|
55
52
|
}
|
56
53
|
/**
|
57
54
|
* Opens the CKBox Image Editor dialog for editing the image.
|
@@ -60,23 +57,32 @@ export default class CKBoxImageEditCommand extends Command {
|
|
60
57
|
if (this._getValue()) {
|
61
58
|
return;
|
62
59
|
}
|
60
|
+
const wrapper = createElement(document, 'div', { class: 'ck ckbox-wrapper' });
|
61
|
+
this._wrapper = wrapper;
|
63
62
|
this.value = true;
|
64
|
-
this._wrapper = createElement(document, 'div', { class: 'ck ckbox-wrapper' });
|
65
63
|
document.body.appendChild(this._wrapper);
|
66
64
|
const imageElement = this.editor.model.document.selection.getSelectedElement();
|
67
|
-
const ckboxImageId = imageElement.getAttribute('ckboxImageId');
|
68
65
|
const processingState = {
|
69
|
-
ckboxImageId,
|
70
66
|
element: imageElement,
|
71
67
|
controller: new AbortController()
|
72
68
|
};
|
73
|
-
window.CKBox.mountImageEditor(
|
69
|
+
this._prepareOptions(processingState).then(options => window.CKBox.mountImageEditor(wrapper, options), error => {
|
70
|
+
const editor = this.editor;
|
71
|
+
const t = editor.t;
|
72
|
+
const notification = editor.plugins.get(Notification);
|
73
|
+
notification.showWarning(t('Failed to determine category of edited image.'), {
|
74
|
+
namespace: 'ckbox'
|
75
|
+
});
|
76
|
+
console.error(error);
|
77
|
+
this._handleImageEditorClose();
|
78
|
+
});
|
74
79
|
}
|
75
80
|
/**
|
76
81
|
* @inheritDoc
|
77
82
|
*/
|
78
83
|
destroy() {
|
79
84
|
this._handleImageEditorClose();
|
85
|
+
this._prepareOptions.abort();
|
80
86
|
for (const state of this._processInProgress.values()) {
|
81
87
|
state.controller.abort();
|
82
88
|
}
|
@@ -91,11 +97,28 @@ export default class CKBoxImageEditCommand extends Command {
|
|
91
97
|
/**
|
92
98
|
* Creates the options object for the CKBox Image Editor dialog.
|
93
99
|
*/
|
94
|
-
|
100
|
+
async _prepareOptionsAbortable(signal, state) {
|
95
101
|
const editor = this.editor;
|
96
102
|
const ckboxConfig = editor.config.get('ckbox');
|
103
|
+
const ckboxUtils = editor.plugins.get(CKBoxUtils);
|
104
|
+
const { element } = state;
|
105
|
+
let imageMountOptions;
|
106
|
+
const ckboxImageId = element.getAttribute('ckboxImageId');
|
107
|
+
if (ckboxImageId) {
|
108
|
+
imageMountOptions = {
|
109
|
+
assetId: ckboxImageId
|
110
|
+
};
|
111
|
+
}
|
112
|
+
else {
|
113
|
+
const imageUrl = element.getAttribute('src');
|
114
|
+
const uploadCategoryId = await ckboxUtils.getCategoryIdForFile(imageUrl, { signal });
|
115
|
+
imageMountOptions = {
|
116
|
+
imageUrl,
|
117
|
+
uploadCategoryId
|
118
|
+
};
|
119
|
+
}
|
97
120
|
return {
|
98
|
-
|
121
|
+
...imageMountOptions,
|
99
122
|
imageEditing: {
|
100
123
|
allowOverwrite: false
|
101
124
|
},
|
@@ -128,6 +151,14 @@ export default class CKBoxImageEditCommand extends Command {
|
|
128
151
|
}
|
129
152
|
return states;
|
130
153
|
}
|
154
|
+
_checkIfElementIsBeingProcessed(selectedElement) {
|
155
|
+
for (const { element } of this._processInProgress) {
|
156
|
+
if (isEqual(element, selectedElement)) {
|
157
|
+
return true;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
return false;
|
161
|
+
}
|
131
162
|
/**
|
132
163
|
* Closes the CKBox Image Editor dialog.
|
133
164
|
*/
|
@@ -138,6 +169,7 @@ export default class CKBoxImageEditCommand extends Command {
|
|
138
169
|
this._wrapper.remove();
|
139
170
|
this._wrapper = null;
|
140
171
|
this.editor.editing.view.focus();
|
172
|
+
this.refresh();
|
141
173
|
}
|
142
174
|
/**
|
143
175
|
* Save edited image. In case server respond with "success" replace with edited image,
|
@@ -148,7 +180,7 @@ export default class CKBoxImageEditCommand extends Command {
|
|
148
180
|
const notification = this.editor.plugins.get(Notification);
|
149
181
|
const pendingActions = this.editor.plugins.get(PendingActions);
|
150
182
|
const action = pendingActions.add(t('Processing the edited image.'));
|
151
|
-
this._processInProgress.
|
183
|
+
this._processInProgress.add(state);
|
152
184
|
this._showImageProcessingIndicator(state.element, asset);
|
153
185
|
this.refresh();
|
154
186
|
this._waitForAssetProcessed(asset.data.id, state.controller.signal)
|
@@ -169,7 +201,7 @@ export default class CKBoxImageEditCommand extends Command {
|
|
169
201
|
console.error(error);
|
170
202
|
}
|
171
203
|
}).finally(() => {
|
172
|
-
this._processInProgress.delete(state
|
204
|
+
this._processInProgress.delete(state);
|
173
205
|
pendingActions.remove(action);
|
174
206
|
this.refresh();
|
175
207
|
});
|
@@ -179,12 +211,12 @@ export default class CKBoxImageEditCommand extends Command {
|
|
179
211
|
* image is already proceeded and ready for saving.
|
180
212
|
*/
|
181
213
|
async _getAssetStatusFromServer(id, signal) {
|
182
|
-
const
|
214
|
+
const ckboxUtils = this.editor.plugins.get(CKBoxUtils);
|
183
215
|
const url = new URL('assets/' + id, this.editor.config.get('ckbox.serviceOrigin'));
|
184
216
|
const response = await sendHttpRequest({
|
185
217
|
url,
|
186
218
|
signal,
|
187
|
-
authorization:
|
219
|
+
authorization: ckboxUtils.getToken().value
|
188
220
|
});
|
189
221
|
const status = response.metadata.metadataProcessingStatus;
|
190
222
|
if (!status || status == 'queued') {
|
@@ -7,6 +7,8 @@
|
|
7
7
|
*/
|
8
8
|
import { PendingActions, Plugin } from 'ckeditor5/src/core';
|
9
9
|
import { Notification } from 'ckeditor5/src/ui';
|
10
|
+
import CKBoxEditing from '../ckboxediting';
|
11
|
+
import CKBoxUtils from '../ckboxutils';
|
10
12
|
/**
|
11
13
|
* The CKBox image edit editing plugin.
|
12
14
|
*/
|
@@ -18,7 +20,7 @@ export default class CKBoxImageEditEditing extends Plugin {
|
|
18
20
|
/**
|
19
21
|
* @inheritDoc
|
20
22
|
*/
|
21
|
-
static get requires(): readonly [typeof PendingActions, typeof Notification, "ImageUtils", "ImageEditing"];
|
23
|
+
static get requires(): readonly [typeof CKBoxEditing, typeof CKBoxUtils, typeof PendingActions, typeof Notification, "ImageUtils", "ImageEditing"];
|
22
24
|
/**
|
23
25
|
* @inheritDoc
|
24
26
|
*/
|
@@ -8,6 +8,8 @@
|
|
8
8
|
import { PendingActions, Plugin } from 'ckeditor5/src/core';
|
9
9
|
import { Notification } from 'ckeditor5/src/ui';
|
10
10
|
import CKBoxImageEditCommand from './ckboximageeditcommand';
|
11
|
+
import CKBoxEditing from '../ckboxediting';
|
12
|
+
import CKBoxUtils from '../ckboxutils';
|
11
13
|
/**
|
12
14
|
* The CKBox image edit editing plugin.
|
13
15
|
*/
|
@@ -22,7 +24,7 @@ export default class CKBoxImageEditEditing extends Plugin {
|
|
22
24
|
* @inheritDoc
|
23
25
|
*/
|
24
26
|
static get requires() {
|
25
|
-
return [PendingActions, Notification, 'ImageUtils', 'ImageEditing'];
|
27
|
+
return [CKBoxEditing, CKBoxUtils, PendingActions, Notification, 'ImageUtils', 'ImageEditing'];
|
26
28
|
}
|
27
29
|
/**
|
28
30
|
* @inheritDoc
|
@@ -0,0 +1,10 @@
|
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
+
*/
|
5
|
+
import type { Element } from 'ckeditor5/src/engine';
|
6
|
+
import type { CKBoxConfig } from '../ckboxconfig';
|
7
|
+
/**
|
8
|
+
* @internal
|
9
|
+
*/
|
10
|
+
export declare function createEditabilityChecker(allowExternalImagesEditing: CKBoxConfig['allowExternalImagesEditing']): (element: Element) => boolean;
|
@@ -0,0 +1,48 @@
|
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
+
*/
|
5
|
+
/**
|
6
|
+
* @module ckbox/ckboximageedit/utils
|
7
|
+
*/
|
8
|
+
import { global } from 'ckeditor5/src/utils';
|
9
|
+
/**
|
10
|
+
* @internal
|
11
|
+
*/
|
12
|
+
export function createEditabilityChecker(allowExternalImagesEditing) {
|
13
|
+
const checkUrl = createUrlChecker(allowExternalImagesEditing);
|
14
|
+
return element => {
|
15
|
+
const isImageElement = element.is('element', 'imageInline') ||
|
16
|
+
element.is('element', 'imageBlock');
|
17
|
+
if (!isImageElement) {
|
18
|
+
return false;
|
19
|
+
}
|
20
|
+
if (element.hasAttribute('ckboxImageId')) {
|
21
|
+
return true;
|
22
|
+
}
|
23
|
+
if (element.hasAttribute('src')) {
|
24
|
+
return checkUrl(element.getAttribute('src'));
|
25
|
+
}
|
26
|
+
return false;
|
27
|
+
};
|
28
|
+
}
|
29
|
+
function createUrlChecker(allowExternalImagesEditing) {
|
30
|
+
if (Array.isArray(allowExternalImagesEditing)) {
|
31
|
+
const urlMatchers = allowExternalImagesEditing.map(createUrlChecker);
|
32
|
+
return src => urlMatchers.some(matcher => matcher(src));
|
33
|
+
}
|
34
|
+
if (allowExternalImagesEditing == 'origin') {
|
35
|
+
const origin = global.window.location.origin;
|
36
|
+
return src => src.startsWith(origin + '/');
|
37
|
+
}
|
38
|
+
if (typeof allowExternalImagesEditing == 'function') {
|
39
|
+
return allowExternalImagesEditing;
|
40
|
+
}
|
41
|
+
if (allowExternalImagesEditing instanceof RegExp) {
|
42
|
+
return src => !!(src.match(allowExternalImagesEditing) ||
|
43
|
+
src.replace(/^https?:\/\//, '').match(allowExternalImagesEditing));
|
44
|
+
}
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
46
|
+
const shouldBeUndefned = allowExternalImagesEditing;
|
47
|
+
return () => false;
|
48
|
+
}
|
package/src/ckboximageedit.d.ts
CHANGED
@@ -6,7 +6,6 @@
|
|
6
6
|
* @module ckbox/ckboximageedit
|
7
7
|
*/
|
8
8
|
import { Plugin } from 'ckeditor5/src/core';
|
9
|
-
import CKBoxEditing from './ckboxediting';
|
10
9
|
import CKBoxImageEditEditing from './ckboximageedit/ckboximageeditediting';
|
11
10
|
import CKBoxImageEditUI from './ckboximageedit/ckboximageeditui';
|
12
11
|
import '../theme/ckboximageedit.css';
|
@@ -21,5 +20,5 @@ export default class CKBoxImageEdit extends Plugin {
|
|
21
20
|
/**
|
22
21
|
* @inheritDoc
|
23
22
|
*/
|
24
|
-
static get requires(): readonly [typeof
|
23
|
+
static get requires(): readonly [typeof CKBoxImageEditEditing, typeof CKBoxImageEditUI];
|
25
24
|
}
|
package/src/ckboximageedit.js
CHANGED
@@ -6,7 +6,6 @@
|
|
6
6
|
* @module ckbox/ckboximageedit
|
7
7
|
*/
|
8
8
|
import { Plugin } from 'ckeditor5/src/core';
|
9
|
-
import CKBoxEditing from './ckboxediting';
|
10
9
|
import CKBoxImageEditEditing from './ckboximageedit/ckboximageeditediting';
|
11
10
|
import CKBoxImageEditUI from './ckboximageedit/ckboximageeditui';
|
12
11
|
import '../theme/ckboximageedit.css';
|
@@ -24,6 +23,6 @@ export default class CKBoxImageEdit extends Plugin {
|
|
24
23
|
* @inheritDoc
|
25
24
|
*/
|
26
25
|
static get requires() {
|
27
|
-
return [
|
26
|
+
return [CKBoxImageEditEditing, CKBoxImageEditUI];
|
28
27
|
}
|
29
28
|
}
|
package/src/ckboxui.js
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
/**
|
6
6
|
* @module ckbox/ckboxui
|
7
7
|
*/
|
8
|
-
import { Plugin } from 'ckeditor5/src/core';
|
8
|
+
import { icons, Plugin } from 'ckeditor5/src/core';
|
9
9
|
import { ButtonView } from 'ckeditor5/src/ui';
|
10
10
|
import browseFilesIcon from '../theme/icons/browse-files.svg';
|
11
11
|
/**
|
@@ -43,5 +43,32 @@ export default class CKBoxUI extends Plugin {
|
|
43
43
|
});
|
44
44
|
return button;
|
45
45
|
});
|
46
|
+
if (editor.plugins.has('ImageInsertUI')) {
|
47
|
+
const imageInsertUI = editor.plugins.get('ImageInsertUI');
|
48
|
+
imageInsertUI.registerIntegration({
|
49
|
+
name: 'assetManager',
|
50
|
+
observable: command,
|
51
|
+
buttonViewCreator: () => {
|
52
|
+
const button = this.editor.ui.componentFactory.create('ckbox');
|
53
|
+
button.icon = icons.imageAssetManager;
|
54
|
+
button.bind('label').to(imageInsertUI, 'isImageSelected', isImageSelected => isImageSelected ?
|
55
|
+
t('Replace image with file manager') :
|
56
|
+
t('Insert image with file manager'));
|
57
|
+
return button;
|
58
|
+
},
|
59
|
+
formViewCreator: () => {
|
60
|
+
const button = this.editor.ui.componentFactory.create('ckbox');
|
61
|
+
button.icon = icons.imageAssetManager;
|
62
|
+
button.withText = true;
|
63
|
+
button.bind('label').to(imageInsertUI, 'isImageSelected', isImageSelected => isImageSelected ?
|
64
|
+
t('Replace with file manager') :
|
65
|
+
t('Insert with file manager'));
|
66
|
+
button.on('execute', () => {
|
67
|
+
imageInsertUI.dropdownView.isOpen = false;
|
68
|
+
});
|
69
|
+
return button;
|
70
|
+
}
|
71
|
+
});
|
72
|
+
}
|
46
73
|
}
|
47
74
|
}
|
@@ -8,9 +8,9 @@
|
|
8
8
|
*/
|
9
9
|
import { Plugin } from 'ckeditor5/src/core';
|
10
10
|
import { FileRepository } from 'ckeditor5/src/upload';
|
11
|
-
import { logError } from 'ckeditor5/src/utils';
|
12
11
|
import CKBoxEditing from './ckboxediting';
|
13
|
-
import { getImageUrls,
|
12
|
+
import { getImageUrls, sendHttpRequest } from './utils';
|
13
|
+
import CKBoxUtils from './ckboxutils';
|
14
14
|
/**
|
15
15
|
* A plugin that enables file uploads in CKEditor 5 using the CKBox server–side connector.
|
16
16
|
* See the {@glink features/file-management/ckbox CKBox file manager integration} guide to learn how to configure
|
@@ -47,10 +47,8 @@ export default class CKBoxUploadAdapter extends Plugin {
|
|
47
47
|
return;
|
48
48
|
}
|
49
49
|
const fileRepository = editor.plugins.get(FileRepository);
|
50
|
-
const
|
51
|
-
fileRepository.createUploadAdapter = loader =>
|
52
|
-
return new Adapter(loader, ckboxEditing.getToken(), editor);
|
53
|
-
};
|
50
|
+
const ckboxUtils = editor.plugins.get(CKBoxUtils);
|
51
|
+
fileRepository.createUploadAdapter = loader => new Adapter(loader, editor, ckboxUtils);
|
54
52
|
const shouldInsertDataId = !editor.config.get('ckbox.ignoreDataId');
|
55
53
|
const imageUploadEditing = editor.plugins.get('ImageUploadEditing');
|
56
54
|
// Mark uploaded assets with the `ckboxImageId` attribute. Its value represents an ID in CKBox.
|
@@ -70,118 +68,27 @@ class Adapter {
|
|
70
68
|
/**
|
71
69
|
* Creates a new adapter instance.
|
72
70
|
*/
|
73
|
-
constructor(loader,
|
71
|
+
constructor(loader, editor, ckboxUtils) {
|
74
72
|
this.loader = loader;
|
75
|
-
this.token =
|
73
|
+
this.token = ckboxUtils.getToken();
|
74
|
+
this.ckboxUtils = ckboxUtils;
|
76
75
|
this.editor = editor;
|
77
76
|
this.controller = new AbortController();
|
78
77
|
this.serviceOrigin = editor.config.get('ckbox.serviceOrigin');
|
79
78
|
}
|
80
|
-
/**
|
81
|
-
* The ID of workspace to use.
|
82
|
-
*/
|
83
|
-
getWorkspaceId() {
|
84
|
-
const t = this.editor.t;
|
85
|
-
const cannotAccessDefaultWorkspaceError = t('Cannot access default workspace.');
|
86
|
-
const defaultWorkspaceId = this.editor.config.get('ckbox.defaultUploadWorkspaceId');
|
87
|
-
const workspaceId = getWorkspaceId(this.token, defaultWorkspaceId);
|
88
|
-
if (workspaceId == null) {
|
89
|
-
/**
|
90
|
-
* The user is not authorized to access the workspace defined in the`ckbox.defaultUploadWorkspaceId` configuration.
|
91
|
-
*
|
92
|
-
* @error ckbox-access-default-workspace-error
|
93
|
-
*/
|
94
|
-
logError('ckbox-access-default-workspace-error');
|
95
|
-
throw cannotAccessDefaultWorkspaceError;
|
96
|
-
}
|
97
|
-
return workspaceId;
|
98
|
-
}
|
99
|
-
/**
|
100
|
-
* Resolves a promise with an array containing available categories with which the uploaded file can be associated.
|
101
|
-
*
|
102
|
-
* If the API returns limited results, the method will collect all items.
|
103
|
-
*/
|
104
|
-
async getAvailableCategories(offset = 0) {
|
105
|
-
const ITEMS_PER_REQUEST = 50;
|
106
|
-
const categoryUrl = new URL('categories', this.serviceOrigin);
|
107
|
-
categoryUrl.searchParams.set('limit', ITEMS_PER_REQUEST.toString());
|
108
|
-
categoryUrl.searchParams.set('offset', offset.toString());
|
109
|
-
categoryUrl.searchParams.set('workspaceId', this.getWorkspaceId());
|
110
|
-
return sendHttpRequest({
|
111
|
-
url: categoryUrl,
|
112
|
-
signal: this.controller.signal,
|
113
|
-
authorization: this.token.value
|
114
|
-
})
|
115
|
-
.then(async (data) => {
|
116
|
-
const remainingItems = data.totalCount - (offset + ITEMS_PER_REQUEST);
|
117
|
-
if (remainingItems > 0) {
|
118
|
-
const offsetItems = await this.getAvailableCategories(offset + ITEMS_PER_REQUEST);
|
119
|
-
return [
|
120
|
-
...data.items,
|
121
|
-
...offsetItems
|
122
|
-
];
|
123
|
-
}
|
124
|
-
return data.items;
|
125
|
-
})
|
126
|
-
.catch(() => {
|
127
|
-
this.controller.signal.throwIfAborted();
|
128
|
-
/**
|
129
|
-
* Fetching a list of available categories with which an uploaded file can be associated failed.
|
130
|
-
*
|
131
|
-
* @error ckbox-fetch-category-http-error
|
132
|
-
*/
|
133
|
-
logError('ckbox-fetch-category-http-error');
|
134
|
-
});
|
135
|
-
}
|
136
|
-
/**
|
137
|
-
* Resolves a promise with an object containing a category with which the uploaded file is associated or an error code.
|
138
|
-
*/
|
139
|
-
async getCategoryIdForFile(file) {
|
140
|
-
const extension = getFileExtension(file.name);
|
141
|
-
const allCategories = await this.getAvailableCategories();
|
142
|
-
// Couldn't fetch all categories. Perhaps the authorization token is invalid.
|
143
|
-
if (!allCategories) {
|
144
|
-
return null;
|
145
|
-
}
|
146
|
-
// The plugin allows defining to which category the uploaded file should be assigned.
|
147
|
-
const defaultCategories = this.editor.config.get('ckbox.defaultUploadCategories');
|
148
|
-
// If a user specifies the plugin configuration, find the first category that accepts the uploaded file.
|
149
|
-
if (defaultCategories) {
|
150
|
-
const userCategory = Object.keys(defaultCategories).find(category => {
|
151
|
-
return defaultCategories[category].find(e => e.toLowerCase() == extension);
|
152
|
-
});
|
153
|
-
// If found, return its ID if the category exists on the server side.
|
154
|
-
if (userCategory) {
|
155
|
-
const serverCategory = allCategories.find(category => category.id === userCategory || category.name === userCategory);
|
156
|
-
if (!serverCategory) {
|
157
|
-
return null;
|
158
|
-
}
|
159
|
-
return serverCategory.id;
|
160
|
-
}
|
161
|
-
}
|
162
|
-
// Otherwise, find the first category that accepts the uploaded file and returns its ID.
|
163
|
-
const category = allCategories.find(category => category.extensions.find(e => e.toLowerCase() == extension));
|
164
|
-
if (!category) {
|
165
|
-
return null;
|
166
|
-
}
|
167
|
-
return category.id;
|
168
|
-
}
|
169
79
|
/**
|
170
80
|
* Starts the upload process.
|
171
81
|
*
|
172
82
|
* @see module:upload/filerepository~UploadAdapter#upload
|
173
83
|
*/
|
174
84
|
async upload() {
|
85
|
+
const ckboxUtils = this.ckboxUtils;
|
175
86
|
const t = this.editor.t;
|
176
|
-
const cannotFindCategoryError = t('Cannot determine a category for the uploaded file.');
|
177
87
|
const file = (await this.loader.file);
|
178
|
-
const category = await
|
179
|
-
if (!category) {
|
180
|
-
return Promise.reject(cannotFindCategoryError);
|
181
|
-
}
|
88
|
+
const category = await ckboxUtils.getCategoryIdForFile(file, { signal: this.controller.signal });
|
182
89
|
const uploadUrl = new URL('assets', this.serviceOrigin);
|
183
90
|
const formData = new FormData();
|
184
|
-
uploadUrl.searchParams.set('workspaceId',
|
91
|
+
uploadUrl.searchParams.set('workspaceId', ckboxUtils.getWorkspaceId());
|
185
92
|
formData.append('categoryId', category);
|
186
93
|
formData.append('file', file);
|
187
94
|
const requestConfig = {
|
@@ -221,11 +128,3 @@ class Adapter {
|
|
221
128
|
this.controller.abort();
|
222
129
|
}
|
223
130
|
}
|
224
|
-
/**
|
225
|
-
* Returns an extension from the given value.
|
226
|
-
*/
|
227
|
-
function getFileExtension(value) {
|
228
|
-
const extensionRegExp = /\.(?<ext>[^.]+)$/;
|
229
|
-
const match = value.match(extensionRegExp);
|
230
|
-
return match.groups.ext.toLowerCase();
|
231
|
-
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
+
*/
|
5
|
+
/**
|
6
|
+
* @module ckbox/ckboxutils
|
7
|
+
*/
|
8
|
+
import type { InitializedToken } from '@ckeditor/ckeditor5-cloud-services';
|
9
|
+
import { Plugin } from 'ckeditor5/src/core';
|
10
|
+
/**
|
11
|
+
* The CKBox editing feature. It introduces the {@link module:ckbox/ckboxcommand~CKBoxCommand CKBox command} and
|
12
|
+
* {@link module:ckbox/ckboxuploadadapter~CKBoxUploadAdapter CKBox upload adapter}.
|
13
|
+
*/
|
14
|
+
export default class CKBoxUtils extends Plugin {
|
15
|
+
/**
|
16
|
+
* CKEditor Cloud Services access token.
|
17
|
+
*/
|
18
|
+
private _token;
|
19
|
+
/**
|
20
|
+
* @inheritDoc
|
21
|
+
*/
|
22
|
+
static get pluginName(): "CKBoxUtils";
|
23
|
+
/**
|
24
|
+
* @inheritDoc
|
25
|
+
*/
|
26
|
+
static get requires(): readonly ["CloudServices"];
|
27
|
+
/**
|
28
|
+
* @inheritDoc
|
29
|
+
*/
|
30
|
+
init(): Promise<void>;
|
31
|
+
/**
|
32
|
+
* Returns a token used by the CKBox plugin for communication with the CKBox service.
|
33
|
+
*/
|
34
|
+
getToken(): InitializedToken;
|
35
|
+
/**
|
36
|
+
* The ID of workspace to use when uploading an image.
|
37
|
+
*/
|
38
|
+
getWorkspaceId(): string;
|
39
|
+
/**
|
40
|
+
* Resolves a promise with an object containing a category with which the uploaded file is associated or an error code.
|
41
|
+
*/
|
42
|
+
getCategoryIdForFile(fileOrUrl: File | string, options: {
|
43
|
+
signal: AbortSignal;
|
44
|
+
}): Promise<string>;
|
45
|
+
/**
|
46
|
+
* Resolves a promise with an array containing available categories with which the uploaded file can be associated.
|
47
|
+
*
|
48
|
+
* If the API returns limited results, the method will collect all items.
|
49
|
+
*/
|
50
|
+
private _getAvailableCategories;
|
51
|
+
}
|
@@ -0,0 +1,184 @@
|
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
+
*/
|
5
|
+
import { CKEditorError, logError } from 'ckeditor5/src/utils';
|
6
|
+
import { Plugin } from 'ckeditor5/src/core';
|
7
|
+
import { convertMimeTypeToExtension, getContentTypeOfUrl, getFileExtension, getWorkspaceId, sendHttpRequest } from './utils';
|
8
|
+
const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
9
|
+
/**
|
10
|
+
* The CKBox editing feature. It introduces the {@link module:ckbox/ckboxcommand~CKBoxCommand CKBox command} and
|
11
|
+
* {@link module:ckbox/ckboxuploadadapter~CKBoxUploadAdapter CKBox upload adapter}.
|
12
|
+
*/
|
13
|
+
export default class CKBoxUtils extends Plugin {
|
14
|
+
/**
|
15
|
+
* @inheritDoc
|
16
|
+
*/
|
17
|
+
static get pluginName() {
|
18
|
+
return 'CKBoxUtils';
|
19
|
+
}
|
20
|
+
/**
|
21
|
+
* @inheritDoc
|
22
|
+
*/
|
23
|
+
static get requires() {
|
24
|
+
return ['CloudServices'];
|
25
|
+
}
|
26
|
+
/**
|
27
|
+
* @inheritDoc
|
28
|
+
*/
|
29
|
+
async init() {
|
30
|
+
const editor = this.editor;
|
31
|
+
const hasConfiguration = !!editor.config.get('ckbox');
|
32
|
+
const isLibraryLoaded = !!window.CKBox;
|
33
|
+
// Proceed with plugin initialization only when the integrator intentionally wants to use it, i.e. when the `config.ckbox` exists or
|
34
|
+
// the CKBox JavaScript library is loaded.
|
35
|
+
if (!hasConfiguration && !isLibraryLoaded) {
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
editor.config.define('ckbox', {
|
39
|
+
serviceOrigin: 'https://api.ckbox.io',
|
40
|
+
defaultUploadCategories: null,
|
41
|
+
ignoreDataId: false,
|
42
|
+
language: editor.locale.uiLanguage,
|
43
|
+
theme: DEFAULT_CKBOX_THEME_NAME,
|
44
|
+
tokenUrl: editor.config.get('cloudServices.tokenUrl')
|
45
|
+
});
|
46
|
+
const cloudServices = editor.plugins.get('CloudServices');
|
47
|
+
const cloudServicesTokenUrl = editor.config.get('cloudServices.tokenUrl');
|
48
|
+
const ckboxTokenUrl = editor.config.get('ckbox.tokenUrl');
|
49
|
+
if (!ckboxTokenUrl) {
|
50
|
+
/**
|
51
|
+
* The {@link module:ckbox/ckboxconfig~CKBoxConfig#tokenUrl `config.ckbox.tokenUrl`} or the
|
52
|
+
* {@link module:cloud-services/cloudservicesconfig~CloudServicesConfig#tokenUrl `config.cloudServices.tokenUrl`}
|
53
|
+
* configuration is required for the CKBox plugin.
|
54
|
+
*
|
55
|
+
* ```ts
|
56
|
+
* ClassicEditor.create( document.createElement( 'div' ), {
|
57
|
+
* ckbox: {
|
58
|
+
* tokenUrl: "YOUR_TOKEN_URL"
|
59
|
+
* // ...
|
60
|
+
* }
|
61
|
+
* // ...
|
62
|
+
* } );
|
63
|
+
* ```
|
64
|
+
*
|
65
|
+
* @error ckbox-plugin-missing-token-url
|
66
|
+
*/
|
67
|
+
throw new CKEditorError('ckbox-plugin-missing-token-url', this);
|
68
|
+
}
|
69
|
+
if (ckboxTokenUrl == cloudServicesTokenUrl) {
|
70
|
+
this._token = cloudServices.token;
|
71
|
+
}
|
72
|
+
else {
|
73
|
+
this._token = await cloudServices.registerTokenUrl(ckboxTokenUrl);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
/**
|
77
|
+
* Returns a token used by the CKBox plugin for communication with the CKBox service.
|
78
|
+
*/
|
79
|
+
getToken() {
|
80
|
+
return this._token;
|
81
|
+
}
|
82
|
+
/**
|
83
|
+
* The ID of workspace to use when uploading an image.
|
84
|
+
*/
|
85
|
+
getWorkspaceId() {
|
86
|
+
const t = this.editor.t;
|
87
|
+
const cannotAccessDefaultWorkspaceError = t('Cannot access default workspace.');
|
88
|
+
const defaultWorkspaceId = this.editor.config.get('ckbox.defaultUploadWorkspaceId');
|
89
|
+
const workspaceId = getWorkspaceId(this._token, defaultWorkspaceId);
|
90
|
+
if (workspaceId == null) {
|
91
|
+
/**
|
92
|
+
* The user is not authorized to access the workspace defined in the`ckbox.defaultUploadWorkspaceId` configuration.
|
93
|
+
*
|
94
|
+
* @error ckbox-access-default-workspace-error
|
95
|
+
*/
|
96
|
+
logError('ckbox-access-default-workspace-error');
|
97
|
+
throw cannotAccessDefaultWorkspaceError;
|
98
|
+
}
|
99
|
+
return workspaceId;
|
100
|
+
}
|
101
|
+
/**
|
102
|
+
* Resolves a promise with an object containing a category with which the uploaded file is associated or an error code.
|
103
|
+
*/
|
104
|
+
async getCategoryIdForFile(fileOrUrl, options) {
|
105
|
+
const t = this.editor.t;
|
106
|
+
const cannotFindCategoryError = t('Cannot determine a category for the uploaded file.');
|
107
|
+
const defaultCategories = this.editor.config.get('ckbox.defaultUploadCategories');
|
108
|
+
const allCategoriesPromise = this._getAvailableCategories(options);
|
109
|
+
const extension = typeof fileOrUrl == 'string' ?
|
110
|
+
convertMimeTypeToExtension(await getContentTypeOfUrl(fileOrUrl, options)) :
|
111
|
+
getFileExtension(fileOrUrl);
|
112
|
+
const allCategories = await allCategoriesPromise;
|
113
|
+
// Couldn't fetch all categories. Perhaps the authorization token is invalid.
|
114
|
+
if (!allCategories) {
|
115
|
+
throw cannotFindCategoryError;
|
116
|
+
}
|
117
|
+
// If a user specifies the plugin configuration, find the first category that accepts the uploaded file.
|
118
|
+
if (defaultCategories) {
|
119
|
+
const userCategory = Object.keys(defaultCategories).find(category => {
|
120
|
+
return defaultCategories[category].find(e => e.toLowerCase() == extension);
|
121
|
+
});
|
122
|
+
// If found, return its ID if the category exists on the server side.
|
123
|
+
if (userCategory) {
|
124
|
+
const serverCategory = allCategories.find(category => category.id === userCategory || category.name === userCategory);
|
125
|
+
if (!serverCategory) {
|
126
|
+
throw cannotFindCategoryError;
|
127
|
+
}
|
128
|
+
return serverCategory.id;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
// Otherwise, find the first category that accepts the uploaded file and returns its ID.
|
132
|
+
const category = allCategories.find(category => category.extensions.find(e => e.toLowerCase() == extension));
|
133
|
+
if (!category) {
|
134
|
+
throw cannotFindCategoryError;
|
135
|
+
}
|
136
|
+
return category.id;
|
137
|
+
}
|
138
|
+
/**
|
139
|
+
* Resolves a promise with an array containing available categories with which the uploaded file can be associated.
|
140
|
+
*
|
141
|
+
* If the API returns limited results, the method will collect all items.
|
142
|
+
*/
|
143
|
+
async _getAvailableCategories(options) {
|
144
|
+
const ITEMS_PER_REQUEST = 50;
|
145
|
+
const editor = this.editor;
|
146
|
+
const token = this._token;
|
147
|
+
const { signal } = options;
|
148
|
+
const serviceOrigin = editor.config.get('ckbox.serviceOrigin');
|
149
|
+
const workspaceId = this.getWorkspaceId();
|
150
|
+
try {
|
151
|
+
const result = [];
|
152
|
+
let offset = 0;
|
153
|
+
let remainingItems;
|
154
|
+
do {
|
155
|
+
const data = await fetchCategories(offset);
|
156
|
+
result.push(...data.items);
|
157
|
+
remainingItems = data.totalCount - (offset + ITEMS_PER_REQUEST);
|
158
|
+
offset += ITEMS_PER_REQUEST;
|
159
|
+
} while (remainingItems > 0);
|
160
|
+
return result;
|
161
|
+
}
|
162
|
+
catch {
|
163
|
+
signal.throwIfAborted();
|
164
|
+
/**
|
165
|
+
* Fetching a list of available categories with which an uploaded file can be associated failed.
|
166
|
+
*
|
167
|
+
* @error ckbox-fetch-category-http-error
|
168
|
+
*/
|
169
|
+
logError('ckbox-fetch-category-http-error');
|
170
|
+
return undefined;
|
171
|
+
}
|
172
|
+
function fetchCategories(offset) {
|
173
|
+
const categoryUrl = new URL('categories', serviceOrigin);
|
174
|
+
categoryUrl.searchParams.set('limit', ITEMS_PER_REQUEST.toString());
|
175
|
+
categoryUrl.searchParams.set('offset', offset.toString());
|
176
|
+
categoryUrl.searchParams.set('workspaceId', workspaceId);
|
177
|
+
return sendHttpRequest({
|
178
|
+
url: categoryUrl,
|
179
|
+
signal,
|
180
|
+
authorization: token.value
|
181
|
+
});
|
182
|
+
}
|
183
|
+
}
|
184
|
+
}
|
package/src/utils.d.ts
CHANGED
@@ -47,3 +47,11 @@ export declare function sendHttpRequest({ url, method, data, onUploadProgress, s
|
|
47
47
|
data?: FormData | null;
|
48
48
|
onUploadProgress?: (evt: ProgressEvent) => void;
|
49
49
|
}): Promise<any>;
|
50
|
+
export declare function convertMimeTypeToExtension(mimeType: string): string;
|
51
|
+
export declare function getContentTypeOfUrl(url: string, options: {
|
52
|
+
signal: AbortSignal;
|
53
|
+
}): Promise<string>;
|
54
|
+
/**
|
55
|
+
* Returns an extension from the given value.
|
56
|
+
*/
|
57
|
+
export declare function getFileExtension(file: File): string;
|
package/src/utils.js
CHANGED
@@ -131,3 +131,39 @@ export function sendHttpRequest({ url, method = 'GET', data, onUploadProgress, s
|
|
131
131
|
xhr.send(data);
|
132
132
|
});
|
133
133
|
}
|
134
|
+
const MIME_TO_EXTENSION = {
|
135
|
+
'image/gif': 'gif',
|
136
|
+
'image/jpeg': 'jpg',
|
137
|
+
'image/png': 'png',
|
138
|
+
'image/webp': 'webp',
|
139
|
+
'image/bmp': 'bmp',
|
140
|
+
'image/tiff': 'tiff'
|
141
|
+
};
|
142
|
+
export function convertMimeTypeToExtension(mimeType) {
|
143
|
+
return MIME_TO_EXTENSION[mimeType];
|
144
|
+
}
|
145
|
+
export async function getContentTypeOfUrl(url, options) {
|
146
|
+
try {
|
147
|
+
const response = await fetch(url, {
|
148
|
+
method: 'HEAD',
|
149
|
+
cache: 'force-cache',
|
150
|
+
...options
|
151
|
+
});
|
152
|
+
if (!response.ok) {
|
153
|
+
return '';
|
154
|
+
}
|
155
|
+
return response.headers.get('content-type') || '';
|
156
|
+
}
|
157
|
+
catch {
|
158
|
+
return '';
|
159
|
+
}
|
160
|
+
}
|
161
|
+
/**
|
162
|
+
* Returns an extension from the given value.
|
163
|
+
*/
|
164
|
+
export function getFileExtension(file) {
|
165
|
+
const fileName = file.name;
|
166
|
+
const extensionRegExp = /\.(?<ext>[^.]+)$/;
|
167
|
+
const match = fileName.match(extensionRegExp);
|
168
|
+
return match.groups.ext.toLowerCase();
|
169
|
+
}
|
@@ -1 +1 @@
|
|
1
|
-
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M1.201 1C.538 1 0 1.47 0 2.1v12.86C0 15.603.534 16 1.186 16H6.45l3.647-3.596-3.48-3.254a.694.694 0 0 0-.958-.033L1.5 13.6V2.5h15v4.59a3.477 3.477 0 0 1 1.5.15V2.1c0-.63-.547-1.1-1.2-1.1H1.202Zm11.723 2.805a2.137 2.137 0 0 0-2.045 2.406 2.13 2.13 0 0 0 4.172.277 2.134 2.134 0 0 0-.76-2.244 2.13 2.13 0 0 0-1.367-.44Z"/><path d="M8.1 17.612V20h2.39l7.046-7.046-2.39-2.39L8.1 17.612Zm11.283-6.506a.638.638 0 0 0 .139-.692.603.603 0 0 0-.139-.206L17.892 8.72a.63.63 0 0 0-.898 0l-1.167 1.163 2.391 2.39 1.165-1.167Z"/></svg>
|