Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize bespoke template for bfcache #323

Merged
merged 6 commits into from
Feb 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Fixed

- Optimize bespoke template for bfcache ([#323](https://github.com/marp-team/marp-cli/pull/323))

## v0.23.2 - 2021-02-11

### Changed
Expand Down
18 changes: 8 additions & 10 deletions src/templates/bespoke/bespoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@ import bespokeProgress from './progress'
import bespokeState from './state'
import bespokeSync from './sync'
import bespokeTouch from './touch'
import { getViewMode, popQuery, setQuery, setViewMode, ViewMode } from './utils'
import { getViewMode, popQuery, setViewMode, ViewMode } from './utils'
import bespokeWakeLock from './wake-lock'

const pattern = [ViewMode.Normal, ViewMode.Presenter, ViewMode.Next] as const

const parse = (
...patterns: [[boolean, boolean, boolean], (...args: unknown[]) => void][]
...patterns: [
[normalView: boolean, presnterView: boolean, nextView: boolean],
(...args: unknown[]) => void
][]
) => {
const idx = pattern.findIndex((v) => getViewMode() === v)
const idx = [ViewMode.Normal, ViewMode.Presenter, ViewMode.Next].findIndex(
(v) => getViewMode() === v
)
if (idx < 0) throw new Error('Invalid view')

return patterns.map(([pat, plugin]) => pat[idx] && plugin).filter((p) => p)
Expand Down Expand Up @@ -56,10 +59,5 @@ export default function bespokeTemplate(
)
)

window.addEventListener('beforeunload', () =>
setQuery({ sync: deck.syncKey })
)
window.addEventListener('unload', () => deck.destroy())

return deck
}
1 change: 0 additions & 1 deletion src/templates/bespoke/presenter/next-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,4 @@ export default function nextView(deck) {
}

window.addEventListener('message', listener)
deck.on('destroy', () => window.removeEventListener('message', listener))
}
28 changes: 22 additions & 6 deletions src/templates/bespoke/sync.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { nanoid } from 'nanoid'
import { FragmentEvent } from './fragments'
import { storage } from './utils'
import { storage, setHistoryState } from './utils'

export interface BespokeSyncOption {
key?: string
Expand All @@ -13,9 +12,15 @@ export interface BespokeSyncState {
}

export default function bespokeSync(opts: BespokeSyncOption = {}) {
const key = opts.key || nanoid()
const key =
opts.key ||
window.history.state?.marpBespokeSyncKey ||
Math.random().toString(36).slice(2)

const storageKey = `bespoke-marp-sync-${key}`

setHistoryState({ marpBespokeSyncKey: key })

const getState = (): Partial<BespokeSyncState> => {
const stateJSON = storage.get(storageKey)
if (!stateJSON) return Object.create(null)
Expand All @@ -33,10 +38,14 @@ export default function bespokeSync(opts: BespokeSyncOption = {}) {
return newState
}

// Initialize or increase reference count
setState((prev) => ({ reference: (prev.reference || 0) + 1 }))
const initialize = () => {
window.removeEventListener('pageshow', initialize)
setState((prev) => ({ reference: (prev.reference || 0) + 1 }))
}

return (deck) => {
initialize()

Object.defineProperty(deck, 'syncKey', {
value: key,
enumerable: true,
Expand Down Expand Up @@ -73,14 +82,21 @@ export default function bespokeSync(opts: BespokeSyncOption = {}) {
}
})

deck.on('destroy', () => {
const destructor = () => {
const { reference } = getState()

if (reference === undefined || reference <= 1) {
storage.remove(storageKey)
} else {
setState(() => ({ reference: reference - 1 }))
}
}

window.addEventListener('pagehide', (e: PageTransitionEvent) => {
if (e.persisted) window.addEventListener('pageshow', initialize)
destructor()
})

deck.on('destroy', destructor)
}
}
7 changes: 5 additions & 2 deletions src/templates/bespoke/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ export const setQuery = (

try {
options.setter(
null,
document.title,
{ ...(window.history.state ?? {}) },
'',
generateURLfromParams(params, options.location)
)
} catch (e) {
Expand All @@ -73,6 +73,9 @@ export const setQuery = (
}
}

export const setHistoryState = (state: Record<string, any>) =>
setQuery({}, { setter: (s, ...r) => replacer({ ...s, ...state }, ...r) })

export const setViewMode = () =>
document.body.setAttribute(
viewAttr,
Expand Down
24 changes: 24 additions & 0 deletions test/templates/bespoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ beforeAll(() => {
})

afterEach(() => {
window.dispatchEvent(
new PageTransitionEvent('pagehide', { persisted: false })
)
window.dispatchEvent(new Event('unload'))
jest.restoreAllMocks()
jest.clearAllTimers()
Expand Down Expand Up @@ -967,6 +970,8 @@ describe("Bespoke template's browser context", () => {
beforeEach(() => render(markdown))

it('defines auto-generated deck.syncKey', () => {
jest.spyOn(history, 'state', 'get').mockImplementation(() => null)

const deck = bespoke()
expect(typeof deck.syncKey).toBe('string')
})
Expand Down Expand Up @@ -1066,6 +1071,25 @@ describe("Bespoke template's browser context", () => {
})
})

describe('when leaved from the slide with bfcache', () => {
it('adds event listener for pageshow event to increment reference count', () => {
replaceLocation('/?sync=bfcache', () => {
bespoke()
expect(getStore('bfcache').reference).toBe(1)

window.dispatchEvent(
new PageTransitionEvent('pagehide', { persisted: true })
)
expect(getStore('bfcache')).toBeNull()

window.dispatchEvent(
new PageTransitionEvent('pageshow', { persisted: true })
)
expect(getStore('bfcache').reference).toBe(1)
})
})
})

describe('when the quota of storage has limited', () => {
beforeEach(() => {
// Eat up to the default quota
Expand Down