193 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			193 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(); | ||
|  | })); |