diff options
author | Samy Pesse <samypesse@gmail.com> | 2016-10-03 00:59:26 +0200 |
---|---|---|
committer | Samy Pesse <samypesse@gmail.com> | 2016-10-03 00:59:26 +0200 |
commit | 3ae72bb47c146212d40fc74d857880fa0616ae57 (patch) | |
tree | 28986218bb512580272f9709fbdee01f6ede52dd | |
parent | cd2d5e5101edb466b13ada19b09ea42ef726ad96 (diff) | |
download | gitbook-3ae72bb47c146212d40fc74d857880fa0616ae57.zip gitbook-3ae72bb47c146212d40fc74d857880fa0616ae57.tar.gz gitbook-3ae72bb47c146212d40fc74d857880fa0616ae57.tar.bz2 |
Sync search with querystring
-rw-r--r-- | docs/api/i18n.md | 4 | ||||
-rw-r--r-- | docs/api/navigation.md | 21 | ||||
-rw-r--r-- | packages/gitbook-core/package.json | 1 | ||||
-rw-r--r-- | packages/gitbook-core/src/actions/TYPES.js | 2 | ||||
-rw-r--r-- | packages/gitbook-core/src/actions/navigation.js | 61 | ||||
-rw-r--r-- | packages/gitbook-core/src/models/Location.js | 73 | ||||
-rw-r--r-- | packages/gitbook-core/src/reducers/navigation.js | 13 | ||||
-rw-r--r-- | packages/gitbook-plugin-search/src/actions/search.js | 15 | ||||
-rw-r--r-- | packages/gitbook-plugin-search/src/index.js | 13 |
9 files changed, 160 insertions, 43 deletions
diff --git a/docs/api/i18n.md b/docs/api/i18n.md index 026a2d5..b58f1e8 100644 --- a/docs/api/i18n.md +++ b/docs/api/i18n.md @@ -8,8 +8,8 @@ The first step is to register messages for a language: ```js module.exports = GitBook.createPlugin({ - init: (dispatch) => { - dispatch(GitBook.registerLocale('en-US', { + init: (dispatch, getState, { I18n }) => { + dispatch(I18n.registerLocale('en-US', { MY_PLUGIN_MESSAGE: 'Hello World' })); } diff --git a/docs/api/navigation.md b/docs/api/navigation.md new file mode 100644 index 0000000..667aa66 --- /dev/null +++ b/docs/api/navigation.md @@ -0,0 +1,21 @@ +# Navigation + +### Listen to url change + +Listen for changes to the current location: + +```js +const onLocationChanged = (location) => { + console.log(location.pathname); + console.log(location.query); + console.log(location.hash); +}; + +module.exports = GitBook.createPlugin({ + init: (dispatch, getState, { Navigation }) => { + dispatch(Navigation.listen(onLocationChanged)); + } +}); +``` + +The `onLocationChanged` will be triggered for initial state. diff --git a/packages/gitbook-core/package.json b/packages/gitbook-core/package.json index 1bda456..c6cfeed 100644 --- a/packages/gitbook-core/package.json +++ b/packages/gitbook-core/package.json @@ -6,6 +6,7 @@ "dependencies": { "bluebird": "^3.4.6", "classnames": "^2.2.5", + "history": "^4.3.0", "html-tags": "^1.1.1", "immutable": "^3.8.1", "react": "^15.3.1", diff --git a/packages/gitbook-core/src/actions/TYPES.js b/packages/gitbook-core/src/actions/TYPES.js index 3177dbd..e758a44 100644 --- a/packages/gitbook-core/src/actions/TYPES.js +++ b/packages/gitbook-core/src/actions/TYPES.js @@ -7,8 +7,6 @@ module.exports = { PAGE_FETCH_START: 'navigation/fetch:start', PAGE_FETCH_END: 'navigation/fetch:end', PAGE_FETCH_ERROR: 'navigation/fetch:error', - PAGE_UPDATE_ANCHOR: 'navigation/update:anchor', - PAGE_UPDATE_QUERY: 'navigation/update:query', // i18n I18N_REGISTER_LOCALE: 'i18n/register:locale' }; diff --git a/packages/gitbook-core/src/actions/navigation.js b/packages/gitbook-core/src/actions/navigation.js index f13e878..4afd4fb 100644 --- a/packages/gitbook-core/src/actions/navigation.js +++ b/packages/gitbook-core/src/actions/navigation.js @@ -1,5 +1,10 @@ +const { createBrowserHistory, createMemoryHistory } = require('history'); + const ACTION_TYPES = require('./TYPES'); const getPayload = require('../lib/getPayload'); +const Location = require('../models/Location'); + +const isServerSide = (typeof window === 'undefined'); const SUPPORTED = ( typeof window !== 'undefined' && @@ -8,48 +13,39 @@ const SUPPORTED = ( !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/) ); -let PUSH_ID = 0; - -/** - * Generate a new state to be pushed or replaced - * @param {Object} - */ -function genState() { - return { - id: (PUSH_ID++) - }; -} +// Create tge history instance +const history = isServerSide ? createMemoryHistory() : createBrowserHistory(); /** * Push a new url into the navigation - * @param {String} uri + * @param {String|Location} location * @return {Action} action */ -function pushURI(uri) { +function pushURI(location) { return () => { - const state = genState(); + location = Location.fromNative(location); if (SUPPORTED) { - window.history.pushState(state, '', uri); + history.push(location.toNative()); } else { - redirect(uri); + redirect(location.toString()); } }; } /** * Replace current state in navigation - * @param {String} uri + * @param {String|Location} location * @return {Action} action */ -function replaceURI(uri) { +function replaceURI(location) { return () => { - const state = genState(); + location = Location.fromNative(location); if (SUPPORTED) { - window.history.replaceState(state, '', uri); + history.replace(location.toNative()); } else { - redirect(uri); + redirect(location.toString()); } }; } @@ -66,6 +62,20 @@ function redirect(uri) { } /** + * Listen to url change + * @param {Function} fn + * @return {Action} action + */ +function listen(fn) { + return (dispatch, getState) => { + history.listen(location => { + location = Location.fromNative(location); + fn(location, dispatch, getState); + }); + }; +} + +/** * Fetch a new page and update the store accordingly * @param {String} uri * @param {Boolean} options.replace @@ -125,11 +135,11 @@ function fetchArticle(article) { /** * Update anchor for current page - * @param {String} anchor + * @param {String} hash * @return {Action} action */ -function updateAnchor(anchor) { - return { type: ACTION_TYPES.PAGE_UPDATE_ANCHOR, anchor }; +function updateAnchor(hash) { + return pushURI({ hash }); } /** @@ -138,10 +148,11 @@ function updateAnchor(anchor) { * @return {Action} action */ function updateQuery(query) { - return { type: ACTION_TYPES.PAGE_UPDATE_QUERY, query }; + return pushURI({ query }); } module.exports = { + listen, pushURI, fetchPage, fetchArticle, diff --git a/packages/gitbook-core/src/models/Location.js b/packages/gitbook-core/src/models/Location.js new file mode 100644 index 0000000..3b62bef --- /dev/null +++ b/packages/gitbook-core/src/models/Location.js @@ -0,0 +1,73 @@ +const { Record, Map } = require('immutable'); +const querystring = require('querystring'); + +const DEFAULTS = { + pathname: String(''), + // Hash without the # + hash: String(''), + // If query is a non empty map + query: Map() +}; + +class Location extends Record(DEFAULTS) { + get search() { + const { query } = this; + return query.size === 0 ? + '' : + '?' + querystring.stringify(query.toJS()); + } + + /** + * Convert this location to a string. + * @return {String} + */ + toString() { + + } + + /** + * Convert this immutable instance to an object + * for "history". + * @return {Object} + */ + toNative() { + return { + pathname: this.pathname, + hash: this.hash ? `#${this.hash}` : '', + search: this.search + }; + } + + /** + * Convert an instance from "history" to Location. + * @param {Object|String} location + * @return {Location} + */ + static fromNative(location) { + if (typeof location === 'string') { + location = { pathname: location }; + } + + const pathname = location.pathname; + let hash = location.hash || ''; + let search = location.search || ''; + let query = location.query; + + hash = hash[0] === '#' ? hash.slice(1) : hash; + search = search[0] === '?' ? search.slice(1) : search; + + if (query) { + query = Map(query); + } else { + query = Map(querystring.parse(search)); + } + + return new Location({ + pathname, + hash, + query + }); + } +} + +module.exports = Location; diff --git a/packages/gitbook-core/src/reducers/navigation.js b/packages/gitbook-core/src/reducers/navigation.js index 625adef..9831cd5 100644 --- a/packages/gitbook-core/src/reducers/navigation.js +++ b/packages/gitbook-core/src/reducers/navigation.js @@ -1,15 +1,11 @@ -const { Record, Map } = require('immutable'); +const { Record } = require('immutable'); const ACTION_TYPES = require('../actions/TYPES'); const NavigationState = Record({ // Are we loading a new page loading: Boolean(false), // Did we fail loading a page? - error: null, - // Query string - query: Map(), - // Current anchor - anchor: String('') + error: null }); function reduceNavigation(state, action) { @@ -32,11 +28,6 @@ function reduceNavigation(state, action) { error: action.error }); - case ACTION_TYPES.PAGE_UPDATE_ANCHOR: - return state.merge({ - anchor: action.anchor - }); - default: return state; diff --git a/packages/gitbook-plugin-search/src/actions/search.js b/packages/gitbook-plugin-search/src/actions/search.js index 7d42917..b4f811e 100644 --- a/packages/gitbook-plugin-search/src/actions/search.js +++ b/packages/gitbook-plugin-search/src/actions/search.js @@ -8,14 +8,24 @@ const TYPES = require('./types'); * @return {Action} */ function query(q) { + return (dispatch, getState, { Navigation }) => { + dispatch(Navigation.updateQuery({ q })); + }; +} + + +/** + * Update results for a query + * @param {String} q + * @return {Action} + */ +function handleQuery(q) { if (!q) { return clear(); } return (dispatch, getState, { Navigation }) => { const { handlers } = getState().search; - - dispatch(Navigation.updateQuery({ q })); dispatch({ type: TYPES.START, query: q }); return Promise.reduce( @@ -64,6 +74,7 @@ function unregisterHandler(name) { module.exports = { clear, query, + handleQuery, registerHandler, unregisterHandler }; diff --git a/packages/gitbook-plugin-search/src/index.js b/packages/gitbook-plugin-search/src/index.js index f08d5d6..05c2056 100644 --- a/packages/gitbook-plugin-search/src/index.js +++ b/packages/gitbook-plugin-search/src/index.js @@ -5,8 +5,19 @@ const SearchResults = require('./components/Results'); const reducers = require('./reducers'); const Search = require('./actions/search'); +const onLocationChange = (location, dispatch) => { + const { query } = location; + const q = query.get('q'); + + dispatch(Search.handleQuery(q)); +}; + module.exports = GitBook.createPlugin({ - init: (dispatch, getState, { Components }) => { + init: (dispatch, getState, { Navigation, Components }) => { + // Register the navigation handler + dispatch(Navigation.listen(onLocationChange)); + + // Register components dispatch(Components.registerComponent(SearchInput, { role: 'search:input' })); dispatch(Components.registerComponent(SearchResults, { role: 'search:results' })); }, |