summaryrefslogtreecommitdiffstats
path: root/packages/gitbook-core/src/actions/history.js
diff options
context:
space:
mode:
Diffstat (limited to 'packages/gitbook-core/src/actions/history.js')
-rw-r--r--packages/gitbook-core/src/actions/history.js188
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
+};