UNPKG

3.71 kBJavaScriptView Raw
1(function (doc, define) {
2
3 define(['./util/beget'], function (beget) {
4 "use strict";
5
6 var absoluteUrlRE, urlEncodedBraceOpenRE, urlEncodedBraceCloseRE;
7
8 absoluteUrlRE = /^https?:\/\//i;
9 urlEncodedBraceOpenRE = /%7b/i;
10 urlEncodedBraceCloseRE = /%7d/i;
11
12 /**
13 * Apply params to the template to create a URL.
14 *
15 * Parameters that are not applied directly to the template, are appended
16 * to the URL as query string parameters.
17 *
18 * @param {String} template the URI template
19 * @param {Object} params parameters to apply to the template
20 * @return {String} the resulting URL
21 */
22 function buildUrl(template, params) {
23 // internal builder to convert template with params.
24 var url, name, queryStringParams, re;
25
26 url = template;
27 queryStringParams = {};
28
29 if (params) {
30 for (name in params) {
31 re = new RegExp("\\{" + name + "\\}");
32 if (re.test(url)) {
33 url = url.replace(re, encodeURIComponent(params[name]), "g");
34 }
35 else {
36 queryStringParams[name] = params[name];
37 }
38 }
39 for (name in queryStringParams) {
40 url += url.indexOf("?") === -1 ? "?" : "&";
41 url += encodeURIComponent(name);
42 if (queryStringParams[name] !== null && queryStringParams[name] !== undefined) {
43 url += "=";
44 url += encodeURIComponent(queryStringParams[name]);
45 }
46 }
47 }
48 return url;
49 }
50
51 /**
52 * Create a new URL Builder
53 *
54 * @param {String|UrlBuilder} template the base template to build from, may be another UrlBuilder
55 * @param {Object} [params] base parameters
56 * @constructor
57 */
58 function UrlBuilder(template, params) {
59 if (template instanceof UrlBuilder) {
60 this._template = template.template;
61 this._params = beget(this._params, params);
62 }
63 else {
64 this._template = (template || '').toString();
65 this._params = params;
66 }
67 }
68
69 UrlBuilder.prototype = {
70
71 /**
72 * Create a new UrlBuilder instance that extends the current builder.
73 * The current builder is unmodified.
74 *
75 * @param {String} [template] URL template to append to the current template
76 * @param {Object} [params] params to combine with current params. New params override existing params
77 * @return {UrlBuilder} the new builder
78 */
79 append: function (template, params) {
80 // TODO consider query strings and fragments
81 return new UrlBuilder(this._template + template, beget(this._params, params));
82 },
83
84 /**
85 * Create a new UrlBuilder with a fully qualified URL based on the
86 * window's location or base href and the current templates relative URL.
87 *
88 * Path variables are preserved.
89 *
90 * *Browser only*
91 *
92 * @return {UrlBuilder} the fully qualified URL template
93 */
94 absolute: function () {
95 if (!doc || absoluteUrlRE.test(this._template)) { return this; }
96
97 var a, template;
98
99 a = doc.createElement('a');
100 a.href = this._template;
101 template = a.href.replace(urlEncodedBraceOpenRE, '{').replace(urlEncodedBraceCloseRE, '}');
102
103 return new UrlBuilder(template, this._params);
104 },
105
106 /**
107 * Expand the template replacing path variables with parameters
108 *
109 * @param {Object} [params] params to combine with current params. New params override existing params
110 * @return {String} the expanded URL
111 */
112 build: function (params) {
113 return buildUrl(this._template, beget(this._params, params));
114 },
115
116 /**
117 * @see build
118 */
119 toString: function () {
120 return this.build();
121 }
122 };
123
124 return UrlBuilder;
125 });
126
127}(
128 this.document,
129 typeof define === 'function' ? define : function (deps, factory) {
130 module.exports = factory.apply(this, deps.map(require));
131 }
132 // Boilerplate for AMD and Node
133));