##// END OF EJS Templates
fixed isNode, isWidget, isRendition type predicated, fixed handling primitive values
cin -
r127:8095aad89415 v1.7.1 default
parent child
Show More
@@ -1,215 +1,215
1 import { IDestroyable } from "@implab/core-amd/interfaces";
1 import { IDestroyable } from "@implab/core-amd/interfaces";
2 import { isDestroyable } from "@implab/core-amd/safe";
2 import { isDestroyable } from "@implab/core-amd/safe";
3 import _WidgetBase = require("dijit/_WidgetBase");
3 import _WidgetBase = require("dijit/_WidgetBase");
4 import registry = require("dijit/registry");
4 import registry = require("dijit/registry");
5
5
6 interface _WidgetBaseConstructor {
6 interface _WidgetBaseConstructor {
7 new <E extends { [k in keyof E]: Event } = object>(params?: Partial<_WidgetBase<E>> & ThisType<_WidgetBase<E>>, srcNodeRef?: string | Node): _WidgetBase<E> & dojo._base.DeclareCreatedObject;
7 new <E extends { [k in keyof E]: Event } = object>(params?: Partial<_WidgetBase<E>> & ThisType<_WidgetBase<E>>, srcNodeRef?: string | Node): _WidgetBase<E> & dojo._base.DeclareCreatedObject;
8 prototype: _WidgetBase;
8 prototype: _WidgetBase;
9 }
9 }
10
10
11 export type DojoNodePosition = "first" | "after" | "before" | "last" | "replace" | "only" | number;
11 export type DojoNodePosition = "first" | "after" | "before" | "last" | "replace" | "only" | number;
12
12
13 export type DojoNodeLocation = [Node, DojoNodePosition];
13 export type DojoNodeLocation = [Node, DojoNodePosition];
14
14
15 export interface Rendition<TNode extends Node = Node> {
15 export interface Rendition<TNode extends Node = Node> {
16 getDomNode(): TNode;
16 getDomNode(): TNode;
17
17
18 placeAt(refNode: string | Node, position?: DojoNodePosition): void;
18 placeAt(refNode: string | Node, position?: DojoNodePosition): void;
19 }
19 }
20
20
21 /**
21 /**
22 * @deprecated use Rendition
22 * @deprecated use Rendition
23 */
23 */
24 export type BuildContext<TNode extends Node = Node> = Rendition<TNode>;
24 export type BuildContext<TNode extends Node = Node> = Rendition<TNode>;
25
25
26 export interface IRecursivelyDestroyable {
26 export interface IRecursivelyDestroyable {
27 destroyRecursive(): void;
27 destroyRecursive(): void;
28 }
28 }
29
29
30 export const isNode = (el: unknown): el is Node => !!(el && (el as Node).nodeName && (el as Node).nodeType);
30 export const isNode = (el: unknown): el is Node => !!(el !== null && typeof el === "object" && (el as Node).nodeName && (el as Node).nodeType);
31
31
32 export const isElementNode = (el: unknown): el is Element => isNode(el) && el.nodeType === 1;
32 export const isElementNode = (el: unknown): el is Element => isNode(el) && el.nodeType === 1;
33
33
34 export const isTextNode = (el: unknown): el is Text => isNode(el) && el.nodeType === 3;
34 export const isTextNode = (el: unknown): el is Text => isNode(el) && el.nodeType === 3;
35
35
36 export const isProcessingInstructionNode = (el: unknown): el is ProcessingInstruction => isNode(el) && el.nodeType === 7;
36 export const isProcessingInstructionNode = (el: unknown): el is ProcessingInstruction => isNode(el) && el.nodeType === 7;
37
37
38 export const isCommentNode = (el: unknown): el is Comment => isNode(el) && el.nodeType === 8;
38 export const isCommentNode = (el: unknown): el is Comment => isNode(el) && el.nodeType === 8;
39
39
40 export const isDocumentNode = (el: unknown): el is Document => isNode(el) && el.nodeType === 9;
40 export const isDocumentNode = (el: unknown): el is Document => isNode(el) && el.nodeType === 9;
41
41
42 export const isDocumentTypeNode = (el: unknown): el is DocumentType => isNode(el) && el.nodeType === 10;
42 export const isDocumentTypeNode = (el: unknown): el is DocumentType => isNode(el) && el.nodeType === 10;
43
43
44 export const isDocumentFragmentNode = (el: unknown): el is DocumentFragment => isNode(el) && el.nodeType === 11;
44 export const isDocumentFragmentNode = (el: unknown): el is DocumentFragment => isNode(el) && el.nodeType === 11;
45
45
46 export const isWidget = (v: unknown): v is _WidgetBase => !!(v && "domNode" in (v as _WidgetBase));
46 export const isWidget = (v: unknown): v is _WidgetBase => !!(v !== null && typeof v === "object" && "domNode" in (v as _WidgetBase));
47
47
48 export const isRendition = (v: unknown): v is Rendition => !!(v && typeof (v as Rendition).getDomNode === "function");
48 export const isRendition = (v: unknown): v is Rendition => !!(v !== null && typeof v === "object" && typeof (v as Rendition).getDomNode === "function");
49
49
50 /**
50 /**
51 * @deprecated use isRendition
51 * @deprecated use isRendition
52 */
52 */
53 export const isBuildContext = isRendition;
53 export const isBuildContext = isRendition;
54
54
55 export const isPlainObject = (v: object) => {
55 export const isPlainObject = (v: object) => {
56 if (typeof v !== "object")
56 if (typeof v !== "object")
57 return false;
57 return false;
58
58
59 const vp = Object.getPrototypeOf(v) as object;
59 const vp = Object.getPrototypeOf(v) as object;
60 return !vp || vp === Object.prototype;
60 return !vp || vp === Object.prototype;
61 };
61 };
62
62
63 export const isWidgetConstructor = (v: unknown): v is _WidgetBaseConstructor =>
63 export const isWidgetConstructor = (v: unknown): v is _WidgetBaseConstructor =>
64 typeof v === "function" && !!v.prototype && (
64 typeof v === "function" && !!v.prototype && (
65 "domNode" in v.prototype ||
65 "domNode" in v.prototype ||
66 "buildRendering" in v.prototype
66 "buildRendering" in v.prototype
67 );
67 );
68
68
69
69
70 /** Tests whether the specified node is placed in visible dom.
70 /** Tests whether the specified node is placed in visible dom.
71 * @param {Node} node The node to test
71 * @param {Node} node The node to test
72 */
72 */
73 export const isInPage = (node: Node) => node === document.body ? false : document.body.contains(node);
73 export const isInPage = (node: Node) => node === document.body ? false : document.body.contains(node);
74
74
75 export const isRecursivelyDestroyable = (target: unknown): target is IRecursivelyDestroyable =>
75 export const isRecursivelyDestroyable = (target: unknown): target is IRecursivelyDestroyable =>
76 !!(target && typeof (target as IRecursivelyDestroyable).destroyRecursive === "function");
76 !!(target && typeof (target as IRecursivelyDestroyable).destroyRecursive === "function");
77
77
78
78
79
79
80 /** Destroys DOM Node with all contained widgets.
80 /** Destroys DOM Node with all contained widgets.
81 * If the specified node is the root node of a widget, then the
81 * If the specified node is the root node of a widget, then the
82 * widget will be destroyed.
82 * widget will be destroyed.
83 *
83 *
84 * @param target DOM Node or widget to destroy
84 * @param target DOM Node or widget to destroy
85 */
85 */
86 export const destroy = (target: Node | IDestroyable | IRecursivelyDestroyable) => {
86 export const destroy = (target: Node | IDestroyable | IRecursivelyDestroyable) => {
87 if (isRecursivelyDestroyable(target)) {
87 if (isRecursivelyDestroyable(target)) {
88 target.destroyRecursive();
88 target.destroyRecursive();
89 } else if (isDestroyable(target)) {
89 } else if (isDestroyable(target)) {
90 target.destroy();
90 target.destroy();
91 } else if (isNode(target)) {
91 } else if (isNode(target)) {
92 if (isElementNode(target)) {
92 if (isElementNode(target)) {
93 const w = registry.byNode(target);
93 const w = registry.byNode(target);
94 if (w) {
94 if (w) {
95 w.destroyRecursive();
95 w.destroyRecursive();
96 return;
96 return;
97 } else {
97 } else {
98 emptyNode(target);
98 emptyNode(target);
99 }
99 }
100 }
100 }
101 const parent = target.parentNode;
101 const parent = target.parentNode;
102 if (parent)
102 if (parent)
103 parent.removeChild(target);
103 parent.removeChild(target);
104
104
105 }
105 }
106 };
106 };
107
107
108 /** Empties a content of the specified node and destroys all contained widgets.
108 /** Empties a content of the specified node and destroys all contained widgets.
109 *
109 *
110 * @param target DOM node to empty.
110 * @param target DOM node to empty.
111 */
111 */
112 export const emptyNode = (target: Node) => {
112 export const emptyNode = (target: Node) => {
113 registry.findWidgets(target).forEach(destroy);
113 registry.findWidgets(target).forEach(destroy);
114
114
115 // eslint-disable-next-line no-cond-assign
115 // eslint-disable-next-line no-cond-assign
116 for (let c; c = target.lastChild;) { // intentional assignment
116 for (let c; c = target.lastChild;) { // intentional assignment
117 target.removeChild(c);
117 target.removeChild(c);
118 }
118 }
119 };
119 };
120
120
121 /** This function starts all widgets inside the DOM node if the target is a node
121 /** This function starts all widgets inside the DOM node if the target is a node
122 * or starts widget itself if the target is the widget. If the specified node
122 * or starts widget itself if the target is the widget. If the specified node
123 * associated with the widget that widget will be started.
123 * associated with the widget that widget will be started.
124 *
124 *
125 * @param target DOM node to find and start widgets or the widget itself.
125 * @param target DOM node to find and start widgets or the widget itself.
126 */
126 */
127 export const startupWidgets = (target: Node | _WidgetBase, skipNode?: Node) => {
127 export const startupWidgets = (target: Node | _WidgetBase, skipNode?: Node) => {
128 if (isNode(target)) {
128 if (isNode(target)) {
129 if (isElementNode(target)) {
129 if (isElementNode(target)) {
130 const w = registry.byNode(target);
130 const w = registry.byNode(target);
131 if (w) {
131 if (w) {
132 if (w.startup)
132 if (w.startup)
133 w.startup();
133 w.startup();
134 } else {
134 } else {
135 registry.findWidgets(target, skipNode).forEach(x => x.startup());
135 registry.findWidgets(target, skipNode).forEach(x => x.startup());
136 }
136 }
137 }
137 }
138 } else {
138 } else {
139 if (target.startup)
139 if (target.startup)
140 target.startup();
140 target.startup();
141 }
141 }
142 };
142 };
143
143
144 /** Places the specified DOM node at the specified location.
144 /** Places the specified DOM node at the specified location.
145 *
145 *
146 * @param node The node which should be placed
146 * @param node The node which should be placed
147 * @param refNodeOrId The reference node where the created
147 * @param refNodeOrId The reference node where the created
148 * DOM should be placed.
148 * DOM should be placed.
149 * @param position Optional parameter, specifies the
149 * @param position Optional parameter, specifies the
150 * position relative to refNode. Default is "last" (i.e. last child).
150 * position relative to refNode. Default is "last" (i.e. last child).
151 */
151 */
152 export const placeAt = (node: Node, refNodeOrId: string | Node, position: DojoNodePosition = "last") => {
152 export const placeAt = (node: Node, refNodeOrId: string | Node, position: DojoNodePosition = "last") => {
153 const ref = typeof refNodeOrId == "string" ? document.getElementById(refNodeOrId) : refNodeOrId;
153 const ref = typeof refNodeOrId == "string" ? document.getElementById(refNodeOrId) : refNodeOrId;
154 if (!ref)
154 if (!ref)
155 return;
155 return;
156
156
157 const parent = ref.parentNode;
157 const parent = ref.parentNode;
158
158
159 if (typeof position == "number") {
159 if (typeof position == "number") {
160 if (ref.childNodes.length <= position) {
160 if (ref.childNodes.length <= position) {
161 ref.appendChild(node);
161 ref.appendChild(node);
162 } else {
162 } else {
163 ref.insertBefore(node, ref.childNodes[position]);
163 ref.insertBefore(node, ref.childNodes[position]);
164 }
164 }
165 } else {
165 } else {
166 switch (position) {
166 switch (position) {
167 case "before":
167 case "before":
168 parent && parent.insertBefore(node, ref);
168 parent && parent.insertBefore(node, ref);
169 break;
169 break;
170 case "after":
170 case "after":
171 parent && parent.insertBefore(node, ref.nextSibling);
171 parent && parent.insertBefore(node, ref.nextSibling);
172 break;
172 break;
173 case "first":
173 case "first":
174 ref.insertBefore(node, ref.firstChild);
174 ref.insertBefore(node, ref.firstChild);
175 break;
175 break;
176 case "last":
176 case "last":
177 ref.appendChild(node);
177 ref.appendChild(node);
178 break;
178 break;
179 case "only":
179 case "only":
180 emptyNode(ref);
180 emptyNode(ref);
181 ref.appendChild(node);
181 ref.appendChild(node);
182 break;
182 break;
183 case "replace":
183 case "replace":
184 if (parent)
184 if (parent)
185 parent.replaceChild(node, ref);
185 parent.replaceChild(node, ref);
186 destroy(ref);
186 destroy(ref);
187 break;
187 break;
188 }
188 }
189 }
189 }
190 };
190 };
191
191
192 /** Collects nodes from collection to an array.
192 /** Collects nodes from collection to an array.
193 *
193 *
194 * @param collection The collection of nodes.
194 * @param collection The collection of nodes.
195 * @returns The array of nodes.
195 * @returns The array of nodes.
196 */
196 */
197 export const collectNodes = (collection: NodeListOf<ChildNode>) => {
197 export const collectNodes = (collection: NodeListOf<ChildNode>) => {
198 const items = [];
198 const items = [];
199 for (let i = 0, n = collection.length; i < n; i++) {
199 for (let i = 0, n = collection.length; i < n; i++) {
200 items.push(collection[i]);
200 items.push(collection[i]);
201 }
201 }
202 return items;
202 return items;
203 };
203 };
204
204
205
205
206 export const isMounted = (node: Node) => {
206 export const isMounted = (node: Node) => {
207 if (node.parentNode) {
207 if (node.parentNode) {
208 const parentWidget = registry.getEnclosingWidget(node.parentNode);
208 const parentWidget = registry.getEnclosingWidget(node.parentNode);
209 if (parentWidget && parentWidget._started)
209 if (parentWidget && parentWidget._started)
210 return true;
210 return true;
211 }
211 }
212 if (isInPage(node))
212 if (isInPage(node))
213 return true;
213 return true;
214 return false;
214 return false;
215 }; No newline at end of file
215 };
General Comments 0
You need to be logged in to leave comments. Login now