A tiny foundation that providing nested state-based routing for complex web application.

Overview

StateMan

Gitter

Build Status

stateman: A tiny foundation that provides nested state-based routing for complex web applications.

stateman is highly inspired by ui-router; you will find many features similar to it.

But stateman is a standalone library with an extremely tiny codebase (5kb minified). Feel free to integrate it with whatever framework you like!

Reference

Feature

  1. nested routing support.
  2. standalone with tiny codebase.
  3. async routing support if you need asynchronous logic in navigating. Support Promise
  4. html5 history supported, fallback to hash-based in old browser.
  5. concise API, deadly simple to getting start with it.
  6. support IE6+ and other modern browsers.
  7. well tested, born in large product.

Quick Start

You may need a static server to run the demo. puer is simple to get start.

just paste the code to your own index.html, and load it up in a browser.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>StateMan Test</title>
  <script src="https://rawgit.com/leeluolee/stateman/master/stateman.js"></script>
</head>
<body>

<ul>
  <li><a href="#/home">/home"</a></li>
  <li><a href="#/contact">/contact"</a></li>
  <li><a href="#/contact/list">/contact/list</a></li>
  <li><a href="#/contact/2">/contact/2</a></li>
  <li><a href="#/contact/2/option">/contact/2/option</a></li>
  <li><a href="#/contact/2/message">/contact/2/message</a></li>
</ul>
  
<script>
  var config = {
    enter: function(){
      console.log("enter: " + this.name)
    },
    leave: function(){
      console.log("leave: " + this.name)
    }
  }

  function create(o){
    o = o || {};
    o.enter= config.enter;
    o.leave = config.leave;
    return o;
  }

  var stateman = new StateMan();

  stateman
    .state("home", config)
    .state("contact", config)
    .state("contact.list", config )
    .state("contact.detail", create({url: ":id(\\d+)"}))
    .state("contact.detail.option", config)
    .state("contact.detail.message", config)
    .start({});
</script>
</body>
</html>

open the console to see the output when navigating.

Demos

###1. Simple Layout Demo:

The code in this demo is for demonstration only. In a production development, you will want a view layer to create nested views.

###2. A simple SPA built upon Regularjs (Living Template) + requirejs + stateman: Link

I create a simple wrapping (regular-state) to integrate stateman with Regularjs, which makes it easy to build a single Page Application. thanks to the concise API, the code is very clean. You will find that integrating stateman with other libraries is also simple.

Browser Support

  1. Modern browsers, including mobile devices
  2. IE6+

Installation

Bower

bower install stateman

stateman.js have been packaged as a standard UMD, so you can use it in AMD, CommonJS and as a global.

npm (browserify or other based on commonjs)

npm install stateman

To use:

var StateMan = require('stateman');

spm

spm install stateman

To use:

var StateMan = require('stateman');

Component

component install leeluolee/stateman

To use:

var StateMan = require('leeluolee/stateman');

Direct downloads

  1. stateman.js
  2. stateman.min.js

Examples

Some basic examples can be found in the examples directory.

run demo local

  1. clone this repo
  2. npm install gulp -g && npm install
  3. gulp server
  4. check the example folder

LICENSE

MIT.

ChangLog

Comments
  • stateman.nav(url, option, cb)这个函数的option参数好像没有用

    stateman.nav(url, option, cb)这个函数的option参数好像没有用

    RT,看了代码,也用API.html测试了一下,这个参数没有文档里讲的 { Example stateman.nav("/app/contact/1?name=leeluolee", {data: 1}); 最终传入到enter, leave与update的option参数会是{param: {id: "1", name:"leeluolee"}, data: 1}. } 这个作用。

    opened by tuoxiansp 4
  • 多级加载问题

    多级加载问题

    有三个状态"app",“app.list”,"app.list.info",都采用ajax加载内容进行更新。 1

    如上图的前端模式,请求#/app的时候将红色区域的html用ajax请求渲染到1中,请求#/app/list的时候将"app.list.info"用ajax请求渲染到3中。

    如果按照顺序先访问#/app,然后访问#/app/list 完全没有问题

    如果直接请求#app/list的时候会先请求#/app,然后请求#/app/list,这个时候由于同时执行2个ajax请求,如果第2个ajax先执行完毕就会导致无法渲染到3中,因为这个时候第一个ajax还没有执行完,也就是页面上还没有渲染1中的内容。

    这个问题应该怎么处理?

    question 
    opened by zanderpu 2
  • Cleanup and work coordination

    Cleanup and work coordination

    I found quite a few issues with code when was closely debugging some issues. I was thinking about cleaning up code and fixing these issues, and adding ESLint config to prevent these from cropping-in in future. But this will make any merges almost impossible.. Do you think you get to the point where you are "done" with changes for enough time for me to make few passes on improving quality of the code? So we do not work on the code base at the same time.

    enhancement 
    opened by hippich 2
  • Histery vs. History

    Histery vs. History

    I don't think that this library needs to call it "Histery." The only conflict would be window.history, but the lib is not attaching an instance of Histery to the global scope.

    I'd prefer it to be called History, 'cause it's more in line with what people would expect. Backbone, for instance, calls it Backbone.History.

    If you are :+1: @leeluolee I will make a PR.

    opened by jamesplease 2
  • `encode` explodes if state does not exist

    `encode` explodes if state does not exist

    stateman.encode('state-that-doesnt-exist')

    Uncaught TypeError: Cannot read property 'encode' of undefined

    This is a matter of preference, but I would probably return undefined.

    I'll PR this if you want to change it @leeluolee.

    opened by jamesplease 2
  • Promises

    Promises

    I think that the API around async methods is limited by the fact that this library assumes that Promises don't exist.

    @leeluolee, I understand that you have two priorities:

    1. Support old IEs
    2. Don't include a Promise library

    These are priorities that I, too, share. But I still build my libraries assuming Promises, because they are a familiar tool for devs, and they make for a much nicer API.

    What I do is require that the developer set Library.Promise before they can use the library, if they're in a legacy environment. Other popular libraries have adopted this pattern, too. Here's a good example.

    I would wager that a surprising number of developers use a Promise implementation in their source, so it's not creating too much extra effort for them, I think.

    This would allow you to get rid of the var done = this.async() pattern, and instead switch to: return myPromise;, which I find way nicer!

    Little summary of pros/cons...

    Pros:

    • Devs get to continue using Promises, which they're likely familiar with.
    • Devs don't need to learn this less-familiar, more-verbose pattern

    Cons:

    • Slightly more work setting up the library if you need to support older IEs
    enhancement 
    opened by jamesplease 2
  • 怎样可以连续点击url

    怎样可以连续点击url

    你好,我尝试在项目中使用你的stateman,可是发现路由绑定的函数不允许连续触发两次的,就是不能连续点击同一个url,你网上的demo也是这样。。http://leeluolee.github.io/stateman/example/api.html#/app,是不是要配置什么参数才能支持连续点击,我在文档上找不到具体的。。

    opened by chenyeyuze 1
  • fix two bugs

    fix two bugs

    1. emitting a notfound event when navigate to a unexists state when using a statename.
    2. check whether the link target is the same domain and avoid navigating.
    opened by em-yuanbo 1
  • v0.2.0  is comming . Maybe the last version before v1.0

    v0.2.0 is comming . Maybe the last version before v1.0

    I have complete the work with version 0.2.0. you can find it at branch:develop.

    ChangeLog

    • add askForPermission phase in Lifecyle. which is useful for control navigation.
    • support Promise in enterleave and canEnter, canLeave( introduced in v0.2.0) to help us implement some asynchronous navigation. #7
    • add namespace support for builtin emitter #16
    • remove [state.async], you can use option.async for asynchronous navigation. but I suggest you to use promise instead. The only change that isn't backward-compatible.
    • remove $notfound #11
    • coverage is almost 100% now .
    • take watch as the default task #13
    • unify the routing option.

    I need some time to update the doc, you can preview the incomplete version HERE

    Although stateman 's version is only 0.2.x, but I think it is ready to release the stable version. So, I will do my best to make it good enough during the v0.2.x. The next version will be 1.0.0.

    Discuss 
    opened by leeluolee 1
  • Redundant

    Redundant "notfound" functionality

    There are two ways to add notfound functionality, a $notfound state, and the notfound event. Not too big a deal, I guess, but I don't think both are necessary. Fwiw $notfound is not documented, and can only be found in the src and examples.

    enhancement 
    opened by jamesplease 1
  • one bug in _autoLink

    one bug in _autoLink

    I met a problem when using stateman in my webapp, there is a link relativing to a page with a different domain but its url contains a hash. when clicked, new tab should be opened ,but the stateman checks the target , and a hash found in the href, so it try to routing . btw i didn't init the stateman with a 'prefix' option.

    I think it should check the domain first, and do nothing without the same domain .

    the code may appear here. https://github.com/leeluolee/stateman/blob/master/src/histery.js#L151

    browser.on( document.body, "click", function(ev){
    
              var target = ev.target || ev.srcElement;
              if( target.tagName.toLowerCase() !== "a" ) return;
              var tmp = (browser.getHref(target)||"").match(self.rPrefix);
                  .....some checking here?
              var hash = tmp && tmp[1]? tmp[1]: "";
    
              if(!hash) return;
    
              ev.preventDefault && ev.preventDefault();
              self.nav( hash )
              return (ev.returnValue = false);
            } )
    
    opened by em-yuanbo 0
  • baseTitle 赋值不变

    baseTitle 赋值不变

    https://github.com/leeluolee/stateman/blob/e195ed177ab1fd5e34353fde2bd31f63c5769ad5/src/manager/client.js#L7

    https://github.com/leeluolee/stateman/blob/e195ed177ab1fd5e34353fde2bd31f63c5769ad5/src/manager/client.js#L20

    这个 baseTitle 作为 document.title 的赋值,即使后续 document.title 变化了,baseTitle 是不变的,希望 document.title = cur.getTitle( options ) || ocument.title || baseTitle

    opened by shizhipeng 0
  • src/state.js中的encode方法,使用for in语法枚举出了polyfill到Object.propertype上的方法

    src/state.js中的encode方法,使用for in语法枚举出了polyfill到Object.propertype上的方法

    背景:ie8中使用core.js polyfill了assign方法到Object.prototype上 使用manager.go时如果带上url参数(e.g. manager.go('error', { param: { t:'type'} })),state.js中encode方法142行的for in语法遍历到param的'assign'属性,该属性是个function,带到参数中会导致报错 建议:加上hasOwnProperty判断过滤

    opened by icyfanfan 0
  • Always call `update` after `enter`?

    Always call `update` after `enter`?

    We have used stateman in a dozen projects already and find that we always do similiar work in enter and update , so most of the states like below

    stateman.state({
        'app.blog': {
            enter: function( option ){
                 this.udpate(option)
             }
            update: function(option){
                // logic here
            }
        }
    })
    

    At that rate, why not call update after enter?

    Plan to change the logic in 0.3.0.

    Just get it over with instead of keep suffering.

    Discuss 
    opened by leeluolee 0
  • Logic on current state, previous and lifecycle

    Logic on current state, previous and lifecycle

    Hi!, nice work, small and they have all I need. So, I have some problem (not very big) with the lifecycle. I take your html example and I add, canLeave and canEnter callback function. I print the :

    "this.name", "event.current.name" and "event.previous.name".

    I navigate by the link on "home" after "contact" and I uptain :

    canEnter: home. Current : home. Previous : 
    enter: home. Current : home. Previous : 
    canLeave: home. Current : contact. Previous : home
    canEnter: contact. Current : contact. Previous : home
    leave: home. Current : contact. Previous : home
    enter: contact. Current : contact. Previous : home
    
    1. If you look only "this.name" when you navigate from "home" to "contact", you are :

    canLeave home, canEnter contact, leave home, enter contact.

    In "my" logic, the canEnter contact and leave home must be inverse and we must have :

    canLeave home, leave home, canEnter contact, enter contact.

    It is look right? (sure in sync way)

    1. If you look current state and previous state :

    Clic on "home", in the canEnter event, the current state must be empty cause we don't are in the state home, but just ask for enter to it.

    Clic on "contact" :

    • on canLeave home event, the current state must be home and previous empty, we don't leave yet, just ask.
    • on canEnter contact event, the current state must be empty we leave home but we don't enter to contact yet.
    • on leave home (they must be before canEnetr see point 1), we are two choice, first, the current state must be empty and previous must be home or the second, current state must be home and previous empty. But I prefer the first choice for make a difference from enter to the state where the current is home and previous is empty.

    This is look right to you? So if not, explain your logic for current, previous and this in the event. If yes, do you need some help, I can change the code and you validate it after.

    Nacrylyc.

    opened by Nacrylyc 1
Releases(v0.2.0)
  • v0.2.0(Sep 28, 2015)

    • add askForPermission phase in Lifecyle. which is useful for control navigation.
    • support Promise in enterleave and canEnter, canLeave( introduced in v0.2.0) to help us implement some asynchronous navigation. #7
    • add namespace support for builtin emitter #16
    • remove [state.async], you can use option.async for asynchronous navigation. but I suggest you to use promise instead. The only change that isn't backward-compatible.
    • remove $notfound #11
    • coverage is almost 100% now .
    • take watch as the default task #13
    • unify the routing option.
    Source code(tar.gz)
    Source code(zip)
  • v0.1.8(Feb 10, 2015)

    Changelog

    1. fix #4
    2. introduce config.title to change the document.title when navigating is over. see here
    3. introduce option.strict . see here. if strict is true, it will resulting only the leaf state can be directly visited.
    Source code(tar.gz)
    Source code(zip)
Owner
ZhengHaibo
zhihu: @郑海波
ZhengHaibo
Deploy a multi-account cloud foundation to support highly-regulated workloads and complex compliance requirements.

Landing Zone Accelerator on AWS The Landing Zone Accelerator on AWS solution helps you quickly deploy a secure, resilient, scalable, and fully automat

Amazon Web Services - Labs 130 Dec 29, 2022
Nested Sort is a JavaScript library which helps you to sort a nested list of items via drag and drop.

Nested Sort Nested Sort is a vanilla JavaScript library, without any dependencies, which helps you to sort a nested list of items via drag and drop. U

Hesam Bahrami 40 Dec 7, 2022
🐻 Trying out the bear necessities for complex state management.

?? Zustand Demos My practice repository for the Zustand library--the bear necessities for complex state management. You can find some examples of how

Carlo Taleon 2 Jul 2, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Example code for MFE routing, shared state, build-time & runtime deploy video

Turborepo starter with pnpm This is an official starter turborepo. What's inside? This turborepo uses pnpm as a packages manager. It includes the foll

Jack Herrington 42 Nov 2, 2022
This package support to build a complex application with domain driven design.

The library implement Domain Driven Design for Nodejs base on Typescript. Description This package support to build a complex application with th doma

null 11 Nov 7, 2022
Tiny JavaScript library (1kB) by CurrencyRate.today, providing simple way and advanced number, money and currency formatting and removes all formatting/cruft and returns the raw float value.

Zero dependency tiny JavaScript library (1kB bytes) by CurrencyRate.today, providing simple way and advanced number, money and currency formatting and removes all formatting/cruft and returns the raw float value.

Yurii De 11 Nov 8, 2022
A WebApp to preview FTML, the SCP Foundation's markup language, on the Web.

Wikitext Previewer (FTML/Wikidot Web Previewer) A WebApp to preview FTML, the SCP Foundation's markup language, on the Web. "SCP-173" by Moto42, from

RTa 8 Jun 4, 2022
A tiny, reactive JavaScript library for structured state and tabular data.

A JavaScript library for structured state. Using plain old JavaScript objects to manage data gets old very quickly. It's error-prone, tricky to track

tinyplex 1.4k Jan 1, 2023
A tiny JavaScript library to easily toggle the state of any HTML element in any contexts, and create UI components in no time.

A tiny JavaScript library to easily toggle the state of any HTML element in any contexts, and create UI components in no time. Dropdown, navigation bu

Matthieu Bué 277 Nov 25, 2022
NoExGen is a node.js express application generator with modern folder structure, namespace/project mapping and much more! It contains preconfigured Settings and Routing files, ready to be used in any project.

Installation $ npm install -g noexgen Quick Start You can use Node Package Execution to create your node-express application as shown below: Create th

Souvik Sen 7 Oct 8, 2022
From the Linux Foundation office in New York City, welcome to The Untold Stories of Open Source

From the Linux Foundation office in New York City, welcome to The Untold Stories of Open Source. Each week we explore the people who are supporting Open Source projects, how they became involved with it, and the problems they faced along the way.

The Linux Foundation 77 Jan 5, 2023
A Foundation for Scalable Cross-Platform Apps

Electron React Boilerplate uses Electron, React, React Router, Webpack and React Fast Refresh. Install Clone the repo and install dependencies: git cl

Electron React Boilerplate 20.7k Jan 4, 2023
This package is an open source extension for MikroORM, which enables Nested Set Tree for your needs

MikroORM nested set This package is an open source extension for MikroORM, which enables Nested Set Tree for your needs Disclaimer For now, this packa

Kamil Fronczak 5 Dec 15, 2022
Ordered lists, flat or nested, multiple formats ordered lists.

logseq-plugin-ol 有序列表,单级或多级、多种样式的有序列表。 Ordered lists, flat or nested, multiple formats ordered lists. 使用展示 (Usage) 在想要展示为有序列表的块上添加一个以 #.ol 开头的标签就可以了。有

Seth Yuan 25 Jan 1, 2023
javascript library to convert a list of objects to a nested json output format, depending on the names in the list

formToNestedJson javascript "library" to convert a list of objects to a nested json output format, depending on the names in the list Basic usage Give

null 2 Aug 2, 2021
Serialize an HTML Form to a JavaScript Object, supporting nested attributes and arrays.

jquery.serializeJSON Adds the method .serializeJSON() to jQuery to serializes a form into a JavaScript Object. Supports the same format for nested par

Mario Izquierdo 1.7k Dec 12, 2022