@develia/commons 0.4.9 → 0.4.13

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.
Files changed (271) hide show
  1. package/dist/cjs/array.js +0 -0
  2. package/dist/cjs/array.js.map +0 -0
  3. package/dist/cjs/async-pool-executor.js +0 -0
  4. package/dist/cjs/async-pool-executor.js.map +0 -0
  5. package/dist/cjs/browser/form-utilities.js +23 -18
  6. package/dist/cjs/browser/form-utilities.js.map +1 -1
  7. package/dist/cjs/browser/geo-location.js +60 -36
  8. package/dist/cjs/browser/geo-location.js.map +1 -1
  9. package/dist/cjs/browser/index.js +73 -0
  10. package/dist/cjs/browser/index.js.map +1 -1
  11. package/dist/cjs/browser/native-bridge.js +0 -0
  12. package/dist/cjs/browser/native-bridge.js.map +0 -0
  13. package/dist/cjs/cancellable-promise.js +0 -0
  14. package/dist/cjs/cancellable-promise.js.map +0 -0
  15. package/dist/cjs/clean-url-search-params.js +0 -0
  16. package/dist/cjs/clean-url-search-params.js.map +0 -0
  17. package/dist/cjs/collections/cache-dictionary.js +0 -0
  18. package/dist/cjs/collections/cache-dictionary.js.map +0 -0
  19. package/dist/cjs/collections/default-map.js +0 -0
  20. package/dist/cjs/collections/default-map.js.map +0 -0
  21. package/dist/cjs/collections/default-weak-map.js +0 -0
  22. package/dist/cjs/collections/default-weak-map.js.map +0 -0
  23. package/dist/cjs/collections/index.js +0 -0
  24. package/dist/cjs/collections/index.js.map +0 -0
  25. package/dist/cjs/draft.js +149 -0
  26. package/dist/cjs/draft.js.map +1 -0
  27. package/dist/cjs/event-bus.js +70 -0
  28. package/dist/cjs/event-bus.js.map +1 -0
  29. package/dist/cjs/from.js +0 -0
  30. package/dist/cjs/from.js.map +0 -0
  31. package/dist/cjs/index.js +6 -1
  32. package/dist/cjs/index.js.map +1 -1
  33. package/dist/cjs/key-value-pair.js +0 -0
  34. package/dist/cjs/key-value-pair.js.map +0 -0
  35. package/dist/cjs/lazy.js +0 -0
  36. package/dist/cjs/lazy.js.map +0 -0
  37. package/dist/cjs/math.js +0 -0
  38. package/dist/cjs/math.js.map +0 -0
  39. package/dist/cjs/order.js +0 -0
  40. package/dist/cjs/order.js.map +0 -0
  41. package/dist/cjs/parse.js +0 -0
  42. package/dist/cjs/parse.js.map +0 -0
  43. package/dist/cjs/patch.js +0 -0
  44. package/dist/cjs/patch.js.map +0 -0
  45. package/dist/cjs/stopwatch.js +0 -0
  46. package/dist/cjs/stopwatch.js.map +0 -0
  47. package/dist/cjs/string.js +39 -0
  48. package/dist/cjs/string.js.map +1 -1
  49. package/dist/cjs/timer.js +0 -0
  50. package/dist/cjs/timer.js.map +0 -0
  51. package/dist/cjs/timespan.js +0 -0
  52. package/dist/cjs/timespan.js.map +0 -0
  53. package/dist/cjs/type-code.js +0 -0
  54. package/dist/cjs/type-code.js.map +0 -0
  55. package/dist/cjs/type.js +0 -0
  56. package/dist/cjs/type.js.map +0 -0
  57. package/dist/cjs/types.js +0 -0
  58. package/dist/cjs/types.js.map +0 -0
  59. package/dist/cjs/utilities.js +61 -34
  60. package/dist/cjs/utilities.js.map +1 -1
  61. package/dist/esm/array.js +0 -0
  62. package/dist/esm/array.js.map +0 -0
  63. package/dist/esm/async-pool-executor.js +0 -0
  64. package/dist/esm/async-pool-executor.js.map +0 -0
  65. package/dist/esm/browser/form-utilities.js +23 -18
  66. package/dist/esm/browser/form-utilities.js.map +1 -1
  67. package/dist/esm/browser/geo-location.js +60 -36
  68. package/dist/esm/browser/geo-location.js.map +1 -1
  69. package/dist/esm/browser/index.js +71 -0
  70. package/dist/esm/browser/index.js.map +1 -1
  71. package/dist/esm/browser/native-bridge.js +0 -0
  72. package/dist/esm/browser/native-bridge.js.map +0 -0
  73. package/dist/esm/cancellable-promise.js +0 -0
  74. package/dist/esm/cancellable-promise.js.map +0 -0
  75. package/dist/esm/clean-url-search-params.js +0 -0
  76. package/dist/esm/clean-url-search-params.js.map +0 -0
  77. package/dist/esm/collections/cache-dictionary.js +0 -0
  78. package/dist/esm/collections/cache-dictionary.js.map +0 -0
  79. package/dist/esm/collections/default-map.js +0 -0
  80. package/dist/esm/collections/default-map.js.map +0 -0
  81. package/dist/esm/collections/default-weak-map.js +0 -0
  82. package/dist/esm/collections/default-weak-map.js.map +0 -0
  83. package/dist/esm/collections/index.js +0 -0
  84. package/dist/esm/collections/index.js.map +0 -0
  85. package/dist/esm/draft.js +146 -0
  86. package/dist/esm/draft.js.map +1 -0
  87. package/dist/esm/event-bus.js +65 -0
  88. package/dist/esm/event-bus.js.map +1 -0
  89. package/dist/esm/from.js +0 -0
  90. package/dist/esm/from.js.map +0 -0
  91. package/dist/esm/index.js +2 -0
  92. package/dist/esm/index.js.map +1 -1
  93. package/dist/esm/key-value-pair.js +0 -0
  94. package/dist/esm/key-value-pair.js.map +0 -0
  95. package/dist/esm/lazy.js +0 -0
  96. package/dist/esm/lazy.js.map +0 -0
  97. package/dist/esm/math.js +0 -0
  98. package/dist/esm/math.js.map +0 -0
  99. package/dist/esm/order.js +0 -0
  100. package/dist/esm/order.js.map +0 -0
  101. package/dist/esm/parse.js +0 -0
  102. package/dist/esm/parse.js.map +0 -0
  103. package/dist/esm/patch.js +0 -0
  104. package/dist/esm/patch.js.map +0 -0
  105. package/dist/esm/stopwatch.js +0 -0
  106. package/dist/esm/stopwatch.js.map +0 -0
  107. package/dist/esm/string.js +34 -0
  108. package/dist/esm/string.js.map +1 -1
  109. package/dist/esm/timer.js +0 -0
  110. package/dist/esm/timer.js.map +0 -0
  111. package/dist/esm/timespan.js +0 -0
  112. package/dist/esm/timespan.js.map +0 -0
  113. package/dist/esm/type-code.js +0 -0
  114. package/dist/esm/type-code.js.map +0 -0
  115. package/dist/esm/type.js +0 -0
  116. package/dist/esm/type.js.map +0 -0
  117. package/dist/esm/types.js +0 -0
  118. package/dist/esm/types.js.map +0 -0
  119. package/dist/esm/utilities.js +61 -34
  120. package/dist/esm/utilities.js.map +1 -1
  121. package/dist/types/array.d.ts +0 -0
  122. package/dist/types/array.d.ts.map +0 -0
  123. package/dist/types/async-pool-executor.d.ts +0 -0
  124. package/dist/types/async-pool-executor.d.ts.map +0 -0
  125. package/dist/types/browser/form-utilities.d.ts +2 -2
  126. package/dist/types/browser/form-utilities.d.ts.map +1 -1
  127. package/dist/types/browser/geo-location.d.ts +0 -0
  128. package/dist/types/browser/geo-location.d.ts.map +1 -1
  129. package/dist/types/browser/index.d.ts +10 -0
  130. package/dist/types/browser/index.d.ts.map +1 -1
  131. package/dist/types/browser/native-bridge.d.ts +0 -0
  132. package/dist/types/browser/native-bridge.d.ts.map +0 -0
  133. package/dist/types/cancellable-promise.d.ts +0 -0
  134. package/dist/types/cancellable-promise.d.ts.map +0 -0
  135. package/dist/types/clean-url-search-params.d.ts +0 -0
  136. package/dist/types/clean-url-search-params.d.ts.map +0 -0
  137. package/dist/types/collections/cache-dictionary.d.ts +0 -0
  138. package/dist/types/collections/cache-dictionary.d.ts.map +0 -0
  139. package/dist/types/collections/default-map.d.ts +0 -0
  140. package/dist/types/collections/default-map.d.ts.map +0 -0
  141. package/dist/types/collections/default-weak-map.d.ts +0 -0
  142. package/dist/types/collections/default-weak-map.d.ts.map +0 -0
  143. package/dist/types/collections/index.d.ts +0 -0
  144. package/dist/types/collections/index.d.ts.map +0 -0
  145. package/dist/types/draft.d.ts +17 -0
  146. package/dist/types/draft.d.ts.map +1 -0
  147. package/dist/types/event-bus.d.ts +21 -0
  148. package/dist/types/event-bus.d.ts.map +1 -0
  149. package/dist/types/from.d.ts +0 -0
  150. package/dist/types/from.d.ts.map +0 -0
  151. package/dist/types/index.d.ts +2 -0
  152. package/dist/types/index.d.ts.map +1 -1
  153. package/dist/types/key-value-pair.d.ts +0 -0
  154. package/dist/types/key-value-pair.d.ts.map +0 -0
  155. package/dist/types/lazy.d.ts +0 -0
  156. package/dist/types/lazy.d.ts.map +0 -0
  157. package/dist/types/math.d.ts +0 -0
  158. package/dist/types/math.d.ts.map +0 -0
  159. package/dist/types/order.d.ts +0 -0
  160. package/dist/types/order.d.ts.map +0 -0
  161. package/dist/types/parse.d.ts +0 -0
  162. package/dist/types/parse.d.ts.map +0 -0
  163. package/dist/types/patch.d.ts +0 -0
  164. package/dist/types/patch.d.ts.map +0 -0
  165. package/dist/types/stopwatch.d.ts +0 -0
  166. package/dist/types/stopwatch.d.ts.map +0 -0
  167. package/dist/types/string.d.ts +5 -0
  168. package/dist/types/string.d.ts.map +1 -1
  169. package/dist/types/timer.d.ts +0 -0
  170. package/dist/types/timer.d.ts.map +0 -0
  171. package/dist/types/timespan.d.ts +0 -0
  172. package/dist/types/timespan.d.ts.map +0 -0
  173. package/dist/types/type-code.d.ts +0 -0
  174. package/dist/types/type-code.d.ts.map +0 -0
  175. package/dist/types/type.d.ts +0 -0
  176. package/dist/types/type.d.ts.map +0 -0
  177. package/dist/types/types.d.ts +0 -0
  178. package/dist/types/types.d.ts.map +0 -0
  179. package/dist/types/utilities.d.ts +2 -2
  180. package/dist/types/utilities.d.ts.map +1 -1
  181. package/dist/web/array.js +0 -0
  182. package/dist/web/array.js.map +0 -0
  183. package/dist/web/async-pool-executor.js +0 -0
  184. package/dist/web/async-pool-executor.js.map +0 -0
  185. package/dist/web/browser/form-utilities.js +23 -18
  186. package/dist/web/browser/form-utilities.js.map +1 -1
  187. package/dist/web/browser/geo-location.js +60 -36
  188. package/dist/web/browser/geo-location.js.map +1 -1
  189. package/dist/web/browser/index.js +71 -0
  190. package/dist/web/browser/index.js.map +1 -1
  191. package/dist/web/browser/native-bridge.js +0 -0
  192. package/dist/web/browser/native-bridge.js.map +0 -0
  193. package/dist/web/cancellable-promise.js +0 -0
  194. package/dist/web/cancellable-promise.js.map +0 -0
  195. package/dist/web/clean-url-search-params.js +0 -0
  196. package/dist/web/clean-url-search-params.js.map +0 -0
  197. package/dist/web/collections/cache-dictionary.js +0 -0
  198. package/dist/web/collections/cache-dictionary.js.map +0 -0
  199. package/dist/web/collections/default-map.js +0 -0
  200. package/dist/web/collections/default-map.js.map +0 -0
  201. package/dist/web/collections/default-weak-map.js +0 -0
  202. package/dist/web/collections/default-weak-map.js.map +0 -0
  203. package/dist/web/collections/index.js +0 -0
  204. package/dist/web/collections/index.js.map +0 -0
  205. package/dist/web/draft.js +146 -0
  206. package/dist/web/draft.js.map +1 -0
  207. package/dist/web/event-bus.js +65 -0
  208. package/dist/web/event-bus.js.map +1 -0
  209. package/dist/web/from.js +0 -0
  210. package/dist/web/from.js.map +0 -0
  211. package/dist/web/index.js +2 -0
  212. package/dist/web/index.js.map +1 -1
  213. package/dist/web/key-value-pair.js +0 -0
  214. package/dist/web/key-value-pair.js.map +0 -0
  215. package/dist/web/lazy.js +0 -0
  216. package/dist/web/lazy.js.map +0 -0
  217. package/dist/web/math.js +0 -0
  218. package/dist/web/math.js.map +0 -0
  219. package/dist/web/order.js +0 -0
  220. package/dist/web/order.js.map +0 -0
  221. package/dist/web/parse.js +0 -0
  222. package/dist/web/parse.js.map +0 -0
  223. package/dist/web/patch.js +0 -0
  224. package/dist/web/patch.js.map +0 -0
  225. package/dist/web/stopwatch.js +0 -0
  226. package/dist/web/stopwatch.js.map +0 -0
  227. package/dist/web/string.js +34 -0
  228. package/dist/web/string.js.map +1 -1
  229. package/dist/web/timer.js +0 -0
  230. package/dist/web/timer.js.map +0 -0
  231. package/dist/web/timespan.js +0 -0
  232. package/dist/web/timespan.js.map +0 -0
  233. package/dist/web/type-code.js +0 -0
  234. package/dist/web/type-code.js.map +0 -0
  235. package/dist/web/type.js +0 -0
  236. package/dist/web/type.js.map +0 -0
  237. package/dist/web/types.js +0 -0
  238. package/dist/web/types.js.map +0 -0
  239. package/dist/web/utilities.js +61 -34
  240. package/dist/web/utilities.js.map +1 -1
  241. package/package.json +8 -4
  242. package/src/array.ts +0 -0
  243. package/src/async-pool-executor.ts +0 -0
  244. package/src/browser/form-utilities.ts +179 -173
  245. package/src/browser/geo-location.ts +88 -54
  246. package/src/browser/index.ts +115 -4
  247. package/src/browser/native-bridge.ts +0 -0
  248. package/src/cancellable-promise.ts +0 -0
  249. package/src/clean-url-search-params.ts +0 -0
  250. package/src/collections/cache-dictionary.ts +0 -0
  251. package/src/collections/default-map.ts +0 -0
  252. package/src/collections/default-weak-map.ts +0 -0
  253. package/src/collections/index.ts +0 -0
  254. package/src/draft.ts +264 -0
  255. package/src/event-bus.ts +84 -0
  256. package/src/from.ts +0 -0
  257. package/src/index.ts +6 -0
  258. package/src/key-value-pair.ts +0 -0
  259. package/src/lazy.ts +0 -0
  260. package/src/math.ts +0 -0
  261. package/src/order.ts +0 -0
  262. package/src/parse.ts +0 -0
  263. package/src/patch.ts +0 -0
  264. package/src/stopwatch.ts +0 -0
  265. package/src/string.ts +128 -48
  266. package/src/timer.ts +0 -0
  267. package/src/timespan.ts +0 -0
  268. package/src/type-code.ts +0 -0
  269. package/src/type.ts +0 -0
  270. package/src/types.ts +0 -0
  271. package/src/utilities.ts +82 -50
@@ -1,174 +1,180 @@
1
- import {type Optional, type Supplier} from "../types.js";
2
-
3
-
4
- /**
5
- * Submits a form via AJAX and returns a Promise that resolves to the Response object.
6
- *
7
- * @param {HTMLFormElement | string} selectorOrElement - The form element or selector.
8
- * @return {Promise<Response>} A Promise that resolves to the Response object.
9
- * @throws {Error} If the element is invalid.
10
- */
11
- export async function ajaxSubmit(selectorOrElement: HTMLFormElement | string): Promise<Response> {
12
-
13
- const form = typeof selectorOrElement === 'string'
14
- ? document.querySelector(selectorOrElement)
15
- : selectorOrElement;
16
-
17
- if (!(form instanceof HTMLFormElement)) {
18
- throw new Error("Invalid element.");
19
- }
20
-
21
- // Crear un objeto FormData a partir del formulario
22
- return await fetch(form.action, {
23
- method: form.method,
24
- body: new FormData(form),
25
- });
26
- }
27
-
28
-
29
- export function submitForm(
30
- url: string,
31
- data: Record<string, any>,
32
- method: 'POST' | 'GET' = 'POST',
33
- target?: '_blank' | '_self' | '_parent' | '_top'
34
- ): void {
35
-
36
- const form = document.createElement('form');
37
- form.method = method.toUpperCase();
38
- form.action = url;
39
- form.style.display = 'none';
40
-
41
- if (target) {
42
- form.target = target;
43
- }
44
-
45
- /**
46
- * Recursively appends inputs to the form, supporting nested keys and arrays.
47
- * @param keyPrefix - Key path, e.g., 'user[name]' or 'tags[]'
48
- * @param value - The value to append (can be nested)
49
- */
50
- const appendInputs = (keyPrefix: string, value: any) => {
51
- if (Array.isArray(value)) {
52
- value.forEach(val => {
53
- appendInputs(`${keyPrefix}[]`, val);
54
- });
55
- } else if (typeof value === 'object' && value !== null) {
56
- for (const subKey in value) {
57
- if (value.hasOwnProperty(subKey)) {
58
- appendInputs(`${keyPrefix}[${subKey}]`, value[subKey]);
59
- }
60
- }
61
- } else {
62
- const input = document.createElement('input');
63
- input.type = 'hidden';
64
- input.name = keyPrefix;
65
- input.value = String(value);
66
- form.appendChild(input);
67
- }
68
- };
69
-
70
- for (const key in data) {
71
- if (data.hasOwnProperty(key)) {
72
- appendInputs(key, data[key]);
73
- }
74
- }
75
-
76
- document.body.appendChild(form);
77
- form.submit();
78
- }
79
-
80
- export function formToObject(form: HTMLFormElement): Record<string, FormDataEntryValue | FormDataEntryValue[]> {
81
- const fd = new FormData(form);
82
- const out: Record<string, FormDataEntryValue | FormDataEntryValue[]> = {};
83
-
84
- for (const [key, value] of fd.entries()) {
85
- if (key in out) {
86
- const current = out[key];
87
- if (Array.isArray(current)) {
88
- current.push(value);
89
- } else {
90
- out[key] = [current, value];
91
- }
92
- } else {
93
- out[key] = value;
94
- }
95
- }
96
-
97
- return out;
98
- }
99
-
100
- /**
101
- * Converts an object to `FormData` format recursively.
102
- *
103
- * @param {Record<string, any>} data - The object data to convert.
104
- * @param {FormData} formData - The `FormData` instance to append data to.
105
- * @param {string} parentKey - The parent key to append to child keys in the `FormData`.
106
- * @returns {FormData} - The `FormData` instance with the converted data.
107
- */
108
- function _objectToFormData(data: Record<string, any>, formData: FormData, parentKey: string = ''): FormData {
109
-
110
- for (const key in data) {
111
- if (data.hasOwnProperty(key)) {
112
- const value = data[key];
113
-
114
- if (value instanceof Date) {
115
- formData.append(parentKey ? `${parentKey}[${key}]` : key, value.toISOString());
116
- } else if (value instanceof File) {
117
- formData.append(parentKey ? `${parentKey}[${key}]` : key, value);
118
- } else if (typeof value === 'object' && !Array.isArray(value)) {
119
- _objectToFormData(value, formData, parentKey ? `${parentKey}[${key}]` : key);
120
- } else if (Array.isArray(value)) {
121
- value.forEach((item, index) => {
122
- const arrayKey = `${parentKey ? `${parentKey}[${key}]` : key}[${index}]`;
123
- if (typeof item === 'object' && !Array.isArray(item)) {
124
- _objectToFormData(item, formData, arrayKey);
125
- } else {
126
- formData.append(arrayKey, item);
127
- }
128
- });
129
- } else {
130
- formData.append(parentKey ? `${parentKey}[${key}]` : key, value);
131
- }
132
- }
133
- }
134
-
135
- return formData;
136
- }
137
-
138
- /**
139
- * Converts an object into FormData.
140
- *
141
- * @param {Record<string, any>} data - The object to be converted into FormData.
142
- * @return {FormData} - The FormData object representing the converted data.
143
- */
144
- export function objectToFormData(data: Record<string, any>): FormData {
145
- let formData = new FormData();
146
- return _objectToFormData(data, formData);
147
- }
148
-
149
- export function ajaxSubmission(selectorOrElement: HTMLFormElement | string,
150
- onSuccess: Optional<Supplier<any>> = undefined,
151
- onFailure: Optional<Supplier<any>> = undefined): void {
152
-
153
- const form = typeof selectorOrElement === 'string'
154
- ? document.querySelector(selectorOrElement)
155
- : selectorOrElement;
156
-
157
- if (!(form instanceof HTMLFormElement)) {
158
- return;
159
- }
160
-
161
- form.addEventListener('submit', async (event) => {
162
- event.preventDefault();
163
- let promise = ajaxSubmit(form);
164
- if (promise) {
165
- if (onSuccess)
166
- promise = promise.then(onSuccess);
167
- if (onFailure)
168
- promise.catch(onFailure);
169
- }
170
-
171
- });
172
-
173
-
1
+ import {type Consumer, type Optional} from "../types.js";
2
+
3
+
4
+ /**
5
+ * Submits a form via AJAX and returns a Promise that resolves to the Response object.
6
+ *
7
+ * @param {HTMLFormElement | string} selectorOrElement - The form element or selector.
8
+ * @return {Promise<Response>} A Promise that resolves to the Response object.
9
+ * @throws {Error} If the element is invalid.
10
+ */
11
+ export async function ajaxSubmit(selectorOrElement: HTMLFormElement | string): Promise<Response> {
12
+
13
+ const form = typeof selectorOrElement === 'string'
14
+ ? document.querySelector(selectorOrElement)
15
+ : selectorOrElement;
16
+
17
+ if (!(form instanceof HTMLFormElement)) {
18
+ throw new Error("Invalid element.");
19
+ }
20
+
21
+
22
+ const formData = new FormData(form);
23
+ const method = form.getAttribute('method') as string ?? form.method;
24
+ const action = form.getAttribute('action') as string ?? form.action;
25
+
26
+ return await fetch(action, {
27
+ method: method,
28
+ body: formData,
29
+ });
30
+ }
31
+
32
+
33
+ export function submitForm(
34
+ url: string,
35
+ data: Record<string, any>,
36
+ method: 'POST' | 'GET' = 'POST',
37
+ target?: '_blank' | '_self' | '_parent' | '_top'
38
+ ): void {
39
+
40
+ const form = document.createElement('form');
41
+ form.method = method.toUpperCase();
42
+ form.action = url;
43
+ form.style.display = 'none';
44
+
45
+ if (target) {
46
+ form.target = target;
47
+ }
48
+
49
+ /**
50
+ * Recursively appends inputs to the form, supporting nested keys and arrays.
51
+ * @param keyPrefix - Key path, e.g., 'user[name]' or 'tags[]'
52
+ * @param value - The value to append (can be nested)
53
+ */
54
+ const appendInputs = (keyPrefix: string, value: any) => {
55
+ if (Array.isArray(value)) {
56
+ value.forEach(val => {
57
+ appendInputs(`${keyPrefix}[]`, val);
58
+ });
59
+ } else if (typeof value === 'object' && value !== null) {
60
+ for (const subKey in value) {
61
+ if (value.hasOwnProperty(subKey)) {
62
+ appendInputs(`${keyPrefix}[${subKey}]`, value[subKey]);
63
+ }
64
+ }
65
+ } else {
66
+ const input = document.createElement('input');
67
+ input.type = 'hidden';
68
+ input.name = keyPrefix;
69
+ input.value = String(value);
70
+ form.appendChild(input);
71
+ }
72
+ };
73
+
74
+ for (const key in data) {
75
+ if (data.hasOwnProperty(key)) {
76
+ appendInputs(key, data[key]);
77
+ }
78
+ }
79
+
80
+ document.body.appendChild(form);
81
+ form.submit();
82
+ }
83
+
84
+ export function formToObject(form: HTMLFormElement): Record<string, FormDataEntryValue | FormDataEntryValue[]> {
85
+ const fd = new FormData(form);
86
+ const out: Record<string, FormDataEntryValue | FormDataEntryValue[]> = {};
87
+
88
+ for (const [key, value] of fd.entries()) {
89
+ if (key in out) {
90
+ const current = out[key];
91
+ if (Array.isArray(current)) {
92
+ current.push(value);
93
+ } else {
94
+ out[key] = [current, value];
95
+ }
96
+ } else {
97
+ out[key] = value;
98
+ }
99
+ }
100
+
101
+ return out;
102
+ }
103
+
104
+ /**
105
+ * Converts an object to `FormData` format recursively.
106
+ *
107
+ * @param {Record<string, any>} data - The object data to convert.
108
+ * @param {FormData} formData - The `FormData` instance to append data to.
109
+ * @param {string} parentKey - The parent key to append to child keys in the `FormData`.
110
+ * @returns {FormData} - The `FormData` instance with the converted data.
111
+ */
112
+ function _objectToFormData(data: Record<string, any>, formData: FormData, parentKey: string = ''): FormData {
113
+
114
+ for (const key in data) {
115
+ if (data.hasOwnProperty(key)) {
116
+ const value = data[key];
117
+
118
+ if (value instanceof Date) {
119
+ formData.append(parentKey ? `${parentKey}[${key}]` : key, value.toISOString());
120
+ } else if (value instanceof File) {
121
+ formData.append(parentKey ? `${parentKey}[${key}]` : key, value);
122
+ } else if (typeof value === 'object' && !Array.isArray(value)) {
123
+ _objectToFormData(value, formData, parentKey ? `${parentKey}[${key}]` : key);
124
+ } else if (Array.isArray(value)) {
125
+ value.forEach((item, index) => {
126
+ const arrayKey = `${parentKey ? `${parentKey}[${key}]` : key}[${index}]`;
127
+ if (typeof item === 'object' && !Array.isArray(item)) {
128
+ _objectToFormData(item, formData, arrayKey);
129
+ } else {
130
+ formData.append(arrayKey, item);
131
+ }
132
+ });
133
+ } else {
134
+ formData.append(parentKey ? `${parentKey}[${key}]` : key, value);
135
+ }
136
+ }
137
+ }
138
+
139
+ return formData;
140
+ }
141
+
142
+ /**
143
+ * Converts an object into FormData.
144
+ *
145
+ * @param {Record<string, any>} data - The object to be converted into FormData.
146
+ * @return {FormData} - The FormData object representing the converted data.
147
+ */
148
+ export function objectToFormData(data: Record<string, any>): FormData {
149
+ let formData = new FormData();
150
+ return _objectToFormData(data, formData);
151
+ }
152
+
153
+ export function ajaxSubmission(
154
+ selectorOrElement: HTMLFormElement | string,
155
+ onSuccess: Optional<Consumer<any>> = undefined,
156
+ onFailure: Optional<Consumer<any>> = undefined
157
+ ): void {
158
+
159
+ const forms: HTMLFormElement[] = typeof selectorOrElement === 'string'
160
+ ? Array.from(document.querySelectorAll(selectorOrElement))
161
+ .filter(el => el instanceof HTMLFormElement) as HTMLFormElement[]
162
+ : [selectorOrElement];
163
+
164
+ forms.forEach(form => {
165
+ form.addEventListener('submit', async (event) => {
166
+ event.preventDefault();
167
+
168
+ try {
169
+ let result = await ajaxSubmit(event.currentTarget as HTMLFormElement);
170
+ if (onSuccess)
171
+ onSuccess(result);
172
+ } catch (e) {
173
+ if (onFailure)
174
+ onFailure(e);
175
+ }
176
+
177
+
178
+ });
179
+ });
174
180
  }
@@ -3,78 +3,112 @@
3
3
  export interface GeoLocation {
4
4
  latitude: number;
5
5
  longitude: number;
6
- accuracy: number; // metros
6
+ accuracy: number;
7
7
  altitude: number | null;
8
8
  altitudeAccuracy: number | null;
9
- heading: number | null; // grados desde el norte
10
- speed: number | null; // m/s
9
+ heading: number | null;
10
+ speed: number | null;
11
11
  timestamp: number;
12
12
  }
13
13
 
14
14
  export interface GeoLocationOptions {
15
- enableHighAccuracy?: boolean; // GPS real vs torres/wifi
16
- timeout?: number; // ms máximo de espera
17
- maximumAge?: number; // ms cache válida
15
+ enableHighAccuracy?: boolean;
16
+ timeout?: number;
17
+ maximumAge?: number;
18
18
  }
19
19
 
20
- // ─── Función ─────────────────────────────────────────────
20
+ // ─── Helpers ─────────────────────────────────────────────
21
21
 
22
- export default async function getGeoLocation(options: GeoLocationOptions = {}): Promise<GeoLocation> {
22
+ function positionToGeoLocation(position: GeolocationPosition): GeoLocation {
23
+ const {coords, timestamp} = position;
24
+ return {
25
+ latitude: coords.latitude,
26
+ longitude: coords.longitude,
27
+ accuracy: coords.accuracy,
28
+ altitude: coords.altitude,
29
+ altitudeAccuracy: coords.altitudeAccuracy,
30
+ heading: coords.heading,
31
+ speed: coords.speed,
32
+ timestamp,
33
+ };
34
+ }
23
35
 
24
- // ── Soporte del navegador ────────────────────────────
25
- if (!navigator.geolocation) {
26
- throw new Error('Tu navegador no soporta geolocalización.');
36
+ function geolocationError(error: GeolocationPositionError): Error {
37
+ switch (error.code) {
38
+ case error.PERMISSION_DENIED:
39
+ return new Error('Has denegado el permiso de ubicación.');
40
+ case error.POSITION_UNAVAILABLE:
41
+ return new Error('No se pudo determinar tu ubicación.');
42
+ case error.TIMEOUT:
43
+ return new Error('Tiempo de espera agotado al obtener la ubicación.');
44
+ default:
45
+ return new Error('Error desconocido al obtener la ubicación.');
46
+ }
47
+ }
48
+
49
+ function requestPosition(options: PositionOptions): Promise<GeoLocation> {
50
+ return new Promise((resolve, reject) => {
51
+ navigator.geolocation.getCurrentPosition(
52
+ (position) => resolve(positionToGeoLocation(position)),
53
+ (error) => reject(geolocationError(error)),
54
+ options,
55
+ );
56
+ });
57
+ }
58
+
59
+ async function ensurePermission(): Promise<void> {
60
+ if (!navigator.permissions) return;
61
+
62
+ const permission = await navigator.permissions.query({name: 'geolocation'});
63
+
64
+ if (permission.state === 'denied') {
65
+ throw new Error(
66
+ 'Permiso de ubicación denegado. Actívalo en la configuración del navegador.',
67
+ );
27
68
  }
28
69
 
29
- // ── Comprobar permisos (API Permissions) ─────────────
30
- if (navigator.permissions) {
31
- const permission = await navigator.permissions.query({ name: 'geolocation' });
70
+ if (permission.state === 'prompt') {
71
+ await new Promise<void>((resolve, reject) => {
72
+ // Escuchar cambio de estado del permiso
73
+ permission.onchange = () => {
74
+ permission.onchange = null;
75
+ if (permission.state === 'granted') {
76
+ resolve();
77
+ } else {
78
+ reject(new Error('Has denegado el permiso de ubicación.'));
79
+ }
80
+ };
32
81
 
33
- if (permission.state === 'denied') {
34
- throw new Error(
35
- 'Permiso de ubicación denegado. Actívalo en la configuración del navegador.'
82
+ // Forzar el diálogo nativo del navegador
83
+ navigator.geolocation.getCurrentPosition(
84
+ () => {
85
+ permission.onchange = null;
86
+ resolve();
87
+ },
88
+ (error) => {
89
+ permission.onchange = null;
90
+ reject(geolocationError(error));
91
+ },
92
+ {timeout: 30000},
36
93
  );
37
- }
94
+ });
95
+ }
96
+ }
97
+
98
+ // ─── Función principal ──────────────────────────────────
99
+
100
+ export default async function getGeoLocation(
101
+ options: GeoLocationOptions = {},
102
+ ): Promise<GeoLocation> {
103
+ if (!navigator.geolocation) {
104
+ throw new Error('Tu navegador no soporta geolocalización.');
38
105
  }
39
106
 
40
- // ── Pedir ubicación ──────────────────────────────────
41
- const defaultOptions: PositionOptions = {
107
+ await ensurePermission();
108
+
109
+ return requestPosition({
42
110
  enableHighAccuracy: options.enableHighAccuracy ?? true,
43
111
  timeout: options.timeout ?? 10000,
44
112
  maximumAge: options.maximumAge ?? 0,
45
- };
46
-
47
- return new Promise<GeoLocation>((resolve, reject) => {
48
- navigator.geolocation.getCurrentPosition(
49
- (position) => {
50
- const { coords, timestamp } = position;
51
- resolve({
52
- latitude: coords.latitude,
53
- longitude: coords.longitude,
54
- accuracy: coords.accuracy,
55
- altitude: coords.altitude,
56
- altitudeAccuracy: coords.altitudeAccuracy,
57
- heading: coords.heading,
58
- speed: coords.speed,
59
- timestamp,
60
- });
61
- },
62
- (error) => {
63
- switch (error.code) {
64
- case error.PERMISSION_DENIED:
65
- reject(new Error('Has denegado el permiso de ubicación.'));
66
- break;
67
- case error.POSITION_UNAVAILABLE:
68
- reject(new Error('No se pudo determinar tu ubicación.'));
69
- break;
70
- case error.TIMEOUT:
71
- reject(new Error('Tiempo de espera agotado al obtener la ubicación.'));
72
- break;
73
- default:
74
- reject(new Error('Error desconocido al obtener la ubicación.'));
75
- }
76
- },
77
- defaultOptions,
78
- );
79
113
  });
80
114
  }
@@ -1,5 +1,116 @@
1
- export * from './form-utilities.js'
2
-
3
- export {default as NativeBridge} from "./native-bridge.js"
4
-
1
+ import {delay} from "../utilities.js";
2
+
3
+ interface FetchIntoOptions {
4
+ url?: string;
5
+ fetchOptions?: RequestInit;
6
+ runScripts?: boolean;
7
+ transition?: string;
8
+ }
9
+
10
+ export async function waitFor(
11
+ selector: string,
12
+ options: { timeout?: number } = {}
13
+ ): Promise<HTMLElement | null> {
14
+ const {timeout = 5000} = options;
15
+
16
+ const element = document.querySelector(selector);
17
+ if (element) {
18
+ return element as HTMLElement;
19
+ }
20
+
21
+ let observer: MutationObserver | undefined;
22
+ const timeoutPromise = delay(timeout).then(() => {
23
+ observer?.disconnect();
24
+ return null;
25
+ });
26
+
27
+ const observerPromise = new Promise<HTMLElement | null>((resolve) => {
28
+ observer = new MutationObserver(() => {
29
+ const element = document.querySelector(selector);
30
+ if (element) {
31
+ observer?.disconnect();
32
+ resolve(element as HTMLElement);
33
+ }
34
+ });
35
+
36
+ observer.observe(document.body, {
37
+ childList: true,
38
+ subtree: true,
39
+ });
40
+ });
41
+
42
+ return Promise.race([observerPromise, timeoutPromise]);
43
+ }
44
+
45
+ export async function fetchInto(
46
+ selector: string,
47
+ options: FetchIntoOptions = {}
48
+ ): Promise<number> {
49
+ const {
50
+ url = window.location.href,
51
+ fetchOptions = {},
52
+ runScripts = false,
53
+ transition = null,
54
+ } = options;
55
+
56
+ const response = await fetch(url, fetchOptions);
57
+
58
+ if (!response.ok) {
59
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
60
+ }
61
+
62
+ const html = await response.text();
63
+ const doc = new DOMParser().parseFromString(html, "text/html");
64
+ const oldElements = document.querySelectorAll(selector);
65
+ let replacedCount = 0;
66
+
67
+ for (let i = 0; i < oldElements.length; i++) {
68
+ const oldEl = oldElements[i];
69
+ const newEl = doc.querySelector(selector);
70
+
71
+ if (!newEl) continue;
72
+
73
+ if (transition) {
74
+ oldEl.classList.add(transition);
75
+ await new Promise<void>((r) =>
76
+ requestAnimationFrame(() => requestAnimationFrame(() => r()))
77
+ );
78
+ }
79
+
80
+ oldEl.replaceWith(newEl.cloneNode(true));
81
+
82
+ if (runScripts) {
83
+ const scripts = newEl.querySelectorAll("script");
84
+
85
+ for (let j = 0; j < scripts.length; j++) {
86
+ const script = scripts[j];
87
+ const fresh = document.createElement("script");
88
+
89
+ if (script.src) {
90
+ fresh.src = script.src;
91
+ } else {
92
+ fresh.textContent = script.textContent;
93
+ }
94
+
95
+ const attrs = script.attributes;
96
+ for (let k = 0; k < attrs.length; k++) {
97
+ if (attrs[k].name !== "src") {
98
+ fresh.setAttribute(attrs[k].name, attrs[k].value);
99
+ }
100
+ }
101
+
102
+ script.replaceWith(fresh);
103
+ }
104
+ }
105
+
106
+ replacedCount++;
107
+ }
108
+
109
+ return replacedCount;
110
+ }
111
+
112
+ export * from './form-utilities.js'
113
+
114
+ export {default as NativeBridge} from "./native-bridge.js"
115
+
5
116
  export {default as getGeoLocation} from './geo-location.js';
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes