@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.
@@ -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: '18'
66
+ node-version: '20'
59
67
  - name: Publish to NPM
60
68
  run: |
61
- echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > ~/.npmrc
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 package
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._updateValidationStateASAPHandle = null
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
- if (this._updateValidationStateASAPHandle) {
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({type: 'error', message: msg}).show()
190
- e.preventDefault()
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
- /* Also consider the entire label as is */
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.18.3",
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": "^7",
20
- "@babel/plugin-proposal-class-properties": "^7",
21
- "@babel/preset-env": "^7",
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": "^0",
27
- "file-loader": "^6",
28
- "glob": "^7",
29
+ "expose-loader": "^1",
30
+ "file-loader": "*",
31
+ "glob": "*",
29
32
  "jsdoc": "^3",
30
- "jsdoc-export-default-interop": "^0",
31
- "jsdoc-typeof-plugin": "^1",
32
- "less": "^3",
33
+ "jsdoc-export-default-interop": "*",
34
+ "jsdoc-typeof-plugin": "*",
35
+ "less": "*",
33
36
  "less-loader": "^6",
34
- "mini-css-extract-plugin": "^0",
35
- "optimize-css-assets-webpack-plugin": "^5",
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": "^0",
41
- "webpack-inject-plugin": "^1",
42
- "webpack-shell-plugin": "^0"
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.18.3"
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 = "==3.10.*"
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
- ...requireFromDir(LESS_REGEX, quiLessPath, excludeLessRegex),
236
- ...requireFromDir(LESS_REGEX, appLessPath, excludeLessRegex)
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 */