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

Add bespoke sync plugin #145

Merged
merged 5 commits into from
Sep 10, 2019
Merged
Show file tree
Hide file tree
Changes from 2 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
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,17 @@
"@types/ws": "^6.0.2",
"@types/yargs": "^13.0.2",
"autoprefixer": "^9.6.1",
"bespoke": "^1.1.0",
"bespoke": "bespokejs/bespoke",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to use Bespoke.js from GitHub directly because Bespoke.prototype.destroy() is not defined in the latest release on npm.

"bespoke-forms": "^1.0.0",
"builtin-modules": "^3.1.0",
"cheerio": "^1.0.0-rc.3",
"codecov": "^3.5.0",
"cssnano": "^4.1.10",
"image-size": "^0.7.4",
"jest": "^24.9.0",
"jest-junit": "^7.0.0",
"jest-plugin-context": "^2.9.0",
"nanoid": "^2.1.0",
"npm-run-all": "^4.1.5",
"pkg": "^4.4.0",
"postcss-url": "^8.0.0",
Expand All @@ -97,6 +99,7 @@
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-postcss": "^2.0.3",
"rollup-plugin-pug": "^1.1.1",
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-terser": "^5.1.1",
"rollup-plugin-typescript": "^1.0.1",
"rollup-plugin-url": "^2.2.2",
Expand Down
40 changes: 22 additions & 18 deletions rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import autoprefixer from 'autoprefixer'
import builtinModules from 'builtin-modules'
import cssnano from 'cssnano'
import path from 'path'
import postcssUrl from 'postcss-url'
Expand All @@ -7,28 +8,25 @@ import json from 'rollup-plugin-json'
import nodeResolve from 'rollup-plugin-node-resolve'
import postcss from 'rollup-plugin-postcss'
import pugPlugin from 'rollup-plugin-pug'
import replace from 'rollup-plugin-replace'
import { terser } from 'rollup-plugin-terser'
import typescript from 'rollup-plugin-typescript'
import url from 'rollup-plugin-url'
import { dependencies } from './package.json'

const external = [
...Object.keys(dependencies),
'crypto',
'events',
'fs',
'os',
'path',
'querystring',
'url',
'util',
'chrome-launcher/dist/chrome-finder',
'yargs/yargs',
]

const plugins = [
const plugins = (opts = {}) => [
json({ preferConst: true }),
nodeResolve({ mainFields: ['module', 'jsnext:main', 'main'] }),
nodeResolve({
browser: !!opts.browser,
mainFields: ['module', 'jsnext:main', 'main'],
}),
replace({ 'process.env.NODE_ENV': JSON.stringify('production') }),
Copy link
Member Author

@yhatt yhatt Sep 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bundled nanoid package cannot work without replacing process.env.NODE_ENV.

See also: ai/nanoid#127 (comment)

commonjs(),
typescript({ resolveJsonModule: false }),
postcss({
Expand All @@ -48,28 +46,34 @@ const plugins = [
!process.env.ROLLUP_WATCH && terser(),
]

const browser = {
external,
plugins: plugins({ browser: true }),
}

const cli = {
external: [...builtinModules, ...external],
plugins: plugins(),
}

export default [
{
external,
plugins,
...browser,
input: 'src/templates/bespoke.js',
output: { file: 'lib/bespoke.js', format: 'iife' },
},
{
external,
plugins,
...browser,
input: 'src/templates/watch.js',
output: { file: 'lib/watch.js', format: 'iife' },
},
{
external,
plugins,
...browser,
input: 'src/server/server-index.js',
output: { file: 'lib/server/server-index.js', format: 'iife' },
},
{
external,
plugins,
...cli,
input: 'src/marp-cli.ts',
output: { exports: 'named', file: 'lib/marp-cli.js', format: 'cjs' },
},
Expand Down
9 changes: 8 additions & 1 deletion src/templates/bespoke/bespoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import bespokeHash from './hash'
import bespokeNavigation from './navigation'
import bespokeOSC from './osc'
import bespokeProgress from './progress'
import bespokeSync from './sync'
import bespokeTouch from './touch'
import { readQuery } from './utils'

export default function() {
window.addEventListener('load', () => document.body.classList.add('loaded'))

return bespoke.from(document.getElementById('presentation'), [
const deck = bespoke.from(document.getElementById('presentation'), [
bespokeForms(),
bespokeClasses,
bespokeInactive(),
Expand All @@ -24,5 +26,10 @@ export default function() {
bespokeTouch(),
bespokeOSC(),
bespokeFragments,
bespokeSync({ key: readQuery('sync') || undefined }),
])

window.addEventListener('unload', () => deck.destroy())

return deck
}
41 changes: 28 additions & 13 deletions src/templates/bespoke/fragments.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
// Based on https://github.com/bespokejs/bespoke-bullets
export interface FragmentEvent {
slide: any[]
index: number
fragments: any[]
fragmentIndex: number
}

// Based on https://github.com/bespokejs/bespoke-bullets
export default function bespokeFragments(deck) {
let activeSlideIdx = 0
let activeFragmentIdx = 0

const fragments = deck.slides.map(slide => [
null,
...slide.querySelectorAll('[data-marpit-fragment]'),
])
Object.defineProperty(deck, 'fragments', {
enumerable: true,
value: deck.slides.map(slide => [
null,
...slide.querySelectorAll('[data-marpit-fragment]'),
]),
})

const activeSlideHasFragmentByOffset = (offset: number) =>
fragments[activeSlideIdx][activeFragmentIdx + offset] !== undefined
deck.fragments[activeSlideIdx][activeFragmentIdx + offset] !== undefined

const activate = (slideIdx: number, fragmentIdx: number) => {
activeSlideIdx = slideIdx
activeFragmentIdx = fragmentIdx

fragments.forEach(
deck.fragments.forEach(
(slideFragments: (HTMLElement | null)[], slideCurrentIdx: number) => {
slideFragments.forEach((fragment, fragmentCurrentIdx) => {
if (fragment == null) return
Expand Down Expand Up @@ -45,12 +54,16 @@ export default function bespokeFragments(deck) {
}
)

deck.fire('fragment', {
deck.fragmentIndex = fragmentIdx

const fragmentEvent: FragmentEvent = {
slide: deck.slides[slideIdx],
index: slideIdx,
fragments: fragments[slideIdx],
fragments: deck.fragments[slideIdx],
fragmentIndex: fragmentIdx,
})
}

deck.fire('fragment', fragmentEvent)
}

deck.on('next', () => {
Expand All @@ -60,7 +73,7 @@ export default function bespokeFragments(deck) {
}

const nextIdx = activeSlideIdx + 1
if (fragments[nextIdx]) activate(nextIdx, 0)
if (deck.fragments[nextIdx]) activate(nextIdx, 0)
})

deck.on('prev', () => {
Expand All @@ -70,14 +83,16 @@ export default function bespokeFragments(deck) {
}

const prevIdx = activeSlideIdx - 1
if (fragments[prevIdx]) activate(prevIdx, fragments[prevIdx].length - 1)

if (deck.fragments[prevIdx])
activate(prevIdx, deck.fragments[prevIdx].length - 1)
})

deck.on('slide', ({ index, fragment }) => {
let fragmentPos = 0

if (fragment !== undefined) {
const slideFragments = fragments[index]
const slideFragments = deck.fragments[index]

if (slideFragments) {
const { length } = slideFragments
Expand Down
77 changes: 77 additions & 0 deletions src/templates/bespoke/sync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import nanoid from 'nanoid'
import { FragmentEvent } from './fragments'

export interface BespokeSyncOption {
key?: string
}

export interface BespokeSyncState {
reference: number
index: number
fragmentIndex: number
}

export default function bespokeSync(opts: BespokeSyncOption = {}) {
const key = opts.key || nanoid()
const storageKey = `bespoke-marp-sync-${key}`

const getState = (): Partial<BespokeSyncState> => {
const stateJSON = localStorage.getItem(storageKey)
if (!stateJSON) return Object.create(null)

return JSON.parse(stateJSON)
}

const setState = (
updater: (prevState: Partial<BespokeSyncState>) => Partial<BespokeSyncState>
) => {
const currentState = getState()
const newState = { ...currentState, ...updater(currentState) }

localStorage.setItem(storageKey, JSON.stringify(newState))
return newState
}

// Initialize or increase reference count
setState(prev => ({ reference: (prev.reference || 0) + 1 }))

return deck => {
Object.defineProperty(deck, 'syncKey', {
value: key,
enumerable: true,
})

// Update storage value to store current page and fragment index
// (Wrap by setTimeout to skip fragment event for initialization)
setTimeout(() => {
deck.on('fragment', (e: FragmentEvent) => {
setState(() => ({ index: e.index, fragmentIndex: e.fragmentIndex }))
})
}, 0)

// Listen "storage" event
window.addEventListener('storage', e => {
if (e.key === storageKey && e.oldValue && e.newValue) {
const prev: Partial<BespokeSyncState> = JSON.parse(e.oldValue)
const current: Partial<BespokeSyncState> = JSON.parse(e.newValue)

if (
prev.index !== current.index ||
prev.fragmentIndex !== current.fragmentIndex
) {
deck.slide(current.index, { fragment: current.fragmentIndex })
}
}
})

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

if (reference === undefined || reference <= 1) {
localStorage.removeItem(storageKey)
} else {
setState(() => ({ reference: reference - 1 }))
}
})
}
}
2 changes: 2 additions & 0 deletions src/templates/bespoke/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const readQuery = (name: string) =>
new URLSearchParams(location.search).get(name)
22 changes: 17 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1143,10 +1143,9 @@ bespoke-forms@^1.0.0:
resolved "https://registry.yarnpkg.com/bespoke-forms/-/bespoke-forms-1.0.0.tgz#fccdc60a1f7b598ed7df7c8efe554a4c4d8ce158"
integrity sha1-/M3GCh97WY7X33yO/lVKTE2M4Vg=

bespoke@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/bespoke/-/bespoke-1.1.0.tgz#7b0fb3cfff580220a0da4020138365a55f063b3c"
integrity sha1-ew+zz/9YAiCg2kAgE4NlpV8GOzw=
bespoke@bespokejs/bespoke:
version "1.2.0-dev"
resolved "https://codeload.github.com/bespokejs/bespoke/tar.gz/81c1da25210feca2a166ec782abcbf88ae969593"

big.js@^3.1.3:
version "3.2.0"
Expand Down Expand Up @@ -4815,6 +4814,11 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==

nanoid@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.0.tgz#3de3dbd68cfb2f3bd52550e2bfd439cf75040eb2"
integrity sha512-g5WwS+p6Cm+zQhO2YOpRbQThZVnNb7DDq74h8YDCLfAGynrEOrbx2E16dc8ciENiP1va5sqaAruqn2sN+xpkWg==

nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
Expand Down Expand Up @@ -6545,6 +6549,14 @@ rollup-plugin-pug@^1.1.1:
pug-runtime "^2.0.4"
rollup-pluginutils "^2.3.3"

rollup-plugin-replace@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz#f41ae5372e11e7a217cde349c8b5d5fd115e70e3"
integrity sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA==
dependencies:
magic-string "^0.25.2"
rollup-pluginutils "^2.6.0"

rollup-plugin-terser@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.1.1.tgz#e9d2545ec8d467f96ba99b9216d2285aad8d5b66"
Expand Down Expand Up @@ -6573,7 +6585,7 @@ rollup-plugin-url@^2.2.2:
mkpath "^1.0.0"
rollup-pluginutils "^2.8.1"

rollup-pluginutils@^2.0.1, rollup-pluginutils@^2.3.3, rollup-pluginutils@^2.5.0, rollup-pluginutils@^2.8.1:
rollup-pluginutils@^2.0.1, rollup-pluginutils@^2.3.3, rollup-pluginutils@^2.5.0, rollup-pluginutils@^2.6.0, rollup-pluginutils@^2.8.1:
version "2.8.1"
resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz#8fa6dd0697344938ef26c2c09d2488ce9e33ce97"
integrity sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg==
Expand Down