@yuneta/gobj-ui 7.23.114 → 7.23.116

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.
@@ -7219,6 +7219,30 @@ function destroy_ui$10(gobj) {
7219
7219
  /******************************************************************
7220
7220
  * Build form with bulma and createElement2
7221
7221
  ******************************************************************/
7222
+ /************************************************************
7223
+ * Put the field's NAME on its control.
7224
+ *
7225
+ * The label of a field is written `<label for={name}>` -- and
7226
+ * `for` matches an **id**, which no control here sets: they
7227
+ * carry `name`. So the association reads right in the source
7228
+ * and does not exist in the document, and every field of every
7229
+ * form of this library was unlabelled for anything that is not
7230
+ * an eye.
7231
+ *
7232
+ * `aria-label` and not an `id`: two forms can be open at once
7233
+ * (a record in a window and another in a modal), and duplicate
7234
+ * ids would break the association for both. The key is the
7235
+ * label's own, so a language change reaches it.
7236
+ ************************************************************/
7237
+ function name_form_control($field, conf) {
7238
+ if (!$field || typeof $field.querySelector !== "function" || !conf) return;
7239
+ let key = conf.label_i18n || conf.label || "";
7240
+ if (!key) return;
7241
+ let $control = $field.querySelector("input, select, textarea");
7242
+ if (!$control || $control.getAttribute("aria-label")) return;
7243
+ $control.setAttribute("aria-label", (0, i18next.t)(key));
7244
+ $control.setAttribute("data-i18n-aria-label", key);
7245
+ }
7222
7246
  function build_form(gobj) {
7223
7247
  let form_id = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "form_id");
7224
7248
  let $form = (0, _yuneta_gobj_js.createElement2)(["form", {
@@ -7255,6 +7279,7 @@ function build_html_form(gobj, $form, prefix, template) {
7255
7279
  if (placeholders[key]) html_field_conf.placeholder = placeholders[key];
7256
7280
  if (html_field_conf.tag) {
7257
7281
  let $field = create_form_field(gobj, $form, prefix, field_desc, html_field_conf);
7282
+ name_form_control($field, html_field_conf);
7258
7283
  $form.appendChild($field);
7259
7284
  }
7260
7285
  });
@@ -34979,7 +35004,7 @@ var reRgbaInteger = new RegExp(`^rgba\\(${reI},${reI},${reI},${reN}\\)$`);
34979
35004
  var reRgbaPercent = new RegExp(`^rgba\\(${reP},${reP},${reP},${reN}\\)$`);
34980
35005
  var reHslPercent = new RegExp(`^hsl\\(${reN},${reP},${reP}\\)$`);
34981
35006
  var reHslaPercent = new RegExp(`^hsla\\(${reN},${reP},${reP},${reN}\\)$`);
34982
- var named = {
35007
+ var named$1 = {
34983
35008
  aliceblue: 15792383,
34984
35009
  antiquewhite: 16444375,
34985
35010
  aqua: 65535,
@@ -35158,7 +35183,7 @@ function color_formatRgb() {
35158
35183
  function color(format) {
35159
35184
  var m, l;
35160
35185
  format = (format + "").trim().toLowerCase();
35161
- return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) : l === 3 ? new Rgb(m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, (m & 15) << 4 | m & 15, 1) : l === 8 ? rgba(m >> 24 & 255, m >> 16 & 255, m >> 8 & 255, (m & 255) / 255) : l === 4 ? rgba(m >> 12 & 15 | m >> 8 & 240, m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, ((m & 15) << 4 | m & 15) / 255) : null) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) : named.hasOwnProperty(format) ? rgbn(named[format]) : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
35186
+ return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) : l === 3 ? new Rgb(m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, (m & 15) << 4 | m & 15, 1) : l === 8 ? rgba(m >> 24 & 255, m >> 16 & 255, m >> 8 & 255, (m & 255) / 255) : l === 4 ? rgba(m >> 12 & 15 | m >> 8 & 240, m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, ((m & 15) << 4 | m & 15) / 255) : null) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) : named$1.hasOwnProperty(format) ? rgbn(named$1[format]) : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
35162
35187
  }
35163
35188
  function rgbn(n) {
35164
35189
  return new Rgb(n >> 16 & 255, n >> 8 & 255, n & 255, 1);
@@ -68242,15 +68267,42 @@ function open_dialog(gobj, $content, title, logical, title_prefix) {
68242
68267
  * carries its name, so reading the form back is one query and
68243
68268
  * a language change does not have to know the form exists.
68244
68269
  ***************************************************************/
68245
- function field(logical, name, label, $control, help) {
68246
- if ((0, _yuneta_gobj_js.is_array)($control) && (0, _yuneta_gobj_js.is_object)($control[1]) && [
68270
+ /***************************************************************
68271
+ * Put a NAME on the control of a field, from the label's key.
68272
+ *
68273
+ * It DESCENDS: `select_input()` hands back Bulma's wrapper
68274
+ * (`<div class="select"><select>`), so a check on the outer tag
68275
+ * named the div -- which names nothing -- and every select of
68276
+ * the two forms stayed anonymous while the inputs beside them
68277
+ * were fixed. Measured on a deployed schema: `SELECT[type]` with
68278
+ * no `aria-label` while `INPUT[header]` had one.
68279
+ *
68280
+ * The first control found is the one named: a field has one, and
68281
+ * where it has two (the hook's topic and column) they are named
68282
+ * where they are built, because "hook" would not tell them apart.
68283
+ ***************************************************************/
68284
+ function named($spec, label) {
68285
+ name_control($spec, label);
68286
+ return $spec;
68287
+ }
68288
+ function name_control($spec, label) {
68289
+ if (!(0, _yuneta_gobj_js.is_array)($spec) || !(0, _yuneta_gobj_js.is_object)($spec[1])) return false;
68290
+ if ([
68247
68291
  "input",
68248
68292
  "select",
68249
68293
  "textarea"
68250
- ].includes($control[0]) && !$control[1]["aria-label"]) {
68251
- $control[1]["aria-label"] = (0, i18next.t)(label);
68252
- $control[1]["data-i18n-aria-label"] = label;
68294
+ ].includes($spec[0])) {
68295
+ if (!$spec[1]["aria-label"]) {
68296
+ $spec[1]["aria-label"] = (0, i18next.t)(label);
68297
+ $spec[1]["data-i18n-aria-label"] = label;
68298
+ }
68299
+ return true;
68253
68300
  }
68301
+ for (let child of $spec[2] || []) if (name_control(child, label)) return true;
68302
+ return false;
68303
+ }
68304
+ function field(logical, name, label, $control, help) {
68305
+ name_control($control, label);
68254
68306
  return [
68255
68307
  "div",
68256
68308
  { class: `${logical} field mb-3` },
@@ -68473,7 +68525,7 @@ function open_column_form(gobj, topic, col, prefill) {
68473
68525
  class: "is-flex",
68474
68526
  style: "gap:.4rem;"
68475
68527
  },
68476
- [select_input("hook_topic", hook_topic, [""].concat(sibling_topics)), text_input("hook_col", hook_col, (0, i18next.t)("the fkey column of the child"))]
68528
+ [named(select_input("hook_topic", hook_topic, [""].concat(sibling_topics)), "hook topic"), named(text_input("hook_col", hook_col, (0, i18next.t)("the fkey column of the child")), "hook column")]
68477
68529
  ],
68478
68530
  [
68479
68531
  "p",
@@ -7214,6 +7214,30 @@ function destroy_ui$10(gobj) {
7214
7214
  /******************************************************************
7215
7215
  * Build form with bulma and createElement2
7216
7216
  ******************************************************************/
7217
+ /************************************************************
7218
+ * Put the field's NAME on its control.
7219
+ *
7220
+ * The label of a field is written `<label for={name}>` -- and
7221
+ * `for` matches an **id**, which no control here sets: they
7222
+ * carry `name`. So the association reads right in the source
7223
+ * and does not exist in the document, and every field of every
7224
+ * form of this library was unlabelled for anything that is not
7225
+ * an eye.
7226
+ *
7227
+ * `aria-label` and not an `id`: two forms can be open at once
7228
+ * (a record in a window and another in a modal), and duplicate
7229
+ * ids would break the association for both. The key is the
7230
+ * label's own, so a language change reaches it.
7231
+ ************************************************************/
7232
+ function name_form_control($field, conf) {
7233
+ if (!$field || typeof $field.querySelector !== "function" || !conf) return;
7234
+ let key = conf.label_i18n || conf.label || "";
7235
+ if (!key) return;
7236
+ let $control = $field.querySelector("input, select, textarea");
7237
+ if (!$control || $control.getAttribute("aria-label")) return;
7238
+ $control.setAttribute("aria-label", t(key));
7239
+ $control.setAttribute("data-i18n-aria-label", key);
7240
+ }
7217
7241
  function build_form(gobj) {
7218
7242
  let form_id = gobj_read_str_attr(gobj, "form_id");
7219
7243
  let $form = createElement2(["form", {
@@ -7250,6 +7274,7 @@ function build_html_form(gobj, $form, prefix, template) {
7250
7274
  if (placeholders[key]) html_field_conf.placeholder = placeholders[key];
7251
7275
  if (html_field_conf.tag) {
7252
7276
  let $field = create_form_field(gobj, $form, prefix, field_desc, html_field_conf);
7277
+ name_form_control($field, html_field_conf);
7253
7278
  $form.appendChild($field);
7254
7279
  }
7255
7280
  });
@@ -34974,7 +34999,7 @@ var reRgbaInteger = new RegExp(`^rgba\\(${reI},${reI},${reI},${reN}\\)$`);
34974
34999
  var reRgbaPercent = new RegExp(`^rgba\\(${reP},${reP},${reP},${reN}\\)$`);
34975
35000
  var reHslPercent = new RegExp(`^hsl\\(${reN},${reP},${reP}\\)$`);
34976
35001
  var reHslaPercent = new RegExp(`^hsla\\(${reN},${reP},${reP},${reN}\\)$`);
34977
- var named = {
35002
+ var named$1 = {
34978
35003
  aliceblue: 15792383,
34979
35004
  antiquewhite: 16444375,
34980
35005
  aqua: 65535,
@@ -35153,7 +35178,7 @@ function color_formatRgb() {
35153
35178
  function color(format) {
35154
35179
  var m, l;
35155
35180
  format = (format + "").trim().toLowerCase();
35156
- return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) : l === 3 ? new Rgb(m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, (m & 15) << 4 | m & 15, 1) : l === 8 ? rgba(m >> 24 & 255, m >> 16 & 255, m >> 8 & 255, (m & 255) / 255) : l === 4 ? rgba(m >> 12 & 15 | m >> 8 & 240, m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, ((m & 15) << 4 | m & 15) / 255) : null) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) : named.hasOwnProperty(format) ? rgbn(named[format]) : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
35181
+ return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) : l === 3 ? new Rgb(m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, (m & 15) << 4 | m & 15, 1) : l === 8 ? rgba(m >> 24 & 255, m >> 16 & 255, m >> 8 & 255, (m & 255) / 255) : l === 4 ? rgba(m >> 12 & 15 | m >> 8 & 240, m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, ((m & 15) << 4 | m & 15) / 255) : null) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) : named$1.hasOwnProperty(format) ? rgbn(named$1[format]) : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
35157
35182
  }
35158
35183
  function rgbn(n) {
35159
35184
  return new Rgb(n >> 16 & 255, n >> 8 & 255, n & 255, 1);
@@ -68237,15 +68262,42 @@ function open_dialog(gobj, $content, title, logical, title_prefix) {
68237
68262
  * carries its name, so reading the form back is one query and
68238
68263
  * a language change does not have to know the form exists.
68239
68264
  ***************************************************************/
68240
- function field(logical, name, label, $control, help) {
68241
- if (is_array($control) && is_object($control[1]) && [
68265
+ /***************************************************************
68266
+ * Put a NAME on the control of a field, from the label's key.
68267
+ *
68268
+ * It DESCENDS: `select_input()` hands back Bulma's wrapper
68269
+ * (`<div class="select"><select>`), so a check on the outer tag
68270
+ * named the div -- which names nothing -- and every select of
68271
+ * the two forms stayed anonymous while the inputs beside them
68272
+ * were fixed. Measured on a deployed schema: `SELECT[type]` with
68273
+ * no `aria-label` while `INPUT[header]` had one.
68274
+ *
68275
+ * The first control found is the one named: a field has one, and
68276
+ * where it has two (the hook's topic and column) they are named
68277
+ * where they are built, because "hook" would not tell them apart.
68278
+ ***************************************************************/
68279
+ function named($spec, label) {
68280
+ name_control($spec, label);
68281
+ return $spec;
68282
+ }
68283
+ function name_control($spec, label) {
68284
+ if (!is_array($spec) || !is_object($spec[1])) return false;
68285
+ if ([
68242
68286
  "input",
68243
68287
  "select",
68244
68288
  "textarea"
68245
- ].includes($control[0]) && !$control[1]["aria-label"]) {
68246
- $control[1]["aria-label"] = t(label);
68247
- $control[1]["data-i18n-aria-label"] = label;
68289
+ ].includes($spec[0])) {
68290
+ if (!$spec[1]["aria-label"]) {
68291
+ $spec[1]["aria-label"] = t(label);
68292
+ $spec[1]["data-i18n-aria-label"] = label;
68293
+ }
68294
+ return true;
68248
68295
  }
68296
+ for (let child of $spec[2] || []) if (name_control(child, label)) return true;
68297
+ return false;
68298
+ }
68299
+ function field(logical, name, label, $control, help) {
68300
+ name_control($control, label);
68249
68301
  return [
68250
68302
  "div",
68251
68303
  { class: `${logical} field mb-3` },
@@ -68468,7 +68520,7 @@ function open_column_form(gobj, topic, col, prefill) {
68468
68520
  class: "is-flex",
68469
68521
  style: "gap:.4rem;"
68470
68522
  },
68471
- [select_input("hook_topic", hook_topic, [""].concat(sibling_topics)), text_input("hook_col", hook_col, t("the fkey column of the child"))]
68523
+ [named(select_input("hook_topic", hook_topic, [""].concat(sibling_topics)), "hook topic"), named(text_input("hook_col", hook_col, t("the fkey column of the child")), "hook column")]
68472
68524
  ],
68473
68525
  [
68474
68526
  "p",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.114",
3
+ "version": "7.23.116",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
package/src/c_yui_form.js CHANGED
@@ -490,6 +490,38 @@ function destroy_ui(gobj)
490
490
  /******************************************************************
491
491
  * Build form with bulma and createElement2
492
492
  ******************************************************************/
493
+ /************************************************************
494
+ * Put the field's NAME on its control.
495
+ *
496
+ * The label of a field is written `<label for={name}>` -- and
497
+ * `for` matches an **id**, which no control here sets: they
498
+ * carry `name`. So the association reads right in the source
499
+ * and does not exist in the document, and every field of every
500
+ * form of this library was unlabelled for anything that is not
501
+ * an eye.
502
+ *
503
+ * `aria-label` and not an `id`: two forms can be open at once
504
+ * (a record in a window and another in a modal), and duplicate
505
+ * ids would break the association for both. The key is the
506
+ * label's own, so a language change reaches it.
507
+ ************************************************************/
508
+ function name_form_control($field, conf)
509
+ {
510
+ if(!$field || typeof $field.querySelector !== "function" || !conf) {
511
+ return;
512
+ }
513
+ let key = conf.label_i18n || conf.label || "";
514
+ if(!key) {
515
+ return; /* a field with no label names nothing */
516
+ }
517
+ let $control = $field.querySelector("input, select, textarea");
518
+ if(!$control || $control.getAttribute("aria-label")) {
519
+ return;
520
+ }
521
+ $control.setAttribute("aria-label", t(key));
522
+ $control.setAttribute("data-i18n-aria-label", key);
523
+ }
524
+
493
525
  function build_form(gobj)
494
526
  {
495
527
  let form_id = gobj_read_str_attr(gobj, "form_id");
@@ -566,6 +598,7 @@ function build_html_form(gobj, $form, prefix, template)
566
598
  */
567
599
  if(html_field_conf.tag) {
568
600
  let $field = create_form_field(gobj, $form, prefix, field_desc, html_field_conf);
601
+ name_form_control($field, html_field_conf);
569
602
  $form.appendChild($field);
570
603
  }
571
604
  });
@@ -1556,6 +1556,46 @@ function open_dialog(gobj, $content, title, logical, title_prefix)
1556
1556
  * carries its name, so reading the form back is one query and
1557
1557
  * a language change does not have to know the form exists.
1558
1558
  ***************************************************************/
1559
+ /***************************************************************
1560
+ * Put a NAME on the control of a field, from the label's key.
1561
+ *
1562
+ * It DESCENDS: `select_input()` hands back Bulma's wrapper
1563
+ * (`<div class="select"><select>`), so a check on the outer tag
1564
+ * named the div -- which names nothing -- and every select of
1565
+ * the two forms stayed anonymous while the inputs beside them
1566
+ * were fixed. Measured on a deployed schema: `SELECT[type]` with
1567
+ * no `aria-label` while `INPUT[header]` had one.
1568
+ *
1569
+ * The first control found is the one named: a field has one, and
1570
+ * where it has two (the hook's topic and column) they are named
1571
+ * where they are built, because "hook" would not tell them apart.
1572
+ ***************************************************************/
1573
+ function named($spec, label)
1574
+ {
1575
+ name_control($spec, label);
1576
+ return $spec;
1577
+ }
1578
+
1579
+ function name_control($spec, label)
1580
+ {
1581
+ if(!is_array($spec) || !is_object($spec[1])) {
1582
+ return false;
1583
+ }
1584
+ if(["input", "select", "textarea"].includes($spec[0])) {
1585
+ if(!$spec[1]["aria-label"]) {
1586
+ $spec[1]["aria-label"] = t(label);
1587
+ $spec[1]["data-i18n-aria-label"] = label;
1588
+ }
1589
+ return true;
1590
+ }
1591
+ for(let child of ($spec[2] || [])) {
1592
+ if(name_control(child, label)) {
1593
+ return true;
1594
+ }
1595
+ }
1596
+ return false;
1597
+ }
1598
+
1559
1599
  function field(logical, name, label, $control, help)
1560
1600
  {
1561
1601
  /* The label is a SIBLING of the control -- Bulma's `field` shape --
@@ -1563,12 +1603,7 @@ function field(logical, name, label, $control, help)
1563
1603
  * wrapping, and a reader announces the box as unlabelled. The name
1564
1604
  * is put on the control itself, from the label's own key, so the
1565
1605
  * two cannot drift and a language change reaches both. */
1566
- if(is_array($control) && is_object($control[1]) &&
1567
- ["input", "select", "textarea"].includes($control[0]) &&
1568
- !$control[1]["aria-label"]) {
1569
- $control[1]["aria-label"] = t(label);
1570
- $control[1]["data-i18n-aria-label"] = label;
1571
- }
1606
+ name_control($control, label);
1572
1607
  return ["div", {class: `${logical} field mb-3`}, [
1573
1608
  ["label", {class: "label", i18n: label}, t(label)],
1574
1609
  ["div", {class: "control"}, [$control]],
@@ -1733,9 +1768,13 @@ function open_column_form(gobj, topic, col, prefill)
1733
1768
  ]],
1734
1769
  ["div", {class: "SCHEMA_COL_FORM_HOOK field mb-3"}, [
1735
1770
  ["label", {class: "label", i18n: "hook"}, t("hook")],
1771
+ /* TWO controls in one field, so each says which half it
1772
+ * is: `hook` alone would name them both the same. */
1736
1773
  ["div", {class: "is-flex", style: "gap:.4rem;"}, [
1737
- select_input("hook_topic", hook_topic, [""].concat(sibling_topics)),
1738
- text_input("hook_col", hook_col, t("the fkey column of the child"))
1774
+ named(select_input("hook_topic", hook_topic,
1775
+ [""].concat(sibling_topics)), "hook topic"),
1776
+ named(text_input("hook_col", hook_col,
1777
+ t("the fkey column of the child")), "hook column")
1739
1778
  ]],
1740
1779
  ["p", {class: "help", i18n: "a hook names the child topic and the column of the child that points back"},
1741
1780
  t("a hook names the child topic and the column of the child that points back")]