mirror of
https://github.com/php-flasher/php-flasher.git
synced 2026-03-31 15:07:47 +01:00
2 lines
11 KiB
JavaScript
2 lines
11 KiB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).flasher=t()}(this,(function(){"use strict";function e(e,t,s,n){return new(s||(s=Promise))((function(r,o){function i(e){try{a(n.next(e))}catch(e){o(e)}}function l(e){try{a(n.throw(e))}catch(e){o(e)}}function a(e){var t;e.done?r(e.value):(t=e.value,t instanceof s?t:new s((function(e){e(t)}))).then(i,l)}a((n=n.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;class t{success(e,t,s){this.flash("success",e,t,s)}error(e,t,s){this.flash("error",e,t,s)}info(e,t,s){this.flash("info",e,t,s)}warning(e,t,s){this.flash("warning",e,t,s)}flash(e,t,s,n){let r,o,i,l={};if("object"==typeof e?(l=Object.assign({},e),r=l.type,o=l.message,i=l.title,delete l.type,delete l.message,delete l.title):"object"==typeof t?(l=Object.assign({},t),r=e,o=l.message,i=l.title,delete l.message,delete l.title):(r=e,o=t,null==s?(i=void 0,l=n||{}):"string"==typeof s?(i=s,l=n||{}):"object"==typeof s&&(l=Object.assign({},s),"title"in l?(i=l.title,delete l.title):i=void 0,n&&"object"==typeof n&&(l=Object.assign(Object.assign({},l),n)))),!r)throw new Error("Type is required for notifications");if(null==o)throw new Error("Message is required for notifications");null==i&&(i=r.charAt(0).toUpperCase()+r.slice(1));const a={type:r,message:o,title:i,options:l,metadata:{plugin:""}};this.renderOptions({}),this.renderEnvelopes([a])}}class s extends t{constructor(e){if(super(),this.options={timeout:null,timeouts:{success:1e4,info:1e4,error:1e4,warning:1e4},fps:30,position:"top-right",direction:"top",rtl:!1,style:{},escapeHtml:!1},!e)throw new Error("Theme is required");if("function"!=typeof e.render)throw new TypeError("Theme must have a render function");this.theme=e}renderEnvelopes(e){if(!(null==e?void 0:e.length))return;const t=()=>{e.forEach((e=>{var t,s,n,r;try{const o=null!==(s=null!==(t=this.options.timeout)&&void 0!==t?t:this.options.timeouts[e.type])&&void 0!==s?s:1e4,i=Object.assign(Object.assign(Object.assign({},this.options),e.options),{timeout:this.normalizeTimeout(null!==(n=e.options.timeout)&&void 0!==n?n:o),escapeHtml:null!==(r=e.options.escapeHtml)&&void 0!==r?r:this.options.escapeHtml}),l=this.createContainer(i),a={direction:i.direction,timeout:Number(i.timeout||0),fps:i.fps,rtl:i.rtl,escapeHtml:i.escapeHtml};this.addToContainer(l,e,a)}catch(t){console.error("PHPFlasher: Error rendering envelope",t,e)}}))};if("loading"===document.readyState){const e=()=>{document.removeEventListener("DOMContentLoaded",e),t()};document.addEventListener("DOMContentLoaded",e)}else t()}renderOptions(e){e&&(this.options=Object.assign(Object.assign({},this.options),e))}createContainer(e){let t=document.querySelector(`.fl-wrapper[data-position="${e.position}"]`);return t||(t=document.createElement("div"),t.className="fl-wrapper",t.dataset.position=e.position,Object.entries(e.style).forEach((([e,s])=>{if(null!=s){const n=e.replace(/([A-Z])/g,"-$1").toLowerCase();t.style.setProperty(n,String(s))}})),document.body.appendChild(t)),t.dataset.turboTemporary="",t}addToContainer(e,t,s){s.escapeHtml&&(t.title=this.escapeHtml(t.title),t.message=this.escapeHtml(t.message));const n=this.stringToHTML(this.theme.render(t));n.classList.add("fl-container"),s.rtl&&n.classList.add("fl-rtl"),"bottom"===s.direction?e.append(n):e.prepend(n),requestAnimationFrame((()=>n.classList.add("fl-show")));const r=n.querySelector(".fl-close");if(r&&r.addEventListener("click",(e=>{e.stopPropagation(),this.removeNotification(n)})),n.addEventListener("click",(e=>{e.target.closest(".fl-close")||this.dispatchClickEvents(t)})),s.timeout>0)this.addTimer(n,s);else{n.classList.add("fl-sticky");const e=n.querySelector(".fl-progress-bar");if(e){const t=document.createElement("span");t.classList.add("fl-progress","fl-sticky-progress"),t.style.width="100%",e.append(t)}}}normalizeTimeout(e){return!1===e||"number"==typeof e&&e<0||null==e?0:Number(e)||0}addTimer(e,{timeout:t,fps:s}){if(t<=0)return;const n=1e3/s;let r,o=0;const i=()=>{o+=n;const s=e.querySelector(".fl-progress-bar");if(s){let e=s.querySelector(".fl-progress");e||(e=document.createElement("span"),e.classList.add("fl-progress"),s.append(e));const n=100*(1-o/t);e.style.width=`${Math.max(0,n)}%`}o>=t&&(clearInterval(r),this.removeNotification(e))};r=window.setInterval(i,n);const l=()=>{clearInterval(r),r=window.setInterval(i,n)},a=()=>clearInterval(r);e.addEventListener("mouseout",l),e.addEventListener("mouseover",a),e._flasherCleanup=()=>{clearInterval(r),e.removeEventListener("mouseout",l),e.removeEventListener("mouseover",a)}}removeNotification(e){e&&(e._flasherCleanup&&(e._flasherCleanup(),delete e._flasherCleanup),e.classList.remove("fl-show"),e.ontransitionend=()=>{const t=e.parentElement;e.remove(),t&&!t.hasChildNodes()&&t.remove()})}stringToHTML(e){const t=document.createElement("template");t.innerHTML=e.trim();const s=t.content.firstElementChild;if(!s)throw new Error("PHPFlasher: Invalid HTML template - no element found");return s}escapeHtml(e){if(null==e)return"";const t={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`","=":"=","/":"/"};return e.replace(/[&<>"'`=/]/g,(e=>t[e]||e))}dispatchClickEvents(e){const t={envelope:e};window.dispatchEvent(new CustomEvent("flasher:theme:click",{detail:t}));const s=this.getThemeName(e);s&&window.dispatchEvent(new CustomEvent(`flasher:theme:${s}:click`,{detail:t}))}getThemeName(e){var t;const s=(null===(t=e.metadata)||void 0===t?void 0:t.plugin)||"";return s.startsWith("theme.")?s.replace("theme.",""):"flasher"===s?"flasher":s}}const n="fl-content",r="fl-message",o="fl-title",i="fl-icon",l="fl-close",a="fl-progress-bar",c="fl-progress",d=e=>`fl-${e}`,u=e=>`fl-${e}`,p={success:"Success",error:"Error",warning:"Warning",info:"Information"};const h={render:e=>{const{type:t,title:s,message:h}=e,f=function(e,t){return e||p[t]||function(e){return e.charAt(0).toUpperCase()+e.slice(1)}(t)}(s,t);return`\n <div class="${u("flasher")} ${d(t)}" ${function(e){const t=function(e){const t="error"===e||"warning"===e;return{role:t?"alert":"status",ariaLive:t?"assertive":"polite",ariaAtomic:"true"}}(e);return`role="${t.role}" aria-live="${t.ariaLive}" aria-atomic="${t.ariaAtomic}"`}(t)}>\n <div class="${n}">\n <div class="${i}"></div>\n <div>\n <strong class="${o}">${f}</strong>\n <span class="${r}">${h}</span>\n </div>\n <button class="${l}" ${function(e){return`aria-label="Close ${e} message"`}(t)}>×</button>\n </div>\n <span class="${a}">\n <span class="${c}"></span>\n </span>\n </div>`}},f=new class extends t{constructor(){super(...arguments),this.defaultPlugin="flasher",this.plugins=new Map,this.themes=new Map,this.loadedAssets=new Set}render(t){return e(this,void 0,void 0,(function*(){const e=this.resolveResponse(t);try{yield this.addAssets([{urls:e.styles,nonce:e.context.csp_style_nonce,type:"style"},{urls:e.scripts,nonce:e.context.csp_script_nonce,type:"script"}]),this.renderOptions(e.options),this.renderEnvelopes(e.envelopes)}catch(e){console.error("PHPFlasher: Error rendering notifications",e)}}))}renderEnvelopes(e){if(!(null==e?void 0:e.length))return;const t={};e.forEach((e=>{const s=this.resolvePluginAlias(e.metadata.plugin);t[s]=t[s]||[],t[s].push(e)})),Object.entries(t).forEach((([e,t])=>{try{this.use(e).renderEnvelopes(t)}catch(t){console.error(`PHPFlasher: Error rendering envelopes for plugin "${e}"`,t)}}))}renderOptions(e){e&&Object.entries(e).forEach((([e,t])=>{try{this.use(e).renderOptions(t)}catch(t){console.error(`PHPFlasher: Error applying options for plugin "${e}"`,t)}}))}addPlugin(e,t){if(!e||!t)throw new Error("Both plugin name and instance are required");this.plugins.set(e,t)}addTheme(e,t){if(!e||!t)throw new Error("Both theme name and definition are required");this.themes.set(e,t)}use(e){const t=this.resolvePluginAlias(e);this.resolvePlugin(t);const s=this.plugins.get(t);if(!s)throw new Error(`Unable to resolve "${t}" plugin, did you forget to register it?`);return s}create(e){return this.use(e)}resolveResponse(e){const t=Object.assign({envelopes:[],options:{},scripts:[],styles:[],context:{}},e);return Object.entries(t.options).forEach((([e,s])=>{t.options[e]=this.resolveOptions(s)})),t.context.csp_style_nonce=t.context.csp_style_nonce||"",t.context.csp_script_nonce=t.context.csp_script_nonce||"",t.envelopes.forEach((e=>{e.metadata=e.metadata||{},e.metadata.plugin=this.resolvePluginAlias(e.metadata.plugin),this.addThemeStyles(t,e.metadata.plugin),e.options=this.resolveOptions(e.options),e.context=t.context})),t}resolveOptions(e){if(!e)return{};const t=Object.assign({},e);return Object.entries(t).forEach((([e,s])=>{t[e]=this.resolveFunction(s)})),t}resolveFunction(e){var t,s,n,r;if("string"!=typeof e)return e;const o=e.match(/^function\s*(\w*)\s*\(([^)]*)\)\s*\{([\s\S]*)\}$/),i=e.match(/^\s*(\(([^)]*)\)|[^=]+)\s*=>\s*([\s\S]+)$/);if(!o&&!i)return e;let l,a;o?(l=null!==(s=null===(t=o[2])||void 0===t?void 0:t.split(",").map((e=>e.trim())).filter(Boolean))&&void 0!==s?s:[],a=o[3].trim()):(l=null!==(r=null===(n=i[2])||void 0===n?void 0:n.split(",").map((e=>e.trim())).filter(Boolean))&&void 0!==r?r:[],a=i[3].trim(),a=a.startsWith("{")?a.slice(1,-1).trim():`return ${a};`);try{return new Function(...l,a)}catch(t){return console.error("PHPFlasher: Error converting string to function:",t),e}}resolvePlugin(e){if(this.plugins.get(e)||!e.includes("theme."))return;const t=e.replace("theme.",""),n=this.themes.get(t);n&&this.addPlugin(e,new s(n))}resolvePluginAlias(e){return"flasher"===(e=e||this.defaultPlugin)?"theme.flasher":e}addAssets(t){return e(this,void 0,void 0,(function*(){try{const e=t.filter((e=>"style"===e.type)),s=[];for(const{urls:t,nonce:n,type:r}of e)if(null==t?void 0:t.length)for(const e of t)e&&!this.loadedAssets.has(e)&&(s.push(this.loadAsset(e,n,r)),this.loadedAssets.add(e));yield Promise.all(s);const n=t.filter((e=>"script"===e.type));for(const{urls:e,nonce:t,type:s}of n)if(null==e?void 0:e.length)for(const n of e)n&&!this.loadedAssets.has(n)&&(yield this.loadAsset(n,t,s),this.loadedAssets.add(n))}catch(e){console.error("PHPFlasher: Error loading assets",e)}}))}loadAsset(e,t,s){const n="style"===s?`link[href="${e}"]`:`script[src="${e}"]`;return document.querySelector(n)?Promise.resolve():new Promise(((n,r)=>{const o=document.createElement("style"===s?"link":"script");"style"===s?(o.rel="stylesheet",o.href=e):(o.type="text/javascript",o.src=e),t&&o.setAttribute("nonce",t),o.onload=()=>n(),o.onerror=()=>r(new Error(`Failed to load ${e}`)),document.head.appendChild(o)}))}addThemeStyles(e,t){if("flasher"!==t&&!t.includes("theme."))return;const s=t.replace("theme.",""),n=this.themes.get(s);if(!(null==n?void 0:n.styles))return;const r=Array.isArray(n.styles)?n.styles:[n.styles];e.styles=Array.from(new Set([...e.styles,...r]))}};return f.addTheme("flasher",h),"undefined"!=typeof window&&(window.flasher=f),f}));
|