Skip to content

Commit

Permalink
Merge pull request #162 from marp-team/keep-sync-query
Browse files Browse the repository at this point in the history
Keep "sync" query between navigations
  • Loading branch information
yhatt authored Nov 6, 2019
2 parents 6643333 + 12307cf commit 67da269
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 48 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
### Fixed

- Navigate twice when hitting space bar after clicked next button on OSC ([#156](https://github.com/marp-team/marp-cli/issues/156), [#181](https://github.com/marp-team/marp-cli/pull/181))
- Keep generated `sync` query between navigations ([#162](https://github.com/marp-team/marp-cli/pull/162))

### Changed

Expand Down
10 changes: 8 additions & 2 deletions src/templates/bespoke/bespoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import bespokeProgress from './progress'
import bespokeState from './state'
import bespokeSync from './sync'
import bespokeTouch from './touch'
import { readQuery } from './utils'
import { popQuery, setQuery } from './utils'

export default function(target = document.getElementById('p')!) {
const key = popQuery('sync') || undefined

const deck = bespoke.from(target, [
bespokeInteractive,
bespokeClasses,
Expand All @@ -26,9 +28,13 @@ export default function(target = document.getElementById('p')!) {
bespokeTouch(),
bespokeOSC(),
bespokeFragments,
bespokeSync({ key: readQuery('sync') || undefined }),
bespokeSync({ key }),
])

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

return deck
}
49 changes: 11 additions & 38 deletions src/templates/bespoke/state.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { generateURLfromParams, readQuery } from './utils'
import { readQuery, setQuery } from './utils'

export interface BespokeStateOption {
history?: boolean
Expand All @@ -12,17 +12,6 @@ const coerceInt = (ns: string) => {
export default function bespokeState(opts: BespokeStateOption = {}) {
const options: BespokeStateOption = { history: true, ...opts }

const updateState = (...args: Parameters<typeof history['pushState']>) => {
try {
options.history
? history.pushState(...args)
: history.replaceState(...args)
} catch (e) {
// Safari may throw SecurityError by replacing state 100 times per 30 seconds.
console.error(e)
}
}

return deck => {
let internalNavigation = true

Expand Down Expand Up @@ -59,18 +48,15 @@ export default function bespokeState(opts: BespokeStateOption = {}) {
deck.on('fragment', ({ index, fragmentIndex }) => {
if (internalNavigation) return

const params = new URLSearchParams(location.search)

if (fragmentIndex === 0) {
params.delete('f')
} else {
params.set('f', fragmentIndex.toString())
}

updateState(
null,
document.title,
generateURLfromParams(params, { ...location, hash: `#${index + 1}` })
setQuery(
{ f: fragmentIndex === 0 || fragmentIndex.toString() },
{
location: { ...location, hash: `#${index + 1}` },
setter: (...args) =>
options.history
? history.pushState(...args)
: history.replaceState(...args),
}
)
})

Expand All @@ -80,20 +66,7 @@ export default function bespokeState(opts: BespokeStateOption = {}) {
window.addEventListener('hashchange', () =>
navInternally(() => {
parseState({ fragment: false })

// f parameter has to remove
const params = new URLSearchParams(location.search)
params.delete('f')

try {
history.replaceState(
null,
document.title,
generateURLfromParams(params)
)
} catch (e) {
console.error(e)
}
setQuery({ f: undefined }) // f parameter has to remove
})
)

Expand Down
46 changes: 45 additions & 1 deletion src/templates/bespoke/utils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,54 @@
type LocationLike = Pick<
Location,
'protocol' | 'host' | 'pathname' | 'hash' | 'search'
>
type QuerySetter = (...args: Parameters<History['pushState']>) => void

const replacer: QuerySetter = (...args) => history.replaceState(...args)

export const generateURLfromParams = (
params: URLSearchParams,
{ protocol, host, pathname, hash }: Location = location
{ protocol, host, pathname, hash }: LocationLike = location
) => {
const q = params.toString()
return `${protocol}//${host}${pathname}${q ? '?' : ''}${q}${hash}`
}

export const readQuery = (name: string) =>
new URLSearchParams(location.search).get(name)

export const popQuery = (name: string) => {
const value = readQuery(name)
setQuery({ [name]: undefined })

return value
}

export const setQuery = (
queries: Record<string, string | false | null | undefined>,
opts: { location?: LocationLike; setter?: QuerySetter } = {}
) => {
const options = { location, setter: replacer, ...opts }
const params = new URLSearchParams(options.location.search)

for (const k of Object.keys(queries)) {
const value = queries[k]

if (typeof value === 'string') {
params.set(k, value)
} else {
params.delete(k)
}
}

try {
options.setter(
null,
document.title,
generateURLfromParams(params, options.location)
)
} catch (e) {
// Safari may throw SecurityError by replacing state 100 times per 30 seconds.
console.error(e)
}
}
19 changes: 12 additions & 7 deletions test/templates/bespoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -658,19 +658,24 @@ describe("Bespoke template's browser context", () => {
})

it('updates reference count stored in localStorage', () => {
let deck
let anotherDeck

replaceLocation('/?sync=test', () => {
const deck = bespoke()
deck = bespoke()
expect(getStore('test').reference).toBe(1)
})

const anotherDeck = bespoke(document.createElement('div'))
replaceLocation('/?sync=test', () => {
anotherDeck = bespoke(document.createElement('div'))
expect(getStore('test').reference).toBe(2)
})

anotherDeck.destroy()
expect(getStore('test').reference).toBe(1)
anotherDeck.destroy()
expect(getStore('test').reference).toBe(1)

deck.destroy()
expect(getStore('test')).toBeNull()
})
deck.destroy()
expect(getStore('test')).toBeNull()
})

it('stores the state of slide progress by navigation', () => {
Expand Down

0 comments on commit 67da269

Please sign in to comment.