UNPKG

react-router

Version:
145 lines (120 loc) 4.4 kB
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; import { matchPattern } from './PatternUtils'; function deepEqual(a, b) { if (a == b) return true; if (a == null || b == null) return false; if (Array.isArray(a)) { return Array.isArray(b) && a.length === b.length && a.every(function (item, index) { return deepEqual(item, b[index]); }); } if ((typeof a === 'undefined' ? 'undefined' : _typeof(a)) === 'object') { for (var p in a) { if (!Object.prototype.hasOwnProperty.call(a, p)) { continue; } if (a[p] === undefined) { if (b[p] !== undefined) { return false; } } else if (!Object.prototype.hasOwnProperty.call(b, p)) { return false; } else if (!deepEqual(a[p], b[p])) { return false; } } return true; } return String(a) === String(b); } /** * Returns true if the current pathname matches the supplied one, net of * leading and trailing slash normalization. This is sufficient for an * indexOnly route match. */ function pathIsActive(pathname, currentPathname) { // Normalize leading slash for consistency. Leading slash on pathname has // already been normalized in isActive. See caveat there. if (currentPathname.charAt(0) !== '/') { currentPathname = '/' + currentPathname; } // Normalize the end of both path names too. Maybe `/foo/` shouldn't show // `/foo` as active, but in this case, we would already have failed the // match. if (pathname.charAt(pathname.length - 1) !== '/') { pathname += '/'; } if (currentPathname.charAt(currentPathname.length - 1) !== '/') { currentPathname += '/'; } return currentPathname === pathname; } /** * Returns true if the given pathname matches the active routes and params. */ function routeIsActive(pathname, routes, params) { var remainingPathname = pathname, paramNames = [], paramValues = []; // for...of would work here but it's probably slower post-transpilation. for (var i = 0, len = routes.length; i < len; ++i) { var route = routes[i]; var pattern = route.path || ''; if (pattern.charAt(0) === '/') { remainingPathname = pathname; paramNames = []; paramValues = []; } if (remainingPathname !== null && pattern) { var matched = matchPattern(pattern, remainingPathname); if (matched) { remainingPathname = matched.remainingPathname; paramNames = [].concat(paramNames, matched.paramNames); paramValues = [].concat(paramValues, matched.paramValues); } else { remainingPathname = null; } if (remainingPathname === '') { // We have an exact match on the route. Just check that all the params // match. // FIXME: This doesn't work on repeated params. return paramNames.every(function (paramName, index) { return String(paramValues[index]) === String(params[paramName]); }); } } } return false; } /** * Returns true if all key/value pairs in the given query are * currently active. */ function queryIsActive(query, activeQuery) { if (activeQuery == null) return query == null; if (query == null) return true; return deepEqual(query, activeQuery); } /** * Returns true if a <Link> to the given pathname/query combination is * currently active. */ export default function isActive(_ref, indexOnly, currentLocation, routes, params) { var pathname = _ref.pathname, query = _ref.query; if (currentLocation == null) return false; // TODO: This is a bit ugly. It keeps around support for treating pathnames // without preceding slashes as absolute paths, but possibly also works // around the same quirks with basenames as in matchRoutes. if (pathname.charAt(0) !== '/') { pathname = '/' + pathname; } if (!pathIsActive(pathname, currentLocation.pathname)) { // The path check is necessary and sufficient for indexOnly, but otherwise // we still need to check the routes. if (indexOnly || !routeIsActive(pathname, routes, params)) { return false; } } return queryIsActive(query, currentLocation.query); }