@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,187 @@
1
+ /**
2
+ * A class holding the details of a URL.
3
+ * @alias qui.utils.URL
4
+ */
5
+ class URL {
6
+
7
+ static VALID_REGEX = new RegExp(
8
+ '^(?:(?:http|https)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d' +
9
+ '|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d' +
10
+ '|2[0-4]\\d|25[0-4]))|(?:(?:[a-z_\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)' +
11
+ '(?:\\.(?:[a-z_\\u00a1-\\uffff0-9]+-?)*[a-z_\\u00a1-\\uffff0-9]+)*(?:\\.?' +
12
+ '(?:[a-z_\\u00a1-\\uffff]*)))|localhost)(?::\\d{1,5})?(?:(/|\\?|#)[^\\s]*)?$',
13
+ 'i'
14
+ )
15
+
16
+
17
+ /**
18
+ * @constructs
19
+ * @param {String} scheme
20
+ * @param {String} [username]
21
+ * @param {String} [password]
22
+ * @param {String} host
23
+ * @param {Number} [port]
24
+ * @param {String} [path]
25
+ * @param {Object} [query]
26
+ * @param {String} [fragment]
27
+ */
28
+ constructor({
29
+ scheme,
30
+ username = '',
31
+ password = '',
32
+ host,
33
+ port = null,
34
+ path = '',
35
+ query = {},
36
+ fragment = ''
37
+ }) {
38
+ this.scheme = scheme
39
+ this.username = username
40
+ this.password = password
41
+ this.host = host
42
+ this.port = port
43
+ this.path = path
44
+ this.query = query
45
+ this.fragment = fragment
46
+ }
47
+
48
+ /**
49
+ * Serialize the query and returns it as a string.
50
+ * @returns {String}
51
+ */
52
+ get queryStr() {
53
+ return Object.entries(this.query)
54
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
55
+ .join('&')
56
+ }
57
+
58
+ /**
59
+ * Compose the string representation of this URL.
60
+ * @returns {String}
61
+ */
62
+ toString() {
63
+ /* Scheme */
64
+ let url = `${this.scheme}://`
65
+
66
+ /* Credentials */
67
+ if (this.username) {
68
+ url += this.username
69
+ if (this.password) {
70
+ url += `:${this.password}`
71
+ }
72
+
73
+ url += '@'
74
+ }
75
+
76
+ /* Host */
77
+ url += this.host
78
+
79
+ /* Port */
80
+ let port = this.port
81
+ if ((this.scheme === 'http' && this.port === 80) || (this.scheme === 'https' && this.port === 443)) {
82
+ port = null
83
+ }
84
+ if (port != null) {
85
+ url += `:${port}`
86
+ }
87
+
88
+ /* Path */
89
+ let path = this.path
90
+ if (path && !path.startsWith('/')) {
91
+ path = `/${path}`
92
+ }
93
+ url += path
94
+
95
+ /* Query */
96
+ if (Object.keys(this.query).length > 0) {
97
+ url += `?${this.queryStr}`
98
+ }
99
+
100
+ /* Fragment */
101
+ if (this.fragment) {
102
+ url += `#${this.fragment}`
103
+ }
104
+
105
+ return url
106
+ }
107
+
108
+ /**
109
+ * Return all the attributes of this URL as a dictionary.
110
+ * @returns {Object}
111
+ */
112
+ toAttributes() {
113
+ return {
114
+ scheme: this.scheme,
115
+ username: this.username,
116
+ password: this.password,
117
+ host: this.host,
118
+ port: this.port,
119
+ path: this.path,
120
+ query: this.query,
121
+ fragment: this.fragment
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Alter one or more attributes of this URL, returning the new URL.
127
+ * @param {Object} attributes
128
+ * @returns {qui.utils.URL}
129
+ */
130
+ alter(attributes) {
131
+ let oldAttributes = this.toAttributes()
132
+ Object.assign(oldAttributes, attributes)
133
+
134
+ return new this.constructor(oldAttributes)
135
+ }
136
+
137
+ /**
138
+ * Parse a string representation of a URL and returns a URL object.
139
+ * @param {String} urlStr
140
+ * @returns {qui.utils.URL}
141
+ */
142
+ static parse(urlStr = '') {
143
+ let a = document.createElement('a')
144
+ a.href = urlStr
145
+
146
+ let params = {
147
+ scheme: a.protocol.replace(':', ''),
148
+ host: a.hostname,
149
+ path: a.pathname,
150
+ port: a.port ? parseInt(a.port) : null,
151
+ username: a.username,
152
+ password: a.password,
153
+ query: {}
154
+ }
155
+
156
+ if (a.search) {
157
+ a.search.substring(1).split('&').forEach(function (s) {
158
+ let parts = s.split('=')
159
+ let name = parts[0]
160
+ let value = parts.slice(1).join('=')
161
+
162
+ params.query[decodeURIComponent(name)] = decodeURIComponent(value)
163
+ })
164
+ }
165
+
166
+ if (a.hash) {
167
+ params.fragment = a.hash.substring(1)
168
+ }
169
+
170
+ return new this(params)
171
+ }
172
+
173
+ /**
174
+ * Transform the string representation of a partial URL into a full URL.
175
+ * @param {String} urlStr
176
+ * @returns {String}
177
+ */
178
+ static qualify(urlStr) {
179
+ let a = document.createElement('a')
180
+ a.href = urlStr
181
+ return a.href
182
+ }
183
+
184
+ }
185
+
186
+
187
+ export default URL
@@ -0,0 +1,3 @@
1
+ /**
2
+ * @namespace qui.utils
3
+ */
@@ -0,0 +1,211 @@
1
+
2
+ import * as Theme from '$qui/theme.js'
3
+ import {asap} from '$qui/utils/misc.js'
4
+
5
+
6
+ /**
7
+ * A class that resolves the problem of waiting an async iteration before applying styles with transitions, after
8
+ * changing the `display` style property.
9
+ * @alias qui.utils.VisibilityManager
10
+ */
11
+ class VisibilityManager {
12
+
13
+ /**
14
+ * @constructs
15
+ * @param {jQuery} element the element to be managed
16
+ * @param {String} [visibleDisplay] the display style property when element is visible; defaults to `""`
17
+ * @param {String} [hiddenDisplay] the display style property when element is hidden; defaults to `"none"`
18
+ * @param {?String} [visibleClass] the class(es) to add to element when it's visible; defaults to `"visible"`
19
+ * @param {?String} [hiddenClass] the class(es) to add to element when it's hidden; defaults to `"hidden"`
20
+ * @param {Boolean} [widthTransition] set to `true` if width should be transitioned while hiding/showing
21
+ * @param {Boolean} [heightTransition] set to `true` if height should be transitioned while hiding/showing
22
+ * @param {Number} [transitionDuration] the duration of the transition, in milliseconds; defaults to
23
+ * {@link qui.theme.getTransitionDuration()}
24
+ */
25
+ constructor({
26
+ element,
27
+ visibleDisplay = '',
28
+ hiddenDisplay = 'none',
29
+ visibleClass = 'visible',
30
+ hiddenClass = 'hidden',
31
+ widthTransition = false,
32
+ heightTransition = false,
33
+ transitionDuration = Theme.getTransitionDuration()
34
+ }) {
35
+
36
+ let currentDisplay = element.css('display') || window.getComputedStyle(element[0]).display
37
+
38
+ this._element = element
39
+ this._visibleDisplay = visibleDisplay != null ? visibleDisplay : currentDisplay
40
+ this._hiddenDisplay = hiddenDisplay
41
+ this._visibleClass = visibleClass
42
+ this._hiddenClass = hiddenClass
43
+ this._widthTransition = widthTransition
44
+ this._heightTransition = heightTransition
45
+
46
+ this._transitionDuration = transitionDuration
47
+
48
+ /* Autodetect initial visibility */
49
+ this._visibleAfterTransition = !this._hiddenDisplay || (currentDisplay !== this._hiddenDisplay)
50
+
51
+ this._transitionHandle = null
52
+ this._asapHandle = null
53
+ }
54
+
55
+ /**
56
+ * Show element.
57
+ */
58
+ showElement() {
59
+ if (this._visibleAfterTransition) {
60
+ return
61
+ }
62
+ this._visibleAfterTransition = true
63
+
64
+ if (this._transitionHandle) {
65
+ clearTimeout(this._transitionHandle)
66
+ this._transitionHandle = null
67
+ }
68
+ if (this._asapHandle) {
69
+ clearTimeout(this._asapHandle)
70
+ this._asapHandle = null
71
+ }
72
+
73
+ this._element.css('display', this._visibleDisplay)
74
+
75
+ /* If element is not yet part of DOM, don't bother with transitions */
76
+ if (!this._isAddedToDOM()) {
77
+ this._element.addClass(this._visibleClass || '')
78
+ this._element.removeClass(
79
+ `${this._hiddenClass || ''} qui-visibility-manager-hidden-width qui-visibility-manager-hidden-height`
80
+ )
81
+ if (this._widthTransition) {
82
+ this._element.css('width', '')
83
+ }
84
+ if (this._heightTransition) {
85
+ this._element.css('height', '')
86
+ }
87
+
88
+ return
89
+ }
90
+
91
+ /* Handle special case where element has been hidden while not part of DOM and thus has width/height 0px */
92
+ if (this._widthTransition && this._element.css('width') === '0px') {
93
+ this._element.css('width', '')
94
+ this._element.removeClass('qui-visibility-manager-hidden-width')
95
+ this._element.css('width', this._element.width())
96
+ this._element.addClass('qui-visibility-manager-hidden-width')
97
+ }
98
+ if (this._heightTransition && this._element.css('height') === '0px') {
99
+ this._element.css('height', '')
100
+ this._element.removeClass('qui-visibility-manager-hidden-height')
101
+ this._element.css('height', this._element.height())
102
+ this._element.addClass('qui-visibility-manager-hidden-height')
103
+ }
104
+
105
+ this._asapHandle = asap(function () {
106
+
107
+ this._asapHandle = null
108
+ this._element.addClass(this._visibleClass || '')
109
+ this._element.removeClass(
110
+ `${this._hiddenClass || ''} qui-visibility-manager-hidden-width qui-visibility-manager-hidden-height`
111
+ )
112
+
113
+ this._transitionHandle = setTimeout(function () {
114
+
115
+ this._transitionHandle = null
116
+ if (this._widthTransition) {
117
+ this._element.css('width', '')
118
+ }
119
+ if (this._heightTransition) {
120
+ this._element.css('height', '')
121
+ }
122
+
123
+ }.bind(this), this._transitionDuration)
124
+
125
+ }.bind(this))
126
+ }
127
+
128
+ /**
129
+ * Hide element.
130
+ */
131
+ hideElement() {
132
+ if (!this._visibleAfterTransition) {
133
+ return
134
+ }
135
+ this._visibleAfterTransition = false
136
+
137
+ if (this._transitionHandle) {
138
+ clearTimeout(this._transitionHandle)
139
+ this._transitionHandle = null
140
+ }
141
+ if (this._asapHandle) {
142
+ clearTimeout(this._asapHandle)
143
+ this._asapHandle = null
144
+ }
145
+
146
+ if (this._widthTransition) {
147
+ this._element.css('width', this._element.width())
148
+ }
149
+ if (this._heightTransition) {
150
+ this._element.css('height', this._element.height())
151
+ }
152
+
153
+ /* If element is not yet part of DOM, don't bother with transitions */
154
+ if (!this._isAddedToDOM()) {
155
+ this._element.removeClass(this._visibleClass || '')
156
+ this._element.addClass(this._hiddenClass || '')
157
+ if (this._widthTransition) {
158
+ this._element.addClass('qui-visibility-manager-hidden-width')
159
+ }
160
+ if (this._heightTransition) {
161
+ this._element.addClass('qui-visibility-manager-hidden-height')
162
+ }
163
+ this._element.css('display', this._hiddenDisplay)
164
+
165
+ return
166
+ }
167
+
168
+ let hideAfterTransition = function () {
169
+
170
+ this._asapHandle = null
171
+ this._element.removeClass(this._visibleClass || '')
172
+ this._element.addClass(this._hiddenClass || '')
173
+ if (this._widthTransition) {
174
+ this._element.addClass('qui-visibility-manager-hidden-width')
175
+ }
176
+ if (this._heightTransition) {
177
+ this._element.addClass('qui-visibility-manager-hidden-height')
178
+ }
179
+
180
+ this._transitionHandle = setTimeout(function () {
181
+
182
+ this._transitionHandle = null
183
+ this._element.css('display', this._hiddenDisplay)
184
+
185
+ }.bind(this), this._transitionDuration)
186
+
187
+ }.bind(this)
188
+
189
+ if (this._widthTransition || this._heightTransition) {
190
+ this._asapHandle = asap(hideAfterTransition)
191
+ }
192
+ else {
193
+ hideAfterTransition()
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Tell if element is visible or not.
199
+ * @returns {Boolean}
200
+ */
201
+ isElementVisible() {
202
+ return this._visibleAfterTransition
203
+ }
204
+
205
+ _isAddedToDOM() {
206
+ return this._element.parents('body').length > 0
207
+ }
208
+
209
+ }
210
+
211
+ export default VisibilityManager
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @namespace qui.views.commonviews
3
+ */
4
+
5
+ export {default as IconLabelViewMixin} from './icon-label-view.js'
6
+ export {default as ProgressViewMixin} from './progress-view.js'
7
+ export {default as StructuredViewMixin} from './structured-view.js'
@@ -0,0 +1,210 @@
1
+
2
+ import $ from '$qui/lib/jquery.module.js'
3
+
4
+ import {Mixin} from '$qui/base/mixwith.js'
5
+ import StockIcon from '$qui/icons/stock-icon.js'
6
+
7
+
8
+ /** @lends qui.views.commonviews.IconLabelViewMixin */
9
+ const IconLabelViewMixin = Mixin((superclass = Object) => {
10
+
11
+ /**
12
+ * A view made of an icon with a label.
13
+ * @alias qui.views.commonviews.IconLabelViewMixin
14
+ */
15
+ class IconLabelViewMixin extends superclass {
16
+
17
+ /**
18
+ * @constructs
19
+ * @param {qui.icons.Icon} [icon] icon
20
+ * @param {?String} [label] label
21
+ * @param {?String} [subLabel] subscript label
22
+ * @param {Boolean} [clickable] whether to make view clickable or not (defaults to `false`)
23
+ * @param {...*} args parent class parameters
24
+ */
25
+ constructor({icon = null, label = null, subLabel = null, clickable = false, ...args} = {}) {
26
+ super(args)
27
+
28
+ this._icon = icon
29
+ this._label = label || null
30
+ this._subLabel = subLabel || null
31
+ this._clickable = clickable
32
+ this._iconElement = null
33
+ this._labelElement = null
34
+ this._subLabelElement = null
35
+ this._iconLabelContainer = null
36
+ }
37
+
38
+ /**
39
+ * Create the icon and label container.
40
+ * @returns {jQuery}
41
+ */
42
+ makeIconLabelContainer() {
43
+ let container = $('<div></div>', {class: 'qui-icon-label-view'})
44
+
45
+ if (this._clickable) {
46
+ container.addClass('qui-base-button')
47
+ }
48
+
49
+ this._iconElement = $('<div></div>', {class: 'qui-icon'})
50
+ this._applyIcon(this._icon, this._iconElement)
51
+ container.append(this._iconElement)
52
+
53
+ let labelsContainer = $('<div></div>', {class: 'labels'})
54
+ container.append(labelsContainer)
55
+
56
+ this._labelElement = $('<div></div>', {class: 'label'})
57
+ this.setLabel(this._label)
58
+ labelsContainer.append(this._labelElement)
59
+
60
+ this._subLabelElement = $('<div></div>', {class: 'sub-label'})
61
+ this.setSubLabel(this._subLabel)
62
+ labelsContainer.append(this._subLabelElement)
63
+
64
+ return container
65
+ }
66
+
67
+ /**
68
+ * Return the icon and label container.
69
+ * @returns {jQuery}
70
+ */
71
+ getIconLabelContainer() {
72
+ if (this._iconLabelContainer == null) {
73
+ this._iconLabelContainer = this.makeIconLabelContainer()
74
+ }
75
+
76
+ return this._iconLabelContainer
77
+ }
78
+
79
+ /**
80
+ * Return the icon.
81
+ * @returns {?qui.icons.Icon}
82
+ */
83
+ getIcon() {
84
+ return this._icon
85
+ }
86
+
87
+ /**
88
+ * Update the icon.
89
+ * @param {?qui.icons.Icon} icon
90
+ */
91
+ setIcon(icon) {
92
+ this._icon = icon
93
+ this._applyIcon(icon, this._iconElement)
94
+ }
95
+
96
+ /**
97
+ * Reapply the icon.
98
+ */
99
+ updateIcon() {
100
+ this._applyIcon(this._icon, this._iconElement)
101
+ }
102
+
103
+ /**
104
+ * Prepare the view icon, altering its attributes as needed, before applying it.
105
+ * @param {qui.icons.Icon} icon
106
+ * @returns {?qui.icons.Icon}
107
+ */
108
+ prepareIcon(icon) {
109
+ if (!icon) {
110
+ return null
111
+ }
112
+
113
+ if (!(icon instanceof StockIcon)) {
114
+ return icon
115
+ }
116
+
117
+ if (this._clickable) {
118
+ icon = icon.alterDefault({
119
+ variant: 'interactive',
120
+ activeVariant: 'interactive',
121
+ selectedVariant: 'background'
122
+ })
123
+ }
124
+ else {
125
+ icon = icon.alterDefault({variant: 'foreground'})
126
+ }
127
+
128
+ return icon
129
+ }
130
+
131
+ _applyIcon(icon, element) {
132
+ icon = this.prepareIcon(icon)
133
+
134
+ if (icon) {
135
+ element.css('display', '')
136
+ icon.applyTo(element)
137
+ }
138
+ else {
139
+ element.css('display', 'none')
140
+ }
141
+
142
+ return icon
143
+ }
144
+
145
+ /**
146
+ * Return the label.
147
+ * @returns {String}
148
+ */
149
+ getLabel() {
150
+ return this._label
151
+ }
152
+
153
+ /**
154
+ * Update the label.
155
+ * @param {?String} label
156
+ */
157
+ setLabel(label) {
158
+ this._label = label || ''
159
+ if (this._labelElement) {
160
+ this._labelElement.html(label)
161
+ this._labelElement.css('display', label ? '' : 'none')
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Return the subscript label.
167
+ * @returns {?String}
168
+ */
169
+ getSubLabel() {
170
+ return this._subLabel
171
+ }
172
+
173
+ /**
174
+ * Update the subscript label.
175
+ * @param {?String} subLabel
176
+ */
177
+ setSubLabel(subLabel) {
178
+ this._subLabel = subLabel || ''
179
+ if (this._subLabelElement) {
180
+ this._subLabelElement.html(subLabel)
181
+ this._subLabelElement.css('display', subLabel ? '' : 'none')
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Tell if view is clickable.
187
+ * @returns {Boolean}
188
+ */
189
+ isClickable() {
190
+ return this._clickable
191
+ }
192
+
193
+ /**
194
+ * Set or clear the clickable flag.
195
+ * @param {Boolean} clickable
196
+ */
197
+ setClickable(clickable) {
198
+ this._clickable = clickable
199
+ this.getIconLabelContainer().toggleClass('qui-base-button', clickable)
200
+ this._applyIcon(this._icon, this._iconElement)
201
+ }
202
+
203
+ }
204
+
205
+ return IconLabelViewMixin
206
+
207
+ })
208
+
209
+
210
+ export default IconLabelViewMixin
@@ -0,0 +1,89 @@
1
+
2
+ import $ from '$qui/lib/jquery.module.js'
3
+
4
+ import {Mixin} from '$qui/base/mixwith.js'
5
+ import VisibilityManager from '$qui/utils/visibility-manager.js'
6
+
7
+
8
+ /** @lends qui.views.commonviews.ProgressViewMixin */
9
+ const ProgressViewMixin = Mixin((superclass = Object) => {
10
+
11
+ /**
12
+ * A view with progress indicator. Designed to be mixed together with {@link qui.views.ViewMixin}.
13
+ * @alias qui.views.commonviews.ProgressViewMixin
14
+ * @mixin
15
+ */
16
+ class ProgressViewMixin extends superclass {
17
+
18
+ /**
19
+ * @constructs
20
+ * @param {Boolean} [verticallyCentered] set to `true` to vertically center the progress widget
21
+ * @param {...*} args parent class parameters
22
+ */
23
+ constructor({verticallyCentered = false, ...args}) {
24
+ super(args)
25
+
26
+ this._glassDiv = $('<div></div>', {class: 'qui-progress-view-glass'})
27
+ this._glassVisibilityManager = new VisibilityManager({
28
+ element: this._glassDiv
29
+ })
30
+ this._glassVisibilityManager.hideElement()
31
+
32
+ this._progressWidget = $('<div></div>', {class: 'qui-progress-view-widget'}).progressdisk({radius: '2em'})
33
+ if (verticallyCentered) {
34
+ this._progressWidget.addClass('vertically-centered')
35
+ }
36
+ this._progressMessage = $('<span></span>', {class: 'qui-progress-view-message'})
37
+
38
+ this._glassDiv.append(this._progressWidget)
39
+ this._glassDiv.append(this._progressMessage)
40
+ }
41
+
42
+ initHTML(html) {
43
+ super.initHTML(html)
44
+
45
+ html.addClass('qui-progress-view')
46
+ html.append(this._glassDiv)
47
+ }
48
+
49
+ showProgress(percent) {
50
+ if (percent == null) {
51
+ percent = -1
52
+ }
53
+
54
+ this._glassVisibilityManager.showElement()
55
+ this._progressWidget.progressdisk('setValue', percent)
56
+
57
+ this.getHTML().addClass('has-progress')
58
+ }
59
+
60
+ hideProgress() {
61
+ this._glassVisibilityManager.hideElement()
62
+
63
+ this.getHTML().removeClass('has-progress')
64
+ }
65
+
66
+ /**
67
+ * Return the progress disk widget.
68
+ * @returns {jQuery}
69
+ */
70
+ getProgressWidget() {
71
+ return this._progressWidget
72
+ }
73
+
74
+ /**
75
+ * Set or clear view's progress message.
76
+ * @param {?String|jQuery} message
77
+ */
78
+ setProgressMessage(message) {
79
+ this._progressMessage.html(message)
80
+ }
81
+
82
+ }
83
+
84
+ return ProgressViewMixin
85
+
86
+ })
87
+
88
+
89
+ export default ProgressViewMixin