@dogiloki/artha-js 1.0.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,33 +1,122 @@
1
1
  const EVENT_BUS=new EventTarget();
2
2
 
3
3
  export default class EventBus{
4
+
5
+ static debug=false;
6
+ static listeners=new Map();
7
+ static any_listeners=new Set();
4
8
 
5
9
  // Emitir evento
6
10
  static emit(name,data){
11
+ if(this.debug){
12
+ try{
13
+ console.log(`[EventBus] emit -> ${name}`,structuredClone(data));
14
+ }catch(ex){
15
+ console.log(`[EventBus] emit -> ${name}`,data);
16
+ }
17
+ }
18
+ this.any_listeners.forEach(cb=>{
19
+ try{
20
+ cb(name,data);
21
+ }catch(ex){
22
+ console.error(`[EventBus error] ${name}`,ex);
23
+ }
24
+ });
7
25
  EVENT_BUS.dispatchEvent(new CustomEvent(name,{detail:data}));
8
26
  }
9
27
 
28
+ // Emitir y esperar promesa (async listeners)
29
+ static emitAsync(name,data){
30
+ this.any_listeners.forEach(cb=>{
31
+ try{
32
+ cb(name,data);
33
+ }catch(ex){
34
+ console.error(`[EventBus error] ${name}`,ex);
35
+ }
36
+ });
37
+ const listeners=this.listeners.get(name)||[];
38
+ const results=listeners.map(async({callback})=>{
39
+ try{
40
+ return await callback(data);
41
+ }catch(ex){
42
+ console.error(`[EventBus error] ${name}`,ex);
43
+ return null;
44
+ }
45
+ });
46
+ return Promise.all(results);
47
+ }
48
+
10
49
  // Escuchar evento
11
50
  static on(name,callback){
12
51
  const handler=(evt)=>{
13
52
  callback(evt.detail);
14
53
  };
15
- EVENT_BUS.addEventListener(name,callback);
16
- return ()=>EVENT_BUS.removeEventListener(name,handler);
54
+ EVENT_BUS.addEventListener(name,handler);
55
+ if(!this.listeners.has(name)){
56
+ this.listeners.set(name,[]);
57
+ }
58
+ this.listeners.get(name).push({callback,handler});
59
+ return ()=>this.off(name,callback);
17
60
  }
18
61
 
19
62
  // Escucha una sola vez
20
63
  static once(name,callback){
21
64
  const handler=(evt)=>{
22
65
  callback(evt.detail);
23
- EVENT_BUS.removeEventListener(name,handler);
66
+ this.off(name,callback);
24
67
  };
25
- EVENT_BUS.addEventListener(name,callback);
68
+ EVENT_BUS.addEventListener(name,handler,{once:true});
69
+ // Guardar referencia
70
+ if(!this.listeners.has(name)){
71
+ this.listeners.set(name,[]);
72
+ }
73
+ this.listeners.get(name).push({callback,handler});
74
+ }
75
+
76
+ // Escuchar todos los eventos
77
+ static onAny(callback){
78
+ this.any_listeners.add(callback);
79
+ return ()=>this.any_listeners.delete(callback);
26
80
  }
27
81
 
28
82
  // Remover listener manualmente
29
83
  static off(name,callback){
30
- EVENT_BUS.removeEventListener(name,callback);
84
+ if(!this.listeners.has(name)) return;
85
+ const arr=this.listeners.get(name);
86
+ const filtered=arr.filter(item=>{
87
+ if(item.callback===callback){
88
+ EVENT_BUS.removeEventListener(name,item.handler);
89
+ return false;
90
+ }
91
+ return true;
92
+ });
93
+ if(filtered.length!==arr.length){
94
+ this.listeners.set(name,filtered);
95
+ }
96
+ if(filtered.length===0){
97
+ this.listeners.delete(name);
98
+ }
99
+ }
100
+
101
+ // Limpiar todos los listeners de un evento
102
+ static clean(name){
103
+ if(!this.listeners.has(name)) return;
104
+ const arr=this.listeners.get(name);
105
+ arr.forEach(({handler})=>{
106
+ EVENT_BUS.removeEventListener(name,handler);
107
+ });
108
+ this.listeners.delete(name);
109
+ }
110
+
111
+ // Limpiar todo
112
+ static clearAll(){
113
+ this.listeners.forEach((arr,name)=>{
114
+ arr.forEach(({handler})=>{
115
+ EVENT_BUS.removeEventListener(name,handler);
116
+ });
117
+ });
118
+ this.listeners.clear();
119
+ this.any_listeners.clear();
31
120
  }
32
121
 
33
122
  }
@@ -1,9 +1,13 @@
1
- import Config from "./Config.js";
2
1
  import Util from "./Util.js";
3
2
  import ArthaMessage from "../components/artha-message.js";
4
3
 
5
4
  export default class TaskQueue{
6
5
 
6
+ static defaults={
7
+ title:"Petición en proceso...",
8
+ close:false,
9
+ message:null
10
+ };
7
11
  static INSTNACE=null;
8
12
 
9
13
  static singleton(){
@@ -50,7 +54,7 @@ class TaskQueueItem{
50
54
  constructor(id,callback,options){
51
55
  this.id=id;
52
56
  this.callback=callback;
53
- options={...Config.get("task_queue"),...options};
57
+ options={...TaskQueue.defaults,...options};
54
58
  const {
55
59
  title,
56
60
  close,
@@ -127,20 +131,21 @@ class TaskQueueItem{
127
131
  }
128
132
  }
129
133
  message=message||json.message||"Operación completada";
130
- if(message){
131
- this.message_element?.show(message,json?.status??null);
132
- }
133
134
  // Validar respuesta http
134
135
  if(Util.withinRange(data.status,200,299)){
135
- if(!message){
136
+ if(message){
137
+ this.message_element?.show(message,json?.status??null);
138
+ }else{
136
139
  this.message_element?.success("Operación completada");
137
140
  }
138
- this.status="success";
141
+ this.status=json?.status||"success";
139
142
  }else{
140
- if(!message){
143
+ if(message){
144
+ this.message_element?.show(message,json?.status??null);
145
+ }else{
141
146
  this.message_element?.error("Error en la respuesta del servidor");
142
147
  }
143
- this.status="error";
148
+ this.status=json?.status||"error";
144
149
  this.onFinalize();
145
150
  return;
146
151
  }
package/src/core/Util.js CHANGED
@@ -1,6 +1,13 @@
1
- import Config from "./Config.js";
2
-
3
1
  export default class Util{
2
+
3
+ static defaults={
4
+ locale:"es-MX",
5
+ currency:"MXN",
6
+ money:{
7
+ style:"currency",
8
+ digits:2
9
+ }
10
+ };
4
11
 
5
12
  static getMeta(name){
6
13
  const meta=document.querySelector(`meta[name="${name}"]`);
@@ -37,21 +44,19 @@ export default class Util{
37
44
 
38
45
  static formatMoney(value,options={}){
39
46
  const {
40
- locale=Config.get("locale"),
41
- currency=Config.get("currency"),
42
- digits=Config.get("money.digits")
47
+ locale=this.defaults.locale,
48
+ currency=this.defaults.currency,
49
+ digits=this.defaults.money.digits,
50
+ style=this.defaults.money.style
43
51
  }=options;
44
52
  value=value.toString();
45
- if(value.endsWith(".") && !add_decimals){
46
- add_decimals=true;
47
- }
48
53
  let amount=Number(value.replace(/[^0-9.]/g,""));
49
54
  if(isNaN(amount)){
50
55
  return value;
51
56
  }
52
57
  let minimum=0;
53
58
  return new Intl.NumberFormat(locale,{
54
- style:"currency",
59
+ style:style,
55
60
  currency,
56
61
  minimum,
57
62
  digits
@@ -68,9 +73,7 @@ export default class Util{
68
73
 
69
74
  static createElement(type,value=null,options={}){
70
75
  const el=document.createElement(type,options);
71
- if(value!==null){
72
- return el;
73
- }
76
+ if(value===null) return el;
74
77
  if(Array.isArray(value)){
75
78
  value.forEach((item)=>{
76
79
  el.appendChild(item);
package/src/core/XHR.js CHANGED
@@ -1,10 +1,34 @@
1
- import Config from './Config.js';
2
1
  import Util from './Util.js';
3
2
 
4
3
  export default class XHR{
5
4
 
5
+ static defaults={
6
+ method:"GET",
7
+ url:null,
8
+ uri:"",
9
+ headers:{},
10
+ data:{},
11
+ query:{},
12
+ files:{},
13
+ response_type:"json",
14
+ with_credentials:false,
15
+ timeout:0,
16
+ retry:false,
17
+ retry_delay:5000,
18
+ transformResponse:(xhr)=>{
19
+ return xhr.response;
20
+ },
21
+ onLoad:()=>{},
22
+ onData:()=>{},
23
+ onError:()=>{},
24
+ onTimeout:()=>{},
25
+ onProgress:()=>{},
26
+ onAbort:()=>{},
27
+ onAction:()=>{},
28
+ };
29
+
6
30
  static request(options){
7
- options={...Config.get("xhr"),...options};
31
+ options={...this.defaults,...options};
8
32
  const {
9
33
  method,
10
34
  url,
@@ -18,6 +42,7 @@ export default class XHR{
18
42
  timeout,
19
43
  retry,
20
44
  retry_delay,
45
+ transformResponse,
21
46
  onLoad,
22
47
  onData,
23
48
  onError,
@@ -26,6 +51,14 @@ export default class XHR{
26
51
  onAbort,
27
52
  onAction
28
53
  }=options;
54
+ const safeTransform=(xhr)=>{
55
+ try{
56
+ return transformResponse(xhr);
57
+ }catch(ex){
58
+ console.error("transformResponse error:",ex);
59
+ return xhr.response;
60
+ }
61
+ };
29
62
  url??="/"+uri;
30
63
  const xhr=new XMLHttpRequest();
31
64
  const query_string=Object.keys(query).length?"?"+Object.entries(query)
@@ -71,35 +104,37 @@ export default class XHR{
71
104
  xhr.addEventListener("load",()=>{
72
105
  onLoad(xhr);
73
106
  if(Util.withinRange(xhr.status,200,299)){
74
- onData(xhr,xhr.response);
107
+ onData(xhr,safeTransform(xhr));
75
108
  }else{
76
- onError(xhr.response);
109
+ onError(safeTransform(xhr));
77
110
  }
78
111
  });
79
112
 
80
113
  // Error
81
114
  xhr.addEventListener("error",()=>{
115
+ const retry_options={...options};
82
116
  if(retry){
83
117
  setTimeout(()=>{
84
- XHR.request(options);
118
+ XHR.request(retry_options);
85
119
  },retry_delay);
86
120
  }
87
- onError(xhr.response);
121
+ onError(safeTransform(xhr));
88
122
  });
89
123
 
90
124
  // Aborto
91
125
  xhr.addEventListener("abort",()=>{
92
- onAbort(xhr.response);
126
+ onAbort(safeTransform(xhr));
93
127
  });
94
128
 
95
129
  // Tiempo de espera
96
130
  xhr.addEventListener("timeout",()=>{
131
+ const retry_options={...options};
97
132
  if(retry){
98
133
  setTimeout(()=>{
99
- XHR.request(options);
134
+ XHR.request(retry_options);
100
135
  },retry_delay);
101
136
  }
102
- onTimeout(xhr.response);
137
+ onTimeout(safeTransform(xhr));
103
138
  });
104
139
 
105
140
  // Progreso
@@ -6,4 +6,8 @@ $msg-text-info-color: #3a87ad;
6
6
  $msg-background-error-color: #f2dede;
7
7
  $msg-background-success-color: #dff0d8;
8
8
  $msg-background-warning-color: #fcf8e3;
9
- $msg-background-info-color: #d9edf7;
9
+ $msg-background-info-color: #d9edf7;
10
+
11
+ $loader-primary-color: #3b82f6;
12
+ $loader-secondary-color: #93c5fd;
13
+ $loader-muted-color: #5b6e8c;
@@ -0,0 +1,70 @@
1
+ @use './colors.scss' as *;
2
+
3
+ artha-loader{
4
+ display: inline-flex;
5
+ flex-direction: column;
6
+ align-items: center;
7
+
8
+ .loader-content{
9
+ display: flex;
10
+ justify-content: center;
11
+ align-items: center;
12
+ gap: 10px;
13
+ }
14
+ &[type="dots"]{
15
+ .loader-content{
16
+
17
+ >div{
18
+ width: 10px;
19
+ height: 10px;
20
+ background-color: $loader-primary-color;
21
+ border-radius: 50%;
22
+ animation: dot 1.2s infinite ease-in-out;
23
+
24
+ &:nth-of-type(1){
25
+ animation-delay: 0s;
26
+ }
27
+ &:nth-of-type(2){
28
+ animation-delay: 0.2s;
29
+ }
30
+ &:nth-of-type(3){
31
+ animation-delay: 0.4s;
32
+ }
33
+ }
34
+ }
35
+ }
36
+ &[type="ring"]{
37
+ .loader-content{
38
+
39
+ >div{
40
+ width: 32px;
41
+ height: 32px;
42
+ border: 3px solid $loader-secondary-color;
43
+ border-top-color: $loader-primary-color;
44
+ border-radius: 50%;
45
+ animation: ring 0.8s linear infinite;
46
+ }
47
+ }
48
+ }
49
+ span{
50
+ font-size: 1rem;
51
+ color: $loader-muted-color;
52
+ }
53
+ }
54
+
55
+ @keyframes dot{
56
+ 0%,100%{
57
+ transform: scale(0.8);
58
+ opacity: 0.4;
59
+ }
60
+ 50%{
61
+ transform: scale(1.2);
62
+ opacity: 1;
63
+ }
64
+ }
65
+
66
+ @keyframes ring{
67
+ to{
68
+ transform: rotate(360deg);
69
+ }
70
+ }
@@ -1 +1,2 @@
1
1
  @use './message.scss' as *;
2
+ @use './loader.scss' as *;
@@ -8,19 +8,19 @@ artha-message{
8
8
  cursor: default;
9
9
 
10
10
  &[type="error"]{
11
- background-color: $msg_background_error_color;
12
- color: $msg_text_error_color;
11
+ background-color: $msg-background-error-color;
12
+ color: $msg-text-error-color;
13
13
  }
14
14
  &[type="success"]{
15
- background-color: $msg_background_success_color;
16
- color: $msg_text_success_color;
15
+ background-color: $msg-background-success-color;
16
+ color: $msg-text-success-color;
17
17
  }
18
18
  &[type="warning"]{
19
- background-color: $msg_background_warning_color;
20
- color: $msg_text_warning_color;
19
+ background-color: $msg-background-warning-color;
20
+ color: $msg-text-warning-color;
21
21
  }
22
22
  &[type="info"]{
23
- background-color: $msg_background_info_color;
24
- color: $msg_text_info_color;
23
+ background-color: $msg-background-info-color;
24
+ color: $msg-text-info-color;
25
25
  }
26
26
  }
@@ -1,47 +0,0 @@
1
- const DEFAULT_CONFIG={
2
- locale:"es-MX",
3
- currency:"MXN",
4
- money:{
5
- digits:2
6
- },
7
- xhr:{
8
- method:"GET",
9
- url:null,
10
- uri:"",
11
- headers:{},
12
- data:{},
13
- query:{},
14
- files:{},
15
- response_type:"json",
16
- with_credentials:false,
17
- timeout:0,
18
- retry:false,
19
- retry_delay:5000,
20
- onLoad:()=>{},
21
- onData:()=>{},
22
- onError:()=>{},
23
- onTimeout:()=>{},
24
- onProgress:()=>{},
25
- onAbort:()=>{},
26
- onAction:()=>{},
27
- },
28
- task_queue:{
29
- title:"Petición en proceso...",
30
- close:false,
31
- message:null
32
- }
33
- };
34
-
35
- export default class Config{
36
-
37
- static SETTINGS={...DEFAULT_CONFIG};
38
-
39
- static set(options){
40
- this.SETTINGS={...this.SETTINGS,...options};
41
- }
42
-
43
- static get(path,def=null){
44
- return path.split(".").reduce((o,p)=>o?o[p]:def,this.SETTINGS);
45
- }
46
-
47
- }