From 6fe770d6aa3ff74de42ec382fdc3480fb239192e Mon Sep 17 00:00:00 2001 From: volkov Date: Mon, 25 Sep 2023 14:02:15 +0300 Subject: [PATCH] Add inline mode --- README.md | 30 +++--- dist/dark-editable.iife.js | 2 +- dist/dark-editable.js | 185 ++++++++++++++++++++++++++----------- dist/dark-editable.umd.cjs | 2 +- src/Modes/BaseMode.js | 34 +++++++ src/Modes/InlineMode.js | 31 +++++++ src/Modes/PopupMode.js | 44 +++++++++ src/dark-editable.js | 84 +++++++---------- 8 files changed, 288 insertions(+), 124 deletions(-) create mode 100644 src/Modes/BaseMode.js create mode 100644 src/Modes/InlineMode.js create mode 100644 src/Modes/PopupMode.js diff --git a/README.md b/README.md index 2433ecc..6deaac0 100644 --- a/README.md +++ b/README.md @@ -104,20 +104,22 @@ Required }); ``` # Options -Options can be defined via javascript or via data-* html attributes.\ -| Name | Type | Default | Description | -| ----------- | --------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ajaxOptions | object | null | Text shown when element is empty | -| disabled | boolean | false | Sets disabled state of editable | -| emptytext | string | 'Empty' | Text shown when element is empty. | -| error | function | null | | -| success | function | null | | -| name | string | null | Name of field. Will be submitted on server. Can be taken from ```id``` attribute | -| pk | string | null | Primary key of editable object (e.g. record id in database). | -| send | boolean | true | Strategy for sending data on server. When ```true``` data will be sent on server only if pk and url defined, otherwise new value will be stored locally. | -| type | string | 'text' | Type of input. Can be text/textarea/select/date and more | -| url | string | null | Url for submit, e.g. ```'/post'``` | -| value | mixed | element's text | Initial value of input. If not set, taken from element's text. | +Options can be defined via javascript or via data-* html attributes. + +| Name | Type | Default | Description | +|--------------| --------------- |----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------| +| ajaxOptions | object | null | Text shown when element is empty | +| disabled | boolean | false | Sets disabled state of editable | +| emptytext | string | 'Empty' | Text shown when element is empty. | +| error | function | null | | +| success | function | null | | +| name | string | null | Name of field. Will be submitted on server. Can be taken from ```id``` attribute | +| pk | string | null | Primary key of editable object (e.g. record id in database). | +| send | boolean | true | Strategy for sending data on server. When ```true``` data will be sent on server only if pk and url defined, otherwise new value will be stored locally. | +| type | string | 'text' | Type of input. Can be text/textarea/select/date and more | +| url | string | null | Url for submit, e.g. ```'/post'``` | +| value | mixed | element's text | Initial value of input. If not set, taken from element's text. | +| mode | string | 'popup' | Mode of editable, can be popup or inline. | # Methods | Method | Parameters | Description | | ----------------- | --------------------------------- | ------------------------------------------------------------- | diff --git a/dist/dark-editable.iife.js b/dist/dark-editable.iife.js index ebd3276..9d452d7 100644 --- a/dist/dark-editable.iife.js +++ b/dist/dark-editable.iife.js @@ -1 +1 @@ -var DarkEditable=function(){"use strict";const d="";class c{constructor(e,t={}){this._element={element:null,form:null,load:null,buttons:{success:null,cancel:null}},this.element=e,this.options=t,this.init_options(),this.init_popover(),this.init_text(),this.init_hide_onclick(),this.init_style(),this.disabled&&this.disable(),this.element.dispatchEvent(new CustomEvent("init"))}init_options(){var s,i,a,r;const e=(n,o)=>{var l,h;return this[n]=((l=this.element.dataset)==null?void 0:l[n])??((h=this.options)==null?void 0:h[n])??o},t=(n,o)=>(e(n,o),typeof this[n]!="boolean"&&(this[n]=="true"?this[n]=!0:this[n]=="false"?this[n]=!1:this[n]=o),this[n]);switch(e("value",this.element.innerHTML),e("name",this.element.id),e("pk",null),e("title",""),e("type","text"),e("emptytext","Empty"),e("url",null),e("ajaxOptions",{}),this.ajaxOptions=Object.assign({method:"POST",dataType:"text"},this.ajaxOptions),t("send",!0),t("disabled",!1),t("required",!1),(s=this.options)!=null&&s.success&&typeof((i=this.options)==null?void 0:i.success)=="function"&&(this.success=this.options.success),(a=this.options)!=null&&a.error&&typeof((r=this.options)==null?void 0:r.error)=="function"&&(this.error=this.options.error),this.type){case"select":e("source",[]),typeof this.source=="string"&&this.source!=""&&(this.source=JSON.parse(this.source));break;case"date":e("format","YYYY-MM-DD"),e("viewformat","YYYY-MM-DD");break;case"datetime":e("format","YYYY-MM-DD HH:mm"),e("viewformat","YYYY-MM-DD HH:mm"),this.value=moment(this.value).format("YYYY-MM-DDTHH:mm");break}}init_text(){const e="dark-editable-element-empty";this.element.classList.remove(e);let t=!0;switch(this.type){default:this.value==""?this.element.innerHTML=this.emptytext:(this.element.innerHTML=this.value,t=!1);break;case"select":this.element.innerHTML=this.emptytext,this.value!=""&&this.source.length>0&&this.source.forEach(s=>{s.value==this.value&&(this.element.innerHTML=s.text,t=!1)});break;case"date":case"datetime":this.value==""?this.element.innerHTML=this.emptytext:(this.element.innerHTML=moment(this.value).format(this.viewformat),t=!1);break}t&&this.element.classList.add(e)}init_style(){this.element.classList.add("dark-editable-element")}init_hide_onclick(){document.addEventListener("click",e=>{const t=e.target;if(t===this.popover.tip||t==this.element)return;let s=t;for(;s=s.parentNode;)if(s===this.popover.tip)return;this.popover.hide()})}init_popover(){this.popover=new bootstrap.Popover(this.element,{container:"body",content:this.route_type(),html:!0,customClass:"dark-editable",title:this.title}),this.element.addEventListener("show.bs.popover",()=>{this._element.element.value=this.value,this.hideError(),this.element.dispatchEvent(new CustomEvent("show"))}),this.element.addEventListener("shown.bs.popover",()=>{this.element.dispatchEvent(new CustomEvent("shown"))}),this.element.addEventListener("hide.bs.popover",()=>{this.element.dispatchEvent(new CustomEvent("hide"))}),this.element.addEventListener("hidden.bs.popover",()=>{this.element.dispatchEvent(new CustomEvent("hidden"))})}route_type(){switch(this.type){default:throw new Error("Undefined type");case"text":case"password":case"email":case"url":case"tel":case"number":case"range":case"time":return this.type_input();case"textarea":return this.type_textarea();case"select":return this.type_select();case"date":return this.type_date();case"datetime":return this.type_datetime()}}createElement(e){const t=document.createElement(e);return t.classList.add("form-control"),this.required&&(t.required=this.required),this.add_focus(t),t}type_input(){const e=this.createElement("input");return e.type=this.type,this.createContainer(e)}type_textarea(){const e=this.createElement("textarea");return this.createContainer(e)}type_select(){const e=this.createElement("select");return this.source.forEach(t=>{const s=document.createElement("option");s.value=t.value,s.innerHTML=t.text,e.append(s)}),this.createContainer(e)}type_date(){const e=this.createElement("input");return e.type="date",this.createContainer(e)}type_datetime(){const e=this.createElement("input");return e.type="datetime-local",this.createContainer(e)}add_focus(e){this.element.addEventListener("shown.bs.popover",function(){e.focus()})}load(e){e?this._element.load.style.display="block":this._element.load.style.display="none"}setError(e){this._element.error.innerHTML=e}showError(){this._element.error.style.display="block"}hideError(){this._element.error.style.display="none"}createContainer(e){const t=document.createElement("div");return this._element.element=e,this._element.error=this.createContainerError(),this._element.form=this.createContainerForm(e),this._element.load=this.createContainerLoad(),this._element.buttons.success=this.createButtonSuccess(),this._element.buttons.cancel=this.createButtonCancel(),this._element.form.append(e,this._element.load,this._element.buttons.success,this._element.buttons.cancel),t.append(this._element.error,this._element.form),t}createContainerError(){const e=document.createElement("div");return e.classList.add("text-danger","fst-italic","mb-2","fw-bold"),e.style.display="none",e}createContainerForm(e){const t=document.createElement("form");return t.classList.add("d-flex","align-items-start"),t.style.gap="20px",t.addEventListener("submit",async s=>{s.preventDefault();const i=e.value;if(this.send&&this.pk&&this.url&&this.value!=i){this.load(!0);let a;try{const r=await this.ajax(i);r.ok?a=await this.success(r,i):a=await this.error(r,i)||`${r.status} ${r.statusText}`}catch(r){console.error(r),a=r}a?(this.setError(a),this.showError()):(this.setError(null),this.hideError(),this.value=e.value,this.popover.hide(),this.init_text()),this.load(!1)}else this.value=e.value,this.popover.hide(),this.init_text();this.element.dispatchEvent(new CustomEvent("save"))}),t}createContainerLoad(){const e=document.createElement("div");e.style.display="none",e.style.position="absolute",e.style.background="white",e.style.width="100%",e.style.height="100%",e.style.top=0,e.style.left=0;const t=document.createElement("div");return t.classList.add("dark-editable-loader"),e.append(t),e}createButton(){const e=document.createElement("button");return e.type="button",e.classList.add("btn","btn-sm"),e.style.color="transparent",e.style.textShadow="0 0 0 white",e}createButtonSuccess(){const e=this.createButton();return e.type="submit",e.classList.add("btn-success"),e.innerHTML="✔",e}createButtonCancel(){const e=this.createButton();e.classList.add("btn-danger");const t=document.createElement("div");return t.innerHTML="✖",e.append(t),e.addEventListener("click",()=>{this.popover.hide()}),e}ajax(e){let t=this.url;const s=new FormData;s.append("pk",this.pk),s.append("name",this.name),s.append("value",e);const i={};return i.method=this.ajaxOptions.method,i.method=="POST"?i.body=s:t+="?"+new URLSearchParams(s).toString(),fetch(t,i)}async success(e,t){}async error(e,t){}enable(){this.disabled=!1,this.element.classList.remove("dark-editable-element-disabled"),this.popover.enable()}disable(){this.disabled=!0,this.element.classList.add("dark-editable-element-disabled"),this.popover.disable()}setValue(e){this.value=e,this.init_text()}getValue(){return this.value}}return c}(); +var DarkEditable=function(){"use strict";var b=Object.defineProperty;var E=(h,n,l)=>n in h?b(h,n,{enumerable:!0,configurable:!0,writable:!0,value:l}):h[n]=l;var p=(h,n,l)=>(E(h,typeof n!="symbol"?n+"":n,l),l);const h="";class n{constructor(e){if(this.constructor===n)throw new Error("It's abstract class");this.context=e}event_show(){this.context.hideError(),this.context._element.element.value=this.context.value,this.context.element.dispatchEvent(new CustomEvent("show"))}event_shown(){this.context.element.dispatchEvent(new CustomEvent("shown"))}event_hide(){this.context.element.dispatchEvent(new CustomEvent("hide"))}event_hidden(){this.context.element.dispatchEvent(new CustomEvent("hidden"))}init(){throw new Error("Method `init` not define!")}enable(){throw new Error("Method `enable` not define!")}disable(){throw new Error("Method `disable` not define!")}hide(){throw new Error("Method `hide` not define!")}}class l extends n{init(){this.popover=new bootstrap.Popover(this.context.element,{container:"body",content:this.context.route_type(),html:!0,customClass:"dark-editable",title:this.context.title}),this.context.element.addEventListener("show.bs.popover",()=>{this.event_show()}),this.context.element.addEventListener("shown.bs.popover",()=>{this.event_shown()}),this.context.element.addEventListener("hide.bs.popover",()=>{this.event_hide()}),this.context.element.addEventListener("hidden.bs.popover",()=>{this.event_hidden()}),document.addEventListener("click",e=>{const t=e.target;if(t===this.popover.tip||t===this.context.element)return;let s=t;for(;s=s.parentNode;)if(s===this.popover.tip)return;this.hide()})}enable(){this.popover.enable()}disable(){this.popover.disable()}hide(){this.popover.hide()}}class v extends n{init(){const e=()=>{if(!this.context.disabled){const t=this.context.route_type();this.event_show(),this.context.element.removeEventListener("click",e),this.context.element.innerHTML="",this.context.element.append(t),this.event_shown()}};this.context.element.addEventListener("click",e)}enable(){}disable(){}hide(){this.event_hide(),this.context.element.innerHTML=this.context.value,setTimeout(()=>{this.init(),this.event_hidden()},100)}}class f{constructor(e,t={}){p(this,"modeElement",null);switch(this._element={element:null,form:null,load:null,buttons:{success:null,cancel:null}},this.element=e,this.options=t,this.init_options(),this.mode){default:throw new Error(`Mode ${this.mode} not found!`);case"popup":this.modeElement=new l(this);break;case"inline":this.modeElement=new v(this);break}this.modeElement.init(),this.init_text(),this.init_style(),this.disabled&&this.disable(),this.element.dispatchEvent(new CustomEvent("init"))}init_options(){var s,i,a,o;const e=(r,c)=>{var u,m;return this[r]=((u=this.element.dataset)==null?void 0:u[r])??((m=this.options)==null?void 0:m[r])??c},t=(r,c)=>(e(r,c),typeof this[r]!="boolean"&&(this[r]==="true"?this[r]=!0:this[r]==="false"?this[r]=!1:this[r]=c),this[r]);switch(e("value",this.element.innerHTML),e("name",this.element.id),e("pk",null),e("title",""),e("type","text"),e("emptytext","Empty"),e("mode","popup"),e("url",null),e("ajaxOptions",{}),this.ajaxOptions=Object.assign({method:"POST",dataType:"text"},this.ajaxOptions),t("send",!0),t("disabled",!1),t("required",!1),(s=this.options)!=null&&s.success&&typeof((i=this.options)==null?void 0:i.success)=="function"&&(this.success=this.options.success),(a=this.options)!=null&&a.error&&typeof((o=this.options)==null?void 0:o.error)=="function"&&(this.error=this.options.error),this.type){case"select":e("source",[]),typeof this.source=="string"&&this.source!==""&&(this.source=JSON.parse(this.source));break;case"date":e("format","YYYY-MM-DD"),e("viewformat","YYYY-MM-DD");break;case"datetime":e("format","YYYY-MM-DD HH:mm"),e("viewformat","YYYY-MM-DD HH:mm"),this.value=moment(this.value).format("YYYY-MM-DDTHH:mm");break}}init_text(){const e="dark-editable-element-empty";this.element.classList.remove(e);let t=!0;switch(this.type){default:this.value===""?this.element.innerHTML=this.emptytext:(this.element.innerHTML=this.value,t=!1);break;case"select":this.element.innerHTML=this.emptytext,this.value!==""&&this.source.length>0&&this.source.forEach(s=>{s.value==this.value&&(this.element.innerHTML=s.text,t=!1)});break;case"date":case"datetime":this.value===""?this.element.innerHTML=this.emptytext:(this.element.innerHTML=moment(this.value).format(this.viewformat),t=!1);break}t&&this.element.classList.add(e)}init_style(){this.element.classList.add("dark-editable-element")}route_type(){switch(this.type){default:throw new Error("Undefined type");case"text":case"password":case"email":case"url":case"tel":case"number":case"range":case"time":return this.type_input();case"textarea":return this.type_textarea();case"select":return this.type_select();case"date":return this.type_date();case"datetime":return this.type_datetime()}}createElement(e){const t=document.createElement(e);return t.classList.add("form-control"),this.required&&(t.required=this.required),this.add_focus(t),t}type_input(){const e=this.createElement("input");return e.type=this.type,this.createContainer(e)}type_textarea(){const e=this.createElement("textarea");return this.createContainer(e)}type_select(){const e=this.createElement("select");return this.source.forEach(t=>{const s=document.createElement("option");s.value=t.value,s.innerHTML=t.text,e.append(s)}),this.createContainer(e)}type_date(){const e=this.createElement("input");return e.type="date",this.createContainer(e)}type_datetime(){const e=this.createElement("input");return e.type="datetime-local",this.createContainer(e)}add_focus(e){this.element.addEventListener("shown",function(){e.focus()})}load(e){e?this._element.load.style.display="block":this._element.load.style.display="none"}setError(e){this._element.error.innerHTML=e}showError(){this._element.error.style.display="block"}hideError(){this._element.error&&(this._element.error.style.display="none")}createContainer(e){const t=document.createElement("div");return this._element.element=e,this._element.error=this.createContainerError(),this._element.form=this.createContainerForm(e),this._element.load=this.createContainerLoad(),this._element.buttons.success=this.createButtonSuccess(),this._element.buttons.cancel=this.createButtonCancel(),this._element.form.append(e,this._element.load,this._element.buttons.success,this._element.buttons.cancel),t.append(this._element.error,this._element.form),t}createContainerError(){const e=document.createElement("div");return e.classList.add("text-danger","fst-italic","mb-2","fw-bold"),e.style.display="none",e}createContainerForm(e){const t=document.createElement("form");return t.classList.add("d-flex","align-items-start"),t.style.gap="20px",t.addEventListener("submit",async s=>{s.preventDefault();const i=e.value;if(this.send&&this.pk&&this.url&&this.value!=i){this.load(!0);let a;try{const o=await this.ajax(i);o.ok?a=await this.success(o,i):a=await this.error(o,i)||`${o.status} ${o.statusText}`}catch(o){console.error(o),a=o}a?(this.setError(a),this.showError()):(this.setError(null),this.hideError(),this.value=e.value,this.modeElement.hide(),this.init_text()),this.load(!1)}else this.value=e.value,this.modeElement.hide(),this.init_text();this.element.dispatchEvent(new CustomEvent("save"))}),t}createContainerLoad(){const e=document.createElement("div");e.style.display="none",e.style.position="absolute",e.style.background="white",e.style.width="100%",e.style.height="100%",e.style.top=0,e.style.left=0;const t=document.createElement("div");return t.classList.add("dark-editable-loader"),e.append(t),e}createButton(){const e=document.createElement("button");return e.type="button",e.classList.add("btn","btn-sm"),e.style.color="transparent",e.style.textShadow="0 0 0 white",e}createButtonSuccess(){const e=this.createButton();return e.type="submit",e.classList.add("btn-success"),e.innerHTML="✔",e}createButtonCancel(){const e=this.createButton();e.classList.add("btn-danger");const t=document.createElement("div");return t.innerHTML="✖",e.append(t),e.addEventListener("click",()=>{this.modeElement.hide()}),e}ajax(e){let t=this.url;const s=new FormData;s.append("pk",this.pk),s.append("name",this.name),s.append("value",e);const i={};return i.method=this.ajaxOptions.method,i.method=="POST"?i.body=s:t+="?"+new URLSearchParams(s).toString(),fetch(t,i)}async success(e,t){}async error(e,t){}enable(){this.disabled=!1,this.element.classList.remove("dark-editable-element-disabled"),this.modeElement.enable()}disable(){this.disabled=!0,this.element.classList.add("dark-editable-element-disabled"),this.modeElement.enable()}setValue(e){this.value=e,this.init_text()}getValue(){return this.value}}return f}(); diff --git a/dist/dark-editable.js b/dist/dark-editable.js index 8a842ac..91aad4f 100644 --- a/dist/dark-editable.js +++ b/dist/dark-editable.js @@ -1,20 +1,122 @@ -class d { +var m = Object.defineProperty; +var p = (o, e, t) => e in o ? m(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t; +var u = (o, e, t) => (p(o, typeof e != "symbol" ? e + "" : e, t), t); +class h { + constructor(e) { + if (this.constructor === h) + throw new Error("It's abstract class"); + this.context = e; + } + event_show() { + this.context.hideError(), this.context._element.element.value = this.context.value, this.context.element.dispatchEvent(new CustomEvent("show")); + } + event_shown() { + this.context.element.dispatchEvent(new CustomEvent("shown")); + } + event_hide() { + this.context.element.dispatchEvent(new CustomEvent("hide")); + } + event_hidden() { + this.context.element.dispatchEvent(new CustomEvent("hidden")); + } + init() { + throw new Error("Method `init` not define!"); + } + enable() { + throw new Error("Method `enable` not define!"); + } + disable() { + throw new Error("Method `disable` not define!"); + } + hide() { + throw new Error("Method `hide` not define!"); + } +} +class v extends h { + init() { + this.popover = new bootstrap.Popover(this.context.element, { + container: "body", + content: this.context.route_type(), + html: !0, + customClass: "dark-editable", + title: this.context.title + }), this.context.element.addEventListener("show.bs.popover", () => { + this.event_show(); + }), this.context.element.addEventListener("shown.bs.popover", () => { + this.event_shown(); + }), this.context.element.addEventListener("hide.bs.popover", () => { + this.event_hide(); + }), this.context.element.addEventListener("hidden.bs.popover", () => { + this.event_hidden(); + }), document.addEventListener("click", (e) => { + const t = e.target; + if (t === this.popover.tip || t === this.context.element) + return; + let s = t; + for (; s = s.parentNode; ) + if (s === this.popover.tip) + return; + this.hide(); + }); + } + enable() { + this.popover.enable(); + } + disable() { + this.popover.disable(); + } + hide() { + this.popover.hide(); + } +} +class f extends h { + init() { + const e = () => { + if (!this.context.disabled) { + const t = this.context.route_type(); + this.event_show(), this.context.element.removeEventListener("click", e), this.context.element.innerHTML = "", this.context.element.append(t), this.event_shown(); + } + }; + this.context.element.addEventListener("click", e); + } + enable() { + } + disable() { + } + hide() { + this.event_hide(), this.context.element.innerHTML = this.context.value, setTimeout(() => { + this.init(), this.event_hidden(); + }, 100); + } +} +class E { constructor(e, t = {}) { - this._element = { element: null, form: null, load: null, buttons: { success: null, cancel: null } }, this.element = e, this.options = t, this.init_options(), this.init_popover(), this.init_text(), this.init_hide_onclick(), this.init_style(), this.disabled && this.disable(), this.element.dispatchEvent(new CustomEvent("init")); + u(this, "modeElement", null); + switch (this._element = { element: null, form: null, load: null, buttons: { success: null, cancel: null } }, this.element = e, this.options = t, this.init_options(), this.mode) { + default: + throw new Error(`Mode ${this.mode} not found!`); + case "popup": + this.modeElement = new v(this); + break; + case "inline": + this.modeElement = new f(this); + break; + } + this.modeElement.init(), this.init_text(), this.init_style(), this.disabled && this.disable(), this.element.dispatchEvent(new CustomEvent("init")); } /* INIT METHODS */ init_options() { - var s, i, a, r; - const e = (n, o) => { - var l, h; - return this[n] = ((l = this.element.dataset) == null ? void 0 : l[n]) ?? ((h = this.options) == null ? void 0 : h[n]) ?? o; - }, t = (n, o) => (e(n, o), typeof this[n] != "boolean" && (this[n] == "true" ? this[n] = !0 : this[n] == "false" ? this[n] = !1 : this[n] = o), this[n]); - switch (e("value", this.element.innerHTML), e("name", this.element.id), e("pk", null), e("title", ""), e("type", "text"), e("emptytext", "Empty"), e("url", null), e("ajaxOptions", {}), this.ajaxOptions = Object.assign({ + var s, n, a, r; + const e = (i, l) => { + var c, d; + return this[i] = ((c = this.element.dataset) == null ? void 0 : c[i]) ?? ((d = this.options) == null ? void 0 : d[i]) ?? l; + }, t = (i, l) => (e(i, l), typeof this[i] != "boolean" && (this[i] === "true" ? this[i] = !0 : this[i] === "false" ? this[i] = !1 : this[i] = l), this[i]); + switch (e("value", this.element.innerHTML), e("name", this.element.id), e("pk", null), e("title", ""), e("type", "text"), e("emptytext", "Empty"), e("mode", "popup"), e("url", null), e("ajaxOptions", {}), this.ajaxOptions = Object.assign({ method: "POST", dataType: "text" - }, this.ajaxOptions), t("send", !0), t("disabled", !1), t("required", !1), (s = this.options) != null && s.success && typeof ((i = this.options) == null ? void 0 : i.success) == "function" && (this.success = this.options.success), (a = this.options) != null && a.error && typeof ((r = this.options) == null ? void 0 : r.error) == "function" && (this.error = this.options.error), this.type) { + }, this.ajaxOptions), t("send", !0), t("disabled", !1), t("required", !1), (s = this.options) != null && s.success && typeof ((n = this.options) == null ? void 0 : n.success) == "function" && (this.success = this.options.success), (a = this.options) != null && a.error && typeof ((r = this.options) == null ? void 0 : r.error) == "function" && (this.error = this.options.error), this.type) { case "select": - e("source", []), typeof this.source == "string" && this.source != "" && (this.source = JSON.parse(this.source)); + e("source", []), typeof this.source == "string" && this.source !== "" && (this.source = JSON.parse(this.source)); break; case "date": e("format", "YYYY-MM-DD"), e("viewformat", "YYYY-MM-DD"); @@ -30,16 +132,16 @@ class d { let t = !0; switch (this.type) { default: - this.value == "" ? this.element.innerHTML = this.emptytext : (this.element.innerHTML = this.value, t = !1); + this.value === "" ? this.element.innerHTML = this.emptytext : (this.element.innerHTML = this.value, t = !1); break; case "select": - this.element.innerHTML = this.emptytext, this.value != "" && this.source.length > 0 && this.source.forEach((s) => { + this.element.innerHTML = this.emptytext, this.value !== "" && this.source.length > 0 && this.source.forEach((s) => { s.value == this.value && (this.element.innerHTML = s.text, t = !1); }); break; case "date": case "datetime": - this.value == "" ? this.element.innerHTML = this.emptytext : (this.element.innerHTML = moment(this.value).format(this.viewformat), t = !1); + this.value === "" ? this.element.innerHTML = this.emptytext : (this.element.innerHTML = moment(this.value).format(this.viewformat), t = !1); break; } t && this.element.classList.add(e); @@ -47,35 +149,6 @@ class d { init_style() { this.element.classList.add("dark-editable-element"); } - init_hide_onclick() { - document.addEventListener("click", (e) => { - const t = e.target; - if (t === this.popover.tip || t == this.element) - return; - let s = t; - for (; s = s.parentNode; ) - if (s === this.popover.tip) - return; - this.popover.hide(); - }); - } - init_popover() { - this.popover = new bootstrap.Popover(this.element, { - container: "body", - content: this.route_type(), - html: !0, - customClass: "dark-editable", - title: this.title - }), this.element.addEventListener("show.bs.popover", () => { - this._element.element.value = this.value, this.hideError(), this.element.dispatchEvent(new CustomEvent("show")); - }), this.element.addEventListener("shown.bs.popover", () => { - this.element.dispatchEvent(new CustomEvent("shown")); - }), this.element.addEventListener("hide.bs.popover", () => { - this.element.dispatchEvent(new CustomEvent("hide")); - }), this.element.addEventListener("hidden.bs.popover", () => { - this.element.dispatchEvent(new CustomEvent("hidden")); - }); - } /* INIT METHODS END */ route_type() { switch (this.type) { @@ -131,7 +204,7 @@ class d { /* TYPES END */ /* ADD FOCUS */ add_focus(e) { - this.element.addEventListener("shown.bs.popover", function() { + this.element.addEventListener("shown", function() { e.focus(); }); } @@ -150,7 +223,7 @@ class d { this._element.error.style.display = "block"; } hideError() { - this._element.error.style.display = "none"; + this._element.error && (this._element.error.style.display = "none"); } /* DIV ERROR END */ /* CONTAINER DIV */ @@ -166,19 +239,19 @@ class d { const t = document.createElement("form"); return t.classList.add("d-flex", "align-items-start"), t.style.gap = "20px", t.addEventListener("submit", async (s) => { s.preventDefault(); - const i = e.value; - if (this.send && this.pk && this.url && this.value != i) { + const n = e.value; + if (this.send && this.pk && this.url && this.value != n) { this.load(!0); let a; try { - const r = await this.ajax(i); - r.ok ? a = await this.success(r, i) : a = await this.error(r, i) || `${r.status} ${r.statusText}`; + const r = await this.ajax(n); + r.ok ? a = await this.success(r, n) : a = await this.error(r, n) || `${r.status} ${r.statusText}`; } catch (r) { console.error(r), a = r; } - a ? (this.setError(a), this.showError()) : (this.setError(null), this.hideError(), this.value = e.value, this.popover.hide(), this.init_text()), this.load(!1); + a ? (this.setError(a), this.showError()) : (this.setError(null), this.hideError(), this.value = e.value, this.modeElement.hide(), this.init_text()), this.load(!1); } else - this.value = e.value, this.popover.hide(), this.init_text(); + this.value = e.value, this.modeElement.hide(), this.init_text(); this.element.dispatchEvent(new CustomEvent("save")); }), t; } @@ -203,7 +276,7 @@ class d { e.classList.add("btn-danger"); const t = document.createElement("div"); return t.innerHTML = "✖", e.append(t), e.addEventListener("click", () => { - this.popover.hide(); + this.modeElement.hide(); }), e; } /* BUTTONS END */ @@ -212,8 +285,8 @@ class d { let t = this.url; const s = new FormData(); s.append("pk", this.pk), s.append("name", this.name), s.append("value", e); - const i = {}; - return i.method = this.ajaxOptions.method, i.method == "POST" ? i.body = s : t += "?" + new URLSearchParams(s).toString(), fetch(t, i); + const n = {}; + return n.method = this.ajaxOptions.method, n.method == "POST" ? n.body = s : t += "?" + new URLSearchParams(s).toString(), fetch(t, n); } async success(e, t) { } @@ -222,10 +295,10 @@ class d { /* AJAX END */ /* METHODS */ enable() { - this.disabled = !1, this.element.classList.remove("dark-editable-element-disabled"), this.popover.enable(); + this.disabled = !1, this.element.classList.remove("dark-editable-element-disabled"), this.modeElement.enable(); } disable() { - this.disabled = !0, this.element.classList.add("dark-editable-element-disabled"), this.popover.disable(); + this.disabled = !0, this.element.classList.add("dark-editable-element-disabled"), this.modeElement.enable(); } setValue(e) { this.value = e, this.init_text(); @@ -236,5 +309,5 @@ class d { /* METHODS END */ } export { - d as default + E as default }; diff --git a/dist/dark-editable.umd.cjs b/dist/dark-editable.umd.cjs index 8d3e077..49b91e2 100644 --- a/dist/dark-editable.umd.cjs +++ b/dist/dark-editable.umd.cjs @@ -1 +1 @@ -(function(l,o){typeof exports=="object"&&typeof module<"u"?module.exports=o():typeof define=="function"&&define.amd?define(o):(l=typeof globalThis<"u"?globalThis:l||self,l.DarkEditable=o())})(this,function(){"use strict";const l="";class o{constructor(e,t={}){this._element={element:null,form:null,load:null,buttons:{success:null,cancel:null}},this.element=e,this.options=t,this.init_options(),this.init_popover(),this.init_text(),this.init_hide_onclick(),this.init_style(),this.disabled&&this.disable(),this.element.dispatchEvent(new CustomEvent("init"))}init_options(){var s,i,a,r;const e=(n,h)=>{var c,d;return this[n]=((c=this.element.dataset)==null?void 0:c[n])??((d=this.options)==null?void 0:d[n])??h},t=(n,h)=>(e(n,h),typeof this[n]!="boolean"&&(this[n]=="true"?this[n]=!0:this[n]=="false"?this[n]=!1:this[n]=h),this[n]);switch(e("value",this.element.innerHTML),e("name",this.element.id),e("pk",null),e("title",""),e("type","text"),e("emptytext","Empty"),e("url",null),e("ajaxOptions",{}),this.ajaxOptions=Object.assign({method:"POST",dataType:"text"},this.ajaxOptions),t("send",!0),t("disabled",!1),t("required",!1),(s=this.options)!=null&&s.success&&typeof((i=this.options)==null?void 0:i.success)=="function"&&(this.success=this.options.success),(a=this.options)!=null&&a.error&&typeof((r=this.options)==null?void 0:r.error)=="function"&&(this.error=this.options.error),this.type){case"select":e("source",[]),typeof this.source=="string"&&this.source!=""&&(this.source=JSON.parse(this.source));break;case"date":e("format","YYYY-MM-DD"),e("viewformat","YYYY-MM-DD");break;case"datetime":e("format","YYYY-MM-DD HH:mm"),e("viewformat","YYYY-MM-DD HH:mm"),this.value=moment(this.value).format("YYYY-MM-DDTHH:mm");break}}init_text(){const e="dark-editable-element-empty";this.element.classList.remove(e);let t=!0;switch(this.type){default:this.value==""?this.element.innerHTML=this.emptytext:(this.element.innerHTML=this.value,t=!1);break;case"select":this.element.innerHTML=this.emptytext,this.value!=""&&this.source.length>0&&this.source.forEach(s=>{s.value==this.value&&(this.element.innerHTML=s.text,t=!1)});break;case"date":case"datetime":this.value==""?this.element.innerHTML=this.emptytext:(this.element.innerHTML=moment(this.value).format(this.viewformat),t=!1);break}t&&this.element.classList.add(e)}init_style(){this.element.classList.add("dark-editable-element")}init_hide_onclick(){document.addEventListener("click",e=>{const t=e.target;if(t===this.popover.tip||t==this.element)return;let s=t;for(;s=s.parentNode;)if(s===this.popover.tip)return;this.popover.hide()})}init_popover(){this.popover=new bootstrap.Popover(this.element,{container:"body",content:this.route_type(),html:!0,customClass:"dark-editable",title:this.title}),this.element.addEventListener("show.bs.popover",()=>{this._element.element.value=this.value,this.hideError(),this.element.dispatchEvent(new CustomEvent("show"))}),this.element.addEventListener("shown.bs.popover",()=>{this.element.dispatchEvent(new CustomEvent("shown"))}),this.element.addEventListener("hide.bs.popover",()=>{this.element.dispatchEvent(new CustomEvent("hide"))}),this.element.addEventListener("hidden.bs.popover",()=>{this.element.dispatchEvent(new CustomEvent("hidden"))})}route_type(){switch(this.type){default:throw new Error("Undefined type");case"text":case"password":case"email":case"url":case"tel":case"number":case"range":case"time":return this.type_input();case"textarea":return this.type_textarea();case"select":return this.type_select();case"date":return this.type_date();case"datetime":return this.type_datetime()}}createElement(e){const t=document.createElement(e);return t.classList.add("form-control"),this.required&&(t.required=this.required),this.add_focus(t),t}type_input(){const e=this.createElement("input");return e.type=this.type,this.createContainer(e)}type_textarea(){const e=this.createElement("textarea");return this.createContainer(e)}type_select(){const e=this.createElement("select");return this.source.forEach(t=>{const s=document.createElement("option");s.value=t.value,s.innerHTML=t.text,e.append(s)}),this.createContainer(e)}type_date(){const e=this.createElement("input");return e.type="date",this.createContainer(e)}type_datetime(){const e=this.createElement("input");return e.type="datetime-local",this.createContainer(e)}add_focus(e){this.element.addEventListener("shown.bs.popover",function(){e.focus()})}load(e){e?this._element.load.style.display="block":this._element.load.style.display="none"}setError(e){this._element.error.innerHTML=e}showError(){this._element.error.style.display="block"}hideError(){this._element.error.style.display="none"}createContainer(e){const t=document.createElement("div");return this._element.element=e,this._element.error=this.createContainerError(),this._element.form=this.createContainerForm(e),this._element.load=this.createContainerLoad(),this._element.buttons.success=this.createButtonSuccess(),this._element.buttons.cancel=this.createButtonCancel(),this._element.form.append(e,this._element.load,this._element.buttons.success,this._element.buttons.cancel),t.append(this._element.error,this._element.form),t}createContainerError(){const e=document.createElement("div");return e.classList.add("text-danger","fst-italic","mb-2","fw-bold"),e.style.display="none",e}createContainerForm(e){const t=document.createElement("form");return t.classList.add("d-flex","align-items-start"),t.style.gap="20px",t.addEventListener("submit",async s=>{s.preventDefault();const i=e.value;if(this.send&&this.pk&&this.url&&this.value!=i){this.load(!0);let a;try{const r=await this.ajax(i);r.ok?a=await this.success(r,i):a=await this.error(r,i)||`${r.status} ${r.statusText}`}catch(r){console.error(r),a=r}a?(this.setError(a),this.showError()):(this.setError(null),this.hideError(),this.value=e.value,this.popover.hide(),this.init_text()),this.load(!1)}else this.value=e.value,this.popover.hide(),this.init_text();this.element.dispatchEvent(new CustomEvent("save"))}),t}createContainerLoad(){const e=document.createElement("div");e.style.display="none",e.style.position="absolute",e.style.background="white",e.style.width="100%",e.style.height="100%",e.style.top=0,e.style.left=0;const t=document.createElement("div");return t.classList.add("dark-editable-loader"),e.append(t),e}createButton(){const e=document.createElement("button");return e.type="button",e.classList.add("btn","btn-sm"),e.style.color="transparent",e.style.textShadow="0 0 0 white",e}createButtonSuccess(){const e=this.createButton();return e.type="submit",e.classList.add("btn-success"),e.innerHTML="✔",e}createButtonCancel(){const e=this.createButton();e.classList.add("btn-danger");const t=document.createElement("div");return t.innerHTML="✖",e.append(t),e.addEventListener("click",()=>{this.popover.hide()}),e}ajax(e){let t=this.url;const s=new FormData;s.append("pk",this.pk),s.append("name",this.name),s.append("value",e);const i={};return i.method=this.ajaxOptions.method,i.method=="POST"?i.body=s:t+="?"+new URLSearchParams(s).toString(),fetch(t,i)}async success(e,t){}async error(e,t){}enable(){this.disabled=!1,this.element.classList.remove("dark-editable-element-disabled"),this.popover.enable()}disable(){this.disabled=!0,this.element.classList.add("dark-editable-element-disabled"),this.popover.disable()}setValue(e){this.value=e,this.init_text()}getValue(){return this.value}}return o}); +(function(a,n){typeof exports=="object"&&typeof module<"u"?module.exports=n():typeof define=="function"&&define.amd?define(n):(a=typeof globalThis<"u"?globalThis:a||self,a.DarkEditable=n())})(this,function(){"use strict";var b=Object.defineProperty;var E=(a,n,h)=>n in a?b(a,n,{enumerable:!0,configurable:!0,writable:!0,value:h}):a[n]=h;var p=(a,n,h)=>(E(a,typeof n!="symbol"?n+"":n,h),h);const a="";class n{constructor(e){if(this.constructor===n)throw new Error("It's abstract class");this.context=e}event_show(){this.context.hideError(),this.context._element.element.value=this.context.value,this.context.element.dispatchEvent(new CustomEvent("show"))}event_shown(){this.context.element.dispatchEvent(new CustomEvent("shown"))}event_hide(){this.context.element.dispatchEvent(new CustomEvent("hide"))}event_hidden(){this.context.element.dispatchEvent(new CustomEvent("hidden"))}init(){throw new Error("Method `init` not define!")}enable(){throw new Error("Method `enable` not define!")}disable(){throw new Error("Method `disable` not define!")}hide(){throw new Error("Method `hide` not define!")}}class h extends n{init(){this.popover=new bootstrap.Popover(this.context.element,{container:"body",content:this.context.route_type(),html:!0,customClass:"dark-editable",title:this.context.title}),this.context.element.addEventListener("show.bs.popover",()=>{this.event_show()}),this.context.element.addEventListener("shown.bs.popover",()=>{this.event_shown()}),this.context.element.addEventListener("hide.bs.popover",()=>{this.event_hide()}),this.context.element.addEventListener("hidden.bs.popover",()=>{this.event_hidden()}),document.addEventListener("click",e=>{const t=e.target;if(t===this.popover.tip||t===this.context.element)return;let s=t;for(;s=s.parentNode;)if(s===this.popover.tip)return;this.hide()})}enable(){this.popover.enable()}disable(){this.popover.disable()}hide(){this.popover.hide()}}class v extends n{init(){const e=()=>{if(!this.context.disabled){const t=this.context.route_type();this.event_show(),this.context.element.removeEventListener("click",e),this.context.element.innerHTML="",this.context.element.append(t),this.event_shown()}};this.context.element.addEventListener("click",e)}enable(){}disable(){}hide(){this.event_hide(),this.context.element.innerHTML=this.context.value,setTimeout(()=>{this.init(),this.event_hidden()},100)}}class f{constructor(e,t={}){p(this,"modeElement",null);switch(this._element={element:null,form:null,load:null,buttons:{success:null,cancel:null}},this.element=e,this.options=t,this.init_options(),this.mode){default:throw new Error(`Mode ${this.mode} not found!`);case"popup":this.modeElement=new h(this);break;case"inline":this.modeElement=new v(this);break}this.modeElement.init(),this.init_text(),this.init_style(),this.disabled&&this.disable(),this.element.dispatchEvent(new CustomEvent("init"))}init_options(){var s,i,l,r;const e=(o,c)=>{var u,m;return this[o]=((u=this.element.dataset)==null?void 0:u[o])??((m=this.options)==null?void 0:m[o])??c},t=(o,c)=>(e(o,c),typeof this[o]!="boolean"&&(this[o]==="true"?this[o]=!0:this[o]==="false"?this[o]=!1:this[o]=c),this[o]);switch(e("value",this.element.innerHTML),e("name",this.element.id),e("pk",null),e("title",""),e("type","text"),e("emptytext","Empty"),e("mode","popup"),e("url",null),e("ajaxOptions",{}),this.ajaxOptions=Object.assign({method:"POST",dataType:"text"},this.ajaxOptions),t("send",!0),t("disabled",!1),t("required",!1),(s=this.options)!=null&&s.success&&typeof((i=this.options)==null?void 0:i.success)=="function"&&(this.success=this.options.success),(l=this.options)!=null&&l.error&&typeof((r=this.options)==null?void 0:r.error)=="function"&&(this.error=this.options.error),this.type){case"select":e("source",[]),typeof this.source=="string"&&this.source!==""&&(this.source=JSON.parse(this.source));break;case"date":e("format","YYYY-MM-DD"),e("viewformat","YYYY-MM-DD");break;case"datetime":e("format","YYYY-MM-DD HH:mm"),e("viewformat","YYYY-MM-DD HH:mm"),this.value=moment(this.value).format("YYYY-MM-DDTHH:mm");break}}init_text(){const e="dark-editable-element-empty";this.element.classList.remove(e);let t=!0;switch(this.type){default:this.value===""?this.element.innerHTML=this.emptytext:(this.element.innerHTML=this.value,t=!1);break;case"select":this.element.innerHTML=this.emptytext,this.value!==""&&this.source.length>0&&this.source.forEach(s=>{s.value==this.value&&(this.element.innerHTML=s.text,t=!1)});break;case"date":case"datetime":this.value===""?this.element.innerHTML=this.emptytext:(this.element.innerHTML=moment(this.value).format(this.viewformat),t=!1);break}t&&this.element.classList.add(e)}init_style(){this.element.classList.add("dark-editable-element")}route_type(){switch(this.type){default:throw new Error("Undefined type");case"text":case"password":case"email":case"url":case"tel":case"number":case"range":case"time":return this.type_input();case"textarea":return this.type_textarea();case"select":return this.type_select();case"date":return this.type_date();case"datetime":return this.type_datetime()}}createElement(e){const t=document.createElement(e);return t.classList.add("form-control"),this.required&&(t.required=this.required),this.add_focus(t),t}type_input(){const e=this.createElement("input");return e.type=this.type,this.createContainer(e)}type_textarea(){const e=this.createElement("textarea");return this.createContainer(e)}type_select(){const e=this.createElement("select");return this.source.forEach(t=>{const s=document.createElement("option");s.value=t.value,s.innerHTML=t.text,e.append(s)}),this.createContainer(e)}type_date(){const e=this.createElement("input");return e.type="date",this.createContainer(e)}type_datetime(){const e=this.createElement("input");return e.type="datetime-local",this.createContainer(e)}add_focus(e){this.element.addEventListener("shown",function(){e.focus()})}load(e){e?this._element.load.style.display="block":this._element.load.style.display="none"}setError(e){this._element.error.innerHTML=e}showError(){this._element.error.style.display="block"}hideError(){this._element.error&&(this._element.error.style.display="none")}createContainer(e){const t=document.createElement("div");return this._element.element=e,this._element.error=this.createContainerError(),this._element.form=this.createContainerForm(e),this._element.load=this.createContainerLoad(),this._element.buttons.success=this.createButtonSuccess(),this._element.buttons.cancel=this.createButtonCancel(),this._element.form.append(e,this._element.load,this._element.buttons.success,this._element.buttons.cancel),t.append(this._element.error,this._element.form),t}createContainerError(){const e=document.createElement("div");return e.classList.add("text-danger","fst-italic","mb-2","fw-bold"),e.style.display="none",e}createContainerForm(e){const t=document.createElement("form");return t.classList.add("d-flex","align-items-start"),t.style.gap="20px",t.addEventListener("submit",async s=>{s.preventDefault();const i=e.value;if(this.send&&this.pk&&this.url&&this.value!=i){this.load(!0);let l;try{const r=await this.ajax(i);r.ok?l=await this.success(r,i):l=await this.error(r,i)||`${r.status} ${r.statusText}`}catch(r){console.error(r),l=r}l?(this.setError(l),this.showError()):(this.setError(null),this.hideError(),this.value=e.value,this.modeElement.hide(),this.init_text()),this.load(!1)}else this.value=e.value,this.modeElement.hide(),this.init_text();this.element.dispatchEvent(new CustomEvent("save"))}),t}createContainerLoad(){const e=document.createElement("div");e.style.display="none",e.style.position="absolute",e.style.background="white",e.style.width="100%",e.style.height="100%",e.style.top=0,e.style.left=0;const t=document.createElement("div");return t.classList.add("dark-editable-loader"),e.append(t),e}createButton(){const e=document.createElement("button");return e.type="button",e.classList.add("btn","btn-sm"),e.style.color="transparent",e.style.textShadow="0 0 0 white",e}createButtonSuccess(){const e=this.createButton();return e.type="submit",e.classList.add("btn-success"),e.innerHTML="✔",e}createButtonCancel(){const e=this.createButton();e.classList.add("btn-danger");const t=document.createElement("div");return t.innerHTML="✖",e.append(t),e.addEventListener("click",()=>{this.modeElement.hide()}),e}ajax(e){let t=this.url;const s=new FormData;s.append("pk",this.pk),s.append("name",this.name),s.append("value",e);const i={};return i.method=this.ajaxOptions.method,i.method=="POST"?i.body=s:t+="?"+new URLSearchParams(s).toString(),fetch(t,i)}async success(e,t){}async error(e,t){}enable(){this.disabled=!1,this.element.classList.remove("dark-editable-element-disabled"),this.modeElement.enable()}disable(){this.disabled=!0,this.element.classList.add("dark-editable-element-disabled"),this.modeElement.enable()}setValue(e){this.value=e,this.init_text()}getValue(){return this.value}}return f}); diff --git a/src/Modes/BaseMode.js b/src/Modes/BaseMode.js new file mode 100644 index 0000000..e75f632 --- /dev/null +++ b/src/Modes/BaseMode.js @@ -0,0 +1,34 @@ +export default class BaseMode{ + constructor(context) { + if(this.constructor === BaseMode){ + throw new Error(`It's abstract class`); + } + this.context = context; + } + event_show(){ + this.context.hideError(); + this.context._element.element.value = this.context.value; + this.context.element.dispatchEvent(new CustomEvent("show")); + } + event_shown(){ + this.context.element.dispatchEvent(new CustomEvent("shown")); + } + event_hide(){ + this.context.element.dispatchEvent(new CustomEvent("hide")); + } + event_hidden(){ + this.context.element.dispatchEvent(new CustomEvent("hidden")); + } + init(){ + throw new Error('Method `init` not define!'); + } + enable(){ + throw new Error('Method `enable` not define!'); + } + disable(){ + throw new Error('Method `disable` not define!'); + } + hide(){ + throw new Error('Method `hide` not define!'); + } +} \ No newline at end of file diff --git a/src/Modes/InlineMode.js b/src/Modes/InlineMode.js new file mode 100644 index 0000000..cfc9afb --- /dev/null +++ b/src/Modes/InlineMode.js @@ -0,0 +1,31 @@ +import BaseMode from "./BaseMode.js"; + +export default class InlineMode extends BaseMode{ + init(){ + const open = () => { + if(!this.context.disabled){ + const item = this.context.route_type(); + this.event_show(); + this.context.element.removeEventListener('click', open); + this.context.element.innerHTML = ''; + this.context.element.append(item); + this.event_shown(); + } + } + this.context.element.addEventListener('click', open); + } + enable(){ + + } + disable(){ + + } + hide(){ + this.event_hide(); + this.context.element.innerHTML = this.context.value; + setTimeout(() => { + this.init(); + this.event_hidden(); + }, 100); + } +} \ No newline at end of file diff --git a/src/Modes/PopupMode.js b/src/Modes/PopupMode.js new file mode 100644 index 0000000..c78d652 --- /dev/null +++ b/src/Modes/PopupMode.js @@ -0,0 +1,44 @@ +import BaseMode from "./BaseMode.js"; + +export default class PopupMode extends BaseMode{ + init(){ + this.popover = new bootstrap.Popover(this.context.element, { + container: "body", + content: this.context.route_type(), + html: true, + customClass: "dark-editable", + title: this.context.title, + }); + this.context.element.addEventListener('show.bs.popover', () => { + this.event_show(); + }); + this.context.element.addEventListener('shown.bs.popover', () => { + this.event_shown(); + }); + this.context.element.addEventListener('hide.bs.popover', () => { + this.event_hide(); + }); + this.context.element.addEventListener('hidden.bs.popover', () => { + this.event_hidden(); + }); + + document.addEventListener('click', (e) => { + const target = e.target; + if(target === this.popover.tip || target === this.context.element) return; + let current = target; + while(current = current.parentNode){ + if(current === this.popover.tip) return; + } + this.hide(); + }) + } + enable(){ + this.popover.enable(); + } + disable(){ + this.popover.disable(); + } + hide(){ + this.popover.hide(); + } +} \ No newline at end of file diff --git a/src/dark-editable.js b/src/dark-editable.js index 41a9275..d8ee0a7 100644 --- a/src/dark-editable.js +++ b/src/dark-editable.js @@ -1,15 +1,27 @@ import "./dark-editable.css"; +import PopupMode from "./Modes/PopupMode.js"; +import InlineMode from "./Modes/InlineMode.js"; export default class DarkEditable{ + modeElement = null; constructor(element, options = {}){ this._element = { element: null, form: null, load: null, buttons: {success: null, cancel: null}} this.element = element; this.options = options; this.init_options(); - this.init_popover(); + switch (this.mode){ + default: + throw new Error(`Mode ${this.mode} not found!`) + case 'popup': + this.modeElement = new PopupMode(this); + break; + case 'inline': + this.modeElement = new InlineMode(this); + break; + } + this.modeElement.init(); this.init_text(); - this.init_hide_onclick(); this.init_style(); if(this.disabled){ this.disable(); @@ -25,10 +37,10 @@ export default class DarkEditable{ } const get_opt_bool = (name, default_value) => { get_opt(name, default_value); - if(typeof this[ name ] != "boolean"){ - if(this[ name ] == "true") { + if(typeof this[ name ] !== "boolean"){ + if(this[ name ] === "true") { this[ name ] = true; - } else if(this[ name ] == "false") { + } else if(this[ name ] === "false") { this[ name ] = false; } else { this[ name ] = default_value; @@ -43,6 +55,7 @@ export default class DarkEditable{ get_opt("title", ""); get_opt("type", "text"); get_opt("emptytext", "Empty"); + get_opt("mode", "popup"); get_opt("url", null); get_opt("ajaxOptions", {}); this.ajaxOptions = Object.assign({ @@ -61,7 +74,7 @@ export default class DarkEditable{ switch(this.type){ case "select": get_opt("source", []); - if(typeof this.source == "string" && this.source != ""){ + if(typeof this.source == "string" && this.source !== ""){ this.source = JSON.parse(this.source); } break; @@ -84,7 +97,7 @@ export default class DarkEditable{ let empty = true; switch(this.type){ default: - if(this.value == ""){ + if(this.value === ""){ this.element.innerHTML = this.emptytext; } else { this.element.innerHTML = this.value; @@ -93,7 +106,7 @@ export default class DarkEditable{ break; case "select": this.element.innerHTML = this.emptytext; - if(this.value != "" && this.source.length > 0){ + if(this.value !== "" && this.source.length > 0){ this.source.forEach(item => { if(item.value == this.value){ this.element.innerHTML = item.text; @@ -104,7 +117,7 @@ export default class DarkEditable{ break; case "date": case "datetime": - if(this.value == ""){ + if(this.value === ""){ this.element.innerHTML = this.emptytext; } else { this.element.innerHTML = moment(this.value).format(this.viewformat); @@ -121,42 +134,6 @@ export default class DarkEditable{ this.element.classList.add("dark-editable-element"); } - init_hide_onclick(){ - document.addEventListener('click', (e) => { - const target = e.target; - if(target === this.popover.tip || target == this.element) return; - let current = target; - while(current = current.parentNode){ - if(current === this.popover.tip) return; - } - this.popover.hide(); - }) - } - - init_popover(){ - this.popover = new bootstrap.Popover(this.element, { - container: "body", - content: this.route_type(), - html: true, - customClass: "dark-editable", - title: this.title, - }); - this.element.addEventListener('show.bs.popover', () => { - this._element.element.value = this.value; - this.hideError(); - this.element.dispatchEvent(new CustomEvent("show")); - }); - this.element.addEventListener('shown.bs.popover', () => { - this.element.dispatchEvent(new CustomEvent("shown")); - }); - this.element.addEventListener('hide.bs.popover', () => { - this.element.dispatchEvent(new CustomEvent("hide")); - }); - this.element.addEventListener('hidden.bs.popover', () => { - this.element.dispatchEvent(new CustomEvent("hidden")); - }); - } - /* INIT METHODS END */ route_type(){ @@ -239,7 +216,7 @@ export default class DarkEditable{ /* ADD FOCUS */ add_focus(element){ - this.element.addEventListener('shown.bs.popover', function(){ + this.element.addEventListener('shown', function(){ element.focus(); }); } @@ -270,7 +247,9 @@ export default class DarkEditable{ } hideError(){ - this._element.error.style.display = "none"; + if(this._element.error){ + this._element.error.style.display = "none"; + } } /* DIV ERROR END */ @@ -326,13 +305,13 @@ export default class DarkEditable{ this.setError(null); this.hideError(); this.value = element.value; - this.popover.hide(); + this.modeElement.hide(); this.init_text(); } this.load(false); } else { this.value = element.value; - this.popover.hide(); + this.modeElement.hide(); this.init_text(); } this.element.dispatchEvent(new CustomEvent("save")); @@ -383,7 +362,7 @@ export default class DarkEditable{ div.innerHTML = "✖"; btn_cancel.append(div); btn_cancel.addEventListener("click", () => { - this.popover.hide(); + this.modeElement.hide(); }); return btn_cancel; } @@ -423,13 +402,14 @@ export default class DarkEditable{ enable(){ this.disabled = false; this.element.classList.remove("dark-editable-element-disabled"); - this.popover.enable(); + this.modeElement.enable(); + } disable(){ this.disabled = true; this.element.classList.add("dark-editable-element-disabled"); - this.popover.disable(); + this.modeElement.enable(); } setValue(value){