Skip to content

Commit c856eb8

Browse files
committed
Dynamic respreading for fixed-layout. Odd-pages verso. Fixes in spread logic.
1 parent a43dd28 commit c856eb8

File tree

1 file changed

+94
-46
lines changed

1 file changed

+94
-46
lines changed

fixed-layout.js

Lines changed: 94 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@ const getViewport = (doc, viewport) => {
3030
}
3131

3232
export class FixedLayout extends HTMLElement {
33-
static observedAttributes = ['zoom']
33+
static observedAttributes = ['zoom','spread','odd-pages']
3434
#root = this.attachShadow({ mode: 'closed' })
3535
#observer = new ResizeObserver(() => this.#render())
3636
#spreads
3737
#index = -1
3838
defaultViewport
3939
spread
40+
#rtl
41+
#oddPages
4042
#portrait = false
4143
#left
4244
#right
@@ -57,6 +59,8 @@ export class FixedLayout extends HTMLElement {
5759
overflow: auto;
5860
}`)
5961

62+
this.#oddPages = this.getAttribute('odd-pages')
63+
6064
this.#observer.observe(this)
6165
}
6266
attributeChangedCallback(name, _, value) {
@@ -66,6 +70,15 @@ export class FixedLayout extends HTMLElement {
6670
? parseFloat(value) : value
6771
this.#render()
6872
break
73+
case 'spread':
74+
this.spread = value
75+
this.respread()
76+
break
77+
case 'odd-pages':
78+
this.#oddPages = value
79+
this.#determineOddPages()
80+
this.respread()
81+
break
6982
}
7083
}
7184
async #createFrame({ index, src: srcOption }) {
@@ -198,50 +211,85 @@ export class FixedLayout extends HTMLElement {
198211
return true
199212
}
200213
}
214+
#determineOddPages() {
215+
if (this.#oddPages !== 'recto' && this.#oddPages !== 'verso') {
216+
this.#oddPages = 'recto'
217+
const firstPageSpread = this.book.sections[0]?.pageSpread
218+
if (this.#rtl && firstPageSpread === 'right' || !this.#rtl && firstPageSpread === 'left') {
219+
this.#oddPages = 'verso'
220+
}
221+
}
222+
}
223+
#respread() {
224+
if (this.spread === 'none')
225+
this.#spreads = this.book.sections.map(section => ({ center: section }))
226+
else {
227+
const rtl = this.#rtl
228+
const ltr = !this.#rtl
229+
const oddPagesVerso = this.#oddPages === 'verso'
230+
231+
//Work out first page position based on settings and epub standard assumptions
232+
let firstPageSpread = this.book.sections[0]?.pageSpread
233+
|| (ltr && oddPagesVerso || rtl && !oddPagesVerso ? 'left' : 'right')
234+
235+
//Determine if the spread must be flipped (never flip based on just embedded pagination direction)
236+
const flipSpreads = this.#oddPages === 'recto' && (ltr && firstPageSpread === 'left' || rtl && firstPageSpread === 'right')
237+
|| this.#oddPages === 'verso' && (ltr && firstPageSpread === 'right' || rtl && firstPageSpread === 'left')
238+
239+
this.#spreads = this.book.sections.reduce((arr, section, i) => {
240+
const last = arr[arr.length - 1]
241+
const isFirstPage = !i
242+
243+
let { pageSpread } = section
244+
if (!pageSpread && isFirstPage) pageSpread = firstPageSpread
245+
if (flipSpreads) {
246+
if (pageSpread === 'left') pageSpread = 'right'
247+
else if (pageSpread === 'right') pageSpread = 'left'
248+
}
249+
250+
const newSpread = () => {
251+
const spread = {}
252+
arr.push(spread)
253+
return spread
254+
}
255+
256+
if (pageSpread === 'center') {
257+
const spread = newSpread()
258+
spread.center = section
259+
}
260+
else if (pageSpread === 'left') {
261+
const spread = !last || last.center || last.left || ltr ? newSpread() : last
262+
spread.left = section
263+
}
264+
else if (pageSpread === 'right') {
265+
const spread = !last || last.center || last.right || rtl ? newSpread() : last
266+
spread.right = section
267+
}
268+
else if (ltr) {
269+
if (!last || last.center || last.right) newSpread().left = section
270+
else last.right = section
271+
}
272+
else {
273+
if (!last || last.center || last.left) newSpread().right = section
274+
else last.left = section
275+
}
276+
return arr
277+
}, [])
278+
}
279+
}
280+
respread() {
281+
this.#respread()
282+
this.goToSpread(this.#index, this.#side, 'respread')
283+
}
201284
open(book) {
202285
this.book = book
203286
const { rendition } = book
204-
this.spread = rendition?.spread
287+
this.spread = this.getAttribute('spread')
288+
if (!this.spread || this.spread === 'auto') this.spread = rendition?.spread
205289
this.defaultViewport = rendition?.viewport
206-
207-
const rtl = book.dir === 'rtl'
208-
const ltr = !rtl
209-
this.rtl = rtl
210-
211-
if (rendition?.spread === 'none')
212-
this.#spreads = book.sections.map(section => ({ center: section }))
213-
else this.#spreads = book.sections.reduce((arr, section, i) => {
214-
const last = arr[arr.length - 1]
215-
const { pageSpread } = section
216-
const newSpread = () => {
217-
const spread = {}
218-
arr.push(spread)
219-
return spread
220-
}
221-
if (pageSpread === 'center') {
222-
const spread = last.left || last.right ? newSpread() : last
223-
spread.center = section
224-
}
225-
else if (pageSpread === 'left') {
226-
const spread = last.center || last.left || ltr && i ? newSpread() : last
227-
spread.left = section
228-
}
229-
else if (pageSpread === 'right') {
230-
const spread = last.center || last.right || rtl && i ? newSpread() : last
231-
spread.right = section
232-
}
233-
else if (ltr) {
234-
if (last.center || last.right) newSpread().left = section
235-
else if (last.left || !i) last.right = section
236-
else last.left = section
237-
}
238-
else {
239-
if (last.center || last.left) newSpread().right = section
240-
else if (last.right || !i) last.left = section
241-
else last.right = section
242-
}
243-
return arr
244-
}, [{}])
290+
this.#rtl = book.dir === 'rtl'
291+
this.#determineOddPages()
292+
this.#respread()
245293
}
246294
get index() {
247295
const spread = this.#spreads[this.#index]
@@ -264,7 +312,7 @@ export class FixedLayout extends HTMLElement {
264312
}
265313
async goToSpread(index, side, reason) {
266314
if (index < 0 || index > this.#spreads.length - 1) return
267-
if (index === this.#index) {
315+
if (index === this.#index && reason !== 'respread') {
268316
this.#render(side)
269317
return
270318
}
@@ -298,12 +346,12 @@ export class FixedLayout extends HTMLElement {
298346
await this.goToSpread(index, side)
299347
}
300348
async next() {
301-
const s = this.rtl ? this.#goLeft() : this.#goRight()
302-
if (!s) return this.goToSpread(this.#index + 1, this.rtl ? 'right' : 'left', 'page')
349+
const s = this.#rtl ? this.#goLeft() : this.#goRight()
350+
if (!s) return this.goToSpread(this.#index + 1, this.#rtl ? 'right' : 'left', 'page')
303351
}
304352
async prev() {
305-
const s = this.rtl ? this.#goRight() : this.#goLeft()
306-
if (!s) return this.goToSpread(this.#index - 1, this.rtl ? 'left' : 'right', 'page')
353+
const s = this.#rtl ? this.#goRight() : this.#goLeft()
354+
if (!s) return this.goToSpread(this.#index - 1, this.#rtl ? 'left' : 'right', 'page')
307355
}
308356
getContents() {
309357
return Array.from(this.#root.querySelectorAll('iframe'), frame => ({

0 commit comments

Comments
 (0)