@qooxdoo/framework 7.7.0 → 7.7.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qooxdoo/framework",
3
- "version": "7.7.0",
3
+ "version": "7.7.2",
4
4
  "description": "The JS Framework for Coders",
5
5
  "author": "The qooxdoo project",
6
6
  "keywords": [
@@ -840,7 +840,7 @@ qx.Bootstrap.define("qx.Class", {
840
840
  ? this.__staticAllowedKeys
841
841
  : this.__allowedKeys;
842
842
  for (var key in config) {
843
- if (!allowed[key]) {
843
+ if (!(key in allowed)) {
844
844
  throw new Error(
845
845
  'The configuration key "' +
846
846
  key +
@@ -371,16 +371,18 @@ qx.Bootstrap.define("qx.Mixin", {
371
371
  break;
372
372
  }
373
373
  }
374
+
374
375
  // Try looking in the class itself
375
376
  if (!fn && mixedInAt.prototype[methodName]) {
376
- fn = mixedInAt.prototype[methodName].base;
377
- // if fn.self is set fn is an overloaded mixin method from
378
- // another mixin. In this case fn.base contains the original
379
- // class method.
380
- if (fn && fn.self) {
377
+ fn = mixedInAt.prototype[methodName];
378
+ for (let i = 0; i < mixedInAt.$$flatIncludes.length; i++) {
379
+ if (!mixedInAt.$$flatIncludes[i].$$members[methodName]) {
380
+ continue;
381
+ }
381
382
  fn = fn.base;
382
383
  }
383
384
  }
385
+
384
386
  // Try looking in the superclass
385
387
  if (!fn && mixedInAt.superclass) {
386
388
  fn = mixedInAt.superclass.prototype[methodName];
@@ -44,19 +44,30 @@ qx.Bootstrap.define("qx.bom.Input", {
44
44
  statics: {
45
45
  /** @type {Map} Internal data structures with all supported input types */
46
46
  __types: {
47
- text: 1,
48
- textarea: 1,
49
- select: 1,
50
- checkbox: 1,
51
- radio: 1,
52
- password: 1,
53
- hidden: 1,
54
- submit: 1,
55
- image: 1,
56
- file: 1,
57
- search: 1,
58
- reset: 1,
59
- button: 1
47
+ textarea: true,
48
+ select: true,
49
+ button: true,
50
+ checkbox: true,
51
+ color: true,
52
+ date: true,
53
+ "datetime-local": true,
54
+ email: true,
55
+ file: true,
56
+ hidden: true,
57
+ image: true,
58
+ month: true,
59
+ number: true,
60
+ password: true,
61
+ radio: true,
62
+ range: true,
63
+ reset: true,
64
+ search: true,
65
+ submit: true,
66
+ tel: true,
67
+ text: true,
68
+ time: true,
69
+ url: true,
70
+ week: true
60
71
  },
61
72
 
62
73
  /**
@@ -173,7 +173,7 @@ qx.Bootstrap.define("qx.lang.Function", {
173
173
  return func;
174
174
  }
175
175
 
176
- return function (event) {
176
+ let result = function (event) {
177
177
  if (qx.core.Environment.get("qx.debug")) {
178
178
  function testSelf(self) {
179
179
  if (
@@ -233,6 +233,10 @@ qx.Bootstrap.define("qx.lang.Function", {
233
233
  return func.apply(options.self || this, args);
234
234
  }
235
235
  };
236
+ if (qx.core.Environment.get("qx.debug")) {
237
+ result.$$original = func;
238
+ }
239
+ return result;
236
240
  },
237
241
 
238
242
  /**
@@ -610,6 +610,266 @@ qx.Class.define("qx.test.Mixin", {
610
610
  var o = new qx.D();
611
611
  this.assertEquals("Double MA MB", o.sayJuhu());
612
612
  o.dispose();
613
+ },
614
+
615
+ testDoubleMixinWithSuperStruct() {
616
+ qx.Class.define("qx.E1", {
617
+ extend: qx.core.Object,
618
+ members: {
619
+ sayJuhu() {
620
+ return "E1";
621
+ }
622
+ }
623
+ });
624
+ qx.Mixin.define("qx.ME1a", {
625
+ members: {
626
+ sayJuhu() {
627
+ return `${super.sayJuhu()} ME1`;
628
+ }
629
+ }
630
+ });
631
+ qx.Mixin.define("qx.ME1b", {
632
+ members: {
633
+ // does not implement `sayJuhu`
634
+ }
635
+ });
636
+
637
+ qx.Class.define("qx.E2", {
638
+ extend: qx.E1,
639
+ members: {
640
+ sayJuhu() {
641
+ return `${super.sayJuhu()} E2`;
642
+ }
643
+ }
644
+ });
645
+ qx.Mixin.define("qx.ME2a", {
646
+ members: {
647
+ sayJuhu() {
648
+ return `${super.sayJuhu()} ME2a`;
649
+ }
650
+ }
651
+ });
652
+ qx.Mixin.define("qx.ME2b", {
653
+ members: {
654
+ sayJuhu() {
655
+ return `${super.sayJuhu()} ME2b`;
656
+ }
657
+ }
658
+ });
659
+
660
+ qx.Class.patch(qx.E1, qx.ME1a);
661
+ qx.Class.patch(qx.E1, qx.ME1b);
662
+ qx.Class.patch(qx.E2, qx.ME2a);
663
+ qx.Class.patch(qx.E2, qx.ME2b);
664
+
665
+ const e = new qx.E2();
666
+ this.assertEquals("E1 ME1 E2 ME2a ME2b", e.sayJuhu());
667
+ e.dispose();
668
+ },
669
+
670
+ /**
671
+ * tests a large structure to ensure that combinations of patch order,
672
+ * presence of given method, nor patched class count have an impact on
673
+ * the behavior of `super` in mixin methods.
674
+ */
675
+ testLotsMixinLotsSuper() {
676
+ qx.Class.define("qx.G1", {
677
+ extend: qx.core.Object,
678
+ members: {
679
+ sayJuhu() {
680
+ return "G1";
681
+ }
682
+ }
683
+ });
684
+ qx.Mixin.define("qx.M1G1", {
685
+ members: {
686
+ sayJuhu() {
687
+ return `${super.sayJuhu()} M1G1`;
688
+ }
689
+ }
690
+ });
691
+ qx.Class.patch(qx.G1, qx.M1G1);
692
+ qx.Mixin.define("qx.M2G1", {
693
+ members: {
694
+ sayJuhu() {
695
+ return `${super.sayJuhu()} M2G1`;
696
+ }
697
+ }
698
+ });
699
+ qx.Class.patch(qx.G1, qx.M2G1);
700
+ qx.Mixin.define("qx.M3G1", {
701
+ members: {
702
+ sayJuhu() {
703
+ return `${super.sayJuhu()} M3G1`;
704
+ }
705
+ }
706
+ });
707
+ qx.Class.patch(qx.G1, qx.M3G1);
708
+ qx.Mixin.define("qx.M4G1", {
709
+ members: {
710
+ sayJuhu() {
711
+ return `${super.sayJuhu()} M4G1`;
712
+ }
713
+ }
714
+ });
715
+ qx.Class.patch(qx.G1, qx.M4G1);
716
+ qx.Mixin.define("qx.M5G1", {
717
+ members: {
718
+ // does not implement `sayJuhu`
719
+ }
720
+ });
721
+ qx.Class.patch(qx.G1, qx.M5G1);
722
+ qx.Mixin.define("qx.M6G1", {
723
+ members: {
724
+ // does not implement `sayJuhu`
725
+ }
726
+ });
727
+ qx.Class.patch(qx.G1, qx.M6G1);
728
+
729
+ qx.Class.define("qx.G2", {
730
+ extend: qx.G1,
731
+ members: {
732
+ sayJuhu() {
733
+ return `${super.sayJuhu()} G2`;
734
+ }
735
+ }
736
+ });
737
+ qx.Mixin.define("qx.M1G2", {
738
+ members: {
739
+ sayJuhu() {
740
+ return `${super.sayJuhu()} M1G2`;
741
+ }
742
+ }
743
+ });
744
+ qx.Class.patch(qx.G2, qx.M1G2);
745
+ qx.Mixin.define("qx.M2G2", {
746
+ members: {
747
+ sayJuhu() {
748
+ return `${super.sayJuhu()} M2G2`;
749
+ }
750
+ }
751
+ });
752
+ qx.Class.patch(qx.G2, qx.M2G2);
753
+ qx.Mixin.define("qx.M3G2", {
754
+ members: {
755
+ // does not implement `sayJuhu`
756
+ }
757
+ });
758
+ qx.Class.patch(qx.G2, qx.M3G2);
759
+ qx.Mixin.define("qx.M4G2", {
760
+ members: {
761
+ sayJuhu() {
762
+ return `${super.sayJuhu()} M4G2`;
763
+ }
764
+ }
765
+ });
766
+ qx.Class.patch(qx.G2, qx.M4G2);
767
+ qx.Mixin.define("qx.M5G2", {
768
+ members: {
769
+ sayJuhu() {
770
+ return `${super.sayJuhu()} M5G2`;
771
+ }
772
+ }
773
+ });
774
+ qx.Class.patch(qx.G2, qx.M5G2);
775
+
776
+ qx.Class.define("qx.G3", {
777
+ extend: qx.G2,
778
+ members: {
779
+ sayJuhu() {
780
+ return `${super.sayJuhu()} G3`;
781
+ }
782
+ }
783
+ });
784
+ qx.Mixin.define("qx.M1G3", {
785
+ members: {
786
+ // does not implement `sayJuhu`
787
+ }
788
+ });
789
+ qx.Class.patch(qx.G3, qx.M1G3);
790
+ qx.Mixin.define("qx.M2G3", {
791
+ members: {
792
+ sayJuhu() {
793
+ return `${super.sayJuhu()} M2G3`;
794
+ }
795
+ }
796
+ });
797
+ qx.Class.patch(qx.G3, qx.M2G3);
798
+ qx.Mixin.define("qx.M3G3", {
799
+ members: {
800
+ sayJuhu() {
801
+ return `${super.sayJuhu()} M3G3`;
802
+ }
803
+ }
804
+ });
805
+ qx.Class.patch(qx.G3, qx.M3G3);
806
+ qx.Mixin.define("qx.M4G3", {
807
+ members: {
808
+ // does not implement `sayJuhu`
809
+ }
810
+ });
811
+ qx.Class.patch(qx.G3, qx.M4G3);
812
+
813
+ qx.Class.define("qx.G4", {
814
+ extend: qx.G3,
815
+ members: {
816
+ sayJuhu() {
817
+ return `${super.sayJuhu()} G4`;
818
+ }
819
+ }
820
+ });
821
+ qx.Mixin.define("qx.M1G4", {
822
+ members: {
823
+ sayJuhu() {
824
+ return `${super.sayJuhu()} M1G4`;
825
+ }
826
+ }
827
+ });
828
+ qx.Class.patch(qx.G4, qx.M1G4);
829
+ qx.Mixin.define("qx.M2G4", {
830
+ members: {
831
+ // does not implement `sayJuhu`
832
+ }
833
+ });
834
+ qx.Class.patch(qx.G4, qx.M2G4);
835
+ qx.Mixin.define("qx.M3G4", {
836
+ members: {
837
+ sayJuhu() {
838
+ return `${super.sayJuhu()} M3G4`;
839
+ }
840
+ }
841
+ });
842
+ qx.Class.patch(qx.G4, qx.M3G4);
843
+
844
+ qx.Class.define("qx.G5", {
845
+ extend: qx.G4,
846
+ members: {
847
+ sayJuhu() {
848
+ return `${super.sayJuhu()} G5`;
849
+ }
850
+ }
851
+ });
852
+ qx.Mixin.define("qx.M1G5", {
853
+ members: {
854
+ sayJuhu() {
855
+ return `${super.sayJuhu()} M1G5`;
856
+ }
857
+ }
858
+ });
859
+ qx.Class.patch(qx.G5, qx.M1G5);
860
+ qx.Mixin.define("qx.M2G5", {
861
+ members: {
862
+ // does not implement `sayJuhu`
863
+ }
864
+ });
865
+ qx.Class.patch(qx.G5, qx.M2G5);
866
+
867
+ const g5 = new qx.G5();
868
+ this.assertEquals(
869
+ "G1 M1G1 M2G1 M3G1 M4G1 G2 M1G2 M2G2 M4G2 M5G2 G3 M2G3 M3G3 G4 M1G4 M3G4 G5 M1G5",
870
+ g5.sayJuhu()
871
+ );
872
+ g5.dispose();
613
873
  }
614
874
  }
615
875
  });
@@ -789,14 +789,11 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
789
789
  }
790
790
 
791
791
  for (let filename of classFiles) {
792
- if (this.argv.verbose) {
793
- qx.tool.compiler.Console.info(`Processing ${filename} ...`);
794
- }
795
792
  await metaDb.addFile(filename, !!this.argv.clean);
796
793
  }
797
794
  await metaDb.reparseAll();
798
795
  await metaDb.save();
799
- this.fireDataEvent("writtenMetaData", metaDb);
796
+ await this.fireDataEventAsync("writtenMetaData", metaDb);
800
797
 
801
798
  // Do the inital write
802
799
  let tsWriter = null;
@@ -806,7 +803,7 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
806
803
  if (this.__typescriptFile) {
807
804
  tsWriter.setOutputTo(this.__typescriptFile);
808
805
  } else {
809
- tsWriter.setOutputTo(path.join("compiled", "qooxdoo.d.ts"));
806
+ tsWriter.setOutputTo(path.join(this.__metaDir, "..", "qooxdoo.d.ts"));
810
807
  }
811
808
  await tsWriter.process();
812
809
  }
@@ -885,9 +882,12 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
885
882
 
886
883
  if (qx.lang.Type.isBoolean(data?.meta?.typescript)) {
887
884
  this.__typescriptEnabled = data.meta.typescript;
888
- } else if (qx.lang.Type.isString(data?.typescript)) {
885
+ } else if (qx.lang.Type.isString(data?.meta?.typescript)) {
889
886
  this.__typescriptEnabled = true;
890
- this.__typescriptFile = data.typescript;
887
+ this.__typescriptFile = path.relative(
888
+ process.cwd(),
889
+ path.resolve(data?.meta?.typescript)
890
+ );
891
891
  }
892
892
  if (qx.lang.Type.isBoolean(this.argv.typescript)) {
893
893
  this.__typescriptEnabled = this.argv.typescript;
@@ -1349,8 +1349,12 @@ qx.Class.define("qx.tool.compiler.ClassFile", {
1349
1349
  t.__hasDefer = true;
1350
1350
  t.__inDefer = true;
1351
1351
  }
1352
- t.__classMeta.functionName = FUNCTION_NAMES[keyName] || keyName;
1353
- if (FUNCTION_NAMES[keyName] !== undefined) {
1352
+ var isSpecialFunctionName =
1353
+ Object.keys(FUNCTION_NAMES).includes(keyName);
1354
+ t.__classMeta.functionName = isSpecialFunctionName
1355
+ ? FUNCTION_NAMES[keyName]
1356
+ : keyName;
1357
+ if (isSpecialFunctionName) {
1354
1358
  makeMeta(keyName, null, functionNode);
1355
1359
  }
1356
1360
  enterFunction(path, functionNode);
@@ -1393,8 +1397,9 @@ qx.Class.define("qx.tool.compiler.ClassFile", {
1393
1397
  }
1394
1398
  var keyName = getKeyName(prop.key);
1395
1399
  checkValidTopLevel(path);
1396
-
1397
- if (FUNCTION_NAMES[keyName] !== undefined) {
1400
+ var isSpecialFunctionName =
1401
+ Object.keys(FUNCTION_NAMES).includes(keyName);
1402
+ if (isSpecialFunctionName) {
1398
1403
  let val = path.node.value;
1399
1404
  val.leadingComments = (path.node.leadingComments || []).concat(
1400
1405
  val.leadingComments || []
@@ -373,10 +373,10 @@ qx.Class.define("qx.tool.compiler.targets.Target", {
373
373
 
374
374
  appMeta.setSourceUri(mapTo ? mapTo : targetUri + "transpiled/");
375
375
  mapTo = this.getPathMapping(
376
- path.join(appRootDir, this.getOutputDir(), "resource/")
376
+ path.join(appRootDir, this.getOutputDir(), "resource")
377
377
  );
378
378
 
379
- appMeta.setResourceUri(mapTo ? mapTo : targetUri + "resource/");
379
+ appMeta.setResourceUri(mapTo ? mapTo : targetUri + "resource");
380
380
 
381
381
  const requiredLibs = application.getRequiredLibraries();
382
382
 
@@ -21,7 +21,7 @@
21
21
  *
22
22
  * *********************************************************************** */
23
23
 
24
- var path = require("path");
24
+ var path = require("upath");
25
25
 
26
26
  var fs = require("fs");
27
27
  const { promisify } = require("util");
@@ -77,13 +77,8 @@ qx.Class.define("qx.tool.compiler.targets.TypeScriptWriter", {
77
77
  this.__outputStream.on("close", () =>
78
78
  this.__outputStreamClosed.resolve()
79
79
  );
80
-
81
80
  this.write(`// Generated declaration file at ${time}\n`);
82
-
83
- let str = qx.util.ResourceManager.getInstance().toUri(
84
- "qx/tool/cli/templates/TypeScriptWriter-base_declaration.d.ts"
85
- );
86
-
81
+ let str = path.join(qx.tool.utils.Utils.getTemplateDir(), "TypeScriptWriter-base_declaration.d.ts")
87
82
  let baseDeclaration = await fs.promises.readFile(str, "utf8");
88
83
  this.write(baseDeclaration + "\n");
89
84
  },
@@ -35,19 +35,19 @@ qx.Class.define("qx.ui.form.AbstractField", {
35
35
  type: "abstract",
36
36
 
37
37
  statics: {
38
- /** Stylesheet needed to style the native placeholder element. */
39
- __stylesheet: null,
40
-
41
- __addedPlaceholderRules: false,
38
+ __addedPlaceholderRules: "",
42
39
 
43
40
  /**
44
41
  * Adds the CSS rules needed to style the native placeholder element.
45
42
  */
46
43
  __addPlaceholderRules() {
47
- if (qx.ui.form.AbstractField.__addedPlaceholderRules) {
44
+ const theme = qx.theme.manager.Meta.getInstance().getTheme();
45
+ const currentThemeName = theme ? theme.title || theme.name : "";
46
+
47
+ if (qx.ui.form.AbstractField.__addedPlaceholderRules === currentThemeName) {
48
48
  return;
49
49
  }
50
- qx.ui.form.AbstractField.__addedPlaceholderRules = true;
50
+ qx.ui.form.AbstractField.__addedPlaceholderRules = currentThemeName;
51
51
  var engine = qx.core.Environment.get("engine.name");
52
52
  var browser = qx.core.Environment.get("browser.name");
53
53
  var colorManager = qx.theme.manager.Color.getInstance();
@@ -100,7 +100,9 @@ qx.Class.define("qx.ui.form.AbstractField", {
100
100
  "-ms-input-placeholder"
101
101
  ].join(separator);
102
102
  }
103
-
103
+ if(qx.ui.style.Stylesheet.getInstance().hasRule(selector)) {
104
+ qx.ui.style.Stylesheet.getInstance().removeRule(selector);
105
+ }
104
106
  qx.ui.style.Stylesheet.getInstance().addRule(
105
107
  selector,
106
108
  "color: " + color + " !important"
@@ -931,9 +933,7 @@ qx.Class.define("qx.ui.form.AbstractField", {
931
933
  this._placeholder.dispose();
932
934
  this._placeholder = null;
933
935
  }
934
- if (!this.__useQxPlaceholder && qx.ui.form.AbstractField.__stylesheet) {
935
- qx.bom.Stylesheet.removeSheet(qx.ui.form.AbstractField.__stylesheet);
936
- qx.ui.form.AbstractField.__stylesheet = null;
936
+ if (!this.__useQxPlaceholder) {
937
937
  qx.ui.form.AbstractField.__addPlaceholderRules();
938
938
  }
939
939
  },
@@ -20,4 +20,51 @@
20
20
  * This is a marker interface for classes which can act as a children of
21
21
  * {@link qx.ui.form.List}
22
22
  */
23
- qx.Interface.define("qx.ui.form.IListItem", {});
23
+ qx.Interface.define("qx.ui.form.IListItem", {
24
+ /*
25
+ *****************************************************************************
26
+ EVENTS
27
+ *****************************************************************************
28
+ */
29
+
30
+ events: {
31
+ /** Fired when the value was modified */
32
+ changeReadOnly: "qx.event.type.Data"
33
+ },
34
+
35
+ /*
36
+ *****************************************************************************
37
+ MEMBERS
38
+ *****************************************************************************
39
+ */
40
+
41
+ members: {
42
+ /*
43
+ ---------------------------------------------------------------------------
44
+ READONLY PROPERTY
45
+ ---------------------------------------------------------------------------
46
+ */
47
+
48
+ /**
49
+ * Sets the element's value.
50
+ *
51
+ * @param value {Boolean|null} The new value of the element.
52
+ * @return {Boolean|null}
53
+ */
54
+ setReadOnly(value) {
55
+ this.assertArgumentsCount(arguments, 1, 1);
56
+ },
57
+
58
+ /**
59
+ * Resets the element's value to its initial value.
60
+ */
61
+ resetReadOnly() {},
62
+
63
+ /**
64
+ * The element's user set value.
65
+ *
66
+ * @return {Boolean|null} The value.
67
+ */
68
+ getReadOnly() {}
69
+ }
70
+ });
@@ -199,10 +199,12 @@ qx.Class.define("qx.ui.form.List", {
199
199
  */
200
200
  _onAddChild(e) {
201
201
  const child = e.getData();
202
- this.__childrenBindings.set(
203
- child.toHashCode(),
204
- this.bind("readOnly", child, "readOnly")
205
- );
202
+ if (qx.Class.implementsInterface(child, qx.ui.form.IListItem)) {
203
+ this.__childrenBindings.set(
204
+ child.toHashCode(),
205
+ this.bind("readOnly", child, "readOnly")
206
+ );
207
+ }
206
208
 
207
209
  this.fireDataEvent("addItem", child);
208
210
  },
@@ -214,8 +216,11 @@ qx.Class.define("qx.ui.form.List", {
214
216
  */
215
217
  _onRemoveChild(e) {
216
218
  const child = e.getData();
217
- child.removeBinding(this.__childrenBindings.get(child.toHashCode()));
218
- this.__childrenBindings.delete(child.toHashCode());
219
+ const binding = this.__childrenBindings.get(child.toHashCode());
220
+ if (binding) {
221
+ child.removeBinding(binding);
222
+ this.__childrenBindings.delete(child.toHashCode());
223
+ }
219
224
  this.fireDataEvent("removeItem", child);
220
225
  },
221
226
 
@@ -543,6 +543,14 @@ qx.Class.define("qx.ui.table.Table", {
543
543
  event: "changeDataRowRenderer"
544
544
  },
545
545
 
546
+ /**
547
+ * The action to take when a cell is being edited and the focus moves elsewhere.
548
+ */
549
+ cellEditorBlurAction: {
550
+ check: ["nothing", "save", "cancel"],
551
+ init: "nothing"
552
+ },
553
+
546
554
  /**
547
555
  * A function to call when before modal cell editor is opened.
548
556
  *
@@ -1873,6 +1873,7 @@ qx.Class.define("qx.ui.table.pane.Scroller", {
1873
1873
  // Make the focus indicator visible during editing
1874
1874
  this.__focusIndicator.setDecorator("table-scroller-focus-indicator");
1875
1875
 
1876
+ this._cellEditor.addListenerOnce('focusin', this._onFocusinCellEditorAddBlurListener, this);
1876
1877
  this._cellEditor.focus();
1877
1878
  this._cellEditor.activate();
1878
1879
  }
@@ -1964,6 +1965,40 @@ qx.Class.define("qx.ui.table.pane.Scroller", {
1964
1965
  this.stopEditing();
1965
1966
  },
1966
1967
 
1968
+ /**
1969
+ * Focusin event handler which attaches the blur event listener ot the cell editor
1970
+ * and uses a timer event to allow the focusin event listener execution before
1971
+ * the blur event listener execution
1972
+ */
1973
+ _onFocusinCellEditorAddBlurListener(e) {
1974
+ this.debug("executed FOCUSIN event listener for hash: " + e.getTarget().$$hash);
1975
+ qx.event.Timer.once(function() {
1976
+ this._cellEditor.addListenerOnce('blur', this._onBlurCellEditorStopEditing, this);
1977
+ this.debug('added BLUR listener to hash: ' + this._cellEditor.$$hash);
1978
+ }, this, 0);
1979
+ },
1980
+
1981
+ /**
1982
+ * Stop editing whenever the cell editor blurs.
1983
+ */
1984
+ _onBlurCellEditorStopEditing(e) {
1985
+ this.debug("executed BLUR listener for hash " + e.getTarget().$$hash);
1986
+ if (this._cellEditor === e.getTarget()) {
1987
+ this.debug('hash: ' + this._cellEditor.$$hash);
1988
+ switch (this.getTable().getCellEditorBlurAction()) {
1989
+ case "save":
1990
+ this.stopEditing();
1991
+ break;
1992
+ case "cancel":
1993
+ this.cancelEditing();
1994
+ break;
1995
+ case "nothing":
1996
+ default:
1997
+ // do nothing
1998
+ }
1999
+ }
2000
+ },
2001
+
1967
2002
  /**
1968
2003
  * Returns the model index of the column the pointer is over or null if the pointer
1969
2004
  * is not over a column.