native-document 1.0.17-1.7 → 1.0.17-1.9
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/package.json +1 -1
- package/src/core/data/MemoryManager.js +6 -1
- package/src/core/data/ObservableItem.js +6 -1
- package/src/core/elements/content-formatter.js +19 -0
- package/src/core/elements/control/for-each-array.js +2 -2
- package/src/core/wrappers/AttributesWrapper.js +5 -5
- package/src/core/wrappers/ElementCreator.js +10 -0
- package/src/core/wrappers/HtmlElementWrapper.js +1 -1
- package/src/core/wrappers/NDElement.js +0 -1
- package/src/core/wrappers/NdPrototype.js +27 -6
- package/src/core/wrappers/prototypes/nd-element-extensions.js +37 -0
- package/types/elements.d.ts +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "native-document",
|
|
3
|
-
"version": "1.0.171.
|
|
3
|
+
"version": "1.0.171.9",
|
|
4
4
|
"description": "A reactive JavaScript framework that preserves native DOM simplicity without sacrificing modern features",
|
|
5
5
|
"author": "AfroCodeur <https://github.com/afrocodeur>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,7 +23,12 @@ const MemoryManager = (function() {
|
|
|
23
23
|
$observables.delete(id);
|
|
24
24
|
},
|
|
25
25
|
getObservableById(id) {
|
|
26
|
-
|
|
26
|
+
const observable = $observables.get(id);
|
|
27
|
+
if(!observable) {
|
|
28
|
+
$observables.delete(id);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return observable.deref();
|
|
27
32
|
},
|
|
28
33
|
cleanup() {
|
|
29
34
|
for (const [_, weakObservableRef] of $observables) {
|
|
@@ -556,7 +556,12 @@ ObservableItem.prototype.reset = function() {
|
|
|
556
556
|
* @returns {string} String representation of the current value
|
|
557
557
|
*/
|
|
558
558
|
ObservableItem.prototype.toString = function() {
|
|
559
|
-
|
|
559
|
+
if(this.$id) {
|
|
560
|
+
return this.$id.toString();
|
|
561
|
+
}
|
|
562
|
+
const id = MemoryManager.register(this);
|
|
563
|
+
this.$id = id;
|
|
564
|
+
return '{{obs:'+id+'}}';
|
|
560
565
|
};
|
|
561
566
|
|
|
562
567
|
/**
|
|
@@ -24,6 +24,25 @@ export const Label = HtmlElementWrapper('label');
|
|
|
24
24
|
*/
|
|
25
25
|
export const P = HtmlElementWrapper('p');
|
|
26
26
|
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Parses a string containing Observable placeholders and returns an array
|
|
30
|
+
* of strings and Observable instances ready to be used as NativeDocument children.
|
|
31
|
+
*
|
|
32
|
+
* Observable placeholders are generated automatically when an ObservableItem
|
|
33
|
+
* is interpolated in a template string via its toString() method.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} string - Template string with optional Observable placeholders
|
|
36
|
+
* @returns {Array<string|ObservableItem>} Mixed array of static strings and resolved Observables
|
|
37
|
+
* @example
|
|
38
|
+
* const name = Observable('John');
|
|
39
|
+
* const count = Observable(5);
|
|
40
|
+
*
|
|
41
|
+
* Text(`Hello ${name}, count: ${count}`)
|
|
42
|
+
* // → ['Hello ', ObservableItem(John), ', count: ', ObservableItem(5)]
|
|
43
|
+
*/
|
|
44
|
+
export const Text = (string) => string.toNdChildren();
|
|
45
|
+
|
|
27
46
|
/**
|
|
28
47
|
* Alias for {@link P}.
|
|
29
48
|
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLParagraphElement}
|
|
@@ -176,11 +176,11 @@ export function ForEachArray(data, callback, configs = {}) {
|
|
|
176
176
|
}
|
|
177
177
|
},
|
|
178
178
|
add: (items) => {
|
|
179
|
-
Actions.appendToElement(items)
|
|
179
|
+
Actions.appendToElement(items);
|
|
180
180
|
},
|
|
181
181
|
replace: (items) => {
|
|
182
182
|
clear(items);
|
|
183
|
-
Actions.appendToElement(items)
|
|
183
|
+
Actions.appendToElement(items);
|
|
184
184
|
},
|
|
185
185
|
set,
|
|
186
186
|
reOrder: (items) => {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import Validator from '../utils/validator';
|
|
2
|
-
import NativeDocumentError from '../errors/NativeDocumentError';
|
|
3
2
|
import {BOOL_ATTRIBUTES_NAME, BOOLEAN_ATTRIBUTES} from './constants.js';
|
|
4
3
|
import {Observable} from '../data/Observable';
|
|
5
4
|
|
|
5
|
+
|
|
6
|
+
|
|
6
7
|
/**
|
|
7
8
|
* Applies a reactive class map to an HTMLElement.
|
|
8
9
|
* Each key is a CSS class name; each value is a boolean or ObservableItem<boolean>.
|
|
@@ -14,7 +15,6 @@ import {Observable} from '../data/Observable';
|
|
|
14
15
|
export const bindClassAttribute = (element, data) => {
|
|
15
16
|
for(const className in data) {
|
|
16
17
|
const value = data[className];
|
|
17
|
-
|
|
18
18
|
if (value.__$isObservableChecker) {
|
|
19
19
|
let lastClass = value.val();
|
|
20
20
|
if (typeof lastClass === 'string') {
|
|
@@ -24,19 +24,19 @@ export const bindClassAttribute = (element, data) => {
|
|
|
24
24
|
element.classes.toggle(currentValue, true);
|
|
25
25
|
lastClass = currentValue;
|
|
26
26
|
});
|
|
27
|
-
|
|
27
|
+
return;
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
if (value.__$Observable) {
|
|
32
32
|
element.classes.toggle(className, value.val());
|
|
33
33
|
value.subscribe((shouldAdd) => element.classes.toggle(className, shouldAdd));
|
|
34
|
-
|
|
34
|
+
return;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
if (value.$hydrate) {
|
|
38
38
|
value.$hydrate(element, className);
|
|
39
|
-
|
|
39
|
+
return;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
element.classes.toggle(className, value);
|
|
@@ -88,6 +88,16 @@ export const ElementCreator = {
|
|
|
88
88
|
if(process.env.NODE_ENV === 'development') {
|
|
89
89
|
PluginsManager.emit('BeforeProcessChildren', parent);
|
|
90
90
|
}
|
|
91
|
+
if(Array.isArray(children)) {
|
|
92
|
+
for(let i = 0, length = children.length; i < length; i++) {
|
|
93
|
+
const child = ElementCreator.getChild(children[i]);
|
|
94
|
+
if(child === null) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
parent.appendChild(child);
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
91
101
|
const child = ElementCreator.getChild(children);
|
|
92
102
|
parent.appendChild(child);
|
|
93
103
|
if(process.env.NODE_ENV === 'development') {
|
|
@@ -54,7 +54,7 @@ const OBJECT_PROTOTYPE = Object.prototype;
|
|
|
54
54
|
*/
|
|
55
55
|
export const createHtmlElement = (element, _attributes, _children = null) => {
|
|
56
56
|
let attributes = _attributes, children = _children;
|
|
57
|
-
if(_attributes
|
|
57
|
+
if(_attributes?.__$isValidNdChild) { // If attributes is a ValidChild
|
|
58
58
|
attributes = _children;
|
|
59
59
|
children = _attributes;
|
|
60
60
|
}
|
|
@@ -20,13 +20,17 @@ Object.defineProperty(NDElement.prototype, 'nd', {
|
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
|
|
24
23
|
// ----------------------------------------------------------------
|
|
25
24
|
// Events helpers
|
|
26
25
|
// ----------------------------------------------------------------
|
|
27
26
|
EVENTS.forEach(eventSourceName => {
|
|
28
27
|
const eventName = eventSourceName.toLowerCase();
|
|
29
|
-
|
|
28
|
+
const inlineHandler = 'on'+eventName;
|
|
29
|
+
NDElement.prototype['on'+eventSourceName] = function(callback = null, options = null) {
|
|
30
|
+
if(!this.$element[inlineHandler] && !options) {
|
|
31
|
+
this.$element[inlineHandler] = callback;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
30
34
|
this.$element.addEventListener(eventName, callback, options);
|
|
31
35
|
return this;
|
|
32
36
|
};
|
|
@@ -34,11 +38,11 @@ EVENTS.forEach(eventSourceName => {
|
|
|
34
38
|
|
|
35
39
|
EVENTS_WITH_STOP.forEach(eventSourceName => {
|
|
36
40
|
const eventName = eventSourceName.toLowerCase();
|
|
37
|
-
NDElement.prototype['onStop'+eventSourceName] = function(callback = null, options =
|
|
41
|
+
NDElement.prototype['onStop'+eventSourceName] = function(callback = null, options = null) {
|
|
38
42
|
_stop(this.$element, eventName, callback, options);
|
|
39
43
|
return this;
|
|
40
44
|
};
|
|
41
|
-
NDElement.prototype['onPreventStop'+eventSourceName] = function(callback = null, options =
|
|
45
|
+
NDElement.prototype['onPreventStop'+eventSourceName] = function(callback = null, options = null) {
|
|
42
46
|
_preventStop(this.$element, eventName, callback, options);
|
|
43
47
|
return this;
|
|
44
48
|
};
|
|
@@ -46,7 +50,7 @@ EVENTS_WITH_STOP.forEach(eventSourceName => {
|
|
|
46
50
|
|
|
47
51
|
EVENTS_WITH_PREVENT.forEach(eventSourceName => {
|
|
48
52
|
const eventName = eventSourceName.toLowerCase();
|
|
49
|
-
NDElement.prototype['onPrevent'+eventSourceName] = function(callback = null, options =
|
|
53
|
+
NDElement.prototype['onPrevent'+eventSourceName] = function(callback = null, options = null) {
|
|
50
54
|
_prevent(this.$element, eventName, callback, options);
|
|
51
55
|
return this;
|
|
52
56
|
};
|
|
@@ -122,8 +126,13 @@ const _prevent = function(element, eventName, callback, options) {
|
|
|
122
126
|
event.preventDefault();
|
|
123
127
|
callback && callback.call(element, event);
|
|
124
128
|
};
|
|
129
|
+
|
|
130
|
+
const inlineHandler = 'on' + eventName;
|
|
131
|
+
if(!element[inlineHandler] && !options) {
|
|
132
|
+
element[inlineHandler] = handler;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
125
135
|
element.addEventListener(eventName, handler, options);
|
|
126
|
-
return this;
|
|
127
136
|
};
|
|
128
137
|
|
|
129
138
|
const _stop = function(element, eventName, callback, options) {
|
|
@@ -131,6 +140,13 @@ const _stop = function(element, eventName, callback, options) {
|
|
|
131
140
|
event.stopPropagation();
|
|
132
141
|
callback && callback.call(element, event);
|
|
133
142
|
};
|
|
143
|
+
|
|
144
|
+
const inlineHandler = 'on' + eventName;
|
|
145
|
+
if(!element[inlineHandler] && !options) {
|
|
146
|
+
element[inlineHandler] = handler;
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
134
150
|
element.addEventListener(eventName, handler, options);
|
|
135
151
|
return this;
|
|
136
152
|
};
|
|
@@ -141,6 +157,11 @@ const _preventStop = function(element, eventName, callback, options) {
|
|
|
141
157
|
event.preventDefault();
|
|
142
158
|
callback && callback.call(element, event);
|
|
143
159
|
};
|
|
160
|
+
const inlineHandler = 'on' + eventName;
|
|
161
|
+
if(!element[inlineHandler] && !options) {
|
|
162
|
+
element[inlineHandler] = handler;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
144
165
|
element.addEventListener(eventName, handler, options);
|
|
145
166
|
return this;
|
|
146
167
|
};
|
|
@@ -4,6 +4,43 @@ import TemplateBinding from '../TemplateBinding';
|
|
|
4
4
|
import { ElementCreator } from '../ElementCreator';
|
|
5
5
|
import PluginsManager from '../../utils/plugins-manager';
|
|
6
6
|
import ObservableChecker from '../../data/ObservableChecker';
|
|
7
|
+
import MemoryManager from '../../data/MemoryManager';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const OBS_PATTERN = /({{obs:\d+}})/;
|
|
12
|
+
const OBS_ID_PATTERN = /\d+/;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parses a string containing Observable placeholders and returns an array
|
|
17
|
+
* of strings and Observable instances.
|
|
18
|
+
*
|
|
19
|
+
* Placeholders are generated automatically when an ObservableItem is interpolated
|
|
20
|
+
* in a template string via its toString() method.
|
|
21
|
+
*
|
|
22
|
+
* @returns {Array<string|ObservableItem>} Mixed array of static strings and resolved Observables
|
|
23
|
+
* @example
|
|
24
|
+
* const name = Observable('John');
|
|
25
|
+
* const count = Observable(5);
|
|
26
|
+
*
|
|
27
|
+
* `Hello ${name}, count: ${count}`.toNdChildren()
|
|
28
|
+
* // → ['Hello ', ObservableItem(John), ', count: ', ObservableItem(5)]
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(String.prototype, 'toNdChildren', {
|
|
31
|
+
value: function() {
|
|
32
|
+
return this.split(OBS_PATTERN).filter(Boolean).map((item) => {
|
|
33
|
+
if(OBS_PATTERN.test(item)) {
|
|
34
|
+
const id = item.match(OBS_ID_PATTERN)[0];
|
|
35
|
+
return MemoryManager.getObservableById(Number(id));
|
|
36
|
+
}
|
|
37
|
+
return item;
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
writable: true,
|
|
41
|
+
configurable: true,
|
|
42
|
+
enumerable: false,
|
|
43
|
+
});
|
|
7
44
|
|
|
8
45
|
/**
|
|
9
46
|
* Registers a non-enumerable toNdElement method on a prototype.
|
package/types/elements.d.ts
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import { ObservableItem } from './observable';
|
|
3
3
|
import { BindingHydrator } from './template-cloner';
|
|
4
4
|
import { NDElement } from './nd-element';
|
|
5
|
+
import {AnchorAttributes,
|
|
6
|
+
AudioAttributes, CanvasAttributes, DetailsAttributes, DialogAttributes, GlobalAttributes, OlAttributes,
|
|
7
|
+
SourceAttributes, SvgAttributes, TrackAttributes, VideoAttributes, ThAttributes, ModAttributes, TdAttributes, TimeAttributes } from './globals';
|
|
5
8
|
|
|
6
9
|
// - Re-export all attribute types and utilities from globals
|
|
7
10
|
export type {
|
|
@@ -75,6 +78,8 @@ export type NdHTMLElement<T extends HTMLElement = HTMLElement> = T & { nd: NDEle
|
|
|
75
78
|
// Text & structural elements
|
|
76
79
|
// ---------------------------------------------------------
|
|
77
80
|
|
|
81
|
+
|
|
82
|
+
export declare function Text(string: string): string | Array<string | ObservableItem>;
|
|
78
83
|
export declare const Div: ElementFunction<GlobalAttributes, HTMLDivElement>;
|
|
79
84
|
export declare const Span: ElementFunction<GlobalAttributes, HTMLSpanElement>;
|
|
80
85
|
export declare const P: ElementFunction<GlobalAttributes, HTMLParagraphElement>;
|