@yuneta/gobj-ui 7.23.158 → 7.23.160
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 +78 -1
- package/dist/gobj-ui.cjs.js +987 -168
- package/dist/gobj-ui.es.js +987 -168
- package/package.json +1 -1
- package/src/c_yui_form.js +52 -1
- package/src/c_yui_treedb_schema.js +134 -10
- package/src/c_yui_treedb_topic_with_form.css +67 -0
- package/src/c_yui_treedb_topic_with_form.js +401 -9
- package/src/c_yui_treedb_topics.js +80 -0
- package/src/yui_asset.css +51 -0
- package/src/yui_asset.js +223 -3
- package/src/yui_asset.test.js +18 -0
- package/src/yui_file_field.css +28 -0
- package/src/yui_file_field.js +45 -1
- package/src/yui_graph_camera.js +64 -0
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -6095,6 +6095,299 @@ function yui_tabulator_relocalize(table, t) {
|
|
|
6095
6095
|
}
|
|
6096
6096
|
}
|
|
6097
6097
|
//#endregion
|
|
6098
|
+
//#region src/yui_asset.js
|
|
6099
|
+
var BLOB_ATTR = "data-yui-blob";
|
|
6100
|
+
function ref_to_id(ref) {
|
|
6101
|
+
if (!ref) return null;
|
|
6102
|
+
if (typeof ref === "string") {
|
|
6103
|
+
if (ref.indexOf("^") < 0) return ref;
|
|
6104
|
+
const parts = ref.split("^");
|
|
6105
|
+
return parts.length >= 2 && parts[1] ? parts[1] : null;
|
|
6106
|
+
}
|
|
6107
|
+
if (typeof ref === "object" && typeof ref.id === "string") return ref.id;
|
|
6108
|
+
return null;
|
|
6109
|
+
}
|
|
6110
|
+
/***************************************************************************
|
|
6111
|
+
* Every asset id a column names, in order. Always an array, possibly empty.
|
|
6112
|
+
***************************************************************************/
|
|
6113
|
+
function yui_asset_ids(ref) {
|
|
6114
|
+
if (Array.isArray(ref)) return ref.map(ref_to_id).filter((id) => !!id);
|
|
6115
|
+
const id = ref_to_id(ref);
|
|
6116
|
+
return id ? [id] : [];
|
|
6117
|
+
}
|
|
6118
|
+
/***************************************************************************
|
|
6119
|
+
* The first asset id a column names, or null.
|
|
6120
|
+
***************************************************************************/
|
|
6121
|
+
function yui_asset_id(ref) {
|
|
6122
|
+
const ids = yui_asset_ids(ref);
|
|
6123
|
+
return ids.length ? ids[0] : null;
|
|
6124
|
+
}
|
|
6125
|
+
/***************************************************************************
|
|
6126
|
+
* Turn a `get-asset` answer into something an element can load.
|
|
6127
|
+
*
|
|
6128
|
+
* Returns null when the answer carries neither -- which the caller must
|
|
6129
|
+
* treat as "missing", never as an empty src: an <img src=""> reloads the
|
|
6130
|
+
* PAGE in some browsers.
|
|
6131
|
+
***************************************************************************/
|
|
6132
|
+
function yui_asset_src(answer) {
|
|
6133
|
+
if (!answer) return null;
|
|
6134
|
+
if (answer.mode === "url" && answer.url) return answer.url;
|
|
6135
|
+
if (answer.mode === "inline" && answer.content64) return `data:${answer.content_type || "application/octet-stream"};base64,${answer.content64}`;
|
|
6136
|
+
return null;
|
|
6137
|
+
}
|
|
6138
|
+
/***************************************************************************
|
|
6139
|
+
* The marker for an asset that is not there.
|
|
6140
|
+
*
|
|
6141
|
+
* A missing image used to leave a broken box and no word about it, which
|
|
6142
|
+
* is indistinguishable from a slow one and from a bug. This says so, and
|
|
6143
|
+
* it says WHICH: `detail` is data (a name, a path) and is never
|
|
6144
|
+
* translated, while the label carries its i18n key so a language change
|
|
6145
|
+
* re-translates it.
|
|
6146
|
+
***************************************************************************/
|
|
6147
|
+
function yui_asset_missing(detail, opts = {}) {
|
|
6148
|
+
const key = opts.key || "asset not available";
|
|
6149
|
+
const children = [["span", { class: "ASSET_MISSING_ICON yi-triangle-exclamation" }], [
|
|
6150
|
+
"span",
|
|
6151
|
+
{
|
|
6152
|
+
class: "ASSET_MISSING_LABEL",
|
|
6153
|
+
i18n: key
|
|
6154
|
+
},
|
|
6155
|
+
key
|
|
6156
|
+
]];
|
|
6157
|
+
if (detail) children.push([
|
|
6158
|
+
"span",
|
|
6159
|
+
{ class: "ASSET_MISSING_DETAIL" },
|
|
6160
|
+
String(detail)
|
|
6161
|
+
]);
|
|
6162
|
+
const attrs = { class: `ASSET_MISSING ${opts.class || ""}`.trim() };
|
|
6163
|
+
if (detail) attrs.title = String(detail);
|
|
6164
|
+
else attrs["data-i18n-title"] = key;
|
|
6165
|
+
return (0, _yuneta_gobj_js.createElement2)([
|
|
6166
|
+
"div",
|
|
6167
|
+
attrs,
|
|
6168
|
+
children
|
|
6169
|
+
]);
|
|
6170
|
+
}
|
|
6171
|
+
/***************************************************************************
|
|
6172
|
+
* What KIND of thing a content type is, as far as showing it goes:
|
|
6173
|
+
*
|
|
6174
|
+
* "image" | "video" | "audio" the browser draws it in an element
|
|
6175
|
+
* "pdf" the browser's own viewer, in a frame
|
|
6176
|
+
* "other" nothing here can draw it: a card
|
|
6177
|
+
* saying what it is, and a way to open
|
|
6178
|
+
*
|
|
6179
|
+
* The content type is the one the BACKEND stored (treedb checks it
|
|
6180
|
+
* against the bytes), never the extension of a name a person typed.
|
|
6181
|
+
***************************************************************************/
|
|
6182
|
+
function yui_asset_kind(content_type) {
|
|
6183
|
+
const ct = String(content_type || "").toLowerCase().split(";")[0].trim();
|
|
6184
|
+
if (ct.startsWith("image/")) return "image";
|
|
6185
|
+
if (ct.startsWith("video/")) return "video";
|
|
6186
|
+
if (ct.startsWith("audio/")) return "audio";
|
|
6187
|
+
if (ct === "application/pdf") return "pdf";
|
|
6188
|
+
return "other";
|
|
6189
|
+
}
|
|
6190
|
+
/***************************************************************************
|
|
6191
|
+
* A `blob:` url for inline bytes, or null.
|
|
6192
|
+
*
|
|
6193
|
+
* A frame and a new tab need a blob and not a data url: Firefox refuses to
|
|
6194
|
+
* NAVIGATE to a data url (a new tab opened on one stays blank), and its
|
|
6195
|
+
* PDF viewer does not run on one inside a frame.
|
|
6196
|
+
***************************************************************************/
|
|
6197
|
+
function base64_to_blob_url(content64, content_type) {
|
|
6198
|
+
try {
|
|
6199
|
+
const binary = atob(content64);
|
|
6200
|
+
const bytes = new Uint8Array(binary.length);
|
|
6201
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
6202
|
+
const blob = new Blob([bytes], { type: content_type || "application/octet-stream" });
|
|
6203
|
+
return URL.createObjectURL(blob);
|
|
6204
|
+
} catch (e) {
|
|
6205
|
+
(0, _yuneta_gobj_js.log_error)(`cannot decode the bytes of an asset: ${e && e.message ? e.message : e}`);
|
|
6206
|
+
return null;
|
|
6207
|
+
}
|
|
6208
|
+
}
|
|
6209
|
+
/***************************************************************************
|
|
6210
|
+
* Where a frame or a link can take an asset:
|
|
6211
|
+
*
|
|
6212
|
+
* -> {href, blob} `blob` true when href is a blob url THIS call
|
|
6213
|
+
* created, which the caller must mark (BLOB_ATTR)
|
|
6214
|
+
* so that yui_asset_release() revokes it
|
|
6215
|
+
* -> null nothing to open
|
|
6216
|
+
***************************************************************************/
|
|
6217
|
+
function yui_asset_href(answer) {
|
|
6218
|
+
if (!answer) return null;
|
|
6219
|
+
if (answer.mode === "url" && answer.url) return {
|
|
6220
|
+
href: answer.url,
|
|
6221
|
+
blob: false
|
|
6222
|
+
};
|
|
6223
|
+
if (answer.mode === "inline" && answer.content64) {
|
|
6224
|
+
const href = base64_to_blob_url(answer.content64, answer.content_type);
|
|
6225
|
+
return href ? {
|
|
6226
|
+
href,
|
|
6227
|
+
blob: true
|
|
6228
|
+
} : null;
|
|
6229
|
+
}
|
|
6230
|
+
return null;
|
|
6231
|
+
}
|
|
6232
|
+
/***************************************************************************
|
|
6233
|
+
* The answer a picked `File` would have had from the backend.
|
|
6234
|
+
*
|
|
6235
|
+
* A file a person picked and has not saved yet is shown BEFORE it exists
|
|
6236
|
+
* as an asset, so it goes through the same element as a stored one: a
|
|
6237
|
+
* `url` answer whose url is a blob url over the File itself -- which
|
|
6238
|
+
* reads nothing until the browser draws it.
|
|
6239
|
+
*
|
|
6240
|
+
* `blob: true` says the url is owned: whoever drops the element revokes
|
|
6241
|
+
* it with yui_asset_release().
|
|
6242
|
+
***************************************************************************/
|
|
6243
|
+
function yui_asset_file_answer(file) {
|
|
6244
|
+
if (!file) return null;
|
|
6245
|
+
let url;
|
|
6246
|
+
try {
|
|
6247
|
+
url = URL.createObjectURL(file);
|
|
6248
|
+
} catch (e) {
|
|
6249
|
+
(0, _yuneta_gobj_js.log_error)(`cannot preview the picked file: ${e && e.message ? e.message : e}`);
|
|
6250
|
+
return null;
|
|
6251
|
+
}
|
|
6252
|
+
return {
|
|
6253
|
+
mode: "url",
|
|
6254
|
+
url,
|
|
6255
|
+
content_type: file.type || "",
|
|
6256
|
+
size: file.size,
|
|
6257
|
+
original_name: file.name || "",
|
|
6258
|
+
blob: true
|
|
6259
|
+
};
|
|
6260
|
+
}
|
|
6261
|
+
/***************************************************************************
|
|
6262
|
+
* Revoke every blob url this module created under `$root`, $root included.
|
|
6263
|
+
*
|
|
6264
|
+
* Call it on whatever element is about to be dropped: a preview being
|
|
6265
|
+
* replaced, a dialog being closed. A blob url that is never revoked keeps
|
|
6266
|
+
* its bytes in memory for the life of the page.
|
|
6267
|
+
***************************************************************************/
|
|
6268
|
+
function yui_asset_release($root) {
|
|
6269
|
+
if (!$root || !$root.querySelectorAll) return;
|
|
6270
|
+
const marked = Array.from($root.querySelectorAll(`[${BLOB_ATTR}]`));
|
|
6271
|
+
if ($root.hasAttribute && $root.hasAttribute(BLOB_ATTR)) marked.push($root);
|
|
6272
|
+
marked.forEach(($el) => {
|
|
6273
|
+
const url = $el.getAttribute(BLOB_ATTR);
|
|
6274
|
+
$el.removeAttribute(BLOB_ATTR);
|
|
6275
|
+
if (url) URL.revokeObjectURL(url);
|
|
6276
|
+
});
|
|
6277
|
+
}
|
|
6278
|
+
/***************************************************************************
|
|
6279
|
+
* The link that opens an asset in a new tab, or null when there is
|
|
6280
|
+
* nothing to open. A control: named for the eye and for a reader, both
|
|
6281
|
+
* through their keys so a language change re-translates them.
|
|
6282
|
+
***************************************************************************/
|
|
6283
|
+
function yui_asset_open_link(answer, opts = {}) {
|
|
6284
|
+
const target = yui_asset_href(answer);
|
|
6285
|
+
if (!target) return null;
|
|
6286
|
+
const key = "open in a new tab";
|
|
6287
|
+
const $a = (0, _yuneta_gobj_js.createElement2)([
|
|
6288
|
+
"a",
|
|
6289
|
+
{
|
|
6290
|
+
class: `ASSET_OPEN ${opts.class || ""}`.trim(),
|
|
6291
|
+
target: "_blank",
|
|
6292
|
+
rel: "noopener",
|
|
6293
|
+
title: (0, i18next.t)(key),
|
|
6294
|
+
"data-i18n-title": key,
|
|
6295
|
+
"aria-label": (0, i18next.t)(key),
|
|
6296
|
+
"data-i18n-aria-label": key
|
|
6297
|
+
},
|
|
6298
|
+
[["span", { class: "ASSET_OPEN_ICON yi-link" }], [
|
|
6299
|
+
"span",
|
|
6300
|
+
{
|
|
6301
|
+
class: "ASSET_OPEN_LABEL",
|
|
6302
|
+
i18n: key
|
|
6303
|
+
},
|
|
6304
|
+
key
|
|
6305
|
+
]]
|
|
6306
|
+
]);
|
|
6307
|
+
$a.href = target.href;
|
|
6308
|
+
if (target.blob) $a.setAttribute(BLOB_ATTR, target.href);
|
|
6309
|
+
return $a;
|
|
6310
|
+
}
|
|
6311
|
+
/***************************************************************************
|
|
6312
|
+
* The element for one asset.
|
|
6313
|
+
*
|
|
6314
|
+
* The KIND comes from the content type the backend stored, not from the
|
|
6315
|
+
* name a person typed: video and audio are assets too, and an <img> whose
|
|
6316
|
+
* src is a film shows the broken box this module exists to remove.
|
|
6317
|
+
*
|
|
6318
|
+
* `detail` is what the missing marker shows -- pass the original name or
|
|
6319
|
+
* the source path, the thing a person can act on.
|
|
6320
|
+
*
|
|
6321
|
+
* A PDF goes in a frame, where the browser's own viewer draws it. Any
|
|
6322
|
+
* other kind gets a card: what it is, and a link to open it.
|
|
6323
|
+
* TODO: draw more kinds in place (plain text, office documents); today
|
|
6324
|
+
* they are only opened in a new tab, where the browser does what it can.
|
|
6325
|
+
***************************************************************************/
|
|
6326
|
+
function yui_asset_element(answer, opts = {}) {
|
|
6327
|
+
const src = yui_asset_src(answer);
|
|
6328
|
+
if (!src) return yui_asset_missing(opts.detail, opts);
|
|
6329
|
+
const kind = yui_asset_kind(answer.content_type);
|
|
6330
|
+
const cls = `ASSET_MEDIA ${opts.class || ""}`.trim();
|
|
6331
|
+
if (kind === "pdf") {
|
|
6332
|
+
const target = yui_asset_href(answer);
|
|
6333
|
+
if (!target) return yui_asset_missing(opts.detail, opts);
|
|
6334
|
+
const $frame = (0, _yuneta_gobj_js.createElement2)(["iframe", {
|
|
6335
|
+
class: `${cls} ASSET_DOCUMENT`,
|
|
6336
|
+
title: opts.detail || answer.content_type || ""
|
|
6337
|
+
}]);
|
|
6338
|
+
$frame.src = target.href;
|
|
6339
|
+
if (target.blob) $frame.setAttribute(BLOB_ATTR, target.href);
|
|
6340
|
+
return $frame;
|
|
6341
|
+
}
|
|
6342
|
+
if (kind === "other") {
|
|
6343
|
+
const children = [[
|
|
6344
|
+
"span",
|
|
6345
|
+
{ class: "ASSET_OTHER_TYPE" },
|
|
6346
|
+
String(answer.content_type || "?")
|
|
6347
|
+
]];
|
|
6348
|
+
if (opts.detail) children.push([
|
|
6349
|
+
"span",
|
|
6350
|
+
{ class: "ASSET_OTHER_DETAIL" },
|
|
6351
|
+
String(opts.detail)
|
|
6352
|
+
]);
|
|
6353
|
+
const $card = (0, _yuneta_gobj_js.createElement2)([
|
|
6354
|
+
"div",
|
|
6355
|
+
{ class: `${cls} ASSET_OTHER` },
|
|
6356
|
+
children
|
|
6357
|
+
]);
|
|
6358
|
+
const $open = yui_asset_open_link(answer);
|
|
6359
|
+
if ($open) $card.appendChild($open);
|
|
6360
|
+
return $card;
|
|
6361
|
+
}
|
|
6362
|
+
let el;
|
|
6363
|
+
if (kind === "video") el = (0, _yuneta_gobj_js.createElement2)(["video", {
|
|
6364
|
+
class: cls,
|
|
6365
|
+
controls: "",
|
|
6366
|
+
preload: "metadata"
|
|
6367
|
+
}]);
|
|
6368
|
+
else if (kind === "audio") el = (0, _yuneta_gobj_js.createElement2)(["audio", {
|
|
6369
|
+
class: cls,
|
|
6370
|
+
controls: "",
|
|
6371
|
+
preload: "metadata"
|
|
6372
|
+
}]);
|
|
6373
|
+
else {
|
|
6374
|
+
el = (0, _yuneta_gobj_js.createElement2)(["img", {
|
|
6375
|
+
class: cls,
|
|
6376
|
+
loading: "lazy"
|
|
6377
|
+
}]);
|
|
6378
|
+
el.alt = opts.alt || opts.detail || "";
|
|
6379
|
+
}
|
|
6380
|
+
el.src = src;
|
|
6381
|
+
if (answer.blob) el.setAttribute(BLOB_ATTR, src);
|
|
6382
|
+
el.onerror = () => {
|
|
6383
|
+
(0, _yuneta_gobj_js.log_error)(`asset could not be loaded: ${opts.detail || src}`);
|
|
6384
|
+
const $marker = yui_asset_missing(opts.detail, opts);
|
|
6385
|
+
if (el.parentNode) el.parentNode.replaceChild($marker, el);
|
|
6386
|
+
yui_asset_release(el);
|
|
6387
|
+
};
|
|
6388
|
+
return el;
|
|
6389
|
+
}
|
|
6390
|
+
//#endregion
|
|
6098
6391
|
//#region src/yui_file_field.js
|
|
6099
6392
|
/***********************************************************************
|
|
6100
6393
|
* yui_file_field.js
|
|
@@ -6331,6 +6624,10 @@ function yui_file_control(gobj, { name, value, readonly, accept, on_pick }) {
|
|
|
6331
6624
|
const $name = (0, _yuneta_gobj_js.createElement2)(["span", { class: "FILE_NAME" }]);
|
|
6332
6625
|
const $size = (0, _yuneta_gobj_js.createElement2)(["span", { class: "FILE_SIZE" }]);
|
|
6333
6626
|
const $state = (0, _yuneta_gobj_js.createElement2)(["span", { class: "FILE_STATE" }]);
|
|
6627
|
+
const $preview = (0, _yuneta_gobj_js.createElement2)(["div", {
|
|
6628
|
+
class: "FILE_PREVIEW",
|
|
6629
|
+
hidden: ""
|
|
6630
|
+
}]);
|
|
6334
6631
|
const $control = (0, _yuneta_gobj_js.createElement2)([
|
|
6335
6632
|
"div",
|
|
6336
6633
|
{ class: "FILE_FIELD" },
|
|
@@ -6340,11 +6637,13 @@ function yui_file_control(gobj, { name, value, readonly, accept, on_pick }) {
|
|
|
6340
6637
|
$name,
|
|
6341
6638
|
$size,
|
|
6342
6639
|
$state,
|
|
6343
|
-
$clear
|
|
6640
|
+
$clear,
|
|
6641
|
+
$preview
|
|
6344
6642
|
]
|
|
6345
6643
|
]);
|
|
6346
6644
|
$control.yui_file = null;
|
|
6347
6645
|
$control.yui_file_value = value || "";
|
|
6646
|
+
$control.yui_file_stored = null;
|
|
6348
6647
|
const render = () => {
|
|
6349
6648
|
const picked = $control.yui_file;
|
|
6350
6649
|
const kept = $control.yui_file_value;
|
|
@@ -6365,6 +6664,24 @@ function yui_file_control(gobj, { name, value, readonly, accept, on_pick }) {
|
|
|
6365
6664
|
}
|
|
6366
6665
|
$clear.hidden = readonly || !picked && !kept;
|
|
6367
6666
|
$pick.hidden = !!readonly;
|
|
6667
|
+
yui_asset_release($preview);
|
|
6668
|
+
$preview.replaceChildren();
|
|
6669
|
+
let $media = null;
|
|
6670
|
+
if (picked) {
|
|
6671
|
+
const answer = yui_asset_file_answer(picked);
|
|
6672
|
+
if (answer) $media = yui_asset_element(answer, {
|
|
6673
|
+
detail: picked.name || "",
|
|
6674
|
+
class: "FILE_PREVIEW_MEDIA"
|
|
6675
|
+
});
|
|
6676
|
+
} else if (kept) {
|
|
6677
|
+
const stored = $control.yui_file_stored;
|
|
6678
|
+
if (stored && stored.id === kept) $media = yui_asset_element(stored.answer, {
|
|
6679
|
+
detail: stored.error || kept,
|
|
6680
|
+
class: "FILE_PREVIEW_MEDIA"
|
|
6681
|
+
});
|
|
6682
|
+
}
|
|
6683
|
+
if ($media) $preview.appendChild($media);
|
|
6684
|
+
$preview.hidden = !$media;
|
|
6368
6685
|
};
|
|
6369
6686
|
if (!readonly) {
|
|
6370
6687
|
$pick.addEventListener("click", () => {
|
|
@@ -6393,120 +6710,6 @@ function yui_file_control(gobj, { name, value, readonly, accept, on_pick }) {
|
|
|
6393
6710
|
};
|
|
6394
6711
|
}
|
|
6395
6712
|
//#endregion
|
|
6396
|
-
//#region src/yui_asset.js
|
|
6397
|
-
function ref_to_id(ref) {
|
|
6398
|
-
if (!ref) return null;
|
|
6399
|
-
if (typeof ref === "string") {
|
|
6400
|
-
if (ref.indexOf("^") < 0) return ref;
|
|
6401
|
-
const parts = ref.split("^");
|
|
6402
|
-
return parts.length >= 2 && parts[1] ? parts[1] : null;
|
|
6403
|
-
}
|
|
6404
|
-
if (typeof ref === "object" && typeof ref.id === "string") return ref.id;
|
|
6405
|
-
return null;
|
|
6406
|
-
}
|
|
6407
|
-
/***************************************************************************
|
|
6408
|
-
* Every asset id a column names, in order. Always an array, possibly empty.
|
|
6409
|
-
***************************************************************************/
|
|
6410
|
-
function yui_asset_ids(ref) {
|
|
6411
|
-
if (Array.isArray(ref)) return ref.map(ref_to_id).filter((id) => !!id);
|
|
6412
|
-
const id = ref_to_id(ref);
|
|
6413
|
-
return id ? [id] : [];
|
|
6414
|
-
}
|
|
6415
|
-
/***************************************************************************
|
|
6416
|
-
* The first asset id a column names, or null.
|
|
6417
|
-
***************************************************************************/
|
|
6418
|
-
function yui_asset_id(ref) {
|
|
6419
|
-
const ids = yui_asset_ids(ref);
|
|
6420
|
-
return ids.length ? ids[0] : null;
|
|
6421
|
-
}
|
|
6422
|
-
/***************************************************************************
|
|
6423
|
-
* Turn a `get-asset` answer into something an element can load.
|
|
6424
|
-
*
|
|
6425
|
-
* Returns null when the answer carries neither -- which the caller must
|
|
6426
|
-
* treat as "missing", never as an empty src: an <img src=""> reloads the
|
|
6427
|
-
* PAGE in some browsers.
|
|
6428
|
-
***************************************************************************/
|
|
6429
|
-
function yui_asset_src(answer) {
|
|
6430
|
-
if (!answer) return null;
|
|
6431
|
-
if (answer.mode === "url" && answer.url) return answer.url;
|
|
6432
|
-
if (answer.mode === "inline" && answer.content64) return `data:${answer.content_type || "application/octet-stream"};base64,${answer.content64}`;
|
|
6433
|
-
return null;
|
|
6434
|
-
}
|
|
6435
|
-
/***************************************************************************
|
|
6436
|
-
* The marker for an asset that is not there.
|
|
6437
|
-
*
|
|
6438
|
-
* A missing image used to leave a broken box and no word about it, which
|
|
6439
|
-
* is indistinguishable from a slow one and from a bug. This says so, and
|
|
6440
|
-
* it says WHICH: `detail` is data (a name, a path) and is never
|
|
6441
|
-
* translated, while the label carries its i18n key so a language change
|
|
6442
|
-
* re-translates it.
|
|
6443
|
-
***************************************************************************/
|
|
6444
|
-
function yui_asset_missing(detail, opts = {}) {
|
|
6445
|
-
const key = opts.key || "asset not available";
|
|
6446
|
-
const children = [["span", { class: "ASSET_MISSING_ICON yi-triangle-exclamation" }], [
|
|
6447
|
-
"span",
|
|
6448
|
-
{
|
|
6449
|
-
class: "ASSET_MISSING_LABEL",
|
|
6450
|
-
i18n: key
|
|
6451
|
-
},
|
|
6452
|
-
key
|
|
6453
|
-
]];
|
|
6454
|
-
if (detail) children.push([
|
|
6455
|
-
"span",
|
|
6456
|
-
{ class: "ASSET_MISSING_DETAIL" },
|
|
6457
|
-
String(detail)
|
|
6458
|
-
]);
|
|
6459
|
-
const attrs = { class: `ASSET_MISSING ${opts.class || ""}`.trim() };
|
|
6460
|
-
if (detail) attrs.title = String(detail);
|
|
6461
|
-
else attrs["data-i18n-title"] = key;
|
|
6462
|
-
return (0, _yuneta_gobj_js.createElement2)([
|
|
6463
|
-
"div",
|
|
6464
|
-
attrs,
|
|
6465
|
-
children
|
|
6466
|
-
]);
|
|
6467
|
-
}
|
|
6468
|
-
/***************************************************************************
|
|
6469
|
-
* The element for one asset.
|
|
6470
|
-
*
|
|
6471
|
-
* The KIND comes from the content type the backend stored, not from the
|
|
6472
|
-
* name a person typed: video and audio are assets too, and an <img> whose
|
|
6473
|
-
* src is a film shows the broken box this module exists to remove.
|
|
6474
|
-
*
|
|
6475
|
-
* `detail` is what the missing marker shows -- pass the original name or
|
|
6476
|
-
* the source path, the thing a person can act on.
|
|
6477
|
-
***************************************************************************/
|
|
6478
|
-
function yui_asset_element(answer, opts = {}) {
|
|
6479
|
-
const src = yui_asset_src(answer);
|
|
6480
|
-
if (!src) return yui_asset_missing(opts.detail, opts);
|
|
6481
|
-
const ct = (answer.content_type || "").toLowerCase();
|
|
6482
|
-
const cls = `ASSET_MEDIA ${opts.class || ""}`.trim();
|
|
6483
|
-
let el;
|
|
6484
|
-
if (ct.startsWith("video/")) el = (0, _yuneta_gobj_js.createElement2)(["video", {
|
|
6485
|
-
class: cls,
|
|
6486
|
-
controls: "",
|
|
6487
|
-
preload: "metadata"
|
|
6488
|
-
}]);
|
|
6489
|
-
else if (ct.startsWith("audio/")) el = (0, _yuneta_gobj_js.createElement2)(["audio", {
|
|
6490
|
-
class: cls,
|
|
6491
|
-
controls: "",
|
|
6492
|
-
preload: "metadata"
|
|
6493
|
-
}]);
|
|
6494
|
-
else {
|
|
6495
|
-
el = (0, _yuneta_gobj_js.createElement2)(["img", {
|
|
6496
|
-
class: cls,
|
|
6497
|
-
loading: "lazy"
|
|
6498
|
-
}]);
|
|
6499
|
-
el.alt = opts.alt || opts.detail || "";
|
|
6500
|
-
}
|
|
6501
|
-
el.src = src;
|
|
6502
|
-
el.onerror = () => {
|
|
6503
|
-
(0, _yuneta_gobj_js.log_error)(`asset could not be loaded: ${opts.detail || src}`);
|
|
6504
|
-
const $marker = yui_asset_missing(opts.detail, opts);
|
|
6505
|
-
if (el.parentNode) el.parentNode.replaceChild($marker, el);
|
|
6506
|
-
};
|
|
6507
|
-
return el;
|
|
6508
|
-
}
|
|
6509
|
-
//#endregion
|
|
6510
6713
|
//#region src/yui_inputs.js
|
|
6511
6714
|
/***************************************************************
|
|
6512
6715
|
* The ✕ shows only when there is something to clear AND the field
|
|
@@ -7176,6 +7379,7 @@ function mt_create$17(gobj) {
|
|
|
7176
7379
|
* and subscriptions are already deleted.
|
|
7177
7380
|
************************************************************/
|
|
7178
7381
|
function mt_destroy$17(gobj) {
|
|
7382
|
+
yui_asset_release((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"));
|
|
7179
7383
|
destroy_ui$10(gobj);
|
|
7180
7384
|
}
|
|
7181
7385
|
/************************************************************
|
|
@@ -9324,6 +9528,43 @@ function ac_clear_record(gobj, event, kw, src) {
|
|
|
9324
9528
|
return 0;
|
|
9325
9529
|
}
|
|
9326
9530
|
/************************************************************
|
|
9531
|
+
* From the host: what it fetched for the asset a `file` column
|
|
9532
|
+
* names -- the `get-asset` answer, or why there is none.
|
|
9533
|
+
* {
|
|
9534
|
+
* name: the column
|
|
9535
|
+
* id: the asset id the answer is for
|
|
9536
|
+
* answer: the get-asset answer, or null
|
|
9537
|
+
* error: why there is no answer, when there is none
|
|
9538
|
+
* }
|
|
9539
|
+
*
|
|
9540
|
+
* Kept on the control and drawn only while the column still names
|
|
9541
|
+
* THAT id: an answer landing after the person picked another file
|
|
9542
|
+
* or cleared the column must not bring the old picture back.
|
|
9543
|
+
************************************************************/
|
|
9544
|
+
function ac_set_file_preview(gobj, event, kw, src) {
|
|
9545
|
+
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
9546
|
+
let $form = $container ? $container.querySelector("form") : null;
|
|
9547
|
+
if (!$form) {
|
|
9548
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no form to show the file preview in`);
|
|
9549
|
+
return -1;
|
|
9550
|
+
}
|
|
9551
|
+
let $file = null;
|
|
9552
|
+
$form.querySelectorAll(".FILE_FIELD").forEach(($el) => {
|
|
9553
|
+
if ($el.dataset.treedb_name === kw.name) $file = $el;
|
|
9554
|
+
});
|
|
9555
|
+
if (!$file) {
|
|
9556
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no file column '${kw.name}' in the form`);
|
|
9557
|
+
return -1;
|
|
9558
|
+
}
|
|
9559
|
+
$file.yui_file_stored = {
|
|
9560
|
+
id: kw.id || "",
|
|
9561
|
+
answer: kw.answer || null,
|
|
9562
|
+
error: kw.error || ""
|
|
9563
|
+
};
|
|
9564
|
+
if ($file.yui_file_render) $file.yui_file_render();
|
|
9565
|
+
return 0;
|
|
9566
|
+
}
|
|
9567
|
+
/************************************************************
|
|
9327
9568
|
* From internal form button for new rows
|
|
9328
9569
|
* or from load_tabulator_data() to load data from backend
|
|
9329
9570
|
************************************************************/
|
|
@@ -9517,6 +9758,11 @@ function create_gclass$17(gclass_name) {
|
|
|
9517
9758
|
ac_paste_record,
|
|
9518
9759
|
null
|
|
9519
9760
|
],
|
|
9761
|
+
[
|
|
9762
|
+
"EV_SET_FILE_PREVIEW",
|
|
9763
|
+
ac_set_file_preview,
|
|
9764
|
+
null
|
|
9765
|
+
],
|
|
9520
9766
|
[
|
|
9521
9767
|
"EV_WINDOW_MOVED",
|
|
9522
9768
|
null,
|
|
@@ -9562,6 +9808,7 @@ function create_gclass$17(gclass_name) {
|
|
|
9562
9808
|
["EV_RECORD_CHANGED", 0],
|
|
9563
9809
|
["EV_COPY_RECORD", 0],
|
|
9564
9810
|
["EV_PASTE_RECORD", 0],
|
|
9811
|
+
["EV_SET_FILE_PREVIEW", 0],
|
|
9565
9812
|
["EV_WINDOW_MOVED", 0],
|
|
9566
9813
|
["EV_WINDOW_RESIZED", 0],
|
|
9567
9814
|
["EV_WINDOW_TO_CLOSE", 0],
|
|
@@ -11258,6 +11505,64 @@ function yui_graph_camera_behaviors() {
|
|
|
11258
11505
|
}];
|
|
11259
11506
|
}
|
|
11260
11507
|
/************************************************************
|
|
11508
|
+
* Make the wheel work over HTML nodes too.
|
|
11509
|
+
*
|
|
11510
|
+
* G6's HTML nodes live in a DOM layer BESIDE the canvas
|
|
11511
|
+
* element, not in it, and they forward six pointer events and
|
|
11512
|
+
* not the wheel. `scroll-canvas` listens on the canvas element
|
|
11513
|
+
* and `zoom-canvas` reads G's own wheel event, which is fed
|
|
11514
|
+
* from that same element -- so a wheel over a card reaches
|
|
11515
|
+
* neither, and on a graph drawn with big cards the wheel only
|
|
11516
|
+
* works in the gaps between them.
|
|
11517
|
+
*
|
|
11518
|
+
* The wheel is caught on `$host` (the element G6 was mounted
|
|
11519
|
+
* in) and dispatched again ON the canvas element, carrying the
|
|
11520
|
+
* deltas, the position and the modifiers: both behaviors then
|
|
11521
|
+
* take it exactly as a wheel over empty canvas. Control is
|
|
11522
|
+
* read by G6 from the real keydown, which is still held.
|
|
11523
|
+
*
|
|
11524
|
+
* A wheel whose target is the canvas passes untouched, which
|
|
11525
|
+
* is also what keeps the re-dispatched one from looping. An
|
|
11526
|
+
* element that must scroll by itself (a popover) stops the
|
|
11527
|
+
* wheel before it gets here.
|
|
11528
|
+
*
|
|
11529
|
+
* Returns the function that removes the listener.
|
|
11530
|
+
************************************************************/
|
|
11531
|
+
function yui_graph_forward_wheel(graph, $host) {
|
|
11532
|
+
if (!graph || !$host) return () => {};
|
|
11533
|
+
const on_wheel = (e) => {
|
|
11534
|
+
let dom = null;
|
|
11535
|
+
try {
|
|
11536
|
+
dom = graph.getCanvas().getContextService().getDomElement();
|
|
11537
|
+
} catch (err) {
|
|
11538
|
+
return;
|
|
11539
|
+
}
|
|
11540
|
+
if (!dom || e.target === dom) return;
|
|
11541
|
+
e.preventDefault();
|
|
11542
|
+
e.stopPropagation();
|
|
11543
|
+
dom.dispatchEvent(new WheelEvent("wheel", {
|
|
11544
|
+
deltaX: e.deltaX,
|
|
11545
|
+
deltaY: e.deltaY,
|
|
11546
|
+
deltaZ: e.deltaZ,
|
|
11547
|
+
deltaMode: e.deltaMode,
|
|
11548
|
+
clientX: e.clientX,
|
|
11549
|
+
clientY: e.clientY,
|
|
11550
|
+
screenX: e.screenX,
|
|
11551
|
+
screenY: e.screenY,
|
|
11552
|
+
ctrlKey: e.ctrlKey,
|
|
11553
|
+
shiftKey: e.shiftKey,
|
|
11554
|
+
altKey: e.altKey,
|
|
11555
|
+
metaKey: e.metaKey,
|
|
11556
|
+
bubbles: true,
|
|
11557
|
+
cancelable: true
|
|
11558
|
+
}));
|
|
11559
|
+
};
|
|
11560
|
+
$host.addEventListener("wheel", on_wheel, { passive: false });
|
|
11561
|
+
return () => {
|
|
11562
|
+
$host.removeEventListener("wheel", on_wheel);
|
|
11563
|
+
};
|
|
11564
|
+
}
|
|
11565
|
+
/************************************************************
|
|
11261
11566
|
* The camera cluster: zoom in, zoom out, readout, fit,
|
|
11262
11567
|
* actual size. Returns createElement2 specs, in order.
|
|
11263
11568
|
*
|
|
@@ -13319,7 +13624,7 @@ function ac_toggle_anchor$2(gobj, event, kw, src) {
|
|
|
13319
13624
|
/************************************************************
|
|
13320
13625
|
*
|
|
13321
13626
|
************************************************************/
|
|
13322
|
-
function ac_zoom_in$
|
|
13627
|
+
function ac_zoom_in$4(gobj, event, kw, src) {
|
|
13323
13628
|
let graph = gobj.priv.graph;
|
|
13324
13629
|
if (graph) {
|
|
13325
13630
|
let z = graph.getZoom();
|
|
@@ -13330,7 +13635,7 @@ function ac_zoom_in$3(gobj, event, kw, src) {
|
|
|
13330
13635
|
/************************************************************
|
|
13331
13636
|
*
|
|
13332
13637
|
************************************************************/
|
|
13333
|
-
function ac_zoom_out$
|
|
13638
|
+
function ac_zoom_out$4(gobj, event, kw, src) {
|
|
13334
13639
|
let graph = gobj.priv.graph;
|
|
13335
13640
|
if (graph) {
|
|
13336
13641
|
let z = graph.getZoom();
|
|
@@ -13341,7 +13646,7 @@ function ac_zoom_out$3(gobj, event, kw, src) {
|
|
|
13341
13646
|
/************************************************************
|
|
13342
13647
|
*
|
|
13343
13648
|
************************************************************/
|
|
13344
|
-
function ac_zoom_reset$
|
|
13649
|
+
function ac_zoom_reset$4(gobj, event, kw, src) {
|
|
13345
13650
|
let priv = gobj.priv;
|
|
13346
13651
|
let graph = priv.graph;
|
|
13347
13652
|
if (graph && graph.rendered) {
|
|
@@ -13356,7 +13661,7 @@ function ac_zoom_reset$3(gobj, event, kw, src) {
|
|
|
13356
13661
|
/************************************************************
|
|
13357
13662
|
*
|
|
13358
13663
|
************************************************************/
|
|
13359
|
-
function ac_center$
|
|
13664
|
+
function ac_center$4(gobj, event, kw, src) {
|
|
13360
13665
|
let graph = gobj.priv.graph;
|
|
13361
13666
|
if (graph) {
|
|
13362
13667
|
graph.fitCenter();
|
|
@@ -13492,22 +13797,22 @@ function create_gclass$14(gclass_name) {
|
|
|
13492
13797
|
],
|
|
13493
13798
|
[
|
|
13494
13799
|
"EV_ZOOM_IN",
|
|
13495
|
-
ac_zoom_in$
|
|
13800
|
+
ac_zoom_in$4,
|
|
13496
13801
|
null
|
|
13497
13802
|
],
|
|
13498
13803
|
[
|
|
13499
13804
|
"EV_ZOOM_OUT",
|
|
13500
|
-
ac_zoom_out$
|
|
13805
|
+
ac_zoom_out$4,
|
|
13501
13806
|
null
|
|
13502
13807
|
],
|
|
13503
13808
|
[
|
|
13504
13809
|
"EV_ZOOM_RESET",
|
|
13505
|
-
ac_zoom_reset$
|
|
13810
|
+
ac_zoom_reset$4,
|
|
13506
13811
|
null
|
|
13507
13812
|
],
|
|
13508
13813
|
[
|
|
13509
13814
|
"EV_CENTER",
|
|
13510
|
-
ac_center$
|
|
13815
|
+
ac_center$4,
|
|
13511
13816
|
null
|
|
13512
13817
|
],
|
|
13513
13818
|
[
|
|
@@ -16604,16 +16909,16 @@ function ac_language_changed$7(gobj, event, kw, src) {
|
|
|
16604
16909
|
/************************************************************
|
|
16605
16910
|
* The camera.
|
|
16606
16911
|
************************************************************/
|
|
16607
|
-
function ac_zoom_in$
|
|
16912
|
+
function ac_zoom_in$3(gobj, event, kw, src) {
|
|
16608
16913
|
return camera(gobj, "zoom in", (graph) => graph.zoomBy(1.2));
|
|
16609
16914
|
}
|
|
16610
|
-
function ac_zoom_out$
|
|
16915
|
+
function ac_zoom_out$3(gobj, event, kw, src) {
|
|
16611
16916
|
return camera(gobj, "zoom out", (graph) => graph.zoomBy(1 / 1.2));
|
|
16612
16917
|
}
|
|
16613
|
-
function ac_zoom_reset$
|
|
16918
|
+
function ac_zoom_reset$3(gobj, event, kw, src) {
|
|
16614
16919
|
return camera(gobj, "reset the zoom", (graph) => graph.zoomTo(1));
|
|
16615
16920
|
}
|
|
16616
|
-
function ac_center$
|
|
16921
|
+
function ac_center$3(gobj, event, kw, src) {
|
|
16617
16922
|
return camera(gobj, "fit the graph", (graph) => fit_readable(graph));
|
|
16618
16923
|
}
|
|
16619
16924
|
/************************************************************
|
|
@@ -16672,22 +16977,22 @@ function create_gclass$11(gclass_name) {
|
|
|
16672
16977
|
],
|
|
16673
16978
|
[
|
|
16674
16979
|
"EV_ZOOM_IN",
|
|
16675
|
-
ac_zoom_in$
|
|
16980
|
+
ac_zoom_in$3,
|
|
16676
16981
|
null
|
|
16677
16982
|
],
|
|
16678
16983
|
[
|
|
16679
16984
|
"EV_ZOOM_OUT",
|
|
16680
|
-
ac_zoom_out$
|
|
16985
|
+
ac_zoom_out$3,
|
|
16681
16986
|
null
|
|
16682
16987
|
],
|
|
16683
16988
|
[
|
|
16684
16989
|
"EV_ZOOM_RESET",
|
|
16685
|
-
ac_zoom_reset$
|
|
16990
|
+
ac_zoom_reset$3,
|
|
16686
16991
|
null
|
|
16687
16992
|
],
|
|
16688
16993
|
[
|
|
16689
16994
|
"EV_CENTER",
|
|
16690
|
-
ac_center$
|
|
16995
|
+
ac_center$3,
|
|
16691
16996
|
null
|
|
16692
16997
|
],
|
|
16693
16998
|
[
|
|
@@ -20795,7 +21100,7 @@ function ac_toggle_anchor$1(gobj, event, kw, src) {
|
|
|
20795
21100
|
/************************************************************
|
|
20796
21101
|
*
|
|
20797
21102
|
************************************************************/
|
|
20798
|
-
function ac_zoom_in$
|
|
21103
|
+
function ac_zoom_in$2(gobj, event, kw, src) {
|
|
20799
21104
|
let graph = gobj.priv.graph;
|
|
20800
21105
|
if (graph) {
|
|
20801
21106
|
let z = graph.getZoom();
|
|
@@ -20806,7 +21111,7 @@ function ac_zoom_in$1(gobj, event, kw, src) {
|
|
|
20806
21111
|
/************************************************************
|
|
20807
21112
|
*
|
|
20808
21113
|
************************************************************/
|
|
20809
|
-
function ac_zoom_out$
|
|
21114
|
+
function ac_zoom_out$2(gobj, event, kw, src) {
|
|
20810
21115
|
let graph = gobj.priv.graph;
|
|
20811
21116
|
if (graph) {
|
|
20812
21117
|
let z = graph.getZoom();
|
|
@@ -20817,7 +21122,7 @@ function ac_zoom_out$1(gobj, event, kw, src) {
|
|
|
20817
21122
|
/************************************************************
|
|
20818
21123
|
*
|
|
20819
21124
|
************************************************************/
|
|
20820
|
-
function ac_zoom_reset$
|
|
21125
|
+
function ac_zoom_reset$2(gobj, event, kw, src) {
|
|
20821
21126
|
let priv = gobj.priv;
|
|
20822
21127
|
let graph = priv.graph;
|
|
20823
21128
|
if (graph && graph.rendered) {
|
|
@@ -20832,7 +21137,7 @@ function ac_zoom_reset$1(gobj, event, kw, src) {
|
|
|
20832
21137
|
/************************************************************
|
|
20833
21138
|
*
|
|
20834
21139
|
************************************************************/
|
|
20835
|
-
function ac_center$
|
|
21140
|
+
function ac_center$2(gobj, event, kw, src) {
|
|
20836
21141
|
let graph = gobj.priv.graph;
|
|
20837
21142
|
if (graph) {
|
|
20838
21143
|
graph.fitCenter();
|
|
@@ -21038,22 +21343,22 @@ function create_gclass$9(gclass_name) {
|
|
|
21038
21343
|
],
|
|
21039
21344
|
[
|
|
21040
21345
|
"EV_ZOOM_IN",
|
|
21041
|
-
ac_zoom_in$
|
|
21346
|
+
ac_zoom_in$2,
|
|
21042
21347
|
null
|
|
21043
21348
|
],
|
|
21044
21349
|
[
|
|
21045
21350
|
"EV_ZOOM_OUT",
|
|
21046
|
-
ac_zoom_out$
|
|
21351
|
+
ac_zoom_out$2,
|
|
21047
21352
|
null
|
|
21048
21353
|
],
|
|
21049
21354
|
[
|
|
21050
21355
|
"EV_ZOOM_RESET",
|
|
21051
|
-
ac_zoom_reset$
|
|
21356
|
+
ac_zoom_reset$2,
|
|
21052
21357
|
null
|
|
21053
21358
|
],
|
|
21054
21359
|
[
|
|
21055
21360
|
"EV_CENTER",
|
|
21056
|
-
ac_center$
|
|
21361
|
+
ac_center$2,
|
|
21057
21362
|
null
|
|
21058
21363
|
],
|
|
21059
21364
|
[
|
|
@@ -22759,6 +23064,7 @@ var attrs_table$6 = [
|
|
|
22759
23064
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "subscriber", 0, null, "Subscriber of output events"),
|
|
22760
23065
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "gobj_remote_yuno", 0, null, "Remote yuno for data fetching"),
|
|
22761
23066
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote TreeDB service name"),
|
|
23067
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "assets_service", 0, "assets", "Remote service that answers `get-asset` (a C_ASSETS) for the bytes of the treedb's `file` columns: the form's preview and the table's file popup ask it. Empty: nothing is asked, and a file cell opens a marker saying the asset is not available"),
|
|
22762
23068
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "descs", 0, null, "Description of topics"),
|
|
22763
23069
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_remote_paging", 0, false, "Each topic table pulls its rows a PAGE at a time (`nodes` from/limit) instead of loading the topic whole. ⚠️ DO NOT TURN THIS ON: a partial topic BREAKS LINKING -- the link picker of a record is built from the rows the PARENT topic's table holds, which with paging is one page, so the right parent is usually not offered and an existing link the form cannot match is dropped on save. Off in every consumer until linking asks the backend instead of the sibling table"),
|
|
22764
23070
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_INTEGER, "page_size", 0, 0, "Rows per page of each topic table (the DISPLAY; the fetch is whole). 0 leaves the table's own default"),
|
|
@@ -24078,6 +24384,24 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
24078
24384
|
else (0, _yuneta_gobj_js.gobj_send_event)(jv, "EV_SET_JSON", { json: data }, gobj);
|
|
24079
24385
|
return 0;
|
|
24080
24386
|
}
|
|
24387
|
+
if (command === "get-asset") {
|
|
24388
|
+
let asset_topic = (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0);
|
|
24389
|
+
let req_id = (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "req_id", "", 0);
|
|
24390
|
+
let gobj_topic_form = (0, _yuneta_gobj_js.gobj_find_child)(gobj, { __gobj_name__: `${(0, _yuneta_gobj_js.gobj_name)(gobj)}?${asset_topic}` });
|
|
24391
|
+
if (!gobj_topic_form || !req_id) {
|
|
24392
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: get-asset answer for nobody: topic '${asset_topic}', req_id '${req_id}'`);
|
|
24393
|
+
return 0;
|
|
24394
|
+
}
|
|
24395
|
+
if (result < 0) (0, _yuneta_gobj_js.gobj_send_event)(gobj_topic_form, "EV_ASSET_FAILED", {
|
|
24396
|
+
req_id,
|
|
24397
|
+
error: comment || "get-asset failed"
|
|
24398
|
+
}, gobj);
|
|
24399
|
+
else (0, _yuneta_gobj_js.gobj_send_event)(gobj_topic_form, "EV_ASSET_LOADED", {
|
|
24400
|
+
req_id,
|
|
24401
|
+
answer: data
|
|
24402
|
+
}, gobj);
|
|
24403
|
+
return 0;
|
|
24404
|
+
}
|
|
24081
24405
|
if (result < 0) {
|
|
24082
24406
|
if (command === "descs") show_load_error$1(gobj, (0, i18next.t)(comment));
|
|
24083
24407
|
else {
|
|
@@ -24359,6 +24683,48 @@ function ac_request_page(gobj, event, kw, src) {
|
|
|
24359
24683
|
return 0;
|
|
24360
24684
|
}
|
|
24361
24685
|
/********************************************
|
|
24686
|
+
* Event from formtable: the bytes of one asset a `file` column names,
|
|
24687
|
+
* for the form's preview or the table's file popup.
|
|
24688
|
+
*
|
|
24689
|
+
* Asked to the ASSETS service and not to the treedb: storing is the
|
|
24690
|
+
* treedb's, the way out is C_ASSETS's (a signed url when a web server
|
|
24691
|
+
* sits in front of the store, the bytes inline when there is none). The
|
|
24692
|
+
* answer goes back down to the table that asked, by `req_id`.
|
|
24693
|
+
*
|
|
24694
|
+
* A read: a read-only treedb still answers it.
|
|
24695
|
+
********************************************/
|
|
24696
|
+
function ac_request_asset(gobj, event, kw, src) {
|
|
24697
|
+
if (!kw.req_id || !kw.asset_id) {
|
|
24698
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: an asset request with no id`);
|
|
24699
|
+
return -1;
|
|
24700
|
+
}
|
|
24701
|
+
let assets_service = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "assets_service");
|
|
24702
|
+
let gobj_remote_yuno = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "gobj_remote_yuno");
|
|
24703
|
+
if (!assets_service || !gobj_remote_yuno) {
|
|
24704
|
+
(0, _yuneta_gobj_js.gobj_send_event)(src, "EV_ASSET_FAILED", {
|
|
24705
|
+
req_id: kw.req_id,
|
|
24706
|
+
error: assets_service ? "cannot reach the backend" : "no assets service"
|
|
24707
|
+
}, gobj);
|
|
24708
|
+
return 0;
|
|
24709
|
+
}
|
|
24710
|
+
let ret = (0, _yuneta_gobj_js.gobj_command)(gobj_remote_yuno, "get-asset", {
|
|
24711
|
+
service: assets_service,
|
|
24712
|
+
asset_id: kw.asset_id,
|
|
24713
|
+
__md_command__: {
|
|
24714
|
+
topic_name: kw.topic_name || (0, _yuneta_gobj_js.gobj_read_attr)(src, "topic_name"),
|
|
24715
|
+
req_id: kw.req_id
|
|
24716
|
+
}
|
|
24717
|
+
}, gobj);
|
|
24718
|
+
if (ret) {
|
|
24719
|
+
(0, _yuneta_gobj_js.log_error)(ret);
|
|
24720
|
+
(0, _yuneta_gobj_js.gobj_send_event)(src, "EV_ASSET_FAILED", {
|
|
24721
|
+
req_id: kw.req_id,
|
|
24722
|
+
error: "cannot reach the backend"
|
|
24723
|
+
}, gobj);
|
|
24724
|
+
}
|
|
24725
|
+
return 0;
|
|
24726
|
+
}
|
|
24727
|
+
/********************************************
|
|
24362
24728
|
* Event from formtable: ONE field of one record, edited in place.
|
|
24363
24729
|
*
|
|
24364
24730
|
* Written as a PARTIAL update and, deliberately, with NO `autolink`.
|
|
@@ -24544,6 +24910,11 @@ function create_gclass$6(gclass_name) {
|
|
|
24544
24910
|
ac_request_page,
|
|
24545
24911
|
null
|
|
24546
24912
|
],
|
|
24913
|
+
[
|
|
24914
|
+
"EV_REQUEST_ASSET",
|
|
24915
|
+
ac_request_asset,
|
|
24916
|
+
null
|
|
24917
|
+
],
|
|
24547
24918
|
[
|
|
24548
24919
|
"EV_DELETE_RECORD",
|
|
24549
24920
|
ac_delete_record,
|
|
@@ -24624,6 +24995,7 @@ function create_gclass$6(gclass_name) {
|
|
|
24624
24995
|
["EV_UPDATE_RECORD", 0],
|
|
24625
24996
|
["EV_UPDATE_FIELD", 0],
|
|
24626
24997
|
["EV_REQUEST_PAGE", 0],
|
|
24998
|
+
["EV_REQUEST_ASSET", 0],
|
|
24627
24999
|
["EV_DELETE_RECORD", 0],
|
|
24628
25000
|
["EV_RECORD_WRITTEN", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT | _yuneta_gobj_js.event_flag_t.EVF_NO_WARN_SUBS],
|
|
24629
25001
|
["EV_REFRESH_TOPIC", 0],
|
|
@@ -25429,7 +25801,12 @@ var PRIVATE_DATA$5 = {
|
|
|
25429
25801
|
schema_win: null,
|
|
25430
25802
|
cell_json_gobj: null,
|
|
25431
25803
|
cell_json_modal: null,
|
|
25432
|
-
cell_json_win: null
|
|
25804
|
+
cell_json_win: null,
|
|
25805
|
+
cell_file_box: null,
|
|
25806
|
+
cell_file_modal: null,
|
|
25807
|
+
cell_file_win: null,
|
|
25808
|
+
_pending_assets: null,
|
|
25809
|
+
_asset_seq: 0
|
|
25433
25810
|
};
|
|
25434
25811
|
var __gclass__$5 = null;
|
|
25435
25812
|
function is_mobile$1() {
|
|
@@ -25562,6 +25939,8 @@ function mt_stop$5(gobj) {
|
|
|
25562
25939
|
close_form_dialog(gobj);
|
|
25563
25940
|
close_schema_dialog(gobj);
|
|
25564
25941
|
close_cell_json_dialog(gobj);
|
|
25942
|
+
close_cell_file_dialog(gobj);
|
|
25943
|
+
drop_pending_assets(gobj);
|
|
25565
25944
|
table__destroy(gobj);
|
|
25566
25945
|
}
|
|
25567
25946
|
/***************************************************************
|
|
@@ -25571,6 +25950,8 @@ function mt_destroy$5(gobj) {
|
|
|
25571
25950
|
close_form_dialog(gobj);
|
|
25572
25951
|
close_schema_dialog(gobj);
|
|
25573
25952
|
close_cell_json_dialog(gobj);
|
|
25953
|
+
close_cell_file_dialog(gobj);
|
|
25954
|
+
drop_pending_assets(gobj);
|
|
25574
25955
|
destroy_ui$2(gobj);
|
|
25575
25956
|
}
|
|
25576
25957
|
/************************************************************
|
|
@@ -26215,6 +26596,20 @@ function create_tabulator(gobj) {
|
|
|
26215
26596
|
break;
|
|
26216
26597
|
case "file":
|
|
26217
26598
|
colFormatter = file_cell_formatter;
|
|
26599
|
+
cellClick = function(e, cell) {
|
|
26600
|
+
if (!e.target.closest(".FILE_CELL_LINK")) return;
|
|
26601
|
+
e.stopPropagation();
|
|
26602
|
+
let pkey = desc.pkey || "id";
|
|
26603
|
+
let row_id = cell.getData()[pkey];
|
|
26604
|
+
if (row_id === void 0 || row_id === null) {
|
|
26605
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: row without pkey '${pkey}', cannot open the file of '${cell.getField()}'`);
|
|
26606
|
+
return;
|
|
26607
|
+
}
|
|
26608
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SHOW_CELL_FILE", {
|
|
26609
|
+
row_id,
|
|
26610
|
+
col_id: cell.getField()
|
|
26611
|
+
}, gobj);
|
|
26612
|
+
};
|
|
26218
26613
|
break;
|
|
26219
26614
|
case "object":
|
|
26220
26615
|
case "dict":
|
|
@@ -26485,13 +26880,21 @@ function table__destroy(gobj) {
|
|
|
26485
26880
|
* What a `file` column shows in a table cell: the asset it names.
|
|
26486
26881
|
*
|
|
26487
26882
|
* A sha256 in full is 64 characters of noise in a column, so it is
|
|
26488
|
-
* shortened and the whole of it
|
|
26489
|
-
* blank -- a blank cell and a cell whose asset failed
|
|
26490
|
-
* same, and only one of them is normal.
|
|
26883
|
+
* shortened and the whole of it goes to the popup the click opens. Empty
|
|
26884
|
+
* is SAID, not left blank -- a blank cell and a cell whose asset failed
|
|
26885
|
+
* to load look the same, and only one of them is normal.
|
|
26886
|
+
*
|
|
26887
|
+
* The value arrives already turned into ids joined by ", "
|
|
26888
|
+
* (transform__treedb_value_2_table_value), and an array column names
|
|
26889
|
+
* several: the first is shown and the rest counted.
|
|
26491
26890
|
************************************************************/
|
|
26891
|
+
function file_cell_ids(value) {
|
|
26892
|
+
if ((0, _yuneta_gobj_js.is_array)(value)) return yui_asset_ids(value);
|
|
26893
|
+
return String(value || "").split(",").map((s) => s.trim()).filter((s) => !!s).flatMap((s) => yui_asset_ids(s));
|
|
26894
|
+
}
|
|
26492
26895
|
function file_cell_formatter(cell, formatterParams, onRendered) {
|
|
26493
|
-
const
|
|
26494
|
-
if (!
|
|
26896
|
+
const ids = file_cell_ids(cell.getValue());
|
|
26897
|
+
if (!ids.length) return (0, _yuneta_gobj_js.createElement2)([
|
|
26495
26898
|
"span",
|
|
26496
26899
|
{
|
|
26497
26900
|
class: "FILE_CELL is-empty",
|
|
@@ -26499,13 +26902,26 @@ function file_cell_formatter(cell, formatterParams, onRendered) {
|
|
|
26499
26902
|
},
|
|
26500
26903
|
"no file"
|
|
26501
26904
|
]);
|
|
26502
|
-
|
|
26905
|
+
const children = [["span", { class: "FILE_CELL_ICON icon yi-eye" }], [
|
|
26503
26906
|
"span",
|
|
26907
|
+
{ class: "FILE_CELL_ID" },
|
|
26908
|
+
yui_file_id_label(ids[0])
|
|
26909
|
+
]];
|
|
26910
|
+
if (ids.length > 1) children.push([
|
|
26911
|
+
"span",
|
|
26912
|
+
{ class: "FILE_CELL_MORE" },
|
|
26913
|
+
`+${ids.length - 1}`
|
|
26914
|
+
]);
|
|
26915
|
+
return (0, _yuneta_gobj_js.createElement2)([
|
|
26916
|
+
"a",
|
|
26504
26917
|
{
|
|
26505
|
-
class: "FILE_CELL",
|
|
26506
|
-
title:
|
|
26918
|
+
class: "FILE_CELL FILE_CELL_LINK",
|
|
26919
|
+
title: (0, i18next.t)("show file"),
|
|
26920
|
+
"data-i18n-title": "show file",
|
|
26921
|
+
"aria-label": (0, i18next.t)("show file"),
|
|
26922
|
+
"data-i18n-aria-label": "show file"
|
|
26507
26923
|
},
|
|
26508
|
-
|
|
26924
|
+
children
|
|
26509
26925
|
]);
|
|
26510
26926
|
}
|
|
26511
26927
|
function icon_formatter(cell) {
|
|
@@ -26769,6 +27185,7 @@ function open_form_dialog(gobj, mode, record) {
|
|
|
26769
27185
|
});
|
|
26770
27186
|
(0, _yuneta_gobj_js.gobj_start)(form);
|
|
26771
27187
|
(0, _yuneta_gobj_js.refresh_language)($body, i18next.t);
|
|
27188
|
+
request_form_previews(gobj, record);
|
|
26772
27189
|
let $with_focus = $body.querySelector(".with-focus:not([readonly])");
|
|
26773
27190
|
if (!$with_focus) $with_focus = $body.querySelector("input.input:not([readonly]), textarea, select");
|
|
26774
27191
|
if ($with_focus) $with_focus.focus();
|
|
@@ -27016,6 +27433,225 @@ function close_cell_json_dialog(gobj) {
|
|
|
27016
27433
|
teardown_cell_json_child(gobj);
|
|
27017
27434
|
}
|
|
27018
27435
|
/************************************************************
|
|
27436
|
+
* Ask the host for the bytes of ONE asset.
|
|
27437
|
+
*
|
|
27438
|
+
* Same contract as the page requests: the transport belongs to the
|
|
27439
|
+
* HOST, so the request goes up as an event and the answer comes back
|
|
27440
|
+
* down as one, correlated by a `req_id` the host echoes. What is parked
|
|
27441
|
+
* here is WHERE the answer goes -- the form's preview of a column, or a
|
|
27442
|
+
* slot of the file popup -- and the watchdog, because a request whose
|
|
27443
|
+
* answer never lands would leave a "loading" on screen for ever.
|
|
27444
|
+
*
|
|
27445
|
+
* `target` is kept here and never travels: it holds a gobj and a DOM
|
|
27446
|
+
* node, and a kw is plain json.
|
|
27447
|
+
************************************************************/
|
|
27448
|
+
var ASSET_TIMEOUT_MS = 3e4;
|
|
27449
|
+
function request_asset(gobj, asset_id, target) {
|
|
27450
|
+
let priv = gobj.priv;
|
|
27451
|
+
if (!priv._pending_assets) priv._pending_assets = {};
|
|
27452
|
+
let req_id = `a${++priv._asset_seq}`;
|
|
27453
|
+
let timer = window.setTimeout(function() {
|
|
27454
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_ASSET_FAILED", {
|
|
27455
|
+
req_id,
|
|
27456
|
+
error: "asset request timed out"
|
|
27457
|
+
}, gobj);
|
|
27458
|
+
}, ASSET_TIMEOUT_MS);
|
|
27459
|
+
priv._pending_assets[req_id] = Object.assign({
|
|
27460
|
+
id: asset_id,
|
|
27461
|
+
timer
|
|
27462
|
+
}, target);
|
|
27463
|
+
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_REQUEST_ASSET", {
|
|
27464
|
+
topic_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name"),
|
|
27465
|
+
req_id,
|
|
27466
|
+
asset_id
|
|
27467
|
+
});
|
|
27468
|
+
}
|
|
27469
|
+
/************************************************************
|
|
27470
|
+
* Take a parked asset request out, however it ended. Null when
|
|
27471
|
+
* it was already settled (a late answer after a timeout).
|
|
27472
|
+
************************************************************/
|
|
27473
|
+
function take_pending_asset(gobj, req_id) {
|
|
27474
|
+
let priv = gobj.priv;
|
|
27475
|
+
let pend = priv._pending_assets ? priv._pending_assets[req_id] : null;
|
|
27476
|
+
if (!pend) return null;
|
|
27477
|
+
delete priv._pending_assets[req_id];
|
|
27478
|
+
if (pend.timer) window.clearTimeout(pend.timer);
|
|
27479
|
+
return pend;
|
|
27480
|
+
}
|
|
27481
|
+
/************************************************************
|
|
27482
|
+
* Forget every parked asset request: the view is going away,
|
|
27483
|
+
* and a watchdog firing into a stopped gobj is an error for
|
|
27484
|
+
* nothing.
|
|
27485
|
+
************************************************************/
|
|
27486
|
+
function drop_pending_assets(gobj) {
|
|
27487
|
+
let priv = gobj.priv;
|
|
27488
|
+
if (priv._pending_assets) {
|
|
27489
|
+
for (const pend of Object.values(priv._pending_assets)) if (pend.timer) window.clearTimeout(pend.timer);
|
|
27490
|
+
}
|
|
27491
|
+
priv._pending_assets = null;
|
|
27492
|
+
}
|
|
27493
|
+
/************************************************************
|
|
27494
|
+
* Ask for the asset of every `file` column the record names,
|
|
27495
|
+
* for the form's preview. One per column: the form shows the
|
|
27496
|
+
* asset the column keeps, which is the first it names.
|
|
27497
|
+
************************************************************/
|
|
27498
|
+
function request_form_previews(gobj, record) {
|
|
27499
|
+
let priv = gobj.priv;
|
|
27500
|
+
if (!record || !priv.form) return;
|
|
27501
|
+
let desc = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "desc");
|
|
27502
|
+
for (let col of desc.cols) {
|
|
27503
|
+
if (!col.id || col.id.charAt(0) === "_") continue;
|
|
27504
|
+
const field_desc = (0, _yuneta_gobj_js.treedb_get_field_desc)(col);
|
|
27505
|
+
if (field_desc.type !== "file" || field_desc.is_hidden) continue;
|
|
27506
|
+
let ids = file_cell_ids(record[col.id]);
|
|
27507
|
+
if (!ids.length) continue;
|
|
27508
|
+
request_asset(gobj, ids[0], {
|
|
27509
|
+
target: "form",
|
|
27510
|
+
form: priv.form,
|
|
27511
|
+
col: col.id
|
|
27512
|
+
});
|
|
27513
|
+
}
|
|
27514
|
+
}
|
|
27515
|
+
/************************************************************
|
|
27516
|
+
* Show what a `file` cell names -- every asset, when the
|
|
27517
|
+
* column is an array -- in the standardized adaptive dialog.
|
|
27518
|
+
*
|
|
27519
|
+
* Unlike the JSON cell this is NOT offline: the row holds the
|
|
27520
|
+
* ids and the bytes are the backend's, so each slot opens as
|
|
27521
|
+
* "loading" and one `get-asset` per id fills it.
|
|
27522
|
+
************************************************************/
|
|
27523
|
+
function open_cell_file_dialog(gobj, row_id, col_id) {
|
|
27524
|
+
close_cell_file_dialog(gobj);
|
|
27525
|
+
let priv = gobj.priv;
|
|
27526
|
+
let tabulator = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator");
|
|
27527
|
+
if (!tabulator) {
|
|
27528
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no table, no file cell to show`);
|
|
27529
|
+
return;
|
|
27530
|
+
}
|
|
27531
|
+
let row = tabulator.getRow(row_id);
|
|
27532
|
+
if (!row) {
|
|
27533
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: row '${row_id}' not found in the table`);
|
|
27534
|
+
return;
|
|
27535
|
+
}
|
|
27536
|
+
let ids = file_cell_ids(row.getData()[col_id]);
|
|
27537
|
+
if (!ids.length) {
|
|
27538
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: row '${row_id}' col '${col_id}' names no file`);
|
|
27539
|
+
return;
|
|
27540
|
+
}
|
|
27541
|
+
let $items = ids.map((id) => (0, _yuneta_gobj_js.createElement2)([
|
|
27542
|
+
"div",
|
|
27543
|
+
{ class: "CELL_FILE_ITEM" },
|
|
27544
|
+
[[
|
|
27545
|
+
"div",
|
|
27546
|
+
{ class: "CELL_FILE_SLOT" },
|
|
27547
|
+
[[
|
|
27548
|
+
"span",
|
|
27549
|
+
{
|
|
27550
|
+
class: "CELL_FILE_LOADING",
|
|
27551
|
+
i18n: "loading"
|
|
27552
|
+
},
|
|
27553
|
+
"loading"
|
|
27554
|
+
]]
|
|
27555
|
+
], [
|
|
27556
|
+
"div",
|
|
27557
|
+
{ class: "CELL_FILE_CAPTION" },
|
|
27558
|
+
[[
|
|
27559
|
+
"span",
|
|
27560
|
+
{ class: "CELL_FILE_ID" },
|
|
27561
|
+
id
|
|
27562
|
+
]]
|
|
27563
|
+
]]
|
|
27564
|
+
]));
|
|
27565
|
+
let $box = (0, _yuneta_gobj_js.createElement2)([
|
|
27566
|
+
"div",
|
|
27567
|
+
{ class: "TREEDB_CELL_FILE" },
|
|
27568
|
+
$items
|
|
27569
|
+
]);
|
|
27570
|
+
let presented = present_json_popup(gobj, $box, {
|
|
27571
|
+
name: "filewin_" + (0, _yuneta_gobj_js.clean_name)((0, _yuneta_gobj_js.gobj_name)(gobj)),
|
|
27572
|
+
logical_class: "TREEDB_CELL_FILE",
|
|
27573
|
+
title_prefix: String(row_id),
|
|
27574
|
+
title: col_id,
|
|
27575
|
+
icon: "yi-eye",
|
|
27576
|
+
forget_window: function() {
|
|
27577
|
+
priv.cell_file_win = null;
|
|
27578
|
+
},
|
|
27579
|
+
on_close: function() {
|
|
27580
|
+
teardown_cell_file(gobj);
|
|
27581
|
+
}
|
|
27582
|
+
});
|
|
27583
|
+
if (!presented) return;
|
|
27584
|
+
priv.cell_file_box = $box;
|
|
27585
|
+
priv.cell_file_modal = presented.modal;
|
|
27586
|
+
priv.cell_file_win = presented.win;
|
|
27587
|
+
ids.forEach((id, i) => {
|
|
27588
|
+
request_asset(gobj, id, {
|
|
27589
|
+
target: "popup",
|
|
27590
|
+
box: $box,
|
|
27591
|
+
slot: i
|
|
27592
|
+
});
|
|
27593
|
+
});
|
|
27594
|
+
}
|
|
27595
|
+
/************************************************************
|
|
27596
|
+
* Fill one slot of the file popup with what came back.
|
|
27597
|
+
************************************************************/
|
|
27598
|
+
function fill_cell_file_slot(gobj, pend, answer, error) {
|
|
27599
|
+
let priv = gobj.priv;
|
|
27600
|
+
if (!priv.cell_file_box || priv.cell_file_box !== pend.box) return;
|
|
27601
|
+
let $item = pend.box.querySelectorAll(".CELL_FILE_ITEM")[pend.slot];
|
|
27602
|
+
let $slot = $item ? $item.querySelector(".CELL_FILE_SLOT") : null;
|
|
27603
|
+
let $caption = $item ? $item.querySelector(".CELL_FILE_CAPTION") : null;
|
|
27604
|
+
if (!$slot || !$caption) {
|
|
27605
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: file popup has no slot ${pend.slot}`);
|
|
27606
|
+
return;
|
|
27607
|
+
}
|
|
27608
|
+
yui_asset_release($slot);
|
|
27609
|
+
$slot.replaceChildren(yui_asset_element(error ? null : answer, {
|
|
27610
|
+
detail: error || pend.id,
|
|
27611
|
+
alt: pend.id,
|
|
27612
|
+
class: "CELL_FILE_MEDIA"
|
|
27613
|
+
}));
|
|
27614
|
+
(0, _yuneta_gobj_js.refresh_language)($slot, i18next.t);
|
|
27615
|
+
if (!error && answer) {
|
|
27616
|
+
let meta = [answer.content_type, yui_file_size_label(answer.size)].filter((s) => !!s).join(" · ");
|
|
27617
|
+
if (meta) $caption.appendChild((0, _yuneta_gobj_js.createElement2)([
|
|
27618
|
+
"span",
|
|
27619
|
+
{ class: "CELL_FILE_META" },
|
|
27620
|
+
meta
|
|
27621
|
+
]));
|
|
27622
|
+
let $open = yui_asset_open_link(answer);
|
|
27623
|
+
if ($open) $caption.appendChild($open);
|
|
27624
|
+
}
|
|
27625
|
+
}
|
|
27626
|
+
/************************************************************
|
|
27627
|
+
* Retire the file popup. Called from its on_close -- the
|
|
27628
|
+
* shell or the window has already removed the DOM. The blob
|
|
27629
|
+
* urls it made are revoked; answers still in flight for it
|
|
27630
|
+
* land on nobody (fill_cell_file_slot checks the box).
|
|
27631
|
+
************************************************************/
|
|
27632
|
+
function teardown_cell_file(gobj) {
|
|
27633
|
+
let priv = gobj.priv;
|
|
27634
|
+
yui_asset_release(priv.cell_file_box);
|
|
27635
|
+
priv.cell_file_box = null;
|
|
27636
|
+
let win = priv.cell_file_win;
|
|
27637
|
+
priv.cell_file_win = null;
|
|
27638
|
+
retire_popup_window(win);
|
|
27639
|
+
priv.cell_file_modal = null;
|
|
27640
|
+
}
|
|
27641
|
+
/************************************************************
|
|
27642
|
+
* Close the file popup (teardown, or a second open).
|
|
27643
|
+
************************************************************/
|
|
27644
|
+
function close_cell_file_dialog(gobj) {
|
|
27645
|
+
let priv = gobj.priv;
|
|
27646
|
+
if (priv.cell_file_modal) {
|
|
27647
|
+
let modal = priv.cell_file_modal;
|
|
27648
|
+
priv.cell_file_modal = null;
|
|
27649
|
+
modal.close();
|
|
27650
|
+
return;
|
|
27651
|
+
}
|
|
27652
|
+
teardown_cell_file(gobj);
|
|
27653
|
+
}
|
|
27654
|
+
/************************************************************
|
|
27019
27655
|
* True if the topic's pkey col carries the "rowid" flag.
|
|
27020
27656
|
************************************************************/
|
|
27021
27657
|
function pkey_is_rowid(gobj) {
|
|
@@ -27799,6 +28435,57 @@ function ac_show_cell_json(gobj, event, kw, src) {
|
|
|
27799
28435
|
return 0;
|
|
27800
28436
|
}
|
|
27801
28437
|
/************************************************************
|
|
28438
|
+
* Show the asset(s) one `file` cell names
|
|
28439
|
+
* {
|
|
28440
|
+
* row_id:
|
|
28441
|
+
* col_id:
|
|
28442
|
+
* }
|
|
28443
|
+
************************************************************/
|
|
28444
|
+
function ac_show_cell_file(gobj, event, kw, src) {
|
|
28445
|
+
open_cell_file_dialog(gobj, kw.row_id, kw.col_id);
|
|
28446
|
+
return 0;
|
|
28447
|
+
}
|
|
28448
|
+
/************************************************************
|
|
28449
|
+
* Hand an asset answer -- or why there is none -- to whoever
|
|
28450
|
+
* asked for it, if it is still there to take it.
|
|
28451
|
+
************************************************************/
|
|
28452
|
+
function deliver_asset(gobj, pend, answer, error) {
|
|
28453
|
+
let priv = gobj.priv;
|
|
28454
|
+
if (pend.target === "form") {
|
|
28455
|
+
if (!priv.form || priv.form !== pend.form) return;
|
|
28456
|
+
(0, _yuneta_gobj_js.gobj_send_event)(priv.form, "EV_SET_FILE_PREVIEW", {
|
|
28457
|
+
name: pend.col,
|
|
28458
|
+
id: pend.id,
|
|
28459
|
+
answer,
|
|
28460
|
+
error
|
|
28461
|
+
}, gobj);
|
|
28462
|
+
return;
|
|
28463
|
+
}
|
|
28464
|
+
fill_cell_file_slot(gobj, pend, answer, error);
|
|
28465
|
+
}
|
|
28466
|
+
/************************************************************
|
|
28467
|
+
* The host answered an asset.
|
|
28468
|
+
* {req_id, answer}
|
|
28469
|
+
************************************************************/
|
|
28470
|
+
function ac_asset_loaded(gobj, event, kw, src) {
|
|
28471
|
+
let pend = take_pending_asset(gobj, kw.req_id);
|
|
28472
|
+
if (!pend) return 0;
|
|
28473
|
+
deliver_asset(gobj, pend, kw.answer || null, "");
|
|
28474
|
+
return 0;
|
|
28475
|
+
}
|
|
28476
|
+
/************************************************************
|
|
28477
|
+
* The host could not answer it, or nobody did in time.
|
|
28478
|
+
* {req_id, error}
|
|
28479
|
+
************************************************************/
|
|
28480
|
+
function ac_asset_failed(gobj, event, kw, src) {
|
|
28481
|
+
let why = kw && kw.error || "asset request failed";
|
|
28482
|
+
let pend = take_pending_asset(gobj, kw.req_id);
|
|
28483
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: asset '${pend ? pend.id : kw.req_id}': ${why}`);
|
|
28484
|
+
if (!pend) return 0;
|
|
28485
|
+
deliver_asset(gobj, pend, null, why);
|
|
28486
|
+
return 0;
|
|
28487
|
+
}
|
|
28488
|
+
/************************************************************
|
|
27802
28489
|
* One cell of one record changed. Publish it UP as a field write;
|
|
27803
28490
|
* the host owns the treedb command and its options.
|
|
27804
28491
|
************************************************************/
|
|
@@ -28302,6 +28989,21 @@ function create_gclass$5(gclass_name) {
|
|
|
28302
28989
|
ac_show_cell_json,
|
|
28303
28990
|
null
|
|
28304
28991
|
],
|
|
28992
|
+
[
|
|
28993
|
+
"EV_SHOW_CELL_FILE",
|
|
28994
|
+
ac_show_cell_file,
|
|
28995
|
+
null
|
|
28996
|
+
],
|
|
28997
|
+
[
|
|
28998
|
+
"EV_ASSET_LOADED",
|
|
28999
|
+
ac_asset_loaded,
|
|
29000
|
+
null
|
|
29001
|
+
],
|
|
29002
|
+
[
|
|
29003
|
+
"EV_ASSET_FAILED",
|
|
29004
|
+
ac_asset_failed,
|
|
29005
|
+
null
|
|
29006
|
+
],
|
|
28305
29007
|
[
|
|
28306
29008
|
"EV_CHANGE_LOCALE",
|
|
28307
29009
|
ac_change_locale,
|
|
@@ -28402,6 +29104,10 @@ function create_gclass$5(gclass_name) {
|
|
|
28402
29104
|
["EV_UNSELECT_ROWS", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
|
28403
29105
|
["EV_SHOW_HOOK_DATA", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
|
28404
29106
|
["EV_SHOW_CELL_JSON", 0],
|
|
29107
|
+
["EV_SHOW_CELL_FILE", 0],
|
|
29108
|
+
["EV_ASSET_LOADED", 0],
|
|
29109
|
+
["EV_ASSET_FAILED", 0],
|
|
29110
|
+
["EV_REQUEST_ASSET", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
|
28405
29111
|
["EV_CHANGE_LOCALE", 0],
|
|
28406
29112
|
["EV_REFRESH", 0],
|
|
28407
29113
|
["EV_SHOW_SCHEMA", 0],
|
|
@@ -63365,15 +64071,15 @@ function ac_theme$1(gobj, event, kw, src) {
|
|
|
63365
64071
|
/************************************************************
|
|
63366
64072
|
* Zoom controls
|
|
63367
64073
|
************************************************************/
|
|
63368
|
-
function ac_zoom_in(gobj, event, kw, src) {
|
|
64074
|
+
function ac_zoom_in$1(gobj, event, kw, src) {
|
|
63369
64075
|
graph_zoom_in(gobj);
|
|
63370
64076
|
return 0;
|
|
63371
64077
|
}
|
|
63372
|
-
function ac_zoom_out(gobj, event, kw, src) {
|
|
64078
|
+
function ac_zoom_out$1(gobj, event, kw, src) {
|
|
63373
64079
|
graph_zoom_out(gobj);
|
|
63374
64080
|
return 0;
|
|
63375
64081
|
}
|
|
63376
|
-
function ac_zoom_reset(gobj, event, kw, src) {
|
|
64082
|
+
function ac_zoom_reset$1(gobj, event, kw, src) {
|
|
63377
64083
|
let priv = gobj.priv;
|
|
63378
64084
|
let graph = priv.graph;
|
|
63379
64085
|
if (priv.anchor_state === "on" && priv.anchor_id) after_camera(gobj, graph.zoomTo(1));
|
|
@@ -63761,7 +64467,7 @@ function ac_find_next$1(gobj, event, kw, src) {
|
|
|
63761
64467
|
graph_find_step(gobj, !!(kw && kw.back));
|
|
63762
64468
|
return 0;
|
|
63763
64469
|
}
|
|
63764
|
-
function ac_center(gobj, event, kw, src) {
|
|
64470
|
+
function ac_center$1(gobj, event, kw, src) {
|
|
63765
64471
|
graph_center(gobj);
|
|
63766
64472
|
return 0;
|
|
63767
64473
|
}
|
|
@@ -64171,17 +64877,17 @@ function create_gclass$4(gclass_name) {
|
|
|
64171
64877
|
],
|
|
64172
64878
|
[
|
|
64173
64879
|
"EV_ZOOM_IN",
|
|
64174
|
-
ac_zoom_in,
|
|
64880
|
+
ac_zoom_in$1,
|
|
64175
64881
|
null
|
|
64176
64882
|
],
|
|
64177
64883
|
[
|
|
64178
64884
|
"EV_ZOOM_OUT",
|
|
64179
|
-
ac_zoom_out,
|
|
64885
|
+
ac_zoom_out$1,
|
|
64180
64886
|
null
|
|
64181
64887
|
],
|
|
64182
64888
|
[
|
|
64183
64889
|
"EV_ZOOM_RESET",
|
|
64184
|
-
ac_zoom_reset,
|
|
64890
|
+
ac_zoom_reset$1,
|
|
64185
64891
|
null
|
|
64186
64892
|
],
|
|
64187
64893
|
[
|
|
@@ -64281,7 +64987,7 @@ function create_gclass$4(gclass_name) {
|
|
|
64281
64987
|
],
|
|
64282
64988
|
[
|
|
64283
64989
|
"EV_CENTER",
|
|
64284
|
-
ac_center,
|
|
64990
|
+
ac_center$1,
|
|
64285
64991
|
null
|
|
64286
64992
|
],
|
|
64287
64993
|
[
|
|
@@ -66997,6 +67703,12 @@ function register_c_yui_treedb_graph() {
|
|
|
66997
67703
|
* via the host-supplied `node_route`). An alternate landing to the
|
|
66998
67704
|
* topic cards, in the spirit of "every treedb is a graph".
|
|
66999
67705
|
*
|
|
67706
|
+
* The CAMERA is the family's (yui_graph_camera.js): the same
|
|
67707
|
+
* toolbar cluster -- zoom in/out, readout, fit, 1:1 -- and the
|
|
67708
|
+
* same wheel: it SCROLLS, and Ctrl + wheel zooms, over the cards
|
|
67709
|
+
* too (yui_graph_forward_wheel). This view zoomed on a bare wheel
|
|
67710
|
+
* and had no toolbar, beside graphs that did neither.
|
|
67711
|
+
*
|
|
67000
67712
|
* Copyright (c) 2026, ArtGins.
|
|
67001
67713
|
* All Rights Reserved.
|
|
67002
67714
|
***********************************************************************/
|
|
@@ -67034,19 +67746,23 @@ var attrs_table$2 = [
|
|
|
67034
67746
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "node_route", 0, "", "Hash-route template with a {topic} placeholder: a node click opens that topic (e.g. '#/topics/db/<sel>/{topic}')"),
|
|
67035
67747
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_node_click", 0, false, "With no `node_route`, PUBLISH a node click as EV_NODE_CLICK instead of dropping it. Opt-in, because a subscriber has to DECLARE the event: the hosts that route by hash, and the ones that want nothing, must not have it appear underneath them"),
|
|
67036
67748
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "system", 0, false, "Include system topics (__*__) too"),
|
|
67749
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "wide", 0, "40px", "Height of the toolbar buttons: the family's (C_YUI_TREEDB_GRAPH, C_YUI_JSON_GRAPH, C_YUI_GOBJ_TREE_JS)"),
|
|
67037
67750
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "$container", 0, null, "Root HTML element"),
|
|
67038
67751
|
(0, _yuneta_gobj_js.SDATA_END)()
|
|
67039
67752
|
];
|
|
67040
67753
|
var PRIVATE_DATA$2 = {
|
|
67041
67754
|
$container: null,
|
|
67755
|
+
$canvas: null,
|
|
67042
67756
|
graph: null,
|
|
67043
|
-
theme_observer: null
|
|
67757
|
+
theme_observer: null,
|
|
67758
|
+
unforward_wheel: null
|
|
67044
67759
|
};
|
|
67045
67760
|
var __gclass__$2 = null;
|
|
67046
67761
|
/******************************
|
|
67047
67762
|
* Framework Methods
|
|
67048
67763
|
******************************/
|
|
67049
67764
|
function mt_create$2(gobj) {
|
|
67765
|
+
ensure_pinch_zoom_patch();
|
|
67050
67766
|
build_ui$2(gobj);
|
|
67051
67767
|
let subscriber = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "subscriber");
|
|
67052
67768
|
if (!subscriber) subscriber = (0, _yuneta_gobj_js.gobj_parent)(gobj);
|
|
@@ -67076,13 +67792,47 @@ function mt_destroy$2(gobj) {
|
|
|
67076
67792
|
* Build UI
|
|
67077
67793
|
************************************************************/
|
|
67078
67794
|
function build_ui$2(gobj) {
|
|
67795
|
+
let priv = gobj.priv;
|
|
67796
|
+
const $toolbar = yui_toolbar({}, [
|
|
67797
|
+
[
|
|
67798
|
+
"div",
|
|
67799
|
+
{ class: "yui-horizontal-toolbar-section left" },
|
|
67800
|
+
[]
|
|
67801
|
+
],
|
|
67802
|
+
[
|
|
67803
|
+
"div",
|
|
67804
|
+
{ class: "yui-horizontal-toolbar-section center" },
|
|
67805
|
+
yui_graph_camera_items(gobj, null, (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "wide"))
|
|
67806
|
+
],
|
|
67807
|
+
[
|
|
67808
|
+
"div",
|
|
67809
|
+
{ class: "yui-horizontal-toolbar-section right" },
|
|
67810
|
+
[]
|
|
67811
|
+
]
|
|
67812
|
+
]);
|
|
67813
|
+
(0, _yuneta_gobj_js.refresh_language)($toolbar, i18next.t);
|
|
67814
|
+
priv.$canvas = (0, _yuneta_gobj_js.createElement2)([
|
|
67815
|
+
"div",
|
|
67816
|
+
{
|
|
67817
|
+
class: "TREEDB_SCHEMA_CANVAS",
|
|
67818
|
+
style: "position:relative; flex:1 1 auto; min-height:0;"
|
|
67819
|
+
},
|
|
67820
|
+
[]
|
|
67821
|
+
]);
|
|
67079
67822
|
let $container = (0, _yuneta_gobj_js.createElement2)([
|
|
67080
67823
|
"div",
|
|
67081
67824
|
{
|
|
67082
67825
|
class: "C_YUI_TREEDB_SCHEMA TREEDB_SCHEMA_VIEW",
|
|
67083
|
-
style: "position:relative; height:100%; min-height:0;"
|
|
67826
|
+
style: "position:relative; height:100%; min-height:0; display:flex; flex-direction:column;"
|
|
67084
67827
|
},
|
|
67085
|
-
[
|
|
67828
|
+
[[
|
|
67829
|
+
"div",
|
|
67830
|
+
{
|
|
67831
|
+
class: "TREEDB_SCHEMA_TOOLBAR",
|
|
67832
|
+
style: "flex:0 0 auto;"
|
|
67833
|
+
},
|
|
67834
|
+
[$toolbar]
|
|
67835
|
+
], priv.$canvas]
|
|
67086
67836
|
]);
|
|
67087
67837
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "$container", $container);
|
|
67088
67838
|
}
|
|
@@ -67376,7 +68126,10 @@ function edge_style(dark) {
|
|
|
67376
68126
|
function build_graph(gobj) {
|
|
67377
68127
|
let priv = gobj.priv;
|
|
67378
68128
|
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
67379
|
-
if (!$container)
|
|
68129
|
+
if (!$container || !priv.$canvas) {
|
|
68130
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no UI to draw the schema in`);
|
|
68131
|
+
return;
|
|
68132
|
+
}
|
|
67380
68133
|
destroy_graph(gobj);
|
|
67381
68134
|
let data = schema_to_graph(gobj);
|
|
67382
68135
|
if (data.nodes.length === 0) {
|
|
@@ -67388,15 +68141,16 @@ function build_graph(gobj) {
|
|
|
67388
68141
|
},
|
|
67389
68142
|
(0, i18next.t)("no topics", { defaultValue: "No topics" })
|
|
67390
68143
|
]);
|
|
67391
|
-
|
|
68144
|
+
priv.$canvas.appendChild($empty);
|
|
67392
68145
|
return;
|
|
67393
68146
|
}
|
|
67394
68147
|
let dark = yui_is_dark();
|
|
67395
68148
|
let graph;
|
|
67396
68149
|
try {
|
|
67397
68150
|
graph = new _antv_g6.Graph({
|
|
67398
|
-
container:
|
|
68151
|
+
container: priv.$canvas,
|
|
67399
68152
|
autoResize: true,
|
|
68153
|
+
animation: false,
|
|
67400
68154
|
data,
|
|
67401
68155
|
edge: { style: edge_style(dark) },
|
|
67402
68156
|
layout: {
|
|
@@ -67406,8 +68160,8 @@ function build_graph(gobj) {
|
|
|
67406
68160
|
ranksep: 90
|
|
67407
68161
|
},
|
|
67408
68162
|
behaviors: [
|
|
67409
|
-
"zoom-canvas",
|
|
67410
68163
|
"drag-canvas",
|
|
68164
|
+
...yui_graph_camera_behaviors(),
|
|
67411
68165
|
"drag-element"
|
|
67412
68166
|
]
|
|
67413
68167
|
});
|
|
@@ -67417,11 +68171,17 @@ function build_graph(gobj) {
|
|
|
67417
68171
|
}
|
|
67418
68172
|
priv.graph = graph;
|
|
67419
68173
|
graph.setTheme(dark ? "dark" : "light");
|
|
68174
|
+
graph.on("aftertransform", () => {
|
|
68175
|
+
yui_graph_update_zoom($container, priv.graph);
|
|
68176
|
+
});
|
|
68177
|
+
priv.unforward_wheel = yui_graph_forward_wheel(graph, priv.$canvas);
|
|
67420
68178
|
graph.on(_antv_g6.NodeEvent.CLICK, (evt) => {
|
|
67421
68179
|
let node_id = evt && evt.target && evt.target.id;
|
|
67422
68180
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_NODE_CLICK", { node_id }, gobj);
|
|
67423
68181
|
});
|
|
67424
|
-
graph.render().
|
|
68182
|
+
graph.render().then(() => {
|
|
68183
|
+
yui_graph_update_zoom($container, priv.graph);
|
|
68184
|
+
}).catch((e) => {
|
|
67425
68185
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: schema graph render failed: ${e}`);
|
|
67426
68186
|
});
|
|
67427
68187
|
}
|
|
@@ -67430,14 +68190,17 @@ function build_graph(gobj) {
|
|
|
67430
68190
|
************************************************************/
|
|
67431
68191
|
function destroy_graph(gobj) {
|
|
67432
68192
|
let priv = gobj.priv;
|
|
68193
|
+
if (priv.unforward_wheel) {
|
|
68194
|
+
priv.unforward_wheel();
|
|
68195
|
+
priv.unforward_wheel = null;
|
|
68196
|
+
}
|
|
67433
68197
|
if (priv.graph) {
|
|
67434
68198
|
try {
|
|
67435
68199
|
priv.graph.destroy();
|
|
67436
68200
|
} catch (e) {}
|
|
67437
68201
|
priv.graph = null;
|
|
67438
68202
|
}
|
|
67439
|
-
|
|
67440
|
-
if ($container) while ($container.firstChild) $container.removeChild($container.firstChild);
|
|
68203
|
+
if (priv.$canvas) while (priv.$canvas.firstChild) priv.$canvas.removeChild(priv.$canvas.firstChild);
|
|
67441
68204
|
}
|
|
67442
68205
|
/***************************
|
|
67443
68206
|
* Actions
|
|
@@ -67527,6 +68290,38 @@ function ac_theme(gobj, event, kw, src) {
|
|
|
67527
68290
|
return 0;
|
|
67528
68291
|
}
|
|
67529
68292
|
/************************************************************
|
|
68293
|
+
* The camera, from the toolbar. Same moves as the family's
|
|
68294
|
+
* (C_YUI_GOBJ_TREE_JS): +/- 20%, fit, and actual size at the
|
|
68295
|
+
* layout's origin.
|
|
68296
|
+
************************************************************/
|
|
68297
|
+
function camera_move(gobj, what, promise) {
|
|
68298
|
+
Promise.resolve(promise).then(() => {
|
|
68299
|
+
yui_graph_update_zoom((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), gobj.priv.graph);
|
|
68300
|
+
}).catch((e) => {
|
|
68301
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: schema graph ${what} failed: ${e}`);
|
|
68302
|
+
});
|
|
68303
|
+
}
|
|
68304
|
+
function ac_zoom_in(gobj, event, kw, src) {
|
|
68305
|
+
let graph = gobj.priv.graph;
|
|
68306
|
+
if (graph) camera_move(gobj, "zoom in", graph.zoomTo(graph.getZoom() * 1.2));
|
|
68307
|
+
return 0;
|
|
68308
|
+
}
|
|
68309
|
+
function ac_zoom_out(gobj, event, kw, src) {
|
|
68310
|
+
let graph = gobj.priv.graph;
|
|
68311
|
+
if (graph) camera_move(gobj, "zoom out", graph.zoomTo(graph.getZoom() * .8));
|
|
68312
|
+
return 0;
|
|
68313
|
+
}
|
|
68314
|
+
function ac_zoom_reset(gobj, event, kw, src) {
|
|
68315
|
+
let graph = gobj.priv.graph;
|
|
68316
|
+
if (graph && graph.rendered) camera_move(gobj, "actual size", Promise.resolve(graph.zoomTo(1)).then(() => graph.translateTo([0, 0])));
|
|
68317
|
+
return 0;
|
|
68318
|
+
}
|
|
68319
|
+
function ac_center(gobj, event, kw, src) {
|
|
68320
|
+
let graph = gobj.priv.graph;
|
|
68321
|
+
if (graph) camera_move(gobj, "fit", graph.fitView());
|
|
68322
|
+
return 0;
|
|
68323
|
+
}
|
|
68324
|
+
/************************************************************
|
|
67530
68325
|
* Rebuild from a fresh schema (descs arrived / changed).
|
|
67531
68326
|
************************************************************/
|
|
67532
68327
|
function ac_rebuild(gobj, event, kw, src) {
|
|
@@ -67568,13 +68363,37 @@ function create_gclass$2(gclass_name) {
|
|
|
67568
68363
|
"EV_REBUILD",
|
|
67569
68364
|
ac_rebuild,
|
|
67570
68365
|
null
|
|
68366
|
+
],
|
|
68367
|
+
[
|
|
68368
|
+
"EV_ZOOM_IN",
|
|
68369
|
+
ac_zoom_in,
|
|
68370
|
+
null
|
|
68371
|
+
],
|
|
68372
|
+
[
|
|
68373
|
+
"EV_ZOOM_OUT",
|
|
68374
|
+
ac_zoom_out,
|
|
68375
|
+
null
|
|
68376
|
+
],
|
|
68377
|
+
[
|
|
68378
|
+
"EV_ZOOM_RESET",
|
|
68379
|
+
ac_zoom_reset,
|
|
68380
|
+
null
|
|
68381
|
+
],
|
|
68382
|
+
[
|
|
68383
|
+
"EV_CENTER",
|
|
68384
|
+
ac_center,
|
|
68385
|
+
null
|
|
67571
68386
|
]
|
|
67572
68387
|
]]];
|
|
67573
68388
|
const event_types = [
|
|
67574
68389
|
["EV_NODE_CLICK", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT | _yuneta_gobj_js.event_flag_t.EVF_NO_WARN_SUBS],
|
|
67575
68390
|
["EV_SHOW", 0],
|
|
67576
68391
|
["EV_THEME", 0],
|
|
67577
|
-
["EV_REBUILD", 0]
|
|
68392
|
+
["EV_REBUILD", 0],
|
|
68393
|
+
["EV_ZOOM_IN", 0],
|
|
68394
|
+
["EV_ZOOM_OUT", 0],
|
|
68395
|
+
["EV_ZOOM_RESET", 0],
|
|
68396
|
+
["EV_CENTER", 0]
|
|
67578
68397
|
];
|
|
67579
68398
|
__gclass__$2 = (0, _yuneta_gobj_js.gclass_create)(gclass_name, event_types, states, gmt$2, 0, attrs_table$2, PRIVATE_DATA$2, 0, 0, 0, 0);
|
|
67580
68399
|
if (!__gclass__$2) return -1;
|