jpf 5.0.62 → 5.0.64

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 (162) hide show
  1. package/dist/controls/codeMirror/Editor/Editor.d.ts +4 -5
  2. package/dist/controls/codeMirror/Editor/Editor.js +8 -9
  3. package/dist/controls/codeMirror/Editor/Editor.js.map +1 -1
  4. package/dist/controls/custom/FileSelector/FileSelector.d.ts +3 -4
  5. package/dist/controls/custom/FileSelector/FileSelector.js +5 -6
  6. package/dist/controls/custom/FileSelector/FileSelector.js.map +1 -1
  7. package/dist/controls/custom/LabeledControl/LabeledControl.d.ts +5 -6
  8. package/dist/controls/custom/LabeledControl/LabeledControl.js +3 -4
  9. package/dist/controls/custom/LabeledControl/LabeledControl.js.map +1 -1
  10. package/dist/controls/custom/ListItem/ListItem.d.ts +8 -9
  11. package/dist/controls/custom/ListItem/ListItem.js +8 -9
  12. package/dist/controls/custom/ListItem/ListItem.js.map +1 -1
  13. package/dist/controls/html/Button/Button.d.ts +6 -7
  14. package/dist/controls/html/Button/Button.js +8 -9
  15. package/dist/controls/html/Button/Button.js.map +1 -1
  16. package/dist/controls/html/Div/Div.d.ts +4 -5
  17. package/dist/controls/html/Div/Div.js +2 -3
  18. package/dist/controls/html/Div/Div.js.map +1 -1
  19. package/dist/controls/html/Image/Image.d.ts +4 -5
  20. package/dist/controls/html/Image/Image.js +2 -3
  21. package/dist/controls/html/Image/Image.js.map +1 -1
  22. package/dist/controls/html/Input/Input.d.ts +4 -5
  23. package/dist/controls/html/Input/Input.js +23 -23
  24. package/dist/controls/html/Input/Input.js.map +1 -1
  25. package/dist/controls/html/Select/Select.d.ts +4 -5
  26. package/dist/controls/html/Select/Select.js +15 -16
  27. package/dist/controls/html/Select/Select.js.map +1 -1
  28. package/dist/controls/html/Span/Span.d.ts +3 -4
  29. package/dist/controls/html/Span/Span.js +2 -3
  30. package/dist/controls/html/Span/Span.js.map +1 -1
  31. package/dist/controls/jsonViewerAwesome/jsonFormatter/JsonFormatter.d.ts +4 -5
  32. package/dist/controls/jsonViewerAwesome/jsonFormatter/JsonFormatter.js +7 -8
  33. package/dist/controls/jsonViewerAwesome/jsonFormatter/JsonFormatter.js.map +1 -1
  34. package/dist/controls/kendo/Chart/Chart.d.ts +3 -4
  35. package/dist/controls/kendo/Chart/Chart.js +9 -10
  36. package/dist/controls/kendo/Chart/Chart.js.map +1 -1
  37. package/dist/controls/kendo/Editor/Editor.d.ts +3 -4
  38. package/dist/controls/kendo/Editor/Editor.js +13 -14
  39. package/dist/controls/kendo/Editor/Editor.js.map +1 -1
  40. package/dist/controls/kendo/Grid/Grid.d.ts +4 -5
  41. package/dist/controls/kendo/Grid/Grid.js +12 -13
  42. package/dist/controls/kendo/Grid/Grid.js.map +1 -1
  43. package/dist/controls/kendo/Menu/Menu.d.ts +3 -4
  44. package/dist/controls/kendo/Menu/Menu.js +9 -10
  45. package/dist/controls/kendo/Menu/Menu.js.map +1 -1
  46. package/dist/controls/kendo/Treeview/Treeview.d.ts +3 -4
  47. package/dist/controls/kendo/Treeview/Treeview.js +9 -10
  48. package/dist/controls/kendo/Treeview/Treeview.js.map +1 -1
  49. package/dist/controls/leaflet/LabelControl/LabelControl.d.ts +2 -3
  50. package/dist/controls/leaflet/LabelControl/LabelControl.js +1 -2
  51. package/dist/controls/leaflet/LabelControl/LabelControl.js.map +1 -1
  52. package/dist/controls/leaflet/Map/Map.d.ts +4 -5
  53. package/dist/controls/leaflet/Map/Map.js +9 -10
  54. package/dist/controls/leaflet/Map/Map.js.map +1 -1
  55. package/dist/controls/svg/Circle/Circle.d.ts +3 -4
  56. package/dist/controls/svg/Circle/Circle.js +1 -2
  57. package/dist/controls/svg/Circle/Circle.js.map +1 -1
  58. package/dist/controls/svg/Ellipse/Ellipse.d.ts +3 -4
  59. package/dist/controls/svg/Ellipse/Ellipse.js +1 -2
  60. package/dist/controls/svg/Ellipse/Ellipse.js.map +1 -1
  61. package/dist/controls/svg/ForeignObject/ForeignObject.d.ts +3 -4
  62. package/dist/controls/svg/ForeignObject/ForeignObject.js +1 -2
  63. package/dist/controls/svg/ForeignObject/ForeignObject.js.map +1 -1
  64. package/dist/controls/svg/Group/Group.d.ts +3 -4
  65. package/dist/controls/svg/Group/Group.js +1 -2
  66. package/dist/controls/svg/Group/Group.js.map +1 -1
  67. package/dist/controls/svg/Line/Line.d.ts +3 -4
  68. package/dist/controls/svg/Line/Line.js +1 -2
  69. package/dist/controls/svg/Line/Line.js.map +1 -1
  70. package/dist/controls/svg/Pattern/Pattern.d.ts +3 -4
  71. package/dist/controls/svg/Pattern/Pattern.js +1 -2
  72. package/dist/controls/svg/Pattern/Pattern.js.map +1 -1
  73. package/dist/controls/svg/Polygon/Polygon.d.ts +3 -4
  74. package/dist/controls/svg/Polygon/Polygon.js +3 -4
  75. package/dist/controls/svg/Polygon/Polygon.js.map +1 -1
  76. package/dist/controls/svg/Polyline/Polyline.d.ts +3 -4
  77. package/dist/controls/svg/Polyline/Polyline.js +1 -2
  78. package/dist/controls/svg/Polyline/Polyline.js.map +1 -1
  79. package/dist/controls/svg/Rectangle/Rectangle.d.ts +3 -4
  80. package/dist/controls/svg/Rectangle/Rectangle.js +1 -2
  81. package/dist/controls/svg/Rectangle/Rectangle.js.map +1 -1
  82. package/dist/controls/svg/Svg/Svg.d.ts +3 -4
  83. package/dist/controls/svg/Svg/Svg.js +1 -2
  84. package/dist/controls/svg/Svg/Svg.js.map +1 -1
  85. package/dist/controls/svg/Text/Text.d.ts +3 -4
  86. package/dist/controls/svg/Text/Text.js +1 -2
  87. package/dist/controls/svg/Text/Text.js.map +1 -1
  88. package/dist/controls/svg/Title/Title.d.ts +3 -4
  89. package/dist/controls/svg/Title/Title.js +1 -2
  90. package/dist/controls/svg/Title/Title.js.map +1 -1
  91. package/dist/controls/svg/svg.d.ts +1 -1
  92. package/dist/controls/svg/svg.js +5 -5
  93. package/dist/controls/svg/svg.js.map +1 -1
  94. package/dist/framework/attributes.d.ts +1 -1
  95. package/dist/framework/css.d.ts +1 -4
  96. package/dist/framework/element.d.ts +48 -15
  97. package/dist/framework/element.js +279 -29
  98. package/dist/framework/element.js.map +1 -1
  99. package/dist/framework/event.js.map +1 -1
  100. package/dist/framework/observable.d.ts +41 -0
  101. package/dist/framework/observable.js +46 -0
  102. package/dist/framework/observable.js.map +1 -0
  103. package/dist/framework/observablelmplementations.d.ts +1 -24
  104. package/dist/framework/observablelmplementations.js +0 -110
  105. package/dist/framework/observablelmplementations.js.map +1 -1
  106. package/dist/framework/properties.d.ts +1 -40
  107. package/dist/framework/properties.js +0 -265
  108. package/dist/framework/properties.js.map +1 -1
  109. package/dist/framework/style.d.ts +1 -328
  110. package/dist/index.d.ts +6 -10
  111. package/dist/index.js +7 -11
  112. package/dist/index.js.map +1 -1
  113. package/dist/utilities/object/object.d.ts +5 -0
  114. package/dist/utilities/object/object.js +47 -0
  115. package/dist/utilities/object/object.js.map +1 -0
  116. package/dist/utilities/value/value.d.ts +1 -0
  117. package/dist/utilities/value/value.js +7 -0
  118. package/dist/utilities/value/value.js.map +1 -0
  119. package/package.json +1 -1
  120. package/src/controls/codeMirror/Editor/Editor.ts +9 -11
  121. package/src/controls/custom/FileSelector/FileSelector.ts +5 -6
  122. package/src/controls/custom/LabeledControl/LabeledControl.ts +5 -6
  123. package/src/controls/custom/ListItem/ListItem.ts +13 -15
  124. package/src/controls/html/Button/Button.ts +13 -15
  125. package/src/controls/html/Div/Div.ts +4 -5
  126. package/src/controls/html/Image/Image.ts +4 -5
  127. package/src/controls/html/Input/Input.ts +21 -22
  128. package/src/controls/html/Select/Select.ts +16 -18
  129. package/src/controls/html/Span/Span.ts +3 -4
  130. package/src/controls/jsonViewerAwesome/jsonFormatter/JsonFormatter.ts +10 -12
  131. package/src/controls/kendo/Chart/Chart.ts +17 -19
  132. package/src/controls/kendo/Editor/Editor.ts +14 -16
  133. package/src/controls/kendo/Grid/Grid.ts +13 -15
  134. package/src/controls/kendo/Menu/Menu.ts +11 -13
  135. package/src/controls/kendo/Treeview/Treeview.ts +9 -11
  136. package/src/controls/leaflet/LabelControl/LabelControl.ts +4 -5
  137. package/src/controls/leaflet/Map/Map.ts +10 -12
  138. package/src/controls/svg/Circle/Circle.ts +3 -4
  139. package/src/controls/svg/Ellipse/Ellipse.ts +3 -4
  140. package/src/controls/svg/ForeignObject/ForeignObject.ts +3 -4
  141. package/src/controls/svg/Group/Group.ts +3 -4
  142. package/src/controls/svg/Line/Line.ts +3 -4
  143. package/src/controls/svg/Pattern/Pattern.ts +3 -4
  144. package/src/controls/svg/Polygon/Polygon.ts +4 -6
  145. package/src/controls/svg/Polyline/Polyline.ts +3 -4
  146. package/src/controls/svg/Rectangle/Rectangle.ts +3 -4
  147. package/src/controls/svg/Svg/Svg.ts +3 -4
  148. package/src/controls/svg/Text/Text.ts +3 -4
  149. package/src/controls/svg/Title/Title.ts +3 -4
  150. package/src/controls/svg/svg.ts +5 -6
  151. package/src/framework/attributes.ts +1 -47
  152. package/src/framework/css.ts +3 -5
  153. package/src/framework/element.ts +380 -44
  154. package/src/framework/event.ts +0 -2
  155. package/src/framework/observable.ts +100 -0
  156. package/src/framework/style.ts +1556 -1556
  157. package/src/index.ts +16 -11
  158. package/src/utilities/object/object.ts +56 -0
  159. package/src/utilities/value/value.ts +3 -0
  160. package/src/framework/observableInterfaces.ts +0 -39
  161. package/src/framework/observablelmplementations.ts +0 -135
  162. package/src/framework/properties.ts +0 -344
@@ -1,51 +1,5 @@
1
1
  import { PreserveAspectRatio } from "./css";
2
- import { ISubscribable } from "./observableInterfaces";
3
-
4
- //export interface IAttributes {
5
- // alt?: string,
6
- // disabled?: string,
7
- // href?: string,
8
- // target?: string,
9
- // id?: string,
10
- // src?: string,
11
- // title?: string,
12
- // class?: string,
13
- // tabindex?: number,
14
- // draggable?: string,
15
- // placeholder?: string,
16
- // for?: string,
17
- // type?: string,
18
- // value?: string,
19
- // view?: string,
20
- // checked?: string;
21
- // enctype?: string;
22
- // name?: string;
23
- // multiple?: boolean;
24
- // ["aria-label"]?: string;
25
- // cx?: number | string;
26
- // cy?: number | string;
27
- // r?: number | string;
28
- // rx?: number | string;
29
- // ry?: number | string;
30
- // x?: number | string;
31
- // x1?: number | string;
32
- // x2?: number | string;
33
- // y?: number | string;
34
- // y1?: number | string;
35
- // y2?: number | string;
36
- // width?: number | string;
37
- // height?: number | string;
38
- // patternUnits?: string;
39
- // patternTransform?: string;
40
- // points?: string;
41
- // viewBox?: string;
42
- // dx?: number | string;
43
- // dy?: number | string;
44
- // rotate?: string;
45
- // preserveAspectRatio?: PreserveAspectRatio;
46
- // xmlns?: string;
47
- // info?: string;
48
- //}
2
+ import { ISubscribable } from "./observable";
49
3
 
50
4
  export interface IAttributes {
51
5
  alt?: string | ISubscribable<string>,
@@ -3,7 +3,7 @@ export type PatternUnits = "userSpaceOnUse" | "objectboudingBox";
3
3
  export type DropEffect = "none" | "copy" | "link" | "move";
4
4
  export type EffectAllowed = "none" | "copy" | "copyLink" | "copyMove" | "link" | "linkMove" | "move" | "all" | "uninitialized";
5
5
 
6
- type CssPropertyA = "alignContent" | "alignItems" | "alignSelf" | "alignmentAdjust" | "alignmentBaseline" | "animation" | "animationDelay" | "animationDirection" | "animationDuration" |
6
+ export type CssProperty = "alignContent" | "alignItems" | "alignSelf" | "alignmentAdjust" | "alignmentBaseline" | "animation" | "animationDelay" | "animationDirection" | "animationDuration" |
7
7
  "animationFillMode" | "animationIterationCount" | "animationName" | "animationPlayState" | "animationTimingFunction" | "appearance" | "backfaceVisibility" | "background" |
8
8
  "backgroundAttachment" | "backgroundBlendMode" | "backgroundClip" | "backgroundColor" | "backgroundComposite" | "backgroundImage" | "backgroundOrigin" | "backgroundPosition" |
9
9
  "backgroundRepeat" | "backgroundSize" | "baselineShift" | "behavior" | "border" | "borderBottom" | "borderBottomColor" | "borderBottomLeftRadius" | "borderBottomRightRadius" |
@@ -17,9 +17,8 @@ type CssPropertyA = "alignContent" | "alignItems" | "alignSelf" | "alignmentAdju
17
17
  "float" | "flowFrom" | "font" | "fontFamily" | "fontKerning" | "fontSize" | "fontSizeAdjust" | "fontStretch" | "fontStyle" | "fontSynthesis" | "fontVariant" | "fontVariantAlternates" |
18
18
  "fontWeight" | "gridArea" | "gridAutoColumns" | "gridAutoFlow" | "gridAutoRows" | "gridColumn" | "gridColumnGap" | "gridColumnEnd" | "gridColumnStart" | "gridGap" | "gridRow" |
19
19
  "gridRowEnd" | "gridRowGap" | "gridRowStart" | "gridRowPosition" | "gridRowSpan" | "gridTemplate" | "gridTemplateAreas" | "gridTemplateColumns" | "gridTemplateRows" | "height" |
20
- "hyphenateLimitChars" | "hyphenateLimitLines" | "hyphenateLimitZone" | "hyphens" | "imeMode" | "justifyContent" | "justifyItems" | "justifySelf";
21
-
22
- type CssPropertyL = "layoutGrid" | "layoutGridChar" | "layoutGridLine" | "layoutGridMode" | "layoutGridType" | "left" | "letterSpacing" | "lineBreak" | "lineClamp" | "lineHeight" |
20
+ "hyphenateLimitChars" | "hyphenateLimitLines" | "hyphenateLimitZone" | "hyphens" | "imeMode" | "justifyContent" | "justifyItems" | "justifySelf" |
21
+ "layoutGrid" | "layoutGridChar" | "layoutGridLine" | "layoutGridMode" | "layoutGridType" | "left" | "letterSpacing" | "lineBreak" | "lineClamp" | "lineHeight" |
23
22
  "listStyle" | "listStyleImage" | "listStylePosition" | "listStyleType" | "margin" | "marginBottom" | "marginLeft" | "marginRight" | "marginTop" | "marqueeDirection" | "marqueeStyle" |
24
23
  "mask" | "maskBorder" | "maskBorderRepeat" | "maskBorderSlice" | "maskBorderSource" | "maskBorderWidth" | "maskClip" | "maskOrigin" | "maxFontSize" | "maxHeight" | "maxWidth" |
25
24
  "minHeight" | "minWidth" | "mixBlendMode" | "objectFit" | "objectPosition" | "opacity" | "order" | "orphans" | "outline" | "outlineColor" | "outlineStyle" | "outlineOffset" |
@@ -36,7 +35,6 @@ type CssPropertyL = "layoutGrid" | "layoutGridChar" | "layoutGridLine" | "layout
36
35
  "userSelect" | "verticalAlign" | "visibility" | "voiceBalance" | "voiceDuration" | "voiceFamily" | "voicePitch" | "voiceRange" | "voiceRate" | "voiceStress" | "voiceVolume" |
37
36
  "whiteSpace" | "whiteSpaceTreatment" | "widows" | "width" | "willChange" | "wordBreak" | "wordSpacing" | "wordWrap" | "wrapFlow" | "wrapMargin" | "wrapOption" | "writingMode" | "zIndex" | "zoom";
38
37
 
39
- export type CssProperty = CssPropertyA | CssPropertyL;
40
38
  /*
41
39
  * Value of a CSS Property. Could be a single value or a list of fallbacks
42
40
  * NOTE: array is for fallbacks
@@ -1,7 +1,13 @@
1
1
  import "tocca";
2
- import { IDisposer, ISubscribable } from "./observableInterfaces";
3
- import { unwrap, isSubscribable } from "./observablelmplementations";
4
- import { IProperties, Properties, applyBindings } from "./properties";
2
+ import { IDisposer, ISubscribable, observable } from "./observable";
3
+ import { IEventListener } from "./event";
4
+ import { IAttributes } from "./attributes";
5
+ import { IStyle } from "./style";
6
+ import { isNullOrUndefined } from "../utilities/value/value";
7
+
8
+ const svgNamespace = "http://www.w3.org/2000/svg";
9
+
10
+ // #region Element tagNames for HTML and SVG Elements
5
11
 
6
12
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
7
13
  const htmlTags = {
@@ -33,26 +39,47 @@ const svgTags = {
33
39
  }
34
40
 
35
41
  type TagName = keyof typeof htmlTags | keyof typeof svgTags;
42
+ // #endregion
43
+
44
+ // #region Element Interfaces
45
+
46
+ //Element properties except the tagName
47
+ export interface IElementProperties {
48
+ attributes?: IAttributes;
49
+ classNames?: Array<string> | ISubscribable<Array<string>>;
50
+ style?: IStyle;
51
+ visible?: boolean | ISubscribable<boolean>;
52
+ disabled?: boolean | ISubscribable<boolean>;
53
+ innerHtml?: string | ISubscribable<string>;
54
+ textContent?: string | ISubscribable<string>;
55
+ addViewModelToDataObject?: boolean;
56
+ userSelectable?: boolean;
57
+ eventListeners?: Array<IEventListener>;
58
+ elementType?: string;
59
+ focused?: boolean | ISubscribable<boolean>;
60
+ }
36
61
 
37
- const svgNamespace = "http://www.w3.org/2000/svg";
62
+ //Options to create an Element
63
+ export interface IElementOptions<TElementProperties> {
64
+ tagName: TagName;
65
+ properties?: TElementProperties;
66
+ }
38
67
 
39
- //#region Element class
68
+ //public interface of an Element
40
69
  export interface IElement {
41
70
  render(): HTMLElement;
42
71
  unmount(): void;
43
72
  }
44
73
 
45
- export interface IElementOptions<TProperties> {
46
- tagName: TagName;
47
- properties?: TProperties;
48
- }
74
+ // #endregion
49
75
 
50
- export class Element<TProperties = IProperties> implements IElement {
51
- constructor(options: IElementOptions<TProperties>, children?: Array<IElement> | ISubscribable<Array<IElement>>) {
76
+ // #region Element Class definition
77
+ export class Element<TElementProperties = IElementProperties> implements IElement {
78
+ constructor(options: IElementOptions<TElementProperties>, children?: Array<IElement> | ISubscribable<Array<IElement>>) {
52
79
  this.tagName = options.tagName;
53
80
  this.properties = options.properties;
54
81
  this.optionsChildren = children;
55
- this.children = unwrap(children);
82
+ this.children = observable.unwrap(children);
56
83
  }
57
84
 
58
85
  // #region Private members
@@ -62,33 +89,33 @@ export class Element<TProperties = IProperties> implements IElement {
62
89
 
63
90
 
64
91
  private buildChildren() {
65
- if (this.element && this.children && this.children.length > 0) {
92
+ if (this.htmlElement && this.children && this.children.length > 0) {
66
93
  //Create a documentFragment to reduce browser repaints
67
94
  const documentFragment = document.createDocumentFragment();
68
95
  for (const child of this.children) {
69
- this.element.appendChild(child.render());
96
+ this.htmlElement.appendChild(child.render());
70
97
  }
71
98
 
72
99
  //Add the documentFragment to the dom
73
- this.element.appendChild(documentFragment);
100
+ this.htmlElement.appendChild(documentFragment);
74
101
  }
75
102
  }
76
103
  // #endregion
77
104
 
78
105
  // #region Protected members
79
- protected element: HTMLElement;
80
- protected readonly properties: TProperties;
106
+ protected htmlElement: HTMLElement;
107
+ protected readonly properties: TElementProperties;
81
108
  protected readonly disposers = new Array<IDisposer>();
82
109
 
83
110
  protected build(): void {
84
- applyBindings(this.properties as IProperties, this.element, this.disposers);
111
+ applyBindings(this.properties, this.htmlElement, this.disposers);
85
112
 
86
113
  if (this.children) {
87
114
  this.buildChildren();
88
115
  }
89
116
 
90
117
  //Find out if the options.Children are observable.
91
- if (isSubscribable(this.optionsChildren)) {
118
+ if (observable.isSubscribable(this.optionsChildren)) {
92
119
  this.disposers.push(
93
120
  this.optionsChildren.subscribe((children) => {
94
121
  this.setChildren(...children);
@@ -98,26 +125,26 @@ export class Element<TProperties = IProperties> implements IElement {
98
125
  }
99
126
 
100
127
  protected remove(): void {
101
- if (this.element) {
102
- if (this.element.remove) {
103
- this.element.remove();
128
+ if (this.htmlElement) {
129
+ if (this.htmlElement.remove) {
130
+ this.htmlElement.remove();
104
131
  } else {
105
- if (this.element.parentElement) {
106
- this.element.parentElement.removeChild(this.element);
132
+ if (this.htmlElement.parentElement) {
133
+ this.htmlElement.parentElement.removeChild(this.htmlElement);
107
134
  }
108
135
  }
109
136
 
110
- this.element = null;
137
+ this.htmlElement = null;
111
138
  }
112
139
  }
113
140
 
114
- protected addChild(child: IElement): Element<TProperties> {
141
+ protected addChild(child: IElement): Element<TElementProperties> {
115
142
  this.children.push(child);
116
143
  this.buildChildren();
117
144
  return this;
118
145
  }
119
146
 
120
- protected setChildren(...children: Array<IElement>): Element<TProperties> {
147
+ protected setChildren(...children: Array<IElement>): Element<TElementProperties> {
121
148
  this.empty();
122
149
 
123
150
  this.children = children;
@@ -129,10 +156,10 @@ export class Element<TProperties = IProperties> implements IElement {
129
156
  protected empty(): void {
130
157
  this.children = [];
131
158
 
132
- if (this.element) {
133
- this.element.innerHTML = "";
134
- while (this.element.firstChild) {
135
- this.element.removeChild(this.element.firstChild);
159
+ if (this.htmlElement) {
160
+ this.htmlElement.innerHTML = "";
161
+ while (this.htmlElement.firstChild) {
162
+ this.htmlElement.removeChild(this.htmlElement.firstChild);
136
163
  }
137
164
  }
138
165
  }
@@ -140,7 +167,7 @@ export class Element<TProperties = IProperties> implements IElement {
140
167
 
141
168
  // #region Public members
142
169
  render(): HTMLElement {
143
- if (this.element) {
170
+ if (this.htmlElement) {
144
171
  //If the element has already been rendered we remove the element from the dom
145
172
  this.remove();
146
173
  }
@@ -150,17 +177,17 @@ export class Element<TProperties = IProperties> implements IElement {
150
177
  //Create the html element.
151
178
  if (svgTags.hasOwnProperty(this.tagName)) {
152
179
  //Create a SVGElement
153
- this.element = document.createElementNS(svgNamespace, this.tagName) as unknown as HTMLElement;
180
+ this.htmlElement = document.createElementNS(svgNamespace, this.tagName) as unknown as HTMLElement;
154
181
  } else {
155
182
  //Create a HTMLElement
156
- this.element = document.createElement(this.tagName);
183
+ this.htmlElement = document.createElement(this.tagName);
157
184
  }
158
185
 
159
186
  //Build the UiElement
160
187
  this.build();
161
188
 
162
189
  //Return the fully functional html element
163
- return this.element;
190
+ return this.htmlElement;
164
191
  }
165
192
 
166
193
  throw "The build method of this UiElement has not been defined";
@@ -169,7 +196,7 @@ export class Element<TProperties = IProperties> implements IElement {
169
196
 
170
197
  //This method is used to dispose subscriptions before removing the element from the DOM to prevent memory leaks
171
198
  unmount(): void {
172
- const properties = this.properties as IProperties;
199
+ const properties = this.properties as IElementProperties;
173
200
  console.log("Unmount element " + properties.elementType);
174
201
 
175
202
  //If the element has childeren then we unmount the children
@@ -186,28 +213,337 @@ export class Element<TProperties = IProperties> implements IElement {
186
213
  }
187
214
 
188
215
  focus(options?: FocusOptions) {
189
- if (this.element) {
190
- this.element.focus(options);
216
+ if (this.htmlElement) {
217
+ this.htmlElement.focus(options);
191
218
  }
192
219
  }
193
220
  // #endregion
194
221
  }
195
222
 
196
- export function element<TProperties>(options: IElementOptions<TProperties>, children?: Array<IElement> | ISubscribable<Array<IElement>>) {
223
+ // #endregion
224
+
225
+ // #region ElementProperties Class definition
226
+ export abstract class ElementProperties implements IElementProperties {
227
+ protected setProperties<TProperties>(object: object, properties?: TProperties) {
228
+ if (properties) {
229
+ Object.keys(properties).forEach((property) => {
230
+ object[property] = properties[property];
231
+ });
232
+ }
233
+ }
234
+
235
+ attributes?: IAttributes;
236
+ classNames?: Array<string> | ISubscribable<Array<string>>;
237
+ style?: IStyle;
238
+ visible?: boolean | ISubscribable<boolean>;
239
+ disabled?: boolean | ISubscribable<boolean>;
240
+ innerHtml?: string | ISubscribable<string>;
241
+ textContent?: string | ISubscribable<string>;
242
+ addViewModelToDataObject?: boolean;
243
+ userSelectable?: boolean;
244
+ eventListeners?: Array<IEventListener>;
245
+ elementType?: string;
246
+ focused?: boolean | ISubscribable<boolean>;
247
+ }
248
+ // #endregion
249
+
250
+ //#region Element helper functions
251
+
252
+ export function extendProperties<TTarget = IElementProperties, TOverwritingProperties = TTarget, TPreserveExistingProperties = TTarget>(target: TTarget, preserveExisting: TPreserveExistingProperties, overWriteExisting?: TOverwritingProperties): TTarget {
253
+ if (overWriteExisting || preserveExisting) {
254
+ target = target || {} as TTarget;
255
+
256
+ if (typeof preserveExisting === "object") {
257
+ Object.keys(preserveExisting).forEach((key) => {
258
+ //Check if the target object does not already have a property with the given key
259
+ if (!target.hasOwnProperty(key) || typeof target[key] === "undefined") {
260
+ target[key] = preserveExisting[key];
261
+ }
262
+ });
263
+ }
264
+
265
+ if (typeof overWriteExisting === "object") {
266
+ Object.keys(overWriteExisting).forEach((key) => {
267
+ target[key] = overWriteExisting[key];
268
+ });
269
+ }
270
+ }
271
+
272
+ return target;
273
+ }
274
+
275
+
276
+ export function createElement<TProperties>(options: IElementOptions<TProperties>, children?: Array<IElement> | ISubscribable<Array<IElement>>) {
197
277
  return new Element<TProperties>(options, children);
198
278
  }
279
+
280
+ //#endregion
281
+
282
+ //#region Element Binding functions
283
+ export function applyBindings(properties: IElementProperties, element: HTMLElement, disposers: Array<IDisposer>) {
284
+ element.setAttribute("elementtype", properties.elementType || "Element");
285
+
286
+ if (properties.classNames) {
287
+ applyClassesToElement(observable.unwrap(properties.classNames), true, element);
288
+ if (observable.isSubscribable(properties.classNames)) {
289
+ const disposer = properties.classNames.subscribe((classNames) => {
290
+ applyClassesToElement(classNames, true, element);
291
+ });
292
+
293
+ if (disposers) {
294
+ disposers.push(disposer);
295
+ }
296
+ }
297
+ }
298
+
299
+ if (properties.attributes) {
300
+ Object.keys(properties.attributes).forEach((key) => {
301
+ const value = properties.attributes[key];
302
+ applyAttributeToElement(key as keyof IAttributes, observable.unwrap(value), element);
303
+
304
+ if (observable.isSubscribable(value)) {
305
+ const disposer = value.subscribe((value: string) => {
306
+ applyAttributeToElement(key as keyof IAttributes, value, element);
307
+ });
308
+ if (disposers) {
309
+ disposers.push(disposer);
310
+ }
311
+ }
312
+ });
313
+ }
314
+
315
+ if (properties.style) {
316
+ Object.keys(properties.style).forEach((key) => {
317
+ const style = properties.style[key];
318
+
319
+ element.style[key] = observable.unwrap(style);
320
+ if (observable.isSubscribable(style)) {
321
+ const disposer = style.subscribe((style) => {
322
+ element.style[key] = style;
323
+ });
324
+
325
+ if (disposers) {
326
+ disposers.push(disposer);
327
+ }
328
+ }
329
+ });
330
+ }
331
+
332
+ if (!isNullOrUndefined(properties.innerHtml)) {
333
+
334
+ element.innerHTML = observable.unwrap(properties.innerHtml);
335
+
336
+ if (observable.isSubscribable(properties.innerHtml)) {
337
+ const disposer = properties.innerHtml.subscribe((innerHtml: string) => {
338
+ element.innerHTML = innerHtml;
339
+ });
340
+
341
+ if (disposers) {
342
+ disposers.push(disposer);
343
+ }
344
+ }
345
+ }
346
+
347
+ if (!isNullOrUndefined(properties.textContent)) {
348
+
349
+ const textContent = observable.unwrap(properties.textContent);
350
+
351
+ if (element.hasChildNodes() && element.childNodes.length === 1 && element.childNodes[0].nodeType === 3) {
352
+ element.firstChild.nodeValue = textContent;
353
+ } else {
354
+ element.textContent = observable.unwrap(properties.textContent);
355
+ }
356
+
357
+ if (observable.isSubscribable(properties.textContent)) {
358
+ const disposer = properties.textContent.subscribe((textContent) => {
359
+ if (element.hasChildNodes() && element.childNodes.length === 1 && element.childNodes[0].nodeType === 3) {
360
+ element.firstChild.nodeValue = textContent;
361
+ } else {
362
+ element.textContent = observable.unwrap(properties.textContent);
363
+ }
364
+ });
365
+
366
+ if (disposers) {
367
+ disposers.push(disposer);
368
+ }
369
+ }
370
+ }
371
+
372
+ //Find out if the element is none selectable
373
+ if (properties.userSelectable === false) {
374
+ applyEventListenerToElement({
375
+ type: Event,
376
+ name: "selectstart",
377
+ handler: () => { return false; },
378
+ passive: true
379
+ },
380
+ element
381
+ );
382
+ element.style.userSelect = "none";
383
+ }
384
+
385
+ if (properties.addViewModelToDataObject) {
386
+ if (!element["data"]) {
387
+ element["data"] = {};
388
+ }
389
+ element["data"].viewModel = properties;
390
+ }
391
+
392
+ if (properties.eventListeners) {
393
+ applyEventListenersToElement(properties.eventListeners, element);
394
+ }
395
+
396
+ applyVisibilityToElement(observable.unwrap(properties.visible), element);
397
+ if (observable.isSubscribable(properties.visible)) {
398
+ const disposer = properties.visible.subscribe((visible) => {
399
+ applyVisibilityToElement(visible, element);
400
+ });
401
+
402
+ if (disposers) {
403
+ disposers.push(disposer);
404
+ }
405
+ }
406
+
407
+ applyDisabledToElement(observable.unwrap(properties.disabled), element);
408
+ if (observable.isSubscribable(properties.disabled)) {
409
+ const disposer = properties.disabled.subscribe((disabled) => {
410
+ applyDisabledToElement(disabled, element);
411
+ });
412
+
413
+ if (disposers) {
414
+ disposers.push(disposer);
415
+ }
416
+ }
417
+
418
+ applyFocusToElement(observable.unwrap(properties.focused), element);
419
+ if (observable.isSubscribable(properties.focused)) {
420
+ const disposer = properties.focused.subscribe((focused) => {
421
+ applyFocusToElement(focused, element);
422
+ });
423
+
424
+ if (disposers) {
425
+ disposers.push(disposer);
426
+ }
427
+ }
428
+ }
429
+
430
+ function applyVisibilityToElement(visible: boolean, element: HTMLElement) {
431
+ if (visible === false) {
432
+ element.classList.add("hidden");
433
+ } else {
434
+ element.classList.remove("hidden");
435
+ }
436
+ }
437
+
438
+ function applyDisabledToElement(disabled: boolean, element: HTMLElement) {
439
+ if (disabled) {
440
+ element.setAttribute("disabled", "disabled");
441
+ } else {
442
+ element.removeAttribute("disabled");
443
+ }
444
+ }
445
+
446
+ function applyEventListenersToElement(eventListeners: Array<IEventListener>, element: HTMLElement) {
447
+ if (!element.addEventListener) {
448
+ throw new Error("Your browser does not support addEventListener");
449
+ }
450
+
451
+ if (eventListeners) {
452
+ eventListeners.forEach((eventListener) => {
453
+ applyEventListenerToElement(eventListener, element);
454
+ });
455
+ }
456
+ }
457
+
458
+ function applyEventListenerToElement(eventListener: IEventListener, element: HTMLElement) {
459
+ const type = eventListener.type;
460
+ const name = eventListener.name;
461
+ let handler = eventListener.handler;
462
+ const options: AddEventListenerOptions = {
463
+ passive: eventListener.passive || false,
464
+ once: eventListener.once || false
465
+ };
466
+
467
+ if (!type) {
468
+ throw new Error("type is mandatory");
469
+ }
470
+ if (!name) {
471
+ throw new Error("name is mandatory");
472
+ }
473
+ if (!handler) {
474
+ throw new Error("handler is mandatory");
475
+ }
476
+
477
+ if (name === "dragstart") {
478
+ element.setAttribute("draggable", "true");
479
+ }
480
+
481
+ if (eventListener.type === KeyboardEvent) {
482
+ handler = (event: KeyboardEvent) => {
483
+ if (eventListener.altKey && !event.altKey) {
484
+ return;
485
+ }
486
+
487
+ if (eventListener.shiftKey && !event.shiftKey) {
488
+ return;
489
+ }
490
+
491
+ if (eventListener.ctrlKey && !event.ctrlKey) {
492
+ return;
493
+ }
494
+ if (eventListener.key && eventListener.key !== event.key) {
495
+ return;
496
+ }
497
+
498
+ handler(event);
499
+ }
500
+ }
501
+
502
+
503
+ //Add the event listener to the element
504
+ element.addEventListener(name, handler, options);
505
+
506
+ }
507
+
508
+ function applyClassesToElement(classNames: string[], replace: boolean, element: HTMLElement) {
509
+ //If all existing classes need to be replace we reset the classes object to an empty object
510
+ if (replace) {
511
+ element.className = "";
512
+ }
513
+
514
+ //Add all the classNames to the classes object
515
+ if (classNames) {
516
+ classNames.forEach((className) => {
517
+ element.classList.add(className);
518
+ });
519
+ }
520
+ }
521
+
522
+ function applyAttributeToElement(name: keyof IAttributes, value: string, element: HTMLElement) {
523
+ if (isNullOrUndefined(value)) {
524
+ element.removeAttribute(name);
525
+ } else {
526
+ element.setAttribute(name, value);
527
+ }
528
+ }
529
+
530
+ function applyFocusToElement(focused: boolean, element: HTMLElement) {
531
+ if (focused) {
532
+ element.focus();
533
+ }
534
+ }
199
535
  //#endregion
200
536
 
201
- //#region View dictionary
202
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/no-explicit-any
537
+ //#region Element dictionary
538
+ //eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/no-explicit-any
203
539
  const elementDictionary = new Map<Function, any>();
204
540
 
205
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
541
+ //eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
206
542
  export function addElementToDictionary(properties: Function, element: Function) {
207
543
  elementDictionary.set(properties, element);
208
544
  }
209
545
 
210
- export function getElement(properties: Properties): Element {
546
+ export function getElement(properties: IElementProperties): IElement {
211
547
  if (properties && properties.constructor) {
212
548
  const element = elementDictionary.get(properties.constructor);
213
549
  if (element.prototype) {
@@ -220,7 +556,7 @@ export function getElement(properties: Properties): Element {
220
556
  return null;
221
557
  }
222
558
 
223
- export function render(properties: Properties): HTMLElement {
559
+ export function render(properties: IElementProperties): HTMLElement {
224
560
  const view = getElement(properties);
225
561
  if (view && view.render) {
226
562
  return view.render();
@@ -9,8 +9,6 @@ export type TouchEventType = "touchstart" | "touchend" | "touchmove" | "touchcan
9
9
  export type MouseEventType = "contextmenu" | "dblclick" | "mousedown" | "mouseenter" | "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup";
10
10
  export type FocusEventType = "blur" | "focusout" | "focus" | "focusin";
11
11
 
12
-
13
-
14
12
  export interface IEventListener extends AddEventListenerOptions, KeyboardEventInit {
15
13
  type: EventType;
16
14
  name: string;