@dooboostore/dom-render 1.0.98

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 (230) hide show
  1. package/DomRender.d.ts +24 -0
  2. package/DomRender.js +115 -0
  3. package/DomRenderProxy.d.ts +38 -0
  4. package/DomRenderProxy.js +586 -0
  5. package/README.MD +938 -0
  6. package/components/ComponentBase.d.ts +41 -0
  7. package/components/ComponentBase.js +210 -0
  8. package/components/ComponentSet.d.ts +22 -0
  9. package/components/ComponentSet.js +23 -0
  10. package/components/appender/Appender.d.ts +23 -0
  11. package/components/appender/Appender.js +59 -0
  12. package/components/checkbox/CheckBox.d.ts +47 -0
  13. package/components/checkbox/CheckBox.js +118 -0
  14. package/components/choose/Choose.d.ts +39 -0
  15. package/components/choose/Choose.js +110 -0
  16. package/components/details/Details.d.ts +57 -0
  17. package/components/details/Details.js +199 -0
  18. package/components/dialog/Dialog.d.ts +1 -0
  19. package/components/dialog/Dialog.js +85 -0
  20. package/components/dialog/example/ImageEditorDialog.d.ts +1 -0
  21. package/components/dialog/example/ImageEditorDialog.js +116 -0
  22. package/components/forOf/ForOf.d.ts +18 -0
  23. package/components/forOf/ForOf.js +32 -0
  24. package/components/if/If.d.ts +21 -0
  25. package/components/if/If.js +40 -0
  26. package/components/index.d.ts +27 -0
  27. package/components/index.js +13 -0
  28. package/components/input/Input.d.ts +34 -0
  29. package/components/input/Input.js +86 -0
  30. package/components/promise/PromiseSwitch.d.ts +55 -0
  31. package/components/promise/PromiseSwitch.js +181 -0
  32. package/components/radio/Radio.d.ts +45 -0
  33. package/components/radio/Radio.js +123 -0
  34. package/components/select/Select.d.ts +23 -0
  35. package/components/select/Select.js +52 -0
  36. package/components/this/This.d.ts +24 -0
  37. package/components/this/This.js +62 -0
  38. package/components/timer/Timer.d.ts +26 -0
  39. package/components/timer/Timer.js +102 -0
  40. package/configs/Config.d.ts +34 -0
  41. package/configs/Config.js +2 -0
  42. package/configs/TargetAttr.d.ts +7 -0
  43. package/configs/TargetAttr.js +2 -0
  44. package/configs/TargetElement.d.ts +16 -0
  45. package/configs/TargetElement.js +2 -0
  46. package/css/parse/index.d.ts +49 -0
  47. package/css/parse/index.js +498 -0
  48. package/css/stringify/compiler.d.ts +34 -0
  49. package/css/stringify/compiler.js +36 -0
  50. package/css/stringify/compress.d.ts +104 -0
  51. package/css/stringify/compress.js +147 -0
  52. package/css/stringify/identity.d.ts +109 -0
  53. package/css/stringify/identity.js +183 -0
  54. package/css/stringify/index.d.ts +24 -0
  55. package/css/stringify/index.js +27 -0
  56. package/css/stringify/types.d.ts +15 -0
  57. package/css/stringify/types.js +2 -0
  58. package/css/types.d.ts +10 -0
  59. package/css/types.js +2 -0
  60. package/decorators/DomRenderNoProxy.d.ts +4 -0
  61. package/decorators/DomRenderNoProxy.js +15 -0
  62. package/events/EventManager.d.ts +68 -0
  63. package/events/EventManager.js +477 -0
  64. package/index.d.ts +2 -0
  65. package/index.js +2 -0
  66. package/iterators/Range.d.ts +24 -0
  67. package/iterators/Range.js +70 -0
  68. package/lifecycle/OnBeforeReturnGet.d.ts +4 -0
  69. package/lifecycle/OnBeforeReturnGet.js +2 -0
  70. package/lifecycle/OnBeforeReturnSet.d.ts +5 -0
  71. package/lifecycle/OnBeforeReturnSet.js +4 -0
  72. package/lifecycle/OnChangeAttrRender.d.ts +9 -0
  73. package/lifecycle/OnChangeAttrRender.js +4 -0
  74. package/lifecycle/OnChildRenderedByProperty.d.ts +5 -0
  75. package/lifecycle/OnChildRenderedByProperty.js +4 -0
  76. package/lifecycle/OnCreateRender.d.ts +5 -0
  77. package/lifecycle/OnCreateRender.js +4 -0
  78. package/lifecycle/OnCreateRenderData.d.ts +10 -0
  79. package/lifecycle/OnCreateRenderData.js +4 -0
  80. package/lifecycle/OnCreateRendered.d.ts +8 -0
  81. package/lifecycle/OnCreateRendered.js +4 -0
  82. package/lifecycle/OnCreatedThisChild.d.ts +6 -0
  83. package/lifecycle/OnCreatedThisChild.js +4 -0
  84. package/lifecycle/OnDestroyRender.d.ts +9 -0
  85. package/lifecycle/OnDestroyRender.js +4 -0
  86. package/lifecycle/OnInitRender.d.ts +6 -0
  87. package/lifecycle/OnInitRender.js +4 -0
  88. package/lifecycle/OnProxyDomRender.d.ts +5 -0
  89. package/lifecycle/OnProxyDomRender.js +2 -0
  90. package/lifecycle/dr-this/OnDrThisBind.d.ts +5 -0
  91. package/lifecycle/dr-this/OnDrThisBind.js +4 -0
  92. package/lifecycle/dr-this/OnDrThisUnBind.d.ts +5 -0
  93. package/lifecycle/dr-this/OnDrThisUnBind.js +4 -0
  94. package/managers/RenderManager.d.ts +2 -0
  95. package/managers/RenderManager.js +12 -0
  96. package/messenger/DefaultMessenger.d.ts +4 -0
  97. package/messenger/DefaultMessenger.js +4 -0
  98. package/messenger/Messenger.d.ts +79 -0
  99. package/messenger/Messenger.js +185 -0
  100. package/operators/Appender.d.ts +15 -0
  101. package/operators/Appender.js +90 -0
  102. package/operators/Dr.d.ts +9 -0
  103. package/operators/Dr.js +53 -0
  104. package/operators/DrAppender.d.ts +9 -0
  105. package/operators/DrAppender.js +69 -0
  106. package/operators/DrFor.d.ts +9 -0
  107. package/operators/DrFor.js +58 -0
  108. package/operators/DrForOf.d.ts +9 -0
  109. package/operators/DrForOf.js +120 -0
  110. package/operators/DrForm.d.ts +9 -0
  111. package/operators/DrForm.js +79 -0
  112. package/operators/DrIf.d.ts +9 -0
  113. package/operators/DrIf.js +70 -0
  114. package/operators/DrInnerHTML.d.ts +9 -0
  115. package/operators/DrInnerHTML.js +48 -0
  116. package/operators/DrInnerText.d.ts +9 -0
  117. package/operators/DrInnerText.js +46 -0
  118. package/operators/DrPre.d.ts +8 -0
  119. package/operators/DrPre.js +22 -0
  120. package/operators/DrRepeat.d.ts +9 -0
  121. package/operators/DrRepeat.js +70 -0
  122. package/operators/DrStripElement.d.ts +9 -0
  123. package/operators/DrStripElement.js +50 -0
  124. package/operators/DrTargetAttr.d.ts +8 -0
  125. package/operators/DrTargetAttr.js +45 -0
  126. package/operators/DrTargetElement.d.ts +13 -0
  127. package/operators/DrTargetElement.js +91 -0
  128. package/operators/DrTargetElementIsElement.d.ts +13 -0
  129. package/operators/DrTargetElementIsElement.js +79 -0
  130. package/operators/DrThis.d.ts +7 -0
  131. package/operators/DrThis.js +72 -0
  132. package/operators/DrThisProperty.d.ts +11 -0
  133. package/operators/DrThisProperty.js +93 -0
  134. package/operators/OperatorExecuter.d.ts +50 -0
  135. package/operators/OperatorExecuter.js +50 -0
  136. package/operators/OperatorExecuterAttrRequire.d.ts +9 -0
  137. package/operators/OperatorExecuterAttrRequire.js +25 -0
  138. package/package.json +70 -0
  139. package/rawsets/AttrInitCallBack.d.ts +6 -0
  140. package/rawsets/AttrInitCallBack.js +2 -0
  141. package/rawsets/Attrs.d.ts +27 -0
  142. package/rawsets/Attrs.js +2 -0
  143. package/rawsets/CreatorMetaData.d.ts +20 -0
  144. package/rawsets/CreatorMetaData.js +2 -0
  145. package/rawsets/DestroyOptionType.d.ts +5 -0
  146. package/rawsets/DestroyOptionType.js +6 -0
  147. package/rawsets/ElementInitCallBack.d.ts +9 -0
  148. package/rawsets/ElementInitCallBack.js +2 -0
  149. package/rawsets/RawSet.d.ts +180 -0
  150. package/rawsets/RawSet.js +1450 -0
  151. package/rawsets/RawSetOperatorType.d.ts +4 -0
  152. package/rawsets/RawSetOperatorType.js +5 -0
  153. package/rawsets/RawSetType.d.ts +8 -0
  154. package/rawsets/RawSetType.js +9 -0
  155. package/rawsets/Render.d.ts +27 -0
  156. package/rawsets/Render.js +2 -0
  157. package/routers/HashRouter.d.ts +24 -0
  158. package/routers/HashRouter.js +86 -0
  159. package/routers/PathRouter.d.ts +23 -0
  160. package/routers/PathRouter.js +73 -0
  161. package/routers/Router.d.ts +68 -0
  162. package/routers/Router.js +132 -0
  163. package/types/Types.d.ts +12 -0
  164. package/types/Types.js +26 -0
  165. package/validators/AllCheckedValidatorArray.d.ts +7 -0
  166. package/validators/AllCheckedValidatorArray.js +11 -0
  167. package/validators/AllUnCheckedValidatorArray.d.ts +7 -0
  168. package/validators/AllUnCheckedValidatorArray.js +11 -0
  169. package/validators/CheckedValidator.d.ts +6 -0
  170. package/validators/CheckedValidator.js +11 -0
  171. package/validators/CountEqualsCheckedValidatorArray.d.ts +8 -0
  172. package/validators/CountEqualsCheckedValidatorArray.js +12 -0
  173. package/validators/CountEqualsUnCheckedValidatorArray.d.ts +8 -0
  174. package/validators/CountEqualsUnCheckedValidatorArray.js +12 -0
  175. package/validators/CountGreaterThanCheckedValidatorArray.d.ts +8 -0
  176. package/validators/CountGreaterThanCheckedValidatorArray.js +12 -0
  177. package/validators/CountGreaterThanEqualsCheckedValidatorArray.d.ts +8 -0
  178. package/validators/CountGreaterThanEqualsCheckedValidatorArray.js +12 -0
  179. package/validators/CountGreaterThanEqualsUnCheckedValidatorArray.d.ts +8 -0
  180. package/validators/CountGreaterThanEqualsUnCheckedValidatorArray.js +12 -0
  181. package/validators/CountGreaterThanUnCheckedValidatorArray.d.ts +8 -0
  182. package/validators/CountGreaterThanUnCheckedValidatorArray.js +12 -0
  183. package/validators/CountLessThanCheckedValidatorArray.d.ts +8 -0
  184. package/validators/CountLessThanCheckedValidatorArray.js +12 -0
  185. package/validators/CountLessThanEqualsCheckedValidatorArray.d.ts +8 -0
  186. package/validators/CountLessThanEqualsCheckedValidatorArray.js +12 -0
  187. package/validators/CountLessThanEqualsUnCheckedValidatorArray.d.ts +8 -0
  188. package/validators/CountLessThanEqualsUnCheckedValidatorArray.js +12 -0
  189. package/validators/CountLessThanUnCheckedValidatorArray.d.ts +8 -0
  190. package/validators/CountLessThanUnCheckedValidatorArray.js +12 -0
  191. package/validators/CountUnCheckedValidatorArray.d.ts +8 -0
  192. package/validators/CountUnCheckedValidatorArray.js +12 -0
  193. package/validators/EmptyValidator.d.ts +6 -0
  194. package/validators/EmptyValidator.js +12 -0
  195. package/validators/ExcludeCheckedValidatorArray.d.ts +9 -0
  196. package/validators/ExcludeCheckedValidatorArray.js +17 -0
  197. package/validators/FormValidator.d.ts +8 -0
  198. package/validators/FormValidator.js +16 -0
  199. package/validators/IncludeCheckedValidatorArray.d.ts +9 -0
  200. package/validators/IncludeCheckedValidatorArray.js +17 -0
  201. package/validators/MultipleValidator.d.ts +9 -0
  202. package/validators/MultipleValidator.js +25 -0
  203. package/validators/NonPassValidator.d.ts +6 -0
  204. package/validators/NonPassValidator.js +10 -0
  205. package/validators/NotEmptyValidator.d.ts +6 -0
  206. package/validators/NotEmptyValidator.js +13 -0
  207. package/validators/NotRegExpTestValidator.d.ts +7 -0
  208. package/validators/NotRegExpTestValidator.js +20 -0
  209. package/validators/PassValidator.d.ts +6 -0
  210. package/validators/PassValidator.js +10 -0
  211. package/validators/RegExpTestValidator.d.ts +7 -0
  212. package/validators/RegExpTestValidator.js +21 -0
  213. package/validators/RequiredValidator.d.ts +6 -0
  214. package/validators/RequiredValidator.js +12 -0
  215. package/validators/UnCheckedValidator.d.ts +6 -0
  216. package/validators/UnCheckedValidator.js +11 -0
  217. package/validators/ValidMultipleValidator.d.ts +10 -0
  218. package/validators/ValidMultipleValidator.js +12 -0
  219. package/validators/ValidValidator.d.ts +7 -0
  220. package/validators/ValidValidator.js +11 -0
  221. package/validators/ValidValidatorArray.d.ts +8 -0
  222. package/validators/ValidValidatorArray.js +11 -0
  223. package/validators/Validator.d.ts +58 -0
  224. package/validators/Validator.js +203 -0
  225. package/validators/ValidatorArray.d.ts +18 -0
  226. package/validators/ValidatorArray.js +77 -0
  227. package/validators/ValueEqualsValidator.d.ts +7 -0
  228. package/validators/ValueEqualsValidator.js +11 -0
  229. package/validators/ValueNotEqualsValidator.d.ts +7 -0
  230. package/validators/ValueNotEqualsValidator.js +11 -0
package/README.MD ADDED
@@ -0,0 +1,938 @@
1
+ DOM-RENDER
2
+ ===
3
+ [![typescript](https://img.shields.io/badge/-npm-black?logo=npm)](https://www.npmjs.com/package/dom-render) [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE.md)
4
+ * view template engine
5
+ * Dom control and reorder and render
6
+ * all internal variables are managed by proxy. (DomRenderProxy)
7
+
8
+ # 🚀 Quick start
9
+ ```html
10
+ <script src="https://cdn.jsdelivr.net/npm/dom-render@1.0.91/dist/bundle.js"></script>
11
+ ```
12
+ ```html
13
+ <!DOCTYPE html>
14
+ <html lang="en">
15
+ <head``>
16
+ <meta charset="UTF-8">
17
+ <title>Title</title>
18
+ </head>
19
+ <body id="app">
20
+ ${this.name}$
21
+ <script src="https://cdn.jsdelivr.net/npm/dom-render@1.0.86/dist/bundle.js"></script>
22
+ <script>
23
+ let data = {
24
+ name: 'my name is dom-render'
25
+ };
26
+ data = DomRender.run(data , document.querySelector('#app'));
27
+ </script>
28
+ </body>
29
+ </html>
30
+ ```
31
+
32
+ # 😃 examples
33
+ - [examples](./examples)
34
+
35
+
36
+ ## Expression
37
+ <details>
38
+ <summary>${...}$, #{...}# <strong>🔻(click)</strong></summary>
39
+
40
+ ### ${}$ innerTEXT, #{}# innerHTML
41
+ ```html
42
+ <body id="app">
43
+ ${this.name}$ <!-- outout: <i>my name is dom-render</i> -->
44
+ #{this.name}# <!-- outout text is italic: my name is dom-render -->
45
+ <script>
46
+ let data = {
47
+ name: '<i>my name is dom-render</i>'
48
+ };
49
+ data = DomRender.run(data , document.querySelector('#app'));
50
+ </script>
51
+ </body>
52
+ ```
53
+ </details>
54
+
55
+ # dom-render attributes
56
+
57
+
58
+ ## attribute change, bind
59
+ <details>
60
+ <summary>attribute<strong>🔻(click)</strong></summary>
61
+
62
+ ### attribute
63
+ ```html
64
+ <body id="app">
65
+ <input type="text" value="${this.name}$" style="${'color: '+this.color}$">
66
+ <button dr-event-click="this.changeData();">change</button>
67
+ </body>
68
+ ```
69
+ ```typescript
70
+ class Data {
71
+ name = 'my name is dom-render';
72
+ color = '#ff0000';
73
+
74
+ changeData() {
75
+ this.name = RandomUtils.getRandomString(10);
76
+ this.color = RandomUtils.getRandomColor();
77
+ }
78
+ }
79
+ const data = DomRender.run(new Data(), document.querySelector('#app')!);
80
+ ```
81
+ </details>
82
+
83
+
84
+ ## style css
85
+ ```typescript
86
+ export class IndexComponent implements OnInitRender, OnDestroyRender, OnInit, OnSimCreate, OnDrThisBind, OnDrThisUnBind, OnCreateRender, OnCreateRenderData, OnCreatedThisChild {
87
+ private canvas: HTMLCanvasElement | null = null;
88
+ private ctx: CanvasRenderingContext2D | null = null;
89
+
90
+ name = 'IndexComponent';
91
+ age = 10;
92
+ color = 'red';
93
+ img = 'url(\'https://pbs.twimg.com/media/F1FHR-saMAAMTKm?format=jpg&name=360x360\')';
94
+ //...
95
+ }
96
+ ```
97
+ ```css
98
+ .sign-container{
99
+ cursor: pointer;
100
+ width: 32px;
101
+ height: 28px;
102
+ background-image: ${@this@.img}$;
103
+ background-position: center; /* 정가운데 */
104
+ background-size: contain; /* 이미지 전체 표시 */
105
+ background-repeat: no-repeat; /* 반복 방지 */
106
+ }
107
+ ```
108
+ ```css
109
+ .#uuid# {
110
+ color:${@this@.color}$;
111
+ }
112
+ ```
113
+ ```css
114
+ @media (width >= /*$@this@.ss$*/) {
115
+ #profileDialog {
116
+ max-width: ${@this@.ss}$; /* 너비 조정 */
117
+ }
118
+ }
119
+ ```
120
+ ### Release the style that applies only to the inside of the component. Please write (1line) online
121
+ ```css
122
+ ## .wow {...}
123
+ ## body::-webkit-scrollbar {display: none;}
124
+ ```
125
+ ```html
126
+ <button dr-event-click="@this@.ss = '50rem'">aa</button>
127
+ ```
128
+
129
+ selector expression: /*$@this@.ss$*/
130
+ uuid: rawSetUUID
131
+ ##: escape scope
132
+
133
+
134
+
135
+ ## control, print Statement
136
+ <details>
137
+ <summary>dr-if<strong>🔻(click)</strong></summary>
138
+
139
+ ### if element render
140
+ ```html
141
+ <body id="app">
142
+ <div dr-if="true">true</div> <!-- render -->
143
+ <div dr-if="this.gender === 'M'">gender: M</div> <!-- No Render -->
144
+ <script>
145
+ let data = {
146
+ gender: 'F',
147
+ };
148
+ data = DomRender.run(data , document.querySelector('#app'));
149
+ </script>
150
+ </body>
151
+ ```
152
+ </details>
153
+
154
+
155
+
156
+
157
+
158
+ <details>
159
+ <summary>dr-for, dr-for-of<strong>🔻(click)</strong></summary>
160
+
161
+ ```html
162
+ <div dr-for="var i = 0; i < this.friends.length; i++"> friend</div>
163
+ <div dr-for-of="this.friends"> ${#it#.name}$</div>
164
+ <div dr-for-of="$range(10, 20)"><div>${#it#}$</div><div>
165
+ <div dr-for="var i = 1 ; i <= 9 ; i++" dr-it="i">
166
+ ${#it#}$ *
167
+ <scope dr-for="var y = 1 ; y <= 9 ; y++" dr-it="y" dr-var="superIt=#it#" dr-option-strip="true">
168
+ #it# = ${$var.superIt * #it#}$
169
+ </scope>
170
+ </div>
171
+ ```
172
+ </details>
173
+
174
+ <details>
175
+ <summary>dr-appender<strong>🔻(click)</strong></summary>
176
+
177
+ ```html
178
+ <h3>appender</h3>
179
+ <ul>
180
+ <li dr-appender="@this@.appender">
181
+ ${#it#}$
182
+ </li>
183
+ </ul>
184
+ <button dr-event-click="@this@.append()">appending</button>
185
+ <button dr-event-click="@this@.modifyAppender(0)">idx 0 modify</button>
186
+ <button dr-event-click="@this@.clearAppend()">appender clear</button>
187
+ ```
188
+
189
+ ```typescript
190
+ class Data {
191
+ appender = new Appender();
192
+
193
+ constructor() {
194
+ this.appender.push('init' + RandomUtils.uuid(), 'init' + RandomUtils.uuid());
195
+ }
196
+
197
+ append() {
198
+ this.appender.push(RandomUtils.uuid(), RandomUtils.uuid());
199
+ }
200
+
201
+ clearAppend() {
202
+ this.appender.clear()
203
+ }
204
+
205
+ modifyAppender(idx: number) {
206
+ this.appender[idx][0] = RandomUtils.uuid();
207
+ }
208
+ }
209
+
210
+ ```
211
+ </details>
212
+
213
+
214
+ ### dr-strip
215
+ ```html
216
+ <div dr-strip="true">aa</div>
217
+ ```
218
+ only "aa" result strip element
219
+
220
+
221
+
222
+ <details>
223
+ <summary>dr-repeat<strong>🔻(click)</strong></summary>
224
+
225
+ ```html
226
+ <div dr-repeat="10"><div>#it#</div></div>
227
+ <div dr-repeat="$range(10, 20)"><div>#it#</div></div>
228
+ <div dr-repeat="$range(10, 20, 5)"><div>#it#</div></div>
229
+ <div dr-repeat="$range('10..5, 2')"><div>#it#</div></div>
230
+ ```
231
+ </details>
232
+
233
+ <details>
234
+ <summary>dr-inner-text, dr-inner-html<strong>🔻(click)</strong></summary>
235
+
236
+ ```html
237
+ <div dr-inner-text="'<b>aa</b> <button dr-event-click=\'alert(1)\'>aa</button>'"> friend</div>
238
+ <div dr-inner-html="'<b>aa</b> <button dr-event-click=\'alert(1)\'>aa</button>'"> friend</div>
239
+ ```
240
+ </details>
241
+
242
+
243
+ ## event
244
+ <details>
245
+ <summary>dr-event-(name)<strong>🔻(click)</strong></summary>
246
+
247
+ * click, mousedown, mouseup, dblclick, mouseover, mouseout, mousemove, mouseenter, mouseleave, contextmenu, keyup, keydown, keypress, change, input, submit, resize, focus, blur
248
+ * ref: element
249
+ * variable: $event, $target
250
+ ```html
251
+ click: <button dr-event-click="@this@.name = 'name' + new Date()">click</button> <br>
252
+ change: <input type="text" dr-event-change="@this@.name = $target.value"> <br>
253
+ input: <input type="text" dr-event-input="@this@.name = $target.value"> <br>
254
+ keyup: <input type="text" dr-event-keyup="@this@.name = $target.value"> <br>
255
+ ...
256
+ keydown: <input type="text" dr-event-keydown="@this@.name = $target.value"><br>
257
+ submit: <form dr-event-submit="console.log($event); $event.preventDefault();"><input type="text"> <button type="submit">submit</button></form><br>
258
+ ```
259
+ </details>
260
+
261
+ <details>
262
+ <summary>dr-window-event-popstate<strong>🔻(click)</strong></summary>
263
+
264
+ * ref: window
265
+ * variable: $target
266
+
267
+ ```html
268
+ window-event-popstate: <input type="text" dr-window-event-popstate="alert(@this@.name)"><br>
269
+ ```
270
+ </details>
271
+
272
+ <details>
273
+ <summary>dr-event<strong>🔻(click)</strong></summary>
274
+
275
+ * other event
276
+ * ref: element
277
+ * variable: $params, $event
278
+
279
+
280
+ ```html
281
+ <input dr-event:bind='eventName1, eventName2' dr-event="console.log('event', $params, $event)" type="text">
282
+ ```
283
+ </details>
284
+
285
+
286
+ ## this
287
+ <details>
288
+ <summary>dr-this<strong>🔻(click)</strong></summary>
289
+ * dr-this
290
+ * object mapping
291
+
292
+ ```typescript
293
+ class data {
294
+ dictionary = {
295
+ name: 'visualkhh'
296
+ }
297
+ }
298
+ ```
299
+ ```html
300
+ <div dr-this="@this@.dictionary">
301
+ ${@this@.name}$
302
+ </div>
303
+ ```
304
+ </details>
305
+
306
+ <details>
307
+ <summary>dr-this-property<strong>🔻(click)</strong></summary>
308
+ * dr-property
309
+ * property forEach in object
310
+ * dynamic add, delete
311
+
312
+ ```typescript
313
+ class data {
314
+ dictionary = {
315
+ name1: 'visualkhh1',
316
+ name2: 'visualkhh2',
317
+ name3: 'visualkhh3'
318
+ }
319
+ }
320
+ ```
321
+ ```html
322
+ <home dr-this-property="@this@.dictionary" dr-on-init:arguments="[2,#this#]">
323
+ ${this}$
324
+ </home>
325
+ ```
326
+ </details>
327
+
328
+
329
+ ## nearThis
330
+ ```html
331
+ <div dr-this="@this@.dictionary"> (${@nearThis@.name}$) ${$nearThis.name}$ </div>
332
+ ```
333
+
334
+
335
+ ## dr-on-init
336
+ - element on-init event
337
+ ```html
338
+ <canvas id="gameCanvas" dr-on-init="console.log('--@@@@@@@---', $element)"></canvas>sssss
339
+ ```
340
+ ## value
341
+ <details>
342
+ <summary>dr-value, value-link<strong>🔻(click)</strong></summary>
343
+
344
+ * dr-value
345
+ * The value is assigned the first time.
346
+ * dr-value-link
347
+ * Value and variable values are referencing each other. It affects each other when changing. (Immediate reflection event: input)
348
+ * instance variable first
349
+ * dr-checked-link
350
+ * Value and variable values are referencing each other. It affects each other when changing. (Immediate reflection event: input)
351
+ * instance variable first
352
+ * dr-disabled-link
353
+ * Value and variable values are referencing each other. It affects each other when changing. (Immediate reflection event: input)
354
+ * instance variable first
355
+
356
+ ```html
357
+ dr-value: <input type="text" dr-value="@this@.office.name"> <br>
358
+ dr-value-link: <input type="text" dr-value-link="@this@.office.addr.street"> <br>
359
+ ```
360
+ </details>
361
+
362
+ ## dr-on-rendered-init
363
+ - rendered call
364
+
365
+ ## other
366
+ <details>
367
+ <summary>dr-attr<strong>🔻(click)</strong></summary>
368
+
369
+ ```html
370
+ <textarea dr-attr="{rows: @this@.age/2, cols: @this@.age}"></textarea>
371
+ <div dr-attr="{wow: '123', good: 123444}"></div>
372
+ <div dr-attr="['wow=123', 'good=123444']"></div>
373
+ <div dr-attr="'wow=123, good=123444'"></div>
374
+ ```
375
+ </details>
376
+
377
+ <details>
378
+ <summary>dr-class<strong>🔻(click)</strong></summary>
379
+
380
+ ```html
381
+ <div dr-class="{big: @this@.age > 50, red: @this@.age > 50}"></div>
382
+ <div dr-class="'big yellow ' + (@this@.age > 50 ? 'old' : 'young')"></div>
383
+ <div dr-class="['small', 'yellow']"></div>
384
+ ```
385
+ </details>
386
+
387
+ <details>
388
+ <summary>dr-style<strong>🔻(click)</strong></summary>
389
+
390
+ ```html
391
+ <div dr-style="{'background-image': 'url(\''+@this@.my?.image+'\')'}" >aa</div>
392
+ <div dr-style="{fontSize: @this@.age + 'px'}"> style </div>
393
+ <div dr-style="{'font-size': '20px'}"> style</div>
394
+ <div dr-style="'font-size: ' + @this@.age +'px; margin: ' + @this@.age + 'px'"> style </div>
395
+ <div dr-style="['font-size: ' + @this@.age +'px', 'margin: ' + @this@.age + 'px']"> style </div>
396
+ ```
397
+ </details>
398
+
399
+ <details>
400
+ <summary>dr-strip<strong>🔻(click)</strong></summary>
401
+
402
+ ```html
403
+ <div dr-strip="true"><span>hello</span></div> <!-- output html : <span>hello</span> -->
404
+ ```
405
+ </details>
406
+
407
+ <details>
408
+ <summary>dr-before, dr-after<strong>🔻(click)</strong></summary>
409
+
410
+ ```html
411
+ <div dr-before="console.log('process before')" dr-after="console.log('process after')"></div>
412
+ ```
413
+ </details>
414
+
415
+ <details>
416
+ <summary>dr-complete<strong>🔻(click)</strong></summary>
417
+
418
+ ```html
419
+ <select dr-value-link="@this@.currentContry" dr-event-change="@this@.contryChange($event)">
420
+ <option dr-for-of="@this@.languages" dr-value="#it#.key" dr-option-complete="@this@.currentContry='defaultValue'">${#it#.title}$</option>
421
+ </select>
422
+
423
+ <select id="object-type" name="type" class="select-input" dr-value-link="@this@.selectedObjetActionType">
424
+ <option dr-for-of="Object.values(@this@.objetActionType)" dr-detect-option-attr="{value: #it#, selected: @this@.selectedObjetActionType === #it# ? 'selected' : null}" >${@this@.objetActionMetaData[#it#].enName}$</option>
425
+ </select>
426
+ ```
427
+ #nearForOfIndex#
428
+ ```html
429
+ <select dr-value-link="@this@.selectedStationIndex" dr-event-change="@this@.onChangeStation($event)">
430
+ <option dr-for-of="@this@.stations" dr-value="#nearForOfIndex#">
431
+ ${#it#.name}$
432
+ </option>
433
+ </select>
434
+ ```
435
+
436
+ #it#
437
+ ```html
438
+ <input type="text" list="search-details-body-input-datalist" dr-on-init="@this@.onInitSearchElement($element);"> <button class="fa-solid fa-magnifying-glass"></button>
439
+ <datalist id="search-details-body-input-datalist">
440
+ <option dr-for-of="@this@.searchUsers" dr-value="#it#.name">
441
+ </datalist>
442
+
443
+ <div id="search-details-body-result-container">
444
+ <ul>
445
+ <li dr-for-of="@this@.searchUsers">
446
+ ${#it#.name}$
447
+ </li>
448
+ </ul>
449
+ </div>
450
+ ```
451
+ </details>
452
+
453
+ ## dr-form
454
+ <details>
455
+ <summary>form<strong>🔻(click)</strong></summary>
456
+ * event: change
457
+ * modify change: dr-form:event="input"
458
+
459
+ - [examples](./examples/forms)
460
+
461
+ ```html
462
+ <body id="app">
463
+ <form dr-form="@this@.form" dr-event-submit="@this@.submit(); $event.preventDefault();">
464
+ name: <input name="name">
465
+ age: <input name="age">
466
+ <button type="submit">submit</button>
467
+ </form>
468
+ <script>
469
+ let data = {
470
+ form: {},
471
+ submit() {
472
+ console.log(this.form);
473
+ }
474
+ };
475
+ data = DomRender.run(data , document.querySelector('#app'));
476
+ </script>
477
+ </body>
478
+ <!-- 💥 submit call -->
479
+ <!-- console: {name: 'name data', age: 'age data'} -->
480
+ ```
481
+ </details>
482
+
483
+ <details>
484
+ <summary>validator<strong>🔻(click)</strong></summary>
485
+
486
+ ```html
487
+ <body id="app">
488
+ <form dr-form="@this@.form" dr-event-submit="@this@.submit(); $event.preventDefault();">
489
+ name: <input name="name">
490
+ age: <input name="age">
491
+ <button type="submit">submit</button>
492
+ </form>
493
+ <script>
494
+ const form = new FormValidator();
495
+ form.name = new NotEmptyValidator();
496
+ form.age = new NotEmptyValidator();
497
+ let data = {
498
+ form,
499
+ submit() {
500
+ if (this.form.valid()){
501
+ console.log('valid');
502
+ } else {
503
+ console.log('inValid');
504
+ }
505
+ }
506
+ };
507
+ data = DomRender.run(data , document.querySelector('#app'));
508
+ </script>
509
+ </body>
510
+ ```
511
+ validator
512
+ - Validator (abstract)
513
+ - ValidatorArray (abstract)
514
+ - AllCheckedValidatorArray
515
+ - AllUnCheckedValidatorArray
516
+ - CheckedValidator
517
+ - CountEqualsCheckedValidatorArray
518
+ - CountEqualsUnCheckedValidatorArray
519
+ - CountGreaterThanCheckedValidatorArray
520
+ - CountGreaterThanEqualsCheckedValidatorArray
521
+ - CountGreaterThanEqualsUnCheckedValidatorArray
522
+ - CountGreaterThanUnCheckedValidatorArray
523
+ - CountLessThanCheckedValidatorArray
524
+ - CountLessThanEqualsCheckedValidatorArray
525
+ - CountLessThanEqualsUnCheckedValidatorArray
526
+ - CountLessThanUnCheckedValidatorArray
527
+ - CountUnCheckedValidatorArray
528
+ - EmptyValidator
529
+ - ExcludeCheckedValidatorArray
530
+ - FormValidator
531
+ - IncludeCheckedValidatorArray
532
+ - MultipleValidator
533
+ - NonPassValidator
534
+ - NotEmptyValidator
535
+ - NotRegExpTestValidator
536
+ - PassValidator
537
+ - RegExpTestValidator
538
+ - RequiredValidator
539
+ - UnCheckedValidator
540
+ - ValidMultipleValidator
541
+ - ValidValidator
542
+ - ValidValidatorArray
543
+ - ValueEqualsValidator
544
+ - ValueNotEqualsValidator
545
+ </details>
546
+
547
+
548
+
549
+ ## Route
550
+ <details>
551
+ <summary>Route<strong>🔻(click)</strong></summary>
552
+
553
+ - [examples](./examples/router)
554
+
555
+ * config routerType: 'hash' | 'path' | 'none' (default: 'none')
556
+ ```typescript
557
+ // Config
558
+ const config: Config = {
559
+ window
560
+ };
561
+ config.targetElements = [
562
+ DomRender.createComponent({type: Main, tagName: 'page-main', template: MainTemplate}),
563
+ DomRender.createComponent({type: Second, tagName: 'page-second', template: SecondTemplate}),
564
+ DomRender.createComponent({type: Detail, tagName: 'page-detail', template: DetailTemplate})
565
+ ]
566
+ config.routerType = 'hash'; // 'hash' | 'path' | 'none';
567
+ const data = DomRender.run(new Data(), document.querySelector('#app')!, config);
568
+ ```
569
+ ```html
570
+ <header>
571
+ <h1>examples header</h1>
572
+ <h2>${@this@.name}$</h2>
573
+ <div>
574
+ <div><button dr-event-click="$router.go('/')">main</button></div>
575
+ <div>
576
+ <button dr-event-click="$router.go('/second', {secondata: 555})">second</button>
577
+ <button dr-event-click="$router.go('/second/5')">second/1</button>
578
+ <button dr-event-click="$router.go('/second/wow')">second/2</button>
579
+ </div>
580
+ <div><button dr-event-click="$router.go('/detail/25?name=zzz')">detail</button></div>
581
+ </div>
582
+ </header>
583
+ <hr>
584
+ <main>
585
+ <page-main dr-if="$router.test('/')"></page-main>
586
+ <page-second dr-if="$router.test('/second')">1</page-second>
587
+ <page-second dr-if="$router.testRegexp('/second/[0-9]?$')">2</page-second>
588
+ <page-second dr-if="$router.testRegexp('/second/wow$')">wow</page-second>
589
+ <page-detail url='/detail/{id:[0-9]+}' dr-if="$router.test($attribute.url)" dr-on-create:callback="$component.routerData($router.getRouteData($attribute.url))" ></page-detail>
590
+ <div>
591
+ <button dr-event-click="@this@.plusCount()">${@this@.count}$ count pluse++</button>
592
+ </div>
593
+ </main>
594
+ <hr>
595
+ <footer>footer</footer>
596
+ ```
597
+ ```typescript
598
+ export class Second implements OnCreateRender {
599
+ name = 'Second'
600
+
601
+ onCreateRender(data: CreatorMetaData): void {
602
+ console.log('----->', data.router)
603
+ }
604
+ }
605
+ ```
606
+ ```typescript
607
+ import {RouteData} from 'dom-render/routers/Router';
608
+ import {OnCreateRender} from 'dom-render/lifecycle/OnCreateRender';
609
+
610
+ export class Detail implements OnCreateRender {
611
+ name = 'Detail';
612
+
613
+ onCreateRender(data: CreatorMetaData) {
614
+ console.log('routeData->', data);
615
+ }
616
+
617
+ routerData(routeData: RouteData) {
618
+ console.log('--------', routeData);
619
+ }
620
+ }
621
+ ```
622
+
623
+ ```typescript
624
+ // RouteData type
625
+ type RouteData = {
626
+ path: string;
627
+ url: string;
628
+ data?: any;
629
+ searchParams: URLSearchParams;
630
+ pathData?: any;
631
+ }
632
+ ```
633
+ </details>
634
+
635
+ ## Messenger (Data transmission)
636
+ * publish, subscribe
637
+ <details>
638
+ <summary>publish<strong>🔻(click)</strong></summary>
639
+
640
+ ```typescript
641
+ export class Home implements OnProxyDomRender {
642
+ private channel?: Channel;
643
+
644
+ sendIndexMessage() {
645
+ const rtn = this.channel?.publish(Index, {
646
+ name: this.name,
647
+ age: this.age,
648
+ title: this.title
649
+ });
650
+ console.log('sendIndexMessage return value: ', rtn);
651
+ }
652
+
653
+ onProxyDomRender({messenger}: Config): void {
654
+ this.channel = messenger?.createChannel(Home);
655
+ }
656
+ }
657
+ ```
658
+ </details>
659
+ <details>
660
+ <summary>subscribe<strong>🔻(click)</strong></summary>
661
+
662
+ ```typescript
663
+ class Index implements OnProxyDomRender {
664
+ onProxyDomRender({messenger}: Config): void {
665
+ messenger?.createChannel(this).filter((data) => (data.age ?? 0) > 5).subscribe((data) => {
666
+ this.rcvData = data;
667
+ return {data: 'good', action: 'actionGood'}
668
+ });
669
+ // messenger?.createChannel(this).subscribe((data) => {
670
+ // this.rcvData = data;
671
+ // return {data: 'good', action: 'actionGood'}
672
+ // });
673
+ }
674
+ }
675
+ ````
676
+ </details>
677
+
678
+ ## Class
679
+ <details>
680
+ <summary>Range<strong>🔻(click)</strong></summary>
681
+
682
+ ```javascript
683
+ const range = new Range(100,55, 10);
684
+ for (let data of new Range(100,55, 10)) {
685
+ console.log(data);
686
+ }
687
+ const rangeArray = new Range(100,55, 10).toArray();
688
+ ```
689
+ </details>
690
+ <details>
691
+ <summary>Appender<strong>🔻(click)</strong></summary>
692
+
693
+ ```javascript
694
+ const appender = new Appender<number>([1, 2]);
695
+ appender.push(3, 4)
696
+ for (const data of appender) {
697
+ console.log('----appender item--->', data);
698
+ }
699
+ ```
700
+ </details>
701
+
702
+ ## Detect Get, Set
703
+ <details>
704
+ <summary>Method Proxy<strong>🔻(click)</strong></summary>
705
+
706
+ ### using detect
707
+ ```typescript
708
+ {
709
+ name: 'dom-render'
710
+ onBeforeReturnSet: (name: string, value: any, fullpath: string[]) => {
711
+ console.log('set name-->', name, value, fullpath);
712
+ }
713
+ onBeforeReturnGet: (name: string, value: any, fullpath: string[]) => {
714
+ console.log('get name-->', name, value, fullpath);
715
+ }
716
+ }
717
+ ```
718
+ exclude detect property: Config
719
+ - proxyExcludeOnBeforeReturnGets: ['propertyName']
720
+ - proxyExcludeOnBeforeReturnSets: ['propertyName']
721
+ ---
722
+
723
+ ### OnBeforeReturnSet
724
+ ```typescript
725
+ export interface OnBeforeReturnSet {
726
+ onBeforeReturnSet(name: string, value: any, fullPath?: string[]): void;
727
+ }
728
+ ```
729
+ ### OnBeforeReturnGet
730
+ ```typescript
731
+ export interface OnBeforeReturnGet {
732
+ onBeforeReturnGet(name: string, value: any, fullPath?: string[]): void;
733
+ }
734
+ ```
735
+ </details>
736
+
737
+
738
+
739
+ ## Proxy
740
+ all internal variables are managed by proxy. (DomRenderProxy)
741
+ ### exclude proxy (situation: Maximum call stack error)
742
+ exclude detect property: Config
743
+ - proxyExcludeTyps: [Class...]
744
+
745
+ Code base
746
+ ```typescript
747
+ // frezz
748
+ {name : Object.freeze({...})}
749
+
750
+ // Shield Object type: {[k: string]: any}
751
+ {name : new Shield()}
752
+
753
+ // DomRenderProxy Final
754
+ {name : DomRenderProxy.final({...})}
755
+ ```
756
+ ---
757
+
758
+
759
+ ## LifeCycle
760
+ * OnCreateRender
761
+ * onCreateRender(): created call
762
+ * OnInitRender
763
+ * onInitRender(): init render call
764
+ * OnDestroyRender
765
+ * onDestroyRender(): component Destroy call
766
+
767
+ ## Script
768
+ ```typescript
769
+ new DomRender.run(obj, target, {
770
+ scripts: {
771
+ concat: function (head: string, tail: string) {
772
+ return head + tail;
773
+ }
774
+ }
775
+ });
776
+ ```
777
+ using script
778
+ ```typescript
779
+ const data = config.scripts.concat('head', 'tail')
780
+ ```
781
+ ```html
782
+ <div>${$scripts.concat('head', 'tail')}</div>
783
+ <div dr-if="$scripts.concat('wow', 'good') === 'wowgood'"> is wowgood</div>
784
+ ```
785
+
786
+ ---
787
+ # Component, Attribute, AttributeCallBack
788
+ # 😃 examples
789
+ - [examples](./examples/component_script_attr) lazy load (html, css)
790
+ ```html
791
+ <body id="app">
792
+ ${@this@.name}$
793
+ <h1>component</h1>
794
+ <profile dr-on-create:callback="$component.name='jhone'; $component.age=55;"><b>${#component#.details}$</b></profile>
795
+ <profile dr-on-create:callback="$component.name='cal'; $component.age=56;"><b>detail-2</b></profile>
796
+ <profile dr-on-create:callback="$component.name='rose'; $component.age=57;">
797
+ <profile dr-on-create:callback="$component.name='rose-sub'; $component.age=156;">
798
+ <b>${@this@.name}$</b>
799
+ </profile>
800
+ </profile>
801
+ <h3>component data link and detect</h3>
802
+ <Profile dr-if="@this@.toggle" dr-detect="$component.age = @this@.age" dr-on-create:callback="$component.name='papa'; $component.age=58;">
803
+ <b>${@this@.name}$</b>
804
+ </Profile>
805
+ <Profile dr-if="@this@.toggle" dr-detect="$component.age = @this@.age" dr-on-constructor:arguments="[1,2]">
806
+ <b>${@this@.name}$</b>
807
+ </Profile>
808
+
809
+ <button dr-event-click="@this@.name = new Date().toString();">change name</button>
810
+ <button dr-event-click="@this@.age = Date.now();">change age</button>
811
+ <button dr-event-click="@this@.toggle = !@this@.toggle;">change toggle</button>
812
+
813
+ <j1>component constructor, on-create, dr-on-create:callback</j1>
814
+ <home dr-constructor="[@this@.name, @this@.age, 'home welcom']" dr-on-create-arguments="{type: 'onCreate', data: 'datadata'}" dr-on-create:callback="$component.onInit('data')"></home>
815
+
816
+
817
+
818
+ <h1>scripts</h1>
819
+ <div>
820
+ ${$scripts.concat('hello', 'tail')}$
821
+ </div>
822
+
823
+ <h1>attr</h1>
824
+ <button link="@this@.link">
825
+ link attribute
826
+ </button>
827
+ <h1>attrCallBack</h1>
828
+ <input id="callback" type="text" wow>
829
+ </body>
830
+ ```
831
+ ```typescript
832
+ config.targetElements = [
833
+ DomRender.createComponent({type: Profile, template: ProfileTemplate}), // lazy loading format 'lazy://component/home.html'
834
+ DomRender.createComponent({type: Home, template: HomeTemplate, styles: HomeStyle})
835
+ ]
836
+
837
+ config.targetAttrs = [
838
+ DomRender.createAttribute('link',
839
+ (element: Element, attrValue: string, obj: any, rawSet: RawSet) => {
840
+ return obj;
841
+ },
842
+ (element: Element, attrValue: string, obj: any, rawSet: RawSet) => {
843
+ const fag = window.document.createDocumentFragment();
844
+ if (attrValue) {
845
+ const n = element.cloneNode(true) as Element;
846
+ attrValue = ScriptUtils.eval(`return ${attrValue}`, obj)
847
+ n.addEventListener('click', () => {
848
+ location.href = attrValue;
849
+ });
850
+ fag.append(n);
851
+ }
852
+ return fag;
853
+ }
854
+ )
855
+ ]
856
+
857
+ config.applyEvents = [
858
+ {
859
+ attrName: 'wow',
860
+ callBack: (e, a, o) => {
861
+ e.addEventListener('click', (event) => {
862
+ alert((event.target as any).value);
863
+ })
864
+ }
865
+ }
866
+ ]
867
+ const data = DomRender.run(new Data(), document.querySelector('#app')!, config);
868
+ ```
869
+ using component
870
+ ```html
871
+ <my-element dr-on-create:callback="$component.say();"></my-element>
872
+
873
+ <home value="${@this@.name}$" wow="${@this@.color}$">
874
+ ${#component#.homeName}$
875
+ <home value="${#component#.homeName}$" wow="${#component#.homeColor}$" dr-component-name="sub_component" dr-component-inner-html-name="innerHTML">
876
+ ${#sub_component#.homeName}$
877
+ </home>
878
+ </home>
879
+ ```
880
+ lazy loading rollup config
881
+ ```javascript
882
+ copy({
883
+ targets: [
884
+ {
885
+ src: ['**/*.html', '**/*.css', '!node_modules/**/*.html', '!node_modules/**/*.css'], dest: 'dist',
886
+ rename: (name, extension, fullPath) => `${fullPath}`
887
+ },
888
+ { src: 'assets', dest: 'dist' }
889
+ ]
890
+ })
891
+ ```
892
+
893
+ ## parameter
894
+ - dr-option-component-inner-html-name
895
+ - dr-option-component-name
896
+
897
+ - callback
898
+ - onChangeAttrRender
899
+ - onCreateRenderData<T = any>(data: OnCreateRenderDataParams<T>): void
900
+ - type OnCreateRenderDataParams<T = any> = { parent: T, render: Render };
901
+ - OnCreateThisChild
902
+ - thisChild created callback
903
+ - OnChildRenderedByProperty
904
+ - onChildRenderedByProperty(key: string, value: any, config: {rawSets:RawSet[]}): void;
905
+ - event
906
+ - dr-event-...:filter event filter!!
907
+ - ex) dr-event-change:filter="false"
908
+ - dr-event-...:dispatch
909
+ - ```html
910
+ <input name="${@this@.data.attribute.name}$"
911
+ dr-event-change="@this@.change($element.checked)"
912
+ dr-event-change:dispatch
913
+ value="good"
914
+ type="checkbox"
915
+ checked
916
+ />
917
+ ```
918
+ - attribute
919
+ - dr-on-constructor:arguments: component constructor arguments
920
+ - dr-on-create:callback: component created init callback script
921
+ - dr-on-create:arguments: component onCreatedRender arguments
922
+ - dr-on-init:arguments: component onInitRender arguments
923
+ - dr-on-rendered-init: rendered
924
+ - $component: component instance
925
+ - $element: element instance
926
+ - $attribute: element attribute object
927
+ - $innerHTML: element innerHTML string
928
+ - $creatorMetaData: metaData
929
+ - #component#: component instance
930
+ - #innerHTML#: element innerHTML
931
+ - dr-option-this-name: renaming component variable name (default: component)
932
+ - dr-option-component-name: renaming component variable name (default: component)
933
+ - dr-option-inner-html-name: renaming innerHTML variable name (default: innerHTML)
934
+ ---
935
+
936
+ # License
937
+ * MIT
938
+ * visualkhh@gmail.com