web-apps/vendor/touch/src/app/Route.js
2016-09-14 15:04:28 +03:00

211 lines
6.7 KiB
JavaScript

/**
* @author Ed Spencer
* @private
*
* Represents a mapping between a url and a controller/action pair. May also contain additional params. This is a
* private internal class that should not need to be used by end-developer code. Its API and existence are subject to
* change so use at your own risk.
*
* For information on how to use routes we suggest reading the following guides:
*
* - [Using History Support](../../../core_concepts/history_support.html)
* - [Intro to Applications](../../../core_concepts/about_applications.html)
* - [Using Controllers](../../../core_concepts/controllers.html)
*
*/
Ext.define('Ext.app.Route', {
config: {
/**
* @cfg {Object} conditions Optional set of conditions for each token in the url string. Each key should be one
* of the tokens, each value should be a regex that the token should accept. For example, if you have a Route
* with a url like "files/:fileName" and you want it to match urls like "files/someImage.jpg" then you can set
* these conditions to allow the :fileName token to accept strings containing a period ("."):
*
* conditions: {
* ':fileName': "[0-9a-zA-Z\.]+"
* }
*
*/
conditions: {},
/**
* @cfg {String} url (required) The url regex to match against.
*/
url: null,
/**
* @cfg {String} controller The name of the Controller whose {@link #action} will be called if this route is
* matched.
*/
controller: null,
/**
* @cfg {String} action The name of the action that will be called on the {@link #controller} if this route is
* matched.
*/
action: null,
/**
* @private
* @cfg {Boolean} initialized Indicates whether or not this Route has been initialized. We don't initialize
* straight away so as to save unnecessary processing.
*/
initialized: false
},
constructor: function(config) {
this.initConfig(config);
},
/**
* Attempts to recognize a given url string and return controller/action pair for it.
* @param {String} url The url to recognize.
* @return {Object/Boolean} The matched data, or `false` if no match.
*/
recognize: function(url) {
if (!this.getInitialized()) {
this.initialize();
}
if (this.recognizes(url)) {
var matches = this.matchesFor(url),
args = url.match(this.matcherRegex);
args.shift();
return Ext.applyIf(matches, {
controller: this.getController(),
action : this.getAction(),
url : url,
args : args,
// We keep the historyUrl in here for backwards compatibility
historyUrl: url
});
}
},
/**
* @private
* Sets up the relevant regular expressions used to match against this route.
*/
initialize: function() {
/*
* The regular expression we use to match a segment of a route mapping
* this will recognize segments starting with a colon,
* e.g. on 'namespace/:controller/:action', :controller and :action will be recognized
*/
this.paramMatchingRegex = new RegExp(/:([0-9A-Za-z\_]*)/g);
/*
* Converts a route string into an array of symbols starting with a colon. e.g.
* ":controller/:action/:id" => [':controller', ':action', ':id']
*/
this.paramsInMatchString = this.getUrl().match(this.paramMatchingRegex) || [];
this.matcherRegex = this.createMatcherRegex(this.getUrl());
this.setInitialized(true);
},
/**
* @private
* Returns true if this Route matches the given url string
* @param {String} url The url to test
* @return {Boolean} True if this Route recognizes the url
*/
recognizes: function(url) {
return this.matcherRegex.test(url);
},
/**
* @private
* Returns a hash of matching url segments for the given url.
* @param {String} url The url to extract matches for
* @return {Object} matching url segments
*/
matchesFor: function(url) {
var params = {},
keys = this.paramsInMatchString,
values = url.match(this.matcherRegex),
length = keys.length,
i;
//first value is the entire match so reject
values.shift();
for (i = 0; i < length; i++) {
params[keys[i].replace(":", "")] = values[i];
}
return params;
},
/**
* @private
* Returns an array of matching url segments for the given url.
* @param {String} url The url to extract matches for
* @return {Array} matching url segments
*/
argsFor: function(url) {
var args = [],
keys = this.paramsInMatchString,
values = url.match(this.matcherRegex),
length = keys.length,
i;
//first value is the entire match so reject
values.shift();
for (i = 0; i < length; i++) {
args.push(keys[i].replace(':', ""));
params[keys[i].replace(":", "")] = values[i];
}
return params;
},
/**
* @private
* Constructs a url for the given config object by replacing wildcard placeholders in the Route's url
* @param {Object} config The config object
* @return {String} The constructed url
*/
urlFor: function(config) {
var url = this.getUrl();
for (var key in config) {
url = url.replace(":" + key, config[key]);
}
return url;
},
/**
* @private
* Takes the configured url string including wildcards and returns a regex that can be used to match
* against a url
* @param {String} url The url string
* @return {RegExp} The matcher regex
*/
createMatcherRegex: function(url) {
/**
* Converts a route string into an array of symbols starting with a colon. e.g.
* ":controller/:action/:id" => [':controller', ':action', ':id']
*/
var paramsInMatchString = this.paramsInMatchString,
length = paramsInMatchString.length,
i, cond, matcher;
for (i = 0; i < length; i++) {
cond = this.getConditions()[paramsInMatchString[i]];
matcher = Ext.util.Format.format("({0})", cond || "[%a-zA-Z0-9\\-\\_\\s,]+");
url = url.replace(new RegExp(paramsInMatchString[i]), matcher);
}
//we want to match the whole string, so include the anchors
return new RegExp("^" + url + "$");
}
});