@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.
- package/.eslintignore +2 -0
- package/.eslintrc.json +492 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- package/.github/ISSUE_TEMPLATE/improvement_proposal.md +20 -0
- package/.github/workflows/main.yml +74 -0
- package/.pre-commit-config.yaml +8 -0
- package/LICENSE.txt +177 -0
- package/README.md +4 -0
- package/font/dejavusans-bold.woff +0 -0
- package/font/dejavusans-bolditalic.woff +0 -0
- package/font/dejavusans-italic.woff +0 -0
- package/font/dejavusans-regular.woff +0 -0
- package/img/qui-icons.svg +1937 -0
- package/js/base/base.js +47 -0
- package/js/base/condition-variable.js +92 -0
- package/js/base/errors.js +36 -0
- package/js/base/i18n.js +20 -0
- package/js/base/mixwith.js +135 -0
- package/js/base/require-js-compat.js +78 -0
- package/js/base/signal.js +91 -0
- package/js/base/singleton.js +66 -0
- package/js/base/timer.js +126 -0
- package/js/config.js +184 -0
- package/js/forms/common-fields/check-field.js +42 -0
- package/js/forms/common-fields/choice-buttons-field.js +30 -0
- package/js/forms/common-fields/color-combo-field.js +37 -0
- package/js/forms/common-fields/combo-field.js +108 -0
- package/js/forms/common-fields/common-fields.js +23 -0
- package/js/forms/common-fields/composite-field.js +132 -0
- package/js/forms/common-fields/custom-html-field.js +51 -0
- package/js/forms/common-fields/email-field.js +30 -0
- package/js/forms/common-fields/file-picker-field.js +46 -0
- package/js/forms/common-fields/jquery-ui-field.js +111 -0
- package/js/forms/common-fields/labels-field.js +69 -0
- package/js/forms/common-fields/numeric-field.js +39 -0
- package/js/forms/common-fields/password-field.js +28 -0
- package/js/forms/common-fields/phone-field.js +26 -0
- package/js/forms/common-fields/progress-disk-field.js +69 -0
- package/js/forms/common-fields/push-button-field.js +138 -0
- package/js/forms/common-fields/slider-field.js +51 -0
- package/js/forms/common-fields/text-area-field.js +34 -0
- package/js/forms/common-fields/text-field.js +89 -0
- package/js/forms/common-fields/up-down-field.js +85 -0
- package/js/forms/common-forms/common-forms.js +16 -0
- package/js/forms/common-forms/options-form.js +77 -0
- package/js/forms/common-forms/page-form.js +115 -0
- package/js/forms/form-button.js +202 -0
- package/js/forms/form-field.js +1183 -0
- package/js/forms/form.js +1181 -0
- package/js/forms/forms.js +68 -0
- package/js/global-glass.js +100 -0
- package/js/icons/default-stock.js +173 -0
- package/js/icons/icon.js +64 -0
- package/js/icons/icons.js +16 -0
- package/js/icons/multi-state-sprites-icon.js +362 -0
- package/js/icons/stock-icon.js +219 -0
- package/js/icons/stock.js +98 -0
- package/js/icons/stocks.js +57 -0
- package/js/index.js +232 -0
- package/js/lib/jquery.longpress.js +79 -0
- package/js/lib/jquery.module.js +4 -0
- package/js/lib/logger.module.js +4 -0
- package/js/lib/pep.module.js +4 -0
- package/js/lists/common-items/common-items.js +5 -0
- package/js/lists/common-items/icon-label-list-item.js +86 -0
- package/js/lists/common-lists/common-lists.js +5 -0
- package/js/lists/common-lists/page-list.js +53 -0
- package/js/lists/list-item.js +147 -0
- package/js/lists/list.js +636 -0
- package/js/lists/lists.js +26 -0
- package/js/main-ui/main-ui.js +64 -0
- package/js/main-ui/menu-bar.js +144 -0
- package/js/main-ui/options-bar.js +181 -0
- package/js/main-ui/status.js +185 -0
- package/js/main-ui/top-bar.js +59 -0
- package/js/messages/common-message-forms/common-message-forms.js +7 -0
- package/js/messages/common-message-forms/confirm-message-form.js +81 -0
- package/js/messages/common-message-forms/simple-message-form.js +67 -0
- package/js/messages/common-message-forms/sticky-simple-message-form.js +27 -0
- package/js/messages/message-form.js +107 -0
- package/js/messages/messages.js +21 -0
- package/js/messages/sticky-modal-page.js +98 -0
- package/js/messages/sticky-modal-progress-message.js +27 -0
- package/js/messages/toast.js +164 -0
- package/js/navigation.js +654 -0
- package/js/pages/breadcrumbs.js +124 -0
- package/js/pages/common-pages/common-pages.js +6 -0
- package/js/pages/common-pages/modal-progress-page.js +83 -0
- package/js/pages/common-pages/structured-page.js +46 -0
- package/js/pages/page.js +1018 -0
- package/js/pages/pages-context.js +154 -0
- package/js/pages/pages.js +252 -0
- package/js/pwa.js +337 -0
- package/js/sections/section.js +612 -0
- package/js/sections/sections.js +300 -0
- package/js/tables/common-cells/common-cells.js +7 -0
- package/js/tables/common-cells/icon-label-table-cell.js +68 -0
- package/js/tables/common-cells/push-button-table-cell.js +133 -0
- package/js/tables/common-cells/simple-table-cell.js +37 -0
- package/js/tables/common-tables/common-tables.js +5 -0
- package/js/tables/common-tables/page-table.js +55 -0
- package/js/tables/table-cell.js +198 -0
- package/js/tables/table-row.js +126 -0
- package/js/tables/table.js +492 -0
- package/js/tables/tables.js +36 -0
- package/js/theme.js +304 -0
- package/js/utils/ajax.js +126 -0
- package/js/utils/array.js +194 -0
- package/js/utils/colors.js +445 -0
- package/js/utils/cookies.js +65 -0
- package/js/utils/crypto.js +439 -0
- package/js/utils/css.js +234 -0
- package/js/utils/date.js +300 -0
- package/js/utils/files.js +27 -0
- package/js/utils/gestures.js +165 -0
- package/js/utils/html.js +76 -0
- package/js/utils/misc.js +81 -0
- package/js/utils/object.js +324 -0
- package/js/utils/promise.js +49 -0
- package/js/utils/string.js +192 -0
- package/js/utils/url.js +187 -0
- package/js/utils/utils.js +3 -0
- package/js/utils/visibility-manager.js +211 -0
- package/js/views/common-views/common-views.js +7 -0
- package/js/views/common-views/icon-label-view.js +210 -0
- package/js/views/common-views/progress-view.js +89 -0
- package/js/views/common-views/structured-view.js +368 -0
- package/js/views/view.js +467 -0
- package/js/views/views.js +3 -0
- package/js/widgets/base-widget.js +23 -0
- package/js/widgets/common-widgets/check-button.js +109 -0
- package/js/widgets/common-widgets/choice-buttons.js +322 -0
- package/js/widgets/common-widgets/color-combo.js +104 -0
- package/js/widgets/common-widgets/combo.js +645 -0
- package/js/widgets/common-widgets/common-widgets.js +17 -0
- package/js/widgets/common-widgets/email-input.js +7 -0
- package/js/widgets/common-widgets/file-picker.js +133 -0
- package/js/widgets/common-widgets/labels.js +132 -0
- package/js/widgets/common-widgets/numeric-input.js +49 -0
- package/js/widgets/common-widgets/password-input.js +91 -0
- package/js/widgets/common-widgets/phone-input.js +7 -0
- package/js/widgets/common-widgets/progress-disk.js +174 -0
- package/js/widgets/common-widgets/push-button.js +155 -0
- package/js/widgets/common-widgets/slider.js +455 -0
- package/js/widgets/common-widgets/text-area.js +52 -0
- package/js/widgets/common-widgets/text-input.js +174 -0
- package/js/widgets/common-widgets/up-down.js +351 -0
- package/js/widgets/widgets.js +57 -0
- package/js/window.js +557 -0
- package/jsdoc.conf.json +20 -0
- package/less/base.less +123 -0
- package/less/forms/common-fields.less +101 -0
- package/less/forms/common-forms.less +5 -0
- package/less/forms/form-button.less +21 -0
- package/less/forms/form-field.less +266 -0
- package/less/forms/form.less +131 -0
- package/less/global-glass.less +64 -0
- package/less/icon-label-view.less +82 -0
- package/less/icons.less +144 -0
- package/less/lists.less +105 -0
- package/less/main-ui.less +328 -0
- package/less/messages.less +189 -0
- package/less/no-effects.less +24 -0
- package/less/pages/breadcrumbs.less +98 -0
- package/less/pages/common-pages.less +36 -0
- package/less/pages/page.less +70 -0
- package/less/progress-view.less +51 -0
- package/less/stock-icons.less +43 -0
- package/less/structured-view.less +245 -0
- package/less/tables.less +84 -0
- package/less/theme-dark.less +133 -0
- package/less/theme-light.less +132 -0
- package/less/theme.less +419 -0
- package/less/visibility-manager.less +11 -0
- package/less/widgets/check-button.less +96 -0
- package/less/widgets/choice-buttons.less +160 -0
- package/less/widgets/color-combo.less +33 -0
- package/less/widgets/combo.less +230 -0
- package/less/widgets/common-buttons.less +120 -0
- package/less/widgets/common.less +24 -0
- package/less/widgets/input.less +258 -0
- package/less/widgets/labels.less +81 -0
- package/less/widgets/progress-disk.less +70 -0
- package/less/widgets/slider.less +199 -0
- package/less/widgets/updown.less +115 -0
- package/less/widgets/various.less +36 -0
- package/package.json +47 -0
- package/pyproject.toml +45 -0
- package/qui/__init__.py +110 -0
- package/qui/constants.py +1 -0
- package/qui/exceptions.py +2 -0
- package/qui/j2template.py +71 -0
- package/qui/settings.py +60 -0
- package/qui/templates/manifest.json +25 -0
- package/qui/templates/qui.html +126 -0
- package/qui/templates/service-worker.js +188 -0
- package/qui/web/__init__.py +0 -0
- package/qui/web/tornado.py +220 -0
- package/scripts/postinstall.sh +10 -0
- package/webpack/webpack-adjust-css-urls-loader.js +36 -0
- 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
|
+
}
|
package/js/utils/css.js
ADDED
|
@@ -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
|
+
}
|