From 6d87a1a4e8e5daeef28edcf570febafcc9760257 Mon Sep 17 00:00:00 2001
From: Niklas Liljestrand
Date: Wed, 2 Dec 2020 13:50:44 +0200
Subject: [PATCH] Develop (#73)
Merge from Develop to Master
- Lot's of small and some bigger fixes
- New advanced search (still in beta)
- Layout changes
---
Dockerfile | 4 +-
package-lock.json | 6 +-
package.json | 4 +-
src/app/app.component.ts | 325 ++++++--
src/app/app.html | 121 ++-
src/app/app.module.ts | 8 +-
src/app/app.scss | 34 +-
src/app/models/facsimile.model.ts | 10 +-
src/app/models/occurrence.model.ts | 6 +
src/app/models/single-occurrence.model.ts | 1 -
.../models/toc-accordion-menu-option.model.ts | 5 +
src/app/services/comments/comment.service.ts | 29 +-
.../elastic-search/elastic-search.d.ts | 78 ++
.../elastic-search/elastic-search.service.ts | 397 +++++++++
.../services/facsimile/facsimile.service.ts | 10 +-
src/app/services/gallery/gallery.service.ts | 9 +
src/app/services/html/html-cache.service.ts | 4 +-
src/app/services/md/md-content.service.ts | 18 +-
.../services/occurrence/occurence.service.ts | 1 -
.../reference-data/reference-data.service.ts | 2 +-
.../services/search/search-data.service.ts | 12 +
.../semantic-data/semantic-data.service.ts | 402 ++++++++-
.../services/settings/read-popover.service.ts | 1 +
.../settings/user-settings.service.ts | 8 +-
src/app/services/texts/text.service.ts | 89 +-
.../services/toc/table-of-contents.service.ts | 2 -
src/app/services/tooltips/tooltip.service.ts | 71 +-
src/app/services/tutorial/tutorial.service.ts | 76 +-
src/assets/custom_css/custom.css | 2 +-
src/assets/i18n/en.json | 417 ++++++----
src/assets/i18n/fi.json | 523 +++++++-----
src/assets/i18n/sv.json | 549 +++++++-----
src/assets/images/img_placeholder.png | Bin 0 -> 2443 bytes
src/assets/images/symbol_illustration.gif | Bin 0 -> 567 bytes
src/components/comments/comments.html | 25 +
src/components/comments/comments.scss | 17 +
src/components/comments/comments.ts | 87 +-
src/components/components.module.ts | 15 +-
src/components/cover/cover.html | 1 +
src/components/cover/cover.ts | 2 +-
.../date-histogram/date-histogram.html | 35 +
.../date-histogram/date-histogram.scss | 69 ++
.../date-histogram/date-histogram.ts | 91 ++
.../digital-edition-list.component.ts | 45 +-
.../digital-edition-list.html | 18 +-
.../digital-edition-list.scss | 5 +-
src/components/facsimiles/facsimiles.html | 58 +-
src/components/facsimiles/facsimiles.scss | 13 +
src/components/facsimiles/facsimiles.ts | 208 +++--
.../illustrations/illustrations.html | 18 +
.../illustrations/illustrations.scss | 11 +
src/components/illustrations/illustrations.ts | 141 ++++
src/components/introduction/introduction.html | 4 +-
src/components/introduction/introduction.ts | 19 +-
src/components/list-of-songs/list-of-songs.ts | 2 +-
src/components/manuscripts/manuscripts.html | 1 +
src/components/manuscripts/manuscripts.scss | 10 +
src/components/manuscripts/manuscripts.ts | 12 +-
src/components/read-text/read-text.html | 7 +-
src/components/read-text/read-text.scss | 26 +-
src/components/read-text/read-text.ts | 191 +++--
.../simple-search/simple-search.html | 2 +-
.../simple-search/simple-search.scss | 5 +
src/components/simple-search/simple-search.ts | 85 +-
.../static-pages-toc-drilldown-menu.html | 39 +-
.../static-pages-toc-drilldown-menu.ts | 21 +-
.../table-of-content-letter-filter.html | 4 +
.../table-of-content-letter-filter.scss | 3 +
.../table-of-content-letter-filter.ts | 22 +
.../table-of-contents-accordion.html | 161 ++--
.../table-of-contents-accordion.scss | 55 +-
.../table-of-contents-accordion.ts | 307 ++++++-
.../table-of-contents-drilldown-menu.html | 30 +-
.../table-of-contents-drilldown-menu.scss | 22 +
.../table-of-contents-drilldown-menu.ts | 303 ++++---
src/components/text-changer/text-changer.html | 22 +-
src/components/text-changer/text-changer.scss | 92 ++
src/components/text-changer/text-changer.ts | 169 ++--
src/components/title-logo/title-logo.ts | 4 +
src/components/toc-menu/toc-menu.ts | 1 +
src/components/top-menu/top-menu.html | 64 +-
src/components/top-menu/top-menu.scss | 20 +-
src/components/top-menu/top-menu.ts | 18 +
src/components/variations/variations.html | 3 +-
src/components/variations/variations.ts | 77 +-
src/config-sample.json | 787 +++++++++++-------
src/pages/content/content.ts | 3 +
src/pages/cover/cover.module.ts | 2 +-
src/pages/cover/cover.scss | 12 +-
src/pages/cover/cover.ts | 72 +-
src/pages/editions/editions.html | 2 +-
src/pages/elastic-search/elastic-search.html | 214 +++++
.../elastic-search/elastic-search.module.ts | 51 ++
src/pages/elastic-search/elastic-search.scss | 292 +++++++
src/pages/elastic-search/elastic-search.ts | 726 ++++++++++++++++
src/pages/facsimile-zoom/facsimile-zoom.html | 51 +-
src/pages/facsimile-zoom/facsimile-zoom.scss | 26 +-
src/pages/facsimile-zoom/facsimile-zoom.ts | 76 +-
src/pages/filter/filter.html | 33 +-
src/pages/filter/filter.module.ts | 14 +
src/pages/filter/filter.scss | 17 +
src/pages/filter/filter.ts | 72 +-
src/pages/home/home.html | 25 +-
src/pages/home/home.ts | 4 +
src/pages/illustration/illustration.html | 14 +-
src/pages/illustration/illustration.scss | 3 +
src/pages/illustration/illustration.ts | 42 +-
src/pages/introduction/introduction.html | 56 +-
src/pages/introduction/introduction.scss | 199 ++++-
src/pages/introduction/introduction.ts | 388 ++++++++-
.../media-collection/media-collection.html | 17 +-
.../media-collection/media-collection.scss | 6 +-
.../media-collection/media-collection.ts | 28 +-
.../media-collections/media-collections.html | 8 +-
.../media-collections/media-collections.ts | 24 +-
src/pages/music/music.ts | 4 +
.../occurrences-result/occurrences-result.ts | 116 ++-
src/pages/occurrences/occurrences.html | 116 ++-
src/pages/occurrences/occurrences.scss | 57 +-
src/pages/occurrences/occurrences.ts | 233 +++++-
src/pages/pdf/pdf.ts | 4 +
src/pages/person-search/person-search.html | 7 +-
src/pages/person-search/person-search.ts | 160 ++--
src/pages/place-search/place-search.html | 6 +-
src/pages/place-search/place-search.ts | 97 ++-
src/pages/read-popover/read-popover.html | 10 +-
src/pages/read-popover/read-popover.module.ts | 2 +-
src/pages/read-popover/read-popover.scss | 20 +-
src/pages/read-popover/read-popover.ts | 74 +-
src/pages/read/read.html | 141 ++--
src/pages/read/read.scss | 180 +++-
src/pages/read/read.ts | 773 +++++++++++++----
.../reference-data-modal.html | 6 +-
.../reference-data-modal.scss | 5 +-
.../reference-data-modal.ts | 20 +-
src/pages/search-app/search-app.ts | 4 +
.../semantic-data-modal.html | 22 +
.../semantic-data-modal.ts | 131 ++-
src/pages/share-popover/share-popover.html | 31 +
.../share-popover/share-popover.module.ts | 27 +
src/pages/share-popover/share-popover.scss | 27 +
src/pages/share-popover/share-popover.ts | 84 ++
.../single-edition-part.ts | 2 +-
src/pages/single-edition/single-edition.ts | 123 ++-
src/pages/tag-search/tag-search.html | 6 +-
src/pages/tag-search/tag-search.ts | 119 +--
src/pages/title/title.html | 15 +
src/pages/title/title.module.ts | 32 +
src/pages/title/title.scss | 3 +
src/pages/title/title.ts | 188 +++++
.../user-settings-popover.html | 59 +-
.../user-settings-popover.ts | 2 -
src/pages/work-search/work-search.html | 8 +-
src/pages/work-search/work-search.ts | 167 ++--
src/pages/work-search/worksearch.scss | 14 +-
src/theme/_project-variables.scss | 15 +-
src/theme/_tei.scss | 20 +-
src/theme/variables.scss | 3 +-
tsconfig.json | 6 +-
tslint.json | 6 +-
160 files changed, 9704 insertions(+), 2589 deletions(-)
create mode 100644 src/app/services/elastic-search/elastic-search.d.ts
create mode 100644 src/app/services/elastic-search/elastic-search.service.ts
create mode 100644 src/assets/images/img_placeholder.png
create mode 100644 src/assets/images/symbol_illustration.gif
create mode 100644 src/components/date-histogram/date-histogram.html
create mode 100644 src/components/date-histogram/date-histogram.scss
create mode 100644 src/components/date-histogram/date-histogram.ts
create mode 100644 src/components/illustrations/illustrations.html
create mode 100644 src/components/illustrations/illustrations.scss
create mode 100644 src/components/illustrations/illustrations.ts
create mode 100644 src/components/table-of-content-letter-filter/table-of-content-letter-filter.html
create mode 100644 src/components/table-of-content-letter-filter/table-of-content-letter-filter.scss
create mode 100644 src/components/table-of-content-letter-filter/table-of-content-letter-filter.ts
create mode 100644 src/pages/elastic-search/elastic-search.html
create mode 100644 src/pages/elastic-search/elastic-search.module.ts
create mode 100644 src/pages/elastic-search/elastic-search.scss
create mode 100644 src/pages/elastic-search/elastic-search.ts
create mode 100644 src/pages/share-popover/share-popover.html
create mode 100644 src/pages/share-popover/share-popover.module.ts
create mode 100644 src/pages/share-popover/share-popover.scss
create mode 100644 src/pages/share-popover/share-popover.ts
create mode 100644 src/pages/title/title.html
create mode 100644 src/pages/title/title.module.ts
create mode 100644 src/pages/title/title.scss
create mode 100644 src/pages/title/title.ts
diff --git a/Dockerfile b/Dockerfile
index 93b43269..065c0610 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -3,7 +3,7 @@ FROM node:10-alpine
RUN apk update
RUN apk add --no-cache g++ gcc libgcc libstdc++ linux-headers make python git
-RUN git clone --depth 1 -b master https://github.com/slsfi/digital_edition_web.git
+RUN git clone --depth 1 -b develop https://github.com/slsfi/digital_edition_web.git
WORKDIR /digital_edition_web
@@ -20,7 +20,7 @@ RUN mkdir www
RUN npm install
RUN npm install cheerio
RUN npm install rev-hash
-RUN npm install -g ionic
+RUN npm i -g @ionic/cli
RUN npm i -g cordova
RUN npm i -g native-run
RUN npm i -g @sentry/browser
diff --git a/package-lock.json b/package-lock.json
index f492bbea..2c7c0a20 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4516,9 +4516,9 @@
"integrity": "sha512-alGvLE4JBTeGhUuvLwYKnneIkt1dPhGIBTXgNG4G4pbaNpwdZNrTY+YCYj6Dj4lVCgyEJvQcHYTWcXuuT5swyg=="
},
"ngx-pinch-zoom": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/ngx-pinch-zoom/-/ngx-pinch-zoom-1.2.5.tgz",
- "integrity": "sha512-zZJ9t+RifdHZDuNy0vU//yontD4rT/0J3dHvDbKxfnBGXoTuCnaYYUeDtFUIjYSu71xxpELANjeNwna2D02hzw==",
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/ngx-pinch-zoom/-/ngx-pinch-zoom-2.4.4.tgz",
+ "integrity": "sha512-36GZ+ck16m5xrDSz8c/ZX0u5grAelPbi6/hL/UvNSpkgkolamlsg5p+FwMwPgoHiOmwsYQpTo5FPeWmwrS9cHg==",
"requires": {
"tslib": "^1.9.0"
}
diff --git a/package.json b/package.json
index 93cabe1a..4baaeefd 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"scripts": {
"build": "ionic-app-scripts build",
"watch": "ionic-app-scripts watch",
+ "start": "ionic-app-scripts serve --wwwDir",
"serve:before": "watch",
"emulate:before": "build",
"deploy:before": "build",
@@ -53,8 +54,9 @@
"ionic-plugin-deeplinks": "1.0.19",
"ionicons": "~3.0.0",
"leaflet": "^1.4.0",
+ "lodash": "^4.17.15",
"ngx-drag-scroll": "1.7.9",
- "ngx-pinch-zoom": "^1.2.3",
+ "ngx-pinch-zoom": "^2.4.4",
"ngx-sharebuttons": "^3.0.0",
"rev-hash": "^3.0.0",
"rxjs": "5.5.11",
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index c2a0c894..be612c53 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,4 +1,5 @@
-import { Component, ViewChild, Pipe, PipeTransform, ChangeDetectionStrategy, ViewEncapsulation, ChangeDetectorRef } from '@angular/core';
+import { Component, ViewChild, Pipe, PipeTransform, ChangeDetectionStrategy,
+ ViewEncapsulation, ChangeDetectorRef, Renderer, Renderer2 } from '@angular/core';
import './rxjs-operators';
import { Nav, Platform, MenuController, IonicPage, Events, App, NavParams, AlertController } from 'ionic-angular';
import { LangChangeEvent, TranslateService/*, TranslatePipe*/ } from '@ngx-translate/core';
@@ -48,6 +49,7 @@ export class DigitalEditionsApp {
splitPane = false;
collectionsList: any[];
collectionsListWithTOC: any[];
+ tocData: any;
pdfCollections: any[];
currentContentName: string;
showBackButton = true;
@@ -62,19 +64,24 @@ export class DigitalEditionsApp {
menuConditionals = {
songTypesMenuOpen: false
}
+ tocLoaded = false;
googleAnalyticsID: string;
collectionDownloads: Array;
currentCollectionId = '';
currentCollectionName = '';
+ currentCollection: any;
currentMarkdownId = null;
+ openCollectionFromToc = false;
+
+ pageFirstLoad = true;
accordionTOC = false;
accordionMusic = false;
storageCollections = {};
-
+ collectionSortOrder: any;
browserWarning: string;
browserWarningInfo: string;
@@ -98,13 +105,13 @@ export class DigitalEditionsApp {
pagesThatShallShow = {
tocMenu: ['FeaturedFacsimilePage'],
- tocMenuIfNotAccordion: ['SingleEditionPage', 'CoverPage'],
+ tableOfContentsMenu: ['SingleEditionPage', 'CoverPage', 'TitlePage'],
aboutMenu: ['AboutPage'],
- contentMenu: ['HomePage', 'EditionsPage', 'ContentPage', 'MusicPage', 'FeaturedFacsimilePage']
+ contentMenu: ['HomePage', 'EditionsPage', 'ContentPage', 'MusicPage', 'FeaturedFacsimilePage', 'ElasticSearchPage']
}
pagesWithoutMenu = [];
- pagesWithClosedMenu = ['HomePage', 'HomePage'];
+ pagesWithClosedMenu = ['HomePage'];
public options: Array;
public songTypesOptions: {
@@ -134,7 +141,7 @@ export class DigitalEditionsApp {
musicAccordion: false,
songTypesAccordion: false,
galleryAccordion: false,
- collectionsAccordion: false,
+ collectionsAccordion: [false],
aboutMenuAccordion: false,
pdfAccordion: false
}
@@ -171,6 +178,9 @@ export class DigitalEditionsApp {
hasCover = true;
tocItems: GeneralTocItem[];
+ galleryInReadMenu = true;
+ splitReadCollections: any[];
+
constructor(
private platform: Platform,
public translate: TranslateService,
@@ -190,7 +200,8 @@ export class DigitalEditionsApp {
public cdRef: ChangeDetectorRef,
private alertCtrl: AlertController,
private tutorial: TutorialService,
- private galleryService: GalleryService
+ private galleryService: GalleryService,
+ private renderer: Renderer
) {
// Check for IE11
@@ -226,6 +237,21 @@ export class DigitalEditionsApp {
} catch (e) {
this.showBooks = false;
}
+
+ try {
+ this.splitReadCollections = this.genericSettingsService.show('TOC.splitReadCollections');
+ if ( this.splitReadCollections === null || this.splitReadCollections.length <= 0 ) {
+ this.splitReadCollections = [''];
+ }
+ } catch (e) {
+ this.splitReadCollections = [''];
+ }
+
+ try {
+ this.collectionSortOrder = this.config.getSettings('app.CollectionSortOrder');
+ } catch (e) {
+ this.collectionSortOrder = undefined;
+ }
this.sideMenuMobileConfig();
this.songTypesMenuMarkdownConfig();
this.aboutMenuMarkdownConfig();
@@ -235,6 +261,18 @@ export class DigitalEditionsApp {
this.accordionTOC = false;
}
+ try {
+ this.openCollectionFromToc = this.config.getSettings('OpenCollectionFromToc');
+ } catch (e) {
+ this.openCollectionFromToc = false;
+ }
+
+ try {
+ this.galleryInReadMenu = this.config.getSettings('ImageGallery.ShowInReadMenu');
+ } catch (e) {
+ this.galleryInReadMenu = true;
+ }
+
try {
this.accordionMusic = this.config.getSettings('AccordionMusic');
} catch (e) {
@@ -306,6 +344,22 @@ export class DigitalEditionsApp {
showSplitPane() {
this.splitPaneOpen = true;
+
+ this.closeSplitPane();
+ }
+
+ closeSplitPane() {
+ setTimeout(() => {
+ const shadow = document.querySelector('.shadow');
+
+ if (shadow !== null) {
+ shadow.addEventListener('click', () => {
+ if (this.splitPaneOpen) {
+ this.splitPaneOpen = false;
+ }
+ });
+ }
+ }, 1);
}
disableSplitPane() {
@@ -369,7 +423,8 @@ export class DigitalEditionsApp {
openCollectionPage(collection) {
this.currentContentName = collection.title;
const params = { collection: collection, fetch: false, id: collection.id };
- this.nav.setRoot('single-edition', params, { animate: false, direction: 'forward', animation: 'ios-transition' });
+ const nav = this.app.getActiveNavs();
+ nav[0].setRoot('single-edition', params, { animate: false, direction: 'forward', animation: 'ios-transition' });
}
getCollectionsWithTOC() {
@@ -379,7 +434,12 @@ export class DigitalEditionsApp {
return;
}
- collections = this.sortListRoman(collections);
+ if ( this.collectionSortOrder === undefined ) {
+ collections = this.sortListRoman(collections);
+ } else if ( Object.keys(this.collectionSortOrder).length > 0 ) {
+ collections = this.sortListDefined(collections, this.collectionSortOrder);
+ }
+
const collectionsTmp = [];
const pdfCollections = [];
collections.forEach(collection => {
@@ -415,6 +475,7 @@ export class DigitalEditionsApp {
}
});
this.collectionsListWithTOC = collectionsTmp;
+
if (this.showBooks) {
this.pdfCollections = pdfCollections;
this.pdfCollections.sort(function (a, b) {
@@ -461,6 +522,23 @@ export class DigitalEditionsApp {
return list;
}
+ sortListDefined(list, sort) {
+ for (const coll of list) {
+ const order = sort[coll.id];
+ coll['order'] = order;
+ }
+
+ list.sort((a, b) => {
+ if (typeof a['order'] === 'number') {
+ return (a['order'] - b['order']);
+ } else {
+ return ((a['order'] < b['order']) ? -1 : ((a['order'] > b['order']) ? 1 : 0));
+ }
+ });
+
+ return list;
+ }
+
openMusicAccordionItem(musicAccordionItem, findInMusicAccordion?) {
Object.keys(this.musicAccordion).forEach(key => this.musicAccordion[key].selected = false);
if (findInMusicAccordion) {
@@ -497,7 +575,9 @@ export class DigitalEditionsApp {
try {
this.simpleAccordionsExpanded.songTypesAccordion = this.config.getSettings('AccordionsExpandedDefault.SongTypes');
this.simpleAccordionsExpanded.musicAccordion = this.config.getSettings('AccordionsExpandedDefault.Music');
- this.simpleAccordionsExpanded.collectionsAccordion = this.config.getSettings('AccordionsExpandedDefault.Collections');
+ for ( let i = 0; i < this.splitReadCollections.length; i++ ) {
+ this.simpleAccordionsExpanded.collectionsAccordion[i] = this.config.getSettings('AccordionsExpandedDefault.Collections');
+ }
} catch (e) {
}
}
@@ -528,11 +608,13 @@ export class DigitalEditionsApp {
if (this.aboutMenuMarkdownAccordion !== undefined) {
this.aboutMenuMarkdownAccordion.ngOnChanges(aboutMarkdownMenu.children);
}
+ this.cdRef.detectChanges();
}).bind(this)();
}
}
getCollectionTOC(collectionID) {
+ console.log('Getting collection TOC in app component');
this.tableOfContentsService.getTableOfContents(collectionID)
.subscribe(
tocItems => {
@@ -557,7 +639,7 @@ export class DigitalEditionsApp {
'tablet',
'windows',
]
- platforms.map(p => console.log(`${p}: ${this.platform.is(p)}`));
+ // platforms.map(p => console.log(`${p}: ${this.platform.is(p)}`));
this.splashScreen.hide();
this.languageService.getLanguage().subscribe((lang: string) => {
this.language = lang;
@@ -573,9 +655,24 @@ export class DigitalEditionsApp {
}
});
this.events.publish('pdfview:open', { 'isOpen': false });
+
+ /* const tableOfContentsMenu: HTMLElement = document.querySelector('.split-pane-side');
+ const menuResizer = document.querySelector('.menuResizer');
+ const initialtWidth = Number(tableOfContentsMenu.offsetWidth);
+ menuResizer.addEventListener('drag', (event: MouseEvent) => {
+ this.resizeTOCMenu(event, tableOfContentsMenu, initialtWidth);
+ });
+ this.cdRef.detectChanges(); */
});
}
+ resizeTOCMenu( event: MouseEvent, splitPaneItem, initialtWidth ) {
+ const relativeWidth = Number(String(event.clientX).replace('px', ''));
+ if ( relativeWidth > 0 ) {
+ splitPaneItem.style.minWidth = (initialtWidth + relativeWidth) + 'px';
+ }
+ }
+
toggleMusicAccordion() {
this.simpleAccordionsExpanded.musicAccordion = !this.simpleAccordionsExpanded.musicAccordion;
}
@@ -601,6 +698,10 @@ export class DigitalEditionsApp {
}
registerEventListeners() {
+ this.events.subscribe('digital-edition-list:open', (collection) => {
+ console.log('listened to digital-edition-list:open');
+ this.openCollection(collection);
+ });
this.events.subscribe('CollectionWithChildrenPdfs:highlight', (collectionID) => {
for (const collection of this.collectionsListWithTOC) {
if (String(collection.id) === String(collectionID)) {
@@ -611,12 +712,19 @@ export class DigitalEditionsApp {
menuID: selectedMenu,
component: 'app-component'
});
- this.simpleAccordionsExpanded.collectionsAccordion = true;
+ for ( let i = 0; i < this.splitReadCollections.length; i++ ) {
+ this.simpleAccordionsExpanded.collectionsAccordion[i] = true;
+ }
} else {
collection['highlight'] = false;
}
}
});
+
+ this.events.subscribe('exitActiveCollection', () => {
+ this.enableContentMenu();
+ });
+
// Unselect accordion items that doesn't belong to current menu
this.events.subscribe('SelectedItemInMenu', (menu) => {
if (menu.component === 'table-of-contents-accordion-component' || this.currentAccordionMenu !== menu.menuID) {
@@ -648,10 +756,12 @@ export class DigitalEditionsApp {
// Check if there is a need to expand
// Otherwise we might change smth after user clicks on accordion
- if (expand && !this.simpleAccordionsExpanded.collectionsAccordion) {
- this.simpleAccordionsExpanded.collectionsAccordion = true;
- } else if (!expand && this.simpleAccordionsExpanded.collectionsAccordion) {
- this.simpleAccordionsExpanded.collectionsAccordion = false;
+ for ( let i = 0; i < this.splitReadCollections.length; i++ ) {
+ if (expand && !this.simpleAccordionsExpanded.collectionsAccordion[i]) {
+ this.simpleAccordionsExpanded.collectionsAccordion[i] = true;
+ } else if (!expand && this.simpleAccordionsExpanded.collectionsAccordion) {
+ this.simpleAccordionsExpanded.collectionsAccordion[i] = false;
+ }
}
this.cdRef.detectChanges();
});
@@ -690,22 +800,37 @@ export class DigitalEditionsApp {
}
});
this.events.subscribe('tableOfContents:loaded', (data) => {
- if (data.searchTocItem) {
+ this.tocData = data;
+ this.tocLoaded = true;
+ if (data.searchTocItem) {
for (const collection of this.collectionsListWithTOC) {
- if (Number(collection.id) === Number(data.collectionID)) {
+ if ((data.collectionID !== undefined && String(collection.id) === String(data.collectionID.id))
+ || (data.collectionID !== undefined && Number(collection.id) === Number(data.collectionID))) {
collection.expanded = true;
- this.simpleAccordionsExpanded.collectionsAccordion = true;
+ for ( let i = 0; i < this.splitReadCollections.length; i++ ) {
+ this.simpleAccordionsExpanded.collectionsAccordion[i] = true;
+ }
+
+ if ( data.chapterID ) {
+ data.itemId = Number(data.collectionID) + '_' + Number(data.publicationID) + '_' + data.chapterID;
+ }
+
+ if ( data.itemId === undefined && data.collectionID !== undefined && data.publicationID !== undefined) {
+ data.itemId = String(data.collectionID) + '_' + String(data.publicationID);
+ }
- collection.accordionToc.toc = data.tocItems.children;
collection.accordionToc = {
toc: data.tocItems.children,
searchTocItem: true,
+ searchItemId: data.itemId,
searchPublicationId: Number(data.publicationID),
- searchTitle: data.search_title ? data.search_title : null
+ searchCollectionId: Number(data.collectionID),
+ searchTitle: null
}
-
+ collection.accordionToc.toc = data.tocItems.children;
+ this.currentCollection = collection;
break;
}
}
@@ -713,12 +838,23 @@ export class DigitalEditionsApp {
this.options = data.tocItems.children;
this.currentCollectionId = data.tocItems.collectionId;
this.currentCollectionName = data.tocItems.text;
+ this.enableTableOfContentsMenu();
+ });
+
+ this.events.subscribe('exitedTo', (page) => {
+ this.setupPageSettings(page);
});
this.events.subscribe('ionViewWillEnter', (currentPage) => {
+ this.tocLoaded = false;
const homeUrl = document.URL.indexOf('/#/home');
if (homeUrl >= 0) {
this.setupPageSettings(currentPage);
+ } else if ( document.URL.indexOf('/#/') > 0 ) {
+ if ( this.splitPaneOpen === false && this.pageFirstLoad === true ) {
+ this.showSplitPane();
+ this.pageFirstLoad = false;
+ }
}
});
@@ -735,22 +871,34 @@ export class DigitalEditionsApp {
});
this.currentContentName = 'Digital Publications';
const params = {};
- this.nav.setRoot('EditionsPage', params, { animate: false });
+ const nav = this.app.getActiveNavs();
+ this.enableContentMenu();
+ nav[0].setRoot('EditionsPage', params, { animate: false });
});
this.events.subscribe('topMenu:about', () => {
this.events.publish('SelectedItemInMenu', {
menuID: 'topMenu',
component: 'app-component'
});
+ this.enableAboutMenu();
this.languageService.getLanguage().subscribe((lang: string) => {
this.language = lang;
if (this.aboutMenuMarkdown && this.aboutOptionsMarkdown.toc && this.aboutOptionsMarkdown.toc.length) {
- const firstAboutPageID = this.aboutOptionsMarkdown.toc[0].id;
+ let firstAboutPageID = this.aboutOptionsMarkdown.toc[0].id;
+ if ( this.config.getSettings('StaticPagesMenus')[0]['initialAboutPage'] !== undefined ) {
+ firstAboutPageID = this.language + '-' + this.config.getSettings('StaticPagesMenus')[0]['initialAboutPage'];
+ }
this.openStaticPage(firstAboutPageID);
} else {
+
this.enableAboutMenu();
- this.openStaticPage(this.language + '-03-01');
+ if ( this.config.getSettings('StaticPagesMenus')[0]['initialAboutPage'] === undefined ) {
+ this.staticPagesMenus['initialAboutPage'] = this.language + '-03-01';
+ } else {
+ this.staticPagesMenus['initialAboutPage'] = this.language + '-' + this.config.getSettings('StaticPagesMenus')[0]['initialAboutPage'];
+ }
+ this.openStaticPage(this.staticPagesMenus['initialAboutPage']);
}
});
});
@@ -764,7 +912,8 @@ export class DigitalEditionsApp {
// Open music accordion as well
this.simpleAccordionsExpanded.musicAccordion = true;
const params = {};
- this.nav.setRoot('music', params, { animate: false });
+ const nav = this.app.getActiveNavs();
+ nav[0].setRoot('music', params, { animate: false });
});
this.events.subscribe('topMenu:front', () => {
this.events.publish('SelectedItemInMenu', {
@@ -799,19 +948,25 @@ export class DigitalEditionsApp {
this.getMediaCollections();
});
});
+
+ this.events.subscribe('topMenu:elasticSearch', () => {
+ const params = {};
+ this.nav.push('elastic-search', params, { animate: false }).then(e => {
+ });
+ this.tocLoaded = true;
+ // this.resetCurrentCollection();
+ this.enableContentMenu();
+ });
+ }
+
+ resetCurrentCollection() {
+ this.currentCollection = null;
+ this.currentCollectionId = null;
+ this.currentCollectionName = '';
+ this.options = null;
}
mobileSplitPaneDetector() {
- this.events.subscribe('splitPaneToggle:disable', () => {
- if (this.userSettingsService.isMobile()) {
- this.hideSplitPane();
- }
- });
- this.events.subscribe('splitPaneToggle:enable', () => {
- if (this.userSettingsService.isMobile()) {
- this.showSplitPane();
- }
- });
}
doFor(needle, haystack, callback) {
@@ -855,18 +1010,21 @@ export class DigitalEditionsApp {
this.enableTableOfContentsMenu();
});
- this.doFor(p, pagesWith.tocMenuIfNotAccordion, () => {
- if (!this.accordionTOC) {
+ this.doFor(p, pagesWith.tableOfContentsMenu, () => {
+ console.log('Enabling TOC Menu', p, this.openCollectionFromToc, pagesWith.tableOfContentsMenu);
+ if (this.openCollectionFromToc) {
this.enableTableOfContentsMenu();
}
});
this.doFor(p, pagesWith.aboutMenu, () => {
+ console.log('enabling about menu for ' + p);
this.enableAboutMenu();
});
this.doFor(p, pagesWith.contentMenu, () => {
+ console.log('enabling content menu for ' + p);
this.enableContentMenu();
});
@@ -1034,12 +1192,24 @@ export class DigitalEditionsApp {
}
enableTableOfContentsMenu() {
- this.menu.enable(true, 'tableOfContentsMenu');
- if (this.platform.is('core')) {
- this.events.publish('title-logo:show', true);
+ if (this.tocLoaded) {
+ console.log('Toc is loaded');
+ try {
+ this.menu.enable(true, 'tableOfContentsMenu');
+ if (this.platform.is('core')) {
+ this.events.publish('title-logo:show', true);
+ } else {
+ this.events.publish('title-logo:show', false);
+ }
+ } catch (e) {
+ console.log('error att App.enableTableOfContentsMenu');
+ }
} else {
- this.events.publish('title-logo:show', false);
+ console.log('Toc is not loaded');
}
+
+
+
}
openPlaymanTraditionPage() {
@@ -1054,7 +1224,8 @@ export class DigitalEditionsApp {
openStaticPage(id: string) {
const params = { id: id };
- this.nav.setRoot('content', params);
+ const nav = this.app.getActiveNavs();
+ nav[0].setRoot('content', params);
}
openPage(page, selectedMenu?) {
@@ -1072,7 +1243,12 @@ export class DigitalEditionsApp {
/*if ( this.platform.is('mobile') ) {
this.events.publish('splitPaneToggle:disable');
}*/
- this.nav.setRoot(page);
+ try {
+ const nav = this.app.getActiveNavs();
+ nav[0].setRoot(page);
+ } catch (e) {
+ console.error('Error opening page');
+ }
}
openPersonSearchPage(searchPage, selectedMenu?) {
@@ -1085,12 +1261,15 @@ export class DigitalEditionsApp {
component: 'app-component'
});
}
+ if ( searchPage.object_subtype === undefined || searchPage.object_subtype === '' ) {
+ searchPage.object_subtype = encodeURI('subtype');
+ }
const params = {
type: searchPage.object_type,
subtype: searchPage.object_subtype
};
-
- this.nav.setRoot('person-search', params);
+ const nav = this.app.getActiveNavs();
+ nav[0].setRoot('person-search', params);
}
openFirstPage(collection: DigitalEdition) {
@@ -1103,6 +1282,7 @@ export class DigitalEditionsApp {
}
const nav = this.app.getActiveNavs();
+ console.log('Opening read from App.openFirstPage()');
nav[0].setRoot('read', params);
}
@@ -1118,6 +1298,7 @@ export class DigitalEditionsApp {
openCollection(collection: any) {
+ console.log(collection, '<<-- open this...');
if (this.hasCover === false) {
this.getTocRoot(collection);
} else {
@@ -1135,10 +1316,25 @@ export class DigitalEditionsApp {
} else {
this.currentContentName = collection.title;
const params = { collection: collection, fetch: false, id: collection.id };
- this.nav.setRoot('single-edition', params, { animate: false, direction: 'forward', animation: 'ios-transition' });
+
+ const nav = this.app.getActiveNavs();
+ nav[0].setRoot('single-edition', params, { animate: false, direction: 'forward', animation: 'ios-transition' });
}
this.cdRef.detectChanges();
}
+ if (this.openCollectionFromToc) {
+ this.currentCollection = collection;
+ console.log('currentCollection', collection);
+ console.log(this.options, 'options of the fn');
+ try {
+ // if (this.options) {
+ this.enableTableOfContentsMenu();
+ // }
+ } catch (e) {
+ console.log('Error enabling enableTableOfContentsMenu');
+ }
+ }
+ this.currentCollectionId = collection.id;
}
onShowAccordion(show: boolean) {
@@ -1148,13 +1344,15 @@ export class DigitalEditionsApp {
/* Legacy code */
openGalleries() {
const params = { fetch: true };
- this.nav.setRoot('galleries', params, { animate: false, direction: 'forward', animation: 'ios-transition' });
+ const nav = this.app.getActiveNavs();
+ nav[0].setRoot('galleries', params, { animate: false, direction: 'forward', animation: 'ios-transition' });
}
/* Legacy code */
openGalleryPage(galleryPage: string) {
const params = { galleryPage: galleryPage, fetch: false };
- this.nav.setRoot('image-gallery', params, { animate: false, direction: 'forward', animation: 'ios-transition' });
+ const nav = this.app.getActiveNavs();
+ nav[0].setRoot('image-gallery', params, { animate: false, direction: 'forward', animation: 'ios-transition' });
}
getMediaCollections() {
@@ -1173,20 +1371,25 @@ export class DigitalEditionsApp {
t_all = translation;
}, error => { }
);
- mediaCollectionMenu.unshift({ 'id': 'all', 'title': t_all });
+ mediaCollectionMenu.unshift({ 'id': 'all', 'title': t_all, 'highlight': true });
+ mediaCollectionMenu.forEach(item => {
+ item['is_gallery'] = true;
+ });
this.mediaCollectionOptions['toc_exists'] = true;
this.mediaCollectionOptions['expanded'] = false;
this.mediaCollectionOptions['loading'] = false;
this.mediaCollectionOptions['accordionToc'] = {
toc: mediaCollectionMenu,
- searchTocItem: false,
+ searchTocItem: true,
searchTitle: '', // If toc item has to be searched by unique title also
currentPublicationId: null
};
this.mediaCollectionOptions['has_children_pdfs'] = false;
this.mediaCollectionOptions['isDownload'] = false;
this.mediaCollectionOptions['highlight'] = false;
- this.mediaCollectionOptions['title'] = '';
+ this.mediaCollectionOptions['title'] = 'media';
+ this.mediaCollectionOptions['id'] = 'mediaCollections';
+ this.mediaCollectionOptions['collectionId'] = 'mediaCollections';
} else {
this.mediaCollectionOptions = [];
}
@@ -1194,12 +1397,28 @@ export class DigitalEditionsApp {
}
}
+
openMediaCollections() {
+ this.mediaCollectionOptions['accordionToc']['toc'].forEach(element => {
+ if (element.id === 'all') {
+ element.highlight = true;
+ } else {
+ element.highlight = false;
+ }
+ });
const params = {};
- this.nav.setRoot('media-collections', params, { animate: false, direction: 'forward', animation: 'ios-transition' });
+ const nav = this.app.getActiveNavs();
+ nav[0].setRoot('media-collections', params, { animate: false, direction: 'forward', animation: 'ios-transition' });
}
openMediaCollection(gallery) {
+ this.mediaCollectionOptions['accordionToc']['toc'].forEach(element => {
+ if (gallery.id === element.id) {
+ element.highlight = true;
+ } else {
+ element.highlight = false;
+ }
+ });
const nav = this.app.getActiveNavs();
const params = { mediaCollectionId: gallery.id, mediaTitle: this.makeTitle(gallery.image_path), fetch: false };
nav[0].push('media-collection', params, { animate: true, direction: 'forward', animation: 'ios-transition' });
diff --git a/src/app/app.html b/src/app/app.html
index cba1f5e5..246c5d02 100644
--- a/src/app/app.html
+++ b/src/app/app.html
@@ -18,7 +18,8 @@
@@ -28,39 +29,40 @@
{{"TOC.About" | translate }}
-
+
+
+
+
@@ -137,11 +161,6 @@
{{"TOC.Facsimiles" | translate }}
-
-
- {{"TOC.ImageGallery" | translate }}
-
-
{{ps.translation | translate }}
@@ -187,11 +206,16 @@
{{"TOC.Collections" | translate }}
-
- {{collection.title}}
-
-
+
+
+
+ {{collection.title}}
+
+
+
+
+
@@ -221,6 +245,7 @@
+
@@ -246,13 +271,17 @@
-
+
+
+
+
-
\ No newline at end of file
+
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 8b5c0e5f..b73f347a 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -48,6 +48,8 @@ import { SplashScreen } from '@ionic-native/splash-screen';
import { ShareButtonsModule } from 'ngx-sharebuttons';
import { GenericSettingsService } from './services/settings/generic-settings.service';
import { SongService } from './services/song/song.service';
+import { SharePopoverPage } from '../pages/share-popover/share-popover';
+import { SharePopoverPageModule } from '../pages/share-popover/share-popover.module';
import { PinchZoomModule } from 'ngx-pinch-zoom';
import { FacsimileZoomPageModule } from '../pages/facsimile-zoom/facsimile-zoom.module';
import { PersonSearchPageModule } from '../pages/person-search/person-search.module';
@@ -85,7 +87,7 @@ export function createConfigLoader(http: HttpClient): ConfigLoader {
ReferenceDataModalPage
],
imports: [
- BrowserModule,
+ BrowserModule,
HttpModule,
HttpClientModule,
PinchZoomModule,
@@ -121,6 +123,7 @@ export function createConfigLoader(http: HttpClient): ConfigLoader {
UserSettingsPopoverPageModule,
IllustrationPageModule,
SearchAppPageModule,
+ SharePopoverPageModule
// PdfViewerModule,
],
providers: [
@@ -157,7 +160,8 @@ export function createConfigLoader(http: HttpClient): ConfigLoader {
ReferenceDataModalPage,
FacsimileZoomModalPage,
IllustrationPage,
- SearchAppPage
+ SearchAppPage,
+ SharePopoverPage
]
})
export class AppModule { }
diff --git a/src/app/app.scss b/src/app/app.scss
index 86bb0d74..b5127040 100644
--- a/src/app/app.scss
+++ b/src/app/app.scss
@@ -15,6 +15,13 @@
// for the .md, .ios, or .wp mode classes. The mode class is
// automatically applied to the element in the app.
+body {
+ -webkit-user-select: text;
+ -moz-user-select: text;
+ -ms-user-select: text;
+ user-select: text;
+}
+
ion-split-pane {
top: 60px !important;
@@ -26,11 +33,18 @@ ion-split-pane {
}
}
+ion-label {
+ overflow: visible!important;
+}
+
.tei {
font-family: $font-app-tei;
- user-select: text !important;
+ // user-select: text !important;
+
}
+.selectable { -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text; }
+
ion-app, ion-app.md {
font-family: $font-family-base;
font-size: 1.4rem;
@@ -496,7 +510,6 @@ ion-nav{
}
.introjs-fixParent {
- z-index: auto !important;
opacity: 1.0 !important;
-webkit-transform: none !important;
-moz-transform: none !important;
@@ -1047,4 +1060,19 @@ tr.introjs-showElement > th {
.introjs-tooltiptext {
font-size: 14px !important;
}
-}
\ No newline at end of file
+}
+/*.menuResizer {
+ height: 100%;
+ width: 5px;
+
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 0;
+
+ background: #e2e2e2;
+
+ z-index: 99;
+
+ cursor: col-resize;
+}*/
diff --git a/src/app/models/facsimile.model.ts b/src/app/models/facsimile.model.ts
index 23ba9437..41c40a4f 100644
--- a/src/app/models/facsimile.model.ts
+++ b/src/app/models/facsimile.model.ts
@@ -7,8 +7,10 @@ export class Facsimile {
public page_nr: number;
public itemId: string;
public manuscript_id: number;
+ public publication_facsimile_collection_id: number;
+ public number_of_pages: number;
- public title = '';
+ public title: any;
public content = '';
public images = [];
public zoomedImages = [];
@@ -18,14 +20,16 @@ export class Facsimile {
constructor(facsimileInfo: any) {
this.id = facsimileInfo.id;
this.zoom = 1;
- this.page = facsimileInfo.pre_page_count + facsimileInfo.page_nr;
+ this.page = facsimileInfo.start_page_number + facsimileInfo.page_nr;
this.page_nr = facsimileInfo.page_nr;
this.pages = facsimileInfo.pages;
- this.pre_page_count = facsimileInfo.pre_page_count;
+ this.pre_page_count = facsimileInfo.start_page_number;
this.type = facsimileInfo.type;
this.title = facsimileInfo.title;
this.itemId = facsimileInfo.itemId;
this.manuscript_id = facsimileInfo.manuscript_id;
+ this.publication_facsimile_collection_id = facsimileInfo.publication_facsimile_collection_id;
+ this.number_of_pages = facsimileInfo.number_of_pages;
}
}
diff --git a/src/app/models/occurrence.model.ts b/src/app/models/occurrence.model.ts
index 3617fc00..d1a27c5b 100644
--- a/src/app/models/occurrence.model.ts
+++ b/src/app/models/occurrence.model.ts
@@ -51,6 +51,7 @@ export class OccurrenceResult {
name: string;
first_name: string;
last_name: string;
+ full_name: string;
sortBy: string;
object_type?: string;
occurrences: any[];
@@ -66,4 +67,9 @@ export class OccurrenceResult {
region?: any;
source?: any;
type?: any;
+ author_data?: any;
+ publisher?: any;
+ published_year?: any;
+ journal?: any;
+ isbn?: any;
}
diff --git a/src/app/models/single-occurrence.model.ts b/src/app/models/single-occurrence.model.ts
index 81216c8c..492ea730 100644
--- a/src/app/models/single-occurrence.model.ts
+++ b/src/app/models/single-occurrence.model.ts
@@ -34,5 +34,4 @@ export class SingleOccurrence {
public variant?: string;
public volume?: string;
public landscape?: string;
- public publication_name?: string;
}
diff --git a/src/app/models/toc-accordion-menu-option.model.ts b/src/app/models/toc-accordion-menu-option.model.ts
index 79e5913c..6515f60b 100644
--- a/src/app/models/toc-accordion-menu-option.model.ts
+++ b/src/app/models/toc-accordion-menu-option.model.ts
@@ -1,5 +1,6 @@
// MenuOptionModel interface
export interface TocAccordionMenuOptionModel {
+ collapsed?: boolean;
id?: any;
// If the option has sub items and the iconName is null,
// the default icon will be 'ios-arrow-down'.
@@ -30,6 +31,8 @@ export interface TocAccordionMenuOptionModel {
type?: string;
+ description?: string;
+
publication_id?: any;
facsimile_id?: any;
@@ -63,4 +66,6 @@ export interface TocAccordionMenuOptionModel {
search_children_id?: any;
important?: boolean;
+
+ is_gallery?: boolean;
}
diff --git a/src/app/services/comments/comment.service.ts b/src/app/services/comments/comment.service.ts
index 050dae27..b4f8841a 100644
--- a/src/app/services/comments/comment.service.ts
+++ b/src/app/services/comments/comment.service.ts
@@ -21,29 +21,36 @@ export class CommentService {
const parts = id2.split(';');
const collection_id = parts[0].split('_')[0];
const pub_id = parts[0].split('_')[1];
+ const section_id = parts[0].split('_')[2];
- const commentId = parts[0];
if (!parts[1]) {
parts[1] = '';
}
+ const commentId = collection_id + '_' + pub_id + (section_id === undefined && section_id !== '') ? '_' + section_id : '';
const introURL = '/text/' + collection_id + '/' + pub_id + '/com';
const commentIdURL = '/text/' + collection_id + '/' + pub_id + '/com/' + parts[1];
- let url: string;
+ let url: String = '';
if (parts[1]) {
- if (parts[1].length > 1) {
+ if (parts[1].length > 1 ) {
url = commentIdURL;
}
} else {
url = introURL;
}
+ if ( section_id !== undefined && section_id !== '' ) {
+ url = introURL + '/' + section_id + '/' + section_id;
+ } else {
+ url = introURL;
+ }
+
if (this.cache.hasHtml(commentId)) {
return this.cache.getHtmlAsObservable(id2);
} else {
- return this.http.get( this.config.getSettings('app.apiEndpoint') + '/' +
- this.config.getSettings('app.machineName') + url
+ return this.http.get(
+ this.config.getSettings('app.apiEndpoint') + '/' + this.config.getSettings('app.machineName') + url
)
.map(res => {
const body = res.json();
@@ -80,4 +87,16 @@ export class CommentService {
return Observable.throw(errMsg);
}
+ getCorrespondanceMetadata(pub_id) {
+ return this.http.get( this.config.getSettings('app.apiEndpoint') + '/' +
+ this.config.getSettings('app.machineName') +
+ '/correspondence/publication/metadata/' + pub_id + '')
+ .map(res => {
+ const body = res.json();
+
+ return body || ' - no content - ';
+ })
+ .catch(this.handleError);
+ }
+
}
diff --git a/src/app/services/elastic-search/elastic-search.d.ts b/src/app/services/elastic-search/elastic-search.d.ts
new file mode 100644
index 00000000..29cf5c02
--- /dev/null
+++ b/src/app/services/elastic-search/elastic-search.d.ts
@@ -0,0 +1,78 @@
+interface SearchQuery {
+ queries: string[]
+ highlight: object
+ from: number
+ size: number
+ facetGroups?: FacetGroups
+ range?: TimeRange
+ sort?: object[]
+}
+
+interface AggregationQuery {
+ queries: string[]
+ facetGroups?: FacetGroups
+ range?: TimeRange
+}
+
+interface TimeRange {
+ from?: string | number
+ to?: string | number
+}
+
+interface FacetGroups {
+ [facetGroupKey: string]: Facets
+}
+
+interface Facets {
+ [facetKey: string]: Facet
+}
+
+interface Facet {
+ doc_count: number
+ key: string | number
+ key_as_string?: string
+ selected?: boolean
+}
+
+interface Aggregations {
+ [key: string]: Aggregation
+}
+
+interface Aggregation {
+ terms?: Terms
+ date_histogram?: DateHistogram
+}
+
+interface Terms {
+ size: number
+ field: string
+}
+
+interface DateHistogram {
+ field: string
+ calendar_interval: string,
+ format: string
+}
+
+interface SuggestionsQuery {
+ query: string
+}
+
+interface SuggestionsConfig {
+ [aggregationKey: string]: {
+ field: string
+ size: number
+ }
+}
+
+interface AggregationsData {
+ [aggregationKey: string]: AggregationData
+}
+
+interface AggregationData {
+ buckets?: Facet[]
+ filtered?: {
+ buckets: Facet[]
+ }
+}
+
diff --git a/src/app/services/elastic-search/elastic-search.service.ts b/src/app/services/elastic-search/elastic-search.service.ts
new file mode 100644
index 00000000..e5c59e68
--- /dev/null
+++ b/src/app/services/elastic-search/elastic-search.service.ts
@@ -0,0 +1,397 @@
+import { Injectable } from '@angular/core'
+import { Http, Response } from '@angular/http'
+import { Observable } from 'rxjs/Observable'
+import { ConfigService } from '@ngx-config/core'
+
+
+@Injectable()
+export class ElasticSearchService {
+
+ private searchApiPath = '/search/elastic/'
+ private termApiPath = '/search/mtermvector/'
+ private indices = []
+ private apiEndpoint: string
+ private machineName: string
+ private source = []
+ private aggregations: Aggregations = {}
+ private suggestions: SuggestionsConfig = {}
+ private fixedFilters: object[]
+
+ constructor(private http: Http, private config: ConfigService) {
+ // Should fail if config is missing.
+ try {
+ this.apiEndpoint = this.config.getSettings('app.apiEndpoint')
+ this.machineName = this.config.getSettings('app.machineName')
+ this.indices = this.config.getSettings('ElasticSearch.indices')
+ this.source = this.config.getSettings('ElasticSearch.source')
+ this.aggregations = this.config.getSettings('ElasticSearch.aggregations')
+ this.suggestions = this.config.getSettings('ElasticSearch.suggestions')
+ } catch (e) {
+ console.error('Failed to load Elastic Search Service. Configuration error.', e.message)
+ throw e
+ }
+ // Should not fail if config is missing.
+ try {
+ this.fixedFilters = this.config.getSettings('ElasticSearch.fixedFilters')
+ } catch (e) {
+ console.error('Failed to load Elastic Search Service. Configuration error.', e.message)
+ }
+ }
+
+ executeTermQuery(terms: String[], ids: String[]): Observable {
+ const payload = {
+ 'ids' : ids,
+ 'parameters': {
+ 'fields': [
+ 'textDataIndexed'
+ ],
+ 'term_statistics': false,
+ 'field_statistics' : false
+ }
+ }
+
+ return this.http.post(this.getTermUrl() + '/' + terms, payload)
+ .map(this.extractData)
+ .catch(this.handleError)
+ }
+
+ /**
+ * Returns hits.
+ */
+ executeSearchQuery(options: SearchQuery): Observable {
+ const payload = this.generateSearchQueryPayload(options)
+
+ return this.http.post(this.getSearchUrl(), payload)
+ .map(this.extractData)
+ .catch(this.handleError)
+ }
+
+ /**
+ * Returns aggregations that are used for faceted search.
+ */
+ executeAggregationQuery(options: AggregationQuery): Observable {
+ const payload = this.generateAggregationQueryPayload(options)
+
+ return this.http.post(this.getSearchUrl(), payload)
+ .map(this.extractData)
+ .catch(this.handleError)
+ }
+
+ /**
+ * Returns facet suggestions.
+ */
+ executeSuggestionsQuery(options: SuggestionsQuery): Observable {
+ const payload = this.generateSuggestionsQueryPayload(options)
+
+ return this.http.post(this.getSearchUrl(), payload)
+ .map(this.extractData)
+ .catch(this.handleError)
+ }
+
+ private generateSearchQueryPayload({
+ queries,
+ highlight,
+ from,
+ size,
+ range,
+ facetGroups,
+ sort,
+ }: SearchQuery): object {
+ const payload: any = {
+ from,
+ size,
+ _source: this.source,
+ query: {
+ bool: {
+ must: []
+ }
+ },
+ sort,
+ }
+
+ // Add free text query.
+ queries.forEach(query => {
+ if (query) {
+ payload.query.bool.must.push({
+ query_string: {
+ query,
+ }
+ })
+ }
+ })
+
+ // Include highlighted text matches to hits if a query is present.
+ if (queries.some(query => !!query)) {
+ payload.highlight = highlight
+ }
+
+ // Add date range filter.
+ if (range) {
+ payload.query.bool.must.push({
+ range: {
+ orig_date_certain: {
+ gte: range.from,
+ lte: range.to,
+ }
+ }
+ })
+ }
+
+ // Add fixed filters that apply to all queries.
+ if (this.fixedFilters) {
+ this.fixedFilters.forEach(filter => {
+ payload.query.bool.must.push(filter)
+ })
+ }
+
+ if (facetGroups) {
+ this.injectFacetsToPayload(payload, facetGroups)
+ }
+
+ console.log('search payload', payload)
+
+ return payload
+ }
+
+ private generateAggregationQueryPayload({
+ queries,
+ range,
+ facetGroups,
+ }: AggregationQuery): object {
+ const payload: any = {
+ from: 0,
+ size: 0,
+ _source: this.source,
+ query: {
+ bool: {
+ should: []
+ }
+ },
+ }
+
+ // Add free text query.
+ queries.forEach(query => {
+ if (query) {
+ payload.query.bool.should.push({
+ query_string: {
+ query,
+ }
+ })
+ }
+ })
+
+ // Add fixed filters that apply to all queries.
+ if (this.fixedFilters) {
+ this.fixedFilters.forEach(filter => {
+ payload.query.bool.should.push(filter)
+ })
+ }
+
+ if (facetGroups || range) {
+ this.injectFilteredAggregationsToPayload(payload, facetGroups, range)
+ } else {
+ this.injectUnfilteredAggregationsToPayload(payload)
+ }
+
+ console.log('aggregation payload', payload)
+
+ return payload
+ }
+
+ private generateSuggestionsQueryPayload({
+ query,
+ }: SuggestionsQuery): object {
+ const payload: any = {
+ from: 0,
+ size: 0,
+ _source: this.source,
+ aggs: {},
+ }
+
+ for (const [aggregationKey, suggestion] of Object.entries(this.suggestions)) {
+ const aggregation = this.aggregations[aggregationKey]
+ if (aggregation.terms) {
+ payload.aggs[aggregationKey] = {
+ filter: {
+ bool: {
+ should: [
+ {
+ wildcard: {
+ [suggestion.field]: {
+ value: `*${query}*`,
+ }
+ }
+ },
+ {
+ fuzzy: {
+ [suggestion.field]: {
+ value: query,
+ }
+ }
+ }
+ ]
+ }
+ },
+ aggs: {
+ filtered: {
+ terms: {
+ field: aggregation.terms.field,
+ size: suggestion.size,
+ }
+ }
+ }
+ }
+ }
+ }
+
+ console.log('suggestions payload', payload)
+
+ return payload
+ }
+
+ private injectFacetsToPayload(payload: any, facetGroups: FacetGroups) {
+ Object.entries(facetGroups).forEach(([facetGroupKey, facets]: [string, Facets]) => {
+ const terms = this.filterSelectedFacetKeys(facets)
+ if (terms.length > 0) {
+ payload.query.bool.filter = payload.query.bool.filter || []
+ payload.query.bool.filter.push({
+ terms: {
+ [this.aggregations[facetGroupKey].terms.field]: terms,
+ }
+ })
+ }
+ })
+ }
+
+ private filterSelectedFacetKeys(facets: Facets): string[] {
+ return Object.values(facets).filter(facet => facet.selected).map((facet: any) => facet.key)
+ }
+
+ private injectUnfilteredAggregationsToPayload(payload: any) {
+ payload.aggs = {}
+ for (const [key, aggregation] of Object.entries(this.aggregations)) {
+ payload.aggs[key] = aggregation
+ }
+ return payload
+ }
+
+ /**
+ * Inspired by an article that uses an old version of elastic:
+ * https://madewithlove.com/faceted-search-using-elasticsearch/
+ *
+ * Up to date documentation:
+ * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filter-aggregation.html
+ */
+ private injectFilteredAggregationsToPayload(payload: any, facetGroups?: FacetGroups, range?: TimeRange) {
+ payload.aggs = {}
+ for (const [key, aggregation] of Object.entries(this.aggregations)) {
+ const filteredAggregation = this.generateFilteredAggregation(key, aggregation, facetGroups, range)
+
+ // If filtered aggregation doesn't have filters, then use an unfiltered aggregation.
+ payload.aggs[key] = filteredAggregation || aggregation
+ }
+ return payload
+ }
+
+ private generateFilteredAggregation(
+ aggregationKey: string,
+ aggregation: Aggregation,
+ facetGroups?: FacetGroups,
+ range?: TimeRange
+ ) {
+
+ const filtered = {
+ filter: {
+ bool: {
+ // Selected facets go here as filters.
+ filter: []
+ }
+ },
+ aggs: {
+ // Aggregation goes here.
+ filtered: aggregation,
+ }
+ }
+
+ // Add term filters.
+ if (facetGroups) {
+ Object.entries(facetGroups).forEach(([groupKey, facets]: [string, Facets]) => {
+ // Don't filter itself.
+ if (aggregationKey !== groupKey) {
+ const selectedFacetKeys = this.filterSelectedFacetKeys(facets)
+ if (selectedFacetKeys.length > 0) {
+ filtered.filter.bool.filter.push({
+ terms: {
+ [this.getAggregationField(groupKey)]: selectedFacetKeys,
+ }
+ })
+ }
+ }
+ })
+ }
+
+ // Add date range filter.
+ if (range && !aggregation.date_histogram) {
+ filtered.filter.bool.filter.push({
+ range: {
+ orig_date_certain: {
+ gte: range.from,
+ lte: range.to,
+ }
+ }
+ })
+ }
+
+ if (filtered.filter.bool.filter.length > 0) {
+ return filtered
+ } else {
+ return null
+ }
+ }
+
+ isDateHistogramAggregation(aggregationKey: string): boolean {
+ return !!this.aggregations[aggregationKey]['date_histogram']
+ }
+
+ isTermsAggregation(aggregationKey: string): boolean {
+ return !!this.aggregations[aggregationKey]['terms']
+ }
+
+ getAggregationKeys(): string[] {
+ return Object.keys(this.aggregations)
+ }
+
+ getAggregationField(key: string): string {
+ const agg = this.aggregations[key]
+ return (agg.terms || agg.date_histogram).field
+ }
+
+ private getSearchUrl(): string {
+ return this.apiEndpoint + '/' + this.machineName + this.searchApiPath + this.indices.join(',')
+ }
+
+ private getTermUrl(): string {
+ return this.apiEndpoint + '/' + this.machineName + this.termApiPath + this.indices.join(',')
+ }
+
+ private extractData(res: Response) {
+ const body = res.json()
+ return body || {}
+ }
+
+ private handleError(error: Response | any) {
+ let errMsg: string
+ if (error instanceof Response) {
+ const body = error.json() || ''
+ const err = body.error || JSON.stringify(body)
+ errMsg = `${error.status} - ${error.statusText || ''} ${err}`
+ } else {
+ errMsg = error.message ? error.message : error.toString()
+ }
+ console.error('Eleastic Search query failed.', error)
+ return Observable.throw(errMsg)
+ }
+
+}
+
+
diff --git a/src/app/services/facsimile/facsimile.service.ts b/src/app/services/facsimile/facsimile.service.ts
index b02b2c75..7750e712 100644
--- a/src/app/services/facsimile/facsimile.service.ts
+++ b/src/app/services/facsimile/facsimile.service.ts
@@ -21,10 +21,14 @@ export class FacsimileService {
this.facsimileImageUrl + facs_id + '/' + image_nr + '/' + zoom;
}
- getFacsimiles(publication_id) {
+ getFacsimiles(publication_id, chapter?: string) {
+ const parts = String(publication_id).split('_');
+ if ( parts[2] !== undefined ) {
+ chapter = String(parts[2]).split(';')[0];
+ }
return this.http.get(
this.config.getSettings('app.apiEndpoint') + '/' +
- this.config.getSettings('app.machineName') + this.facsimilesUrl + publication_id
+ this.config.getSettings('app.machineName') + this.facsimilesUrl + publication_id + ((chapter) ? '/' + chapter + '' : '')
).map(res => {
const body = res.json();
return body;
@@ -52,7 +56,7 @@ export class FacsimileService {
getFacsimilePage (legacy_id): Observable {
return this.http.get(this.config.getSettings('app.apiEndpoint') + '/' +
this.config.getSettings('app.machineName') +
- `/facsimile/page/${legacy_id}`)
+ `/facsimiles/${legacy_id}`)
.map(this.extractData)
.catch(this.handleError);
}
diff --git a/src/app/services/gallery/gallery.service.ts b/src/app/services/gallery/gallery.service.ts
index b64d98c2..dcbadd73 100644
--- a/src/app/services/gallery/gallery.service.ts
+++ b/src/app/services/gallery/gallery.service.ts
@@ -70,6 +70,15 @@ export class GalleryService {
.catch(this.handleError);
}
+ getMediaMetadata (id: string, lang: String): Observable {
+ return this.http.get( this.config.getSettings('app.apiEndpoint') + '/' +
+ this.config.getSettings('app.machineName') + '/media/image/metadata/' +
+ id + '/' + lang
+ )
+ .map(this.extractData)
+ .catch(this.handleError);
+ }
+
private extractData(res: Response) {
const body = res.json();
return body || { };
diff --git a/src/app/services/html/html-cache.service.ts b/src/app/services/html/html-cache.service.ts
index afa0b791..d93d6674 100644
--- a/src/app/services/html/html-cache.service.ts
+++ b/src/app/services/html/html-cache.service.ts
@@ -25,7 +25,7 @@ export class HtmlCacheService {
} else {
}
- this.docFrags[id] = range.createContextualFragment(html);
+ this.docFrags[id] = range.createContextualFragment(html.replace(/images\//g, 'assets/images/'));
}
getHtml(id) {
@@ -53,7 +53,7 @@ export class HtmlCacheService {
return this.htmlCache[id] || false;
}
} else {
- return ' - no cached html - ';
+ return '';
}
}
diff --git a/src/app/services/md/md-content.service.ts b/src/app/services/md/md-content.service.ts
index 89249b00..4992327f 100644
--- a/src/app/services/md/md-content.service.ts
+++ b/src/app/services/md/md-content.service.ts
@@ -65,17 +65,21 @@ export class MdContentService {
}
}
- private getNodeById(id, node) {
+ /**
+ * Find a node by id in a JSON tree
+ */
+ getNodeById(id, tree) {
const reduce = [].reduce;
- function runner(result, rnode) {
- if (result || !rnode) { return result; }
- return rnode.id === id && rnode ||
- runner(null, rnode.children) ||
- reduce.call(Object(rnode), runner, result);
+ const runner = (result, node) => {
+ if (result || !node) { return result; }
+ return node.id === id && node ||
+ runner(null, node.children) ||
+ reduce.call(Object(node), runner, result);
}
- return runner(null, node);
+ return runner(null, tree);
}
+
private extractData(res: Response) {
const body = res.json();
return body || { };
diff --git a/src/app/services/occurrence/occurence.service.ts b/src/app/services/occurrence/occurence.service.ts
index d7d0f520..2466a7e1 100644
--- a/src/app/services/occurrence/occurence.service.ts
+++ b/src/app/services/occurrence/occurence.service.ts
@@ -14,7 +14,6 @@ export class OccurrenceService {
return this.http.get( this.config.getSettings('app.apiEndpoint') + '/occurrences/' + object_type + '/' + id)
.map(res => {
const body = res.json();
-
return body || ' - no content - ';
})
.catch(this.handleError);
diff --git a/src/app/services/reference-data/reference-data.service.ts b/src/app/services/reference-data/reference-data.service.ts
index 66df9d86..c640ead8 100644
--- a/src/app/services/reference-data/reference-data.service.ts
+++ b/src/app/services/reference-data/reference-data.service.ts
@@ -22,7 +22,7 @@ export class ReferenceDataService {
.map(res => {
const body = res.json();
- return body[0] || ' - no content - ';
+ return body[0] || '';
})
.catch(this.handleError);
}
diff --git a/src/app/services/search/search-data.service.ts b/src/app/services/search/search-data.service.ts
index 55bef6be..50e3e254 100644
--- a/src/app/services/search/search-data.service.ts
+++ b/src/app/services/search/search-data.service.ts
@@ -104,6 +104,18 @@ export class SearchDataService {
.catch(this.handleError);
}
+
+ getProjectCollections() {
+ return this.http.get(this.config.getSettings('app.apiEndpoint') + '/' + this.config.getSettings('app.machineName') +
+ '/collections')
+ .map(res => {
+ const body = res.json();
+
+ return body || ' - no content - ';
+ })
+ .catch(this.handleError);
+ }
+
getGalleryOccurrences( type, id ) {
return this.http.get( this.config.getSettings('app.apiEndpoint') + '/' +
this.config.getSettings('app.machineName') +
diff --git a/src/app/services/semantic-data/semantic-data.service.ts b/src/app/services/semantic-data/semantic-data.service.ts
index 0ed249af..33f97ad7 100644
--- a/src/app/services/semantic-data/semantic-data.service.ts
+++ b/src/app/services/semantic-data/semantic-data.service.ts
@@ -9,6 +9,11 @@ export class SemanticDataService {
textCache: any;
useLegacy: boolean;
+ elasticSubjectIndex: string;
+ elasticLocationIndex: string;
+ elasticWorkIndex: string;
+ elasticTagIndex: string;
+ flattened: any;
constructor(private http: Http, private config: ConfigService) {
try {
@@ -16,8 +21,14 @@ export class SemanticDataService {
} catch (e) {
this.useLegacy = false;
}
+ this.elasticSubjectIndex = 'subject';
+ this.elasticLocationIndex = 'location';
+ this.elasticWorkIndex = 'work';
+ this.elasticTagIndex = 'tag';
+ this.flattened = [];
}
+
getFilterCollections(): Observable {
return this.http.get('assets/filterCollections.json')
.map(this.extractData)
@@ -25,15 +36,54 @@ export class SemanticDataService {
}
getFilterPersonTypes(): Observable {
- return this.http.get('assets/filterPersonTypes.json')
- .map(this.extractData)
- .catch(this.handleError);
+ const payload: any = {
+ size: 0,
+ query: {
+ bool: {
+ must : [{
+ term: { project_id : this.config.getSettings('app.projectId') }
+ }]
+ }
+ },
+ aggs : {
+ types : {
+ terms : {
+ field : 'type.keyword'
+ }
+ }
+ }
+ }
+ return this.http.post(this.getSearchUrl(this.elasticSubjectIndex), payload)
+ .map(this.extractData)
+ .catch(this.handleError)
+ }
+
+ getFilterCategoryTypes(): Observable {
+ const payload: any = {
+ size: 0,
+ query: {
+ bool: {
+ must : [{
+ term: { project_id : this.config.getSettings('app.projectId') }
+ }]
+ }
+ },
+ aggs : {
+ types : {
+ terms : {
+ field : 'tag_type.keyword'
+ }
+ }
+ }
+ }
+ return this.http.post(this.getSearchUrl(this.elasticTagIndex), payload)
+ .map(this.extractData)
+ .catch(this.handleError)
}
getPlace(id: string): Observable {
return this.http.get(this.config.getSettings('app.apiEndpoint') + '/' +
- this.config.getSettings('app.machineName') + '/tooltips/location/' + id +
- ((this.useLegacy) ? '/' + this.useLegacy + '/' : '/'))
+ this.config.getSettings('app.machineName') + '/location/' + id)
.map(res => {
const body = res.json();
@@ -44,11 +94,9 @@ export class SemanticDataService {
getPerson(id: string): Observable {
return this.http.get(this.config.getSettings('app.apiEndpoint') + '/' +
- this.config.getSettings('app.machineName') + '/tooltips/subject/' + id +
- ((this.useLegacy) ? '/' + this.useLegacy + '/' : '/'))
+ this.config.getSettings('app.machineName') + '/subject/' + id)
.map(res => {
const body = res.json();
-
return body || ' - no content - ';
})
.catch(this.handleError);
@@ -56,8 +104,18 @@ export class SemanticDataService {
getTag(id: string): Observable {
return this.http.get(this.config.getSettings('app.apiEndpoint') + '/' +
- this.config.getSettings('app.machineName') + '/tooltips/tag/' + id +
- ((this.useLegacy) ? '/' + this.useLegacy + '/' : '/'))
+ this.config.getSettings('app.machineName') + '/tag/' + id)
+ .map(res => {
+ const body = res.json();
+
+ return body || ' - no content - ';
+ })
+ .catch(this.handleError);
+ }
+
+ getWork(id: string): Observable {
+ return this.http.get(this.config.getSettings('app.apiEndpoint') + '/' +
+ this.config.getSettings('app.machineName') + '/work/' + id)
.map(res => {
const body = res.json();
@@ -68,7 +126,7 @@ export class SemanticDataService {
getSemanticData(id: string): Observable {
return this.http.get(this.config.getSettings('app.apiEndpoint') + '/' +
- this.config.getSettings('app.machineName') + 'tooltips/tag/' + id)
+ this.config.getSettings('app.machineName') + '/tag/' + id)
.map(res => {
const body = res.json();
@@ -79,7 +137,7 @@ export class SemanticDataService {
}
getAllPerson(): Observable {
- return this.http.get(this.config.getSettings('app.apiEndpoint') + '/tooltips/subjects')
+ return this.http.get(this.config.getSettings('app.apiEndpoint') + '/subjects')
.map(res => {
const body = res.json();
@@ -109,6 +167,17 @@ export class SemanticDataService {
return this.http.get(this.config.getSettings('app.apiEndpoint') + '/' +
this.config.getSettings('app.machineName') + '/subject/occurrences/' + ((subject_id) ? subject_id + '/' : ''))
+ .map(res => {
+ const body = res.json();
+ return body || ' - no content - ';
+ })
+ .catch(this.handleError);
+ }
+
+ getSubjects(): Observable {
+
+ return this.http.get(this.config.getSettings('app.apiEndpoint') + '/' +
+ this.config.getSettings('app.machineName') + '/subjects')
.map(res => {
const body = res.json();
@@ -117,12 +186,284 @@ export class SemanticDataService {
.catch(this.handleError);
}
+ getSubjectsElastic(from, searchText?, filters?) {
+ let showPublishedStatus = 2;
+ if ( filters === null ) {
+ filters = {};
+ }
+ try {
+ showPublishedStatus = this.config.getSettings('PersonSearch.ShowPublishedStatus');
+ } catch (e) {
+ showPublishedStatus = 2;
+ }
+ const payload: any = {
+ from: from,
+ size: 200,
+ sort: [
+ { 'full_name.keyword' : {'order' : 'asc'} }
+ ],
+ query: {
+ bool: {
+ must : [{
+ 'term' : { 'project_id' : this.config.getSettings('app.projectId') }
+ },
+ {
+ 'term' : { 'published' : showPublishedStatus }
+ },
+ {
+ 'term' : { 'sub_deleted' : 0 }
+ }],
+ }
+ }
+ }
+
+ if (filters !== undefined && filters['filterPersonTypes'] !== undefined && filters['filterPersonTypes'].length > 0) {
+ payload.from = 0;
+ payload.size = 1000;
+ payload.query.bool.must.push({bool: {should: []}});
+ filters['filterPersonTypes'].forEach(element => {
+ payload.query.bool.must[payload.query.bool.must.length - 1].bool.
+ should.push({'term': {'type.keyword': String(element.name)}});
+ });
+ }
+
+ // Add date range filter.
+ if (filters.filterYearMax && filters.filterYearMin) {
+ payload.from = 0;
+ payload.size = 1000;
+ payload.query.bool.must.push({
+ range: {
+ date_born_date: {
+ gte: filters.filterYearMin + '-01-01',
+ lte: filters.filterYearMax + '-01-01',
+ }
+ }
+ })
+ }
+ // Seach for first character of name
+ if (searchText !== undefined && searchText !== '' && String(searchText).length === 1) {
+ payload.from = 0;
+ payload.size = 5000;
+ payload.query.bool.must.push({regexp: {'full_name.keyword': {
+ 'value': `${String(searchText)}.*|${String(searchText).toLowerCase()}.*`}}});
+ } else if ( searchText !== undefined && searchText !== '' ) {
+ payload.from = 0;
+ payload.size = 5000;
+ payload.sort = ['_score'],
+ payload.query.bool.must.push({fuzzy: {'full_name': {
+ 'value': `${String(searchText)}`}}});
+ }
+
+ return this.http.post(this.getSearchUrl(this.elasticSubjectIndex), payload)
+ .map(this.extractData)
+ .catch(this.handleError)
+ }
+
+ getSingleObjectElastic(type, id) {
+ const payload: any = {
+ from: 0,
+ size: 200,
+ query: {
+ bool: {
+ should : [{
+ bool: {
+ must: [{
+ 'term' : { 'project_id' : this.config.getSettings('app.projectId') }
+ },
+ {
+ 'term' : { 'id' : id }
+ }]
+ }
+ },
+ {
+ bool: {
+ must: [{
+ 'term' : { 'project_id' : this.config.getSettings('app.projectId') }
+ },
+ {
+ 'term' : { 'legacy_id' : id }
+ }]
+ }
+ }]
+ }
+ }
+ }
+
+ if ( type === 'work' ) {
+ payload.query.bool.should[0].bool.must[1]['term'] = {'man_id': id};
+ }
+
+ // remove if the ID is not strictly numerical
+ if ( /^\d+$/.test(id) === false ) {
+ delete payload.query.bool.should[0];
+ }
+
+ return this.http.post(this.getSearchUrl(type), payload)
+ .map(this.extractData)
+ .catch(this.handleError)
+ }
+
+ getLocationElastic(from, searchText?) {
+ let showPublishedStatus = 2;
+ try {
+ showPublishedStatus = this.config.getSettings('LocationSearch.ShowPublishedStatus');
+ } catch (e) {
+ showPublishedStatus = 2;
+ }
+ const payload: any = {
+ from: from,
+ size: 200,
+ sort: [
+ { 'name.keyword' : 'asc' }
+ ],
+ query: {
+ bool: {
+ must : [{
+ 'term' : { 'project_id' : this.config.getSettings('app.projectId') }
+ },
+ {
+ 'term' : { 'published' : showPublishedStatus }
+ },
+ {
+ 'term' : { 'loc_deleted' : 0 }
+ }],
+ }
+ }
+ }
+ // Seach for first character of name
+ if (searchText !== undefined && searchText !== '' && String(searchText).length === 1) {
+ payload.from = 0;
+ payload.size = 5000;
+ payload.query.bool.must.push({regexp: {'name.keyword': {
+ 'value': `${String(searchText)}.*|${String(searchText).toLowerCase()}.*`}}});
+ } else if ( searchText !== undefined && searchText !== '' ) {
+ payload.from = 0;
+ payload.size = 5000;
+ payload.sort = ['_score'],
+ payload.query.bool.must.push({fuzzy: {'name': {
+ 'value': `${String(searchText)}`}}});
+ }
+ return this.http.post(this.getSearchUrl(this.elasticLocationIndex), payload)
+ .map(this.extractData)
+ .catch(this.handleError)
+ }
+
+ getWorksElastic(from, searchText?) {
+ const payload: any = {
+ from: from,
+ size: 200,
+ sort: [
+ { 'author_data.last_name.keyword' : 'asc' }
+ ],
+ query: {
+ bool: {
+ should : [{
+ bool: {
+ must: [{
+ 'term' : { 'project_id' : this.config.getSettings('app.projectId')},
+ },
+ {
+ 'term' : { 'deleted' : 0 }
+ }]
+ }
+ },
+ {
+ bool: {
+ must: [{
+ 'term' : { 'project_id' : this.config.getSettings('app.projectId')}
+ },
+ {
+ 'term' : { 'deleted' : 0 }
+ }]
+ }
+ }]
+ }
+ }
+ }
+ // Seach for first character of name
+ if (searchText !== undefined && searchText !== '' && String(searchText).length === 1) {
+ payload.from = 0;
+ payload.size = 5000;
+ payload.query.bool.should[0].bool.must.push({regexp: {'title.keyword': {
+ 'value': `${String(searchText)}.*|${String(searchText).toLowerCase()}.*`}}});
+ payload.query.bool.should[1].bool.must.push({regexp: {'title.keyword': {
+ 'value': `${String(searchText)}.*|${String(searchText).toLowerCase()}.*`}}});
+ } else if ( searchText !== undefined && searchText !== '' ) {
+ payload.from = 0;
+ payload.size = 5000;
+ payload.sort = ['_score'],
+ payload.query.bool.should[0].bool.must.push({fuzzy: {'title': {
+ 'value': `${String(searchText)}`}}});
+ payload.query.bool.should[1].bool.must.push({regexp: {'author_data.full_name': {
+ 'value': `${String(searchText)}.*|${String(searchText).toLowerCase()}.*`}}});
+ }
+ return this.http.post(this.getSearchUrl(this.elasticWorkIndex), payload)
+ .map(this.extractData)
+ .catch(this.handleError)
+ }
+
+ getTagElastic(from, searchText?, filters?) {
+ let showPublishedStatus = 2;
+ try {
+ showPublishedStatus = this.config.getSettings('LocationSearch.ShowPublishedStatus');
+ } catch (e) {
+ showPublishedStatus = 2;
+ }
+ const payload: any = {
+ from: from,
+ size: 800,
+ sort: [
+ { 'name.keyword' : 'asc' }
+ ],
+ query: {
+ bool: {
+ must : [{
+ 'term' : { 'project_id' : this.config.getSettings('app.projectId') }
+ },
+ {
+ 'term' : { 'published' : showPublishedStatus }
+ },
+ {
+ 'term' : { 'tag_deleted' : 0 }
+ }],
+ }
+ }
+ }
+
+ // Seach for first character of name
+ if (searchText !== undefined && searchText !== '' && String(searchText).length === 1) {
+ payload.from = 0;
+ payload.size = 5000;
+ payload.query.bool.must.push({regexp: {'name.keyword': {
+ 'value': `${String(searchText)}.*|${String(searchText).toLowerCase()}.*`}}});
+ } else if ( searchText !== undefined && searchText !== '' ) {
+ payload.from = 0;
+ payload.size = 5000;
+ payload.sort = ['_score'],
+ payload.query.bool.must.push({fuzzy: {'name': {
+ 'value': `${String(searchText)}`}}});
+ }
+
+ if (filters !== undefined && filters['filterCategoryTypes'] !== undefined) {
+ payload.from = 0;
+ payload.size = 1000;
+ payload.query.bool.must.push({bool: {should: []}});
+ filters['filterCategoryTypes'].forEach(element => {
+ payload.query.bool.must[payload.query.bool.must.length - 1].bool.
+ should.push({'term': {'tag_type.keyword': String(element.name)}});
+ });
+ }
+
+ return this.http.post(this.getSearchUrl(this.elasticTagIndex), payload)
+ .map(this.extractData)
+ .catch(this.handleError)
+ }
+
getSubjectOccurrencesById(id: string): Observable {
return this.http.get(this.config.getSettings('app.apiEndpoint') + '/occurrences/subject/' + id)
.map(res => {
const body = res.json();
-
return body || ' - no content - ';
})
.catch(this.handleError);
@@ -133,7 +474,6 @@ export class SemanticDataService {
return this.http.get(this.config.getSettings('app.apiEndpoint') + '/occurrences/' + type + '/' + id)
.map(res => {
const body = res.json();
-
return body || ' - no content - ';
})
.catch(this.handleError);
@@ -163,7 +503,7 @@ export class SemanticDataService {
getWorkOccurrencesById(id: string): Observable {
- return this.http.get(this.config.getSettings('app.apiEndpoint') + '/occurrences/work/' + id)
+ return this.http.get(this.config.getSettings('app.apiEndpoint') + '/' + this.config.getSettings('app.machineName') + '/workregister/work/project/occurrences/' + id)
.map(res => {
const body = res.json();
@@ -199,7 +539,7 @@ export class SemanticDataService {
getWorkOccurrences(): Observable {
return this.http.get(this.config.getSettings('app.apiEndpoint') + '/' +
- this.config.getSettings('app.machineName') + '/tag/occurrences/')
+ this.config.getSettings('app.machineName') + '/workregister/manifestations/')
.map(res => {
const body = res.json();
@@ -227,6 +567,36 @@ export class SemanticDataService {
.catch(this.handleError);
}
+ getPublicationTOC(collection_id) {
+ return this.http.get(this.config.getSettings('app.apiEndpoint') + '/' +
+ this.config.getSettings('app.machineName') + '/toc/' + collection_id)
+ .map(res => {
+ const data = res.json();
+ this.flatten(data);
+ return this.flattened;
+ },
+ error => {
+ console.log(error);
+ })
+ .catch(this.handleError);
+ }
+
+ private flatten(toc) {
+ if ( toc.children ) {
+ for (let i = 0, count = toc.children.length; i < count; i++) {
+ if ( toc.children[i].itemId !== undefined && toc.children[i].itemId !== '') {
+ this.flattened.push(toc.children[i]);
+ }
+ this.flatten(toc.children[i]);
+ }
+ }
+ }
+
+ private getSearchUrl(index: any): string {
+ return this.config.getSettings('app.apiEndpoint') + '/' +
+ this.config.getSettings('app.machineName') + '/search/elastic/' + index
+ }
+
private extractData(res: Response) {
const body = res.json();
return body || {};
diff --git a/src/app/services/settings/read-popover.service.ts b/src/app/services/settings/read-popover.service.ts
index c507a481..1b418847 100644
--- a/src/app/services/settings/read-popover.service.ts
+++ b/src/app/services/settings/read-popover.service.ts
@@ -15,6 +15,7 @@ export class ReadPopoverService {
'personInfo': false,
'abbreviations': false,
'placeInfo': false,
+ 'workInfo': false,
'changes': false,
'pageNumbering': false,
'pageBreakOriginal': false,
diff --git a/src/app/services/settings/user-settings.service.ts b/src/app/services/settings/user-settings.service.ts
index da9d8bcf..84d96e08 100644
--- a/src/app/services/settings/user-settings.service.ts
+++ b/src/app/services/settings/user-settings.service.ts
@@ -26,18 +26,12 @@ export class UserSettingsService {
detectPlatform() {
this.storage.get('mode').then((mode) => {
// mode is either desktop or mobile
- console.log(`my mode is ${mode}...`);
if (mode) {
- console.log('thus ${mode}');
this._mode = mode;
} else {
- console.log('thus some other');
-
if (this.platform.is('core') || this.platform.is('tablet')) {
this._mode = 'desktop';
- console.log('perhaps desktop');
} else {
- console.log('perhaps mobile');
this._mode = 'mobile';
}
}
@@ -124,7 +118,7 @@ export class UserSettingsService {
set splitPaneOpen(maybe: boolean) {
this._splitPaneOpen = maybe;
- console.log(this._splitPaneOpen);
+ // console.log(this._splitPaneOpen);
this.storage.set('splitPane', maybe);
}
diff --git a/src/app/services/texts/text.service.ts b/src/app/services/texts/text.service.ts
index 76fc2d1b..f76acb48 100644
--- a/src/app/services/texts/text.service.ts
+++ b/src/app/services/texts/text.service.ts
@@ -13,8 +13,11 @@ export class TextService {
private titlePageUrl = '/text/tit/';
private variationsUrl = '/text/var/';
private manuscriptsUrl = '/text/ms/';
+ private illustrationsImage: string;
textCache: any;
+ apiEndPoint: string;
+ appMachineName: string;
constructor(private http: Http, private config: ConfigService, private cache: TextCacheService) {
@@ -22,23 +25,75 @@ export class TextService {
getEstablishedText(id: string): Observable {
-
+ this.appMachineName = this.config.getSettings('app.machineName');
+ this.apiEndPoint = this.config.getSettings('app.apiEndpoint');
const id2 = id.replace('_est', '');
const parts = id2.split(';');
const c_id = `${id}`.split('_')[0];
const pub_id = `${id}`.split('_')[1];
let ch_id = null;
if ( `${id}`.split('_')[2] !== undefined ) {
- ch_id = `${id}`.split('_')[2];
+ ch_id = String(`${id}`.split('_')[2]).split(';')[0];
}
- const textId = parts[0];
- return this.http.get( this.config.getSettings('app.apiEndpoint') + '/' +
- this.config.getSettings('app.machineName') + '/text/' + c_id + '/' + pub_id + '/est' + ((ch_id === null) ? '' : '/' + ch_id))
+ if ( ch_id === '' ) {
+ ch_id = null;
+ }
+
+ const textId = id;
+
+ return this.http.get( `${this.apiEndPoint}/${this.appMachineName}/text/${c_id}/${pub_id}/est${((ch_id === null) ? '' : '/' + ch_id)}`)
.map(res => {
const body = res.json();
+
+ try {
+ if (this.config.getSettings('settings.showReadTextIllustrations')) {
+ const showIllustration = this.config.getSettings('settings.showReadTextIllustrations');
+ let galleryId = 44;
+ try {
+ galleryId = this.config.getSettings('settings.galleryCollectionMapping')[c_id];
+ } catch ( err ) {
+
+ }
+
+ if (!showIllustration.includes(c_id)) {
+ const parser = new DOMParser();
+ body.content = parser.parseFromString(body.content, 'text/html');
+ const images: any = body.content.querySelectorAll('img.est_figure_graphic');
+ for (let i = 0; i < images.length; i++) {
+ images[i].classList.add('hide-illustration');
+ }
+
+ const s = new XMLSerializer();
+ body.content = s.serializeToString(body.content);
+ this.cache.setHtmlCache(textId, body.content.replace(/images\/verk\//g, `${this.apiEndPoint}/${this.appMachineName}/gallery/get/${galleryId}/`));
+ const ret = this.cache.getHtml(id);
+ if ( !ret ) {
+ return body.content;
+ }
+ return this.cache.getHtml(id);
+ }
+ }
+ } catch (e) {
+ console.error(e)
+ }
+
+ const se = new XMLSerializer();
+ try {
+ const parser = new DOMParser();
+ body.content = parser.parseFromString(body.content, 'text/html');
+ body.content = se.serializeToString(body.content);
this.cache.setHtmlCache(textId, body.content);
- return this.cache.getHtml(id);
+ } catch ( err ) {
+ console.log(err);
+ }
+
+ const cachedHTML = this.cache.getHtml(id);
+ if ( cachedHTML && cachedHTML !== '' ) {
+ return cachedHTML;
+ } else {
+ return body.content;
+ }
})
.catch(this.handleError);
}
@@ -79,6 +134,20 @@ export class TextService {
.catch(this.handleError);
}
+
+ getCoverPage(id: string, lang: string): Observable {
+ const data = `${id}`.split('_');
+ const c_id = data[0];
+ const pub_id = (data.length > 1) ? data[1] : 1;
+
+ return this.http.get( this.config.getSettings('app.apiEndpoint') + '/' +
+ this.config.getSettings('app.machineName') + '/text/' + c_id + '/' + pub_id + '/cover/' + lang)
+ .map(res => {
+ return res.json();
+ })
+ .catch(this.handleError);
+ }
+
getVariations(id: string): Observable {
const c_id = `${id}`.split('_')[0];
const pub_id = `${id}`.split('_')[1];
@@ -91,12 +160,16 @@ export class TextService {
.catch(this.handleError);
}
- getManuscripts(id: string): Observable {
+ getManuscripts(id: string, chapter?: string): Observable {
const c_id = `${id}`.split('_')[0];
const pub_id = `${id}`.split('_')[1];
+ if ( chapter !== undefined && chapter !== null ) {
+ chapter = String(chapter).split(';')[0];
+ }
+
return this.http.get( this.config.getSettings('app.apiEndpoint') + '/' +
- this.config.getSettings('app.machineName') + '/text/' + c_id + '/' + pub_id + '/ms')
+ this.config.getSettings('app.machineName') + '/text/' + c_id + '/' + pub_id + '/ms' + ((chapter) ? '/' + chapter + '' : ''))
.map(res => {
return res.json();
})
diff --git a/src/app/services/toc/table-of-contents.service.ts b/src/app/services/toc/table-of-contents.service.ts
index 3e191e93..f7d72d72 100644
--- a/src/app/services/toc/table-of-contents.service.ts
+++ b/src/app/services/toc/table-of-contents.service.ts
@@ -85,8 +85,6 @@ export class TableOfContentsService {
private handleError (error: Response | any) {
let errMsg: string;
- console.error('snafu', error);
-
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
diff --git a/src/app/services/tooltips/tooltip.service.ts b/src/app/services/tooltips/tooltip.service.ts
index 06d4b9ee..8e5fcc8f 100644
--- a/src/app/services/tooltips/tooltip.service.ts
+++ b/src/app/services/tooltips/tooltip.service.ts
@@ -9,52 +9,97 @@ import { CommentService } from '../comments/comment.service';
@Injectable()
export class TooltipService {
- private personTooltipUrl = '/tooltips/subject/';
private placeTooltipUrl = '/tooltips/locations/';
-
- constructor(private http: Http, private config: ConfigService, private commentService: CommentService) {}
+ private apiEndPoint: string;
+ private projectMachineName: string;
+ constructor(private http: Http, private config: ConfigService, private commentService: CommentService) {
+ this.apiEndPoint = this.config.getSettings('app.apiEndpoint');
+ this.projectMachineName = this.config.getSettings('app.machineName');
+ }
getPersonTooltip(id: string): Observable {
+ let url = '';
+ const legacyPrefix = this.config.getSettings('app.legacyIdPrefix');
+
+ url = `${this.apiEndPoint}/${this.projectMachineName}/subject/${legacyPrefix}${id}`
- return this.http.get( this.config.getSettings('app.apiEndpoint') + this.personTooltipUrl + id)
+ return this.http.get(url)
.map(res => {
const body = res.json();
- return body[0] || {'name': 'Error', 'description': 'Person data not found'};
+ return body[0] || {'name': body.full_name, 'description': body.description,
+ 'date_deceased': body.date_deceased,
+ 'date_born': body.date_born};
})
.catch(this.handleError);
}
getPlaceTooltip(id: string): Observable {
+ let url = '';
+ const legacyPrefix = this.config.getSettings('app.legacyIdPrefix');
+
+ url = `${this.apiEndPoint}/${this.projectMachineName}/location/${legacyPrefix}${id}`
+
+ return this.http.get( url )
+ .map(res => {
+ const body = res.json();
+ return body[0] || {'name': body.name, 'description': body.description};
+ })
+ .catch(this.handleError);
+ }
+
+ getTagTooltip(id: string): Observable {
+ let url = '';
+ const legacyPrefix = this.config.getSettings('app.legacyIdPrefix');
+
+ url = `${this.apiEndPoint}/${this.projectMachineName}/tag/${legacyPrefix}${id}`
- return this.http.get( this.config.getSettings('app.apiEndpoint') + this.placeTooltipUrl + id)
+ return this.http.get( url )
.map(res => {
const body = res.json();
- return body[0] || {'name': 'Error', 'description': 'Place data not found'};
+ return body[0] || {'name': 'Tag', 'description': body.description};
})
.catch(this.handleError);
}
+ getWorkTooltip(id: string): Observable {
+ let url = '';
+ url = `${this.apiEndPoint}/${this.projectMachineName}/work/${id}`
+
+ return this.http.get( url )
+ .map(res => {
+ const body = res.json();
+ return body[0] || {'name': 'Work', 'description': body.title};
+ })
+ .catch(this.handleError);
+ }
+
+ decodeHtmlEntity(str: string) {
+ return str.replace(/(\d+);/g, function(match, dec) {
+ return String.fromCharCode(dec);
+ });
+ }
+
+
/**
* Can be used to fetch tooltip in situations like these:
*
*
*/
- getCommentTooltip(id: string) {
+ getCommentTooltip(id: string): Observable {
const parts = id.split(';');
const htmlId = parts[0];
- const elementId = parts[1].replace('end', 'en');
-
-
+ const elementId = parts[parts.length - 1].replace('end', 'en');
return this.commentService.getComment(parts[0]).map(
data => {
const range = document.createRange();
const doc = range.createContextualFragment(data);
- const element = doc.querySelector('#' + elementId).nextElementSibling;
+ const element = doc.querySelector('.' + elementId);
+ const formatedCommentData = element.innerHTML.replace(/(<)/g, '<').replace(/(>)/g, '>');
return {
'name': 'Comment',
- 'description': element.innerHTML.replace(/(<([^>]+)>)/ig, '').replace(/^p\d+/gi, '') }
+ 'description': element.innerHTML = formatedCommentData }
|| {'name': 'Error', 'description': element.innerHTML};
},
error => {
diff --git a/src/app/services/tutorial/tutorial.service.ts b/src/app/services/tutorial/tutorial.service.ts
index cdada04a..03ed23fd 100644
--- a/src/app/services/tutorial/tutorial.service.ts
+++ b/src/app/services/tutorial/tutorial.service.ts
@@ -32,16 +32,24 @@ export class TutorialService {
tutorialTexts => {
this.tutorialTexts = tutorialTexts;
this.tutorialSteps = this.config.getSettings('TutorialSteps');
- console.log(this.tutorialSteps);
for (const i in this.tutorialSteps) {
const str = this.tutorialSteps[i].intro;
this.tutorialSteps[i].intro = tutorialTexts[str] || `${str} Untranslated text`;
}
setTimeout(() => {
- this.storage.get('tutorial-done').then((seen) => {
- if (!seen) {
- this.intro();
+ this.storage.get('all_tutorial_steps').then((steps) => {
+ if (steps !== undefined && steps !== null) {
+ this.tutorialSteps = steps;
}
+ this.storage.get('tutorial-done').then((seen) => {
+ try {
+ if (this.config.getSettings('showTutorial')) {
+ this.intro();
+ }
+ } catch (e) {
+ console.error('Missing showTutorial from config.json');
+ }
+ });
});
}, 1000);
@@ -50,13 +58,26 @@ export class TutorialService {
this.registerListeners();
}
+ private async redoIntro() {
+ setTimeout(() => {
+ this.storage.get('all_tutorial_steps').then((steps) => {
+ if (steps !== undefined && steps !== null) {
+ this.tutorialSteps = steps;
+ this.intro();
+ }
+ });
+ }, 1000);
+ }
private async intro() {
- const intro = introJs();
const steps = this.tutorialSteps.filter((step) => {return this.canBeSeen(step, this.currentPage)});
+ if ( steps.length === 0 ) {
+ return false;
+ }
+
+ const intro = introJs();
- console.log(steps);
intro.setOptions({
steps: steps,
disableInteraction: false,
@@ -67,12 +88,13 @@ export class TutorialService {
prevLabel: this.tutorialTexts.prevLabel,
skipLabel: this.tutorialTexts.skipLabel,
doneLabel: this.tutorialTexts.doneLabel,
+ overlayOpacity: 0.45,
keyboardNavigation: true,
scrollToElement: true,
});
this.canBeSeen = this.canBeSeen.bind(this);
intro.onbeforechange((elem) => {
- console.log('step', elem.selector);
+ // console.log('step', elem.selector);
});
intro.onchange((elem) => {
@@ -83,23 +105,34 @@ export class TutorialService {
intro.oncomplete((elem) => {
this.storage.set('tutorial-done', true);
});
+
+ intro.onexit(() => {
+ this.storage.set('tutorial-done', true);
+ });
+
intro.start();
}
iHaveSeen(selector) {
const i = this.getStep(selector, true);
- console.log(`i have seen ${selector} : ${i}`);
if (i) {
this.tutorialSteps[i].alreadySeen = true;
}
- console.log(this.tutorialSteps);
+ this.storage.set('all_tutorial_steps', this.tutorialSteps);
}
canBeSeen(step, page) {
// i have not already seen it and it is not disabled on this page
// It is visible by default or has been specifically enabled for this page
- return !step.alreadySeen && !step.hideOn.includes(page) &&
- (step.show || step.showOn.includes(page));
+ if ( String(step.element).includes('#') ) {
+ if ( document.getElementById(String(step.element).replace('#', '')) !== null && step.show ) {
+ return !step.alreadySeen;
+ } else {
+ return false;
+ }
+ } else {
+ return !step.alreadySeen;
+ }
}
getStep(selector, returnIndex = false): any {
@@ -109,19 +142,20 @@ export class TutorialService {
// with no element attribute.
for (const i in this.tutorialSteps) {
const step = this.tutorialSteps[i];
- if (!step.element && this.canBeSeen(step, this.currentPage)) {
- if (returnIndex) {
- return i;
- } else {
- return step;
+ if (!step.element) {
+ if (!step.element && this.canBeSeen(step, this.currentPage)) {
+ if (returnIndex) {
+ return i;
+ } else {
+ return step;
+ }
}
}
}
}
for (const i in this.tutorialSteps) {
const step = this.tutorialSteps[i];
- console.log(i, selector, step.element);
- if (step.element && '#' + step.element === selector) {
+ if (step.element && step.element === '#' + selector) {
if (returnIndex) {
return i;
} else {
@@ -135,7 +169,7 @@ export class TutorialService {
for (const i in this.tutorialSteps) {
const step = this.tutorialSteps[i];
this.tutorialSteps[i].alreadySeen = false;
- this.storage.set('tutorial-step-' + step.id, false);
+ this.storage.set('all_tutorial_steps', this.tutorialSteps);
}
this.storage.set('tutorial-done', false);
@@ -150,5 +184,9 @@ export class TutorialService {
this.reset();
this.intro();
});
+
+ this.events.subscribe('help:continue', () => {
+ this.redoIntro();
+ });
}
}
diff --git a/src/assets/custom_css/custom.css b/src/assets/custom_css/custom.css
index 46f06ebe..20acc5ba 100644
--- a/src/assets/custom_css/custom.css
+++ b/src/assets/custom_css/custom.css
@@ -1,4 +1,4 @@
/*
THIS FILE WILL BE REPLACED BY PROJECT SPECIFIC ITEMS
DO NOT MODIFY THIS FILE
-*/
\ No newline at end of file
+*/
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 407abef9..d83e5894 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -1,181 +1,238 @@
{
- "BrowserWarning": "Your browser is not supported",
- "BrowserWarningInfo": "Internet Explorer is not supported by this page. Please use Edge, Firefox or another browser.",
- "BrowserWarningClose": "Close",
- "TopMenu": {
- "Home": "Home",
- "Read": "Content",
- "Info": "About"
- },
- "Tabs": {
- "Home": "Home",
- "Read": "Read",
- "Info": "More Information"
- },
- "Read": {
- "DigitalEditions": "Digital Editions",
- "OpenInTab": "Öppna i ny flik",
- "Popover": {
- "All": "Choose all",
- "Appearance": "Appearance",
- "Show": "Show",
- "Comments": "Comments",
- "PersonInfo": "People",
- "PlaceInfo": "Places",
- "Changes": "Changes",
- "Abbreviations": "Abbreviations",
- "PageNumbering": "Page Numbering",
- "PageBreakOriginal": "Original Page Breaks",
- "PageBreakEdition": "Edition Page Breaks"
- },
- "DownloadDigitalVersion": "Download a Digital Version",
- "CommentsFor": "Comments to",
- "ReadFromBeginning": "From the beginning",
- "Established": {
- "Title": "Established text",
- "AddButtonText": "Established text view"
- },
- "Comments": {
- "Title": "Comments",
- "AddButtonText": "Comments view"
- },
- "Manuscripts": {
- "Title": "Manuscript",
- "AddButtonText": "Manuscript view",
- "SelectManuscript": "Välj manuscript",
- "ShowNormalized": "Visa ändringar inarbetade",
- "ShowChanges": "Visa ändringar",
- "OpenFacsimile": "Open fascimile"
- },
- "Variations": {
- "Title": "Variations",
- "AddButtonText": "Variation view"
- },
- "Facsimiles": {
- "Title": "Facsimiles",
- "AddButtonText": "Facsimile view",
- "SelectFacsimiles": "Choose Facsimile",
- "Page": "Sida",
- "Of": "av",
- "OpenManuscript": "Open manuscript"
- },
- "TitlePage": {
- "Title": "Titel page"
- },
- "Introduction": {
- "Title": ""
- },
- "ShowAll": "Show all"
- },
- "About": {
- "Title": "About the Edition",
- "UI": "User Interface",
- "Language": "Language",
- "Information": "Information"
- },
- "TOC": {
- "Home": "Home",
- "Read": "Read",
- "About": "About Hilma Granqvist",
- "Facsimiles": "Assorted Facsimile",
- "ImageGallery": "Image Gallery",
- "PersonSearch": "Persons",
- "PlaceSearch": "Places",
- "TagSearch": "Subjects",
- "MusicianSearch": "Musicians Search",
- "WriterSearch": "Writers Search",
- "SongTypes": "Song Types",
- "WorkSearch": "Works",
- "Collections": "Publications",
- "Books": "Books",
- "All": "All"
- },
- "GalleryPages": {
- "0": "Headline 1",
- "1": "Headline 2",
- "2": "THeadline 3"
- },
- "MobilePages": {
- "header": "Pages"
- },
- "BackButton": {
- "default": "Go Back"
- },
- "HomePage": {
- "current": "Current",
- "publishedEditions": "Published Editions:",
- "digitalEditionHeading": "Archive of Hilma Granqvist",
- "selectEdition": "View"
- },
- "SearchApp": {
- "simpleSearch": "Simple Search",
- "advancedSearch": "Advanced Search",
- "filter": "Filter",
- "matchesOn": "Match(es):",
- "numberOf": "match(es)",
- "pagenumber": "p.",
- "search-holder": "Seach text",
- "hitCount": "Hit Count",
- "type": "Type",
- "timeline": "Timeline",
- "freetext": "Freetext",
- "start": "Start",
- "end": "End",
- "relevance": "Relevance",
- "alphabetical": "Alphabetical",
- "oldest": "Oldest",
- "genre": "Genre",
- "person-register": "Persons",
- "place-register": "Places ",
- "tag-register": "Subjects/Tags",
- "verk": "Works",
- "sort-by": "Sort by"
- },
- "Occurrences": {
- "Title": "Occurrences",
- "Manuscript": "Manuscript",
- "Variation": "Variation",
- "Commentary": "Commentary",
- "Facsimile": "Facsimile",
- "Established": "Established",
- "longitude": "long.",
- "latitude": "lat.",
- "city": "City",
- "region": "Region",
- "country": "Place",
- "place_of_birth": "Place of Birth",
- "type": "Type",
- "source": "Source",
- "description": "Description",
- "no_occurrences": "No occurrences",
- "download": "download pdf",
- "articles": "Articles"
- },
- "est": "Established text",
- "ms": "Manuscript",
- "com": "Commentary",
- "tit": "Title",
- "var": "Variation",
- "inl": "Introduction",
- "locations": "Locations",
- "location": "Location",
- "tags": "Tags",
- "tag": "Tags",
- "photos": "photos",
- "subjects": "Subjects",
- "subject": "Subject",
- "collections": "Collections",
- "works": "Works",
- "song": "Melody",
- "Reference": {
- "title": "Refer",
- "thisPage": "Refer to this page",
- "established": "Refer to this text",
- "intro": "Refer to this introduction"
- },
- "MusicPage": {
- "Title": "Music",
- "PageTitle": "Music volumes",
- "SubTitle": "FSFD"
- }
-}
\ No newline at end of file
+ "BrowserWarning": "Your browser is not supported",
+ "BrowserWarningInfo": "Internet Explorer is not supported by this page. Please use Edge, Firefox or another browser.",
+ "BrowserWarningClose": "Close",
+ "TutorialTexts": {
+ "nextLabel": "Next",
+ "prevLabel": "Previous",
+ "skipLabel": "Skip",
+ "doneLabel": "Done",
+ "WelcomeText": "Welcome, here is a presentation of the user interface.",
+ "MenuToggleText": "Click here to show or hide the menu.",
+ "searchIcon": "Click here for search.",
+ "ReadTocItemText": "Here you can see all digital publications and volumes.",
+ "DownloadCacheText": "With this button you can save the data locally, and it will be faster next time."
+ },
+ "TopMenu": {
+ "Home": "Home",
+ "Read": "Content",
+ "Info": "About"
+ },
+ "Tabs": {
+ "Home": "Home",
+ "Read": "Read",
+ "Info": "More Information"
+ },
+ "Read": {
+ "DigitalEditions": "Digital Editions",
+ "OpenInTab": "Open in new tab",
+ "Popover": {
+ "All": "Choose all",
+ "Appearance": "Appearance",
+ "Show": "Show",
+ "Comments": "Comments",
+ "PersonInfo": "People",
+ "PlaceInfo": "Places",
+ "Changes": "Changes",
+ "Abbreviations": "Abbreviations",
+ "PageNumbering": "Page Numbering",
+ "PageBreakOriginal": "Original Page Breaks",
+ "PageBreakEdition": "Edition Page Breaks"
+ },
+ "DownloadDigitalVersion": "Download a Digital Version",
+ "DownloadPDF": "",
+ "CommentsFor": "Comments to",
+ "ReadFromBeginning": "From the beginning",
+ "Established": {
+ "Title": "Established text",
+ "AddButtonText": "Established text view"
+ },
+ "Comments": {
+ "Title": "Comments",
+ "AddButtonText": "Comments view"
+ },
+ "Manuscripts": {
+ "Title": "Manuscript",
+ "AddButtonText": "Manuscript view",
+ "SelectManuscript": "Välj manuscript",
+ "ShowNormalized": "Visa ändringar inarbetade",
+ "ShowChanges": "Visa ändringar",
+ "OpenFacsimile": "Open fascimile"
+ },
+ "Variations": {
+ "Title": "Variations",
+ "AddButtonText": "Variation view"
+ },
+ "Facsimiles": {
+ "Title": "Facsimiles",
+ "AddButtonText": "Facsimile view",
+ "SelectFacsimiles": "Choose Facsimile",
+ "Page": "Page",
+ "Of": "of",
+ "OpenManuscript": "Open manuscript",
+ "ExternalHeading" : "External Facsimiles"
+ },
+ "TitlePage": {
+ "Title": "Titel page"
+ },
+ "Introduction": {
+ "Title": ""
+ },
+ "CoverPage": {
+ "Title": "Cover"
+ },
+ "ShowAll": "Show all"
+ },
+ "About": {
+ "Title": "About the Edition",
+ "UI": "User Interface",
+ "Language": "Language",
+ "Information": "Information"
+ },
+ "TOC": {
+ "Home": "Home",
+ "Read": "Read",
+ "Read1": "Read",
+ "Read2": "Read",
+ "ReadN": "Read",
+ "About": "About Hilma Granqvist",
+ "Facsimiles": "Assorted Facsimile",
+ "ImageGallery": "Image Gallery",
+ "PersonSearch": "Persons",
+ "PlaceSearch": "Places",
+ "TagSearch": "Subjects",
+ "MusicianSearch": "Musicians Search",
+ "WriterSearch": "Writers Search",
+ "SongTypes": "Song Types",
+ "WorkSearch": "Works",
+ "Collections": "Publications"
+ },
+ "GalleryPages": {
+ "0": "Headline 1",
+ "1": "Headline 2",
+ "2": "THeadline 3"
+ },
+ "MobilePages": {
+ "header": "Pages"
+ },
+ "BackButton": {
+ "default": "Go Back"
+ },
+ "HomePage": {
+ "current": "Current",
+ "publishedEditions": "Published Editions:",
+ "digitalEditionHeading": "Archive of Hilma Granqvist",
+ "selectEdition": "View"
+ },
+ "SearchApp": {
+ "simpleSearch": "Simple Search",
+ "advancedSearch": "Advanced Search",
+ "filter": "Filter",
+ "matchesOn": "Match(es):",
+ "numberOf": "match(es)",
+ "pagenumber": "p.",
+ "search-holder": "Seach text",
+ "hitCount": "Hit Count",
+ "type": "Type",
+ "timeline": "Timeline",
+ "freetext": "Freetext",
+ "start": "Start",
+ "end": "End",
+ "relevance": "Relevance",
+ "alphabetical": "Alphabetical",
+ "oldest": "Oldest",
+ "genre": "Genre",
+ "person-register": "Persons",
+ "place-register": "Places ",
+ "tag-register": "Subjects/Tags",
+ "verk": "Works",
+ "sort-by": "Sort by"
+ },
+ "Filter":{
+ "personTypes": "Personkategori",
+ "tagTypes": "Ämneskategori",
+ "year": "Född mellan",
+ "apply": "Apply"
+ },
+ "Occurrences": {
+ "Title": "Occurrences",
+ "Manuscript": "Manuscript",
+ "Variation": "Variation",
+ "Commentary": "Commentary",
+ "Facsimile": "Facsimile",
+ "Established": "Established",
+ "longitude": "long.",
+ "latitude": "lat.",
+ "city": "City",
+ "region": "Region",
+ "country": "Place",
+ "place_of_birth": "Place of Birth",
+ "type": "Type",
+ "source": "Source",
+ "description": "Description",
+ "no_occurrences": "No occurrences",
+ "download": "download pdf",
+ "articles": "Articles",
+ "publisher": "Publisher",
+ "journal": "Journal",
+ "isbn": "ISBN",
+ "published_year": "Year of publication",
+ "authors": "Authors"
+ },
+ "ElasticSearch": {
+ "NoHits": "No matches",
+ "Found": "Found",
+ "SearchField": "Add search field",
+ "From": "From",
+ "To": "To",
+ "Search": "Search",
+ "Years": "Year",
+ "ShowMore": "Show more",
+ "ShowLess": "Show less",
+ "SortBy": "Sort by",
+ "Relevance": "Relevans",
+ "OldestFirst": "Oldest first",
+ "NewestFirst": "Newest first"
+ },
+ "Type": "Type",
+ "Genre": "Genre",
+ "Collection": "Collections",
+ "Location": "Location",
+ "Subjects": "Subjects",
+ "Tags": "Taggs",
+ "Person": "Person",
+ "LetterSenderName": "Sender",
+ "LetterReceiverName": "Reciever",
+ "LetterSenderLocation": "Sender place",
+ "LetterReceiverLocation": "Reciever place",
+ "est": "Established text",
+ "ms": "Manuscript",
+ "com": "Commentary",
+ "tit": "Title",
+ "var": "Variation",
+ "inl": "Introduction",
+ "locations": "Locations",
+ "location": "Location",
+ "tags": "Tags",
+ "tag": "Tags",
+ "subjects": "Subjects",
+ "subject": "Subject",
+ "collections": "Collections",
+ "works": "Works",
+ "BC": "f.Kr.",
+ "Reference": {
+ "title": "Refer",
+ "urn": "Link",
+ "thisPage": "Refer to this page",
+ "established": "Refer to this text",
+ "intro": "Refer to this introduction"
+ },
+ "established": "Readtext",
+ "comments": "Commentary",
+ "facsimiles": "Fascimile",
+ "manuscripts": "Manuscript",
+ "variations": "Variations",
+ "introduction": "Introduction",
+ "songexample": "Song",
+ "illustrations": "Illustrationer"
+}
diff --git a/src/assets/i18n/fi.json b/src/assets/i18n/fi.json
index 417444ed..d5c3eb15 100644
--- a/src/assets/i18n/fi.json
+++ b/src/assets/i18n/fi.json
@@ -1,209 +1,316 @@
{
- "BrowserWarning": "Din webbläsare stöds inte",
- "BrowserWarningInfo": "Internet Explorer stöds inte av denna sida. Använd Edge, Firefox eller nån annan webbläsare.",
- "BrowserWarningClose": "Stäng",
- "TopMenu": {
- "Home": "Startsida",
- "Read": "Innehåll",
- "Info": "Om"
- },
- "Tabs": {
- "Home": "Hem",
- "Read": "Läs digitalt",
- "Info": "Mer information"
- },
- "Read": {
- "DigitalEditions": "Digitala utgåvor",
- "OpenInTab": "Öppna i ny flik",
- "Popover": {
- "All": "Välj alla",
- "Appearance": "Utseende",
- "Show": "Visningsalternativ",
- "Comments": "Kommentarer",
- "PersonInfo": "Personupplysningar",
- "PlaceInfo": "Platsupplysningar",
- "Changes": "Ändringar",
- "Abbreviations": "Förkortningar",
- "PageNumbering": "Stycke-/versnummer",
- "PageBreakOriginal": "Sidnummer / sidbrytning i orig.",
- "PageBreakEdition": "Sidnummer i den tryckta utgåvan"
- },
- "DownloadDigitalVersion": "Ladda ner digital version",
- "DownloadPDF": "Ladda ner PDF",
- "CommentsFor": "Kommentarer till",
- "ReadFromBeginning": "Läs från början",
- "Established": {
- "Title": "Lästext",
- "AddButtonText": "Lästextvy"
- },
- "Comments": {
- "Title": "Kommentarer",
- "AddButtonText": "Kommentarvy"
- },
- "Manuscripts": {
- "Title": "Manuskript",
- "AddButtonText": "Manuskriptvy",
- "SelectManuscript": "Välj manuskript",
- "ShowNormalized": "Visa ändringar inarbetade",
- "ShowChanges": "Visa ändringar",
- "OpenFacsimile": "Öppna faksimil"
- },
- "Variations": {
- "Title": "Variationer",
- "AddButtonText": "Variationsvy"
- },
- "Facsimiles": {
- "Title": "Faksimiler",
- "AddButtonText": "Faksimilvy",
- "SelectFacsimiles": "Välj faksimil",
- "Page": "Sida",
- "Of": "av",
- "OpenManuscript": "Öppna manuskript"
- },
- "SongExample": {
- "Title": "Sång exempel",
- "AddButtonText": "Sång exempel"
- },
- "TitlePage": {
- "Title": "Titel"
- },
- "Introduction": {
- "Title": "Inledning",
- "AddButtonText": "Inledning"
- },
- "ShowAll": "Visa alla",
- "ShowSearchResults": "Förekomster"
- },
- "About": {
- "Title": "Om utgåvan",
- "UI": "Användargränssnitt",
- "Language": "Språk",
- "Information": "Information"
- },
- "TOC": {
- "Home": "Till startsidan",
- "Read": "Läs",
- "Facsimiles": "Faksimil i urval",
- "ImageGallery": "Bildgalleri",
- "PersonSearch": "Personsök",
- "PlaceSearch": "Platsregister",
- "TagSearch": "Ämnesord",
- "WorkSearch": "Verkregister",
- "MusicianSearch": "Spelmän",
- "WriterSearch": "Upptecknare",
- "SongTypes": "Låttyper",
- "Music": "Musik",
- "Collections": "Kategorier",
- "Books": "Kirjat",
- "All": "kaikki"
- },
- "GalleryPages": {
- "0": "Finland framställdt i teckningar",
- "1": "En resa i Finland",
- "2": "Topelius liv och verk"
- },
- "MobilePages": {
- "header": "Sidor"
- },
- "BackButton": {
- "default": "Tillbaka"
- },
- "HomePage": {
- "current": "Aktuellt",
- "publishedEditions": "Publicerade utgåvor:",
- "digitalEditionHeading": "Zacharias Topelius verk i digital utgåva",
- "selectEdition": "Se denna"
- },
- "SearchApp": {
- "simpleSearch": "Sök",
- "advancedSearch": "Avancerad sökning",
- "filter": "Filter",
- "matchesOn": "Sökträff(ar):",
- "numberOf": "träffar",
- "pagenumber": "s.",
- "search-holder": "Söktext",
- "hitCount": "Antal träffar",
- "type": "Typ",
- "timeline": "Tidsperiod",
- "freetext": "Fritext",
- "start": "Start",
- "end": "Slut",
- "relevance": "Relevans",
- "alphabetical": "Alfabetet",
- "oldest": "Äldst",
- "genre": "Genre",
- "person-register": "Personregister",
- "place-register": "Platsregister ",
- "tag-register": "Ämnesord",
- "verk": "Verkregister",
- "sort-by": "Sortera enligt"
- },
- "Occurrences": {
- "Title": "Förekomster",
- "Manuscript": "Manuskript",
- "Variation": "Variant",
- "Commentary": "Kommentar",
- "Facsimile": "Faksimil",
- "Established": "Lästext",
- "Song": "Sång",
- "Info": "Information",
- "NoInfoFound": "Ingen information hittades.",
- "OccurrencesSmall": "förekomster",
- "Found": "Hittade",
- "Result": "Resultat",
- "longitude": "long.",
- "latitude": "lat.",
- "city": "Stad",
- "region": "Region",
- "country": "Plats",
- "place_of_birth": "Ort",
- "type": "Typ",
- "source": "Källa",
- "description": "Beskrivning",
- "no_occurrences": "Inga förekomster",
- "download": "ladda ner pdf",
- "articles": "Artiklar"
- },
- "est": "Lästext",
- "ms": "Manuskript",
- "com": "Kommentar",
- "tit": "Titel",
- "var": "Variant",
- "inl": "Inledning",
- "locations": "Platser",
- "location": "Plats",
- "tags": "Ämnesord",
- "tag": "Ämnesord",
- "subjects": "Personer",
- "recorder": "Upptecknare",
- "playman": "Upptecknare",
- "collections": "Samlingar",
- "photos": "kuvaa",
- "song": "Melodi",
- "works": "Verk",
- "Reference": {
- "title": "Hänvisa",
- "thisPage": "Hänvisa till denna sida",
- "established": "Hänvisa till denna lästext",
- "intro": "Hänvisa till denna inledning"
- },
- "Song": {
- "Playman": "Spelman",
- "playman": "Spelman",
- "SongType": "Låttyp",
- "SongName": "Låtens namn",
- "Landscape": "Landskap",
- "Place": "Ort",
- "Recorder": "Upptecknare",
- "recorder": "Upptecknare",
- "Year": "Uppteckningsår",
- "OCL": "Originalsamlingens placering",
- "OCS": "Originalsamlingens signum",
- "Volume": "Volym",
- "SongNumber": "Sångnummer",
- "Comments": "Kommentarer",
- "SongText": "Sångtext",
- "Download": "Ladda ner"
-
- }
-}
\ No newline at end of file
+ "BrowserWarning": "Selainta ei tueta",
+ "BrowserWarningInfo": "Tämä sivusto ei tue Internet Exploreria. Käytä Edgeä, Firefoxia, Chromea tai mitä tahansa muu selain.",
+ "BrowserWarningClose": "Sulje",
+ "TutorialTexts": {
+ "nextLabel": "Seuraava",
+ "prevLabel": "Edellinen",
+ "skipLabel": "Ohita",
+ "doneLabel": "Valmis",
+ "WelcomeText": "Tervetuloa, tässä on käyttöliittymän esittely.",
+ "searchIcon": "Klicka här för att söka i utgåvan.",
+ "MenuToggleText": "Piilota tai näytä sivuvalikko napsauttamalla tätä.",
+ "ReadTocItemText": "Täällä voit nähdä kaikki digitaaliset julkaisut.",
+ "DownloadCacheText": "Tällä painikkeella voit tallentaa tiedot paikallisesti, niin se on nopeampaa seuraavan kerran."
+ },
+ "TopMenu": {
+ "Home": "Etusivu",
+ "Read": "Lue",
+ "Info": "Topeliuksesta ja editiosta",
+ "Music": "Musik",
+ "SimpleSearch": "Hae",
+ "AdvancedSearch": "Hae"
+ },
+ "Tabs": {
+ "Home": "Koti",
+ "Read": "Lue digitaalisesti",
+ "Info": "Lisää aiheesta"
+ },
+ "Read": {
+ "DigitalEditions": "Digitaaliset julkaisut",
+ "OpenInTab": "Avaa uuteen välilehteen",
+ "Popover": {
+ "All": "Valitse kaikki",
+ "Appearance": "Asetukset",
+ "Show": "Näkymävaihtoehdot",
+ "Comments": "Kommentit",
+ "PersonInfo": "Henkilöt",
+ "PlaceInfo": "Paikannimet",
+ "WorkInfo": "Teokset",
+ "Changes": "Toimittajan tekemät muutokset",
+ "Abbreviations": "Lyhennykset",
+ "PageNumbering": "Kappale-/rivinumerointi",
+ "PageBreakOriginal": "Alkuteoksen sivunumerot/sivunvaihdot",
+ "PageBreakEdition": "Painetun ZTS-edition sivunumerot"
+ },
+ "DownloadDigitalVersion": "Lataa digitaalinen versio",
+ "DownloadPDF": "Lataa PDF",
+ "CommentsFor": "Kommentaari",
+ "ReadFromBeginning": "Lue",
+ "Established": {
+ "Title": "Lukuteksti",
+ "AddButtonText": "Lukuteksti"
+ },
+ "Comments": {
+ "Title": "Kommentaari",
+ "AddButtonText": "Kommentaari",
+ "Manuscript": {
+ "Title": "Manuskriptbeskrivning",
+ "LegacyId": "Brevsignum",
+ "Sender": "Avsändare",
+ "Receiver": "Mottagare",
+ "Archive": "Arkiv",
+ "Collection": "Samling, signum",
+ "Type": "Form",
+ "Status": "Status",
+ "Format": "Format",
+ "Leafs": "Lägg",
+ "Sheets": "Antal blad",
+ "Pages": "Sidor brevtext",
+ "Color": "Färg",
+ "Quality": "Kvalitet",
+ "Pattern": "Mönster",
+ "State": "Tillstånd",
+ "Material": "Skrivmaterial",
+ "Other": "Övrigt"
+ }
+ },
+ "Manuscripts": {
+ "Title": "Käsikirjoitus",
+ "AddButtonText": "Käsikirjoitus",
+ "SelectManuscript": "Valitse käsikirjoitus",
+ "ShowNormalized": "Näytä muutokset toteutettuina",
+ "ShowChanges": "Näytä muutokset",
+ "OpenFacsimile": "Näytä faksimilet"
+ },
+ "Variations": {
+ "Title": "Variantit",
+ "AddButtonText": "Variantit"
+ },
+ "Facsimiles": {
+ "Title": "Faksimile",
+ "AddButtonText": "Faksimilet",
+ "SelectFacsimiles": "Näytä faksimilet",
+ "Page": "Sivu",
+ "Of": "",
+ "OpenManuscript": "Käsikirjoitus",
+ "ExternalHeading" : "Ulkopuoliset faksimilet"
+ },
+ "SongExample": {
+ "Title": "Sång exempel",
+ "AddButtonText": "Sång exempel"
+ },
+ "TitlePage": {
+ "Title": "Kansi/nimiölehti/esipuhe"
+ },
+ "Introduction": {
+ "Title": "Johdanto",
+ "AddButtonText": "Johdanto"
+ },
+ "Illustrations": {
+ "AddButtonText": "Kuvat",
+ "Goto": "Näytä esiintymä",
+ "Nothing": "Ei kuvia",
+ "Showall": "Näytä kaikki"
+ },
+ "CoverPage": {
+ "Title": "Kansi"
+ },
+ "ShowAll": "Näytä kaikki",
+ "ShowSearchResults": "Esiintymät"
+ },
+ "About": {
+ "Title": "Topeliuksesta ja editiosta",
+ "UI": "Käyttöliittymä",
+ "Language": "Kieli",
+ "Information": "Tietoa"
+ },
+ "MediaCollections": {
+ "MediaCollections": "Faksimilet"
+ },
+ "TOC": {
+ "Home": "Etusivulle",
+ "About": "Topeliuksesta ja editiosta",
+ "Read": "Lue",
+ "Read1": "Lue",
+ "Read2": "Lue",
+ "ReadN": "Lue",
+ "Facsimiles": "Valikoidut faksimilet",
+ "ImageGallery": "Kuvagalleria",
+ "MediaCollections": "Album",
+ "PersonSearch": "Henkilöhakemisto",
+ "PlaceSearch": "Paikkahakemisto",
+ "TagSearch": "Ämnesord",
+ "WorkSearch": "Teoshakemisto",
+ "MusicianSearch": "Spelmän",
+ "WriterSearch": "Upptecknare",
+ "SongTypes": "Låttyper",
+ "Music": "Musik",
+ "Collections": "Kategorier",
+ "PlaymanTradition": "Finlandssvensk spelmanstradition",
+ "Books": "Böcker",
+ "All": "Alla"
+ },
+ "GalleryPages": {
+ "0": "Finland framställdt i teckningar",
+ "1": "En resa i Finland",
+ "2": "Topeliuksen elämä ja teokset"
+ },
+ "MobilePages": {
+ "header": "Sivut"
+ },
+ "BackButton": {
+ "default": "Takaisin"
+ },
+ "HomePage": {
+ "current": "Ajankohtaista",
+ "publishedEditions": "Julkaistut editiot:",
+ "digitalEditionHeading": "Zacharias Topeliuksen teokset",
+ "selectEdition": "Lue"
+ },
+ "Filter":{
+ "personTypes": "Personkategori",
+ "tagTypes": "Ämneskategori",
+ "year": "Född mellan",
+ "apply": "Verkställ"
+ },
+ "SearchApp": {
+ "simpleSearch": "Hae",
+ "advancedSearch": "Tarkennettu haku",
+ "filter": "Rajaukset",
+ "matchesOn": "Osuma(a):",
+ "numberOf": "osumaa",
+ "pagenumber": "s.",
+ "search-holder": "Hakuteksti",
+ "hitCount": "Osumaa",
+ "type": "Tyyppi",
+ "timeline": "Aikajakso",
+ "freetext": "Vapaateksti",
+ "start": "Alku",
+ "end": "Loppu",
+ "relevance": "Relevanssi",
+ "alphabetical": "Aakkostus",
+ "oldest": "Vanhin",
+ "genre": "Tekstilaji",
+ "person-register": "Henkilöhakemisto",
+ "place-register": "Paikkahakemisto",
+ "tag-register": "Ämnesord",
+ "verk": "Teoshakemisto",
+ "sort-by": "Lajittele"
+ },
+ "Occurrences": {
+ "Title": "Esiintymät",
+ "Manuscript": "Käsikirjoitus",
+ "Variation": "Variantti",
+ "Commentary": "Kommentti",
+ "Facsimile": "Faksimile",
+ "Established": "Lukuteksti",
+ "Song": "Sång",
+ "Info": "Infoa",
+ "NoInfoFound": "Ei löydetty.",
+ "OccurrencesSmall": "esiitymää",
+ "Found": "Löydettiin",
+ "Result": "Esiintymää",
+ "longitude": "long.",
+ "latitude": "lat.",
+ "city": "Stad",
+ "region": "Region",
+ "country": "Plats",
+ "place_of_birth": "Ort",
+ "type": "Typ",
+ "source": "Källa",
+ "description": "Beskrivning",
+ "no_occurrences": "Ei esiintymiä",
+ "download": "lataa pdf",
+ "articles": "Artiklar",
+ "publisher": "Kustantaja",
+ "journal": "Journal",
+ "isbn": "ISBN",
+ "published_year": "Julkaisuvuosi",
+ "authors": "Kirjoittaja"
+ },
+ "ElasticSearch": {
+ "NoHits": "Haku ei vastannut yhtään asiakirjaa",
+ "Found": "Löydettiin",
+ "SearchField": "Lisää hakukenttä",
+ "From": "Vuodesta",
+ "To": "Vuoteen",
+ "Search": "Hae",
+ "Years": "Vuodet",
+ "ShowMore": "Näytä enemmän",
+ "ShowLess": "Näytä vähemmän",
+ "SortBy": "Lajittele",
+ "Relevance": "Relevanssi",
+ "OldestFirst": "Vanhimmat ensin",
+ "NewestFirst": "Uusimmat ensin"
+ },
+ "Type": "Tekstityyppi",
+ "Genre": "Tekstilaji",
+ "Collection": "Editio",
+ "Location": "Paikka",
+ "Subjects": "Aihe",
+ "Tags": "Asiansanat",
+ "Person": "Henkilö",
+ "LetterSenderName": "Lähettäjä",
+ "LetterReceiverName": "Vastaanottaja",
+ "LetterSenderLocation": "Lähettäjän paikkakunta",
+ "LetterReceiverLocation": "Vastaanottajan paikkakunta",
+ "est": "Lukuteksti",
+ "ms": "Käsikirjoitus",
+ "com": "Kommentti",
+ "tit": "Nimiölehti/esipuhe",
+ "var": "Variantti",
+ "inl": "Johdanto",
+ "locations": "Paikat",
+ "location": "Paikka",
+ "tags": "Aihesanat",
+ "tag": "Aihesana",
+ "subjects": "Henkilöt",
+ "subject": "Henkilö",
+ "collections": "Samlingar",
+ "works": "Verk",
+ "photos": "foton",
+ "recorder": "Upptecknare",
+ "playman": "Spelman",
+ "song": "Melodi",
+ "Text": "PDF",
+ "BC": "f.Kr.",
+ "Reference": {
+ "title": "Lähdeviittaus",
+ "urn": "Linkitä",
+ "thisPage": "Lähdevittaus",
+ "established": "Lähdevittaus tähän lukutekstiin",
+ "intro": "Lähdevittaus tähän johdantoon"
+ },
+ "Song": {
+ "Playman": "Spelman",
+ "playman": "Spelman",
+ "SongType": "Låttyp",
+ "SongName": "Låtens namn",
+ "Landscape": "Landskap",
+ "Place": "Ort",
+ "Recorder": "Upptecknare",
+ "recorder": "Upptecknare",
+ "Year": "Uppteckningsår",
+ "OCL": "Originalsamlingens placering",
+ "OCS": "Originalsamlingens signum",
+ "Volume": "Volym",
+ "SongNumber": "Sångnummer",
+ "Comments": "Kommentarer",
+ "SongText": "Sångtext",
+ "Download": "Ladda ner"
+ },
+ "MusicPage": {
+ "Title": "Musik",
+ "PageTitle": "Musikvolymerna",
+ "SubTitle": "FSFD"
+ },
+ "established": "Lukuteksti",
+ "comments": "Kommentaari",
+ "facsimiles": "Faksimilet",
+ "manuscripts": "Käsikirjoitukset",
+ "variations": "Variantit",
+ "introduction": "Johdanto",
+ "songexample": "Sång",
+ "illustrations": "Kuvat"
+}
diff --git a/src/assets/i18n/sv.json b/src/assets/i18n/sv.json
index ef387a94..240cc26a 100644
--- a/src/assets/i18n/sv.json
+++ b/src/assets/i18n/sv.json
@@ -1,232 +1,319 @@
{
- "BrowserWarning": "Din webbläsare stöds inte",
- "BrowserWarningInfo": "Internet Explorer stöds inte av denna sida. Använd Edge, Firefox eller nån annan webbläsare.",
- "BrowserWarningClose": "Stäng",
- "TutorialTexts": {
- "nextLabel": "Nästa",
- "prevLabel": "Föregående",
- "skipLabel": "Hoppa över",
- "doneLabel": "Klar",
- "WelcomeText": "Välkommen, här följer en presentation av anvndargränssnittet.",
- "MenuToggleText": "Klicka här för att dölja eller visa sidomenyn.",
- "ReadTocItemText": "Här kan du se alla digital publikationer och volymer.",
- "DownloadCacheText": "Med denna knapp kan du spara datan lokalt, så går det snabbare nästa gång."
- },
- "TopMenu": {
- "Home": "Startsida",
- "Read": "Innehåll",
- "Info": "Om",
- "Music": "Musik"
- },
- "Tabs": {
- "Home": "Hem",
- "Read": "Läs digitalt",
- "Info": "Mer information"
- },
- "Read": {
- "DigitalEditions": "Digitala utgåvor",
- "OpenInTab": "Öppna i ny flik",
- "Popover": {
- "All": "Välj alla",
- "Appearance": "Utseende",
- "Show": "Visningsalternativ",
- "Comments": "Kommentarer",
- "PersonInfo": "Personupplysningar",
- "PlaceInfo": "Platsupplysningar",
- "Changes": "Ändringar",
- "Abbreviations": "Förkortningar",
- "PageNumbering": "Stycke-/versnummer",
- "PageBreakOriginal": "Sidnummer / sidbrytning i orig.",
- "PageBreakEdition": "Sidnummer i den tryckta utgåvan"
- },
- "DownloadDigitalVersion": "Ladda ner digital version",
- "DownloadPDF": "Ladda ner PDF",
- "CommentsFor": "Kommentarer till",
- "ReadFromBeginning": "Läs från början",
- "Established": {
- "Title": "Lästext",
- "AddButtonText": "Lästextvy"
- },
- "Comments": {
- "Title": "Kommentarer",
- "AddButtonText": "Kommentarvy"
- },
- "Manuscripts": {
- "Title": "Manuskript",
- "AddButtonText": "Manuskriptvy",
- "SelectManuscript": "Välj manuskript",
- "ShowNormalized": "Visa ändringar inarbetade",
- "ShowChanges": "Visa ändringar",
- "OpenFacsimile": "Öppna faksimil"
- },
- "Variations": {
- "Title": "Variationer",
- "AddButtonText": "Variationsvy"
- },
- "Facsimiles": {
- "Title": "Faksimil",
- "AddButtonText": "Faksimilvy",
- "SelectFacsimiles": "Välj faksimil",
- "Page": "Sida",
- "Of": "av",
- "OpenManuscript": "Öppna manuskript"
- },
- "SongExample": {
- "Title": "Sång exempel",
- "AddButtonText": "Sång exempel"
- },
- "TitlePage": {
- "Title": "Titel"
- },
- "Introduction": {
- "Title": "Inledning",
- "AddButtonText": "Inledning"
- },
- "ShowAll": "Visa alla",
- "ShowSearchResults": "Förekomster"
- },
- "About": {
- "Title": "Om utgåvan",
- "UI": "Användargränssnitt",
- "Language": "Språk",
- "Information": "Information"
- },
- "MediaCollections": {
- "MediaCollections": "Faksimilsamlinar"
- },
- "TOC": {
- "Home": "Till startsidan",
- "About": "Om utgåvan",
- "Read": "Läs",
- "Facsimiles": "Faksimil i urval",
- "ImageGallery": "Bildgalleri",
- "MediaCollections": "Album",
- "PersonSearch": "Personsök",
- "PlaceSearch": "Platsregister",
- "TagSearch": "Ämnesord",
- "WorkSearch": "Verkregister",
- "MusicianSearch": "Spelmän",
- "WriterSearch": "Upptecknare",
- "SongTypes": "Låttyper",
- "Music": "Musik",
- "Collections": "Kategorier",
- "PlaymanTradition": "Finlandssvensk spelmanstradition",
- "Books": "Böcker",
- "All": "Alla"
- },
- "GalleryPages": {
- "0": "Finland framställdt i teckningar",
- "1": "En resa i Finland",
- "2": "Topelius liv och verk"
- },
- "MobilePages": {
- "header": "Sidor"
- },
- "BackButton": {
- "default": "Tillbaka"
- },
- "HomePage": {
- "current": "Aktuellt",
- "publishedEditions": "Publicerade utgåvor:",
- "digitalEditionHeading": "Zacharias Topelius verk i digital utgåva",
- "selectEdition": "Se denna"
- },
- "SearchApp": {
- "simpleSearch": "Sök",
- "advancedSearch": "Avancerad sökning",
- "filter": "Filter",
- "matchesOn": "Sökträff(ar):",
- "numberOf": "träffar",
- "pagenumber": "s.",
- "search-holder": "Söktext",
- "hitCount": "Antal träffar",
- "type": "Typ",
- "timeline": "Tidsperiod",
- "freetext": "Fritext",
- "start": "Start",
- "end": "Slut",
- "relevance": "Relevans",
- "alphabetical": "Alfabetet",
- "oldest": "Äldst",
- "genre": "Genre",
- "person-register": "Personregister",
- "place-register": "Platsregister ",
- "tag-register": "Ämnesord",
- "verk": "Verkregister",
- "sort-by": "Sortera enligt"
- },
- "Occurrences": {
- "Title": "Förekomster",
- "Manuscript": "Manuskript",
- "Variation": "Variant",
- "Commentary": "Kommentar",
- "Facsimile": "Faksimil",
- "Established": "Lästext",
- "Song": "Sång",
- "Info": "Information",
- "NoInfoFound": "Ingen information hittades.",
- "OccurrencesSmall": "förekomster",
- "Found": "Hittade",
- "Result": "Resultat",
- "longitude": "long.",
- "latitude": "lat.",
- "city": "Stad",
- "region": "Region",
- "country": "Plats",
- "place_of_birth": "Ort",
- "type": "Typ",
- "source": "Källa",
- "description": "Beskrivning",
- "no_occurrences": "Inga förekomster",
- "download": "ladda ner pdf",
- "articles": "Artiklar"
- },
- "est": "Lästext",
- "ms": "Manuskript",
- "com": "Kommentar",
- "tit": "Titel",
- "var": "Variant",
- "inl": "Inledning",
- "locations": "Platser",
- "location": "Plats",
- "tags": "Ämnesord",
- "tag": "Ämnesord",
- "subjects": "Personer",
- "subject": "Person",
- "collections": "Samlingar",
- "works": "Verk",
- "photos": "foton",
- "recorder": "Upptecknare",
- "playman": "Spelman",
- "song": "Melodi",
- "Text": "PDF",
- "Reference": {
- "title": "Hänvisa",
- "thisPage": "Hänvisa till denna sida",
- "established": "Hänvisa till denna lästext",
- "intro": "Hänvisa till denna inledning"
- },
- "Song": {
- "Playman": "Spelman",
- "playman": "Spelman",
- "SongType": "Låttyp",
- "SongName": "Låtens namn",
- "Landscape": "Landskap",
- "Place": "Ort",
- "Recorder": "Upptecknare",
- "recorder": "Upptecknare",
- "Year": "Uppteckningsår",
- "OCL": "Originalsamlingens placering",
- "OCS": "Originalsamlingens signum",
- "Volume": "Volym",
- "SongNumber": "Sångnummer",
- "Comments": "Kommentarer",
- "SongText": "Sångtext",
- "Download": "Ladda ner"
- },
- "MusicPage": {
- "Title": "Musik",
- "PageTitle": "Musikvolymerna",
- "SubTitle": "FSFD"
- }
-}
\ No newline at end of file
+ "BrowserWarning": "Din webbläsare stöds inte",
+ "BrowserWarningInfo": "Internet Explorer stöds inte av denna sida. Använd Edge, Firefox, Chrome eller nån annan webbläsare.",
+ "BrowserWarningClose": "Stäng",
+ "TutorialTexts": {
+ "nextLabel": "Nästa",
+ "prevLabel": "Föregående",
+ "skipLabel": "Hoppa över",
+ "doneLabel": "Klar",
+ "searchIcon": "Klicka här för att söka i utgåvan.",
+ "WelcomeText": "Välkommen, här följer en presentation av användargränssnittet.",
+ "MenuToggleText": "Klicka här för att dölja eller visa sidomenyn.",
+ "ReadTocItemText": "Här kan du se alla digital publikationer och volymer.",
+ "DownloadCacheText": "Med denna knapp kan du spara datan lokalt, så går det snabbare nästa gång."
+ },
+ "TopMenu": {
+ "Home": "Startsida",
+ "Read": "Läs",
+ "Info": "Om",
+ "Music": "Musik",
+ "SimpleSearch": "Sök",
+ "AdvancedSearch": "Sök"
+ },
+ "Tabs": {
+ "Home": "Hem",
+ "Read": "Läs digitalt",
+ "Info": "Mer information"
+ },
+ "Read": {
+ "DigitalEditions": "Digitala utgåvor",
+ "OpenInTab": "Öppna i ny flik",
+ "Popover": {
+ "All": "Välj alla",
+ "Appearance": "Utseende",
+ "Show": "Visningsalternativ",
+ "Comments": "Kommentarer",
+ "PersonInfo": "Personupplysningar",
+ "PlaceInfo": "Platsupplysningar",
+ "WorkInfo": "Verkupplysningar",
+ "Changes": "Utgivarens ändringar",
+ "Abbreviations": "Förkortningar",
+ "PageNumbering": "Stycke-/radnumrering",
+ "PageBreakOriginal": "Sidnummer/sidbrytning i originalet",
+ "PageBreakEdition": "Sidnummer i ZTS tryckta utgåva"
+ },
+ "DownloadDigitalVersion": "Ladda ner digital version",
+ "DownloadPDF": "Ladda ner PDF",
+ "CommentsFor": "Kommentarer till",
+ "ReadFromBeginning": "Läs från början",
+ "Established": {
+ "Title": "Lästext",
+ "AddButtonText": "Lästext"
+ },
+ "Comments": {
+ "Title": "Kommentarer",
+ "AddButtonText": "Kommentarer",
+ "Manuscript": {
+ "Title": "Manuskriptbeskrivning",
+ "LegacyId": "Brevsignum",
+ "Sender": "Avsändare",
+ "Receiver": "Mottagare",
+ "Archive": "Arkiv",
+ "Collection": "Samling, signum",
+ "Type": "Form",
+ "Status": "Status",
+ "Format": "Format",
+ "Leafs": "Lägg",
+ "Sheets": "Antal blad",
+ "Pages": "Sidor brevtext",
+ "Color": "Färg",
+ "Quality": "Kvalitet",
+ "Pattern": "Mönster",
+ "State": "Tillstånd",
+ "Material": "Skrivmaterial",
+ "Other": "Övrigt"
+ }
+ },
+ "Manuscripts": {
+ "Title": "Manuskript",
+ "AddButtonText": "Manuskript",
+ "SelectManuscript": "Välj manuskript",
+ "ShowNormalized": "Visa ändringar inarbetade",
+ "ShowChanges": "Visa ändringar",
+ "OpenFacsimile": "Öppna faksimil"
+ },
+ "Variations": {
+ "Title": "Varianter",
+ "AddButtonText": "Varianter"
+ },
+ "Facsimiles": {
+ "Title": "Faksimil",
+ "AddButtonText": "Faksimil",
+ "SelectFacsimiles": "Välj faksimil",
+ "Page": "Sida",
+ "Of": "av",
+ "OpenManuscript": "Öppna manuskript",
+ "ExternalHeading" : "Externa faksimil"
+ },
+ "SongExample": {
+ "Title": "Sång exempel",
+ "AddButtonText": "Sång exempel"
+ },
+ "TitlePage": {
+ "Title": "Omslag/titelblad/förord"
+ },
+ "CoverPage": {
+ "Title": "Omslag"
+ },
+ "Introduction": {
+ "Title": "Inledning",
+ "AddButtonText": "Inledning"
+ },
+ "Illustrations": {
+ "AddButtonText": "Illustrationer",
+ "Goto": "Gå till position i lästext",
+ "Nothing": "Inga illustrationer",
+ "Showall": "Visa alla"
+ },
+ "ShowAll": "Visa alla",
+ "ShowSearchResults": "Förekomster"
+ },
+ "About": {
+ "Title": "Om",
+ "UI": "Användargränssnitt",
+ "Language": "Språk",
+ "Information": "Information"
+ },
+ "MediaCollections": {
+ "MediaCollections": "Faksimilsamlingar",
+ "GotoMediaCollection": "Gå till bildbanken"
+ },
+ "TOC": {
+ "Home": "Till startsidan",
+ "About": "Om",
+ "Read": "Läs",
+ "Read1": "Läs",
+ "Read2": "Läs",
+ "ReadN": "Läs",
+ "Facsimiles": "Faksimil i urval",
+ "ImageGallery": "Bildgalleri",
+ "MediaCollections": "Album",
+ "PersonSearch": "Personregister",
+ "PlaceSearch": "Ortregister",
+ "TagSearch": "Ämnesord",
+ "WorkSearch": "Verkregister",
+ "MusicianSearch": "Spelmän",
+ "WriterSearch": "Upptecknare",
+ "SongTypes": "Låttyper",
+ "Music": "Musik",
+ "Collections": "Kategorier",
+ "PlaymanTradition": "Finlandssvensk spelmanstradition",
+ "Books": "Böcker",
+ "All": "Alla"
+ },
+ "GalleryPages": {
+ "0": "Finland framställdt i teckningar",
+ "1": "En resa i Finland",
+ "2": "Topelius liv och verk"
+ },
+ "MobilePages": {
+ "header": "Sidor"
+ },
+ "BackButton": {
+ "default": "Tillbaka"
+ },
+ "HomePage": {
+ "current": "Aktuellt",
+ "publishedEditions": "Publicerade utgåvor:",
+ "digitalEditionHeading": "Zacharias Topelius verk i digital utgåva",
+ "selectEdition": "Se denna"
+ },
+ "SearchApp": {
+ "simpleSearch": "Sök",
+ "advancedSearch": "Avancerad sökning",
+ "filter": "Filter",
+ "matchesOn": "Sökträff(ar):",
+ "numberOf": "träffar",
+ "pagenumber": "s.",
+ "search-holder": "Söktext",
+ "hitCount": "Antal träffar",
+ "type": "Typ",
+ "timeline": "Tidsperiod",
+ "freetext": "Fritext",
+ "start": "Start",
+ "end": "Slut",
+ "relevance": "Relevans",
+ "alphabetical": "Alfabetet",
+ "oldest": "Äldst",
+ "genre": "Genre",
+ "person-register": "Personregister",
+ "place-register": "Platsregister ",
+ "tag-register": "Ämnesord",
+ "verk": "Verkregister",
+ "sort-by": "Sortera enligt"
+ },
+ "Occurrences": {
+ "Title": "Förekomster",
+ "Manuscript": "Manuskript",
+ "Variation": "Variant",
+ "Commentary": "Kommentar",
+ "Facsimile": "Faksimil",
+ "Established": "Lästext",
+ "Song": "Sång",
+ "Info": "Information",
+ "NoInfoFound": "Ingen information hittades.",
+ "OccurrencesSmall": "förekomster",
+ "Found": "Hittade",
+ "Result": "Resultat",
+ "longitude": "long.",
+ "latitude": "lat.",
+ "city": "Stad",
+ "region": "Region",
+ "country": "Plats",
+ "place_of_birth": "Ort",
+ "type": "Typ",
+ "source": "Källa",
+ "description": "Beskrivning",
+ "no_occurrences": "Inga förekomster",
+ "download": "ladda ner pdf",
+ "articles": "Artiklar",
+ "publisher": "Utgivare",
+ "journal": "Journal",
+ "isbn": "ISBN",
+ "published_year": "Utgivningsår",
+ "authors": "Författare"
+ },
+ "ElasticSearch": {
+ "NoHits": "Din sökning matchade inga dokument",
+ "Found": "Hittades",
+ "SearchField": "Lägg till sökfält",
+ "From": "Från",
+ "To": "Till",
+ "Search": "Sök",
+ "Years": "År",
+ "ShowMore": "Visa mera",
+ "ShowLess": "Visa mindre",
+ "SortBy": "Sortera enligt",
+ "Relevance": "Relevans",
+ "OldestFirst": "Äldst först",
+ "NewestFirst": "Nyast först",
+ "WordCount": "Antal träffar (estimat)",
+ "NoWordHits": "inga träffar"
+ },
+ "Filter":{
+ "personTypes": "Personkategori",
+ "tagTypes": "Ämneskategori",
+ "year": "Född mellan",
+ "apply": "Verkställ"
+ },
+ "Type": "Typ",
+ "Genre": "Genre",
+ "Collection": "Utgåvor",
+ "Location": "Plats",
+ "Subjects": "Ämnen",
+ "Tags": "Taggar",
+ "Person": "Person",
+ "LetterSenderName": "Avsändare",
+ "LetterReceiverName": "Mottagare",
+ "LetterSenderLocation": "Avsändarort",
+ "LetterReceiverLocation": "Mottagarort",
+ "est": "Lästext",
+ "ms": "Manuskript",
+ "com": "Kommentar",
+ "tit": "Titel",
+ "var": "Variant",
+ "inl": "Inledning",
+ "locations": "Platser",
+ "location": "Plats",
+ "tags": "Ämnesord",
+ "tag": "Ämnesord",
+ "subjects": "Personer",
+ "subject": "Person",
+ "collections": "Samlingar",
+ "works": "Verk",
+ "photos": "foton",
+ "recorder": "Upptecknare",
+ "playman": "Spelman",
+ "song": "Melodi",
+ "Text": "PDF",
+ "BC": "f.Kr.",
+ "Reference": {
+ "title": "Hänvisa",
+ "urn": "Länka",
+ "thisPage": "Hänvisa till denna sida",
+ "established": "Hänvisa till denna lästext",
+ "intro": "Hänvisa till denna inledning"
+ },
+ "Song": {
+ "Playman": "Spelman",
+ "playman": "Spelman",
+ "SongType": "Låttyp",
+ "SongName": "Låtens namn",
+ "Landscape": "Landskap",
+ "Place": "Ort",
+ "Recorder": "Upptecknare",
+ "recorder": "Upptecknare",
+ "Year": "Uppteckningsår",
+ "OCL": "Originalsamlingens placering",
+ "OCS": "Originalsamlingens signum",
+ "Volume": "Volym",
+ "SongNumber": "Sångnummer",
+ "Comments": "Kommentarer",
+ "SongText": "Sångtext",
+ "Download": "Ladda ner"
+ },
+ "MusicPage": {
+ "Title": "Musik",
+ "PageTitle": "Musikvolymerna",
+ "SubTitle": "FSFD"
+ },
+ "established": "Lästext",
+ "comments": "Kommentarer",
+ "facsimiles": "Faksimil",
+ "manuscripts": "Manuskript",
+ "variations": "Varianter",
+ "introduction": "Inledning",
+ "songexample": "Sång",
+ "illustrations": "Illustrationer"
+}
diff --git a/src/assets/images/img_placeholder.png b/src/assets/images/img_placeholder.png
new file mode 100644
index 0000000000000000000000000000000000000000..edd15b90d9919b6fd52e9b810238b050517ee255
GIT binary patch
literal 2443
zcmbVO3s4hh9^Vvd=~Gd9RrGq>m9cV|>~0c5c1z@uq!1txA}9|BTs9k6^4O3pBxpN6
zdiA2#)_S!bTt!QjGPU5fV~)EDC{?L*g0w0yzL45Md|;zv6-!U-w>&c1p*^RW+3dI9
z_xpbT-~aLbch{#IlAe7k{3!^6p4BC5jNl#yuF#Mv;Qzeltrl>5(vh6wf}p2o2$u+|
z`d}smJwC{0X7kzlG?M0Q63WCCG7^u?0niW>8|QIQw1wf}LZ*nds}TSG0|?BTRLIh3
zJ*Ic4nPN71g_Bvl!jMU?u+W4FiCYNAdPqQEV|WVo*sOLJ=}{r0yd)S4(w&f
zqb&zA=L+69NVSupc+Q#0an^}MrB6tP)oLLz1U!E!Yd3LjSL6eG7!AcUDnwWpW4IV2
zGI5;5a8im#VNw#q#-Mu6#F{G}hT@n2mB~mc_7D_Qjfvu^{|h$Jq?vQtDBv?|qly^R
zVJ|}9KqN^uXXTv0Fi9$tg^Fh^
z=4dL$gkiK;CYLM31SU6&2}KMe#wZ$RFuAgjR?rjn7dcsQ3MuRF<`K@OP(EZb>jH_b
z7(YFWnbPr*m4!zuhNNiWB&ZNtC;`TVj8C(ZMBvdp7^8I;Gl29r>S7G$;>^68axw`;
zAX<-7dg!m|cTwfPt^U#SH<|iLO7(ZD9}g~FOxcSV&|FbO@COyz&{%5FUuJD|?SYmx
z0SA3h7zP?JcnGv`#tx{Rph357D0vxzg0wnKLZ)(4*?WsD5m{kJI-C7jLwrWo_K|JHZZSu$X
znXdC$dwW;*Xg{f{7NMtVM(*_zL+9Of`Fn@f9s2f(yu7?dQHacfoM>M*BlMN+hL_o@
z{HWb>NE8pj$cqe<^RM>L2lvKy?l@5_AFexjB{n_fP4NDjhddsS%VyEF$N%#@)Bt5J
zDa%Vl7a0sKU%%1X_eVPI*4?{z7s{UKdPkc9Z>XvAp4w{MP`NvEUi+u}y33$MP3?L6
zfiC}$e|vRxOT$)UY4yPUUF>l1!OxAM+R)mQktM!xO|Ukj?|#W=*|8gIE~}tj>+1{}
z(dwPUJI`Lfc;g0E*FC`6oojU
z%YA*&8?Et;x%FJrkh|Wu{L<34?`|H#p82YO-9h57-#WZEJE*}!E2>jJ
zKAEG<_#t=BR~P()gXbE%zg#&rbdB-qosp4|kCbl@)%)O@m2H2I0q?yJ-%HF0>n4h{
z!Qt`Kf?MmC?AcveF(3KUhNEA^A&*(a;hWlKCnY6K-FB=W?J(a;g=FRtt33RkvNG*b
z*Gv{V+&!qbP7k~7PXMfMN=7O*z7c?3sd2`eJRBv5MO-l2$
zQ19jL*B0Kte)a0r_4)NnI&a0^udFQSxb@nrF&&?Z`a0V8tnM$&k~FNzd0+pBjYqDm
X8W7c~hRt4;@VTVZ8Z-@w%h&!4i&T>p
literal 0
HcmV?d00001
diff --git a/src/assets/images/symbol_illustration.gif b/src/assets/images/symbol_illustration.gif
new file mode 100644
index 0000000000000000000000000000000000000000..8d44dc77ea618c36672be06c4d5ca8150c4f1d5d
GIT binary patch
literal 567
zcmZ?wbhEHbKaIlq*-R
zT)uqy(xpomFJ8O=H2wVfvuDqq0o!pBsPXXOy?giW*s){NrcLYDuU`$cY}Kk2D}cI}
zFJ8QO?%cU^=FFKgWy<8qlY4r4+S=M$TU%RNT54-+YieprOG^t13bL}YQd3h?Qc{wW
zlM@pYHN<&x^qnMqxo~06FQy8O)
za}bLHCzqUfkBA!&n}e#li=eMXlVq@fv7(Zakp#DUlb4sgik^nKk(p~yQ;>_2o)ZTj
zufFx}uplW@eXr0EC1cIdCT3S-J$r8*VP%`$jIw@eyrPOiCPp59O;-M176y8TB2G-K
k&9?sRx{lJGp)z>}Tni2{Okoe4!Ljh*iiOT@jSLLd0BL2%#Q*>R
literal 0
HcmV?d00001
diff --git a/src/components/comments/comments.html b/src/components/comments/comments.html
index fcfdbcfb..1b921697 100644
--- a/src/components/comments/comments.html
+++ b/src/components/comments/comments.html
@@ -1,7 +1,32 @@
+
+
{{ "Read.Comments.Manuscript.Title" | translate }}
+
+ - {{ "Read.Comments.Manuscript.LegacyId" | translate }}: {{letter['legacy_id']}}
+ - {{ "Read.Comments.Manuscript.Sender" | translate }}: {{sender}}
+ - {{ "Read.Comments.Manuscript.Receiver" | translate }}: {{receiver}}
+ - {{ "Read.Comments.Manuscript.Archive" | translate }}: {{letter['source_archive']}}
+ - {{ "Read.Comments.Manuscript.Collection" | translate }}: {{letter['source_collection_id']}}
+
+
+ - {{ "Read.Comments.Manuscript.Type" | translate }}: {{letter['material_type']}}
+ - {{ "Read.Comments.Manuscript.Status" | translate }}: {{letter['material_source']}}
+ - {{ "Read.Comments.Manuscript.Format" | translate }}: {{letter['material_format']}}
+ - {{ "Read.Comments.Manuscript.Leafs" | translate }}: {{letter['leaf_count']}}
+ - {{ "Read.Comments.Manuscript.Sheets" | translate }}: {{letter['sheet_count']}}
+ - {{ "Read.Comments.Manuscript.Pages" | translate }}: {{letter['page_count']}}
+ - {{ "Read.Comments.Manuscript.Color" | translate }}: {{letter['material_color']}}
+ - {{ "Read.Comments.Manuscript.Quality" | translate }}: {{letter['material_quality']}}
+ - {{ "Read.Comments.Manuscript.Pattern" | translate }}: {{letter['material_pattern']}}
+ - {{ "Read.Comments.Manuscript.State" | translate }}: {{letter['material_state']}}
+ - {{ "Read.Comments.Manuscript.Material" | translate }}: {{letter['material']}}
+ - {{ "Read.Comments.Manuscript.Other" | translate }}: {{letter['material_notes']}}
+
+
diff --git a/src/components/comments/comments.scss b/src/components/comments/comments.scss
index 6df9521a..1eb0affa 100644
--- a/src/components/comments/comments.scss
+++ b/src/components/comments/comments.scss
@@ -18,4 +18,21 @@ comments {
margin-bottom: 0rem !important;
display: block !important;
}
+ div.ms{
+ padding-top: 2rem;
+ }
+ .ms li{
+ list-style: none;
+ line-height: 1.5rem;
+ }
+ .ms ul{
+ padding-left: 0px;
+ }
}
+
+@media (max-width: 800px) {
+ .tei img.comment {
+ width: 20px;
+ height: 20px;
+ }
+}
\ No newline at end of file
diff --git a/src/components/comments/comments.ts b/src/components/comments/comments.ts
index c56f1086..ae86db88 100644
--- a/src/components/comments/comments.ts
+++ b/src/components/comments/comments.ts
@@ -24,6 +24,10 @@ export class CommentsComponent {
public text: any;
protected errorMessage: string;
listenFunc: Function;
+ manuscript: any;
+ sender: any;
+ receiver: any;
+ letter: any;
constructor(
protected readPopoverService: ReadPopoverService,
@@ -49,6 +53,7 @@ export class CommentsComponent {
} else {
this.setText();
}
+ this.getCorrespondanceMetadata();
}
setText() {
@@ -63,7 +68,7 @@ export class CommentsComponent {
this.doAnalytics();
},
error => {
- console.log('Error loading comments...', this.link);
+ console.error('Error loading comments...', this.link);
this.errorMessage = error
}
);
@@ -82,7 +87,13 @@ export class CommentsComponent {
}
openNewView( event, id: any, type: string ) {
- this.events.publish('show:view', type, id);
+ let openId = id;
+ let chapter = null;
+ if (String(id).includes('ch')) {
+ openId = String(String(id).split('ch')[0]).trim();
+ chapter = 'ch' + String(String(id).split('ch')[1]).trim();
+ }
+ this.events.publish('show:view', type, openId, chapter);
}
openNewIntro( event, id: any ) {
@@ -97,34 +108,54 @@ export class CommentsComponent {
event.preventDefault();
// This is tagging in href to another page e.g. introduction
try {
- const elem: HTMLElement = event.target as HTMLElement;
- const targetId = String(elem.getAttribute('href')).split('#')[1];
- let target = document.getElementsByName(targetId)[0] as HTMLElement;
- if ( target !== null && target !== undefined ) {
- this.scrollToHTMLElement(target, true);
- } else if ( targetId !== null && targetId !== undefined ) {
+ const elem: HTMLAnchorElement = event.target as HTMLAnchorElement;
+ let targetId = '';
+ let colPub = '';
+ if ( String(elem.getAttribute('href')).includes('#') === false ) {
+ targetId = String(elem.getAttribute('href'));
+ colPub = String(elem.getAttribute('href'));
+ } else {
+ targetId = String(elem.getAttribute('href')).split('#')[1];
+ colPub = String(elem.getAttribute('href')).split('#')[0];
+ }
+ let target = document.getElementsByName(targetId)[0] as HTMLAnchorElement;
+ if ( targetId !== null && targetId !== undefined && (elem.classList.contains('xref') !== false ||
+ elem.classList.contains('xreference') !== false) ) {
// Check if intro or same publication id
// Check class ref_introduction, readingtext
// Also check if already open and if same publication?
if ( elem.classList !== undefined ) {
const list = elem.classList;
- if ( list.contains('introduction') ) {
- this.openNewIntro(event, {id: String(elem.getAttribute('href')).split('#')[0].trim()});
- } else if ( list.contains('readingtext') ) {
- this.openNewView(event, String(elem.getAttribute('href')).split('#')[0].trim(), 'established');
- } else if ( list.contains('comment') ) {
- this.openNewView(event, String(elem.getAttribute('href')).split('#')[0].trim(), 'comments');
+ if ( list.contains('introduction') || list.contains('ref_introduction') ) {
+ this.openNewIntro(event, {id: colPub});
+ } else if ( list.contains('readingtext') || list.contains('ref_readingtext') ) {
+ this.openNewView(event, colPub, 'established');
+ } else if ( list.contains('comment') || list.contains('ref_comment') ) {
+ if ( target !== null && target !== undefined ) {
+ // this.scrollToHTMLElement(target, true);
+ } else {
+ this.openNewView(event, colPub, 'comments');
+ }
}
}
// Some other text, open in new window
setTimeout(function() {
- target = document.getElementsByName(targetId)[0] as HTMLElement;
+ target = document.getElementsByName(targetId)[0] as HTMLAnchorElement;
+ // Add arrow at correct place, not first occurrence of anchor
+ if ( !elem.classList.contains('comment') && !elem.classList.contains('ref_comment') &&
+ (target === undefined || target.classList.contains('teiComment')) ) {
+ target = document.getElementsByName(targetId)[document.getElementsByName(targetId).length - 1] as HTMLAnchorElement;
+ }
if ( target !== null && target !== undefined ) {
this.scrollToHTMLElement(target, false);
}
}.bind(this), 500);
+
+ } else if ( target !== null && target !== undefined && elem.classList.contains('ext') === false ) {
+ this.scrollToHTMLElement(target, true);
} else if ( elem.classList !== undefined && elem.classList.contains('ext') ) {
- const ref = window.open(elem.getAttribute('href'), '_blank', 'location=no');
+ const anchor = elem;
+ const ref = window.open(anchor.href, '_blank', 'location=no');
}
} catch ( e ) {}
@@ -269,7 +300,29 @@ export class CommentsComponent {
}, timeOut);
}
} catch ( e ) {
- console.log(e);
+ console.error(e);
}
}
+
+ getCorrespondanceMetadata() {
+ this.commentService.getCorrespondanceMetadata(String(this.link).split('_')[1]).subscribe(
+ text => {
+ if (text.length > 0) {
+ text['subjects'].forEach(subject => {
+ if ( subject['avsändare'] ) {
+ this.sender = subject['avsändare'];
+ }
+ if ( subject['mottagare'] ) {
+ this.receiver = subject['mottagare'];
+ }
+ });
+ }
+ this.letter = text['letter'];
+ this.doAnalytics();
+ },
+ error => {
+ this.errorMessage = error
+ }
+ );
+ }
}
diff --git a/src/components/components.module.ts b/src/components/components.module.ts
index bbbf5785..12268861 100644
--- a/src/components/components.module.ts
+++ b/src/components/components.module.ts
@@ -21,6 +21,9 @@ import { DigitalEditionListChildrenComponent } from './digital-edition-list-chil
import { TableOfContentsAccordionComponent } from './table-of-contents-accordion/table-of-contents-accordion';
import { ListOfSongsComponent } from './list-of-songs/list-of-songs';
import { NgxExtendedPdfViewerComponent } from './ngx-extended-pdf-viewer/ngx-extended-pdf-viewer.component';
+import { IllustrationsComponent } from './illustrations/illustrations';
+import { TableOfContentLetterFilterComponent } from './table-of-content-letter-filter/table-of-content-letter-filter';
+import { DateHistogram } from './date-histogram/date-histogram'
export function createTranslateLoader(http: HttpClient) {
@@ -43,7 +46,10 @@ export function createTranslateLoader(http: HttpClient) {
DigitalEditionListChildrenComponent,
TableOfContentsAccordionComponent,
ListOfSongsComponent,
- NgxExtendedPdfViewerComponent
+ NgxExtendedPdfViewerComponent,
+ IllustrationsComponent,
+ TableOfContentLetterFilterComponent,
+ DateHistogram,
],
imports: [
IonicModule,
@@ -72,7 +78,12 @@ export function createTranslateLoader(http: HttpClient) {
DigitalEditionListChildrenComponent,
TableOfContentsAccordionComponent,
ListOfSongsComponent,
- NgxExtendedPdfViewerComponent
+ NgxExtendedPdfViewerComponent,
+ TableOfContentLetterFilterComponent,
+ DateHistogram,
+ IllustrationsComponent,
+ TableOfContentLetterFilterComponent,
+ DateHistogram,
],
providers: [
UserSettingsService
diff --git a/src/components/cover/cover.html b/src/components/cover/cover.html
index 258a4462..d9b31573 100644
--- a/src/components/cover/cover.html
+++ b/src/components/cover/cover.html
@@ -1,6 +1,7 @@
{
this.errorMessage =
error;
- console.log(this.errorMessage);
+ console.error(this.errorMessage);
}
);
}
diff --git a/src/components/date-histogram/date-histogram.html b/src/components/date-histogram/date-histogram.html
new file mode 100644
index 00000000..38356cd3
--- /dev/null
+++ b/src/components/date-histogram/date-histogram.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+ {{'ElasticSearch.From' | translate}}
+
+
+
+
+
+ {{'ElasticSearch.To' | translate}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{year.doc_count}} : {{year.key_as_string}}
+
+
+
{{year.key_as_string}}
+
+
+
diff --git a/src/components/date-histogram/date-histogram.scss b/src/components/date-histogram/date-histogram.scss
new file mode 100644
index 00000000..2f5489e3
--- /dev/null
+++ b/src/components/date-histogram/date-histogram.scss
@@ -0,0 +1,69 @@
+date-histogram {
+ .reset-buttons {
+ height: 32px;
+ ion-icon {
+ font-size: 1.5em;
+ }
+ }
+
+ .years {
+ position: relative;
+ margin: 20px 0 0 50px;
+ cursor: crosshair;
+ }
+
+ .year {
+ position: relative;
+ height: 3px;
+ }
+ .yearIsDecade {
+ height: 4px;
+ border-bottom: 1px solid #aaaaaa;
+ }
+ .yearBar {
+ position: relative;
+ height: 100%;
+ width: 0;
+ background-color: #538393;
+ }
+ .yearDetails {
+ display: none;
+ position: absolute;
+ right: 0;
+ top: -20px;
+ padding: 2px;
+ font-size: 12px !important;
+ color: color($colors, grey);
+ background-color: rgba(255,255,255,0.5);
+ }
+
+ .year:hover {
+ background-color: color($colors, secondary);
+ }
+ .year:hover > .yearBar, .yearBarInRange {
+ background-color: color($colors, location);
+ }
+ .year:hover .yearDetails {
+ display: block;
+ }
+
+ .decadeMarker {
+ position: relative;
+ height: 0px;
+ }
+
+ .decade {
+ position: absolute;
+ left: -55px;
+ top: -7px;
+ width: 50px;
+ font-size: 12px !important;
+ color: color($colors, grey);
+ text-align: right;
+ }
+
+}
+.list-md .item-input:last-child {
+ border-bottom: 1px solid #538292 !important;
+ box-shadow: inset 0 -1px 0 0 #538292 !important;
+}
diff --git a/src/components/date-histogram/date-histogram.ts b/src/components/date-histogram/date-histogram.ts
new file mode 100644
index 00000000..c868062c
--- /dev/null
+++ b/src/components/date-histogram/date-histogram.ts
@@ -0,0 +1,91 @@
+import { Component, Input } from '@angular/core'
+import { Events } from 'ionic-angular'
+
+/**
+ * Visualize and select time ranges using from elastic search date histogram data.
+ *
+ * TODO: Add drag to select range.
+ * TODO: Add more granular months selection.
+ */
+@Component({
+ selector: 'date-histogram',
+ templateUrl: 'date-histogram.html'
+})
+export class DateHistogram {
+
+ @Input() years: [Facet]
+ @Input() change: Function
+
+ from: string
+ to: string
+ max = 0
+
+ ngOnInit() {
+ this.updateMax();
+ }
+
+ ngOnChanges() {
+ this.updateMax();
+ }
+
+ private updateMax() {
+ this.max = this.years.reduce(function (current, year) {
+ return Math.max(current, year.doc_count);
+ }, 0)
+ }
+
+ reset() {
+ this.from = null;
+ this.to = null;
+ this.change(null, null);
+ }
+
+ // Send the change event to the parent component
+ onChange() {
+ const fromTime = new Date(this.from).getTime()
+ // Add one year to get the full year.
+ const toTime = new Date(`${parseInt(this.to) + 1}`).getTime();
+
+ if (fromTime <= toTime) {
+ this.change(fromTime, toTime);
+ }
+ // this.change(
+ // this.years.find(year => year.key_as_string === this.from),
+ // this.years.find(year => year.key_as_string === this.to)
+ // )
+ }
+
+ getYearRelativeToMax(year: Facet) {
+ return `${Math.floor(year.doc_count / this.max * 100)}%`
+ }
+
+ isDecade(year: Facet) {
+ return parseInt(year.key_as_string) % 10 === 0
+ }
+
+ selectYear(selected: Facet) {
+ if (!this.from) {
+ this.from = selected.key_as_string;
+ } else if (!this.to && parseInt(selected.key_as_string) >= parseInt(this.from)) {
+ this.to = selected.key_as_string;
+ } else {
+ this.from = selected.key_as_string;
+ this.to = null;
+ }
+
+ this.onChange();
+ }
+
+ isYearInRange(year: Facet) {
+ const yearNumber = parseInt(year.key_as_string)
+ if (year.key_as_string === this.from || year.key_as_string === this.to) {
+ return true;
+
+ } else if (this.from && this.to) {
+ return yearNumber >= parseInt(this.from) && yearNumber <= parseInt(this.to);
+
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/src/components/digital-edition-list/digital-edition-list.component.ts b/src/components/digital-edition-list/digital-edition-list.component.ts
index c5800976..79d78567 100644
--- a/src/components/digital-edition-list/digital-edition-list.component.ts
+++ b/src/components/digital-edition-list/digital-edition-list.component.ts
@@ -30,6 +30,7 @@ export class DigitalEditionList implements OnInit {
tocItems: GeneralTocItem[];
hasCover = true;
hideBooks = false;
+ collectionSortOrder: any;
@Input() layoutType: string;
@Input() collectionsToShow?: Array;
@@ -55,6 +56,11 @@ export class DigitalEditionList implements OnInit {
} catch (e) {
this.hasCover = true;
}
+ try {
+ this.collectionSortOrder = this.config.getSettings('app.CollectionSortOrder');
+ } catch (e) {
+ this.collectionSortOrder = undefined;
+ }
}
ngOnInit() {
@@ -100,9 +106,12 @@ export class DigitalEditionList implements OnInit {
.subscribe(
digitalEditions => {
this.digitalEditions = digitalEditions;
- const de = digitalEditions;
+ let de = digitalEditions;
this.events.publish('DigitalEditionList:recieveData', { digitalEditions });
this.setPDF(de);
+ if ( this.collectionSortOrder !== undefined && Object.keys(this.collectionSortOrder).length > 0 ) {
+ de = this.sortListDefined(de, this.collectionSortOrder);
+ }
if (this.collectionsToShow !== undefined && this.collectionsToShow.length > 0) {
this.filterCollectionsToShow(de);
}
@@ -111,15 +120,36 @@ export class DigitalEditionList implements OnInit {
);
}
+ sortListDefined(list, sort) {
+ for (const coll of list) {
+ const order = sort[coll.id];
+ coll['order'] = order;
+ }
+
+ list.sort((a, b) => {
+ if (typeof a['order'] === 'number') {
+ return (a['order'] - b['order']);
+ } else {
+ return ((a['order'] < b['order']) ? -1 : ((a['order'] > b['order']) ? 1 : 0));
+ }
+ });
+
+ return list;
+ }
+
shortText(edition_id: string): Array {
let textData = '';
try {
const lang = this.translate.currentLang;
- textData = this.editionShortTexts[lang][edition_id] ||
+ if ( this.editionShortTexts[lang][edition_id] !== undefined ) {
+ textData = this.editionShortTexts[lang][edition_id] ||
this.editionShortTexts[lang].default;
- return textData.split('\n');
+ return textData.split('\n');
+ } else {
+ return String[''];
+ }
} catch (e) {
- console.log(e);
+ // console.error(e);
}
return textData.split('\n');
}
@@ -148,7 +178,6 @@ export class DigitalEditionList implements OnInit {
}
setPDF(de) {
- console.log(de);
let tresh = false;
for (let i = 0; i < de.length; i++) {
if (i === (de.length / 2) && de.length % 2 === 0) {
@@ -206,6 +235,7 @@ export class DigitalEditionList implements OnInit {
}
const nav = this.app.getActiveNavs();
+ console.log('Opening read from DigitalEditionList.openFirstPage()');
nav[0].setRoot('read', params);
}
@@ -214,10 +244,7 @@ export class DigitalEditionList implements OnInit {
if (this.hasCover === false) {
this.getTocRoot(collection);
} else {
- const nav = this.app.getActiveNavs();
- let params;
- params = { collection: collection, fetch: true, collectionID: collection.id };
- nav[0].setRoot('cover', params);
+ this.events.publish('digital-edition-list:open', collection);
}
} else {
this.downloadPDF(collection);
diff --git a/src/components/digital-edition-list/digital-edition-list.html b/src/components/digital-edition-list/digital-edition-list.html
index a2136360..22e5d883 100644
--- a/src/components/digital-edition-list/digital-edition-list.html
+++ b/src/components/digital-edition-list/digital-edition-list.html
@@ -1,18 +1,18 @@
-
-
+
-
+
{{edition.title}}
{{row}}
@@ -26,17 +26,17 @@
{{edition.title}}
+ (click)="openCollection(edition, false)">
-
+
-
+
{{edition.title}}
{{row}}
@@ -74,14 +74,14 @@
{{edition.title}}
justify-content: center;" *ngFor="let edition of digitalEditions" menuClose
(click)="openCollection(edition, false)" col-sm-6 col-sm-3>
-
+
-
+
{{edition.title}}
{{row}}
@@ -146,4 +146,4 @@
{{edition.title}}
-
\ No newline at end of file
+
diff --git a/src/components/digital-edition-list/digital-edition-list.scss b/src/components/digital-edition-list/digital-edition-list.scss
index 4cad9580..b1f5962f 100644
--- a/src/components/digital-edition-list/digital-edition-list.scss
+++ b/src/components/digital-edition-list/digital-edition-list.scss
@@ -32,4 +32,7 @@ digital-editions-list {
}
}
}
-}
\ No newline at end of file
+ .digital-edition-list-card-content{
+ padding-top: 35px;
+ }
+}
diff --git a/src/components/facsimiles/facsimiles.html b/src/components/facsimiles/facsimiles.html
index 1d41fe43..c8f24491 100644
--- a/src/components/facsimiles/facsimiles.html
+++ b/src/components/facsimiles/facsimiles.html
@@ -1,7 +1,7 @@
-
+
- {{facsimile.title}}
+
{{"Read.OpenInTab" | translate}}
-
+
+
+ {{"Read.Facsimiles.ExternalHeading" | translate}}
+
+
+
+
{{"Read.Facsimiles.Page" | translate}} ({{"Read.Facsimiles.Of" | translate}}
- {{(images)?images.length:0}}):
+ {{numberOfPages ? numberOfPages : (images ? images.length : 0)}}):
-
-
![]()
+
+
![]()
+
+
+
-
-
![]()
+
![]()
+
+
+
-
-
@@ -60,6 +85,7 @@
-
\ No newline at end of file
+
diff --git a/src/components/facsimiles/facsimiles.scss b/src/components/facsimiles/facsimiles.scss
index a4c3dbac..75569d51 100644
--- a/src/components/facsimiles/facsimiles.scss
+++ b/src/components/facsimiles/facsimiles.scss
@@ -1,11 +1,16 @@
facsimiles {
.leftFacsimileArrow{
left: 0;
+ right: auto !important;
}
.page_number_input input{
}
+ .external_url a{
+ white-space: normal;
+ }
+
.tab-container{
display: flex;
justify-content: flex-start;
@@ -96,5 +101,13 @@ facsimiles {
img{
cursor: move;
+ // https://github.com/hammerjs/hammer.js/issues/1050#issuecomment-267595556
+ // Need to use !important because something is trying to override the value.
+ touch-action: none !important;
+ }
+
+ .external_url{
+ display: grid;
+ line-height: 2;
}
}
diff --git a/src/components/facsimiles/facsimiles.ts b/src/components/facsimiles/facsimiles.ts
index bd75ebd8..59249c08 100644
--- a/src/components/facsimiles/facsimiles.ts
+++ b/src/components/facsimiles/facsimiles.ts
@@ -1,4 +1,4 @@
-import { Component, Input, EventEmitter, Output } from '@angular/core';
+import { Component, Input, EventEmitter, Output, SecurityContext } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { ModalController, NavParams, Events, ViewController, Platform } from 'ionic-angular';
import { FacsimileZoomModalPage } from '../../pages/facsimile-zoom/facsimile-zoom';
@@ -9,6 +9,7 @@ import { ConfigService } from '@ngx-config/core';
import { TranslateService } from '@ngx-translate/core';
import { SongService } from '../../app/services/song/song.service';
import { IfObservable } from 'rxjs/observable/IfObservable';
+
/**
* Generated class for the FacsimilesComponent component.
*
@@ -41,14 +42,23 @@ export class FacsimilesComponent {
manualPageNumber: number;
zoom = 1.0;
angle = 0;
- latestDeltaX = null;
- latestDeltaY = null;
+ latestDeltaX = 0
+ latestDeltaY = 0
+ prevX = 0
+ prevY = 0
+ isExternal = false;
facsUrl = '';
+ externalURLs = [];
facsimilePagesInfinite = false;
-
+ // If defined, this size will be appended to the image url.
+ // So define only if the image API supports it.
+ facsSize: number;
facsPage: any;
facsNumber = 0;
+ facsimileDefaultZoomLevel = 1;
+ numberOfPages: number;
+ chapter: string;
constructor(
protected sanitizer: DomSanitizer,
@@ -68,6 +78,13 @@ export class FacsimilesComponent {
this.manualPageNumber = 1;
this.text = '';
this.facsimiles = [];
+
+ const parts = String(this.itemId).split('_')
+ this.chapter = null;
+ if ( parts[2] !== undefined ) {
+ this.chapter = parts[2];
+ }
+
if (this.params.get('facsimilePage') !== undefined) {
this.facsimilePage = this.params.get('facsimilePage');
// To account for index at 0
@@ -75,12 +92,17 @@ export class FacsimilesComponent {
} else {
this.facsimilePage = 0;
}
+ try {
+ this.facsimileDefaultZoomLevel = this.config.getSettings('settings.facsimileDefaultZoomLevel');
+ } catch (e) {
+ this.facsimileDefaultZoomLevel = 1;
+ }
}
openNewFacs(event: Event, id: any) {
event.preventDefault();
event.stopPropagation();
- id.viewType = 'facsimile';
+ id.viewType = 'facsimiles';
this.openNewFacsimileView.emit(id);
}
@@ -123,15 +145,17 @@ export class FacsimilesComponent {
this.config.getSettings('app.machineName') +
`/song-example/page/image/${this.facsID}/`;
this.facsNumber = this.facsNr;
+ this.facsSize = null
+
} else if (this.facsID && this.facsNr) {
this.facsUrl = this.config.getSettings('app.apiEndpoint') + '/' +
this.config.getSettings('app.machineName') +
`/facsimile/page/image/${this.facsID}/`;
this.facsNumber = this.facsNr;
+ this.facsSize = null
+
} else {
- this.facsUrl = this.config.getSettings('app.apiEndpoint') + '/' +
- this.config.getSettings('app.machineName') +
- `/facsimile/page/image/${this.params.get('collectionID')}/`;
+ this.facsSize = this.facsimileDefaultZoomLevel;
this.getFacsimilePageInfinite();
}
} else {
@@ -145,11 +169,54 @@ export class FacsimilesComponent {
getFacsimilePageInfinite() {
this.facsimileService.getFacsimilePage(this.itemId).subscribe(
facs => {
- this.facsPage = facs;
- this.facsNumber = facs['page_number'];
+ this.facsimiles = [];
+ if ( String(this.itemId).indexOf('ch') > 0 ) {
+ facs.forEach( fac => {
+ let section = String(this.itemId).split(';')[0];
+ section = String((String(section).split('_')[2]).replace('ch', ''));
+ if ( String(fac['section_id']) === section ) {
+ this.facsPage = fac;
+ }
+ });
+ if ( this.facsPage === undefined ) {
+ this.facsPage = facs[0];
+ }
+ } else {
+ this.facsPage = facs[0];
+ }
+
+ this.manualPageNumber = this.activeImage = this.facsimilePage = this.facsNumber = (this.facsPage['page_nr'] + this.facsPage['start_page_number']);
+ this.numberOfPages = this.facsPage['number_of_pages'];
+
+ this.facsPage['title'] = this.sanitizer.bypassSecurityTrustHtml(this.facsPage['title']);
+
+ this.selectedFacsimile = this.facsPage;
+ this.selectedFacsimile.f_col_id = this.facsPage['publication_facsimile_collection_id'];
+ this.selectedFacsimile.title = this.sanitizer.sanitize(SecurityContext.HTML, this.sanitizer.bypassSecurityTrustHtml(this.facsPage['title']));
+
+ // add all
+ for (const f of facs) {
+ const tmp = f;
+ tmp.title = this.sanitizer.sanitize(SecurityContext.HTML, this.sanitizer.bypassSecurityTrustHtml(tmp.title));
+ const facsimile = new Facsimile(tmp);
+ facsimile.itemId = this.itemId;
+ facsimile.manuscript_id = f.publication_manuscript_id;
+ this.facsimiles.push(facsimile);
+ if ( f['external_url'] !== null ) {
+ this.isExternal = true;
+ this.externalURLs.push({'title': f['title'], 'url': f['external_url']});
+ }
+ }
+
+ if ( this.facsPage['external_url'] === undefined || this.facsPage['external_url'] === null ) {
+ this.facsUrl = this.config.getSettings('app.apiEndpoint') + '/' +
+ this.config.getSettings('app.machineName') +
+ `/facsimiles/${this.facsPage['publication_facsimile_collection_id']}/`;
+ this.isExternal = false;
+ }
},
error => {
- console.log('Error loading facsimiles...');
+ console.error('Error loading facsimiles...');
this.errorMessage = error
}
);
@@ -170,7 +237,7 @@ export class FacsimilesComponent {
if (itemId) {
this.itemId = itemId
}
- this.facsimileService.getFacsimiles(this.itemId).subscribe(
+ this.facsimileService.getFacsimiles(this.itemId, this.chapter).subscribe(
facs => {
// in order to get id attributes for tooltips
this.facsimiles = [];
@@ -180,7 +247,7 @@ export class FacsimilesComponent {
if (f.publication_facsimile_collection_id === undefined && f['publication_facsimile_collection_id'] !== undefined) {
f.publication_facsimile_collection_id = f['publication_facsimile_collection_id'];
}
- const f_url = this.facsimileService.getFacsimileImage(f.publication_facsimile_collection_id, i, 1);
+ const f_url = this.facsimileService.getFacsimileImage(f.publication_facsimile_collection_id, i, this.facsimileDefaultZoomLevel);
facsimile.images.push(f_url);
const zf_url = this.facsimileService.getFacsimileImage(f.publication_facsimile_collection_id, i, 4);
facsimile.zoomedImages.push(zf_url);
@@ -198,7 +265,7 @@ export class FacsimilesComponent {
}
}
} else {
- this.selectedFacsimile = this.facsimiles[0];
+ this.selectedFacsimile = this.facsimiles[this.facsimiles.length - 1];
}
this.images = this.selectedFacsimile.images;
this.activeImage = 0;
@@ -207,7 +274,7 @@ export class FacsimilesComponent {
this.doAnalytics();
},
error => {
- console.log('Error loading facsimiles...', this.itemId);
+ console.error('Error loading facsimiles...', this.itemId);
this.errorMessage = error
}
)
@@ -235,6 +302,13 @@ export class FacsimilesComponent {
if (facs) {
this.selectedFacsimile = facs;
this.itemId = this.selectedFacsimile.itemId;
+ this.facsNumber = facs.page;
+ this.facsPage = facs.page;
+ this.manualPageNumber = facs.page;
+ this.numberOfPages = facs.number_of_pages;
+ this.facsUrl = this.config.getSettings('app.apiEndpoint') + '/' +
+ this.config.getSettings('app.machineName') +
+ `/facsimiles/${facs.publication_facsimile_collection_id}/`;
}
this.text = this.sanitizer.bypassSecurityTrustHtml(
this.selectedFacsimile.content.replace(/images\//g, 'assets/images/')
@@ -246,8 +320,10 @@ export class FacsimilesComponent {
previous() {
if (this.facsimilePagesInfinite) {
- this.prevFacsimileUrl();
- this.manualPageNumber = Number(this.manualPageNumber) - 1;
+ if (this.manualPageNumber > 1) {
+ this.prevFacsimileUrl();
+ this.manualPageNumber = Number(this.manualPageNumber) - 1;
+ }
return;
}
this.activeImage = (this.activeImage - 1);
@@ -263,8 +339,14 @@ export class FacsimilesComponent {
next() {
if (this.facsimilePagesInfinite) {
- this.nextFacsimileUrl();
- this.manualPageNumber = Number(this.manualPageNumber) + 1;
+ if ( (Number(this.manualPageNumber) + 1) <= this.numberOfPages ) {
+ this.nextFacsimileUrl();
+ this.manualPageNumber = Number(this.manualPageNumber) + 1;
+ } else {
+ this.facsNumber = 1;
+ this.manualPageNumber = 1;
+ }
+ // this.manualPageNumber = Number(this.manualPageNumber) + 1;
return;
}
this.activeImage = (this.activeImage + 1);
@@ -293,28 +375,40 @@ export class FacsimilesComponent {
openZoom() {
let modal = null;
+ let params: object;
+ this.facsSize = 4;
+
if (this.facsimilePagesInfinite) {
- const params = {
- 'facsimilePagesInfinite': true,
- 'facsUrl': this.facsUrl,
- 'facsID': this.facsID,
- 'facsNr': this.facsNr
- };
+ // TODO: images array contains 0 index that is invalid since page numbers are 1 based.
+ const images = []
+ for (let i = 0; i < this.numberOfPages; i++) {
+ images.push(this.facsUrl + i + '/' + this.facsSize)
+ }
- modal = this.modalController.create(FacsimileZoomModalPage,
- params,
- { cssClass: 'facsimile-zoom-modal' }
- );
+ params = {
+ facsimilePagesInfinite: false,
+ facsUrl: this.facsUrl,
+ facsID: this.facsID,
+ facsNr: this.facsNr,
+ facsSize: this.facsSize,
+ images,
+ activeImage: this.manualPageNumber,
+ };
} else {
- modal = this.modalController.create(FacsimileZoomModalPage,
- { 'images': this.selectedFacsimile.zoomedImages, 'activeImage': this.activeImage },
- { cssClass: 'facsimile-zoom-modal' }
- );
+ params = {
+ images: this.selectedFacsimile.zoomedImages,
+ activeImage: this.activeImage,
+ };
}
+ modal = this.modalController.create(FacsimileZoomModalPage,
+ params,
+ { cssClass: 'facsimile-zoom-modal' }
+ );
+
modal.present();
modal.onDidDismiss(data => {
- console.log('dismissed', data);
+ console.error('dismissed', data);
});
}
@@ -335,21 +429,25 @@ export class FacsimilesComponent {
}
}
- zoomReset() {
+ resetFacsimile() {
this.zoom = 1 + (Math.random() * (0.00001 - 0.00000001) + 0.00000001);
this.angle = 0;
+ this.prevX = 0;
+ this.prevY = 0;
}
handleSwipeEvent(event) {
const img = event.target;
- let x = event.deltaX;
- let y = event.deltaY;
- if ( this.latestDeltaX !== null ) {
- x = this.latestDeltaX;
- y = this.latestDeltaY;
- this.latestDeltaX = null;
- this.latestDeltaY = null;
- }
+ // Store latest zoom adjusted delta.
+ // NOTE: img must have touch-action: none !important;
+ // otherwise deltaX and deltaY will give wrong values on mobile.
+ this.latestDeltaX = event.deltaX / this.zoom
+ this.latestDeltaY = event.deltaY / this.zoom
+
+ // Get current position from last position and delta.
+ let x = this.prevX + this.latestDeltaX
+ let y = this.prevY + this.latestDeltaY
+
if ( this.angle === 90 ) {
const tmp = x;
x = y;
@@ -364,28 +462,34 @@ export class FacsimilesComponent {
y = tmp;
x = x * -1;
}
+
if (img !== null) {
img.style.transform = 'rotate(' + this.angle + 'deg) scale(' + this.zoom + ') translate3d(' + x + 'px, ' + y + 'px, 0px)';
}
}
- setLatestPos(e) {
- this.latestDeltaX = e.clientX - e.offsetX;
- this.latestDeltaY = e.clientY - e.offsetY;
+ onMouseUp(e) {
+ // Update the previous position on desktop by adding the latest delta.
+ this.prevX += this.latestDeltaX
+ this.prevY += this.latestDeltaY
+ }
+
+ onTouchEnd(e) {
+ // Update the previous position on mobile by adding the latest delta.
+ this.prevX += this.latestDeltaX
+ this.prevY += this.latestDeltaY
}
onMouseWheel(e) {
const img = e.target;
- this.latestDeltaY = e.clientY - e.offsetY;
- this.latestDeltaX = e.clientX - e.offsetX;
if ( e.deltaY > 0 ) {
this.zoomIn();
- img.style.transform = 'rotate(' + this.angle + 'deg) scale(' + this.zoom + ') translate3d(' + this.latestDeltaX + 'px, ' +
- this.latestDeltaY + 'px, 0px)';
+ img.style.transform = 'rotate(' + this.angle + 'deg) scale(' + this.zoom + ') translate3d(' + this.prevX + 'px, ' +
+ this.prevY + 'px, 0px)';
} else {
this.zoomOut();
- img.style.transform = 'rotate(' + this.angle + 'deg) scale(' + this.zoom + ') translate3d(' + this.latestDeltaX + 'px, ' +
- this.latestDeltaY + 'px, 0px)';
+ img.style.transform = 'rotate(' + this.angle + 'deg) scale(' + this.zoom + ') translate3d(' + this.prevX + 'px, ' +
+ this.prevY + 'px, 0px)';
}
}
diff --git a/src/components/illustrations/illustrations.html b/src/components/illustrations/illustrations.html
new file mode 100644
index 00000000..a5a0d3ee
--- /dev/null
+++ b/src/components/illustrations/illustrations.html
@@ -0,0 +1,18 @@
+ 0; then illustrations; else none">
+
+
+ {{"Read.Illustrations.Showall" | translate}}
+
+
+

+
+
+ {{"Read.Illustrations.Goto" | translate}}
+
+
+
+
+
+
+ {{"Read.Illustrations.Nothing" | translate}}
+
diff --git a/src/components/illustrations/illustrations.scss b/src/components/illustrations/illustrations.scss
new file mode 100644
index 00000000..84fda01a
--- /dev/null
+++ b/src/components/illustrations/illustrations.scss
@@ -0,0 +1,11 @@
+illustrations {
+ .illustration-image-wrapper {
+ margin: 10px 0;
+ img {
+ cursor: zoom-in;
+ }
+ }
+ .scroll-to-illustration-button {
+ text-transform: initial;
+ }
+}
diff --git a/src/components/illustrations/illustrations.ts b/src/components/illustrations/illustrations.ts
new file mode 100644
index 00000000..db79ebb8
--- /dev/null
+++ b/src/components/illustrations/illustrations.ts
@@ -0,0 +1,141 @@
+import { Component, Input, OnDestroy } from '@angular/core';
+import { NavParams, Events } from 'ionic-angular';
+import { TextService } from '../../app/services/texts/text.service';
+import { ModalController } from 'ionic-angular';
+import { ConfigService } from '@ngx-config/core';
+import { FacsimileZoomModalPage } from '../../pages/facsimile-zoom/facsimile-zoom';
+/**
+ * Generated class for the IllustrationsComponent component.
+ *
+ * See https://angular.io/api/core/Component for more info on Angular
+ * Components.
+ */
+@Component({
+ selector: 'illustrations',
+ templateUrl: 'illustrations.html'
+})
+export class IllustrationsComponent {
+ @Input() itemId: string;
+ illustrationsPath = 'assets/images/illustrations/2/';
+ imgPath: any;
+ images: Array
diff --git a/src/components/introduction/introduction.ts b/src/components/introduction/introduction.ts
index 18d9cfd9..42a878d0 100644
--- a/src/components/introduction/introduction.ts
+++ b/src/components/introduction/introduction.ts
@@ -25,6 +25,7 @@ export class IntroductionComponent {
public text: any;
protected errorMessage: string;
+ textLoading: Boolean = true;
constructor(
protected readPopoverService: ReadPopoverService,
@@ -42,15 +43,17 @@ export class IntroductionComponent {
this.langService.getLanguage().subscribe(lang => {
this.textService.getIntroduction(String(this.itemId).split('_')[0], lang).subscribe(
res => {
+ this.textLoading = false;
// in order to get id attributes for tooltips
this.text = this.sanitizer.bypassSecurityTrustHtml(
res.content.replace(/images\//g, 'assets/images/')
.replace(/\.png/g, '.svg')
);
},
- error => {this.errorMessage =
error}
+ error => {this.errorMessage = error; this.textLoading = false; }
);
});
+ this.doAnalytics();
}
ngAfterViewInit() {
@@ -70,7 +73,19 @@ export class IntroductionComponent {
try {
element.scrollIntoView({'behavior': 'smooth', 'block': 'center'});
} catch ( e ) {
- console.log(e);
+ console.error(e);
+ }
+ }
+
+ doAnalytics() {
+ try {
+ (window).ga('send', 'event', {
+ eventCategory: 'Introduction',
+ eventLabel: 'Introduction',
+ eventAction: String(this.itemId),
+ eventValue: 10
+ });
+ } catch ( e ) {
}
}
}
diff --git a/src/components/list-of-songs/list-of-songs.ts b/src/components/list-of-songs/list-of-songs.ts
index e32c8380..3a3f873b 100644
--- a/src/components/list-of-songs/list-of-songs.ts
+++ b/src/components/list-of-songs/list-of-songs.ts
@@ -197,7 +197,7 @@ export class ListOfSongsComponent {
this.cdRef.detectChanges();
},
error => {
- console.log('ListOfSongsComponent', error);
+ console.error('ListOfSongsComponent', error);
this.isLoading = false;
}
);
diff --git a/src/components/manuscripts/manuscripts.html b/src/components/manuscripts/manuscripts.html
index 749df2d2..687abacc 100644
--- a/src/components/manuscripts/manuscripts.html
+++ b/src/components/manuscripts/manuscripts.html
@@ -19,6 +19,7 @@
diff --git a/src/components/manuscripts/manuscripts.scss b/src/components/manuscripts/manuscripts.scss
index 3bb3f2e5..487ece19 100644
--- a/src/components/manuscripts/manuscripts.scss
+++ b/src/components/manuscripts/manuscripts.scss
@@ -90,4 +90,14 @@ manuscripts {
.XMLcomment{
display: none;
}
+
+ img.teiManuscript.symbol{
+ width: 0.7rem;
+ display: inline;
+ }
+
+ .tei img {
+ width: 0.9rem;
+ display: inline;
+ }
}
diff --git a/src/components/manuscripts/manuscripts.ts b/src/components/manuscripts/manuscripts.ts
index a716cb98..1b984a08 100644
--- a/src/components/manuscripts/manuscripts.ts
+++ b/src/components/manuscripts/manuscripts.ts
@@ -25,9 +25,10 @@ export class ManuscriptsComponent {
selection: 0;
manuscripts: any;
selectedManuscript: any;
- normalized = true;
+ normalized = false;
errorMessage: string;
msID: string;
+ chapter: string;
constructor(
protected sanitizer: DomSanitizer,
@@ -45,6 +46,11 @@ export class ManuscriptsComponent {
}
ngOnInit() {
+ const parts = String(this.itemId).split('_')
+ this.chapter = null;
+ if ( parts[2] !== undefined ) {
+ this.chapter = parts[2];
+ }
this.msID = this.itemId + '_ms';
this.setText();
}
@@ -88,7 +94,7 @@ export class ManuscriptsComponent {
}
getManuscript() {
- this.textService.getManuscripts(this.itemId).subscribe(
+ this.textService.getManuscripts(this.itemId, this.chapter).subscribe(
res => {
// in order to get id attributes for tooltips
console.log('recieved manuscript ,..,', res.manuscripts);
@@ -97,7 +103,7 @@ export class ManuscriptsComponent {
},
err => console.error(err),
() => {
- console.log('fetched manuscripts');
+ console.error('fetched manuscripts');
}
);
}
diff --git a/src/components/read-text/read-text.html b/src/components/read-text/read-text.html
index 1e9dd5da..e2cb1496 100644
--- a/src/components/read-text/read-text.html
+++ b/src/components/read-text/read-text.html
@@ -1,13 +1,14 @@
-{{toolTipText}}
-
+
+>
+
diff --git a/src/components/read-text/read-text.scss b/src/components/read-text/read-text.scss
index 733c5dee..b0cce3dd 100644
--- a/src/components/read-text/read-text.scss
+++ b/src/components/read-text/read-text.scss
@@ -1,4 +1,21 @@
read-text {
+ img.hide-illustration {
+ visibility: hidden;
+ height: 10px;
+ & ~ p.tei:first-of-type::after {
+ content: '';
+ cursor: pointer;
+ background-image: url('/assets/images/img_placeholder.png');
+ height: 18px;
+ width: 20px;
+ margin-left: 5px;
+ margin-bottom: -3px;
+ display: inline-block;
+ background-repeat: no-repeat;
+ background-size: cover;
+ }
+ }
+
a.xreference.ref_illustration {
img {
max-width: 12px;
@@ -7,7 +24,7 @@ read-text {
}
}
match{
- background-color: rgba( yellow, 0.4 );
+ background-color: rgba( yellow, 0.4 ) !important;
}
.tei.anchor_lemma img{
width: 0.9rem;
@@ -38,7 +55,7 @@ read-text {
position: absolute;
pointer-events: none;
}
-
+
.toolTip:after {
border-color: rgba(136, 183, 213, 0);
border-right-color: #88b7d5;
@@ -63,4 +80,9 @@ read-text {
.inl_ms_arrow{
display: inline !important;
}
+
+ img.doodle{
+ width: 0.7rem;
+ display: inline;
+ }
}
diff --git a/src/components/read-text/read-text.ts b/src/components/read-text/read-text.ts
index ae0e3dc8..92a00345 100644
--- a/src/components/read-text/read-text.ts
+++ b/src/components/read-text/read-text.ts
@@ -1,3 +1,4 @@
+
import { Component, Input, ElementRef, Renderer } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { ReadPopoverService } from '../../app/services/settings/read-popover.service';
@@ -6,6 +7,7 @@ import { Storage } from '@ionic/storage';
import { ToastController, Events, ModalController } from 'ionic-angular';
import { IllustrationPage } from '../../pages/illustration/illustration';
import { ConfigService } from '@ngx-config/core';
+import { TextCacheService } from '../../app/services/texts/text-cache.service';
/**
* Generated class for the ReadTextComponent component.
@@ -25,9 +27,9 @@ export class ReadTextComponent {
public text: any;
protected errorMessage: string;
defaultView: string;
- showToolTip: boolean;
- toolTipPosition: object;
- toolTipText: string;
+ apiEndPoint: string;
+ appMachineName: string;
+ textLoading: Boolean = true;
constructor(
public events: Events,
@@ -41,10 +43,9 @@ export class ReadTextComponent {
private config: ConfigService,
protected modalController: ModalController
) {
+ this.appMachineName = this.config.getSettings('app.machineName');
+ this.apiEndPoint = this.config.getSettings('app.apiEndpoint');
this.defaultView = this.config.getSettings('defaults.ReadModeView');
- this.showToolTip = false;
- this.toolTipPosition = { top: 40 + 'px', left: 100 + 'px' };
- this.toolTipText = '';
}
ngOnInit() {
@@ -63,23 +64,83 @@ export class ReadTextComponent {
ngAfterViewInit() {
this.renderer.listen(this.elementRef.nativeElement, 'click', (event) => {
- if (event.target.classList.contains('variantScrollTarget') && this.readPopoverService.show.comments) {
- if (event.target !== undefined) {
- this.showTooltip(event);
+ try {
+ if (this.config.getSettings('settings.showReadTextIllustrations')) {
+ const showIllustration = this.config.getSettings('settings.showReadTextIllustrations');
+
+ if (event.target.classList.contains('doodle')) {
+ const image = {src: '/assets/images/verk/' + String(event.target.dataset.id).replace('tag_', '') + '.jpg', class: 'doodle'};
+ this.events.publish('give:illustration', image);
+ }
+ if ( showIllustration.includes(this.link.split('_')[1])) {
+ if (event.target.classList.contains('est_figure_graphic')) {
+ // Check if we have the "illustrations" tab open, if not, open
+ if ( document.querySelector('illustrations') === null ) {
+ this.openNewView(event, null, 'illustrations');
+ }
+ const image = {src: event.target.src, class: 'illustration'};
+ this.events.publish('give:illustration', image);
+ }
+ } else {
+ if (event.target.previousElementSibling !== null &&
+ event.target.previousElementSibling.classList.contains('est_figure_graphic')) {
+ // Check if we have the "illustrations" tab open, if not, open
+ if ( document.querySelector('illustrations') === null ) {
+ this.openNewView(event, null, 'illustrations');
+ }
+ const image = {src: event.target.previousElementSibling.src, class: 'illustration'};
+ this.events.publish('give:illustration', image);
+ }
}
}
+ } catch (e) {
+ console.error(e);
+ }
+
+
if (event.target.parentNode.classList.contains('ref_illustration')) {
const hashNumber = event.target.parentNode.hash;
const imageNumber = hashNumber.split('#')[1];
this.openIllustration(imageNumber);
}
});
- this.renderer.listen(this.elementRef.nativeElement, 'mouseover', (event) => {
- if ((event.target.parentNode.classList.contains('tooltiptrigger') || event.target.classList.contains('tooltiptrigger')) &&
- this.readPopoverService.show.comments) {
- if (event.target !== undefined) {
- this.showTooltip(event);
+
+ const checkExist = setInterval(function() {
+ if ( this.link !== undefined ) {
+ const linkData = this.link.split(';');
+ if ( linkData[1] ) {
+ const target = document.getElementsByName('' + linkData[1] + '')[0] as HTMLAnchorElement;
+ if ( target ) {
+ this.scrollToHTMLElement(target, false);
+ clearInterval(checkExist);
+ }
+ } else {
+ clearInterval(checkExist);
}
+ } else {
+ clearInterval(checkExist);
+ }
+ }.bind(this), 100);
+
+ }
+
+ openNewView( event, id: any, type: string ) {
+ let openId = id;
+ let chapter = null;
+ if (String(id).includes('ch')) {
+ openId = String(String(id).split('ch')[0]).trim();
+ chapter = 'ch' + String(String(id).split('ch')[1]).trim();
+ }
+ this.events.publish('show:view', type, openId, chapter);
+ }
+
+ private setIllustrationImages() {
+ this.textService.getEstablishedText(this.link).subscribe(text => {
+ const parser = new DOMParser();
+ const xmlDoc = parser.parseFromString(text, 'text/html');
+ const images: any = xmlDoc.querySelectorAll('img.est_figure_graphic');
+ for (let i = 0; i < images.length ; i++) {
+ images[i].classList.add('show-illustration');
}
});
}
@@ -100,10 +161,18 @@ export class ReadTextComponent {
getCacheText(id: string) {
this.storage.get(id).then((content) => {
+ this.textLoading = false;
+ const c_id = String(this.link).split('_')[0];
+ let galleryId = 44;
+ try {
+ galleryId = this.config.getSettings('settings.galleryCollectionMapping')[c_id];
+ } catch ( err ) {
+
+ }
this.text = content;
this.text = this.sanitizer.bypassSecurityTrustHtml(
- content.replace(/images\//g, 'assets/images/')
- .replace(/\.png/g, '.svg').replace(/class=\"([a-z A-Z _ 0-9]{1,140})\"/g, 'class=\"tei $1\"')
+ content.replace(/images\/verk\//g, `${this.apiEndPoint}/${this.appMachineName}/gallery/get/${galleryId}/`)
+ .replace(/\.png/g, '.svg').replace(/class=\"([a-z A-Z _ 0-9]{1,140})\"/g, 'class=\"tei $1\"').replace(/images\//g, 'assets/images/')
);
this.matches.forEach(function (val) {
const re = new RegExp('(' + val + ')', 'g');
@@ -128,23 +197,70 @@ export class ReadTextComponent {
getEstText() {
this.textService.getEstablishedText(this.link).subscribe(
text => {
+ this.textLoading = false;
+ const c_id = String(this.link).split('_')[0];
+ let galleryId = 44;
+ try {
+ galleryId = this.config.getSettings('settings.galleryCollectionMapping')[c_id];
+ } catch ( err ) {
+
+ }
+ text = text.replace(/images\/verk\//g, `${this.apiEndPoint}/${this.appMachineName}/gallery/get/${galleryId}/`);
+ text = text.replace(/\.png/g, '.svg');
+ text = text.replace(/class=\"([a-z A-Z _ 0-9]{1,140})\"/g, 'class=\"tei $1\"');
+ text = text.replace(/images\//g, 'assets/images/');
this.text = this.sanitizer.bypassSecurityTrustHtml(
- text.replace(/images\//g, 'assets/images/')
- .replace(/\.png/g, '.svg').replace(/class=\"([a-z A-Z _ 0-9]{1,140})\"/g, 'class=\"tei $1\"')
+ text
);
- if (this.matches instanceof Array) {
+ if (this.matches instanceof Array && this.matches.length > 0) {
+ let tmpText: any = '';
this.matches.forEach(function (val) {
- const re = new RegExp('(' + val + ')', 'g');
- this.text = this.sanitizer.bypassSecurityTrustHtml(
+ const re = new RegExp('(' + val + ')', 'ig');
+ tmpText = this.sanitizer.bypassSecurityTrustHtml(
text.replace(re, '
$1')
);
}.bind(this));
+ this.text = tmpText;
}
},
- error => { this.errorMessage =
error }
+ error => { this.errorMessage = error; this.textLoading = false; }
);
}
+ private scrollToHTMLElement(element: HTMLElement, addTag: boolean, timeOut = 8000) {
+ try {
+ element.scrollIntoView({'behavior': 'smooth', 'block': 'start'});
+ const tmp = element.previousElementSibling as HTMLElement;
+ let addedArrow = false;
+
+ if ( tmp !== null && tmp !== undefined && tmp.classList.contains('anchor_lemma') ) {
+ tmp.style.display = 'inline';
+ setTimeout(function() {
+ tmp.style.display = 'none';
+ }, 2000);
+ addedArrow = true;
+ } else {
+ const tmpImage: HTMLImageElement = new Image();
+ tmpImage.src = 'assets/images/ms_arrow_right.svg';
+ tmpImage.classList.add('inl_ms_arrow');
+ element.parentElement.insertBefore(tmpImage, element);
+ setTimeout(function() {
+ element.parentElement.removeChild(tmpImage);
+ }, timeOut);
+ addedArrow = true;
+ }
+
+ if ( addTag && !addedArrow ) {
+ element.innerHTML = '
';
+ setTimeout(function() {
+ element.innerHTML = '';
+ }, timeOut);
+ }
+ } catch ( e ) {
+ console.error(e);
+ }
+ }
+
doAnalytics() {
try {
(window).ga('send', 'event', {
@@ -156,35 +272,4 @@ export class ReadTextComponent {
} catch ( e ) {
}
}
-
- showTooltip(origin: any) {
- let elem = [];
- if (origin.target.nextSibling !== null && origin.target.nextSibling !== undefined &&
- !String(origin.target.nextSibling.className).includes('tooltiptrigger')) {
- elem = origin.target;
- } else if (origin.target.parentNode.nextSibling !== null && origin.target.parentNode.nextSibling !== undefined) {
- elem = origin.target.parentNode;
- }
- if (elem['nextSibling'] !== null && elem['nextSibling'] !== undefined) {
- if (elem['nextSibling'].className !== undefined && String(elem['nextSibling'].className).includes('tooltip')) {
- this.toolTipPosition = {
- top: (elem['offsetTop'] - (elem['offsetHeight'] / 2) + 4) +
- 'px', left: (elem['offsetLeft'] + elem['offsetWidth'] + 4) + 'px'
- };
- this.showToolTip = true;
- this.toolTipText = elem['nextSibling'].textContent;
- if ((elem['offsetParent'].clientWidth) < ((elem['offsetLeft'] + elem['offsetWidth'] + 70))) {
- this.toolTipPosition = {
- top: (elem['offsetTop'] - (elem['offsetHeight'] / 2) + 40) +
- 'px', left: (elem['offsetLeft'] + elem['offsetWidth'] - 100) + 'px'
- };
- }
-
- setTimeout(() => {
- this.showToolTip = false;
- this.toolTipText = '';
- }, 5000);
- }
- }
- }
}
diff --git a/src/components/simple-search/simple-search.html b/src/components/simple-search/simple-search.html
index adb5bfe9..83b82a16 100644
--- a/src/components/simple-search/simple-search.html
+++ b/src/components/simple-search/simple-search.html
@@ -159,4 +159,4 @@
-
\ No newline at end of file
+
diff --git a/src/components/simple-search/simple-search.scss b/src/components/simple-search/simple-search.scss
index d77a1fd8..5ec64d55 100644
--- a/src/components/simple-search/simple-search.scss
+++ b/src/components/simple-search/simple-search.scss
@@ -58,6 +58,11 @@ simple-search {
white-space: normal;
}
+ .textType.title{
+ color: rgba(color($colors, work), 0.7);
+ display: inline;
+ font-size: 0.9rem !important;
+ }
.textType.person{
color: rgba(color($colors, person), 0.7);
display: inline;
diff --git a/src/components/simple-search/simple-search.ts b/src/components/simple-search/simple-search.ts
index 0415e782..5e454dec 100644
--- a/src/components/simple-search/simple-search.ts
+++ b/src/components/simple-search/simple-search.ts
@@ -1,4 +1,5 @@
-import { Component, Input, ViewChild, HostListener, ElementRef } from '@angular/core';
+import { SemanticDataService } from './../../app/services/semantic-data/semantic-data.service';
+import { Component, Input, ViewChild, HostListener, ElementRef, ChangeDetectorRef } from '@angular/core';
import { App, Platform, Events, NavParams, Searchbar, ViewController } from 'ionic-angular';
import { SearchDataService } from '../../app/services/search/search-data.service';
import { TableOfContentsCategory, GeneralTocItem } from '../../app/models/table-of-contents.model';
@@ -59,6 +60,8 @@ export class SimpleSearchComponent {
desktop: 250
}
+ collectionTOCs = [];
+
objectTypes = {
all: ['location', 'tag', 'subject', 'recorder', 'playman', 'person'],
subjects: ['subject', 'recorder', 'playman', 'person']
@@ -73,7 +76,9 @@ export class SimpleSearchComponent {
private _eref: ElementRef,
public userSettingsService: UserSettingsService,
public viewctrl: ViewController,
- private storage: Storage) {
+ public semanticDataService: SemanticDataService,
+ private storage: Storage,
+ private cf: ChangeDetectorRef) {
this.apiEndPoint = this.config.getSettings('app.apiEndpoint');
this.projectMachineName = this.config.getSettings('app.machineName');
this.showPageNumbers = this.config.getSettings('simpleSearch.showPageNumbers');
@@ -114,6 +119,8 @@ export class SimpleSearchComponent {
this.getFacsimileLookupData();
+ this.getTOCLookupData();
+
if (navParams.get('searchResult') !== undefined) {
this.searchString = navParams.get('searchResult');
this.onInput(null, this.searchString);
@@ -162,6 +169,26 @@ export class SimpleSearchComponent {
);
}
+ getTOCLookupData() {
+ this.search.getProjectCollections().subscribe(
+ res => {
+ res.forEach(element => {
+ if ( this.collectionTOCs[element['id']] === undefined ) {
+ this.semanticDataService.getPublicationTOC(element['id']).subscribe(
+ toc_data => {
+ this.collectionTOCs[element['id']] = toc_data;
+ },
+ error => {
+ }
+ );
+ }
+ });
+ },
+ error => { this.errorMessage = error }
+ );
+ }
+
+
getPublicationNameByFacsimileId(fId) {
for (let i = 0; i < this.facsimileLookupData.length; i++) {
if (String(this.facsimileLookupData[i]['pf_id']) === String(fId)) {
@@ -226,6 +253,24 @@ export class SimpleSearchComponent {
}
}
+ getPublicationTOCName(collection_id, publication_id, data) {
+ if ( this.collectionTOCs[collection_id] !== undefined ) {
+ this.updatePublicationNames(collection_id, publication_id, data, this.collectionTOCs[collection_id]);
+ }
+ }
+
+ public updatePublicationNames(collection_id, publication_id, data, toc) {
+ toc.forEach( item => {
+ const id = collection_id + '_' + publication_id;
+ const itemArray = String(item['itemId']).split('_');
+ const itemId = itemArray[0] + '_' + itemArray[1];
+ if ( id === itemId ) {
+ data['publication_name'] = item['text'];
+ return true;
+ }
+ });
+ }
+
configOccurrencePdf() {
try {
this.downloadOccurrencePdf = this.config.getSettings('simpleSearch.downloadOccurrencePdf');
@@ -332,7 +377,26 @@ export class SimpleSearchComponent {
this.search.getAll(searchString, val, 1).subscribe(
res => {
// in order to get id attributes for tooltips
- this.searchResult = res
+ // getPublicationTOCName();
+ res.forEach(function(element, index, object) {
+ const source = element['_source'];
+ const pubId = source['publication_id'];
+ let colID = source['collection_id'] || source['publication_collection_id'];
+ if ( colID === undefined ) {
+ const path = String(source['path']).split('/');
+ colID = path[path.length - 1];
+ colID = String(colID).split('_')[0];
+ }
+ colID = String(colID).split(',')[0];
+ this.getPublicationTOCName(colID, pubId, source);
+ if ( source['publication_name'] === undefined ) {
+ source['publication_name'] = source['publication_data'][0]['pubname'];
+ }
+ if ( source['publication_data'] !== undefined && source['publication_data'][0]['collection_published'] === 0 ) {
+ delete object[index];
+ }
+ }.bind(this));
+ this.searchResult = res;
this.formatSearchresult(val);
this.mergeResults('texts');
this.mergeResults('subjects');
@@ -441,6 +505,7 @@ export class SimpleSearchComponent {
}
this.searchFacets[0].children.sort();
}
+
}
if (this.hasKey('collections', this.searchFacets) === false && this.displayResult[type].length > 0) {
@@ -458,7 +523,7 @@ export class SimpleSearchComponent {
for (let j = 0; j < this.searchFacets.length; j++) {
if (this.searchFacets[j].type === this.displayResult[type][i]['textType']) {
const facet: Facet = new Facet;
- facet.name = this.displayResult[type][i]['text'];
+ facet.name = this.displayResult[type][i]['publication_name'] || this.displayResult[type][i]['text'];
facet.checked = this.checkedDefault;
facet.count = 1;
facet.type = this.displayResult[type][i]['textType'];
@@ -544,6 +609,7 @@ export class SimpleSearchComponent {
'score': element._score,
'facsimilePage': ((subjectData['publication_facsimile_page']) ? subjectData['publication_facsimile_page'] : null),
'publication_name': subjectData['publication_name'],
+ 'publication_collection_id': subjectData['collection_id'],
'collection_name': subjectData['collection_name'],
'publication_id': subjectData['publication_id'],
'publication_version_id': subjectData['publication_version_id'],
@@ -576,6 +642,7 @@ export class SimpleSearchComponent {
'facsimilePage': ((tagData['publication_facsimile_page']) ? tagData['publication_facsimile_page'] : null),
'publication_name': tagData['publication_name'],
'collection_name': tagData['collection_name'],
+ 'publication_collection_id': tagData['collection_id'],
'publication_id': tagData['publication_id'],
'publication_version_id': tagData['publication_version_id'],
'publication_manuscript_id': tagData['publication_manuscript_id'],
@@ -603,6 +670,7 @@ export class SimpleSearchComponent {
'identifier': String('song' + songData['song_name']).toLowerCase().trim().replace(' ', ''),
'origDate': songData['song_original_publication_date'],
'object_id': String(songData['song_id']).toLowerCase(),
+ 'publication_collection_id': songData['collection_id'],
'song_performer_born_name': songData['song_performer_born_name'],
'song_performer_firstname': songData['song_performer_firstname'],
'song_performer_lastname': songData['song_performer_lastname'],
@@ -647,6 +715,7 @@ export class SimpleSearchComponent {
'score': element._score,
'facsimilePage': ((locationData['publication_facsimile_page']) ? locationData['publication_facsimile_page'] : null),
'publication_name': locationData['publication_name'],
+ 'publication_collection_id': locationData['collection_id'],
'collection_name': locationData['collection_name'],
'publication_id': locationData['publication_id'],
'publication_version_id': locationData['publication_version_id'],
@@ -721,7 +790,11 @@ export class SimpleSearchComponent {
}
const pubName = (pData !== undefined) ? pData['p_name'] : null;
const colName = (pData !== undefined) ? pData['pc_name'] : null;
- const pubId = this.getPublicationIdNameByFacsimileId(fId);
+ let pubId = this.getPublicationIdNameByFacsimileId(fId);
+ if ( pubId === undefined || pubId === null ) {
+ pubId = element['_source']['publication_id'];
+ }
+
if (element._score > 1) {
this.displayResult['texts'].push(
{
@@ -737,7 +810,7 @@ export class SimpleSearchComponent {
'score': element._score,
'facsimilePage': facsimilePage,
'SLSCollection': SLSCollection,
- 'publication_name': pubName,
+ 'publication_name': element['_source']['publication_name'],
'publication_id': pubId,
'collection_name': colName
}
diff --git a/src/components/static-pages-toc-drilldown-menu/static-pages-toc-drilldown-menu.html b/src/components/static-pages-toc-drilldown-menu/static-pages-toc-drilldown-menu.html
index 9665dd51..7040a5bd 100644
--- a/src/components/static-pages-toc-drilldown-menu/static-pages-toc-drilldown-menu.html
+++ b/src/components/static-pages-toc-drilldown-menu/static-pages-toc-drilldown-menu.html
@@ -1,24 +1,23 @@
-
-
- {{"TOC.Home" | translate }}
-
-
+ 1" menuClose (click)="unDrill()" class="mainMenuItem">
+
+
+
-
-
-
-
-
- {{item.title}}
-
-
-
-
-
- {{item.title}}
-
-
+
+
+
+
+
+ {{item.title}}
+
+
+
+
+
+ {{item.title}}
+
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/components/static-pages-toc-drilldown-menu/static-pages-toc-drilldown-menu.ts b/src/components/static-pages-toc-drilldown-menu/static-pages-toc-drilldown-menu.ts
index aab38195..e81677b5 100644
--- a/src/components/static-pages-toc-drilldown-menu/static-pages-toc-drilldown-menu.ts
+++ b/src/components/static-pages-toc-drilldown-menu/static-pages-toc-drilldown-menu.ts
@@ -115,15 +115,15 @@ export class StaticPagesTocDrilldownMenuComponent {
/**
* Find a node by id in a JSON tree
*/
- getNodeById(id, node) {
+ getNodeById(id, tree) {
const reduce = [].reduce;
- function runner(result, rnode) {
- if (result || !rnode) { return result; }
- return rnode.id === id && rnode ||
- runner(null, rnode.children) ||
- reduce.call(Object(rnode), runner, result);
+ const runner = (result, node) => {
+ if (result || !node) { return result; }
+ return node.id === id && node ||
+ runner(null, node.children) ||
+ reduce.call(Object(node), runner, result);
}
- return runner(null, node);
+ return runner(null, tree);
}
ngOnInit() {
@@ -136,8 +136,11 @@ export class StaticPagesTocDrilldownMenuComponent {
}
unDrill() {
- this.titleStack.pop();
- this.menuStack.pop();
+ // don't go to far
+ if ( this.menuStack.length > 1 ) {
+ this.titleStack.pop();
+ this.menuStack.pop();
+ }
}
open(item: StaticPage) {
diff --git a/src/components/table-of-content-letter-filter/table-of-content-letter-filter.html b/src/components/table-of-content-letter-filter/table-of-content-letter-filter.html
new file mode 100644
index 00000000..f5908a1f
--- /dev/null
+++ b/src/components/table-of-content-letter-filter/table-of-content-letter-filter.html
@@ -0,0 +1,4 @@
+
+
+ {{text}}
+
diff --git a/src/components/table-of-content-letter-filter/table-of-content-letter-filter.scss b/src/components/table-of-content-letter-filter/table-of-content-letter-filter.scss
new file mode 100644
index 00000000..8772fa20
--- /dev/null
+++ b/src/components/table-of-content-letter-filter/table-of-content-letter-filter.scss
@@ -0,0 +1,3 @@
+table-of-content-letter-filter {
+
+}
diff --git a/src/components/table-of-content-letter-filter/table-of-content-letter-filter.ts b/src/components/table-of-content-letter-filter/table-of-content-letter-filter.ts
new file mode 100644
index 00000000..f3270984
--- /dev/null
+++ b/src/components/table-of-content-letter-filter/table-of-content-letter-filter.ts
@@ -0,0 +1,22 @@
+import { Component } from '@angular/core';
+
+/**
+ * Generated class for the TableOfContentLetterFilterComponent component.
+ *
+ * See https://angular.io/api/core/Component for more info on Angular
+ * Components.
+ */
+@Component({
+ selector: 'table-of-content-letter-filter',
+ templateUrl: 'table-of-content-letter-filter.html'
+})
+export class TableOfContentLetterFilterComponent {
+
+ text: string;
+
+ constructor() {
+ console.log('Hello TableOfContentLetterFilterComponent Component');
+ this.text = 'Hello World';
+ }
+
+}
diff --git a/src/components/table-of-contents-accordion/table-of-contents-accordion.html b/src/components/table-of-contents-accordion/table-of-contents-accordion.html
index 8a20db25..87a92f31 100644
--- a/src/components/table-of-contents-accordion/table-of-contents-accordion.html
+++ b/src/components/table-of-contents-accordion/table-of-contents-accordion.html
@@ -1,83 +1,104 @@
-
- {{ "Read.TitlePage.Title" | translate }}
+
+ {{collectionName}}
-
- {{ "Read.Introduction.Title" | translate }}
+
+
+ {{ "BackButton.default" | translate }}
-
-
-
-
-
- {{ option.text }}
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ "Read.CoverPage.Title" | translate }}
+
+
+ {{ "Read.TitlePage.Title" | translate }}
+
+
+ {{ "Read.Introduction.Title" | translate }}
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ option.text }}
-
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
- {{ option.text }}
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
\ No newline at end of file
+
+
diff --git a/src/components/table-of-contents-accordion/table-of-contents-accordion.scss b/src/components/table-of-contents-accordion/table-of-contents-accordion.scss
index 90061890..0a72674c 100644
--- a/src/components/table-of-contents-accordion/table-of-contents-accordion.scss
+++ b/src/components/table-of-contents-accordion/table-of-contents-accordion.scss
@@ -1,4 +1,35 @@
table-of-contents-accordion {
+ ion-label{
+ cursor: pointer;
+ }
+
+ .collection-name-top{
+ background-color: rgba(color($colors, primary), $alpha: 0.2) !important;
+ }
+ .collection-name-top ion-label{
+ white-space: pre-wrap !important;
+ }
+ .collection-filters {
+ ion-label {
+ display: flex;
+ justify-content: space-around;
+
+ button {
+ .button-inner ion-icon {
+ color: #ddd;
+ }
+
+ &.active {
+ background-color:#4a6770;
+ color: #fff;
+
+ &:hover {
+ background-color: #547a86;
+ }
+ }
+ }
+ }
+ }
ion-item.item-ios [item-left], ion-item.item-ios [item-right],
ion-item.item-md [item-left],
@@ -7,7 +38,7 @@ table-of-contents-accordion {
ion-item.item-wp [item-right] {
margin-left: 0;
}
-
+
ion-item.item-ios ion-icon[item-left] + .item-inner, ion-item.item-ios ion-icon[item-left] + .item-input,
ion-item.item-md ion-icon[item-left] + .item-inner,
ion-item.item-md ion-icon[item-left] + .item-input,
@@ -15,12 +46,24 @@ table-of-contents-accordion {
ion-item.item-wp ion-icon[item-left] + .item-input {
margin-left: 8px;
}
-
+
ion-list.accordion-menu ion-item.header ion-icon.header-icon {
will-change: transform;
transition: transform 0.3s ease;
}
-
+
+ .item.item-block.item-md.option {
+ margin: 0 !important;
+ }
+
+ .options.recursive-suboptions {
+ margin-left: 20px;
+ }
+
+ .accordion-menu .list .list-md {
+ background-color: #ecece4;
+ }
+
ion-list.accordion-menu ion-item.header ion-icon.header-icon.rotate {
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
@@ -28,18 +71,18 @@ table-of-contents-accordion {
-o-transform: rotate(90deg);
transform: rotate(90deg);
}
-
+
ion-list.accordion-menu div.options {
will-change: height;
transition: height 0.3s ease;
overflow-y: hidden;
height: 0;
}
-
+
ion-list.accordion-menu ion-item.item.item-block.item-ios.no-icon .item-inner {
margin-left: 48px;
}
-
+
ion-list.accordion-menu ion-item.item.item-block.item-md.no-icon .item-inner,
ion-list.accordion-menu ion-item.item.item-block.item-wp.no-icon .item-inner {
margin-left: 40px;
diff --git a/src/components/table-of-contents-accordion/table-of-contents-accordion.ts b/src/components/table-of-contents-accordion/table-of-contents-accordion.ts
index e4591a09..2bc84c94 100644
--- a/src/components/table-of-contents-accordion/table-of-contents-accordion.ts
+++ b/src/components/table-of-contents-accordion/table-of-contents-accordion.ts
@@ -40,6 +40,7 @@ class InnerMenuOptionModel {
facs_nr?: any;
children?: Array;
is_child?: boolean;
+ is_gallery?: boolean;
itemId?: any;
markdownID?: any;
datafile?: any;
@@ -47,11 +48,12 @@ class InnerMenuOptionModel {
song_id?: any;
amountOfParents?: any;
openByDefault?: boolean;
- collectionId?: any;
loading?: boolean;
children_id?: any;
search_children_id?: any;
important?: boolean;
+ description: any;
+ collapsed: boolean;
public static fromMenuOptionModel(
option: TocAccordionMenuOptionModel,
@@ -76,6 +78,7 @@ class InnerMenuOptionModel {
if (option.text) {
innerMenuOptionModel.text = option.text;
+ innerMenuOptionModel.description = option.description;
} else if (option.title) {
innerMenuOptionModel.text = option.title;
}
@@ -84,6 +87,8 @@ class InnerMenuOptionModel {
innerMenuOptionModel.page_nr = option.page_nr || null;
innerMenuOptionModel.facs_nr = option.facs_nr || null;
+ innerMenuOptionModel.is_gallery = option.is_gallery || false;
+
if (option.itemId) {
innerMenuOptionModel.itemId = option.itemId;
@@ -139,12 +144,16 @@ class InnerMenuOptionModel {
option.children.forEach(subItem => {
const innerSubItem = InnerMenuOptionModel.fromMenuOptionModel(subItem, innerMenuOptionModel, true, searchingTocItem);
-
+ innerSubItem.collapsed = subItem.collapsed;
if (innerSubItem.text) {
if (storeChildren) {
- childrenToc[innerMenuOptionModel.children_id].push(innerSubItem);
+ if ( childrenToc[innerMenuOptionModel.children_id].indexOf(innerSubItem) === -1 ) {
+ childrenToc[innerMenuOptionModel.children_id].push(innerSubItem);
+ }
} else {
- innerMenuOptionModel.subOptions.push(innerSubItem);
+ if ( innerMenuOptionModel.subOptions.indexOf(innerSubItem) === -1 ) {
+ innerMenuOptionModel.subOptions.push(innerSubItem);
+ }
}
}
@@ -154,7 +163,6 @@ class InnerMenuOptionModel {
innerSubItem.parent.selected = true;
innerSubItem.parent.expanded = true;
}
-
});
}
@@ -181,10 +189,11 @@ export class TableOfContentsAccordionComponent {
toc: Array,
searchTocItem?: Boolean,
searchPublicationId?: Number,
+ searchItemId?: String,
searchTitle?: String
}) {
if (value && value.toc && value.toc.length > 0) {
- if (value.searchTocItem) {
+ if (value.searchTocItem !== undefined && value.searchTocItem === true) {
this.searchingForTocItem = true;
}
this.menuOptions = value.toc;
@@ -194,7 +203,9 @@ export class TableOfContentsAccordionComponent {
// Map the options to our internal models
this.menuOptions.forEach(option => {
const innerMenuOption = InnerMenuOptionModel.fromMenuOptionModel(option, null, false, value.searchTocItem);
- this.collapsableItems.push(innerMenuOption);
+ if ( this.collapsableItems.indexOf(innerMenuOption) === -1 && innerMenuOption.type !== 'folder' ) {
+ this.collapsableItems.push(innerMenuOption);
+ }
// Check if there's any option marked as selected
if (option.selected) {
@@ -214,15 +225,16 @@ export class TableOfContentsAccordionComponent {
console.log('found menu item');
}
- if (value.searchTocItem) {
+ if (value.searchTocItem !== undefined && value.searchTocItem) {
// Find toc item and open its parents
- if (value.searchPublicationId && value.searchTitle) {
- this.findTocByPubAndTitle(this.collapsableItems, value.searchPublicationId, value.searchTitle);
+ if (value.searchItemId) {
+ value.searchItemId = String(value.searchItemId).replace('_nochapter', '').replace(':chapterID', '');
+ this.findTocByPubOnly(this.collapsableItems, value.searchItemId);
this.events.publish('typesAccordion:change', {
expand: true
});
- } else if (value.searchPublicationId) {
- this.findTocByPubOnly(this.collapsableItems, value.searchPublicationId);
+ } else if (value.searchPublicationId && value.searchTitle) {
+ this.findTocByPubAndTitle(this.collapsableItems, value.searchPublicationId, value.searchTitle);
this.events.publish('typesAccordion:change', {
expand: true
});
@@ -239,9 +251,9 @@ export class TableOfContentsAccordionComponent {
}
}
}
-
this.searchingForTocItem = false;
}
+ this.activeMenuTree = this.collapsableItems;
}
@Input('settings')
@@ -257,6 +269,7 @@ export class TableOfContentsAccordionComponent {
@Input() showBackButton?: Boolean;
@Input() isMarkdown?: Boolean;
@Input() isGallery?: Boolean;
+ @Input() open: Boolean;
@Output() selectOption = new EventEmitter();
currentItem: GeneralTocItem;
@@ -265,13 +278,33 @@ export class TableOfContentsAccordionComponent {
searchTocItemInAccordionByTitle = false;
tocItemSearchChildrenCounter = 0;
foundTocItem = false;
- coverSelected: boolean;
titleSelected: boolean;
+ introductionSelected: boolean;
+ coverSelected: boolean;
root: any;
hasCover: boolean;
+ hasTitle: boolean;
hasIntro: boolean;
playmanTraditionPageInMusicAccordion = false;
playmanTraditionPageID = '03-03';
+
+ chronologicalOrderActive: boolean;
+ thematicOrderActive = true;
+ alphabethicOrderActive: boolean;
+
+ visibleactiveMenuTree = [];
+ visibleTitleStack = [];
+
+ chronologicalactiveMenuTree = [];
+ chronologicalTitleStack = [];
+
+ alphabeticalactiveMenuTree: any[];
+ alphabeticalTitleStack: any[];
+
+ activeMenuTree = [];
+
+ sortableLetters = [];
+
constructor(
public platform: Platform,
public events: Events,
@@ -284,27 +317,39 @@ export class TableOfContentsAccordionComponent {
public userSettingsService: UserSettingsService,
public translate: TranslateService
) {
+ this.collectionId = JSON.stringify(this.collectionId);
+
+ this.registerEventListeners();
this.setConfigs();
// Handle the redirect event
this.events.subscribe(SideMenuRedirectEvent, (data: SideMenuRedirectEventData) => {
this.updateSelectedOption(data);
});
+ try {
+ this.sortableLetters = this.config.getSettings('settings.sortableLetters');
+ } catch (e) {
+ this.sortableLetters = [];
+ }
+
this.events.subscribe('SelectedItemInMenu', (menu) => {
if (this.collectionId !== menu.menuID && this.currentOption) {
this.currentOption.selected = false;
this.currentOption = null;
this.cdRef.detectChanges();
+ } else {
+ console.log('this.collectionId', this.collectionId);
}
});
- this.coverSelected = false;
this.titleSelected = false;
+ this.introductionSelected = false;
+ this.coverSelected = false;
try {
- this.hasCover = this.config.getSettings('HasCover');
+ this.hasTitle = this.config.getSettings('HasTitle');
} catch (e) {
- this.hasCover = false;
+ this.hasTitle = false;
}
try {
@@ -313,10 +358,19 @@ export class TableOfContentsAccordionComponent {
this.hasIntro = false;
}
- if ( this.hasCover ) {
- this.coverSelected = true;
- } else if ( this.hasIntro ) {
+ try {
+ this.hasCover = this.config.getSettings('HasCover');
+ } catch (e) {
+ this.hasCover = false;
+ }
+
+ const currentPage = String(window.location.href);
+ if ( currentPage.includes('publication-introduction') ) {
+ this.introductionSelected = true;
+ } else if ( currentPage.includes('publication-title') ) {
this.titleSelected = true;
+ } else if ( currentPage.includes('publication-cover') ) {
+ this.coverSelected = true;
}
this.events.subscribe('tableOfContents:findMarkdownTocItem', (data) => {
@@ -351,19 +405,142 @@ export class TableOfContentsAccordionComponent {
this.unSelectSelectedTocItemEventListener();
}
+ constructAlphabeticalTOC(data) {
+ this.alphabeticalactiveMenuTree = [];
+ this.alphabeticalTitleStack = [];
+ const list = this.flattenList(data.tocItems);
+
+ for (const child of list) {
+ if (child.type !== 'section_title') {
+ this.alphabeticalactiveMenuTree.push(child);
+ }
+ }
+
+ this.alphabeticalactiveMenuTree.sort(
+ (a, b) =>
+ (a.text !== undefined && b.text !== undefined) ?
+ ((String(a.text).toUpperCase() < String(b.text).toUpperCase()) ? -1 :
+ (String(a.text).toUpperCase() > String(b.text).toUpperCase()) ? 1 : 0) : 0
+ );
+ this.storage.set('toc_alfabetical_' + data['collectionID'], this.alphabeticalactiveMenuTree);
+ }
+
+ constructChronologialTOC(data) {
+ this.chronologicalactiveMenuTree = [];
+ this.chronologicalTitleStack = [];
+
+ const list = this.flattenList(data.tocItems);
+
+ for (const child of list) {
+ if (child.date && child.type !== 'section_title') {
+ this.chronologicalactiveMenuTree.push(child);
+ }
+ }
+
+ this.chronologicalactiveMenuTree.sort((a, b) => (a.date < b.date) ? -1 : (a.date > b.date) ? 1 : 0);
+ let prevYear = '';
+
+ const itemArray = [];
+ let childItems = [];
+ for ( let i = 0; i < this.chronologicalactiveMenuTree.length; i++) {
+ const item = this.chronologicalactiveMenuTree[i];
+ const currentYear = String(item['date']).slice(0, 4);
+ if ( prevYear === '' ) {
+ prevYear = currentYear;
+ itemArray.push({type: 'section_title', text: prevYear, subOptions: []});
+ }
+
+ if ( prevYear !== currentYear ) {
+ itemArray[itemArray.length - 1].subOptions = childItems;
+ itemArray[itemArray.length - 1].childrenCount = true;
+ childItems = [];
+ prevYear = currentYear;
+ itemArray.push({type: 'section_title', text: prevYear});
+ }
+ childItems.push(this.chronologicalactiveMenuTree[i]);
+ }
+ if ( itemArray.length > 0 ) {
+ itemArray[itemArray.length - 1].subOptions = childItems;
+ itemArray[itemArray.length - 1].childrenCount = true;
+ } else {
+ itemArray[0] = {};
+ itemArray[0].subOptions = childItems;
+ itemArray[0].childrenCount = true;
+ }
+ this.chronologicalactiveMenuTree = itemArray;
+ this.storage.set('toc_chronological_' + data['collectionID'], this.chronologicalactiveMenuTree);
+ }
+
+ flattenList(data) {
+ data.childrenCount = 0;
+ let list = [data];
+ if (!data.children) {
+ return list;
+ }
+ for (const child of data.children) {
+ list = list.concat(this.flattenList(child));
+ }
+ return list;
+ }
+
+ registerEventListeners() {
+ this.events.subscribe('tableOfContents:loaded', (data) => {
+ this.storage.get('toc_alfabetical_' + data['collectionID']).then((toc) => {
+ if ( toc === null || data['collectionID'] !== toc['collectionID'] ) {
+ this.constructAlphabeticalTOC(data);
+ } else {
+ this.alphabeticalactiveMenuTree = toc;
+ }
+ });
+ this.storage.get('toc_chronologial_' + data['collectionID']).then((toc) => {
+ if ( toc === null || data['collectionID'] !== toc['collectionID'] ) {
+ this.constructChronologialTOC(data);
+ } else {
+ this.chronologicalactiveMenuTree = toc;
+ }
+ });
+ });
+ }
+
+ setActiveSortingType(e) {
+ const thematic = e.target.id === 'thematic' || e.target.parentElement.parentElement.id === 'thematic';
+ const alphabetic = e.target.id === 'alphabetical' || e.target.parentElement.parentElement.id === 'alphabetical';
+ const chronological = e.target.id === 'chronological' || e.target.parentElement.parentElement.id === 'chronological';
+
+ if (thematic) {
+ this.alphabethicOrderActive = false;
+ this.chronologicalOrderActive = false;
+ this.thematicOrderActive = true;
+ } else if (alphabetic) {
+ this.alphabethicOrderActive = true;
+ this.chronologicalOrderActive = false;
+ this.thematicOrderActive = false;
+ } else if (chronological) {
+ this.alphabethicOrderActive = false;
+ this.chronologicalOrderActive = true;
+ this.thematicOrderActive = false;
+ }
+ }
+
ngOnChanges(about) {
if ( Array.isArray(about) ) {
this.menuOptions = about;
this.collapsableItems = new Array();
+ this.activeMenuTree = [];
let foundSelected = false;
// Map the options to our internal models
this.menuOptions.forEach(option => {
const innerMenuOption = InnerMenuOptionModel.fromMenuOptionModel(option, null, false, false);
- this.collapsableItems.push(innerMenuOption);
+ if ( this.collapsableItems.indexOf(innerMenuOption) === -1 ) {
+ this.collapsableItems.push(innerMenuOption);
+ }
+ if ( this.activeMenuTree.indexOf(innerMenuOption) === -1 ) {
+ this.activeMenuTree.push(innerMenuOption);
+ }
// Check if there's any option marked as selected
- if (option.selected) {
+ if (option.selected !== undefined && option.selected === true) {
this.selectedOption = innerMenuOption;
} else if (innerMenuOption.childrenCount) {
innerMenuOption.subOptions.forEach(subItem => {
@@ -411,15 +588,20 @@ export class TableOfContentsAccordionComponent {
if (!data) {
return;
}
+ this.titleSelected = false;
+ this.introductionSelected = false;
+ this.coverSelected = false;
this.currentOption = null;
- if ( this.hasCover ) {
- this.coverSelected = true;
- } else if ( this.hasIntro ) {
+ if ( data.selected === 'title' ) {
this.titleSelected = true;
+ } else if ( data.selected === 'cover' ) {
+ this.coverSelected = true;
+ } else {
+ this.introductionSelected = true;
}
this.unSelectAllItems(this.collapsableItems);
- this.cdRef.detectChanges();
+ // this.cdRef.detectChanges();
});
}
@@ -498,9 +680,7 @@ export class TableOfContentsAccordionComponent {
for (const item of list) {
if (item.subOptions && item.subOptions.length) {
this.findTocByPubOnly(item.subOptions, publicationID);
- } else if (
- item.publication_id &&
- (String(item.publication_id) === String(publicationID) || Number(item.publication_id) === Number(publicationID))
+ } else if ((String(item.itemId) === String(publicationID) || Number(item.publication_id) === Number(publicationID))
) {
item.selected = true;
this.currentOption = item;
@@ -513,8 +693,10 @@ export class TableOfContentsAccordionComponent {
ngOnDestroy() {
this.events.unsubscribe(SideMenuRedirectEvent);
- this.events.unsubscribe('tableOfContents:unSelectSelectedTocItem');
this.events.unsubscribe('SelectedItemInMenu');
+ this.events.unsubscribe('tableOfContents:findMarkdownTocItem');
+ this.events.unsubscribe('tableOfContents:loaded');
+ this.events.unsubscribe('tableOfContents:unSelectSelectedTocItem');
}
// Send the selected option to the caller component
@@ -536,15 +718,17 @@ export class TableOfContentsAccordionComponent {
if (this.isMarkdown) {
this.selectMarkdown(item);
- } else if (this.isGallery) {
+ } else if (item.is_gallery) {
this.selectGallery(item);
- } else {
+ } else if ( item.itemId !== undefined ) {
+
this.storage.set('currentTOCItem', item);
const params = {root: this.options, tocItem: item, collection: {title: item.text}};
const nav = this.app.getActiveNavs();
- this.coverSelected = false;
this.titleSelected = false;
+ this.introductionSelected = false;
+ this.coverSelected = false;
if (item.url) {
params['url'] = item.url;
@@ -604,7 +788,10 @@ export class TableOfContentsAccordionComponent {
this.events.publish('title-logo:show', false);
}
+ console.log('Opening read from TableOfContentsAccordionComponent.openFirstPage()');
nav[0].setRoot('read', params);
+ } else {
+ this.storage.set('currentTOCItem', item);
}
}
@@ -652,7 +839,8 @@ export class TableOfContentsAccordionComponent {
openIntroduction() {
const params = {root: this.root, tocItem: null, collection: {title: 'Introduction'}};
params['collectionID'] = this.collectionId;
- this.titleSelected = true;
+ this.introductionSelected = true;
+ this.titleSelected = false;
this.coverSelected = false;
const nav = this.app.getActiveNavs();
if (this.platform.is('mobile')) {
@@ -666,13 +854,29 @@ export class TableOfContentsAccordionComponent {
const params = {root: this.root, tocItem: null, collection: {title: 'Title Page'}};
params['collectionID'] = this.collectionId;
params['firstItem'] = '1';
- this.coverSelected = true;
+ this.titleSelected = true;
+ this.coverSelected = false;
+ this.introductionSelected = false;
+ const nav = this.app.getActiveNavs();
+ if (this.platform.is('mobile')) {
+ nav[0].push('title-page', params);
+ } else {
+ nav[0].setRoot('title-page', params);
+ }
+ }
+
+ openCoverPage() {
+ const params = {root: this.root, tocItem: null, collection: {title: 'Cover Page'}};
+ params['collectionID'] = this.collectionId;
+ params['firstItem'] = '1';
this.titleSelected = false;
+ this.coverSelected = true;
+ this.introductionSelected = false;
const nav = this.app.getActiveNavs();
if (this.platform.is('mobile')) {
- nav[0].push('cover', params);
+ nav[0].push('cover-page', params);
} else {
- nav[0].setRoot('cover', params);
+ nav[0].setRoot('cover-page', params);
}
}
@@ -701,8 +905,18 @@ export class TableOfContentsAccordionComponent {
exit() {
this.collectionId = null;
this.collectionName = null;
+
+ this.events.publish('exitActiveCollection');
+
+ this.activeMenuTree = [];
+ this.collapsableItems = [];
+
const nav = this.app.getActiveNavs();
nav[0].setRoot('EditionsPage', [], {animate: false, direction: 'back', animation: 'ios-transition'});
+
+ this.alphabethicOrderActive = false;
+ this.chronologicalOrderActive = false;
+ this.thematicOrderActive = false;
}
/**
@@ -721,8 +935,20 @@ export class TableOfContentsAccordionComponent {
targetOption.subOptions = searchChildrenToc[targetOption.search_children_id];
}
}
- // Toggle the selected option
- targetOption.expanded = !targetOption.expanded;
+
+ if ( targetOption.collapsed === undefined || String(targetOption.collapsed) === '' ) {
+ // collapsed is inverted expanded
+ targetOption.collapsed = targetOption.expanded;
+ targetOption.expanded = !targetOption.expanded;
+ } else {
+ // Toggle the selected option
+ targetOption.expanded = targetOption.collapsed;
+ targetOption.collapsed = !targetOption.expanded;
+ }
+
+ if ( targetOption.itemId !== undefined ) {
+ this.select(targetOption);
+ }
}
// Reset the entire menu
@@ -730,11 +956,12 @@ export class TableOfContentsAccordionComponent {
this.collapsableItems.forEach(option => {
if (!option.selected) {
option.expanded = false;
+ option.collapsed = true;
}
if (option.childrenCount) {
option.subOptions.forEach(subItem => {
- if (subItem.selected) {
+ if (subItem.selected || subItem['collapsed'] === false) {
// Expand the parent if any of
// its childs is selected
subItem.parent.expanded = true;
diff --git a/src/components/table-of-contents-drilldown-menu/table-of-contents-drilldown-menu.html b/src/components/table-of-contents-drilldown-menu/table-of-contents-drilldown-menu.html
index 82801711..f8dd28d0 100644
--- a/src/components/table-of-contents-drilldown-menu/table-of-contents-drilldown-menu.html
+++ b/src/components/table-of-contents-drilldown-menu/table-of-contents-drilldown-menu.html
@@ -1,17 +1,33 @@
- 1" (click)="unDrill()" class="back-to-list-button" no-lines>
- {{titleStack[0]}}
-
-
+
+ 0">{{titleStack[0]}}
+
+
+
+ {{ "Read.Back" | translate }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0" shwoWen="core, mobile" [ngClass]="this.coverSelected?'selected':''">
{{ "Read.TitlePage.Title" | translate }}
- 0" [ngClass]="this.titleSelected?'selected':''">
+ 0" [ngClass]="this.introductionSelected?'selected':''">
{{ "Read.Introduction.Title" | translate }}
-
+
{{item.text}}
@@ -19,7 +35,7 @@
-
+
{{item.text}}
diff --git a/src/components/table-of-contents-drilldown-menu/table-of-contents-drilldown-menu.scss b/src/components/table-of-contents-drilldown-menu/table-of-contents-drilldown-menu.scss
index cc8f1b2f..7ea068ec 100644
--- a/src/components/table-of-contents-drilldown-menu/table-of-contents-drilldown-menu.scss
+++ b/src/components/table-of-contents-drilldown-menu/table-of-contents-drilldown-menu.scss
@@ -17,4 +17,26 @@ table-of-contents-drilldown-menu {
white-space: normal;
font-size: 1rem !important;
}
+
+ .collection-filters {
+ ion-label {
+ display: flex;
+ justify-content: space-around;
+
+ button {
+ .button-inner ion-icon {
+ color: #ddd;
+ }
+
+ &.active {
+ background-color:#4a6770;
+ color: #fff;
+
+ &:hover {
+ background-color: #547a86;
+ }
+ }
+ }
+ }
+ }
}
diff --git a/src/components/table-of-contents-drilldown-menu/table-of-contents-drilldown-menu.ts b/src/components/table-of-contents-drilldown-menu/table-of-contents-drilldown-menu.ts
index edb9e936..fb42ff03 100644
--- a/src/components/table-of-contents-drilldown-menu/table-of-contents-drilldown-menu.ts
+++ b/src/components/table-of-contents-drilldown-menu/table-of-contents-drilldown-menu.ts
@@ -6,6 +6,9 @@ import { IntroductionPage } from '../../pages/introduction/introduction';
import { Storage } from '@ionic/storage';
import { TableOfContentsCategory, GeneralTocItem } from '../../app/models/table-of-contents.model';
import { TableOfContentsService } from '../../app/services/toc/table-of-contents.service';
+import { ConfigService, } from '@ngx-config/core';
+import { TocItem } from '../../app/models/toc-item.model';
+
/**
* Class for the TableOfContentsDrilldownMenuComponent component.
@@ -19,8 +22,20 @@ import { TableOfContentsService } from '../../app/services/toc/table-of-contents
})
export class TableOfContentsDrilldownMenuComponent {
root: TableOfContentsCategory[] | any;
- menuStack: any[];
+ visibleMenuStack = [];
+ menuStack = [];
+ thematicMenuStack = [];
+ chronologicalMenuStack = [];
+ chronologicalTitleStack = [];
+ alphabeticalMenuStack: any[];
+
+ chronologicalOrderActive: boolean;
+ thematicOrderActive = true;
+ alphabethicOrderActive: boolean;
+
titleStack: string[];
+ thematicTitleStack: any[];
+ alphabeticalTitleStack: any[];
errorMessage: string;
currentItem: GeneralTocItem;
collectionId: string;
@@ -28,7 +43,11 @@ export class TableOfContentsDrilldownMenuComponent {
titleText: string;
introText: string;
coverSelected: boolean;
- titleSelected: boolean;
+ introductionSelected: boolean;
+
+ sortableLetters = [];
+ letterView = false;
+ visibleTitleStack = [];
constructor(
private events: Events,
@@ -36,14 +55,19 @@ export class TableOfContentsDrilldownMenuComponent {
private app: App,
public platform: Platform,
protected storage: Storage,
- public translate: TranslateService
+ public translate: TranslateService,
+ private config: ConfigService,
) {
// this.open = this.action === 'open' ? true : false;
this.registerEventListeners();
const nav = this.app.getActiveNavs();
this.getTOCItem();
this.coverSelected = false;
- this.titleSelected = false;
+ this.introductionSelected = false;
+ }
+
+ ionViewWillEnter() {
+ this.registerEventListeners();
}
getTOCItem() {
@@ -56,111 +80,198 @@ export class TableOfContentsDrilldownMenuComponent {
});
}
- registerEventListeners() {
- this.events.subscribe('tableOfContents:loaded', (data) => {
- this.getTOCItem();
- this.root = data.tocItems.children;
- this.menuStack = [];
+ setActiveSortingType(e) {
+ const thematic = e.target.id === 'thematic' || e.target.parentElement.parentElement.id === 'thematic';
+ const alphabetic = e.target.id === 'alphabetical' || e.target.parentElement.parentElement.id === 'alphabetical';
+ const chronological = e.target.id === 'chronological' || e.target.parentElement.parentElement.id === 'chronological';
+
+ if (thematic) {
+ this.alphabethicOrderActive = false;
+ this.chronologicalOrderActive = false;
+ this.thematicOrderActive = true;
+ } else if (alphabetic) {
+ this.alphabethicOrderActive = true;
+ this.chronologicalOrderActive = false;
+ this.thematicOrderActive = false;
+ } else if (chronological) {
+ this.alphabethicOrderActive = false;
+ this.chronologicalOrderActive = true;
+ this.thematicOrderActive = false;
+ }
+ }
- if ( data.tocItems.children !== undefined ) {
- this.menuStack.push(data.tocItems.children);
- } else {
- this.menuStack.push(data.tocItems);
- }
+ constructAlphabeticalTOC(data) {
+ this.alphabeticalMenuStack = [];
+ this.alphabeticalTitleStack = [];
+ const list = data.tocItems.children;
- this.collectionId = data.tocItems.collectionId;
- this.collectionName = data.tocItems.text;
-
- this.titleStack = [];
- this.titleStack.push(data.tocItems.text || '');
-
- this.titleText = '';
- this.introText = '';
-
- let pushToMenu = true;
- for (let menuItemIndex = 0; menuItemIndex <= (this.menuStack[0].length - 1); menuItemIndex++) {
- const menuItem = this.menuStack[0][menuItemIndex];
- if ( menuItem.children !== undefined ) {
- for (let menuSubitemIndex = 0; menuSubitemIndex <= (menuItem.children.length - 1); menuSubitemIndex++) {
- const menuSubitem = menuItem.children[menuSubitemIndex];
- if ( this.menuStack[0][menuItemIndex].children[menuSubitemIndex].children !== undefined ) {
- for (let menuSubSubitemIndex = 0;
- menuSubSubitemIndex <= (this.menuStack[0][menuItemIndex].children[menuSubitemIndex].children.length - 1);
- menuSubSubitemIndex++) {
- const menuSubSubitem = menuSubitem.children[menuSubSubitemIndex];
- if ( menuSubSubitem.itemId === data.tocItems.selectedCollId + '_' + data.tocItems.selectedPubId) {
- this.menuStack[0][menuItemIndex].children[menuSubitemIndex].children[menuSubSubitemIndex].selected = true;
- if ( pushToMenu ) {
- this.menuStack.push(this.menuStack[0][menuItemIndex].children);
- this.menuStack.push(this.menuStack[0][menuItemIndex].children[menuSubitemIndex].children);
- this.titleStack.push(this.menuStack[0][menuItemIndex].children[menuSubitemIndex].text);
- pushToMenu = false;
- }
- }
- }
- } else {
- if ( menuSubitem.itemId === data.tocItems.selectedCollId + '_' + data.tocItems.selectedPubId) {
- this.menuStack[0][menuItemIndex].children[menuSubitemIndex].selected = true;
+ for (const child of list) {
+ if (child.date && child.type !== 'section_title') {
+ this.alphabeticalMenuStack.push(child);
+ }
+ }
+
+ this.alphabeticalMenuStack.sort((a, b) =>
+ (a.text.toUpperCase() < b.text.toUpperCase()) ? -1 : (a.text.toUpperCase() > b.text.toUpperCase()) ? 1 : 0);
+ }
+
+ constructChronologialTOC(data) {
+ this.chronologicalMenuStack = [];
+ this.chronologicalTitleStack = [];
+ const list = data.tocItems.children;
+
+ for (const child of list) {
+ if (child.date && child.type !== 'section_title') {
+ this.chronologicalMenuStack.push(child);
+ }
+ }
+
+ this.chronologicalMenuStack.sort((a, b) => (a.date < b.date) ? -1 : (a.date > b.date) ? 1 : 0);
+
+ }
+
+ flattenList(data) {
+ const list = [data];
+ if (!data.children) {
+ return list;
+ }
+
+ for (const child of data.children) {
+ list.concat(this.flattenList(child));
+ }
+ return list;
+ }
+
+ constructToc(data) {
+ this.getTOCItem();
+ this.root = data.tocItems.children;
+ this.menuStack = [];
+
+ if ( data.tocItems.children !== undefined ) {
+ this.menuStack.push(data.tocItems.children);
+ } else {
+ this.menuStack.push(data.tocItems);
+ }
+
+ try {
+ this.sortableLetters = this.config.getSettings('settings.sortableLetters');
+ } catch (e) {
+ this.sortableLetters = null;
+ console.log(e);
+ }
+
+ this.collectionId = data.tocItems.collectionId;
+ this.collectionName = data.tocItems.text;
+
+ this.titleStack = [];
+ this.titleStack.push(data.tocItems.text || '');
+
+ this.titleText = '';
+ this.introText = '';
+
+ let pushToMenu = true;
+ for (let menuItemIndex = 0; menuItemIndex <= (this.menuStack[0].length - 1); menuItemIndex++) {
+ const menuItem = this.menuStack[0][menuItemIndex];
+ if ( menuItem.children !== undefined ) {
+ for (let menuSubitemIndex = 0; menuSubitemIndex <= (menuItem.children.length - 1); menuSubitemIndex++) {
+ const menuSubitem = menuItem.children[menuSubitemIndex];
+ if ( this.menuStack[0][menuItemIndex].children[menuSubitemIndex].children !== undefined ) {
+ for (let menuSubSubitemIndex = 0;
+ menuSubSubitemIndex <= (this.menuStack[0][menuItemIndex].children[menuSubitemIndex].children.length - 1);
+ menuSubSubitemIndex++) {
+ const menuSubSubitem = menuSubitem.children[menuSubSubitemIndex];
+ if ( menuSubSubitem.itemId === data.tocItems.selectedCollId + '_' + data.tocItems.selectedPubId) {
+ this.menuStack[0][menuItemIndex].children[menuSubitemIndex].children[menuSubSubitemIndex].selected = true;
if ( pushToMenu ) {
this.menuStack.push(this.menuStack[0][menuItemIndex].children);
- this.titleStack.push(this.menuStack[0][menuItemIndex].text);
+ this.menuStack.push(this.menuStack[0][menuItemIndex].children[menuSubitemIndex].children);
+ this.titleStack.push(this.menuStack[0][menuItemIndex].children[menuSubitemIndex].text);
pushToMenu = false;
}
}
}
- }
- } else {
- if ( menuItem.itemId === data.tocItems.selectedCollId + '_' + data.tocItems.selectedPubId) {
- this.menuStack[0][menuItemIndex].selected = true;
- if ( pushToMenu ) {
- this.menuStack.push(this.menuStack[0]);
- this.titleStack.push(this.menuStack[0][menuItemIndex].text);
- pushToMenu = false;
+ } else {
+ if ( menuSubitem.itemId === data.tocItems.selectedCollId + '_' + data.tocItems.selectedPubId) {
+ this.menuStack[0][menuItemIndex].children[menuSubitemIndex].selected = true;
+ if ( pushToMenu ) {
+ this.menuStack.push(this.menuStack[0][menuItemIndex].children);
+ this.titleStack.push(this.menuStack[0][menuItemIndex].text);
+ pushToMenu = false;
+ }
}
}
}
+ } else {
+ if ( menuItem.itemId === data.tocItems.selectedCollId + '_' + data.tocItems.selectedPubId) {
+ this.menuStack[0][menuItemIndex].selected = true;
+ if ( pushToMenu ) {
+ this.menuStack.push(this.menuStack[0]);
+ this.titleStack.push(this.menuStack[0][menuItemIndex].text);
+ pushToMenu = false;
+ }
+ }
}
+ }
+
+ if ( data.tocItems.coverSelected !== undefined ) {
+ this.coverSelected = true;
+ } else {
+ this.coverSelected = false;
+ }
+
+ if ( data.tocItems.introductionSelected !== undefined ) {
+ this.introductionSelected = true;
+ } else {
+ this.introductionSelected = false;
+ }
+
+ this.translate.get('Read.TitlePage.Title').subscribe(
+ retData => {
+ this.titleText = retData;
+ }, error => {
- if ( data.tocItems.coverSelected !== undefined ) {
- this.coverSelected = true;
- } else {
- this.coverSelected = false;
}
+ );
+ this.translate.get('Read.Introduction.Title').subscribe(
+ retData => {
+ this.introText = retData;
+ }, error => {
- if ( data.tocItems.titleSelected !== undefined ) {
- this.titleSelected = true;
- } else {
- this.titleSelected = false;
}
+ );
+ };
- this.translate.get('Read.TitlePage.Title').subscribe(
- retData => {
- this.titleText = retData;
- }, error => {
- }
- );
- this.translate.get('Read.Introduction.Title').subscribe(
- retData => {
- this.introText = retData;
- }, error => {
+ registerEventListeners() {
+ this.events.subscribe('tableOfContents:loaded', (data) => {
+ console.log('tableOfContents:loaded in table-of-contents-drilldown.ts');
- }
- );
+ this.constructToc(data);
+ this.constructAlphabeticalTOC(data);
+ this.constructChronologialTOC(data);
+
+
+ this.visibleMenuStack = this.menuStack;
});
}
+ ngOnDestroy() {
+ this.events.unsubscribe('tableOfContents:loaded');
+ }
drillDown(item) {
- this.menuStack.push(item.children);
- this.titleStack.push(item.text);
+ this.visibleMenuStack.push(item.children);
+ this.visibleTitleStack.push(item.text);
}
unDrill() {
- if ( this.menuStack.length === 2 && this.menuStack[0] === this.menuStack[1] ) {
+ if ( this.visibleMenuStack.length === 2 && this.visibleMenuStack[0] === this.visibleMenuStack[1] ) {
this.exit();
}
- this.menuStack.pop();
- this.titleStack.pop();
+ // document.getElementById('contentMenu').classList.add('menu-enabled');
+ // document.getElementById('tableOfContentsMenu').classList.remove('menu-enabled');
+
+ this.visibleMenuStack.pop();
+ this.visibleTitleStack.pop();
}
open(item, type?, html?) {
@@ -171,19 +282,19 @@ export class TableOfContentsDrilldownMenuComponent {
const nav = this.app.getActiveNavs();
this.coverSelected = false;
- this.titleSelected = false;
+ this.introductionSelected = false;
- for (let menuItemIndex = 0; menuItemIndex < this.menuStack.length; menuItemIndex++) {
- const menuItem = this.menuStack[menuItemIndex];
+ for (let menuItemIndex = 0; menuItemIndex < this.visibleMenuStack.length; menuItemIndex++) {
+ const menuItem = this.visibleMenuStack[menuItemIndex];
for (let menuSubitemIndex = 0; menuSubitemIndex < menuItem.length; menuSubitemIndex++) {
const menuSubitem = menuItem[menuSubitemIndex];
- this.menuStack[menuItemIndex].selected = false;
+ this.visibleMenuStack[menuItemIndex].selected = false;
if ( menuSubitem.itemId === item.itemId) {
- this.menuStack[menuItemIndex].selected = true;
- this.menuStack[menuItemIndex][menuSubitemIndex].selected = true;
+ this.visibleMenuStack[menuItemIndex].selected = true;
+ this.visibleMenuStack[menuItemIndex][menuSubitemIndex].selected = true;
} else {
- this.menuStack[menuItemIndex].selected = false;
- this.menuStack[menuItemIndex][menuSubitemIndex].selected = false;
+ this.visibleMenuStack[menuItemIndex].selected = false;
+ this.visibleMenuStack[menuItemIndex][menuSubitemIndex].selected = false;
}
}
}
@@ -201,6 +312,9 @@ export class TableOfContentsDrilldownMenuComponent {
const parts = item.itemId.split('_');
params['collectionID'] = parts[0];
params['publicationID'] = parts[1];
+ if ( parts[2] !== undefined ) {
+ params['chapterID'] = parts[2];
+ }
}
if ( this.currentItem['facsimilePage'] ) {
@@ -234,7 +348,7 @@ export class TableOfContentsDrilldownMenuComponent {
} else {
this.events.publish('title-logo:show', false);
}
-
+ console.log('Opening read from TableOfContentsDrilldownMenuComponent.open()');
nav[0].setRoot('read', params);
try {
@@ -260,9 +374,9 @@ export class TableOfContentsDrilldownMenuComponent {
params['firstItem'] = '1';
const nav = this.app.getActiveNavs();
if (this.platform.is('mobile')) {
- nav[0].push('cover', params);
+ nav[0].push('title-page', params);
} else {
- nav[0].setRoot('cover', params);
+ nav[0].setRoot('title-page', params);
}
}
@@ -275,11 +389,14 @@ export class TableOfContentsDrilldownMenuComponent {
}
private exit() {
+ this.visibleMenuStack = [];
+ this.visibleTitleStack = [];
this.menuStack = [];
- this.titleStack = [];
this.collectionId = null;
this.collectionName = null;
const nav = this.app.getActiveNavs();
nav[0].setRoot('EditionsPage', [], {animate: false, direction: 'back', animation: 'ios-transition'});
+ this.events.publish('exitedTo', 'EditionsPage');
}
}
+
diff --git a/src/components/text-changer/text-changer.html b/src/components/text-changer/text-changer.html
index 4e7f6b14..86c93773 100644
--- a/src/components/text-changer/text-changer.html
+++ b/src/components/text-changer/text-changer.html
@@ -1,7 +1,15 @@
-
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/src/components/text-changer/text-changer.scss b/src/components/text-changer/text-changer.scss
index 46120212..d3f18a69 100644
--- a/src/components/text-changer/text-changer.scss
+++ b/src/components/text-changer/text-changer.scss
@@ -1,5 +1,97 @@
text-changer {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ flex-grow: 2;
.goLeft{
left: 0;
}
+ .forwardBackward {
+ display: flex;
+ grid-template-columns: [first] 30% auto [last] 30%;
+ margin: auto;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ .forwardBackward__currentpage-name {
+ font-size: 15px!important;
+ margin: 0 auto;
+ font-weight: bold;
+ text-align: center;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ }
+
+ .forwardBackward__currentpage-name p{
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ }
+
+ .forwardBackward__previouspage-name,
+ .forwardBackward__nextpage-name {
+ vertical-align: super;
+ margin: 0 0.5rem;
+ &:hover {
+ text-shadow: 1px 0 0 currentColor;
+ }
+ }
+ .forwardButton,
+ .backwardButton {
+ display: flex;
+ align-items: center;
+ hyphens: auto;
+ background: transparent;
+ overflow: hidden;
+ &:hover .forwardBackward__previouspage-name,
+ &:hover .forwardBackward__nextpage-name {
+ text-shadow: 1px 0 0 currentColor;
+ }
+ .forwardBackward__nextpage-name,
+ .forwardBackward__previouspage-name {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ }
+ ion-icon,
+ .forwardBackward__currentpage-name,
+ .forwardBackward__nextpage-name,
+ .forwardBackward__previouspage-name {
+ font-size: 15px!important;
+ }
+ }
+ .forwardButtonDiv {
+ justify-content: flex-end;
+ }
+ .backwardButtonDiv {
+ }
+ }
+ @media screen and (max-width: 800px) {
+ .forwardBackward {
+ max-width: 100%;
+ padding: 0;
+ &__currentpage-name {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ max-width: 70%;
+ }
+ }
+ }
+}
+
+.text-changer-mobile-view {
+ .forwardBackward {
+ position: fixed;
+ max-width: 100vw;
+ width: 100vw;
+ z-index: 9999;
+ background-color: rgba(99,99,99, 0.9);
+ bottom: 0;
+ left: 0;
+ padding: 10px 1em;
+ transform: none;
+ height: 64px;
+ }
}
diff --git a/src/components/text-changer/text-changer.ts b/src/components/text-changer/text-changer.ts
index 11b547cb..9c753a24 100644
--- a/src/components/text-changer/text-changer.ts
+++ b/src/components/text-changer/text-changer.ts
@@ -1,6 +1,7 @@
-import { Component, Input } from '@angular/core';
+import { Component, Input, ChangeDetectorRef } from '@angular/core';
import { Events, App, NavParams } from 'ionic-angular';
import { Storage } from '@ionic/storage';
+import { UserSettingsService } from '../../app/services/settings/user-settings.service';
/**
* Generated class for the TextChangerComponent component.
@@ -18,15 +19,26 @@ export class TextChangerComponent {
@Input() recentlyOpenViews?: any;
prevItem: any;
nextItem: any;
+ lastNext: any;
+ lastPrev: any;
+ prevItemTitle: string;
+ nextItemTitle: string;
+ lastItem: boolean;
+ currentItemTitle: string;
displayNext: Boolean = true;
displayPrev: Boolean = true;
+ flattened: any;
+ currentToc: any;
+
constructor(
public events: Events,
public storage: Storage,
public app: App,
- public params: NavParams
+ public params: NavParams,
+ private userSettingsService: UserSettingsService,
+ private cf: ChangeDetectorRef
) {
this.next(true).then(function(val) {
this.displayNext = val;
@@ -34,21 +46,45 @@ export class TextChangerComponent {
this.previous(true).then(function(val) {
this.displayPrev = val;
}.bind(this))
+ this.flattened = [];
+ this.getTocItemId();
}
ngOnInit() {
+ this.setupData();
}
- async previous(test?: boolean) {
- if ( this.legacyId === undefined ) {
- this.legacyId = this.params.get('collectionID') + '_' + this.params.get('publicationID');
+ setupData() {
+ try {
+ const c_id = this.legacyId.split('_')[0];
+ const toc = this.storage.get('toc_' + c_id);
+ toc.then(val => {
+ this.currentToc = val;
+ if (val && val.children) {
+ for (let i = 0; i < val.children.length; i++) {
+ if (val.children[i].itemId.split('_')[1] === c_id) {
+ this.currentItemTitle = val.children[i].text;
+ this.storage.set('currentTOCItemTitle', this.currentItemTitle);
+ this.nextItemTitle = String(val.children[i + 1].text);
+ this.prevItemTitle = String(val.children[i - 1].text);
+ }
+ }
+ }
+ }).catch(err => console.error(err));
+ } catch ( e ) {
+
}
+ }
+
+ async previous(test?: boolean) {
+ this.getTocItemId();
const c_id = this.legacyId.split('_')[0];
await this.storage.get('toc_' + c_id).then((toc) => {
- this.findItem(toc, 'prev');
+ this.findNext(toc);
});
if (this.prevItem !== undefined && test !== true) {
+ this.storage.set('currentTOCItem', this.prevItem);
await this.open(this.prevItem);
} else if (test && this.prevItem !== undefined) {
return true;
@@ -58,14 +94,13 @@ export class TextChangerComponent {
}
async next(test?: boolean) {
- if ( this.legacyId === undefined ) {
- this.legacyId = this.params.get('collectionID') + '_' + this.params.get('publicationID');
- }
+ this.getTocItemId();
const c_id = this.legacyId.split('_')[0];
await this.storage.get('toc_' + c_id).then((toc) => {
- this.findItem(toc, 'next');
+ this.findNext(toc);
});
if (this.nextItem !== undefined && test !== true) {
+ this.storage.set('currentTOCItem', this.nextItem);
await this.open(this.nextItem);
} else if (test && this.nextItem !== undefined) {
return true;
@@ -74,68 +109,98 @@ export class TextChangerComponent {
}
}
- findItem(toc, type?: string) {
- if (!toc) {
- return;
+ getTocItemId() {
+ if ( this.legacyId === undefined ) {
+ this.legacyId = this.params.get('collectionID') + '_' + this.params.get('publicationID') ;
}
- if (!toc.children && toc instanceof Array) {
- for (let i = 0; i < toc.length; i ++) {
- if (toc[i].itemId && toc[i].itemId === this.legacyId) {
- if (type === 'next' && toc[i + 1]) {
- if (toc[i + 1].type === 'subtitle') {
- i = i + 1;
- }
- if (toc[i + 1] === undefined || i + 1 === toc.length) {
- if ( (i + 1) === toc.length ) {
- this.nextItem = null;
- break;
- }
- } else {
- this.nextItem = toc[i + 1];
- break;
- }
- } else if (type === 'prev' && toc[i - 1]) {
- if (toc[i - 1].type === 'subtitle') {
- i = i - 1;
- }
- if (toc[i - 1] === undefined || i === 0) {
- if ( i === 0 ) {
- this.prevItem = null;
- break;
- }
- } else {
- this.prevItem = toc[i - 1];
- break;
- }
- }
- }
+ if ( this.params.get('chapterID') !== undefined &&
+ String(this.legacyId).indexOf(this.params.get('chapterID')) === -1 &&
+ String(this.params.get('chapterID')).indexOf('ch') >= 0 ) {
+ this.legacyId += '_' + this.params.get('chapterID');
+ }
+
+ if ( this.params.get('tocLinkId') !== undefined ) {
+ this.legacyId = this.params.get('tocLinkId');
+ }
+ }
+
+ findNext(toc) {
+ this.getTocItemId();
+ // flatten the toc structure
+ if ( this.flattened.length === 0 ) {
+ this.flatten(toc);
+ }
+ // get the next id
+ let currentId = 0;
+ for (let i = 0; i < this.flattened.length; i ++) {
+ if ( this.flattened[i].itemId === this.legacyId ) {
+ currentId = i;
+ break;
}
- } else if (toc.children) {
- const childs = toc.children;
- for (let j = 0; j < childs.length; j ++) {
- if (childs[j] && childs[j].itemId && childs[j].itemId === this.legacyId) {
+ }
+ let nextId, prevId = 0;
+ // last item
+ if ((currentId + 1) === this.flattened.length) {
+ nextId = 0;
+ } else {
+ nextId = currentId + 1;
+ }
+
+ if (currentId === 0) {
+ prevId = this.flattened.length - 1;
+ } else {
+ prevId = currentId - 1;
+ }
+
+ this.nextItem = this.flattened[nextId];
+ this.nextItemTitle = String(this.nextItem.text);
+ this.prevItem = this.flattened[prevId];
+ this.prevItemTitle = String(this.prevItem.text);
+ this.currentItemTitle = String(this.flattened[currentId].text);
+ this.storage.set('currentTOCItemTitle', this.currentItemTitle);
+ }
+
+ flatten(toc) {
+ if ( toc.children ) {
+ for (let i = 0, count = toc.children.length; i < count; i++) {
+ if ( toc.children[i].itemId !== undefined && toc.children[i].itemId !== '') {
+ this.flattened.push(toc.children[i]);
}
- if (childs[j] && childs[j].children) {
- this.findItem(childs[j].children, type);
+ this.flatten(toc.children[i]);
+ }
+ }
+ }
+
+ findPrevTitle(toc, currentIndex, prevChild?) {
+ if ( currentIndex === 0 ) {
+ this.findPrevTitle(prevChild, prevChild.length);
+ }
+ for ( let i = currentIndex; i > 0; i-- ) {
+ if ( toc[i - 1] !== undefined ) {
+ if ( toc[i - 1].title !== 'subtitle' && toc[i - 1].title !== 'section_title' ) {
+ return toc[i - 1];
}
}
}
}
open(item) {
- const params = {tocItem: item, collection: {title: item.text}};
+ const params = {tocItem: item, collection: {title: item.itemId}};
const nav = this.app.getActiveNavs();
params['tocLinkId'] = item.itemId;
const parts = item.itemId.split('_');
params['collectionID'] = parts[0];
params['publicationID'] = parts[1];
+ if ( parts[2] !== undefined ) {
+ params['chapterID'] = parts[2];
+ }
if (this.recentlyOpenViews !== undefined && this.recentlyOpenViews.length > 0) {
params['recentlyOpenViews'] = this.recentlyOpenViews;
}
-
+ console.log('Opening read from TextChanged.open()');
nav[0].setRoot('read', params);
}
diff --git a/src/components/title-logo/title-logo.ts b/src/components/title-logo/title-logo.ts
index 5a45cb47..fe658f0e 100644
--- a/src/components/title-logo/title-logo.ts
+++ b/src/components/title-logo/title-logo.ts
@@ -48,4 +48,8 @@ export class TitleLogoComponent {
this.subtitle = subTitle;
});
}
+ ngOnDestroy() {
+ this.events.unsubscribe('title-logo:setTitle');
+ this.events.unsubscribe('title-logo:collectionTitle');
+ }
}
diff --git a/src/components/toc-menu/toc-menu.ts b/src/components/toc-menu/toc-menu.ts
index 2713c4ff..8eb3cd25 100644
--- a/src/components/toc-menu/toc-menu.ts
+++ b/src/components/toc-menu/toc-menu.ts
@@ -76,6 +76,7 @@ export class TocMenuComponent {
params['legacyId'] = item.id;
const nav = this.app.getActiveNavs();
+ console.log('Opening read from TocMenu.openRead()');
nav[0].setRoot('read', params);
}
diff --git a/src/components/top-menu/top-menu.html b/src/components/top-menu/top-menu.html
index 4c6c7da5..601cf7e2 100644
--- a/src/components/top-menu/top-menu.html
+++ b/src/components/top-menu/top-menu.html
@@ -21,8 +21,14 @@
-
-{{toolTipText}}
-
{
- if (event.target.classList.contains('variantScrollTarget') && this.readPopoverService.show.comments ) {
- if (event.target !== undefined) {
- event.target.style.fontWeight = 'bold';
- this.showTooltip(event);
- this.scrollToElement(event.target);
- }
- setTimeout(function() {
- if (event.target !== undefined) {
- event.target.style.fontWeight = 'normal';
- }
- }, 1000);
- }
- if (event.target.classList.contains('tooltiptrigger') && this.readPopoverService.show.comments ) {
- if (event.target !== undefined) {
- event.target.style.fontWeight = 'bold';
- }
- setTimeout(function() {
- if (event.target !== undefined) {
- event.target.style.fontWeight = 'normal';
- }
- }, 1000);
- }
- });
- this.renderer.listen(this.elementRef.nativeElement, 'mouseover', (event) => {
- if (event.target.classList.contains('tooltiptrigger') && this.readPopoverService.show.comments ) {
- if (event.target !== undefined) {
- event.target.style.fontWeight = 'bold';
- this.showTooltip(event);
- }
- setTimeout(function() {
- if (event.target !== undefined) {
- event.target.style.fontWeight = 'normal';
- }
- }, 1000);
- }
- });
- }
-
- private scrollToElement(element: HTMLElement) {
- element.scrollIntoView();
- try {
- const elems: NodeListOf
= document.querySelectorAll('span');
- for (let i = 0; i < elems.length; i++) {
- if ( elems[i].id === element.id ) {
- elems[i].scrollIntoView();
- }
- }
- } catch ( e ) {
-
- }
- }
-
- showTooltip(origin: any) {
- if ( origin.target.nextSibling.className !== undefined && String(origin.target.nextSibling.className).includes('tooltip') ) {
- this.toolTipPosition = {top: (origin.target.offsetTop - ( origin.target.offsetHeight / 2 ) + 4) +
- 'px', left: (origin.target.offsetLeft + origin.target.offsetWidth + 4) + 'px'};
- this.showToolTip = true;
- this.toolTipText = origin.target.nextSibling.textContent;
- setTimeout(() => {
- this.showToolTip = false;
- this.toolTipText = '';
- }, 5000);
- }
- }
-
getVariation() {
this.textService.getVariations(this.itemId).subscribe(
res => {
@@ -168,15 +95,13 @@ export class VariationsComponent {
setVariation() {
const inputFilename = this.linkID + '.xml'
const inputVariation = this.variations.filter(function(item) {
- return (item.id === this.linkID || item.legacy_id === this.linkID);
+ return (item.id + '' === this.linkID + '' || item.legacy_id + '' === this.linkID + '');
}.bind(this))[0];
-
if (this.linkID && this.linkID !== undefined && inputVariation !== undefined ) {
this.selectedVariation = inputVariation;
} else {
this.selectedVariation = this.variations[0];
}
-
this.changeVariation();
}
diff --git a/src/config-sample.json b/src/config-sample.json
index 33d26ca0..3ef198ad 100644
--- a/src/config-sample.json
+++ b/src/config-sample.json
@@ -1,342 +1,491 @@
{
- "app": {
- "readContent": "...",
- "machineName": "topelius",
- "useLegacyIdsForSemanticData": false,
- "legacyIdPrefix": "",
- "apiEndpoint": "http://api.sls.fi:8000/digitaledition",
- "showViewToggle": false,
- "showTopURNButton": false,
- "showTopMusicButton": false,
- "page-title": {
- "sv": "",
- "fi": "",
- "en": ""
- },
- "name": {
- "sv": "Zacharias Topelius Skrifter",
- "fi": "Zacharias Topeliuksen Kirjoitukset",
- "en": "Zacharias Topeliuksen Kirjoitukset"
- },
- "subTitle1": {
- "sv": "Inte en dag utan en rad",
- "fi": "Fi: Författaren, redaktören, professorn och privatpersonen Zacharias Topelius verk i en textkritisk och kommenterad digital utgåva.",
- "en": "Zacharias Topeliuksen Kirjoitukset"
- },
- "subTitle2": {
- "sv": "Författaren, redaktören, professorn och privatpersonen Zacharias Topelius verk i en textkritisk och kommenterad digital utgåva.",
- "fi": "Fi: Författaren, redaktören, professorn och privatpersonen Zacharias Topelius verk i en textkritisk och kommenterad digital utgåva.",
- "en": "Zacharias Topeliuksen Kirjoitukset"
- }
- },
- "TutorialSteps": [
- {
- "id": "welcome",
- "intro": "WelcomeText",
- "show": true,
- "alreadySeen": false,
- "hideOn": [],
- "showOn": []
- },
- {
- "id": "menu",
- "element": "#menuToggle",
- "intro": "MenuToggleText",
- "show": true,
- "alreadySeen": false,
- "hideOn": [],
- "showOn": []
- },
- {
- "id": "readtoc",
- "element": "#readTocItem",
- "intro": "ReadTocItemText",
- "show": true,
- "alreadySeen": false,
- "hideOn": [
- "HomePage"
- ],
- "showOn": []
- },
- {
- "id": "downloadCache",
- "element": "#downloadPerson",
- "intro": "DownloadCacheText",
- "show": false,
- "alreadySeen": false,
- "hideOn": [],
- "showOn": [
- "PersonSearchPage"
- ]
- }
- ],
- "settings": {
- "readToggles": {
- "comments": true,
- "personInfo": true,
- "placeInfo": true,
- "changes": true,
- "abbreviations": true,
- "pageNumbering": true,
- "pageBreakOriginal": true,
- "pageBreakEdition": true
- },
- "displayTypesToggles": {
- "showAll": true,
- "established": true,
- "comments": true,
- "manuscripts": true,
- "variations": true,
- "facsimiles": true,
- "introduction": true,
- "songexample": false
+ "app": {
+ "readContent": "...",
+ "machineName": "topelius",
+ "projectId": 10,
+ "useLegacyIdsForSemanticData": false,
+ "legacyIdPrefix": "",
+ "apiEndpoint": "http://api.sls.fi:8000/digitaledition",
+ "showViewToggle": false,
+ "showTopURNButton": false,
+ "showTopElasticButton": false,
+ "showTopMusicButton": false,
+ "page-title": {
+ "sv": "",
+ "fi": "",
+ "en": ""
+ },
+ "name": {
+ "sv": "Zacharias Topelius Skrifter",
+ "fi": "Zacharias Topeliuksen Kirjoitukset",
+ "en": "Zacharias Topeliuksen Kirjoitukset"
+ },
+ "subTitle1": {
+ "sv": "Inte en dag utan en rad",
+ "fi": "Fi: Författaren, redaktören, professorn och privatpersonen Zacharias Topelius verk i en textkritisk och kommenterad digital utgåva.",
+ "en": "Zacharias Topeliuksen Kirjoitukset"
+ },
+ "subTitle2": {
+ "sv": "Författaren, redaktören, professorn och privatpersonen Zacharias Topelius verk i en textkritisk och kommenterad digital utgåva.",
+ "fi": "Fi: Författaren, redaktören, professorn och privatpersonen Zacharias Topelius verk i en textkritisk och kommenterad digital utgåva.",
+ "en": "Zacharias Topeliuksen Kirjoitukset"
+ },
+ "CollectionSortOrder": {}
},
- "enableModeToggle": true,
- "getFacsimilePagesInfinite": false
- },
- "i18n": {
- "languages": [
- "sv",
- "en"
- ],
- "locale": "sv",
- "enableLanguageChanges": true
- },
- "collectionDownloads": {
- "isDownloadOnly": false,
- "pdf": [
- {
- "pdfFile": "12_3456_sample.pdf",
- "thumbnail": "12_3456.png",
- "title": "Sample PDF title",
- "collectionId": "12",
- "facsimileId": "789",
- "publicationId": "3456",
- "child": false
- }
+ "showTutorial": false,
+ "TutorialSteps": [{
+ "id": "welcome",
+ "intro": "WelcomeText",
+ "show": true,
+ "alreadySeen": false,
+ "hideOn": [],
+ "showOn": []
+ },
+ {
+ "id": "menu",
+ "element": "#menuToggle",
+ "intro": "MenuToggleText",
+ "show": true,
+ "alreadySeen": false,
+ "hideOn": [],
+ "showOn": []
+ },
+ {
+ "id": "readtoc",
+ "element": "#readTocItem",
+ "intro": "ReadTocItemText",
+ "show": true,
+ "alreadySeen": false,
+ "hideOn": [
+ "HomePage"
+ ],
+ "showOn": []
+ },
+ {
+ "id": "downloadCache",
+ "element": "#downloadPerson",
+ "intro": "DownloadCacheText",
+ "show": false,
+ "alreadySeen": false,
+ "hideOn": [],
+ "showOn": [
+ "PersonSearchPage"
+ ]
+ }
],
- "epub": {}
- },
- "simpleSearch": {
- "showPageNumbers": false,
- "user_defined_search_fields": [
- "textData"
- ]
- },
- "editionImages": {
- "default": "assets/images/edition-default-cover.jpg",
- "1": "assets/images/omslag_1.jpg",
- "4": "assets/images/omslag_4.jpg",
- "5": "assets/images/omslag_4.jpg",
- "10": "assets/images/omslag_10.jpg",
- "12": "assets/images/omslag_12.jpg",
- "13": "assets/images/omslag_13.jpg",
- "15": "assets/images/omslag_15.jpg",
- "20": "assets/images/omslag_20.jpg"
- },
- "editionShortTexts": {
- "sv": {
- "default": "En undertitel med lite data...",
- "1": "Tidiga dikter",
- "15": "Korrespondens med förlag och förläggare",
- "4": "Tolv noveller, ursprungligen publicerade som följetonger",
- "5": "Fyra historiska noveller",
- "12": "Historiskt-geografiskt bildverk",
- "13": "Historiskt-geografiskt bildverk",
- "10": "Läseböcker för folkskolan",
- "20": " "
+ "settings": {
+ "readToggles": {
+ "comments": true,
+ "personInfo": true,
+ "placeInfo": true,
+ "workInfo": true,
+ "changes": true,
+ "abbreviations": true,
+ "pageNumbering": true,
+ "pageBreakOriginal": true,
+ "pageBreakEdition": true
+ },
+ "displayTypesToggles": {
+ "showAll": true,
+ "established": true,
+ "comments": true,
+ "manuscripts": true,
+ "variations": true,
+ "facsimiles": true,
+ "introduction": true,
+ "songexample": false
+ },
+ "toolTips": {
+ "comments": true,
+ "personInfo": true,
+ "placeInfo": true,
+ "changes": true,
+ "variations": true,
+ "abbreviations": true,
+ "workInfo": true,
+ "footNotes": true
+ },
+ "enableModeToggle": true,
+ "getFacsimilePagesInfinite": false,
+ "showReadTextIllustrations": [],
+ "galleryCollectionMapping": {"214": 44},
+ "facsimileDefaultZoomLevel": 3
},
- "fi": {
- "default": "FI - En undertitel med lite data...",
- "1": "FI - Tidiga dikter",
- "15": "FI - Korrespondens med förlag och förläggare",
- "4": "FI - Tolv noveller, ursprungligen publicerade som följetonger",
- "5": "FI - Fyra historiska noveller"
+ "i18n": {
+ "languages": [
+ "sv",
+ "en"
+ ],
+ "locale": "sv",
+ "enableLanguageChanges": true
},
- "en": {
- "default": "a Subtitle...",
- "29": "Hilma Granqvists Diaries",
- "30": "Download PDF",
- "31": "Download PDF2"
- }
- },
- "single-editions": {
- "sv": {
- "toc": "Innehåll"
+ "collectionDownloads": {
+ "isDownloadOnly": false,
+ "pdf": [{
+ "pdfFile": "12_3456_sample.pdf",
+ "thumbnail": "12_3456.png",
+ "title": "Sample PDF title",
+ "collectionId": "12",
+ "facsimileId": "789",
+ "publicationId": "3456",
+ "child": false
+ }],
+ "epub": {}
},
- "fi": {
- "toc": "Lue digitaalisesti"
- }
- },
- "staticPages": {
- "about_index": 0,
- "frontpage": {
- "sv": {
- "name": "Hem",
- "file": "frontpage-sv"
- },
- "fi": {
- "name": "Koti",
- "file": "frontpage-fi"
- }
+ "simpleSearch": {
+ "showPageNumbers": false,
+ "user_defined_search_fields": [
+ "textData"
+ ]
},
- "editions": {
- "sv": {
- "name": "Läs digitalt",
- "file": "editions-sv"
- },
- "fi": {
- "name": "Lue digitaalisesti",
- "file": "editions-fi"
- }
+ "editionImages": {
+ "default": "assets/images/edition-default-cover.jpg",
+ "1": "assets/images/omslag_1.jpg",
+ "4": "assets/images/omslag_4.jpg",
+ "5": "assets/images/omslag_4.jpg",
+ "10": "assets/images/omslag_10.jpg",
+ "12": "assets/images/omslag_12.jpg",
+ "13": "assets/images/omslag_13.jpg",
+ "15": "assets/images/omslag_15.jpg",
+ "20": "assets/images/omslag_20.jpg"
},
- "about": [
- {
+ "editionShortTexts": {
"sv": {
- "name": "Om utgåvan",
- "file": "about--about-edition-sv"
+ "default": "En undertitel med lite data...",
+ "1": "Tidiga dikter",
+ "15": "Korrespondens med förlag och förläggare",
+ "4": "Tolv noveller, ursprungligen publicerade som följetonger",
+ "5": "Fyra historiska noveller",
+ "12": "Historiskt-geografiskt bildverk",
+ "13": "Historiskt-geografiskt bildverk",
+ "10": "Läseböcker för folkskolan",
+ "20": " "
},
"fi": {
- "name": "Testi",
- "file": "about--about-edition-fi"
- }
- },
- {
- "sv": {
- "name": "Rättelser och tillägg",
- "file": "about--corrections-and-additions-sv"
+ "default": "FI - En undertitel med lite data...",
+ "1": "FI - Tidiga dikter",
+ "15": "FI - Korrespondens med förlag och förläggare",
+ "4": "FI - Tolv noveller, ursprungligen publicerade som följetonger",
+ "5": "FI - Fyra historiska noveller"
},
- "fi": {
- "name": "Testi",
- "file": "about--corrections-and-additions-fi"
+ "en": {
+ "default": "a Subtitle...",
+ "29": "Hilma Granqvists Diaries",
+ "30": "Download PDF",
+ "31": "Download PDF2"
}
- },
- {
+ },
+ "single-editions": {
"sv": {
- "name": "Om mobilversionen",
- "file": "about--mobile-limitations-sv"
+ "toc": "Innehåll"
},
"fi": {
- "name": "Testi",
- "file": "about--mobile-limitations-fi"
+ "toc": "Lue digitaalisesti"
}
- },
- {
- "sv": {
- "name": "Organisation och kontakt",
- "file": "about--organisation-and-contact-sv"
+ },
+ "staticPages": {
+ "about_index": 0,
+ "frontpage": {
+ "sv": {
+ "name": "Hem",
+ "file": "frontpage-sv"
+ },
+ "fi": {
+ "name": "Koti",
+ "file": "frontpage-fi"
+ }
},
- "fi": {
- "name": "Testi",
- "file": "about--organisation-and-contact-fi"
- }
- },
- {
- "sv": {
- "name": "Om Topelius",
- "file": "about--about-author-sv"
+ "editions": {
+ "sv": {
+ "name": "Läs digitalt",
+ "file": "editions-sv"
+ },
+ "fi": {
+ "name": "Lue digitaalisesti",
+ "file": "editions-fi"
+ }
},
- "fi": {
- "name": "Testi",
- "file": "about--organisation-and-contact-fi"
+ "about": [{
+ "sv": {
+ "name": "Om utgåvan",
+ "file": "about--about-edition-sv"
+ },
+ "fi": {
+ "name": "Testi",
+ "file": "about--about-edition-fi"
+ }
+ },
+ {
+ "sv": {
+ "name": "Rättelser och tillägg",
+ "file": "about--corrections-and-additions-sv"
+ },
+ "fi": {
+ "name": "Testi",
+ "file": "about--corrections-and-additions-fi"
+ }
+ },
+ {
+ "sv": {
+ "name": "Om mobilversionen",
+ "file": "about--mobile-limitations-sv"
+ },
+ "fi": {
+ "name": "Testi",
+ "file": "about--mobile-limitations-fi"
+ }
+ },
+ {
+ "sv": {
+ "name": "Organisation och kontakt",
+ "file": "about--organisation-and-contact-sv"
+ },
+ "fi": {
+ "name": "Testi",
+ "file": "about--organisation-and-contact-fi"
+ }
+ },
+ {
+ "sv": {
+ "name": "Om Topelius",
+ "file": "about--about-author-sv"
+ },
+ "fi": {
+ "name": "Testi",
+ "file": "about--organisation-and-contact-fi"
+ }
+ }
+ ]
+ },
+ "galleryImages": {
+ "0": {
+ "prefix": "FFiT_",
+ "numberOfImages": 120
+ },
+ "1": {
+ "prefix": "ERiF_",
+ "numberOfImages": 39
+ },
+ "2": {
+ "prefix": "foo_",
+ "numberOfImages": 0
+ }
+ },
+ "show": {
+ "TOC": {
+ "Home": true,
+ "About": true,
+ "Read": true,
+ "Facsimiles": true,
+ "ImageGallery": true,
+ "MediaCollections": true,
+ "PersonSearch": true,
+ "PlaceSearch": true,
+ "TagSearch": true,
+ "WorkSearch": true,
+ "SongTypes": false,
+ "Books": false,
+ "splitReadCollections":[]
+ }
+ },
+ "defaults": {
+ "ReadModeView": "established"
+ },
+ "cache": {
+ "viewmodes": {
+ "daysUntilExpires": 2
}
- }
- ]
- },
- "galleryImages": {
- "0": {
- "prefix": "FFiT_",
- "numberOfImages": 120
},
- "1": {
- "prefix": "ERiF_",
- "numberOfImages": 39
+ "PersonSearchTypes": [{
+ "object_type": "subject",
+ "object_subtype": "",
+ "translation": "TOC.PersonSearch"
+ }],
+ "ImageGallery": {
+ "ShowInReadMenu": true
+ },
+ "PersonSearch": {
+ "ShowFilter": true,
+ "ShowPublishedStatus": 2
+ },
+ "LocationSearch": {
+ "ShowFilter": true,
+ "ShowPublishedStatus": 2
+ },
+ "TagSearch": {
+ "ShowFilter": true,
+ "ShowPublishedStatus": 2
+ },
+ "StaticPagesMenus": [{
+ "menuID": "aboutMenu",
+ "idNumber": "03",
+ "hasMenuConditional": false,
+ "initialAboutPage": "03-01-01"
+ }],
+ "Occurrences": {
+ "HideTypeAndDescription": false,
+ "ShowPublishedStatus": 2
+ },
+ "StaticPagesMenusInTOC": [],
+ "GoogleAnalyticsId": "UA-1298100167-1",
+ "LoadCollectionsFromAssets": false,
+ "LoadTitleFromDB": true,
+ "StaticMarkdownCovers": false,
+ "ProjectStaticMarkdownCoversFolder": "08",
+ "ProjectStaticMarkdownTitleFolder": "05",
+ "showOccurencesModalOnReadPageAfterSearch": {
+ "tagSearch": true,
+ "personSearch": false,
+ "placeSearch": false
+ },
+ "SortCollectionsByRomanNumerals": false,
+ "AccordionTOC": false,
+ "AccordionMusic": false,
+ "SearchTocItemInAccordionByTitle": false,
+ "AccordionsExpandedDefault": {
+ "SongTypes": false,
+ "Music": false
+ },
+ "MusicAccordion": {
+ "PersonSearchTypes": false,
+ "TagSearch": false,
+ "PlaceSearch": false,
+ "Music": false
+ },
+ "HasCover": true,
+ "HasTitle": true,
+ "HasIntro": true,
+ "SidemenuMobile": true,
+ "OpenOccurrencesAndInfoOnNewPage": false,
+ "SingleOccurrenceType": null,
+ "HideBackButton": {
+ "TopMenu": true
+ },
+ "MusicPage": {
+ "collectionsToShow": []
+ },
+ "separeateIntroductionToc": false,
+ "ElasticSearch": {
+ "indices": [
+ "topelius"
+ ],
+ "fixedFilters": [{
+ "terms": {
+ "publication_data.published": [
+ 2
+ ]
+ }
+ }],
+ "types": [
+ "est",
+ "com",
+ "var",
+ "inl",
+ "tit",
+ "ms"
+ ],
+ "hitsPerPage": 20,
+ "source": [
+ "xml_type",
+ "TitleIndexed",
+ "publication_data",
+ "publication_locations",
+ "publication_subjects",
+ "publication_tags",
+ "name",
+ "collection_name",
+ "orig_date_year_uncertain",
+ "orig_date_certain",
+ "receiver_subject_name",
+ "sender_subject_name",
+ "receiver_location_name",
+ "sender_location_name"
+ ],
+ "aggregations": {
+ "Years": {
+ "date_histogram": {
+ "field": "orig_date_certain",
+ "calendar_interval": "year",
+ "format": "yyyy"
+ }
+ },
+ "Type": {
+ "terms": {
+ "field": "xml_type.keyword",
+ "size": 40
+ }
+ },
+ "Genre": {
+ "terms": {
+ "field": "publication_data.genre.keyword",
+ "size": 40
+ }
+ },
+ "Collection": {
+ "terms": {
+ "field": "publication_data.colname.keyword",
+ "size": 40
+ }
+ },
+ "Location": {
+ "terms": {
+ "field": "publication_locations.keyword",
+ "size": 40
+ }
+ },
+ "Subjects": {
+ "terms": {
+ "field": "publication_subjects.keyword",
+ "size": 40
+ }
+ },
+ "Tags": {
+ "terms": {
+ "field": "publication_tags.keyword",
+ "size": 40
+ }
+ },
+ "Person": {
+ "terms": {
+ "field": "persName.keyword",
+ "size": 40
+ }
+ },
+ "LetterSenderName": {
+ "terms": {
+ "field": "sender_subject_name.keyword",
+ "size": 40
+ }
+ },
+ "LetterReceiverName": {
+ "terms": {
+ "field": "receiver_subject_name.keyword",
+ "size": 40
+ }
+ },
+ "LetterSenderLocation": {
+ "terms": {
+ "field": "sender_location_name.keyword",
+ "size": 40
+ }
+ },
+ "LetterReceiverLocation": {
+ "terms": {
+ "field": "receiver_location_name.keyword",
+ "size": 40
+ }
+ }
+ },
+ "suggestions": {
+ "LetterSenderName": {
+ "field": "sender_subject_name",
+ "size": 3
+ },
+ "LetterSenderLocation": {
+ "field": "sender_location_name",
+ "size": 3
+ }
+ }
},
- "2": {
- "prefix": "foo_",
- "numberOfImages": 0
- }
- },
- "show": {
- "TOC": {
- "Home": true,
- "About": true,
- "Read": true,
- "Facsimiles": true,
- "ImageGallery": true,
- "PersonSearch": true,
- "PlaceSearch": true,
- "TagSearch": true,
- "WorkSearch": true,
- "SongTypes": false,
- "Books": false
- }
- },
- "defaults": {
- "ReadModeView": "established"
- },
- "cache": {
- "viewmodes": {
- "daysUntilExpires": 2
- }
- },
- "PersonSearchTypes": [
- {
- "object_type": "subject",
- "object_subtype": "",
- "translation": "TOC.PersonSearch"
- }
- ],
- "PersonSearch": {
- "ShowFilter": true
- },
- "LocationSearch": {
- "ShowFilter": true
- },
- "TagSearch": {
- "ShowFilter": true
- },
- "StaticPagesMenus": [
- {
- "menuID": "aboutMenu",
- "idNumber": "03",
- "hasMenuConditional": false
- }
- ],
- "StaticPagesMenusInTOC": [],
- "GoogleAnalyticsId": "UA-1298100167-1",
- "LoadCollectionsFromAssets": false,
- "LoadTitleFromDB": true,
- "StaticMarkdownCovers": false,
- "ProjectStaticMarkdownCoversFolder": "05",
- "showOccurencesModalOnReadPageAfterSearch": {
- "tagSearch": true,
- "personSearch": false,
- "placeSearch": false
- },
- "SortCollectionsByRomanNumerals": false,
- "AccordionTOC": false,
- "AccordionMusic": false,
- "SearchTocItemInAccordionByTitle": false,
- "AccordionsExpandedDefault": {
- "SongTypes": false,
- "Music": false
- },
- "MusicAccordion": {
- "PersonSearchTypes": false,
- "TagSearch": false,
- "PlaceSearch": false,
- "Music": false
- },
- "HasCover": true,
- "HasIntro": true,
- "SidemenuMobile": true,
- "OpenOccurrencesAndInfoOnNewPage": false,
- "SingleOccurrenceType": null,
- "HideBackButton": {
- "TopMenu": true
- },
- "MusicPage": {
- "collectionsToShow": []
- }
+ "OpenCollectionFromToc": true
}
diff --git a/src/pages/content/content.ts b/src/pages/content/content.ts
index 9c186fc1..0f09b961 100644
--- a/src/pages/content/content.ts
+++ b/src/pages/content/content.ts
@@ -73,6 +73,9 @@ export class ContentPage /*implements OnDestroy*/ {
this.songCategoriesConfig();
}
+ ngOnDestroy() {
+ this.events.unsubscribe('language:change');
+ }
songCategoriesConfig() {
try {
this.songCategories = this.config.getSettings(`SongCategories.${this.lang}`);
diff --git a/src/pages/cover/cover.module.ts b/src/pages/cover/cover.module.ts
index 543e6320..1d7a9c59 100644
--- a/src/pages/cover/cover.module.ts
+++ b/src/pages/cover/cover.module.ts
@@ -1,6 +1,7 @@
import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { CoverPage } from './cover';
+
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { ComponentsModule } from '../../components/components.module';
@@ -11,7 +12,6 @@ export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
-
@NgModule({
declarations: [
CoverPage,
diff --git a/src/pages/cover/cover.scss b/src/pages/cover/cover.scss
index 3dfcc8c7..c348defd 100644
--- a/src/pages/cover/cover.scss
+++ b/src/pages/cover/cover.scss
@@ -1,13 +1,3 @@
page-cover {
- ion-card {
- width: 75%;
- max-width: 830px;
- background-color: #fff;
- }
-
- p {
- font-family: $font-read-column-p;
- padding-top: 1rem;
- }
-}
\ No newline at end of file
+}
diff --git a/src/pages/cover/cover.ts b/src/pages/cover/cover.ts
index ed99f17d..6abc3098 100644
--- a/src/pages/cover/cover.ts
+++ b/src/pages/cover/cover.ts
@@ -1,6 +1,7 @@
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, Events } from 'ionic-angular';
import { DomSanitizer } from '@angular/platform-browser';
+import { Storage } from '@ionic/storage';
import { LanguageService } from '../../app/services/languages/language.service';
import { TextService } from '../../app/services/texts/text.service';
import { UserSettingsService } from '../../app/services/settings/user-settings.service';
@@ -11,15 +12,14 @@ import { MdContentService } from '../../app/services/md/md-content.service';
/**
* Generated class for the CoverPage page.
*
- * Collection cover/title page.
- *
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
@IonicPage({
- name: 'cover',
- segment: 'publication/:collectionID/cover/'
+ name: 'cover-page',
+ segment: 'publication-cover/:collectionID',
+ priority: 'high'
})
@Component({
selector: 'page-cover',
@@ -48,6 +48,7 @@ export class CoverPage {
protected sanitizer: DomSanitizer,
protected params: NavParams,
protected events: Events,
+ private storage: Storage,
private userSettingsService: UserSettingsService,
protected tableOfContentsService: TableOfContentsService,
public config: ConfigService,
@@ -55,6 +56,8 @@ export class CoverPage {
) {
this.coverSelected = true;
this.id = this.params.get('collectionID');
+ console.log(`Coverpage id is ${this.id}`);
+
this.collection = this.params.get('collection');
if ( this.params.get('publicationID') === undefined ) {
this.coverSelected = true;
@@ -76,6 +79,7 @@ export class CoverPage {
});
this.checkIfCollectionHasChildrenPdfs();
+
if (!isNaN(Number(this.id))) {
if (this.hasMDCover) {
const folder = this.hasMDCover;
@@ -84,6 +88,10 @@ export class CoverPage {
}
}
+ ngOnDestroy() {
+ this.events.unsubscribe('language:change');
+ }
+
checkIfCollectionHasChildrenPdfs() {
this.collectionID = this.params.get('collectionID');
let configChildrenPdfs = [];
@@ -105,7 +113,13 @@ export class CoverPage {
ionViewWillEnter() {
this.events.publish('ionViewWillEnter', this.constructor.name);
this.events.publish('musicAccordion:reset', true);
- this.events.publish('tableOfContents:unSelectSelectedTocItem', true);
+ this.events.publish('tableOfContents:unSelectSelectedTocItem', {'selected': 'cover'});
+
+ this.events.publish('SelectedItemInMenu', {
+ menuID: this.params.get('collectionID'),
+ component: 'cover-page'
+ });
+
}
getMdContent(fileID: string) {
@@ -117,13 +131,21 @@ export class CoverPage {
}
getTocRoot(id: string) {
- this.tableOfContentsService.getTableOfContents(id)
+ this.storage.get('toc_' + id).then((tocItemsC) => {
+ if (tocItemsC) {
+ tocItemsC.coverSelected = this.coverSelected;
+ this.events.publish('tableOfContents:loaded', {tocItems: tocItemsC, searchTocItem: true, collectionID: tocItemsC.collectionId, 'caller': 'cover'});
+ } else {
+ this.tableOfContentsService.getTableOfContents(id)
.subscribe(
tocItems => {
tocItems.coverSelected = this.coverSelected;
- this.events.publish('tableOfContents:loaded', {tocItems: tocItems, searchTocItem: true, collectionID: tocItems.collectionId});
+ this.events.publish('tableOfContents:loaded', {tocItems: tocItems, searchTocItem: true, collectionID: tocItems.collectionId, 'caller': 'cover'});
+ this.storage.set('toc_' + id, tocItems);
},
- error => {this.errorMessage = error});
+ error => {this.errorMessage = error});
+ }
+ });
}
ionViewDidLoad() {
@@ -132,7 +154,7 @@ export class CoverPage {
if (!isNaN(Number(this.id))) {
if (!this.hasMDCover) {
this.langService.getLanguage().subscribe(lang => {
- this.textService.getTitlePage(this.id, lang).subscribe(
+ this.textService.getCoverPage(this.id, lang).subscribe(
res => {
// in order to get id attributes for tooltips
this.text = this.sanitizer.bypassSecurityTrustHtml(
@@ -145,22 +167,22 @@ export class CoverPage {
}
);
});
- }
- } else {
- if (isNaN(Number(this.id))) {
- this.langService.getLanguage().subscribe(lang => {
- const fileID = lang + '-08';
- this.hasMDCover = true;
- this.mdService.getMdContent(fileID).subscribe(
- res => {
- // in order to get id attributes for tooltips
- this.mdContent = res.content;
- },
- error => {
- this.errorMessage = error;
- }
- );
- });
+ } else {
+ if (isNaN(Number(this.id))) {
+ this.langService.getLanguage().subscribe(lang => {
+ const fileID = lang + '-08';
+ this.hasMDCover = true;
+ this.mdService.getMdContent(fileID).subscribe(
+ res => {
+ // in order to get id attributes for tooltips
+ this.mdContent = res.content;
+ },
+ error => {
+ this.errorMessage = error;
+ }
+ );
+ });
+ }
}
}
}
diff --git a/src/pages/editions/editions.html b/src/pages/editions/editions.html
index 76badb4e..d7ef7887 100644
--- a/src/pages/editions/editions.html
+++ b/src/pages/editions/editions.html
@@ -3,4 +3,4 @@
-
\ No newline at end of file
+
diff --git a/src/pages/elastic-search/elastic-search.html b/src/pages/elastic-search/elastic-search.html
new file mode 100644
index 00000000..46579276
--- /dev/null
+++ b/src/pages/elastic-search/elastic-search.html
@@ -0,0 +1,214 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0" (click)="removeSearchField(i)" class="removeIcon" name="remove-circle">
+
+
+
+
+
+
+ {{'ElasticSearch.SearchField' | translate}}
+
+
+
+
+
+
+
+
+
+ {{'Suggestions' | translate}}
+
+
+ {{groupKey | translate}}
+
+ {{getEllipsisString(facet.key | translate)}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{'ElasticSearch.Years' | translate}}
+
+
+
+
+
+
+
+
+
+ {{facetGroupKey | translate}}
+
+
+
+
+
+
+
+
+ {{facet.key | translate}} ({{facet.doc_count}})
+
+
+ {{facet.key_as_string || facet.key}}
+ ({{facet.doc_count}})
+
+
+
+
+ 10" (click)="showAllFor[facetGroupKey] = !showAllFor[facetGroupKey]">
+ {{'ElasticSearch.ShowMore' | translate}}
+ {{'ElasticSearch.ShowLess' | translate}}
+
+
+
+
+
+ No results
+
+
+
+
+
+
+
+
+
+
+
+ 0" push-col-3>
+
+ {{'ElasticSearch.Found' | translate}} {{total}}
+
+
+
+
+ {{'ElasticSearch.NoHits' | translate}}
+
+
+
+
+ 0" col-auto>
+
+ {{'ElasticSearch.SortBy' | translate}}
+
+ {{'ElasticSearch.Relevance' | translate}}
+ {{'ElasticSearch.OldestFirst' | translate}}
+ {{'ElasticSearch.NewestFirst' | translate}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{groupKey | translate}}
+
+ {{getEllipsisString(facet.key | translate)}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0">
+
+
+
+ 0">
+
+
+
+ {{query}}: {{hit.count[query][0][hit.id]['term_freq']}}
+
+
+ {{query}}: {{'ElasticSearch.NoWordHits' | translate}}
+
+
+
+ {{getHeading(hit.source)}}
+ {{hit.type | translate}}, {{getSubHeading(hit.source)}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/elastic-search/elastic-search.module.ts b/src/pages/elastic-search/elastic-search.module.ts
new file mode 100644
index 00000000..929bd863
--- /dev/null
+++ b/src/pages/elastic-search/elastic-search.module.ts
@@ -0,0 +1,51 @@
+import { OccurrencesPageModule } from '../occurrences/occurrences.module';
+import { FilterPageModule } from '../filter/filter.module';
+import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
+import { IonicPageModule } from 'ionic-angular';
+import { ElasticSearchPage } from './elastic-search';
+import { TableOfContentsModule } from '../../components/table-of-contents/table-of-contents.module';
+import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
+import { ComponentsModule } from '../../components/components.module';
+import { HttpClient } from '@angular/common/http';
+import { TranslateHttpLoader } from '@ngx-translate/http-loader';
+import { PipesModule } from '../../pipes/pipes.module';
+import { FilterPage } from '../filter/filter';
+import { OccurrenceService } from '../../app/services/occurrence/occurence.service';
+import { OccurrencesPage } from '../occurrences/occurrences';
+import { ElasticSearchService } from '../../app/services/elastic-search/elastic-search.service';
+
+export function createTranslateLoader(http: HttpClient) {
+ return new TranslateHttpLoader(http, './assets/i18n/', '.json');
+}
+
+@NgModule({
+ schemas: [
+ NO_ERRORS_SCHEMA
+ ],
+ declarations: [
+ ElasticSearchPage
+ ],
+ imports: [
+ IonicPageModule.forChild(ElasticSearchPage),
+ TableOfContentsModule,
+ PipesModule,
+ TranslateModule.forChild({
+ loader: {
+ provide: TranslateLoader,
+ useFactory: (createTranslateLoader),
+ deps: [HttpClient]
+ }
+ }),
+ ComponentsModule,
+ FilterPageModule,
+ OccurrencesPageModule
+ ],
+ providers: [
+ ElasticSearchService,
+ OccurrenceService
+ ],
+ entryComponents: [
+ ElasticSearchPage
+ ]
+})
+export class ElasticSearchPageModule {}
diff --git a/src/pages/elastic-search/elastic-search.scss b/src/pages/elastic-search/elastic-search.scss
new file mode 100644
index 00000000..800b4739
--- /dev/null
+++ b/src/pages/elastic-search/elastic-search.scss
@@ -0,0 +1,292 @@
+page-elastic-search {
+ .word_count span{
+ display: inline-block;
+ padding-left: 1rem;
+ }
+
+ .fixed-content,
+ .scroll-content {
+ margin-top: 40px !important;
+ }
+
+ ion-icon.settings-icon.icon {
+ font-size: 1.8em;
+ }
+
+ ion-item.hitItem:hover{
+ background-color: rgba(color($colors, primary), 0.3) !important;
+ }
+
+ ul {
+ list-style-type: none;
+ }
+
+ .filter-button {
+ font-size: 2.8rem;
+ }
+
+ .searchbar {
+ color: white;
+ }
+
+ .info-toolbar {
+ width: calc(100% - 27%);
+ position: absolute;
+ right: 0;
+ }
+
+ .hits-column {
+ width: calc(100% - 27%);
+ height: 100%;
+ position: absolute;
+ right: 0;
+ top: 75px;
+ }
+
+ .infinite-scroll-wrapper {
+ width: calc(100% - 27%);
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ }
+
+ .date-histogram-wrapper {
+ border: 0.5px solid rgba(190, 183, 155, 0.4);
+ border-radius: 3px;
+ margin: 20px 0;
+ padding: 10px;
+
+ .years-heading {
+ margin-bottom: -14px;
+ }
+ }
+
+ .sort-by-wrapper {
+
+ .input-wrapper {
+ justify-content: flex-end;
+ }
+
+ .sort-by-label {
+ flex: 0;
+ }
+
+ .sort-by-select {
+ width: 300px;
+ }
+ }
+
+ .hits-heading {
+ text-decoration: underline;
+ }
+
+ .segment-md .segment-button {
+ font-size: 1rem;
+ text-transform: none;
+ }
+
+ .searchStatus {
+ color: color($colors, grey);
+ }
+
+ ion-item.item.item-block.item-md {
+ .item-inner {
+ border-bottom: none;
+ }
+ }
+
+ ion-item.item.item-block.item-md {
+ cursor: pointer;
+
+ .itemHeading {
+ padding-left: 20px;
+ font-weight: bold;
+ color: color($colors, blackish);
+ }
+
+ .highlight {
+ color: color($colors, blackish);
+
+ em {
+ background-color: color($colors, primary);
+ color: white;
+ padding: 0.2rem 6px;
+ line-height: 2.4rem;
+ font-style: normal;
+ }
+ }
+
+ // List of facets
+ ion-list.facets {
+ margin: 0 0 0 20px;
+
+ ion-item.item.item-block.item-md.facet {
+ min-height: 1rem;
+
+ ion-checkbox.checkbox-md {
+ margin: 5px;
+ }
+ }
+ }
+ }
+
+ .searchContainer {
+ display: flex;
+ align-items: stretch;
+ }
+
+ ion-icon.rotate.open {
+ transform: rotate(90deg);
+ transition: transform ease-in-out .15s;
+ }
+
+ ion-icon.closed {
+ transition: transform ease-in-out .15s;
+ }
+
+ ion-icon[name="refresh"],
+ ion-icon[name="close"] {
+ padding-bottom: 0 !important;
+ }
+
+ .selectedFacetGroups {
+ .toolbar-background {
+ background-color: transparent;
+ }
+
+ .toolbar-content {
+ margin: 25px 0;
+ }
+
+ .toolbar-title {
+ color: #000;
+ }
+
+ .selectedFacetButton {
+ font-size: 0.9rem !important;
+ height: 28px !important;
+
+ ion-icon {
+ font-size: 1.5em !important;
+ }
+ }
+ }
+
+ .facet-group-wrapper {
+ .facet-item {
+ margin: 5px 0;
+ padding-bottom: 1rem;
+
+ &.Type,
+ &.Genre,
+ &.Collection {
+ border: 0.5px solid rgba(190, 183, 155, 0.4);
+ border-radius: 3px;
+ }
+ }
+
+ .accordion-item {
+ margin: 0 !important;
+
+ .facet {
+ padding: 0;
+
+ ion-checkbox {
+ margin-right: 15px !important;
+ }
+ }
+
+ ion-label {
+ font-weight: 600;
+ }
+
+ .accordion-arrow {
+ font-size: 1.5em;
+ }
+
+ .show-more-button {
+ font-size: .8rem !important;
+ height: 2rem !important;
+ letter-spacing: 1px;
+ }
+ }
+ }
+
+ .hits-heading {
+ padding-left: 32px;
+ }
+
+ .hits-scroll-content {
+ overflow: auto;
+ margin-top: 0;
+ height: 100% !important;
+
+ .scroll-content::-webkit-scrollbar {
+ display: none !important;
+ }
+
+ .scroll-content {
+ margin-top: 0 !important;
+ }
+ }
+
+ .searchbar-wrapper {
+ position: relative;
+ margin: 10px 0;
+
+ .searchInput {
+ resize: none;
+ height: 32px;
+ text-indent: 25px;
+ line-height: 1.3rem;
+ width: 100%;
+ border-radius: 2px;
+ padding: 6px 8px;
+ box-shadow: rgba(0, 0, 0, 0.14) 0px 2px 2px 0px, rgba(0, 0, 0, 0.2) 0px 3px 1px -2px, rgba(0, 0, 0, 0.12) 0px 1px 5px 0px;
+ border: none !important;
+ }
+
+ .removableSearchInput {
+ width: calc(100% - 25px);
+ }
+
+ ion-icon {
+ position: absolute;
+ }
+
+ ion-icon.searchIcon {
+ font-size: 1.2rem !important;
+ top: 7px;
+ left: 14px;
+ }
+
+ ion-icon.removeIcon {
+ cursor: pointer;
+ top: 6px;
+ right: 0;
+ font-size: 1.4rem !important;
+ }
+ }
+
+ .add-search-bar-wrapper {
+ button {
+ height: 32px !important;
+ padding: 0 16px;
+ margin: auto 0;
+ font-size: .8rem !important;
+ letter-spacing: 1px;
+ }
+ }
+}
+
+.alert-title {
+ font-size: 1rem !important;
+}
+
+.alert-md .alert-tappable {
+ min-height: 3.4rem;
+}
+
+.alert-radio-group {
+ padding: 16px;
+}
diff --git a/src/pages/elastic-search/elastic-search.ts b/src/pages/elastic-search/elastic-search.ts
new file mode 100644
index 00000000..30322354
--- /dev/null
+++ b/src/pages/elastic-search/elastic-search.ts
@@ -0,0 +1,726 @@
+import { Component, ViewChild, ChangeDetectorRef } from '@angular/core'
+// tslint:disable-next-line:max-line-length
+import { IonicPage, NavController, NavParams, ModalController, App, Platform,
+ LoadingController, ToastController, Content, Events, ViewController } from 'ionic-angular'
+import get from 'lodash/get'
+import debounce from 'lodash/debounce'
+import size from 'lodash/size'
+
+import { SemanticDataService } from '../../app/services/semantic-data/semantic-data.service'
+import { LanguageService } from '../../app/services/languages/language.service'
+import { ConfigService } from '@ngx-config/core'
+import { TextService } from '../../app/services/texts/text.service'
+import { SingleOccurrence } from '../../app/models/single-occurrence.model'
+import { Storage } from '@ionic/storage'
+import { UserSettingsService } from '../../app/services/settings/user-settings.service'
+import { ElasticSearchService } from '../../app/services/elastic-search/elastic-search.service'
+import { noUndefined } from '@angular/compiler/src/util'
+
+/*
+
+Specs:
+
+- To the left (probably): all the filters, so the user can decide what filters to use before
+actually performing the search, in order to avoid getting results not relevant.
+
+- Since the filters are always visible, they could simply be updated with the number of results
+in the different categories after the search is finished?
+
+- Results are shown in different tabs according to the following categories:
+ texts by the author ZT (reading texts, variants, manuscripts);
+ texts by editors (introductions, comments, title pages, other info material on the site);
+ results from the indexes (persons, places, literary works (results both from the name fields and the description fields)).
+
+- Filters include:
+ genre -> edition;
+ text type (reading text, variant, manuscript, comment, introduction, index);
+ time period -> decade -> year -> month -> date;
+ sender - receiver (for letters)
+
+
+Use cases:
+
+The user might want to look at the word 'snömos', but only in prose and reading texts (to find out how it was used by the author in the
+19th century). From the results she sees it occurs throughout the decades 1840-1880, so she can take a look directly at the one from 1881.
+The user can then decide to look at only comments containing (i.e. explaining) this word; there are 5 of them (and they are all different).
+
+Another user searches for the name Ulla as free text, only in prose, and gets 2 results (one person).
+Ulla as an index search in prose returns 3 different persons, occurring in total 8 times, because they are mentioned
+in other ways than by their first name in the texts, but connected to index posts containing this first name.
+
+In general, the user of the advanced search might want to use some filters from the start, or at least later choose between the
+results according to their different categorization, so it’s important to always keep an overview of what categories the results belong to.
+
+*/
+
+interface SearchOptions {
+ done?: Function
+ initialSearch?: boolean
+}
+
+/**
+ * Elastic search page.
+ */
+@IonicPage({
+ name: 'elastic-search',
+ segment: 'elastic-search/:query',
+ defaultHistory: ['HomePage']
+})
+@Component({
+ selector: 'page-elastic-search',
+ templateUrl: 'elastic-search.html'
+})
+export class ElasticSearchPage {
+
+ @ViewChild(Content) content: Content
+ @ViewChild('myInput') myInput;
+
+ // Helper to loop objects
+ objectKeys = Object.keys
+ objectValues = Object.values
+
+ loading = false
+ infiniteLoading = false
+ showFilter = true
+ queries: string[] = ['']
+ cleanQueries: string[] = ['']
+ hits: object[] = []
+ termData: object[] = [];
+ hitsPerPage = 20
+ aggregations: object = {}
+ facetGroups: FacetGroups = {}
+ selectedFacetGroups: FacetGroups = {}
+ suggestedFacetGroups: FacetGroups = {}
+
+ showAllFacets = false;
+ showAllFor = {};
+
+ // -1 when there a search hasn't returned anything yet.
+ total = -1
+ from = 0
+ sort = ''
+
+ range: TimeRange
+
+ groupsOpenByDefault: any;
+
+ debouncedSearch = debounce(this.search, 500)
+
+ constructor(
+ public navCtrl: NavController,
+ public navParams: NavParams,
+ public semanticDataService: SemanticDataService,
+ protected langService: LanguageService,
+ protected config: ConfigService,
+ public modalCtrl: ModalController,
+ private app: App,
+ private platform: Platform,
+ protected textService: TextService,
+ public loadingCtrl: LoadingController,
+ public elastic: ElasticSearchService,
+ protected storage: Storage,
+ private toastCtrl: ToastController,
+ private userSettingsService: UserSettingsService,
+ private events: Events,
+ private cf: ChangeDetectorRef
+ ) {
+ console.log('constructing elastic search');
+
+ try {
+ this.hitsPerPage = this.config.getSettings('ElasticSearch.hitsPerPage')
+ } catch (e) {
+ console.error('Failed to load Elastic Search Page. Configuration error.', e)
+ }
+ try {
+ this.groupsOpenByDefault = this.config.getSettings('ElasticSearch.groupOpenByDefault')
+ } catch (e) {
+ console.error('Failed to load set facet groups open by default. Configuration error.', e)
+ }
+ }
+
+ private getParamsData() {
+ try {
+ const query = this.navParams.get('query')
+ if (query !== ':query') {
+ this.queries[0] = query
+ }
+ } catch (e) {
+ console.log('Problems parsing query parameters...');
+ }
+ }
+
+ ionViewDidLoad() {
+ this.search({initialSearch: true})
+ // Open type by default
+ setTimeout(() => {
+ const facetGroups = Object.keys(this.facetGroups);
+ facetGroups.forEach(facetGroup => {
+ const openGroup = facetGroup.toLowerCase();
+ switch (openGroup) {
+ case 'type':
+ if (this.groupsOpenByDefault.type) {
+ const facetListType = document.querySelector('.facetList-' + facetGroup);
+ try {
+ facetListType.style.height = '100%';
+ const facetArrowType = document.querySelector('#arrow-1');
+ facetArrowType.classList.add('open', 'rotate');
+ } catch ( e ) {
+
+ }
+ }
+ break;
+ case 'genre':
+ if (this.groupsOpenByDefault.genre) {
+ const facetListGenre = document.querySelector('.facetList-' + facetGroup);
+ try {
+ facetListGenre.style.height = '100%';
+ const facetArrowGenre = document.querySelector('#arrow-2');
+ facetArrowGenre.classList.add('open', 'rotate');
+ } catch ( e ) {
+
+ }
+ }
+ break;
+ case 'collection':
+ if (this.groupsOpenByDefault.collection) {
+ const facetListCollection = document.querySelector('.facetList-' + facetGroup);
+ try {
+ facetListCollection.style.height = '100%';
+ const facetArrowCollection = document.querySelector('#arrow-3');
+ facetArrowCollection.classList.add('open', 'rotate');
+ } catch ( e ) {
+
+ }
+ }
+ break;
+ default:
+ const facetListRest = document.querySelector('.facetList-' + facetGroup);
+ try {
+ facetListRest.style.setProperty('height', '0px');
+ const facetArrowRest = document.querySelector('#arrow-' + facetGroup);
+ facetArrowRest.classList.add('closed', 'rotate');
+ } catch (e) {
+ }
+ break;
+ }
+ })
+ }, 300);
+ }
+
+ ionViewDidEnter() {
+ try {
+ (window).ga('set', 'page', 'Elastic Search')
+ (window).ga('send', 'pageview')
+ } catch ( e ) {
+
+ }
+ }
+
+ ionViewWillLeave() {
+ this.events.publish('ionViewWillLeave', this.constructor.name)
+ }
+
+ ionViewWillEnter() {
+ console.log('will enter elastic search');
+ this.events.publish('ionViewWillEnter', this.constructor.name)
+ this.events.publish('tableOfContents:unSelectSelectedTocItem', true)
+ this.getParamsData();
+ }
+
+ open(hit) {
+ this.events.publish('searchHitOpened', hit)
+ const params = { tocItem: null, fetch: true, collection: { title: hit.source.TitleIndexed } };
+ const path = hit.source.path;
+ const filename = path.split('/').pop();
+
+ // 199_18434_var_6251.xml This should preferrably be implemented via elastic data instead of path
+ const collection_id = filename.split('_').shift(); // 199
+ const var_ms_id = filename.replace('.xml', '').split('_').pop(); // 6251
+
+ params['tocLinkId'] = collection_id + '_' + hit.source.publication_id;
+ params['collectionID'] = collection_id;
+ params['publicationID'] = hit.source.publication_id;
+ params['chapterID'] = 'nochapter';
+
+ params['facs_id'] = 'not';
+ params['facs_nr'] = 'infinite';
+ params['song_id'] = 'nosong';
+ params['search_title'] = this.queries[0];
+ params['matches'] = this.queries;
+ params['views'] = [];
+ // : facs_id / : facs_nr / : song_id / : search_title / : urlviews
+ // not / infinite / nosong / searchtitle / established & variations & facsimiles
+
+
+ switch (hit.source.xml_type) {
+ case 'est': {
+ params['urlviews'] = 'established';
+ params['views'].push({type: 'established'})
+ break;
+ }
+ case 'ms': {
+ params['urlviews'] = 'manuscripts';
+ params['views'].push({type: 'manuscripts', id: var_ms_id});
+ break;
+ }
+ case 'com': {
+ params['urlviews'] = 'comments';
+ params['views'].push({type: 'comments'})
+ break;
+ }
+ case 'var': {
+ params['urlviews'] = 'variations';
+ params['views'].push({type: 'variations', id: var_ms_id});
+
+ break;
+ }
+ case 'inl': {
+ params['urlviews'] = 'introduction';
+ params['views'].push({type: 'introduction', id: var_ms_id});
+
+ break;
+ }
+ case 'tit': {
+ params['urlviews'] = 'title';
+ params['views'].push({type: 'title', id: var_ms_id});
+
+ break;
+ }
+ default: {
+ params['urlviews'] = 'established';
+ params['views'].push({type: 'established'})
+ // statements;
+ break;
+ }
+ }
+ if (hit.source.xml_type !== 'tit') {
+ params['selectedItemInAccordion'] = false;
+ this.app.getRootNav().push('read', params);
+ } else {
+ this.app.getRootNav().push('title-page', params);
+ }
+ }
+
+ /**
+ * https://stackoverflow.com/questions/46991497/how-properly-bind-an-array-with-ngmodel-in-angular-4
+ */
+ trackByIdx(index: number): number {
+ return index
+ }
+
+ /**
+ * Triggers a new search and clears selected facets.
+ */
+ onQueryChange() {
+ this.autoExpandSearchfields()
+ this.reset()
+ this.loading = true
+ this.debouncedSearch()
+ this.cf.detectChanges()
+ }
+
+ /**
+ * Triggers a new search with selected facets.
+ */
+ onFacetsChanged() {
+ this.cf.detectChanges()
+ this.reset()
+ this.search()
+ }
+
+ /**
+ * Triggers a new search with selected years.
+ */
+ onRangeChange(from: number, to: number) {
+ if (from && to) {
+ // Certain date range
+ this.range = {from, to}
+
+ this.cf.detectChanges()
+ this.reset()
+ this.search()
+
+ } else if (!from && !to) {
+ // All time
+ this.range = null
+ this.cf.detectChanges()
+ this.reset()
+ this.search()
+
+ } else {
+ // Only one year selected, so do nothing
+ this.range = null
+ }
+ }
+
+ /**
+ * Sorting changed so trigger new query.
+ */
+ onSortByChanged() {
+ this.reset()
+ this.search()
+ }
+
+ /**
+ * Resets search results.
+ */
+ reset() {
+ this.hits = []
+ this.from = 0
+ this.total = -1
+ this.suggestedFacetGroups = {}
+ }
+
+ /**
+ * Immediately execute a search.
+ * Use debouncedSearch to wait for additional key presses when use types.
+ */
+ private search({ done, initialSearch }: SearchOptions = {}) {
+ console.log(`search from ${this.from} to ${this.from + this.hitsPerPage}`)
+
+ this.loading = true
+
+ // Fetch hits
+ this.elastic.executeSearchQuery({
+ queries: this.queries,
+ highlight: {
+ fields: {
+ textDataIndexed: { number_of_fragments: 2 },
+ },
+ },
+ from: this.from,
+ size: initialSearch ? 0 : this.hitsPerPage,
+ facetGroups: this.facetGroups,
+ range: this.range,
+ sort: this.parseSortForQuery(),
+ })
+ .subscribe((data: any) => {
+ this.loading = false
+ this.total = data.hits.total.value
+
+ // Append new hits to this.hits array.
+ Array.prototype.push.apply(this.hits, data.hits.hits.map((hit: any) => ({
+ type: hit._source.xml_type,
+ source: hit._source,
+ highlight: hit.highlight,
+ id: hit._id
+ })))
+
+ this.cleanQueries = [];
+ if (this.queries.length > 0 && this.queries[0] !== undefined && this.queries[0].length > 0 ) {
+ this.queries.forEach(term => {
+ this.cleanQueries.push(term.toLowerCase().replace(/[^a-zA-ZåäöÅÄÖ[0-9]+/g, ''));
+ this.analyticsEvent('term', term);
+ });
+ for (const item in data.hits.hits) {
+ this.elastic.executeTermQuery(this.cleanQueries, [data.hits.hits[item]['_id']])
+ .subscribe((termData: any) => {
+ this.termData = termData;
+ const elementsIndex = this.hits.findIndex(element => element['id'] === data.hits.hits[item]['_id'] )
+ this.hits[elementsIndex] = {...this.hits[elementsIndex], count: termData}
+ })
+ }
+ }
+
+ if (done) {
+ done()
+ }
+ })
+
+ // Fetch aggregation data for facets.
+ this.elastic.executeAggregationQuery({
+ queries: this.queries,
+ facetGroups: this.facetGroups,
+ range: this.range,
+ })
+ .subscribe((data: any) => {
+ console.log('aggregation data', data)
+
+ this.populateFacets(data.aggregations)
+ })
+
+ // Fetch suggestions
+ // TODO: Currently only works with the first search field.
+ if (this.queries[0] && this.queries[0].length > 3) {
+ this.elastic.executeSuggestionsQuery({
+ query: this.queries[0],
+ })
+ .subscribe((data: any) => {
+ console.log('suggestions data', data)
+ this.populateSuggestions(data.aggregations)
+ })
+ }
+ }
+
+ private parseSortForQuery() {
+ if (!this.sort) {
+ return
+ }
+
+ const [key, direction] = this.sort.split('.')
+ return [{ [key]: direction }]
+ }
+
+ hasMore() {
+ return this.total > this.from + this.hitsPerPage
+ }
+
+ analyticsEvent(type, term) {
+ try {
+ (window).ga('send', 'event', {
+ eventCategory: 'Search',
+ eventLabel: 'ElasticSearch - ' + type,
+ eventAction: String(term),
+ eventValue: 10
+ });
+ } catch ( e ) {
+ }
+ }
+
+ /**
+ * TODO: Make infinite scroll should work with the super long facets column.
+ * Current workaround for this is to increate hitsPerPage to 20.
+ */
+ loadMore(e) {
+ this.infiniteLoading = true
+ this.from += this.hitsPerPage
+
+ // Search and let ion-infinite-scroll know that it can re-enable itself.
+ this.search({
+ done: () => {
+ this.infiniteLoading = false
+ e.complete()
+ },
+ })
+ }
+
+ canShowHits() {
+ return (!this.loading || this.infiniteLoading) && (this.queries[0] || this.range || this.hasSelectedFacets())
+ }
+
+ hasSelectedFacets() {
+ return Object.values(this.facetGroups).some(facets => Object.values(facets).some(facet => facet.selected))
+ }
+
+ hasSelectedFacetsByGroup(groupKey: string) {
+ return size(this.selectedFacetGroups[groupKey]) > 0
+ }
+
+ hasSelectedNormalFacets() {
+ return Object.keys(this.facetGroups).some(facetGroupKey =>
+ facetGroupKey !== 'Type' && facetGroupKey !== 'Years' && Object.values(this.facetGroups[facetGroupKey]).some(facet => facet.selected)
+ )
+ }
+
+ hasFacets(facetGroupKey: string) {
+ return size(this.facetGroups[facetGroupKey]) > 0
+ }
+
+ hasSuggestedFacetsByGroup(groupKey: string) {
+ return size(this.suggestedFacetGroups[groupKey]) > 0
+ }
+
+ hasSuggestedFacets() {
+ return Object.values(this.suggestedFacetGroups).some(facets => size(facets) > 0)
+ }
+
+ getFacets(facetGroupKey: string): Facet[] {
+ const facets = this.facetGroups[facetGroupKey]
+ return facets ? Object.values(facets) : []
+ }
+
+ /**
+ * Toggles facet on/off. Note that the selected state is controlled by the ion-checkbox
+ * so it should not be modified here.
+ */
+ updateFacet(facetGroupKey: string, facet: Facet) {
+ const facets = this.facetGroups[facetGroupKey] || {}
+ facets[facet.key] = facet
+ this.facetGroups[facetGroupKey] = facets
+
+ this.updateSelectedFacets(facetGroupKey, facet)
+
+ this.onFacetsChanged()
+ this.analyticsEvent('facet', String(facet.key));
+ }
+
+ selectSuggestedFacet(facetGroupKey: string, facet: Facet) {
+ this.suggestedFacetGroups = {}
+ this.queries = ['']
+
+ facet.selected = true
+ this.updateFacet(facetGroupKey, facet)
+ }
+
+ unselectFacet(facetGroupKey: string, facet: Facet) {
+ facet.selected = false
+ this.updateFacet(facetGroupKey, facet)
+ }
+
+ private updateSelectedFacets(facetGroupKey: string, facet: Facet) {
+ const facetGroup = this.selectedFacetGroups[facetGroupKey] || {}
+
+ // Set or delete facet from selected facets
+ if (facet.selected) {
+ facetGroup[facet.key] = facet
+ } else {
+ delete facetGroup[facet.key]
+ }
+
+ // Set or delete facet group from selected facet groups
+ if (size(facetGroup) === 0) {
+ delete this.selectedFacetGroups[facetGroupKey]
+ } else {
+ this.selectedFacetGroups[facetGroupKey] = facetGroup
+ }
+ }
+
+ /**
+ * Populate facets data using the search results aggregation data.
+ */
+ private populateFacets(aggregations: AggregationsData) {
+ // Get aggregation keys that are ordered in config.json.
+ this.elastic.getAggregationKeys().forEach(facetGroupKey => {
+ const newFacets = this.convertAggregationsToFacets(aggregations[facetGroupKey])
+ if (this.facetGroups[facetGroupKey]) {
+ Object.entries(this.facetGroups[facetGroupKey]).forEach(([facetKey, existingFacet]: [string, any]) => {
+ const newFacet = newFacets[facetKey]
+ if (newFacet) {
+ existingFacet.doc_count = newFacet.doc_count
+ } else if (this.hasSelectedFacetsByGroup(facetGroupKey)) {
+ // Unselected facets aren't updating because the terms bool.filter in the query
+ // prevents unselected aggregations from appearing in the results.
+ // TODO: Fix this by separating search and aggregation query.
+ } else {
+ delete this.facetGroups[facetGroupKey][facetKey];
+ // existingFacet.doc_count = 0
+ }
+ })
+ Object.entries(newFacets).forEach(([facetKey, existingFacet]: [string, any]) => {
+ if ( this.facetGroups[facetGroupKey][facetKey] === undefined ) {
+ this.facetGroups[facetGroupKey][facetKey] = existingFacet;
+ }
+ });
+ } else {
+ this.facetGroups[facetGroupKey] = newFacets
+ }
+ })
+ }
+
+ /**
+ * Populate suggestions data using the search results aggregation data.
+ */
+ private populateSuggestions(aggregations: AggregationsData) {
+ Object.entries(aggregations).forEach(([aggregationKey, value]: [string, any]) => {
+ this.suggestedFacetGroups[aggregationKey] = this.convertAggregationsToFacets(value)
+ })
+ }
+
+ /**
+ * Convert aggregation data to facets data.
+ */
+ private convertAggregationsToFacets(aggregation: AggregationData): Facets {
+ const facets = {}
+ // Get buckets from either unfiltered or filtered aggregation.
+ const buckets = aggregation.buckets || aggregation.filtered.buckets
+
+ buckets.forEach((facet: Facet) => {
+ facets[facet.key] = facet
+ })
+ return facets
+ }
+
+ getPublicationName(source: any) {
+ return get(source, 'publication_data[0].pubname')
+ }
+
+ getTitle(source: any) {
+ return (source.TitleIndexed || source.name || '').trim()
+ }
+
+ getGenre(source: any) {
+ return get(source, 'publication_data[0].genre', source.collection_name)
+ }
+
+ private formatISO8601DateToLocale(date: string) {
+ return date && new Date(date).toLocaleDateString('fi-FI')
+ }
+
+ private getDate(source: any) {
+ return get(source, 'publication_data[0].original_publication_date', this.formatISO8601DateToLocale(source.orig_date_certain))
+ }
+
+ private filterEmpty(array: any[]) {
+ return array.filter(str => str).join(', ')
+ }
+
+ getHeading(source: any) {
+ switch (source.type) {
+ case 'brev':
+ return this.filterEmpty([this.getTitle(source), this.getPublicationName(source)])
+
+ default:
+ return this.filterEmpty([this.getTitle(source), this.getPublicationName(source)])
+ }
+ }
+
+ getSubHeading(source) {
+ return this.filterEmpty([
+ this.getGenre(source),
+ source.type !== 'brev' && this.getDate(source)
+ ])
+ }
+
+ getEllipsisString(str: string, max = 15) {
+ if (!str || str.length <= max) {
+ return str
+ } else {
+ return str.substr(0, max) + '...'
+ }
+ }
+
+ openAccordion(e, group) {
+ const facet = document.getElementById('facetList-' + group);
+ const arrow = document.getElementById('arrow-' + group);
+
+ arrow.classList.toggle('rotate');
+
+ if (arrow.classList.contains('open')) {
+ facet.style.height = '0px';
+ arrow.classList.add('closed');
+ arrow.classList.remove('open');
+ } else {
+ facet.style.height = '100%';
+ arrow.classList.add('open');
+ arrow.classList.remove('closed');
+ }
+ this.cf.detectChanges();
+ }
+
+ addSearchField() {
+ this.queries.push('')
+ }
+
+ removeSearchField(i) {
+ this.queries.splice(i, 1)
+ }
+
+ autoExpandSearchfields() {
+ const inputs: NodeListOf = document.querySelectorAll('.searchInput')
+
+ for (let i = 0; i < inputs.length; i++) {
+ const borderTop = measure(inputs[i], 'border-top-width')
+ const borderBottom = measure(inputs[i], 'border-bottom-width')
+
+ inputs[i].style.height = ''
+ inputs[i].style.height = borderTop + inputs[i].scrollHeight + borderBottom + 'px'
+ }
+
+ function measure(elem: Element, property) {
+ return parseInt(
+ window.getComputedStyle(elem, null)
+ .getPropertyValue(property)
+ .replace(/px$/, ''))
+ }
+ }
+}
diff --git a/src/pages/facsimile-zoom/facsimile-zoom.html b/src/pages/facsimile-zoom/facsimile-zoom.html
index 830a795e..7295c39b 100644
--- a/src/pages/facsimile-zoom/facsimile-zoom.html
+++ b/src/pages/facsimile-zoom/facsimile-zoom.html
@@ -1,18 +1,21 @@
-
+