diff options
Diffstat (limited to 'packages/gitbook-core/src/actions/history.js')
-rw-r--r-- | packages/gitbook-core/src/actions/history.js | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/packages/gitbook-core/src/actions/history.js b/packages/gitbook-core/src/actions/history.js new file mode 100644 index 0000000..1c33f4a --- /dev/null +++ b/packages/gitbook-core/src/actions/history.js @@ -0,0 +1,188 @@ +const ACTION_TYPES = require('./TYPES'); +const getPayload = require('../lib/getPayload'); +const Location = require('../models/Location'); + +const SUPPORTED = ( + typeof window !== 'undefined' && + window.history && window.history.pushState && window.history.replaceState && + // pushState isn't reliable on iOS until 5. + !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/) +); + +/** + * Initialize the history + */ +function activate() { + return (dispatch, getState) => { + dispatch({ + type: ACTION_TYPES.HISTORY_ACTIVATE, + listener: (location) => { + location = Location.fromNative(location); + const prevLocation = getState().history.location; + + // Fetch page if required + if (!prevLocation || location.pathname !== prevLocation.pathname) { + dispatch(fetchPage(location.pathname)); + } + + // Signal location to listener + dispatch(emit()); + + // Update the location + dispatch({ + type: ACTION_TYPES.HISTORY_UPDATE, + location + }); + } + }); + + // Trigger for existing listeners + dispatch(emit()); + }; +} + +/** + * Emit current location + * @param {List|Array<Function>} to? + */ +function emit(to) { + return (dispatch, getState) => { + const { listeners, client } = getState().history; + + if (!client) { + return; + } + + const location = Location.fromNative(client.location); + + to = to || listeners; + + to.forEach(handler => { + handler(location, dispatch, getState); + }); + }; +} + +/** + * Cleanup the history + */ +function deactivate() { + return { type: ACTION_TYPES.HISTORY_DEACTIVATE }; +} + +/** + * Push a new url into the history + * @param {String|Location} location + * @return {Action} action + */ +function push(location) { + return (dispatch, getState) => { + const { client } = getState().history; + location = Location.fromNative(location); + + if (SUPPORTED) { + client.push(location.toNative()); + } else { + redirect(location.toString()); + } + }; +} + +/** + * Replace current state in history + * @param {String|Location} location + * @return {Action} action + */ +function replace(location) { + return (dispatch, getState) => { + const { client } = getState().history; + location = Location.fromNative(location); + + if (SUPPORTED) { + client.replace(location.toNative()); + } else { + redirect(location.toString()); + } + }; +} + +/** + * Hard redirection + * @param {String} uri + * @return {Action} action + */ +function redirect(uri) { + return () => { + window.location.href = uri; + }; +} + +/** + * Listen to url change + * @param {Function} listener + * @return {Action} action + */ +function listen(listener) { + return (dispatch, getState) => { + dispatch({ type: ACTION_TYPES.HISTORY_LISTEN, listener }); + + // Trigger for existing listeners + dispatch(emit([ listener ])); + }; +} + +/** + * Fetch a new page and update the store accordingly + * @param {String} pathname + * @return {Action} action + */ +function fetchPage(pathname) { + return (dispatch, getState) => { + dispatch({ type: ACTION_TYPES.PAGE_FETCH_START }); + + window.fetch(pathname, { + credentials: 'include' + }) + .then( + response => { + return response.text(); + } + ) + .then( + html => { + const payload = getPayload(html); + + if (!payload) { + throw new Error('No payload found in page'); + } + + dispatch({ type: ACTION_TYPES.PAGE_FETCH_END, payload }); + } + ) + .catch( + error => { + // dispatch(redirect(pathname)); + dispatch({ type: ACTION_TYPES.PAGE_FETCH_ERROR, error }); + } + ); + }; +} + +/** + * Fetch a new article + * @param {SummaryArticle} article + * @return {Action} action + */ +function fetchArticle(article) { + return fetchPage(article.path); +} + +module.exports = { + activate, + deactivate, + listen, + push, + replace, + fetchPage, + fetchArticle +}; |