192 lines
5.4 KiB
JavaScript
192 lines
5.4 KiB
JavaScript
(function (root, factory) {
|
|
if (typeof exports === 'object') {
|
|
module.exports = factory();
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
define([], factory);
|
|
} else {
|
|
root.urltemplate = factory();
|
|
}
|
|
}(this, function () {
|
|
/**
|
|
* @constructor
|
|
*/
|
|
function UrlTemplate() {
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
* @param {string} str
|
|
* @return {string}
|
|
*/
|
|
UrlTemplate.prototype.encodeReserved = function (str) {
|
|
return str.split(/(%[0-9A-Fa-f]{2})/g).map(function (part) {
|
|
if (!/%[0-9A-Fa-f]/.test(part)) {
|
|
part = encodeURI(part).replace(/%5B/g, '[').replace(/%5D/g, ']');
|
|
}
|
|
return part;
|
|
}).join('');
|
|
};
|
|
|
|
/**
|
|
* @private
|
|
* @param {string} str
|
|
* @return {string}
|
|
*/
|
|
UrlTemplate.prototype.encodeUnreserved = function (str) {
|
|
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
|
|
return '%' + c.charCodeAt(0).toString(16).toUpperCase();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
* @param {string} operator
|
|
* @param {string} value
|
|
* @param {string} key
|
|
* @return {string}
|
|
*/
|
|
UrlTemplate.prototype.encodeValue = function (operator, value, key) {
|
|
value = (operator === '+' || operator === '#') ? this.encodeReserved(value) : this.encodeUnreserved(value);
|
|
|
|
if (key) {
|
|
return this.encodeUnreserved(key) + '=' + value;
|
|
} else {
|
|
return value;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @private
|
|
* @param {*} value
|
|
* @return {boolean}
|
|
*/
|
|
UrlTemplate.prototype.isDefined = function (value) {
|
|
return value !== undefined && value !== null;
|
|
};
|
|
|
|
/**
|
|
* @private
|
|
* @param {string}
|
|
* @return {boolean}
|
|
*/
|
|
UrlTemplate.prototype.isKeyOperator = function (operator) {
|
|
return operator === ';' || operator === '&' || operator === '?';
|
|
};
|
|
|
|
/**
|
|
* @private
|
|
* @param {Object} context
|
|
* @param {string} operator
|
|
* @param {string} key
|
|
* @param {string} modifier
|
|
*/
|
|
UrlTemplate.prototype.getValues = function (context, operator, key, modifier) {
|
|
var value = context[key],
|
|
result = [];
|
|
|
|
if (this.isDefined(value) && value !== '') {
|
|
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
value = value.toString();
|
|
|
|
if (modifier && modifier !== '*') {
|
|
value = value.substring(0, parseInt(modifier, 10));
|
|
}
|
|
|
|
result.push(this.encodeValue(operator, value, this.isKeyOperator(operator) ? key : null));
|
|
} else {
|
|
if (modifier === '*') {
|
|
if (Array.isArray(value)) {
|
|
value.filter(this.isDefined).forEach(function (value) {
|
|
result.push(this.encodeValue(operator, value, this.isKeyOperator(operator) ? key : null));
|
|
}, this);
|
|
} else {
|
|
Object.keys(value).forEach(function (k) {
|
|
if (this.isDefined(value[k])) {
|
|
result.push(this.encodeValue(operator, value[k], k));
|
|
}
|
|
}, this);
|
|
}
|
|
} else {
|
|
var tmp = [];
|
|
|
|
if (Array.isArray(value)) {
|
|
value.filter(this.isDefined).forEach(function (value) {
|
|
tmp.push(this.encodeValue(operator, value));
|
|
}, this);
|
|
} else {
|
|
Object.keys(value).forEach(function (k) {
|
|
if (this.isDefined(value[k])) {
|
|
tmp.push(this.encodeUnreserved(k));
|
|
tmp.push(this.encodeValue(operator, value[k].toString()));
|
|
}
|
|
}, this);
|
|
}
|
|
|
|
if (this.isKeyOperator(operator)) {
|
|
result.push(this.encodeUnreserved(key) + '=' + tmp.join(','));
|
|
} else if (tmp.length !== 0) {
|
|
result.push(tmp.join(','));
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (operator === ';') {
|
|
if (this.isDefined(value)) {
|
|
result.push(this.encodeUnreserved(key));
|
|
}
|
|
} else if (value === '' && (operator === '&' || operator === '?')) {
|
|
result.push(this.encodeUnreserved(key) + '=');
|
|
} else if (value === '') {
|
|
result.push('');
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* @param {string} template
|
|
* @return {function(Object):string}
|
|
*/
|
|
UrlTemplate.prototype.parse = function (template) {
|
|
var that = this;
|
|
var operators = ['+', '#', '.', '/', ';', '?', '&'];
|
|
|
|
return {
|
|
expand: function (context) {
|
|
return template.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, function (_, expression, literal) {
|
|
if (expression) {
|
|
var operator = null,
|
|
values = [];
|
|
|
|
if (operators.indexOf(expression.charAt(0)) !== -1) {
|
|
operator = expression.charAt(0);
|
|
expression = expression.substr(1);
|
|
}
|
|
|
|
expression.split(/,/g).forEach(function (variable) {
|
|
var tmp = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable);
|
|
values.push.apply(values, that.getValues(context, operator, tmp[1], tmp[2] || tmp[3]));
|
|
});
|
|
|
|
if (operator && operator !== '+') {
|
|
var separator = ',';
|
|
|
|
if (operator === '?') {
|
|
separator = '&';
|
|
} else if (operator !== '#') {
|
|
separator = operator;
|
|
}
|
|
return (values.length !== 0 ? operator : '') + values.join(separator);
|
|
} else {
|
|
return values.join(',');
|
|
}
|
|
} else {
|
|
return that.encodeReserved(literal);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
};
|
|
|
|
return new UrlTemplate();
|
|
}));
|