pathparser.js (3006B)
1 /** 2 * pathparser.js - tiny URL parser/router 3 * 4 * Copyright (c) 2014 Dan Stillman 5 * License: MIT 6 * https://github.com/dstillman/pathparser.js 7 */ 8 (function (factory) { 9 // AMD/RequireJS 10 if (typeof define === 'function' && define.amd) { 11 define(factory); 12 // CommonJS/Node 13 } else if (typeof exports === 'object') { 14 module.exports = factory(); 15 // Mozilla JSM 16 } else if (~String(this).indexOf('BackstagePass')) { 17 EXPORTED_SYMBOLS = ["PathParser"]; 18 PathParser = factory(); 19 // Browser global 20 } else { 21 PathParser = factory(); 22 } 23 }(function () { 24 "use strict"; 25 26 var PathParser = function (params) { 27 this.rules = []; 28 this.params = params; 29 } 30 31 PathParser.prototype = (function () { 32 function getParamsFromRule(rule, pathParts, queryParts) { 33 var params = {}; 34 var missingParams = {}; 35 36 // Parse path components 37 for (var i = 0; i < rule.parts.length; i++) { 38 var rulePart = rule.parts[i]; 39 var part = pathParts[i]; 40 41 if (part !== undefined) { 42 if (rulePart.charAt(0) == ':') { 43 params[rulePart.substr(1)] = part; 44 continue; 45 } 46 else if (rulePart !== part) { 47 return false; 48 } 49 } 50 else if (rulePart.charAt(0) != ':') { 51 return false; 52 } 53 else { 54 missingParams[rulePart.substr(1)] = true; 55 } 56 } 57 58 // Parse query strings 59 for (var i = 0; i < queryParts.length; ++i) { 60 var nameValue = queryParts[i].split('=', 2); 61 var key = nameValue[0]; 62 // But ignore empty parameters and don't override named parameters 63 if (nameValue.length == 2 && !params[key] && !missingParams[key]) { 64 params[key] = nameValue[1]; 65 } 66 } 67 68 return params; 69 } 70 71 return { 72 add: function (route, handler, autoPopulateOnMatch) { 73 this.rules.push({ 74 parts: route.replace(/^\//, '').split('/'), 75 handler: handler, 76 autoPopulateOnMatch: autoPopulateOnMatch === undefined || autoPopulateOnMatch 77 }); 78 }, 79 80 run: function (url) { 81 if (url && url.length) { 82 url = url 83 // Remove redundant slashes 84 .replace(/\/+/g, '/') 85 // Strip leading and trailing '/' (at end or before query string) 86 .replace(/^\/|\/($|\?)/, '') 87 // Strip fragment identifiers 88 .replace(/#.*$/, ''); 89 } 90 91 var urlSplit = url.split('?', 2); 92 var pathParts = urlSplit[0].split('/', 50); 93 var queryParts = urlSplit[1] ? urlSplit[1].split('&', 50) : []; 94 95 for (var i=0; i < this.rules.length; i++) { 96 var rule = this.rules[i]; 97 var params = getParamsFromRule(rule, pathParts, queryParts); 98 if (params) { 99 params.url = url; 100 // Automatic parameter assignment 101 if (rule.autoPopulateOnMatch && this.params) { 102 for (var param in params) { 103 this.params[param] = params[param]; 104 } 105 } 106 // Call handler with 'this' bound to parameter object 107 if (rule.handler) { 108 rule.handler.call(params); 109 } 110 return true; 111 } 112 } 113 return false; 114 } 115 }; 116 })(); 117 118 return PathParser; 119 }));