@teipublisher/pb-components 3.6.3 → 3.6.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teipublisher/pb-components",
3
- "version": "3.6.3",
3
+ "version": "3.6.5",
4
4
  "description": "Collection of webcomponents underlying TEI Publisher",
5
5
  "repository": "https://github.com/eeditiones/tei-publisher-components.git",
6
6
  "main": "index.html",
@@ -18,7 +18,7 @@
18
18
  "start": "npm run build && npm run docs && es-dev-server",
19
19
  "test": "karma start",
20
20
  "test:watch": "karma start --auto-watch=true --single-run=false",
21
- "docker": "npm run build:production && docker build --no-cache --pull --rm -f 'Dockerfile' -t pbcomponents:master '.'",
21
+ "docker": "npm run build:production && ci/setup-tei-publisher-app.sh && docker build --no-cache --pull --rm -f 'Dockerfile' -t pbcomponents:master '.'",
22
22
  "docker:run": "docker run --rm -it -p 8080:8080/tcp -p 8443:8443/tcp pbcomponents:master",
23
23
  "docs": "wca src -f json --outFile pb-elements.json",
24
24
  "lint:eslint": "eslint --ext .js,.html . --ignore-path .gitignore",
package/src/pb-page.js CHANGED
@@ -281,19 +281,11 @@ export class PbPage extends pbMixin(LitElement) {
281
281
  console.log('<pb-page> Loading component theme stylesheets from %s', stylesheetURLs.join(', '));
282
282
  this._themeSheet = await loadStylesheets(stylesheetURLs);
283
283
 
284
- // try to figure out what version of TEI Publisher the server is running
284
+ // Determine the server API version. Jinks-generated apps expose a /login
285
+ // page (HTTP 200), so probing that URL is no longer a reliable indicator
286
+ // of a pre-7 server — use /api/version directly.
285
287
  if (!this.apiVersion) {
286
- // first check if it has a login endpoint, i.e. runs a version < 7
287
- // this is necessary to prevent a CORS failure
288
- const json = await fetch(`${this.endpoint}/login`)
289
- .then(res => {
290
- if (res.ok) {
291
- return null;
292
- }
293
- // if not, access the actual /api/version endpoint to retrieve the API version
294
- return fetch(`${this.endpoint}/api/version`).then(res2 => res2.json());
295
- })
296
- .catch(() => fetch(`${this.endpoint}/api/version`).then(res2 => res2.json()));
288
+ const json = await fetch(`${this.endpoint}/api/version`).then(res2 => res2.json());
297
289
 
298
290
  if (json) {
299
291
  this.apiVersion = json.api;
@@ -405,7 +405,7 @@ class PbViewAnnotate extends PbView {
405
405
  console.warn('<pb-view-annotate> history is empty');
406
406
  return;
407
407
  }
408
- this._scrollTop = this.scrollTop;
408
+ this._captureScrollPosition();
409
409
  const lastEntry = this._history.pop();
410
410
  this._clearMarkers();
411
411
  this._ranges = JSON.parse(lastEntry);
@@ -460,11 +460,57 @@ class PbViewAnnotate extends PbView {
460
460
  });
461
461
  }
462
462
 
463
+ /**
464
+ * Return the nearest ancestor (or this element) that actually scrolls.
465
+ * In fixed-layout annotate pages the scroll container is usually `main`,
466
+ * not the pb-view-annotate host.
467
+ */
468
+ _scrollContainer() {
469
+ let el = this;
470
+ while (el) {
471
+ const { overflow, overflowY } = getComputedStyle(el);
472
+ const scrollable =
473
+ /(auto|scroll|overlay)/.test(overflowY) || /(auto|scroll|overlay)/.test(overflow);
474
+ if (scrollable && el.scrollHeight > el.clientHeight) {
475
+ return el;
476
+ }
477
+ el = el.parentElement;
478
+ }
479
+ return this;
480
+ }
481
+
482
+ _captureScrollPosition() {
483
+ const el = this._scrollContainer();
484
+ this._scrollEl = el;
485
+ this._scrollTop = el.scrollTop;
486
+ }
487
+
488
+ _restoreScrollPosition() {
489
+ if (this._scrollTop === undefined || !this._scrollEl) {
490
+ return;
491
+ }
492
+ const { _scrollEl: el, _scrollTop: top } = this;
493
+ const restore = () => {
494
+ el.scrollTop = top;
495
+ };
496
+ restore();
497
+ requestAnimationFrame(() => {
498
+ restore();
499
+ setTimeout(restore, 100);
500
+ // Run after pb-view._scroll() (400ms) so URL-hash scrolling does not win.
501
+ setTimeout(() => {
502
+ restore();
503
+ this._scrollTop = undefined;
504
+ this._scrollEl = undefined;
505
+ }, 450);
506
+ });
507
+ }
508
+
463
509
  _refresh(ev) {
464
- super._refresh(ev);
465
- if (ev && ev.detail && ev.detail.preserveScroll) {
466
- this._scrollTop = this.scrollTop;
510
+ if (ev?.detail?.preserveScroll) {
511
+ this._captureScrollPosition();
467
512
  }
513
+ super._refresh(ev);
468
514
  }
469
515
 
470
516
  _doLoad(params) {
@@ -480,10 +526,7 @@ class PbViewAnnotate extends PbView {
480
526
  this._annotationStyles();
481
527
  this.updateAnnotations(true, false);
482
528
  this._markIncompleteAnnotations();
483
- if (this._scrollTop) {
484
- this.scrollTop = this._scrollTop;
485
- this._scrollTop = undefined;
486
- }
529
+ this._restoreScrollPosition();
487
530
  this.emitTo('pb-annotations-loaded');
488
531
  // Marker positions depend on the ODD stylesheet and final text layout.
489
532
  this._scheduleMarkerRefresh();
package/src/pb-view.js CHANGED
@@ -384,28 +384,26 @@ export class PbView extends themableMixin(pbMixin(LitElement)) {
384
384
  }
385
385
 
386
386
  if (!this.disableHistory) {
387
- if (registry.state.id && !this.xmlId) {
388
- this.xmlId = registry.state.id;
389
- }
387
+ this._syncPositionFromRegistry();
390
388
 
391
389
  if (registry.state.action && registry.state.action === 'search') {
392
390
  this.highlight = true;
393
391
  }
394
392
 
395
- if (this.view === 'single') {
396
- this.nodeId = null;
397
- } else if (registry.state.root && !this.nodeId) {
398
- this.nodeId = registry.state.root;
399
- }
400
-
393
+ const doc = this.getDocument();
394
+ const prevState = { ...registry.state, ...registry.getState(this) };
401
395
  const newState = {
402
- id: this.xmlId,
403
396
  view: this.getView(),
404
397
  odd: this.getOdd(),
405
- path: this.getDocument().path,
398
+ path: doc.path,
406
399
  };
407
- if (this.view !== 'single') {
400
+ if (this.xmlId) {
401
+ newState.id = this.xmlId;
402
+ }
403
+ if (this.view !== 'single' && this.nodeId) {
408
404
  newState.root = this.nodeId;
405
+ } else if (prevState.path && prevState.path !== doc.path) {
406
+ newState.root = null;
409
407
  }
410
408
  if (this.fill) {
411
409
  newState.fill = this.fill;
@@ -567,6 +565,43 @@ export class PbView extends themableMixin(pbMixin(LitElement)) {
567
565
  }
568
566
  }
569
567
 
568
+ _refreshHasPosition(detail) {
569
+ if (!detail) {
570
+ return false;
571
+ }
572
+ return (
573
+ Object.prototype.hasOwnProperty.call(detail, 'id') ||
574
+ Object.prototype.hasOwnProperty.call(detail, 'root') ||
575
+ Object.prototype.hasOwnProperty.call(detail, 'position') ||
576
+ Object.prototype.hasOwnProperty.call(detail, 'path') ||
577
+ Object.prototype.hasOwnProperty.call(detail, 'xpath')
578
+ );
579
+ }
580
+
581
+ _syncPositionFromRegistry() {
582
+ if (this.disableHistory || this.getAttribute('xml-id')) {
583
+ return;
584
+ }
585
+ const doc = this.getDocument();
586
+ if (!doc?.path) {
587
+ return;
588
+ }
589
+ const state = { ...registry.state, ...registry.getState(this) };
590
+ if (state.path && state.path !== doc.path) {
591
+ return;
592
+ }
593
+ if (!this.xmlId && state.id) {
594
+ this.xmlId = state.id;
595
+ }
596
+ if (!this.nodeId) {
597
+ if (this.getView() === 'single') {
598
+ this.nodeId = null;
599
+ } else if (state.root) {
600
+ this.nodeId = state.root;
601
+ }
602
+ }
603
+ }
604
+
570
605
  _refresh(ev) {
571
606
  if (ev && ev.detail) {
572
607
  if (
@@ -588,6 +623,7 @@ export class PbView extends themableMixin(pbMixin(LitElement)) {
588
623
  }
589
624
  if (ev.detail.id) {
590
625
  this.xmlId = ev.detail.id;
626
+ this.nodeId = null;
591
627
  } else if (ev.detail.id == null) {
592
628
  this.xmlId = null;
593
629
  }
@@ -619,6 +655,9 @@ export class PbView extends themableMixin(pbMixin(LitElement)) {
619
655
  this._scrollTarget = ev.detail.hash;
620
656
  }
621
657
  }
658
+ if (!this._refreshHasPosition(ev?.detail)) {
659
+ this._syncPositionFromRegistry();
660
+ }
622
661
  this._updateStyles();
623
662
  if (this.infiniteScroll) {
624
663
  this._clear();
@@ -1264,7 +1303,7 @@ export class PbView extends themableMixin(pbMixin(LitElement)) {
1264
1303
  if (this.view === 'single') {
1265
1304
  // when switching to single view, clear current node id
1266
1305
  this.nodeId = null;
1267
- } else {
1306
+ } else if (this.switchView) {
1268
1307
  // otherwise use value for alternate view returned from server
1269
1308
  this.nodeId = this.switchView;
1270
1309
  }
@@ -1279,7 +1318,9 @@ export class PbView extends themableMixin(pbMixin(LitElement)) {
1279
1318
  this.columnSeparator = properties.columnSeparator;
1280
1319
  }
1281
1320
  this.xmlId = (!this.getAttribute('xml-id') && properties.id) || this.xmlId;
1282
- this.nodeId = (!this.getAttribute('xml-id') && properties.root) || null;
1321
+ if (Object.prototype.hasOwnProperty.call(properties, 'root')) {
1322
+ this.nodeId = (!this.getAttribute('xml-id') && properties.root) || null;
1323
+ }
1283
1324
 
1284
1325
  if (properties.path) {
1285
1326
  this.getDocument().path = properties.path;