@yuneta/gobj-ui 7.23.109 → 7.23.111

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.
@@ -942,7 +942,7 @@ function mt_create$21(gobj) {
942
942
  /***************************************************************
943
943
  * Framework Method: Start
944
944
  ***************************************************************/
945
- function mt_start$18(gobj) {
945
+ function mt_start$19(gobj) {
946
946
  let config = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "config") || {};
947
947
  let priv = gobj.priv;
948
948
  if (!validate_config(config)) {
@@ -1011,7 +1011,7 @@ function mt_start$18(gobj) {
1011
1011
  /***************************************************************
1012
1012
  * Framework Method: Stop
1013
1013
  ***************************************************************/
1014
- function mt_stop$18(gobj) {
1014
+ function mt_stop$19(gobj) {
1015
1015
  let priv = gobj.priv;
1016
1016
  if (!priv) return 0;
1017
1017
  close_toolbar_dropdown(gobj);
@@ -2556,8 +2556,8 @@ function ac_nav_item_close(gobj, event, kw, src) {
2556
2556
  ***************************************************************/
2557
2557
  var gmt$21 = {
2558
2558
  mt_create: mt_create$21,
2559
- mt_start: mt_start$18,
2560
- mt_stop: mt_stop$18,
2559
+ mt_start: mt_start$19,
2560
+ mt_stop: mt_stop$19,
2561
2561
  mt_destroy: mt_destroy$21
2562
2562
  };
2563
2563
  function create_gclass$21(gclass_name) {
@@ -4897,11 +4897,11 @@ function mt_create$18(gobj) {
4897
4897
  /***************************************************************
4898
4898
  * Framework Method: Start
4899
4899
  ***************************************************************/
4900
- function mt_start$17(gobj) {}
4900
+ function mt_start$18(gobj) {}
4901
4901
  /***************************************************************
4902
4902
  * Framework Method: Stop
4903
4903
  ***************************************************************/
4904
- function mt_stop$17(gobj) {
4904
+ function mt_stop$18(gobj) {
4905
4905
  (0, _yuneta_gobj_js.gobj_stop_children)(gobj);
4906
4906
  }
4907
4907
  /***************************************************************
@@ -5188,8 +5188,8 @@ function ac_resize$5(gobj, event, kw, src) {
5188
5188
  ***************************/
5189
5189
  var gmt$18 = {
5190
5190
  mt_create: mt_create$18,
5191
- mt_start: mt_start$17,
5192
- mt_stop: mt_stop$17,
5191
+ mt_start: mt_start$18,
5192
+ mt_stop: mt_stop$18,
5193
5193
  mt_destroy: mt_destroy$18
5194
5194
  };
5195
5195
  /***************************************************************
@@ -5431,11 +5431,11 @@ function mt_create$17(gobj) {
5431
5431
  /***************************************************************
5432
5432
  * Framework Method: Start
5433
5433
  ***************************************************************/
5434
- function mt_start$16(gobj) {}
5434
+ function mt_start$17(gobj) {}
5435
5435
  /***************************************************************
5436
5436
  * Framework Method: Stop
5437
5437
  ***************************************************************/
5438
- function mt_stop$16(gobj) {
5438
+ function mt_stop$17(gobj) {
5439
5439
  (0, _yuneta_gobj_js.gobj_stop_children)(gobj);
5440
5440
  }
5441
5441
  /***************************************************************
@@ -5795,8 +5795,8 @@ function ac_resize$4(gobj, event, kw, src) {
5795
5795
  ***************************/
5796
5796
  var gmt$17 = {
5797
5797
  mt_create: mt_create$17,
5798
- mt_start: mt_start$16,
5799
- mt_stop: mt_stop$16,
5798
+ mt_start: mt_start$17,
5799
+ mt_stop: mt_stop$17,
5800
5800
  mt_destroy: mt_destroy$17
5801
5801
  };
5802
5802
  /***************************************************************
@@ -6922,14 +6922,14 @@ function mt_destroy$16(gobj) {
6922
6922
  /************************************************************
6923
6923
  * Framework Method start
6924
6924
  ************************************************************/
6925
- function mt_start$15(gobj) {
6925
+ function mt_start$16(gobj) {
6926
6926
  let record = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "record");
6927
6927
  if (record) (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_LOAD_RECORD", record, gobj);
6928
6928
  }
6929
6929
  /************************************************************
6930
6930
  * Framework Method stop
6931
6931
  ************************************************************/
6932
- function mt_stop$15(gobj) {}
6932
+ function mt_stop$16(gobj) {}
6933
6933
  /***************************
6934
6934
  * Local Methods
6935
6935
  ***************************/
@@ -9154,8 +9154,8 @@ function cmd_get_picked_files(gobj, cmd, kw, src) {
9154
9154
  }
9155
9155
  var gmt$16 = {
9156
9156
  mt_create: mt_create$16,
9157
- mt_start: mt_start$15,
9158
- mt_stop: mt_stop$15,
9157
+ mt_start: mt_start$16,
9158
+ mt_stop: mt_stop$16,
9159
9159
  mt_destroy: mt_destroy$16,
9160
9160
  mt_command_parser: mt_command_parser$2
9161
9161
  };
@@ -9417,6 +9417,78 @@ var MarkerControl = class {
9417
9417
  (0, _yuneta_gobj_js.gobj_send_event)(this.gobj, "EV_CONTROL_MAP", { user_location: this._enable_user_location }, this.gobj);
9418
9418
  }
9419
9419
  };
9420
+ /***********************************************************************
9421
+ * MAPLIBRE'S OWN CHROME, IN THE APP'S LANGUAGE
9422
+ *
9423
+ * Everything maplibre draws with words -- the zoom tooltips, the
9424
+ * geolocate button, the attribution toggle, a popup's close, and the
9425
+ * notice that teaches the Ctrl + wheel gesture -- comes from its
9426
+ * `locale`, an option merged over its own English defaults at
9427
+ * construction. So a map in a Spanish app was saying *"Zoom in"* and
9428
+ * *"Use Ctrl + scroll to zoom the map"*, which is the same rule this
9429
+ * GUI applies to every other string.
9430
+ *
9431
+ * Two halves, because maplibre reads its strings ONCE, when each
9432
+ * control builds its DOM:
9433
+ *
9434
+ * `yui_maplibre_locale(t)` the `locale` option, for the map's
9435
+ * first paint;
9436
+ * `yui_maplibre_relocalize()` after a language change, which is
9437
+ * the half a `locale` alone cannot
9438
+ * do -- it writes the strings into
9439
+ * the DOM already drawn, and updates
9440
+ * the map's locale so anything built
9441
+ * later is right too.
9442
+ *
9443
+ * The scale units (`km`, `mi`, `nm`) are symbols and are left alone;
9444
+ * the MapLibre logo keeps its name, which is a brand.
9445
+ ***********************************************************************/
9446
+ function yui_maplibre_locale(t) {
9447
+ return {
9448
+ "NavigationControl.ZoomIn": t("zoom in"),
9449
+ "NavigationControl.ZoomOut": t("zoom out"),
9450
+ "NavigationControl.ResetBearing": t("drag to rotate the map, click to reset north"),
9451
+ "GeolocateControl.FindMyLocation": t("find my location"),
9452
+ "GeolocateControl.LocationNotAvailable": t("location not available"),
9453
+ "AttributionControl.ToggleAttribution": t("toggle attribution"),
9454
+ "AttributionControl.MapFeedback": t("map feedback"),
9455
+ "FullscreenControl.Enter": t("enter fullscreen"),
9456
+ "FullscreenControl.Exit": t("exit fullscreen"),
9457
+ "Popup.Close": t("close popup"),
9458
+ "Map.Title": t("map"),
9459
+ "Marker.Title": t("map marker"),
9460
+ "CooperativeGesturesHandler.WindowsHelpText": t("use ctrl + scroll to zoom the map"),
9461
+ "CooperativeGesturesHandler.MacHelpText": t("use cmd + scroll to zoom the map"),
9462
+ "CooperativeGesturesHandler.MobileHelpText": t("use two fingers to move the map")
9463
+ };
9464
+ }
9465
+ function label_ctrl($root, selector, text) {
9466
+ if (!$root || !text) return;
9467
+ for (const $el of $root.querySelectorAll(selector)) {
9468
+ $el.setAttribute("title", text);
9469
+ $el.setAttribute("aria-label", text);
9470
+ }
9471
+ }
9472
+ function yui_maplibre_relocalize(map, t) {
9473
+ if (!map || typeof map.getContainer !== "function") return;
9474
+ const strings = yui_maplibre_locale(t);
9475
+ try {
9476
+ map._locale = Object.assign({}, map._locale, strings);
9477
+ } catch (e) {}
9478
+ const $c = map.getContainer();
9479
+ label_ctrl($c, ".maplibregl-ctrl-zoom-in", strings["NavigationControl.ZoomIn"]);
9480
+ label_ctrl($c, ".maplibregl-ctrl-zoom-out", strings["NavigationControl.ZoomOut"]);
9481
+ label_ctrl($c, ".maplibregl-ctrl-compass", strings["NavigationControl.ResetBearing"]);
9482
+ label_ctrl($c, ".maplibregl-ctrl-geolocate", strings["GeolocateControl.FindMyLocation"]);
9483
+ label_ctrl($c, ".maplibregl-ctrl-attrib-button", strings["AttributionControl.ToggleAttribution"]);
9484
+ label_ctrl($c, ".maplibregl-ctrl-fullscreen", strings["FullscreenControl.Enter"]);
9485
+ label_ctrl($c, ".maplibregl-popup-close-button", strings["Popup.Close"]);
9486
+ const mac = typeof navigator !== "undefined" && (navigator.userAgent || "").includes("Mac");
9487
+ const $desktop = $c.querySelector(".maplibregl-desktop-message");
9488
+ if ($desktop) $desktop.textContent = mac ? strings["CooperativeGesturesHandler.MacHelpText"] : strings["CooperativeGesturesHandler.WindowsHelpText"];
9489
+ const $mobile = $c.querySelector(".maplibregl-mobile-message");
9490
+ if ($mobile) $mobile.textContent = strings["CooperativeGesturesHandler.MobileHelpText"];
9491
+ }
9420
9492
  //#endregion
9421
9493
  //#region src/c_yui_map.js
9422
9494
  /***********************************************************************
@@ -9431,6 +9503,7 @@ var MarkerControl = class {
9431
9503
  * Constants
9432
9504
  ***************************************************************/
9433
9505
  var GCLASS_NAME$15 = "C_YUI_MAP";
9506
+ var GESTURE_HINT_MS = 2e3;
9434
9507
  /***************************************************************
9435
9508
  * Data
9436
9509
  ***************************************************************/
@@ -9457,6 +9530,7 @@ var attrs_table$15 = [
9457
9530
  ];
9458
9531
  var PRIVATE_DATA$15 = {
9459
9532
  xmap: null,
9533
+ gesture_hint_timer: null,
9460
9534
  geojson: null,
9461
9535
  resizeObserver: null,
9462
9536
  width: 0,
@@ -9479,7 +9553,11 @@ function mt_create$15(gobj) {
9479
9553
  let map_settings = (0, _yuneta_gobj_js.json_deep_copy)((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "map_settings"));
9480
9554
  let $map = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$map");
9481
9555
  if ($map) $map.classList.add(GCLASS_NAME$15);
9482
- Object.assign(map_settings, { container: $map });
9556
+ Object.assign(map_settings, {
9557
+ container: $map,
9558
+ cooperativeGestures: true,
9559
+ locale: yui_maplibre_locale(i18next.t)
9560
+ });
9483
9561
  priv.onClick = (ev) => {
9484
9562
  onClick(gobj, ev);
9485
9563
  };
@@ -9496,6 +9574,16 @@ function mt_create$15(gobj) {
9496
9574
  xtouchStart(gobj, ev);
9497
9575
  };
9498
9576
  const map = priv.xmap = new maplibre_gl.Map(map_settings);
9577
+ map.on("cooperativegestureprevented", () => {
9578
+ const $s = map.getCanvasContainer().querySelector(".maplibregl-cooperative-gesture-screen");
9579
+ if (!$s) return;
9580
+ $s.classList.add("MAP_GESTURE_SHOWN");
9581
+ if (priv.gesture_hint_timer) clearTimeout(priv.gesture_hint_timer);
9582
+ priv.gesture_hint_timer = setTimeout(() => {
9583
+ priv.gesture_hint_timer = null;
9584
+ $s.classList.remove("MAP_GESTURE_SHOWN");
9585
+ }, GESTURE_HINT_MS);
9586
+ });
9499
9587
  map.addControl(new maplibre_gl.NavigationControl());
9500
9588
  map.addControl(new MarkerControl(gobj, {}), "top-right");
9501
9589
  map.addControl(new EditControl(gobj, { showMarkerDrag: true }), "top-right");
@@ -9525,10 +9613,46 @@ function mt_create$15(gobj) {
9525
9613
  }
9526
9614
  }
9527
9615
  /***************************************************************
9616
+ * The application changed language: maplibre's own words are
9617
+ * rewritten in place, and the map's locale with them so a
9618
+ * control or a popup built later is right too.
9619
+ ***************************************************************/
9620
+ function ac_language_changed$9(gobj, event, kw, src) {
9621
+ let priv = gobj.priv;
9622
+ if (priv.xmap) yui_maplibre_relocalize(priv.xmap, i18next.t);
9623
+ return 0;
9624
+ }
9625
+ /***************************************************************
9626
+ * Framework Method: Start
9627
+ *
9628
+ * The application's LANGUAGE: what maplibre draws with words is
9629
+ * built from its `locale` when each control builds its DOM, so
9630
+ * `refresh_language()` -- which reaches what carries an i18n key
9631
+ * in OUR dom -- cannot touch any of it. The shell says when the
9632
+ * language changed and this view rewrites those strings.
9633
+ ***************************************************************/
9634
+ function mt_start$15(gobj) {
9635
+ let shell = yui_shell_of(gobj);
9636
+ if (shell) (0, _yuneta_gobj_js.gobj_subscribe_event)(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
9637
+ return 0;
9638
+ }
9639
+ /***************************************************************
9640
+ * Framework Method: Stop
9641
+ ***************************************************************/
9642
+ function mt_stop$15(gobj) {
9643
+ let shell = yui_shell_of(gobj);
9644
+ if (shell) (0, _yuneta_gobj_js.gobj_unsubscribe_event)(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
9645
+ return 0;
9646
+ }
9647
+ /***************************************************************
9528
9648
  * Framework Method: Destroy
9529
9649
  ***************************************************************/
9530
9650
  function mt_destroy$15(gobj) {
9531
9651
  let priv = gobj.priv;
9652
+ if (priv.gesture_hint_timer) {
9653
+ clearTimeout(priv.gesture_hint_timer);
9654
+ priv.gesture_hint_timer = null;
9655
+ }
9532
9656
  if (priv.resizeObserver) {
9533
9657
  priv.resizeObserver.disconnect();
9534
9658
  priv.resizeObserver = null;
@@ -9989,6 +10113,8 @@ function ac_hide$10(gobj, event, kw, src) {
9989
10113
  ***************************/
9990
10114
  var gmt$15 = {
9991
10115
  mt_create: mt_create$15,
10116
+ mt_start: mt_start$15,
10117
+ mt_stop: mt_stop$15,
9992
10118
  mt_destroy: mt_destroy$15
9993
10119
  };
9994
10120
  /***************************************************************
@@ -10000,6 +10126,7 @@ function create_gclass$15(gclass_name) {
10000
10126
  return -1;
10001
10127
  }
10002
10128
  __gclass__$15 = (0, _yuneta_gobj_js.gclass_create)(gclass_name, [
10129
+ ["EV_LANGUAGE_CHANGED", 0],
10003
10130
  ["EV_EDIT_MAP", 0],
10004
10131
  ["EV_CONTROL_MAP", 0],
10005
10132
  ["EV_MAP_ON_LOAD", 0],
@@ -10008,6 +10135,11 @@ function create_gclass$15(gclass_name) {
10008
10135
  ["EV_SHOW", 0],
10009
10136
  ["EV_HIDE", 0]
10010
10137
  ], [["ST_IDLE", [
10138
+ [
10139
+ "EV_LANGUAGE_CHANGED",
10140
+ ac_language_changed$9,
10141
+ null
10142
+ ],
10011
10143
  [
10012
10144
  "EV_EDIT_MAP",
10013
10145
  ac_edit_map,
@@ -937,7 +937,7 @@ function mt_create$21(gobj) {
937
937
  /***************************************************************
938
938
  * Framework Method: Start
939
939
  ***************************************************************/
940
- function mt_start$18(gobj) {
940
+ function mt_start$19(gobj) {
941
941
  let config = gobj_read_attr(gobj, "config") || {};
942
942
  let priv = gobj.priv;
943
943
  if (!validate_config(config)) {
@@ -1006,7 +1006,7 @@ function mt_start$18(gobj) {
1006
1006
  /***************************************************************
1007
1007
  * Framework Method: Stop
1008
1008
  ***************************************************************/
1009
- function mt_stop$18(gobj) {
1009
+ function mt_stop$19(gobj) {
1010
1010
  let priv = gobj.priv;
1011
1011
  if (!priv) return 0;
1012
1012
  close_toolbar_dropdown(gobj);
@@ -2551,8 +2551,8 @@ function ac_nav_item_close(gobj, event, kw, src) {
2551
2551
  ***************************************************************/
2552
2552
  var gmt$21 = {
2553
2553
  mt_create: mt_create$21,
2554
- mt_start: mt_start$18,
2555
- mt_stop: mt_stop$18,
2554
+ mt_start: mt_start$19,
2555
+ mt_stop: mt_stop$19,
2556
2556
  mt_destroy: mt_destroy$21
2557
2557
  };
2558
2558
  function create_gclass$21(gclass_name) {
@@ -4892,11 +4892,11 @@ function mt_create$18(gobj) {
4892
4892
  /***************************************************************
4893
4893
  * Framework Method: Start
4894
4894
  ***************************************************************/
4895
- function mt_start$17(gobj) {}
4895
+ function mt_start$18(gobj) {}
4896
4896
  /***************************************************************
4897
4897
  * Framework Method: Stop
4898
4898
  ***************************************************************/
4899
- function mt_stop$17(gobj) {
4899
+ function mt_stop$18(gobj) {
4900
4900
  gobj_stop_children(gobj);
4901
4901
  }
4902
4902
  /***************************************************************
@@ -5183,8 +5183,8 @@ function ac_resize$5(gobj, event, kw, src) {
5183
5183
  ***************************/
5184
5184
  var gmt$18 = {
5185
5185
  mt_create: mt_create$18,
5186
- mt_start: mt_start$17,
5187
- mt_stop: mt_stop$17,
5186
+ mt_start: mt_start$18,
5187
+ mt_stop: mt_stop$18,
5188
5188
  mt_destroy: mt_destroy$18
5189
5189
  };
5190
5190
  /***************************************************************
@@ -5426,11 +5426,11 @@ function mt_create$17(gobj) {
5426
5426
  /***************************************************************
5427
5427
  * Framework Method: Start
5428
5428
  ***************************************************************/
5429
- function mt_start$16(gobj) {}
5429
+ function mt_start$17(gobj) {}
5430
5430
  /***************************************************************
5431
5431
  * Framework Method: Stop
5432
5432
  ***************************************************************/
5433
- function mt_stop$16(gobj) {
5433
+ function mt_stop$17(gobj) {
5434
5434
  gobj_stop_children(gobj);
5435
5435
  }
5436
5436
  /***************************************************************
@@ -5790,8 +5790,8 @@ function ac_resize$4(gobj, event, kw, src) {
5790
5790
  ***************************/
5791
5791
  var gmt$17 = {
5792
5792
  mt_create: mt_create$17,
5793
- mt_start: mt_start$16,
5794
- mt_stop: mt_stop$16,
5793
+ mt_start: mt_start$17,
5794
+ mt_stop: mt_stop$17,
5795
5795
  mt_destroy: mt_destroy$17
5796
5796
  };
5797
5797
  /***************************************************************
@@ -6917,14 +6917,14 @@ function mt_destroy$16(gobj) {
6917
6917
  /************************************************************
6918
6918
  * Framework Method start
6919
6919
  ************************************************************/
6920
- function mt_start$15(gobj) {
6920
+ function mt_start$16(gobj) {
6921
6921
  let record = gobj_read_attr(gobj, "record");
6922
6922
  if (record) gobj_send_event(gobj, "EV_LOAD_RECORD", record, gobj);
6923
6923
  }
6924
6924
  /************************************************************
6925
6925
  * Framework Method stop
6926
6926
  ************************************************************/
6927
- function mt_stop$15(gobj) {}
6927
+ function mt_stop$16(gobj) {}
6928
6928
  /***************************
6929
6929
  * Local Methods
6930
6930
  ***************************/
@@ -9149,8 +9149,8 @@ function cmd_get_picked_files(gobj, cmd, kw, src) {
9149
9149
  }
9150
9150
  var gmt$16 = {
9151
9151
  mt_create: mt_create$16,
9152
- mt_start: mt_start$15,
9153
- mt_stop: mt_stop$15,
9152
+ mt_start: mt_start$16,
9153
+ mt_stop: mt_stop$16,
9154
9154
  mt_destroy: mt_destroy$16,
9155
9155
  mt_command_parser: mt_command_parser$2
9156
9156
  };
@@ -9412,6 +9412,78 @@ var MarkerControl = class {
9412
9412
  gobj_send_event(this.gobj, "EV_CONTROL_MAP", { user_location: this._enable_user_location }, this.gobj);
9413
9413
  }
9414
9414
  };
9415
+ /***********************************************************************
9416
+ * MAPLIBRE'S OWN CHROME, IN THE APP'S LANGUAGE
9417
+ *
9418
+ * Everything maplibre draws with words -- the zoom tooltips, the
9419
+ * geolocate button, the attribution toggle, a popup's close, and the
9420
+ * notice that teaches the Ctrl + wheel gesture -- comes from its
9421
+ * `locale`, an option merged over its own English defaults at
9422
+ * construction. So a map in a Spanish app was saying *"Zoom in"* and
9423
+ * *"Use Ctrl + scroll to zoom the map"*, which is the same rule this
9424
+ * GUI applies to every other string.
9425
+ *
9426
+ * Two halves, because maplibre reads its strings ONCE, when each
9427
+ * control builds its DOM:
9428
+ *
9429
+ * `yui_maplibre_locale(t)` the `locale` option, for the map's
9430
+ * first paint;
9431
+ * `yui_maplibre_relocalize()` after a language change, which is
9432
+ * the half a `locale` alone cannot
9433
+ * do -- it writes the strings into
9434
+ * the DOM already drawn, and updates
9435
+ * the map's locale so anything built
9436
+ * later is right too.
9437
+ *
9438
+ * The scale units (`km`, `mi`, `nm`) are symbols and are left alone;
9439
+ * the MapLibre logo keeps its name, which is a brand.
9440
+ ***********************************************************************/
9441
+ function yui_maplibre_locale(t) {
9442
+ return {
9443
+ "NavigationControl.ZoomIn": t("zoom in"),
9444
+ "NavigationControl.ZoomOut": t("zoom out"),
9445
+ "NavigationControl.ResetBearing": t("drag to rotate the map, click to reset north"),
9446
+ "GeolocateControl.FindMyLocation": t("find my location"),
9447
+ "GeolocateControl.LocationNotAvailable": t("location not available"),
9448
+ "AttributionControl.ToggleAttribution": t("toggle attribution"),
9449
+ "AttributionControl.MapFeedback": t("map feedback"),
9450
+ "FullscreenControl.Enter": t("enter fullscreen"),
9451
+ "FullscreenControl.Exit": t("exit fullscreen"),
9452
+ "Popup.Close": t("close popup"),
9453
+ "Map.Title": t("map"),
9454
+ "Marker.Title": t("map marker"),
9455
+ "CooperativeGesturesHandler.WindowsHelpText": t("use ctrl + scroll to zoom the map"),
9456
+ "CooperativeGesturesHandler.MacHelpText": t("use cmd + scroll to zoom the map"),
9457
+ "CooperativeGesturesHandler.MobileHelpText": t("use two fingers to move the map")
9458
+ };
9459
+ }
9460
+ function label_ctrl($root, selector, text) {
9461
+ if (!$root || !text) return;
9462
+ for (const $el of $root.querySelectorAll(selector)) {
9463
+ $el.setAttribute("title", text);
9464
+ $el.setAttribute("aria-label", text);
9465
+ }
9466
+ }
9467
+ function yui_maplibre_relocalize(map, t) {
9468
+ if (!map || typeof map.getContainer !== "function") return;
9469
+ const strings = yui_maplibre_locale(t);
9470
+ try {
9471
+ map._locale = Object.assign({}, map._locale, strings);
9472
+ } catch (e) {}
9473
+ const $c = map.getContainer();
9474
+ label_ctrl($c, ".maplibregl-ctrl-zoom-in", strings["NavigationControl.ZoomIn"]);
9475
+ label_ctrl($c, ".maplibregl-ctrl-zoom-out", strings["NavigationControl.ZoomOut"]);
9476
+ label_ctrl($c, ".maplibregl-ctrl-compass", strings["NavigationControl.ResetBearing"]);
9477
+ label_ctrl($c, ".maplibregl-ctrl-geolocate", strings["GeolocateControl.FindMyLocation"]);
9478
+ label_ctrl($c, ".maplibregl-ctrl-attrib-button", strings["AttributionControl.ToggleAttribution"]);
9479
+ label_ctrl($c, ".maplibregl-ctrl-fullscreen", strings["FullscreenControl.Enter"]);
9480
+ label_ctrl($c, ".maplibregl-popup-close-button", strings["Popup.Close"]);
9481
+ const mac = typeof navigator !== "undefined" && (navigator.userAgent || "").includes("Mac");
9482
+ const $desktop = $c.querySelector(".maplibregl-desktop-message");
9483
+ if ($desktop) $desktop.textContent = mac ? strings["CooperativeGesturesHandler.MacHelpText"] : strings["CooperativeGesturesHandler.WindowsHelpText"];
9484
+ const $mobile = $c.querySelector(".maplibregl-mobile-message");
9485
+ if ($mobile) $mobile.textContent = strings["CooperativeGesturesHandler.MobileHelpText"];
9486
+ }
9415
9487
  //#endregion
9416
9488
  //#region src/c_yui_map.js
9417
9489
  /***********************************************************************
@@ -9426,6 +9498,7 @@ var MarkerControl = class {
9426
9498
  * Constants
9427
9499
  ***************************************************************/
9428
9500
  var GCLASS_NAME$15 = "C_YUI_MAP";
9501
+ var GESTURE_HINT_MS = 2e3;
9429
9502
  /***************************************************************
9430
9503
  * Data
9431
9504
  ***************************************************************/
@@ -9452,6 +9525,7 @@ var attrs_table$15 = [
9452
9525
  ];
9453
9526
  var PRIVATE_DATA$15 = {
9454
9527
  xmap: null,
9528
+ gesture_hint_timer: null,
9455
9529
  geojson: null,
9456
9530
  resizeObserver: null,
9457
9531
  width: 0,
@@ -9474,7 +9548,11 @@ function mt_create$15(gobj) {
9474
9548
  let map_settings = json_deep_copy(gobj_read_attr(gobj, "map_settings"));
9475
9549
  let $map = gobj_read_attr(gobj, "$map");
9476
9550
  if ($map) $map.classList.add(GCLASS_NAME$15);
9477
- Object.assign(map_settings, { container: $map });
9551
+ Object.assign(map_settings, {
9552
+ container: $map,
9553
+ cooperativeGestures: true,
9554
+ locale: yui_maplibre_locale(t)
9555
+ });
9478
9556
  priv.onClick = (ev) => {
9479
9557
  onClick(gobj, ev);
9480
9558
  };
@@ -9491,6 +9569,16 @@ function mt_create$15(gobj) {
9491
9569
  xtouchStart(gobj, ev);
9492
9570
  };
9493
9571
  const map = priv.xmap = new maplibregl.Map(map_settings);
9572
+ map.on("cooperativegestureprevented", () => {
9573
+ const $s = map.getCanvasContainer().querySelector(".maplibregl-cooperative-gesture-screen");
9574
+ if (!$s) return;
9575
+ $s.classList.add("MAP_GESTURE_SHOWN");
9576
+ if (priv.gesture_hint_timer) clearTimeout(priv.gesture_hint_timer);
9577
+ priv.gesture_hint_timer = setTimeout(() => {
9578
+ priv.gesture_hint_timer = null;
9579
+ $s.classList.remove("MAP_GESTURE_SHOWN");
9580
+ }, GESTURE_HINT_MS);
9581
+ });
9494
9582
  map.addControl(new maplibregl.NavigationControl());
9495
9583
  map.addControl(new MarkerControl(gobj, {}), "top-right");
9496
9584
  map.addControl(new EditControl(gobj, { showMarkerDrag: true }), "top-right");
@@ -9520,10 +9608,46 @@ function mt_create$15(gobj) {
9520
9608
  }
9521
9609
  }
9522
9610
  /***************************************************************
9611
+ * The application changed language: maplibre's own words are
9612
+ * rewritten in place, and the map's locale with them so a
9613
+ * control or a popup built later is right too.
9614
+ ***************************************************************/
9615
+ function ac_language_changed$9(gobj, event, kw, src) {
9616
+ let priv = gobj.priv;
9617
+ if (priv.xmap) yui_maplibre_relocalize(priv.xmap, t);
9618
+ return 0;
9619
+ }
9620
+ /***************************************************************
9621
+ * Framework Method: Start
9622
+ *
9623
+ * The application's LANGUAGE: what maplibre draws with words is
9624
+ * built from its `locale` when each control builds its DOM, so
9625
+ * `refresh_language()` -- which reaches what carries an i18n key
9626
+ * in OUR dom -- cannot touch any of it. The shell says when the
9627
+ * language changed and this view rewrites those strings.
9628
+ ***************************************************************/
9629
+ function mt_start$15(gobj) {
9630
+ let shell = yui_shell_of(gobj);
9631
+ if (shell) gobj_subscribe_event(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
9632
+ return 0;
9633
+ }
9634
+ /***************************************************************
9635
+ * Framework Method: Stop
9636
+ ***************************************************************/
9637
+ function mt_stop$15(gobj) {
9638
+ let shell = yui_shell_of(gobj);
9639
+ if (shell) gobj_unsubscribe_event(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
9640
+ return 0;
9641
+ }
9642
+ /***************************************************************
9523
9643
  * Framework Method: Destroy
9524
9644
  ***************************************************************/
9525
9645
  function mt_destroy$15(gobj) {
9526
9646
  let priv = gobj.priv;
9647
+ if (priv.gesture_hint_timer) {
9648
+ clearTimeout(priv.gesture_hint_timer);
9649
+ priv.gesture_hint_timer = null;
9650
+ }
9527
9651
  if (priv.resizeObserver) {
9528
9652
  priv.resizeObserver.disconnect();
9529
9653
  priv.resizeObserver = null;
@@ -9984,6 +10108,8 @@ function ac_hide$10(gobj, event, kw, src) {
9984
10108
  ***************************/
9985
10109
  var gmt$15 = {
9986
10110
  mt_create: mt_create$15,
10111
+ mt_start: mt_start$15,
10112
+ mt_stop: mt_stop$15,
9987
10113
  mt_destroy: mt_destroy$15
9988
10114
  };
9989
10115
  /***************************************************************
@@ -9995,6 +10121,7 @@ function create_gclass$15(gclass_name) {
9995
10121
  return -1;
9996
10122
  }
9997
10123
  __gclass__$15 = gclass_create(gclass_name, [
10124
+ ["EV_LANGUAGE_CHANGED", 0],
9998
10125
  ["EV_EDIT_MAP", 0],
9999
10126
  ["EV_CONTROL_MAP", 0],
10000
10127
  ["EV_MAP_ON_LOAD", 0],
@@ -10003,6 +10130,11 @@ function create_gclass$15(gclass_name) {
10003
10130
  ["EV_SHOW", 0],
10004
10131
  ["EV_HIDE", 0]
10005
10132
  ], [["ST_IDLE", [
10133
+ [
10134
+ "EV_LANGUAGE_CHANGED",
10135
+ ac_language_changed$9,
10136
+ null
10137
+ ],
10006
10138
  [
10007
10139
  "EV_EDIT_MAP",
10008
10140
  ac_edit_map,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.109",
3
+ "version": "7.23.111",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
package/src/c_yui_map.css CHANGED
@@ -33,3 +33,29 @@
33
33
  .xmap .column {
34
34
  padding: 0 !important;
35
35
  }
36
+
37
+ /*
38
+ * The cooperative-gesture notice: "Use Ctrl + scroll to zoom the map".
39
+ *
40
+ * maplibre's own sheet shows it for 100ms and lets it FADE for a second
41
+ * more (`transition: opacity 1s ease 1s`). Nothing here has transitions,
42
+ * so that fade is cut -- and with it the only thing that made the notice
43
+ * readable, since 100ms is not reading time. `c_yui_map.js` holds it by
44
+ * the clock instead: it appears and disappears at once, and stands still
45
+ * in between.
46
+ */
47
+ .maplibregl-cooperative-gesture-screen,
48
+ .maplibregl-cooperative-gesture-screen.maplibregl-show {
49
+ transition: none !important;
50
+ }
51
+
52
+ .maplibregl-cooperative-gesture-screen.MAP_GESTURE_SHOWN {
53
+ opacity: 1;
54
+ }
55
+
56
+ /* 1.4em leaves the notice in four lines on the small map of a card. It
57
+ * is an instruction, not a headline. */
58
+ .maplibregl-cooperative-gesture-screen {
59
+ font-size: 1rem;
60
+ text-align: center;
61
+ }
package/src/c_yui_map.js CHANGED
@@ -29,6 +29,7 @@ import {
29
29
  gobj_create_service,
30
30
  gobj_start,
31
31
  gobj_name,
32
+ gobj_unsubscribe_event,
32
33
  } from "@yuneta/gobj-js";
33
34
 
34
35
  import "maplibre-gl/dist/maplibre-gl.css"; // Import MapLibre styles
@@ -36,9 +37,15 @@ import * as maplibregl from "maplibre-gl"; // MapLibre GL JS 6 is ESM-only, no d
36
37
 
37
38
  import {
38
39
  EditControl,
39
- MarkerControl
40
+ MarkerControl,
41
+ yui_maplibre_locale,
42
+ yui_maplibre_relocalize
40
43
  } from "./lib_maplibre.js";
41
44
 
45
+ import {t} from "i18next";
46
+
47
+ import {yui_shell_of} from "./c_yui_shell.js";
48
+
42
49
  import "./c_yui_map.css"; // Must be in index.js ?
43
50
 
44
51
  /***************************************************************
@@ -46,6 +53,9 @@ import "./c_yui_map.css"; // Must be in index.js ?
46
53
  ***************************************************************/
47
54
  const GCLASS_NAME = "C_YUI_MAP";
48
55
 
56
+ /* How long the cooperative-gesture notice stays up, in ms. */
57
+ const GESTURE_HINT_MS = 2000;
58
+
49
59
  /***************************************************************
50
60
  * Data
51
61
  ***************************************************************/
@@ -74,6 +84,7 @@ SDATA_END()
74
84
 
75
85
  let PRIVATE_DATA = {
76
86
  xmap: null,
87
+ gesture_hint_timer: null, /* keeps the gesture notice up long enough */
77
88
  geojson: null,
78
89
  resizeObserver: null,
79
90
  width: 0, // map size, data got from resize observer
@@ -119,6 +130,26 @@ function mt_create(gobj)
119
130
  }
120
131
  Object.assign(map_settings, {
121
132
  container: $map,
133
+ /* THE WHEEL DOES NOT ZOOM; Ctrl + wheel does -- the same
134
+ * vocabulary as the three graphs (`yui_graph_camera.js`), so a
135
+ * reader with a map and a graph open does not have to remember
136
+ * which is which. maplibre calls it `cooperativeGestures`, and
137
+ * it never blocks a wheel carrying ctrlKey, so a trackpad PINCH
138
+ * keeps zooming on every platform (a Mac gets Cmd as well, its
139
+ * own convention, which costs nothing).
140
+ *
141
+ * HERE and not in the attr's default value: a JSON attr is
142
+ * replaced WHOLESALE by a host that passes its own, so a
143
+ * default is a suggestion -- the demo passes `map_settings` and
144
+ * never saw it. This is the house gesture, not a suggestion. */
145
+ cooperativeGestures: true,
146
+ /* maplibre draws words of its own -- the zoom tooltips, the
147
+ * geolocate button, the attribution toggle and the notice that
148
+ * teaches the gesture above -- and they came out in ITS
149
+ * English inside a Spanish app. `locale` is read once, when
150
+ * each control builds its DOM, so the language CHANGE is the
151
+ * other half, in ac_language_changed. */
152
+ locale: yui_maplibre_locale(t),
122
153
  });
123
154
 
124
155
  /*-----------------------------*
@@ -145,6 +176,35 @@ function mt_create(gobj)
145
176
  *-----------------------------*/
146
177
  const map = priv.xmap = new maplibregl.Map(map_settings);
147
178
 
179
+ /* HOW LONG THE NOTICE STAYS UP.
180
+ *
181
+ * maplibre shows it for 100ms and lets it FADE for a second more
182
+ * (`transition: opacity 1s ease 1s`). Nothing in this GUI has
183
+ * transitions, so that fade is cut -- and with it the only thing
184
+ * that made the notice readable, because 100ms is not reading
185
+ * time. It is held by the clock instead: on and off at once, and
186
+ * still in between for as long as it takes to read it.
187
+ *
188
+ * In maplibre's callback and not through the machine, for the same
189
+ * reason as the zoom readout: it is not an action, it is the map
190
+ * acknowledging a gesture it refused, and one wheel fires it
191
+ * dozens of times. */
192
+ map.on("cooperativegestureprevented", () => {
193
+ const $s = map.getCanvasContainer()
194
+ .querySelector(".maplibregl-cooperative-gesture-screen");
195
+ if(!$s) {
196
+ return;
197
+ }
198
+ $s.classList.add("MAP_GESTURE_SHOWN");
199
+ if(priv.gesture_hint_timer) {
200
+ clearTimeout(priv.gesture_hint_timer);
201
+ }
202
+ priv.gesture_hint_timer = setTimeout(() => {
203
+ priv.gesture_hint_timer = null;
204
+ $s.classList.remove("MAP_GESTURE_SHOWN");
205
+ }, GESTURE_HINT_MS);
206
+ });
207
+
148
208
  /*-----------------------------*
149
209
  * Controls
150
210
  *-----------------------------*/
@@ -206,6 +266,51 @@ function mt_create(gobj)
206
266
  }
207
267
  }
208
268
 
269
+ /***************************************************************
270
+ * The application changed language: maplibre's own words are
271
+ * rewritten in place, and the map's locale with them so a
272
+ * control or a popup built later is right too.
273
+ ***************************************************************/
274
+ function ac_language_changed(gobj, event, kw, src)
275
+ {
276
+ let priv = gobj.priv;
277
+
278
+ if(priv.xmap) {
279
+ yui_maplibre_relocalize(priv.xmap, t);
280
+ }
281
+ return 0;
282
+ }
283
+
284
+ /***************************************************************
285
+ * Framework Method: Start
286
+ *
287
+ * The application's LANGUAGE: what maplibre draws with words is
288
+ * built from its `locale` when each control builds its DOM, so
289
+ * `refresh_language()` -- which reaches what carries an i18n key
290
+ * in OUR dom -- cannot touch any of it. The shell says when the
291
+ * language changed and this view rewrites those strings.
292
+ ***************************************************************/
293
+ function mt_start(gobj)
294
+ {
295
+ let shell = yui_shell_of(gobj);
296
+ if(shell) {
297
+ gobj_subscribe_event(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
298
+ }
299
+ return 0;
300
+ }
301
+
302
+ /***************************************************************
303
+ * Framework Method: Stop
304
+ ***************************************************************/
305
+ function mt_stop(gobj)
306
+ {
307
+ let shell = yui_shell_of(gobj);
308
+ if(shell) {
309
+ gobj_unsubscribe_event(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
310
+ }
311
+ return 0;
312
+ }
313
+
209
314
  /***************************************************************
210
315
  * Framework Method: Destroy
211
316
  ***************************************************************/
@@ -213,6 +318,10 @@ function mt_destroy(gobj)
213
318
  {
214
319
  let priv = gobj.priv;
215
320
 
321
+ if(priv.gesture_hint_timer) {
322
+ clearTimeout(priv.gesture_hint_timer);
323
+ priv.gesture_hint_timer = null;
324
+ }
216
325
  if(priv.resizeObserver) {
217
326
  priv.resizeObserver.disconnect();
218
327
  priv.resizeObserver = null;
@@ -921,6 +1030,8 @@ function ac_hide(gobj, event, kw, src)
921
1030
  *---------------------------------------------*/
922
1031
  const gmt = {
923
1032
  mt_create: mt_create,
1033
+ mt_start: mt_start,
1034
+ mt_stop: mt_stop,
924
1035
  mt_destroy: mt_destroy
925
1036
  };
926
1037
 
@@ -939,6 +1050,7 @@ function create_gclass(gclass_name)
939
1050
  *---------------------------------------------*/
940
1051
  const states = [
941
1052
  ["ST_IDLE", [
1053
+ ["EV_LANGUAGE_CHANGED", ac_language_changed, null],
942
1054
  ["EV_EDIT_MAP", ac_edit_map, null],
943
1055
  ["EV_CONTROL_MAP", ac_control_map, null],
944
1056
  ["EV_MAP_ON_LOAD", ac_map_on_load, null],
@@ -953,6 +1065,7 @@ function create_gclass(gclass_name)
953
1065
  * Events
954
1066
  *---------------------------------------------*/
955
1067
  const event_types = [
1068
+ ["EV_LANGUAGE_CHANGED", 0],
956
1069
  ["EV_EDIT_MAP", 0],
957
1070
  ["EV_CONTROL_MAP", 0],
958
1071
  ["EV_MAP_ON_LOAD", 0],
@@ -215,10 +215,116 @@ class MarkerControl {
215
215
  }
216
216
  }
217
217
 
218
+
219
+ /***********************************************************************
220
+ * MAPLIBRE'S OWN CHROME, IN THE APP'S LANGUAGE
221
+ *
222
+ * Everything maplibre draws with words -- the zoom tooltips, the
223
+ * geolocate button, the attribution toggle, a popup's close, and the
224
+ * notice that teaches the Ctrl + wheel gesture -- comes from its
225
+ * `locale`, an option merged over its own English defaults at
226
+ * construction. So a map in a Spanish app was saying *"Zoom in"* and
227
+ * *"Use Ctrl + scroll to zoom the map"*, which is the same rule this
228
+ * GUI applies to every other string.
229
+ *
230
+ * Two halves, because maplibre reads its strings ONCE, when each
231
+ * control builds its DOM:
232
+ *
233
+ * `yui_maplibre_locale(t)` the `locale` option, for the map's
234
+ * first paint;
235
+ * `yui_maplibre_relocalize()` after a language change, which is
236
+ * the half a `locale` alone cannot
237
+ * do -- it writes the strings into
238
+ * the DOM already drawn, and updates
239
+ * the map's locale so anything built
240
+ * later is right too.
241
+ *
242
+ * The scale units (`km`, `mi`, `nm`) are symbols and are left alone;
243
+ * the MapLibre logo keeps its name, which is a brand.
244
+ ***********************************************************************/
245
+ function yui_maplibre_locale(t)
246
+ {
247
+ return {
248
+ "NavigationControl.ZoomIn": t("zoom in"),
249
+ "NavigationControl.ZoomOut": t("zoom out"),
250
+ "NavigationControl.ResetBearing": t("drag to rotate the map, click to reset north"),
251
+ "GeolocateControl.FindMyLocation": t("find my location"),
252
+ "GeolocateControl.LocationNotAvailable": t("location not available"),
253
+ "AttributionControl.ToggleAttribution": t("toggle attribution"),
254
+ "AttributionControl.MapFeedback": t("map feedback"),
255
+ "FullscreenControl.Enter": t("enter fullscreen"),
256
+ "FullscreenControl.Exit": t("exit fullscreen"),
257
+ "Popup.Close": t("close popup"),
258
+ "Map.Title": t("map"),
259
+ "Marker.Title": t("map marker"),
260
+ "CooperativeGesturesHandler.WindowsHelpText": t("use ctrl + scroll to zoom the map"),
261
+ "CooperativeGesturesHandler.MacHelpText": t("use cmd + scroll to zoom the map"),
262
+ "CooperativeGesturesHandler.MobileHelpText": t("use two fingers to move the map"),
263
+ };
264
+ }
265
+
266
+ /* One drawn control: its tooltip and its aria-label say the same
267
+ * thing, and a screen reader needs the second even when the first is
268
+ * what a pointer finds. */
269
+ function label_ctrl($root, selector, text)
270
+ {
271
+ if(!$root || !text) {
272
+ return;
273
+ }
274
+ for(const $el of $root.querySelectorAll(selector)) {
275
+ $el.setAttribute("title", text);
276
+ $el.setAttribute("aria-label", text);
277
+ }
278
+ }
279
+
280
+ function yui_maplibre_relocalize(map, t)
281
+ {
282
+ if(!map || typeof map.getContainer !== "function") {
283
+ return;
284
+ }
285
+ const strings = yui_maplibre_locale(t);
286
+
287
+ /* The map's own table first: a control added later (or a popup
288
+ * opened later) reads it when it builds itself. */
289
+ try {
290
+ map._locale = Object.assign({}, map._locale, strings);
291
+ } catch(e) {
292
+ /* a maplibre that keeps its locale elsewhere: the DOM below
293
+ * still gets translated, which is what is on screen */
294
+ }
295
+
296
+ const $c = map.getContainer();
297
+ label_ctrl($c, ".maplibregl-ctrl-zoom-in", strings["NavigationControl.ZoomIn"]);
298
+ label_ctrl($c, ".maplibregl-ctrl-zoom-out", strings["NavigationControl.ZoomOut"]);
299
+ label_ctrl($c, ".maplibregl-ctrl-compass", strings["NavigationControl.ResetBearing"]);
300
+ label_ctrl($c, ".maplibregl-ctrl-geolocate", strings["GeolocateControl.FindMyLocation"]);
301
+ label_ctrl($c, ".maplibregl-ctrl-attrib-button", strings["AttributionControl.ToggleAttribution"]);
302
+ label_ctrl($c, ".maplibregl-ctrl-fullscreen", strings["FullscreenControl.Enter"]);
303
+ label_ctrl($c, ".maplibregl-popup-close-button", strings["Popup.Close"]);
304
+
305
+ /* The notice of the cooperative gesture: two lines, one for a
306
+ * pointer and one for a finger, built by `_setupUI()` as
307
+ * `.maplibregl-desktop-message` / `.maplibregl-mobile-message`. */
308
+ const mac = (typeof navigator !== "undefined" &&
309
+ (navigator.userAgent || "").includes("Mac"));
310
+ const $desktop = $c.querySelector(".maplibregl-desktop-message");
311
+ if($desktop) {
312
+ $desktop.textContent = mac
313
+ ? strings["CooperativeGesturesHandler.MacHelpText"]
314
+ : strings["CooperativeGesturesHandler.WindowsHelpText"];
315
+ }
316
+ const $mobile = $c.querySelector(".maplibregl-mobile-message");
317
+ if($mobile) {
318
+ $mobile.textContent = strings["CooperativeGesturesHandler.MobileHelpText"];
319
+ }
320
+ }
321
+
218
322
  //=======================================================================
219
323
  // Expose the class via the global object
220
324
  //=======================================================================
221
325
  export {
222
326
  EditControl,
223
- MarkerControl
327
+ MarkerControl,
328
+ yui_maplibre_locale,
329
+ yui_maplibre_relocalize
224
330
  };