@qooxdoo/framework 7.1.1 → 7.2.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.
Files changed (100) hide show
  1. package/Manifest.json +1 -1
  2. package/lib/compiler/compile-info.json +83 -83
  3. package/lib/compiler/index.js +279 -274
  4. package/lib/resource/qx/tool/cli/templates/skeleton/mobile/source/theme/custom/css/custom.css.map +1 -1
  5. package/npm-shrinkwrap.json +235 -11095
  6. package/package.json +6 -6
  7. package/source/class/qx/Interface.js +13 -15
  8. package/source/class/qx/dev/unit/MTestLoader.js +25 -33
  9. package/source/class/qx/dev/unit/TestResult.js +9 -13
  10. package/source/class/qx/html/Element.js +1 -1
  11. package/source/class/qx/html/Node.js +0 -1
  12. package/source/class/qx/io/request/AbstractRequest.js +42 -66
  13. package/source/class/qx/test/Interface.js +70 -6
  14. package/source/class/qx/test/Mixin.js +20 -17
  15. package/source/class/qx/test/Promise.js +67 -91
  16. package/source/class/qx/test/bom/History.js +11 -19
  17. package/source/class/qx/test/bom/WebWorker.js +7 -15
  18. package/source/class/qx/test/bom/media/MediaTestCase.js +10 -18
  19. package/source/class/qx/test/bom/media/Video.js +10 -18
  20. package/source/class/qx/test/bom/rest/Resource.js +3 -7
  21. package/source/class/qx/test/bom/rest/ResourceWithRemote.js +40 -56
  22. package/source/class/qx/test/bom/webfonts/Validator.js +12 -20
  23. package/source/class/qx/test/core/Object.js +3 -7
  24. package/source/class/qx/test/data/controller/List.js +18 -22
  25. package/source/class/qx/test/data/marshal/Json.js +10 -14
  26. package/source/class/qx/test/data/store/Json.js +337 -428
  27. package/source/class/qx/test/data/store/Jsonp.js +46 -66
  28. package/source/class/qx/test/data/store/RestWithRemote.js +10 -18
  29. package/source/class/qx/test/html/Element.js +4 -8
  30. package/source/class/qx/test/html/Iframe.js +48 -60
  31. package/source/class/qx/test/io/jsonrpc/Client.js +1 -1
  32. package/source/class/qx/test/io/request/JsonpWithRemote.js +6 -10
  33. package/source/class/qx/test/io/request/MRequest.js +13 -25
  34. package/source/class/qx/test/io/request/Xhr.js +5 -9
  35. package/source/class/qx/test/io/request/XhrWithRemote.js +50 -78
  36. package/source/class/qx/test/io/rest/Resource.js +3 -7
  37. package/source/class/qx/test/io/rest/ResourceWithRemote.js +41 -57
  38. package/source/class/qx/test/mobile/basic/Image.js +16 -24
  39. package/source/class/qx/test/mobile/container/Navigation.js +3 -7
  40. package/source/class/qx/test/mobile/container/Scroll.js +8 -12
  41. package/source/class/qx/test/mobile/page/Page.js +24 -44
  42. package/source/class/qx/test/performance/Property.js +2 -2
  43. package/source/class/qx/test/ui/basic/Image.js +32 -52
  44. package/source/class/qx/test/ui/core/Blocker.js +6 -14
  45. package/source/class/qx/test/ui/embed/Iframe.js +13 -21
  46. package/source/class/qx/test/ui/form/FileSelectorButton.js +32 -0
  47. package/source/class/qx/test/ui/form/FormValidator.js +147 -211
  48. package/source/class/qx/test/ui/form/Label.js +8 -16
  49. package/source/class/qx/test/ui/root/Inline.js +9 -13
  50. package/source/class/qx/test/ui/table/Table.js +6 -14
  51. package/source/class/qx/test/ui/toolbar/OverflowHandling.js +18 -30
  52. package/source/class/qx/test/ui/virtual/Pane.js +3 -7
  53. package/source/class/qx/test/util/DynamicScriptLoader.js +23 -42
  54. package/source/class/qx/theme/tangible/Appearance.js +22 -3
  55. package/source/class/qx/tool/cli/Watch.js +3 -7
  56. package/source/class/qx/tool/cli/api/AbstractApi.js +1 -1
  57. package/source/class/qx/tool/cli/api/CompilerApi.js +3 -7
  58. package/source/class/qx/tool/cli/commands/Compile.js +3 -3
  59. package/source/class/qx/tool/cli/commands/Lint.js +8 -5
  60. package/source/class/qx/tool/compiler/ClassFile.js +22 -12
  61. package/source/class/qx/tool/compiler/Es6ify.js +7 -3
  62. package/source/class/qx/tool/compiler/TargetError.js +3 -4
  63. package/source/class/qx/tool/compiler/app/Application.js +3 -3
  64. package/source/class/qx/tool/compiler/app/WebFont.js +8 -6
  65. package/source/class/qx/tool/compiler/targets/SourceCodeCopier.js +1 -1
  66. package/source/class/qx/tool/compiler/targets/Target.js +2 -1
  67. package/source/class/qx/tool/compiler/targets/meta/AbstractJavascriptMeta.js +1 -1
  68. package/source/class/qx/tool/compiler/targets/meta/Browserify.js +77 -83
  69. package/source/class/qx/tool/compiler/targets/meta/Uglify.js +11 -3
  70. package/source/class/qx/tool/utils/Website.js +2 -2
  71. package/source/class/qx/ui/basic/Label.js +13 -17
  72. package/source/class/qx/ui/core/MPlacement.js +13 -21
  73. package/source/class/qx/ui/core/Widget.js +2 -3
  74. package/source/class/qx/ui/core/scroll/NativeScrollBar.js +3 -7
  75. package/source/class/qx/ui/core/scroll/ScrollBar.js +3 -7
  76. package/source/class/qx/ui/embed/Iframe.js +40 -50
  77. package/source/class/qx/ui/form/AbstractField.js +8 -12
  78. package/source/class/qx/ui/form/ComboBox.js +7 -15
  79. package/source/class/qx/ui/form/DateField.js +9 -18
  80. package/source/class/qx/ui/form/FileSelectorButton.js +157 -0
  81. package/source/class/qx/ui/form/Spinner.js +7 -15
  82. package/source/class/qx/ui/form/TextArea.js +3 -7
  83. package/source/class/qx/ui/form/VirtualComboBox.js +8 -16
  84. package/source/class/qx/ui/form/VirtualSelectBox.js +21 -37
  85. package/source/class/qx/ui/layout/Canvas.js +2 -2
  86. package/source/class/qx/ui/mobile/container/MIScroll.js +3 -7
  87. package/source/class/qx/ui/progressive/headfoot/Progress.js +22 -34
  88. package/source/class/qx/ui/progressive/renderer/table/Row.js +1 -1
  89. package/source/class/qx/ui/splitpane/Pane.js +14 -22
  90. package/source/class/qx/ui/table/MTableContextMenu.js +63 -71
  91. package/source/class/qx/ui/table/Table.js +3 -7
  92. package/source/class/qx/ui/table/model/Abstract.js +5 -2
  93. package/source/class/qx/ui/table/pane/Scroller.js +8 -12
  94. package/source/class/qx/ui/toolbar/FileSelectorButton.js +57 -0
  95. package/source/class/qx/ui/toolbar/Part.js +3 -7
  96. package/source/class/qx/ui/tree/VirtualTree.js +5 -9
  97. package/source/class/qx/ui/treevirtual/MNode.js +5 -3
  98. package/source/class/qx/ui/treevirtual/TreeVirtual.js +3 -7
  99. package/source/class/qx/ui/virtual/core/Pane.js +30 -42
  100. package/source/class/qx/util/DynamicScriptLoader.js +31 -43
@@ -124,10 +124,18 @@ qx.Class.define("qx.tool.compiler.targets.meta.Uglify", {
124
124
  throw new Error("UglifyJS failed to minimise: " + (err.message || err));
125
125
  }
126
126
  await fs.writeFileAsync(outJsFilename, result.code, { encoding: "utf8" });
127
- await fs.writeFileAsync(outJsFilename + ".map", result.map, { encoding: "utf8" });
127
+ await fs.writeFileAsync(outJsFilename + ".map", result.map, {
128
+ encoding: "utf8"
129
+ });
128
130
  if (this._appMeta.getTarget().isSaveUnminified()) {
129
- await fs.writeFileAsync(outJsFilename + ".unminified", inSourceCode, { encoding: "utf8" });
130
- await fs.writeFileAsync(outJsFilename + ".unminified.map", JSON.stringify(inSourceMap, null, 2), { encoding: "utf8" });
131
+ await fs.writeFileAsync(outJsFilename + ".unminified", inSourceCode, {
132
+ encoding: "utf8"
133
+ });
134
+ await fs.writeFileAsync(
135
+ outJsFilename + ".unminified.map",
136
+ JSON.stringify(inSourceMap, null, 2),
137
+ { encoding: "utf8" }
138
+ );
131
139
  }
132
140
 
133
141
  this.fireDataEvent("minifiedApplication", {
@@ -25,8 +25,8 @@ const rimraf = require("rimraf");
25
25
  const dot = require("dot");
26
26
  require("jstransformer-dot");
27
27
  const metalsmith = require("metalsmith");
28
- const layouts = require("metalsmith-layouts");
29
- const markdown = require("metalsmith-markdown");
28
+ const layouts = require("@metalsmith/layouts");
29
+ const markdown = require("@metalsmith/markdown");
30
30
  //const filenames = require("metalsmith-filenames");
31
31
  //var permalinks = require("metalsmith-permalinks");
32
32
  /**
@@ -415,23 +415,19 @@ qx.Class.define("qx.ui.basic.Label", {
415
415
 
416
416
  if (value != null) {
417
417
  value.bind("enabled", this, "enabled");
418
- this.__tapListenerId = this.addListener(
419
- "tap",
420
- function () {
421
- // only focus focusable elements [BUG #3555]
422
- if (value.isFocusable()) {
423
- value.focus.apply(value);
424
- }
425
- // furthermore toggle if possible [BUG #6881]
426
- if (
427
- "toggleValue" in value &&
428
- typeof value.toggleValue === "function"
429
- ) {
430
- value.toggleValue();
431
- }
432
- },
433
- this
434
- );
418
+ this.__tapListenerId = this.addListener("tap", () => {
419
+ // only focus focusable elements [BUG #3555]
420
+ if (value.isFocusable()) {
421
+ value.focus.apply(value);
422
+ }
423
+ // furthermore toggle if possible [BUG #6881]
424
+ if (
425
+ "toggleValue" in value &&
426
+ typeof value.toggleValue === "function"
427
+ ) {
428
+ value.toggleValue();
429
+ }
430
+ });
435
431
  }
436
432
  },
437
433
 
@@ -461,20 +461,16 @@ qx.Mixin.define("qx.ui.core.MPlacement", {
461
461
  );
462
462
 
463
463
  // Remove the listener when the element disappears.
464
- this.addListener(
465
- "disappear",
466
- function () {
467
- if (this.__ptwLiveUpdater) {
468
- qx.event.Idle.getInstance().removeListener(
469
- "interval",
470
- this.__ptwLiveUpdater
471
- );
472
-
473
- this.__ptwLiveUpdater = null;
474
- }
475
- },
476
- this
477
- );
464
+ this.addListener("disappear", () => {
465
+ if (this.__ptwLiveUpdater) {
466
+ qx.event.Idle.getInstance().removeListener(
467
+ "interval",
468
+ this.__ptwLiveUpdater
469
+ );
470
+
471
+ this.__ptwLiveUpdater = null;
472
+ }
473
+ });
478
474
  }
479
475
 
480
476
  this._place(coords);
@@ -532,13 +528,9 @@ qx.Mixin.define("qx.ui.core.MPlacement", {
532
528
  }
533
529
 
534
530
  if (size == null) {
535
- this.addListenerOnce(
536
- "appear",
537
- function () {
538
- this.__getPlacementSize(callback);
539
- },
540
- this
541
- );
531
+ this.addListenerOnce("appear", () => {
532
+ this.__getPlacementSize(callback);
533
+ });
542
534
  } else {
543
535
  callback.call(this, size);
544
536
  }
@@ -2109,13 +2109,12 @@ qx.Class.define("qx.ui.core.Widget", {
2109
2109
  var manager = qx.locale.Manager.getInstance();
2110
2110
  this.__toolTipTextListenerId = manager.addListener(
2111
2111
  "changeLocale",
2112
- function () {
2112
+ () => {
2113
2113
  var toolTipText = this.getToolTipText();
2114
2114
  if (toolTipText && toolTipText.translate) {
2115
2115
  this.setToolTipText(toolTipText.translate());
2116
2116
  }
2117
- },
2118
- this
2117
+ }
2119
2118
  );
2120
2119
  }
2121
2120
  },
@@ -71,13 +71,9 @@ qx.Class.define("qx.ui.core.scroll.NativeScrollBar", {
71
71
  }
72
72
 
73
73
  // prevent drag & drop on scrolling
74
- this.addListener(
75
- "track",
76
- function (e) {
77
- e.stopPropagation();
78
- },
79
- this
80
- );
74
+ this.addListener("track", e => {
75
+ e.stopPropagation();
76
+ });
81
77
  },
82
78
 
83
79
  events: {
@@ -81,13 +81,9 @@ qx.Class.define("qx.ui.core.scroll.ScrollBar", {
81
81
  }
82
82
 
83
83
  // prevent drag & drop on scrolling
84
- this.addListener(
85
- "track",
86
- function (e) {
87
- e.stopPropagation();
88
- },
89
- this
90
- );
84
+ this.addListener("track", e => {
85
+ e.stopPropagation();
86
+ });
91
87
  },
92
88
 
93
89
  events: {
@@ -92,64 +92,54 @@ qx.Class.define("qx.ui.embed.Iframe", {
92
92
  this.__blockerElement = this._createBlockerElement();
93
93
 
94
94
  if (qx.core.Environment.get("ecmascript.mutationobserver")) {
95
- this.addListenerOnce(
96
- "appear",
97
- function () {
98
- var element = this.getContentElement().getDomElement();
99
-
100
- // Mutation record check callback
101
- var isDOMNodeInserted = function (mutationRecord) {
102
- var i;
103
- // 'our' iframe was either added...
104
- if (mutationRecord.addedNodes) {
105
- for (i = mutationRecord.addedNodes.length; i >= 0; --i) {
106
- if (mutationRecord.addedNodes[i] == element) {
107
- return true;
108
- }
95
+ this.addListenerOnce("appear", () => {
96
+ var element = this.getContentElement().getDomElement();
97
+
98
+ // Mutation record check callback
99
+ var isDOMNodeInserted = function (mutationRecord) {
100
+ var i;
101
+ // 'our' iframe was either added...
102
+ if (mutationRecord.addedNodes) {
103
+ for (i = mutationRecord.addedNodes.length; i >= 0; --i) {
104
+ if (mutationRecord.addedNodes[i] == element) {
105
+ return true;
109
106
  }
110
107
  }
111
- // ...or removed
112
- if (mutationRecord.removedNodes) {
113
- for (i = mutationRecord.removedNodes.length; i >= 0; --i) {
114
- if (mutationRecord.removedNodes[i] == element) {
115
- return true;
116
- }
108
+ }
109
+ // ...or removed
110
+ if (mutationRecord.removedNodes) {
111
+ for (i = mutationRecord.removedNodes.length; i >= 0; --i) {
112
+ if (mutationRecord.removedNodes[i] == element) {
113
+ return true;
117
114
  }
118
115
  }
119
- return false;
120
- };
116
+ }
117
+ return false;
118
+ };
121
119
 
122
- var observer = new MutationObserver(
123
- function (mutationRecords) {
124
- if (mutationRecords.some(isDOMNodeInserted)) {
125
- this._syncSourceAfterDOMMove();
126
- }
127
- }.bind(this)
128
- );
129
-
130
- // Observe parent element
131
- var parent = this.getLayoutParent()
132
- .getContentElement()
133
- .getDomElement();
134
- observer.observe(parent, { childList: true, subtree: true });
135
- },
136
- this
137
- );
120
+ var observer = new MutationObserver(
121
+ function (mutationRecords) {
122
+ if (mutationRecords.some(isDOMNodeInserted)) {
123
+ this._syncSourceAfterDOMMove();
124
+ }
125
+ }.bind(this)
126
+ );
127
+
128
+ // Observe parent element
129
+ var parent = this.getLayoutParent().getContentElement().getDomElement();
130
+ observer.observe(parent, { childList: true, subtree: true });
131
+ });
138
132
  }
139
133
  // !qx.core.Environment.get("ecmascript.mutationobserver")
140
134
  else {
141
- this.addListenerOnce(
142
- "appear",
143
- function () {
144
- var element = this.getContentElement().getDomElement();
145
- qx.bom.Event.addNativeListener(
146
- element,
147
- "DOMNodeInserted",
148
- this._onDOMNodeInserted
149
- );
150
- },
151
- this
152
- );
135
+ this.addListenerOnce("appear", () => {
136
+ var element = this.getContentElement().getDomElement();
137
+ qx.bom.Event.addNativeListener(
138
+ element,
139
+ "DOMNodeInserted",
140
+ this._onDOMNodeInserted
141
+ );
142
+ });
153
143
 
154
144
  this._onDOMNodeInserted = qx.lang.Function.listener(
155
145
  this._syncSourceAfterDOMMove,
@@ -994,18 +994,14 @@ qx.Class.define("qx.ui.form.AbstractField", {
994
994
  /* qx Bug #8870: Firefox 35 will not display a text area's
995
995
  placeholder text if the attribute is set before the
996
996
  element is added to the DOM. This is fixed in FF 36. */
997
- this.addListenerOnce(
998
- "appear",
999
- function () {
1000
- this.getContentElement()
1001
- .getDomElement()
1002
- .removeAttribute("placeholder");
1003
- this.getContentElement()
1004
- .getDomElement()
1005
- .setAttribute("placeholder", value);
1006
- },
1007
- this
1008
- );
997
+ this.addListenerOnce("appear", () => {
998
+ this.getContentElement()
999
+ .getDomElement()
1000
+ .removeAttribute("placeholder");
1001
+ this.getContentElement()
1002
+ .getDomElement()
1003
+ .setAttribute("placeholder", value);
1004
+ });
1009
1005
  }
1010
1006
  }
1011
1007
  }
@@ -53,21 +53,13 @@ qx.Class.define("qx.ui.form.ComboBox", {
53
53
 
54
54
  // forward the focusin and focusout events to the textfield. The textfield
55
55
  // is not focusable so the events need to be forwarded manually.
56
- this.addListener(
57
- "focusin",
58
- function (e) {
59
- textField.fireNonBubblingEvent("focusin", qx.event.type.Focus);
60
- },
61
- this
62
- );
63
-
64
- this.addListener(
65
- "focusout",
66
- function (e) {
67
- textField.fireNonBubblingEvent("focusout", qx.event.type.Focus);
68
- },
69
- this
70
- );
56
+ this.addListener("focusin", e => {
57
+ textField.fireNonBubblingEvent("focusin", qx.event.type.Focus);
58
+ });
59
+
60
+ this.addListener("focusout", e => {
61
+ textField.fireNonBubblingEvent("focusout", qx.event.type.Focus);
62
+ });
71
63
  },
72
64
 
73
65
  /*
@@ -67,21 +67,13 @@ qx.Class.define("qx.ui.form.DateField", {
67
67
 
68
68
  // forward the focusin and focusout events to the textfield. The textfield
69
69
  // is not focusable so the events need to be forwarded manually.
70
- this.addListener(
71
- "focusin",
72
- function (e) {
73
- textField.fireNonBubblingEvent("focusin", qx.event.type.Focus);
74
- },
75
- this
76
- );
77
-
78
- this.addListener(
79
- "focusout",
80
- function (e) {
81
- textField.fireNonBubblingEvent("focusout", qx.event.type.Focus);
82
- },
83
- this
84
- );
70
+ this.addListener("focusin", e => {
71
+ textField.fireNonBubblingEvent("focusin", qx.event.type.Focus);
72
+ });
73
+
74
+ this.addListener("focusout", e => {
75
+ textField.fireNonBubblingEvent("focusout", qx.event.type.Focus);
76
+ });
85
77
 
86
78
  // initializes the DateField with the default format
87
79
  this._setDefaultDateFormat();
@@ -225,10 +217,9 @@ qx.Class.define("qx.ui.form.DateField", {
225
217
  if (qx.core.Environment.get("qx.dynlocale")) {
226
218
  this.__localeListenerId = qx.locale.Manager.getInstance().addListener(
227
219
  "changeLocale",
228
- function () {
220
+ () => {
229
221
  this._setDefaultDateFormat();
230
- },
231
- this
222
+ }
232
223
  );
233
224
  }
234
225
  },
@@ -0,0 +1,157 @@
1
+ /* ************************************************************************
2
+
3
+ qooxdoo
4
+
5
+ https://qooxdoo.org
6
+
7
+ Copyright:
8
+ 2022 OETIKER+PARTNER AG
9
+
10
+ License:
11
+ MIT: https://opensource.org/licenses/MIT
12
+ See the LICENSE file in the project's top-level directory for details.
13
+
14
+ Authors:
15
+ * Tobias Oetiker (oetiker)
16
+
17
+ ************************************************************************ */
18
+
19
+ /**
20
+ * The FileSelectorButton opens a window and lets the user pick one or several
21
+ * files from the local filesystem. A FileList is returned which allows access
22
+ * to the content of the selected files from javascript. The file(s) can now be
23
+ * processed in javascript, or it/they can be uploaded to a server.
24
+ *
25
+ * *Example*
26
+ *
27
+ * Post the content of the file to the server.
28
+ *
29
+ * ```javascript
30
+ * let button = new qx.ui.form.FileSelectorButton("Select File");
31
+ * button.addListener('changeFileSelection',function(e){
32
+ * let fileList = e.getData();
33
+ * let form = new FormData();
34
+ * form.append('file',fileList[0]);
35
+ * let req = new qx.io.request.Xhr("upload",'POST').set({
36
+ * requestData: form
37
+ * });
38
+ * req.addListener('success',(e) => {
39
+ * let response = req.getResponse();
40
+ * });
41
+ * });
42
+ * ```
43
+ *
44
+ * Process the file directly in javascript using the FileReader API.
45
+ *
46
+ * ```javascript
47
+ * let button = new qx.ui.form.FileSelectorButton("Select File");
48
+ * button.addListener('changeFileSelection',function(e){
49
+ * let fileList = e.getData();
50
+ * const reader = new FileReader();
51
+ * reader.addEventListener('load', () => {
52
+ * let response = reader.result;
53
+ * console.log("The first 4 chrs are: " + response);
54
+ * });
55
+ * const file = fileList[0];
56
+ * reader.readAsText(file.slice(0,4));
57
+ * });
58
+
59
+ *
60
+ * [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/File_API/Using_files_from_web_applications)
61
+ */
62
+
63
+ let InputElementIdCounter = 0;
64
+ qx.Class.define("qx.ui.form.FileSelectorButton", {
65
+ extend: qx.ui.form.Button,
66
+ events: {
67
+ /**
68
+ * The event is fired when the file selection changes.
69
+ *
70
+ * The method {@link qx.event.type.Data#getData} returns the
71
+ * current [fileList](https://developer.mozilla.org/en-US/docs/Web/API/FileList)
72
+ */
73
+ changeFileSelection: "qx.event.type.Data"
74
+ },
75
+ properties: {
76
+ /**
77
+ * What type of files should be offered in the fileselection dialog.
78
+ * Use a comma separated list of [Unique file type specifiers](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers). If you dont set anything, all files
79
+ * are allowed.
80
+ *
81
+ * *Example*
82
+ *
83
+ * `.doc,.docx,application/msword`
84
+ */
85
+ accept: {
86
+ nullable: true,
87
+ check: "String",
88
+ apply: "_applyAttribute"
89
+ },
90
+ /**
91
+ * Specify that the camera should be used for getting the "file". The
92
+ * value defines which camera should be used for capturing images.
93
+ * `user` indicates the user-facing camera.
94
+ * `environment` indicates the camera facing away from the user.
95
+ */
96
+ capture: {
97
+ nullable: true,
98
+ check: ["user", "environment"],
99
+ apply: "_applyAttribute"
100
+ },
101
+ /**
102
+ * Set to "true" if you want to allow the selection of multiple files.
103
+ */
104
+ multiple: {
105
+ nullable: true,
106
+ check: "Boolean",
107
+ apply: "_applyAttribute"
108
+ },
109
+ /**
110
+ * If present, indicates that only directories should be available for
111
+ * selection.
112
+ */
113
+ directoriesOnly: {
114
+ nullable: true,
115
+ check: "Boolean",
116
+ apply: "_applyAttribute"
117
+ }
118
+ },
119
+ members: {
120
+ __inputObject: null,
121
+
122
+ _applyAttribute: function (value, old, attr) {
123
+ if (attr === "directoriesOnly") {
124
+ // while the name of the attribute indicates that this only
125
+ // works for webkit borwsers, this is not the case. These
126
+ // days the attribute is supported by
127
+ // [everyone](https://caniuse.com/?search=webkitdirectory).
128
+ attr = "webkitdirectory";
129
+ }
130
+ this.__inputObject.setAttribute(attr, value);
131
+ },
132
+
133
+ _createContentElement: function () {
134
+ let id = "qxFileSelector_" + InputElementIdCounter++;
135
+ let input = (this.__inputObject = new qx.html.Input(
136
+ "file",
137
+ { display: "none" },
138
+ { id: id }
139
+ ));
140
+ let label = new qx.html.Element("label", {}, { for: id });
141
+ label.addListenerOnce(
142
+ "appear",
143
+ e => {
144
+ label.add(input);
145
+ }
146
+ );
147
+ input.addListenerOnce("appear", e => {
148
+ let inputEl = input.getDomElement();
149
+ inputEl.addEventListener("change", e => {
150
+ this.fireDataEvent("changeFileSelection", inputEl.files);
151
+ inputEl.value = "";
152
+ });
153
+ });
154
+ return label;
155
+ }
156
+ }
157
+ });
@@ -116,21 +116,13 @@ qx.Class.define("qx.ui.form.Spinner", {
116
116
 
117
117
  // forward the focusin and focusout events to the textfield. The textfield
118
118
  // is not focusable so the events need to be forwarded manually.
119
- this.addListener(
120
- "focusin",
121
- function (e) {
122
- textField.fireNonBubblingEvent("focusin", qx.event.type.Focus);
123
- },
124
- this
125
- );
126
-
127
- this.addListener(
128
- "focusout",
129
- function (e) {
130
- textField.fireNonBubblingEvent("focusout", qx.event.type.Focus);
131
- },
132
- this
133
- );
119
+ this.addListener("focusin", e => {
120
+ textField.fireNonBubblingEvent("focusin", qx.event.type.Focus);
121
+ });
122
+
123
+ this.addListener("focusout", e => {
124
+ textField.fireNonBubblingEvent("focusout", qx.event.type.Focus);
125
+ });
134
126
  },
135
127
 
136
128
  /*
@@ -193,13 +193,9 @@ qx.Class.define("qx.ui.form.TextArea", {
193
193
 
194
194
  // On init, the clone is not yet present. Try again on appear.
195
195
  } else {
196
- this.getContentElement().addListenerOnce(
197
- "appear",
198
- function () {
199
- this.__autoSize();
200
- },
201
- this
202
- );
196
+ this.getContentElement().addListenerOnce("appear", () => {
197
+ this.__autoSize();
198
+ });
203
199
  }
204
200
  }
205
201
  },
@@ -46,22 +46,14 @@ qx.Class.define("qx.ui.form.VirtualComboBox", {
46
46
 
47
47
  // forward the focusin and focusout events to the textfield. The textfield
48
48
  // is not focusable so the events need to be forwarded manually.
49
- this.addListener(
50
- "focusin",
51
- function (e) {
52
- textField.fireNonBubblingEvent("focusin", qx.event.type.Focus);
53
- },
54
- this
55
- );
56
-
57
- this.addListener(
58
- "focusout",
59
- function (e) {
60
- textField.fireNonBubblingEvent("focusout", qx.event.type.Focus);
61
- this.fireNonBubblingEvent("blur", qx.event.type.Focus);
62
- },
63
- this
64
- );
49
+ this.addListener("focusin", e => {
50
+ textField.fireNonBubblingEvent("focusin", qx.event.type.Focus);
51
+ });
52
+
53
+ this.addListener("focusout", e => {
54
+ textField.fireNonBubblingEvent("focusout", qx.event.type.Focus);
55
+ this.fireNonBubblingEvent("blur", qx.event.type.Focus);
56
+ });
65
57
  },
66
58
 
67
59
  properties: {