2006-10-04 17:16:56 +00:00
|
|
|
/*
|
|
|
|
***** BEGIN LICENSE BLOCK *****
|
|
|
|
|
2009-12-28 09:47:49 +00:00
|
|
|
Copyright © 2009 Center for History and New Media
|
|
|
|
George Mason University, Fairfax, Virginia, USA
|
|
|
|
http://zotero.org
|
2006-10-04 17:16:56 +00:00
|
|
|
|
2009-12-28 09:47:49 +00:00
|
|
|
This file is part of Zotero.
|
2006-10-04 17:16:56 +00:00
|
|
|
|
2009-12-28 09:47:49 +00:00
|
|
|
Zotero is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
2006-10-04 17:16:56 +00:00
|
|
|
|
2009-12-28 09:47:49 +00:00
|
|
|
Zotero is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
2006-10-04 17:16:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
Utilities based in part on code taken from Piggy Bank 2.1.1 (BSD-licensed)
|
|
|
|
|
|
|
|
***** END LICENSE BLOCK *****
|
|
|
|
*/
|
2006-06-26 14:46:57 +00:00
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
/**
|
|
|
|
* @class Functions for text manipulation and other miscellaneous purposes
|
2006-06-26 14:46:57 +00:00
|
|
|
*/
|
2010-10-25 00:58:47 +00:00
|
|
|
Zotero.Utilities = {
|
|
|
|
/**
|
|
|
|
* Cleans extraneous punctuation off a creator name and parse into first and last name
|
|
|
|
*
|
|
|
|
* @param {String} author Creator string
|
|
|
|
* @param {String} type Creator type string (e.g., "author" or "editor")
|
|
|
|
* @param {Boolean} useComma Whether the creator string is in inverted (Last, First) format
|
|
|
|
* @return {Object} firstName, lastName, and creatorType
|
|
|
|
*/
|
|
|
|
"cleanAuthor":function(author, type, useComma) {
|
|
|
|
const allCapsRe = /^[A-Z\u0400-\u042f]+$/;
|
2007-10-23 07:11:59 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
if(typeof(author) != "string") {
|
|
|
|
throw "cleanAuthor: author must be a string";
|
|
|
|
}
|
|
|
|
|
|
|
|
author = author.replace(/^[\s\.\,\/\[\]\:]+/, '');
|
|
|
|
author = author.replace(/[\s\,\/\[\]\:\.]+$/, '');
|
|
|
|
author = author.replace(/ +/, ' ');
|
|
|
|
if(useComma) {
|
|
|
|
// Add spaces between periods
|
|
|
|
author = author.replace(/\.([^ ])/, ". $1");
|
|
|
|
|
|
|
|
var splitNames = author.split(/, ?/);
|
|
|
|
if(splitNames.length > 1) {
|
|
|
|
var lastName = splitNames[0];
|
|
|
|
var firstName = splitNames[1];
|
|
|
|
} else {
|
|
|
|
var lastName = author;
|
|
|
|
}
|
closes #78, figure out import/export architecture
closes #100, migrate ingester to Scholar.Translate
closes #88, migrate scrapers away from RDF
closes #9, pull out LC subject heading tags
references #87, add fromArray() and toArray() methods to item objects
API changes:
all translation (import/export/web) now goes through Scholar.Translate
all Scholar-specific functions in scrapers start with "Scholar." rather than the jumbled up piggy bank un-namespaced confusion
scrapers now longer specify items through RDF (the beginning of an item.fromArray()-like function exists in Scholar.Translate.prototype._itemDone())
scrapers can be any combination of import, export, and web (type is the sum of 1/2/4 respectively)
scrapers now contain functions (doImport, doExport, doWeb) rather than loose code
scrapers can call functions in other scrapers or just call the function to translate itself
export accesses items item-by-item, rather than accepting a huge array of items
MARC functions are now in the MARC import translator, and accessed by the web translators
new features:
import now works
rudimentary RDF (unqualified dublin core only), RIS, and MARC import translators are implemented (although they are a little picky with respect to file extensions at the moment)
items appear as they are scraped
MARC import translator pulls out tags, although this seems to slow things down
no icon appears next to a the URL when Scholar hasn't detected metadata, since this seemed somewhat confusing
apologizes for the size of this diff. i figured if i was going to re-write the API, i might as well do it all at once and get everything working right.
2006-07-17 04:06:58 +00:00
|
|
|
} else {
|
2010-10-25 00:58:47 +00:00
|
|
|
var spaceIndex = author.lastIndexOf(" ");
|
|
|
|
var lastName = author.substring(spaceIndex+1);
|
|
|
|
var firstName = author.substring(0, spaceIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(firstName && allCapsRe.test(firstName) &&
|
|
|
|
firstName.length < 4 &&
|
|
|
|
(firstName.length == 1 || lastName.toUpperCase() != lastName)) {
|
|
|
|
// first name is probably initials
|
|
|
|
var newFirstName = "";
|
|
|
|
for(var i=0; i<firstName.length; i++) {
|
|
|
|
newFirstName += " "+firstName[i]+".";
|
|
|
|
}
|
|
|
|
firstName = newFirstName.substr(1);
|
closes #78, figure out import/export architecture
closes #100, migrate ingester to Scholar.Translate
closes #88, migrate scrapers away from RDF
closes #9, pull out LC subject heading tags
references #87, add fromArray() and toArray() methods to item objects
API changes:
all translation (import/export/web) now goes through Scholar.Translate
all Scholar-specific functions in scrapers start with "Scholar." rather than the jumbled up piggy bank un-namespaced confusion
scrapers now longer specify items through RDF (the beginning of an item.fromArray()-like function exists in Scholar.Translate.prototype._itemDone())
scrapers can be any combination of import, export, and web (type is the sum of 1/2/4 respectively)
scrapers now contain functions (doImport, doExport, doWeb) rather than loose code
scrapers can call functions in other scrapers or just call the function to translate itself
export accesses items item-by-item, rather than accepting a huge array of items
MARC functions are now in the MARC import translator, and accessed by the web translators
new features:
import now works
rudimentary RDF (unqualified dublin core only), RIS, and MARC import translators are implemented (although they are a little picky with respect to file extensions at the moment)
items appear as they are scraped
MARC import translator pulls out tags, although this seems to slow things down
no icon appears next to a the URL when Scholar hasn't detected metadata, since this seemed somewhat confusing
apologizes for the size of this diff. i figured if i was going to re-write the API, i might as well do it all at once and get everything working right.
2006-07-17 04:06:58 +00:00
|
|
|
}
|
2010-10-25 00:58:47 +00:00
|
|
|
|
|
|
|
return {firstName:firstName, lastName:lastName, creatorType:type};
|
|
|
|
},
|
2007-10-23 07:11:59 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Removes leading and trailing whitespace from a string
|
|
|
|
* @type String
|
|
|
|
*/
|
|
|
|
"trim":function(/**String*/ s) {
|
|
|
|
if (typeof(s) != "string") {
|
|
|
|
throw "trim: argument must be a string";
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
2010-10-25 00:58:47 +00:00
|
|
|
|
|
|
|
s = s.replace(/^\s+/, "");
|
|
|
|
return s.replace(/\s+$/, "");
|
|
|
|
},
|
2009-06-01 20:13:09 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Cleans whitespace off a string and replaces multiple spaces with one
|
|
|
|
* @type String
|
|
|
|
*/
|
|
|
|
"trimInternal":function(/**String*/ s) {
|
|
|
|
if (typeof(s) != "string") {
|
|
|
|
throw "trimInternal: argument must be a string";
|
|
|
|
}
|
|
|
|
|
|
|
|
s = s.replace(/[\xA0\r\n\s]+/g, " ");
|
|
|
|
return this.trim(s);
|
|
|
|
},
|
2009-06-01 20:13:09 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Cleans any non-word non-parenthesis characters off the ends of a string
|
|
|
|
* @type String
|
|
|
|
*/
|
|
|
|
"superCleanString":function(/**String*/ x) {
|
|
|
|
if(typeof(x) != "string") {
|
|
|
|
throw "superCleanString: argument must be a string";
|
|
|
|
}
|
|
|
|
|
|
|
|
var x = x.replace(/^[\x00-\x27\x29-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/, "");
|
|
|
|
return x.replace(/[\x00-\x28\x2A-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+$/, "");
|
|
|
|
},
|
2009-12-26 03:40:30 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Eliminates HTML tags, replacing <br>s with newlines
|
|
|
|
* @type String
|
|
|
|
*/
|
|
|
|
"cleanTags":function(/**String*/ x) {
|
|
|
|
if(typeof(x) != "string") {
|
|
|
|
throw "cleanTags: argument must be a string";
|
|
|
|
}
|
|
|
|
|
|
|
|
x = x.replace(/<br[^>]*>/gi, "\n");
|
|
|
|
return x.replace(/<[^>]+>/g, "");
|
|
|
|
},
|
2009-12-26 03:40:30 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Strip info:doi prefix and any suffixes from a DOI
|
|
|
|
* @type String
|
|
|
|
*/
|
|
|
|
"cleanDOI":function(/**String**/ x) {
|
|
|
|
if(typeof(x) != "string") {
|
|
|
|
throw "cleanDOI: argument must be a string";
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
2010-10-25 00:58:47 +00:00
|
|
|
|
|
|
|
return x.match(/10\.[^\s\/]+\/[^\s]+/);
|
|
|
|
},
|
2007-10-23 07:11:59 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Convert plain text to HTML by replacing special characters and replacing newlines with BRs or
|
|
|
|
* P tags
|
|
|
|
* @param {String} str Plain text string
|
|
|
|
* @param {Boolean} singleNewlineIsParagraph Whether single newlines should be considered as
|
|
|
|
* paragraphs. If true, each newline is replaced with a P tag. If false, double newlines
|
|
|
|
* are replaced with P tags, while single newlines are replaced with BR tags.
|
|
|
|
* @type String
|
|
|
|
*/
|
|
|
|
"text2html":function (/**String**/ str, /**Boolean**/ singleNewlineIsParagraph) {
|
|
|
|
str = Zotero.Utilities.htmlSpecialChars(str);
|
|
|
|
|
|
|
|
// \n => <p>
|
|
|
|
if (singleNewlineIsParagraph) {
|
|
|
|
str = '<p>'
|
|
|
|
+ str.replace(/\n/g, '</p><p>')
|
2011-03-29 00:40:11 +00:00
|
|
|
.replace(/ /g, ' ')
|
2010-10-25 00:58:47 +00:00
|
|
|
+ '</p>';
|
|
|
|
}
|
|
|
|
// \n\n => <p>, \n => <br/>
|
|
|
|
else {
|
|
|
|
str = Zotero.Utilities.htmlSpecialChars(str);
|
|
|
|
str = '<p>'
|
|
|
|
+ str.replace(/\n\n/g, '</p><p>')
|
|
|
|
.replace(/\n/g, '<br/>')
|
2011-03-29 00:40:11 +00:00
|
|
|
.replace(/ /g, ' ')
|
2010-10-25 00:58:47 +00:00
|
|
|
+ '</p>';
|
|
|
|
}
|
|
|
|
return str.replace(/<p>\s*<\/p>/g, '<p> </p>');
|
|
|
|
},
|
2007-10-23 07:11:59 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Encode special XML/HTML characters<br/>
|
|
|
|
* <br/>
|
|
|
|
* Certain entities can be inserted manually:<br/>
|
|
|
|
* <pre> <ZOTEROBREAK/> => <br/>
|
|
|
|
* <ZOTEROHELLIP/> => &#8230;</pre>
|
|
|
|
* @type String
|
|
|
|
*/
|
|
|
|
"htmlSpecialChars":function(/**String*/ str) {
|
|
|
|
if (typeof str != 'string') {
|
|
|
|
throw "Argument '" + str + "' must be a string in Zotero.Utilities.htmlSpecialChars()";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!str) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
var chars = ['&', '"',"'",'<','>'];
|
|
|
|
var entities = ['amp', 'quot', 'apos', 'lt', 'gt'];
|
|
|
|
|
|
|
|
var newString = str;
|
|
|
|
for (var i = 0; i < chars.length; i++) {
|
|
|
|
var re = new RegExp(chars[i], 'g');
|
|
|
|
newString = newString.replace(re, '&' + entities[i] + ';');
|
|
|
|
}
|
|
|
|
|
|
|
|
newString = newString.replace(/<ZOTERO([^\/]+)\/>/g, function (str, p1, offset, s) {
|
|
|
|
switch (p1) {
|
|
|
|
case 'BREAK':
|
|
|
|
return '<br/>';
|
|
|
|
case 'HELLIP':
|
|
|
|
return '…';
|
|
|
|
default:
|
|
|
|
return p1;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return newString;
|
|
|
|
},
|
2009-10-27 02:31:59 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Decodes HTML entities within a string, returning plain text
|
|
|
|
* @type String
|
|
|
|
*/
|
|
|
|
"unescapeHTML":function(/**String*/ str) {
|
|
|
|
var nsISUHTML = Components.classes["@mozilla.org/feed-unescapehtml;1"]
|
|
|
|
.getService(Components.interfaces.nsIScriptableUnescapeHTML);
|
|
|
|
return nsISUHTML.unescape(str);
|
|
|
|
},
|
2009-10-27 02:31:59 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Wrap URLs and DOIs in <a href=""> links in plain text
|
|
|
|
*
|
|
|
|
* Ignore URLs preceded by '>', just in case there are already links
|
|
|
|
* @type String
|
|
|
|
*/
|
|
|
|
"autoLink":function (/**String**/ str) {
|
|
|
|
// "http://www.google.com."
|
|
|
|
// "http://www.google.com. "
|
|
|
|
// "<http://www.google.com>" (and other characters, with or without a space after)
|
|
|
|
str = str.replace(/([^>])(https?:\/\/[^\s]+)([\."'>:\]\)](\s|$))/g, '$1<a href="$2">$2</a>$3');
|
|
|
|
// "http://www.google.com"
|
|
|
|
// "http://www.google.com "
|
|
|
|
str = str.replace(/([^">])(https?:\/\/[^\s]+)(\s|$)/g, '$1<a href="$2">$2</a>$3');
|
|
|
|
|
|
|
|
// DOI
|
|
|
|
str = str.replace(/(doi:[ ]*)(10\.[^\s]+[0-9a-zA-Z])/g, '$1<a href="http://dx.doi.org/$2">$2</a>');
|
|
|
|
return str;
|
|
|
|
},
|
2007-10-23 07:11:59 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Parses a text string for HTML/XUL markup and returns an array of parts. Currently only finds
|
|
|
|
* HTML links (<a> tags)
|
|
|
|
*
|
|
|
|
* @return {Array} An array of objects with the following form:<br>
|
|
|
|
* <pre> {
|
|
|
|
* type: 'text'|'link',
|
|
|
|
* text: "text content",
|
|
|
|
* [ attributes: { key1: val [ , key2: val, ...] }
|
|
|
|
* }</pre>
|
|
|
|
*/
|
|
|
|
"parseMarkup":function(/**String*/ str) {
|
|
|
|
var parts = [];
|
|
|
|
var splits = str.split(/(<a [^>]+>[^<]*<\/a>)/);
|
|
|
|
|
2010-10-27 02:10:45 +00:00
|
|
|
for(var i=0; i<splits.length; i++) {
|
2010-10-25 00:58:47 +00:00
|
|
|
// Link
|
2010-10-27 02:10:45 +00:00
|
|
|
if (splits[i].indexOf('<a ') == 0) {
|
|
|
|
var matches = splits[i].match(/<a ([^>]+)>([^<]*)<\/a>/);
|
2010-10-25 00:58:47 +00:00
|
|
|
if (matches) {
|
|
|
|
// Attribute pairs
|
|
|
|
var attributes = {};
|
|
|
|
var pairs = matches[1].match(/([^ =]+)="([^"]+")/g);
|
2010-10-27 02:10:45 +00:00
|
|
|
for(var j=0; j<pairs.length; j++) {
|
|
|
|
var keyVal = pairs[j].split(/=/);
|
2010-11-02 21:39:54 +00:00
|
|
|
attributes[keyVal[0]] = keyVal[1].substr(1, keyVal[1].length - 2);
|
2010-10-25 00:58:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
parts.push({
|
|
|
|
type: 'link',
|
|
|
|
text: matches[2],
|
|
|
|
attributes: attributes
|
|
|
|
});
|
|
|
|
continue;
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
}
|
2010-10-25 00:58:47 +00:00
|
|
|
|
|
|
|
parts.push({
|
|
|
|
type: 'text',
|
2010-11-02 21:39:54 +00:00
|
|
|
text: splits[i]
|
2010-10-25 00:58:47 +00:00
|
|
|
});
|
2007-10-23 07:11:59 +00:00
|
|
|
}
|
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
return parts;
|
|
|
|
},
|
2008-06-25 00:19:41 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Calculates the Levenshtein distance between two strings
|
|
|
|
* @type Number
|
|
|
|
*/
|
|
|
|
"levenshtein":function (/**String*/ a, /**String**/ b) {
|
|
|
|
var aLen = a.length;
|
|
|
|
var bLen = b.length;
|
|
|
|
|
|
|
|
var arr = new Array(aLen+1);
|
|
|
|
var i, j, cost;
|
|
|
|
|
|
|
|
for (i = 0; i <= aLen; i++) {
|
|
|
|
arr[i] = new Array(bLen);
|
|
|
|
arr[i][0] = i;
|
2008-06-23 20:33:57 +00:00
|
|
|
}
|
2010-10-25 00:58:47 +00:00
|
|
|
|
|
|
|
for (j = 0; j <= bLen; j++) {
|
|
|
|
arr[0][j] = j;
|
2008-12-27 05:42:52 +00:00
|
|
|
}
|
2010-10-25 00:58:47 +00:00
|
|
|
|
|
|
|
for (i = 1; i <= aLen; i++) {
|
|
|
|
for (j = 1; j <= bLen; j++) {
|
|
|
|
cost = (a[i-1] == b[j-1]) ? 0 : 1;
|
|
|
|
arr[i][j] = Math.min(arr[i-1][j] + 1, Math.min(arr[i][j-1] + 1, arr[i-1][j-1] + cost));
|
|
|
|
}
|
2009-09-22 09:00:09 +00:00
|
|
|
}
|
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
return arr[aLen][bLen];
|
|
|
|
},
|
Zotero File Storage megacommit
- Group file sync via Zotero File Storage
- Split file syncing into separate modules for ZFS and WebDAV
- Dragging items between libraries copies child notes, snapshots/files, and links based on checkboxes for each (enabled by default) in the Zotero preferences
- Sync errors now trigger an exclamation/error icon separate from the sync icon, with a popup window displaying the error and an option to report it
- Various errors that could cause perpetual sync icon spinning now stop the sync properly
- Zotero.Utilities.md5(str) is now md5(strOrFile, base64)
- doPost(), doHead(), and retrieveSource() now takes a headers parameter instead of requestContentType
- doHead() can now accept an nsIURI (with login credentials), is a background request, and isn't cached
- When library access or file writing access is denied during sync, display a warning and then reset local group to server version
- Perform additional steps (e.g., removing local groups) when switching sync users to prevent errors
- Compare hash as well as mod time when checking for modified local files
- Don't trigger notifications when removing groups from the client
- Clear relation links to items in removed groups
- Zotero.Item.attachmentHash property to get file MD5
- importFromFile() now takes libraryID as a third parameter
- Zotero.Attachments.getNumFiles() returns the number of files in the attachment directory
- Zotero.Attachments.copyAttachmentToLibrary() copies an attachment item, including files, to another library
- Removed Zotero.File.getFileHash() in favor of updated Zotero.Utilities.md5()
- Zotero.File.copyDirectory(dir, newDir) copies all files from dir into newDir
- Preferences shuffling: OpenURL to Advanced, import/export character set options to Export, "Include URLs of paper articles in references" to Styles
- Other stuff I don't remember
Suffice it to say, this could use testing.
2009-09-13 07:23:29 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Test if an object is empty
|
|
|
|
*
|
|
|
|
* @param {Object} obj
|
|
|
|
* @type Boolean
|
|
|
|
*/
|
|
|
|
"isEmpty":function (obj) {
|
|
|
|
for (var i in obj) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
2008-11-29 14:13:29 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Compares an array with another and returns an array with
|
|
|
|
* the values from array1 that don't exist in array2
|
|
|
|
*
|
|
|
|
* @param {Array} array1
|
|
|
|
* @param {Array} array2
|
|
|
|
* @param {Boolean} useIndex If true, return an array containing just
|
|
|
|
* the index of array2's elements;
|
|
|
|
* otherwise return the values
|
|
|
|
*/
|
|
|
|
"arrayDiff":function(array1, array2, useIndex) {
|
|
|
|
if (array1.constructor.name != 'Array') {
|
|
|
|
throw ("array1 is not an array in Zotero.Utilities.arrayDiff() (" + array1 + ")");
|
|
|
|
}
|
|
|
|
if (array2.constructor.name != 'Array') {
|
|
|
|
throw ("array2 is not an array in Zotero.Utilities.arrayDiff() (" + array2 + ")");
|
|
|
|
}
|
|
|
|
|
|
|
|
var val, pos, vals = [];
|
|
|
|
for (var i=0; i<array1.length; i++) {
|
|
|
|
val = array1[i];
|
|
|
|
pos = array2.indexOf(val);
|
|
|
|
if (pos == -1) {
|
|
|
|
vals.push(useIndex ? pos : val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return vals;
|
|
|
|
},
|
2008-11-29 14:13:29 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Generate a random integer between min and max inclusive
|
|
|
|
*
|
|
|
|
* @param {Integer} min
|
|
|
|
* @param {Integer} max
|
|
|
|
* @return {Integer}
|
|
|
|
*/
|
|
|
|
"rand":function (min, max) {
|
|
|
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
|
|
},
|
2006-08-06 09:34:51 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Parse a page range
|
|
|
|
*
|
|
|
|
* @param {String} Page range to parse
|
|
|
|
* @return {Integer[]} Start and end pages
|
|
|
|
*/
|
|
|
|
"getPageRange":function(pages) {
|
|
|
|
const pageRangeRegexp = /^\s*([0-9]+) ?[-\u2013] ?([0-9]+)\s*$/
|
|
|
|
|
|
|
|
var pageNumbers;
|
|
|
|
var m = pageRangeRegexp.exec(pages);
|
|
|
|
if(m) {
|
|
|
|
// A page range
|
|
|
|
pageNumbers = [m[1], m[2]];
|
|
|
|
} else {
|
|
|
|
// Assume start and end are the same
|
|
|
|
pageNumbers = [pages, pages];
|
|
|
|
}
|
|
|
|
return pageNumbers;
|
|
|
|
},
|
2007-10-23 07:11:59 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Pads a number or other string with a given string on the left
|
|
|
|
*
|
|
|
|
* @param {String} string String to pad
|
|
|
|
* @param {String} pad String to use as padding
|
|
|
|
* @length {Integer} length Length of new padded string
|
|
|
|
* @type String
|
|
|
|
*/
|
|
|
|
"lpad":function(string, pad, length) {
|
|
|
|
string = string ? string + '' : '';
|
|
|
|
while(string.length < length) {
|
|
|
|
string = pad + string;
|
|
|
|
}
|
|
|
|
return string;
|
|
|
|
},
|
2007-10-23 07:11:59 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Shorten and add an ellipsis to a string if necessary
|
|
|
|
*
|
|
|
|
* @param {String} str
|
|
|
|
* @param {Integer} len
|
|
|
|
* @param {Boolean} [countChars=false]
|
|
|
|
*/
|
|
|
|
"ellipsize":function (str, len, countChars) {
|
|
|
|
if (!len) {
|
|
|
|
throw ("Length not specified in Zotero.Utilities.ellipsize()");
|
|
|
|
}
|
|
|
|
if (str.length > len) {
|
|
|
|
return str.substr(0, len) + '...' + (countChars ? ' (' + str.length + ' chars)' : '');
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Port of PHP's number_format()
|
|
|
|
*
|
|
|
|
* MIT Licensed
|
|
|
|
*
|
|
|
|
* From http://kevin.vanzonneveld.net
|
|
|
|
* + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
|
|
|
|
* + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
|
|
|
* + bugfix by: Michael White (http://getsprink.com)
|
|
|
|
* + bugfix by: Benjamin Lupton
|
|
|
|
* + bugfix by: Allan Jensen (http://www.winternet.no)
|
|
|
|
* + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
|
|
|
|
* + bugfix by: Howard Yeend
|
|
|
|
* * example 1: number_format(1234.5678, 2, '.', '');
|
|
|
|
* * returns 1: 1234.57
|
|
|
|
*/
|
|
|
|
"numberFormat":function (number, decimals, dec_point, thousands_sep) {
|
|
|
|
var n = number, c = isNaN(decimals = Math.abs(decimals)) ? 2 : decimals;
|
|
|
|
var d = dec_point == undefined ? "." : dec_point;
|
|
|
|
var t = thousands_sep == undefined ? "," : thousands_sep, s = n < 0 ? "-" : "";
|
|
|
|
var i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;
|
|
|
|
|
|
|
|
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
|
|
|
|
},
|
2006-09-04 18:16:50 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Cleans a title, converting it to title case and replacing " :" with ":"
|
|
|
|
*
|
|
|
|
* @param {String} string
|
|
|
|
* @param {Boolean} force Forces title case conversion, even if the capitalizeTitles pref is off
|
|
|
|
* @type String
|
|
|
|
*/
|
|
|
|
"capitalizeTitle":function(string, force) {
|
|
|
|
string = this.trimInternal(string);
|
|
|
|
string = string.replace(" : ", ": ", "g");
|
|
|
|
if(Zotero.Prefs.get('capitalizeTitles') || force) {
|
|
|
|
// fix colons
|
|
|
|
string = Zotero.Text.titleCase(string);
|
|
|
|
}
|
|
|
|
return string;
|
|
|
|
},
|
2009-03-19 22:25:00 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/**
|
|
|
|
* Run sets of data through multiple asynchronous callbacks
|
|
|
|
*
|
|
|
|
* Each callback is passed the current set and a callback to call when done
|
|
|
|
*
|
|
|
|
* @param {Object[]} sets Sets of data
|
|
|
|
* @param {Function[]} callbacks
|
|
|
|
* @param {Function} onDone Function to call when done
|
|
|
|
*/
|
|
|
|
"processAsync":function (sets, callbacks, onDone) {
|
|
|
|
var currentSet;
|
|
|
|
var index = 0;
|
|
|
|
|
|
|
|
var nextSet = function () {
|
|
|
|
if (!sets.length) {
|
|
|
|
onDone();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
index = 0;
|
|
|
|
currentSet = sets.shift();
|
|
|
|
callbacks[0](currentSet, nextCallback);
|
|
|
|
};
|
|
|
|
var nextCallback = function () {
|
|
|
|
index++;
|
|
|
|
callbacks[index](currentSet, nextCallback);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Add a final callback to proceed to the next set
|
|
|
|
callbacks[callbacks.length] = function () {
|
|
|
|
nextSet();
|
2009-03-19 22:25:00 +00:00
|
|
|
}
|
|
|
|
nextSet();
|
2010-10-27 02:10:45 +00:00
|
|
|
},
|
|
|
|
|
2010-11-07 03:13:58 +00:00
|
|
|
/**
|
|
|
|
* Performs a deep copy of a JavaScript object
|
|
|
|
* @param {Object} obj
|
|
|
|
* @return {Object}
|
|
|
|
*/
|
|
|
|
"deepCopy":function(obj) {
|
|
|
|
var obj2 = {};
|
|
|
|
for(var i in obj) {
|
|
|
|
if(typeof obj[i] === "object") {
|
|
|
|
obj2[i] = Zotero.Utilities.deepCopy(obj[i]);
|
|
|
|
} else {
|
|
|
|
obj2[i] = obj[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return obj2;
|
|
|
|
},
|
|
|
|
|
2010-10-27 02:10:45 +00:00
|
|
|
/**
|
|
|
|
* Tests if an item type exists
|
|
|
|
*
|
|
|
|
* @param {String} type Item type
|
|
|
|
* @type Boolean
|
|
|
|
*/
|
|
|
|
"itemTypeExists":function(type) {
|
2010-11-05 03:10:56 +00:00
|
|
|
if(Zotero.ItemTypes.getID(type)) {
|
|
|
|
return true;
|
2010-10-27 02:10:45 +00:00
|
|
|
} else {
|
2010-11-05 03:10:56 +00:00
|
|
|
return false;
|
2010-10-27 02:10:45 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find valid creator types for a given item type
|
|
|
|
*
|
|
|
|
* @param {String} type Item type
|
|
|
|
* @return {String[]} Creator types
|
|
|
|
*/
|
|
|
|
"getCreatorsForType":function(type) {
|
2010-11-05 03:10:56 +00:00
|
|
|
var types = Zotero.CreatorTypes.getTypesForItemType(Zotero.ItemTypes.getID(type));
|
|
|
|
var cleanTypes = new Array();
|
|
|
|
for(var i=0; i<types.length; i++) {
|
|
|
|
cleanTypes.push(types[i].name);
|
2010-11-02 21:39:54 +00:00
|
|
|
}
|
2010-11-05 03:10:56 +00:00
|
|
|
return cleanTypes;
|
2010-11-02 21:39:54 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find valid creator types for a given item type
|
|
|
|
*
|
|
|
|
* @param {String} type Item type
|
|
|
|
* @return {String[]} Creator types
|
|
|
|
*/
|
|
|
|
"fieldIsValidForType":function(field, type) {
|
2010-11-05 03:10:56 +00:00
|
|
|
return Zotero.ItemFields.isValidForType(field, Zotero.ItemTypes.getID(type));
|
2010-10-27 02:10:45 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a creator type name, localized to the current locale
|
|
|
|
*
|
|
|
|
* @param {String} type Creator type
|
|
|
|
* @param {String} Localized creator type
|
|
|
|
* @type Boolean
|
|
|
|
*/
|
|
|
|
"getLocalizedCreatorType":function(type) {
|
2010-11-05 03:10:56 +00:00
|
|
|
try {
|
|
|
|
return Zotero.CreatorTypes.getLocalizedString(type);
|
|
|
|
} catch(e) {
|
|
|
|
return false;
|
2010-10-27 02:10:45 +00:00
|
|
|
}
|
2009-03-19 22:25:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
/**
|
|
|
|
* @class All functions accessible from within Zotero.Utilities namespace inside sandboxed
|
|
|
|
* translators
|
|
|
|
*
|
|
|
|
* @constructor
|
|
|
|
* @augments Zotero.Utilities
|
|
|
|
* @borrows Zotero.Date.formatDate as this.formatDate
|
|
|
|
* @borrows Zotero.Date.strToDate as this.strToDate
|
|
|
|
* @borrows Zotero.Date.strToISO as this.strToISO
|
2009-03-24 02:08:08 +00:00
|
|
|
* @borrows Zotero.OpenURL.createContextObject as this.createContextObject
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
* @borrows Zotero.OpenURL.parseContextObject as this.parseContextObject
|
2010-10-25 00:58:47 +00:00
|
|
|
* @borrows Zotero.HTTP.processDocuments as this.processDocuments
|
|
|
|
* @borrows Zotero.HTTP.doPost as this.doPost
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
* @param {Zotero.Translate} translate
|
2006-06-26 16:19:44 +00:00
|
|
|
*/
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
Zotero.Utilities.Translate = function(translate) {
|
2010-11-02 21:39:54 +00:00
|
|
|
this._translate = translate;
|
2006-06-26 16:19:44 +00:00
|
|
|
}
|
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
var tmp = function() {};
|
|
|
|
tmp.prototype = Zotero.Utilities;
|
|
|
|
Zotero.Utilities.Translate.prototype = new tmp();
|
|
|
|
Zotero.Utilities.Translate.prototype.formatDate = Zotero.Date.formatDate;
|
|
|
|
Zotero.Utilities.Translate.prototype.strToDate = Zotero.Date.strToDate;
|
|
|
|
Zotero.Utilities.Translate.prototype.strToISO = Zotero.Date.strToISO;
|
|
|
|
Zotero.Utilities.Translate.prototype.createContextObject = Zotero.OpenURL.createContextObject;
|
|
|
|
Zotero.Utilities.Translate.prototype.parseContextObject = Zotero.OpenURL.parseContextObject;
|
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
/**
|
|
|
|
* Gets the current Zotero version
|
|
|
|
*
|
|
|
|
* @type String
|
|
|
|
*/
|
2010-08-02 02:26:46 +00:00
|
|
|
Zotero.Utilities.Translate.prototype.getVersion = function() {
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
return Zotero.version;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Takes an XPath query and returns the results
|
|
|
|
*
|
|
|
|
* @deprecated Use doc.evaluate() directly instead
|
|
|
|
* @type Node[]
|
|
|
|
*/
|
|
|
|
Zotero.Utilities.Translate.prototype.gatherElementsOnXPath = function(doc, parentNode, xpath, nsResolver) {
|
2006-06-26 16:19:44 +00:00
|
|
|
var elmts = [];
|
|
|
|
|
|
|
|
var iterator = doc.evaluate(xpath, parentNode, nsResolver, Components.interfaces.nsIDOMXPathResult.ANY_TYPE,null);
|
|
|
|
var elmt = iterator.iterateNext();
|
|
|
|
var i = 0;
|
|
|
|
while (elmt) {
|
|
|
|
elmts[i++] = elmt;
|
|
|
|
elmt = iterator.iterateNext();
|
|
|
|
}
|
|
|
|
return elmts;
|
|
|
|
}
|
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
/**
|
2006-06-26 14:46:57 +00:00
|
|
|
* Gets a given node as a string containing all child nodes
|
2007-10-23 07:11:59 +00:00
|
|
|
*
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
* @deprecated Use doc.evaluate and the "nodeValue" or "textContent" property
|
|
|
|
* @type String
|
2006-06-26 14:46:57 +00:00
|
|
|
*/
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
Zotero.Utilities.Translate.prototype.getNodeString = function(doc, contextNode, xpath, nsResolver) {
|
2006-06-26 14:46:57 +00:00
|
|
|
var elmts = this.gatherElementsOnXPath(doc, contextNode, xpath, nsResolver);
|
|
|
|
var returnVar = "";
|
|
|
|
for(var i=0; i<elmts.length; i++) {
|
|
|
|
returnVar += elmts[i].nodeValue;
|
|
|
|
}
|
|
|
|
return returnVar;
|
|
|
|
}
|
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
/**
|
2006-06-26 14:46:57 +00:00
|
|
|
* Grabs items based on URLs
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
*
|
|
|
|
* @param {Document} doc DOM document object
|
|
|
|
* @param {Element|Element[]} inHere DOM element(s) to process
|
|
|
|
* @param {RegExp} [urlRe] Regexp of URLs to add to list
|
|
|
|
* @param {RegExp} [urlRe] Regexp of URLs to reject
|
|
|
|
* @return {Object} Associative array of link => textContent pairs, suitable for passing to
|
|
|
|
* Zotero.selectItems from within a translator
|
2006-06-26 14:46:57 +00:00
|
|
|
*/
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
Zotero.Utilities.Translate.prototype.getItemArray = function(doc, inHere, urlRe, rejectRe) {
|
2006-06-26 14:46:57 +00:00
|
|
|
var availableItems = new Object(); // Technically, associative arrays are objects
|
|
|
|
|
|
|
|
// Require link to match this
|
|
|
|
if(urlRe) {
|
2006-09-08 05:47:47 +00:00
|
|
|
if(urlRe.exec) {
|
|
|
|
var urlRegexp = urlRe;
|
|
|
|
} else {
|
|
|
|
var urlRegexp = new RegExp();
|
|
|
|
urlRegexp.compile(urlRe, "i");
|
|
|
|
}
|
2006-06-26 14:46:57 +00:00
|
|
|
}
|
|
|
|
// Do not allow text to match this
|
|
|
|
if(rejectRe) {
|
2006-09-08 05:47:47 +00:00
|
|
|
if(rejectRe.exec) {
|
|
|
|
var rejectRegexp = rejectRe;
|
|
|
|
} else {
|
|
|
|
var rejectRegexp = new RegExp();
|
|
|
|
rejectRegexp.compile(rejectRe, "i");
|
|
|
|
}
|
2006-06-26 14:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!inHere.length) {
|
|
|
|
inHere = new Array(inHere);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(var j=0; j<inHere.length; j++) {
|
|
|
|
var links = inHere[j].getElementsByTagName("a");
|
|
|
|
for(var i=0; i<links.length; i++) {
|
|
|
|
if(!urlRe || urlRegexp.test(links[i].href)) {
|
2006-09-08 05:47:47 +00:00
|
|
|
var text = links[i].textContent;
|
2006-06-26 14:46:57 +00:00
|
|
|
if(text) {
|
Merged revisions 2190-2192,2194,2196-2199,2202-2205,2209,2212,2214-2215,2227-2228,2230,2232-2243,2245,2247-2256,2263-2272,2276,2278-2279,2281,2284-2286,2292,2296-2297,2299-2302,2304-2305,2309-2310,2314,2317-2323,2325-2329,2331-2337,2339,2341-2342,2344,2347-2366,2370-2371,2373-2377,2379-2391,2393-2402,2405-2410,2413,2415-2416,2418,2420-2421,2423,2427-2429,2431-2433,2437,2440-2441,2443-2450,2453,2455-2459,2461-2467,2471,2475-2480,2482-2490,2493,2495-2499,2501-2506,2511,2513-2519,2521,2525-2536,2540,2543-2553,2555-2559,2561-2576,2578,2580-2603,2606-2609,2611-2616,2618-2620,2624-2630,2632-2633 to trunk via svnmerge from 1.0 branch
2008-05-05 07:19:34 +00:00
|
|
|
text = this.trimInternal(text);
|
2006-06-26 14:46:57 +00:00
|
|
|
if(!rejectRe || !rejectRegexp.test(text)) {
|
|
|
|
if(availableItems[links[i].href]) {
|
|
|
|
if(text != availableItems[links[i].href]) {
|
|
|
|
availableItems[links[i].href] += " "+text;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
availableItems[links[i].href] = text;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return availableItems;
|
|
|
|
}
|
|
|
|
|
2009-03-19 22:25:00 +00:00
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
/**
|
|
|
|
* Load a single document in a hidden browser
|
|
|
|
*
|
|
|
|
* @deprecated Use processDocuments with a single URL
|
|
|
|
* @see Zotero.Utilities.Translate#processDocuments
|
|
|
|
*/
|
|
|
|
Zotero.Utilities.Translate.prototype.loadDocument = function(url, succeeded, failed) {
|
|
|
|
Zotero.debug("Zotero.Utilities.loadDocument is deprecated; please use processDocuments in new code");
|
|
|
|
this.processDocuments([url], succeeded, null, failed);
|
2006-06-26 20:02:30 +00:00
|
|
|
}
|
2006-08-18 05:58:14 +00:00
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
/**
|
2010-10-25 00:58:47 +00:00
|
|
|
* Already documented in Zotero.HTTP
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
* @ignore
|
|
|
|
*/
|
|
|
|
Zotero.Utilities.Translate.prototype.processDocuments = function(urls, processor, done, exception) {
|
2010-11-02 21:39:54 +00:00
|
|
|
if(this._translate.locationIsProxied) {
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
if(typeof(urls) == "string") {
|
|
|
|
urls = [this._convertURL(urls)];
|
|
|
|
} else {
|
|
|
|
for(var i in urls) {
|
|
|
|
urls[i] = this._convertURL(urls[i]);
|
2006-08-18 05:58:14 +00:00
|
|
|
}
|
2006-08-11 15:28:18 +00:00
|
|
|
}
|
2006-06-27 04:08:21 +00:00
|
|
|
}
|
closes #187, make berkeley's library work
closes #186, stop translators from hanging
when a document loads inside a frameset, we now check whether we can scrape each individual frame.
all functions involving tabs have been vastly simplified, because in the process of figuring this out, i discovered Firefox 2's new tab events.
if a translator throws an exception inside loadDocument(), doGet(), doPost(), or processDocuments(), a translate error message will appear, and the translator will not hang
2006-08-15 19:46:42 +00:00
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
// Unless the translator has proposed some way to handle an error, handle it
|
closes #187, make berkeley's library work
closes #186, stop translators from hanging
when a document loads inside a frameset, we now check whether we can scrape each individual frame.
all functions involving tabs have been vastly simplified, because in the process of figuring this out, i discovered Firefox 2's new tab events.
if a translator throws an exception inside loadDocument(), doGet(), doPost(), or processDocuments(), a translate error message will appear, and the translator will not hang
2006-08-15 19:46:42 +00:00
|
|
|
// by throwing a "scraping error" message
|
|
|
|
if(!exception) {
|
2010-11-02 21:39:54 +00:00
|
|
|
var translate = this._translate;
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
var exception = function(e) {
|
2010-11-02 21:39:54 +00:00
|
|
|
translate.complete(false, e);
|
closes #187, make berkeley's library work
closes #186, stop translators from hanging
when a document loads inside a frameset, we now check whether we can scrape each individual frame.
all functions involving tabs have been vastly simplified, because in the process of figuring this out, i discovered Firefox 2's new tab events.
if a translator throws an exception inside loadDocument(), doGet(), doPost(), or processDocuments(), a translate error message will appear, and the translator will not hang
2006-08-15 19:46:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
Zotero.HTTP.processDocuments(urls, processor, done, exception);
|
2006-06-26 20:02:30 +00:00
|
|
|
}
|
|
|
|
|
2009-08-10 07:48:33 +00:00
|
|
|
/**
|
|
|
|
* Gets the DOM document object corresponding to the page located at URL, but avoids locking the
|
|
|
|
* UI while the request is in process.
|
|
|
|
*
|
|
|
|
* @param {String} url URL to load
|
|
|
|
* @return {Document} DOM document object
|
|
|
|
*/
|
|
|
|
Zotero.Utilities.Translate.prototype.retrieveDocument = function(url) {
|
2010-11-02 21:39:54 +00:00
|
|
|
if(this._translate.locationIsProxied) url = this._convertURL(url);
|
2009-08-10 07:48:33 +00:00
|
|
|
|
|
|
|
var mainThread = Zotero.mainThread;
|
|
|
|
var loaded = false;
|
|
|
|
var listener = function() {
|
|
|
|
loaded = hiddenBrowser.contentDocument.location.href != "about:blank";
|
|
|
|
}
|
|
|
|
|
|
|
|
var hiddenBrowser = Zotero.Browser.createHiddenBrowser();
|
|
|
|
hiddenBrowser.addEventListener("pageshow", listener, true);
|
|
|
|
hiddenBrowser.loadURI(url);
|
|
|
|
|
|
|
|
// Use a timeout of 2 minutes. Without a timeout, a request to an IP at which no system is
|
|
|
|
// configured will continue indefinitely, and hang Firefox as it shuts down. No same request
|
|
|
|
// should ever take longer than 2 minutes.
|
|
|
|
var endTime = Date.now() + 120000;
|
|
|
|
while(!loaded && Date.now() < endTime) {
|
|
|
|
mainThread.processNextEvent(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
hiddenBrowser.removeEventListener("pageshow", listener, true);
|
|
|
|
hiddenBrowser.contentWindow.setTimeout(function() {
|
|
|
|
Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
|
|
|
|
}, 1);
|
|
|
|
|
|
|
|
if(!loaded) throw "retrieveDocument failed: request timeout";
|
|
|
|
return hiddenBrowser.contentDocument;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the source of the page located at URL, but avoids locking the UI while the request is in
|
|
|
|
* process.
|
|
|
|
*
|
|
|
|
* @param {String} url URL to load
|
|
|
|
* @param {String} [body=null] Request body to POST to the URL; a GET request is
|
|
|
|
* executed if no body is present
|
Zotero File Storage megacommit
- Group file sync via Zotero File Storage
- Split file syncing into separate modules for ZFS and WebDAV
- Dragging items between libraries copies child notes, snapshots/files, and links based on checkboxes for each (enabled by default) in the Zotero preferences
- Sync errors now trigger an exclamation/error icon separate from the sync icon, with a popup window displaying the error and an option to report it
- Various errors that could cause perpetual sync icon spinning now stop the sync properly
- Zotero.Utilities.md5(str) is now md5(strOrFile, base64)
- doPost(), doHead(), and retrieveSource() now takes a headers parameter instead of requestContentType
- doHead() can now accept an nsIURI (with login credentials), is a background request, and isn't cached
- When library access or file writing access is denied during sync, display a warning and then reset local group to server version
- Perform additional steps (e.g., removing local groups) when switching sync users to prevent errors
- Compare hash as well as mod time when checking for modified local files
- Don't trigger notifications when removing groups from the client
- Clear relation links to items in removed groups
- Zotero.Item.attachmentHash property to get file MD5
- importFromFile() now takes libraryID as a third parameter
- Zotero.Attachments.getNumFiles() returns the number of files in the attachment directory
- Zotero.Attachments.copyAttachmentToLibrary() copies an attachment item, including files, to another library
- Removed Zotero.File.getFileHash() in favor of updated Zotero.Utilities.md5()
- Zotero.File.copyDirectory(dir, newDir) copies all files from dir into newDir
- Preferences shuffling: OpenURL to Advanced, import/export character set options to Export, "Include URLs of paper articles in references" to Styles
- Other stuff I don't remember
Suffice it to say, this could use testing.
2009-09-13 07:23:29 +00:00
|
|
|
* @param {Object} [headers] HTTP headers to include in request;
|
|
|
|
* Content-Type defaults to application/x-www-form-urlencoded
|
|
|
|
* for POST; ignored if no body
|
2009-08-10 07:48:33 +00:00
|
|
|
* @param {String} [responseCharset] Character set to force on the response
|
|
|
|
* @return {String} Request body
|
|
|
|
*/
|
Zotero File Storage megacommit
- Group file sync via Zotero File Storage
- Split file syncing into separate modules for ZFS and WebDAV
- Dragging items between libraries copies child notes, snapshots/files, and links based on checkboxes for each (enabled by default) in the Zotero preferences
- Sync errors now trigger an exclamation/error icon separate from the sync icon, with a popup window displaying the error and an option to report it
- Various errors that could cause perpetual sync icon spinning now stop the sync properly
- Zotero.Utilities.md5(str) is now md5(strOrFile, base64)
- doPost(), doHead(), and retrieveSource() now takes a headers parameter instead of requestContentType
- doHead() can now accept an nsIURI (with login credentials), is a background request, and isn't cached
- When library access or file writing access is denied during sync, display a warning and then reset local group to server version
- Perform additional steps (e.g., removing local groups) when switching sync users to prevent errors
- Compare hash as well as mod time when checking for modified local files
- Don't trigger notifications when removing groups from the client
- Clear relation links to items in removed groups
- Zotero.Item.attachmentHash property to get file MD5
- importFromFile() now takes libraryID as a third parameter
- Zotero.Attachments.getNumFiles() returns the number of files in the attachment directory
- Zotero.Attachments.copyAttachmentToLibrary() copies an attachment item, including files, to another library
- Removed Zotero.File.getFileHash() in favor of updated Zotero.Utilities.md5()
- Zotero.File.copyDirectory(dir, newDir) copies all files from dir into newDir
- Preferences shuffling: OpenURL to Advanced, import/export character set options to Export, "Include URLs of paper articles in references" to Styles
- Other stuff I don't remember
Suffice it to say, this could use testing.
2009-09-13 07:23:29 +00:00
|
|
|
Zotero.Utilities.Translate.prototype.retrieveSource = function(url, body, headers, responseCharset) {
|
2009-08-10 07:48:33 +00:00
|
|
|
/* Apparently, a synchronous XMLHttpRequest would have the behavior of this routine in FF3, but
|
|
|
|
* in FF3.5, synchronous XHR blocks all JavaScript on the thread. See
|
|
|
|
* http://hacks.mozilla.org/2009/07/synchronous-xhr/. */
|
2010-11-02 21:39:54 +00:00
|
|
|
if(this._translate.locationIsProxied) url = this._convertURL(url);
|
Zotero File Storage megacommit
- Group file sync via Zotero File Storage
- Split file syncing into separate modules for ZFS and WebDAV
- Dragging items between libraries copies child notes, snapshots/files, and links based on checkboxes for each (enabled by default) in the Zotero preferences
- Sync errors now trigger an exclamation/error icon separate from the sync icon, with a popup window displaying the error and an option to report it
- Various errors that could cause perpetual sync icon spinning now stop the sync properly
- Zotero.Utilities.md5(str) is now md5(strOrFile, base64)
- doPost(), doHead(), and retrieveSource() now takes a headers parameter instead of requestContentType
- doHead() can now accept an nsIURI (with login credentials), is a background request, and isn't cached
- When library access or file writing access is denied during sync, display a warning and then reset local group to server version
- Perform additional steps (e.g., removing local groups) when switching sync users to prevent errors
- Compare hash as well as mod time when checking for modified local files
- Don't trigger notifications when removing groups from the client
- Clear relation links to items in removed groups
- Zotero.Item.attachmentHash property to get file MD5
- importFromFile() now takes libraryID as a third parameter
- Zotero.Attachments.getNumFiles() returns the number of files in the attachment directory
- Zotero.Attachments.copyAttachmentToLibrary() copies an attachment item, including files, to another library
- Removed Zotero.File.getFileHash() in favor of updated Zotero.Utilities.md5()
- Zotero.File.copyDirectory(dir, newDir) copies all files from dir into newDir
- Preferences shuffling: OpenURL to Advanced, import/export character set options to Export, "Include URLs of paper articles in references" to Styles
- Other stuff I don't remember
Suffice it to say, this could use testing.
2009-09-13 07:23:29 +00:00
|
|
|
if(!headers) headers = null;
|
2009-08-10 07:48:33 +00:00
|
|
|
if(!responseCharset) responseCharset = null;
|
|
|
|
|
|
|
|
var mainThread = Zotero.mainThread;
|
|
|
|
var xmlhttp = false;
|
|
|
|
var listener = function(aXmlhttp) { xmlhttp = aXmlhttp };
|
|
|
|
|
|
|
|
if(body) {
|
2010-10-25 00:58:47 +00:00
|
|
|
Zotero.HTTP.doPost(url, body, listener, headers, responseCharset);
|
2009-08-10 07:48:33 +00:00
|
|
|
} else {
|
2010-10-25 00:58:47 +00:00
|
|
|
Zotero.HTTP.doGet(url, listener, responseCharset);
|
2009-08-10 07:48:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
while(!xmlhttp) mainThread.processNextEvent(true);
|
|
|
|
if(xmlhttp.status >= 400) throw "retrieveSource failed: "+xmlhttp.status+" "+xmlhttp.statusText;
|
|
|
|
|
|
|
|
return xmlhttp.responseText;
|
|
|
|
}
|
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
/**
|
|
|
|
* Send an HTTP GET request via XMLHTTPRequest
|
|
|
|
*
|
|
|
|
* @param {String|String[]} urls URL(s) to request
|
|
|
|
* @param {Function} processor Callback to be executed for each document loaded
|
|
|
|
* @param {Function} done Callback to be executed after all documents have been loaded
|
|
|
|
* @param {String} responseCharset Character set to force on the response
|
|
|
|
* @return {Boolean} True if the request was sent, or false if the browser is offline
|
|
|
|
*/
|
|
|
|
Zotero.Utilities.Translate.prototype.doGet = function(urls, processor, done, responseCharset) {
|
2007-10-23 07:11:59 +00:00
|
|
|
var callAgain = false;
|
|
|
|
|
|
|
|
if(typeof(urls) == "string") {
|
|
|
|
var url = urls;
|
|
|
|
} else {
|
|
|
|
if(urls.length > 1) callAgain = true;
|
|
|
|
var url = urls.shift();
|
|
|
|
}
|
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
url = this._convertURL(url);
|
closes #187, make berkeley's library work
closes #186, stop translators from hanging
when a document loads inside a frameset, we now check whether we can scrape each individual frame.
all functions involving tabs have been vastly simplified, because in the process of figuring this out, i discovered Firefox 2's new tab events.
if a translator throws an exception inside loadDocument(), doGet(), doPost(), or processDocuments(), a translate error message will appear, and the translator will not hang
2006-08-15 19:46:42 +00:00
|
|
|
|
2007-10-23 07:11:59 +00:00
|
|
|
var me = this;
|
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
Zotero.HTTP.doGet(url, function(xmlhttp) {
|
closes #187, make berkeley's library work
closes #186, stop translators from hanging
when a document loads inside a frameset, we now check whether we can scrape each individual frame.
all functions involving tabs have been vastly simplified, because in the process of figuring this out, i discovered Firefox 2's new tab events.
if a translator throws an exception inside loadDocument(), doGet(), doPost(), or processDocuments(), a translate error message will appear, and the translator will not hang
2006-08-15 19:46:42 +00:00
|
|
|
try {
|
2007-10-23 07:11:59 +00:00
|
|
|
if(processor) {
|
|
|
|
processor(xmlhttp.responseText, xmlhttp, url);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(callAgain) {
|
|
|
|
me.doGet(urls, processor, done);
|
|
|
|
} else {
|
|
|
|
if(done) {
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
}
|
closes #187, make berkeley's library work
closes #186, stop translators from hanging
when a document loads inside a frameset, we now check whether we can scrape each individual frame.
all functions involving tabs have been vastly simplified, because in the process of figuring this out, i discovered Firefox 2's new tab events.
if a translator throws an exception inside loadDocument(), doGet(), doPost(), or processDocuments(), a translate error message will appear, and the translator will not hang
2006-08-15 19:46:42 +00:00
|
|
|
} catch(e) {
|
2010-11-02 21:39:54 +00:00
|
|
|
me._translate.complete(false, e);
|
closes #187, make berkeley's library work
closes #186, stop translators from hanging
when a document loads inside a frameset, we now check whether we can scrape each individual frame.
all functions involving tabs have been vastly simplified, because in the process of figuring this out, i discovered Firefox 2's new tab events.
if a translator throws an exception inside loadDocument(), doGet(), doPost(), or processDocuments(), a translate error message will appear, and the translator will not hang
2006-08-15 19:46:42 +00:00
|
|
|
}
|
2010-10-25 00:58:47 +00:00
|
|
|
}, responseCharset);
|
2006-06-26 16:19:44 +00:00
|
|
|
}
|
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
/**
|
2010-10-25 00:58:47 +00:00
|
|
|
* Already documented in Zotero.HTTP
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
* @ignore
|
|
|
|
*/
|
Zotero File Storage megacommit
- Group file sync via Zotero File Storage
- Split file syncing into separate modules for ZFS and WebDAV
- Dragging items between libraries copies child notes, snapshots/files, and links based on checkboxes for each (enabled by default) in the Zotero preferences
- Sync errors now trigger an exclamation/error icon separate from the sync icon, with a popup window displaying the error and an option to report it
- Various errors that could cause perpetual sync icon spinning now stop the sync properly
- Zotero.Utilities.md5(str) is now md5(strOrFile, base64)
- doPost(), doHead(), and retrieveSource() now takes a headers parameter instead of requestContentType
- doHead() can now accept an nsIURI (with login credentials), is a background request, and isn't cached
- When library access or file writing access is denied during sync, display a warning and then reset local group to server version
- Perform additional steps (e.g., removing local groups) when switching sync users to prevent errors
- Compare hash as well as mod time when checking for modified local files
- Don't trigger notifications when removing groups from the client
- Clear relation links to items in removed groups
- Zotero.Item.attachmentHash property to get file MD5
- importFromFile() now takes libraryID as a third parameter
- Zotero.Attachments.getNumFiles() returns the number of files in the attachment directory
- Zotero.Attachments.copyAttachmentToLibrary() copies an attachment item, including files, to another library
- Removed Zotero.File.getFileHash() in favor of updated Zotero.Utilities.md5()
- Zotero.File.copyDirectory(dir, newDir) copies all files from dir into newDir
- Preferences shuffling: OpenURL to Advanced, import/export character set options to Export, "Include URLs of paper articles in references" to Styles
- Other stuff I don't remember
Suffice it to say, this could use testing.
2009-09-13 07:23:29 +00:00
|
|
|
Zotero.Utilities.Translate.prototype.doPost = function(url, body, onDone, headers, responseCharset) {
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
url = this._convertURL(url);
|
closes #187, make berkeley's library work
closes #186, stop translators from hanging
when a document loads inside a frameset, we now check whether we can scrape each individual frame.
all functions involving tabs have been vastly simplified, because in the process of figuring this out, i discovered Firefox 2's new tab events.
if a translator throws an exception inside loadDocument(), doGet(), doPost(), or processDocuments(), a translate error message will appear, and the translator will not hang
2006-08-15 19:46:42 +00:00
|
|
|
|
2010-11-02 21:39:54 +00:00
|
|
|
var translate = this._translate;
|
2010-10-25 00:58:47 +00:00
|
|
|
Zotero.HTTP.doPost(url, body, function(xmlhttp) {
|
closes #187, make berkeley's library work
closes #186, stop translators from hanging
when a document loads inside a frameset, we now check whether we can scrape each individual frame.
all functions involving tabs have been vastly simplified, because in the process of figuring this out, i discovered Firefox 2's new tab events.
if a translator throws an exception inside loadDocument(), doGet(), doPost(), or processDocuments(), a translate error message will appear, and the translator will not hang
2006-08-15 19:46:42 +00:00
|
|
|
try {
|
|
|
|
onDone(xmlhttp.responseText, xmlhttp);
|
|
|
|
} catch(e) {
|
2010-11-02 21:39:54 +00:00
|
|
|
translate.complete(false, e);
|
closes #187, make berkeley's library work
closes #186, stop translators from hanging
when a document loads inside a frameset, we now check whether we can scrape each individual frame.
all functions involving tabs have been vastly simplified, because in the process of figuring this out, i discovered Firefox 2's new tab events.
if a translator throws an exception inside loadDocument(), doGet(), doPost(), or processDocuments(), a translate error message will appear, and the translator will not hang
2006-08-15 19:46:42 +00:00
|
|
|
}
|
2010-10-25 00:58:47 +00:00
|
|
|
}, headers, responseCharset);
|
|
|
|
}
|
|
|
|
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
/**
|
|
|
|
* Translate a URL to a form that goes through the appropriate proxy, or convert a relative URL to
|
|
|
|
* an absolute one
|
|
|
|
*
|
|
|
|
* @param {String} url
|
|
|
|
* @type String
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
Zotero.Utilities.Translate.prototype._convertURL = function(url) {
|
|
|
|
const protocolRe = /^(?:(?:http|https|ftp):)/i;
|
|
|
|
const fileRe = /^[^:]*/;
|
2006-06-26 16:19:44 +00:00
|
|
|
|
2010-11-02 21:39:54 +00:00
|
|
|
if(this._translate.locationIsProxied) {
|
2008-09-01 04:25:40 +00:00
|
|
|
url = Zotero.Proxies.properToProxy(url);
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
}
|
|
|
|
if(protocolRe.test(url)) return url;
|
|
|
|
if(!fileRe.test(url)) {
|
|
|
|
throw "Invalid URL supplied for HTTP request";
|
|
|
|
} else {
|
|
|
|
return Components.classes["@mozilla.org/network/io-service;1"].
|
|
|
|
getService(Components.interfaces.nsIIOService).
|
2010-11-02 21:39:54 +00:00
|
|
|
newURI(this._translate.location, "", null).resolve(url);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-07 04:46:18 +00:00
|
|
|
Zotero.Utilities.Translate.prototype.__exposedProps__ = {"HTTP":"r"};
|
2010-11-02 21:39:54 +00:00
|
|
|
for(var j in Zotero.Utilities.Translate.prototype) {
|
|
|
|
if(typeof Zotero.Utilities.Translate.prototype[j] === "function" && j[0] !== "_" && j != "Translate") {
|
2011-02-02 04:39:42 +00:00
|
|
|
Zotero.Utilities.Translate.prototype.__exposedProps__[j] = "r";
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-02 02:26:46 +00:00
|
|
|
/**
|
2010-10-25 00:58:47 +00:00
|
|
|
* @class Utility functions not made available to translators
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
*/
|
2010-10-25 00:58:47 +00:00
|
|
|
Zotero.Utilities.Internal = {
|
|
|
|
/*
|
|
|
|
* Adapted from http://developer.mozilla.org/en/docs/nsICryptoHash
|
2008-08-31 23:36:01 +00:00
|
|
|
*
|
2010-10-25 00:58:47 +00:00
|
|
|
* @param {String|nsIFile} strOrFile
|
|
|
|
* @param {Boolean} [base64=false] Return as base-64-encoded string rather than hex string
|
|
|
|
* @return {String}
|
2008-08-31 23:36:01 +00:00
|
|
|
*/
|
2010-10-25 00:58:47 +00:00
|
|
|
"md5":function(strOrFile, base64) {
|
|
|
|
if (typeof strOrFile == 'string') {
|
|
|
|
var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
|
|
|
|
createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
|
|
|
|
converter.charset = "UTF-8";
|
|
|
|
var result = {};
|
|
|
|
var data = converter.convertToByteArray(strOrFile, result);
|
|
|
|
var ch = Components.classes["@mozilla.org/security/hash;1"]
|
|
|
|
.createInstance(Components.interfaces.nsICryptoHash);
|
|
|
|
ch.init(ch.MD5);
|
|
|
|
ch.update(data, data.length);
|
|
|
|
}
|
|
|
|
else if (strOrFile instanceof Components.interfaces.nsIFile) {
|
|
|
|
// Otherwise throws (NS_ERROR_NOT_AVAILABLE) [nsICryptoHash.updateFromStream]
|
|
|
|
if (!strOrFile.fileSize) {
|
|
|
|
// MD5 for empty string
|
|
|
|
return "d41d8cd98f00b204e9800998ecf8427e";
|
2008-08-31 23:36:01 +00:00
|
|
|
}
|
2010-10-25 00:58:47 +00:00
|
|
|
|
|
|
|
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
|
|
|
|
.createInstance(Components.interfaces.nsIFileInputStream);
|
|
|
|
// open for reading
|
|
|
|
istream.init(strOrFile, 0x01, 0444, 0);
|
|
|
|
var ch = Components.classes["@mozilla.org/security/hash;1"]
|
|
|
|
.createInstance(Components.interfaces.nsICryptoHash);
|
|
|
|
// we want to use the MD5 algorithm
|
|
|
|
ch.init(ch.MD5);
|
|
|
|
// this tells updateFromStream to read the entire file
|
|
|
|
const PR_UINT32_MAX = 0xffffffff;
|
|
|
|
ch.updateFromStream(istream, PR_UINT32_MAX);
|
2008-08-31 23:36:01 +00:00
|
|
|
}
|
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
// pass false here to get binary data back
|
|
|
|
var hash = ch.finish(base64);
|
2008-08-31 23:36:01 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
if (istream) {
|
|
|
|
istream.close();
|
2008-08-31 23:36:01 +00:00
|
|
|
}
|
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
if (base64) {
|
|
|
|
return hash;
|
2008-09-17 11:27:36 +00:00
|
|
|
}
|
2008-08-31 23:36:01 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
/*
|
|
|
|
// This created 36-character hashes
|
2008-08-31 23:36:01 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
// return the two-digit hexadecimal code for a byte
|
|
|
|
function toHexString(charCode) {
|
|
|
|
return ("0" + charCode.toString(16)).slice(-2);
|
2008-08-31 23:36:01 +00:00
|
|
|
}
|
Merged revisions 3080-3081,3084,3087-3088,3090,3092,3099-3103,3113-3114,3132,3134-3143,3145,3148-3151,3154-3159,3165,3174,3194,3234-3235,3239-3240,3244,3246-3254,3258-3262,3268,3270,3274,3279,3286-3288,3294-3295 from 1.0 branch via svnmerge
2008-09-01 01:54:00 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
// convert the binary hash data to a hex string.
|
|
|
|
return [toHexString(hash.charCodeAt(i)) for (i in hash)].join("");
|
|
|
|
*/
|
Autocomplete for creators in item pane
Differentiates between single and double fields for the search, but there's a problem in the current implementation in that only one field is editable at once, so displaying two-field names in a drop-down is a little problematic. While I could display the full names, comma-delimited, and get the discrete parts (which is what Scholar.Utilities.AutoComplete.getResultComment(), included in this commit, is for--the creatorID for the row would be hidden in the autocomplete drop-down comment field), it's a bit unclear what should happen when a user selects a comma-separated name from the drop-down of one of the fields. One option would be to have a row for the last name (in case that's all they want to complete) and other rows for "last, first" matches, and selecting one of the two-part names would replace whatever's in the opposite name field with the appropriate text (and save it to the DB, I'm afraid, unless I change how the creator fields work), keeping the focus in the current textbox for easy tabbing. Not great, but it might work.
Other ideas?
2006-09-25 06:38:47 +00:00
|
|
|
|
2010-10-25 00:58:47 +00:00
|
|
|
// From http://rcrowley.org/2007/11/15/md5-in-xulrunner-or-firefox-extensions/
|
2010-11-06 19:51:31 +00:00
|
|
|
var ascii = [];
|
|
|
|
var ii = hash.length;
|
2010-10-25 00:58:47 +00:00
|
|
|
for (var i = 0; i < ii; ++i) {
|
|
|
|
var c = hash.charCodeAt(i);
|
|
|
|
var ones = c % 16;
|
|
|
|
var tens = c >> 4;
|
|
|
|
ascii.push(String.fromCharCode(tens + (tens > 9 ? 87 : 48)) + String.fromCharCode(ones + (ones > 9 ? 87 : 48)));
|
Autocomplete for creators in item pane
Differentiates between single and double fields for the search, but there's a problem in the current implementation in that only one field is editable at once, so displaying two-field names in a drop-down is a little problematic. While I could display the full names, comma-delimited, and get the discrete parts (which is what Scholar.Utilities.AutoComplete.getResultComment(), included in this commit, is for--the creatorID for the row would be hidden in the autocomplete drop-down comment field), it's a bit unclear what should happen when a user selects a comma-separated name from the drop-down of one of the fields. One option would be to have a row for the last name (in case that's all they want to complete) and other rows for "last, first" matches, and selecting one of the two-part names would replace whatever's in the opposite name field with the appropriate text (and save it to the DB, I'm afraid, unless I change how the creator fields work), keeping the focus in the current textbox for easy tabbing. Not great, but it might work.
Other ideas?
2006-09-25 06:38:47 +00:00
|
|
|
}
|
2010-10-25 00:58:47 +00:00
|
|
|
return ascii.join('');
|
Autocomplete for creators in item pane
Differentiates between single and double fields for the search, but there's a problem in the current implementation in that only one field is editable at once, so displaying two-field names in a drop-down is a little problematic. While I could display the full names, comma-delimited, and get the discrete parts (which is what Scholar.Utilities.AutoComplete.getResultComment(), included in this commit, is for--the creatorID for the row would be hidden in the autocomplete drop-down comment field), it's a bit unclear what should happen when a user selects a comma-separated name from the drop-down of one of the fields. One option would be to have a row for the last name (in case that's all they want to complete) and other rows for "last, first" matches, and selecting one of the two-part names would replace whatever's in the opposite name field with the appropriate text (and save it to the DB, I'm afraid, unless I change how the creator fields work), keeping the focus in the current textbox for easy tabbing. Not great, but it might work.
Other ideas?
2006-09-25 06:38:47 +00:00
|
|
|
}
|
2008-08-31 23:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Base64 encode / decode
|
|
|
|
* From http://www.webtoolkit.info/
|
|
|
|
*/
|
2010-10-25 00:58:47 +00:00
|
|
|
Zotero.Utilities.Internal.Base64 = {
|
2008-08-31 23:36:01 +00:00
|
|
|
// private property
|
|
|
|
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
|
|
|
|
|
|
|
|
// public method for encoding
|
|
|
|
encode : function (input) {
|
|
|
|
var output = "";
|
|
|
|
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
|
|
|
|
var i = 0;
|
|
|
|
|
|
|
|
input = this._utf8_encode(input);
|
|
|
|
|
|
|
|
while (i < input.length) {
|
|
|
|
|
|
|
|
chr1 = input.charCodeAt(i++);
|
|
|
|
chr2 = input.charCodeAt(i++);
|
|
|
|
chr3 = input.charCodeAt(i++);
|
|
|
|
|
|
|
|
enc1 = chr1 >> 2;
|
|
|
|
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
|
|
|
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
|
|
|
enc4 = chr3 & 63;
|
|
|
|
|
|
|
|
if (isNaN(chr2)) {
|
|
|
|
enc3 = enc4 = 64;
|
|
|
|
} else if (isNaN(chr3)) {
|
|
|
|
enc4 = 64;
|
|
|
|
}
|
|
|
|
|
|
|
|
output = output +
|
|
|
|
this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
|
|
|
|
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return output;
|
|
|
|
},
|
|
|
|
|
|
|
|
// public method for decoding
|
|
|
|
decode : function (input) {
|
|
|
|
var output = "";
|
|
|
|
var chr1, chr2, chr3;
|
|
|
|
var enc1, enc2, enc3, enc4;
|
|
|
|
var i = 0;
|
|
|
|
|
|
|
|
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
|
|
|
|
|
|
|
|
while (i < input.length) {
|
|
|
|
|
|
|
|
enc1 = this._keyStr.indexOf(input.charAt(i++));
|
|
|
|
enc2 = this._keyStr.indexOf(input.charAt(i++));
|
|
|
|
enc3 = this._keyStr.indexOf(input.charAt(i++));
|
|
|
|
enc4 = this._keyStr.indexOf(input.charAt(i++));
|
|
|
|
|
|
|
|
chr1 = (enc1 << 2) | (enc2 >> 4);
|
|
|
|
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
|
|
|
chr3 = ((enc3 & 3) << 6) | enc4;
|
|
|
|
|
|
|
|
output = output + String.fromCharCode(chr1);
|
|
|
|
|
|
|
|
if (enc3 != 64) {
|
|
|
|
output = output + String.fromCharCode(chr2);
|
|
|
|
}
|
|
|
|
if (enc4 != 64) {
|
|
|
|
output = output + String.fromCharCode(chr3);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
output = this._utf8_decode(output);
|
|
|
|
|
|
|
|
return output;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
// private method for UTF-8 encoding
|
|
|
|
_utf8_encode : function (string) {
|
|
|
|
string = string.replace(/\r\n/g,"\n");
|
|
|
|
var utftext = "";
|
|
|
|
|
|
|
|
for (var n = 0; n < string.length; n++) {
|
|
|
|
|
|
|
|
var c = string.charCodeAt(n);
|
|
|
|
|
|
|
|
if (c < 128) {
|
|
|
|
utftext += String.fromCharCode(c);
|
|
|
|
}
|
|
|
|
else if((c > 127) && (c < 2048)) {
|
|
|
|
utftext += String.fromCharCode((c >> 6) | 192);
|
|
|
|
utftext += String.fromCharCode((c & 63) | 128);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
utftext += String.fromCharCode((c >> 12) | 224);
|
|
|
|
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
|
|
|
utftext += String.fromCharCode((c & 63) | 128);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return utftext;
|
|
|
|
},
|
|
|
|
|
|
|
|
// private method for UTF-8 decoding
|
|
|
|
_utf8_decode : function (utftext) {
|
|
|
|
var string = "";
|
|
|
|
var i = 0;
|
|
|
|
var c = c1 = c2 = 0;
|
|
|
|
|
|
|
|
while ( i < utftext.length ) {
|
|
|
|
|
|
|
|
c = utftext.charCodeAt(i);
|
|
|
|
|
|
|
|
if (c < 128) {
|
|
|
|
string += String.fromCharCode(c);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
else if((c > 191) && (c < 224)) {
|
|
|
|
c2 = utftext.charCodeAt(i+1);
|
|
|
|
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
|
|
|
|
i += 2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
c2 = utftext.charCodeAt(i+1);
|
|
|
|
c3 = utftext.charCodeAt(i+2);
|
|
|
|
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
|
|
|
|
i += 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
}
|