278 lines
12 KiB
JavaScript
278 lines
12 KiB
JavaScript
'use strict';
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
|
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
|
|
exports.default = addUrlProps;
|
|
|
|
var _react = require('react');
|
|
|
|
var _react2 = _interopRequireDefault(_react);
|
|
|
|
var _propTypes = require('prop-types');
|
|
|
|
var _propTypes2 = _interopRequireDefault(_propTypes);
|
|
|
|
var _queryString = require('query-string');
|
|
|
|
var _urlQueryDecoder = require('../urlQueryDecoder');
|
|
|
|
var _urlQueryDecoder2 = _interopRequireDefault(_urlQueryDecoder);
|
|
|
|
var _urlQueryConfig = require('../urlQueryConfig');
|
|
|
|
var _urlQueryConfig2 = _interopRequireDefault(_urlQueryConfig);
|
|
|
|
var _updateUrlQuery = require('../updateUrlQuery');
|
|
|
|
var _serialize = require('../serialize');
|
|
|
|
var _UrlUpdateTypes = require('../UrlUpdateTypes');
|
|
|
|
var _UrlUpdateTypes2 = _interopRequireDefault(_UrlUpdateTypes);
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
|
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
|
|
/**
|
|
* Higher order component (HOC) that injects URL query parameters as props.
|
|
*
|
|
* @param {Function} mapUrlToProps `function(url, props) -> {Object}` returns props to inject
|
|
* @return {React.Component}
|
|
*/
|
|
function addUrlProps() {
|
|
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
|
|
var _options$mapUrlToProp = options.mapUrlToProps;
|
|
var mapUrlToProps = _options$mapUrlToProp === undefined ? function (d) {
|
|
return d;
|
|
} : _options$mapUrlToProp;
|
|
var mapUrlChangeHandlersToProps = options.mapUrlChangeHandlersToProps;
|
|
var urlPropsQueryConfig = options.urlPropsQueryConfig;
|
|
var addRouterParams = options.addRouterParams;
|
|
var addUrlChangeHandlers = options.addUrlChangeHandlers;
|
|
var changeHandlerName = options.changeHandlerName;
|
|
|
|
|
|
return function addPropsWrapper(WrappedComponent) {
|
|
// caching to prevent unnecessary generation of new onChange functions
|
|
var cachedHandlers = void 0;
|
|
|
|
var decodeQuery = void 0;
|
|
|
|
// initialize decode query (with cache) if a config is provided
|
|
if (urlPropsQueryConfig) {
|
|
decodeQuery = (0, _urlQueryDecoder2.default)(urlPropsQueryConfig);
|
|
}
|
|
|
|
/**
|
|
* Parse the URL query into an object. If a urlPropsQueryConfig is provided
|
|
* the values are decoded based on type.
|
|
*/
|
|
function getUrlObject(props) {
|
|
var location = void 0;
|
|
|
|
// check in history
|
|
if (_urlQueryConfig2.default.history.location) {
|
|
location = _urlQueryConfig2.default.history.location;
|
|
|
|
// react-router provides it as a prop
|
|
} else if (props.location && (props.location.query || props.location.search != null)) {
|
|
location = props.location;
|
|
|
|
// not found. just use location from window
|
|
} else {
|
|
location = window.location;
|
|
}
|
|
|
|
var currentQuery = location.query || (0, _queryString.parse)(location.search) || {};
|
|
|
|
var result = void 0;
|
|
// if a url query decoder is provided, decode the query then return that.
|
|
if (decodeQuery) {
|
|
result = decodeQuery(currentQuery);
|
|
} else {
|
|
result = currentQuery;
|
|
}
|
|
|
|
// add in react-router params if requested
|
|
if (addRouterParams || addRouterParams !== false && _urlQueryConfig2.default.addRouterParams) {
|
|
Object.assign(result, props.params, props.match && props.match.params);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
var displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component';
|
|
|
|
var AddUrlProps = function (_Component) {
|
|
_inherits(AddUrlProps, _Component);
|
|
|
|
function AddUrlProps() {
|
|
_classCallCheck(this, AddUrlProps);
|
|
|
|
return _possibleConstructorReturn(this, (AddUrlProps.__proto__ || Object.getPrototypeOf(AddUrlProps)).apply(this, arguments));
|
|
}
|
|
|
|
_createClass(AddUrlProps, [{
|
|
key: 'getUrlChangeHandlerProps',
|
|
|
|
|
|
/**
|
|
* Create URL change handlers based on props, the urlPropsQueryConfig (if provided),
|
|
* and mapUrlChangeHandlersToProps (if provided).
|
|
* As a member function so we can read `this.props` in generated handlers dynamically.
|
|
*/
|
|
value: function getUrlChangeHandlerProps(propsWithUrl) {
|
|
var _this2 = this;
|
|
|
|
var handlers = void 0;
|
|
|
|
if (urlPropsQueryConfig) {
|
|
// if we have a props->query config, generate the change handler props unless
|
|
// addUrlChangeHandlers is false
|
|
if (addUrlChangeHandlers || addUrlChangeHandlers == null && _urlQueryConfig2.default.addUrlChangeHandlers) {
|
|
// use cache if available. Have to do this since urlQueryConfig can change between
|
|
// renders (although that is unusual).
|
|
if (cachedHandlers) {
|
|
handlers = cachedHandlers;
|
|
} else {
|
|
// read in function from options for how to generate a name from a prop
|
|
if (!changeHandlerName) {
|
|
changeHandlerName = _urlQueryConfig2.default.changeHandlerName;
|
|
}
|
|
|
|
// for each URL config prop, create a handler
|
|
handlers = Object.keys(urlPropsQueryConfig).reduce(function (handlersAccum, propName) {
|
|
var _urlPropsQueryConfig$ = urlPropsQueryConfig[propName];
|
|
var updateType = _urlPropsQueryConfig$.updateType;
|
|
var _urlPropsQueryConfig$2 = _urlPropsQueryConfig$.queryParam;
|
|
var queryParam = _urlPropsQueryConfig$2 === undefined ? propName : _urlPropsQueryConfig$2;
|
|
var type = _urlPropsQueryConfig$.type;
|
|
|
|
// name handler for `foo` => `onChangeFoo`
|
|
|
|
var handlerName = changeHandlerName(propName);
|
|
|
|
// handler encodes the value and updates the URL with the encoded value
|
|
// based on the `updateType` in the config. Default is `replaceIn`
|
|
handlersAccum[handlerName] = function generatedUrlChangeHandler(value) {
|
|
var location = _urlQueryConfig2.default.history.location;
|
|
|
|
// for backwards compatibility
|
|
|
|
if (!location) {
|
|
location = this.props.location;
|
|
}
|
|
|
|
var encodedValue = (0, _serialize.encode)(type, value);
|
|
|
|
// add a simple check when we have props.location.query to see if
|
|
// we even need to update.
|
|
if (location && location.query && location.query[queryParam] === encodedValue) {
|
|
return undefined; // skip updating
|
|
}
|
|
|
|
return (0, _updateUrlQuery.updateUrlQuerySingle)(updateType, queryParam, encodedValue, location);
|
|
}.bind(_this2); // bind this so we can access props dynamically
|
|
|
|
return handlersAccum;
|
|
}, {});
|
|
|
|
// add in a batch change handler
|
|
var batchHandlerName = changeHandlerName('urlQueryParams');
|
|
handlers[batchHandlerName] = function generatedBatchUrlChangeHandler(queryValues) {
|
|
var updateType = arguments.length <= 1 || arguments[1] === undefined ? _UrlUpdateTypes2.default.replaceIn : arguments[1];
|
|
var location = _urlQueryConfig2.default.history.location;
|
|
|
|
// for backwards compatibility
|
|
|
|
if (!location) {
|
|
location = this.props.location;
|
|
}
|
|
|
|
var allEncodedValuesUnchanged = true;
|
|
|
|
// encode each value
|
|
var queryReplacements = Object.keys(queryValues).reduce(function (accum, propName) {
|
|
var _urlPropsQueryConfig$3 = urlPropsQueryConfig[propName];
|
|
var _urlPropsQueryConfig$4 = _urlPropsQueryConfig$3.queryParam;
|
|
var queryParam = _urlPropsQueryConfig$4 === undefined ? propName : _urlPropsQueryConfig$4;
|
|
var type = _urlPropsQueryConfig$3.type;
|
|
|
|
var value = queryValues[propName];
|
|
|
|
var encodedValue = (0, _serialize.encode)(type, value);
|
|
accum[queryParam] = encodedValue;
|
|
|
|
// add a simple check when we have props.location.query to see if
|
|
// we even need to update.
|
|
if (location && location.query && location.query[queryParam] !== encodedValue) {
|
|
allEncodedValuesUnchanged = false;
|
|
}
|
|
|
|
return accum;
|
|
}, {});
|
|
|
|
if (location && location.query && allEncodedValuesUnchanged) {
|
|
return undefined; // skip updating if no encoded values changed
|
|
}
|
|
|
|
return (0, _updateUrlQuery.updateUrlQueryMulti)(updateType, queryReplacements, location);
|
|
}.bind(this);
|
|
|
|
// cache these so we don't regenerate new functions every render
|
|
cachedHandlers = handlers;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if a manual mapping function is provided, use it, passing in the auto-generated
|
|
// handlers as an optional secondary argument.
|
|
if (mapUrlChangeHandlersToProps) {
|
|
handlers = mapUrlChangeHandlersToProps.call(this, propsWithUrl, handlers);
|
|
}
|
|
|
|
return handlers;
|
|
}
|
|
}, {
|
|
key: 'render',
|
|
value: function render() {
|
|
// get the url query parameters as an object mapping name to value.
|
|
// if a config is provided, these are decoded based on their `type` and their
|
|
// name will match the prop name.
|
|
// if no config is provided, they are not decoded and their names are whatever
|
|
// they were in the URL.
|
|
var url = getUrlObject(this.props);
|
|
|
|
// pass to mapUrlToProps for further decoding if provided
|
|
this.propsWithUrl = Object.assign({}, this.props, mapUrlToProps(url, this.props));
|
|
|
|
// add in the URL change handlers - either auto-generated based on config
|
|
// or from mapUrlChangeHandlersToProps.
|
|
Object.assign(this.propsWithUrl, this.getUrlChangeHandlerProps(this.propsWithUrl));
|
|
|
|
// render the wrapped component with the URL props added in.
|
|
return _react2.default.createElement(WrappedComponent, this.propsWithUrl);
|
|
}
|
|
}]);
|
|
|
|
return AddUrlProps;
|
|
}(_react.Component);
|
|
|
|
AddUrlProps.displayName = 'AddUrlProps(' + displayName + ')';
|
|
AddUrlProps.WrappedComponent = WrappedComponent;
|
|
AddUrlProps.propTypes = {
|
|
location: _propTypes2.default.any };
|
|
|
|
|
|
return AddUrlProps;
|
|
};
|
|
} |