react-view-router
Version:
react-view-router
178 lines (175 loc) • 6.12 kB
JavaScript
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
import { Action, HistoryType } from './types';
import { createEvents, createPath, createKey, parsePath, freeze, clamp, allowTx } from './utils';
/**
* A memory history stores locations in memory. This is useful in stateful
* environments where there is no web browser, such as node tests or React
* Native.
*
* @see https://github.com/ReactTraining/history/tree/master/docs/api-reference.md#memoryhistory
*/
/**
* A user-supplied object that describes a location. Used when providing
* entries to `createMemoryHistory` via its `initialEntries` option.
*/
export function createMemoryHref(to) {
return typeof to === 'string' ? to : createPath(to);
}
/**
* Memory history stores the current location in memory. It is designed for use
* in stateful non-browser environments like tests and React Native.
*
* @see https://github.com/ReactTraining/history/tree/master/docs/api-reference.md#creatememoryhistory
*/
export function createMemoryHistory(options = {}) {
const {
initialEntries = ['/'],
initialIndex
} = options;
const entries = initialEntries.map(entry => {
const location = freeze(_objectSpread({
pathname: '/',
search: '',
hash: '',
state: null,
key: createKey()
}, typeof entry === 'string' ? parsePath(entry) : entry));
return location;
});
let index = clamp(initialIndex == null ? entries.length - 1 : initialIndex, 0, entries.length - 1);
const type = HistoryType.memory;
let action = Action.Push;
let location = entries[index];
const listeners = createEvents();
const blockers = createEvents();
const createHref = to => createMemoryHref(to);
function getNextLocation(to, state = null) {
const {
pathname = '/',
search = '',
hash = ''
} = location;
return freeze(_objectSpread(_objectSpread({
pathname,
search,
hash
}, typeof to === 'string' ? parsePath(to) : to), {}, {
state,
key: createKey()
}));
}
function applyTx(nextAction, nextLocation, nextIndex, payload) {
action = nextAction;
location = nextLocation;
index = nextIndex;
listeners.call({
action,
location,
index
}, payload);
}
function getIndex(delta) {
const ret = index;
if (delta) {
index = clamp(index + delta, 0, entries.length - 1);
}
return ret;
}
function push(to, state) {
const nextAction = Action.Push;
const nextLocation = getNextLocation(to, state);
const callback = (ok, payload) => {
if (!ok) return;
index = getIndex(typeof to !== 'string' ? to.delta : undefined) + 1;
entries.splice(index, entries.length, nextLocation);
applyTx(nextAction, nextLocation, index, payload);
};
if (allowTx(blockers, nextAction, nextLocation, index, getIndex(typeof to !== 'string' ? to.delta : undefined) + 1, callback)) {
callback(true, to);
}
}
function replace(to, state) {
const nextAction = Action.Replace;
const nextLocation = getNextLocation(to, state);
const callback = (ok, payload) => {
if (!ok) return;
if (typeof to !== 'string' && to.delta) {
index = clamp(index + to.delta, 0, entries.length - 1);
}
entries[index] = nextLocation;
applyTx(nextAction, nextLocation, index, payload);
};
if (allowTx(blockers, nextAction, nextLocation, index, getIndex(typeof to !== 'string' ? to.delta : undefined), callback)) {
callback(true, to);
}
}
function go(delta) {
const nextIndex = clamp(index + delta, 0, entries.length - 1);
const nextAction = Action.Pop;
const nextLocation = entries[nextIndex];
const callback = (ok, payload) => {
if (!ok) return;
index = nextIndex;
applyTx(nextAction, nextLocation, index, payload);
};
if (allowTx(blockers, nextAction, nextLocation, index, getIndex(delta), callback)) {
callback(true);
}
}
const history = {
get extra() {
return options.extra;
},
get type() {
return type;
},
get action() {
return action;
},
get location() {
return location;
},
get index() {
return index;
},
get length() {
return entries.length;
},
get state() {
return location.state;
},
get realtimeLocation() {
return location;
},
createHref,
getIndexAndLocation() {
return [index, location];
},
push,
replace,
replaceState(state) {
return location.state = state;
},
refresh() {
return [index, location];
},
go,
back() {
go(-1);
},
forward() {
go(1);
},
listen(listener) {
return listeners.push(listener);
},
block(blocker) {
return blockers.push(blocker);
}
};
return history;
}