@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,612 @@
|
|
|
1
|
+
|
|
2
|
+
import $ from '$qui/lib/jquery.module.js'
|
|
3
|
+
import Logger from '$qui/lib/logger.module.js'
|
|
4
|
+
|
|
5
|
+
import {NotImplementedError} from '$qui/base/errors.js'
|
|
6
|
+
import {AssertionError} from '$qui/base/errors.js'
|
|
7
|
+
import {mix} from '$qui/base/mixwith.js'
|
|
8
|
+
import SingletonMixin from '$qui/base/singleton.js'
|
|
9
|
+
import StockIcon from '$qui/icons/stock-icon.js'
|
|
10
|
+
import * as MenuBar from '$qui/main-ui/menu-bar.js'
|
|
11
|
+
import * as TopBar from '$qui/main-ui/top-bar.js'
|
|
12
|
+
import * as Navigation from '$qui/navigation.js'
|
|
13
|
+
import {getCurrentContext} from '$qui/pages/pages.js'
|
|
14
|
+
import {setCurrentContext} from '$qui/pages/pages.js'
|
|
15
|
+
import * as Window from '$qui/window.js'
|
|
16
|
+
|
|
17
|
+
import * as Sections from './sections.js'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The base class for sections.
|
|
22
|
+
* @alias qui.sections.Section
|
|
23
|
+
* @mixes qui.base.SingletonMixin
|
|
24
|
+
*/
|
|
25
|
+
class Section extends mix().with(SingletonMixin) {
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @constructs
|
|
29
|
+
* @param {String} id section identifier
|
|
30
|
+
* @param {String} title section title
|
|
31
|
+
* @param {qui.icons.Icon} icon section icon
|
|
32
|
+
* @param {String} [buttonType] one of:
|
|
33
|
+
* * {@link qui.sections.BUTTON_TYPE_NONE}
|
|
34
|
+
* * {@link qui.sections.BUTTON_TYPE_MENU_BAR} (default)
|
|
35
|
+
* * {@link qui.sections.BUTTON_TYPE_TOP_BAR}
|
|
36
|
+
* @param {Boolean} [closeMainPageOnHide] set to `true` to close the main page when section is hidden
|
|
37
|
+
* {@link qui.sections.BUTTON_TYPE_TOP_BAR} and {@link qui.sections.BUTTON_TYPE_NONE}
|
|
38
|
+
* @param {Number} [index] sets the section position (ordering) in relation with other sections; by default,
|
|
39
|
+
* sections are positioned based on their registration order
|
|
40
|
+
*/
|
|
41
|
+
constructor({
|
|
42
|
+
id,
|
|
43
|
+
title,
|
|
44
|
+
icon,
|
|
45
|
+
buttonType = Sections.BUTTON_TYPE_MENU_BAR,
|
|
46
|
+
index = 0,
|
|
47
|
+
closeMainPageOnHide = false
|
|
48
|
+
}) {
|
|
49
|
+
|
|
50
|
+
super()
|
|
51
|
+
|
|
52
|
+
this._id = id
|
|
53
|
+
this._title = title
|
|
54
|
+
this._icon = icon
|
|
55
|
+
this._buttonType = buttonType
|
|
56
|
+
this._index = index
|
|
57
|
+
this._closeMainPageOnHide = closeMainPageOnHide
|
|
58
|
+
|
|
59
|
+
this._mainPage = null
|
|
60
|
+
this._savedPagesContext = null
|
|
61
|
+
this._whenPreloaded = null
|
|
62
|
+
this._whenLoaded = null
|
|
63
|
+
|
|
64
|
+
this.logger = Logger.get(`qui.sections.${this._id}`)
|
|
65
|
+
|
|
66
|
+
this._button = this._makeSectionButton()
|
|
67
|
+
this._button.on('click', function () {
|
|
68
|
+
|
|
69
|
+
if (this.isCurrent()) {
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Sections.switchTo(this, /* source = */ 'button', /* historyEntry = */ true)
|
|
74
|
+
|
|
75
|
+
}.bind(this))
|
|
76
|
+
|
|
77
|
+
/* Hide menu bar after selecting a menu entry */
|
|
78
|
+
this._button.on('pointerup', function () {
|
|
79
|
+
if (MenuBar.isOpened()) {
|
|
80
|
+
MenuBar.close()
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
this._applyIcon()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Return the id of this section.
|
|
89
|
+
* @returns {String}
|
|
90
|
+
*/
|
|
91
|
+
getId() {
|
|
92
|
+
return this._id
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Override this to implement how the section is preloaded (i.e. before pushing the main page).
|
|
97
|
+
*
|
|
98
|
+
* During the preload execution, this section should not be assumed to be the current section. Preloading blocks
|
|
99
|
+
* navigation by blocking switching to this section.
|
|
100
|
+
*
|
|
101
|
+
* By default, returns a resolved promise.
|
|
102
|
+
*
|
|
103
|
+
* @returns {Promise}
|
|
104
|
+
*/
|
|
105
|
+
preload() {
|
|
106
|
+
return Promise.resolve()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Override this to implement how the section is loaded, after pushing the main page.
|
|
111
|
+
*
|
|
112
|
+
* Loading the main page and loading the section may happen concurrently.
|
|
113
|
+
*
|
|
114
|
+
* By default, returns a resolved promise.
|
|
115
|
+
*
|
|
116
|
+
* @returns {Promise}
|
|
117
|
+
*/
|
|
118
|
+
load() {
|
|
119
|
+
return Promise.resolve()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Return a promise that settles as soon as the section is preloaded.
|
|
124
|
+
*
|
|
125
|
+
* This method calls {@link qui.sections.Section#preload} once per section instance.
|
|
126
|
+
*
|
|
127
|
+
* @returns {Promise}
|
|
128
|
+
*/
|
|
129
|
+
whenPreloaded() {
|
|
130
|
+
if (!this._whenPreloaded) {
|
|
131
|
+
this._whenPreloaded = this.preload()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return this._whenPreloaded
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Return a promise that settles as soon as the section is loaded.
|
|
139
|
+
*
|
|
140
|
+
* This method calls {@link qui.sections.Section#load} once per section instance.
|
|
141
|
+
*
|
|
142
|
+
* A loaded section can also be assumed to be preloaded.
|
|
143
|
+
*
|
|
144
|
+
* @returns {Promise}
|
|
145
|
+
*/
|
|
146
|
+
whenLoaded() {
|
|
147
|
+
return this.whenPreloaded().then(function () {
|
|
148
|
+
|
|
149
|
+
if (!this._whenLoaded) {
|
|
150
|
+
this._whenLoaded = this.load()
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return this._whenLoaded
|
|
154
|
+
|
|
155
|
+
}.bind(this))
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Override this method to prevent accidental closing of the section, to the possible extent. Sections can be closed
|
|
160
|
+
* by default.
|
|
161
|
+
*
|
|
162
|
+
* A section is closed only when application window is closed or reloaded.
|
|
163
|
+
*
|
|
164
|
+
* @returns {Boolean}
|
|
165
|
+
*/
|
|
166
|
+
canClose() {
|
|
167
|
+
return true
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* This method is called when {@link qui.sections.register} is called on this section and is responsible of section
|
|
172
|
+
* setting up after registration.
|
|
173
|
+
*/
|
|
174
|
+
handleRegister() {
|
|
175
|
+
this._addSectionButton()
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* This method is called when {@link qui.sections.unregister} is called on this section and is responsible of
|
|
180
|
+
* cleaning up after section removal.
|
|
181
|
+
*/
|
|
182
|
+
handleUnregister() {
|
|
183
|
+
this._button.detach()
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
/* Visibility & layout */
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Called whenever the section becomes visible.
|
|
191
|
+
* @param {String} source the source why the section has been shown; known sources are:
|
|
192
|
+
* * `"button"` - the section button has been pressed
|
|
193
|
+
* * `"navigation"` - {@link qui.navigation.navigate} was used to switch to this section
|
|
194
|
+
* * `"home"` - {@link qui.sections.showHome} was called
|
|
195
|
+
* * `"program"` - {@link qui.sections.switchTo} called from program
|
|
196
|
+
* @param {?qui.sections.Section} prevSection the previous section
|
|
197
|
+
*/
|
|
198
|
+
onShow(source, prevSection) {
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Handle the event of section becoming visible.
|
|
203
|
+
* @param {String} source (see {@link qui.sections.Section#onShow})
|
|
204
|
+
* @param {?qui.sections.Section} prevSection the previous section
|
|
205
|
+
*/
|
|
206
|
+
handleShow(source, prevSection) {
|
|
207
|
+
/* Inform all pages of event */
|
|
208
|
+
let context = this.getPagesContext()
|
|
209
|
+
context.getPages().forEach(page => page.handleSectionShow())
|
|
210
|
+
|
|
211
|
+
this.onShow(source, prevSection)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Called whenever the section is hidden.
|
|
216
|
+
*/
|
|
217
|
+
onHide() {
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Handle the event of section becoming hidden.
|
|
222
|
+
* @returns {Promise} a promise that resolves if the section can be hidden and rejected otherwise
|
|
223
|
+
*/
|
|
224
|
+
handleHide() {
|
|
225
|
+
let promise = Promise.resolve()
|
|
226
|
+
if (this._mainPage && this._closeMainPageOnHide) {
|
|
227
|
+
promise = this._mainPage.close()
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return promise.then(function () {
|
|
231
|
+
|
|
232
|
+
/* Inform all pages of event */
|
|
233
|
+
let context = this.getPagesContext()
|
|
234
|
+
context.getPages().forEach(page => page.handleSectionHide())
|
|
235
|
+
|
|
236
|
+
this.onHide()
|
|
237
|
+
|
|
238
|
+
}.bind(this))
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Called when the screen layout changes.
|
|
243
|
+
* @param {Boolean} smallScreen whether the screen is now a small screen or not
|
|
244
|
+
* @param {Boolean} landscape whether the screen layout is now landscape or portrait
|
|
245
|
+
*/
|
|
246
|
+
onScreenLayoutChange(smallScreen, landscape) {
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Called whenever the screen size changes.
|
|
251
|
+
* @param {Number} width the new width of the screen
|
|
252
|
+
* @param {Number} height the new height of the screen
|
|
253
|
+
*/
|
|
254
|
+
onWindowResize(width, height) {
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Called when the window becomes active or inactive.
|
|
259
|
+
* @param {Boolean} active
|
|
260
|
+
* @param active
|
|
261
|
+
*/
|
|
262
|
+
onWindowActiveChange(active) {
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Called when the window becomes focused or unfocused.
|
|
267
|
+
* @param {Boolean} focused
|
|
268
|
+
* @param focused
|
|
269
|
+
*/
|
|
270
|
+
onWindowFocusedChange(focused) {
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Called when the options bar is opened or closed, while this section is the current section.
|
|
275
|
+
* @param {Boolean} opened `true` if the bar is opened, `false` otherwise
|
|
276
|
+
*/
|
|
277
|
+
onOptionsBarOpenClose(opened) {
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
_makeAndPushMainPage() {
|
|
281
|
+
this.logger.debug('creating main page')
|
|
282
|
+
this._mainPage = this.makeMainPage()
|
|
283
|
+
|
|
284
|
+
let pagesContext = this.getPagesContext()
|
|
285
|
+
|
|
286
|
+
/* Overwrite path id with the section id */
|
|
287
|
+
this._mainPage._pathId = this._id
|
|
288
|
+
|
|
289
|
+
/* Unset mainPage on close */
|
|
290
|
+
pagesContext.popSignal.connect(function (page, index) {
|
|
291
|
+
if (index === 0) { /* Main page removed */
|
|
292
|
+
this._mainPage = null
|
|
293
|
+
}
|
|
294
|
+
}.bind(this))
|
|
295
|
+
|
|
296
|
+
this._mainPage.pushSelf(pagesContext)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
_show(source, prevSection) {
|
|
300
|
+
this.logger.debug('showing section')
|
|
301
|
+
|
|
302
|
+
/* Restore the pages context, if present */
|
|
303
|
+
if (this._savedPagesContext) {
|
|
304
|
+
this.logger.debug('restoring pages context')
|
|
305
|
+
setCurrentContext(this._savedPagesContext)
|
|
306
|
+
this._savedPagesContext = null
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* Create and push the main page if not already created */
|
|
310
|
+
if (!this._mainPage) {
|
|
311
|
+
this._makeAndPushMainPage()
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
this._button.addClass('selected')
|
|
315
|
+
this.handleShow(source, prevSection)
|
|
316
|
+
|
|
317
|
+
return this.whenLoaded().then(function () {
|
|
318
|
+
|
|
319
|
+
/* Start loading the main page when pushed, but don't wait for result */
|
|
320
|
+
this._mainPage.whenLoaded()
|
|
321
|
+
|
|
322
|
+
}.bind(this))
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
_hide(historyEntry) {
|
|
326
|
+
this.logger.debug('hiding section')
|
|
327
|
+
return this.handleHide().then(function () {
|
|
328
|
+
this._savedPagesContext = getCurrentContext()
|
|
329
|
+
this._button.removeClass('selected')
|
|
330
|
+
|
|
331
|
+
if (historyEntry) {
|
|
332
|
+
Navigation.addHistoryEntry()
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
setCurrentContext(null)
|
|
336
|
+
}.bind(this)).catch(function (e) {
|
|
337
|
+
if (e == null) {
|
|
338
|
+
e = new Sections.HideCancelled()
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (e instanceof Sections.HideCancelled) {
|
|
342
|
+
this.logger.debug('hiding cancelled')
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
throw e
|
|
346
|
+
}.bind(this))
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Tell if this section is the current section or not.
|
|
351
|
+
* @returns {Boolean}
|
|
352
|
+
*/
|
|
353
|
+
isCurrent() {
|
|
354
|
+
return Sections.getCurrent() === this
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Return the current page of this section.
|
|
359
|
+
* @returns {?qui.pages.PageMixin}
|
|
360
|
+
*/
|
|
361
|
+
getCurrentPage() {
|
|
362
|
+
let context = this.getPagesContext()
|
|
363
|
+
return context ? context.getCurrentPage() : null
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Return the pages context of this section.
|
|
368
|
+
* @returns {?qui.pages.PagesContext}
|
|
369
|
+
*/
|
|
370
|
+
getPagesContext() {
|
|
371
|
+
/* A hidden section has its pages context stored in _savedPagesContext. A visible (current) section owns the
|
|
372
|
+
* current pages context. */
|
|
373
|
+
|
|
374
|
+
if (this.isCurrent()) {
|
|
375
|
+
return getCurrentContext()
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
return this._savedPagesContext
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
/* Title, icon & button */
|
|
384
|
+
|
|
385
|
+
_makeSectionButton() {
|
|
386
|
+
let button = $('<div></div>', {class: 'qui-base-button qui-section-button'})
|
|
387
|
+
button.append($('<div></div>', {class: 'qui-icon'}))
|
|
388
|
+
button.append($('<span></span>', {class: 'label'}))
|
|
389
|
+
|
|
390
|
+
button.addClass(this._id)
|
|
391
|
+
button.css('order', this._index * 10)
|
|
392
|
+
|
|
393
|
+
switch (this._buttonType) {
|
|
394
|
+
case Sections.BUTTON_TYPE_MENU_BAR:
|
|
395
|
+
button.find('.label').html(this._title)
|
|
396
|
+
break
|
|
397
|
+
|
|
398
|
+
case Sections.BUTTON_TYPE_TOP_BAR:
|
|
399
|
+
button.find('.label').remove()
|
|
400
|
+
button.attr('title', this._title)
|
|
401
|
+
break
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return button
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
_addSectionButton() {
|
|
408
|
+
switch (this._buttonType) {
|
|
409
|
+
case Sections.BUTTON_TYPE_MENU_BAR:
|
|
410
|
+
MenuBar.addButton(this._button)
|
|
411
|
+
break
|
|
412
|
+
|
|
413
|
+
case Sections.BUTTON_TYPE_TOP_BAR:
|
|
414
|
+
TopBar.addButton(this._button)
|
|
415
|
+
break
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Show or hide the section button.
|
|
421
|
+
* @param {Boolean} visible
|
|
422
|
+
*/
|
|
423
|
+
setButtonVisibility(visible) {
|
|
424
|
+
this._button.toggle(visible)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Return the section icon.
|
|
429
|
+
* @returns {qui.icons.Icon}
|
|
430
|
+
*/
|
|
431
|
+
getIcon() {
|
|
432
|
+
return this._icon
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Set the section icon.
|
|
437
|
+
* @param {qui.icons.Icon} icon the new icon
|
|
438
|
+
*/
|
|
439
|
+
setIcon(icon) {
|
|
440
|
+
this._icon = icon
|
|
441
|
+
this._applyIcon()
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
_applyIcon() {
|
|
445
|
+
let icon = this._icon
|
|
446
|
+
|
|
447
|
+
if (icon instanceof StockIcon) {
|
|
448
|
+
switch (this._buttonType) {
|
|
449
|
+
case Sections.BUTTON_TYPE_MENU_BAR:
|
|
450
|
+
icon = icon.alterDefault({
|
|
451
|
+
variant: 'interactive',
|
|
452
|
+
activeVariant: 'interactive',
|
|
453
|
+
selectedVariant: 'background'
|
|
454
|
+
})
|
|
455
|
+
break
|
|
456
|
+
|
|
457
|
+
case Sections.BUTTON_TYPE_TOP_BAR:
|
|
458
|
+
icon = icon.alterDefault({variant: Window.isSmallScreen() ? 'white' : 'interactive'})
|
|
459
|
+
break
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/* Following css manipulations are a workaround for properly detecting decoration background */
|
|
464
|
+
let origSelected = this._button.hasClass('selected')
|
|
465
|
+
|
|
466
|
+
this._button.css('transition', 'none')
|
|
467
|
+
this._button.removeClass('selected')
|
|
468
|
+
|
|
469
|
+
this._button.find('.qui-icon').empty()
|
|
470
|
+
icon.applyTo(this._button.find('.qui-icon'))
|
|
471
|
+
|
|
472
|
+
this._button.css('transition', '')
|
|
473
|
+
if (origSelected) {
|
|
474
|
+
this._button.addClass('selected')
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
this._icon = icon
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Return the title of this section.
|
|
482
|
+
* @returns {String}
|
|
483
|
+
*/
|
|
484
|
+
getTitle() {
|
|
485
|
+
return this._title
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Set the title of this section.
|
|
490
|
+
* @param {String} title
|
|
491
|
+
*/
|
|
492
|
+
setTitle(title) {
|
|
493
|
+
this._title = title
|
|
494
|
+
if (this._button) {
|
|
495
|
+
this._button.find('.label').html(this._title)
|
|
496
|
+
this._button.attr('title', this._title)
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
/* Pages & navigation */
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Override this method to create the main section page.
|
|
505
|
+
* @returns {qui.pages.PageMixin} the section's main page
|
|
506
|
+
*/
|
|
507
|
+
makeMainPage() {
|
|
508
|
+
throw new NotImplementedError()
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Return the main page of this section.
|
|
513
|
+
* @returns {?qui.pages.PageMixin}
|
|
514
|
+
*/
|
|
515
|
+
getMainPage() {
|
|
516
|
+
return this._mainPage
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Push a new page onto the section's context. The page is not guaranteed to be pushed by the time the function
|
|
521
|
+
* exists.
|
|
522
|
+
* @param {qui.pages.PageMixin} page the page to be pushed
|
|
523
|
+
* @param {Boolean} [historyEntry] whether to create a new history entry for current page before adding the new
|
|
524
|
+
* page, or not (determined automatically by default, using new page's `pathId`)
|
|
525
|
+
* @returns {Promise} a promise that resolves as soon as the page is pushed, or rejected if the page cannot be
|
|
526
|
+
* pushed
|
|
527
|
+
*/
|
|
528
|
+
pushPage(page, historyEntry = null) {
|
|
529
|
+
/* By default, pages with pathId will add a new history entry */
|
|
530
|
+
if (historyEntry == null) {
|
|
531
|
+
historyEntry = !!page.getPathId()
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
let context = this.getPagesContext()
|
|
535
|
+
if (!context) {
|
|
536
|
+
throw new AssertionError('Attempt to push page to uninitialized section')
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (!context.isCurrent()) {
|
|
540
|
+
historyEntry = false
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
let currentPage = context.getCurrentPage()
|
|
544
|
+
if (currentPage) {
|
|
545
|
+
return currentPage.pushPage(page, historyEntry)
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
page.pushSelf(context)
|
|
549
|
+
page.whenLoaded() /* Start loading the page automatically when pushed */
|
|
550
|
+
|
|
551
|
+
if (historyEntry) {
|
|
552
|
+
Navigation.addHistoryEntry()
|
|
553
|
+
}
|
|
554
|
+
else if (context.isCurrent()) {
|
|
555
|
+
Navigation.updateHistoryEntry()
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return Promise.resolve()
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Reset the section to its initial state, closing all pages, including the main page.
|
|
564
|
+
* @returns {Promise} a promise that is resolved as soon as the section is reset and the main page is loaded
|
|
565
|
+
*/
|
|
566
|
+
reset() {
|
|
567
|
+
this.logger.debug('resetting section')
|
|
568
|
+
|
|
569
|
+
let promise = Promise.resolve()
|
|
570
|
+
if (this._mainPage) {
|
|
571
|
+
/* Close main page and all following pages */
|
|
572
|
+
promise = this._mainPage.close(/* force = */ true)
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
this.onReset()
|
|
576
|
+
|
|
577
|
+
/* Also re-apply button icon, as theme might have been changed */
|
|
578
|
+
this._applyIcon()
|
|
579
|
+
|
|
580
|
+
return promise.then(function () {
|
|
581
|
+
this._mainPage = null
|
|
582
|
+
if (this.isCurrent()) {
|
|
583
|
+
this._makeAndPushMainPage()
|
|
584
|
+
return this.whenLoaded().then(function () {
|
|
585
|
+
/* Start loading the main page when pushed, but don't wait for result */
|
|
586
|
+
return this._mainPage.whenLoaded()
|
|
587
|
+
}.bind(this))
|
|
588
|
+
}
|
|
589
|
+
}.bind(this))
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Called whenever the section is reset.
|
|
594
|
+
*/
|
|
595
|
+
onReset() {
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Override this to implement redirects from this section when switching to it using
|
|
600
|
+
* {@link qui.navigation.navigate}. By default it returns this section.
|
|
601
|
+
*
|
|
602
|
+
* @param {String[]} path the requested navigation path
|
|
603
|
+
* @returns {qui.sections.Section|Promise<qui.sections.Section>} the new section
|
|
604
|
+
*/
|
|
605
|
+
navigate(path) {
|
|
606
|
+
return this
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
export default Section
|