Update zotero:// extensions (report, timeline, etc.) for async DB, and more
- Protocol handler extensions can now handle promises and can also make
data available as it's ready instead of all at once (e.g., reports now
output one entry at a time)
- zotero:// URL syntaxes are now more consistent and closer to the web
API (old URLs should work, but some may currently be broken)
Also:
- Code to generate server API, currently available for testing via
zotero://data URLs but eventually moving to HTTP -- zotero://data URLs match
web API URLs, with a different prefix for the personal library (/library vs.
/users/12345)
- Miscellaneous fixes to data objects
Under the hood:
- Extensions now return an AsyncChannel, which is an nsIChannel implementation
that takes a promise-yielding generator that returns a string,
nsIAsyncInputStream, or file that will be used for the channel's data
- New function Zotero.Utilities.Internal.getAsyncInputStream() takes a
generator that yields either promises or strings and returns an async input
stream filled with the yielded strings
- Zotero.Router parsers URLs and extract parameters
- Zotero.Item.toResponseJSON()
2014-09-08 20:51:05 +00:00
|
|
|
/**
|
|
|
|
* pathparser.js - tiny URL parser/router
|
|
|
|
*
|
|
|
|
* Copyright (c) 2014 Dan Stillman
|
|
|
|
* License: MIT
|
|
|
|
* https://github.com/dstillman/pathparser.js
|
|
|
|
*/
|
2018-02-24 09:54:53 +00:00
|
|
|
(function (root, factory) {
|
Update zotero:// extensions (report, timeline, etc.) for async DB, and more
- Protocol handler extensions can now handle promises and can also make
data available as it's ready instead of all at once (e.g., reports now
output one entry at a time)
- zotero:// URL syntaxes are now more consistent and closer to the web
API (old URLs should work, but some may currently be broken)
Also:
- Code to generate server API, currently available for testing via
zotero://data URLs but eventually moving to HTTP -- zotero://data URLs match
web API URLs, with a different prefix for the personal library (/library vs.
/users/12345)
- Miscellaneous fixes to data objects
Under the hood:
- Extensions now return an AsyncChannel, which is an nsIChannel implementation
that takes a promise-yielding generator that returns a string,
nsIAsyncInputStream, or file that will be used for the channel's data
- New function Zotero.Utilities.Internal.getAsyncInputStream() takes a
generator that yields either promises or strings and returns an async input
stream filled with the yielded strings
- Zotero.Router parsers URLs and extract parameters
- Zotero.Item.toResponseJSON()
2014-09-08 20:51:05 +00:00
|
|
|
// AMD/RequireJS
|
|
|
|
if (typeof define === 'function' && define.amd) {
|
|
|
|
define(factory);
|
|
|
|
// CommonJS/Node
|
|
|
|
} else if (typeof exports === 'object') {
|
|
|
|
module.exports = factory();
|
|
|
|
// Mozilla JSM
|
2018-02-24 09:54:53 +00:00
|
|
|
} else if (typeof Components != 'undefined'
|
|
|
|
&& typeof Components.utils != 'undefined'
|
|
|
|
&& typeof Components.utils.import == 'function') {
|
|
|
|
root.EXPORTED_SYMBOLS = ["PathParser"];
|
|
|
|
root.PathParser = factory();
|
Update zotero:// extensions (report, timeline, etc.) for async DB, and more
- Protocol handler extensions can now handle promises and can also make
data available as it's ready instead of all at once (e.g., reports now
output one entry at a time)
- zotero:// URL syntaxes are now more consistent and closer to the web
API (old URLs should work, but some may currently be broken)
Also:
- Code to generate server API, currently available for testing via
zotero://data URLs but eventually moving to HTTP -- zotero://data URLs match
web API URLs, with a different prefix for the personal library (/library vs.
/users/12345)
- Miscellaneous fixes to data objects
Under the hood:
- Extensions now return an AsyncChannel, which is an nsIChannel implementation
that takes a promise-yielding generator that returns a string,
nsIAsyncInputStream, or file that will be used for the channel's data
- New function Zotero.Utilities.Internal.getAsyncInputStream() takes a
generator that yields either promises or strings and returns an async input
stream filled with the yielded strings
- Zotero.Router parsers URLs and extract parameters
- Zotero.Item.toResponseJSON()
2014-09-08 20:51:05 +00:00
|
|
|
// Browser global
|
|
|
|
} else {
|
2018-02-24 09:54:53 +00:00
|
|
|
root.PathParser = factory();
|
Update zotero:// extensions (report, timeline, etc.) for async DB, and more
- Protocol handler extensions can now handle promises and can also make
data available as it's ready instead of all at once (e.g., reports now
output one entry at a time)
- zotero:// URL syntaxes are now more consistent and closer to the web
API (old URLs should work, but some may currently be broken)
Also:
- Code to generate server API, currently available for testing via
zotero://data URLs but eventually moving to HTTP -- zotero://data URLs match
web API URLs, with a different prefix for the personal library (/library vs.
/users/12345)
- Miscellaneous fixes to data objects
Under the hood:
- Extensions now return an AsyncChannel, which is an nsIChannel implementation
that takes a promise-yielding generator that returns a string,
nsIAsyncInputStream, or file that will be used for the channel's data
- New function Zotero.Utilities.Internal.getAsyncInputStream() takes a
generator that yields either promises or strings and returns an async input
stream filled with the yielded strings
- Zotero.Router parsers URLs and extract parameters
- Zotero.Item.toResponseJSON()
2014-09-08 20:51:05 +00:00
|
|
|
}
|
2018-02-24 09:54:53 +00:00
|
|
|
}(this, function () {
|
Update zotero:// extensions (report, timeline, etc.) for async DB, and more
- Protocol handler extensions can now handle promises and can also make
data available as it's ready instead of all at once (e.g., reports now
output one entry at a time)
- zotero:// URL syntaxes are now more consistent and closer to the web
API (old URLs should work, but some may currently be broken)
Also:
- Code to generate server API, currently available for testing via
zotero://data URLs but eventually moving to HTTP -- zotero://data URLs match
web API URLs, with a different prefix for the personal library (/library vs.
/users/12345)
- Miscellaneous fixes to data objects
Under the hood:
- Extensions now return an AsyncChannel, which is an nsIChannel implementation
that takes a promise-yielding generator that returns a string,
nsIAsyncInputStream, or file that will be used for the channel's data
- New function Zotero.Utilities.Internal.getAsyncInputStream() takes a
generator that yields either promises or strings and returns an async input
stream filled with the yielded strings
- Zotero.Router parsers URLs and extract parameters
- Zotero.Item.toResponseJSON()
2014-09-08 20:51:05 +00:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
var PathParser = function (params) {
|
|
|
|
this.rules = [];
|
|
|
|
this.params = params;
|
|
|
|
}
|
|
|
|
|
|
|
|
PathParser.prototype = (function () {
|
|
|
|
function getParamsFromRule(rule, pathParts, queryParts) {
|
|
|
|
var params = {};
|
|
|
|
var missingParams = {};
|
|
|
|
|
|
|
|
// Parse path components
|
|
|
|
for (var i = 0; i < rule.parts.length; i++) {
|
|
|
|
var rulePart = rule.parts[i];
|
|
|
|
var part = pathParts[i];
|
|
|
|
|
|
|
|
if (part !== undefined) {
|
|
|
|
if (rulePart.charAt(0) == ':') {
|
|
|
|
params[rulePart.substr(1)] = part;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (rulePart !== part) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (rulePart.charAt(0) != ':') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
missingParams[rulePart.substr(1)] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse query strings
|
|
|
|
for (var i = 0; i < queryParts.length; ++i) {
|
|
|
|
var nameValue = queryParts[i].split('=', 2);
|
|
|
|
var key = nameValue[0];
|
|
|
|
// But ignore empty parameters and don't override named parameters
|
|
|
|
if (nameValue.length == 2 && !params[key] && !missingParams[key]) {
|
|
|
|
params[key] = nameValue[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return params;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
add: function (route, handler, autoPopulateOnMatch) {
|
|
|
|
this.rules.push({
|
|
|
|
parts: route.replace(/^\//, '').split('/'),
|
|
|
|
handler: handler,
|
|
|
|
autoPopulateOnMatch: autoPopulateOnMatch === undefined || autoPopulateOnMatch
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
run: function (url) {
|
|
|
|
if (url && url.length) {
|
|
|
|
url = url
|
|
|
|
// Remove redundant slashes
|
|
|
|
.replace(/\/+/g, '/')
|
|
|
|
// Strip leading and trailing '/' (at end or before query string)
|
|
|
|
.replace(/^\/|\/($|\?)/, '')
|
|
|
|
// Strip fragment identifiers
|
|
|
|
.replace(/#.*$/, '');
|
|
|
|
}
|
|
|
|
|
|
|
|
var urlSplit = url.split('?', 2);
|
|
|
|
var pathParts = urlSplit[0].split('/', 50);
|
|
|
|
var queryParts = urlSplit[1] ? urlSplit[1].split('&', 50) : [];
|
|
|
|
|
|
|
|
for (var i=0; i < this.rules.length; i++) {
|
|
|
|
var rule = this.rules[i];
|
|
|
|
var params = getParamsFromRule(rule, pathParts, queryParts);
|
|
|
|
if (params) {
|
|
|
|
params.url = url;
|
|
|
|
// Automatic parameter assignment
|
|
|
|
if (rule.autoPopulateOnMatch && this.params) {
|
|
|
|
for (var param in params) {
|
|
|
|
this.params[param] = params[param];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Call handler with 'this' bound to parameter object
|
|
|
|
if (rule.handler) {
|
|
|
|
rule.handler.call(params);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
})();
|
|
|
|
|
|
|
|
return PathParser;
|
|
|
|
}));
|