UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

308 lines (269 loc) • 9.46 kB
"use strict"; var extend = require("../core/utils/extend").extend, typeUtils = require("../core/utils/type"), iteratorUtils = require("../core/utils/iterator"), inArray = require("../core/utils/array").inArray, Class = require("../core/class"); // NOTE: replaceState crushes on WP8 if url contains ':' character (T108063) var JSON_URI_PREFIX = encodeURIComponent("json:"); var Route = Class.inherit({ _trimSeparators: function _trimSeparators(str) { return str.replace(/^[\/.]+|\/+$/g, ""); }, _escapeRe: function _escapeRe(str) { return str.replace(/[^-\w]/g, "\\$1"); }, _checkConstraint: function _checkConstraint(param, constraint) { param = String(param); if (typeof constraint === "string") { constraint = new RegExp(constraint); } var match = constraint.exec(param); if (!match || match[0] !== param) { return false; } return true; }, _ensureReady: function _ensureReady() { var that = this; if (this._patternRe) { return false; } this._pattern = this._trimSeparators(this._pattern); this._patternRe = ""; this._params = []; this._segments = []; this._separators = []; this._pattern.replace(/[^\/]+/g, function (segment, index) { that._segments.push(segment); if (index) { that._separators.push(that._pattern.substr(index - 1, 1)); } }); iteratorUtils.each(this._segments, function (index) { var segment = this, separator = index ? that._separators[index - 1] : ""; if (segment.charAt(0) === ":") { segment = segment.substr(1); that._params.push(segment); that._patternRe += "(?:" + separator + "([^/]*))"; if (segment in that._defaults) { that._patternRe += "?"; } } else { that._patternRe += separator + that._escapeRe(segment); } }); this._patternRe = new RegExp("^" + this._patternRe + "$"); }, ctor: function ctor(pattern, defaults, constraints) { this._pattern = pattern || ""; this._defaults = defaults || {}; this._constraints = constraints || {}; }, parse: function parse(uri) { var that = this; this._ensureReady(); var matches = this._patternRe.exec(uri); if (!matches) { return false; } var result = extend({}, this._defaults); iteratorUtils.each(this._params, function (i) { var index = i + 1; if (matches.length >= index && matches[index]) { result[this] = that.parseSegment(matches[index]); } }); iteratorUtils.each(this._constraints, function (key) { if (!that._checkConstraint(result[key], that._constraints[key])) { result = false; return false; } }); return result; }, format: function format(routeValues) { var that = this, query = ""; this._ensureReady(); var mergeValues = extend({}, this._defaults), useStatic = 0, result = [], dels = [], unusedRouteValues = {}; iteratorUtils.each(routeValues, function (paramName, paramValue) { routeValues[paramName] = that.formatSegment(paramValue); if (!(paramName in mergeValues)) { unusedRouteValues[paramName] = true; } }); iteratorUtils.each(this._segments, function (index, segment) { result[index] = index ? that._separators[index - 1] : ''; if (segment.charAt(0) === ':') { var paramName = segment.substr(1); if (!(paramName in routeValues) && !(paramName in that._defaults)) { result = null; return false; } if (paramName in that._constraints && !that._checkConstraint(routeValues[paramName], that._constraints[paramName])) { result = null; return false; } if (paramName in routeValues) { if (routeValues[paramName] !== undefined) { mergeValues[paramName] = routeValues[paramName]; result[index] += routeValues[paramName]; useStatic = index; } delete unusedRouteValues[paramName]; } else if (paramName in mergeValues) { result[index] += mergeValues[paramName]; dels.push(index); } } else { result[index] += segment; useStatic = index; } }); iteratorUtils.each(mergeValues, function (key, value) { if (!!value && inArray(":" + key, that._segments) === -1 && routeValues[key] !== value) { result = null; return false; } }); var unusedCount = 0; if (!typeUtils.isEmptyObject(unusedRouteValues)) { query = "?"; iteratorUtils.each(unusedRouteValues, function (key) { query += key + "=" + routeValues[key] + "&"; unusedCount++; }); query = query.substr(0, query.length - 1); } if (result === null) { return false; } if (dels.length) { iteratorUtils.map(dels, function (i) { if (i >= useStatic) { result[i] = ''; } }); } var path = result.join(''); path = path.replace(/\/+$/, ""); return { uri: path + query, unusedCount: unusedCount }; }, formatSegment: function formatSegment(value) { if (Array.isArray(value) || typeUtils.isPlainObject(value)) { return JSON_URI_PREFIX + encodeURIComponent(JSON.stringify(value)); } return encodeURIComponent(value); }, parseSegment: function parseSegment(value) { if (value.substr(0, JSON_URI_PREFIX.length) === JSON_URI_PREFIX) { try { return JSON.parse(decodeURIComponent(value.substr(JSON_URI_PREFIX.length))); } catch (x) {} } return decodeURIComponent(value); } }); /** * @name Router * @publicName Router * @type object * @module framework/router * @export default */ var Router = Class.inherit({ ctor: function ctor() { this._registry = []; }, _trimSeparators: function _trimSeparators(str) { return str.replace(/^[\/.]+|\/+$/g, ""); }, _createRoute: function _createRoute(pattern, defaults, constraints) { return new Route(pattern, defaults, constraints); }, /** * @name RouterMethods.register * @publicName register(pattern, defaults, constraints) * @type method * @param1 pattern:string * @param2 defaults:object|undefined * @param3 constraints:object|undefined */ register: function register(pattern, defaults, constraints) { this._registry.push(this._createRoute(pattern, defaults, constraints)); }, _parseQuery: function _parseQuery(query) { var result = {}, values = query.split("&"); iteratorUtils.each(values, function (index, value) { var keyValuePair = value.split("="); result[keyValuePair[0]] = decodeURIComponent(keyValuePair[1]); }); return result; }, /** * @name RouterMethods.parse * @publicName parse(uri) * @type method * @param1 uri:string * @return object */ parse: function parse(uri) { var that = this, result; uri = this._trimSeparators(uri); var parts = uri.split("?", 2), path = parts[0], query = parts[1]; iteratorUtils.each(this._registry, function () { var parseResult = this.parse(path); if (parseResult !== false) { result = parseResult; if (query) { result = extend(result, that._parseQuery(query)); } return false; } }); return result ? result : false; }, /** * @name RouterMethods.format * @publicName format(obj) * @type method * @param1 obj:object * @return string */ format: function format(obj) { var result = false, minUnusedCount = 99999; obj = obj || {}; iteratorUtils.each(this._registry, function () { var toFormat = extend(true, {}, obj); var formatResult = this.format(toFormat); if (formatResult !== false) { if (minUnusedCount > formatResult.unusedCount) { minUnusedCount = formatResult.unusedCount; result = formatResult.uri; } } }); return result; } }); ///#DEBUG Route.__internals = { JSON_URI_PREFIX: JSON_URI_PREFIX }; ///#ENDDEBUG module.exports = Router; module.exports.Route = Route;