GithubHelp home page GithubHelp logo

neetjn / riot-view-router Goto Github PK

View Code? Open in Web Editor NEW
9.0 4.0 3.0 467 KB

Lightweight, extensive state based riot.js router for tag views.

Home Page: https://neetjn.github.io/riot-view-router/

License: MIT License

JavaScript 100.00%
riotjs riot router javascript nodejs es6 babel state state-machine

riot-view-router's Introduction

riot-view-router

npm

build npm version codecov Join the chat at https://gitter.im/riot-view-router/Lobby

NPM

This project only supports Riot.js 3.x and is no longer maintained, for Riot.js 4.x see riot-routing.

About

riot-view-router is a lightweight, extensive state based riot.js router for tag views. It was designed after the ui-router project, with all the quirks of riot.js.

This project makes use of the HTML5 history api, using pushState under the hood; in other words this is a client sided router.

Support

Chome Edge Firefox Opera Safari
5.0+ ✔ 4.0+ ✔ 11.50+ ✔ 5.0+ ✔

Examples

  • riot-todo: Todo web app created with riot.js, skeletoncss, animate.css, and foundation-icons.

Usage

To install via Bower, simply do the following:

bower install riot-view-router

To install via NPM:

npm install riot-view-router

For a quick start using jsdelivr:

<script src="https://cdn.jsdelivr.net/npm/riot-view-router/dist/riot-view-router.min.js"></script>

riot-view-router supports the following settings,

*default ; string : Default state for router to navigate to on start if route not matched.

debugging ; bool : Will default to true, spits errors and warnings to console.

href ; string : Will default to originating location, router will operate off of this.

fragments ; bool : Will default to true, adds support for fragment identification.

fallback ; string : Will default to fallback, state to fallback to on mismatch.

title ; string : Title prefix for routes using a page title.

marker ; string : Marker for mounting views, default is r-view.

<r-view />

or

<div r-view></div>

States are composed of the following properties,

*name ; string : State name.

*route ; string : Route to match state by.

*tag ; string : Tag to inject into rout view, mount.

title ; string : Title suffix for routes.

onEnter(*handler) ; function : Callback for entering state.

onLeave(*handler) ; function : Callback for leaving state.

Using the mixin is then as simple as,

import riot from 'riot'
import Router from 'riot-view-router'

const router = new Router(riot, {
  debugging: true,
  default: 'home',
  fallback: '404',
  href: 'https://mysite.com/blogs'
})

router.add({
  name: '404',
  route: '/notfound',
  tag:'not-found',
  title: '404 Page Not Found',
  onLeave: (state) => {
    console.log('Leaving home')
  }
})

router.add([
  {
    name: 'home',
    route: '/',
    tag:'home',
    title: 'Hello World',
    onEnter: (state) => {
      console.log('Entering home')
    }
  },
  {
    name: 'profile',
    route: '/profile/:username',
    tag: 'profile',
    title: '<username>\'s profile'
  }
])

You may then access the Router instance via your tags with router like so,

<app>
  <r-view></r-view>

  this.router.start()
</app>

To navigate to a route within your riot tags, you may use r-sref to reference a state on any element supporting a click event listener. r-sref can be used with both complete routes and state names.

<sometag>
  <button r-sref="/profile/{username}">Navigate to profile</button>
  <a r-sref="about">About Page</a>
</sometag>

You may also use a general anchor tag, the router comes with a helper function baked in to help construct urls on the fly. It also supports url encoding.

<sometag>
  <a href={ route(['profile', username]) }>Profile</a>
</sometag>

Both route and query string variables can also be accessed directly via the target tag with opts. Take for example navigating to the url .../!#/profile/john?views=1 with the route pattern /profile/:username.

<profile>
  <h1>
    User: <small>{this.opts.username}</small>
  </h1>
  <h5>Views: {this.opts.qargs.views}</h5>
</profile>

Router API

The riot-view-router has a very simple, easily operable API.

add(*state): Create a new state for the given router instance.

navigate(*route, skipPush): Navigate to a given route.

push(name, opts): Invoke a state change. If arguments arent specified, automatically detect the state and extract opts from the defined state variables.

start(): Start router, listen on window hash changes.

stop(): Stop router, related listeners and lifecycle events.

reload(): Reload current route.

on(*event, *handler): Register a lifecycle event (start, stop, navigation, push, transition).

Router Observable

This router supports the following observable events,

start: Triggered when the router is started.

stop: Triggered when the router is stopped.

reload: Triggered when a route is reloaded.

navigate: Trigerred when navigation occurs.

push: Triggered when pushing a new state.

transition: Triggered when transitioning into a new state, emits an optional argument state.

<Header>
  <nav>
    <ul>
      <li each={ route in routes }
          class={ is-active: route.active }
          r-sref={ route.state }>
        { route.label }
      </li>
    </ul>
  </nav>
  <script type="es6">
    const self = this

    self.routes = [
      { label: 'Home', state: 'home', active: false },
      { label: 'About', state: 'about', active: false },
      { label: 'Help', state: 'help', active: false },      
    ]
    // middleware for toggling nav items
    self.router.on('transition', state => {
      self.routes.forEach(route => {
        route.active = false
      })
      const s = self.routes.find(i => i.name == state.name)
      if(s)
        s.active = true

      self.update()
    })
  </script>
</Header>

Contributors

Contributing guidelines are as follows,

  • Any new features must include either a unit test, e2e test, or both.

    • Branches for bugs and features should be structured like so, issue-x-username.
  • Before putting in a pull request, be sure to verify you've built all your changes.

    Travis will build your changes before testing and publishing, but bower pulls from this repository directly.

  • Include your name and email in the contributors list.


Copyright (c) 2017 John Nolette Licensed under the MIT license.

riot-view-router's People

Contributors

gitter-badger avatar neetjn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

riot-view-router's Issues

Replace error with proper promise rejection and log error for default state check

When reworking the start api method to allow for the new add method, I coincidentally forgot to replace the error thrown with a proper promise rejection and log the error. It's not a pressing issue, the promise will still naturally be rejected so the error can be caught using .catch, but the core should be updated to properly log the error.

0.2.0 - Riot.js 4

After thoughtful consideration, it seems the best way to tackle integration with Riot 4 would be a complete re-write of the code code base.

Observations

  1. Observable: Riot.js 4 has fundamentally changed a number of coding paradigms birthed in Riot.js 1 - 3 with the observable. A push was made towards a more uniform lifecycle event pattern (see observable ). The issue standing is this project was deeply integrated into the Riot.js observable, so there there must be a redesign of how events are managed in version 0.2.0.

  2. Mounting: This project as it stands could very easily have been converted into a framework agnostic client sided router -- this is because it's "mounting" logic persists of simply appending a new node to the dom by name of the provided component. I'd also baked some hack unmount logic in there was this functionality was never directly provided by the Riot.js api. With the release of Riot.js 4 however, there are new features in the api that can leveraged to make this process much easier and predictable. See mount and unmount.

  3. Plugins: This project, like many other Rot.js "plugins" has an unorthodox methodology when it comes to instantiating the router and initializing the "plugin". In Riot.js 4, there's an official plugin api to help make this process more seemless. See install.

  4. Conditional Rendering: A scenario, not edge case that this project did not initially address. Going forward, the router should

Miscellaneous

  • Logging: As a mechanism for debugging, logging was implemented into this project. In retrospect, this functionality is not necessary and adds unnecessary weight to the core library.

Moving Forward

Each of this four observations addressed should extrapolated into related tasks in a roadmap. A new repository has been created (riot-routing), this repository will be archived.

Clean up constructor, move installation to router core.

The current api for "installing" a new router is a bit of a stretch; the specification for states is also rather unintuitive.

I would like to propose the exported module simply expose the router constructor, scrapping the "installation" procedure and mixin wrapper. We can move the creation of the mixin into the router constructor, as we're now passing in a riot.js instance regardless.

I would also like to propose a new core api method, add, to add a new state or list of states to the router.

Additionally, because we would no longer be taking any states in by the constructor, we can remove the states/options cross check for the default and fallback states and instead move that check into the start method.


Proposed changes sample

import Router from 'riot-view-router'

router = new Router(riot, {
  debugging: true,
  default: 'home',
  fallback: '404',
  href: 'https://mysite.com/blogs'
})

router.add({
  name: 'profile',
  route: '/profile/:username',
  tag: 'profile',
  title: '<username>\'s profile'
})

router.start()

Bug - On start, regardless of route the router will append hash to the url.

On start, regardless of route the router will append hash to the url.

This seems to be due to an invalid reference to the hash pattern in constants in the start method of the router core.

Line 212

       if (self.location.hash.split(self.$constants.hash).length !== 2) {
          self.navigate(
            self.$utils.stateByName(
              self.defaultState
            ).route.route, true).then(_start)
        }
        else
          _start()

Overhaul tests, replace Karma/Electron with Jest + Jest-Dom

  1. Describe your issue:

The tests should be overhauled to include more edge cases. The amount of resources required for testing is also staggering, the Karma + Electron setup should be replaced with Jest.

  1. Can you reproduce the issue?

  2. On which browser/OS does the issue appear?

  3. Which version of riot-view-router does it affect?

  4. How would you tag this issue?

  • Question
  • Bug
  • Discussion
  • Feature request
  • Tip
  • Enhancement
  • Performance

Include ability to generate anchor tag hrefs to state routes in prototype

An anchor marker, r-sref, will be processed in tag templates when tags are mounted. We may be able to toss this into a riot lifecycle event, otherwise in the transition process for the router.

Example,

const states = [{
  name: 'home',
  route: '/',
  tag: 'home-view'
  ...
}, {
  name: 'about',
  route: '/about',
  tag: 'about-view'
  ...
}]
<home-view>
  <h1>Hello World!</h1>
  <a r-sref="about">About</a>
</home-view>

becomes

<home-view>
  <h1>Hello World!</h1>
  <a href="#!/about">About</a>
</home-view>

Create utility to split and process routes

Rather than tossing regex everywhere and rewriting the same operations, a singular utility should be added to the utility class to process routes and split their location, query string,and fragment identifier.

Clean up dispatcher to support multiple observable methods

As it stands, the router's current observable events only support a single trigger method. The router should support as many trigger methods per event as the developer would like, I can see how the current behavior could be a handicap for larger projects.

After sitting on the idea, I've decided to replace the current observable logic with Riot's. There's no real gain in using our own at this point if it's going to mirror Riot's.

class Core(...) {
  constructor(...) {
    riot.observable(this)
  }
}

Resolve NPM security vulnerabilities

IMPORTANT

Your issue might be labeled as invalid and eventually closed if:

  • You have deleted completely the issue template for no reason
  • You can not reproduce the issue
  • Your question is not an issue nor a feature request but it's only a support/consulting request (use stack overflow for it)
  • Your post violates our code of conduct

Help us to manage our issues by answering the following:

  1. Describe your issue:

The NPM dependencies of this project must be updated due to security vulnerabilities in Electron.

  1. Can you reproduce the issue?

  2. On which browser/OS does the issue appear?

  3. Which version of riot-view-router does it affect?

  4. How would you tag this issue?

  • Question
  • Bug
  • Discussion
  • Feature request
  • Tip
  • Enhancement
  • Performance

Implement built-in logger

A built in logger should be created to retain logs and automatically log to the console if debugging is enabled, instead of tossing conditions everywhere.

Fix router start location flicker.

Noticed when using webpack dev server, also experienced on jsfiddle.

Observed Behavior: Router appends default state route onto existing route.
Expected Behavior: Router begins routing based on current route.

Create prototype for 0.0.1 release (Spec)

Initial pitch:

  • mixin will be injected into main view
  • mixin will contain router options/settings and components paths
  • on route match, we'll mount/unmount the view
  • the main view will have a custom dom with some attribute that we target to mount/unmount our views

This router should work for riot.js version 1, 2, and 3. This project is also actually loosely coupled with riot.js, simply being a mixin and assuming riot.js won't have a refactor anytime soon -- maintaining it shouldn't be that difficult.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.