@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,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @namespace qui.icons.stocks
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import Logger from '$qui/lib/logger.module.js'
|
|
6
|
+
|
|
7
|
+
import * as Theme from '$qui/theme.js'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const logger = Logger.get('qui.icons')
|
|
11
|
+
|
|
12
|
+
let stocks = {}
|
|
13
|
+
let stockMakers = []
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
function makeStocks() {
|
|
17
|
+
Object.values(stockMakers).forEach(function ({name, stockMaker}) {
|
|
18
|
+
logger.debug(`making stock "${name}"`)
|
|
19
|
+
let stock = stocks[name] = stockMaker()
|
|
20
|
+
stock.prepare()
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Lookup and return an icon stock by its name.
|
|
27
|
+
* @alias qui.icons.stocks.get
|
|
28
|
+
* @param {String} name
|
|
29
|
+
* @returns {qui.icons.Stock}
|
|
30
|
+
*/
|
|
31
|
+
export function get(name) {
|
|
32
|
+
return stocks[name]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Register an icon stock.
|
|
37
|
+
* @alias qui.icons.stocks.register
|
|
38
|
+
* @param {String} name stock name
|
|
39
|
+
* @param {Function} stockMaker a function that creates the stock
|
|
40
|
+
*/
|
|
41
|
+
export function register(name, stockMaker) {
|
|
42
|
+
stockMakers.push({name: name, stockMaker: stockMaker})
|
|
43
|
+
logger.debug(`registering stock "${name}"`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Initialize icon stocks.
|
|
48
|
+
* @alias qui.icons.stocks.init
|
|
49
|
+
*/
|
|
50
|
+
export function init() {
|
|
51
|
+
makeStocks()
|
|
52
|
+
|
|
53
|
+
Theme.changeSignal.connect(function () {
|
|
54
|
+
stocks = {}
|
|
55
|
+
makeStocks()
|
|
56
|
+
})
|
|
57
|
+
}
|
package/js/index.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @namespace qui
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as RequireJSCompat from '$qui/base/require-js-compat.js'
|
|
6
|
+
import $ from '$qui/lib/jquery.module.js'
|
|
7
|
+
import Logger from '$qui/lib/logger.module.js'
|
|
8
|
+
|
|
9
|
+
import '$qui/lib/jquery-ui.js'
|
|
10
|
+
import '$qui/lib/jquery.mousewheel.js'
|
|
11
|
+
import '$qui/lib/jquery.longpress.js'
|
|
12
|
+
import '$qui/lib/pep.js'
|
|
13
|
+
|
|
14
|
+
import {globalize} from '$qui/base/base.js'
|
|
15
|
+
import ConditionVariable from '$qui/base/condition-variable.js'
|
|
16
|
+
import {CancelledError} from '$qui/base/errors.js'
|
|
17
|
+
import {gettext} from '$qui/base/i18n.js'
|
|
18
|
+
import Config from '$qui/config.js'
|
|
19
|
+
import * as Forms from '$qui/forms/forms.js'
|
|
20
|
+
import * as GlobalGlass from '$qui/global-glass.js'
|
|
21
|
+
import * as Icons from '$qui/icons/icons.js'
|
|
22
|
+
import * as MainUI from '$qui/main-ui/main-ui.js'
|
|
23
|
+
import * as Status from '$qui/main-ui/status.js'
|
|
24
|
+
import {StickySimpleMessageForm} from '$qui/messages/common-message-forms/common-message-forms.js'
|
|
25
|
+
import * as Messages from '$qui/messages/messages.js'
|
|
26
|
+
import * as Navigation from '$qui/navigation.js'
|
|
27
|
+
import * as Pages from '$qui/pages/pages.js'
|
|
28
|
+
import * as PWA from '$qui/pwa.js'
|
|
29
|
+
import * as Sections from '$qui/sections/sections.js'
|
|
30
|
+
import * as Theme from '$qui/theme.js'
|
|
31
|
+
import * as ArrayUtils from '$qui/utils/array.js'
|
|
32
|
+
import * as DateUtils from '$qui/utils/date.js'
|
|
33
|
+
import * as ObjectUtils from '$qui/utils/object.js'
|
|
34
|
+
import * as Widgets from '$qui/widgets/widgets.js'
|
|
35
|
+
import * as Window from '$qui/window.js'
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
const logger = Logger.get('qui')
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A condition that is fulfilled as soon as the app is fully initialized and ready to be used.
|
|
42
|
+
* @alias qui.whenReady
|
|
43
|
+
* @type {qui.base.ConditionVariable}
|
|
44
|
+
*/
|
|
45
|
+
export let whenReady = new ConditionVariable()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
function initConfig() {
|
|
49
|
+
/* Look for the main script name */
|
|
50
|
+
let error = new Error()
|
|
51
|
+
let names = error.stack.match(new RegExp('[A-Za-z0-9_-]+\\.js', 'g'))
|
|
52
|
+
if (!names) {
|
|
53
|
+
throw new Error('Cannot find main script: empty stack')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let scripts = document.getElementsByTagName('script')
|
|
57
|
+
|
|
58
|
+
/* Find the reference to the main app DOM script */
|
|
59
|
+
let mainAppScriptName = names[names.length - 1]
|
|
60
|
+
let mainAppScript = Array.from(scripts).find(s => s.src.split('?')[0].endsWith(mainAppScriptName))
|
|
61
|
+
if (!mainAppScript) {
|
|
62
|
+
throw new Error(`Cannot find main script: no such script ${mainAppScriptName}`)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Deduce app name from main app script name */
|
|
66
|
+
let appName = mainAppScriptName.slice(0, -3) /* remove .js */
|
|
67
|
+
if (appName.endsWith('-bundle')) {
|
|
68
|
+
appName = appName.slice(0, -7)
|
|
69
|
+
}
|
|
70
|
+
if (appName === 'index') { /* development mode */
|
|
71
|
+
appName = 'qui-app'
|
|
72
|
+
}
|
|
73
|
+
Config.appName = appName
|
|
74
|
+
|
|
75
|
+
/* Copy all data-* attributes from script tag to Config */
|
|
76
|
+
ObjectUtils.forEach(mainAppScript.dataset, (n, v) => Config.set(n, v))
|
|
77
|
+
|
|
78
|
+
/* Find the URL to the QUI index */
|
|
79
|
+
let urls = error.stack.match(/http.*?\.js/gi)
|
|
80
|
+
if (!urls || !urls.length) {
|
|
81
|
+
throw new Error('Cannot find QUI index script: no script URLs found in stack')
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Detect QUI static URL - we know it's the first script in stack */
|
|
85
|
+
let quiIndexScript = urls[0]
|
|
86
|
+
let m = quiIndexScript.match(new RegExp('[.a-z0-9_-]+\\.js'))
|
|
87
|
+
if (!m) {
|
|
88
|
+
throw new Error('Cannot find QUI index script: no JS file found in stack')
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
Config.quiIndexName = quiIndexScript.split('/').slice(-1)[0]
|
|
92
|
+
Config.quiIndexName = Config.quiIndexName.split(':')[0] /* Remove :row:col */
|
|
93
|
+
Config.quiStaticURL = quiIndexScript.slice(0, m.index - 1)
|
|
94
|
+
/* In debug mode, we have an extra "/js" dir */
|
|
95
|
+
if (Config.debug) {
|
|
96
|
+
Config.quiStaticURL = Config.quiStaticURL.split('/').slice(0, -1).join('/')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Detect app static URL - we know it's the last script in stack */
|
|
100
|
+
let appIndexScript = urls.slice(-1)[0]
|
|
101
|
+
m = appIndexScript.match(new RegExp('[.a-z0-9_-]+\\.js'))
|
|
102
|
+
|
|
103
|
+
Config.appIndexName = appIndexScript.split('/').slice(-1)[0]
|
|
104
|
+
Config.appIndexName = Config.appIndexName.split(':')[0] /* Remove :row:col */
|
|
105
|
+
Config.appStaticURL = appIndexScript.slice(0, m.index - 1)
|
|
106
|
+
/* In debug mode, we have an extra "/js" dir */
|
|
107
|
+
if (Config.debug) {
|
|
108
|
+
Config.appStaticURL = Config.appStaticURL.split('/').slice(0, -1).join('/')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Use details supplied by webpack at build time */
|
|
112
|
+
if (window.__quiAppVersion) {
|
|
113
|
+
Config.appCurrentVersion = window.__quiAppVersion
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function initJQuery() {
|
|
118
|
+
function passivizeEvent(eventName) {
|
|
119
|
+
$.event.special[eventName] = {
|
|
120
|
+
setup: function (_, ns, handle) {
|
|
121
|
+
if (ns.includes('noPreventDefault')) {
|
|
122
|
+
this.addEventListener(eventName, handle, {passive: false})
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
this.addEventListener(eventName, handle, {passive: true})
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
passivizeEvent('touchstart')
|
|
132
|
+
passivizeEvent('touchmove')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function configureLogging() {
|
|
136
|
+
Logger.setHandler(Logger.createDefaultHandler({
|
|
137
|
+
formatter: function (messages, context) {
|
|
138
|
+
messages.unshift(`[${context.name}]`)
|
|
139
|
+
messages.unshift(`${context.level.name}:`)
|
|
140
|
+
messages.unshift(DateUtils.formatPercent(new Date(), '%Y-%m-%d %H:%M:%S:'))
|
|
141
|
+
}
|
|
142
|
+
}))
|
|
143
|
+
|
|
144
|
+
Logger.setLevel(Config.debug ? Logger.DEBUG : Logger.INFO)
|
|
145
|
+
|
|
146
|
+
/* Inject errorStack logger method */
|
|
147
|
+
Object.getPrototypeOf(logger).errorStack = function (msg, error) {
|
|
148
|
+
this.error(`${msg}: ${error ? error.toString() : '(no error supplied)'}`)
|
|
149
|
+
if (error && error.stack) {
|
|
150
|
+
this.error(error.stack)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* Unlimited stack trace */
|
|
155
|
+
Error.stackTraceLimit = Infinity
|
|
156
|
+
|
|
157
|
+
/* Export Logger to global scope */
|
|
158
|
+
let qui = (window.qui = window.qui || {})
|
|
159
|
+
qui.Logger = Logger
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function logCurrentConfig() {
|
|
163
|
+
ArrayUtils.sortKey(Object.entries(Config), e => e[0]).forEach(function ([key, value]) {
|
|
164
|
+
if (typeof value === 'function') {
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
logger.debug(`using Config.${key} = ${JSON.stringify(value)}`)
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function configureGlobalErrorHandling() {
|
|
173
|
+
window.addEventListener('unhandledrejection', function (e) {
|
|
174
|
+
/* Uncaught/unhandled cancelled errors are silently ignored */
|
|
175
|
+
if (e.reason instanceof CancelledError) {
|
|
176
|
+
e.preventDefault()
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
logger.error(`unhandled promise rejection: ${e.reason || '<unspecified reason>'}`)
|
|
181
|
+
if (e.reason != null) {
|
|
182
|
+
logger.error(e.reason)
|
|
183
|
+
}
|
|
184
|
+
logger.error(e.promise)
|
|
185
|
+
|
|
186
|
+
let msg = gettext('An unexpected error occurred.')
|
|
187
|
+
msg += '<br>'
|
|
188
|
+
msg += gettext('Application reloading is recommended.')
|
|
189
|
+
new StickySimpleMessageForm({type: 'error', message: msg}).show()
|
|
190
|
+
e.preventDefault()
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Initialize the QUI library.
|
|
197
|
+
* @alias qui.init
|
|
198
|
+
* @returns {Promise} a promise that resolves when QUI is initialized and ready
|
|
199
|
+
*/
|
|
200
|
+
export function init() {
|
|
201
|
+
RequireJSCompat.cleanup()
|
|
202
|
+
initConfig()
|
|
203
|
+
initJQuery()
|
|
204
|
+
configureLogging()
|
|
205
|
+
logCurrentConfig()
|
|
206
|
+
|
|
207
|
+
return Promise.resolve()
|
|
208
|
+
.then(() => Window.init())
|
|
209
|
+
.then(() => PWA.init())
|
|
210
|
+
.then(() => Theme.init())
|
|
211
|
+
.then(() => Icons.init())
|
|
212
|
+
.then(() => MainUI.init())
|
|
213
|
+
.then(() => Status.init())
|
|
214
|
+
.then(() => Widgets.init())
|
|
215
|
+
.then(() => Messages.init())
|
|
216
|
+
.then(() => GlobalGlass.init())
|
|
217
|
+
.then(() => Sections.init())
|
|
218
|
+
.then(() => Pages.init())
|
|
219
|
+
.then(() => Navigation.init())
|
|
220
|
+
.then(() => Forms.init())
|
|
221
|
+
.then(() => configureGlobalErrorHandling())
|
|
222
|
+
.then(function () {
|
|
223
|
+
whenReady.fulfill()
|
|
224
|
+
logger.debug('QUI is ready')
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* Make some modules accessible globally, via window */
|
|
229
|
+
import('$qui/config.js').then(globalize('qui.Config'))
|
|
230
|
+
import('$qui/lib/logger.module.js').then(globalize('qui.Logger'))
|
|
231
|
+
import('$qui/navigation.js').then(globalize('qui.navigation'))
|
|
232
|
+
import('$qui/sections/sections.js').then(globalize('qui.sections'))
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Longpress is a jQuery plugin that makes it easy to support long press
|
|
3
|
+
* events on mobile devices and desktop borwsers.
|
|
4
|
+
*
|
|
5
|
+
* @name longpress
|
|
6
|
+
* @version 0.1.2
|
|
7
|
+
* @requires jQuery v1.2.3+
|
|
8
|
+
* @author Vaidik Kapoor
|
|
9
|
+
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
|
|
10
|
+
*
|
|
11
|
+
* For usage and examples, check out the README at:
|
|
12
|
+
* http://github.com/vaidik/jquery-longpress/
|
|
13
|
+
*
|
|
14
|
+
* Copyright (c) 2008-2013, Vaidik Kapoor (kapoor [*dot*] vaidik -[at]- gmail [*dot*] com)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
(function($) {
|
|
18
|
+
$.fn.longpress = function(longCallback, shortCallback, duration) {
|
|
19
|
+
if (typeof duration === "undefined") {
|
|
20
|
+
duration = 500;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return this.each(function() {
|
|
24
|
+
var $this = $(this);
|
|
25
|
+
|
|
26
|
+
// to keep track of how long something was pressed
|
|
27
|
+
var mouse_down_time;
|
|
28
|
+
var timeout;
|
|
29
|
+
|
|
30
|
+
// mousedown or touchstart callback
|
|
31
|
+
function mousedown_callback(e) {
|
|
32
|
+
mouse_down_time = new Date().getTime();
|
|
33
|
+
var context = $(this);
|
|
34
|
+
|
|
35
|
+
// set a timeout to call the longpress callback when time elapses
|
|
36
|
+
timeout = setTimeout(function() {
|
|
37
|
+
if (typeof longCallback === "function") {
|
|
38
|
+
longCallback.call(context, e);
|
|
39
|
+
} else {
|
|
40
|
+
$.error('Callback required for long press. You provided: ' + typeof longCallback);
|
|
41
|
+
}
|
|
42
|
+
}, duration);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// mouseup or touchend callback
|
|
46
|
+
function mouseup_callback(e) {
|
|
47
|
+
var press_time = new Date().getTime() - mouse_down_time;
|
|
48
|
+
if (press_time < duration) {
|
|
49
|
+
// cancel the timeout
|
|
50
|
+
clearTimeout(timeout);
|
|
51
|
+
|
|
52
|
+
// call the shortCallback if provided
|
|
53
|
+
if (typeof shortCallback === "function") {
|
|
54
|
+
shortCallback.call($(this), e);
|
|
55
|
+
} else if (typeof shortCallback === "undefined") {
|
|
56
|
+
;
|
|
57
|
+
} else {
|
|
58
|
+
$.error('Optional callback for short press should be a function.');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// cancel long press event if the finger or mouse was moved
|
|
64
|
+
function move_callback(e) {
|
|
65
|
+
clearTimeout(timeout);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Browser Support
|
|
69
|
+
$this.on('mousedown', mousedown_callback);
|
|
70
|
+
$this.on('mouseup', mouseup_callback);
|
|
71
|
+
$this.on('mousemove', move_callback);
|
|
72
|
+
|
|
73
|
+
// Mobile Support
|
|
74
|
+
$this.on('touchstart', mousedown_callback);
|
|
75
|
+
$this.on('touchend', mouseup_callback);
|
|
76
|
+
$this.on('touchmove', move_callback);
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
}(jQuery));
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
|
|
2
|
+
import {mix} from '$qui/base/mixwith.js'
|
|
3
|
+
import * as StringUtils from '$qui/utils/string.js'
|
|
4
|
+
import {IconLabelViewMixin} from '$qui/views/common-views/common-views.js'
|
|
5
|
+
|
|
6
|
+
import ListItem from '../list-item.js'
|
|
7
|
+
import * as Lists from '../lists.js'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const PHRASE_SPLIT_REGEX = /[^a-zA-Z0-9]/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A list item made of an icon and a label.
|
|
15
|
+
* @alias qui.lists.commonitems.IconLabelListItem
|
|
16
|
+
* @extends qui.lists.ListItem
|
|
17
|
+
* @mixes qui.views.commonviews.IconLabelViewMixin
|
|
18
|
+
*/
|
|
19
|
+
class IconLabelListItem extends mix(ListItem).with(IconLabelViewMixin) {
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @constructs
|
|
23
|
+
* @param {...*} args parent class parameters
|
|
24
|
+
*/
|
|
25
|
+
constructor({...args} = {}) {
|
|
26
|
+
super(args)
|
|
27
|
+
|
|
28
|
+
this._matchPhrase = null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
makeContent() {
|
|
32
|
+
return this.getIconLabelContainer()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
setSelected(selected) {
|
|
36
|
+
super.setSelected(selected)
|
|
37
|
+
this.getIconLabelContainer().toggleClass('selected', selected)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
setSelectMode(selectMode) {
|
|
41
|
+
this.setClickable(selectMode !== Lists.LIST_SELECT_MODE_DISABLED)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getMatchPhrase() {
|
|
45
|
+
if (this._matchPhrase == null) {
|
|
46
|
+
this._matchPhrase =
|
|
47
|
+
this._matchPhrase = [
|
|
48
|
+
...this.getLabel().split(PHRASE_SPLIT_REGEX),
|
|
49
|
+
...this.getSubLabel().split(PHRASE_SPLIT_REGEX)
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
/* Also consider the entire label as is */
|
|
53
|
+
if (this.getLabel()) {
|
|
54
|
+
this._matchPhrase.push(this.getLabel().toLowerCase())
|
|
55
|
+
}
|
|
56
|
+
if (this.getSubLabel()) {
|
|
57
|
+
this._matchPhrase.push(this.getSubLabel().toLowerCase())
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this._matchPhrase = this._matchPhrase.filter(p => Boolean(p))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return this._matchPhrase
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
isMatch(filter) {
|
|
67
|
+
return this.getMatchPhrase().some(p => StringUtils.intelliSearch(p, filter) != null)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
/* Override set*Label() to invalidate cached matchPhrase */
|
|
72
|
+
|
|
73
|
+
setLabel(label) {
|
|
74
|
+
super.setLabel(label)
|
|
75
|
+
this._matchPhrase = null
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
setSubLabel(subLabel) {
|
|
79
|
+
super.setSubLabel(subLabel)
|
|
80
|
+
this._matchPhrase = null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
export default IconLabelListItem
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
import {mix} from '$qui/base/mixwith.js'
|
|
3
|
+
import StockIcon from '$qui/icons/stock-icon.js'
|
|
4
|
+
import PageMixin from '$qui/pages/page.js'
|
|
5
|
+
import * as ObjectUtils from '$qui/utils/object.js'
|
|
6
|
+
|
|
7
|
+
import List from '../list.js'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A list that can be used as a page.
|
|
12
|
+
* @alias qui.lists.commonlists.PageList
|
|
13
|
+
* @extends qui.lists.List
|
|
14
|
+
* @mixes qui.pages.PageMixin
|
|
15
|
+
*/
|
|
16
|
+
class PageList extends mix(List).with(PageMixin) {
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @constructs
|
|
20
|
+
* @param {...*} args parent class parameters
|
|
21
|
+
*/
|
|
22
|
+
constructor({...args} = {}) {
|
|
23
|
+
ObjectUtils.setDefault(args, 'transparent', false)
|
|
24
|
+
ObjectUtils.setDefault(args, 'topless', true)
|
|
25
|
+
|
|
26
|
+
super(args)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
prepareIcon(icon) {
|
|
30
|
+
/* Popup page views should normally have the default foreground icon color, even on small screens */
|
|
31
|
+
if (this.isPopup() && (icon instanceof StockIcon)) {
|
|
32
|
+
icon = icon.alterDefault({variant: 'foreground'})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return super.prepareIcon(icon)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
handleVertScroll() {
|
|
39
|
+
super.handleVertScroll()
|
|
40
|
+
this._updateVertScroll()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
_updateVertScroll() {
|
|
44
|
+
let params = this.getVertScrollParams()
|
|
45
|
+
|
|
46
|
+
/* Place progress widget in the viewport by pushing it down a bit */
|
|
47
|
+
this.getProgressWidget().css('margin-top', `${params.offset}px`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
export default PageList
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
|
|
2
|
+
import $ from '$qui/lib/jquery.module.js'
|
|
3
|
+
|
|
4
|
+
import {mix} from '$qui/base/mixwith.js'
|
|
5
|
+
import * as StringUtils from '$qui/utils/string.js'
|
|
6
|
+
import VisibilityManager from '$qui/utils/visibility-manager.js'
|
|
7
|
+
import ViewMixin from '$qui/views/view.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A list item.
|
|
11
|
+
* @alias qui.lists.ListItem
|
|
12
|
+
* @mixes qui.views.ViewMixin
|
|
13
|
+
*/
|
|
14
|
+
class ListItem extends mix().with(ViewMixin) {
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @constructs
|
|
18
|
+
* @param {*} [data] user data associated with the item
|
|
19
|
+
* @param {...*} args parent class parameters
|
|
20
|
+
*/
|
|
21
|
+
constructor({data = null, ...args} = {}) {
|
|
22
|
+
super(args)
|
|
23
|
+
|
|
24
|
+
this._data = data
|
|
25
|
+
this._list = null
|
|
26
|
+
this._visibilityManager = null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
makeHTML() {
|
|
30
|
+
let html = $('<div></div>', {class: 'qui-list-child qui-list-item'})
|
|
31
|
+
html.html(this.makeContent())
|
|
32
|
+
|
|
33
|
+
this._visibilityManager = new VisibilityManager({element: html})
|
|
34
|
+
|
|
35
|
+
return html
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Implement this method to create the actual list item content.
|
|
40
|
+
* @abstract
|
|
41
|
+
* @returns {jQuery}
|
|
42
|
+
*/
|
|
43
|
+
makeContent() {
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
/* User data */
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Return the item user data.
|
|
51
|
+
* @returns {*}
|
|
52
|
+
*/
|
|
53
|
+
getData() {
|
|
54
|
+
return this._data
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Set the item user data.
|
|
59
|
+
* @param {*} data
|
|
60
|
+
*/
|
|
61
|
+
setData(data) {
|
|
62
|
+
this._data = data
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Selection */
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Tell if item is selected or not.
|
|
69
|
+
*/
|
|
70
|
+
isSelected() {
|
|
71
|
+
return this.getHTML().hasClass('selected')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Select or deselect item.
|
|
76
|
+
* @param {Boolean} selected
|
|
77
|
+
*/
|
|
78
|
+
setSelected(selected) {
|
|
79
|
+
this.getHTML().toggleClass('selected', selected)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Set select mode. This is internally called by owning {@link qui.lists.List}.
|
|
84
|
+
* @param {String} selectMode one of:
|
|
85
|
+
* * {@link qui.lists.LIST_SELECT_MODE_DISABLED}
|
|
86
|
+
* * {@link qui.lists.LIST_SELECT_MODE_SINGLE} (default)
|
|
87
|
+
* * {@link qui.lists.LIST_SELECT_MODE_MULTIPLE}
|
|
88
|
+
*/
|
|
89
|
+
setSelectMode(selectMode) {
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
/* Visibility */
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Tell if the item is hidden.
|
|
97
|
+
* @returns {Boolean}
|
|
98
|
+
*/
|
|
99
|
+
isHidden() {
|
|
100
|
+
return !this._visibilityManager.isElementVisible()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Show the item.
|
|
105
|
+
*/
|
|
106
|
+
show() {
|
|
107
|
+
this._visibilityManager.showElement()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Hide the field.
|
|
112
|
+
*/
|
|
113
|
+
hide() {
|
|
114
|
+
this._visibilityManager.hideElement()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Tell if item matches a search filter. By default, uses {@link qui.utils.string.intelliSearch} on textual content
|
|
119
|
+
* of the HTML element.
|
|
120
|
+
* @param {String} filter search filter
|
|
121
|
+
* @returns {Boolean}
|
|
122
|
+
*/
|
|
123
|
+
isMatch(filter) {
|
|
124
|
+
let text = this.getHTML().text().trim().toLowerCase()
|
|
125
|
+
return StringUtils.intelliSearch(text, filter) != null
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Return the owning list.
|
|
130
|
+
* @returns {qui.lists.List}
|
|
131
|
+
*/
|
|
132
|
+
getList() {
|
|
133
|
+
return this._list
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Set the owning list.
|
|
138
|
+
* @param {qui.lists.List} list
|
|
139
|
+
*/
|
|
140
|
+
setList(list) {
|
|
141
|
+
this._list = list
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
export default ListItem
|