@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
package/js/pwa.js
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @namespace qui.pwa
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import Logger from '$qui/lib/logger.module.js'
|
|
6
|
+
|
|
7
|
+
import ConditionVariable from '$qui/base/condition-variable.js'
|
|
8
|
+
import {AssertionError} from '$qui/base/errors.js'
|
|
9
|
+
import Signal from '$qui/base/signal.js'
|
|
10
|
+
import Config from '$qui/config.js'
|
|
11
|
+
import * as QUI from '$qui/index.js'
|
|
12
|
+
import * as Navigation from '$qui/navigation.js'
|
|
13
|
+
import * as Theme from '$qui/theme.js'
|
|
14
|
+
import {appendBuildHash} from '$qui/utils/misc.js'
|
|
15
|
+
import * as PromiseUtils from '$qui/utils/promise.js'
|
|
16
|
+
import URL from '$qui/utils/url.js'
|
|
17
|
+
import * as Window from '$qui/window.js'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
const SERVICE_WORKER_SCRIPT = 'service-worker.js'
|
|
21
|
+
const SERVICE_WORKER_MESSAGE_ACTIVATE = 'qui-activate'
|
|
22
|
+
|
|
23
|
+
const MANIFEST_FILE = 'manifest.json'
|
|
24
|
+
|
|
25
|
+
const logger = Logger.get('qui.pwa')
|
|
26
|
+
|
|
27
|
+
let manifestParams = {}
|
|
28
|
+
let serviceWorker = null
|
|
29
|
+
let serviceWorkerUpdateCalled = false /* duplicate call protection */
|
|
30
|
+
let installElementHandler = null
|
|
31
|
+
let installResponseHandler = null
|
|
32
|
+
let installPrompted = false
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A condition that is fulfilled as soon as this client becomes controlled by a service worker.
|
|
36
|
+
* The condition is passed the service worker as parameter.
|
|
37
|
+
* @type {qui.base.ConditionVariable}
|
|
38
|
+
*/
|
|
39
|
+
export let whenServiceWorkerReady = new ConditionVariable()
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Emitted whenever a message is received from the controlling service worker. Handlers are called with the following
|
|
43
|
+
* parameters:
|
|
44
|
+
* * `serviceWorker`, the new controlling service worker
|
|
45
|
+
* * `message`, the incoming message
|
|
46
|
+
* @type {qui.base.Signal}
|
|
47
|
+
*/
|
|
48
|
+
export const serviceWorkerMessageSignal = new Signal()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
function handleServiceWorkerUpdate(sw, updateHandler) {
|
|
52
|
+
if (serviceWorkerUpdateCalled) {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
serviceWorkerUpdateCalled = true
|
|
57
|
+
|
|
58
|
+
logger.info('service worker updated')
|
|
59
|
+
|
|
60
|
+
if (updateHandler) {
|
|
61
|
+
let result = updateHandler(sw)
|
|
62
|
+
if (result) {
|
|
63
|
+
if (result.then) { /* A promise */
|
|
64
|
+
result.then(function () {
|
|
65
|
+
provisionServiceWorker(sw)
|
|
66
|
+
}).catch(() => {})
|
|
67
|
+
}
|
|
68
|
+
else { /* Assuming a true value */
|
|
69
|
+
provisionServiceWorker(sw)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
provisionServiceWorker(sw)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function handleServiceWorkerReady(sw) {
|
|
79
|
+
logger.info('service worker is ready')
|
|
80
|
+
serviceWorker = sw
|
|
81
|
+
whenServiceWorkerReady.fulfill(serviceWorker)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function provisionServiceWorker(sw) {
|
|
85
|
+
logger.info('provisioning service worker')
|
|
86
|
+
let message = {
|
|
87
|
+
type: SERVICE_WORKER_MESSAGE_ACTIVATE,
|
|
88
|
+
config: Config.dump()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
sw.postMessage(message)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function handleServiceWorkerMessage(message) {
|
|
95
|
+
logger.debug(`received service worker message: ${message.data}`)
|
|
96
|
+
serviceWorkerMessageSignal.emit(serviceWorker, message.data)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Tell if service workers are supported.
|
|
102
|
+
* @returns {Boolean}
|
|
103
|
+
*/
|
|
104
|
+
export function isServiceWorkerSupported() {
|
|
105
|
+
return 'serviceWorker' in navigator
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Enable the service worker functionality.
|
|
110
|
+
*
|
|
111
|
+
* @param {String} [url] URL at which the service worker lives; {@link qui.config.navigationBasePrefix} +
|
|
112
|
+
* `"/service-worker.js"` will be used by default
|
|
113
|
+
* @param {Function} [updateHandler] a function to be called when the service worker is updated; should return a promise
|
|
114
|
+
* that will be used to control the activation of the new service worker
|
|
115
|
+
* @alias qui.pwa.enableServiceWorker
|
|
116
|
+
*/
|
|
117
|
+
export function enableServiceWorker(url = null, updateHandler = null) {
|
|
118
|
+
if (!('serviceWorker' in navigator)) {
|
|
119
|
+
throw new Error('service workers not supported')
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!url) {
|
|
123
|
+
url = `${Config.navigationBasePrefix}/${SERVICE_WORKER_SCRIPT}`
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
url = appendBuildHash(url)
|
|
127
|
+
if (Config.debug) {
|
|
128
|
+
url += '&debug=true'
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
navigator.serviceWorker.addEventListener('message', handleServiceWorkerMessage)
|
|
132
|
+
|
|
133
|
+
let refreshing = false
|
|
134
|
+
navigator.serviceWorker.addEventListener('controllerchange', function () {
|
|
135
|
+
if (refreshing) {
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
refreshing = true
|
|
140
|
+
Window.reload()
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
navigator.serviceWorker.ready.then(function (registration) {
|
|
144
|
+
handleServiceWorkerReady(registration.active)
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
navigator.serviceWorker.register(url).then(function (registration) {
|
|
148
|
+
logger.info(`service worker registered with scope "${registration.scope}"`)
|
|
149
|
+
registration.update() /* Manually trigger an update on each refresh */
|
|
150
|
+
|
|
151
|
+
function awaitStateChange() {
|
|
152
|
+
registration.installing.addEventListener('statechange', function () {
|
|
153
|
+
if (this.state === 'installed') {
|
|
154
|
+
handleServiceWorkerUpdate(this, updateHandler)
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (registration.waiting) {
|
|
160
|
+
return handleServiceWorkerUpdate(registration.waiting, updateHandler)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (registration.installing) {
|
|
164
|
+
awaitStateChange()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
registration.addEventListener('updatefound', awaitStateChange)
|
|
168
|
+
|
|
169
|
+
}).catch(function (e) {
|
|
170
|
+
logger.error(`service worker registration failed: ${e}`)
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
logger.debug(`service worker setup with URL = "${url}"`)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Return the service worker that currently controls the client.
|
|
178
|
+
* @returns {?ServiceWorker}
|
|
179
|
+
*/
|
|
180
|
+
export function getServiceWorker() {
|
|
181
|
+
return serviceWorker
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Send a message to the controlling service worker.
|
|
186
|
+
* @param {*} message the message to send
|
|
187
|
+
*/
|
|
188
|
+
export function sendServiceWorkerMessage(message) {
|
|
189
|
+
if (!serviceWorker) {
|
|
190
|
+
throw new AssertionError('Attempt to send service worker message from uncontrolled client')
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
serviceWorker.postMessage(message)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* A handler function responsible for providing a clickable element that prompts user for app installation.
|
|
198
|
+
* @callback qui.pwa.InstallElementHandler
|
|
199
|
+
* @returns {Promise<jQuery>} a promise that resolves to a clickable element that prompts for app installation upon
|
|
200
|
+
* click
|
|
201
|
+
*/
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* A handler function called after the user responds to installation prompt.
|
|
205
|
+
* @callback qui.pwa.InstallResponseHandler
|
|
206
|
+
* @param {Boolean} accepted indicates whether user accepted installation or not
|
|
207
|
+
*/
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Configures the handler functions for the app installation.
|
|
211
|
+
*
|
|
212
|
+
* This must be called before {@link qui.init}.
|
|
213
|
+
*
|
|
214
|
+
* @alias qui.pwa.setInstallHandlers
|
|
215
|
+
* @param {qui.pwa.InstallElementHandler} elementHandler
|
|
216
|
+
* @param {?qui.pwa.InstallResponseHandler} [responseHandler]
|
|
217
|
+
*/
|
|
218
|
+
export function setInstallHandlers(elementHandler, responseHandler = null) {
|
|
219
|
+
installElementHandler = elementHandler
|
|
220
|
+
installResponseHandler = responseHandler
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Setup the web app manifest.
|
|
225
|
+
* @alias qui.pwa.setupManifest
|
|
226
|
+
* @param {String} [url] the URL where the manifest file lives; {@link qui.config.navigationBasePrefix} +
|
|
227
|
+
* `"/manifest.json"` will be used if not specified
|
|
228
|
+
* @param {String} [displayName] an optional display name to append to the URL as a query argument (must be handled by
|
|
229
|
+
* the template rendering engine on the server side); defaults to {@link qui.config.appDisplayName}
|
|
230
|
+
* @param {String} [displayShortName] an optional short display name to append to the URL as a query argument (must be
|
|
231
|
+
* handled by the template rendering engine on the server side)
|
|
232
|
+
* @param {String} [description] an optional description to append to the URL as a query argument (must be handled by
|
|
233
|
+
* the template rendering engine on the server side)
|
|
234
|
+
* @param {String} [version] an optional version to append to the URL as a query argument (must be handled by the
|
|
235
|
+
* template rendering engine on the server side)
|
|
236
|
+
* @param {String} [themeColor] an optional theme color to append to the URL as a query argument (must be handled by the
|
|
237
|
+
* template rendering engine on the server side); defaults to `@interactive-color`
|
|
238
|
+
* @param {String} [backgroundColor] an optional background color to append to the URL as a query argument (must be
|
|
239
|
+
* handled by the template rendering engine on the server side); defaults to `@background-color`
|
|
240
|
+
*/
|
|
241
|
+
export function setupManifest({
|
|
242
|
+
url = `${Config.navigationBasePrefix}/${MANIFEST_FILE}`,
|
|
243
|
+
displayName = Config.appDisplayName,
|
|
244
|
+
displayShortName = null,
|
|
245
|
+
description = null,
|
|
246
|
+
version = null,
|
|
247
|
+
themeColor = Theme.getColor('@interactive-color'),
|
|
248
|
+
backgroundColor = Theme.getColor('@background-color')
|
|
249
|
+
} = {}) {
|
|
250
|
+
manifestParams = {
|
|
251
|
+
url,
|
|
252
|
+
displayName,
|
|
253
|
+
displayShortName,
|
|
254
|
+
description,
|
|
255
|
+
version,
|
|
256
|
+
themeColor,
|
|
257
|
+
backgroundColor
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
let manifest = Window.$document.find('link[rel=manifest]')
|
|
261
|
+
if (!manifest.length) {
|
|
262
|
+
throw new Error('Manifest link element not found')
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
url = appendBuildHash(url)
|
|
266
|
+
|
|
267
|
+
let parsedURL = URL.parse(url)
|
|
268
|
+
if (displayName != null) {
|
|
269
|
+
parsedURL.query['display_name'] = displayName
|
|
270
|
+
}
|
|
271
|
+
if (displayShortName != null) {
|
|
272
|
+
parsedURL.query['display_short_name'] = displayShortName
|
|
273
|
+
}
|
|
274
|
+
if (description != null) {
|
|
275
|
+
parsedURL.query['description'] = description
|
|
276
|
+
}
|
|
277
|
+
if (version != null) {
|
|
278
|
+
parsedURL.query['version'] = version
|
|
279
|
+
}
|
|
280
|
+
if (themeColor != null) {
|
|
281
|
+
parsedURL.query['theme_color'] = themeColor
|
|
282
|
+
}
|
|
283
|
+
if (backgroundColor != null) {
|
|
284
|
+
parsedURL.query['background_color'] = backgroundColor
|
|
285
|
+
}
|
|
286
|
+
url = parsedURL.toString()
|
|
287
|
+
|
|
288
|
+
manifest.attr('href', url)
|
|
289
|
+
|
|
290
|
+
logger.debug(`manifest setup with URL = "${url}"`)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export function init() {
|
|
294
|
+
Window.$window.on('beforeinstallprompt', function (e) {
|
|
295
|
+
logger.debug('received install prompt event')
|
|
296
|
+
if (installElementHandler) {
|
|
297
|
+
let promptEvent = e.originalEvent
|
|
298
|
+
promptEvent.preventDefault()
|
|
299
|
+
|
|
300
|
+
if (installPrompted) {
|
|
301
|
+
logger.debug('ignoring subsequent install prompt event')
|
|
302
|
+
return
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
installPrompted = true
|
|
306
|
+
|
|
307
|
+
/* Don't call the install handler before QUI & initial navigation are ready, as it will probably use UI
|
|
308
|
+
* elements that need to be initialized first; add an extra delay to allow the UI animations to settle */
|
|
309
|
+
Promise.all([QUI.whenReady, Navigation.whenInitialNavigationReady]).then(function () {
|
|
310
|
+
return PromiseUtils.later(1000)
|
|
311
|
+
}).then(function () {
|
|
312
|
+
logger.debug('calling install handler')
|
|
313
|
+
installElementHandler().then(function (element) {
|
|
314
|
+
element.on('click', function clickHandler() {
|
|
315
|
+
element.off('click', clickHandler) /* Don't prompt again */
|
|
316
|
+
|
|
317
|
+
promptEvent.prompt()
|
|
318
|
+
promptEvent.userChoice.then(function (choiceResult) {
|
|
319
|
+
if (choiceResult.outcome === 'accepted') {
|
|
320
|
+
logger.info('user accepted installation')
|
|
321
|
+
if (installResponseHandler) {
|
|
322
|
+
installResponseHandler(true)
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
logger.info('user rejected installation')
|
|
327
|
+
if (installResponseHandler) {
|
|
328
|
+
installResponseHandler(false)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
})
|
|
332
|
+
})
|
|
333
|
+
}).catch(() => {})
|
|
334
|
+
})
|
|
335
|
+
}
|
|
336
|
+
})
|
|
337
|
+
}
|