@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/pages/page.js
ADDED
|
@@ -0,0 +1,1018 @@
|
|
|
1
|
+
|
|
2
|
+
import $ from '$qui/lib/jquery.module.js'
|
|
3
|
+
|
|
4
|
+
import {AssertionError} from '$qui/base/errors.js'
|
|
5
|
+
import {Mixin} from '$qui/base/mixwith.js'
|
|
6
|
+
import * as GlobalGlass from '$qui/global-glass.js'
|
|
7
|
+
import * as OptionsBar from '$qui/main-ui/options-bar.js'
|
|
8
|
+
import * as Navigation from '$qui/navigation.js'
|
|
9
|
+
import * as Theme from '$qui/theme.js'
|
|
10
|
+
import {asap} from '$qui/utils/misc.js'
|
|
11
|
+
import ViewMixin from '$qui/views/view.js'
|
|
12
|
+
import * as Sections from '$qui/sections/sections.js'
|
|
13
|
+
import * as Window from '$qui/window.js'
|
|
14
|
+
|
|
15
|
+
import {getPagesContainer} from './pages.js'
|
|
16
|
+
import {updateUI} from './pages.js'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
const viewMixinPrototype = ViewMixin().prototype
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/** @lends qui.pages.PageMixin */
|
|
23
|
+
const PageMixin = Mixin((superclass = Object, rootclass) => {
|
|
24
|
+
|
|
25
|
+
let rootPrototype = rootclass.prototype
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A mixin that offers page behavior.
|
|
30
|
+
* @alias qui.pages.PageMixin
|
|
31
|
+
* @mixin
|
|
32
|
+
* @extends qui.views.ViewMixin
|
|
33
|
+
*/
|
|
34
|
+
class PageMixin extends ViewMixin(superclass) {
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @constructs
|
|
38
|
+
* @param {?String} [title] page title
|
|
39
|
+
* @param {String} [pathId] identifies the page in the URL; leave this unset if the page should not be part
|
|
40
|
+
* of the URL or is the main page of a section
|
|
41
|
+
* @param {Boolean} [columnLayout] indicates that the page layout is a column and does not expand horizontally
|
|
42
|
+
* (defaults to `false`)
|
|
43
|
+
* @param {Boolean} [keepPrevVisible] indicates that the previous page should be kept visible while this page
|
|
44
|
+
* is the current one, to the extent possible (defaults to `false`)
|
|
45
|
+
* @param {Boolean} [popup] indicates that the page should be shown as a popup container, on top of the existing
|
|
46
|
+
* content (defaults to `false`)
|
|
47
|
+
* @param {Boolean} [modal] indicates that the page should be modal, not allowing any external interaction
|
|
48
|
+
* (defaults to `false`, implies `popup` as `true`)
|
|
49
|
+
* @param {Boolean} [transparent] indicates that the page should be transparent (defaults to `true`)
|
|
50
|
+
* @param {...*} args parent class parameters
|
|
51
|
+
*/
|
|
52
|
+
constructor({
|
|
53
|
+
title = null,
|
|
54
|
+
pathId = null,
|
|
55
|
+
columnLayout = false,
|
|
56
|
+
keepPrevVisible = false,
|
|
57
|
+
popup = false,
|
|
58
|
+
modal = false,
|
|
59
|
+
transparent = true,
|
|
60
|
+
...args
|
|
61
|
+
} = {}) {
|
|
62
|
+
super(args)
|
|
63
|
+
|
|
64
|
+
this._title = title
|
|
65
|
+
this._pathId = pathId
|
|
66
|
+
this._columnLayout = columnLayout
|
|
67
|
+
this._keepPrevVisible = keepPrevVisible
|
|
68
|
+
this._transparent = transparent
|
|
69
|
+
this._popup = popup || modal
|
|
70
|
+
this._modal = modal
|
|
71
|
+
|
|
72
|
+
this._pageHTML = null
|
|
73
|
+
this._closingPromise = null
|
|
74
|
+
this._closed = false
|
|
75
|
+
this._attached = false
|
|
76
|
+
this._context = null
|
|
77
|
+
this._optionsBarContent = null
|
|
78
|
+
this._optionsBarOpen = false /* Flag indicating the last known options bar status for this page */
|
|
79
|
+
this._whenLoaded = null
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Override this method to customize navigation beyond this page. By default, it returns `null`, preventing
|
|
84
|
+
* further navigation.
|
|
85
|
+
*
|
|
86
|
+
* It is safe to assume that this page is visible and loaded when this method is called.
|
|
87
|
+
*
|
|
88
|
+
* @param {String} pathId the next path id
|
|
89
|
+
* @returns {?qui.pages.PageMixin|Promise<qui.pages.PageMixin>} the next page or `null` if navigation to given
|
|
90
|
+
* path id is not possible; a promise that resolves to a page can also be returned
|
|
91
|
+
*/
|
|
92
|
+
navigate(pathId) {
|
|
93
|
+
return null
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Return the page title.
|
|
98
|
+
* @returns {?String}
|
|
99
|
+
*/
|
|
100
|
+
getTitle() {
|
|
101
|
+
if (rootPrototype.getTitle) {
|
|
102
|
+
return rootPrototype.getTitle.call(this)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return this._title
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Set the page title.
|
|
110
|
+
* @param {?String} title the new title
|
|
111
|
+
*/
|
|
112
|
+
setTitle(title) {
|
|
113
|
+
if (rootPrototype.getTitle) {
|
|
114
|
+
rootPrototype.setTitle.call(this, title)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
this._title = title
|
|
118
|
+
if (this.getContext() && this.getContext().isCurrent()) {
|
|
119
|
+
updateUI()
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Return the path id of the page.
|
|
125
|
+
* @returns {?String}
|
|
126
|
+
*/
|
|
127
|
+
getPathId() {
|
|
128
|
+
return this._pathId
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Update the path id of the page.
|
|
133
|
+
* @param {?String} pathId
|
|
134
|
+
*/
|
|
135
|
+
setPathId(pathId) {
|
|
136
|
+
this._pathId = pathId
|
|
137
|
+
if (this.getContext() && this.getContext().isCurrent()) {
|
|
138
|
+
Navigation.updateHistoryEntry()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Override this method to specify page state to be saved when page is saved into browser history.
|
|
144
|
+
*
|
|
145
|
+
* This state will later be restored by calling {@link qui.pages.PageMixin#restoreHistoryState}.
|
|
146
|
+
*
|
|
147
|
+
* @returns {*} the state
|
|
148
|
+
*/
|
|
149
|
+
getHistoryState() {
|
|
150
|
+
return {}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Override this method to implement restoring page state from history.
|
|
155
|
+
*
|
|
156
|
+
* This method will be given as argument the state that has been previously created by
|
|
157
|
+
* {@link qui.pages.PageMixin#getHistoryState}.
|
|
158
|
+
*
|
|
159
|
+
* This method must be prepared to receive a `null` history state.
|
|
160
|
+
*
|
|
161
|
+
* @param {*} state
|
|
162
|
+
*/
|
|
163
|
+
restoreHistoryState(state) {
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Call this whenever the content of the history state changes.
|
|
168
|
+
*/
|
|
169
|
+
updateHistoryState() {
|
|
170
|
+
if (this.getContext() && this.getContext().isCurrent()) {
|
|
171
|
+
Navigation.updateHistoryEntry()
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Ad a new entry to the browser history. This is just a convenience wrapper around
|
|
177
|
+
* {@link qui.navigation.addHistoryEntry}.
|
|
178
|
+
*/
|
|
179
|
+
addHistoryEntry() {
|
|
180
|
+
Navigation.addHistoryEntry()
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Override this to implement how the page is loaded.
|
|
185
|
+
*
|
|
186
|
+
* Does nothing by default, returning a resolved promise.
|
|
187
|
+
*
|
|
188
|
+
* @returns {Promise}
|
|
189
|
+
*/
|
|
190
|
+
load() {
|
|
191
|
+
return Promise.resolve()
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Return a promise that settles as soon as the page is loaded.
|
|
196
|
+
*
|
|
197
|
+
* This method calls {@link qui.pages.PageMixin#load} once per page instance.
|
|
198
|
+
*
|
|
199
|
+
* @returns {Promise}
|
|
200
|
+
*/
|
|
201
|
+
whenLoaded() {
|
|
202
|
+
if (!this._whenLoaded) {
|
|
203
|
+
this.setProgress()
|
|
204
|
+
this._whenLoaded = this.load()
|
|
205
|
+
this._whenLoaded.then(function () {
|
|
206
|
+
this.clearProgress()
|
|
207
|
+
}.bind(this)).catch(function (error) {
|
|
208
|
+
this.setError(error)
|
|
209
|
+
}.bind(this))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return this._whenLoaded
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Create the page HTML wrapper. This method is called only once per page instance.
|
|
217
|
+
* @returns {jQuery}
|
|
218
|
+
*/
|
|
219
|
+
makePageHTML() {
|
|
220
|
+
let html = $('<div></div>', {class: 'qui-page'})
|
|
221
|
+
|
|
222
|
+
if (this._columnLayout) {
|
|
223
|
+
html.addClass('column-layout')
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (this._transparent) {
|
|
227
|
+
html.addClass('transparent')
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (this._popup) {
|
|
231
|
+
html.addClass('popup')
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (this._modal) {
|
|
235
|
+
html.addClass('modal')
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* Add a reference from HTML element to the page object */
|
|
239
|
+
html.data('page', this)
|
|
240
|
+
|
|
241
|
+
html.append(this.getHTML())
|
|
242
|
+
|
|
243
|
+
return html
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Override this to further initialize the Page HTML wrapper.
|
|
248
|
+
* @param {jQuery} html the HTML wrapper to be initialized
|
|
249
|
+
*/
|
|
250
|
+
initPageHTML(html) {
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Return the page HTML wrapper. Calls {@link qui.pages.PageMixin#makePageHTML} at first invocation.
|
|
255
|
+
* @returns {jQuery}
|
|
256
|
+
*/
|
|
257
|
+
getPageHTML() {
|
|
258
|
+
if (this._pageHTML == null) {
|
|
259
|
+
this._pageHTML = this.makePageHTML()
|
|
260
|
+
this.initPageHTML(this._pageHTML)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return this._pageHTML
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Attach the page to the page container.
|
|
268
|
+
*/
|
|
269
|
+
attach() {
|
|
270
|
+
if (this._attached) {
|
|
271
|
+
throw new AssertionError('Attempt to attach an already attached page')
|
|
272
|
+
}
|
|
273
|
+
// TODO following condition breaks sticky modal pages
|
|
274
|
+
// if (!this._context || !this._context.isCurrent()) {
|
|
275
|
+
// throw new AssertionError('Attempt to attach a page belonging to a non-current context')
|
|
276
|
+
// }
|
|
277
|
+
|
|
278
|
+
let html = this.getPageHTML()
|
|
279
|
+
if (this.isPopup()) {
|
|
280
|
+
GlobalGlass.addContent(html)
|
|
281
|
+
GlobalGlass.setModal(this.isModal())
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
getPagesContainer().append(html)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
asap(function () {
|
|
288
|
+
this.getPageHTML().addClass('attached')
|
|
289
|
+
}.bind(this))
|
|
290
|
+
|
|
291
|
+
this._attached = true
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Detach the page from the page container.
|
|
296
|
+
*/
|
|
297
|
+
detach() {
|
|
298
|
+
if (!this._attached) {
|
|
299
|
+
throw new AssertionError('Attempt to detach an already detached page')
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
this._attached = false
|
|
303
|
+
|
|
304
|
+
this.getPageHTML().removeClass('attached')
|
|
305
|
+
if (this.isPopup()) {
|
|
306
|
+
GlobalGlass.setModal(true) /* default */
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
Theme.afterTransition(function () {
|
|
310
|
+
|
|
311
|
+
if (this._attached) {
|
|
312
|
+
/* Detaching cancelled by subsequent attach */
|
|
313
|
+
return
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
this.getPageHTML().detach()
|
|
317
|
+
|
|
318
|
+
}.bind(this), this.getPageHTML())
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Tell if the page layout is a column and does not expand horizontally.
|
|
323
|
+
* @returns {Boolean}
|
|
324
|
+
*/
|
|
325
|
+
isColumnLayout() {
|
|
326
|
+
return this._columnLayout
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Set the page column layout.
|
|
331
|
+
* @param {Boolean} columnLayout
|
|
332
|
+
*/
|
|
333
|
+
setColumnLayout(columnLayout) {
|
|
334
|
+
if (columnLayout !== this._columnLayout) {
|
|
335
|
+
this._columnLayout = columnLayout
|
|
336
|
+
this.getPageHTML().toggleClass('column-layout', columnLayout)
|
|
337
|
+
|
|
338
|
+
updateUI()
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Return the current vertical scroll parameters.
|
|
344
|
+
* @returns {{offset: Number, maxOffset: Number}} `offset` represents the current scroll offset and `maxOffset`
|
|
345
|
+
* is the maximum scroll offset (`0` if no scrolling is possible)
|
|
346
|
+
*/
|
|
347
|
+
getVertScrollParams() {
|
|
348
|
+
let pageHTML = this.getPageHTML()
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
offset: pageHTML[0].scrollTop,
|
|
352
|
+
maxOffset: pageHTML[0].scrollHeight - pageHTML[0].clientHeight
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Called when the page is scrolled vertically.
|
|
358
|
+
* @param {Number} offset the vertical scroll offset
|
|
359
|
+
* @param {Number} maxOffset the maximum vertical scroll offset
|
|
360
|
+
*/
|
|
361
|
+
onVertScroll(offset, maxOffset) {
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Handle vertical scroll events. Internally calls {@link qui.pages.PageMixin#onVertScroll}.
|
|
366
|
+
*/
|
|
367
|
+
handleVertScroll() {
|
|
368
|
+
let params = this.getVertScrollParams()
|
|
369
|
+
|
|
370
|
+
this.onVertScroll(params.offset, params.maxOffset)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Called when the page is resized.
|
|
375
|
+
*/
|
|
376
|
+
onResize() {
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Handle the resize events. Internally calls {@link qui.pages.PageMixin#onResize}.
|
|
381
|
+
*/
|
|
382
|
+
handleResize() {
|
|
383
|
+
this.onResize()
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Return the index of this page in its context. If page has no context, `-1` is returned.
|
|
388
|
+
* @returns {Number}
|
|
389
|
+
*/
|
|
390
|
+
getContextIndex() {
|
|
391
|
+
if (!this._context) {
|
|
392
|
+
return -1
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return this._context.getPages().indexOf(this)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Return the associated pages context.
|
|
400
|
+
* @returns {?qui.pages.PagesContext}
|
|
401
|
+
*/
|
|
402
|
+
getContext() {
|
|
403
|
+
return this._context
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Tell if this page is the current page within its context.
|
|
408
|
+
* @returns {Boolean}
|
|
409
|
+
*/
|
|
410
|
+
isCurrent() {
|
|
411
|
+
if (!this._context) {
|
|
412
|
+
return false
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return this._context.getCurrentPage() === this
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Tell if the page is visible.
|
|
420
|
+
* @returns {Boolean}
|
|
421
|
+
*/
|
|
422
|
+
isVisible() {
|
|
423
|
+
if (!this._context) {
|
|
424
|
+
return false
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (!this._context.isCurrent()) {
|
|
428
|
+
return false
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (!this._context.getPages().includes(this)) {
|
|
432
|
+
return false /* Not part of current context */
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (Window.isSmallScreen() && this.getContextIndex() < this._context.getSize() - 1) {
|
|
436
|
+
return false /* On small screens, only the last page is actually visible */
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return this._context.getVisiblePages().includes(this)
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Tells if the page has a context, effectively indicating whether the page is currently added to a context, or
|
|
444
|
+
* not.
|
|
445
|
+
* @returns {Boolean}
|
|
446
|
+
*/
|
|
447
|
+
hasContext() {
|
|
448
|
+
return !!this._context
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Tell if the page is kept visible while the next page is current.
|
|
453
|
+
* @returns {Boolean}
|
|
454
|
+
*/
|
|
455
|
+
isPrevKeptVisible() {
|
|
456
|
+
return this._keepPrevVisible
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Set the *keep-prev-visible* flag, controlling if the page is kept visible while the next page is current.
|
|
461
|
+
* @param {Boolean} keepPrevVisible
|
|
462
|
+
*/
|
|
463
|
+
setKeepPrevVisible(keepPrevVisible) {
|
|
464
|
+
this._keepPrevVisible = keepPrevVisible
|
|
465
|
+
|
|
466
|
+
if (this._context && this._context.isCurrent()) {
|
|
467
|
+
updateUI()
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Tell if the page is popup.
|
|
473
|
+
* @returns {Boolean}
|
|
474
|
+
*/
|
|
475
|
+
isPopup() {
|
|
476
|
+
return this._popup
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Set the popup flag.
|
|
481
|
+
* @param {Boolean} popup
|
|
482
|
+
*/
|
|
483
|
+
setPopup(popup) {
|
|
484
|
+
if (this._modal) {
|
|
485
|
+
popup = true /* Modals are always popups */
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
let needsReattach = false
|
|
489
|
+
if (this._popup !== popup && this._attached) {
|
|
490
|
+
needsReattach = true
|
|
491
|
+
this.detach()
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
this._popup = popup
|
|
495
|
+
|
|
496
|
+
if (needsReattach) {
|
|
497
|
+
this.attach()
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
this.getPageHTML().toggleClass('popup', popup)
|
|
501
|
+
|
|
502
|
+
if (this.getContext() && this.getContext().isCurrent()) {
|
|
503
|
+
updateUI()
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Tell if the page is modal.
|
|
509
|
+
* @returns {Boolean}
|
|
510
|
+
*/
|
|
511
|
+
isModal() {
|
|
512
|
+
return this._modal
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Set the modal flag.
|
|
517
|
+
* @param {Boolean} modal
|
|
518
|
+
*/
|
|
519
|
+
setModal(modal) {
|
|
520
|
+
let needsReattach = false
|
|
521
|
+
if (this._modal !== modal && this._attached) {
|
|
522
|
+
needsReattach = true
|
|
523
|
+
this.detach()
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
this._modal = modal
|
|
527
|
+
if (modal) {
|
|
528
|
+
this._popup = true /* Modals are always popups */
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (needsReattach) {
|
|
532
|
+
this.attach()
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
this.getPageHTML().toggleClass('modal', this._modal)
|
|
536
|
+
this.getPageHTML().toggleClass('popup', this._popup) /* Popup might have also changed */
|
|
537
|
+
|
|
538
|
+
if (this.getContext() && this.getContext().isCurrent()) {
|
|
539
|
+
updateUI()
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Called when the page is closed.
|
|
545
|
+
*/
|
|
546
|
+
onClose() {
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Called when the next page is closed.
|
|
551
|
+
* @param {qui.pages.PageMixin} next the next page that has just been closed
|
|
552
|
+
*/
|
|
553
|
+
onCloseNext(next) {
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Close the page. Calls {@link qui.pages.PageMixin#canClose} to determine if the page can be closed.
|
|
558
|
+
* @param {Boolean} [force] set to `true` to force page close without calling
|
|
559
|
+
* {@link qui.pages.PageMixin#canClose}
|
|
560
|
+
* @returns {Promise} a promise that is resolved as soon as the page is closed and is rejected if the page close
|
|
561
|
+
* was rejected.
|
|
562
|
+
*/
|
|
563
|
+
close(force = false) {
|
|
564
|
+
if (this._closed) {
|
|
565
|
+
throw new AssertionError('Attempt to close an already closed page')
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/* If page is already in the process of being closed, return the closing promise */
|
|
569
|
+
if (this._closingPromise) {
|
|
570
|
+
return this._closingPromise
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/* Close all following pages */
|
|
574
|
+
let promise = Promise.resolve()
|
|
575
|
+
let index = this.getContextIndex()
|
|
576
|
+
let context = this.getContext()
|
|
577
|
+
if (index >= 0 && context && context.getSize() > index + 1) {
|
|
578
|
+
promise = context.getPageAt(index + 1).close(force)
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
this._closingPromise = promise.then(() => force || this.canClose()).then(function () {
|
|
582
|
+
if (rootPrototype.close) {
|
|
583
|
+
rootPrototype.close.call(this)
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/* Mark as closed */
|
|
587
|
+
this._closed = true
|
|
588
|
+
this._closingPromise = null
|
|
589
|
+
|
|
590
|
+
/* Pop this page from context */
|
|
591
|
+
if (context) {
|
|
592
|
+
let currentPage = context.getCurrentPage()
|
|
593
|
+
if (currentPage !== this) {
|
|
594
|
+
throw new AssertionError('New page added to context while current page closing')
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (context.isCurrent()) {
|
|
598
|
+
this.handleLeaveCurrent()
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
context.pop()
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
this.onClose()
|
|
605
|
+
this._context = null
|
|
606
|
+
|
|
607
|
+
/* Detach from DOM */
|
|
608
|
+
if (this._attached) {
|
|
609
|
+
this.detach()
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
updateUI()
|
|
613
|
+
|
|
614
|
+
if (context) {
|
|
615
|
+
let currentPage = context.getCurrentPage()
|
|
616
|
+
if (currentPage) {
|
|
617
|
+
currentPage.onCloseNext(this)
|
|
618
|
+
|
|
619
|
+
if (context.isCurrent()) {
|
|
620
|
+
currentPage.handleBecomeCurrent()
|
|
621
|
+
Navigation.updateHistoryEntry()
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
else {
|
|
625
|
+
if (context.isCurrent()) {
|
|
626
|
+
OptionsBar.setContent(null)
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}.bind(this)).catch(function (e) {
|
|
631
|
+
|
|
632
|
+
/* Clear closing promise if close cancelled */
|
|
633
|
+
this._closingPromise = null
|
|
634
|
+
throw e
|
|
635
|
+
|
|
636
|
+
}.bind(this))
|
|
637
|
+
|
|
638
|
+
return this._closingPromise
|
|
639
|
+
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Tell if the page has been closed.
|
|
644
|
+
* @returns {Boolean}
|
|
645
|
+
*/
|
|
646
|
+
isClosed() {
|
|
647
|
+
/* Prefer root isClosed unless it's the one inherited from ViewMixin */
|
|
648
|
+
if (rootPrototype.isClosed &&
|
|
649
|
+
(rootPrototype.isClosed !== viewMixinPrototype.isClosed) &&
|
|
650
|
+
(rootPrototype.isClosed.toString() !== viewMixinPrototype.isClosed.toString())) {
|
|
651
|
+
|
|
652
|
+
return rootPrototype.isClosed.call(this)
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
return this._closed
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Override this method to prevent accidental closing of the page, to the possible extent. Pages can be closed
|
|
660
|
+
* by default.
|
|
661
|
+
* @returns {Promise} a promise that, if rejected, will prevent the page close
|
|
662
|
+
*/
|
|
663
|
+
canClose() {
|
|
664
|
+
return Promise.resolve()
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Called when the page becomes the current page on the current context.
|
|
669
|
+
*/
|
|
670
|
+
onBecomeCurrent() {
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Handle the event of becoming the current page of the current context.
|
|
675
|
+
*/
|
|
676
|
+
handleBecomeCurrent() {
|
|
677
|
+
this.onBecomeCurrent()
|
|
678
|
+
let context = this.getContext()
|
|
679
|
+
if (!context || !context.isCurrent()) {
|
|
680
|
+
throw new AssertionError('Attempt to call handleBecomeCurrent() on non-current context')
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
OptionsBar.setContent(this._prepareOptionsBarContent())
|
|
684
|
+
if (this._optionsBarOpen) {
|
|
685
|
+
OptionsBar.open()
|
|
686
|
+
}
|
|
687
|
+
else {
|
|
688
|
+
OptionsBar.close()
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Called when the page is no longer the current page on the current context.
|
|
694
|
+
*/
|
|
695
|
+
onLeaveCurrent() {
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Handle the event of no longer being the current page of the current context.
|
|
700
|
+
*/
|
|
701
|
+
handleLeaveCurrent() {
|
|
702
|
+
this.onLeaveCurrent()
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Called when the section to which page belongs is shown.
|
|
707
|
+
*/
|
|
708
|
+
onSectionShow() {
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Handle the event of owning section becoming visible.
|
|
713
|
+
*/
|
|
714
|
+
handleSectionShow() {
|
|
715
|
+
this.onSectionShow()
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Called when the section to which page belongs is hidden.
|
|
720
|
+
*/
|
|
721
|
+
onSectionHide() {
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Handle the event of owning section becoming hidden.
|
|
726
|
+
*/
|
|
727
|
+
handleSectionHide() {
|
|
728
|
+
this.onSectionHide()
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* Returns the section to which the page currently belongs (may be `null`).
|
|
733
|
+
* @returns {?qui.sections.Section}
|
|
734
|
+
*/
|
|
735
|
+
getSection() {
|
|
736
|
+
return Sections.all().find(s => s.getPagesContext() === this.getContext()) || null
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Override this method to enable the options bar for this page.
|
|
741
|
+
* @returns {?jQuery|qui.views.ViewMixin}
|
|
742
|
+
*/
|
|
743
|
+
makeOptionsBarContent() {
|
|
744
|
+
return null
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Return the options bar content of this page.
|
|
749
|
+
* @returns {?jQuery|qui.views.ViewMixin}
|
|
750
|
+
*/
|
|
751
|
+
getOptionsBarContent() {
|
|
752
|
+
if (!this._optionsBarContent) {
|
|
753
|
+
this._optionsBarContent = this.makeOptionsBarContent()
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
return this._optionsBarContent
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Called when the page options change; the page options are defined by the options bar content.
|
|
761
|
+
*
|
|
762
|
+
* This currently works only when using an {@link qui.forms.OptionsForm} for the options bar content.
|
|
763
|
+
*
|
|
764
|
+
* @param {Object} options
|
|
765
|
+
*/
|
|
766
|
+
onOptionsChange(options) {
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
_prepareOptionsBarContent() {
|
|
770
|
+
let content = this.getOptionsBarContent()
|
|
771
|
+
if (content) {
|
|
772
|
+
if (content instanceof ViewMixin) {
|
|
773
|
+
content = content.getHTML()
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
return content
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* If this is the current page, open the options bar right away. Otherwise, the options bar will be
|
|
782
|
+
* automatically opened as soon as this page becomes current.
|
|
783
|
+
*/
|
|
784
|
+
openOptionsBar() {
|
|
785
|
+
if (this.isCurrent()) {
|
|
786
|
+
OptionsBar.open()
|
|
787
|
+
}
|
|
788
|
+
else {
|
|
789
|
+
this._optionsBarOpen = true
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* If this is the current page, close the options bar right away. Otherwise, the options bar will remain closed
|
|
795
|
+
* as soon as this page becomes current.
|
|
796
|
+
*/
|
|
797
|
+
closeOptionsBar() {
|
|
798
|
+
if (this.isCurrent()) {
|
|
799
|
+
OptionsBar.close()
|
|
800
|
+
}
|
|
801
|
+
else {
|
|
802
|
+
this._optionsBarOpen = false
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
/**
|
|
807
|
+
* Called when the page is pushed to a context.
|
|
808
|
+
*/
|
|
809
|
+
onPush() {
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* Push a new page after this one. Any following pages will be closed. The new page is not guaranteed to be
|
|
814
|
+
* pushed by the time the function exists.
|
|
815
|
+
* @param {qui.pages.PageMixin} page the page to be pushed
|
|
816
|
+
* @param {Boolean} [historyEntry] whether to create a new history entry for current page before adding the new
|
|
817
|
+
* page, or not (determined automatically by default, using new page's `pathId`)
|
|
818
|
+
* @returns {Promise} a promise that resolves as soon as the page is pushed, or rejected if the page cannot be
|
|
819
|
+
* pushed
|
|
820
|
+
*/
|
|
821
|
+
pushPage(page, historyEntry = null) {
|
|
822
|
+
let index = this.getContextIndex()
|
|
823
|
+
if (index < 0) {
|
|
824
|
+
throw new AssertionError('Attempt to push from a contextless page')
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
/* By default, pages with pathId will add a new history entry */
|
|
828
|
+
if (historyEntry == null) {
|
|
829
|
+
historyEntry = !!page.getPathId()
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
let context = this.getContext()
|
|
833
|
+
if (!context.isCurrent()) {
|
|
834
|
+
historyEntry = false
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/* Preserve current state for after potential next page close */
|
|
838
|
+
let state = null
|
|
839
|
+
if (historyEntry) {
|
|
840
|
+
state = Navigation.getCurrentHistoryEntryState()
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/* Close any following page */
|
|
844
|
+
let promise
|
|
845
|
+
let nextPage = context.getPageAt(index + 1)
|
|
846
|
+
if (nextPage) {
|
|
847
|
+
promise = nextPage.close()
|
|
848
|
+
}
|
|
849
|
+
else {
|
|
850
|
+
promise = Promise.resolve()
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
return promise.then(function () {
|
|
854
|
+
if (historyEntry) {
|
|
855
|
+
Navigation.updateHistoryEntry(state)
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
if (context.isCurrent()) {
|
|
859
|
+
this.handleLeaveCurrent()
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
page.pushSelf(context)
|
|
863
|
+
page.whenLoaded() /* Start loading the page automatically when pushed */
|
|
864
|
+
|
|
865
|
+
if (historyEntry) {
|
|
866
|
+
Navigation.addHistoryEntry()
|
|
867
|
+
}
|
|
868
|
+
else if (context.isCurrent()) {
|
|
869
|
+
Navigation.updateHistoryEntry()
|
|
870
|
+
}
|
|
871
|
+
}.bind(this))
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Push this page to a context.
|
|
876
|
+
* @param {qui.pages.PagesContext} context
|
|
877
|
+
*/
|
|
878
|
+
pushSelf(context) {
|
|
879
|
+
if (this._context) {
|
|
880
|
+
throw new AssertionError('Attempt to push page with context')
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
this._closed = false
|
|
884
|
+
this._closingPromise = null
|
|
885
|
+
|
|
886
|
+
/* Attach the page to context */
|
|
887
|
+
context.push(this)
|
|
888
|
+
this._context = context
|
|
889
|
+
|
|
890
|
+
if (context.isCurrent()) {
|
|
891
|
+
this.attach()
|
|
892
|
+
updateUI()
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
this.onPush()
|
|
896
|
+
|
|
897
|
+
if (context.isCurrent()) {
|
|
898
|
+
this.handleBecomeCurrent()
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* Return the previous page in context.
|
|
904
|
+
* @returns {?qui.pages.PageMixin}
|
|
905
|
+
*/
|
|
906
|
+
getPrev() {
|
|
907
|
+
let index = this.getContextIndex()
|
|
908
|
+
if (index < 0) {
|
|
909
|
+
return null
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
return this._context.getPageAt(index - 1)
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* Return the next page in context.
|
|
917
|
+
* @returns {?qui.pages.PageMixin}
|
|
918
|
+
*/
|
|
919
|
+
getNext() {
|
|
920
|
+
let index = this.getContextIndex()
|
|
921
|
+
if (index < 0) {
|
|
922
|
+
return null
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
return this._context.getPageAt(index + 1)
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
|
|
929
|
+
/* Following methods are overridden so that versions from the rootclass are also taken into consideration */
|
|
930
|
+
|
|
931
|
+
makeHTML() {
|
|
932
|
+
if (rootPrototype.makeHTML) {
|
|
933
|
+
return rootPrototype.makeHTML.call(this)
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return super.makeHTML()
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
initHTML(html) {
|
|
940
|
+
if (rootPrototype.initHTML) {
|
|
941
|
+
rootPrototype.initHTML.call(this, html)
|
|
942
|
+
}
|
|
943
|
+
else {
|
|
944
|
+
super.initHTML(html)
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
init() {
|
|
949
|
+
if (rootPrototype.init) {
|
|
950
|
+
rootPrototype.init.call(this)
|
|
951
|
+
}
|
|
952
|
+
else {
|
|
953
|
+
super.init()
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
showProgress(percent) {
|
|
958
|
+
if (rootPrototype.showProgress) {
|
|
959
|
+
rootPrototype.showProgress.call(this, percent)
|
|
960
|
+
}
|
|
961
|
+
else {
|
|
962
|
+
super.showProgress(percent)
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
hideProgress() {
|
|
967
|
+
if (rootPrototype.hideProgress) {
|
|
968
|
+
rootPrototype.hideProgress.call(this)
|
|
969
|
+
}
|
|
970
|
+
else {
|
|
971
|
+
super.hideProgress()
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
showWarning(message) {
|
|
976
|
+
if (rootPrototype.showWarning) {
|
|
977
|
+
rootPrototype.showWarning.call(this, message)
|
|
978
|
+
}
|
|
979
|
+
else {
|
|
980
|
+
super.showWarning(message)
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
hideWarning() {
|
|
985
|
+
if (rootPrototype.hideWarning) {
|
|
986
|
+
rootPrototype.hideWarning.call(this)
|
|
987
|
+
}
|
|
988
|
+
else {
|
|
989
|
+
super.hideWarning()
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
showError(message) {
|
|
994
|
+
if (rootPrototype.showError) {
|
|
995
|
+
rootPrototype.showError.call(this, message)
|
|
996
|
+
}
|
|
997
|
+
else {
|
|
998
|
+
super.showError(message)
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
hideError() {
|
|
1003
|
+
if (rootPrototype.hideError) {
|
|
1004
|
+
rootPrototype.hideError.call(this)
|
|
1005
|
+
}
|
|
1006
|
+
else {
|
|
1007
|
+
super.hideError()
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
return PageMixin
|
|
1014
|
+
|
|
1015
|
+
})
|
|
1016
|
+
|
|
1017
|
+
|
|
1018
|
+
export default PageMixin
|