@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,439 @@
1
+ /**
2
+ * @namespace qui.utils.crypto
3
+ */
4
+
5
+ import * as ArrayUtils from '$qui/utils/array.js'
6
+ import * as StringUtils from '$qui/utils/string.js'
7
+
8
+
9
+ const HEX_CHARS = '0123456789abcdef'.split('')
10
+
11
+
12
+ /**
13
+ * Convert a hex representation of binary data into string representation.
14
+ * @alias qui.utils.crypto.hex2str
15
+ * @param {String} hex
16
+ * @returns {String}
17
+ */
18
+ export function hex2str(hex) {
19
+ let s = ''
20
+ for (let i = 0; i < hex.length / 2; i++) {
21
+ s += String.fromCharCode(parseInt(hex.substring(2 * i, 2 * i + 2), 16))
22
+ }
23
+
24
+ return s
25
+ }
26
+
27
+ /**
28
+ * Convert a string representation of binary data into hex representation.
29
+ * @alias qui.utils.crypto.str2hex
30
+ * @param {String} bin
31
+ * @returns {String}
32
+ */
33
+ export function str2hex(bin) {
34
+ return bin.split('').map(function (c) {
35
+ let n = c.charCodeAt(0)
36
+ return HEX_CHARS[(n >> 4) & 0x0F] + HEX_CHARS[n & 0x0F]
37
+ }).join('')
38
+ }
39
+
40
+ /**
41
+ * Convert an array representation of binary data into string representation.
42
+ * @alias qui.utils.crypto.arr2str
43
+ * @param {Number[]} arr
44
+ * @returns {String}
45
+ */
46
+ export function arr2str(arr) {
47
+ return arr.map(n => String.fromCharCode(n)).join('')
48
+ }
49
+
50
+ /**
51
+ * Convert a string representation of binary data into array representation.
52
+ * @alias qui.utils.crypto.str2arr
53
+ * @param {String} str
54
+ * @returns {Number[]}
55
+ */
56
+ export function str2arr(str) {
57
+ return str.split('').map(c => c.charCodeAt(0))
58
+ }
59
+
60
+ /**
61
+ * Convert a base64 representation of binary data into string representation.
62
+ * @alias qui.utils.crypto.b642str
63
+ * @param {String} b64
64
+ * @returns {String}
65
+ */
66
+ export function b642str(b64) {
67
+ b64 = (`${b64}===`).slice(0, b64.length + (b64.length % 4))
68
+ b64 = b64.replace(/-/g, '+').replace(/_/g, '/')
69
+
70
+ return window.atob(b64)
71
+ }
72
+
73
+ /**
74
+ * Convert a string representation of binary data into base64 representation.
75
+ * @alias qui.utils.crypto.str2b64
76
+ * @param {String} str
77
+ * @returns {String}
78
+ */
79
+ export function str2b64(str) {
80
+ return window.btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
81
+ }
82
+
83
+
84
+ /**
85
+ * Generate a random token of a given length from a specified set of characters.
86
+ * @param {String} chars allowed characters (e.g. `"a-zA-Z0-9"`).
87
+ * @param {Number} length desired token length
88
+ * @returns {String} the generated token
89
+ */
90
+ export function makeToken(chars, length) {
91
+ /* Preprocess chars */
92
+ let c, i, j, bcc, ecc, range, token = ''
93
+ for (i = 1; i < chars.length - 1; i++) {
94
+ c = chars.charAt(i)
95
+ if (c === '-') {
96
+ bcc = chars.charCodeAt(i - 1)
97
+ ecc = chars.charCodeAt(i + 1)
98
+
99
+ /* Generate char range */
100
+ range = ''
101
+ for (j = bcc; j <= ecc; j++) {
102
+ range += String.fromCharCode(j)
103
+ }
104
+
105
+ /* Update chars with range */
106
+ chars = chars.substring(0, i - 1) + range + chars.substring(i + 2)
107
+
108
+ i += range.length - 1
109
+ }
110
+ }
111
+
112
+ /* Create next() function */
113
+ let next
114
+ if (window.crypto && window.crypto.getRandomValues) {
115
+ next = function () {
116
+ return window.crypto.getRandomValues(new Uint8Array(32))
117
+ }
118
+ }
119
+ else { /* Crypto functions not available */
120
+ next = function () {
121
+ return ArrayUtils.range(0, 32).map(() => Math.floor(Math.random() * 255))
122
+ }
123
+ }
124
+
125
+ while (token.length < length) {
126
+ let nextBytes = next()
127
+ for (i = 0; i < nextBytes.length; i++) {
128
+ c = String.fromCharCode(nextBytes[i])
129
+ if (!chars.includes(c)) {
130
+ continue
131
+ }
132
+
133
+ token += c
134
+ if (token.length >= length) {
135
+ break
136
+ }
137
+ }
138
+ }
139
+
140
+ return token
141
+ }
142
+
143
+
144
+ /**
145
+ * A SHA256 digest implementation.
146
+ * @alias qui.utils.crypto.SHA256
147
+ */
148
+ export class SHA256 {
149
+
150
+ static _SHIFT = [24, 16, 8, 0]
151
+ static _EXTRA = [-2147483648, 8388608, 32768, 128]
152
+ static _K = [
153
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
154
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
155
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
156
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
157
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
158
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
159
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
160
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
161
+ ]
162
+
163
+
164
+ /**
165
+ * @constructs
166
+ * @param {String|Number[]} [data] the data to hash
167
+ */
168
+ constructor(data = null) {
169
+ this._blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
170
+
171
+ this._h0 = 0x6a09e667
172
+ this._h1 = 0xbb67ae85
173
+ this._h2 = 0x3c6ef372
174
+ this._h3 = 0xa54ff53a
175
+ this._h4 = 0x510e527f
176
+ this._h5 = 0x9b05688c
177
+ this._h6 = 0x1f83d9ab
178
+ this._h7 = 0x5be0cd19
179
+
180
+ this._block = this.start = this.bytes = this.hBytes = 0
181
+ this._finalized = false
182
+ this._hashed = false
183
+ this._first = true
184
+
185
+ if (data != null) {
186
+ this.update(data)
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Feed more data.
192
+ * @param {String|Number[]} data
193
+ * @returns {qui.utils.crypto.SHA256} this object
194
+ */
195
+ update(data) {
196
+ if (this._finalized) {
197
+ return this
198
+ }
199
+
200
+ if (typeof data === 'string') {
201
+ data = str2arr(StringUtils.toUTF8(data))
202
+ }
203
+
204
+ let index = 0, i, length = data.length, blocks = this._blocks
205
+
206
+ while (index < length) {
207
+ if (this._hashed) {
208
+ this._hashed = false
209
+ blocks[0] = this._block
210
+ blocks[16] = blocks[1] = blocks[2] = blocks[3] =
211
+ blocks[4] = blocks[5] = blocks[6] = blocks[7] =
212
+ blocks[8] = blocks[9] = blocks[10] = blocks[11] =
213
+ blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0
214
+ }
215
+
216
+ for (i = this.start; index < length && i < 64; ++index) {
217
+ blocks[i >> 2] |= data[index] << SHA256._SHIFT[i++ & 3]
218
+ }
219
+
220
+ this.lastByteIndex = i
221
+ this.bytes += i - this.start
222
+ if (i >= 64) {
223
+ this._block = blocks[16]
224
+ this.start = i - 64
225
+ this._hash()
226
+ this._hashed = true
227
+ }
228
+ else {
229
+ this.start = i
230
+ }
231
+ }
232
+
233
+ if (this.bytes > 4294967295) {
234
+ this.hBytes += this.bytes / 4294967296 << 0
235
+ this.bytes = this.bytes % 4294967296
236
+ }
237
+
238
+ return this
239
+ }
240
+
241
+ /**
242
+ * Return the array representation of the hash digest.
243
+ * @returns {Number[]}
244
+ */
245
+ digest() {
246
+ this._finalize()
247
+
248
+ let h0 = this._h0, h1 = this._h1, h2 = this._h2, h3 = this._h3, h4 = this._h4, h5 = this._h5,
249
+ h6 = this._h6, h7 = this._h7
250
+
251
+ return [
252
+ (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, h0 & 0xFF,
253
+ (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, h1 & 0xFF,
254
+ (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, h2 & 0xFF,
255
+ (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, h3 & 0xFF,
256
+ (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, h4 & 0xFF,
257
+ (h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, h5 & 0xFF,
258
+ (h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, h6 & 0xFF,
259
+ (h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, h7 & 0xFF
260
+ ]
261
+ }
262
+
263
+ /**
264
+ * Return the hex representation of the hash digest.
265
+ * @returns {String}
266
+ */
267
+ toString() {
268
+ return str2hex(arr2str(this.digest()))
269
+ }
270
+
271
+ _hash() {
272
+ let a = this._h0, b = this._h1, c = this._h2, d = this._h3, e = this._h4, f = this._h5, g = this._h6,
273
+ h = this._h7, blocks = this._blocks, s0, s1, maj, t1, t2, ch, ab, da, cd, bc
274
+
275
+ for (let j = 16; j < 64; ++j) {
276
+ /* Rotate right */
277
+ t1 = blocks[j - 15]
278
+ s0 = ((t1 >>> 7) | (t1 << 25)) ^ ((t1 >>> 18) | (t1 << 14)) ^ (t1 >>> 3)
279
+ t1 = blocks[j - 2]
280
+ s1 = ((t1 >>> 17) | (t1 << 15)) ^ ((t1 >>> 19) | (t1 << 13)) ^ (t1 >>> 10)
281
+ blocks[j] = blocks[j - 16] + s0 + blocks[j - 7] + s1 << 0
282
+ }
283
+
284
+ bc = b & c
285
+ for (let j = 0; j < 64; j += 4) {
286
+ if (this._first) {
287
+ ab = 704751109
288
+ t1 = blocks[0] - 210244248
289
+ h = t1 - 1521486534 << 0
290
+ d = t1 + 143694565 << 0
291
+ this._first = false
292
+ }
293
+ else {
294
+ s0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10))
295
+ s1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7))
296
+ ab = a & b
297
+ maj = ab ^ (a & c) ^ bc
298
+ ch = (e & f) ^ (~e & g)
299
+ t1 = h + s1 + ch + SHA256._K[j] + blocks[j]
300
+ t2 = s0 + maj
301
+ h = d + t1 << 0
302
+ d = t1 + t2 << 0
303
+ }
304
+
305
+ s0 = ((d >>> 2) | (d << 30)) ^ ((d >>> 13) | (d << 19)) ^ ((d >>> 22) | (d << 10))
306
+ s1 = ((h >>> 6) | (h << 26)) ^ ((h >>> 11) | (h << 21)) ^ ((h >>> 25) | (h << 7))
307
+ da = d & a
308
+ maj = da ^ (d & b) ^ ab
309
+ ch = (h & e) ^ (~h & f)
310
+ t1 = g + s1 + ch + SHA256._K[j + 1] + blocks[j + 1]
311
+ t2 = s0 + maj
312
+ g = c + t1 << 0
313
+ c = t1 + t2 << 0
314
+ s0 = ((c >>> 2) | (c << 30)) ^ ((c >>> 13) | (c << 19)) ^ ((c >>> 22) | (c << 10))
315
+ s1 = ((g >>> 6) | (g << 26)) ^ ((g >>> 11) | (g << 21)) ^ ((g >>> 25) | (g << 7))
316
+ cd = c & d
317
+ maj = cd ^ (c & a) ^ da
318
+ ch = (g & h) ^ (~g & e)
319
+ t1 = f + s1 + ch + SHA256._K[j + 2] + blocks[j + 2]
320
+ t2 = s0 + maj
321
+ f = b + t1 << 0
322
+ b = t1 + t2 << 0
323
+ s0 = ((b >>> 2) | (b << 30)) ^ ((b >>> 13) | (b << 19)) ^ ((b >>> 22) | (b << 10))
324
+ s1 = ((f >>> 6) | (f << 26)) ^ ((f >>> 11) | (f << 21)) ^ ((f >>> 25) | (f << 7))
325
+ bc = b & c
326
+ maj = bc ^ (b & d) ^ cd
327
+ ch = (f & g) ^ (~f & h)
328
+ t1 = e + s1 + ch + SHA256._K[j + 3] + blocks[j + 3]
329
+ t2 = s0 + maj
330
+ e = a + t1 << 0
331
+ a = t1 + t2 << 0
332
+ }
333
+
334
+ this._h0 = this._h0 + a << 0
335
+ this._h1 = this._h1 + b << 0
336
+ this._h2 = this._h2 + c << 0
337
+ this._h3 = this._h3 + d << 0
338
+ this._h4 = this._h4 + e << 0
339
+ this._h5 = this._h5 + f << 0
340
+ this._h6 = this._h6 + g << 0
341
+ this._h7 = this._h7 + h << 0
342
+ }
343
+
344
+ _finalize() {
345
+ if (this._finalized) {
346
+ return
347
+ }
348
+
349
+ this._finalized = true
350
+ let blocks = this._blocks, i = this.lastByteIndex
351
+
352
+ blocks[16] = this._block
353
+ blocks[i >> 2] |= SHA256._EXTRA[i & 3]
354
+ this._block = blocks[16]
355
+ if (i >= 56) {
356
+ if (!this._hashed) {
357
+ this._hash()
358
+ }
359
+ blocks[0] = this._block
360
+ blocks[16] = blocks[1] = blocks[2] = blocks[3] =
361
+ blocks[4] = blocks[5] = blocks[6] = blocks[7] =
362
+ blocks[8] = blocks[9] = blocks[10] = blocks[11] =
363
+ blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0
364
+ }
365
+
366
+ blocks[14] = this.hBytes << 3 | this.bytes >>> 29
367
+ blocks[15] = this.bytes << 3
368
+
369
+ this._hash()
370
+ }
371
+
372
+ }
373
+
374
+
375
+ /**
376
+ * A SHA256 HMAC implementation.
377
+ * @alias qui.utils.crypto.HMACSHA256
378
+ */
379
+
380
+ export class HMACSHA256 {
381
+
382
+ /**
383
+ * @constructs
384
+ * @param {String|Number[]} key the HMAC key
385
+ * @param {String|Number[]} [data] the data to hash
386
+ */
387
+ constructor(key, data = null) {
388
+ if (typeof key === 'string') {
389
+ key = str2arr(StringUtils.toUTF8(key))
390
+ }
391
+
392
+ /* If key is larger than one block, we have to hash it first */
393
+ if (key.length > 64) {
394
+ key = new SHA256(key).digest()
395
+ }
396
+
397
+ let oKeyPad = [], iKeyPad = []
398
+ for (let i = 0; i < 64; i++) {
399
+ let b = key[i] || 0
400
+ oKeyPad[i] = 0x5c ^ b
401
+ iKeyPad[i] = 0x36 ^ b
402
+ }
403
+
404
+ this._innerHash = new SHA256(iKeyPad)
405
+ if (data) {
406
+ this._innerHash.update(data)
407
+ }
408
+
409
+ this._oKeyPad = oKeyPad
410
+ }
411
+
412
+ /**
413
+ * Feed more data.
414
+ * @param {String|Number[]} data
415
+ * @returns {qui.utils.crypto.HMACSHA256} this object
416
+ */
417
+ update(data) {
418
+ this._innerHash.update(data)
419
+
420
+ return this
421
+ }
422
+
423
+ /**
424
+ * Return the array representation of the hash digest.
425
+ * @returns {Number[]}
426
+ */
427
+ digest() {
428
+ return new SHA256(this._oKeyPad).update(this._innerHash.digest()).digest()
429
+ }
430
+
431
+ /**
432
+ * Return the hex representation of the hash digest.
433
+ * @returns {String}
434
+ */
435
+ toString() {
436
+ return str2hex(arr2str(this.digest()))
437
+ }
438
+
439
+ }
@@ -0,0 +1,234 @@
1
+ /**
2
+ * @namespace qui.utils.css
3
+ */
4
+
5
+ import $ from '$qui/lib/jquery.module.js'
6
+
7
+ import * as Window from '$qui/window.js'
8
+
9
+
10
+ const CSS_VALUE_RE = new RegExp('([\\d.]+)(.*)')
11
+
12
+ let customStyleElement = null
13
+ let cachedBodyEmPx = null
14
+
15
+
16
+ function getCustomStyleElement() {
17
+ if (!customStyleElement) {
18
+ customStyleElement = createStyleElement()
19
+ }
20
+
21
+ return customStyleElement
22
+ }
23
+
24
+
25
+ /**
26
+ * Create an empty style element and add it to document head.
27
+ * @alias qui.utils.css.createStyleElement
28
+ * @returns {HTMLStyleElement}
29
+ */
30
+ export function createStyleElement() {
31
+ let style = document.createElement('style')
32
+ style.type = 'text/css'
33
+ style.appendChild(document.createTextNode('')) /* Webkit hack */
34
+
35
+ let head = document.getElementsByTagName('head')[0]
36
+ head.appendChild(style)
37
+
38
+ return style
39
+ }
40
+
41
+ /**
42
+ * Return the link element from the DOM corresponding to a given CSS file.
43
+ * @alias qui.utils.css.getStyleLinkElement
44
+ * @param {String} filename
45
+ * @returns {?HTMLLinkElement}
46
+ */
47
+ export function getStyleLinkElement(filename) {
48
+ let links = [...document.getElementsByTagName('link')]
49
+ return links.find(l => l.href.endsWith(filename)) || null
50
+ }
51
+
52
+ /**
53
+ * Create and add a style rule.
54
+ * @alias qui.utils.css.addRule
55
+ * @param {String} selector a CSS selector (e.g. `"div.my-class > div.my-sub-class"`)
56
+ * @param {CSSStyleDeclaration|String} style style declaration (e.g. `"text-align: left; padding: 5px;"`)
57
+ * @param {HTMLStyleElement} [styleElement] an optional style element to add the rule to; by default, rules are added to
58
+ * a common custom style element
59
+ * @returns {Number} the index of the rule within the style element rules list
60
+ */
61
+ export function addRule(selector, style, styleElement = null) {
62
+ if (style instanceof window.CSSStyleDeclaration) {
63
+ style = style.cssText
64
+ }
65
+
66
+ styleElement = styleElement || getCustomStyleElement()
67
+ return styleElement.sheet.insertRule(`${selector} { ${style} }`, styleElement.sheet.cssRules.length)
68
+ }
69
+
70
+ /**
71
+ * Delete a style rule that matches a given selector.
72
+ * @alias qui.utils.css.delRule
73
+ * @param {String} selector a CSS selector (e.g. `"div.my-class > div.my-sub-class"`)
74
+ * @param {HTMLStyleElement} [styleElement] an optional style element to restrict the search to
75
+ */
76
+ export function delRule(selector, styleElement = null) {
77
+ let styleElements
78
+
79
+ if (styleElement) {
80
+ styleElements = [styleElement]
81
+ }
82
+ else {
83
+ /* Look through all existing style elements */
84
+ styleElements = [...document.getElementsByTagName('style')]
85
+ }
86
+
87
+ styleElements.forEach(function (styleElement) {
88
+ for (let i = 0; i < styleElement.sheet.cssRules.length; i++) {
89
+ let rule = styleElement.sheet.cssRules[i]
90
+ if (rule.selectorText === selector) {
91
+ styleElement.sheet.deleteRule(i--)
92
+ }
93
+ }
94
+ })
95
+ }
96
+
97
+ /**
98
+ * Find all style rules that match a selector regular expression.
99
+ * @alias qui.utils.css.findRules
100
+ * @param {String|RegExp} selectorRe
101
+ * @returns {Object[]} a list of objects with `selector` and `declaration`
102
+ */
103
+ export function findRules(selectorRe) {
104
+ if (!(selectorRe instanceof RegExp)) {
105
+ selectorRe = new RegExp(selectorRe)
106
+ }
107
+
108
+ let matchedRules = []
109
+ let styleSheets = [...document.styleSheets]
110
+ styleSheets.forEach(function (sheet) {
111
+ if (sheet.disabled) {
112
+ return
113
+ }
114
+
115
+ let rules = [...sheet.cssRules]
116
+ let mRules = rules.filter(r => r.selectorText && r.selectorText.match(selectorRe)).map(function (rule) {
117
+ return {
118
+ selector: rule.selectorText,
119
+ declaration: rule.cssText.substring(rule.selectorText.length).trim()
120
+ }
121
+ })
122
+
123
+ matchedRules = matchedRules.concat(mRules)
124
+ })
125
+
126
+ return matchedRules
127
+ }
128
+
129
+ /**
130
+ * Perform an add operation on a CSS value with unit, preserving the unit.
131
+ * @alias qui.utils.css.addValue
132
+ * @param {String} value the CSS value (e.g. `"15px"`)
133
+ * @param {Number|String} operand the number to add
134
+ * @returns {String}
135
+ */
136
+ export function addValue(value, operand) {
137
+ let parts = value.toString().match(CSS_VALUE_RE)
138
+ if (!parts) {
139
+ return value
140
+ }
141
+
142
+ return parseFloat(parts[1]) + parseFloat(operand) + parts[2]
143
+ }
144
+
145
+ /**
146
+ * Perform a subtract operation on a CSS value with unit, preserving the unit.
147
+ * @alias qui.utils.css.subValue
148
+ * @param {String} value the CSS value (e.g. `"15px"`)
149
+ * @param {Number|String} operand the number to subtract
150
+ * @returns {String}
151
+ */
152
+ export function subValue(value, operand) {
153
+ let parts = value.toString().match(CSS_VALUE_RE)
154
+ if (!parts) {
155
+ return value
156
+ }
157
+
158
+ return parseFloat(parts[1]) - parseFloat(operand) + parts[2]
159
+ }
160
+
161
+ /**
162
+ * Perform a multiply operation on a CSS value with unit, preserving the unit.
163
+ * @alias qui.utils.css.mulValue
164
+ * @param {String} value the CSS value (e.g. `"15px"`)
165
+ * @param {Number|String} operand the number to multiply by
166
+ * @returns {String}
167
+ */
168
+ export function mulValue(value, operand) {
169
+ let parts = value.toString().match(CSS_VALUE_RE)
170
+ if (!parts) {
171
+ return value
172
+ }
173
+
174
+ return parseFloat(parts[1]) * parseFloat(operand) + parts[2]
175
+ }
176
+
177
+ /**
178
+ * Perform a divide operation on a CSS value with unit, preserving the unit.
179
+ * @alias qui.utils.css.divValue
180
+ * @param {String} value the CSS value (e.g. `"15px"`)
181
+ * @param {Number|String} operand the number to divide by
182
+ * @returns {String}
183
+ */
184
+ export function divValue(value, operand) {
185
+ let parts = value.toString().match(CSS_VALUE_RE)
186
+ if (!parts) {
187
+ return value
188
+ }
189
+
190
+ return parseFloat(parts[1]) / parseFloat(operand) + parts[2]
191
+ }
192
+
193
+ /**
194
+ * Convert *em* units to pixel units.
195
+ * @alias qui.utils.css.em2px
196
+ * @param {Number} em
197
+ * @param {jQuery} [elem] optional HTML element; document's body is used by default
198
+ * @returns {Number}
199
+ */
200
+ export function em2px(em, elem = Window.$body) {
201
+ if (elem === Window.$body && cachedBodyEmPx != null) {
202
+ return cachedBodyEmPx * em
203
+ }
204
+
205
+ let dummyDiv = $('<div></div>', {style: 'width: 1em'})
206
+ elem.append(dummyDiv)
207
+
208
+ let clientWidth = dummyDiv[0].clientWidth
209
+ let width = clientWidth * em
210
+ dummyDiv.remove()
211
+
212
+ if (elem === Window.$body) {
213
+ cachedBodyEmPx = clientWidth
214
+ }
215
+
216
+ return width
217
+ }
218
+
219
+ /**
220
+ * Convert pixel units to *em* units.
221
+ * @alias qui.utils.css.px2em
222
+ * @param {Number} px
223
+ * @param {jQuery} [elem] optional HTML element; document's body is used by default
224
+ * @returns {Number}
225
+ */
226
+ export function px2em(px, elem = Window.$body) {
227
+ let dummyDiv = $('<div style="width: 1em"></div>')
228
+ elem.append(dummyDiv)
229
+
230
+ let width = px / dummyDiv.width()
231
+ dummyDiv.remove()
232
+
233
+ return width
234
+ }