From 127944819c57fdfc538dfabd815e185cb361ecd8 Mon Sep 17 00:00:00 2001 From: gianlucaguarini Date: Fri, 17 Nov 2023 22:59:24 +0100 Subject: [PATCH] fixed: Computed path attributes and invalid query selector strings autoscrolling --- src/components/route-hoc.js | 14 ++++++++++---- src/util.js | 4 ++++ test/components.spec.js | 24 ++++++++++++++++++++++++ test/components/computed-routes.riot | 21 +++++++++++++++++++++ 4 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 test/components/computed-routes.riot diff --git a/src/components/route-hoc.js b/src/components/route-hoc.js index 72365da..f7df1c5 100644 --- a/src/components/route-hoc.js +++ b/src/components/route-hoc.js @@ -9,7 +9,11 @@ import { import $ from 'bianco.query' import getCurrentRoute from '../get-current-route.js' import { get as getAttr } from 'bianco.attr' -import { createDefaultSlot, getAttribute } from '../util.js' +import { + createDefaultSlot, + getAttribute, + isValidQuerySelectorString, +} from '../util.js' import compose from 'cumpa' const getInitialRouteValue = (pathToRegexp, path, options) => { @@ -42,7 +46,8 @@ export const routeHoc = ({ slots, attributes }) => { // create the component state const currentRoute = getCurrentRoute() const path = - getAttribute(attributes, PATH_ATTRIBUTE) || getAttr(el, PATH_ATTRIBUTE) + getAttribute(attributes, PATH_ATTRIBUTE)?.evaluate(context) || + getAttr(el, PATH_ATTRIBUTE) const pathToRegexp = toRegexp(path, []) const state = { pathToRegexp, @@ -127,11 +132,12 @@ export const routeHoc = ({ slots, attributes }) => { // if this route component was already mounted we need to update it if (prevRoute) this.slot.update({}, this.context) - // this route component was never mounted so we need to create its DOM + // this route component was never mounted, so we need to create its DOM else this.mountSlot() // emulate the default browser anchor links behaviour - if (route.hash) $(route.hash)?.[0].scrollIntoView() + if (route.hash && isValidQuerySelectorString(route.hash)) + $(route.hash)?.[0].scrollIntoView() }, callLifecycleProperty(method, ...params) { const attr = getAttribute(attributes, method) diff --git a/src/util.js b/src/util.js index bc10d34..4e3afc5 100644 --- a/src/util.js +++ b/src/util.js @@ -41,3 +41,7 @@ export const createDefaultSlot = (attributes = []) => { }, ]) } + +// True if the selector string is valid +export const isValidQuerySelectorString = (selector) => + /^([a-zA-Z0-9-_*#.:[\]\s>+~()='"]|\\.)+$/.test(selector) diff --git a/test/components.spec.js b/test/components.spec.js index 314d2e9..0e4bd5e 100644 --- a/test/components.spec.js +++ b/test/components.spec.js @@ -4,6 +4,7 @@ import NestedUpdates from './components/nested-updates.riot' import RecursiveUpdatesBugRouter from './components/recursive-updates-bug-router.riot' import StaticBasePath from './components/static-base-path.riot' import SameRouteMatches from './components/same-route-matches.riot' +import ComputedRoutes from './components/computed-routes.riot' import { component } from 'riot' import { expect } from 'chai' import { router, defaults } from '../src/index.js' @@ -105,4 +106,27 @@ describe('components', function () { comp.unmount() }) + + it('Computed routes get properly rendered', async function () { + const el = document.createElement('div') + const comp = component(ComputedRoutes)(el) + + expect(comp.$('p')).to.be.not.ok + + router.push('/home') + + await sleep() + + expect(comp.$('p')).to.be.ok + + await sleep() + + router.push('/') + + await sleep() + + expect(comp.$('p')).to.be.not.ok + + comp.unmount() + }) }) diff --git a/test/components/computed-routes.riot b/test/components/computed-routes.riot new file mode 100644 index 0000000..d719132 --- /dev/null +++ b/test/components/computed-routes.riot @@ -0,0 +1,21 @@ + + + +

{state.name}

+
+
+ +