Last active
November 29, 2016 17:48
-
-
Save ngbrown/d1874f93beebc3e6724217f88cc2d295 to your computer and use it in GitHub Desktop.
redux-little-router utility functions for onClick and onSubmit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {PUSH, REPLACE} from "redux-little-router"; | |
import defaultCreateLocation from "redux-little-router/lib/util/create-location.js"; | |
// Adapted from https://github.com/FormidableLabs/redux-little-router | |
// specifically the Link component (https://github.com/FormidableLabs/redux-little-router/blob/master/src/link.js) | |
const normalizeHref = ({ basename, pathname, search }) => | |
`${basename || ''}${pathname}${search || ''}`; | |
const normalizeLocation = href => { | |
if (typeof href === 'string') { | |
const pathnameAndQuery = href.split('?'); | |
const pathname = pathnameAndQuery[0]; // eslint-disable-line no-magic-numbers | |
const query = pathnameAndQuery[1]; // eslint-disable-line no-magic-numbers | |
return query ? { pathname, search: `?${query}` } : { pathname }; | |
} | |
return href; | |
}; | |
const resolveQueryForLocation = ({ | |
linkLocation, | |
persistQuery, | |
currentLocation | |
}) => { | |
const currentQuery = currentLocation && | |
currentLocation.query; | |
// Only use the query from state if it exists | |
// and the href doesn't provide its own query | |
if ( | |
persistQuery && | |
currentQuery && | |
!linkLocation.search && | |
!linkLocation.query | |
) { | |
return { | |
pathname: linkLocation.pathname, | |
query: currentQuery | |
}; | |
} | |
return linkLocation; | |
}; | |
const isNotLeftClick = e => e.button && e.button !== LEFT_MOUSE_BUTTON; | |
const hasModifier = e => Boolean(e.shiftKey || e.altKey || e.metaKey || e.ctrlKey); | |
// use like this: | |
// <NavItem href="/items" onClick={handleClickNav(router, "/items")}>View Items</NavItem> | |
const handleClickNav = (router, href, replaceState=false, persistQuery=false) => { | |
const locationDescriptor = | |
resolveQueryForLocation({ | |
linkLocation: normalizeLocation(href), | |
currentLocation: router.store.getState().router, | |
persistQuery | |
}); | |
const location = defaultCreateLocation(locationDescriptor); | |
return (e) => { | |
if (hasModifier(e) || isNotLeftClick(e)) { return; } | |
if (e.defaultPrevented) { return; } | |
if (router) { | |
router.store.dispatch({ | |
type: replaceState ? PUSH : PUSH, | |
payload: location | |
}); | |
e.preventDefault(); | |
} | |
}; | |
}; | |
// from http://stackoverflow.com/a/40705993/25182 | |
function serializeForm(form) { | |
var result = []; | |
if (typeof form === 'object' && form.nodeName === 'FORM') | |
Array.prototype.slice.call(form.elements).forEach(function(control) { | |
if ( | |
control.name && | |
!control.disabled && | |
['file', 'reset', 'submit', 'button'].indexOf(control.type) === -1 | |
) | |
if (control.type === 'select-multiple') | |
Array.prototype.slice.call(control.options).forEach(function(option) { | |
if (option.selected) | |
result.push(encodeURIComponent(control.name) + '=' + encodeURIComponent(option.value)); | |
}); | |
else if ( | |
['checkbox', 'radio'].indexOf(control.type) === -1 || | |
control.checked | |
) result.push(encodeURIComponent(control.name) + '=' + encodeURIComponent(control.value)); | |
}); | |
return result.join('&').replace(/%20/g, '+'); | |
} | |
// use like this: | |
// <form action="/search" onSubmit={handleOnSubmitNav(router, "/search")}> | |
const handleOnSubmitNav = (router, action, replaceState=false) => { | |
const linkLocation = normalizeLocation(action); | |
return (e) => { | |
if (hasModifier(e) || isNotLeftClick(e)) { return; } | |
if (e.defaultPrevented) { return; } | |
const formQuery = serializeForm(e.currentTarget); | |
const locationDescriptor = { | |
pathname: linkLocation.pathname, | |
search: (linkLocation.search ? (linkLocation.search + "&") : "?") + formQuery | |
}; | |
const location = defaultCreateLocation(locationDescriptor); | |
if (router) { | |
router.store.dispatch({ | |
type: replaceState ? PUSH : PUSH, | |
payload: location | |
}); | |
e.preventDefault(); | |
} | |
}; | |
}; | |
export { | |
handleClickNav, | |
handleOnSubmitNav, | |
normalizeHref, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment