@yuneta/gobj-ui 7.26.35 → 7.26.37
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/dist/gobj-ui.cjs.js +76 -4
- package/dist/gobj-ui.es.js +76 -4
- package/package.json +1 -1
- package/src/c_yui_window_manager.js +95 -3
- package/src/tabulator.css +19 -3
- package/src/tabulator_css.test.js +63 -0
- package/src/window_layer.wiring.test.js +41 -1
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -5335,7 +5335,8 @@ var attrs_table$20 = [
|
|
|
5335
5335
|
var PRIVATE_DATA$20 = {
|
|
5336
5336
|
windows: null,
|
|
5337
5337
|
mql: null,
|
|
5338
|
-
mql_handler: null
|
|
5338
|
+
mql_handler: null,
|
|
5339
|
+
lang_shell: null
|
|
5339
5340
|
};
|
|
5340
5341
|
var __gclass__$20 = null;
|
|
5341
5342
|
/******************************
|
|
@@ -5357,6 +5358,7 @@ function mt_create$20(gobj) {
|
|
|
5357
5358
|
}
|
|
5358
5359
|
build_dock(gobj);
|
|
5359
5360
|
yui_shell_watch_changes(gobj);
|
|
5361
|
+
follow_language(gobj);
|
|
5360
5362
|
const subscriber = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "subscriber");
|
|
5361
5363
|
if (subscriber) (0, _yuneta_gobj_js.gobj_subscribe_event)(gobj, null, {}, subscriber);
|
|
5362
5364
|
}
|
|
@@ -5366,6 +5368,10 @@ function mt_create$20(gobj) {
|
|
|
5366
5368
|
function mt_destroy$20(gobj) {
|
|
5367
5369
|
let priv = gobj.priv;
|
|
5368
5370
|
yui_shell_unwatch_changes(gobj);
|
|
5371
|
+
if (priv.lang_shell) {
|
|
5372
|
+
if (!(0, _yuneta_gobj_js.gobj_is_destroying)(priv.lang_shell)) (0, _yuneta_gobj_js.gobj_unsubscribe_event)(priv.lang_shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
5373
|
+
priv.lang_shell = null;
|
|
5374
|
+
}
|
|
5369
5375
|
if (priv.mql && priv.mql_handler) {
|
|
5370
5376
|
priv.mql.removeEventListener("change", priv.mql_handler);
|
|
5371
5377
|
priv.mql = null;
|
|
@@ -5377,6 +5383,37 @@ function mt_destroy$20(gobj) {
|
|
|
5377
5383
|
* Local Methods
|
|
5378
5384
|
***************************/
|
|
5379
5385
|
/************************************************************
|
|
5386
|
+
* Hear the language of the shell that holds the dock -- the
|
|
5387
|
+
* dock outlives a shell, so it follows them: the dying one's
|
|
5388
|
+
* subscription goes with it, the next one is heard. The
|
|
5389
|
+
* toggle of a chip whose window's title has a DATA half has a
|
|
5390
|
+
* composed title, which no key carries: it is written again in
|
|
5391
|
+
* the new language (ac_language_changed).
|
|
5392
|
+
************************************************************/
|
|
5393
|
+
function follow_language(gobj) {
|
|
5394
|
+
let priv = gobj.priv;
|
|
5395
|
+
let shell = yui_shell_of(gobj);
|
|
5396
|
+
if (shell && (0, _yuneta_gobj_js.gobj_is_destroying)(shell)) shell = null;
|
|
5397
|
+
if (shell === priv.lang_shell) return;
|
|
5398
|
+
if (priv.lang_shell && !(0, _yuneta_gobj_js.gobj_is_destroying)(priv.lang_shell)) (0, _yuneta_gobj_js.gobj_unsubscribe_event)(priv.lang_shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
5399
|
+
priv.lang_shell = null;
|
|
5400
|
+
if (shell) {
|
|
5401
|
+
(0, _yuneta_gobj_js.gobj_subscribe_event)(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
5402
|
+
priv.lang_shell = shell;
|
|
5403
|
+
}
|
|
5404
|
+
}
|
|
5405
|
+
/************************************************************
|
|
5406
|
+
* The toggle's title and aria-label, in the current language:
|
|
5407
|
+
* the same join as C_YUI_WINDOW's composed_title(), DATA half
|
|
5408
|
+
* first. The title the window registered with when it gave no
|
|
5409
|
+
* halves (a legacy caller).
|
|
5410
|
+
************************************************************/
|
|
5411
|
+
function chip_title(entry) {
|
|
5412
|
+
let kind = entry.title_key ? (0, i18next.t)(entry.title_key) : "";
|
|
5413
|
+
if (entry.title_prefix && kind) return `${entry.title_prefix} · ${kind}`;
|
|
5414
|
+
return entry.title_prefix || kind || entry.title;
|
|
5415
|
+
}
|
|
5416
|
+
/************************************************************
|
|
5380
5417
|
* Inject the dock stylesheet once (theme-aware).
|
|
5381
5418
|
************************************************************/
|
|
5382
5419
|
function ensure_dock_style() {
|
|
@@ -5701,7 +5738,10 @@ function ac_register_window(gobj, event, kw, src) {
|
|
|
5701
5738
|
let entry = {
|
|
5702
5739
|
gobj: win,
|
|
5703
5740
|
$chip: null,
|
|
5704
|
-
minimized: false
|
|
5741
|
+
minimized: false,
|
|
5742
|
+
title,
|
|
5743
|
+
title_key,
|
|
5744
|
+
title_prefix: prefix
|
|
5705
5745
|
};
|
|
5706
5746
|
let window_name = (0, _yuneta_gobj_js.gobj_full_name)(win);
|
|
5707
5747
|
let $chip = (0, _yuneta_gobj_js.createElement2)([
|
|
@@ -5816,10 +5856,36 @@ function ac_toggle_window(gobj, event, kw, src) {
|
|
|
5816
5856
|
* popup layer, or its zone when inline -- may have gone with
|
|
5817
5857
|
* it, or be in the new one: place it again. Up to 7.26.34 an
|
|
5818
5858
|
* inline dock stayed in the destroyed shell's zone after a
|
|
5819
|
-
* logout, detached, until a window registered.
|
|
5859
|
+
* logout, detached, until a window registered. Its language
|
|
5860
|
+
* is the new shell's too.
|
|
5820
5861
|
************************************************************/
|
|
5821
5862
|
function ac_shell_changed(gobj, event, kw, src) {
|
|
5822
5863
|
apply_placement(gobj);
|
|
5864
|
+
follow_language(gobj);
|
|
5865
|
+
return 0;
|
|
5866
|
+
}
|
|
5867
|
+
/************************************************************
|
|
5868
|
+
* EV_LANGUAGE_CHANGED -- from the shell that holds the dock.
|
|
5869
|
+
* A chip's label re-translates by its key (refresh_language()
|
|
5870
|
+
* reaches its kind half); the toggle's title and aria-label
|
|
5871
|
+
* of a window with a DATA half are COMPOSED, so no key carries
|
|
5872
|
+
* them: written again here. Up to 7.26.35 they stayed in the
|
|
5873
|
+
* language the window was opened in (a reader took the
|
|
5874
|
+
* aria-labelledby, which changed; the tooltip did not).
|
|
5875
|
+
************************************************************/
|
|
5876
|
+
function ac_language_changed$11(gobj, event, kw, src) {
|
|
5877
|
+
let priv = gobj.priv;
|
|
5878
|
+
for (let entry of priv.windows) {
|
|
5879
|
+
if (!entry.title_prefix || !entry.$chip) continue;
|
|
5880
|
+
let $toggle = entry.$chip.querySelector(".DOCK_CHIP_TOGGLE");
|
|
5881
|
+
if (!$toggle) {
|
|
5882
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: a chip without its toggle`);
|
|
5883
|
+
continue;
|
|
5884
|
+
}
|
|
5885
|
+
let title = chip_title(entry);
|
|
5886
|
+
$toggle.setAttribute("title", title);
|
|
5887
|
+
$toggle.setAttribute("aria-label", title);
|
|
5888
|
+
}
|
|
5823
5889
|
return 0;
|
|
5824
5890
|
}
|
|
5825
5891
|
/***************************
|
|
@@ -5843,7 +5909,8 @@ function create_gclass$20(gclass_name) {
|
|
|
5843
5909
|
["EV_MINIMIZE_WINDOW", 0],
|
|
5844
5910
|
["EV_FOCUS_WINDOW", 0],
|
|
5845
5911
|
["EV_TOGGLE_WINDOW", 0],
|
|
5846
|
-
["EV_SHELL_CHANGED", 0]
|
|
5912
|
+
["EV_SHELL_CHANGED", 0],
|
|
5913
|
+
["EV_LANGUAGE_CHANGED", 0]
|
|
5847
5914
|
], [["ST_IDLE", [
|
|
5848
5915
|
[
|
|
5849
5916
|
"EV_REGISTER_WINDOW",
|
|
@@ -5874,6 +5941,11 @@ function create_gclass$20(gclass_name) {
|
|
|
5874
5941
|
"EV_SHELL_CHANGED",
|
|
5875
5942
|
ac_shell_changed,
|
|
5876
5943
|
null
|
|
5944
|
+
],
|
|
5945
|
+
[
|
|
5946
|
+
"EV_LANGUAGE_CHANGED",
|
|
5947
|
+
ac_language_changed$11,
|
|
5948
|
+
null
|
|
5877
5949
|
]
|
|
5878
5950
|
]]], gmt$20, 0, attrs_table$20, PRIVATE_DATA$20, 0, 0, 0, 0);
|
|
5879
5951
|
if (!__gclass__$20) return -1;
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -5330,7 +5330,8 @@ var attrs_table$20 = [
|
|
|
5330
5330
|
var PRIVATE_DATA$20 = {
|
|
5331
5331
|
windows: null,
|
|
5332
5332
|
mql: null,
|
|
5333
|
-
mql_handler: null
|
|
5333
|
+
mql_handler: null,
|
|
5334
|
+
lang_shell: null
|
|
5334
5335
|
};
|
|
5335
5336
|
var __gclass__$20 = null;
|
|
5336
5337
|
/******************************
|
|
@@ -5352,6 +5353,7 @@ function mt_create$20(gobj) {
|
|
|
5352
5353
|
}
|
|
5353
5354
|
build_dock(gobj);
|
|
5354
5355
|
yui_shell_watch_changes(gobj);
|
|
5356
|
+
follow_language(gobj);
|
|
5355
5357
|
const subscriber = gobj_read_pointer_attr(gobj, "subscriber");
|
|
5356
5358
|
if (subscriber) gobj_subscribe_event(gobj, null, {}, subscriber);
|
|
5357
5359
|
}
|
|
@@ -5361,6 +5363,10 @@ function mt_create$20(gobj) {
|
|
|
5361
5363
|
function mt_destroy$20(gobj) {
|
|
5362
5364
|
let priv = gobj.priv;
|
|
5363
5365
|
yui_shell_unwatch_changes(gobj);
|
|
5366
|
+
if (priv.lang_shell) {
|
|
5367
|
+
if (!gobj_is_destroying(priv.lang_shell)) gobj_unsubscribe_event(priv.lang_shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
5368
|
+
priv.lang_shell = null;
|
|
5369
|
+
}
|
|
5364
5370
|
if (priv.mql && priv.mql_handler) {
|
|
5365
5371
|
priv.mql.removeEventListener("change", priv.mql_handler);
|
|
5366
5372
|
priv.mql = null;
|
|
@@ -5372,6 +5378,37 @@ function mt_destroy$20(gobj) {
|
|
|
5372
5378
|
* Local Methods
|
|
5373
5379
|
***************************/
|
|
5374
5380
|
/************************************************************
|
|
5381
|
+
* Hear the language of the shell that holds the dock -- the
|
|
5382
|
+
* dock outlives a shell, so it follows them: the dying one's
|
|
5383
|
+
* subscription goes with it, the next one is heard. The
|
|
5384
|
+
* toggle of a chip whose window's title has a DATA half has a
|
|
5385
|
+
* composed title, which no key carries: it is written again in
|
|
5386
|
+
* the new language (ac_language_changed).
|
|
5387
|
+
************************************************************/
|
|
5388
|
+
function follow_language(gobj) {
|
|
5389
|
+
let priv = gobj.priv;
|
|
5390
|
+
let shell = yui_shell_of(gobj);
|
|
5391
|
+
if (shell && gobj_is_destroying(shell)) shell = null;
|
|
5392
|
+
if (shell === priv.lang_shell) return;
|
|
5393
|
+
if (priv.lang_shell && !gobj_is_destroying(priv.lang_shell)) gobj_unsubscribe_event(priv.lang_shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
5394
|
+
priv.lang_shell = null;
|
|
5395
|
+
if (shell) {
|
|
5396
|
+
gobj_subscribe_event(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
5397
|
+
priv.lang_shell = shell;
|
|
5398
|
+
}
|
|
5399
|
+
}
|
|
5400
|
+
/************************************************************
|
|
5401
|
+
* The toggle's title and aria-label, in the current language:
|
|
5402
|
+
* the same join as C_YUI_WINDOW's composed_title(), DATA half
|
|
5403
|
+
* first. The title the window registered with when it gave no
|
|
5404
|
+
* halves (a legacy caller).
|
|
5405
|
+
************************************************************/
|
|
5406
|
+
function chip_title(entry) {
|
|
5407
|
+
let kind = entry.title_key ? t(entry.title_key) : "";
|
|
5408
|
+
if (entry.title_prefix && kind) return `${entry.title_prefix} · ${kind}`;
|
|
5409
|
+
return entry.title_prefix || kind || entry.title;
|
|
5410
|
+
}
|
|
5411
|
+
/************************************************************
|
|
5375
5412
|
* Inject the dock stylesheet once (theme-aware).
|
|
5376
5413
|
************************************************************/
|
|
5377
5414
|
function ensure_dock_style() {
|
|
@@ -5696,7 +5733,10 @@ function ac_register_window(gobj, event, kw, src) {
|
|
|
5696
5733
|
let entry = {
|
|
5697
5734
|
gobj: win,
|
|
5698
5735
|
$chip: null,
|
|
5699
|
-
minimized: false
|
|
5736
|
+
minimized: false,
|
|
5737
|
+
title,
|
|
5738
|
+
title_key,
|
|
5739
|
+
title_prefix: prefix
|
|
5700
5740
|
};
|
|
5701
5741
|
let window_name = gobj_full_name(win);
|
|
5702
5742
|
let $chip = createElement2([
|
|
@@ -5811,10 +5851,36 @@ function ac_toggle_window(gobj, event, kw, src) {
|
|
|
5811
5851
|
* popup layer, or its zone when inline -- may have gone with
|
|
5812
5852
|
* it, or be in the new one: place it again. Up to 7.26.34 an
|
|
5813
5853
|
* inline dock stayed in the destroyed shell's zone after a
|
|
5814
|
-
* logout, detached, until a window registered.
|
|
5854
|
+
* logout, detached, until a window registered. Its language
|
|
5855
|
+
* is the new shell's too.
|
|
5815
5856
|
************************************************************/
|
|
5816
5857
|
function ac_shell_changed(gobj, event, kw, src) {
|
|
5817
5858
|
apply_placement(gobj);
|
|
5859
|
+
follow_language(gobj);
|
|
5860
|
+
return 0;
|
|
5861
|
+
}
|
|
5862
|
+
/************************************************************
|
|
5863
|
+
* EV_LANGUAGE_CHANGED -- from the shell that holds the dock.
|
|
5864
|
+
* A chip's label re-translates by its key (refresh_language()
|
|
5865
|
+
* reaches its kind half); the toggle's title and aria-label
|
|
5866
|
+
* of a window with a DATA half are COMPOSED, so no key carries
|
|
5867
|
+
* them: written again here. Up to 7.26.35 they stayed in the
|
|
5868
|
+
* language the window was opened in (a reader took the
|
|
5869
|
+
* aria-labelledby, which changed; the tooltip did not).
|
|
5870
|
+
************************************************************/
|
|
5871
|
+
function ac_language_changed$11(gobj, event, kw, src) {
|
|
5872
|
+
let priv = gobj.priv;
|
|
5873
|
+
for (let entry of priv.windows) {
|
|
5874
|
+
if (!entry.title_prefix || !entry.$chip) continue;
|
|
5875
|
+
let $toggle = entry.$chip.querySelector(".DOCK_CHIP_TOGGLE");
|
|
5876
|
+
if (!$toggle) {
|
|
5877
|
+
log_error(`${gobj_short_name(gobj)}: a chip without its toggle`);
|
|
5878
|
+
continue;
|
|
5879
|
+
}
|
|
5880
|
+
let title = chip_title(entry);
|
|
5881
|
+
$toggle.setAttribute("title", title);
|
|
5882
|
+
$toggle.setAttribute("aria-label", title);
|
|
5883
|
+
}
|
|
5818
5884
|
return 0;
|
|
5819
5885
|
}
|
|
5820
5886
|
/***************************
|
|
@@ -5838,7 +5904,8 @@ function create_gclass$20(gclass_name) {
|
|
|
5838
5904
|
["EV_MINIMIZE_WINDOW", 0],
|
|
5839
5905
|
["EV_FOCUS_WINDOW", 0],
|
|
5840
5906
|
["EV_TOGGLE_WINDOW", 0],
|
|
5841
|
-
["EV_SHELL_CHANGED", 0]
|
|
5907
|
+
["EV_SHELL_CHANGED", 0],
|
|
5908
|
+
["EV_LANGUAGE_CHANGED", 0]
|
|
5842
5909
|
], [["ST_IDLE", [
|
|
5843
5910
|
[
|
|
5844
5911
|
"EV_REGISTER_WINDOW",
|
|
@@ -5869,6 +5936,11 @@ function create_gclass$20(gclass_name) {
|
|
|
5869
5936
|
"EV_SHELL_CHANGED",
|
|
5870
5937
|
ac_shell_changed,
|
|
5871
5938
|
null
|
|
5939
|
+
],
|
|
5940
|
+
[
|
|
5941
|
+
"EV_LANGUAGE_CHANGED",
|
|
5942
|
+
ac_language_changed$11,
|
|
5943
|
+
null
|
|
5872
5944
|
]
|
|
5873
5945
|
]]], gmt$20, 0, attrs_table$20, PRIVATE_DATA$20, 0, 0, 0, 0);
|
|
5874
5946
|
if (!__gclass__$20) return -1;
|
package/package.json
CHANGED
|
@@ -40,6 +40,8 @@ import {
|
|
|
40
40
|
gobj_short_name,
|
|
41
41
|
gobj_read_pointer_attr,
|
|
42
42
|
gobj_subscribe_event,
|
|
43
|
+
gobj_unsubscribe_event,
|
|
44
|
+
gobj_is_destroying,
|
|
43
45
|
gobj_send_event,
|
|
44
46
|
createElement2,
|
|
45
47
|
gobj_write_attr,
|
|
@@ -92,9 +94,10 @@ SDATA_END()
|
|
|
92
94
|
];
|
|
93
95
|
|
|
94
96
|
let PRIVATE_DATA = {
|
|
95
|
-
windows: null, /* [{gobj, $chip, minimized}] */
|
|
97
|
+
windows: null, /* [{gobj, $chip, minimized, title, title_key, title_prefix}] */
|
|
96
98
|
mql: null, /* MediaQueryList when dock_mode is 'responsive' */
|
|
97
99
|
mql_handler: null, /* its change listener (kept for teardown) */
|
|
100
|
+
lang_shell: null, /* the shell whose EV_LANGUAGE_CHANGED we hear */
|
|
98
101
|
};
|
|
99
102
|
|
|
100
103
|
let __gclass__ = null;
|
|
@@ -139,6 +142,7 @@ function mt_create(gobj)
|
|
|
139
142
|
* a shell is built or destroyed, it places itself again
|
|
140
143
|
* (ac_shell_changed). Unwatched in mt_destroy. */
|
|
141
144
|
yui_shell_watch_changes(gobj);
|
|
145
|
+
follow_language(gobj);
|
|
142
146
|
|
|
143
147
|
/*
|
|
144
148
|
* SERVICE subscription model
|
|
@@ -157,6 +161,12 @@ function mt_destroy(gobj)
|
|
|
157
161
|
let priv = gobj.priv;
|
|
158
162
|
|
|
159
163
|
yui_shell_unwatch_changes(gobj);
|
|
164
|
+
if(priv.lang_shell) {
|
|
165
|
+
if(!gobj_is_destroying(priv.lang_shell)) {
|
|
166
|
+
gobj_unsubscribe_event(priv.lang_shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
167
|
+
}
|
|
168
|
+
priv.lang_shell = null;
|
|
169
|
+
}
|
|
160
170
|
|
|
161
171
|
if(priv.mql && priv.mql_handler) {
|
|
162
172
|
priv.mql.removeEventListener("change", priv.mql_handler);
|
|
@@ -177,6 +187,54 @@ function mt_destroy(gobj)
|
|
|
177
187
|
|
|
178
188
|
|
|
179
189
|
|
|
190
|
+
/************************************************************
|
|
191
|
+
* Hear the language of the shell that holds the dock -- the
|
|
192
|
+
* dock outlives a shell, so it follows them: the dying one's
|
|
193
|
+
* subscription goes with it, the next one is heard. The
|
|
194
|
+
* toggle of a chip whose window's title has a DATA half has a
|
|
195
|
+
* composed title, which no key carries: it is written again in
|
|
196
|
+
* the new language (ac_language_changed).
|
|
197
|
+
************************************************************/
|
|
198
|
+
function follow_language(gobj)
|
|
199
|
+
{
|
|
200
|
+
let priv = gobj.priv;
|
|
201
|
+
|
|
202
|
+
let shell = yui_shell_of(gobj);
|
|
203
|
+
if(shell && gobj_is_destroying(shell)) {
|
|
204
|
+
shell = null;
|
|
205
|
+
}
|
|
206
|
+
if(shell === priv.lang_shell) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if(priv.lang_shell && !gobj_is_destroying(priv.lang_shell)) {
|
|
210
|
+
gobj_unsubscribe_event(priv.lang_shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
211
|
+
}
|
|
212
|
+
priv.lang_shell = null;
|
|
213
|
+
if(shell) {
|
|
214
|
+
gobj_subscribe_event(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
215
|
+
priv.lang_shell = shell;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/************************************************************
|
|
220
|
+
* The toggle's title and aria-label, in the current language:
|
|
221
|
+
* the same join as C_YUI_WINDOW's composed_title(), DATA half
|
|
222
|
+
* first. The title the window registered with when it gave no
|
|
223
|
+
* halves (a legacy caller).
|
|
224
|
+
************************************************************/
|
|
225
|
+
function chip_title(entry)
|
|
226
|
+
{
|
|
227
|
+
/* `title_key` is the window's title, a key its HOST chose. */
|
|
228
|
+
let kind = entry.title_key ? t(/* i18n: data */ entry.title_key) : "";
|
|
229
|
+
if(entry.title_prefix && kind) {
|
|
230
|
+
return `${entry.title_prefix} · ${kind}`;
|
|
231
|
+
}
|
|
232
|
+
return entry.title_prefix || kind || entry.title;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
180
238
|
/************************************************************
|
|
181
239
|
* Inject the dock stylesheet once (theme-aware).
|
|
182
240
|
************************************************************/
|
|
@@ -588,7 +646,8 @@ function ac_register_window(gobj, event, kw, src)
|
|
|
588
646
|
return item[1].id;
|
|
589
647
|
});
|
|
590
648
|
|
|
591
|
-
let entry = {gobj: win, $chip: null, minimized: false
|
|
649
|
+
let entry = {gobj: win, $chip: null, minimized: false,
|
|
650
|
+
title: title, title_key: title_key, title_prefix: prefix};
|
|
592
651
|
/* The chip is a CONTAINER of two sibling controls, and no control
|
|
593
652
|
* itself: the TOGGLE (minimise / bring back, the whole label) and
|
|
594
653
|
* the ✕ (EV_CLOSE_WINDOW → the window's own teardown →
|
|
@@ -735,11 +794,42 @@ function ac_toggle_window(gobj, event, kw, src)
|
|
|
735
794
|
* popup layer, or its zone when inline -- may have gone with
|
|
736
795
|
* it, or be in the new one: place it again. Up to 7.26.34 an
|
|
737
796
|
* inline dock stayed in the destroyed shell's zone after a
|
|
738
|
-
* logout, detached, until a window registered.
|
|
797
|
+
* logout, detached, until a window registered. Its language
|
|
798
|
+
* is the new shell's too.
|
|
739
799
|
************************************************************/
|
|
740
800
|
function ac_shell_changed(gobj, event, kw, src)
|
|
741
801
|
{
|
|
742
802
|
apply_placement(gobj);
|
|
803
|
+
follow_language(gobj);
|
|
804
|
+
return 0;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/************************************************************
|
|
808
|
+
* EV_LANGUAGE_CHANGED -- from the shell that holds the dock.
|
|
809
|
+
* A chip's label re-translates by its key (refresh_language()
|
|
810
|
+
* reaches its kind half); the toggle's title and aria-label
|
|
811
|
+
* of a window with a DATA half are COMPOSED, so no key carries
|
|
812
|
+
* them: written again here. Up to 7.26.35 they stayed in the
|
|
813
|
+
* language the window was opened in (a reader took the
|
|
814
|
+
* aria-labelledby, which changed; the tooltip did not).
|
|
815
|
+
************************************************************/
|
|
816
|
+
function ac_language_changed(gobj, event, kw, src)
|
|
817
|
+
{
|
|
818
|
+
let priv = gobj.priv;
|
|
819
|
+
|
|
820
|
+
for(let entry of priv.windows) {
|
|
821
|
+
if(!entry.title_prefix || !entry.$chip) {
|
|
822
|
+
continue; // a key alone: data-i18n-title / -aria-label re-translate it
|
|
823
|
+
}
|
|
824
|
+
let $toggle = entry.$chip.querySelector(".DOCK_CHIP_TOGGLE");
|
|
825
|
+
if(!$toggle) {
|
|
826
|
+
log_error(`${gobj_short_name(gobj)}: a chip without its toggle`);
|
|
827
|
+
continue;
|
|
828
|
+
}
|
|
829
|
+
let title = chip_title(entry);
|
|
830
|
+
$toggle.setAttribute("title", title);
|
|
831
|
+
$toggle.setAttribute("aria-label", title);
|
|
832
|
+
}
|
|
743
833
|
return 0;
|
|
744
834
|
}
|
|
745
835
|
|
|
@@ -782,6 +872,7 @@ function create_gclass(gclass_name)
|
|
|
782
872
|
["EV_FOCUS_WINDOW", ac_focus_window, null],
|
|
783
873
|
["EV_TOGGLE_WINDOW", ac_toggle_window, null],
|
|
784
874
|
["EV_SHELL_CHANGED", ac_shell_changed, null],
|
|
875
|
+
["EV_LANGUAGE_CHANGED", ac_language_changed, null],
|
|
785
876
|
]]
|
|
786
877
|
];
|
|
787
878
|
|
|
@@ -795,6 +886,7 @@ function create_gclass(gclass_name)
|
|
|
795
886
|
["EV_FOCUS_WINDOW", 0],
|
|
796
887
|
["EV_TOGGLE_WINDOW", 0],
|
|
797
888
|
["EV_SHELL_CHANGED", 0],
|
|
889
|
+
["EV_LANGUAGE_CHANGED", 0],
|
|
798
890
|
];
|
|
799
891
|
|
|
800
892
|
__gclass__ = gclass_create(
|
package/src/tabulator.css
CHANGED
|
@@ -186,11 +186,16 @@
|
|
|
186
186
|
* (`.tabulator-editing {padding: 0}`) and the control brings its own, so
|
|
187
187
|
* the text jumps sideways too. Inherit the font and restore the cell's 4px
|
|
188
188
|
* so entering edit mode changes nothing but the caret.
|
|
189
|
+
*
|
|
190
|
+
* A box to type in, never a box to TICK: a checkbox or a radio given the
|
|
191
|
+
* whole cell is drawn as a square the size of the cell -- the tickCross
|
|
192
|
+
* editor of a boolean (estadodelaire's "validated") opened as a huge empty
|
|
193
|
+
* box on a phone, which read as broken. Those keep their own size.
|
|
189
194
|
* ==================================================================== */
|
|
190
|
-
.tabulator-row .tabulator-cell.tabulator-editing input,
|
|
195
|
+
.tabulator-row .tabulator-cell.tabulator-editing input:not([type=checkbox]):not([type=radio]),
|
|
191
196
|
.tabulator-row .tabulator-cell.tabulator-editing select,
|
|
192
197
|
.tabulator-row .tabulator-cell.tabulator-editing textarea,
|
|
193
|
-
.tabulator .tabulator-header .tabulator-header-filter input,
|
|
198
|
+
.tabulator .tabulator-header .tabulator-header-filter input:not([type=checkbox]):not([type=radio]),
|
|
194
199
|
.tabulator .tabulator-header .tabulator-header-filter select {
|
|
195
200
|
font-family: inherit;
|
|
196
201
|
font-size: inherit;
|
|
@@ -199,11 +204,22 @@
|
|
|
199
204
|
padding: 0 4px;
|
|
200
205
|
}
|
|
201
206
|
|
|
202
|
-
.tabulator-row .tabulator-cell.tabulator-editing input,
|
|
207
|
+
.tabulator-row .tabulator-cell.tabulator-editing input:not([type=checkbox]):not([type=radio]),
|
|
203
208
|
.tabulator-row .tabulator-cell.tabulator-editing select {
|
|
204
209
|
height: 100%;
|
|
205
210
|
}
|
|
206
211
|
|
|
212
|
+
/* The box to tick, sized for a finger where there is one: the browser's
|
|
213
|
+
* own checkbox is ~13px, too small to hit on a phone -- and the cell
|
|
214
|
+
* is no size for it either (above). */
|
|
215
|
+
@media (pointer: coarse) {
|
|
216
|
+
.tabulator-row .tabulator-cell.tabulator-editing input[type=checkbox],
|
|
217
|
+
.tabulator-row .tabulator-cell.tabulator-editing input[type=radio] {
|
|
218
|
+
width: 1.5rem;
|
|
219
|
+
height: 1.5rem;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
207
223
|
/*
|
|
208
224
|
* The CELL EDITOR in dark theme.
|
|
209
225
|
*
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/***********************************************************************
|
|
2
|
+
* tabulator_css.test.js
|
|
3
|
+
*
|
|
4
|
+
* The stylesheet of the tables: an editor fills its cell only when
|
|
5
|
+
* it is a box to TYPE in. A checkbox or a radio given width and
|
|
6
|
+
* height 100% is drawn as a square the size of the cell (the
|
|
7
|
+
* tickCross editor of estadodelaire's "validated" opened as a huge
|
|
8
|
+
* empty box on a phone, gobj-ui 7.26.36).
|
|
9
|
+
*
|
|
10
|
+
* Read as text, as the window layer's invariants are: jsdom applies
|
|
11
|
+
* no stylesheet.
|
|
12
|
+
*
|
|
13
|
+
* Copyright (c) 2026, ArtGins.
|
|
14
|
+
* All Rights Reserved.
|
|
15
|
+
***********************************************************************/
|
|
16
|
+
import {describe, test, expect} from "vitest";
|
|
17
|
+
import {readFileSync} from "node:fs";
|
|
18
|
+
import {dirname, join} from "node:path";
|
|
19
|
+
import {fileURLToPath} from "node:url";
|
|
20
|
+
|
|
21
|
+
const CSS = readFileSync(join(dirname(fileURLToPath(import.meta.url)), "tabulator.css"), "utf8")
|
|
22
|
+
.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
23
|
+
|
|
24
|
+
/* Every rule: its selectors, and its body. */
|
|
25
|
+
function rules()
|
|
26
|
+
{
|
|
27
|
+
const out = [];
|
|
28
|
+
const re = /([^{}]+)\{([^{}]*)\}/g;
|
|
29
|
+
let m;
|
|
30
|
+
while((m = re.exec(CSS)) !== null) {
|
|
31
|
+
out.push({
|
|
32
|
+
selectors: m[1].split(",").map((s) => s.trim()).filter(Boolean),
|
|
33
|
+
body: m[2]
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe("an editor fills its cell only when it is a box to type in", () => {
|
|
40
|
+
test("no rule sizes a checkbox or a radio of a table to its cell", () => {
|
|
41
|
+
const offenders = [];
|
|
42
|
+
for(const r of rules()) {
|
|
43
|
+
if(!/\b(width|height)\s*:\s*100%/.test(r.body)) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
for(const sel of r.selectors) {
|
|
47
|
+
/* A bare `input` in a cell editor or a header filter reaches
|
|
48
|
+
* a checkbox too, unless the selector leaves it out. */
|
|
49
|
+
if(/\binput\b/.test(sel) && /tabulator/.test(sel) &&
|
|
50
|
+
!(/:not\(\[type=checkbox\]\)/.test(sel) && /:not\(\[type=radio\]\)/.test(sel))) {
|
|
51
|
+
offenders.push(sel);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
expect(offenders).toEqual([]);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("a text input of a cell being edited still fills it", () => {
|
|
59
|
+
const fill = rules().filter((r) => /\bwidth\s*:\s*100%/.test(r.body) &&
|
|
60
|
+
r.selectors.some((s) => /tabulator-editing input:not\(\[type=checkbox\]\)/.test(s)));
|
|
61
|
+
expect(fill.length).toBeGreaterThan(0);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -36,7 +36,7 @@ const {
|
|
|
36
36
|
gobj_start, gobj_stop, gobj_destroy, gobj_read_attr, gobj_is_destroying,
|
|
37
37
|
set_log_callback,
|
|
38
38
|
} = await import("@yuneta/gobj-js");
|
|
39
|
-
const {register_c_yui_shell, yui_shell_window_layer} = await import("./c_yui_shell.js");
|
|
39
|
+
const {register_c_yui_shell, yui_shell_window_layer, yui_shell_language_changed} = await import("./c_yui_shell.js");
|
|
40
40
|
const {register_c_yui_nav} = await import("./c_yui_nav.js");
|
|
41
41
|
const {register_c_yui_window} = await import("./c_yui_window.js");
|
|
42
42
|
const {register_c_yui_window_manager} = await import("./c_yui_window_manager.js");
|
|
@@ -369,3 +369,43 @@ describe("the stacking of the windows", () => {
|
|
|
369
369
|
expect(z_of(windows) < z_of(drawer)).toBe(true);
|
|
370
370
|
});
|
|
371
371
|
});
|
|
372
|
+
|
|
373
|
+
describe("the title of a dock chip changes language (REV-CLOUD V23, QA of estadodelaire)", () => {
|
|
374
|
+
/* A window with a DATA half (a device id) and a KIND half (a key):
|
|
375
|
+
* the toggle's title and aria-label are COMPOSED, so no key carries
|
|
376
|
+
* them. Up to 7.26.35 they stayed in the language the window was
|
|
377
|
+
* opened in; the dock composes them again on the shell's
|
|
378
|
+
* EV_LANGUAGE_CHANGED -- of the shell that holds it now, across a
|
|
379
|
+
* logout. */
|
|
380
|
+
test("composed again in the new language, and after a logout by the next shell", async () => {
|
|
381
|
+
const i18next = (await import("i18next")).default;
|
|
382
|
+
i18next.addResourceBundle("en", "translation", {"device alarms": "Device alarms"}, true, true);
|
|
383
|
+
i18next.addResourceBundle("es", "translation", {"device alarms": "Alarmas del dispositivo"}, true, true);
|
|
384
|
+
await i18next.changeLanguage("en");
|
|
385
|
+
|
|
386
|
+
const shell = build_shell();
|
|
387
|
+
const dock = gobj_create_service(`lang_dock_${++seq}`, "C_YUI_WINDOW_MANAGER", {}, yuno);
|
|
388
|
+
gobj_start(dock);
|
|
389
|
+
const w = open_window(`lang_w_${seq}`,
|
|
390
|
+
{title: "device alarms", title_prefix: "DEV-1", manager: dock});
|
|
391
|
+
const $toggle = gobj_read_attr(dock, "$container").querySelector(".DOCK_CHIP_TOGGLE");
|
|
392
|
+
expect($toggle.getAttribute("title")).toBe("DEV-1 · Device alarms");
|
|
393
|
+
|
|
394
|
+
await i18next.changeLanguage("es");
|
|
395
|
+
yui_shell_language_changed(shell);
|
|
396
|
+
expect($toggle.getAttribute("title")).toBe("DEV-1 · Alarmas del dispositivo");
|
|
397
|
+
expect($toggle.getAttribute("aria-label")).toBe("DEV-1 · Alarmas del dispositivo");
|
|
398
|
+
|
|
399
|
+
logout(shell);
|
|
400
|
+
const shell2 = build_shell();
|
|
401
|
+
await i18next.changeLanguage("en");
|
|
402
|
+
yui_shell_language_changed(shell2);
|
|
403
|
+
expect($toggle.getAttribute("title")).toBe("DEV-1 · Device alarms");
|
|
404
|
+
expect($toggle.getAttribute("aria-label")).toBe("DEV-1 · Device alarms");
|
|
405
|
+
expect(errors()).toEqual([]);
|
|
406
|
+
|
|
407
|
+
close(w);
|
|
408
|
+
gobj_destroy(dock);
|
|
409
|
+
logout(shell2);
|
|
410
|
+
});
|
|
411
|
+
});
|