@mosaicajs/components 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/explorer.d.ts +2 -0
- package/dist/explorer.js +11 -2
- package/dist/item-card.d.ts +18 -1
- package/dist/item-card.js +76 -9
- package/dist/mosaica-components.js +544 -532
- package/dist/mosaica-components.js.sri +1 -1
- package/dist/mosaica-components.json +2 -2
- package/dist/parts.d.ts +1 -1
- package/dist/parts.js +1 -1
- package/package.json +3 -3
package/dist/explorer.d.ts
CHANGED
|
@@ -211,6 +211,8 @@ export declare class MosaicaExplorer extends MosaicaElement {
|
|
|
211
211
|
accessor subtitleField: string;
|
|
212
212
|
/** The fields the item card shows before "Show all", in order, as for `<mosaica-item-card>`. Unset, the first three. */
|
|
213
213
|
accessor cardFields: string;
|
|
214
|
+
/** The fields the item card draws as images, as for `<mosaica-item-card>`'s `image-fields`. */
|
|
215
|
+
accessor imageFields: string;
|
|
214
216
|
/** The link template for the item card's Open button, as for `<mosaica-item-card>`. Without it or `open`, there is no Open button. */
|
|
215
217
|
accessor openUrl: string;
|
|
216
218
|
/** A function the item card calls when Open is pressed, as for `<mosaica-item-card>`. Takes precedence over `open-url`. */
|
package/dist/explorer.js
CHANGED
|
@@ -305,6 +305,9 @@ let MosaicaExplorer = (() => {
|
|
|
305
305
|
let _cardFields_decorators;
|
|
306
306
|
let _cardFields_initializers = [];
|
|
307
307
|
let _cardFields_extraInitializers = [];
|
|
308
|
+
let _imageFields_decorators;
|
|
309
|
+
let _imageFields_initializers = [];
|
|
310
|
+
let _imageFields_extraInitializers = [];
|
|
308
311
|
let _openUrl_decorators;
|
|
309
312
|
let _openUrl_initializers = [];
|
|
310
313
|
let _openUrl_extraInitializers = [];
|
|
@@ -448,6 +451,7 @@ let MosaicaExplorer = (() => {
|
|
|
448
451
|
_titleField_decorators = [property({ attribute: 'title-field' })];
|
|
449
452
|
_subtitleField_decorators = [property({ attribute: 'subtitle-field' })];
|
|
450
453
|
_cardFields_decorators = [property({ attribute: 'card-fields' })];
|
|
454
|
+
_imageFields_decorators = [property({ attribute: 'image-fields' })];
|
|
451
455
|
_openUrl_decorators = [property({ attribute: 'open-url' })];
|
|
452
456
|
_open_decorators = [property({ attribute: false })];
|
|
453
457
|
_budget_decorators = [property({ type: Number })];
|
|
@@ -500,6 +504,7 @@ let MosaicaExplorer = (() => {
|
|
|
500
504
|
__esDecorate(this, null, _titleField_decorators, { kind: "accessor", name: "titleField", static: false, private: false, access: { has: obj => "titleField" in obj, get: obj => obj.titleField, set: (obj, value) => { obj.titleField = value; } }, metadata: _metadata }, _titleField_initializers, _titleField_extraInitializers);
|
|
501
505
|
__esDecorate(this, null, _subtitleField_decorators, { kind: "accessor", name: "subtitleField", static: false, private: false, access: { has: obj => "subtitleField" in obj, get: obj => obj.subtitleField, set: (obj, value) => { obj.subtitleField = value; } }, metadata: _metadata }, _subtitleField_initializers, _subtitleField_extraInitializers);
|
|
502
506
|
__esDecorate(this, null, _cardFields_decorators, { kind: "accessor", name: "cardFields", static: false, private: false, access: { has: obj => "cardFields" in obj, get: obj => obj.cardFields, set: (obj, value) => { obj.cardFields = value; } }, metadata: _metadata }, _cardFields_initializers, _cardFields_extraInitializers);
|
|
507
|
+
__esDecorate(this, null, _imageFields_decorators, { kind: "accessor", name: "imageFields", static: false, private: false, access: { has: obj => "imageFields" in obj, get: obj => obj.imageFields, set: (obj, value) => { obj.imageFields = value; } }, metadata: _metadata }, _imageFields_initializers, _imageFields_extraInitializers);
|
|
503
508
|
__esDecorate(this, null, _openUrl_decorators, { kind: "accessor", name: "openUrl", static: false, private: false, access: { has: obj => "openUrl" in obj, get: obj => obj.openUrl, set: (obj, value) => { obj.openUrl = value; } }, metadata: _metadata }, _openUrl_initializers, _openUrl_extraInitializers);
|
|
504
509
|
__esDecorate(this, null, _open_decorators, { kind: "accessor", name: "open", static: false, private: false, access: { has: obj => "open" in obj, get: obj => obj.open, set: (obj, value) => { obj.open = value; } }, metadata: _metadata }, _open_initializers, _open_extraInitializers);
|
|
505
510
|
__esDecorate(this, null, _budget_decorators, { kind: "accessor", name: "budget", static: false, private: false, access: { has: obj => "budget" in obj, get: obj => obj.budget, set: (obj, value) => { obj.budget = value; } }, metadata: _metadata }, _budget_initializers, _budget_extraInitializers);
|
|
@@ -1038,7 +1043,11 @@ let MosaicaExplorer = (() => {
|
|
|
1038
1043
|
/** The fields the item card shows before "Show all", in order, as for `<mosaica-item-card>`. Unset, the first three. */
|
|
1039
1044
|
get cardFields() { return this.#cardFields_accessor_storage; }
|
|
1040
1045
|
set cardFields(value) { this.#cardFields_accessor_storage = value; }
|
|
1041
|
-
#
|
|
1046
|
+
#imageFields_accessor_storage = (__runInitializers(this, _cardFields_extraInitializers), __runInitializers(this, _imageFields_initializers, ''));
|
|
1047
|
+
/** The fields the item card draws as images, as for `<mosaica-item-card>`'s `image-fields`. */
|
|
1048
|
+
get imageFields() { return this.#imageFields_accessor_storage; }
|
|
1049
|
+
set imageFields(value) { this.#imageFields_accessor_storage = value; }
|
|
1050
|
+
#openUrl_accessor_storage = (__runInitializers(this, _imageFields_extraInitializers), __runInitializers(this, _openUrl_initializers, ''));
|
|
1042
1051
|
/** The link template for the item card's Open button, as for `<mosaica-item-card>`. Without it or `open`, there is no Open button. */
|
|
1043
1052
|
get openUrl() { return this.#openUrl_accessor_storage; }
|
|
1044
1053
|
set openUrl(value) { this.#openUrl_accessor_storage = value; }
|
|
@@ -1514,7 +1523,7 @@ let MosaicaExplorer = (() => {
|
|
|
1514
1523
|
*/
|
|
1515
1524
|
itemCard(item, actions) {
|
|
1516
1525
|
return html `<mosaica-item-card exportparts=${FORWARD['item-card']} compact .item=${item} .pick=${item ? null : (this.map?.lastPick ?? null)}
|
|
1517
|
-
title-field=${this.titleField || nothing} subtitle-field=${this.subtitleField || nothing} card-fields=${this.cardFields || nothing} open-url=${this.openUrl || nothing} .open=${this.open}>${actions}</mosaica-item-card>`;
|
|
1526
|
+
title-field=${this.titleField || nothing} subtitle-field=${this.subtitleField || nothing} card-fields=${this.cardFields || nothing} image-fields=${this.imageFields || nothing} open-url=${this.openUrl || nothing} .open=${this.open}>${actions}</mosaica-item-card>`;
|
|
1518
1527
|
}
|
|
1519
1528
|
/** Whether the card for the selection is the artifact card: the artifact, or its refusal, changed last. */
|
|
1520
1529
|
showsArtifact() {
|
package/dist/item-card.d.ts
CHANGED
|
@@ -11,6 +11,11 @@ import { MosaicaElement, type PickOutcome } from './base.js';
|
|
|
11
11
|
* empty. To render a field your own way, as a link for example, put an element in its
|
|
12
12
|
* `field-<name>` slot.
|
|
13
13
|
*
|
|
14
|
+
* A field named in `image-fields` whose value is an `http:` or `https:` address, or a path
|
|
15
|
+
* resolved against the page, is drawn as the image at that address, across the card's width. The viewer's browser loads it from the host
|
|
16
|
+
* that serves it, without a referrer. A value that is not such an address, and an image that does
|
|
17
|
+
* not load, are shown as text.
|
|
18
|
+
*
|
|
14
19
|
* The Open button appears only when you set `open-url` or `open`. `open-url` is a link template
|
|
15
20
|
* such as `https://www.geonames.org/{geonameid}`, in which each `{name}` is replaced by the item's
|
|
16
21
|
* value for that field. Because the values are URL-encoded, a template cannot open an address that
|
|
@@ -43,6 +48,7 @@ import { MosaicaElement, type PickOutcome } from './base.js';
|
|
|
43
48
|
* @csspart field - One field, with `data-name`, and `data-prose` on a value over 60 characters.
|
|
44
49
|
* @csspart label - A field's name, and the heading above the view chips.
|
|
45
50
|
* @csspart value - A field's value.
|
|
51
|
+
* @csspart image - A field's value drawn as an image, under `image-fields`.
|
|
46
52
|
* @csspart scoped - The group-scoped values, grouped by key.
|
|
47
53
|
* @csspart key - One key's heading among the group-scoped values, with `data-key`.
|
|
48
54
|
* @csspart open - The Open button.
|
|
@@ -75,6 +81,11 @@ export declare class MosaicaItemCard extends MosaicaElement {
|
|
|
75
81
|
* Unset, the first three. The full list shows these fields first, then the rest.
|
|
76
82
|
*/
|
|
77
83
|
accessor cardFields: string;
|
|
84
|
+
/**
|
|
85
|
+
* The fields whose value is the address of an image, separated by spaces or commas. Each is drawn
|
|
86
|
+
* as its image rather than as text.
|
|
87
|
+
*/
|
|
88
|
+
accessor imageFields: string;
|
|
78
89
|
/**
|
|
79
90
|
* The link template for Open, with `{name}` for the value of the field `name` and `{mosaica_id}`
|
|
80
91
|
* for the item's id. Without it or `open`, there is no Open button.
|
|
@@ -85,6 +96,10 @@ export declare class MosaicaItemCard extends MosaicaElement {
|
|
|
85
96
|
/** Whether "Show all" was pressed, for the item it was pressed on. @internal */
|
|
86
97
|
accessor expanded: boolean;
|
|
87
98
|
private expandedFor;
|
|
99
|
+
/** The image addresses that failed to load, shown as text. @internal */
|
|
100
|
+
accessor broken: ReadonlySet<string>;
|
|
101
|
+
/** `image-fields` as a list, kept in step by `willUpdate`. */
|
|
102
|
+
private imageNames;
|
|
88
103
|
/** A category value's title as the store holds it, else from the legend or a suggestion page, else its key. */
|
|
89
104
|
private titleOf;
|
|
90
105
|
/** A field's value as text: a category value by its title, anything else by its declared type. */
|
|
@@ -105,6 +120,8 @@ export declare class MosaicaItemCard extends MosaicaElement {
|
|
|
105
120
|
private openButton;
|
|
106
121
|
/** The fields of `fields` that `card-fields` names, in its order. */
|
|
107
122
|
private named;
|
|
123
|
+
/** The address of the image a field's value names, where `image-fields` lists the field. */
|
|
124
|
+
private imageOf;
|
|
108
125
|
/** `fields` with those `card-fields` names first, in its order. */
|
|
109
126
|
private namedFirst;
|
|
110
127
|
/**
|
|
@@ -124,7 +141,7 @@ export declare class MosaicaItemCard extends MosaicaElement {
|
|
|
124
141
|
* key through a `members` group share a heading.
|
|
125
142
|
*/
|
|
126
143
|
private scoped;
|
|
127
|
-
/** One field, presented by its declared type; prose
|
|
144
|
+
/** One field, presented by its declared type; prose and images span the grid. */
|
|
128
145
|
private field;
|
|
129
146
|
}
|
|
130
147
|
declare global {
|
package/dist/item-card.js
CHANGED
|
@@ -49,6 +49,11 @@ import { chrome, tokens } from './tokens.js';
|
|
|
49
49
|
* empty. To render a field your own way, as a link for example, put an element in its
|
|
50
50
|
* `field-<name>` slot.
|
|
51
51
|
*
|
|
52
|
+
* A field named in `image-fields` whose value is an `http:` or `https:` address, or a path
|
|
53
|
+
* resolved against the page, is drawn as the image at that address, across the card's width. The viewer's browser loads it from the host
|
|
54
|
+
* that serves it, without a referrer. A value that is not such an address, and an image that does
|
|
55
|
+
* not load, are shown as text.
|
|
56
|
+
*
|
|
52
57
|
* The Open button appears only when you set `open-url` or `open`. `open-url` is a link template
|
|
53
58
|
* such as `https://www.geonames.org/{geonameid}`, in which each `{name}` is replaced by the item's
|
|
54
59
|
* value for that field. Because the values are URL-encoded, a template cannot open an address that
|
|
@@ -81,6 +86,7 @@ import { chrome, tokens } from './tokens.js';
|
|
|
81
86
|
* @csspart field - One field, with `data-name`, and `data-prose` on a value over 60 characters.
|
|
82
87
|
* @csspart label - A field's name, and the heading above the view chips.
|
|
83
88
|
* @csspart value - A field's value.
|
|
89
|
+
* @csspart image - A field's value drawn as an image, under `image-fields`.
|
|
84
90
|
* @csspart scoped - The group-scoped values, grouped by key.
|
|
85
91
|
* @csspart key - One key's heading among the group-scoped values, with `data-key`.
|
|
86
92
|
* @csspart open - The Open button.
|
|
@@ -112,6 +118,9 @@ let MosaicaItemCard = (() => {
|
|
|
112
118
|
let _cardFields_decorators;
|
|
113
119
|
let _cardFields_initializers = [];
|
|
114
120
|
let _cardFields_extraInitializers = [];
|
|
121
|
+
let _imageFields_decorators;
|
|
122
|
+
let _imageFields_initializers = [];
|
|
123
|
+
let _imageFields_extraInitializers = [];
|
|
115
124
|
let _openUrl_decorators;
|
|
116
125
|
let _openUrl_initializers = [];
|
|
117
126
|
let _openUrl_extraInitializers = [];
|
|
@@ -121,6 +130,9 @@ let MosaicaItemCard = (() => {
|
|
|
121
130
|
let _expanded_decorators;
|
|
122
131
|
let _expanded_initializers = [];
|
|
123
132
|
let _expanded_extraInitializers = [];
|
|
133
|
+
let _broken_decorators;
|
|
134
|
+
let _broken_initializers = [];
|
|
135
|
+
let _broken_extraInitializers = [];
|
|
124
136
|
return class MosaicaItemCard extends _classSuper {
|
|
125
137
|
static {
|
|
126
138
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
@@ -132,9 +144,11 @@ let MosaicaItemCard = (() => {
|
|
|
132
144
|
_compact_decorators = [property({ type: Boolean, reflect: true })];
|
|
133
145
|
_subtitleField_decorators = [property({ attribute: 'subtitle-field' })];
|
|
134
146
|
_cardFields_decorators = [property({ attribute: 'card-fields' })];
|
|
147
|
+
_imageFields_decorators = [property({ attribute: 'image-fields' })];
|
|
135
148
|
_openUrl_decorators = [property({ attribute: 'open-url' })];
|
|
136
149
|
_open_decorators = [property({ attribute: false })];
|
|
137
150
|
_expanded_decorators = [state()];
|
|
151
|
+
_broken_decorators = [state()];
|
|
138
152
|
__esDecorate(this, null, _item_decorators, { kind: "accessor", name: "item", static: false, private: false, access: { has: obj => "item" in obj, get: obj => obj.item, set: (obj, value) => { obj.item = value; } }, metadata: _metadata }, _item_initializers, _item_extraInitializers);
|
|
139
153
|
__esDecorate(this, null, _refusal_decorators, { kind: "accessor", name: "refusal", static: false, private: false, access: { has: obj => "refusal" in obj, get: obj => obj.refusal, set: (obj, value) => { obj.refusal = value; } }, metadata: _metadata }, _refusal_initializers, _refusal_extraInitializers);
|
|
140
154
|
__esDecorate(this, null, _pick_decorators, { kind: "accessor", name: "pick", static: false, private: false, access: { has: obj => "pick" in obj, get: obj => obj.pick, set: (obj, value) => { obj.pick = value; } }, metadata: _metadata }, _pick_initializers, _pick_extraInitializers);
|
|
@@ -143,9 +157,11 @@ let MosaicaItemCard = (() => {
|
|
|
143
157
|
__esDecorate(this, null, _compact_decorators, { kind: "accessor", name: "compact", static: false, private: false, access: { has: obj => "compact" in obj, get: obj => obj.compact, set: (obj, value) => { obj.compact = value; } }, metadata: _metadata }, _compact_initializers, _compact_extraInitializers);
|
|
144
158
|
__esDecorate(this, null, _subtitleField_decorators, { kind: "accessor", name: "subtitleField", static: false, private: false, access: { has: obj => "subtitleField" in obj, get: obj => obj.subtitleField, set: (obj, value) => { obj.subtitleField = value; } }, metadata: _metadata }, _subtitleField_initializers, _subtitleField_extraInitializers);
|
|
145
159
|
__esDecorate(this, null, _cardFields_decorators, { kind: "accessor", name: "cardFields", static: false, private: false, access: { has: obj => "cardFields" in obj, get: obj => obj.cardFields, set: (obj, value) => { obj.cardFields = value; } }, metadata: _metadata }, _cardFields_initializers, _cardFields_extraInitializers);
|
|
160
|
+
__esDecorate(this, null, _imageFields_decorators, { kind: "accessor", name: "imageFields", static: false, private: false, access: { has: obj => "imageFields" in obj, get: obj => obj.imageFields, set: (obj, value) => { obj.imageFields = value; } }, metadata: _metadata }, _imageFields_initializers, _imageFields_extraInitializers);
|
|
146
161
|
__esDecorate(this, null, _openUrl_decorators, { kind: "accessor", name: "openUrl", static: false, private: false, access: { has: obj => "openUrl" in obj, get: obj => obj.openUrl, set: (obj, value) => { obj.openUrl = value; } }, metadata: _metadata }, _openUrl_initializers, _openUrl_extraInitializers);
|
|
147
162
|
__esDecorate(this, null, _open_decorators, { kind: "accessor", name: "open", static: false, private: false, access: { has: obj => "open" in obj, get: obj => obj.open, set: (obj, value) => { obj.open = value; } }, metadata: _metadata }, _open_initializers, _open_extraInitializers);
|
|
148
163
|
__esDecorate(this, null, _expanded_decorators, { kind: "accessor", name: "expanded", static: false, private: false, access: { has: obj => "expanded" in obj, get: obj => obj.expanded, set: (obj, value) => { obj.expanded = value; } }, metadata: _metadata }, _expanded_initializers, _expanded_extraInitializers);
|
|
164
|
+
__esDecorate(this, null, _broken_decorators, { kind: "accessor", name: "broken", static: false, private: false, access: { has: obj => "broken" in obj, get: obj => obj.broken, set: (obj, value) => { obj.broken = value; } }, metadata: _metadata }, _broken_initializers, _broken_extraInitializers);
|
|
149
165
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
150
166
|
}
|
|
151
167
|
static styles = [
|
|
@@ -225,9 +241,18 @@ let MosaicaItemCard = (() => {
|
|
|
225
241
|
.head [part='state'] {
|
|
226
242
|
min-height: 24px;
|
|
227
243
|
}
|
|
228
|
-
[part='field'][data-prose]
|
|
244
|
+
[part='field'][data-prose],
|
|
245
|
+
[part='field'][data-image] {
|
|
229
246
|
grid-column: 1 / -1;
|
|
230
247
|
}
|
|
248
|
+
[part='image'] {
|
|
249
|
+
display: block;
|
|
250
|
+
max-width: 100%;
|
|
251
|
+
max-height: 240px;
|
|
252
|
+
margin-top: 4px;
|
|
253
|
+
border-radius: 6px;
|
|
254
|
+
object-fit: contain;
|
|
255
|
+
}
|
|
231
256
|
[part='field'][data-prose] [part='value'] {
|
|
232
257
|
display: -webkit-box;
|
|
233
258
|
-webkit-line-clamp: 6;
|
|
@@ -317,7 +342,14 @@ let MosaicaItemCard = (() => {
|
|
|
317
342
|
*/
|
|
318
343
|
get cardFields() { return this.#cardFields_accessor_storage; }
|
|
319
344
|
set cardFields(value) { this.#cardFields_accessor_storage = value; }
|
|
320
|
-
#
|
|
345
|
+
#imageFields_accessor_storage = (__runInitializers(this, _cardFields_extraInitializers), __runInitializers(this, _imageFields_initializers, ''));
|
|
346
|
+
/**
|
|
347
|
+
* The fields whose value is the address of an image, separated by spaces or commas. Each is drawn
|
|
348
|
+
* as its image rather than as text.
|
|
349
|
+
*/
|
|
350
|
+
get imageFields() { return this.#imageFields_accessor_storage; }
|
|
351
|
+
set imageFields(value) { this.#imageFields_accessor_storage = value; }
|
|
352
|
+
#openUrl_accessor_storage = (__runInitializers(this, _imageFields_extraInitializers), __runInitializers(this, _openUrl_initializers, ''));
|
|
321
353
|
/**
|
|
322
354
|
* The link template for Open, with `{name}` for the value of the field `name` and `{mosaica_id}`
|
|
323
355
|
* for the item's id. Without it or `open`, there is no Open button.
|
|
@@ -333,6 +365,12 @@ let MosaicaItemCard = (() => {
|
|
|
333
365
|
get expanded() { return this.#expanded_accessor_storage; }
|
|
334
366
|
set expanded(value) { this.#expanded_accessor_storage = value; }
|
|
335
367
|
expandedFor = (__runInitializers(this, _expanded_extraInitializers), null);
|
|
368
|
+
#broken_accessor_storage = __runInitializers(this, _broken_initializers, new Set());
|
|
369
|
+
/** The image addresses that failed to load, shown as text. @internal */
|
|
370
|
+
get broken() { return this.#broken_accessor_storage; }
|
|
371
|
+
set broken(value) { this.#broken_accessor_storage = value; }
|
|
372
|
+
/** `image-fields` as a list, kept in step by `willUpdate`. */
|
|
373
|
+
imageNames = (__runInitializers(this, _broken_extraInitializers), []);
|
|
336
374
|
/** A category value's title as the store holds it, else from the legend or a suggestion page, else its key. */
|
|
337
375
|
titleOf(field, key) {
|
|
338
376
|
return this.resolvedStore?.heldTitle(field, key) ?? keyTitle(this.resolvedStore, field, key);
|
|
@@ -347,6 +385,8 @@ let MosaicaItemCard = (() => {
|
|
|
347
385
|
*/
|
|
348
386
|
willUpdate(changed) {
|
|
349
387
|
super.willUpdate(changed);
|
|
388
|
+
if (changed.has('imageFields'))
|
|
389
|
+
this.imageNames = listed(this.imageFields);
|
|
350
390
|
const { item, meta } = this.shown;
|
|
351
391
|
const id = item?.id ?? null;
|
|
352
392
|
if (id !== this.expandedFor) {
|
|
@@ -484,8 +524,15 @@ let MosaicaItemCard = (() => {
|
|
|
484
524
|
}
|
|
485
525
|
/** The fields of `fields` that `card-fields` names, in its order. */
|
|
486
526
|
named(fields) {
|
|
487
|
-
const names = this.cardFields
|
|
488
|
-
return names.filter((n, i) =>
|
|
527
|
+
const names = listed(this.cardFields);
|
|
528
|
+
return names.filter((n, i) => fields.includes(n) && names.indexOf(n) === i);
|
|
529
|
+
}
|
|
530
|
+
/** The address of the image a field's value names, where `image-fields` lists the field. */
|
|
531
|
+
imageOf(name, value) {
|
|
532
|
+
if (typeof value !== 'string' || !this.imageNames.includes(name))
|
|
533
|
+
return null;
|
|
534
|
+
const address = webAddress(value);
|
|
535
|
+
return address && !this.broken.has(address) ? address : null;
|
|
489
536
|
}
|
|
490
537
|
/** `fields` with those `card-fields` names first, in its order. */
|
|
491
538
|
namedFirst(fields) {
|
|
@@ -547,12 +594,21 @@ let MosaicaItemCard = (() => {
|
|
|
547
594
|
</div>`)}
|
|
548
595
|
</div>`;
|
|
549
596
|
}
|
|
550
|
-
/** One field, presented by its declared type; prose
|
|
597
|
+
/** One field, presented by its declared type; prose and images span the grid. */
|
|
551
598
|
field(name, value, column) {
|
|
599
|
+
const caption = column ? columnCaption(name) : name;
|
|
600
|
+
const image = this.imageOf(name, value);
|
|
601
|
+
if (image) {
|
|
602
|
+
const failed = () => (this.broken = new Set([...this.broken, image]));
|
|
603
|
+
return html `<div part="field" data-name=${name} data-image>
|
|
604
|
+
<span part="label" class="k">${caption}</span>
|
|
605
|
+
<slot name=${`field-${name}`}><img part="image" src=${image} alt=${caption} loading="lazy" referrerpolicy="no-referrer" @error=${failed} /></slot>
|
|
606
|
+
</div>`;
|
|
607
|
+
}
|
|
552
608
|
const text = this.text(name, value, column);
|
|
553
609
|
const prose = text.length > 60;
|
|
554
610
|
return html `<div part="field" data-name=${name} ?data-prose=${prose} style=${prose ? nothing : 'display:contents'}>
|
|
555
|
-
<span part="label" class="k">${
|
|
611
|
+
<span part="label" class="k">${caption}</span>
|
|
556
612
|
<slot name=${`field-${name}`}><span part="value" class="v" title=${prose ? text : nothing}>${text}</span></slot>
|
|
557
613
|
</div>`;
|
|
558
614
|
}
|
|
@@ -573,15 +629,26 @@ function openAddress(template, values) {
|
|
|
573
629
|
missing = true;
|
|
574
630
|
return encodeURIComponent(String(value));
|
|
575
631
|
});
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
632
|
+
return missing ? null : webAddress(filled);
|
|
633
|
+
}
|
|
634
|
+
catch {
|
|
635
|
+
return null;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
/** `text` resolved against the page, where it is an `http:` or `https:` address. */
|
|
639
|
+
function webAddress(text) {
|
|
640
|
+
try {
|
|
641
|
+
const url = new URL(text, document.baseURI);
|
|
579
642
|
return url.protocol === 'http:' || url.protocol === 'https:' ? url.href : null;
|
|
580
643
|
}
|
|
581
644
|
catch {
|
|
582
645
|
return null;
|
|
583
646
|
}
|
|
584
647
|
}
|
|
648
|
+
/** The names in a list separated by spaces or commas. */
|
|
649
|
+
function listed(names) {
|
|
650
|
+
return names.split(/[\s,]+/).filter(Boolean);
|
|
651
|
+
}
|
|
585
652
|
/** A value as text, by the column's declared type. */
|
|
586
653
|
function present(value, column) {
|
|
587
654
|
if (value === null || value === undefined)
|