Skip to content

Instantly share code, notes, and snippets.

@heleneshaikh
Created January 4, 2019 14:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save heleneshaikh/a0d629dd944d30af120b69b96b3a8822 to your computer and use it in GitHub Desktop.
Save heleneshaikh/a0d629dd944d30af120b69b96b3a8822 to your computer and use it in GitHub Desktop.
(function (root, factory) {
var routing = factory();
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], routing.Routing);
} else if (typeof module === 'object' && module.exports) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = routing.Routing;
} else {
// Browser globals (root is window)
root.Routing = routing.Routing;
root.fos = {
Router: routing.Router
};
}
}(this, function () {
'use strict';
/**
* @fileoverview This file defines the Router class.
*
* You can compile this file by running the following command from the Resources folder:
*
* npm install && npm run build
*/
/**
* Class Router
*/
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
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; };
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; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Router = function () {
/**
* @constructor
* @param {Router.Context=} context
* @param {Object.<string, Router.Route>=} routes
*/
function Router(context, routes) {
_classCallCheck(this, Router);
this.context_ = context || { base_url: '', prefix: '', host: '', port: '', scheme: '' };
this.setRoutes(routes || {});
}
/**
* Returns the current instance.
* @returns {Router}
*/
_createClass(Router, [{
key: 'setRoutingData',
/**
* Sets data for the current instance
* @param {Object} data
*/
value: function setRoutingData(data) {
this.setBaseUrl(data['base_url']);
this.setRoutes(data['routes']);
if ('prefix' in data) {
this.setPrefix(data['prefix']);
}
if ('port' in data) {
this.setPort(data['port']);
}
this.setHost(data['host']);
this.setScheme(data['scheme']);
}
/**
* @param {Object.<string, Router.Route>} routes
*/
}, {
key: 'setRoutes',
value: function setRoutes(routes) {
this.routes_ = Object.freeze(routes);
}
/**
* @return {Object.<string, Router.Route>} routes
*/
}, {
key: 'getRoutes',
value: function getRoutes() {
return this.routes_;
}
/**
* @param {string} baseUrl
*/
}, {
key: 'setBaseUrl',
value: function setBaseUrl(baseUrl) {
this.context_.base_url = baseUrl;
}
/**
* @return {string}
*/
}, {
key: 'getBaseUrl',
value: function getBaseUrl() {
return this.context_.base_url;
}
/**
* @param {string} prefix
*/
}, {
key: 'setPrefix',
value: function setPrefix(prefix) {
this.context_.prefix = prefix;
}
/**
* @param {string} scheme
*/
}, {
key: 'setScheme',
value: function setScheme(scheme) {
this.context_.scheme = scheme;
}
/**
* @return {string}
*/
}, {
key: 'getScheme',
value: function getScheme() {
return this.context_.scheme;
}
/**
* @param {string} host
*/
}, {
key: 'setHost',
value: function setHost(host) {
this.context_.host = host;
}
/**
* @return {string}
*/
}, {
key: 'getHost',
value: function getHost() {
return this.context_.host;
}
/**
* @param {string} port
*/
}, {
key: 'setPort',
value: function setPort(port) {
this.context_.port = port;
}
/**
* @return {string}
*/
}, {
key: 'getPort',
value: function getPort() {
return this.context_.port;
}
}, {
key: 'buildQueryParams',
/**
* Builds query string params added to a URL.
* Port of jQuery's $.param() function, so credit is due there.
*
* @param {string} prefix
* @param {Array|Object|string} params
* @param {Function} add
*/
value: function buildQueryParams(prefix, params, add) {
var _this = this;
var name = void 0;
var rbracket = new RegExp(/\[\]$/);
if (params instanceof Array) {
params.forEach(function (val, i) {
if (rbracket.test(prefix)) {
add(prefix, val);
} else {
_this.buildQueryParams(prefix + '[' + ((typeof val === 'undefined' ? 'undefined' : _typeof(val)) === 'object' ? i : '') + ']', val, add);
}
});
} else if ((typeof params === 'undefined' ? 'undefined' : _typeof(params)) === 'object') {
for (name in params) {
this.buildQueryParams(prefix + '[' + name + ']', params[name], add);
}
} else {
add(prefix, params);
}
}
/**
* Returns a raw route object.
*
* @param {string} name
* @return {Router.Route}
*/
}, {
key: 'getRoute',
value: function getRoute(name) {
var prefixedName = this.context_.prefix + name;
if (!(prefixedName in this.routes_)) {
// Check first for default route before failing
if (!(name in this.routes_)) {
throw new Error('The route "' + name + '" does not exist.');
}
} else {
name = prefixedName;
}
return this.routes_[name];
}
/**
* Generates the URL for a route.
*
* @param {string} name
* @param {Object.<string, string>} opt_params
* @param {boolean} absolute
* @return {string}
*/
}, {
key: 'generate',
value: function generate(name, opt_params) {
var absolute = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
var route = this.getRoute(name),
params = opt_params || {},
unusedParams = _extends({}, params),
url = '',
optional = true,
host = '',
port = typeof this.getPort() == "undefined" || this.getPort() === null ? '' : this.getPort();
route.tokens.forEach(function (token) {
if ('text' === token[0]) {
url = token[1] + url;
optional = false;
return;
}
if ('variable' === token[0]) {
var hasDefault = route.defaults && token[3] in route.defaults;
if (false === optional || !hasDefault || token[3] in params && params[token[3]] != route.defaults[token[3]]) {
var value = void 0;
if (token[3] in params) {
value = params[token[3]];
delete unusedParams[token[3]];
} else if (hasDefault) {
value = route.defaults[token[3]];
} else if (optional) {
return;
} else {
throw new Error('The route "' + name + '" requires the parameter "' + token[3] + '".');
}
var empty = true === value || false === value || '' === value;
if (!empty || !optional) {
var encodedValue = encodeURIComponent(value).replace(/%2F/g, '/');
if ('null' === encodedValue && null === value) {
encodedValue = '';
}
url = token[1] + encodedValue + url;
}
optional = false;
} else if (hasDefault && token[3] in unusedParams) {
delete unusedParams[token[3]];
}
return;
}
throw new Error('The token type "' + token[0] + '" is not supported.');
});
if (url === '') {
url = '/';
}
route.hosttokens.forEach(function (token) {
var value = void 0;
if ('text' === token[0]) {
host = token[1] + host;
return;
}
if ('variable' === token[0]) {
if (token[3] in params) {
value = params[token[3]];
delete unusedParams[token[3]];
} else if (route.defaults && token[3] in route.defaults) {
value = route.defaults[token[3]];
}
host = token[1] + value + host;
}
});
// Foo-bar!
url = this.context_.base_url + url;
if (route.requirements && "_scheme" in route.requirements && this.getScheme() != route.requirements["_scheme"]) {
url = route.requirements["_scheme"] + "://" + (host || this.getHost()) + url;
} else if ("undefined" !== typeof route.schemes && "undefined" !== typeof route.schemes[0] && this.getScheme() !== route.schemes[0]) {
url = route.schemes[0] + "://" + (host || this.getHost()) + url;
} else if (host && this.getHost() !== host + ('' === port ? '' : ':' + port)) {
url = this.getScheme() + "://" + host + ('' === port ? '' : ':' + port) + url;
} else if (absolute === true) {
url = this.getScheme() + "://" + this.getHost() + url;
}
if (Object.keys(unusedParams).length > 0) {
var prefix = void 0;
var queryParams = [];
var add = function add(key, value) {
// if value is a function then call it and assign it's return value as value
value = typeof value === 'function' ? value() : value;
// change null to empty string
value = value === null ? '' : value;
queryParams.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
};
for (prefix in unusedParams) {
this.buildQueryParams(prefix, unusedParams[prefix], add);
}
url = url + '?' + queryParams.join('&').replace(/%20/g, '+');
}
return url;
}
}], [{
key: 'getInstance',
value: function getInstance() {
return Routing;
}
/**
* Configures the current Router instance with the provided data.
* @param {Object} data
*/
}, {
key: 'setData',
value: function setData(data) {
var router = Router.getInstance();
router.setRoutingData(data);
}
}]);
return Router;
}();
/**
* @typedef {{
* tokens: (Array.<Array.<string>>),
* defaults: (Object.<string, string>),
* requirements: Object,
* hosttokens: (Array.<string>)
* }}
*/
Router.Route;
/**
* @typedef {{
* base_url: (string)
* }}
*/
Router.Context;
/**
* Router singleton.
* @const
* @type {Router}
*/
var Routing = new Router();
return { Router: Router, Routing: Routing };
}));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment