@gogocat/data-bind 1.12.0 → 2.0.0

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 (271) hide show
  1. package/.editorconfig +14 -14
  2. package/.vscode/launch.json +12 -12
  3. package/CONFIGURATION.md +294 -0
  4. package/REACTIVE_MODE.md +553 -0
  5. package/README.md +266 -829
  6. package/babel.config.json +30 -0
  7. package/dist/js/_escape.d.ts +14 -0
  8. package/dist/js/_escape.d.ts.map +1 -0
  9. package/dist/js/applyBinding.d.ts +11 -0
  10. package/dist/js/applyBinding.d.ts.map +1 -0
  11. package/dist/js/attrBinding.d.ts +12 -0
  12. package/dist/js/attrBinding.d.ts.map +1 -0
  13. package/dist/js/binder.d.ts +67 -0
  14. package/dist/js/binder.d.ts.map +1 -0
  15. package/dist/js/changeBinding.d.ts +19 -0
  16. package/dist/js/changeBinding.d.ts.map +1 -0
  17. package/dist/js/commentWrapper.d.ts +39 -0
  18. package/dist/js/commentWrapper.d.ts.map +1 -0
  19. package/dist/js/config.d.ts +55 -0
  20. package/dist/js/config.d.ts.map +1 -0
  21. package/dist/js/createBindingOption.d.ts +32 -0
  22. package/dist/js/createBindingOption.d.ts.map +1 -0
  23. package/dist/js/createEventBinding.d.ts +10 -0
  24. package/dist/js/createEventBinding.d.ts.map +1 -0
  25. package/dist/js/cssBinding.d.ts +15 -0
  26. package/dist/js/cssBinding.d.ts.map +1 -0
  27. package/dist/js/dataBind.js +2756 -2530
  28. package/dist/js/dataBind.min.js +8 -1
  29. package/dist/js/dataBind.min.js.map +1 -1
  30. package/dist/js/domWalker.d.ts +9 -0
  31. package/dist/js/domWalker.d.ts.map +1 -0
  32. package/dist/js/forOfBinding.d.ts +12 -0
  33. package/dist/js/forOfBinding.d.ts.map +1 -0
  34. package/dist/js/hoverBinding.d.ts +13 -0
  35. package/dist/js/hoverBinding.d.ts.map +1 -0
  36. package/dist/js/ifBinding.d.ts +12 -0
  37. package/dist/js/ifBinding.d.ts.map +1 -0
  38. package/dist/js/index.d.ts +10 -0
  39. package/dist/js/index.d.ts.map +1 -0
  40. package/dist/js/modelBinding.d.ts +12 -0
  41. package/dist/js/modelBinding.d.ts.map +1 -0
  42. package/dist/js/postProcess.d.ts +3 -0
  43. package/dist/js/postProcess.d.ts.map +1 -0
  44. package/dist/js/pubSub.d.ts +11 -0
  45. package/dist/js/pubSub.d.ts.map +1 -0
  46. package/dist/js/reactiveProxy.d.ts +28 -0
  47. package/dist/js/reactiveProxy.d.ts.map +1 -0
  48. package/dist/js/renderForOfBinding.d.ts +8 -0
  49. package/dist/js/renderForOfBinding.d.ts.map +1 -0
  50. package/dist/js/renderIfBinding.d.ts +22 -0
  51. package/dist/js/renderIfBinding.d.ts.map +1 -0
  52. package/dist/js/renderIteration.d.ts +16 -0
  53. package/dist/js/renderIteration.d.ts.map +1 -0
  54. package/dist/js/renderTemplate.d.ts +14 -0
  55. package/dist/js/renderTemplate.d.ts.map +1 -0
  56. package/dist/js/renderTemplatesBinding.d.ts +19 -0
  57. package/dist/js/renderTemplatesBinding.d.ts.map +1 -0
  58. package/dist/js/showBinding.d.ts +13 -0
  59. package/dist/js/showBinding.d.ts.map +1 -0
  60. package/dist/js/switchBinding.d.ts +13 -0
  61. package/dist/js/switchBinding.d.ts.map +1 -0
  62. package/dist/js/textBinding.d.ts +13 -0
  63. package/dist/js/textBinding.d.ts.map +1 -0
  64. package/dist/js/types/_escape.d.ts +14 -0
  65. package/dist/js/types/_escape.d.ts.map +1 -0
  66. package/dist/js/types/applyBinding.d.ts +11 -0
  67. package/dist/js/types/applyBinding.d.ts.map +1 -0
  68. package/dist/js/types/attrBinding.d.ts +12 -0
  69. package/dist/js/types/attrBinding.d.ts.map +1 -0
  70. package/dist/js/types/binder.d.ts +67 -0
  71. package/dist/js/types/binder.d.ts.map +1 -0
  72. package/dist/js/types/changeBinding.d.ts +19 -0
  73. package/dist/js/types/changeBinding.d.ts.map +1 -0
  74. package/dist/js/types/commentWrapper.d.ts +39 -0
  75. package/dist/js/types/commentWrapper.d.ts.map +1 -0
  76. package/dist/js/types/config.d.ts +55 -0
  77. package/dist/js/types/config.d.ts.map +1 -0
  78. package/dist/js/types/createBindingOption.d.ts +32 -0
  79. package/dist/js/types/createBindingOption.d.ts.map +1 -0
  80. package/dist/js/types/createEventBinding.d.ts +10 -0
  81. package/dist/js/types/createEventBinding.d.ts.map +1 -0
  82. package/dist/js/types/cssBinding.d.ts +15 -0
  83. package/dist/js/types/cssBinding.d.ts.map +1 -0
  84. package/dist/js/types/domWalker.d.ts +9 -0
  85. package/dist/js/types/domWalker.d.ts.map +1 -0
  86. package/dist/js/types/forOfBinding.d.ts +12 -0
  87. package/dist/js/types/forOfBinding.d.ts.map +1 -0
  88. package/dist/js/types/hoverBinding.d.ts +13 -0
  89. package/dist/js/types/hoverBinding.d.ts.map +1 -0
  90. package/dist/js/types/ifBinding.d.ts +12 -0
  91. package/dist/js/types/ifBinding.d.ts.map +1 -0
  92. package/dist/js/types/index.d.ts +10 -0
  93. package/dist/js/types/index.d.ts.map +1 -0
  94. package/dist/js/types/modelBinding.d.ts +12 -0
  95. package/dist/js/types/modelBinding.d.ts.map +1 -0
  96. package/dist/js/types/postProcess.d.ts +3 -0
  97. package/dist/js/types/postProcess.d.ts.map +1 -0
  98. package/dist/js/types/pubSub.d.ts +11 -0
  99. package/dist/js/types/pubSub.d.ts.map +1 -0
  100. package/dist/js/types/reactiveProxy.d.ts +28 -0
  101. package/dist/js/types/reactiveProxy.d.ts.map +1 -0
  102. package/dist/js/types/renderForOfBinding.d.ts +8 -0
  103. package/dist/js/types/renderForOfBinding.d.ts.map +1 -0
  104. package/dist/js/types/renderIfBinding.d.ts +22 -0
  105. package/dist/js/types/renderIfBinding.d.ts.map +1 -0
  106. package/dist/js/types/renderIteration.d.ts +16 -0
  107. package/dist/js/types/renderIteration.d.ts.map +1 -0
  108. package/dist/js/types/renderTemplate.d.ts +14 -0
  109. package/dist/js/types/renderTemplate.d.ts.map +1 -0
  110. package/dist/js/types/renderTemplatesBinding.d.ts +19 -0
  111. package/dist/js/types/renderTemplatesBinding.d.ts.map +1 -0
  112. package/dist/js/types/showBinding.d.ts +13 -0
  113. package/dist/js/types/showBinding.d.ts.map +1 -0
  114. package/dist/js/types/switchBinding.d.ts +13 -0
  115. package/dist/js/types/switchBinding.d.ts.map +1 -0
  116. package/dist/js/types/textBinding.d.ts +13 -0
  117. package/dist/js/types/textBinding.d.ts.map +1 -0
  118. package/dist/js/types/types.d.ts +111 -0
  119. package/dist/js/types/types.d.ts.map +1 -0
  120. package/dist/js/types/util.d.ts +119 -0
  121. package/dist/js/types/util.d.ts.map +1 -0
  122. package/dist/js/types.d.ts +111 -0
  123. package/dist/js/types.d.ts.map +1 -0
  124. package/dist/js/util.d.ts +119 -0
  125. package/dist/js/util.d.ts.map +1 -0
  126. package/eslint.config.js +124 -0
  127. package/examples/DBMONSTER_COMPARISON.md +123 -0
  128. package/examples/afterRenderDemo.html +119 -0
  129. package/examples/bootstrap/css/animate.css +1579 -1579
  130. package/examples/bootstrap/css/bootstrap.min.css +6 -6
  131. package/examples/bootstrap/css/homeservices.css +378 -390
  132. package/examples/bootstrap/css/open-iconic.css +511 -511
  133. package/examples/bootstrap/fonts/open-iconic.svg +543 -543
  134. package/examples/bootstrap/js/compMessageDialog.js +20 -19
  135. package/examples/bootstrap/js/compSearchBar.js +12 -19
  136. package/examples/bootstrap/js/compSearchResults.js +50 -46
  137. package/examples/bootstrap/js/featureAdsResult.json +65 -65
  138. package/examples/bootstrap/js/searchResult.json +57 -57
  139. package/examples/bootstrap.html +343 -332
  140. package/examples/css/baseTodo.css +141 -141
  141. package/examples/css/dbMonsterStyles.css +27 -27
  142. package/examples/css/indexTodo.css +374 -374
  143. package/examples/dbmonsterForOfReactive.html +40 -0
  144. package/examples/dbmonsterReact.html +19 -0
  145. package/examples/forOfBindingSimpleDebug.html +45 -0
  146. package/examples/globalConfig.html +131 -0
  147. package/examples/js/afterRenderDemo.js +190 -0
  148. package/examples/js/appTodo.js +46 -46
  149. package/examples/js/attrBindingDemo.js +2 -2
  150. package/examples/js/dbMonApp.js +24 -26
  151. package/examples/js/dbMonAppReact.jsx +79 -0
  152. package/examples/js/dbMonAppReactive.js +28 -0
  153. package/examples/js/fiberDemo.js +4 -4
  154. package/examples/js/filtersDemo.js +8 -8
  155. package/examples/js/forOfDemo.js +7 -9
  156. package/examples/js/forOfDemoComplex.js +44 -17
  157. package/examples/js/form.js +14 -14
  158. package/examples/js/globalConfig.js +117 -0
  159. package/examples/js/ifBindingDemo.js +16 -16
  160. package/examples/js/reactiveDemo.js +119 -0
  161. package/examples/js/switchBindingDemo.js +8 -8
  162. package/examples/react-dbmonster/dist/bundle.js +43 -0
  163. package/examples/react-dbmonster/package-lock.json +537 -0
  164. package/examples/react-dbmonster/package.json +16 -0
  165. package/examples/react-dbmonster/src/index.jsx +80 -0
  166. package/examples/reactiveDemo.html +127 -0
  167. package/examples/refreshRateTest.html +75 -75
  168. package/index.html +841 -0
  169. package/package.json +31 -34
  170. package/rollup.config.js +79 -36
  171. package/src/{_escape.js → _escape.ts} +19 -17
  172. package/src/{applyBinding.js → applyBinding.ts} +27 -18
  173. package/src/{attrBinding.js → attrBinding.ts} +14 -13
  174. package/src/{binder.js → binder.ts} +289 -181
  175. package/src/changeBinding.ts +93 -0
  176. package/src/{commentWrapper.js → commentWrapper.ts} +33 -30
  177. package/src/config.ts +107 -0
  178. package/src/{createBindingOption.js → createBindingOption.ts} +39 -15
  179. package/src/createEventBinding.ts +88 -0
  180. package/src/{cssBinding.js → cssBinding.ts} +13 -11
  181. package/src/{domWalker.js → domWalker.ts} +44 -30
  182. package/src/{forOfBinding.js → forOfBinding.ts} +4 -3
  183. package/src/hoverBinding.ts +84 -0
  184. package/src/{ifBinding.js → ifBinding.ts} +14 -12
  185. package/src/index.ts +53 -0
  186. package/src/{modelBinding.js → modelBinding.ts} +11 -9
  187. package/src/{postProcess.js → postProcess.ts} +6 -4
  188. package/src/{pubSub.js → pubSub.ts} +24 -21
  189. package/src/reactiveProxy.ts +285 -0
  190. package/src/{renderForOfBinding.js → renderForOfBinding.ts} +54 -32
  191. package/src/{renderIfBinding.js → renderIfBinding.ts} +41 -19
  192. package/src/{renderIteration.js → renderIteration.ts} +24 -8
  193. package/src/renderTemplate.ts +165 -0
  194. package/src/renderTemplatesBinding.ts +73 -0
  195. package/src/{showBinding.js → showBinding.ts} +4 -3
  196. package/src/{switchBinding.js → switchBinding.ts} +18 -15
  197. package/src/{textBinding.js → textBinding.ts} +5 -4
  198. package/src/types.ts +124 -0
  199. package/src/util.ts +810 -0
  200. package/test/css/reporter.css +9 -9
  201. package/test/globals.d.ts +19 -0
  202. package/test/helpers/testHelper.js +46 -11
  203. package/test/mocks/featureAdsResult.json +65 -65
  204. package/test/mocks/searchResult.json +57 -57
  205. package/test/specs/{attrBinding.spec.js → attrBinding.spec.ts} +103 -106
  206. package/test/specs/{binder.spec.js → binder.spec.ts} +29 -27
  207. package/test/specs/blurBinding.spec.ts +60 -0
  208. package/test/specs/chainableUse.spec.ts +125 -0
  209. package/test/specs/clickBinding.spec.ts +194 -0
  210. package/test/specs/{cssBinding.spec.js → cssBinding.spec.ts} +72 -79
  211. package/test/specs/{dataBindBootstrap.spec.js → dataBindBootstrap.spec.ts} +332 -313
  212. package/test/specs/{filter.spec.js → filter.spec.ts} +75 -76
  213. package/test/specs/{forOfBinding.spec.js → forOfBinding.spec.ts} +208 -219
  214. package/test/specs/formBinding.spec.ts +272 -0
  215. package/test/specs/ifBinding.spec.ts +165 -0
  216. package/test/specs/{nestedComponent.spec.js → nestedComponent.spec.ts} +88 -88
  217. package/test/specs/reactiveProxy.spec.ts +465 -0
  218. package/test/specs/{showBinding.spec.js → showBinding.spec.ts} +148 -149
  219. package/test/specs/{switchBinding.spec.js → switchBinding.spec.ts} +172 -173
  220. package/test/specs/templateBinding.spec.ts +273 -0
  221. package/test/specs/{textBinding.spec.js → textBinding.spec.ts} +47 -48
  222. package/test/tsconfig.json +31 -0
  223. package/test-output.txt +200 -0
  224. package/test-reactive.html +224 -0
  225. package/tsconfig.json +28 -0
  226. package/vendors/lodash.custom.js +4577 -4577
  227. package/vendors/lodash.custom.min.js +45 -45
  228. package/vitest.config.js +27 -0
  229. package/.eslintrc.js +0 -1
  230. package/.grunt/grunt-contrib-jasmine/boot.js +0 -161
  231. package/.grunt/grunt-contrib-jasmine/dist/js/dataBind.js +0 -9
  232. package/.grunt/grunt-contrib-jasmine/grunt-template-jasmine-istanbul/reporter.js +0 -23
  233. package/.grunt/grunt-contrib-jasmine/jasmine-html.js +0 -853
  234. package/.grunt/grunt-contrib-jasmine/jasmine.css +0 -271
  235. package/.grunt/grunt-contrib-jasmine/jasmine.js +0 -9761
  236. package/.grunt/grunt-contrib-jasmine/jasmine_favicon.png +0 -0
  237. package/.grunt/grunt-contrib-jasmine/json2.js +0 -489
  238. package/.grunt/grunt-contrib-jasmine/reporter.js +0 -107
  239. package/coverage/coverage.json +0 -1
  240. package/coverage/lcov/lcov-report/base.css +0 -213
  241. package/coverage/lcov/lcov-report/index.html +0 -93
  242. package/coverage/lcov/lcov-report/js/dataBind.js.html +0 -6596
  243. package/coverage/lcov/lcov-report/js/index.html +0 -93
  244. package/coverage/lcov/lcov-report/prettify.css +0 -1
  245. package/coverage/lcov/lcov-report/prettify.js +0 -1
  246. package/coverage/lcov/lcov-report/sort-arrow-sprite.png +0 -0
  247. package/coverage/lcov/lcov-report/sorter.js +0 -158
  248. package/coverage/lcov/lcov.info +0 -1991
  249. package/eslintrc.json +0 -40
  250. package/examples/bootstrap/js/bootstrap.min.js +0 -6
  251. package/examples/bootstrap/js/popper.min.js +0 -5
  252. package/examples/bootstrap/js/searchSuggestion.js +0 -58
  253. package/examples/bootstrap/js/typeahead.jquery.js +0 -1538
  254. package/gruntfile.js +0 -92
  255. package/gulpfile.js +0 -32
  256. package/src/applyBindingExport.js +0 -5
  257. package/src/changeBinding.js +0 -63
  258. package/src/config.js +0 -66
  259. package/src/createEventBinding.js +0 -46
  260. package/src/eventSystem.js +0 -46
  261. package/src/hoverBinding.js +0 -57
  262. package/src/index.js +0 -26
  263. package/src/renderTemplate.js +0 -128
  264. package/src/renderTemplatesBinding.js +0 -44
  265. package/src/util.js +0 -648
  266. package/test/specs/blurBinding.spec.js +0 -57
  267. package/test/specs/formBinding.spec.js +0 -316
  268. package/test/specs/ifBinding.spec.js +0 -169
  269. package/test/specs/templateBinding.spec.js +0 -117
  270. package/vendors/jasmine-jquery.js +0 -841
  271. package/vendors/jquery-3.2.1.min.js +0 -4
@@ -1,15 +1,16 @@
1
- /* eslint-disable no-invalid-this */
1
+
2
2
  import * as config from './config';
3
3
  import * as util from './util';
4
+ import type {BindingCache} from './types';
4
5
 
5
- const createClonedElementCache = (bindingData) => {
6
+ const createClonedElementCache = (bindingData: BindingCache): BindingCache => {
6
7
  const clonedElement = bindingData.el.cloneNode(true);
7
8
  bindingData.fragment = document.createDocumentFragment();
8
9
  bindingData.fragment.appendChild(clonedElement);
9
10
  return bindingData;
10
11
  };
11
12
 
12
- const setCommentPrefix = (bindingData) => {
13
+ const setCommentPrefix = (bindingData: BindingCache): BindingCache => {
13
14
  if (!bindingData || !bindingData.type) {
14
15
  return bindingData;
15
16
  }
@@ -17,18 +18,18 @@ const setCommentPrefix = (bindingData) => {
17
18
  const dataKeyMarker = bindingData.dataKey ? bindingData.dataKey.replace(util.REGEX.WHITE_SPACES, '_') : '';
18
19
 
19
20
  switch (bindingData.type) {
20
- case config.bindingAttrs.forOf:
21
- commentPrefix = config.commentPrefix.forOf;
22
- break;
23
- case config.bindingAttrs.if:
24
- commentPrefix = config.commentPrefix.if;
25
- break;
26
- case config.bindingAttrs.case:
27
- commentPrefix = config.commentPrefix.case;
28
- break;
29
- case config.bindingAttrs.default:
30
- commentPrefix = config.commentPrefix.default;
31
- break;
21
+ case config.bindingAttrs.forOf:
22
+ commentPrefix = config.commentPrefix.forOf;
23
+ break;
24
+ case config.bindingAttrs.if:
25
+ commentPrefix = config.commentPrefix.if;
26
+ break;
27
+ case config.bindingAttrs.case:
28
+ commentPrefix = config.commentPrefix.case;
29
+ break;
30
+ case config.bindingAttrs.default:
31
+ commentPrefix = config.commentPrefix.default;
32
+ break;
32
33
  }
33
34
  bindingData.commentPrefix = commentPrefix + dataKeyMarker;
34
35
  return bindingData;
@@ -44,18 +45,18 @@ const setCommentPrefix = (bindingData) => {
44
45
  * if not found deleteContents will has no operation
45
46
  * @return {undefined}
46
47
  */
47
- const setDocRangeEndAfter = (node, bindingData) => {
48
+ const setDocRangeEndAfter = (node: Node | null, bindingData: BindingCache): void => {
48
49
  if (!bindingData.commentPrefix) {
49
50
  setCommentPrefix(bindingData);
50
51
  }
51
- const startTextContent = bindingData.commentPrefix;
52
+ const startTextContent = bindingData.commentPrefix as string;
52
53
  const endTextContent = startTextContent + config.commentSuffix;
53
54
  node = node.nextSibling;
54
55
 
55
56
  // check last wrap comment node
56
57
  if (node) {
57
58
  if (node.nodeType === 8 && node.textContent === endTextContent) {
58
- return bindingData.docRange.setEndBefore(node);
59
+ return (bindingData.docRange as Range).setEndBefore(node);
59
60
  }
60
61
  setDocRangeEndAfter(node, bindingData);
61
62
  }
@@ -69,12 +70,12 @@ const setDocRangeEndAfter = (node, bindingData) => {
69
70
  * @description
70
71
  * wrap frament with comment node
71
72
  */
72
- const wrapCommentAround = (bindingData, node) => {
73
+ const wrapCommentAround = (bindingData: BindingCache, node: Node | DocumentFragment): Node | DocumentFragment => {
73
74
  let prefix = '';
74
75
  if (!bindingData.commentPrefix) {
75
76
  setCommentPrefix(bindingData);
76
77
  }
77
- prefix = bindingData.commentPrefix;
78
+ prefix = bindingData.commentPrefix as string;
78
79
  const commentBegin = document.createComment(prefix);
79
80
  const commentEnd = document.createComment(prefix + config.commentSuffix);
80
81
  // document fragment - logic for ForOf binding
@@ -100,25 +101,26 @@ const wrapCommentAround = (bindingData, node) => {
100
101
  * @return {undefined}
101
102
  * @description remove elments by range
102
103
  */
103
- const removeElemnetsByCommentWrap = (bindingData) => {
104
+ const removeElemnetsByCommentWrap = (bindingData: BindingCache): void => {
104
105
  if (!bindingData.docRange) {
105
106
  bindingData.docRange = document.createRange();
106
107
  }
108
+ const docRange = bindingData.docRange as Range;
107
109
  try {
108
110
  if (bindingData.previousNonTemplateElement) {
109
111
  // update docRange start and end match the wrapped comment node
110
- bindingData.docRange.setStartBefore(bindingData.previousNonTemplateElement.nextSibling);
112
+ docRange.setStartBefore(bindingData.previousNonTemplateElement.nextSibling as Node);
111
113
  setDocRangeEndAfter(bindingData.previousNonTemplateElement.nextSibling, bindingData);
112
114
  } else {
113
115
  // insert before next non template element
114
- bindingData.docRange.setStartBefore(bindingData.parentElement.firstChild);
115
- setDocRangeEndAfter(bindingData.parentElement.firstChild, bindingData);
116
+ docRange.setStartBefore((bindingData.parentElement as HTMLElement).firstChild as Node);
117
+ setDocRangeEndAfter((bindingData.parentElement as HTMLElement).firstChild, bindingData);
116
118
  }
117
- } catch (err) {
118
- console.log('error removeElemnetsByCommentWrap: ', err.message);
119
+ } catch (err: unknown) {
120
+ console.log('error removeElemnetsByCommentWrap: ', err instanceof Error ? err.message : String(err));
119
121
  }
120
122
 
121
- return bindingData.docRange.deleteContents();
123
+ docRange.deleteContents();
122
124
  };
123
125
 
124
126
  /**
@@ -126,15 +128,16 @@ const removeElemnetsByCommentWrap = (bindingData) => {
126
128
  * @param {object} bindingData
127
129
  * @return {object} null
128
130
  */
129
- const removeDomTemplateElement = (bindingData) => {
131
+ const removeDomTemplateElement = (bindingData: BindingCache): void => {
130
132
  // first render - forElement is live DOM element so has parentNode
131
133
  if (bindingData.el.parentNode) {
132
- return bindingData.el.parentNode.removeChild(bindingData.el);
134
+ bindingData.el.parentNode.removeChild(bindingData.el);
135
+ return;
133
136
  }
134
137
  removeElemnetsByCommentWrap(bindingData);
135
138
  };
136
139
 
137
- const insertRenderedElements = (bindingData, fragment) => {
140
+ const insertRenderedElements = (bindingData: BindingCache, fragment: DocumentFragment): void => {
138
141
  // insert rendered fragment after the previousNonTemplateElement
139
142
  if (bindingData.previousNonTemplateElement) {
140
143
  util.insertAfter(bindingData.parentElement, fragment, bindingData.previousNonTemplateElement);
package/src/config.ts ADDED
@@ -0,0 +1,107 @@
1
+ export interface BindingAttrs {
2
+ comp: string;
3
+ tmp: string;
4
+ text: string;
5
+ click: string;
6
+ dblclick: string;
7
+ blur: string;
8
+ focus: string;
9
+ hover: string;
10
+ input: string;
11
+ change: string;
12
+ submit: string;
13
+ model: string;
14
+ show: string;
15
+ css: string;
16
+ attr: string;
17
+ forOf: string;
18
+ if: string;
19
+ switch: string;
20
+ case: string;
21
+ default: string;
22
+ }
23
+
24
+ export const bindingAttrs: BindingAttrs = {
25
+ comp: 'data-bind-comp',
26
+ tmp: 'data-bind-tmp',
27
+ text: 'data-bind-text',
28
+ click: 'data-bind-click',
29
+ dblclick: 'data-bind-dblclick',
30
+ blur: 'data-bind-blur',
31
+ focus: 'data-bind-focus',
32
+ hover: 'data-bind-hover',
33
+ input: 'data-bind-input',
34
+ change: 'data-bind-change',
35
+ submit: 'data-bind-submit',
36
+ model: 'data-bind-model',
37
+ show: 'data-bind-show',
38
+ css: 'data-bind-css',
39
+ attr: 'data-bind-attr',
40
+ forOf: 'data-bind-for',
41
+ if: 'data-bind-if',
42
+ switch: 'data-bind-switch',
43
+ case: 'data-bind-case',
44
+ default: 'data-bind-default',
45
+ };
46
+
47
+ export const serverRenderedAttr = 'data-server-rendered';
48
+ export const dataIndexAttr = 'data-index';
49
+
50
+ export interface CommentPrefix {
51
+ forOf: string;
52
+ if: string;
53
+ case: string;
54
+ default: string;
55
+ }
56
+
57
+ export const commentPrefix: CommentPrefix = {
58
+ forOf: 'data-forOf_',
59
+ if: 'data-if_',
60
+ case: 'data-case_',
61
+ default: 'data-default_',
62
+ };
63
+
64
+ export const commentSuffix = '_end';
65
+
66
+ export interface BindingDataReference {
67
+ rootDataKey: string;
68
+ currentData: string;
69
+ currentIndex: string;
70
+ mouseEnterHandlerName: string;
71
+ mouseLeaveHandlerName: string;
72
+ }
73
+
74
+ export const bindingDataReference: BindingDataReference = {
75
+ rootDataKey: '$root',
76
+ currentData: '$data',
77
+ currentIndex: '$index',
78
+ mouseEnterHandlerName: 'in',
79
+ mouseLeaveHandlerName: 'out',
80
+ };
81
+
82
+ export interface BindingUpdateConditions {
83
+ serverRendered: string;
84
+ init: string;
85
+ }
86
+
87
+ export const bindingUpdateConditions: BindingUpdateConditions = {
88
+ serverRendered: 'SERVER-RENDERED',
89
+ init: 'INIT',
90
+ };
91
+
92
+ // maximum string length before running regex
93
+ export const maxDatakeyLength = 250;
94
+
95
+ export interface Constants {
96
+ filters: {
97
+ ONCE: string;
98
+ };
99
+ PARENT_REF: string;
100
+ }
101
+
102
+ export const constants: Constants = {
103
+ filters: {
104
+ ONCE: 'once',
105
+ },
106
+ PARENT_REF: '_parent',
107
+ };
@@ -2,6 +2,29 @@ import {
2
2
  bindingUpdateConditions,
3
3
  } from './config';
4
4
  import {extend} from './util';
5
+
6
+ export interface BindingOption {
7
+ templateBinding?: boolean;
8
+ textBinding?: boolean;
9
+ cssBinding?: boolean;
10
+ ifBinding?: boolean;
11
+ showBinding?: boolean;
12
+ modelBinding?: boolean;
13
+ attrBinding?: boolean;
14
+ forOfBinding?: boolean;
15
+ switchBinding?: boolean;
16
+ changeBinding?: boolean;
17
+ clickBinding?: boolean;
18
+ dblclickBinding?: boolean;
19
+ blurBinding?: boolean;
20
+ focusBinding?: boolean;
21
+ hoverBinding?: boolean;
22
+ inputBinding?: boolean;
23
+ submitBinding?: boolean;
24
+ forceRender?: boolean;
25
+ [key: string]: unknown;
26
+ }
27
+
5
28
  /**
6
29
  * createBindingOption
7
30
  * @param {string} condition
@@ -10,8 +33,8 @@ import {extend} from './util';
10
33
  * generate binding update option object by condition
11
34
  * @return {object} updateOption
12
35
  */
13
- function createBindingOption(condition = '', opt = {}) {
14
- const visualBindingOptions = {
36
+ const createBindingOption = (condition: string = '', opt: BindingOption = {}): BindingOption => {
37
+ const visualBindingOptions: BindingOption = {
15
38
  templateBinding: false,
16
39
  textBinding: true,
17
40
  cssBinding: true,
@@ -22,7 +45,7 @@ function createBindingOption(condition = '', opt = {}) {
22
45
  forOfBinding: true,
23
46
  switchBinding: true,
24
47
  };
25
- const eventsBindingOptions = {
48
+ const eventsBindingOptions: BindingOption = {
26
49
  changeBinding: true,
27
50
  clickBinding: true,
28
51
  dblclickBinding: true,
@@ -34,7 +57,7 @@ function createBindingOption(condition = '', opt = {}) {
34
57
  };
35
58
  // this is visualBindingOptions but everything false
36
59
  // concrete declear for performance purpose
37
- const serverRenderedOptions = {
60
+ const serverRenderedOptions: BindingOption = {
38
61
  templateBinding: false,
39
62
  textBinding: false,
40
63
  cssBinding: false,
@@ -45,23 +68,24 @@ function createBindingOption(condition = '', opt = {}) {
45
68
  forOfBinding: false,
46
69
  switchBinding: false,
47
70
  };
48
- let updateOption = {};
71
+ let updateOption: BindingOption = {};
49
72
 
50
73
  switch (condition) {
51
- case bindingUpdateConditions.serverRendered:
52
- updateOption = extend({}, eventsBindingOptions, serverRenderedOptions, opt);
53
- break;
54
- case bindingUpdateConditions.init:
74
+ case bindingUpdateConditions.serverRendered:
75
+ updateOption = extend(false, {}, eventsBindingOptions, serverRenderedOptions, opt);
76
+ break;
77
+ case bindingUpdateConditions.init:
55
78
  // flag templateBinding to true to render tempalte(s)
56
- opt.templateBinding = true;
57
- updateOption = extend({}, visualBindingOptions, eventsBindingOptions, opt);
58
- break;
59
- default:
79
+ opt.templateBinding = true;
80
+ opt.forceRender = true;
81
+ updateOption = extend(false, {}, visualBindingOptions, eventsBindingOptions, opt);
82
+ break;
83
+ default:
60
84
  // when called again only update visualBinding options
61
- updateOption = extend({}, visualBindingOptions, opt);
85
+ updateOption = extend(false, {}, visualBindingOptions, opt);
62
86
  }
63
87
 
64
88
  return updateOption;
65
- }
89
+ };
66
90
 
67
91
  export default createBindingOption;
@@ -0,0 +1,88 @@
1
+ import {
2
+ getFormData,
3
+ getViewModelValue,
4
+ resolveViewModelContext,
5
+ resolveParamList,
6
+ } from './util';
7
+ import type {BindingCache, ViewModel} from './types';
8
+
9
+ /**
10
+ * Create event handler wrapper
11
+ */
12
+ const createEventHandlerWrapper = (
13
+ type: string,
14
+ paramList: unknown[],
15
+ handlerFn: Function,
16
+ viewModelContext: ViewModel,
17
+ ): EventListener => {
18
+ return function handlerWrap(e: Event): void {
19
+ let formData: Record<string, unknown>;
20
+ let args: unknown[] = [];
21
+ if (type === 'submit') {
22
+ formData = getFormData(e.currentTarget as HTMLFormElement);
23
+ args = [e, e.currentTarget, formData, ...paramList];
24
+ } else {
25
+ args = [e, e.currentTarget, ...paramList];
26
+ }
27
+ handlerFn.apply(viewModelContext, args);
28
+ };
29
+ };
30
+
31
+ interface CreateEventBindingParams {
32
+ cache?: BindingCache;
33
+ forceRender?: boolean;
34
+ type?: string;
35
+ viewModel?: ViewModel;
36
+ }
37
+
38
+ const createEventBinding = ({
39
+ cache = {} as BindingCache,
40
+ forceRender = false,
41
+ type = '',
42
+ viewModel = {} as ViewModel,
43
+ }: CreateEventBindingParams): void => {
44
+ const handlerName = cache.dataKey;
45
+ let paramList = cache.parameters;
46
+ let viewModelContext: ViewModel;
47
+ const APP = viewModel.APP || viewModel.$root?.APP;
48
+ const rootElement = APP?.$rootElement as HTMLElement | undefined;
49
+
50
+ if (!type || !handlerName || (!forceRender && rootElement && !rootElement.contains(cache.el))) {
51
+ return;
52
+ }
53
+
54
+ const handlerFn = getViewModelValue(viewModel, handlerName);
55
+
56
+ if (typeof handlerFn === 'function') {
57
+ viewModelContext = resolveViewModelContext(viewModel, handlerName);
58
+ paramList = paramList ? resolveParamList(viewModel, paramList) : [];
59
+
60
+ // Store handler key for this event type on the DOM element itself
61
+ // This prevents duplicate handlers even if multiple cache objects exist for same element
62
+ const handlerKey = `_db_${type}Handler`;
63
+ const el = cache.el as HTMLElement & Record<string, unknown>;
64
+
65
+ // Check if handler already exists and skip if it's the same
66
+ // This prevents adding duplicate handlers when the same element is processed multiple times
67
+ if (el[handlerKey]) {
68
+ // Handler already exists, remove it before adding new one
69
+ el.removeEventListener(type, el[handlerKey] as EventListener, false);
70
+ }
71
+
72
+ // Create new handler wrapper
73
+ const handlerWrap = createEventHandlerWrapper(
74
+ type,
75
+ paramList,
76
+ handlerFn,
77
+ viewModelContext,
78
+ );
79
+
80
+ // Store the handler on the DOM element so we can remove it later
81
+ el[handlerKey] = handlerWrap;
82
+
83
+ // Add the new event listener
84
+ el.addEventListener(type, handlerWrap, false);
85
+ }
86
+ };
87
+
88
+ export default createEventBinding;
@@ -4,6 +4,7 @@ import {
4
4
  arrayRemoveMatch,
5
5
  each,
6
6
  } from './util';
7
+ import type {BindingCache, ViewModel, BindingAttrs, PlainObject} from './types';
7
8
 
8
9
  /**
9
10
  * cssBinding
@@ -16,11 +17,11 @@ import {
16
17
  * @param {object} bindingAttrs
17
18
  * @param {boolean} forceRender
18
19
  */
19
- const cssBinding = (cache, viewModel, bindingAttrs, forceRender) => {
20
+ const cssBinding = (cache: BindingCache, viewModel: ViewModel, bindingAttrs: BindingAttrs, forceRender: boolean): void => {
20
21
  const dataKey = cache.dataKey;
21
- const APP = viewModel.APP || viewModel.$root.APP;
22
+ const APP = viewModel.APP || viewModel.$root?.APP;
22
23
 
23
- if (!dataKey || (!forceRender && !APP.$rootElement.contains(cache.el))) {
24
+ if (!dataKey || (!forceRender && !(APP?.$rootElement as HTMLElement)?.contains(cache.el))) {
24
25
  return;
25
26
  }
26
27
 
@@ -30,10 +31,10 @@ const cssBinding = (cache, viewModel, bindingAttrs, forceRender) => {
30
31
  const oldCssList = cache.elementData.viewModelPropValue;
31
32
  let newCssList = '';
32
33
  const vmCssListObj = getViewModelPropValue(viewModel, cache);
33
- let vmCssListArray = [];
34
+ let vmCssListArray: string[] = [];
34
35
  let isViewDataObject = false;
35
36
  let isViewDataString = false;
36
- let cssList = [];
37
+ let cssList: string[] = [];
37
38
 
38
39
  if (typeof vmCssListObj === 'string') {
39
40
  isViewDataString = true;
@@ -47,7 +48,7 @@ const cssBinding = (cache, viewModel, bindingAttrs, forceRender) => {
47
48
  if (isViewDataObject) {
48
49
  newCssList = JSON.stringify(vmCssListObj);
49
50
  } else {
50
- newCssList = vmCssListObj.replace(/\s\s+/g, ' ').trim();
51
+ newCssList = (vmCssListObj as string).replace(/\s\s+/g, ' ').trim();
51
52
  vmCssListArray = newCssList.split(' ');
52
53
  }
53
54
  // reject if nothing changed
@@ -64,7 +65,7 @@ const cssBinding = (cache, viewModel, bindingAttrs, forceRender) => {
64
65
  }
65
66
 
66
67
  if (isViewDataObject) {
67
- each(vmCssListObj, function(k, v) {
68
+ each(vmCssListObj as PlainObject, (k: string, v: unknown) => {
68
69
  const i = cssList.indexOf(k);
69
70
  if (v === true) {
70
71
  cssList.push(k);
@@ -74,20 +75,21 @@ const cssBinding = (cache, viewModel, bindingAttrs, forceRender) => {
74
75
  });
75
76
  } else if (isViewDataString) {
76
77
  // remove oldCssList items from cssList
77
- cssList = arrayRemoveMatch(cssList, oldCssList);
78
+ const oldCssArray = typeof oldCssList === 'string' && oldCssList ? oldCssList.split(' ') : [];
79
+ cssList = arrayRemoveMatch(cssList, oldCssArray) as string[];
78
80
  cssList = cssList.concat(vmCssListArray);
79
81
  }
80
82
 
81
83
  // unique cssList array
82
- cssList = cssList.filter((v, i, a) => {
84
+ cssList = cssList.filter((v: string, i: number, a: string[]) => {
83
85
  return a.indexOf(v) === i;
84
86
  });
85
87
 
86
- cssList = cssList.join(' ');
88
+ const cssListString = cssList.join(' ');
87
89
  // update element data
88
90
  cache.elementData.viewModelPropValue = newCssList;
89
91
  // replace all css classes
90
- cache.el.setAttribute('class', cssList);
92
+ cache.el.setAttribute('class', cssListString);
91
93
  };
92
94
 
93
95
  export default cssBinding;
@@ -1,7 +1,8 @@
1
1
  import {invertObj, extractFilterList, getFunctionParameterList, REGEX} from './util';
2
2
  import {constants} from './config';
3
+ import type {PlainObject, BindingAttrs, ElementCache, BindingCache} from './types';
3
4
 
4
- let bindingAttrsMap;
5
+ let bindingAttrsMap: PlainObject | undefined;
5
6
 
6
7
  /**
7
8
  * walkDOM
@@ -10,47 +11,52 @@ let bindingAttrsMap;
10
11
  * @param {object} node
11
12
  * @param {function} func
12
13
  */
13
- const walkDOM = (node, func) => {
14
+ const walkDOM = (node: HTMLElement, func: (node: HTMLElement) => boolean): void => {
14
15
  let parseChildNode = true;
15
- node = node.firstElementChild;
16
- while (node) {
17
- parseChildNode = func(node);
16
+ let currentNode = node.firstElementChild as HTMLElement | null;
17
+ while (currentNode) {
18
+ parseChildNode = func(currentNode);
18
19
  if (parseChildNode) {
19
- walkDOM(node, func);
20
+ walkDOM(currentNode, func);
20
21
  }
21
- node = node.nextElementSibling;
22
+ currentNode = currentNode.nextElementSibling as HTMLElement | null;
22
23
  }
23
24
  };
24
25
 
25
- const getAttributesObject = (node) => {
26
- const ret = {};
27
- Array.prototype.slice.call(node.attributes).forEach((item) => {
26
+ const getAttributesObject = (node: HTMLElement): PlainObject => {
27
+ const ret: PlainObject = {};
28
+ Array.prototype.slice.call(node.attributes).forEach((item: Attr) => {
28
29
  ret[item.name] = item.value;
29
30
  });
30
31
  return ret;
31
32
  };
32
33
 
33
- const checkSkipChildParseBindings = (attrObj = {}, bindingAttrs) => {
34
- return [bindingAttrs.forOf, bindingAttrs.if, bindingAttrs.case, bindingAttrs.default].filter((type) => {
34
+ const checkSkipChildParseBindings = (attrObj: PlainObject = {}, bindingAttrs: BindingAttrs): string[] => {
35
+ return [bindingAttrs.forOf, bindingAttrs.if, bindingAttrs.case, bindingAttrs.default].filter((type: string) => {
35
36
  return typeof attrObj[type] !== 'undefined';
36
37
  });
37
38
  };
38
39
 
39
- const rootSkipCheck = (node) => {
40
+ const rootSkipCheck = (node: HTMLElement): boolean => {
40
41
  return node.tagName === 'SVG';
41
42
  };
42
43
 
43
- const defaultSkipCheck = (node, bindingAttrs) => {
44
+ const defaultSkipCheck = (node: HTMLElement, bindingAttrs: BindingAttrs): boolean => {
44
45
  return node.tagName === 'SVG' || node.hasAttribute(bindingAttrs.comp);
45
46
  };
46
47
 
47
- const populateBindingCache = ({node, attrObj, bindingCache, type}) => {
48
- let attrValue;
49
- let cacheData;
48
+ const populateBindingCache = ({node, attrObj, bindingCache, type}: {
49
+ node: HTMLElement;
50
+ attrObj: PlainObject;
51
+ bindingCache: ElementCache;
52
+ type: string;
53
+ }): ElementCache => {
54
+ let attrValue: string;
55
+ let cacheData: Partial<BindingCache>;
50
56
 
51
57
  if (bindingAttrsMap && bindingAttrsMap[type] && typeof attrObj[type] !== 'undefined') {
52
58
  bindingCache[type] = bindingCache[type] || [];
53
- attrValue = attrObj[type] || '';
59
+ attrValue = (attrObj[type] as string) || '';
54
60
 
55
61
  if (attrValue) {
56
62
  attrValue = attrValue.replace(REGEX.LINE_BREAKS_TABS, '').replace(REGEX.WHITE_SPACES, ' ').trim();
@@ -67,28 +73,36 @@ const populateBindingCache = ({node, attrObj, bindingCache, type}) => {
67
73
  // populate cacheData.parameters
68
74
  // for store function call parameters eg. '$index', '$root'
69
75
  // useful with DOM for-loop template as reference to binding data
70
- const paramList = getFunctionParameterList(cacheData.dataKey);
76
+ const paramList = getFunctionParameterList(cacheData.dataKey || '');
71
77
  if (paramList) {
72
78
  cacheData.parameters = paramList;
73
- cacheData.dataKey = cacheData.dataKey.replace(REGEX.FUNCTION_PARAM, '').trim();
79
+ cacheData.dataKey = (cacheData.dataKey || '').replace(REGEX.FUNCTION_PARAM, '').trim();
74
80
  }
75
81
  // store parent array reference to cacheData
76
82
  cacheData[constants.PARENT_REF] = bindingCache[type];
77
- bindingCache[type].push(cacheData);
83
+ bindingCache[type].push(cacheData as BindingCache);
78
84
  }
79
85
  return bindingCache;
80
86
  };
81
87
 
82
- const createBindingCache = ({rootNode = null, bindingAttrs = {}, skipCheck, isRenderedTemplate = false}) => {
83
- let bindingCache = {};
88
+ const createBindingCache = ({rootNode = null, bindingAttrs = {} as BindingAttrs, skipCheck, isRenderedTemplate = false}: {
89
+ rootNode?: HTMLElement | null;
90
+ bindingAttrs?: BindingAttrs;
91
+ skipCheck?: (node: HTMLElement) => boolean;
92
+ isRenderedTemplate?: boolean;
93
+ }): ElementCache => {
94
+ let bindingCache: ElementCache = {};
84
95
 
85
- if (!rootNode instanceof window.Node) {
96
+ if (!(rootNode instanceof window.Node)) {
86
97
  throw new TypeError('walkDOM: Expected a DOM node');
87
98
  }
88
99
 
89
100
  bindingAttrsMap = bindingAttrsMap || invertObj(bindingAttrs);
90
101
 
91
- const parseNode = (node, skipNodeCheckFn = defaultSkipCheck) => {
102
+ const parseNode = (
103
+ node: HTMLElement,
104
+ skipNodeCheckFn: (node: HTMLElement, bindingAttrs: BindingAttrs) => boolean = defaultSkipCheck,
105
+ ): boolean => {
92
106
  let isSkipForOfChild = false;
93
107
 
94
108
  if (node.nodeType !== 1 || !node.hasAttributes()) {
@@ -102,7 +116,7 @@ const createBindingCache = ({rootNode = null, bindingAttrs = {}, skipCheck, isRe
102
116
  // skip same element that has forOf binding the forOf is alredy parsed
103
117
  const attrObj = getAttributesObject(node);
104
118
  const hasSkipChildParseBindings = checkSkipChildParseBindings(attrObj, bindingAttrs);
105
- let iterateList = [];
119
+ let iterateList: string[] = [];
106
120
 
107
121
  if (hasSkipChildParseBindings.length) {
108
122
  isSkipForOfChild = true;
@@ -114,13 +128,13 @@ const createBindingCache = ({rootNode = null, bindingAttrs = {}, skipCheck, isRe
114
128
  iterateList = Object.keys(attrObj);
115
129
  }
116
130
 
117
- iterateList.forEach((key) => {
131
+ iterateList.forEach((key: string) => {
118
132
  // skip for switch case and default bining
119
133
  if (key !== bindingAttrs.case && key !== bindingAttrs.default) {
120
134
  bindingCache = populateBindingCache({
121
- node: node,
122
- attrObj: attrObj,
123
- bindingCache: bindingCache,
135
+ node,
136
+ attrObj,
137
+ bindingCache,
124
138
  type: key,
125
139
  });
126
140
  }