From f01122844afd4603f4189a4762b088566d87d9d7 Mon Sep 17 00:00:00 2001 From: Aferdita Muriqi Date: Wed, 18 Nov 2020 21:05:19 -0500 Subject: [PATCH 1/9] Initial positions and timeline module --- src/index.ts | 84 ++++++++++++++ src/model/Locator.ts | 5 +- src/model/Publication.ts | 18 ++- src/modules/positions/TimelineModule.ts | 147 ++++++++++++++++++++++++ src/styles/sass/reader.scss | 2 + src/styles/sass/reader/_timeline.scss | 59 ++++++++++ 6 files changed, 313 insertions(+), 2 deletions(-) create mode 100644 src/modules/positions/TimelineModule.ts create mode 100644 src/styles/sass/reader/_timeline.scss diff --git a/src/index.ts b/src/index.ts index c099c874..4d8cc388 100644 --- a/src/index.ts +++ b/src/index.ts @@ -29,6 +29,8 @@ import { oc } from "ts-optchain" import { TTSSettings } from "./modules/TTS/TTSSettings"; import SearchModule from "./modules/search/SearchModule"; import TextHighlighter from "./modules/highlight/TextHighlighter"; +import { Locator } from "./model/Locator"; +import TimelineModule from "./modules/positions/TimelineModule"; var R2Settings: UserSettings; var R2TTSSettings: TTSSettings; @@ -38,6 +40,7 @@ var BookmarkModuleInstance: BookmarkModule; var AnnotationModuleInstance: AnnotationModule; var TTSModuleInstance: TTSModule; var SearchModuleInstance:SearchModule; +var TimelineModuleInstance: TimelineModule; export const IS_DEV = (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "dev"); @@ -60,6 +63,9 @@ export async function unload() { if (oc(R2Navigator.rights).enableSearch(false)) { SearchModuleInstance.stop() } + if (oc(R2Navigator.rights).enableTimeline(false)) { + TimelineModuleInstance.stop() + } } export function startReadAloud() { if (IS_DEV) { console.log("startReadAloud") } @@ -245,6 +251,18 @@ export async function scroll(value) { R2Settings.scroll(value) } +export async function currentLocator() { + if (IS_DEV) { console.log("currentLocator") } + return R2Navigator.currentLocator() +} +export async function positions() { + if (IS_DEV) { console.log("positions") } + return R2Navigator.positions() +} +export async function goToPosition(value) { + if (IS_DEV) { console.log("goToPosition") } + return R2Navigator.goToPosition(value) +} export async function load(config: ReaderConfig): Promise { var mainElement = document.getElementById("D2Reader-Container"); @@ -269,6 +287,53 @@ export async function load(config: ReaderConfig): Promise { const publication: Publication = await Publication.getManifest(webpubManifestUrl, store); + var startPosition = 0 + var totalContentLength = 0 + var positions = [] + publication.readingOrder.map(async (link, index) => { + var href = publication.getAbsoluteHref(link.href); + await fetch(href) + .then(async r => { + let length = (await r.blob()).size + link.contentLength = length + totalContentLength += length + let positionLength = 1024 + let positionCount = Math.max(1, Math.ceil(length / positionLength)) + console.log(length + " Bytes") + console.log(positionCount + " Positions") + Array.from(Array(positionCount).keys()).map((_, position) => { + const locator: Locator = { + href: link.href, + locations: { + progression: (position) / (positionCount), + position: startPosition + (position + 1), + }, + type: link.type + }; + console.log(locator) + positions.push(locator) + }); + startPosition = startPosition + positionCount + }) + if (index + 1 == publication.readingOrder.length) { + publication.readingOrder.map(async (link) => { + console.log(totalContentLength) + console.log(link.contentLength) + link.contentWeight = 100 / totalContentLength * link.contentLength + console.log(link.contentWeight) + }) + positions.map((locator, _index) => { + let resource = positions.filter((el: Locator) => el.href === locator.href) + let positionIndex = Math.ceil(locator.locations.progression * (resource.length - 1)) + locator.locations.totalProgression = (locator.locations.position - 1) / (positions.length) + locator.locations.remainingPositions = Math.abs((positionIndex) - (resource.length - 1)) + locator.locations.totalRemainingPositions = Math.abs((locator.locations.position - 1) - (positions.length - 1)) + }) + publication.positions = positions + console.log(positions) + } + }); + // Settings R2Settings = await UserSettings.create({ store: settingsStore, @@ -358,6 +423,16 @@ export async function load(config: ReaderConfig): Promise { }); } + // Timeline Module + if (oc(config.rights).enableTimeline(false)) { + TimelineModule.create({ + publication: publication, + delegate: R2Navigator + }).then(function (timelineModule) { + TimelineModuleInstance = timelineModule + }) + } + return new Promise(resolve => resolve(R2Navigator)); } @@ -489,4 +564,13 @@ exports.goToSearchIndex = function (href, index, current) { } exports.goToSearchID = function (href, index, current) { goToSearchID(href, index, current) +} +exports.currentLocator = function () { + return currentLocator() +} +exports.positions = function () { + return positions() +} +exports.goToPosition = function (value) { + goToPosition(value) } \ No newline at end of file diff --git a/src/model/Locator.ts b/src/model/Locator.ts index 57814a84..5eb4b0d6 100644 --- a/src/model/Locator.ts +++ b/src/model/Locator.ts @@ -22,9 +22,10 @@ import { IHighlight } from "../modules/highlight/common/highlight"; export interface Locator { href: string; type?: string; - title: string; + title?: string; locations: Locations; text?: LocatorText; + displayInfo?: any; } @@ -39,6 +40,8 @@ export interface Locations { progression?: number; // 3 = bookmarks position?: number; // 4 = goto page totalProgression?: number; + remainingPositions?: number; + totalRemainingPositions?: number; } export interface ReadingPosition extends Locator { diff --git a/src/model/Publication.ts b/src/model/Publication.ts index 55d9e87e..01432c42 100644 --- a/src/model/Publication.ts +++ b/src/model/Publication.ts @@ -18,6 +18,7 @@ */ import Store from "../store/Store"; +import { Locator } from "./Locator"; export interface Metadata { title?: string; @@ -54,6 +55,8 @@ export interface Link { // The MediaOverlays associated to the resource of the Link // mediaOverlays?: MediaOverlays; + contentLength?: number; + contentWeight?: number; } export default class Publication { @@ -65,6 +68,7 @@ export default class Publication { public readonly landmarks: Array; public readonly pageList: Array; public readonly images: Array; + public positions: Array; private readonly manifestUrl: URL; @@ -158,7 +162,11 @@ export default class Publication { } public getRelativeHref(href: string): string | null { const manifest = this.manifestUrl.href.replace("/manifest.json", ""); //new URL(this.manifestUrl.href, this.manifestUrl.href).href; - return href.replace(manifest, ""); + var href = href.replace(manifest, ""); + if(href.charAt(0) === '/') { + href = href.substring(1); + } + return href; } @@ -215,4 +223,12 @@ export default class Publication { } return link } + + /** + * positionsByHref + */ + public positionsByHref(href:string) { + return this.positions.filter((el: Locator) => el.href === href) + } + } diff --git a/src/modules/positions/TimelineModule.ts b/src/modules/positions/TimelineModule.ts new file mode 100644 index 00000000..c0e8ed62 --- /dev/null +++ b/src/modules/positions/TimelineModule.ts @@ -0,0 +1,147 @@ +/* + * Copyright 2018-2020 DITA (AM Consulting LLC) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Developed on behalf of: DITA + * Licensed to: Bibliotheca LLC, Bokbasen AS and CAST under one or more contributor license agreements. + */ + +import { IS_DEV } from "../.."; +import { Locator } from "../../model/Locator"; +import Publication from "../../model/Publication"; +import IFrameNavigator from "../../navigator/IFrameNavigator"; +import { addEventListenerOptional } from "../../utils/EventHandler"; +import ReaderModule from "../ReaderModule"; +import * as HTMLUtilities from "../../utils/HTMLUtilities"; +import { oc } from "ts-optchain"; + +export interface TimelineModuleConfig { + publication: Publication; + delegate: IFrameNavigator; +} + +export default class TimelineModule implements ReaderModule { + + private publication: Publication; + private delegate: IFrameNavigator; + private timelineContainer: HTMLDivElement; + private positionSlider: HTMLInputElement; + + public static async create(config: TimelineModuleConfig) { + const timeline = new this( + config.delegate, + config.publication + ); + + await timeline.start(); + return timeline; + } + + private constructor(delegate: IFrameNavigator, publication: Publication) { + this.delegate = delegate + this.publication = publication + } + + async stop() { + if (IS_DEV) { console.log("Timeline module stop") } + } + + protected async start(): Promise { + + this.delegate.timelineModule = this + + this.timelineContainer = HTMLUtilities.findElement(document, "#container-view-timeline") as HTMLDivElement; + if (oc(this.delegate.rights).enableMaterial(false)) { + this.positionSlider = HTMLUtilities.findElement(document, "#positionSlider") as HTMLInputElement; + } + } + + async initialize() { + return new Promise(async (resolve) => { + await (document as any).fonts.ready; + + let locator = this.delegate.currentLocator() + if (oc(this.delegate.rights).enableMaterial(false)) { + this.positionSlider.value = locator.locations.position.toString() + this.positionSlider.max = (locator.locations.totalRemainingPositions + locator.locations.position).toString() + } + + this.timelineContainer.innerHTML = "" + this.publication.readingOrder.forEach(link => { + + console.log(link.contentWeight) + const linkHref = this.publication.getAbsoluteHref(link.href); + const tocItemAbs = this.publication.getTOCItemAbsolute(linkHref); + const tocHref = (tocItemAbs.href.indexOf("#") !== -1) ? tocItemAbs.href.slice(0, tocItemAbs.href.indexOf("#")) : tocItemAbs.href + const tocHrefAbs = this.publication.getAbsoluteHref(tocHref); + + var chapterHeight + if (this.publication.positions) { + if (link.contentWeight) { + chapterHeight = link.contentWeight + } else { + chapterHeight = 5 + } + } else { + chapterHeight = 100 / this.publication.readingOrder.length + } + + var chapter = document.createElement("div") + chapter.style.height = chapterHeight + "%" + chapter.style.width = "100%" + chapter.className = "chapter"; + + if (tocItemAbs.title !== undefined) { + var tooltip = document.createElement("span") + tooltip.innerHTML = tocItemAbs.title; + tooltip.className = "chapter-tooltip"; + chapter.appendChild(tooltip); + } + + addEventListenerOptional(chapter, 'click', (event: MouseEvent) => { + + event.preventDefault(); + event.stopPropagation(); + + const position1 = this.publication.positions.filter((el: Locator) => el.href === link.href)[0] + position1.href = this.publication.getAbsoluteHref(position1.href) + console.log(position1) + this.delegate.navigate(position1) + }); + + if (tocHrefAbs === this.delegate.currentChapterLink.href) { + chapter.className += " active"; + } else { + chapter.className = chapter.className.replace(" active", ""); + } + + // append bookmarks indicator + // append notes indicator + // append highlights indicator + + this.timelineContainer.appendChild(chapter) + + // if (oc(this.delegate.rights).enableMaterial(false)) { + // this.timelineContainer.style.height = window.innerHeight - 240 + "px"; + // } else { + // this.timelineContainer.style.height = window.innerHeight - 170 + "px"; + // } + + }); + + resolve() + }); + } + +} diff --git a/src/styles/sass/reader.scss b/src/styles/sass/reader.scss index 641f2110..a6e621eb 100644 --- a/src/styles/sass/reader.scss +++ b/src/styles/sass/reader.scss @@ -43,3 +43,5 @@ @import "reader/toolbox"; // TTS ui tools @import "reader/tts"; + +@import "reader/timeline"; diff --git a/src/styles/sass/reader/_timeline.scss b/src/styles/sass/reader/_timeline.scss new file mode 100644 index 00000000..a0a8927c --- /dev/null +++ b/src/styles/sass/reader/_timeline.scss @@ -0,0 +1,59 @@ +/* + * Copyright 2018-2020 DITA (AM Consulting LLC) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Developed on behalf of: DITA + * Licensed to: Bibliotheca LLC, Bokbasen AS and CAST under one or more contributor license agreements. + */ + + .timeline { + position: fixed; + top: 1.5rem; + left: 2.5rem; + bottom: 1.5rem; + width: 1.25rem; + .chapter { + border-left: 6px solid transparent; + transition: border-color 300ms ease-out; + background: $ui-light-gray; + border: 1px solid $ui-white; + border-radius: 5px; + position: relative; + &:hover { + background-color: $ui-light-gray; + .chapter-tooltip { + display: block; + } + } + &.active { + background-color: $ui-default; + } + } + .chapter-tooltip { + display: none; + position: absolute; + left: 2rem; + top: 50%; + transform: translate(0,-50%); + background: $ui-light-gray; + padding: 0.25rem 0.5rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 22rem; + } +} + + + From 241d4517199d8a7d6518003226f4a29787f3c14a Mon Sep 17 00:00:00 2001 From: Aferdita Muriqi Date: Wed, 18 Nov 2020 21:27:16 -0500 Subject: [PATCH 2/9] updated css and html example --- src/styles/sass/reader/_global.scss | 8 +++++++- viewer/index_api.html | 12 +++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/styles/sass/reader/_global.scss b/src/styles/sass/reader/_global.scss index 532523ea..95f43e52 100644 --- a/src/styles/sass/reader/_global.scss +++ b/src/styles/sass/reader/_global.scss @@ -60,6 +60,11 @@ box-sizing: border-box; } + #reader-info-bottom { + bottom: 0px; + position: fixed; + width: 100%; + } .info { color: $ui-dark-gray; margin: 0; @@ -87,7 +92,8 @@ } .chapter-position, - .chapter-title { + .chapter-title, + .remaining-positions { font-size: 0.85rem; font-variant-numeric: lining-nums tabular-nums; } diff --git a/viewer/index_api.html b/viewer/index_api.html index c214dacc..4192965f 100644 --- a/viewer/index_api.html +++ b/viewer/index_api.html @@ -69,6 +69,14 @@


+
+


@@ -221,6 +229,7 @@ +
@@ -325,7 +334,8 @@ enableBookmarks: true, enableAnnotations: true, enableTTS: true, - enableSearch: true + enableSearch: true, + enableTimeline: true }, tts: { enableSplitter: true, From 84b91796a2c4aab9b77ed6b56a49aeafd827a92e Mon Sep 17 00:00:00 2001 From: Aferdita Muriqi Date: Wed, 18 Nov 2020 21:28:51 -0500 Subject: [PATCH 3/9] integrate timeline and positions info apis --- src/navigator/IFrameNavigator.ts | 126 ++++++++++++++++++++----------- 1 file changed, 84 insertions(+), 42 deletions(-) diff --git a/src/navigator/IFrameNavigator.ts b/src/navigator/IFrameNavigator.ts index 530c9ffd..d2400c3e 100644 --- a/src/navigator/IFrameNavigator.ts +++ b/src/navigator/IFrameNavigator.ts @@ -30,12 +30,13 @@ import { UserSettingsUIConfig, UserSettings } from "../model/user-settings/UserS import BookmarkModule from "../modules/BookmarkModule"; import AnnotationModule from "../modules/AnnotationModule"; import TTSModule, { TTSSpeechConfig } from "../modules/TTS/TTSModule"; -import { IS_DEV } from ".."; +import { goTo, IS_DEV } from ".."; import Splitting from "../modules/TTS/splitting"; import { oc } from "ts-optchain"; import ReflowableBookView from "../views/ReflowableBookView"; import SearchModule from "../modules/search/SearchModule"; import TextHighlighter from "../modules/highlight/TextHighlighter"; +import TimelineModule from "../modules/positions/TimelineModule"; export interface UpLinkConfig { url?: URL; @@ -85,6 +86,7 @@ export interface ReaderRights { enableTTS?: boolean; enableSearch?: boolean; enableMaterial?: boolean; + enableTimeline?: boolean; } export interface ReaderUI { @@ -121,6 +123,7 @@ export default class IFrameNavigator implements Navigator { ttsModule?: TTSModule; searchModule?: SearchModule; highlighter?: TextHighlighter; + timelineModule?: TimelineModule; sideNavExpanded: boolean = false material: boolean = false @@ -175,6 +178,7 @@ export default class IFrameNavigator implements Navigator { private bookTitle: HTMLSpanElement; private chapterTitle: HTMLSpanElement; private chapterPosition: HTMLSpanElement; + private remainingPositions: HTMLSpanElement; private newPosition: Locator | null; private newElementId: string | null; private isBeingStyled: boolean; @@ -290,14 +294,16 @@ export default class IFrameNavigator implements Navigator { // Main Element this.iframe = HTMLUtilities.findRequiredElement(mainElement, "main#iframe-wrapper iframe") as HTMLIFrameElement; - - this.loadingMessage = HTMLUtilities.findRequiredElement(mainElement, "#reader-loading") as HTMLDivElement; - this.loadingMessage.innerHTML = readerLoading; - this.loadingMessage.style.display = "none"; - - this.errorMessage = HTMLUtilities.findRequiredElement(mainElement, "#reader-error") as HTMLDivElement; - this.errorMessage.innerHTML = readerError; - this.errorMessage.style.display = "none"; + this.loadingMessage = HTMLUtilities.findElement(mainElement, "#reader-loading") as HTMLDivElement; + if (this.loadingMessage) { + this.loadingMessage.innerHTML = readerLoading; + this.loadingMessage.style.display = "none"; + } + this.errorMessage = HTMLUtilities.findElement(mainElement, "#reader-error") as HTMLDivElement; + if (this.errorMessage) { + this.errorMessage.innerHTML = readerError; + this.errorMessage.style.display = "none"; + } this.tryAgainButton = HTMLUtilities.findElement(mainElement, "button[class=try-again]") as HTMLButtonElement; this.goBackButton = HTMLUtilities.findElement(mainElement, "button[class=go-back]") as HTMLButtonElement; @@ -306,8 +312,9 @@ export default class IFrameNavigator implements Navigator { if (this.headerMenu) this.bookTitle = HTMLUtilities.findElement(this.headerMenu, "#book-title") as HTMLSpanElement; - if (this.infoBottom) this.chapterTitle = HTMLUtilities.findRequiredElement(this.infoBottom, "span[class=chapter-title]") as HTMLSpanElement; - if (this.infoBottom) this.chapterPosition = HTMLUtilities.findRequiredElement(this.infoBottom, "span[class=chapter-position]") as HTMLSpanElement; + if (this.infoBottom) this.chapterTitle = HTMLUtilities.findElement(this.infoBottom, "span[class=chapter-title]") as HTMLSpanElement; + if (this.infoBottom) this.chapterPosition = HTMLUtilities.findElement(this.infoBottom, "span[class=chapter-position]") as HTMLSpanElement; + if (this.infoBottom) this.remainingPositions = HTMLUtilities.findElement(this.infoBottom, "span[class=remaining-positions]") as HTMLSpanElement; if (this.headerMenu) this.espandMenuIcon = HTMLUtilities.findElement(this.headerMenu, "#expand-menu") as HTMLElement; @@ -423,8 +430,10 @@ export default class IFrameNavigator implements Navigator { self.annotationModule.drawHighlights() // self.annotationModule.drawIndicators() } else { - await this.highlighter.destroyAllhighlights(this.iframe.contentDocument) - self.searchModule.drawSearch() + if (oc(this.rights).enableSearch(false)) { + await this.highlighter.destroyAllhighlights(this.iframe.contentDocument) + self.searchModule.drawSearch() + } } }, 300); @@ -559,6 +568,7 @@ export default class IFrameNavigator implements Navigator { if (this.previousPageAnchorElement) this.previousPageAnchorElement.style.display = "unset" if (this.chapterTitle) this.chapterTitle.style.display = "inline"; if (this.chapterPosition) this.chapterPosition.style.display = "inline"; + if (this.remainingPositions) this.remainingPositions.style.display = "inline"; if (this.eventHandler) { this.eventHandler.onInternalLink = this.handleInternalLink.bind(this); this.eventHandler.onClickThrough = this.handleClickThrough.bind(this); @@ -626,6 +636,7 @@ export default class IFrameNavigator implements Navigator { if (this.chapterTitle) this.chapterTitle.style.display = "none"; if (this.chapterPosition) this.chapterPosition.style.display = "none"; + if (this.remainingPositions) this.remainingPositions.style.display = "none"; if (this.eventHandler) { this.eventHandler.onInternalLink = this.handleInternalLink.bind(this); this.eventHandler.onClickThrough = this.handleClickThrough.bind(this); @@ -644,10 +655,12 @@ export default class IFrameNavigator implements Navigator { if (this.annotationModule !== undefined) { this.annotationModule.drawHighlights() } else { - await this.highlighter.destroyAllhighlights(this.iframe.contentDocument) - this.searchModule.drawSearch() + if (oc(this.rights).enableSearch(false)) { + await this.highlighter.destroyAllhighlights(this.iframe.contentDocument) + this.searchModule.drawSearch() + } } - }, 100); + }, 200); } @@ -872,7 +885,7 @@ export default class IFrameNavigator implements Navigator { } private async handleIFrameLoad(): Promise { - this.errorMessage.style.display = "none"; + if (this.errorMessage) this.errorMessage.style.display = "none"; this.showLoadingMessageAfterDelay(); try { let bookViewPosition = 0; @@ -887,7 +900,6 @@ export default class IFrameNavigator implements Navigator { setTimeout(() => { this.reflowable.goToPosition(bookViewPosition); - this.updatePositionInfo(); }, 100); setTimeout(() => { @@ -900,7 +912,9 @@ export default class IFrameNavigator implements Navigator { let currentLocation = this.currentChapterLink.href - this.updatePositionInfo(); + setTimeout(() => { + this.updatePositionInfo(); + }, 200); const previous = this.publication.getPreviousSpineItem(currentLocation); if (previous && previous.href) { @@ -1050,6 +1064,13 @@ export default class IFrameNavigator implements Navigator { }, 100); + setTimeout(async () => { + + if (this.timelineModule !== undefined) { + await this.timelineModule.initialize() + } + + }, 100); return new Promise(resolve => resolve()); @@ -1061,7 +1082,7 @@ export default class IFrameNavigator implements Navigator { } private abortOnError() { - this.errorMessage.style.display = "block"; + if (this.errorMessage) this.errorMessage.style.display = "block"; if (this.isLoading) { this.hideLoadingMessage(); } @@ -1150,20 +1171,13 @@ export default class IFrameNavigator implements Navigator { private hideModal(modal: HTMLDivElement, control?: HTMLAnchorElement | HTMLButtonElement) { // Restore the page for screen readers. this.iframe.setAttribute("aria-hidden", "false"); - if (this.upLink) { - this.upLink.setAttribute("aria-hidden", "false"); - } - if (this.linksBottom) { - this.linksBottom.setAttribute("aria-hidden", "false"); - } - if (this.linksMiddle) { - this.linksMiddle.setAttribute("aria-hidden", "false"); - } - this.loadingMessage.setAttribute("aria-hidden", "false"); - this.errorMessage.setAttribute("aria-hidden", "false"); - this.infoTop.setAttribute("aria-hidden", "false"); - this.infoBottom.setAttribute("aria-hidden", "false"); - + if (this.upLink) this.upLink.setAttribute("aria-hidden", "false"); + if (this.linksBottom) this.linksBottom.setAttribute("aria-hidden", "false"); + if (this.linksMiddle) this.linksMiddle.setAttribute("aria-hidden", "false"); + if (this.loadingMessage) this.loadingMessage.setAttribute("aria-hidden", "false"); + if (this.errorMessage) this.errorMessage.setAttribute("aria-hidden", "false"); + if (this.infoTop) this.infoTop.setAttribute("aria-hidden", "false"); + if (this.infoBottom) this.infoBottom.setAttribute("aria-hidden", "false"); this.hideElement(modal, control); } @@ -1274,7 +1288,25 @@ export default class IFrameNavigator implements Navigator { this.stopReadAloud(); this.navigate(position); } + currentLocator():Locator { + let positions = this.publication.positionsByHref(this.publication.getRelativeHref(this.currentTOCRawLink)); + let positionIndex = Math.ceil(this.reflowable.getCurrentPosition() * (positions.length - 1)) + let position = positions[positionIndex] + position.locations.progression = this.reflowable.getCurrentPosition() + position.displayInfo = { + resourceScreenIndex : Math.round(this.reflowable.getCurrentPage()), + resourceScreenCount : Math.round(this.reflowable.getPageCount()) + } + return position + } + positions():any { + return this.publication.positions + } + goToPosition(position:number) { + let locator = this.publication.positions.filter((el: Locator) => el.locations.position == position)[0] + goTo(locator) + } private handlePreviousPageClick(event: MouseEvent | TouchEvent | KeyboardEvent): void { this.stopReadAloud(); if(this.reflowable.isPaginated()) { @@ -1479,18 +1511,24 @@ export default class IFrameNavigator implements Navigator { if (this.annotationModule !== undefined) { this.annotationModule.handleResize() } else { - this.searchModule.handleResize() + if (oc(this.rights).enableSearch(false)) { + this.searchModule.handleResize() + } } }, 100); } updatePositionInfo() { if(this.reflowable.isPaginated()) { - const currentPage = Math.round(this.reflowable.getCurrentPage()); - const pageCount = Math.round(this.reflowable.getPageCount()); + const locator = this.currentLocator() + const currentPage = locator.displayInfo.resourceScreenIndex + const pageCount = locator.displayInfo.resourceScreenCount + const remaining = locator.locations.remainingPositions; if (this.chapterPosition) this.chapterPosition.innerHTML = "Page " + currentPage + " of " + pageCount; + if (this.remainingPositions) this.remainingPositions.innerHTML = remaining + " left in chapter"; } else { if (this.chapterPosition) this.chapterPosition.innerHTML = ""; + if (this.remainingPositions) this.remainingPositions.innerHTML = ""; } } @@ -1603,8 +1641,10 @@ export default class IFrameNavigator implements Navigator { this.annotationModule.drawHighlights() this.annotationModule.showHighlights(); } else { - await this.highlighter.destroyAllhighlights(this.iframe.contentDocument) - this.searchModule.drawSearch() + if (oc(this.rights).enableSearch(false)) { + await this.highlighter.destroyAllhighlights(this.iframe.contentDocument) + this.searchModule.drawSearch() + } } if(this.reflowable.isScrollmode()) { @@ -1657,7 +1697,7 @@ export default class IFrameNavigator implements Navigator { private showLoadingMessageAfterDelay() { this.isLoading = true; setTimeout(() => { - if (this.isLoading) { + if (this.isLoading && this.loadingMessage) { this.loadingMessage.style.display = "block"; this.loadingMessage.classList.add("is-loading"); } @@ -1671,8 +1711,10 @@ export default class IFrameNavigator implements Navigator { private hideLoadingMessage() { this.isLoading = false; - this.loadingMessage.style.display = "none"; - this.loadingMessage.classList.remove("is-loading"); + if (this.loadingMessage) { + this.loadingMessage.style.display = "none"; + this.loadingMessage.classList.remove("is-loading"); + } } private async saveCurrentReadingPosition(): Promise { From 07245f4727d36c4a80cdb9aac399459d68104cb6 Mon Sep 17 00:00:00 2001 From: Aferdita Muriqi Date: Wed, 18 Nov 2020 21:29:15 -0500 Subject: [PATCH 4/9] version bump to 1.5.0-alpha.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d19acf56..01cd6c48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@d-i-t-a/reader", - "version": "1.4.0-alpha.7", + "version": "1.5.0-alpha.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3782,7 +3782,7 @@ }, "materialize-css": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/materialize-css/-/materialize-css-1.0.0.tgz", + "resolved": "http://ci2.bokskya.webbe.no/nexus/repository/npm-group/materialize-css/-/materialize-css-1.0.0.tgz", "integrity": "sha512-4/oecXl8y/1i8RDZvyvwAICyqwNoKU4or5uf8uoAd74k76KzZ0Llym4zhJ5lLNUskcqjO0AuMcvNyDkpz8Z6zw==", "dev": true }, diff --git a/package.json b/package.json index 39010d2f..5b9281e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@d-i-t-a/reader", - "version": "1.4.0-alpha.7", + "version": "1.5.0-alpha.1", "description": "A viewer application for EPUB files.", "repository": "https://github.com/d-i-t-a/R2D2BC", "license": "Apache-2.0", From b1942f2a999adce3644844aa8549634cf3970668 Mon Sep 17 00:00:00 2001 From: Aferdita Muriqi Date: Wed, 18 Nov 2020 21:38:02 -0500 Subject: [PATCH 5/9] adjusted html examples --- viewer/index_api.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/viewer/index_api.html b/viewer/index_api.html index 4192965f..7dc27586 100644 --- a/viewer/index_api.html +++ b/viewer/index_api.html @@ -42,7 +42,7 @@
-
+
+ +
  • Table of Contentschevron_left +
    +
    +
  • +
  • Bookmarks chevron_left +
    +
    +
  • +
  • Highlightschevron_left +
    +
    +
  • +
  • Landmarkschevron_left +
    +
    +
  • +
  • Page + Listchevron_left +
    +
    +
  • + + + + + + + + + +
    +
    +
    +
    +
    + +
    + +
    +
    + + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    + + + + +
    +
    + +
    + +
    + + +
    + +
    +
    + + + + + +
    +
    + +
    +
    + +
    + + +
    + + + + + + + + + + + + \ No newline at end of file From 8095efe3a3004be74d12fb81533ed92ef48ce5a4 Mon Sep 17 00:00:00 2001 From: Aferdita Muriqi Date: Thu, 19 Nov 2020 08:23:06 -0500 Subject: [PATCH 7/9] cleanup html source formatting --- src/modules/positions/TimelineModule.ts | 6 - viewer/index.html | 364 ++++++++++++++---------- viewer/index_api.html | 128 ++++++--- viewer/index_material.html | 144 ++++++---- 4 files changed, 392 insertions(+), 250 deletions(-) diff --git a/src/modules/positions/TimelineModule.ts b/src/modules/positions/TimelineModule.ts index c0e8ed62..b42af879 100644 --- a/src/modules/positions/TimelineModule.ts +++ b/src/modules/positions/TimelineModule.ts @@ -132,12 +132,6 @@ export default class TimelineModule implements ReaderModule { this.timelineContainer.appendChild(chapter) - // if (oc(this.delegate.rights).enableMaterial(false)) { - // this.timelineContainer.style.height = window.innerHeight - 240 + "px"; - // } else { - // this.timelineContainer.style.height = window.innerHeight - 170 + "px"; - // } - }); resolve() diff --git a/viewer/index.html b/viewer/index.html index 0202f93a..6b0a25db 100644 --- a/viewer/index.html +++ b/viewer/index.html @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Developed on behalf of: Bokbasen AS (https://www.bokbasen.no) + * Developed on behalf of: DITA * Licensed to: Bokbasen AS and CAST under one or more contributor license agreements. --> @@ -25,7 +25,8 @@ - + @@ -51,102 +52,135 @@ - - +