cedar-embeddable-editor 2.0.1 → 2.0.2
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/CHANGELOG.md +19 -0
- package/README.md +78 -634
- package/bundle-manifest.json +2 -2
- package/cedar-embeddable-editor.d.ts +22 -6
- package/cedar-embeddable-editor.js +78 -78
- package/license.txt +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# CEDAR Embeddable Editor (CEE)
|
|
2
2
|
|
|
3
|
+
[](https://github.com/metadatacenter/cedar-embeddable-editor/actions/workflows/test.yml)
|
|
4
|
+
|
|
3
5
|
The CEDAR Embeddable Editor (CEE) is a reusable Web Component for adding
|
|
4
6
|
structured, standards-based metadata authoring to web applications.
|
|
5
7
|
|
|
6
|
-
CEE dynamically renders data-entry forms from machine-actionable CEDAR
|
|
8
|
+
The CEE dynamically renders data-entry forms from machine-actionable CEDAR
|
|
7
9
|
templates and produces semantically rich metadata as JSON-LD. Templates define
|
|
8
10
|
the fields, constraints, controlled vocabularies, and repeatable structures in a
|
|
9
11
|
form, allowing the metadata-authoring experience to evolve independently of the
|
|
10
|
-
application that embeds it. CEE also supports ontology-backed value selection
|
|
12
|
+
application that embeds it. The CEE also supports ontology-backed value selection
|
|
11
13
|
and persistent identifiers from external authorities such as ORCID and ROR.
|
|
12
14
|
|
|
13
15
|
For the design rationale, architecture, and deployments in research platforms,
|
|
@@ -15,66 +17,14 @@ see [*Author Once, Publish Everywhere: Portable Metadata Authoring with the CEDA
|
|
|
15
17
|
Embeddable Editor*](https://doi.org/10.5334/dsj-2026-002), published in the
|
|
16
18
|
*Data Science Journal* (2026).
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
[CEDAR Embeddable Editor](https://metadatacenter.readthedocs.io/en/latest/cedar-embeddable-editor/intro/).
|
|
21
|
-
|
|
22
|
-
## Browser support
|
|
23
|
-
|
|
24
|
-
CEE supports the browser targets of the Angular version each release is built
|
|
25
|
-
with. It requires native Custom Elements v1 and native Shadow DOM.
|
|
26
|
-
|
|
27
|
-
Automated compatibility tests run against current desktop Chromium, Firefox and
|
|
28
|
-
WebKit engines. Firefox ESR and the configured Edge, Safari and iOS versions are
|
|
29
|
-
compilation targets, but are not all exercised as separate browser products.
|
|
30
|
-
|
|
31
|
-
Internet Explorer, legacy EdgeHTML, and browsers or embedded web views without
|
|
32
|
-
native `window.customElements` and Shadow DOM support are not supported. CEE
|
|
33
|
-
does not polyfill its host page. Consumers choosing to support browsers outside
|
|
34
|
-
this contract must load and maintain their own Web Components polyfills before
|
|
35
|
-
loading CEE.
|
|
36
|
-
|
|
37
|
-
## Running as a standalone application
|
|
38
|
-
|
|
39
|
-
You can run CEE as a standalone application. This is helpful for developers to
|
|
40
|
-
see changes to the code reflected immediately in the application. The standalone
|
|
41
|
-
app fetches a small template and instance from `src/assets/cee-demo` and assigns
|
|
42
|
-
them to `templateAndInstanceObject`, the same way any host supplies an artifact,
|
|
43
|
-
so it needs no separate template server and no `cedar-component-distribution`
|
|
44
|
-
checkout.
|
|
45
|
-
|
|
46
|
-
Proceed with the following steps:
|
|
47
|
-
|
|
48
|
-
### Clone the repository
|
|
20
|
+
For embedding and using the CEE in a web application, see the
|
|
21
|
+
[CEDAR Embeddable Editor documentation](https://metadatacenter.readthedocs.io/en/latest/cedar-embeddable-editor/intro/).
|
|
49
22
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
```shell
|
|
53
|
-
git clone https://github.com/metadatacenter/cedar-embeddable-editor.git
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Edit configuration
|
|
57
|
-
|
|
58
|
-
1. Open the file ```cedar-embeddable-editor/src/app/app.component.dev.ts``` in your favorite editor.
|
|
59
|
-
2. Edit configuration parameters based on your local environment (see section [Configuration](https://github.com/metadatacenter/cedar-embeddable-editor/tree/develop#configuration) for details).
|
|
60
|
-
|
|
61
|
-
### Build the project and start the server
|
|
62
|
-
|
|
63
|
-
1. Navigate to the CEE directory:
|
|
64
|
-
```shell
|
|
65
|
-
$ cd <...>/<clone directory>/cedar-embeddable-editor/
|
|
66
|
-
```
|
|
67
|
-
1. Run these commands:
|
|
68
|
-
```shell
|
|
69
|
-
cedar-embeddable-editor$ npm install
|
|
70
|
-
cedar-embeddable-editor$ ng serve
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
1. In your browser, navigate to `http://localhost:4400/`. The app will automatically reload if you change any of the source files.
|
|
23
|
+
This README covers developing, building, and testing the component.
|
|
74
24
|
|
|
75
25
|
## Building the Web Component
|
|
76
26
|
|
|
77
|
-
CEE is shipped as one JavaScript file that can be embedded in an application or
|
|
27
|
+
The CEE is shipped as one JavaScript file that can be embedded in an application or
|
|
78
28
|
HTML page. Do not concatenate named Angular output files manually: their names,
|
|
79
29
|
locations, and module structure change when Angular changes builders.
|
|
80
30
|
|
|
@@ -87,10 +37,9 @@ npm run build:production
|
|
|
87
37
|
npm run test:visual:prebuilt
|
|
88
38
|
```
|
|
89
39
|
|
|
90
|
-
|
|
91
|
-
tests
|
|
92
|
-
|
|
93
|
-
do, so the dist that ships is produced on the same Node that exercised it.
|
|
40
|
+
Use Node 24.19.0, which `.nvmrc`, `package.json` and CI all specify. The build and
|
|
41
|
+
tests use that same version, so the distribution is produced by the toolchain
|
|
42
|
+
that exercises it.
|
|
94
43
|
|
|
95
44
|
Once that exact bundle is green, stage the publishable npm directory from it:
|
|
96
45
|
|
|
@@ -98,6 +47,10 @@ Once that exact bundle is green, stage the publishable npm directory from it:
|
|
|
98
47
|
npm run package:npm:prebuilt
|
|
99
48
|
```
|
|
100
49
|
|
|
50
|
+
For a release candidate, `npm run test:package` performs both operations in one command: it builds
|
|
51
|
+
and browser-tests the production bundle, then stages and verifies the package from those exact
|
|
52
|
+
tested bytes.
|
|
53
|
+
|
|
101
54
|
This copies the tested bytes to
|
|
102
55
|
`dist-npm/cedar-embeddable-editor/cedar-embeddable-editor.js`, refreshes its
|
|
103
56
|
version, README, changelog, and package lock, and records the bundle manifest.
|
|
@@ -105,37 +58,6 @@ The command fails if the browser bundle is stale or does not match its SHA-256
|
|
|
105
58
|
digest. `npm run check:npm-package` can repeat the byte-for-byte verification
|
|
106
59
|
before `npm pack` or `npm publish`.
|
|
107
60
|
|
|
108
|
-
## Running as an `npm` package
|
|
109
|
-
|
|
110
|
-
Releases are published to npmjs.org as
|
|
111
|
-
[`cedar-embeddable-editor`](https://www.npmjs.com/package/cedar-embeddable-editor)
|
|
112
|
-
under the `latest` tag, so an embedder installs the current one by name:
|
|
113
|
-
|
|
114
|
-
```shell
|
|
115
|
-
npm install cedar-embeddable-editor
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
`1.6.0` is current on npmjs.org.
|
|
119
|
-
|
|
120
|
-
Dev snapshots go somewhere else: the BMIR Nexus, as the scoped
|
|
121
|
-
`@org.metadatacenter/cedar-embeddable-editor` under a `dev` tag. `scripts/npm-package.mjs`
|
|
122
|
-
derives which from the version — a `-dev.` in it selects the scoped name and the Nexus
|
|
123
|
-
registry, and anything else the unscoped name and the default one — so the two channels
|
|
124
|
-
cannot be confused by a flag someone forgets to pass. npm routes by scope rather than by
|
|
125
|
-
package name, which is what lets one package come from Nexus while everything else resolves
|
|
126
|
-
from npmjs.org.
|
|
127
|
-
|
|
128
|
-
A CEDAR frontend names a snapshot through an npm alias:
|
|
129
|
-
|
|
130
|
-
```json
|
|
131
|
-
"cedar-embeddable-editor": "npm:@org.metadatacenter/cedar-embeddable-editor@2.0.0-dev.20260816.5e7dca6"
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
Cutting one is in
|
|
135
|
-
[CEE-RUNBOOK.md](https://github.com/metadatacenter/cedar-development/blob/develop/ops/CEE-RUNBOOK.md),
|
|
136
|
-
including the version convention and which host needs what afterwards. Publishing needs the
|
|
137
|
-
Nexus credential; reads are anonymous.
|
|
138
|
-
|
|
139
61
|
## Testing
|
|
140
62
|
|
|
141
63
|
The complete test gate is available from the repository root:
|
|
@@ -165,8 +87,8 @@ The domain corpora are checked into `harness/fixtures/`; running the tests does
|
|
|
165
87
|
not require `cedar-artifact-library` or `cedar-test-artifacts` checkouts.
|
|
166
88
|
|
|
167
89
|
`.github/workflows/test.yml` runs the same gate on every pull request and on
|
|
168
|
-
pushes to `main
|
|
169
|
-
|
|
90
|
+
pushes to `main` and `develop`. Nothing is published from CI: releasing is a
|
|
91
|
+
separate, manual procedure.
|
|
170
92
|
|
|
171
93
|
### Auditing what ships
|
|
172
94
|
|
|
@@ -179,17 +101,18 @@ the one that describes the shipped artifact, and it is deliberately not part of
|
|
|
179
101
|
`test:ci` — it can fail on a disclosure rather than on a commit, which would
|
|
180
102
|
break an unrelated pull request its author cannot fix.
|
|
181
103
|
|
|
182
|
-
A root `npm audit` reports
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
104
|
+
A root `npm audit` also reports on development tooling that is not shipped to an
|
|
105
|
+
embedder. **Never run `npm audit fix --force` here:** it can replace the declared
|
|
106
|
+
toolchain with incompatible major versions. Review and update affected
|
|
107
|
+
dependencies explicitly instead.
|
|
186
108
|
|
|
187
109
|
### First-time setup
|
|
188
110
|
|
|
189
|
-
CEE resolves
|
|
190
|
-
|
|
111
|
+
The CEE resolves `cedar-model-typescript-library` from npmjs.org, so a sibling
|
|
112
|
+
checkout is not needed:
|
|
191
113
|
|
|
192
114
|
```shell
|
|
115
|
+
nvm use
|
|
193
116
|
npm ci
|
|
194
117
|
npm --prefix harness ci
|
|
195
118
|
```
|
|
@@ -198,37 +121,21 @@ The visual suite installs nothing here. It runs inside Playwright's own containe
|
|
|
198
121
|
which carries the browsers it drives, and installs its dependencies there against a
|
|
199
122
|
named volume — so it needs Docker running and no `playwright install` of its own.
|
|
200
123
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
The root `.nvmrc` pins the Node version used to update, lint and compile the
|
|
204
|
-
current Angular version. Move that pin with each completed framework hop.
|
|
124
|
+
The CEE uses Angular 22.1 and Node 24.19.0. `.nvmrc`, the package `engines` field and
|
|
125
|
+
CI specify the Node version.
|
|
205
126
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
is the active LTS where 22 is in maintenance, so that is the one CEE uses.
|
|
209
|
-
|
|
210
|
-
Build and test share it. Through Angular 14 they could not: no Node version
|
|
211
|
-
satisfied both that toolchain and the test tools, so CI built on one and switched
|
|
212
|
-
the runner to another without replacing `dist`. `npm run test:ci:prebuilt` is what
|
|
213
|
-
remains of that arrangement — it tests an already-built artifact and deliberately
|
|
214
|
-
does not invoke `ng build`, which is still what CI wants, because it means the
|
|
215
|
-
bytes tested are the bytes that ship.
|
|
216
|
-
|
|
217
|
-
Only that one package comes from Nexus; everything else resolves from npmjs.org.
|
|
218
|
-
An `.npmrc` alongside each of the three `package.json` files maps the
|
|
219
|
-
`@org.metadatacenter` scope to Nexus, and reads need no credentials.
|
|
220
|
-
|
|
221
|
-
Each manifest depends on it under an alias:
|
|
127
|
+
The application bundle and the visual fixture generator each install the model
|
|
128
|
+
library directly from npmjs.org:
|
|
222
129
|
|
|
223
130
|
```json
|
|
224
|
-
"cedar-model-typescript-library": "
|
|
131
|
+
"cedar-model-typescript-library": "<version>"
|
|
225
132
|
```
|
|
226
133
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
installation.
|
|
134
|
+
Keep the version in the root and `visual/` manifests, and both lockfiles, in
|
|
135
|
+
sync. The production bundle imports the root copy while the browser fixtures are
|
|
136
|
+
generated with the visual copy, so a mismatch means the tests and the artifact
|
|
137
|
+
are using different model contracts. The harness declares no separate copy; it
|
|
138
|
+
resolves the root installation.
|
|
232
139
|
|
|
233
140
|
### Focused test commands
|
|
234
141
|
|
|
@@ -246,539 +153,76 @@ npm run test:visual # production build, fixture preparation, Playwrigh
|
|
|
246
153
|
`npm test` runs the unit tests once, and `npm run test:watch` keeps them running
|
|
247
154
|
for interactive development. Use `npm run test:ci` for a complete verification.
|
|
248
155
|
|
|
249
|
-
The unit tests run in Node
|
|
250
|
-
|
|
251
|
-
took the suite from a Chrome launch to about a second. Anything that does need a
|
|
252
|
-
real browser belongs in the Playwright suite under `visual/`, which tests the
|
|
156
|
+
The unit tests run in Node and do not use `TestBed` or Angular's JIT compiler.
|
|
157
|
+
Browser behavior belongs in the Playwright suite under `visual/`, which tests the
|
|
253
158
|
shipped bundle rather than the sources.
|
|
254
159
|
|
|
255
|
-
##
|
|
256
|
-
|
|
257
|
-
### Configuration file
|
|
258
|
-
|
|
259
|
-
The CEE configuration file format and storage location depends on the application and the mode in which CEE is being used.
|
|
260
|
-
|
|
261
|
-
* When running CEE in the standalone mode (developer mode), the configuration parameters are stored in and read from the file: `src/app/app.component.dev.ts`.
|
|
262
|
-
* When running CEE as a generic Webcomponent, the configuration parameters can be stored in any `.json` file that is visible to the application that embeds CEE Webcomponent. Fetch it and assign the result:
|
|
263
|
-
```javascript
|
|
264
|
-
customElements.whenDefined('cedar-embeddable-editor').then(async () => {
|
|
265
|
-
const cee = document.querySelector('cedar-embeddable-editor');
|
|
266
|
-
cee.config = await (await fetch('assets/data/cee-config.json')).json();
|
|
267
|
-
});
|
|
268
|
-
```
|
|
269
|
-
* The configuration can also be passed into the editor as a json map. In Angular this looks as follows:
|
|
270
|
-
```html
|
|
271
|
-
<cedar-embeddable-editor
|
|
272
|
-
[config]="conf"
|
|
273
|
-
[templateObject]="template"
|
|
274
|
-
[instanceObject]="instance"
|
|
275
|
-
></cedar-embeddable-editor>
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
### Required configuration parameters
|
|
280
|
-
|
|
281
|
-
Two keys name the CEDAR services CEE calls, and neither has a default. CEE cannot
|
|
282
|
-
know which deployment it is embedded in, and a default would name one — so a key
|
|
283
|
-
left unset turns its lookups off and CEE reports which key is missing, rather than
|
|
284
|
-
sending a host's users' keystrokes to somebody else's server.
|
|
285
|
-
|
|
286
|
-
Both are bases and both must end in a slash. Every path below them is CEE's own.
|
|
287
|
-
|
|
288
|
-
* **terminologyBaseUrl:** the CEDAR terminology server, which searches BioPortal.
|
|
289
|
-
Unset, controlled fields offer no terms.
|
|
290
|
-
* **bridgeBaseUrl:** the CEDAR bridge server, which reaches the external
|
|
291
|
-
authorities. Unset, the seven authority fields offer no terms and resolve no
|
|
292
|
-
identifiers.
|
|
293
|
-
|
|
294
|
-
```json
|
|
295
|
-
{
|
|
296
|
-
"terminologyBaseUrl": "https://terminology.metadatacenter.org/",
|
|
297
|
-
"bridgeBaseUrl": "https://bridge.metadatacenter.org/"
|
|
298
|
-
}
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
### Optional configuration parameters
|
|
302
|
-
|
|
303
|
-
Every other key is optional. The defaults below are the component's own, read
|
|
304
|
-
from `CedarEmbeddableMetadataEditorComponent` and its wrapper, not from the
|
|
305
|
-
standalone developer app in `src/app/app.component.dev.ts`, whose values differ.
|
|
306
|
-
|
|
307
|
-
What the user sees:
|
|
308
|
-
|
|
309
|
-
| Key | Default |
|
|
310
|
-
|---|---|
|
|
311
|
-
| `showTemplateDescription` | `false` |
|
|
312
|
-
|
|
313
|
-
CEE draws no page chrome of its own. It used to render a header carrying the CEDAR
|
|
314
|
-
logo and title, and a footer carrying the Stanford Division of Computational
|
|
315
|
-
Medicine mark and a contact link, behind `showHeader` and `showFooter`. Every string
|
|
316
|
-
and destination was hardcoded, so an embedder took CEDAR's branding or nothing.
|
|
317
|
-
A host renders its own header and footer around the element; the standalone app in
|
|
318
|
-
`src/app/app.component.dev.html` is a worked example.
|
|
319
|
-
|
|
320
|
-
What CEE keeps is the CEDAR mark and the version stamp inside the form's own title
|
|
321
|
-
block, which is a component naming itself rather than dressing someone else's page.
|
|
322
|
-
|
|
323
|
-
Editing behaviour and serialization:
|
|
324
|
-
|
|
325
|
-
| Key | Default |
|
|
326
|
-
|---|---|
|
|
327
|
-
| `readOnlyMode` | `false` |
|
|
328
|
-
| `trustTemplateRichText` | `false` |
|
|
329
|
-
|
|
330
|
-
`showDownloadMenu` offers a menu that saves CEE's views of the artifact as files.
|
|
331
|
-
It defaults to `false`, and nothing is rendered under the form either way:
|
|
332
|
-
|
|
333
|
-
| Menu entry | Saves | As |
|
|
334
|
-
|---|---|---|
|
|
335
|
-
| JSON-LD - Instance | The instance as a CEDAR document | `<name>-instance.json` |
|
|
336
|
-
| YAML - Instance | The same instance, as CEDAR YAML | `<name>-instance.yaml` |
|
|
337
|
-
| Compact YAML - Instance | The same instance without root identity and provenance metadata | `<name>-instance-compact.yaml` |
|
|
338
|
-
| JSON Schema - Template | The template as the host supplied it | `<name>-template.json` |
|
|
339
|
-
| YAML - Template | The same template, as CEDAR YAML | `<name>-template.yaml` |
|
|
340
|
-
| Compact YAML - Template | Its compact authoring form, without repository-managed metadata | `<name>-template-compact.yaml` |
|
|
341
|
-
| Data Quality Report | Required-field tally and constraint violations | `<name>-data-quality.json` |
|
|
342
|
-
|
|
343
|
-
`<name>` is the template's own `schema:name`, reduced to file-name-safe
|
|
344
|
-
characters, so a developer with several forms open can tell the files apart.
|
|
345
|
-
|
|
346
|
-
These were eight panels once, each printing a dump under the form, and each
|
|
347
|
-
costing two keys — one to show it and one to expand it. Two of the sixteen were
|
|
348
|
-
on by default, so an embedder who configured nothing got a JSON Schema dump and
|
|
349
|
-
a JSON-LD dump beneath every form.
|
|
350
|
-
|
|
351
|
-
A download is started by the page, which a host running under a restrictive
|
|
352
|
-
sandbox can refuse, with no event to observe when it does. CEE traces each
|
|
353
|
-
attempt through the event handler, so a developer seeing the trace and no file
|
|
354
|
-
knows to look at their own sandbox.
|
|
355
|
-
|
|
356
|
-
Language:
|
|
357
|
-
|
|
358
|
-
| Key | Default |
|
|
359
|
-
|---|---|
|
|
360
|
-
| `defaultLanguage` | `en` |
|
|
361
|
-
| `fallbackLanguage` | `en` |
|
|
362
|
-
| `languageMapPathPrefix` | none |
|
|
363
|
-
|
|
364
|
-
`trustTemplateRichText` decides whether a template author's rich text renders verbatim
|
|
365
|
-
or is sanitized first. It defaults to `false` and should stay there unless your
|
|
366
|
-
application controls which templates load — see [Embedding security](#embedding-security).
|
|
367
|
-
|
|
368
|
-
`bridgeBaseUrl` is the whole of the external-authority surface, covering the
|
|
369
|
-
seven authorities: ORCID, ROR, PFAS, PubMed, RRID, NIH Grant and DOI. CEE appends
|
|
370
|
-
the bridge server's `ext-auth/` resource, then the path for the authority a field
|
|
371
|
-
is bound to — a search path for a name typed into it, and a details path for an
|
|
372
|
-
identifier pasted into it. All of that is the bridge server's own route shape, so
|
|
373
|
-
none of it is configurable: a deployment moves all fourteen endpoints by moving
|
|
374
|
-
the base, or none of them.
|
|
375
|
-
|
|
376
|
-
| Authority | Search path | Details path |
|
|
377
|
-
|---|---|---|
|
|
378
|
-
| ORCID | `orcid/search-by-name` | `orcid` |
|
|
379
|
-
| ROR | `ror/search-by-name` | `ror` |
|
|
380
|
-
| PFAS | `comp-tox/search-by-name` | `comp-tox` |
|
|
381
|
-
| PubMed | `pmid/search-by-name` | `pmid` |
|
|
382
|
-
| RRID | `rrid/search-by-name` | `rrid` |
|
|
383
|
-
| NIH Grant | `nih-grant/search-by-name` | `nih-grant` |
|
|
384
|
-
| DOI | `doi/search-by-name` | `doi` |
|
|
385
|
-
|
|
386
|
-
### TypeScript types
|
|
387
|
-
|
|
388
|
-
The package ships declarations. A host importing them gets a checked configuration
|
|
389
|
-
object and a typed element:
|
|
390
|
-
|
|
391
|
-
```ts
|
|
392
|
-
import type { CeeConfig, CedarEmbeddableEditorElement } from 'cedar-embeddable-editor';
|
|
393
|
-
|
|
394
|
-
const config: CeeConfig = { readOnlyMode: true, showDownloadMenu: true };
|
|
395
|
-
|
|
396
|
-
// Typed by the package, with no cast: it declares the tag in HTMLElementTagNameMap.
|
|
397
|
-
const cee = document.querySelector('cedar-embeddable-editor');
|
|
398
|
-
cee!.config = config;
|
|
399
|
-
const report = cee!.dataQualityReport; // CeeDataQualityReport
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
The declarations are **types only**. The bundle is a script that registers a custom
|
|
403
|
-
element and exports no values, so there is nothing to import at runtime — use
|
|
404
|
-
`import type`, and let the interface rather than a constant catch a mistyped key.
|
|
405
|
-
|
|
406
|
-
If you are not using TypeScript, or your configuration comes from a JSON file no
|
|
407
|
-
compiler has seen, CEE checks it at runtime instead and reports what it cannot use.
|
|
408
|
-
An unknown key is named, with the nearest real key suggested; a value of the wrong
|
|
409
|
-
kind says what was expected; and settings that conflict are called out. The messages
|
|
410
|
-
go to the console and to any `eventHandler` you registered:
|
|
411
|
-
|
|
412
|
-
```
|
|
413
|
-
CEE ERROR: Unknown configuration key "readOnlyMod". It has no effect. Did you mean "readOnlyMode"?
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
A key CEE cannot use is reported *and* refused: it reads as unset, so the setting
|
|
417
|
-
keeps the default it documents. One bad key costs only that key — every other key in
|
|
418
|
-
the same configuration applies. CEE does not repair a value either, so a base URL
|
|
419
|
-
missing its trailing slash is dropped rather than completed, since appending CEE's
|
|
420
|
-
own path to it would name an endpoint nobody chose.
|
|
421
|
-
|
|
422
|
-
An assignment that is not an object at all configures nothing and does not spend the
|
|
423
|
-
one assignment there is, so your next attempt is still your first.
|
|
424
|
-
|
|
425
|
-
Configuration and the artifact inputs take one assignment each and keep it. Assign
|
|
426
|
-
`config` a second time, or an artifact input a second time, and CEE reports it and
|
|
427
|
-
ignores it: the first value stands. Build the configuration you want, assign it once,
|
|
428
|
-
and create a new element if it has to change. `eventHandler` is the exception and may
|
|
429
|
-
be replaced, with the last handler assigned receiving — register it before the
|
|
430
|
-
configuration and the artifact if you want the diagnostics from those, since a
|
|
431
|
-
handler hears only what follows it.
|
|
432
|
-
|
|
433
|
-
The same handler provides the lifecycle signal a host can use instead of polling
|
|
434
|
-
the DOM. `ready` is called once after the element's first successful form render;
|
|
435
|
-
it is not called for a rejected artifact and is not replayed to a handler attached
|
|
436
|
-
after rendering:
|
|
437
|
-
|
|
438
|
-
```javascript
|
|
439
|
-
cee.eventHandler = {
|
|
440
|
-
error: (message) => console.error(message),
|
|
441
|
-
ready: () => startAutosave(),
|
|
442
|
-
};
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
`readOnlyMode` is the only way in or out of read-only mode. CEE used to offer the
|
|
446
|
-
user a switch of its own, in a preferences menu, which wrote to the same state the
|
|
447
|
-
widgets read — so a form you embedded as a viewer could be made editable from inside
|
|
448
|
-
it. Both are gone, along with the `showPreferencesMenu` key that governed the menu.
|
|
449
|
-
|
|
450
|
-
## Embedding security
|
|
451
|
-
|
|
452
|
-
CEE renders inside your page, in your origin. It is a custom element using Shadow
|
|
453
|
-
DOM, and **Shadow DOM is not a security boundary**: it scopes styles and markup, not
|
|
454
|
-
privileges. Anything CEE executes runs with the same access to cookies, storage and
|
|
455
|
-
network as the rest of your application.
|
|
456
|
-
|
|
457
|
-
That matters for one input in particular.
|
|
458
|
-
|
|
459
|
-
### Templates are trusted input
|
|
460
|
-
|
|
461
|
-
A template can carry a **static rich-text field**, whose body is HTML composed by the
|
|
462
|
-
template's author and rendered as HTML by CEE. Instance data is different and is
|
|
463
|
-
always sanitized — a value a form's user typed can never introduce markup that runs.
|
|
464
|
-
The question is only what a *template author* may do.
|
|
465
|
-
|
|
466
|
-
CEE sanitizes template rich text by default. Script elements, event-handler
|
|
467
|
-
attributes such as `onerror`, `javascript:` URLs, `iframe`, `form` controls and
|
|
468
|
-
AngularJS directive attributes such as `ng-click` are removed. Formatting is
|
|
469
|
-
preserved: inline styles, tables, lists, headings, links, and inline `data:` images
|
|
470
|
-
in the raster formats all render as the author composed them.
|
|
160
|
+
## Running
|
|
471
161
|
|
|
472
|
-
|
|
473
|
-
come from a source you control — you may prefer the author's markup to render exactly
|
|
474
|
-
as written:
|
|
162
|
+
### As an `npm` package
|
|
475
163
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
}
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
**Only set this if template authors are as trusted as your own application code.**
|
|
483
|
-
With it on, a template author can run JavaScript in your origin. "Allowed to define a
|
|
484
|
-
form" and "allowed to run code in this page" are very different permissions, and this
|
|
485
|
-
key is where you say they are the same for your deployment.
|
|
486
|
-
|
|
487
|
-
In particular, **do not set it if your users choose their own templates** — from
|
|
488
|
-
CEDAR's public library, or from anywhere your users can write to. Leave it off and
|
|
489
|
-
CEE will render the formatting without the risk.
|
|
490
|
-
|
|
491
|
-
### What is sanitized where
|
|
492
|
-
|
|
493
|
-
| Content | Origin | Treatment |
|
|
494
|
-
|---|---|---|
|
|
495
|
-
| Static rich-text field body | Template author | Sanitized, unless `trustTemplateRichText` is on |
|
|
496
|
-
| Static section break, image, YouTube | Template author | Not rendered as HTML; content is used as text or a URL |
|
|
497
|
-
| Field values, in the form and in read-only view | Instance data | Always sanitized. Not configurable |
|
|
498
|
-
|
|
499
|
-
## Metadata API
|
|
500
|
-
|
|
501
|
-
CEE Webcomponent includes APIs for exporting metadata externally and importing metadata into CEE.
|
|
502
|
-
|
|
503
|
-
### Metadata Export
|
|
504
|
-
|
|
505
|
-
The metadata currently being edited inside CEE can be exported at anytime by making this API call:
|
|
506
|
-
|
|
507
|
-
```javascript
|
|
508
|
-
const meta = cee.currentMetadata;
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
`currentMetadata` always returns a CEDAR JSON object. For YAML, read the
|
|
512
|
-
companion accessor instead:
|
|
513
|
-
|
|
514
|
-
```javascript
|
|
515
|
-
const yaml = cee.currentMetadataYaml; // always a YAML string
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
Either accessor works whatever form the template arrived in. A template written
|
|
519
|
-
as CEDAR YAML is assigned to `templateObject` like any other, as the parsed YAML
|
|
520
|
-
object rather than the YAML source string, and CEE picks the reader from the
|
|
521
|
-
template's own shape:
|
|
522
|
-
|
|
523
|
-
```javascript
|
|
524
|
-
cee.templateObject = parsedTemplateYaml;
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
In the example below, the metadata is sent to an external endpoint every 15 seconds:
|
|
528
|
-
|
|
529
|
-
```javascript
|
|
530
|
-
customElements.whenDefined('cedar-embeddable-editor').then(async () => {
|
|
531
|
-
const cee = document.querySelector('cedar-embeddable-editor');
|
|
532
|
-
cee.config = await (await fetch('assets/data/cee-config.json')).json();
|
|
533
|
-
const saveTime = 15000; // 15 seconds
|
|
534
|
-
|
|
535
|
-
setInterval(() => {
|
|
536
|
-
const meta = cee.currentMetadata;
|
|
537
|
-
|
|
538
|
-
const xhr = new XMLHttpRequest();
|
|
539
|
-
xhr.open("POST", "http://localhost:8001/metadatasave.php");
|
|
540
|
-
xhr.setRequestHeader("Accept", "application/json");
|
|
541
|
-
xhr.setRequestHeader("Content-Type", "application/json");
|
|
542
|
-
xhr.send(JSON.stringify(meta, null, 2));
|
|
543
|
-
console.log('Saved metadata after ' + saveTime / 1000 + ' seconds');
|
|
544
|
-
}, saveTime);
|
|
545
|
-
});
|
|
546
|
-
```
|
|
547
|
-
|
|
548
|
-
### Template Injection
|
|
549
|
-
|
|
550
|
-
You can inject your template into CEE:
|
|
551
|
-
|
|
552
|
-
```javascript
|
|
553
|
-
cee.templateObject = yourCustomTemplateJson;
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
### Metadata Injection
|
|
557
|
-
|
|
558
|
-
You can inject your metadata into CEE, provided it matches the template currently being edited:
|
|
559
|
-
|
|
560
|
-
```javascript
|
|
561
|
-
cee.instanceObject = yourCustomMetadataJson
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
`templateObject` and `instanceObject` are independent, and either may be assigned
|
|
565
|
-
first: CEE does not build the form until a template is present, so an instance
|
|
566
|
-
supplied ahead of one waits rather than loading against nothing.
|
|
567
|
-
|
|
568
|
-
Each takes one assignment. Fetch the metadata before you assign it, rather than
|
|
569
|
-
assigning a placeholder and correcting it once the fetch lands:
|
|
570
|
-
|
|
571
|
-
```javascript
|
|
572
|
-
customElements.whenDefined('cedar-embeddable-editor').then(async () => {
|
|
573
|
-
const cee = document.querySelector('cedar-embeddable-editor');
|
|
574
|
-
cee.config = await (await fetch('assets/data/cee-config.json')).json();
|
|
575
|
-
cee.instanceObject = await (await fetch('uploads/metadata-for-restore.json')).json();
|
|
576
|
-
cee.templateObject = yourCustomTemplateJson;
|
|
577
|
-
});
|
|
578
|
-
```
|
|
579
|
-
|
|
580
|
-
An instance counts only after CEE can read it. If deserialization fails, CEE
|
|
581
|
-
reports the rejection to the console and to `eventHandler`, does not render a
|
|
582
|
-
replacement empty form, and leaves the instance assignment available for a
|
|
583
|
-
corrected value. The same rule applies to the instance inside
|
|
584
|
-
`templateAndInstanceObject`; a rejected combined value spends neither artifact
|
|
585
|
-
assignment.
|
|
586
|
-
|
|
587
|
-
To load a different instance, create a new element. Reassigning `instanceObject`
|
|
588
|
-
reports an error and leaves the first instance in place.
|
|
589
|
-
|
|
590
|
-
To reiterate, the metadata being injected **MUST** match the template currently being edited and open in your browser window.
|
|
591
|
-
|
|
592
|
-
### Injecting Template And Metadata Together
|
|
593
|
-
|
|
594
|
-
You can inject your template and metadata together into CEE:
|
|
595
|
-
|
|
596
|
-
```javascript
|
|
597
|
-
const templateAndInstance = {templateObject: object, instanceObject: object};
|
|
598
|
-
cee.templateAndInstanceObject = templateAndInstance;
|
|
599
|
-
```
|
|
600
|
-
|
|
601
|
-
Injecting template and metadata together brings performance benefits as well as allows configuring hiding empty fields.
|
|
602
|
-
Object being injected must strictly have two objects one named 'templateObject' and the other 'instanceObject'.
|
|
603
|
-
|
|
604
|
-
### Temporal Values
|
|
605
|
-
|
|
606
|
-
CEE treats a temporal field's declared `temporalType`, `temporalGranularity`
|
|
607
|
-
and `timezoneEnabled` settings as its storage contract. The editor shows only
|
|
608
|
-
the parts named by that contract and emits a complete lexical `xsd:date`,
|
|
609
|
-
`xsd:time` or `xsd:dateTime` value:
|
|
610
|
-
|
|
611
|
-
| Declared precision | Canonical stored example |
|
|
612
|
-
| --- | --- |
|
|
613
|
-
| date, year | `2026-01-01` |
|
|
614
|
-
| date, month | `2026-08-01` |
|
|
615
|
-
| date, day | `2026-08-09` |
|
|
616
|
-
| time, hour | `21:00:00` |
|
|
617
|
-
| time, minute | `21:45:00` |
|
|
618
|
-
| time, second | `21:45:32` |
|
|
619
|
-
| time, decimal second | `21:45:32.001` |
|
|
620
|
-
| date-time, day | `2026-08-09T00:00:00` |
|
|
621
|
-
| date-time, minute | `2026-08-09T21:45:00` |
|
|
622
|
-
|
|
623
|
-
The same padding rule applies to the other date-time granularities. If time
|
|
624
|
-
zones are enabled, CEE appends the selected fixed offset (`Z` or `+/-HH:mm`);
|
|
625
|
-
if they are disabled, any offset is removed.
|
|
626
|
-
|
|
627
|
-
Granularity is authoritative when an existing instance is loaded. Information
|
|
628
|
-
finer than the declared granularity is intentionally discarded and the
|
|
629
|
-
canonical value is written back. For example,
|
|
630
|
-
`2026-08-09T21:45:32.125-07:00` in a day-granularity date-time field becomes
|
|
631
|
-
`2026-08-09T00:00:00-07:00`. Embedders should account for that normalization
|
|
632
|
-
when comparing a saved instance with its original input.
|
|
633
|
-
|
|
634
|
-
### Data Quality Report
|
|
635
|
-
|
|
636
|
-
The dataQualityReport summarizes basic metrics on the instance data.
|
|
637
|
-
|
|
638
|
-
```javascript
|
|
639
|
-
const report = cee.dataQualityReport;
|
|
640
|
-
```
|
|
641
|
-
|
|
642
|
-
The report answers two questions: is anything required missing, and is anything
|
|
643
|
-
present invalid.
|
|
164
|
+
Releases are published to npmjs.org as
|
|
165
|
+
[`cedar-embeddable-editor`](https://www.npmjs.com/package/cedar-embeddable-editor)
|
|
166
|
+
under the `latest` tag, so an embedder installs the current one by name:
|
|
644
167
|
|
|
645
|
-
```
|
|
646
|
-
|
|
647
|
-
nonNullRequiredFieldValueCount: int
|
|
648
|
-
problems: ValidationProblem[]
|
|
649
|
-
isValid: boolean
|
|
168
|
+
```shell
|
|
169
|
+
npm install cedar-embeddable-editor
|
|
650
170
|
```
|
|
651
171
|
|
|
652
|
-
`
|
|
172
|
+
The `latest` tag is the public stable channel. To see the current release without
|
|
173
|
+
depending on a version copied into this README:
|
|
653
174
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
```javascript
|
|
657
|
-
{
|
|
658
|
-
path: ['_author', '_email'], // component path from the template root
|
|
659
|
-
field: '_email',
|
|
660
|
-
inputType: 'email',
|
|
661
|
-
code: 'email', // stable, matchable without parsing the message
|
|
662
|
-
message: 'Not a valid email address.',
|
|
663
|
-
value: 'not-an-email'
|
|
664
|
-
}
|
|
175
|
+
```shell
|
|
176
|
+
npm view cedar-embeddable-editor version
|
|
665
177
|
```
|
|
666
178
|
|
|
667
|
-
|
|
668
|
-
email, link, phone and external-authority IRI format; numeric type — including
|
|
669
|
-
`xsd:decimal`, `xsd:byte` and `xsd:short` — with the type's own range,
|
|
670
|
-
`minValue`, `maxValue` and `decimalPlace`; temporal shape against
|
|
671
|
-
`temporalType`, `granularity` and `timezoneEnabled`, plus calendar validity;
|
|
672
|
-
membership of a value in its declared choice literals; `minItems` and
|
|
673
|
-
`maxItems`; and the structure of a controlled-term value.
|
|
674
|
-
|
|
675
|
-
Controlled-term **membership** — whether a term belongs to the declared
|
|
676
|
-
ontologies, value sets, classes or branches — is not checked. It requires the
|
|
677
|
-
terminology server, and a local synchronous report should not depend on the
|
|
678
|
-
network. Structural checks on controlled values (`@id` and `rdfs:label` present
|
|
679
|
-
as a pair, `@id` well-formed) are performed.
|
|
680
|
-
|
|
681
|
-
An absent value produces no constraint problems; that is the required check's
|
|
682
|
-
business, so an empty form reports what is missing rather than also reporting
|
|
683
|
-
every blank as malformed.
|
|
684
|
-
|
|
685
|
-
### Language Maps / Translations
|
|
179
|
+
### As a standalone application
|
|
686
180
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
If you wish to change the language to another built-in one (currently the only other language is `Hungarian`), specify the config like below:
|
|
690
|
-
|
|
691
|
-
```json
|
|
692
|
-
{
|
|
693
|
-
"defaultLanguage": "hu",
|
|
694
|
-
"fallbackLanguage": "en"
|
|
695
|
-
}
|
|
696
|
-
```
|
|
181
|
+
You can run the CEE as a standalone application. This is helpful for developers to
|
|
182
|
+
see changes to the code reflected immediately in the application.
|
|
697
183
|
|
|
698
|
-
|
|
184
|
+
Proceed with the following steps:
|
|
699
185
|
|
|
700
|
-
|
|
186
|
+
#### Clone the repository
|
|
701
187
|
|
|
702
|
-
|
|
188
|
+
Clone this repository onto a local directory of your choice:
|
|
703
189
|
|
|
704
|
-
```
|
|
705
|
-
|
|
706
|
-
"languageMapPathPrefix": "/assets/i18n-cee/",
|
|
707
|
-
"defaultLanguage": "de",
|
|
708
|
-
"fallbackLanguage": "en"
|
|
709
|
-
}
|
|
190
|
+
```shell
|
|
191
|
+
git clone https://github.com/metadatacenter/cedar-embeddable-editor.git
|
|
710
192
|
```
|
|
711
193
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
In our case the `/assets/i18n-cee/de.json` will be loaded if present.
|
|
715
|
-
|
|
716
|
-
If the file is missing, the `/assets/i18n-cee/en.json` will be used.
|
|
717
|
-
|
|
718
|
-
If that file is also missing, the built-in `de` map would be the next. As this does not exist at this moment, the last option, the built-in `en` map will be used.
|
|
719
|
-
|
|
720
|
-
Information about the loading process is logged onto the console with the `CEE TRACE` prefix.
|
|
721
|
-
|
|
722
|
-
### Listening for changes
|
|
194
|
+
#### Edit configuration
|
|
723
195
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
blur, paging, read-only controls, and a write that leaves `currentMetadata` unchanged
|
|
727
|
-
produce no event. Field edits, clears, controlled-term selections, and multi-instance
|
|
728
|
-
add, copy, and delete operations do.
|
|
729
|
-
|
|
730
|
-
The event is a `CustomEvent<CeeChangeDetail>`. Its detail carries the operation,
|
|
731
|
-
template path, supplied value, current validity and full data-quality report, plus
|
|
732
|
-
the current title and description. Multi-instance details also retain their former
|
|
733
|
-
`message` name for compatibility.
|
|
734
|
-
|
|
735
|
-
The package's custom-element declaration types the listener and its detail without
|
|
736
|
-
a cast:
|
|
196
|
+
Open the standalone application's configuration file, `src/app/app.component.dev.ts`.
|
|
197
|
+
This minimal configuration enables lookups through the public CEDAR services:
|
|
737
198
|
|
|
738
199
|
```typescript
|
|
739
|
-
import type {
|
|
740
|
-
|
|
741
|
-
const cee = document.querySelector('cedar-embeddable-editor');
|
|
742
|
-
if (!cee) throw new Error('CEE element is missing');
|
|
200
|
+
import type { CeeConfig } from 'cedar-embeddable-editor';
|
|
743
201
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
});
|
|
202
|
+
const ceeConfig: CeeConfig = {
|
|
203
|
+
terminologyBaseUrl: 'https://terminology.metadatacenter.org/',
|
|
204
|
+
bridgeBaseUrl: 'https://bridge.metadatacenter.org/',
|
|
205
|
+
};
|
|
749
206
|
```
|
|
750
207
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
The optional `eventHandler.valueChanged(path, value)` callback receives the same
|
|
756
|
-
field mutations. It is not a dirty flag: only the host knows which serialization
|
|
757
|
-
was last loaded or saved. Keep that baseline in the host and compare
|
|
758
|
-
`cee.currentMetadata` after each `change`; doing so also clears dirty state when an
|
|
759
|
-
edit is undone.
|
|
208
|
+
For a different CEDAR deployment, replace both URLs with its service URLs. See
|
|
209
|
+
the [configuration documentation](https://metadatacenter.readthedocs.io/en/latest/cedar-embeddable-editor/configuration/)
|
|
210
|
+
for all available settings.
|
|
760
211
|
|
|
761
|
-
|
|
212
|
+
#### Build the project and start the server
|
|
762
213
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
```json
|
|
766
|
-
"readOnlyMode": true
|
|
767
|
-
```
|
|
768
|
-
When used in this mode, users won't be able to manipulate the metadata instance but can only read it.
|
|
769
|
-
## Example Applications
|
|
214
|
+
1. Navigate to the CEE directory:
|
|
770
215
|
|
|
771
|
-
|
|
772
|
-
|
|
216
|
+
```shell
|
|
217
|
+
cd <...>/<clone directory>/cedar-embeddable-editor/
|
|
218
|
+
```
|
|
773
219
|
|
|
774
|
-
|
|
775
|
-
|---|---|
|
|
776
|
-
| `cedar-cee-demo-angular-src` | Angular |
|
|
777
|
-
| `cedar-cee-demo-react` | React |
|
|
778
|
-
| `cedar-cee-demo-ember-src` | Ember |
|
|
220
|
+
2. Run these commands:
|
|
779
221
|
|
|
780
|
-
|
|
781
|
-
|
|
222
|
+
```shell
|
|
223
|
+
npm install
|
|
224
|
+
ng serve
|
|
225
|
+
```
|
|
782
226
|
|
|
783
|
-
|
|
784
|
-
|
|
227
|
+
3. In your browser, navigate to `http://localhost:4400/`. The app will
|
|
228
|
+
automatically reload if you change any of the source files.
|