diff --git a/.gitignore b/.gitignore index 641d5eb0..18e438ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ node_modules/* npm-debug.log .idea/ -.DS_Store -dist +.DS_Store \ No newline at end of file diff --git a/.npmignore b/.npmignore index 6f5da4d2..1bd55208 100644 --- a/.npmignore +++ b/.npmignore @@ -1,5 +1,4 @@ .idea/ -dev/ src/ .babelrc .eslintrc diff --git a/dist/bundle.js b/dist/bundle.js new file mode 100644 index 00000000..d20802fd --- /dev/null +++ b/dist/bundle.js @@ -0,0 +1,41 @@ +/*! + * Image tool + * + * @version 2.8.24 + * + * @package https://github.com/editor-js/image + * @licence MIT + * @author CodeX + */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ImageTool=t():e.ImageTool=t()}(window,(function(){return function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=10)}([function(e,t){function n(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};if(e.url&&"string"!=typeof e.url)throw new Error("Url must be a string");if(e.url=e.url||"",e.method&&"string"!=typeof e.method)throw new Error("`method` must be a string or null");if(e.method=e.method?e.method.toUpperCase():"GET",e.headers&&"object"!==o(e.headers))throw new Error("`headers` must be an object or null");if(e.headers=e.headers||{},e.type&&("string"!=typeof e.type||!Object.values(r).includes(e.type)))throw new Error("`type` must be taken from module's «contentType» library");if(e.progress&&"function"!=typeof e.progress)throw new Error("`progress` must be a function or null");if(e.progress=e.progress||function(e){},e.beforeSend=e.beforeSend||function(e){},e.ratio&&"number"!=typeof e.ratio)throw new Error("`ratio` must be a number");if(e.ratio<0||e.ratio>100)throw new Error("`ratio` must be in a 0-100 interval");if(e.ratio=e.ratio||90,e.accept&&"string"!=typeof e.accept)throw new Error("`accept` must be a string with a list of allowed mime-types");if(e.accept=e.accept||"*/*",e.multiple&&"boolean"!=typeof e.multiple)throw new Error("`multiple` must be a true or false");if(e.multiple=e.multiple||!1,e.fieldName&&"string"!=typeof e.fieldName)throw new Error("`fieldName` must be a string");return e.fieldName=e.fieldName||"files",e},u=function(e){switch(e.method){case"GET":var t=c(e.data,r.URLENCODED);delete e.data,e.url=/\?/.test(e.url)?e.url+"&"+t:e.url+"?"+t;break;case"POST":case"PUT":case"DELETE":case"UPDATE":var n=function(){return(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).type||r.JSON}(e);(d.isFormData(e.data)||d.isFormElement(e.data))&&(n=r.FORM),e.data=c(e.data,n),n!==f.contentType.FORM&&(e.headers["content-type"]=n)}return e},c=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};switch(arguments.length>1?arguments[1]:void 0){case r.URLENCODED:return d.urlEncode(e);case r.JSON:return d.jsonEncode(e);case r.FORM:return d.formEncode(e);default:return e}},l=function(e){return e>=200&&e<300},{contentType:r={URLENCODED:"application/x-www-form-urlencoded; charset=utf-8",FORM:"multipart/form-data",JSON:"application/json; charset=utf-8"},request:i,get:function(e){return e.method="GET",i(e)},post:a,transport:function(e){return e=s(e),d.selectFiles(e).then((function(t){for(var n=new FormData,o=0;o=0&&(e._idleTimeoutId=setTimeout((function(){e._onTimeout&&e._onTimeout()}),t))},n(6),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(this,n(0))},function(e,t,n){(function(e,t){!function(e,n){"use strict";if(!e.setImmediate){var o,r,i,a,s,u=1,c={},l=!1,d=e.document,f=Object.getPrototypeOf&&Object.getPrototypeOf(e);f=f&&f.setTimeout?f:e,"[object process]"==={}.toString.call(e.process)?o=function(e){t.nextTick((function(){h(e)}))}:function(){if(e.postMessage&&!e.importScripts){var t=!0,n=e.onmessage;return e.onmessage=function(){t=!1},e.postMessage("","*"),e.onmessage=n,t}}()?(a="setImmediate$"+Math.random()+"$",s=function(t){t.source===e&&"string"==typeof t.data&&0===t.data.indexOf(a)&&h(+t.data.slice(a.length))},e.addEventListener?e.addEventListener("message",s,!1):e.attachEvent("onmessage",s),o=function(t){e.postMessage(a+t,"*")}):e.MessageChannel?((i=new MessageChannel).port1.onmessage=function(e){h(e.data)},o=function(e){i.port2.postMessage(e)}):d&&"onreadystatechange"in d.createElement("script")?(r=d.documentElement,o=function(e){var t=d.createElement("script");t.onreadystatechange=function(){h(e),t.onreadystatechange=null,r.removeChild(t),t=null},r.appendChild(t)}):o=function(e){setTimeout(h,0,e)},f.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),n=0;n1)for(var n=1;n HTMLElement")}},{key:"isObject",value:function(e){return"[object Object]"===Object.prototype.toString.call(e)}},{key:"isFormData",value:function(e){return e instanceof FormData}},{key:"isFormElement",value:function(e){return e instanceof HTMLFormElement}},{key:"selectFiles",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return new Promise((function(t,n){var o=document.createElement("INPUT");o.type="file",e.multiple&&o.setAttribute("multiple","multiple"),e.accept&&o.setAttribute("accept",e.accept),o.style.display="none",document.body.appendChild(o),o.addEventListener("change",(function(e){var n=e.target.files;t(n),document.body.removeChild(o)}),!1),o.click()}))}},{key:"parseHeaders",value:function(e){var t=e.trim().split(/[\r\n]+/),n={};return t.forEach((function(e){var t=e.split(": "),o=t.shift(),r=t.join(": ");o&&(n[o]=r)})),n}}])&&o(t,n),e}()},function(e,t){var n=function(e){return encodeURIComponent(e).replace(/[!'()*]/g,escape).replace(/%20/g,"+")},o=function(e,t,r,i){return t=t||null,r=r||"&",i=i||null,e?function(e){for(var t=new Array,n=0;ne.length)&&(t=e.length);for(var n=0,o=new Array(t);n=0;--r){var i=this.tryEntries[r],a=i.completion;if("root"===i.tryLoc)return o("end");if(i.tryLoc<=this.prev){var s=n.call(i,"catchLoc"),u=n.call(i,"finallyLoc");if(s&&u){if(this.prev=0;--o){var r=this.tryEntries[o];if(r.tryLoc<=this.prev&&n.call(r,"finallyLoc")&&this.prev=0;--t){var n=this.tryEntries[t];if(n.finallyLoc===e)return this.complete(n.completion,n.afterLoc),k(n),c}},catch:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var n=this.tryEntries[t];if(n.tryLoc===e){var o=n.completion;if("throw"===o.type){var r=o.arg;k(n)}return r}}throw new Error("illegal catch attempt")},delegateYield:function(e,t,n){return this.delegate={iterator:E(e),resultName:t,nextLoc:n},"next"===this.method&&(this.arg=void 0),c}},e}(e.exports);try{regeneratorRuntime=o}catch(e){Function("r","regeneratorRuntime = r")(o)}},function(e,t,n){var o=n(13),r=n(14);"string"==typeof(r=r.__esModule?r.default:r)&&(r=[[e.i,r,""]]);var i={insert:"head",singleton:!1},a=(o(r,i),r.locals?r.locals:{});e.exports=a},function(e,t,n){"use strict";var o,r=function(){return void 0===o&&(o=Boolean(window&&document&&document.all&&!window.atob)),o},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]}}(),a=[];function s(e){for(var t=-1,n=0;n1&&void 0!==arguments[1]?arguments[1]:null,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=document.createElement(e);Array.isArray(n)?(t=r.classList).add.apply(t,p()(n)):n&&r.classList.add(n);for(var i in o)r[i]=o[i];return r}var m=n(8),g=n.n(m),y=function(){function e(t){var n=t.api,o=t.config,r=t.onSelectFile,i=t.readOnly;u()(this,e),this.api=n,this.config=o,this.onSelectFile=r,this.readOnly=i,this.nodes={wrapper:h("div",[this.CSS.baseClass,this.CSS.wrapper]),imageContainer:h("div",[this.CSS.imageContainer]),fileButton:this.createFileButton(),imageWrapper:h("div",[this.CSS.imageWrapper,"tw-relative","tw-w-24","tw-h-24"]),imageEl:void 0,imageDeleteIcon:void 0,imagePreloader:h("div",this.CSS.imagePreloader),caption:h("div",[this.CSS.input,this.CSS.caption],{contentEditable:!this.readOnly})},this.nodes.caption.dataset.placeholder=this.config.captionPlaceholder,this.nodes.imageContainer.appendChild(this.nodes.imagePreloader),this.nodes.imageContainer.appendChild(this.nodes.imageWrapper),this.nodes.wrapper.appendChild(this.nodes.imageContainer),this.nodes.wrapper.appendChild(this.nodes.caption),this.nodes.wrapper.appendChild(this.nodes.fileButton)}return l()(e,[{key:"render",value:function(t){return t.file&&0!==Object.keys(t.file).length?this.toggleStatus(e.status.UPLOADING):this.toggleStatus(e.status.EMPTY),this.nodes.wrapper}},{key:"pxToRem",value:function(e){return"".concat(e/16*1,"rem")}},{key:"createFileButton",value:function(){var e=this,t=h("div",[this.CSS.button]);return t.innerHTML=this.config.buttonContent||"".concat(d," ").concat(this.api.i18n.t("Select an Image")),t.addEventListener("click",(function(){e.onSelectFile()})),t}},{key:"showPreloader",value:function(t){this.nodes.imagePreloader.style.backgroundImage="url(".concat(t,")"),this.toggleStatus(e.status.UPLOADING)}},{key:"hidePreloader",value:function(){this.nodes.imagePreloader.style.backgroundImage="",this.toggleStatus(e.status.EMPTY)}},{key:"fillImage",value:function(t){var n=this,o=/\.mp4$/.test(t)?"VIDEO":"IMG",r={src:t},i="load";"VIDEO"===o&&(r.autoplay=!0,r.loop=!0,r.muted=!0,r.playsinline=!0,i="loadeddata");var a=document.createElement("div");a.style.strokeWidth="0px",a.style.position="absolute",a.style.right=this.pxToRem(0),a.style.top=this.pxToRem(0),a.style.cursor="pointer",a.addEventListener("click",(function(){n.api.blocks.delete(n.api.blocks.getCurrentBlockIndex())})),a.addEventListener("mouseover",(function(){a.firstChild.style.fill="#585A68"})),a.addEventListener("mouseout",(function(){a.firstChild.style.fill="#7E8194"})),a.innerHTML=g.a,a.firstChild.style.fill="#7E8194",this.nodes.imageDeleteIcon=a,this.nodes.imageDeleteIcon.style.display="none",this.nodes.imageEl=h(o,[this.CSS.imageEl,"tw-w-24","tw-h-24"],r),this.nodes.imageEl.style.width=this.pxToRem(96),this.nodes.imageEl.style.height=this.pxToRem(96),this.nodes.imageWrapper.addEventListener("mouseover",(function(e){e.preventDefault(),n.nodes.imageDeleteIcon&&(n.nodes.imageDeleteIcon.style.display="block")})),this.nodes.imageWrapper.addEventListener("mouseout",(function(e){e.preventDefault(),n.nodes.imageDeleteIcon&&(n.nodes.imageDeleteIcon.style.display="none")})),this.nodes.imageEl.addEventListener(i,(function(){n.toggleStatus(e.status.FILLED),n.nodes.imagePreloader&&(n.nodes.imagePreloader.style.backgroundImage="")})),this.nodes.imageWrapper.appendChild(this.nodes.imageDeleteIcon),this.nodes.imageWrapper.appendChild(this.nodes.imageEl)}},{key:"fillCaption",value:function(e){this.nodes.caption&&(this.nodes.caption.innerHTML=e)}},{key:"toggleStatus",value:function(t){for(var n in e.status)Object.prototype.hasOwnProperty.call(e.status,n)&&this.nodes.wrapper.classList.toggle("".concat(this.CSS.wrapper,"--").concat(e.status[n]),t===e.status[n])}},{key:"applyTune",value:function(e,t){this.nodes.wrapper.classList.toggle("".concat(this.CSS.wrapper,"--").concat(e),t)}},{key:"CSS",get:function(){return{baseClass:this.api.styles.block,loading:this.api.styles.loader,input:this.api.styles.input,button:this.api.styles.button,wrapper:"image-tool",imageContainer:"image-tool__image",imagePreloader:"image-tool__image-preloader",imageWrapper:"image-tool__image-wrapper",imageEl:"image-tool__image-picture",caption:"image-tool__caption"}}}],[{key:"status",get:function(){return{EMPTY:"empty",UPLOADING:"loading",FILLED:"filled"}}}]),e}(),v=n(9),w=n.n(v),b=n(1),k=n.n(b);function x(e){return e&&"function"==typeof e.then}var E=function(){function e(t){var n=t.config,o=t.onUpload,r=t.onError;u()(this,e),this.config=n,this.onUpload=o,this.onError=r}return l()(e,[{key:"uploadSelectedFile",value:function(e){var t=this,n=e.onPreview,o=function(e){var t=new FileReader;t.readAsDataURL(e),t.onload=function(e){n(e.target.result)}};(this.config.uploader&&"function"==typeof this.config.uploader.uploadByFile?k.a.selectFiles({accept:this.config.types}).then((function(e){o(e[0]);var n=t.config.uploader.uploadByFile(e[0]);return x(n)||console.warn("Custom uploader method uploadByFile should return a Promise"),n})):k.a.transport({url:this.config.endpoints.byFile,data:this.config.additionalRequestData,accept:this.config.types,headers:this.config.additionalRequestHeaders,beforeSend:function(e){o(e[0])},fieldName:this.config.field}).then((function(e){return e.body}))).then((function(e){t.onUpload(e)})).catch((function(e){t.onError(e)}))}},{key:"uploadByUrl",value:function(e){var t,n=this;this.config.uploader&&"function"==typeof this.config.uploader.uploadByUrl?x(t=this.config.uploader.uploadByUrl(e))||console.warn("Custom uploader method uploadByUrl should return a Promise"):t=k.a.post({url:this.config.endpoints.byUrl,data:Object.assign({url:e},this.config.additionalRequestData),type:k.a.contentType.JSON,headers:this.config.additionalRequestHeaders}).then((function(e){return e.body})),t.then((function(e){n.onUpload(e)})).catch((function(e){n.onError(e)}))}},{key:"uploadByFile",value:function(e,t){var n,o=this,r=t.onPreview,i=new FileReader;if(i.readAsDataURL(e),i.onload=function(e){r(e.target.result)},this.config.uploader&&"function"==typeof this.config.uploader.uploadByFile)x(n=this.config.uploader.uploadByFile(e))||console.warn("Custom uploader method uploadByFile should return a Promise");else{var a=new FormData;a.append(this.config.field,e),this.config.additionalRequestData&&Object.keys(this.config.additionalRequestData).length&&Object.entries(this.config.additionalRequestData).forEach((function(e){var t=w()(e,2),n=t[0],o=t[1];a.append(n,o)})),n=k.a.post({url:this.config.endpoints.byFile,data:a,type:k.a.contentType.JSON,headers:this.config.additionalRequestHeaders}).then((function(e){return e.body}))}n.then((function(e){o.onUpload(e)})).catch((function(e){o.onError(e)}))}}]),e}(),_=function(){function e(t){var n=this,o=t.data,r=t.config,i=t.api,a=t.readOnly;u()(this,e),this.api=i,this.readOnly=a,this.config={endpoints:r.endpoints||"",additionalRequestData:r.additionalRequestData||{},additionalRequestHeaders:r.additionalRequestHeaders||{},field:r.field||"image",types:r.types||"image/*",captionPlaceholder:this.api.i18n.t(r.captionPlaceholder||"Caption"),buttonContent:r.buttonContent||"",uploader:r.uploader||void 0,actions:r.actions||[]},this.uploader=new E({config:this.config,onUpload:function(e){return n.onUpload(e)},onError:function(e){return n.uploadingFailed(e)}}),this.ui=new y({api:i,config:this.config,onSelectFile:function(){n.uploader.uploadSelectedFile({onPreview:function(e){n.ui.showPreloader(e)}})},readOnly:a}),this._data={},this.data=o}var t;return l()(e,null,[{key:"isReadOnlySupported",get:function(){return!0}},{key:"toolbox",get:function(){return{icon:d,title:"Image"}}},{key:"tunes",get:function(){return[{name:"withBorder",icon:'',title:"With border",toggle:!0},{name:"stretched",icon:'',title:"Stretch image",toggle:!0},{name:"withBackground",icon:'',title:"With background",toggle:!0}]}}]),l()(e,[{key:"render",value:function(){return this.ui.render(this.data)}},{key:"validate",value:function(e){return e.file&&e.file.url}},{key:"save",value:function(){var e=this.ui.nodes.caption;return this._data.caption=e.innerHTML,this.data}},{key:"renderSettings",value:function(){var t=this;return e.tunes.concat(this.config.actions).map((function(e){return{icon:e.icon,label:t.api.i18n.t(e.title),name:e.name,toggle:e.toggle,isActive:t.data[e.name],onActivate:function(){"function"!=typeof e.action?t.tuneToggled(e.name):e.action(e.name)}}}))}},{key:"appendCallback",value:function(){this.ui.nodes.fileButton.click()}},{key:"onPaste",value:(t=a()(r.a.mark((function e(t){var n,o,i,a,s;return r.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:e.t0=t.type,e.next="tag"===e.t0?3:"pattern"===e.t0?15:"file"===e.t0?18:21;break;case 3:if(n=t.detail.data,!/^blob:/.test(n.src)){e.next=13;break}return e.next=7,fetch(n.src);case 7:return o=e.sent,e.next=10,o.blob();case 10:return i=e.sent,this.uploadFile(i),e.abrupt("break",21);case 13:return this.uploadUrl(n.src),e.abrupt("break",21);case 15:return a=t.detail.data,this.uploadUrl(a),e.abrupt("break",21);case 18:return s=t.detail.file,this.uploadFile(s),e.abrupt("break",21);case 21:case"end":return e.stop()}}),e,this)}))),function(e){return t.apply(this,arguments)})},{key:"onUpload",value:function(e){e.success&&e.file?this.image=e.file:this.uploadingFailed("incorrect response: "+JSON.stringify(e))}},{key:"uploadingFailed",value:function(e){console.log("Image Tool: uploading failed because of",e),this.api.notifier.show({message:this.api.i18n.t("Couldn’t upload image. Please try another."),style:"error"}),this.ui.hidePreloader()}},{key:"tuneToggled",value:function(e){this.setTune(e,!this._data[e])}},{key:"setTune",value:function(e,t){var n=this;this._data[e]=t,this.ui.applyTune(e,t),"stretched"===e&&Promise.resolve().then((function(){var e=n.api.blocks.getCurrentBlockIndex();n.api.blocks.stretchBlock(e,t)})).catch((function(e){console.error(e)}))}},{key:"uploadFile",value:function(e){var t=this;this.uploader.uploadByFile(e,{onPreview:function(e){t.ui.showPreloader(e)}})}},{key:"uploadUrl",value:function(e){this.ui.showPreloader(e),this.uploader.uploadByUrl(e)}},{key:"data",set:function(t){var n=this;this.image=t.file,this._data.caption=t.caption||"",this.ui.fillCaption(this._data.caption),e.tunes.forEach((function(e){var o=e.name,r=void 0!==t[o]&&(!0===t[o]||"true"===t[o]);n.setTune(o,r)}))},get:function(){return this._data}},{key:"image",set:function(e){this._data.file=e||{},e&&e.url&&this.ui.fillImage(e.url)}}],[{key:"pasteConfig",get:function(){return{tags:[{img:{src:!0}}],patterns:{image:/https?:\/\/\S+\.(gif|jpe?g|tiff|png|svg|webp)(\?[a-z0-9=]*)?$/i},files:{mimeTypes:["image/*"]}}}}]),e}(); +/** + * Image Tool for the Editor.js + * + * @author CodeX + * @license MIT + * @see {@link https://github.com/editor-js/image} + * + * To developers. + * To simplify Tool structure, we split it to 4 parts: + * 1) index.js — main Tool's interface, public API and methods for working with data + * 2) uploader.js — module that has methods for sending files via AJAX: from device, by URL or File pasting + * 3) ui.js — module for UI manipulations: render, showing preloader, etc + * 4) tunes.js — working with Block Tunes: render buttons, handle clicks + * + * For debug purposes there is a testing server + * that can save uploaded files and return a Response {@link UploadResponseFormat} + * + * $ node dev/server.js + * + * It will expose 8008 port, so you can pass http://localhost:8008 with the Tools config: + * + * image: { + * class: ImageTool, + * config: { + * endpoints: { + * byFile: 'http://localhost:8008/uploadFile', + * byUrl: 'http://localhost:8008/fetchUrl', + * } + * }, + * }, + */}]).default})); \ No newline at end of file diff --git a/package.json b/package.json index fac81895..d0b86b4e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "@editorjs/image", - "version": "2.8.1", + "name": "@personalai/editorjs-image", + "version": "2.8.24", "keywords": [ "codex editor", "tool", @@ -10,7 +10,7 @@ ], "description": "Image Tool for Editor.js", "license": "MIT", - "repository": "https://github.com/editor-js/image", + "repository": "https://github.com/personal-ai/editorjs-image-fork.git", "main": "./dist/bundle.js", "scripts": { "build": "webpack --mode production", diff --git a/src/assets/x-circle.svg b/src/assets/x-circle.svg new file mode 100644 index 00000000..9c25c4a9 --- /dev/null +++ b/src/assets/x-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui.js b/src/ui.js index 8609ef21..ae299d91 100644 --- a/src/ui.js +++ b/src/ui.js @@ -1,5 +1,6 @@ import { IconPicture } from '@codexteam/icons'; import { make } from './utils/dom'; +import IconClose from './assets/x-circle.svg'; /** * Class for working with UI: @@ -24,7 +25,9 @@ export default class Ui { wrapper: make('div', [this.CSS.baseClass, this.CSS.wrapper]), imageContainer: make('div', [ this.CSS.imageContainer ]), fileButton: this.createFileButton(), + imageWrapper: make('div', [this.CSS.imageWrapper, 'tw-relative', 'tw-w-24', 'tw-h-24']), imageEl: undefined, + imageDeleteIcon: undefined, imagePreloader: make('div', this.CSS.imagePreloader), caption: make('div', [this.CSS.input, this.CSS.caption], { contentEditable: !this.readOnly, @@ -43,6 +46,7 @@ export default class Ui { */ this.nodes.caption.dataset.placeholder = this.config.captionPlaceholder; this.nodes.imageContainer.appendChild(this.nodes.imagePreloader); + this.nodes.imageContainer.appendChild(this.nodes.imageWrapper); this.nodes.wrapper.appendChild(this.nodes.imageContainer); this.nodes.wrapper.appendChild(this.nodes.caption); this.nodes.wrapper.appendChild(this.nodes.fileButton); @@ -66,6 +70,7 @@ export default class Ui { wrapper: 'image-tool', imageContainer: 'image-tool__image', imagePreloader: 'image-tool__image-preloader', + imageWrapper: 'image-tool__image-wrapper', imageEl: 'image-tool__image-picture', caption: 'image-tool__caption', }; @@ -103,6 +108,16 @@ export default class Ui { return this.nodes.wrapper; } + /** + * convert pixels to rem + * + * @param {number} size - size of px + * @returns {string} + */ + pxToRem(size) { + return `${(size / 16) * 1}rem`; + }; + /** * Creates upload-file button * @@ -189,12 +204,63 @@ export default class Ui { eventName = 'loadeddata'; } + /** + * compose iconWrapper + */ + const iconWrapper = document.createElement('div'); + + iconWrapper.style.strokeWidth = '0px'; + + iconWrapper.style.position = 'absolute'; + iconWrapper.style.right = this.pxToRem(0); + iconWrapper.style.top = this.pxToRem(0); + iconWrapper.style.cursor = 'pointer'; + iconWrapper.addEventListener('click', () => { + this.api.blocks.delete(this.api.blocks.getCurrentBlockIndex()); + }); + iconWrapper.addEventListener('mouseover', () => { + const svgWrapper = iconWrapper.firstChild; + + svgWrapper.style.fill = '#585A68'; + }); + iconWrapper.addEventListener('mouseout', () => { + const svgWrapper = iconWrapper.firstChild; + + svgWrapper.style.fill = '#7E8194'; + }); + iconWrapper.innerHTML = IconClose; + const svgWrapper = iconWrapper.firstChild; + + svgWrapper.style.fill = '#7E8194'; + this.nodes.imageDeleteIcon = iconWrapper; + this.nodes.imageDeleteIcon.style.display = 'none'; + /** * Compose tag with defined attributes * * @type {Element} */ - this.nodes.imageEl = make(tag, this.CSS.imageEl, attributes); + this.nodes.imageEl = make(tag, [this.CSS.imageEl, 'tw-w-24', 'tw-h-24'], attributes); + this.nodes.imageEl.style.width = this.pxToRem(96); + this.nodes.imageEl.style.height = this.pxToRem(96); + + /** + * add imageWrapper hover event listener + */ + this.nodes.imageWrapper.addEventListener('mouseover', (event) => { + event.preventDefault(); + if (!this.nodes.imageDeleteIcon) { + return; + } + this.nodes.imageDeleteIcon.style.display = 'block'; + }); + this.nodes.imageWrapper.addEventListener('mouseout', (event) => { + event.preventDefault(); + if (!this.nodes.imageDeleteIcon) { + return; + } + this.nodes.imageDeleteIcon.style.display = 'none'; + }); /** * Add load event listener @@ -210,7 +276,8 @@ export default class Ui { } }); - this.nodes.imageContainer.appendChild(this.nodes.imageEl); + this.nodes.imageWrapper.appendChild(this.nodes.imageDeleteIcon); + this.nodes.imageWrapper.appendChild(this.nodes.imageEl); } /** @@ -250,4 +317,3 @@ export default class Ui { this.nodes.wrapper.classList.toggle(`${this.CSS.wrapper}--${tuneName}`, status); } } -