@qtoggle/qui 1.18.3 → 1.19.1
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/.github/workflows/main.yml +11 -5
- package/js/forms/form.js +3 -11
- package/js/index.js +17 -2
- package/js/lists/common-items/icon-label-list-item.js +2 -9
- package/js/utils/debouncer.js +44 -0
- package/less/all.less +39 -0
- package/package.json +18 -15
- package/pyproject.toml +2 -3
- package/webpack/webpack-common.js +3 -3
|
@@ -2,6 +2,10 @@ name: Main
|
|
|
2
2
|
|
|
3
3
|
on: push
|
|
4
4
|
|
|
5
|
+
permissions:
|
|
6
|
+
id-token: write
|
|
7
|
+
contents: write
|
|
8
|
+
|
|
5
9
|
jobs:
|
|
6
10
|
lint:
|
|
7
11
|
name: Lint
|
|
@@ -24,6 +28,10 @@ jobs:
|
|
|
24
28
|
uses: actions/checkout@v4
|
|
25
29
|
- name: Replace source version
|
|
26
30
|
uses: qtoggle/actions-common/actions/replace-source-version@v1
|
|
31
|
+
- name: Setup NodeJS
|
|
32
|
+
uses: actions/setup-node@v4
|
|
33
|
+
with:
|
|
34
|
+
node-version: '18'
|
|
27
35
|
- name: Install
|
|
28
36
|
run: |
|
|
29
37
|
npm install && rm -rf docs/* js/lib/* && npx jsdoc -c jsdoc.conf.json
|
|
@@ -55,19 +63,17 @@ jobs:
|
|
|
55
63
|
- name: Setup NodeJS
|
|
56
64
|
uses: actions/setup-node@v4
|
|
57
65
|
with:
|
|
58
|
-
node-version: '
|
|
66
|
+
node-version: '20'
|
|
59
67
|
- name: Publish to NPM
|
|
60
68
|
run: |
|
|
61
|
-
|
|
69
|
+
npm install -g npm@latest &&
|
|
62
70
|
npm publish
|
|
63
|
-
env:
|
|
64
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
65
71
|
- name: Fetch python dist folder
|
|
66
72
|
uses: actions/download-artifact@v4
|
|
67
73
|
with:
|
|
68
74
|
name: python-package-dist
|
|
69
75
|
path: dist/
|
|
70
|
-
- name: Publish
|
|
76
|
+
- name: Publish to PyPI
|
|
71
77
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
72
78
|
with:
|
|
73
79
|
user: __token__
|
package/js/forms/form.js
CHANGED
|
@@ -4,6 +4,7 @@ import $ from '$qui/lib/jquery.module.js'
|
|
|
4
4
|
import {AssertionError} from '$qui/base/errors.js'
|
|
5
5
|
import {mix} from '$qui/base/mixwith.js'
|
|
6
6
|
import * as Theme from '$qui/theme.js'
|
|
7
|
+
import Debouncer from '$qui/utils/debouncer.js'
|
|
7
8
|
import {asap} from '$qui/utils/misc.js'
|
|
8
9
|
import * as ObjectUtils from '$qui/utils/object.js'
|
|
9
10
|
import {ProgressViewMixin} from '$qui/views/common-views/common-views.js'
|
|
@@ -78,7 +79,7 @@ class Form extends mix().with(ViewMixin, StructuredViewMixin, ProgressViewMixin)
|
|
|
78
79
|
/* Last known validity state */
|
|
79
80
|
this._isValid = null
|
|
80
81
|
this._validationCache = {}
|
|
81
|
-
this.
|
|
82
|
+
this._updateValidationStateDebouncer = new Debouncer(() => this.updateValidationState())
|
|
82
83
|
|
|
83
84
|
this._fieldsByName = {}
|
|
84
85
|
|
|
@@ -737,16 +738,7 @@ class Form extends mix().with(ViewMixin, StructuredViewMixin, ProgressViewMixin)
|
|
|
737
738
|
* Calls {@link qui.forms.Form#updateValidationState} asap, preventing multiple unnecessary successive calls.
|
|
738
739
|
*/
|
|
739
740
|
updateValidationStateASAP() {
|
|
740
|
-
|
|
741
|
-
clearTimeout(this._updateValidationStateASAPHandle)
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
this._updateValidationStateASAPHandle = asap(function () {
|
|
745
|
-
|
|
746
|
-
this._updateValidationStateASAPHandle = null
|
|
747
|
-
this.updateValidationState()
|
|
748
|
-
|
|
749
|
-
}.bind(this))
|
|
741
|
+
this._updateValidationStateDebouncer.call()
|
|
750
742
|
}
|
|
751
743
|
|
|
752
744
|
/**
|
package/js/index.js
CHANGED
|
@@ -44,6 +44,8 @@ const logger = Logger.get('qui')
|
|
|
44
44
|
*/
|
|
45
45
|
export let whenReady = new ConditionVariable()
|
|
46
46
|
|
|
47
|
+
let globalErrorMessageForm = null
|
|
48
|
+
|
|
47
49
|
|
|
48
50
|
function initConfig() {
|
|
49
51
|
/* Look for the main script name */
|
|
@@ -177,6 +179,11 @@ function configureGlobalErrorHandling() {
|
|
|
177
179
|
return
|
|
178
180
|
}
|
|
179
181
|
|
|
182
|
+
/* Don't show another global error message on top of an existing one */
|
|
183
|
+
if (globalErrorMessageForm != null) {
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
|
|
180
187
|
logger.error(`unhandled promise rejection: ${e.reason || '<unspecified reason>'}`)
|
|
181
188
|
if (e.reason != null) {
|
|
182
189
|
logger.error(e.reason)
|
|
@@ -186,8 +193,16 @@ function configureGlobalErrorHandling() {
|
|
|
186
193
|
let msg = gettext('An unexpected error occurred.')
|
|
187
194
|
msg += '<br>'
|
|
188
195
|
msg += gettext('Application reloading is recommended.')
|
|
189
|
-
new StickySimpleMessageForm(
|
|
190
|
-
|
|
196
|
+
globalErrorMessageForm = new StickySimpleMessageForm(
|
|
197
|
+
{
|
|
198
|
+
type: 'error',
|
|
199
|
+
message: msg,
|
|
200
|
+
onClose: function () {
|
|
201
|
+
globalErrorMessageForm = null
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
)
|
|
205
|
+
globalErrorMessageForm.show()
|
|
191
206
|
})
|
|
192
207
|
}
|
|
193
208
|
|
|
@@ -7,9 +7,6 @@ import ListItem from '../list-item.js'
|
|
|
7
7
|
import * as Lists from '../lists.js'
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
const PHRASE_SPLIT_REGEX = /[^a-zA-Z0-9]/
|
|
11
|
-
|
|
12
|
-
|
|
13
10
|
/**
|
|
14
11
|
* A list item made of an icon and a label.
|
|
15
12
|
* @alias qui.lists.commonitems.IconLabelListItem
|
|
@@ -43,13 +40,9 @@ class IconLabelListItem extends mix(ListItem).with(IconLabelViewMixin) {
|
|
|
43
40
|
|
|
44
41
|
getMatchPhrase() {
|
|
45
42
|
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
|
-
]
|
|
43
|
+
this._matchPhrase = []
|
|
51
44
|
|
|
52
|
-
/*
|
|
45
|
+
/* Consider the entire label as is */
|
|
53
46
|
if (this.getLabel()) {
|
|
54
47
|
this._matchPhrase.push(this.getLabel().toLowerCase())
|
|
55
48
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* A class that debounces function calls, ensuring that a function is not called more often than a specified delay.
|
|
4
|
+
* @alias qui.utils.Debouncer
|
|
5
|
+
*/
|
|
6
|
+
class Debouncer {
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @constructs
|
|
10
|
+
* @param {Function} func the function to debounce
|
|
11
|
+
* @param {Number} [delay] the debouncing delay, in milliseconds (defaults to `0`)
|
|
12
|
+
*/
|
|
13
|
+
constructor(func, delay = 0) {
|
|
14
|
+
this._func = func
|
|
15
|
+
this._delay = delay
|
|
16
|
+
this._timeoutHandle = null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Call function ensuring debouncing condition. Any previous pending call is cancelled.
|
|
21
|
+
* Arguments are passed to the function when called.
|
|
22
|
+
*/
|
|
23
|
+
call(...args) {
|
|
24
|
+
if (this._timeoutHandle !== null) {
|
|
25
|
+
clearTimeout(this._timeoutHandle)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this._timeoutHandle = setTimeout(function () {
|
|
29
|
+
this._timeoutHandle = null
|
|
30
|
+
this._func(...args)
|
|
31
|
+
}.bind(this), this._delay)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Tell if there is a pending call.
|
|
36
|
+
* @return {Boolean}
|
|
37
|
+
*/
|
|
38
|
+
isPending() {
|
|
39
|
+
return this._timeoutHandle != null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default Debouncer
|
package/less/all.less
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
@import "base.less";
|
|
2
|
+
@import "main-ui.less";
|
|
3
|
+
@import "no-effects.less";
|
|
4
|
+
@import "visibility-manager.less";
|
|
5
|
+
@import "icons.less";
|
|
6
|
+
|
|
7
|
+
@import "widgets/check-button.less";
|
|
8
|
+
@import "widgets/choice-buttons.less";
|
|
9
|
+
@import "widgets/color-combo.less";
|
|
10
|
+
@import "widgets/combo.less";
|
|
11
|
+
@import "widgets/common.less";
|
|
12
|
+
@import "widgets/common-buttons.less";
|
|
13
|
+
@import "widgets/labels.less";
|
|
14
|
+
@import "widgets/progress-disk.less";
|
|
15
|
+
@import "widgets/slider.less";
|
|
16
|
+
@import "widgets/input.less";
|
|
17
|
+
@import "widgets/updown.less";
|
|
18
|
+
@import "widgets/various.less";
|
|
19
|
+
|
|
20
|
+
@import "messages.less";
|
|
21
|
+
@import "global-glass.less";
|
|
22
|
+
@import "structured-view.less";
|
|
23
|
+
@import "progress-view.less";
|
|
24
|
+
@import "icon-label-view.less";
|
|
25
|
+
|
|
26
|
+
@import "pages/breadcrumbs.less";
|
|
27
|
+
@import "pages/common-pages.less";
|
|
28
|
+
@import "pages/page.less";
|
|
29
|
+
|
|
30
|
+
@import "forms/common-fields.less";
|
|
31
|
+
@import "forms/common-forms.less";
|
|
32
|
+
@import "forms/form.less";
|
|
33
|
+
@import "forms/form-button.less";
|
|
34
|
+
@import "forms/form-field.less";
|
|
35
|
+
|
|
36
|
+
@import "lists.less";
|
|
37
|
+
@import "tables.less";
|
|
38
|
+
|
|
39
|
+
@import "theme.less";
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qtoggle/qui",
|
|
3
3
|
"description": "A JavaScript UI library with batteries included.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.19.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Calin Crisan",
|
|
7
7
|
"email": "ccrisan@gmail.com"
|
|
8
8
|
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"url": "https://github.com/qtoggle/qui.git"
|
|
11
|
+
},
|
|
9
12
|
"keywords": [],
|
|
10
13
|
"license": "Apache-2.0",
|
|
11
14
|
"dependencies": {
|
|
@@ -16,30 +19,30 @@
|
|
|
16
19
|
"pepjs": "*"
|
|
17
20
|
},
|
|
18
21
|
"devDependencies": {
|
|
19
|
-
"@babel/core": "
|
|
20
|
-
"@babel/plugin-proposal-class-properties": "
|
|
21
|
-
"@babel/preset-env": "
|
|
22
|
+
"@babel/core": "*",
|
|
23
|
+
"@babel/plugin-proposal-class-properties": "*",
|
|
24
|
+
"@babel/preset-env": "*",
|
|
22
25
|
"@babel/eslint-parser": "*",
|
|
23
26
|
"babel-loader": "^8",
|
|
24
27
|
"css-loader": "^3",
|
|
25
28
|
"eslint": "^9",
|
|
26
|
-
"expose-loader": "^
|
|
27
|
-
"file-loader": "
|
|
28
|
-
"glob": "
|
|
29
|
+
"expose-loader": "^1",
|
|
30
|
+
"file-loader": "*",
|
|
31
|
+
"glob": "*",
|
|
29
32
|
"jsdoc": "^3",
|
|
30
|
-
"jsdoc-export-default-interop": "
|
|
31
|
-
"jsdoc-typeof-plugin": "
|
|
32
|
-
"less": "
|
|
33
|
+
"jsdoc-export-default-interop": "*",
|
|
34
|
+
"jsdoc-typeof-plugin": "*",
|
|
35
|
+
"less": "*",
|
|
33
36
|
"less-loader": "^6",
|
|
34
|
-
"mini-css-extract-plugin": "^
|
|
35
|
-
"optimize-css-assets-webpack-plugin": "
|
|
37
|
+
"mini-css-extract-plugin": "^1",
|
|
38
|
+
"optimize-css-assets-webpack-plugin": "*",
|
|
36
39
|
"string-replace-loader": "^2",
|
|
37
40
|
"terser-webpack-plugin": "^3",
|
|
38
41
|
"webpack": "^4",
|
|
39
42
|
"webpack-cli": "^3",
|
|
40
|
-
"webpack-fix-style-only-entries": "
|
|
41
|
-
"webpack-inject-plugin": "
|
|
42
|
-
"webpack-shell-plugin": "
|
|
43
|
+
"webpack-fix-style-only-entries": "*",
|
|
44
|
+
"webpack-inject-plugin": "*",
|
|
45
|
+
"webpack-shell-plugin": "*"
|
|
43
46
|
},
|
|
44
47
|
"scripts": {
|
|
45
48
|
"postinstall": "scripts/postinstall.sh"
|
package/pyproject.toml
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "qui-server"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.19.1"
|
|
4
4
|
description = "A fully fledged qToggle implementation written in Python"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Calin Crisan", email = "ccrisan@gmail.com"},
|
|
7
7
|
]
|
|
8
|
-
requires-python = "
|
|
8
|
+
requires-python = ">=3.11"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "Apache 2.0"}
|
|
11
11
|
dependencies = [
|
|
@@ -28,7 +28,6 @@ package = true
|
|
|
28
28
|
|
|
29
29
|
[tool.ruff]
|
|
30
30
|
line-length = 120
|
|
31
|
-
target-version = "py310"
|
|
32
31
|
lint.extend-select = ["I", "RUF022"]
|
|
33
32
|
lint.isort.lines-after-imports = 2
|
|
34
33
|
lint.isort.lines-between-types = 1
|
|
@@ -125,7 +125,7 @@ function makeLessRule({type, theme, isProduction, appName, appFullPath, quiFullP
|
|
|
125
125
|
if (isProduction) {
|
|
126
126
|
loaders = [
|
|
127
127
|
MiniCssExtractPlugin.loader,
|
|
128
|
-
cssLoader
|
|
128
|
+
cssLoader
|
|
129
129
|
]
|
|
130
130
|
}
|
|
131
131
|
else { /* Development mode */
|
|
@@ -232,8 +232,8 @@ function makeConfig({theme, isProduction, appName, appFullPath, extraAliases, cs
|
|
|
232
232
|
|
|
233
233
|
let excludeLessRegex = new RegExp('theme-(' + THEMES.join('|') + ')\\.less', 'i')
|
|
234
234
|
let cssRequirements = [
|
|
235
|
-
|
|
236
|
-
|
|
235
|
+
quiLessPath + '/all.less',
|
|
236
|
+
appLessPath + '/all.less'
|
|
237
237
|
]
|
|
238
238
|
|
|
239
239
|
/* This is needed because FixStyleOnlyEntriesPlugin() needs resources for theme entries to be different */
|