Skip to content

Commit

Permalink
updated: refactor the router logic
Browse files Browse the repository at this point in the history
  • Loading branch information
GianlucaGuarini committed Oct 20, 2023
1 parent 17e7eac commit cdfcc06
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 96 deletions.
1 change: 1 addition & 0 deletions .eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ extends: eslint-config-riot

rules:
fp/no-mutating-methods: 0
fp/no-rest-parameters: 0
105 changes: 105 additions & 0 deletions src/components/router-hoc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { router } from '../index.js'
import { defer, cancelDefer, getAttribute } from '../util.js'
import { __ } from 'riot'
import getCurrentRoute from '../get-current-route.js'
import setBase from '../set-base.js'
import { panic } from '@riotjs/util/misc'
import initDomListeners from '../dom.js'

const BASE_ATTRIBUTE_NAME = 'base'
const INITIAL_ROUTE = 'initialRoute'
const ON_STARTED_ATTRIBUTE_NAME = 'onStarted'
const { template, bindingTypes } = __.DOMBindings

export function routerHoc({ slots, attributes, props }) {
if (routerHoc.wasInitialized)
panic('Multiple <router> components are not supported')

return {
slot: null,
el: null,
teardown: null,
mount(el, context) {
const initialRouteAttr = getAttribute(attributes, INITIAL_ROUTE)
const initialRoute = initialRouteAttr
? initialRouteAttr.evaluate(context)
: null
const currentRoute = getCurrentRoute()
const onFirstRoute = () => {
this.createSlot(context)
router.off.value(onFirstRoute)
}
routerHoc.wasInitialized = true

this.el = el
this.teardown = initDomListeners(this.root)

this.setBase(context)

// mount the slots only if the current route was defined
if (currentRoute && !initialRoute) {
this.createSlot(context)
} else {
router.on.value(onFirstRoute)
router.push(initialRoute || window.location.href)
}
},
createSlot(context) {
if (!slots || !slots.length) return
const onStartedAttr = getAttribute(attributes, ON_STARTED_ATTRIBUTE_NAME)

this.slot = template(null, [
{
type: bindingTypes.SLOT,
name: 'default',
},
])

this.slot.mount(
this.el,
{
slots,
},
context,
)

if (onStartedAttr) {
onStartedAttr.evaluate(context)(getCurrentRoute())
}
},
update(context) {
this.setBase(context)

// defer the updates to avoid internal recursive update calls
// see https://github.com/riot/route/issues/148
if (this.slot) {
cancelDefer(this.deferred)

this.deferred = defer(() => {
this.slot.update({}, context)
})
}
},
unmount(...args) {
this.teardown()
routerHoc.wasInitialized = false

if (this.slot) {
this.slot.unmount(...args)
}
},
getBase(context) {
const baseAttr = getAttribute(attributes, BASE_ATTRIBUTE_NAME)

return baseAttr
? baseAttr.evaluate(context)
: this.el.getAttribute(BASE_ATTRIBUTE_NAME) || '/'
},
setBase(context) {
setBase(props ? props.base : this.getBase(context))
},
}
}

// flag to avoid multiple router instances
routerHoc.wasInitialized = false
99 changes: 3 additions & 96 deletions src/components/router-hoc.riot
Original file line number Diff line number Diff line change
@@ -1,101 +1,8 @@
<router-hoc>
<script>
import {router} from '../index.js'
import {defer, cancelDefer} from '../util.js'
import {pure, __} from 'riot'
import getCurrentRoute from '../get-current-route.js'
import setBase from '../set-base.js'
import {panic} from '@riotjs/util/misc'
import {dashToCamelCase} from '@riotjs/util/strings'
import initDomListeners from '../dom.js'
import { pure } from 'riot'
import { routerHoc } from './router-hoc.js'
const BASE_ATTRIBUTE_NAME = 'base'
const INITIAL_ROUTE = 'initialRoute'
const ON_STARTED_ATTRIBUTE_NAME = 'onStarted'
const {template, bindingTypes} = __.DOMBindings
let wasInitialized = false
export default pure(({slots, attributes, props}) => {
if (wasInitialized) panic('Multiple <router> components are not supported')
const getAttribute = name => attributes && attributes.find(a => dashToCamelCase(a.name) === name)
return {
slot: null,
el: null,
teardown: null,
mount(el, context) {
const initialRouteAttr = getAttribute(INITIAL_ROUTE)
const initialRoute = initialRouteAttr ? initialRouteAttr.evaluate(context) : null
const currentRoute = getCurrentRoute()
const onFirstRoute = () => {
this.createSlot(context)
router.off.value(onFirstRoute)
}
wasInitialized = true
this.el = el
this.teardown = initDomListeners(this.root)
this.setBase(context)
// mount the slots only if the current route was defined
if (currentRoute && !initialRoute) {
this.createSlot(context)
} else {
router.on.value(onFirstRoute)
router.push(initialRoute || window.location.href)
}
},
createSlot(context) {
if (!slots || !slots.length) return
const onStartedAttr = getAttribute(ON_STARTED_ATTRIBUTE_NAME)
this.slot = template(null, [{
type: bindingTypes.SLOT,
name: 'default'
}])
this.slot.mount(this.el, {
slots
}, context)
if (onStartedAttr) {
onStartedAttr.evaluate(context)(getCurrentRoute())
}
},
update(context) {
this.setBase(context)
// defer the updates to avoid internal recursive update calls
// see https://github.com/riot/route/issues/148
if (this.slot) {
cancelDefer(this.deferred)
this.deferred = defer(() => {
this.slot.update({}, context)
})
}
},
unmount(...args) {
this.teardown()
wasInitialized = false
if (this.slot) {
this.slot.unmount(...args)
}
},
getBase(context) {
const baseAttr = getAttribute(BASE_ATTRIBUTE_NAME)
return baseAttr ? baseAttr.evaluate(context) : this.el.getAttribute(BASE_ATTRIBUTE_NAME) || '/'
},
setBase(context) {
setBase(props ? props.base : this.getBase(context))
}
}
})
export default pure(routerHoc)
</script>
</router-hoc>
5 changes: 5 additions & 0 deletions src/util.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { dashToCamelCase } from '@riotjs/util/strings'

export const getGlobal = () => getWindow() || global
export const getWindow = () => (typeof window === 'undefined' ? null : window)
export const getDocument = () =>
Expand All @@ -20,3 +22,6 @@ export const cancelDefer = (() => {

return globalScope.cancelAnimationFrame || globalScope.clearTimeout
})()

export const getAttribute = (attributes, name) =>
attributes && attributes.find((a) => dashToCamelCase(a.name) === name)

0 comments on commit cdfcc06

Please sign in to comment.