datafolder 1.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 (182) hide show
  1. package/README.md +169 -0
  2. package/index.js +3 -0
  3. package/package.json +27 -0
  4. package/sample.js +37 -0
  5. package/scripts/airbnb.js +73 -0
  6. package/scripts/airbnb2.js +74 -0
  7. package/scripts/airbnb2_queries.js +231 -0
  8. package/scripts/airbnb_queries.js +264 -0
  9. package/scripts/downloadFile.js +42 -0
  10. package/scripts/express.js +46 -0
  11. package/scripts/fastify.js +79 -0
  12. package/scripts/flights.js +75 -0
  13. package/scripts/flights2.js +81 -0
  14. package/scripts/flights2_queries.js +453 -0
  15. package/scripts/flights_queries.js +403 -0
  16. package/src/QyAcl.js +252 -0
  17. package/src/QyAclSaver.js +14 -0
  18. package/src/QyAclSaver_Worker.js +29 -0
  19. package/src/QyAclWriter.js +19 -0
  20. package/src/QyBatch.js +501 -0
  21. package/src/QyBinWriter.js +140 -0
  22. package/src/QyCD.js +61 -0
  23. package/src/QyCache.js +212 -0
  24. package/src/QyCompressor.js +60 -0
  25. package/src/QyCompressor_Worker.js +13 -0
  26. package/src/QyDB.js +122 -0
  27. package/src/QyDefaultOptions.js +59 -0
  28. package/src/QyDir.js +192 -0
  29. package/src/QyFetch.js +38 -0
  30. package/src/QyFile.js +124 -0
  31. package/src/QyFileContentUtils.js +175 -0
  32. package/src/QyFileLogger.js +58 -0
  33. package/src/QyIndex.js +237 -0
  34. package/src/QyIndexPropTree.js +92 -0
  35. package/src/QyIntersectNode.js +48 -0
  36. package/src/QyItem.js +105 -0
  37. package/src/QyJsonSaver.js +20 -0
  38. package/src/QyKVData.js +289 -0
  39. package/src/QyKVDataCleaner.js +17 -0
  40. package/src/QyKVDataCleaner_Worker.js +94 -0
  41. package/src/QyKVDataLoader.js +65 -0
  42. package/src/QyKVDataSaver.js +17 -0
  43. package/src/QyKVDataSaver_Worker.js +81 -0
  44. package/src/QyLogFileSaver.js +14 -0
  45. package/src/QyLogFileSaver_Worker.js +26 -0
  46. package/src/QyLogger.js +76 -0
  47. package/src/QyMessageWorker.js +41 -0
  48. package/src/QyMessager.js +84 -0
  49. package/src/QyMessager_Run.js +13 -0
  50. package/src/QyMod.js +15 -0
  51. package/src/QyOpRunner.js +73 -0
  52. package/src/QyQueue.js +60 -0
  53. package/src/QySaver.js +83 -0
  54. package/src/QySnapshotCompactor.js +17 -0
  55. package/src/QySnapshotCompactor_Worker.js +151 -0
  56. package/src/QySnapshotSaver.js +17 -0
  57. package/src/QySnapshotSaver_Worker.js +164 -0
  58. package/src/QySnapshots.js +354 -0
  59. package/src/QyStructure.js +50 -0
  60. package/src/QyTrigger.js +133 -0
  61. package/src/QyUnionNode.js +105 -0
  62. package/src/QyUtils.js +250 -0
  63. package/src/QyWorker.js +33 -0
  64. package/src/hackernews.js +93 -0
  65. package/src/rpc/evalCode.js +9 -0
  66. package/src/rpc/getFileContent.js +16 -0
  67. package/src/rpc/getSubItems.js +32 -0
  68. package/src/rpc/queryFiles.js +33 -0
  69. package/src/rpc/reloadRpc.js +1 -0
  70. package/src/simulate.js +114 -0
  71. package/src/simulate2.js +110 -0
  72. package/src/soc_pokec.js +43 -0
  73. package/static/bootstrap-5.3.8-dist/css/bootstrap.min.css +6 -0
  74. package/static/bootstrap-5.3.8-dist/js/bootstrap.bundle.js +6312 -0
  75. package/static/datafolderui/QyStyledElement.js +30 -0
  76. package/static/datafolderui/QyUIFolderTree.js +203 -0
  77. package/static/datafolderui/QyUIUtils.js +42 -0
  78. package/static/datafolderui/display-tree.js +108 -0
  79. package/static/datafolderui/explore-tree.js +122 -0
  80. package/static/datafolderui/folder-tree.js +5 -0
  81. package/static/datafolderui/hscrpt.js +25 -0
  82. package/static/datafolderui/index.css +6 -0
  83. package/static/datafolderui/index.html +20 -0
  84. package/static/datafolderui/json-view.js +74 -0
  85. package/static/datafolderui/kv-input.js +66 -0
  86. package/static/datafolderui/list-input.js +52 -0
  87. package/static/datafolderui/main-page.js +98 -0
  88. package/static/datafolderui/num-input.js +27 -0
  89. package/static/datafolderui/query-editor.js +229 -0
  90. package/static/datafolderui/querySelectorShadowRoot.js +24 -0
  91. package/static/datafolderui/resizable-input.js +67 -0
  92. package/static/favicon.ico +0 -0
  93. package/static/icons-1.13.1/font/bootstrap-icons.min.css +5 -0
  94. package/static/icons-1.13.1/font/fonts/bootstrap-icons.woff +0 -0
  95. package/static/icons-1.13.1/font/fonts/bootstrap-icons.woff2 +0 -0
  96. package/static/json-view/dist/jsonview.js +433 -0
  97. package/static/tree.js/tree.css +106 -0
  98. package/static/tree.js/tree.js +374 -0
  99. package/static/w2ui/dist/w2ui.min.css +2 -0
  100. package/static/w2ui/src/less/icons/icons.json +1 -0
  101. package/static/w2ui/src/less/icons/preview.html +33 -0
  102. package/static/w2ui/src/less/icons/readme.md +15 -0
  103. package/static/w2ui/src/less/icons/svg/box.svg +3 -0
  104. package/static/w2ui/src/less/icons/svg/check.svg +3 -0
  105. package/static/w2ui/src/less/icons/svg/colors.svg +3 -0
  106. package/static/w2ui/src/less/icons/svg/columns.svg +5 -0
  107. package/static/w2ui/src/less/icons/svg/cross.svg +4 -0
  108. package/static/w2ui/src/less/icons/svg/drop.svg +6 -0
  109. package/static/w2ui/src/less/icons/svg/empty.svg +3 -0
  110. package/static/w2ui/src/less/icons/svg/eye-dropper.svg +4 -0
  111. package/static/w2ui/src/less/icons/svg/info.svg +8 -0
  112. package/static/w2ui/src/less/icons/svg/paste.svg +4 -0
  113. package/static/w2ui/src/less/icons/svg/pencil.svg +5 -0
  114. package/static/w2ui/src/less/icons/svg/plus.svg +3 -0
  115. package/static/w2ui/src/less/icons/svg/reload.svg +5 -0
  116. package/static/w2ui/src/less/icons/svg/search.svg +3 -0
  117. package/static/w2ui/src/less/icons/svg/settings.svg +8 -0
  118. package/static/w2ui/src/less/icons/w2ui-font.css +36 -0
  119. package/static/w2ui/src/less/icons/w2ui-font.woff +0 -0
  120. package/static/w2ui/src/less/src/buttons.less +184 -0
  121. package/static/w2ui/src/less/src/common.less +541 -0
  122. package/static/w2ui/src/less/src/fields.less +302 -0
  123. package/static/w2ui/src/less/src/form.less +319 -0
  124. package/static/w2ui/src/less/src/grid.less +1057 -0
  125. package/static/w2ui/src/less/src/icons.less +37 -0
  126. package/static/w2ui/src/less/src/layout.less +86 -0
  127. package/static/w2ui/src/less/src/mixins.less +87 -0
  128. package/static/w2ui/src/less/src/popup.less +277 -0
  129. package/static/w2ui/src/less/src/sidebar.less +343 -0
  130. package/static/w2ui/src/less/src/tabs.less +145 -0
  131. package/static/w2ui/src/less/src/toolbar.less +219 -0
  132. package/static/w2ui/src/less/src/tooltip.less +948 -0
  133. package/static/w2ui/src/less/w2ui.less +196 -0
  134. package/static/w2ui/src/locale/az-az.json +114 -0
  135. package/static/w2ui/src/locale/ba-ba.json +114 -0
  136. package/static/w2ui/src/locale/bg-bg.json +114 -0
  137. package/static/w2ui/src/locale/ca-es.json +114 -0
  138. package/static/w2ui/src/locale/da-dk.json +114 -0
  139. package/static/w2ui/src/locale/de-de.json +114 -0
  140. package/static/w2ui/src/locale/en-gb.json +17 -0
  141. package/static/w2ui/src/locale/en-us.json +17 -0
  142. package/static/w2ui/src/locale/es-ar.json +115 -0
  143. package/static/w2ui/src/locale/es-cr.json +119 -0
  144. package/static/w2ui/src/locale/es-es.json +114 -0
  145. package/static/w2ui/src/locale/es-mx.json +114 -0
  146. package/static/w2ui/src/locale/fr-fr.json +114 -0
  147. package/static/w2ui/src/locale/gl-es.json +114 -0
  148. package/static/w2ui/src/locale/hr-hr.json +114 -0
  149. package/static/w2ui/src/locale/hu-hu.json +114 -0
  150. package/static/w2ui/src/locale/id-id.json +114 -0
  151. package/static/w2ui/src/locale/it-it.json +114 -0
  152. package/static/w2ui/src/locale/ja-jp.json +114 -0
  153. package/static/w2ui/src/locale/kk-kz.json +116 -0
  154. package/static/w2ui/src/locale/ko-kr.json +114 -0
  155. package/static/w2ui/src/locale/lt-lt.json +114 -0
  156. package/static/w2ui/src/locale/nl-nl.json +114 -0
  157. package/static/w2ui/src/locale/no-no.json +114 -0
  158. package/static/w2ui/src/locale/pl-pl.json +114 -0
  159. package/static/w2ui/src/locale/pt-br.json +114 -0
  160. package/static/w2ui/src/locale/ru-ru.json +116 -0
  161. package/static/w2ui/src/locale/sk-sk.json +114 -0
  162. package/static/w2ui/src/locale/sl-si.json +116 -0
  163. package/static/w2ui/src/locale/sr-rs.json +114 -0
  164. package/static/w2ui/src/locale/tr-tr.json +114 -0
  165. package/static/w2ui/src/locale/uk-ua.json +114 -0
  166. package/static/w2ui/src/locale/zh-cn.json +114 -0
  167. package/static/w2ui/src/locale/zh-tw.json +114 -0
  168. package/static/w2ui/src/query.js +583 -0
  169. package/static/w2ui/src/readme.md +11 -0
  170. package/static/w2ui/src/w2base.js +311 -0
  171. package/static/w2ui/src/w2compat.js +207 -0
  172. package/static/w2ui/src/w2field.js +1854 -0
  173. package/static/w2ui/src/w2form.js +2411 -0
  174. package/static/w2ui/src/w2grid.js +8916 -0
  175. package/static/w2ui/src/w2layout.js +1194 -0
  176. package/static/w2ui/src/w2locale.js +129 -0
  177. package/static/w2ui/src/w2popup.js +909 -0
  178. package/static/w2ui/src/w2sidebar.js +1769 -0
  179. package/static/w2ui/src/w2tabs.js +669 -0
  180. package/static/w2ui/src/w2toolbar.js +1180 -0
  181. package/static/w2ui/src/w2tooltip.js +3134 -0
  182. package/static/w2ui/src/w2utils.js +2457 -0
@@ -0,0 +1,909 @@
1
+ /**
2
+ * Part of w2ui 2.0 library
3
+ * - Dependencies: mQuery, w2utils, w2base
4
+ *
5
+ * == 2.0 changes
6
+ * - CSP - fixed inline events
7
+ * - removed jQuery dependency
8
+ * - popup.open - returns promise like object
9
+ * - popup.confirm - refactored
10
+ * - popup.message - refactored
11
+ * - removed popup.options.mutliple
12
+ * - refactores w2alert, w2confirm, w2prompt
13
+ * - add w2popup.open().on('')
14
+ * - removed w2popup.restoreTemplate
15
+ * - deprecated onMsgOpen and onMsgClose
16
+ * - deprecated options.bgColor
17
+ * - rename focus -> setFocus
18
+ * - added center() // will auto center on window resize
19
+ * - close(immediate), also refactored if popup is closed when opening
20
+ * - options.resizable
21
+ * - actions in popup can be just html (for example separator)
22
+ * - resize - returns promise
23
+ */
24
+
25
+ import { w2base } from './w2base.js'
26
+ import { w2utils } from './w2utils.js'
27
+ import { query } from './query.js'
28
+
29
+ class Dialog extends w2base {
30
+ constructor() {
31
+ super()
32
+ this.defaults = {
33
+ title: '',
34
+ text: '', // just a text (will be centered)
35
+ body: '',
36
+ buttons: '',
37
+ width: 450,
38
+ height: 250,
39
+ focus: null, // brings focus to the element, can be a number or selector
40
+ actions: null, // actions object
41
+ style: '', // style of the message div
42
+ speed: 0.3,
43
+ blockPage: true,
44
+ modal: false,
45
+ maximized: false, // this is a flag to show the state - to open the popup maximized use openMaximized instead
46
+ keyboard: true, // will close popup on esc if not modal
47
+ showClose: true,
48
+ showMax: false,
49
+ resizable: false,
50
+ transition: null,
51
+ openMaximized: false,
52
+ moved: false
53
+ }
54
+ this.name = 'popup'
55
+ this.status = 'closed' // string that describes current status
56
+ this.onOpen = null
57
+ this.onClose = null
58
+ this.onMax = null
59
+ this.onMin = null
60
+ this.onToggle = null
61
+ this.onKeydown = null
62
+ this.onAction = null
63
+ this.onMove = null
64
+ this.tmp = {}
65
+ // event handler for resize
66
+ this.handleResize = (event) => {
67
+ // if it was moved by the user, do not auto resize
68
+ if (!this.options.moved) {
69
+ this.center(undefined, undefined, true)
70
+ }
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Sample calls
76
+ * - w2popup.open('ddd').ok(() => { w2popup.close() })
77
+ * - w2popup.open('ddd', { height: 120 }).ok(() => { w2popup.close() })
78
+ * - w2popup.open({ body: 'text', title: 'caption', actions: ["Close"] }).close(() => { w2popup.close() })
79
+ * - w2popup.open({ body: 'text', title: 'caption', actions: { Close() { w2popup.close() }} })
80
+ */
81
+ open(options) {
82
+ let self = this
83
+ if (this.status == 'closing' || query('#w2ui-popup').hasClass('animating')) {
84
+ // if called when previous is closing
85
+ this.close(true)
86
+ }
87
+ // get old options and merge them
88
+ let old_options = this.options
89
+ if (['string', 'number'].includes(typeof options)) {
90
+ options = w2utils.extend({
91
+ title: 'Notification',
92
+ body: `<div class="w2ui-centered">${options}</div>`,
93
+ actions: { Ok() { self.close() }},
94
+ cancelAction: 'ok'
95
+ }, arguments[1] ?? {})
96
+ }
97
+ if (options.text != null) options.body = `<div class="w2ui-centered w2ui-msg-text">${options.text}</div>`
98
+ options = Object.assign({}, this.defaults, old_options, { title: '', body : '' }, options, { maximized: false })
99
+ this.options = options
100
+ // if new - reset event handlers
101
+ if (query('#w2ui-popup').length === 0) {
102
+ this.off('*')
103
+ Object.keys(this).forEach(key => {
104
+ if (key.startsWith('on') && key != 'on') this[key] = null
105
+ })
106
+ }
107
+ // reassign events
108
+ Object.keys(options).forEach(key => {
109
+ if (key.startsWith('on') && key != 'on' && options[key]) {
110
+ this[key] = options[key]
111
+ }
112
+ })
113
+ options.width = parseInt(options.width)
114
+ options.height = parseInt(options.height)
115
+
116
+ let edata, msg, tmp
117
+ let { top, left, width, height } = this.center()
118
+ // make sure popup is not bigger then available screen
119
+ if (options.width > width) options.width = width
120
+ if (options.height > height) options.height = height
121
+
122
+ let prom = {
123
+ self: this,
124
+ action(callBack) {
125
+ self.on('action.prom', callBack)
126
+ return prom
127
+ },
128
+ close(callBack) {
129
+ self.on('close.prom', callBack)
130
+ return prom
131
+ },
132
+ then(callBack) {
133
+ self.on('open:after.prom', callBack)
134
+ return prom
135
+ }
136
+ }
137
+ // convert action arrays into buttons
138
+ if (options.actions != null && !options.buttons) {
139
+ options.buttons = ''
140
+ Object.keys(options.actions).forEach((action) => {
141
+ let handler = options.actions[action]
142
+ let btnAction = action
143
+ if (typeof handler == 'function') {
144
+ options.buttons += `<button class="w2ui-btn w2ui-eaction" name="${action}" data-click='["action","${action}","event"]'>${action}</button>`
145
+ }
146
+ if (typeof handler == 'object') {
147
+ options.buttons += `<button class="w2ui-btn w2ui-eaction ${handler.class || ''}" name="${action}" data-click='["action","${action}","event"]'
148
+ style="${handler.style}" ${handler.attrs}>${handler.text || action}</button>`
149
+ btnAction = Array.isArray(options.actions) ? handler.text : action
150
+ }
151
+ if (typeof handler == 'string') {
152
+ if (handler.trim().startsWith('<')) {
153
+ btnAction = 'none'
154
+ options.buttons += handler
155
+
156
+ } else {
157
+ btnAction = handler[0].toLowerCase() + handler.substr(1).replace(/\s+/g, '')
158
+ options.buttons += `<button class="w2ui-btn w2ui-eaction" name="${action}" data-click='["action","${btnAction}","event"]'>${handler}</button>`
159
+ }
160
+ }
161
+ if (typeof btnAction == 'string') {
162
+ btnAction = btnAction[0].toLowerCase() + btnAction.substr(1).replace(/\s+/g, '')
163
+ }
164
+ prom[btnAction] = function (callBack) {
165
+ self.on('action.buttons', (event) => {
166
+ let target = event.detail.action[0].toLowerCase() + event.detail.action.substr(1).replace(/\s+/g, '')
167
+ if (target == btnAction) callBack(event)
168
+ })
169
+ return prom
170
+ }
171
+ })
172
+ }
173
+ // check if message is already displayed
174
+ let titleBtns = ''
175
+ if (options.showClose) {
176
+ titleBtns += `<div class="w2ui-popup-button w2ui-popup-close">
177
+ <span class="w2ui-icon w2ui-icon-cross w2ui-eaction" data-mousedown="stop" data-click="close"></span>
178
+ </div>`
179
+ }
180
+ if (options.showMax) {
181
+ titleBtns += `<div class="w2ui-popup-button w2ui-popup-max">
182
+ <span class="w2ui-icon w2ui-icon-box w2ui-eaction" data-mousedown="stop" data-click="toggle"></span>
183
+ </div>`
184
+ }
185
+
186
+ if (query('#w2ui-popup').length === 0) {
187
+ // trigger event
188
+ edata = this.trigger('open', { target: 'popup', present: false })
189
+ if (edata.isCancelled === true) return
190
+ this.status = 'opening'
191
+ // output message
192
+ if (options.blockPage) {
193
+ w2utils.lock(document.body, {
194
+ opacity: 0.3,
195
+ onClick: options.modal ? null : () => { this.close() }
196
+ })
197
+ }
198
+ // first insert just body
199
+ let styles = `
200
+ left: ${left}px;
201
+ top: ${top}px;
202
+ width: ${parseInt(options.width)}px;
203
+ height: ${parseInt(options.height)}px;
204
+ transition: ${options.speed}s
205
+ `
206
+ msg = `<div id="w2ui-popup" class="w2ui-popup w2ui-anim-open animating ${!options.blockPage ? 'w2ui-non-blocking' : ''}" style="${w2utils.stripSpaces(styles)}"></div>`
207
+ query('body').append(msg)
208
+ query('#w2ui-popup')[0]._w2popup = {
209
+ self: this,
210
+ created: new Promise((resolve) => { this._promCreated = resolve }),
211
+ opened: new Promise((resolve) => { this._promOpened = resolve }),
212
+ closing: new Promise((resolve) => { this._promClosing = resolve }),
213
+ closed: new Promise((resolve) => { this._promClosed = resolve }),
214
+ }
215
+ // then content
216
+ styles = `${!options.title ? 'top: 0px !important;' : ''} ${!options.buttons ? 'bottom: 0px !important;' : ''}`
217
+ msg = `
218
+ <span name="hidden-first" tabindex="0" style="position: absolute; top: -100px"></span>
219
+ <div class="w2ui-popup-title-btns">${titleBtns}</div>
220
+ <div class="w2ui-popup-title" style="${!options.title ? 'display: none' : ''}"></div>
221
+ <div class="w2ui-box" style="${styles}">
222
+ <div class="w2ui-popup-body ${!options.title || ' w2ui-popup-no-title'}
223
+ ${!options.buttons || ' w2ui-popup-no-buttons'}" style="${options.style}">
224
+ </div>
225
+ </div>
226
+ <div class="w2ui-popup-buttons" style="${!options.buttons ? 'display: none' : ''}"></div>
227
+ <div class="w2ui-popup-resizer resize-point resize-icon"></div>
228
+ <span name="hidden-last" tabindex="0" style="position: absolute; top: -100px"></span>
229
+ `
230
+ query('#w2ui-popup').html(msg)
231
+
232
+ if (options.title) query('#w2ui-popup .w2ui-popup-title').append(w2utils.lang(options.title))
233
+ if (options.buttons) query('#w2ui-popup .w2ui-popup-buttons').append(options.buttons)
234
+ if (options.body) query('#w2ui-popup .w2ui-popup-body').append(options.body)
235
+
236
+ // allow element to render
237
+ setTimeout(() => {
238
+ query('#w2ui-popup')
239
+ .css('transition', options.speed + 's')
240
+ .removeClass('w2ui-anim-open')
241
+ w2utils.bindEvents('#w2ui-popup .w2ui-eaction', this)
242
+ query('#w2ui-popup').find('.w2ui-popup-body').show()
243
+ this._promCreated()
244
+ }, 1)
245
+ // clean transform
246
+ clearTimeout(this._timer)
247
+ this._timer = setTimeout(() => {
248
+ this.status = 'open'
249
+ self.setFocus(options.focus)
250
+ // event after
251
+ edata.finish()
252
+ this._promOpened()
253
+ query('#w2ui-popup').removeClass('animating')
254
+ }, options.speed * 1000)
255
+
256
+ } else {
257
+ // trigger event
258
+ edata = this.trigger('open', { target: 'popup', present: true })
259
+ if (edata.isCancelled === true) return
260
+ // check if size changed
261
+ this.status = 'opening'
262
+ if (old_options != null) {
263
+ if (!old_options.maximized && (old_options.width != options.width || old_options.height != options.height)) {
264
+ this.resize(options.width, options.height)
265
+ }
266
+ options.prevSize = options.width + 'px:' + options.height + 'px'
267
+ options.maximized = old_options.maximized
268
+ }
269
+ // show new items
270
+ let cloned = query('#w2ui-popup .w2ui-box').get(0).cloneNode(true)
271
+ query(cloned).removeClass('w2ui-box').addClass('w2ui-box-temp').find('.w2ui-popup-body').empty().append(options.body)
272
+ query('#w2ui-popup .w2ui-box').after(cloned)
273
+
274
+ if (options.buttons) {
275
+ query('#w2ui-popup .w2ui-popup-buttons').show().html('').append(options.buttons)
276
+ query('#w2ui-popup .w2ui-popup-body').removeClass('w2ui-popup-no-buttons')
277
+ query('#w2ui-popup .w2ui-box, #w2ui-popup .w2ui-box-temp').css('bottom', '')
278
+ } else {
279
+ query('#w2ui-popup .w2ui-popup-buttons').hide().html('')
280
+ query('#w2ui-popup .w2ui-popup-body').addClass('w2ui-popup-no-buttons')
281
+ query('#w2ui-popup .w2ui-box, #w2ui-popup .w2ui-box-temp').css('bottom', '0px')
282
+ }
283
+ if (options.title) {
284
+ query('#w2ui-popup .w2ui-popup-title')
285
+ .show()
286
+ .html(w2utils.lang(options.title))
287
+ query('#w2ui-popup .w2ui-popup-body').removeClass('w2ui-popup-no-title')
288
+ query('#w2ui-popup .w2ui-box, #w2ui-popup .w2ui-box-temp').css('top', '')
289
+ } else {
290
+ query('#w2ui-popup .w2ui-popup-title').hide().html('')
291
+ query('#w2ui-popup .w2ui-popup-body').addClass('w2ui-popup-no-title')
292
+ query('#w2ui-popup .w2ui-box, #w2ui-popup .w2ui-box-temp').css('top', '0px')
293
+ }
294
+ if (titleBtns) {
295
+ query('#w2ui-popup .w2ui-popup-title-btns')
296
+ .show()
297
+ .html(titleBtns)
298
+ } else {
299
+ query('#w2ui-popup .w2ui-popup-title-btns')
300
+ .hide()
301
+ }
302
+ // transition
303
+ let div_old = query('#w2ui-popup .w2ui-box')[0]
304
+ let div_new = query('#w2ui-popup .w2ui-box-temp')[0]
305
+ query('#w2ui-popup').addClass('animating')
306
+ w2utils.transition(div_old, div_new, options.transition, () => {
307
+ // clean up
308
+ query(div_old).remove()
309
+ query(div_new).removeClass('w2ui-box-temp').addClass('w2ui-box')
310
+ let $body = query(div_new).find('.w2ui-popup-body')
311
+ if ($body.length == 1) {
312
+ $body[0].style.cssText = options.style
313
+ $body.show()
314
+ }
315
+ // focus on first button
316
+ self.setFocus(options.focus)
317
+ query('#w2ui-popup').removeClass('animating')
318
+ })
319
+ // call event onOpen
320
+ this.status = 'open'
321
+ edata.finish()
322
+ w2utils.bindEvents('#w2ui-popup .w2ui-eaction', this)
323
+ query('#w2ui-popup').find('.w2ui-popup-body').show()
324
+ }
325
+
326
+ if (options.openMaximized) {
327
+ this.max()
328
+ }
329
+ // save new options
330
+ options._last_focus = document.activeElement
331
+ // keyboard events
332
+ if (options.keyboard) {
333
+ query(document.body)
334
+ .off('.w2popup')
335
+ .on('keydown.w2popup', (event) => {
336
+ this.keydown(event)
337
+ })
338
+ }
339
+ query(window).on('resize', this.handleResize)
340
+ // initialize move
341
+ tmp = {
342
+ changing : false,
343
+ mvMove : mvMove,
344
+ mvStop : mvStop
345
+ }
346
+ query('#w2ui-popup .w2ui-popup-title')
347
+ .off('mousedown')
348
+ .on('mousedown', function(event) {
349
+ if (!self.options.maximized) mvStart(event)
350
+ })
351
+
352
+ if (options.resizable) {
353
+ query('#w2ui-popup .w2ui-popup-resizer').show()
354
+ query('#w2ui-popup .w2ui-popup-resizer')
355
+ .off('mousedown')
356
+ .on('mousedown', event => {
357
+ mvStart(event, true)
358
+ })
359
+ } else {
360
+ query('#w2ui-popup .w2ui-popup-resizer').hide()
361
+ }
362
+
363
+ return prom
364
+
365
+ // handlers
366
+ function mvStart(evt, resizer) {
367
+ if (!evt) evt = window.event
368
+ self.status = resizer ? 'resizing' : 'moving'
369
+ let rect = query('#w2ui-popup').get(0).getBoundingClientRect()
370
+ Object.assign(tmp, {
371
+ changing: true,
372
+ isLocked: query('#w2ui-popup > .w2ui-lock').length == 1 ? true : false,
373
+ x : evt.screenX,
374
+ y : evt.screenY,
375
+ pos_x : rect.x,
376
+ pos_y : rect.y,
377
+ width : rect.width,
378
+ height : rect.height
379
+ })
380
+ if (!tmp.isLocked) self.lock({ opacity: 0 })
381
+ query(document.body)
382
+ .on('mousemove.w2ui-popup', tmp.mvMove)
383
+ .on('mouseup.w2ui-popup', tmp.mvStop)
384
+ if (evt.stopPropagation) evt.stopPropagation(); else evt.cancelBubble = true
385
+ if (evt.preventDefault) evt.preventDefault(); else return false
386
+ }
387
+
388
+ function mvMove(evt) {
389
+ if (tmp.changing != true) return
390
+ if (!evt) evt = window.event
391
+ tmp.div_x = evt.screenX - tmp.x
392
+ tmp.div_y = evt.screenY - tmp.y
393
+ // trigger event
394
+ let edata = self.trigger('move', { target: 'popup', div_x: tmp.div_x, div_y: tmp.div_y, originalEvent: evt })
395
+ if (edata.isCancelled === true) return
396
+ // default behavior
397
+ if (self.status == 'moving') {
398
+ query('#w2ui-popup').css({
399
+ 'transition': 'none',
400
+ 'transform' : 'translate3d('+ tmp.div_x +'px, '+ tmp.div_y +'px, 0px)'
401
+ })
402
+ self.options.moved = true
403
+ } else {
404
+ query('#w2ui-popup').css({
405
+ transition: 'none',
406
+ width: (tmp.width + tmp.div_x) + 'px',
407
+ height: (tmp.height + tmp.div_y) + 'px'
408
+ })
409
+ }
410
+ // event after
411
+ edata.finish()
412
+ }
413
+
414
+ function mvStop(evt) {
415
+ if (tmp.changing != true) return
416
+ if (!evt) evt = window.event
417
+ tmp.div_x = (evt.screenX - tmp.x)
418
+ tmp.div_y = (evt.screenY - tmp.y)
419
+ if (self.status == 'moving') {
420
+ query('#w2ui-popup')
421
+ .css({
422
+ 'left': (tmp.pos_x + tmp.div_x) + 'px',
423
+ 'top' : (tmp.pos_y + tmp.div_y) + 'px'
424
+ })
425
+ .css({
426
+ 'transition': 'none',
427
+ 'transform' : 'translate3d(0px, 0px, 0px)'
428
+ })
429
+ } else {
430
+ query('#w2ui-popup').css({
431
+ transition: 'none',
432
+ width: (tmp.width + tmp.div_x) + 'px',
433
+ height: (tmp.height + tmp.div_y) + 'px'
434
+ })
435
+ self.resizeMessages()
436
+ }
437
+ tmp.changing = false
438
+ self.status = 'open'
439
+ query(document.body).off('.w2ui-popup')
440
+ if (!tmp.isLocked) self.unlock()
441
+ }
442
+ }
443
+
444
+ load(options) {
445
+ return new Promise((resolve, reject) => {
446
+ if (typeof options == 'string') {
447
+ options = { url: options }
448
+ }
449
+ if (options.url == null) {
450
+ console.log('ERROR: The url is not defined.')
451
+ reject('The url is not defined')
452
+ return
453
+ }
454
+ this.status = 'loading'
455
+ let [url, selector] = String(options.url).split('#')
456
+ if (url) {
457
+ fetch(url).then(res => res.text()).then(html => {
458
+ resolve(this.template(html, selector, options))
459
+ })
460
+ }
461
+ })
462
+ }
463
+
464
+ template(data, id, options = {}) {
465
+ let html
466
+ try {
467
+ html = query(data)
468
+ } catch (e) {
469
+ html = query.html(data)
470
+ }
471
+ if (id) html = html.filter('#' + id)
472
+ Object.assign(options, {
473
+ width: parseInt(query(html).css('width')),
474
+ height: parseInt(query(html).css('height')),
475
+ title: query(html).find('[rel=title]').html(),
476
+ body: query(html).find('[rel=body]').html(),
477
+ buttons: query(html).find('[rel=buttons]').html(),
478
+ style: query(html).find('[rel=body]').get(0).style.cssText,
479
+ })
480
+ return this.open(options)
481
+ }
482
+
483
+ action(action, event) {
484
+ let click = this.options.actions[action]
485
+ if (click instanceof Object && click.onClick) click = click.onClick
486
+ // event before
487
+ let edata = this.trigger('action', { action, target: 'popup', self: this,
488
+ originalEvent: event, value: this.input ? this.input.value : null })
489
+ if (edata.isCancelled === true) return
490
+ // default actions
491
+ if (typeof click === 'function') click.call(this, event)
492
+ // event after
493
+ edata.finish()
494
+ }
495
+
496
+ keydown(event) {
497
+ if (this.options && !this.options.keyboard) return
498
+ // trigger event
499
+ let edata = this.trigger('keydown', { target: 'popup', originalEvent: event })
500
+ if (edata.isCancelled === true) return
501
+ // default behavior
502
+ switch (event.keyCode) {
503
+ case 27:
504
+ event.preventDefault()
505
+ if (query('#w2ui-popup .w2ui-message').length == 0) {
506
+ if (this.options.cancelAction) {
507
+ this.action(this.options.cancelAction)
508
+ } else {
509
+ this.close()
510
+ }
511
+ }
512
+ break
513
+ }
514
+ // event after
515
+ edata.finish()
516
+ }
517
+
518
+ close(immediate) {
519
+ // trigger event
520
+ let edata = this.trigger('close', { target: 'popup' })
521
+ if (edata.isCancelled === true) return
522
+ let cleanUp = () => {
523
+ // return template
524
+ query('#w2ui-popup').remove()
525
+ // restore active
526
+ if (this.options._last_focus && this.options._last_focus.length > 0) this.options._last_focus.focus()
527
+ this.status = 'closed'
528
+ this.options = {}
529
+ // event after
530
+ edata.finish()
531
+ this._promClosed()
532
+ }
533
+ if (query('#w2ui-popup').length === 0 || this.status == 'closed') { // already closed
534
+ return
535
+ }
536
+ if (this.status == 'opening') { // if it is opening
537
+ immediate = true
538
+ }
539
+ if (this.status == 'closing' && immediate === true) {
540
+ cleanUp()
541
+ clearTimeout(this.tmp.closingTimer)
542
+ w2utils.unlock(document.body, 0)
543
+ return
544
+ }
545
+ // default behavior
546
+ this.status = 'closing'
547
+ query('#w2ui-popup')
548
+ .css('transition', this.options.speed + 's')
549
+ .addClass('w2ui-anim-close animating')
550
+ w2utils.unlock(document.body, 300)
551
+ this._promClosing()
552
+
553
+ if (immediate) {
554
+ cleanUp()
555
+ } else {
556
+ this.tmp.closingTimer = setTimeout(cleanUp, this.options.speed * 1000)
557
+ }
558
+ // remove keyboard events
559
+ if (this.options.keyboard) {
560
+ query(document.body).off('keydown', this.keydown)
561
+ }
562
+ query(window).off('resize', this.handleResize)
563
+ }
564
+
565
+ toggle() {
566
+ let edata = this.trigger('toggle', { target: 'popup' })
567
+ if (edata.isCancelled === true) return
568
+ // default action
569
+ if (this.options.maximized === true) this.min(); else this.max()
570
+ // event after
571
+ setTimeout(() => {
572
+ edata.finish()
573
+ }, (this.options.speed * 1000) + 50)
574
+ }
575
+
576
+ max() {
577
+ if (this.options.maximized === true) return
578
+ // trigger event
579
+ let edata = this.trigger('max', { target: 'popup' })
580
+ if (edata.isCancelled === true) return
581
+ // default behavior
582
+ this.status = 'resizing'
583
+ let rect = query('#w2ui-popup').get(0).getBoundingClientRect()
584
+ this.options.prevSize = rect.width + ':' + rect.height
585
+ // do resize
586
+ this.resize(10000, 10000, () => {
587
+ this.status = 'open'
588
+ this.options.maximized = true
589
+ edata.finish()
590
+ })
591
+ }
592
+
593
+ min() {
594
+ if (this.options.maximized !== true) return
595
+ let size = this.options.prevSize.split(':')
596
+ // trigger event
597
+ let edata = this.trigger('min', { target: 'popup' })
598
+ if (edata.isCancelled === true) return
599
+ // default behavior
600
+ this.status = 'resizing'
601
+ // do resize
602
+ this.options.maximized = false
603
+ this.resize(parseInt(size[0]), parseInt(size[1]), () => {
604
+ this.status = 'open'
605
+ this.options.prevSize = null
606
+ edata.finish()
607
+ })
608
+ }
609
+
610
+ clear() {
611
+ query('#w2ui-popup .w2ui-popup-title').html('')
612
+ query('#w2ui-popup .w2ui-popup-body').html('')
613
+ query('#w2ui-popup .w2ui-popup-buttons').html('')
614
+ }
615
+
616
+ reset() {
617
+ this.open(this.defaults)
618
+ }
619
+
620
+ message(options) {
621
+ return w2utils.message({
622
+ owner: this,
623
+ box : query('#w2ui-popup').get(0),
624
+ after: '.w2ui-popup-title'
625
+ }, options)
626
+ }
627
+
628
+ confirm(options) {
629
+ return w2utils.confirm({
630
+ owner: this,
631
+ box : query('#w2ui-popup'),
632
+ after: '.w2ui-popup-title'
633
+ }, options)
634
+ }
635
+
636
+ setFocus(focus) {
637
+ let box = query('#w2ui-popup')
638
+ let sel = 'input, button, select, textarea, [contentEditable], [tabindex], .w2ui-input'
639
+ if (focus != null) {
640
+ let el = isNaN(focus)
641
+ ? box.find(sel).filter(focus).filter(':not([name=hidden-first])').get(0)
642
+ : box.find(sel).filter(':not([name=hidden-first])').get(focus)
643
+ el?.focus()
644
+ } else {
645
+ let el = box.find('[name=hidden-first]').get(0)
646
+ if (el) el.focus()
647
+ }
648
+ // keep focus/blur inside popup
649
+ query(box).find(sel)
650
+ .off('.keep-focus')
651
+ .on('blur.keep-focus', function (event) {
652
+ setTimeout(() => {
653
+ let focus = document.activeElement
654
+ let inside = query(box).find(sel).filter(focus).length > 0
655
+ let name = query(focus).attr('name')
656
+ if (!inside && focus && focus !== document.body) {
657
+ query(box).find(sel).get(0)?.focus()
658
+ }
659
+ if (name == 'hidden-last') {
660
+ query(box).find(sel).get(1)?.focus()
661
+ }
662
+ if (name == 'hidden-first') {
663
+ query(box).find(sel).get(-2)?.focus()
664
+ }
665
+ }, 1)
666
+ })
667
+ }
668
+
669
+ lock(msg, showSpinner) {
670
+ let args = Array.from(arguments)
671
+ args.unshift(query('#w2ui-popup'))
672
+ w2utils.lock(...args)
673
+ }
674
+
675
+ unlock(speed) {
676
+ w2utils.unlock(query('#w2ui-popup'), speed)
677
+ }
678
+
679
+ center(width, height, force) {
680
+ let maxW, maxH
681
+ if (window.innerHeight == undefined) {
682
+ maxW = parseInt(document.documentElement.offsetWidth)
683
+ maxH = parseInt(document.documentElement.offsetHeight)
684
+ } else {
685
+ maxW = parseInt(window.innerWidth)
686
+ maxH = parseInt(window.innerHeight)
687
+ }
688
+ width = parseInt(width ?? this.options.width)
689
+ height = parseInt(height ?? this.options.height)
690
+ if (this.options.maximized === true) {
691
+ width = maxW
692
+ height = maxH
693
+ }
694
+ if (maxW - 10 < width) width = maxW - 10
695
+ if (maxH - 10 < height) height = maxH - 10
696
+ let top = (maxH - height) / 3 // it is my oppinion that it is more estatic to show closer to top then in exact middle
697
+ let left = (maxW - width) / 2
698
+ if (force) {
699
+ query('#w2ui-popup').css({
700
+ 'transition': 'none',
701
+ 'top' : top + 'px',
702
+ 'left' : left + 'px',
703
+ 'width' : width + 'px',
704
+ 'height': height + 'px'
705
+ })
706
+ this.resizeMessages() // then messages resize nicely
707
+ }
708
+ return { top, left, width, height }
709
+ }
710
+
711
+ resize(newWidth, newHeight, callBack) {
712
+ return new Promise(resolve => {
713
+ let self = this
714
+ if (this.options.speed == null) this.options.speed = 0
715
+ // calculate new position
716
+ let { top, left, width, height } = this.center(newWidth, newHeight)
717
+ let speed = this.options.speed
718
+ query('#w2ui-popup').css({
719
+ 'transition': `${speed}s width, ${speed}s height, ${speed}s left, ${speed}s top`,
720
+ 'top' : top + 'px',
721
+ 'left' : left + 'px',
722
+ 'width' : width + 'px',
723
+ 'height': height + 'px'
724
+ })
725
+ let tmp_int = setInterval(() => { self.resizeMessages() }, 10) // then messages resize nicely
726
+ setTimeout(() => {
727
+ clearInterval(tmp_int)
728
+ self.resizeMessages()
729
+ if (typeof callBack == 'function') callBack()
730
+ resolve()
731
+ }, (this.options.speed * 1000) + 50) // give extra 50 ms
732
+ })
733
+ }
734
+
735
+ // internal function
736
+ resizeMessages() {
737
+ // see if there are messages and resize them
738
+ query('#w2ui-popup .w2ui-message').each(msg => {
739
+ let mopt = msg._msg_options
740
+ let popup = query('#w2ui-popup')
741
+ if (parseInt(mopt.width) < 10) mopt.width = 10
742
+ if (parseInt(mopt.height) < 10) mopt.height = 10
743
+ let rect = popup[0].getBoundingClientRect()
744
+ let titleHeight = parseInt(popup.find('.w2ui-popup-title')[0].clientHeight)
745
+ let pWidth = parseInt(rect.width)
746
+ let pHeight = parseInt(rect.height)
747
+ // re-calc width
748
+ mopt.width = mopt.originalWidth
749
+ if (mopt.width > pWidth - 10) {
750
+ mopt.width = pWidth - 10
751
+ }
752
+ // re-calc height
753
+ mopt.height = mopt.originalHeight
754
+ if (mopt.height > pHeight - titleHeight - 5) {
755
+ mopt.height = pHeight - titleHeight - 5
756
+ }
757
+ if (mopt.originalHeight < 0) mopt.height = pHeight + mopt.originalHeight - titleHeight
758
+ if (mopt.originalWidth < 0) mopt.width = pWidth + mopt.originalWidth * 2 // x 2 because there is left and right margin
759
+ query(msg).css({
760
+ left : ((pWidth - mopt.width) / 2) + 'px',
761
+ width : mopt.width + 'px',
762
+ height : mopt.height + 'px'
763
+ })
764
+ })
765
+ }
766
+ }
767
+
768
+ function w2alert(msg, title, callBack) {
769
+ let prom
770
+ let options = {
771
+ title: w2utils.lang(title ?? 'Notification'),
772
+ body: `<div class="w2ui-centered w2ui-msg-text">${msg}</div>`,
773
+ showClose: false,
774
+ actions: { ok: w2utils.lang('Ok') },
775
+ cancelAction: 'ok'
776
+ }
777
+ if (query('#w2ui-popup').length > 0 && w2popup.status != 'closing') {
778
+ prom = w2popup.message(options)
779
+ } else {
780
+ prom = w2popup.open(options)
781
+ }
782
+ prom.ok(event => {
783
+ if (typeof event.detail.self?.close == 'function') {
784
+ event.detail.self.close()
785
+ }
786
+ if (typeof callBack == 'function') callBack()
787
+ })
788
+ return prom
789
+ }
790
+
791
+ function w2confirm(msg, title, callBack) {
792
+ let prom
793
+ let options = msg
794
+ if (['string', 'number'].includes(typeof options)) {
795
+ options = { msg: options }
796
+ }
797
+ if (options.msg) {
798
+ options.body = `<div class="w2ui-centered w2ui-msg-text">${options.msg}</div>`,
799
+ delete options.msg
800
+ }
801
+ if (typeof title == 'function' && callBack == null) {
802
+ callBack = title
803
+ title = undefined
804
+ }
805
+ w2utils.extend(options, {
806
+ title: w2utils.lang(title ?? options.title ?? 'Confirmation'),
807
+ showClose: false,
808
+ modal: true,
809
+ cancelAction: 'no'
810
+ })
811
+ if (callBack == null && options.callBack != null) {
812
+ callBack = options.callBack
813
+ }
814
+ w2utils.normButtons(options, { yes: w2utils.lang('Yes'), no: w2utils.lang('No') })
815
+ if (query('#w2ui-popup').length > 0 && w2popup.status != 'closing') {
816
+ prom = w2popup.message(options)
817
+ } else {
818
+ prom = w2popup.open(options)
819
+ }
820
+ prom.self
821
+ .off('.confirm')
822
+ .on('action:after.confirm', (event) => {
823
+ if (typeof event.detail.self?.close == 'function') {
824
+ event.detail.self.close()
825
+ }
826
+ if (typeof callBack == 'function') callBack(event.detail.action)
827
+ })
828
+ return prom
829
+ }
830
+
831
+ function w2prompt(label, title, callBack) {
832
+ let prom
833
+ let options = label
834
+ if (['string', 'number'].includes(typeof options)) {
835
+ options = { label: options }
836
+ }
837
+ if (options.label) {
838
+ options.focus = 0 // the input should be in focus, which is first in the popup
839
+ options.body = (options.textarea
840
+ ? `<div class="w2ui-prompt textarea">
841
+ <div>${options.label}</div>
842
+ <textarea id="w2prompt" class="w2ui-input" ${options.attrs ?? ''}
843
+ data-keydown="keydown|event" data-keyup="change|event"></textarea>
844
+ </div>`
845
+ : `<div class="w2ui-prompt w2ui-centered">
846
+ <label>${options.label}</label>
847
+ <input id="w2prompt" class="w2ui-input" ${options.attrs ?? ''}
848
+ data-keydown="keydown|event" data-keyup="change|event">
849
+ </div>`
850
+ )
851
+ }
852
+ w2utils.extend(options, {
853
+ title: w2utils.lang(title ?? options.title ?? 'Notification'),
854
+ showClose: false,
855
+ modal: true,
856
+ cancelAction: 'cancel'
857
+ })
858
+ w2utils.normButtons(options, { ok: w2utils.lang('Ok'), cancel: w2utils.lang('Cancel') })
859
+ if (query('#w2ui-popup').length > 0 && w2popup.status != 'closing') {
860
+ prom = w2popup.message(options)
861
+ } else {
862
+ prom = w2popup.open(options)
863
+ }
864
+ if (prom.self.box) {
865
+ prom.self.input = query(prom.self.box).find('#w2prompt').get(0)
866
+ } else {
867
+ prom.self.input = query('#w2ui-popup .w2ui-popup-body #w2prompt').get(0)
868
+ }
869
+ if (options.value != null) {
870
+ prom.self.input.value = options.value
871
+ prom.self.input.select()
872
+ }
873
+ prom.change = function (callback) {
874
+ prom.self.on('change', callback)
875
+ return this
876
+ }
877
+ prom.self
878
+ .off('.prompt')
879
+ .on('open:after.prompt', (event) => {
880
+ let box = event.detail.box ? event.detail.box : query('#w2ui-popup .w2ui-popup-body').get(0)
881
+ w2utils.bindEvents(query(box).find('#w2prompt'), {
882
+ keydown(evt) {
883
+ if (evt.keyCode == 27) evt.stopPropagation()
884
+ },
885
+ change(evt) {
886
+ let edata = prom.self.trigger('change', { target: 'prompt', originalEvent: evt })
887
+ if (edata.isCancelled === true) return
888
+ if (evt.keyCode == 13 && (evt.ctrlKey || evt.metaKey || evt.target.tagName != 'TEXTAREA')) {
889
+ prom.self.action('Ok', evt)
890
+ }
891
+ if (evt.keyCode == 27) {
892
+ prom.self.action('Cancel', evt)
893
+ }
894
+ edata.finish()
895
+ }
896
+ })
897
+ query(box).find('.w2ui-eaction').trigger('keyup')
898
+ })
899
+ .on('action:after.prompt', (event) => {
900
+ if (typeof event.detail.self?.close == 'function') {
901
+ event.detail.self.close()
902
+ }
903
+ if (typeof callBack == 'function') callBack(event.detail.action)
904
+ })
905
+ return prom
906
+ }
907
+
908
+ let w2popup = new Dialog()
909
+ export { w2popup, w2alert, w2confirm, w2prompt, Dialog }