ultimate_turbo_modal
Version:
The ultimate Turbo / Stimulus / Hotwire modal window for Rails
2 lines (1 loc) • 12.1 kB
JavaScript
import{Controller as e}from"@hotwired/stimulus";async function t(e,t,r){const i=t.dataset,a=r?`${r}-${e}`:e;let s=`transition${e.charAt(0).toUpperCase()+e.slice(1)}`;const d=i[s]?i[s].split(" "):[a],l=i[`${s}Start`]?i[`${s}Start`].split(" "):[`${a}-start`],c=i[`${s}End`]?i[`${s}End`].split(" "):[`${a}-end`];n(t,d),n(t,l),await new Promise((e=>{requestAnimationFrame((()=>{requestAnimationFrame(e)}))})),o(t,l),n(t,c),await function(e){return new Promise((t=>{const n=getComputedStyle(e).transitionDuration.split(",")[0],o=1e3*Number(n.replace("s",""));setTimeout((()=>{t()}),o)}))}(t),o(t,c),o(t,d)}function n(e,t){e.classList.add(...t)}function o(e,t){e.classList.remove(...t)}const r="2.0.4";class i extends e{static targets=["container","content"];static values={advanceUrl:String,allowedClickOutsideSelector:String};connect(){let e=this;this.#e(),this.showModal(),this.turboFrame=this.element.closest("turbo-frame"),window.addEventListener("popstate",(function(t){e.#t()&&e.#n()})),window.modal=this}disconnect(){window.modal=void 0}showModal(){!async function(e,n=null){e.classList.remove("hidden"),await t("enter",e,n)}(this.containerTarget),this.advanceUrlValue&&!this.#t()&&(this.#o(),history.pushState({},"",this.advanceUrlValue))}hideModal(){if(this.hidingModal)return;this.hidingModal=!0;let e=new Event("modal:closing",{cancelable:!0});this.turboFrame.dispatchEvent(e),e.defaultPrevented||(this.#n(),e=new Event("modal:closed",{cancelable:!1}),this.turboFrame.dispatchEvent(e),this.#t()&&history.back())}hide(){this.hideModal()}refreshPage(){window.Turbo.visit(window.location.href,{action:"replace"})}submitEnd(e){e.detail.success&&this.hideModal()}closeWithKeyboard(e){"Escape"==e.code&&this.hideModal()}outsideModalClicked(e){let t=!document.contains(e.target)||this.contentTarget.contains(e.target)||this.contentTarget==e.target,n=this.allowedClickOutsideSelectorValue&&""!==this.allowedClickOutsideSelectorValue&&null!=e.target.closest(this.allowedClickOutsideSelectorValue);t||n||this.hideModal()}#n(){(async function(e,n=null){await t("leave",e,n),e.classList.add("hidden")})(this.containerTarget).then((()=>{this.turboFrame.removeAttribute("src"),this.containerTarget.remove(),this.#r()}))}#t(){return"true"==document.body.getAttribute("data-turbo-modal-history-advanced")}#o(){return document.body.setAttribute("data-turbo-modal-history-advanced","true")}#r(){document.body.removeAttribute("data-turbo-modal-history-advanced")}#e(){const e=this.element.dataset.utmrVersion;e&&e!==r&&console.warn(`[UltimateTurboModal] Version Mismatch!\n\nGem Version: ${e}\nJS Version: ${r}\n\nPlease ensure both the 'ultimate_turbo_modal' gem and the 'ultimate-turbo-modal' npm package are updated to the same version.\nElement:`,this.element)}}var a=function(){const e=()=>{},t={morphStyle:"outerHTML",callbacks:{beforeNodeAdded:e,afterNodeAdded:e,beforeNodeMorphed:e,afterNodeMorphed:e,beforeNodeRemoved:e,afterNodeRemoved:e,beforeAttributeUpdated:e},head:{style:"merge",shouldPreserve:e=>"true"===e.getAttribute("im-preserve"),shouldReAppend:e=>"true"===e.getAttribute("im-re-append"),shouldRemove:e,afterHeadMorphed:e},restoreFocus:!0};const n=function(){function e(e,t,n,r){if(!1===r.callbacks.beforeNodeAdded(t))return null;if(r.idMap.has(t)){const i=document.createElement(t.tagName);return e.insertBefore(i,n),o(i,t,r),r.callbacks.afterNodeAdded(i),i}{const o=document.importNode(t,!0);return e.insertBefore(o,n),r.callbacks.afterNodeAdded(o),o}}const t=function(){function e(e,t,n){let o=e.idMap.get(t),r=e.idMap.get(n);if(!r||!o)return!1;for(const e of o)if(r.has(e))return!0;return!1}function t(e,t){const n=e,o=t;return n.nodeType===o.nodeType&&n.tagName===o.tagName&&(!n.id||n.id===o.id)}return function(n,o,r,i){let a=null,s=o.nextSibling,d=0,l=r;for(;l&&l!=i;){if(t(l,o)){if(e(n,l,o))return l;null===a&&(n.idMap.has(l)||(a=l))}if(null===a&&s&&t(l,s)&&(d++,s=s.nextSibling,d>=2&&(a=void 0)),l.contains(document.activeElement))break;l=l.nextSibling}return a||null}}();function n(e,t){if(e.idMap.has(t))a(e.pantry,t,null);else{if(!1===e.callbacks.beforeNodeRemoved(t))return;t.parentNode?.removeChild(t),e.callbacks.afterNodeRemoved(t)}}function r(e,t,o){let r=t;for(;r&&r!==o;){let t=r;r=r.nextSibling,n(e,t)}return r}function i(e,t,n,o){const r=o.target.id===t&&o.target||o.target.querySelector(`[id="${t}"]`)||o.pantry.querySelector(`[id="${t}"]`);return function(e,t){const n=e.id;for(;e=e.parentNode;){let o=t.idMap.get(e);o&&(o.delete(n),o.size||t.idMap.delete(e))}}(r,o),a(e,r,n),r}function a(e,t,n){if(e.moveBefore)try{e.moveBefore(t,n)}catch(o){e.insertBefore(t,n)}else e.insertBefore(t,n)}return function(a,s,d,l=null,c=null){s instanceof HTMLTemplateElement&&d instanceof HTMLTemplateElement&&(s=s.content,d=d.content),l||=s.firstChild;for(const n of d.childNodes){if(l&&l!=c){const e=t(a,n,l,c);if(e){e!==l&&r(a,l,e),o(e,n,a),l=e.nextSibling;continue}}if(n instanceof Element&&a.persistentIds.has(n.id)){const e=i(s,n.id,l,a);o(e,n,a),l=e.nextSibling;continue}const d=e(s,n,l,a);d&&(l=d.nextSibling)}for(;l&&l!=c;){const e=l;l=l.nextSibling,n(a,e)}}}(),o=function(){function e(e,n,o,r){const i=n[o];if(i!==e[o]){const a=t(o,e,"update",r);a||(e[o]=n[o]),i?a||e.setAttribute(o,""):t(o,e,"remove",r)||e.removeAttribute(o)}}function t(e,t,n,o){return!("value"!==e||!o.ignoreActiveValue||t!==document.activeElement)||!1===o.callbacks.beforeAttributeUpdated(e,t,n)}function o(e,t){return!!t.ignoreActiveValue&&e===document.activeElement&&e!==document.body}return function(i,a,s){return s.ignoreActive&&i===document.activeElement?null:(!1===s.callbacks.beforeNodeMorphed(i,a)||(i instanceof HTMLHeadElement&&s.head.ignore||(i instanceof HTMLHeadElement&&"morph"!==s.head.style?r(i,a,s):(!function(n,r,i){let a=r.nodeType;if(1===a){const a=n,s=r,d=a.attributes,l=s.attributes;for(const e of l)t(e.name,a,"update",i)||a.getAttribute(e.name)!==e.value&&a.setAttribute(e.name,e.value);for(let e=d.length-1;0<=e;e--){const n=d[e];if(n&&!s.hasAttribute(n.name)){if(t(n.name,a,"remove",i))continue;a.removeAttribute(n.name)}}o(a,i)||function(n,o,r){if(n instanceof HTMLInputElement&&o instanceof HTMLInputElement&&"file"!==o.type){let i=o.value,a=n.value;e(n,o,"checked",r),e(n,o,"disabled",r),o.hasAttribute("value")?a!==i&&(t("value",n,"update",r)||(n.setAttribute("value",i),n.value=i)):t("value",n,"remove",r)||(n.value="",n.removeAttribute("value"))}else if(n instanceof HTMLOptionElement&&o instanceof HTMLOptionElement)e(n,o,"selected",r);else if(n instanceof HTMLTextAreaElement&&o instanceof HTMLTextAreaElement){let e=o.value,i=n.value;if(t("value",n,"update",r))return;e!==i&&(n.value=e),n.firstChild&&n.firstChild.nodeValue!==e&&(n.firstChild.nodeValue=e)}}(a,s,i)}8!==a&&3!==a||n.nodeValue!==r.nodeValue&&(n.nodeValue=r.nodeValue)}(i,a,s),o(i,s)||n(s,i,a))),s.callbacks.afterNodeMorphed(i,a)),i)}}();function r(e,t,n){let o=[],r=[],i=[],a=[],s=new Map;for(const e of t.children)s.set(e.outerHTML,e);for(const t of e.children){let e=s.has(t.outerHTML),o=n.head.shouldReAppend(t),d=n.head.shouldPreserve(t);e||d?o?r.push(t):(s.delete(t.outerHTML),i.push(t)):"append"===n.head.style?o&&(r.push(t),a.push(t)):!1!==n.head.shouldRemove(t)&&r.push(t)}a.push(...s.values());let d=[];for(const t of a){let r=document.createRange().createContextualFragment(t.outerHTML).firstChild;if(!1!==n.callbacks.beforeNodeAdded(r)){if("href"in r&&r.href||"src"in r&&r.src){let e,t=new Promise((function(t){e=t}));r.addEventListener("load",(function(){e()})),d.push(t)}e.appendChild(r),n.callbacks.afterNodeAdded(r),o.push(r)}}for(const t of r)!1!==n.callbacks.beforeNodeRemoved(t)&&(e.removeChild(t),n.callbacks.afterNodeRemoved(t));return n.head.afterHeadMorphed(e,{added:o,kept:i,removed:r}),d}const i=function(){function e(){const e=document.createElement("div");return e.hidden=!0,document.body.insertAdjacentElement("afterend",e),e}function n(e){let t=Array.from(e.querySelectorAll("[id]"));return e.id&&t.push(e),t}function o(e,t,n,o){for(const r of o)if(t.has(r.id)){let t=r;for(;t;){let o=e.get(t);if(null==o&&(o=new Set,e.set(t,o)),o.add(r.id),t===n)break;t=t.parentElement}}}return function(r,i,a){const{persistentIds:s,idMap:d}=function(e,t){const r=n(e),i=n(t),a=function(e,t){let n=new Set,o=new Map;for(const{id:t,tagName:r}of e)o.has(t)?n.add(t):o.set(t,r);let r=new Set;for(const{id:e,tagName:i}of t)r.has(e)?n.add(e):o.get(e)===i&&r.add(e);for(const e of n)r.delete(e);return r}(r,i);let s=new Map;o(s,a,e,r);const d=t.__idiomorphRoot||t;return o(s,a,d,i),{persistentIds:a,idMap:s}}(r,i),l=function(e){let n=Object.assign({},t);return Object.assign(n,e),n.callbacks=Object.assign({},t.callbacks,e.callbacks),n.head=Object.assign({},t.head,e.head),n}(a),c=l.morphStyle||"outerHTML";if(!["innerHTML","outerHTML"].includes(c))throw`Do not understand how to morph style ${c}`;return{target:r,newContent:i,config:l,morphStyle:c,ignoreActive:l.ignoreActive,ignoreActiveValue:l.ignoreActiveValue,restoreFocus:l.restoreFocus,idMap:d,persistentIds:s,pantry:e(),callbacks:l.callbacks,head:l.head}}}(),{normalizeElement:a,normalizeParent:s}=function(){const e=new WeakSet;class t{constructor(e){this.originalNode=e,this.realParentNode=e.parentNode,this.previousSibling=e.previousSibling,this.nextSibling=e.nextSibling}get childNodes(){const e=[];let t=this.previousSibling?this.previousSibling.nextSibling:this.realParentNode.firstChild;for(;t&&t!=this.nextSibling;)e.push(t),t=t.nextSibling;return e}querySelectorAll(e){return this.childNodes.reduce(((t,n)=>{if(n instanceof Element){n.matches(e)&&t.push(n);const o=n.querySelectorAll(e);for(let e=0;e<o.length;e++)t.push(o[e])}return t}),[])}insertBefore(e,t){return this.realParentNode.insertBefore(e,t)}moveBefore(e,t){return this.realParentNode.moveBefore(e,t)}get __idiomorphRoot(){return this.originalNode}}return{normalizeElement:function(e){return e instanceof Document?e.documentElement:e},normalizeParent:function n(o){if(null==o)return document.createElement("div");if("string"==typeof o)return n(function(t){let n=new DOMParser,o=t.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");if(o.match(/<\/html>/)||o.match(/<\/head>/)||o.match(/<\/body>/)){let r=n.parseFromString(t,"text/html");if(o.match(/<\/html>/))return e.add(r),r;{let t=r.firstChild;return t&&e.add(t),t}}{let o=n.parseFromString("<body><template>"+t+"</template></body>","text/html").body.querySelector("template").content;return e.add(o),o}}(o));if(e.has(o))return o;if(o instanceof Node){if(o.parentNode)return new t(o);{const e=document.createElement("div");return e.append(o),e}}{const e=document.createElement("div");for(const t of[...o])e.append(t);return e}}}}();return{morph:function(e,t,o={}){e=a(e);const d=s(t),l=i(e,d,o),c=function(e,t){if(!e.config.restoreFocus)return t();let n=document.activeElement;if(!(n instanceof HTMLInputElement||n instanceof HTMLTextAreaElement))return t();const{id:o,selectionStart:r,selectionEnd:i}=n,a=t();o&&o!==document.activeElement?.id&&(n=e.target.querySelector(`[id="${o}"]`),n?.focus());n&&!n.selectionEnd&&i&&n.setSelectionRange(r,i);return a}(l,(()=>function(e,t,n,o){if(e.head.block){const i=t.querySelector("head"),a=n.querySelector("head");if(i&&a){const t=r(i,a,e);return Promise.all(t).then((()=>{const t=Object.assign(e,{head:{block:!1,ignore:!0}});return o(t)}))}}return o(e)}(l,e,d,(t=>"innerHTML"===t.morphStyle?(n(t,e,d),Array.from(e.childNodes)):function(e,t,o){const r=s(t);return n(e,r,o,t,t.nextSibling),Array.from(r.childNodes)}(t,e,d)))));return l.pantry.remove(),c},defaults:t}}();Turbo.StreamActions.modal=function(){const e=this.getAttribute("message");"hide"==e&&window.modal?.hide(),"close"==e&&window.modal?.hide()};const s=e=>{e.detail.response.redirected&&e.target==document.querySelector("turbo-frame#modal")&&(e.preventDefault(),e.detail.visit(e.detail.response))},d=e=>{"modal"===e.target.id&&(e.detail.render=(e,t)=>{a.morph(e,t,{morphstyle:"innerHTML"})})};document.removeEventListener("turbo:frame-missing",s),document.addEventListener("turbo:frame-missing",s),document.removeEventListener("turbo:before-frame-render",d),document.addEventListener("turbo:before-frame-render",d);export{i as UltimateTurboModalController};