native-document 1.0.9 → 1.0.11

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.
package/router.js CHANGED
@@ -1,9 +1,11 @@
1
1
 
2
2
  import Router from "./src/router/Router.js";
3
+ import {RouteParamPatterns} from "./src/router/Route.js";
3
4
  import { Link } from './src/router/link.js';
4
5
 
5
6
 
6
7
  export {
8
+ RouteParamPatterns,
7
9
  Router,
8
10
  Link
9
11
  }
@@ -5,10 +5,15 @@ const MemoryManager = (function() {
5
5
 
6
6
  let $nexObserverId = 0;
7
7
  const $observables = new Map();
8
- const $registry = new FinalizationRegistry((heldValue) => {
9
- DebugManager.log('MemoryManager', '🧹 Auto-cleanup observable:', heldValue);
10
- heldValue.listeners.splice(0);
11
- })
8
+ let $registry = null;
9
+ try {
10
+ $registry = new FinalizationRegistry((heldValue) => {
11
+ DebugManager.log('MemoryManager', '🧹 Auto-cleanup observable:', heldValue);
12
+ heldValue.listeners.splice(0);
13
+ });
14
+ } catch (e) {
15
+ DebugManager.warn('MemoryManager', 'FinalizationRegistry not supported, observables will not be cleaned automatically');
16
+ }
12
17
 
13
18
  return {
14
19
  /**
@@ -24,10 +29,15 @@ const MemoryManager = (function() {
24
29
  id: id,
25
30
  listeners
26
31
  };
27
- $registry.register(observable, heldValue);
32
+ if($registry) {
33
+ $registry.register(observable, heldValue);
34
+ }
28
35
  $observables.set(id, new WeakRef(observable));
29
36
  return id;
30
37
  },
38
+ getObservableById(id) {
39
+ return $observables.get(id)?.deref();
40
+ },
31
41
  cleanup() {
32
42
  for (const [_, weakObservableRef] of $observables) {
33
43
  const observable = weakObservableRef.deref();
@@ -14,18 +14,31 @@ export function Observable(value) {
14
14
  return new ObservableItem(value);
15
15
  }
16
16
 
17
-
18
17
  Observable.computed = function(callback, dependencies = []) {
19
18
  const initialValue = callback();
20
19
  const observable = new ObservableItem(initialValue);
21
20
 
22
- const updatedValue = throttle(() => observable.set(callback()), 10, { debounce: true });
21
+ const updatedValue = () => observable.set(callback());
23
22
 
24
23
  dependencies.forEach(dependency => dependency.subscribe(updatedValue));
25
24
 
26
25
  return observable;
27
26
  };
28
27
 
28
+ /**
29
+ *
30
+ * @param id
31
+ * @returns {ObservableItem|null}
32
+ */
33
+ Observable.getById = function(id) {
34
+ const item = MemoryManager.getObservableById(parseInt(id));
35
+ if(!item) {
36
+ throw new NativeDocumentError('Observable.getById : No observable found with id ' + id);
37
+ }
38
+ return item;
39
+ };
40
+
41
+
29
42
  /**
30
43
  *
31
44
  * @param {ObservableItem} observable
@@ -120,6 +133,26 @@ Observable.init = function(value) {
120
133
 
121
134
  Observable.object = Observable.init;
122
135
  Observable.json = Observable.init;
136
+ Observable.update = function($target, data) {
137
+ for(const key in data) {
138
+ const targetItem = $target[key];
139
+ const newValue = data[key];
140
+
141
+ if(Validator.isObservable(targetItem)) {
142
+ if(Validator.isArray(newValue)) {
143
+ Observable.update(targetItem, newValue);
144
+ continue;
145
+ }
146
+ targetItem.set(newValue);
147
+ continue;
148
+ }
149
+ if(Validator.isProxy(targetItem)) {
150
+ Observable.update(targetItem, newValue);
151
+ continue;
152
+ }
153
+ $target[key] = newValue;
154
+ }
155
+ };
123
156
  /**
124
157
  *
125
158
  * @param {Array} target
@@ -17,6 +17,9 @@ export default function ObservableChecker($observable, $checker) {
17
17
  this.val = function() {
18
18
  return $checker && $checker($observable.val());
19
19
  };
20
+ this.check = function(callback) {
21
+ return $observable.check(() => callback(this.val()));
22
+ };
20
23
 
21
24
  this.set = function(value) {
22
25
  return $observable.set(value);
@@ -109,4 +109,8 @@ export default function ObservableItem(value) {
109
109
  }
110
110
  })
111
111
 
112
+ this.toString = function() {
113
+ return '{{#ObItem::(' +$memoryId+ ')}}';
114
+ };
115
+
112
116
  }
package/src/data/Store.js CHANGED
@@ -11,7 +11,7 @@ export const Store = (function() {
11
11
  * @returns {ObservableItem}
12
12
  */
13
13
  use(name) {
14
- const {observer: originalObserver, followers } = $stores.get(name);
14
+ const {observer: originalObserver, subscribers } = $stores.get(name);
15
15
  const observerFollower = Observable(originalObserver.val());
16
16
  const unSubscriber = originalObserver.subscribe(value => observerFollower.set(value));
17
17
  const updaterUnsubscriber = observerFollower.subscribe(value => originalObserver.set(value));
@@ -20,7 +20,7 @@ export const Store = (function() {
20
20
  updaterUnsubscriber();
21
21
  observerFollower.cleanup();
22
22
  };
23
- followers.add(observerFollower);
23
+ subscribers.add(observerFollower);
24
24
 
25
25
  return observerFollower;
26
26
  },
@@ -39,7 +39,7 @@ export const Store = (function() {
39
39
  */
40
40
  create(name, value) {
41
41
  const observer = Observable(value);
42
- $stores.set(name, { observer, followers: new Set()});
42
+ $stores.set(name, { observer, subscribers: new Set()});
43
43
  return observer;
44
44
  },
45
45
  /**
@@ -54,9 +54,9 @@ export const Store = (function() {
54
54
  /**
55
55
  *
56
56
  * @param {string} name
57
- * @returns {{observer: ObservableItem, followers: Set}}
57
+ * @returns {{observer: ObservableItem, subscribers: Set}}
58
58
  */
59
- getWithFollowers(name) {
59
+ getWithSubscribers(name) {
60
60
  return $stores.get(name);
61
61
  },
62
62
  /**
@@ -67,7 +67,7 @@ export const Store = (function() {
67
67
  const item = $stores.get(name);
68
68
  if(!item) return;
69
69
  item.observer.cleanup();
70
- item.followers.forEach(follower => follower.destroy());
70
+ item.subscribers.forEach(follower => follower.destroy());
71
71
  item.observer.clear();
72
72
  }
73
73
  };
@@ -9,7 +9,7 @@ import MemoryRouter from "./modes/MemoryRouter.js";
9
9
  import DebugManager from "../utils/debug-manager.js";
10
10
  import {RouterComponent} from "./RouterComponent.js";
11
11
 
12
- const DEFAULT_ROUTER_NAME = 'default';
12
+ export const DEFAULT_ROUTER_NAME = 'default';
13
13
 
14
14
  /**
15
15
  *
@@ -209,21 +209,21 @@ Router.create = function(options, callback) {
209
209
 
210
210
  router.init(options.entry);
211
211
 
212
- return {
213
- mount: (container) => {
214
- if(Validator.isString(container)) {
215
- const mountContainer = document.querySelector(container);
216
- if(!mountContainer) {
217
- throw new RouterError(`Container not found for selector: ${container}`);
218
- }
219
- container = mountContainer;
220
- } else if(!Validator.isElement(container)) {
221
- throw new RouterError('Container must be a string or an Element');
212
+ router.mount = function(container) {
213
+ if(Validator.isString(container)) {
214
+ const mountContainer = document.querySelector(container);
215
+ if(!mountContainer) {
216
+ throw new RouterError(`Container not found for selector: ${container}`);
222
217
  }
223
-
224
- RouterComponent(router, container);
218
+ container = mountContainer;
219
+ } else if(!Validator.isElement(container)) {
220
+ throw new RouterError('Container must be a string or an Element');
225
221
  }
222
+
223
+ return RouterComponent(router, container);
226
224
  };
225
+
226
+ return router;
227
227
  };
228
228
 
229
229
  Router.get = function(name) {
@@ -1,20 +1,23 @@
1
1
  import Validator from "../utils/validator.js";
2
2
  import {Link as NativeLink} from "../../elements.js";
3
- import Router from "./Router.js";
3
+ import Router, {DEFAULT_ROUTER_NAME} from "./Router.js";
4
4
  import RouterError from "../errors/RouterError.js";
5
5
 
6
6
 
7
- export function Link(attributes, children){
8
- const target = attributes.to || attributes.href;
7
+ export function Link(options, children){
8
+ const { to, href, ...attributes } = options;
9
+ const target = to || href;
9
10
  if(Validator.isString(target)) {
10
11
  const router = Router.get();
11
12
  return NativeLink({ ...attributes, href: target}, children).nd.on.prevent.click(() => {
12
13
  router.push(target);
13
14
  });
14
15
  }
15
- const router = Router.get(target.router);
16
+ const routerName = target.router || DEFAULT_ROUTER_NAME;
17
+ const router = Router.get(routerName);
18
+ console.log(routerName)
16
19
  if(!router) {
17
- throw new RouterError('Router not found "'+target.router+'" for link "'+target.name+'"');
20
+ throw new RouterError('Router not found "'+routerName+'" for link "'+target.name+'"');
18
21
  }
19
22
  const url = router.generateUrl(target.name, target.params, target.query);
20
23
  return NativeLink({ ...attributes, href: url }, children).nd.on.prevent.click(() => {
@@ -0,0 +1,12 @@
1
+
2
+ const pluginsManager = (function() {
3
+
4
+ const $plugins = [];
5
+
6
+ return {
7
+ list : () => $plugins,
8
+ add : (plugin) => $plugins.push(plugin)
9
+ };
10
+ }());
11
+
12
+ export default pluginsManager;
@@ -29,4 +29,17 @@ String.prototype.use = function(args) {
29
29
  return data;
30
30
  });
31
31
  }, Object.values(args));
32
+ };
33
+
34
+ String.prototype.resolveObservableTemplate = function() {
35
+ if(!Validator.containsObservableReference(this)) {
36
+ return this;
37
+ }
38
+ return this.split(/(\{\{#ObItem::\([0-9]+\)\}\})/g).filter(Boolean).map((value) => {
39
+ if(!Validator.containsObservableReference(value)) {
40
+ return value;
41
+ }
42
+ const [_, id] = value.match(/\{\{#ObItem::\(([0-9]+)\)\}\}/);
43
+ return Observable.getById(id);
44
+ });
32
45
  }
@@ -70,7 +70,29 @@ const Validator = {
70
70
 
71
71
  return children;
72
72
  },
73
-
73
+ /**
74
+ * Check if the data contains observables.
75
+ * @param {Array|Object} data
76
+ * @returns {boolean}
77
+ */
78
+ containsObservables(data) {
79
+ if(!data) {
80
+ return false;
81
+ }
82
+ return Validator.isObject(data)
83
+ && Object.values(data).some(value => Validator.isObservable(value));
84
+ },
85
+ /**
86
+ * Check if the data contains an observable reference.
87
+ * @param {string} data
88
+ * @returns {boolean}
89
+ */
90
+ containsObservableReference(data) {
91
+ if(!data || typeof data !== 'string') {
92
+ return false;
93
+ }
94
+ return /\{\{#ObItem::\([0-9]+\)\}\}/.test(data);
95
+ },
74
96
  validateAttributes(attributes) {
75
97
  if (!attributes || typeof attributes !== 'object') {
76
98
  return attributes;
@@ -1,6 +1,7 @@
1
1
  import Validator from "../utils/validator";
2
2
  import NativeDocumentError from "../errors/NativeDocumentError";
3
3
  import {BOOLEAN_ATTRIBUTES} from "./constants.js";
4
+ import {Observable} from "../data/Observable";
4
5
 
5
6
  /**
6
7
  *
@@ -124,7 +125,16 @@ export default function AttributesWrapper(element, attributes) {
124
125
 
125
126
  for(let key in attributes) {
126
127
  const attributeName = key.toLowerCase();
127
- const value = attributes[attributeName];
128
+ let value = attributes[attributeName];
129
+ if(Validator.isString(value) && Validator.isFunction(value.resolveObservableTemplate)) {
130
+ value = value.resolveObservableTemplate();
131
+ if(Validator.isArray(value)) {
132
+ const observables = value.filter(item => Validator.isObservable(item));
133
+ value = Observable.computed(() => {
134
+ return value.map(item => Validator.isObservable(item) ? item.val() : item).join(' ') || ' ';
135
+ }, observables);
136
+ }
137
+ }
128
138
  if(BOOLEAN_ATTRIBUTES.includes(attributeName)) {
129
139
  bindBooleanAttribute(element, attributeName, value);
130
140
  continue;
@@ -5,6 +5,7 @@ import DocumentObserver from "./DocumentObserver";
5
5
  import Validator from "../utils/validator";
6
6
  import DebugManager from "../utils/debug-manager";
7
7
  import Anchor from "../elements/anchor";
8
+ import PluginsManager from "../utils/plugins-manager";
8
9
 
9
10
  /**
10
11
  *
@@ -116,6 +117,9 @@ export const ElementCreator = {
116
117
  const childrenArray = Array.isArray(children) ? children : [children];
117
118
  childrenArray.forEach(child => {
118
119
  if (child === null) return;
120
+ if(Validator.isString(child) && Validator.isFunction(child.resolveObservableTemplate)) {
121
+ child = child.resolveObservableTemplate();
122
+ }
119
123
  if(Validator.isFunction(child)) {
120
124
  this.processChildren(child(), parent);
121
125
  return;
@@ -160,6 +164,11 @@ export const ElementCreator = {
160
164
  HtmlElementEventsWrapper(element);
161
165
  const item = (typeof customWrapper === 'function') ? customWrapper(element) : element;
162
166
  addUtilsMethods(item);
167
+
168
+ PluginsManager.list().forEach(plugin => {
169
+ plugin?.element?.setup && plugin.element.setup(item, attributes);
170
+ });
171
+
163
172
  return item;
164
173
  }
165
174
  };
@@ -189,7 +198,7 @@ export default function HtmlElementWrapper(name, customWrapper) {
189
198
  } catch (error) {
190
199
  DebugManager.error('ElementCreation', `Error creating ${$tagName}`, error);
191
200
  }
192
- }
201
+ };
193
202
 
194
203
  builder.hold = (children, attributes) => (() => builder(children, attributes));
195
204