Skip to content
This repository has been archived by the owner on Jan 19, 2022. It is now read-only.

Commit

Permalink
support files for testing
Browse files Browse the repository at this point in the history
  • Loading branch information
ianb committed May 23, 2012
1 parent 38ab4e4 commit 8dc5e52
Show file tree
Hide file tree
Showing 2 changed files with 312 additions and 0 deletions.
118 changes: 118 additions & 0 deletions mocks.js
@@ -0,0 +1,118 @@
function DOMRequest() {
this.onsuccess = null;
this.onerror = null;
this.error = null;
this.result = undefined;
this.readyState = "pending";
};

DOMRequest.prototype.fireSuccess = function (result) {
this.result = result;
this.readyState = "done";
if (this.onsuccess) {
this.onsuccess({type: "success", target: this, toString: function () {return '[object Event]';}});
}
};

DOMRequest.prototype.fireError = function (errorName) {
this.error = {name: errorName, type: "error"};
this.readyState = "done";
if (this.onerror) {
this.onerror();
}
};

DOMRequest.prototype.toString = function () {
return '[object DOMRequest]';
}

var mockMozApps = {
_repo: {},
monkeypatch: function () {
navigator.mozApps = this;
},
install: function (manifestURL, installData) {
var pending = new DOMRequest();
var req = new XMLHttpRequest();
var self = this;
req.open("GET", manifestURL);
req.onreadystatechange = function () {
if (req.readyState != 4) {
return;
}
if (req.status != 200) {
pending.fireError("NETWORK_ERROR");
return;
}
try {
var manifest = JSON.parse(req.responseText);
} catch (e) {
pending.fireError("MANIFEST_PARSE_ERROR");
return;
}
self._installManifest(manifestURL, manifest, this._getOrigin(location.href), installData, pending);
};
req.send();
return pending;
},

_installManifest: function (manifestURL, manifest, installOrigin, installData, pending) {
var origin = this._getOrigin(manifestURL);
var appData = this._repo[origin] = {
manifestURL: manifestURL,
manifest: manifest,
installTime: Date.now(),
installData: installData,
origin: origin,
installOrigin: installOrigin
};
var app = new Application(this, appData);
pending.fireSuccess(app);
},

_getOrigin: function (url) {
return URLParse(url).originOnly().toString();
},

getSelf: function () {
var pending = new DOMRequest();
var self = this;
setTimeout(function () {
var thisOrigin = URLParse(location.href).originOnly().toString();
var appData = self._repo[thisOrigin];
if (! appData) {
pending.fireSuccess(null);
} else {
pending.fireSuccess(new Application(self, appData));
}
});
return pending;
}

};

function Application(repo, data) {
this._repo = repo;
this._rawData = data;
this.manifestURL = data.manifestURL;
// Note: doesn't do a deep copy
this.manifest = data.manifest;
this.origin = data.origin;
this.installTime = data.installTime;
this.receipts = data.installData && data.installData.receipts;
};

Application.prototype = {
launch: function () {
throw 'app.launch() not implemented';
},
uninstall: function () {
var pending = new DOMRequest();
var self = this;
setTimeout(function () {
delete self._repo[self.origin];
pending.fireSuccess(this);
});
return pending;
}
};
194 changes: 194 additions & 0 deletions urlmatch.js
@@ -0,0 +1,194 @@
/**
* urlmatch.js
*
* Includes parseUri (c) Steven Levithan <steven@levithan.com> Under the MIT License
*
* Features:
* + parse a url into components
* + url validiation
* + semantically lossless normalization
* + url prefix matching
*
* window.URLParse(string) -
* parse a url using the 'parseUri' algorithm, returning an object containing various
* uri components. returns an object with the following properties (all optional):
*
* PROPERTIES:
* anchor - stuff after the #
* authority - everything after the :// and before the path. Including user auth, host, and port
* directory - path with trailing filename and everything after removed
* file - path without directory
* host - host
* password - password part when user:pass@ is prepended to host
* path - full path, sans query or anchor
* port - port, when present in url
* query - ?XXX
* relative -
* scheme - url scheme (http, file, https, etc.)
* source - full string passed to URLParse()
* user - user part when user:pass@ is prepended to host
* userInfo -
*
* FUNCTIONS:
* (string) toString() - generate a string representation of the url
*
* (this) validate() - validate the url, possbly throwing a string exception
* if determined to not be a valid URL. Returns this, thus may be chained.
*
* (this) normalize() - perform in-place modification of the url to place it in a normal
* (and verbose) form. Returns this, thus may be chained.
*
* (bool) contains(str) - returns whether the object upon which contains() is called is a
* "url prefix" for the passed in string, after normalization.
*
* (this) originOnly() - removes everything that would occur after port, including
* path, query, and anchor.
*
*/

URLParse = (function() {
/* const */ var INV_URL = "invalid url: ";
var parseURL = function(s) {
var toString = function() {
var str = this.scheme + "://";
if (this.user) str += this.user;
if (this.password) str += ":" + this.password;
if (this.user || this.password) str += "@";
if (this.host) str += this.host;
if (this.port) str += ":" + this.port;
if (this.path) str += this.path;
if (this.query) str += "?" + this.query;
if (this.anchor) str += "#" + this.anchor;
return str;
};

var originOnly = function() {
this.path = this.query = this.anchor = undefined;
return this;
};

var validate = function() {
if (!this.scheme) throw INV_URL +"missing scheme";
if (this.scheme !== 'http' && this.scheme !== 'https')
throw INV_URL + "unsupported scheme: " + this.scheme;
if (!this.host) throw INV_URL + "missing host";
if (this.port) {
var p = parseInt(this.port);
if (!this.port.match(/^\d+$/)) throw INV_URL + "non-numeric numbers in port";
if (p <= 0 || p >= 65536) throw INV_URL + "port out of range (" +this.port+")";
}
if (this.path && this.path.indexOf('/') != 0) throw INV_URL + "path must start with '/'";

return this;
};

var normalize = function() {
// lowercase scheme
if (this.scheme) this.scheme = this.scheme.toLowerCase();

// for directory references, append trailing slash
if (!this.path) this.path = "/";

// remove port numbers same as default
if (this.port === "80" && 'http' === this.scheme) delete this.port;
if (this.port === "443" && 'https' === this.scheme) delete this.port;

// remove dot segments from path, algorithm
// http://tools.ietf.org/html/rfc3986#section-5.2.4
this.path = (function (p) {
var out = [];
while (p) {
if (p.indexOf('../') === 0) p = p.substr(3);
else if (p.indexOf('./') === 0) p = p.substr(2);
else if (p.indexOf('/./') === 0) p = p.substr(2);
else if (p === '/.') p = '/';
else if (p.indexOf('/../') === 0 || p === '/..') {
if (out.length > 0) out.pop();
p = '/' + p.substr(4);
} else if (p === '.' || p === '..') p = '';
else {
var m = p.match(/^\/?([^\/]*)/);
// remove path match from input
p = p.substr(m[0].length);
// add path to output
out.push(m[1]);
}
}
return '/' + out.join('/');
})(this.path);

// XXX: upcase chars in % escaping?

// now we need to update all members
var n = parseURL(this.toString()),
i = 14,
o = parseUri.options;

while (i--) {
var k = o.key[i];
if (n[k] && typeof(n[k]) === 'string') this[k] = n[k];
else if (this[k] && typeof(this[k]) === 'string') delete this[k];
}

return this;
};

var contains = function(str) {
try {
this.validate();
var prefix = parseURL(this.toString()).normalize().toString();
var url = parseURL(str).validate().normalize().toString();
return (url.indexOf(prefix) === 0);
} catch(e) {
console.log(e);
// if any exceptions are raised, then the comparison fails
return false;
}
};

// parseUri 1.2.2
// (c) Steven Levithan <stevenlevithan.com>
// MIT License
var parseUri = function(str) {
var o = parseUri.options,
m = o.parser.exec(str),
uri = {},
i = 14;

while (i--) if (m[i]) uri[o.key[i]] = m[i];

if (uri[o.key[12]]) {
uri[o.q.name] = {};
uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
if ($1) uri[o.q.name][$1] = $2;
});
}
// member functions
uri.toString = toString;
uri.validate = validate;
uri.normalize = normalize;
uri.contains = contains;
uri.originOnly = originOnly;
return uri;
};

parseUri.options = {
key: ["source","scheme","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
q: {
name: "queryKey",
parser: /(?:^|&)([^&=]*)=?([^&]*)/g
},
parser: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/
};
// end parseUri

// parse URI using the parseUri code and return the resultant object
return parseUri(s);
};

return parseURL;
})();

/* Jetpack specific export */
if (typeof exports !== "undefined")
exports.URLParse = URLParse;

0 comments on commit 8dc5e52

Please sign in to comment.