All Projects → 4Catalyzer → Farce

4Catalyzer / Farce

Licence: mit
History repeats itself

Programming Languages

javascript
184084 projects - #8 most used programming language

Labels

Projects that are alternatives of or similar to Farce

Java Almanac
The history and future of Java.
Stars: ✭ 710 (+697.75%)
Mutual labels:  history
Iobroker.sql
Store history data in SQL Database: MySQL, PostgreSQL or SQLite
Stars: ✭ 37 (-58.43%)
Mutual labels:  history
Pg wait sampling
Sampling based statistics of wait events
Stars: ✭ 81 (-8.99%)
Mutual labels:  history
Mind Expanding Books
📚 Books everyone should read!
Stars: ✭ 7,151 (+7934.83%)
Mutual labels:  history
Unesco Map
Show all the monuments of the UNESCO on an interactive map
Stars: ✭ 23 (-74.16%)
Mutual labels:  history
Piwik React Router
Piwik analytics component for react-router
Stars: ✭ 53 (-40.45%)
Mutual labels:  history
Conventional Changelog
Generate changelogs and release notes from a project's commit messages and metadata.
Stars: ✭ 5,962 (+6598.88%)
Mutual labels:  history
Grand Timeline
Interactive grand unified timeline of 30,800 ancient Chinese people / 古人全表
Stars: ✭ 83 (-6.74%)
Mutual labels:  history
Bashhub Client
☁️ Bash history in the cloud. Indexed and searchable.
Stars: ✭ 858 (+864.04%)
Mutual labels:  history
Method log
Trace the history of an individual method in a git repository (experimental)
Stars: ✭ 73 (-17.98%)
Mutual labels:  history
Zsh Histdb
A slightly better history for zsh
Stars: ✭ 801 (+800%)
Mutual labels:  history
Zsh History To Fish
Bring your ZSH history to Fish shell.
Stars: ✭ 23 (-74.16%)
Mutual labels:  history
Changed Log
Returns all commit messages between 2 versions of an NPM module
Stars: ✭ 58 (-34.83%)
Mutual labels:  history
Nano Sql
Universal database layer for the client, server & mobile devices. It's like Lego for databases.
Stars: ✭ 717 (+705.62%)
Mutual labels:  history
Reactivehistory
Reactive undo/redo framework for .NET.
Stars: ✭ 82 (-7.87%)
Mutual labels:  history
Navaid
A navigation aid (aka, router) for the browser in 850 bytes~!
Stars: ✭ 648 (+628.09%)
Mutual labels:  history
Crossline
A small, self-contained, zero-config, MIT licensed, cross-platform, readline and libedit replacement.
Stars: ✭ 53 (-40.45%)
Mutual labels:  history
Sketchpad
Sketchpad is fully customisable collaborative whiteboard plugin written in pure JavaScript.
Stars: ✭ 85 (-4.49%)
Mutual labels:  history
Mongoose Patch History
Mongoose plugin that saves a history of JSON patch operations for all documents belonging to a schema in an associated 'patches' collection
Stars: ✭ 82 (-7.87%)
Mutual labels:  history
Route
原生 js 实现的轻量级路由,且页面跳转间有缓存功能。
Stars: ✭ 68 (-23.6%)
Mutual labels:  history

Farce Travis npm

History repeats itself.

Farce provides a Redux store enhancer that wraps a series of middlewares to allow controlling browser navigation by dispatching actions and to allow managing location state with the rest of your store state.

Codecov

Table of Contents generated with DocToc

Usage

import {
  Actions as FarceActions,
  BrowserProtocol,
  createHistoryEnhancer,
  locationReducer,
  queryMiddleware,
} from 'farce';
import { combineReducers, createStore } from 'redux';

const store = createStore(
  combineReducers({
    location: locationReducer,
  }),
  createHistoryEnhancer({
    protocol: new BrowserProtocol(),
    middlewares: [queryMiddleware],
  }),
);

store.dispatch(FarceActions.init());

// To navigate to a new location:
store.dispatch(FarceActions.push('/new/path'));

// To get the current location:
const location = store.getState().location;
// -> { action: 'PUSH', pathname: '/new/path', ... }

Guide

Installation

$ npm i -S redux
$ npm i -S farce

Basic usage

Create a history enhancer with createHistoryEnhancer. Configure it with an options object with a protocol property to control how to interact with browser APIs and an optional middlewares property to customize handling of location objects. Use this history enhancer to enhance your store.

Install locationReducer to track the current location state in your store.

const store = createStore(
  combineReducers({
    location: locationReducer,
  }),
  createHistoryEnhancer({
    protocol: new BrowserProtocol(),
    middlewares: [queryMiddleware],
  }),
);

Dispatch FarceActions.init() to initialize up your store with the current browser state and to set up event listeners.

Dispatch FarceActions.push(location), FarceActions.replace(location), or FarceActions.go(delta) to navigate.

// Add a /foo history entry.
store.dispatch(FarceActions.push('/foo'));

// Replace the current history entry with /bar.
store.dispatch(FarceActions.replace('/bar'));

// Go back one entry.
store.dispatch(FarceActions.go(-1));

If you want to tear down all event listeners, dispatch FarceActions.dispose().

store.dispatch(FarceActions.dispose());

Protocols

BrowserProtocol

BrowserProtocol uses the browser URL path and the HTML5 History API.

const protocol = new BrowserProtocol();

The examples here assume the use of a new BrowserProtocol().

HashProtocol

HashProtocol uses the URL hash for navigation, and is intended for use in cases where server-side routing is not available, or in legacy environments where the HTML5 History API is not available. Prefer using BrowserProtocol over HashProtocol when possible.

const protocol = new HashProtocol();

ServerProtocol

ServerProtocol uses a fixed, in-memory location for use in server-side rendering. It takes the path for the location to use. ServerProtocol instances do not support location.state and cannot navigate.

// Given a standard Node request object:
const protocol = new ServerProtocol(req.url);

MemoryProtocol

MemoryProtocol tracks the current location and the location history in memory. It is intended for use in tests exercising navigation, and in cases where actual browser navigation is not possible or not desired, such as in browser plugins and in Electron apps. MemoryProtocol requires an initial location.

const protocol = new MemoryProtocol(initialLocation);

MemoryProtocol also supports persisting the location history state to session storage, which allows for use cases like preserving navigation state when refreshing in an Electron app.

const protocol = new MemoryProtocol(initialLocation, { persistent: true });

Middlewares

queryMiddleware and createQueryMiddleware

The queryMiddleware middleware adds support for the query property, which enables the use of query objects to set the search string.

The createQueryMiddleware middleware factory creates a custom query middleware. It takes a configuration object with parse and stringify functions as properties to configure parsing and stringifying queries.

import qs from 'qs';

const customQueryMiddleware = createQueryMiddleware({
  parse: qs.parse,
  stringify: qs.stringify,
});

The examples here assume the use of queryMiddleware.

createBasenameMiddleware

The createBasenameMiddleware middleware factory creates a middleware that implicitly prepends all paths with a base path. It takes a configuration object with a basename string.

// With this middleware, dispatching FarceActions.push('/bar') will navigate to
// /foo/bar:
const basenameMiddleware = createBasenameMiddleware({ basename: '/foo' });

Locations and location descriptors

The locationReducer reducer updates the store state with a location object. Location objects have the following properties:

  • action: 'PUSH' or 'REPLACE' if the location was reached via FarceActions.push or FarceActions.replace respectively; 'POP' on the initial location, or if the location was reached via the browser back or forward buttons or via FarceActions.go
  • pathname: the path name; as on window.location
  • search: the search string; as on window.location
  • hash: the location hash; as on window.location
  • key: if present, a unique key identifying the current history entry
  • index: the current index of the history entry, starting at 0 for the initial entry; this increments on FarceActions.push but not on FarceActions.replace
  • delta: the difference between the current index and the index of the previous location
  • state: additional location state that is not part of the URL

If a queryMiddleware is applied, the location object will also contain a query property that is the parsed query object from the search string. If a basenameMiddleware is applied, pathname will be relative to the specified basename.

FarceActions.push and FarceActions.replace take a location descriptor. A location descriptor can be an object with the shape of the location object. If it is an object, the action, key, index, and delta keys are ignored. A location descriptor can also be a string with the full path.

// Location descriptor string:
store.dispatch(FarceActions.push('/foo?bar=baz#qux'));

// Equivalent location descriptor object:
store.dispatch(
  FarceActions.push({
    pathname: '/foo',
    search: '?bar=baz',
    hash: '#qux',
  }),
);

// Given a location object, you can override a subset of its properties:
store.dispatch(
  FarceActions.replace({
    ...location,
    query: { the: 'new-query' },
    hash: '#new-hash',
  }),
);

The history enhancer adds a farce object as a property to the store that exposes createHref and createLocation methods. createHref takes a location descriptor and returns a link href. createLocation takes a location descriptor and returns a fully-populated location descriptor object.

const href = store.farce.createHref({
  pathname: '/foo',
  query: { the: 'query' },
});
// -> '/foo?the=query'

const location = store.farce.createLocation('/foo?the=query');
// -> { pathname: '/foo', query: { the: 'query' }, ... }

Navigation listeners

The farce object on the store also has an addNavigationListener method. This method takes a navigation listener function and an optional options object and returns a function to remove the navigation listener.

const removeNavigationListener = store.farce.addNavigationListener(
  (location) =>
    location.pathname === '/bar'
      ? 'Are you sure you want to go to /bar?'
      : true,
);

// To remove the navigation listener:
removeNavigationListener();

The navigation listener function receives the location to which the user is attempting to navigate. This function may return:

  • true to allow navigation
  • false to block navigation
  • A string to prompt the user with that string as the message
  • A nully value to call the next navigation listener and use its return value, if present, or else to allow the navigation
  • A promise that resolves to any of the above values, to allow or block navigation once the promise resolves

When adding a navigation listener, you can set the beforeUnload option to run the listener when the user attempts to leave the page entirely. If beforeUnload is set, the navigation listener will be called with a null location when the user attempts to leave the page. In this scenario, the navigation listener must return a non-promise value.

store.farce.addNavigationListener(
  (location) => {
    if (!location) {
      return false;
    }

    return asyncConfirm(location);
  },
  { beforeUnload: true },
);

Transient state storage

The StateStorage class provides transient storage associated with location objects. This can be used for tracking values like scroll position that should not be propagated when using a location object to build a new location descriptor. The StateStorage constructor takes the farce property from the store and a namespace string to uniquely identify the state storage instance.

const stateStorage = new StateStorage(store.farce, 'my-transient-state');

The state storage object exposes read and save methods. The save method takes a location object, an optional key to further qualify the saved property, and a JSON-serializable value; it saves the value to session storage. The read method takes the location object and the key; it returns the saved value if retrievable or undefined otherwise.

stateStorage.save(location, null, 1);
stateStorage.save(location, 'foo', [2, 3]);

const value1 = stateStorage.read(location);
// -> 1
const value2 = stateStorage.read(location, 'foo');
// -> [2, 3]
const value3 = stateStorage.read(location, 'bar');
// -> undefined

StateStorage intentionally ignores errors. As such, it should be treated as unreliable. Do not use StateStorage for managing state that is critical to the operation of your application.

Minimizing bundle size

The top-level farce package exports everything available in this library. It is unlikely that any single application will use all the features available. As such, for real applications, you should import the modules you need directly, to pull in only the code that you use.

import BrowserProtocol from 'farce/BrowserProtocol';
import createHistoryEnhancer from 'farce/createHistoryEnhancer';
import queryMiddleware from 'farce/queryMiddleware';

// Instead of:
// import {
//  BrowserProtocol,
//  createHistoryEnhancer,
//  queryMiddleware,
// } from 'farce';
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].