@qtoggle/qui 0.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 (202) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc.json +492 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  5. package/.github/ISSUE_TEMPLATE/improvement_proposal.md +20 -0
  6. package/.github/workflows/main.yml +74 -0
  7. package/.pre-commit-config.yaml +8 -0
  8. package/LICENSE.txt +177 -0
  9. package/README.md +4 -0
  10. package/font/dejavusans-bold.woff +0 -0
  11. package/font/dejavusans-bolditalic.woff +0 -0
  12. package/font/dejavusans-italic.woff +0 -0
  13. package/font/dejavusans-regular.woff +0 -0
  14. package/img/qui-icons.svg +1937 -0
  15. package/js/base/base.js +47 -0
  16. package/js/base/condition-variable.js +92 -0
  17. package/js/base/errors.js +36 -0
  18. package/js/base/i18n.js +20 -0
  19. package/js/base/mixwith.js +135 -0
  20. package/js/base/require-js-compat.js +78 -0
  21. package/js/base/signal.js +91 -0
  22. package/js/base/singleton.js +66 -0
  23. package/js/base/timer.js +126 -0
  24. package/js/config.js +184 -0
  25. package/js/forms/common-fields/check-field.js +42 -0
  26. package/js/forms/common-fields/choice-buttons-field.js +30 -0
  27. package/js/forms/common-fields/color-combo-field.js +37 -0
  28. package/js/forms/common-fields/combo-field.js +108 -0
  29. package/js/forms/common-fields/common-fields.js +23 -0
  30. package/js/forms/common-fields/composite-field.js +132 -0
  31. package/js/forms/common-fields/custom-html-field.js +51 -0
  32. package/js/forms/common-fields/email-field.js +30 -0
  33. package/js/forms/common-fields/file-picker-field.js +46 -0
  34. package/js/forms/common-fields/jquery-ui-field.js +111 -0
  35. package/js/forms/common-fields/labels-field.js +69 -0
  36. package/js/forms/common-fields/numeric-field.js +39 -0
  37. package/js/forms/common-fields/password-field.js +28 -0
  38. package/js/forms/common-fields/phone-field.js +26 -0
  39. package/js/forms/common-fields/progress-disk-field.js +69 -0
  40. package/js/forms/common-fields/push-button-field.js +138 -0
  41. package/js/forms/common-fields/slider-field.js +51 -0
  42. package/js/forms/common-fields/text-area-field.js +34 -0
  43. package/js/forms/common-fields/text-field.js +89 -0
  44. package/js/forms/common-fields/up-down-field.js +85 -0
  45. package/js/forms/common-forms/common-forms.js +16 -0
  46. package/js/forms/common-forms/options-form.js +77 -0
  47. package/js/forms/common-forms/page-form.js +115 -0
  48. package/js/forms/form-button.js +202 -0
  49. package/js/forms/form-field.js +1183 -0
  50. package/js/forms/form.js +1181 -0
  51. package/js/forms/forms.js +68 -0
  52. package/js/global-glass.js +100 -0
  53. package/js/icons/default-stock.js +173 -0
  54. package/js/icons/icon.js +64 -0
  55. package/js/icons/icons.js +16 -0
  56. package/js/icons/multi-state-sprites-icon.js +362 -0
  57. package/js/icons/stock-icon.js +219 -0
  58. package/js/icons/stock.js +98 -0
  59. package/js/icons/stocks.js +57 -0
  60. package/js/index.js +232 -0
  61. package/js/lib/jquery.longpress.js +79 -0
  62. package/js/lib/jquery.module.js +4 -0
  63. package/js/lib/logger.module.js +4 -0
  64. package/js/lib/pep.module.js +4 -0
  65. package/js/lists/common-items/common-items.js +5 -0
  66. package/js/lists/common-items/icon-label-list-item.js +86 -0
  67. package/js/lists/common-lists/common-lists.js +5 -0
  68. package/js/lists/common-lists/page-list.js +53 -0
  69. package/js/lists/list-item.js +147 -0
  70. package/js/lists/list.js +636 -0
  71. package/js/lists/lists.js +26 -0
  72. package/js/main-ui/main-ui.js +64 -0
  73. package/js/main-ui/menu-bar.js +144 -0
  74. package/js/main-ui/options-bar.js +181 -0
  75. package/js/main-ui/status.js +185 -0
  76. package/js/main-ui/top-bar.js +59 -0
  77. package/js/messages/common-message-forms/common-message-forms.js +7 -0
  78. package/js/messages/common-message-forms/confirm-message-form.js +81 -0
  79. package/js/messages/common-message-forms/simple-message-form.js +67 -0
  80. package/js/messages/common-message-forms/sticky-simple-message-form.js +27 -0
  81. package/js/messages/message-form.js +107 -0
  82. package/js/messages/messages.js +21 -0
  83. package/js/messages/sticky-modal-page.js +98 -0
  84. package/js/messages/sticky-modal-progress-message.js +27 -0
  85. package/js/messages/toast.js +164 -0
  86. package/js/navigation.js +654 -0
  87. package/js/pages/breadcrumbs.js +124 -0
  88. package/js/pages/common-pages/common-pages.js +6 -0
  89. package/js/pages/common-pages/modal-progress-page.js +83 -0
  90. package/js/pages/common-pages/structured-page.js +46 -0
  91. package/js/pages/page.js +1018 -0
  92. package/js/pages/pages-context.js +154 -0
  93. package/js/pages/pages.js +252 -0
  94. package/js/pwa.js +337 -0
  95. package/js/sections/section.js +612 -0
  96. package/js/sections/sections.js +300 -0
  97. package/js/tables/common-cells/common-cells.js +7 -0
  98. package/js/tables/common-cells/icon-label-table-cell.js +68 -0
  99. package/js/tables/common-cells/push-button-table-cell.js +133 -0
  100. package/js/tables/common-cells/simple-table-cell.js +37 -0
  101. package/js/tables/common-tables/common-tables.js +5 -0
  102. package/js/tables/common-tables/page-table.js +55 -0
  103. package/js/tables/table-cell.js +198 -0
  104. package/js/tables/table-row.js +126 -0
  105. package/js/tables/table.js +492 -0
  106. package/js/tables/tables.js +36 -0
  107. package/js/theme.js +304 -0
  108. package/js/utils/ajax.js +126 -0
  109. package/js/utils/array.js +194 -0
  110. package/js/utils/colors.js +445 -0
  111. package/js/utils/cookies.js +65 -0
  112. package/js/utils/crypto.js +439 -0
  113. package/js/utils/css.js +234 -0
  114. package/js/utils/date.js +300 -0
  115. package/js/utils/files.js +27 -0
  116. package/js/utils/gestures.js +165 -0
  117. package/js/utils/html.js +76 -0
  118. package/js/utils/misc.js +81 -0
  119. package/js/utils/object.js +324 -0
  120. package/js/utils/promise.js +49 -0
  121. package/js/utils/string.js +192 -0
  122. package/js/utils/url.js +187 -0
  123. package/js/utils/utils.js +3 -0
  124. package/js/utils/visibility-manager.js +211 -0
  125. package/js/views/common-views/common-views.js +7 -0
  126. package/js/views/common-views/icon-label-view.js +210 -0
  127. package/js/views/common-views/progress-view.js +89 -0
  128. package/js/views/common-views/structured-view.js +368 -0
  129. package/js/views/view.js +467 -0
  130. package/js/views/views.js +3 -0
  131. package/js/widgets/base-widget.js +23 -0
  132. package/js/widgets/common-widgets/check-button.js +109 -0
  133. package/js/widgets/common-widgets/choice-buttons.js +322 -0
  134. package/js/widgets/common-widgets/color-combo.js +104 -0
  135. package/js/widgets/common-widgets/combo.js +645 -0
  136. package/js/widgets/common-widgets/common-widgets.js +17 -0
  137. package/js/widgets/common-widgets/email-input.js +7 -0
  138. package/js/widgets/common-widgets/file-picker.js +133 -0
  139. package/js/widgets/common-widgets/labels.js +132 -0
  140. package/js/widgets/common-widgets/numeric-input.js +49 -0
  141. package/js/widgets/common-widgets/password-input.js +91 -0
  142. package/js/widgets/common-widgets/phone-input.js +7 -0
  143. package/js/widgets/common-widgets/progress-disk.js +174 -0
  144. package/js/widgets/common-widgets/push-button.js +155 -0
  145. package/js/widgets/common-widgets/slider.js +455 -0
  146. package/js/widgets/common-widgets/text-area.js +52 -0
  147. package/js/widgets/common-widgets/text-input.js +174 -0
  148. package/js/widgets/common-widgets/up-down.js +351 -0
  149. package/js/widgets/widgets.js +57 -0
  150. package/js/window.js +557 -0
  151. package/jsdoc.conf.json +20 -0
  152. package/less/base.less +123 -0
  153. package/less/forms/common-fields.less +101 -0
  154. package/less/forms/common-forms.less +5 -0
  155. package/less/forms/form-button.less +21 -0
  156. package/less/forms/form-field.less +266 -0
  157. package/less/forms/form.less +131 -0
  158. package/less/global-glass.less +64 -0
  159. package/less/icon-label-view.less +82 -0
  160. package/less/icons.less +144 -0
  161. package/less/lists.less +105 -0
  162. package/less/main-ui.less +328 -0
  163. package/less/messages.less +189 -0
  164. package/less/no-effects.less +24 -0
  165. package/less/pages/breadcrumbs.less +98 -0
  166. package/less/pages/common-pages.less +36 -0
  167. package/less/pages/page.less +70 -0
  168. package/less/progress-view.less +51 -0
  169. package/less/stock-icons.less +43 -0
  170. package/less/structured-view.less +245 -0
  171. package/less/tables.less +84 -0
  172. package/less/theme-dark.less +133 -0
  173. package/less/theme-light.less +132 -0
  174. package/less/theme.less +419 -0
  175. package/less/visibility-manager.less +11 -0
  176. package/less/widgets/check-button.less +96 -0
  177. package/less/widgets/choice-buttons.less +160 -0
  178. package/less/widgets/color-combo.less +33 -0
  179. package/less/widgets/combo.less +230 -0
  180. package/less/widgets/common-buttons.less +120 -0
  181. package/less/widgets/common.less +24 -0
  182. package/less/widgets/input.less +258 -0
  183. package/less/widgets/labels.less +81 -0
  184. package/less/widgets/progress-disk.less +70 -0
  185. package/less/widgets/slider.less +199 -0
  186. package/less/widgets/updown.less +115 -0
  187. package/less/widgets/various.less +36 -0
  188. package/package.json +47 -0
  189. package/pyproject.toml +45 -0
  190. package/qui/__init__.py +110 -0
  191. package/qui/constants.py +1 -0
  192. package/qui/exceptions.py +2 -0
  193. package/qui/j2template.py +71 -0
  194. package/qui/settings.py +60 -0
  195. package/qui/templates/manifest.json +25 -0
  196. package/qui/templates/qui.html +126 -0
  197. package/qui/templates/service-worker.js +188 -0
  198. package/qui/web/__init__.py +0 -0
  199. package/qui/web/tornado.py +220 -0
  200. package/scripts/postinstall.sh +10 -0
  201. package/webpack/webpack-adjust-css-urls-loader.js +36 -0
  202. package/webpack/webpack-common.js +384 -0
@@ -0,0 +1,467 @@
1
+
2
+ import $ from '$qui/lib/jquery.module.js'
3
+
4
+ import {AssertionError} from '$qui/base/errors.js'
5
+ import {Mixin} from '$qui/base/mixwith.js'
6
+ import * as Toast from '$qui/messages/toast.js'
7
+
8
+
9
+ /**
10
+ * @alias qui.views.STATE_NORMAL
11
+ */
12
+ export const STATE_NORMAL = 'normal'
13
+
14
+ /**
15
+ * @alias qui.views.STATE_WARNING
16
+ */
17
+ export const STATE_WARNING = 'warning'
18
+
19
+ /**
20
+ * @alias qui.views.STATE_ERROR
21
+ */
22
+ export const STATE_ERROR = 'error'
23
+
24
+ /**
25
+ * @alias qui.views.STATE_PROGRESS
26
+ */
27
+ export const STATE_PROGRESS = 'progress'
28
+
29
+
30
+ /** @lends qui.views.ViewMixin */
31
+ const ViewMixin = Mixin((superclass = Object) => {
32
+
33
+ /**
34
+ * A mixin to be used with classes that behave as views (have a visual HTML representation).
35
+ * @alias qui.views.ViewMixin
36
+ * @mixin
37
+ */
38
+ class ViewMixin extends superclass {
39
+
40
+ /**
41
+ * @constructs
42
+ * @param {String} [cssClass] additional CSS classes to set to the view element
43
+ * @param {...*} args parent class parameters
44
+ */
45
+ constructor({cssClass = null, ...args} = {}) {
46
+ super(args)
47
+
48
+ /* ViewMixin is prepared to be initialized multiple times along the inheritance path;
49
+ * this may happen when inheriting ViewMixin more than once through mixins */
50
+
51
+ if (this._html === undefined) {
52
+ this._html = null
53
+ }
54
+
55
+ if (this._state === undefined) {
56
+ this._state = STATE_NORMAL
57
+ this._warningMessage = null
58
+ this._errorMessage = null
59
+ this._progressPercent = null
60
+ }
61
+
62
+ if (!this._cssClass) {
63
+ this._cssClass = cssClass
64
+ }
65
+ else {
66
+ this._cssClass += ` ${cssClass}`
67
+ }
68
+ }
69
+
70
+
71
+ /* HTML */
72
+
73
+ /**
74
+ * Create the HTML element of this view.
75
+ * @abstract
76
+ * @returns {jQuery}
77
+ */
78
+ makeHTML() {
79
+ return $('<div></div>')
80
+ }
81
+
82
+ /**
83
+ * Override this to further initialize the HTML element of this view.
84
+ * @param {jQuery} html the HTML element to be initialized
85
+ */
86
+ initHTML(html) {
87
+ }
88
+
89
+ /**
90
+ * Return the HTML element of this view.
91
+ * @returns {jQuery}
92
+ */
93
+ getHTML() {
94
+ if (this._html == null) {
95
+ this._html = this.makeHTML()
96
+ this.initHTML(this._html)
97
+
98
+ if (this._cssClass) {
99
+ this._html.addClass(this._cssClass)
100
+ }
101
+
102
+ this.init()
103
+ }
104
+
105
+ return this._html
106
+ }
107
+
108
+ /**
109
+ * Tells if the HTML element of this view has been created.
110
+ * @return {Boolean}
111
+ */
112
+ hasHTML() {
113
+ return this._html != null
114
+ }
115
+
116
+ /**
117
+ * Initialize the view. Called after the HTML has been created and initialized.
118
+ */
119
+ init() {
120
+ }
121
+
122
+
123
+ /* State */
124
+
125
+ /**
126
+ * Update the current state.
127
+ * @param {String} state the desired state
128
+ */
129
+ setState(state) {
130
+ /* Make sure we have the HTML created before switching states */
131
+ this.getHTML()
132
+
133
+ if (this._state !== state) {
134
+ this.leaveState(this._state, state)
135
+ }
136
+
137
+ let oldState = this._state
138
+ this._state = state
139
+
140
+ this.enterState(oldState, state)
141
+ }
142
+
143
+ /**
144
+ * Return the current view state.
145
+ * @returns {String}
146
+ */
147
+ getState() {
148
+ return this._state
149
+ }
150
+
151
+ /**
152
+ * Define the behavior of the view when entering states. Entering a state usually means showing a visual element
153
+ * corresponding to that state.
154
+ * @param {String} oldState
155
+ * @param {String} newState
156
+ */
157
+ enterState(oldState, newState) {
158
+ switch (newState) {
159
+ case STATE_NORMAL:
160
+ break
161
+
162
+ case STATE_WARNING:
163
+ this.showWarning(this._warningMessage)
164
+ break
165
+
166
+ case STATE_ERROR:
167
+ this.showError(this._errorMessage)
168
+ break
169
+
170
+ case STATE_PROGRESS:
171
+ this.showProgress(this._progressPercent)
172
+ break
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Define the behavior of the view when leaving states. Leaving a state usually means hiding a visual element
178
+ * corresponding to that state.
179
+ * @param {String} oldState
180
+ * @param {String} newState
181
+ */
182
+ leaveState(oldState, newState) {
183
+ switch (oldState) {
184
+ case STATE_NORMAL:
185
+ break
186
+
187
+ case STATE_WARNING:
188
+ this._warningMessage = null
189
+ this.hideWarning()
190
+ break
191
+
192
+ case STATE_ERROR:
193
+ this._errorMessage = null
194
+ this.hideError()
195
+ break
196
+
197
+ case STATE_PROGRESS:
198
+ this._progressPercent = null
199
+ this.hideProgress()
200
+ break
201
+ }
202
+ }
203
+
204
+
205
+ /* Progress */
206
+
207
+ /**
208
+ * Put the view in the progress state or updates the progress. The view state is set to
209
+ * {@link qui.views.STATE_PROGRESS}.
210
+ *
211
+ * It is safe to call this method multiple times, updating the progress percent.
212
+ *
213
+ * @param {?Number} [percent] optional progress percent (from `0` to `100`); `null` indicates indefinite
214
+ * progress
215
+ */
216
+ setProgress(percent = null) {
217
+ /* No duplicate setProgress() protection, since we want to be able to update the progress */
218
+
219
+ this._progressPercent = percent
220
+ this.setState(STATE_PROGRESS)
221
+ }
222
+
223
+ /**
224
+ * Put the view in the normal state, but only if the current state is {@link qui.views.STATE_PROGRESS}.
225
+ */
226
+ clearProgress() {
227
+ if (this._state === STATE_PROGRESS) {
228
+ this.setState(STATE_NORMAL)
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Return the current progress percent.
234
+ *
235
+ * An exception will be thrown if the current view state is not {@link qui.views.STATE_PROGRESS}.
236
+ *
237
+ * @returns {?Number}
238
+ */
239
+ getProgressPercent() {
240
+ if (this._state !== STATE_PROGRESS) {
241
+ throw new AssertionError(`getProgressPercent() called in ${this._state} state`)
242
+ }
243
+
244
+ return this._progressPercent
245
+ }
246
+
247
+ /**
248
+ * Define how the view is displayed in progress state, disallowing any user interaction.
249
+ *
250
+ * {@link qui.views.ViewMixin#inProgress} returns `true` when called from this method.
251
+ *
252
+ * Does nothing by default. Override this method to implement your own progress display.
253
+ *
254
+ * @param {?Number} [percent] optional progress percent (from `0` to `100`); `null` indicates indefinite
255
+ * progress
256
+ */
257
+ showProgress(percent) {
258
+ }
259
+
260
+ /**
261
+ * Hide a previously displayed progress, re-enabling user interaction.
262
+ *
263
+ * {@link qui.views.ViewMixin#inProgress} returns `false` when called from this method.
264
+ *
265
+ * Does nothing by default. Override this method to implement your own progress hiding.
266
+ */
267
+ hideProgress() {
268
+ }
269
+
270
+ /**
271
+ * Tell if the view is currently in progress (its state is {@link qui.views.STATE_PROGRESS}).
272
+ * @returns {Boolean}
273
+ */
274
+ inProgress() {
275
+ return this._state === STATE_PROGRESS
276
+ }
277
+
278
+
279
+ /* Warning */
280
+
281
+ /**
282
+ * Put the view in the warning state or updates the warning message. The view state is set to
283
+ * {@link qui.views.STATE_WARNING}.
284
+ *
285
+ * It is safe to call this method multiple times, updating the warning message.
286
+ *
287
+ * @param {?String} [message] an optional warning message
288
+ */
289
+ setWarning(message = null) {
290
+ /* No duplicate setWarning() protection, since we want to be able to update the error */
291
+
292
+ this._warningMessage = message
293
+ this.setState(STATE_WARNING)
294
+ }
295
+
296
+ /**
297
+ * Put the view in the normal state, but only if the current state is {@link qui.views.STATE_WARNING}.
298
+ */
299
+ clearWarning() {
300
+ if (this._state === STATE_WARNING) {
301
+ this.setState(STATE_NORMAL)
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Return the warning message set with {@link qui.views.ViewMixin#setWarning} or `null` if no warning message
307
+ * was set.
308
+ *
309
+ * An exception will be thrown if the current view state is not {@link qui.views.STATE_WARNING}.
310
+ *
311
+ * @returns {?String}
312
+ */
313
+ getWarningMessage() {
314
+ if (this._state !== STATE_WARNING) {
315
+ throw new AssertionError(`getWarningMessage() called in ${this._state} state`)
316
+ }
317
+
318
+ return this._warningMessage
319
+ }
320
+
321
+ /**
322
+ * Define how the view is displayed in warning state, showing the warning message.
323
+ *
324
+ * {@link qui.views.ViewMixin#hasWarning} returns `true` when called from this method.
325
+ *
326
+ * By default displays a warning toast message. Override this method to implement your own warning display.
327
+ *
328
+ * @param {?String} message the warning message, or `null` if no warning message available
329
+ */
330
+ showWarning(message) {
331
+ Toast.show({message: message, type: 'error', timeout: 0})
332
+ }
333
+
334
+ /**
335
+ * Hide a previously displayed warning.
336
+ *
337
+ * {@link qui.views.ViewMixin#hasWarning} returns `false` when called from this method.
338
+ *
339
+ * By default calls {@link qui.messages.toast.hide}. Override this method to implement your own warning
340
+ * hiding.
341
+ */
342
+ hideWarning() {
343
+ Toast.hide()
344
+ }
345
+
346
+ /**
347
+ * Tell if the view is currently in the warning state (its state is {@link qui.views.STATE_WARNING}).
348
+ * @returns {Boolean}
349
+ */
350
+ hasWarning() {
351
+ return this._state === STATE_WARNING
352
+ }
353
+
354
+
355
+ /* Error */
356
+
357
+ /**
358
+ * Put the view in the error state or updates the error message.
359
+ *
360
+ * The view state is set to {@link qui.views.STATE_ERROR}.
361
+ *
362
+ * It is safe to call this method multiple times, updating the error message.
363
+ *
364
+ * @param {?String|Error} [message] an error message
365
+ */
366
+ setError(message = null) {
367
+ /* No duplicate setError() protection, since we want to be able to update the error */
368
+
369
+ if (message instanceof Error) {
370
+ message = message.message
371
+ }
372
+
373
+ this._errorMessage = message
374
+ this.setState(STATE_ERROR)
375
+ }
376
+
377
+ /**
378
+ * Put the view in the normal state, but only if the current state is {@link qui.views.STATE_ERROR}.
379
+ */
380
+ clearError() {
381
+ if (this._state === STATE_ERROR) {
382
+ this.setState(STATE_NORMAL)
383
+ }
384
+ }
385
+
386
+ /**
387
+ * Return the error message set with {@link qui.views.ViewMixin#setError} or `null` if no error message was set.
388
+ *
389
+ * An exception will be thrown if the current view state is not {@link qui.views.STATE_ERROR}.
390
+ *
391
+ * @returns {?String}
392
+ */
393
+ getErrorMessage() {
394
+ if (this._state !== STATE_ERROR) {
395
+ throw new AssertionError(`getErrorMessage() called in ${this._state} state`)
396
+ }
397
+
398
+ return this._errorMessage
399
+ }
400
+
401
+ /**
402
+ * Define how the view is displayed in error state, showing the error message.
403
+ *
404
+ * {@link qui.views.ViewMixin#hasError} returns `true` when called from this method.
405
+ *
406
+ * By default displays a error toast message. Override this method to implement your own error display.
407
+ *
408
+ * @param {?String} message the error message, or `null` if no error message available
409
+ */
410
+ showError(message) {
411
+ Toast.show({message: message, type: 'error', timeout: 0})
412
+ }
413
+
414
+ /**
415
+ * Hide a previously displayed error.
416
+ *
417
+ * {@link qui.views.ViewMixin#hasError} returns `false` when called from this method.
418
+ *
419
+ * By default calls {@link qui.messages.toast.hide}. Override this method to implement your own error
420
+ * hiding.
421
+ */
422
+ hideError() {
423
+ Toast.hide()
424
+ }
425
+
426
+ /**
427
+ * Tell if the view is currently in the error state (its state is {@link qui.views.STATE_ERROR}).
428
+ * @returns {Boolean}
429
+ */
430
+ hasError() {
431
+ return this._state === STATE_ERROR
432
+ }
433
+
434
+
435
+ /* Closing */
436
+
437
+ /**
438
+ * Tell if the view has been closed.
439
+ *
440
+ * By default returns `false`.
441
+ *
442
+ * Override this method to implement your own closed status.
443
+ *
444
+ * @returns {Boolean}
445
+ */
446
+ isClosed() {
447
+ return false
448
+ }
449
+
450
+ /**
451
+ * Close the view.
452
+ *
453
+ * By default does nothing.
454
+ *
455
+ * Override this method to implement your own close behavior.
456
+ */
457
+ close() {
458
+ }
459
+
460
+ }
461
+
462
+ return ViewMixin
463
+
464
+ })
465
+
466
+
467
+ export default ViewMixin
@@ -0,0 +1,3 @@
1
+ /**
2
+ * @namespace qui.views
3
+ */
@@ -0,0 +1,23 @@
1
+
2
+ import $ from '$qui/lib/jquery.module.js'
3
+
4
+
5
+ $.widget('qui.basewidget', {
6
+
7
+ options: {
8
+ warning: null,
9
+ error: null
10
+ },
11
+
12
+ _setOption: function (key, value) {
13
+ this._super(key, value)
14
+
15
+ switch (key) {
16
+ case 'warning':
17
+ case 'error':
18
+ this.element.toggleClass(`has-${key}`, value != null)
19
+ break
20
+ }
21
+ }
22
+
23
+ })
@@ -0,0 +1,109 @@
1
+
2
+ import $ from '$qui/lib/jquery.module.js'
3
+
4
+ import * as BaseWidget from '../base-widget.js' /* Needed */
5
+
6
+
7
+ $.widget('qui.checkbutton', $.qui.basewidget, {
8
+
9
+ options: {
10
+ onClass: 'on',
11
+ readonly: false,
12
+ disabled: false
13
+ },
14
+
15
+ _create: function () {
16
+ let widget = this
17
+
18
+ this.element.addClass('qui-base-button qui-interactive-button qui-check-button')
19
+ if (this.options.readonly) {
20
+ this.element.addClass('readonly')
21
+ }
22
+ if (this.options.disabled) {
23
+ this.element.addClass('disabled')
24
+ }
25
+ if (!this.options.disabled) {
26
+ this.element.attr('tabIndex', 0) /* Make element focusable */
27
+ }
28
+
29
+ this.element.on('click', function () {
30
+ widget._toggleChange()
31
+ })
32
+ this.element.on('keydown', function (e) {
33
+ if (e.which === 32 /* Space */) {
34
+ widget._toggleChange()
35
+ return false
36
+ }
37
+ })
38
+ },
39
+
40
+ isOn: function () {
41
+ return this.element.hasClass(this.options.onClass)
42
+ },
43
+
44
+ setOn: function () {
45
+ this.element.addClass(this.options.onClass)
46
+ },
47
+
48
+ setOff: function () {
49
+ this.element.removeClass(this.options.onClass)
50
+ },
51
+
52
+ toggle: function () {
53
+ if (this.isOn()) {
54
+ this.setOff()
55
+ }
56
+ else {
57
+ this.setOn()
58
+ }
59
+ },
60
+
61
+ getValue: function () {
62
+ return this.isOn()
63
+ },
64
+
65
+ setValue: function (value) {
66
+ if (value) {
67
+ this.setOn()
68
+ }
69
+ else {
70
+ this.setOff()
71
+ }
72
+ },
73
+
74
+ _toggleChange: function () {
75
+ if (this.options.readonly || this.options.disabled) {
76
+ return
77
+ }
78
+
79
+ if (this.element.hasClass(this.options.onClass)) {
80
+ this.setOff()
81
+ this.element.trigger('change', false)
82
+ }
83
+ else {
84
+ this.setOn()
85
+ this.element.trigger('change', true)
86
+ }
87
+ },
88
+
89
+ _setOption: function (key, value) {
90
+ this._super(key, value)
91
+
92
+ switch (key) {
93
+ case 'readonly':
94
+ this.element.toggleClass('readonly', value)
95
+ break
96
+
97
+ case 'disabled':
98
+ this.element.toggleClass('disabled', value)
99
+ if (value) {
100
+ this.element.removeAttr('tabIndex')
101
+ }
102
+ else {
103
+ this.element.attr('tabIndex', 0)
104
+ }
105
+ break
106
+ }
107
+ }
108
+
109
+ })