diff --git a/.gitignore b/.gitignore
index 671a5be..5b53730 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+/dist
+
# Caches
/node_modules
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..8e39a4c
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,13 @@
+.github/
+.husky/
+examples/
+node_modules/
+tests/
+.editorconfig
+.eslintignore
+.prettierignore
+mirlo.code-workspace
+mirlo.png
+package-lock.json
+rollup.config.mjs
+setup-jest.mjs
diff --git a/README.md b/README.md
index d09e8d7..3681a1b 100644
--- a/README.md
+++ b/README.md
@@ -54,9 +54,9 @@ app.registerComponent('demo01', Demo01);
### Available Services:
-- requests: Do HTTP operations
-- localStorage: Do local storage operations
-- sessionStorage: Do session storage operations
+- requests: HTTP operations (always included)
+- localStorage: Local storage operations
+- sessionStorage: Session storage operations
### Example
@@ -66,14 +66,12 @@ app.registerComponent('demo01', Demo01);
import {Component} from 'mirlo';
export default class Demo01 extends Component {
- useServices = ['requests'];
+ useServices = ['localStorage'];
onStart() {
super.onStart();
- this.dom_el.innerHTML = 'Hello World!';
- this.requests
- .postJSON('/demo01')
- .then(result => (this.dom_el.innerHTML = result));
+ const username = this.localStorage.getItem('username');
+ this.dom_el.innerHTML = `Hello ${username}!`;
}
}
```
diff --git a/dist/mirlo.mjs b/dist/mirlo.mjs
deleted file mode 100644
index 4074987..0000000
--- a/dist/mirlo.mjs
+++ /dev/null
@@ -1 +0,0 @@
-function e(e,t,s){document.querySelectorAll(t).forEach((t=>{t.addEventListener(e,s)}))}function t(e,t,s){document.querySelectorAll(t).forEach((t=>{t.removeEventListener(e,s)}))}function s(e){return Object.hasOwn(e,"mirlo")||(e.mirlo={}),e.mirlo}function o(e){const t=s(e);if(Object.hasOwn(t,"component_obj"))return t.component_obj}var r={component_obj:null,set(e,t,s){const o=typeof s;if(this.component_obj&&("string"===o||"number"===o)){this.component_obj.queryAll(`[data-component-state-binds*='${t}-']`).forEach((e=>{e.dataset.componentStateBinds.split(" ").forEach((o=>{const r=o.split("-");r[0]===t&&(1===r.length?e.textContent=s:"html"===r[1]?e.innerHTML=s:e.setAttribute(r[1],s))}))}))}return Reflect.set(...arguments)}};class i{useServices=[];fetchData={};data={};#e=null;#t=[];#s={};state=null;constructor(e,t,s){-1===this.useServices.indexOf("requests")&&this.useServices.push("requests"),this.options=s||{},this.setParent(e),this.setElement(t);const o=Object.assign({},r,{component_obj:this});this.state=new Proxy(this.#s,o)}onWillStart(){const e=[];for(const t in this.fetchData)e.push(this.requests.postJSON(this.fetchData[t].endpoint,this.fetchData[t].data).then((e=>(this.data[t]=e,e))));return Promise.all(e)}onStart(){for(const e in this.events){const[t,...s]=e.split(" "),o=s&&s.join(" ")||null;(o&&this.query(o)||this.dom_el).addEventListener(t,this.events[e].bind(this))}}remove(){this.dom_el.remove()}destroy(){this.#t=[];for(const e in this.events){const[t,...s]=e.split(" "),o=s&&s.join(" ")||null;(o&&this.query(o)||this.dom_el).removeEventListener(t,this.events[e].bind(this))}}setParent(e){this.#e=e,this.#e&&this.#e.addChildren(this)}getParent(){return this.#e}addChildren(e){this.#t.push(e)}removeChildren(e){this.#t=this.#t.filter((t=>t!==e))}setElement(e){this.dom_el=e}queryAll(e){return this.dom_el.querySelectorAll(e)}query(e){return this.dom_el.querySelector(e)}}const n=new class extends i{#o={components:{},services:{}};#r={};#i=null;constructor(e,t,s,o){super(e,t,s),this.__data=o}destroy(){super.destroy();const e=Object.values(this.#r);for(const t of e)t.destroy();this.#r=[],this.#i.disconnect(),t("click","[class~='dropdown']"),t("click","[data-dismiss]")}registerComponent(e,t){Object.hasOwn(this.#o.components,e)?console.warn(`Already exists a component called '${e}'!`):this.#o.components[e]=t}getComponentClass(e){return this.#o.components[e]}invokeComponent(e,...t){const s=this.getComponentClass(e);if(s){const e=new s(this,...t);this.#n(e),e.onWillStart().then((()=>{e.onStart()}))}else console.warn(`The component '${e}' don't exists!`)}registerService(e,t,s=!1){!Object.hasOwn(this.#o.services,e)||s?this.#o.services[e]=t:console.warn(`Already exists a service called '${e}'!`)}getServiceClass(e){return this.#o.services[e]}getService(e){return this.#r[e]}getComponentById(e){const t=this.query(`#${e}`);if(t)return o(t)}onWillStart(){return super.onWillStart().then((()=>this.#a())).then((()=>this.#c()))}onStart(){super.onStart(),this.#i=new MutationObserver(this.#l.bind(this)),this.#i.observe(document.body,{childList:!0,subtree:!0}),e("click","[class~='dropdown']",this.#h.bind(this)),e("click","[data-dismiss]",this.#d.bind(this))}#a(){for(const e in this.#o.services)this.#r[e]=new this.#o.services[e];const e=[],t=Object.keys(this.#r);for(const s of t){const t=this.#r[s];e.push(t.onWillStart())}return Promise.all(e)}#c(){const e=[],t=this.queryAll("[data-component]");for(const r of t){if(o(r))continue;const t=r.dataset.component,i=this.getComponentClass(t),n=r.closest("[data-component]"),a=n&&o(n),c={};if(Object.keys(r.dataset).forEach((e=>{if(e.startsWith("componentOption")){const t=e.replace(/^componentOption/,"").toLowerCase();c[t]=r.dataset[e]}})),i){const t=new i(a||this,r,c);this.#n(t);const o=s(r);Object.assign(o,{component_obj:t}),e.push(t.onWillStart().then((()=>t.onStart())))}else console.warn(`Can't found the '${t}' component!`,r)}return Promise.all(e)}#n(e){for(const t of e.useServices)e[t]=this.#r[t]}#l(e){let t=!1;const s=function(e){for(const t of e.childNodes)s(t);const t=o(e);t&&t.destroy()};e.forEach((e=>{if("childList"===e.type){e.addedNodes.length&&(t=!0);for(const t of e.removedNodes)s(t)}})),t&&this.#c()}#h(e){this.query(e.currentTarget.dataset.target).classList.toggle("hidden")}#d(e){const t=`.${e.currentTarget.datatset.dismiss}`;e.currentTarget.closest(t).remove()}}(null,document.body);class a{onWillStart(){return Promise.resolve()}destroy(){throw Error("Not Implemented!")}}class c extends a{storage=null;getItem(e){return this.storage&&JSON.parse(this.storage.getItem(e))||void 0}setItem(e,t,s){try{return this.storage.setItem(e,JSON.stringify(t))}catch(o){if(console.error(`[StorageService] Can't set the item '${e}' = '${t}'`),s){this.#u(o)&&s(o)}}return!1}removeItem(e){return this.storage&&this.storage.removeItem(e)||void 0}#u(e){return"QuotaExceededError"===e.name}}class l extends c{storage=localStorage}class h extends c{storage=sessionStorage}class d extends a{MESSAGES={e200:"200: Invalid server result!"};getHeaders(e){return e}async postJSON(e,t){const s=(await fetch(e,{method:"POST",mode:"same-origin",cache:"no-cache",credentials:"same-origin",headers:this.getHeaders({"Content-Type":"application/json"}),redirect:"follow",referrerPolicy:"same-origin",body:JSON.stringify(t)})).json();if(this.checkServerResult(s))return s;throw Error(this.MESSAGES.e200)}async post(e,t,s="default"){let o=!1;if("object"==typeof t){o=new URLSearchParams;for(const e in t)o.append(e,t[e])}else"string"==typeof t&&(o=t);const r=(await fetch(e,{method:"POST",mode:"same-origin",cache:s,credentials:"same-origin",headers:this.getHeaders({"Content-Type":"application/x-www-form-urlencoded"}),redirect:"follow",referrerPolicy:"same-origin",body:o})).json();if(this.checkServerResult(r))return r;throw Error(this.MESSAGES.e200)}async get(e,t="default"){return(await fetch(e,{method:"GET",mode:"same-origin",cache:t,credentials:"same-origin",headers:this.getHeaders(),redirect:"follow",referrerPolicy:"same-origin"})).blob()}checkServerResult(e){if(!e||void 0===e)return!0}}function u(e,t){Object.keys(t).forEach((s=>{e.setAttribute(s,t[s])}))}class m extends i{LAZY_ELEMENT_CLASS="lazy";getNormalizedAttributes(e,t=!1){const s={};return Object.keys(e.dataset).forEach((o=>{if(o.startsWith("lazy")){const r=o.replace(/^lazy/,"").toLowerCase(),i=e.getAttribute(r),n=e.dataset[o];i&&i===n||(s[r]=n,t&&e.removeAttribute(o))}})),s}applyLazyAttributes(e){e.removeClass(this.LAZY_ELEMENT_CLASS);const t=this.getNormalizedAttributes(e,!0);if(e?.dataset.createTag){const s=document.createElement(e.dataset.createTag);u(s,t),e.replaceWith(s)}else u(e,t)}getLazyElements(){return this.queryAll(`.${this.LAZY_ELEMENT_CLASS}`)}}class p extends m{events={[`click .${this.LAZY_ELEMENT_CLASS}`]:this.#m};#m(e){this.applyLazyAttributes(e.currentTarget)}}class f extends m{events={scroll:this.#p};constructor(){super(...arguments),Object.assign(this.options,{bounce_time_scroll:75,zone_y_offset:150,zone_x_offset:75},this.options),this.load=function(e,t=300){let s=null;return(...o)=>{clearTimeout(s),s=setTimeout((()=>{e.apply(this,o)}),t)}}(this.#f.bind(this),this.options.bounce_time_scroll)}onStart(){super.onStart(),this.#f()}#f(){this.getLazyElements().forEach((e=>{this.#g(e)&&this.applyLazyAttributes(e)}))}#y(e){const t=e.offset(),s=t.left,o=t.top;return[s,o,s+e.width(),o+e.height()]}#g(e){let[t,s,o,r]=this.#y(this.dom_el);t-=this.options.zone_x_offset,s-=this.options.zone_y_offset,o+=this.options.zone_x_offset,r+=this.options.zone_y_offset;const[i,n,a,c]=this.#y(e);return i<=o&&n<=r&&a>=t&&c>=s}#p(){this.load()}}n.registerService("requests",d),n.registerService("localStorage",l),n.registerService("sessionStorage",h),n.registerComponent("lazyClick",p),n.registerComponent("lazyScroll",f),window.addEventListener("load",(()=>{n.onWillStart().then((()=>{n.onStart()}))}));export{i as Component,p as LazyClickComponent,f as LazyScrollComponent,l as LocalStorageService,d as RequestsService,a as Service,h as SessionStorageService,n as default};
diff --git a/src/js/components/lazy.mjs b/examples/components/lazy.mjs
similarity index 81%
rename from src/js/components/lazy.mjs
rename to examples/components/lazy.mjs
index c1727fd..3e43639 100644
--- a/src/js/components/lazy.mjs
+++ b/examples/components/lazy.mjs
@@ -1,5 +1,5 @@
-import domSetAttributes from '../utils/dom_set_attributes';
-import Component from '../base/component';
+import $ from 'jquery-slim';
+import {Component} from 'mirlo';
export default class LazyComponent extends Component {
LAZY_ELEMENT_CLASS = 'lazy';
@@ -29,11 +29,10 @@ export default class LazyComponent extends Component {
dom_el.removeClass(this.LAZY_ELEMENT_CLASS);
const attrs = this.getNormalizedAttributes(dom_el, true);
if (dom_el?.dataset.createTag) {
- const new_dom_elm = document.createElement(dom_el.dataset.createTag);
- domSetAttributes(new_dom_elm, attrs);
+ const new_dom_elm = $(`<${dom_el.dataset.createTag}>`, attrs);
dom_el.replaceWith(new_dom_elm);
} else {
- domSetAttributes(dom_el, attrs);
+ $(dom_el).attr(attrs);
}
}
diff --git a/src/js/components/lazy_click.mjs b/examples/components/lazy_click.mjs
similarity index 100%
rename from src/js/components/lazy_click.mjs
rename to examples/components/lazy_click.mjs
diff --git a/src/js/components/lazy_scroll.mjs b/examples/components/lazy_scroll.mjs
similarity index 93%
rename from src/js/components/lazy_scroll.mjs
rename to examples/components/lazy_scroll.mjs
index 22eefa1..1bd5046 100644
--- a/src/js/components/lazy_scroll.mjs
+++ b/examples/components/lazy_scroll.mjs
@@ -1,4 +1,4 @@
-import debounce from '../utils/debounce';
+import $ from 'jquery-slim';
import LazyComponent from './lazy';
export default class LazyScrollComponent extends LazyComponent {
@@ -17,7 +17,7 @@ export default class LazyScrollComponent extends LazyComponent {
},
this.options,
);
- this.load = debounce(
+ this.load = $.debounce(
this.#doLazyLoad.bind(this),
this.options.bounce_time_scroll,
);
@@ -37,7 +37,8 @@ export default class LazyScrollComponent extends LazyComponent {
});
}
- #getDimensions($elm) {
+ #getDimensions(dom_el) {
+ const $elm = $(dom_el);
const $offset = $elm.offset();
const left = $offset.left;
const top = $offset.top;
diff --git a/package.json b/package.json
index f199d28..bd81da1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mirlo",
- "version": "0.0.3",
+ "version": "0.1.0",
"type": "module",
"keywords": [
"initiator",
diff --git a/src/js/mirlo.mjs b/src/js/mirlo.mjs
index 4348bcc..ab5fee5 100644
--- a/src/js/mirlo.mjs
+++ b/src/js/mirlo.mjs
@@ -1,4 +1,4 @@
-// Copyright (C) 2022 Alexandre Díaz
+// Copyright (C) 2024 Alexandre D. Díaz
import {app} from './base/app';
import Component from './base/component';
import Service from './base/service';
@@ -6,16 +6,10 @@ import Service from './base/service';
import {LocalStorageService, SessionStorageService} from './services/storage';
import RequestsService from './services/requests';
-import LazyClickComponent from './components/lazy_click';
-import LazyScrollComponent from './components/lazy_scroll';
-
app.registerService('requests', RequestsService);
app.registerService('localStorage', LocalStorageService);
app.registerService('sessionStorage', SessionStorageService);
-app.registerComponent('lazyClick', LazyClickComponent);
-app.registerComponent('lazyScroll', LazyScrollComponent);
-
// On Start APP
window.addEventListener('load', () => {
app.onWillStart().then(() => {
@@ -29,7 +23,5 @@ export {
LocalStorageService,
SessionStorageService,
RequestsService,
- LazyClickComponent,
- LazyScrollComponent,
};
export default app;
diff --git a/src/js/utils/debounce.mjs b/src/js/utils/debounce.mjs
deleted file mode 100644
index 052becd..0000000
--- a/src/js/utils/debounce.mjs
+++ /dev/null
@@ -1,9 +0,0 @@
-export default function (func, timeout = 300) {
- let timer = null;
- return (...args) => {
- clearTimeout(timer);
- timer = setTimeout(() => {
- func.apply(this, args);
- }, timeout);
- };
-}
diff --git a/src/js/utils/dom_set_attributes.mjs b/src/js/utils/dom_set_attributes.mjs
deleted file mode 100644
index 695008d..0000000
--- a/src/js/utils/dom_set_attributes.mjs
+++ /dev/null
@@ -1,5 +0,0 @@
-export default function (dom_el, attrs) {
- Object.keys(attrs).forEach(key => {
- dom_el.setAttribute(key, attrs[key]);
- });
-}