structured-fw 0.9.2 → 0.9.4

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/README.md CHANGED
@@ -644,6 +644,7 @@ Methods:
644
644
  - `find(componentName: string, recursive: boolean = true): ClientComponent | null` - find a child component
645
645
  - `findParent(componentName: string): ClientComponent | null` - find the first parent with given name
646
646
  - `query(componentName: string, recursive: boolean = true): Array<ClientComponent>` - return all components with given name found within this component, if `recursive = false`, only direct children are considered
647
+ - `bind(element: HTMLElement, eventName: string | Array<string>, callback: (e: Event) => void): void` - adds event listener(s) to given element. This is preferred over addEventListener because when the component is redrawn/removed, the event listeners added using bind method are automatically removed
647
648
  - `ref<T>(refName: string): T` - get a HTMLElement or ClientComponent that has attribute `ref="[refName]"`
648
649
  - `arrayRef<T>(refName: string): Array<T>` - get an array of HTMLElement or ClientComponent that have attribute `array:ref="[refName]"`
649
650
  - `add(appendTo: HTMLElement, componentName: string, data?: LooseObject): Promise<ClientComponent | null>` - add `componentName` component to `appendTo` element, optionally passing `data` to the component when it's being rendered. Returns a promise that resolves with added ClientComponent or null if something went wrong
@@ -3,5 +3,5 @@ export declare class EventEmitter<T extends Record<string, any> = Record<string,
3
3
  protected listeners: Partial<Record<keyof T, Array<EventEmitterCallback<any>>>>;
4
4
  on<K extends keyof T>(eventName: K, callback: EventEmitterCallback<T[K]>): void;
5
5
  emit(eventName: keyof T, payload?: any): void;
6
- unbind(eventName: keyof T, callback: EventEmitterCallback<any>): void;
6
+ off(eventName: keyof T, callback: EventEmitterCallback<any>): void;
7
7
  }
@@ -15,7 +15,7 @@ export class EventEmitter {
15
15
  });
16
16
  }
17
17
  }
18
- unbind(eventName, callback) {
18
+ off(eventName, callback) {
19
19
  if (Array.isArray(this.listeners[eventName])) {
20
20
  while (true) {
21
21
  const index = this.listeners[eventName].indexOf(callback);
@@ -159,7 +159,11 @@ export type InitializerFunctionContext = {
159
159
  isRedraw: boolean;
160
160
  };
161
161
  export type StoreChangeCallback = (key: string, value: any, oldValue: any, componentId: string) => void;
162
- export type AsteriskAny = '*';
162
+ export type ClientComponentBoundEvent = {
163
+ element: HTMLElement;
164
+ event: keyof HTMLElementEventMap;
165
+ callback: (e: Event) => void;
166
+ };
163
167
  export type ClientComponentTransition = {
164
168
  fade: false | number;
165
169
  slide: false | number;
@@ -215,8 +215,9 @@ function base64ToBytes(base64) {
215
215
  return Uint8Array.from(binString, (m) => m.codePointAt(0));
216
216
  }
217
217
  function bytesToBase64(bytes) {
218
- const binString = String.fromCodePoint(...bytes);
219
- return btoa(binString);
218
+ return btoa(bytes.reduce((prev, curr) => {
219
+ return prev + String.fromCharCode(curr);
220
+ }, ''));
220
221
  }
221
222
  export function attributeValueToString(key, value) {
222
223
  return 'base64:' + bytesToBase64(new TextEncoder().encode(JSON.stringify({ key, value })));
@@ -55,6 +55,7 @@ export declare class ClientComponent extends EventEmitter {
55
55
  private transitionAttributes;
56
56
  private transitionAxis;
57
57
  private destroy;
58
- bind(element: HTMLElement, event: string, callback: (e: Event) => void): void;
58
+ bind(element: HTMLElement, event: keyof HTMLElementEventMap | Array<keyof HTMLElementEventMap>, callback: (e: Event) => void): void;
59
+ unbind(element: HTMLElement, event: keyof HTMLElementEventMap | Array<keyof HTMLElementEventMap>, callback: (e: Event) => void): void;
59
60
  private unbindAll;
60
61
  }
@@ -714,6 +714,12 @@ export class ClientComponent extends EventEmitter {
714
714
  this.emit('afterDestroy');
715
715
  }
716
716
  bind(element, event, callback) {
717
+ if (Array.isArray(event)) {
718
+ event.forEach((eventName) => {
719
+ this.bind(element, eventName, callback);
720
+ });
721
+ return;
722
+ }
717
723
  if (element instanceof HTMLElement) {
718
724
  this.bound.push({
719
725
  element,
@@ -723,6 +729,22 @@ export class ClientComponent extends EventEmitter {
723
729
  element.addEventListener(event, callback);
724
730
  }
725
731
  }
732
+ unbind(element, event, callback) {
733
+ if (Array.isArray(event)) {
734
+ event.forEach((eventName) => {
735
+ this.unbind(element, eventName, callback);
736
+ });
737
+ return;
738
+ }
739
+ const boundIndex = this.bound.findIndex((bound) => {
740
+ return bound.event === event && bound.element === element && callback === callback;
741
+ });
742
+ if (boundIndex > -1) {
743
+ const bound = this.bound[boundIndex];
744
+ bound.element.removeEventListener(bound.event, bound.callback);
745
+ this.bound.splice(boundIndex, 1);
746
+ }
747
+ }
726
748
  unbindAll() {
727
749
  this.bound.forEach((bound) => {
728
750
  bound.element.removeEventListener(bound.event, bound.callback);
@@ -1,4 +1,4 @@
1
- import { AsteriskAny, StoreChangeCallback } from '../Types.js';
1
+ import { StoreChangeCallback } from '../Types.js';
2
2
  import { ClientComponent } from './ClientComponent.js';
3
3
  export declare class DataStore {
4
4
  protected data: {
@@ -16,7 +16,7 @@ export declare class DataStore {
16
16
  hasKey(componentId: string, key: string): boolean;
17
17
  clear(componentId: string): void;
18
18
  destroy(componentId: string): void;
19
- onChange(componentId: string, key: string | AsteriskAny, callback: StoreChangeCallback): DataStore;
19
+ onChange(componentId: string, key: string, callback: StoreChangeCallback): DataStore;
20
20
  onChangeCallbacks(componentId: string): Record<string, Array<StoreChangeCallback>>;
21
21
  private unbindAll;
22
22
  }
@@ -1,4 +1,4 @@
1
- import { AsteriskAny, StoreChangeCallback } from '../Types.js';
1
+ import { StoreChangeCallback } from '../Types.js';
2
2
  import { ClientComponent } from './ClientComponent.js';
3
3
  import { DataStore } from './DataStore.js';
4
4
  export declare class DataStoreView {
@@ -14,6 +14,6 @@ export declare class DataStoreView {
14
14
  clear(): void;
15
15
  destroy(): void;
16
16
  private componentId;
17
- onChange(key: string | AsteriskAny, callback: StoreChangeCallback): DataStoreView;
17
+ onChange(key: string, callback: StoreChangeCallback): DataStoreView;
18
18
  onChangeCallbacks(): Record<string, Array<StoreChangeCallback>>;
19
19
  }
@@ -88,19 +88,18 @@ export class Component extends EventEmitter {
88
88
  this.setAttributes({ deferred: true }, 'data-', true);
89
89
  return;
90
90
  }
91
- if (typeof this.attributes.use === 'string' && this.parent !== null) {
92
- this.attributes = Object.assign(this.importedParentData(this.parent.data) || {}, this.attributes);
93
- }
91
+ const importedParentData = this.parent ? this.importedParentData(this.parent.data) : {};
94
92
  if (data === undefined) {
95
93
  if (this.entry && this.entry.module) {
96
- this.data = Object.assign(this.data, await this.entry.module.getData(this.attributes, this.document.ctx, this.document.application, this) || {});
94
+ this.data = Object.assign(this.data, await this.entry.module.getData(Object.assign(importedParentData, this.attributes), this.document.ctx, this.document.application, this) || {});
97
95
  }
98
96
  else {
97
+ this.attributes = Object.assign(importedParentData, this.attributes);
99
98
  this.data = Object.assign(exportedContextData, this.attributes);
100
99
  }
101
100
  }
102
101
  else {
103
- this.data = Object.assign(exportedContextData, data, this.attributes);
102
+ this.data = Object.assign(exportedContextData, Object.assign(importedParentData, data), this.attributes);
104
103
  }
105
104
  this.fillData(this.data);
106
105
  if (this.entry === null || this.entry.exportData) {
@@ -1,6 +1,6 @@
1
1
  import { HTMLParser } from "./HTMLParser.js";
2
- export const selfClosingTags = ['br', 'hr', 'input', 'img', 'link', 'meta', 'source', 'embed', 'path', 'area'];
3
- export const recognizedHTMLTags = ['body', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'b', 'i', 'a', 'em', 'strong', 'br', 'hr', 'abbr', 'bdi', 'bdo', 'blockquote', 'cite', 'code', 'del', 'dfn', 'ins', 'kbd', 'mark', 'pre', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'small', 'span', 'sub', 'sup', 'time', 'u', 'var', 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'img', 'area', 'map', 'object', 'param', 'table', 'tr', 'td', 'th', 'caption', 'colgroup', 'col', 'form', 'input', 'label', 'select', 'option', 'textarea', 'button', 'fieldset', 'datalist', 'iframe', 'audio', 'video', 'source', 'track', 'script', 'noscript', 'div', 'nav', 'aside', 'canvas', 'embed', 'template'];
2
+ export const selfClosingTags = ['br', 'wbr', 'hr', 'input', 'img', 'link', 'meta', 'source', 'embed', 'path', 'area'];
3
+ export const recognizedHTMLTags = ['body', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'b', 'i', 'a', 'em', 'strong', 'br', 'wbr', 'hr', 'abbr', 'bdi', 'bdo', 'blockquote', 'cite', 'code', 'del', 'dfn', 'ins', 'kbd', 'mark', 'pre', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'small', 'span', 'sub', 'sup', 'time', 'u', 'var', 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'img', 'area', 'map', 'object', 'param', 'table', 'tr', 'td', 'th', 'caption', 'colgroup', 'col', 'form', 'input', 'label', 'select', 'option', 'textarea', 'button', 'fieldset', 'datalist', 'iframe', 'audio', 'video', 'source', 'track', 'script', 'noscript', 'div', 'nav', 'aside', 'canvas', 'embed', 'template'];
4
4
  export class DOMNode {
5
5
  constructor(root, parentNode, tagName) {
6
6
  this.parentNode = null;
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "license": "MIT",
15
15
  "type": "module",
16
16
  "main": "build/index",
17
- "version": "0.9.2",
17
+ "version": "0.9.4",
18
18
  "scripts": {
19
19
  "develop": "tsc --watch",
20
20
  "startDev": "cd build && nodemon --watch '../app/**/*' --watch '../build/**/*' -e js,html,css index.js",