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/README.md CHANGED
@@ -1,13 +1,15 @@
1
1
  # CEDAR Embeddable Editor (CEE)
2
2
 
3
+ [![Test](https://github.com/metadatacenter/cedar-embeddable-editor/actions/workflows/test.yml/badge.svg?branch=develop)](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
- This README covers building, testing and releasing the component. For embedding
19
- it in an application, the CEDAR documentation site carries a fuller guide:
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
- Clone this repository onto a local directory of your choice:
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
- One Node version throughout — 24.19.0, which `.nvmrc` names. The build and the
91
- tests used to run on different ones, because Angular 14's toolchain and the
92
- Playwright the suite needs did not accept the same version; from Angular 15 they
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`, `develop` and the `cee-angular-**` branches. Nothing is
169
- published from CI: releasing is a separate, manual procedure.
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 advisories against `@angular/cli` and the packages
183
- reached through it. **Never run `npm audit fix --force` here.** npm's idea of
184
- fixing that tree is to walk the toolchain years backwards, undoing the Angular
185
- march to silence warnings about build tooling an embedder never downloads.
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 the model library from `@org.metadatacenter/cedar-model-typescript-library`,
190
- published to the BMIR Nexus, so no sibling checkout is needed:
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
- ### Node versions during the Angular migration
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
- CEE is on **Angular 22.1** and **Node 24.19.0**, named in `.nvmrc`, declared in
207
- `engines`, and pinned by CI. Angular 22 accepts `^22.22.3 || ^24.15.0 || >=26`; 24
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": "npm:@org.metadatacenter/cedar-model-typescript-library@<version>"
131
+ "cedar-model-typescript-library": "<version>"
225
132
  ```
226
133
 
227
- The alias keeps the local import name, so source files import
228
- `cedar-model-typescript-library` regardless of the published name. To move to a
229
- newer build, publish it to Nexus and bump the version in the root and `visual/`
230
- manifests together. The harness declares no separate copy; it resolves the root
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 rather than a browser. None of them uses `TestBed`, so
250
- none needs Angular's JIT compiler to build a component, and dropping the browser
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
- ## Configuration
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
- If your application decides which templates load — they ship with the application, or
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
- ```json
477
- {
478
- "trustTemplateRichText": true
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
- requiredFieldValueCount: int
647
- nonNullRequiredFieldValueCount: int
648
- problems: ValidationProblem[]
649
- isValid: boolean
168
+ ```shell
169
+ npm install cedar-embeddable-editor
650
170
  ```
651
171
 
652
- `isValid` is true when nothing required is missing **and** `problems` is empty.
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
- Each problem names the field and what is wrong with it:
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
- Constraints checked: `requiredValue`; `minLength`, `maxLength` and `regex`;
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
- The application currently has two built-in language maps: `en` and `hu`. If you do not specify any language-related config option, the default `English` map will be used.
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
- You can use external language maps as well. In order to do this, specify a relative path to a folder containing the language file. The file should be named `x.json`, and should have the identical structure of the language map found in the source of the application:
184
+ Proceed with the following steps:
699
185
 
700
- https://github.com/metadatacenter/cedar-embeddable-editor/blob/main/src/assets/i18n-cee/en.json
186
+ #### Clone the repository
701
187
 
702
- In order to use an external language file, specify the config as follows:
188
+ Clone this repository onto a local directory of your choice:
703
189
 
704
- ```json
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
- In the example above we want to use a `German` language file, which is located in the specified directory. Starting the path with `/` makes the path absolute.
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
- CEE emits one composed, bubbling `change` event after an operation actually changes
725
- the serialized instance. It does not forward incidental DOM control traffic: focus,
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 { CeeChangeDetail } from 'cedar-embeddable-editor';
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
- cee.addEventListener('change', (event) => {
745
- const detail: CeeChangeDetail = event.detail;
746
- console.log(detail.operation, detail.path);
747
- console.log('valid:', detail.validity);
748
- });
202
+ const ceeConfig: CeeConfig = {
203
+ terminologyBaseUrl: 'https://terminology.metadatacenter.org/',
204
+ bridgeBaseUrl: 'https://bridge.metadatacenter.org/',
205
+ };
749
206
  ```
750
207
 
751
- Framework event bindings receive the same custom event. For example, Angular can
752
- bind `(change)="logChange($event)"` on the element and type the handler parameter as
753
- `CustomEvent<CeeChangeDetail>`.
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
- ### Viewer Mode
212
+ #### Build the project and start the server
762
213
 
763
- CEE can be used as a viewer to display metadata instances. This can be achieved by the following configuration setting:
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
- [`cedar-component-demo`](https://github.com/metadatacenter/cedar-component-demo)
772
- holds small runnable applications that embed CEE, each with its own README:
216
+ ```shell
217
+ cd <...>/<clone directory>/cedar-embeddable-editor/
218
+ ```
773
219
 
774
- | Application | Framework |
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
- Each edits the same template, `eDNA ECT Demonstration`, kept as a file inside the
781
- application rather than fetched from a server.
222
+ ```shell
223
+ npm install
224
+ ng serve
225
+ ```
782
226
 
783
- `cedar-cee-demo-angular-src` needs `npm install --legacy-peer-deps`; the others
784
- do not.
227
+ 3. In your browser, navigate to `http://localhost:4400/`. The app will
228
+ automatically reload if you change any of the source files.