UNPKG

bugcore

Version:

bugcore is a JavaScript library that provides a foundational architecture for object oriented JS

362 lines (305 loc) 10.7 kB
/* * Copyright (c) 2016 airbug Inc. http://airbug.com * * bugcore may be freely distributed under the MIT license. */ //------------------------------------------------------------------------------- // Annotations //------------------------------------------------------------------------------- //@Export('Url') //@Require('Class') //@Require('Map') //@Require('Obj') //@Require('ObjectUtil') //@Require('TypeUtil') //------------------------------------------------------------------------------- // Context //------------------------------------------------------------------------------- require('bugpack').context("*", function(bugpack) { //------------------------------------------------------------------------------- // BugPack //------------------------------------------------------------------------------- var Class = bugpack.require('Class'); var Map = bugpack.require('Map'); var Obj = bugpack.require('Obj'); var ObjectUtil = bugpack.require('ObjectUtil'); var TypeUtil = bugpack.require('TypeUtil'); //------------------------------------------------------------------------------- // Declare Class //------------------------------------------------------------------------------- /** * @class * @extends {Obj} */ var Url = Class.extend(Obj, { _name: "Url", //------------------------------------------------------------------------------- // Constructor //------------------------------------------------------------------------------- /** * @constructs * @param {{ * host: ?string, * path: ?string, * port: ?number, * protocol: ?string, * anchor: ?string, * queryKey: Object.<string, string> * }} urlParts */ _constructor: function(urlParts) { this._super(); if (!TypeUtil.isObject(urlParts)) { urlParts = {}; } if (!TypeUtil.isString(urlParts.protocol) || urlParts.protocol === "") { urlParts.protocol = "http"; } if (!TypeUtil.isNumber(urlParts.port) || urlParts.port <= 0) { urlParts.port = 80; } if (!TypeUtil.isString(urlParts.path) || urlParts.path === "") { urlParts.path = "/"; } if (urlParts.path.substr(0, 1) !== "/") { urlParts.path = "/" + urlParts.path; } //------------------------------------------------------------------------------- // Private Properties //------------------------------------------------------------------------------- /** * @private * @type {?string} */ this.anchor = urlParts.anchor; /** * @private * @type {?string} */ this.host = urlParts.host; /** * @private * @type {?string} */ this.path = urlParts.path; /** * @private * @type {?number} */ this.port = urlParts.port - 0; /** * @private * @type {?string} */ this.protocol = urlParts.protocol; /** * @private * @type {Map.<string, string>} */ this.urlQueryMap = new Map(urlParts.queryKey); }, //------------------------------------------------------------------------------- // Getters and Setters //------------------------------------------------------------------------------- /** * @return {string} */ getAnchor: function() { return this.anchor; }, /** * @return {?string} */ getHost: function() { return this.host; }, /** * @return {?string} */ getPath: function() { return this.path; }, /** * @return {number} */ getPort: function() { return this.port; }, /** * @return {string} */ getProtocol: function() { return this.protocol; }, //------------------------------------------------------------------------------- // Obj Methods //------------------------------------------------------------------------------- /** * @param {boolean} deep * @return {Url} */ clone: function(deep) { var options = { anchor: this.getAnchor(), host: this.getHost(), path: this.getPath(), port: this.getPort(), protocol: this.getProtocol(), queryKey: this.urlQueryMap.toObject() }; return new Url(options); }, /** * @override * @param {*} value * @return {boolean} */ equals: function(value) { if (Class.doesExtend(value, Url)) { return (Obj.equals(value.toString(), this.toString())); } return false; }, /** * @override * @return {number} */ hashCode: function() { if (!this._hashCode) { this._hashCode = Obj.hashCode("[Url]" + Obj.hashCode(this.toString())); } return this._hashCode; }, /** * @return {string} */ toString: function() { var output = ""; output += this.getProtocol() + "://"; output += this.getHost(); if (this.getPort() && this.getPort() !== 80) { output += ":" + this.getPort(); } if (this.getPath()) { output += this.getPath(); } if (!this.urlQueryMap.isEmpty()) { output += "?"; var first = true; this.urlQueryMap.forEach(function(value, key) { if (first) { first = false; output += key + "=" + encodeURIComponent(value); } else { output += "&" + key + "=" + encodeURIComponent(value); } }); } if (this.getAnchor()) { output += "#"; output += this.getAnchor(); } return output; }, //------------------------------------------------------------------------------- // Public Methods //------------------------------------------------------------------------------- /** * @param {string} key * @return {string} */ getUrlQuery: function(key) { return this.urlQueryMap.get(key); }, /** * @param {string} key * @return {boolean} */ hasUrlQuery: function(key) { return this.urlQueryMap.containsKey(key); }, /** * @return {string} */ toBaseUrlString: function() { return this.getProtocol() + "://" + this.toHostString(); }, /** * @return {string} */ toHostString: function() { var hostString = this.getHost(); var port = this.getPort(); if (port !== 80) { hostString += ":" + port; } return hostString; }, /** * @return {string} */ toUrlString: function() { var urlString = this.toBaseUrlString(); var path = this.getPath(); if (path) { urlString += path; } return urlString; } }); //------------------------------------------------------------------------------- // Static Methods //------------------------------------------------------------------------------- /** * @static * @param {string} value * @return {boolean} */ Url.isUrl = function(value) { var regex = /^((((([A-Za-z]{3,9}:(?:\/\/)?)|\/\/)(?:[-;:&=\+\$,A-Za-z0-9]+@)?([A-Za-z0-9-]*\.)*[A-Za-z0-9]+)|(?:(?:(?:\w*\.)+|[-;:&=\+\$,A-Za-z0-9]+@)([A-Za-z0-9-]*\.)*[A-Za-z0-9]+))(:(?:[0-9]+))?((?:\/[\+~=&$%\/.A-Za-z0-9-_]*)?(?:\?(?:[-\+=&;:%@.A-Za-z0-9_,]*))?(?:#(?:[A-Za-z0-9\/]*))?)?)$/; if (TypeUtil.isString(value)) { return regex.test(value); } return false; }; /** * @static * @param {string} urlString * @param {Object=} options * @return {Url} */ Url.parse = function(urlString, options) { if (!options) { options = {}; } var finalOptions = { strictMode: false, key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], q: { name: "queryKey", parser: /(?:^|&)([^&=]*)=?([^&]*)/g }, parser: { strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ } }; ObjectUtil.merge(finalOptions, options); var m = finalOptions.parser[finalOptions.strictMode ? "strict" : "loose"].exec(urlString); var uri = {}; var i = 14; while (i--) { uri[finalOptions.key[i]] = m[i] || ""; } uri[finalOptions.q.name] = {}; uri[finalOptions.key[12]].replace(finalOptions.q.parser, function ($0, $1, $2) { if ($1) uri[finalOptions.q.name][$1] = $2; }); return new Url(uri); }; //------------------------------------------------------------------------------- // Exports //------------------------------------------------------------------------------- bugpack.export('Url', Url); });