@yuneta/gobj-ui 7.25.15 → 7.25.16
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/README.md +59 -4
- package/dist/gobj-ui.cjs.js +222 -41
- package/dist/gobj-ui.es.js +222 -41
- package/package.json +2 -2
- package/src/c_g6_nodes_tree.js +37 -4
- package/src/c_yui_schema_editor.js +239 -29
- package/src/form_busy.test.js +1 -1
- package/src/form_writes_in_flight.test.js +1 -1
- package/src/g6_graphs_write_owed.wiring.test.js +200 -0
- package/src/host_drafts.test.js +2 -2
- package/src/schema_editor_drafts.wiring.test.js +1 -1
- package/src/schema_editor_reload.wiring.test.js +152 -4
- package/src/shell_modals.js +29 -8
- package/src/shell_toast_once.test.js +63 -0
- package/src/table_cell_text.test.js +1 -1
- package/src/treedb_topics_transport.wiring.test.js +1 -1
- package/src/yui_install.js +14 -3
- package/src/yui_install.test.js +23 -0
|
@@ -316,6 +316,8 @@ const WAIT = "the schemas are loading: wait for them";
|
|
|
316
316
|
const STALE = "the schemas were read again: open the dialog again";
|
|
317
317
|
const KEPT = "cannot read the schemas again: the ones shown may be out of date, your next change reads them first";
|
|
318
318
|
const OWED = "the schemas shown may be out of date: they are read again, try again when they are in";
|
|
319
|
+
const OWED_FORM = "the schemas shown may be out of date: they are read again, and the form opens again on them with your changes";
|
|
320
|
+
const GONE = "the schemas were read again and what the form was editing is not there any more";
|
|
319
321
|
const NOT_SENT = "the treedb did not describe a write back: the writes after it were not sent";
|
|
320
322
|
|
|
321
323
|
describe("the screen of a reload", () => {
|
|
@@ -618,6 +620,7 @@ describe("a load that fails IN session", () => {
|
|
|
618
620
|
const {editor, remote, host} = build("b1", "db/users");
|
|
619
621
|
gobj_send_event(editor, "EV_EDIT_COLUMN", {col: "id"}, host);
|
|
620
622
|
const form = modals[modals.length - 1];
|
|
623
|
+
form.$content.querySelector('[data-name="header"]').value = "Identifier";
|
|
621
624
|
gobj_send_event(editor, "EV_REFRESH", {}, host);
|
|
622
625
|
const asked = take("nodes");
|
|
623
626
|
answer(editor, remote, asked[0], -1, null, "deadline");
|
|
@@ -634,16 +637,28 @@ describe("a load that fails IN session", () => {
|
|
|
634
637
|
|
|
635
638
|
/* The form was built on a model that may be older than the
|
|
636
639
|
* store: its Save would write every field of it. It runs the
|
|
637
|
-
* reload owed instead
|
|
638
|
-
*
|
|
640
|
+
* reload owed instead. The load that lands closes the form,
|
|
641
|
+
* and opens it again ON THE SCHEMAS JUST READ with what the
|
|
642
|
+
* operator changed: closed alone, what was typed was lost. */
|
|
639
643
|
form.$content.querySelector(".SCHEMA_COL_FORM_SAVE").click();
|
|
640
644
|
expect(not_defined()).toEqual([]);
|
|
641
645
|
expect(take("update-node")).toEqual([]);
|
|
642
|
-
expect(shown).toEqual([KEPT,
|
|
646
|
+
expect(shown).toEqual([KEPT, OWED_FORM]);
|
|
647
|
+
const before = modals.length;
|
|
643
648
|
expect(answer_the_load(editor, remote)).toBe(3);
|
|
644
649
|
expect(form.closed).toBe(true);
|
|
645
|
-
expect(
|
|
650
|
+
expect(modals.length).toBe(before + 1);
|
|
651
|
+
const again = modals[modals.length - 1];
|
|
652
|
+
expect(again.closed).toBe(false);
|
|
653
|
+
expect(again.$content.querySelector('[data-name="header"]').value).toBe("Identifier");
|
|
654
|
+
expect(shown).toEqual([KEPT, OWED_FORM]);
|
|
646
655
|
expect(editor.priv.reload_on_open).toBe(false);
|
|
656
|
+
|
|
657
|
+
/* Its Save writes, on the record just read. */
|
|
658
|
+
again.$content.querySelector(".SCHEMA_COL_FORM_SAVE").click();
|
|
659
|
+
const [write] = take("update-node");
|
|
660
|
+
expect(write.kw.record.id).toBe("db.users.id");
|
|
661
|
+
expect(write.kw.record.header).toBe("Identifier");
|
|
647
662
|
expect(errors()).toEqual([]);
|
|
648
663
|
});
|
|
649
664
|
|
|
@@ -1353,3 +1368,136 @@ describe("a move sent by the host while a dialog is up", () => {
|
|
|
1353
1368
|
expect(shown).toEqual([]);
|
|
1354
1369
|
});
|
|
1355
1370
|
});
|
|
1371
|
+
|
|
1372
|
+
describe("the form opened again after the owed reload", () => {
|
|
1373
|
+
|
|
1374
|
+
function owing(name, subpath)
|
|
1375
|
+
{
|
|
1376
|
+
const built = build(name, subpath);
|
|
1377
|
+
built.editor.priv.reload_on_open = true; /* as a load refused in session leaves it */
|
|
1378
|
+
return built;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
test("only what was CHANGED is carried: a field the store changed meanwhile shows the store's", () => {
|
|
1382
|
+
const {editor, remote, host} = build("ro6", "db/users");
|
|
1383
|
+
gobj_send_event(editor, "EV_EDIT_COLUMN", {col: "id"}, host);
|
|
1384
|
+
editor.priv.reload_on_open = true;
|
|
1385
|
+
const form = modals[modals.length - 1];
|
|
1386
|
+
form.$content.querySelector('[data-name="header"]').value = "Identifier";
|
|
1387
|
+
form.$content.querySelector(".SCHEMA_COL_FORM_SAVE").click();
|
|
1388
|
+
answer_the_load_with(editor, remote, records_with((r) => {
|
|
1389
|
+
r.cols[0].description = "written by somebody else";
|
|
1390
|
+
}));
|
|
1391
|
+
const again = modals[modals.length - 1];
|
|
1392
|
+
expect(again.$content.querySelector('[data-name="header"]').value).toBe("Identifier");
|
|
1393
|
+
expect(again.$content.querySelector('[data-name="description"]').value)
|
|
1394
|
+
.toBe("written by somebody else");
|
|
1395
|
+
again.$content.querySelector(".SCHEMA_COL_FORM_SAVE").click();
|
|
1396
|
+
const [write] = take("update-node");
|
|
1397
|
+
expect(write.kw.record.description).toBe("written by somebody else");
|
|
1398
|
+
expect(write.kw.record.header).toBe("Identifier");
|
|
1399
|
+
expect(errors()).toEqual([]);
|
|
1400
|
+
});
|
|
1401
|
+
|
|
1402
|
+
test("a NEW column comes back whole: its name, its type and its flags", () => {
|
|
1403
|
+
const {editor, remote, host} = owing("ro2", "db/users");
|
|
1404
|
+
/* The owed reload runs on the form's opening too: open it on a
|
|
1405
|
+
* model that is current, then owe the reload. */
|
|
1406
|
+
editor.priv.reload_on_open = false;
|
|
1407
|
+
gobj_send_event(editor, "EV_ADD_COLUMN", {}, host);
|
|
1408
|
+
editor.priv.reload_on_open = true;
|
|
1409
|
+
const form = modals[modals.length - 1];
|
|
1410
|
+
form.$content.querySelector('[data-name="value"]').value = "email";
|
|
1411
|
+
form.$content.querySelector('[data-name="header"]').value = "Email";
|
|
1412
|
+
for(const $box of form.$content.querySelectorAll(".SCHEMA_FLAG_BOX")) {
|
|
1413
|
+
if($box.dataset.flag === "required") {
|
|
1414
|
+
$box.checked = true;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
form.$content.querySelector(".SCHEMA_COL_FORM_SAVE").click();
|
|
1418
|
+
expect(shown).toEqual([OWED_FORM]);
|
|
1419
|
+
answer_the_load(editor, remote);
|
|
1420
|
+
const again = modals[modals.length - 1];
|
|
1421
|
+
expect(again).not.toBe(form);
|
|
1422
|
+
expect(again.$content.querySelector('[data-name="value"]').value).toBe("email");
|
|
1423
|
+
expect(again.$content.querySelector('[data-name="header"]').value).toBe("Email");
|
|
1424
|
+
const on = [...again.$content.querySelectorAll(".SCHEMA_FLAG_BOX")]
|
|
1425
|
+
.filter(($b) => $b.checked).map(($b) => $b.dataset.flag);
|
|
1426
|
+
expect(on).toContain("required");
|
|
1427
|
+
expect(errors()).toEqual([]);
|
|
1428
|
+
});
|
|
1429
|
+
|
|
1430
|
+
test("a topic form comes back the same way", () => {
|
|
1431
|
+
const {editor, remote, host} = build("ro3", "db");
|
|
1432
|
+
gobj_send_event(editor, "EV_EDIT_TOPIC", {topic: "users"}, host);
|
|
1433
|
+
editor.priv.reload_on_open = true;
|
|
1434
|
+
const form = modals[modals.length - 1];
|
|
1435
|
+
form.$content.querySelector('[data-name="tkey"]').value = "tm";
|
|
1436
|
+
form.$content.querySelector(".SCHEMA_TOPIC_FORM_SAVE").click();
|
|
1437
|
+
expect(shown).toEqual([OWED_FORM]);
|
|
1438
|
+
answer_the_load(editor, remote);
|
|
1439
|
+
const again = modals[modals.length - 1];
|
|
1440
|
+
expect(again).not.toBe(form);
|
|
1441
|
+
expect(again.$content.querySelector('[data-name="tkey"]').value).toBe("tm");
|
|
1442
|
+
expect(errors()).toEqual([]);
|
|
1443
|
+
});
|
|
1444
|
+
|
|
1445
|
+
test("what the form edited is gone after the reload: not opened again, and SAID", () => {
|
|
1446
|
+
const {editor, remote, host} = build("ro4", "db/users");
|
|
1447
|
+
gobj_send_event(editor, "EV_EDIT_COLUMN", {col: "id"}, host);
|
|
1448
|
+
editor.priv.reload_on_open = true;
|
|
1449
|
+
const form = modals[modals.length - 1];
|
|
1450
|
+
form.$content.querySelector(".SCHEMA_COL_FORM_SAVE").click();
|
|
1451
|
+
const before = modals.length;
|
|
1452
|
+
answer_the_load_with(editor, remote, records_with((r) => {
|
|
1453
|
+
r.cols = [];
|
|
1454
|
+
}));
|
|
1455
|
+
expect(form.closed).toBe(true);
|
|
1456
|
+
expect(modals.length).toBe(before);
|
|
1457
|
+
expect(shown).toEqual([OWED_FORM, GONE]);
|
|
1458
|
+
expect(errors()).toEqual([]);
|
|
1459
|
+
});
|
|
1460
|
+
|
|
1461
|
+
test("a form closed by the operator while the reload ran is not opened again", () => {
|
|
1462
|
+
const {editor, remote, host} = build("ro5", "db/users");
|
|
1463
|
+
gobj_send_event(editor, "EV_EDIT_COLUMN", {col: "id"}, host);
|
|
1464
|
+
editor.priv.reload_on_open = true;
|
|
1465
|
+
const form = modals[modals.length - 1];
|
|
1466
|
+
form.$content.querySelector(".SCHEMA_COL_FORM_SAVE").click();
|
|
1467
|
+
form.$content.querySelector(".SCHEMA_COL_FORM_CANCEL").click();
|
|
1468
|
+
const before = modals.length;
|
|
1469
|
+
answer_the_load(editor, remote);
|
|
1470
|
+
expect(modals.length).toBe(before);
|
|
1471
|
+
expect(shown).toEqual([OWED_FORM]);
|
|
1472
|
+
expect(errors()).toEqual([]);
|
|
1473
|
+
});
|
|
1474
|
+
});
|
|
1475
|
+
|
|
1476
|
+
describe("EV_REFRESH while a write is in flight", () => {
|
|
1477
|
+
|
|
1478
|
+
test("waits for the end of the writes: the queue is written whole, then the schemas are read", () => {
|
|
1479
|
+
const {editor, remote, host} = build("rq1", "db");
|
|
1480
|
+
gobj_send_event(editor, "EV_CONFIRMED", {what: "topic", topic: "users",
|
|
1481
|
+
model_gen: editor.priv.model_gen}, editor);
|
|
1482
|
+
expect(gobj_current_state(editor)).toBe("ST_SAVING");
|
|
1483
|
+
const [first] = take("delete-node");
|
|
1484
|
+
expect(first.kw.topic_name).toBe("cols");
|
|
1485
|
+
|
|
1486
|
+
gobj_send_event(editor, "EV_REFRESH", {}, host);
|
|
1487
|
+
expect(gobj_current_state(editor)).toBe("ST_SAVING");
|
|
1488
|
+
expect(take("nodes")).toEqual([]);
|
|
1489
|
+
expect(logged.some((l) => l.level === "warning" &&
|
|
1490
|
+
/EV_REFRESH.*when the writes end/.test(l.msg))).toBe(true);
|
|
1491
|
+
|
|
1492
|
+
answer(editor, remote, first, 0, {});
|
|
1493
|
+
const [second] = take("delete-node");
|
|
1494
|
+
expect(second.kw.topic_name).toBe("topics");
|
|
1495
|
+
answer(editor, remote, second, 0, {});
|
|
1496
|
+
|
|
1497
|
+
expect(gobj_current_state(editor)).toBe("ST_LOADING");
|
|
1498
|
+
expect(answer_the_load(editor, remote)).toBe(3);
|
|
1499
|
+
expect(editor.priv.written).toEqual({});
|
|
1500
|
+
expect(errors()).toEqual([]);
|
|
1501
|
+
expect(not_defined()).toEqual([]);
|
|
1502
|
+
});
|
|
1503
|
+
});
|
package/src/shell_modals.js
CHANGED
|
@@ -613,9 +613,30 @@ function build_dialog(shell, message, buttons, opts)
|
|
|
613
613
|
}
|
|
614
614
|
|
|
615
615
|
|
|
616
|
+
/***************************************************************
|
|
617
|
+
* The labels a confirmation shows when the caller names none.
|
|
618
|
+
*
|
|
619
|
+
* They are i18n KEYS, lower-case like every key: a button
|
|
620
|
+
* translates its label with the app's t() -- its text, its title
|
|
621
|
+
* and its aria-label. Until 7.25.16 they were "OK", "Yes", "No",
|
|
622
|
+
* "Delete" and "Cancel", keys that no locale carries, so a dialog
|
|
623
|
+
* that took the defaults read in English in every language.
|
|
624
|
+
*
|
|
625
|
+
* Written as `i18n:` entries so the validate-locales script of a
|
|
626
|
+
* consumer finds them when it scans this module: an app that
|
|
627
|
+
* mounts these dialogs must define the five keys.
|
|
628
|
+
***************************************************************/
|
|
629
|
+
const DEFAULT_LABEL = Object.freeze({
|
|
630
|
+
ok: Object.freeze({i18n: "ok"}),
|
|
631
|
+
yes: Object.freeze({i18n: "yes"}),
|
|
632
|
+
no: Object.freeze({i18n: "no"}),
|
|
633
|
+
delete: Object.freeze({i18n: "delete"}),
|
|
634
|
+
cancel: Object.freeze({i18n: "cancel"})
|
|
635
|
+
});
|
|
636
|
+
|
|
616
637
|
export function yui_shell_confirm_ok(shell, message, opts)
|
|
617
638
|
{
|
|
618
|
-
let label = (opts && opts.ok_label) ||
|
|
639
|
+
let label = (opts && opts.ok_label) || DEFAULT_LABEL.ok.i18n;
|
|
619
640
|
if(!opts || !opts.type) {
|
|
620
641
|
opts = Object.assign({}, opts, {type: "success"});
|
|
621
642
|
}
|
|
@@ -626,8 +647,8 @@ export function yui_shell_confirm_ok(shell, message, opts)
|
|
|
626
647
|
|
|
627
648
|
export function yui_shell_confirm_yesno(shell, message, opts)
|
|
628
649
|
{
|
|
629
|
-
let yes_label = (opts && opts.yes_label) ||
|
|
630
|
-
let no_label = (opts && opts.no_label) ||
|
|
650
|
+
let yes_label = (opts && opts.yes_label) || DEFAULT_LABEL.yes.i18n;
|
|
651
|
+
let no_label = (opts && opts.no_label) || DEFAULT_LABEL.no.i18n;
|
|
631
652
|
return build_dialog(shell, message, [
|
|
632
653
|
{label: yes_label, value: "yes", kind: "primary"},
|
|
633
654
|
{label: no_label, value: "no"}
|
|
@@ -650,8 +671,8 @@ export function yui_shell_confirm_yesno(shell, message, opts)
|
|
|
650
671
|
***************************************************************/
|
|
651
672
|
export function yui_shell_confirm_danger(shell, message, opts)
|
|
652
673
|
{
|
|
653
|
-
let confirm_label = (opts && opts.confirm_label) ||
|
|
654
|
-
let cancel_label = (opts && opts.cancel_label) ||
|
|
674
|
+
let confirm_label = (opts && opts.confirm_label) || DEFAULT_LABEL.delete.i18n;
|
|
675
|
+
let cancel_label = (opts && opts.cancel_label) || DEFAULT_LABEL.cancel.i18n;
|
|
655
676
|
if(!opts || !opts.type) {
|
|
656
677
|
opts = Object.assign({}, opts, {type: "danger"});
|
|
657
678
|
}
|
|
@@ -663,9 +684,9 @@ export function yui_shell_confirm_danger(shell, message, opts)
|
|
|
663
684
|
|
|
664
685
|
export function yui_shell_confirm_yesnocancel(shell, message, opts)
|
|
665
686
|
{
|
|
666
|
-
let yes_label = (opts && opts.yes_label) ||
|
|
667
|
-
let no_label = (opts && opts.no_label) ||
|
|
668
|
-
let cancel_label = (opts && opts.cancel_label) ||
|
|
687
|
+
let yes_label = (opts && opts.yes_label) || DEFAULT_LABEL.yes.i18n;
|
|
688
|
+
let no_label = (opts && opts.no_label) || DEFAULT_LABEL.no.i18n;
|
|
689
|
+
let cancel_label = (opts && opts.cancel_label) || DEFAULT_LABEL.cancel.i18n;
|
|
669
690
|
return build_dialog(shell, message, [
|
|
670
691
|
{label: yes_label, value: "yes", kind: "primary"},
|
|
671
692
|
{label: no_label, value: "no"},
|
|
@@ -30,6 +30,9 @@ const {
|
|
|
30
30
|
yui_shell_show_info,
|
|
31
31
|
yui_shell_show_modal,
|
|
32
32
|
yui_shell_confirm_danger,
|
|
33
|
+
yui_shell_confirm_ok,
|
|
34
|
+
yui_shell_confirm_yesno,
|
|
35
|
+
yui_shell_confirm_yesnocancel,
|
|
33
36
|
} = await import("./shell_modals.js");
|
|
34
37
|
|
|
35
38
|
let shell = null;
|
|
@@ -200,3 +203,63 @@ describe("every other button of a dialog is named", () => {
|
|
|
200
203
|
]);
|
|
201
204
|
});
|
|
202
205
|
});
|
|
206
|
+
|
|
207
|
+
/*
|
|
208
|
+
* A confirmation that names no label shows the DEFAULT ones, and those
|
|
209
|
+
* are i18n keys like every other label: lower-case, translated by the
|
|
210
|
+
* app's t(), and carried as the key of the text, the title and the
|
|
211
|
+
* aria-label. They were "OK", "Yes", "No", "Delete" and "Cancel" --
|
|
212
|
+
* keys no locale has, so the button read in English in every language.
|
|
213
|
+
*/
|
|
214
|
+
describe("the default labels of a confirmation are i18n keys", () => {
|
|
215
|
+
|
|
216
|
+
function keys_of($layer)
|
|
217
|
+
{
|
|
218
|
+
return [...$layer.querySelectorAll(".CONFIRM_BTN")].map(($b) => [
|
|
219
|
+
$b.getAttribute("data-i18n"),
|
|
220
|
+
$b.getAttribute("data-i18n-title"),
|
|
221
|
+
$b.getAttribute("data-i18n-aria-label"),
|
|
222
|
+
]);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* What the reader hears: the aria-label, translated by t() when
|
|
226
|
+
* the button is built. */
|
|
227
|
+
function texts_of($layer)
|
|
228
|
+
{
|
|
229
|
+
return [...$layer.querySelectorAll(".CONFIRM_BTN")].map(($b) => $b.getAttribute("aria-label"));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const k = (key) => [key, key, key];
|
|
233
|
+
|
|
234
|
+
/* A translator that tells a key it knows from one it does not. */
|
|
235
|
+
const ES = {ok: "Aceptar", yes: "Sí", no: "No", delete: "Borrar", cancel: "Cancelar"};
|
|
236
|
+
const t = (key) => ES[key] || `?${key}?`;
|
|
237
|
+
|
|
238
|
+
test("ok", () => {
|
|
239
|
+
shell.priv.layers.modal = document.createElement("div");
|
|
240
|
+
yui_shell_confirm_ok(shell, "saved", {t: t});
|
|
241
|
+
expect(keys_of(shell.priv.layers.modal)).toEqual([k("ok")]);
|
|
242
|
+
expect(texts_of(shell.priv.layers.modal)).toEqual(["Aceptar"]);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
test("yes / no", () => {
|
|
246
|
+
shell.priv.layers.modal = document.createElement("div");
|
|
247
|
+
yui_shell_confirm_yesno(shell, "go on?", {t: t});
|
|
248
|
+
expect(keys_of(shell.priv.layers.modal)).toEqual([k("yes"), k("no")]);
|
|
249
|
+
expect(texts_of(shell.priv.layers.modal)).toEqual(["Sí", "No"]);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test("yes / no / cancel", () => {
|
|
253
|
+
shell.priv.layers.modal = document.createElement("div");
|
|
254
|
+
yui_shell_confirm_yesnocancel(shell, "keep it?", {t: t});
|
|
255
|
+
expect(keys_of(shell.priv.layers.modal)).toEqual([k("yes"), k("no"), k("cancel")]);
|
|
256
|
+
expect(texts_of(shell.priv.layers.modal)).toEqual(["Sí", "No", "Cancelar"]);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test("delete / cancel", () => {
|
|
260
|
+
shell.priv.layers.modal = document.createElement("div");
|
|
261
|
+
yui_shell_confirm_danger(shell, "delete this column?", {t: t});
|
|
262
|
+
expect(keys_of(shell.priv.layers.modal)).toEqual([k("delete"), k("cancel")]);
|
|
263
|
+
expect(texts_of(shell.priv.layers.modal)).toEqual(["Borrar", "Cancelar"]);
|
|
264
|
+
});
|
|
265
|
+
});
|
|
@@ -9,7 +9,7 @@ const doc = {
|
|
|
9
9
|
describe("table_cell_text", () => {
|
|
10
10
|
|
|
11
11
|
it("record text is a text node, markup included", () => {
|
|
12
|
-
/*
|
|
12
|
+
/* Tabulator puts a string through innerHTML */
|
|
13
13
|
const node = cell_text("limit a<b and c>d", doc);
|
|
14
14
|
expect(node.nodeType).toBe(3);
|
|
15
15
|
expect(node.textContent).toBe("limit a<b and c>d");
|
|
@@ -169,7 +169,7 @@ function errors()
|
|
|
169
169
|
return logged.filter((l) => l.level === "error").map((l) => l.msg);
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
describe("a Save in flight when the backend drops
|
|
172
|
+
describe("a Save in flight when the backend drops", () => {
|
|
173
173
|
|
|
174
174
|
test("the shell's connection edge answers every form, with no host forwarding", () => {
|
|
175
175
|
const {shell, topics, forms} = build("t1");
|
package/src/yui_install.js
CHANGED
|
@@ -194,6 +194,17 @@ function yui_install_start_watch()
|
|
|
194
194
|
* app can call yui_install_prompt() from a button of its
|
|
195
195
|
* own whenever it likes.
|
|
196
196
|
***************************************************************/
|
|
197
|
+
/* The question and its answers when the app names none. They are i18n
|
|
198
|
+
* KEYS, lower-case, and the ones every consumer already defines; the
|
|
199
|
+
* question was "Install this app?" until 7.25.16, a key no locale
|
|
200
|
+
* carries. Written as `i18n:` entries so the validate-locales script of
|
|
201
|
+
* a consumer finds them when it scans this module. */
|
|
202
|
+
const DEFAULT_ASK = Object.freeze({
|
|
203
|
+
message: Object.freeze({i18n: "install this app"}),
|
|
204
|
+
yes: Object.freeze({i18n: "install"}),
|
|
205
|
+
no: Object.freeze({i18n: "not now"})
|
|
206
|
+
});
|
|
207
|
+
|
|
197
208
|
function yui_install_ask_once(shell, opts)
|
|
198
209
|
{
|
|
199
210
|
opts = opts || {};
|
|
@@ -213,10 +224,10 @@ function yui_install_ask_once(shell, opts)
|
|
|
213
224
|
S.asking = true;
|
|
214
225
|
kw_set_local_storage_value(ASKED_KEY, true);
|
|
215
226
|
|
|
216
|
-
yui_shell_confirm_yesno(shell, opts.message ||
|
|
227
|
+
yui_shell_confirm_yesno(shell, opts.message || DEFAULT_ASK.message.i18n, {
|
|
217
228
|
t: opts.t,
|
|
218
|
-
yes_label: opts.yes_label ||
|
|
219
|
-
no_label: opts.no_label ||
|
|
229
|
+
yes_label: opts.yes_label || DEFAULT_ASK.yes.i18n,
|
|
230
|
+
no_label: opts.no_label || DEFAULT_ASK.no.i18n
|
|
220
231
|
}).then(function(yes) {
|
|
221
232
|
S.asking = false;
|
|
222
233
|
if(yes) {
|
package/src/yui_install.test.js
CHANGED
|
@@ -140,3 +140,26 @@ test("subscribe(): a throwing listener does not break the others", async () => {
|
|
|
140
140
|
off1();
|
|
141
141
|
off2();
|
|
142
142
|
});
|
|
143
|
+
|
|
144
|
+
/* The question asked when the app names none is an i18n KEY, the one
|
|
145
|
+
* every consumer already defines ("install this app"). It was
|
|
146
|
+
* "Install this app?", a key no locale carries, so an app that took
|
|
147
|
+
* the default asked in English in every language. */
|
|
148
|
+
test("ask_once(): the default question and answers are i18n keys", async () => {
|
|
149
|
+
const asked = [];
|
|
150
|
+
vi.resetModules();
|
|
151
|
+
vi.doMock("./shell_modals.js", () => ({
|
|
152
|
+
yui_shell_confirm_yesno: (shell, message, opts) => {
|
|
153
|
+
asked.push({message, yes: opts.yes_label, no: opts.no_label});
|
|
154
|
+
return new Promise(() => {});
|
|
155
|
+
}
|
|
156
|
+
}));
|
|
157
|
+
try {
|
|
158
|
+
const {yui_install_ask_once} = await import("./yui_install.js");
|
|
159
|
+
window[STASH] = fake_event("accepted");
|
|
160
|
+
yui_install_ask_once({fake_shell: true}, {});
|
|
161
|
+
expect(asked).toEqual([{message: "install this app", yes: "install", no: "not now"}]);
|
|
162
|
+
} finally {
|
|
163
|
+
vi.doUnmock("./shell_modals.js");
|
|
164
|
+
}
|
|
165
|
+
});
|