diff --git a/chrome/content/zotero/browser.js b/chrome/content/zotero/browser.js
index 604557f972..e774bc6f3c 100644
--- a/chrome/content/zotero/browser.js
+++ b/chrome/content/zotero/browser.js
@@ -372,11 +372,15 @@ var Zotero_Browser = new function() {
*/
function finishScraping(obj, returnValue, collection) {
if(!returnValue) {
- Zotero_Browser.Progress.changeHeadline(Zotero.getString("ingester.scrapeError"));
- Zotero_Browser.Progress.addDescription(Zotero.getString("ingester.scrapeErrorDescription"));
+ Zotero_Browser.progress.changeHeadline(Zotero.getString("ingester.scrapeError"));
+ // Include link to Known Translator Issues page
+ var url = "http://www.zotero.org/documentation/known_translator_issues";
+ var linkText = ''
+ + Zotero.getString('ingester.scrapeErrorDescription.linkText') + '';
+ Zotero_Browser.progress.addDescription(Zotero.getString("ingester.scrapeErrorDescription", linkText));
}
- Zotero_Browser.Progress.fade();
+ Zotero_Browser.progress.fade();
}
@@ -386,7 +390,8 @@ var Zotero_Browser = new function() {
function itemDone(obj, item, collection) {
var title = item.getField("title");
var icon = item.getImageSrc();
- Zotero_Browser.Progress.addLines([title], [icon]);
+ Zotero_Browser.progress.changeHeadline(Zotero.getString("ingester.scraping"));
+ Zotero_Browser.progress.addLines([title], [icon]);
// add item to collection, if one was specified
if(collection) {
@@ -547,7 +552,7 @@ Zotero_Browser.Tab.prototype._searchFrames = function(rootDoc, searchDoc) {
*/
Zotero_Browser.Tab.prototype.translate = function(saveLocation) {
if(this.page.translators && this.page.translators.length) {
- Zotero_Browser.Progress.show();
+ Zotero_Browser.progress.show();
if(saveLocation) {
saveLocation = Zotero.Collections.get(saveLocation);
@@ -602,7 +607,7 @@ Zotero_Browser.Tab.prototype._selectItems = function(obj, itemList) {
"_blank","chrome,modal,centerscreen,resizable=yes", io);
if(!io.dataOut) { // user selected no items, so kill the progress indicatior
- Zotero_Browser.Progress.kill();
+ Zotero_Browser.progress.kill();
}
return io.dataOut;
@@ -621,143 +626,7 @@ Zotero_Browser.Tab.prototype._translatorsAvailable = function(translate, transla
Zotero_Browser.updateStatus();
}
-//////////////////////////////////////////////////////////////////////////////
-//
-// Zotero_Browser.Progress
-//
-//////////////////////////////////////////////////////////////////////////////
-
// Handles the display of a div showing progress in scraping
-Zotero_Browser.Progress = new function() {
- var _progressWindow;
-
- var _windowLoaded = false;
- var _windowLoading = false;
- // keep track of all of these things in case they're called before we're
- // done loading the progress window
- var _loadDescription = null;
- var _loadLines = new Array();
- var _loadIcons = new Array();
- var _loadHeadline = Zotero.getString("ingester.scraping");
-
- this.show = show;
- this.changeHeadline = changeHeadline;
- this.addLines = addLines;
- this.addDescription = addDescription;
- this.fade = fade;
- this.kill = kill;
-
- function show() {
- if(_windowLoading || _windowLoaded) { // already loading or loaded
- return false;
- }
- _progressWindow = window.openDialog("chrome://zotero/chrome/ingester/progress.xul",
- "", "chrome,dialog=no,titlebar=no,popup=yes");
- _progressWindow.addEventListener("load", _onWindowLoaded, false);
- _windowLoading = true;
-
- return true;
- }
-
- function changeHeadline(headline) {
- if(_windowLoaded) {
- _progressWindow.document.getElementById("zotero-progress-text-headline").value = headline;
- } else {
- _loadHeadline = headline;
- }
- }
-
- function addLines(label, icon) {
- if(_windowLoaded) {
- for(i in label) {
- var newLabel = _progressWindow.document.createElement("label");
- newLabel.setAttribute("class", "zotero-progress-item-label");
- newLabel.setAttribute("crop", "end");
- newLabel.setAttribute("value", label[i]);
-
- var newImage = _progressWindow.document.createElement("image");
- newImage.setAttribute("class", "zotero-progress-item-icon");
- newImage.setAttribute("src", icon[i]);
-
- var newHB = _progressWindow.document.createElement("hbox");
- newHB.setAttribute("class", "zotero-progress-item-hbox");
- newHB.setAttribute("valign", "center");
- newHB.appendChild(newImage);
- newHB.appendChild(newLabel);
-
- _progressWindow.document.getElementById("zotero-progress-text-box").appendChild(newHB);
- }
-
- _move();
- } else {
- _loadLines = _loadLines.concat(label);
- _loadIcons = _loadIcons.concat(icon);
- }
- }
-
- function addDescription(text) {
- if(_windowLoaded) {
- var newHB = _progressWindow.document.createElement("hbox");
- newHB.setAttribute("class", "zotero-progress-item-hbox");
- var newDescription = _progressWindow.document.createElement("description");
- newDescription.setAttribute("class", "zotero-progress-description");
- var newText = _progressWindow.document.createTextNode(text);
-
- newDescription.appendChild(newText);
- newHB.appendChild(newDescription);
- _progressWindow.document.getElementById("zotero-progress-text-box").appendChild(newHB);
-
- _move();
- } else {
- _loadDescription = text;
- }
- }
-
- function fade() {
- if(_windowLoaded || _windowLoading) {
- setTimeout(_timeout, 2500);
- }
- }
-
- function kill() {
- _windowLoaded = false;
- _windowLoading = false;
- try {
- _progressWindow.close();
- } catch(ex) {}
- }
-
- function _onWindowLoaded() {
- _windowLoading = false;
- _windowLoaded = true;
-
- _move();
- // do things we delayed because the window was loading
- changeHeadline(_loadHeadline);
- addLines(_loadLines, _loadIcons);
- if(_loadDescription) {
- addDescription(_loadDescription);
- }
-
- // reset parameters
- _loadDescription = null;
- _loadLines = new Array();
- _loadIcons = new Array();
- _loadHeadline = Zotero.getString("ingester.scraping")
- }
-
- function _move() {
- _progressWindow.sizeToContent();
- _progressWindow.moveTo(
- window.screenX + window.innerWidth - _progressWindow.outerWidth - 30,
- window.screenY + window.innerHeight - _progressWindow.outerHeight - 10
- );
- }
-
- function _timeout() {
- kill(); // could check to see if we're really supposed to fade yet
- // (in case multiple scrapers are operating at once)
- }
-}
+Zotero_Browser.progress = new Zotero.ProgressWindow();
Zotero_Browser.init();
\ No newline at end of file
diff --git a/chrome/content/zotero/overlay.js b/chrome/content/zotero/overlay.js
index a9eeb4536f..ea43cfca66 100644
--- a/chrome/content/zotero/overlay.js
+++ b/chrome/content/zotero/overlay.js
@@ -962,7 +962,9 @@ var ZoteroPane = new function()
}
function getSelectedCollection(asID) {
- if (this.collectionsView.selection.count > 0 && this.collectionsView.selection.currentIndex != -1) {
+ if (this.collectionsView.selection
+ && this.collectionsView.selection.count > 0
+ && this.collectionsView.selection.currentIndex != -1) {
var collection = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex);
if (collection && collection.isCollection()) {
if (asID) {
diff --git a/chrome/content/zotero/overlay.xul b/chrome/content/zotero/overlay.xul
index ba271ef37a..e0146e3fc0 100644
--- a/chrome/content/zotero/overlay.xul
+++ b/chrome/content/zotero/overlay.xul
@@ -26,7 +26,7 @@
-
+
@@ -367,6 +367,8 @@
}, false);
document.getElementById('appcontent').addEventListener('keydown', ZoteroPane.handleKeyDown, true);
+ // Make sure open progress windows are fading
+ document.getElementById('appcontent').addEventListener('mousemove', Zotero.ProgressWindowSet.updateTimers, false);
]]>
diff --git a/chrome/content/zotero/progressWindow.xul b/chrome/content/zotero/progressWindow.xul
index 341d27d8d9..26a1b69562 100755
--- a/chrome/content/zotero/progressWindow.xul
+++ b/chrome/content/zotero/progressWindow.xul
@@ -5,13 +5,11 @@
-
+ windowtype="alert:alert">
+
-
diff --git a/chrome/content/zotero/xpcom/progressWindow.js b/chrome/content/zotero/xpcom/progressWindow.js
index 2adee453b3..b561c33b83 100644
--- a/chrome/content/zotero/xpcom/progressWindow.js
+++ b/chrome/content/zotero/xpcom/progressWindow.js
@@ -25,49 +25,79 @@ Zotero.ProgressWindowSet = new function() {
this.add = add;
this.tile = tile;
this.remove = remove;
+ this.updateTimers = updateTimers;
- var _numWindows = 0;
var _progressWindows = [];
- const X_OFFSET = 30;
- const Y_OFFSET = 10;
+ const X_OFFSET = 25;
+ const Y_OFFSET = 35;
+ const Y_SEPARATOR = 12;
+ const X_WINDOWLESS_OFFSET = 50;
+ const Y_WINDOWLESS_OFFSET = 100;
- function add(progressWin) {
- _progressWindows.push(progressWin);
- _numWindows++;
+ function add(progressWindow, instance) {
+ _progressWindows.push({
+ progressWindow: progressWindow,
+ instance: instance
+ });
}
function tile(progressWin) {
var parent = progressWin.opener;
- var sum = 0;
+ var y_sub = null;
for (var i=0; i<_progressWindows.length; i++) {
- var p = _progressWindows[i];
+ var p = _progressWindows[i].progressWindow;
// Skip progress windows from other windows
if (p.opener != parent) {
continue;
}
- sum += Y_OFFSET + p.outerHeight;
+ if (!y_sub) {
+ y_sub = Y_OFFSET + p.outerHeight;
+ }
- p.moveTo(
- parent.screenX + parent.innerWidth - p.outerWidth - X_OFFSET,
- parent.screenY + parent.innerHeight - sum
- );
+ if (parent) {
+ var right = parent.screenX + parent.outerWidth;
+ var bottom = parent.screenY + parent.outerHeight;
+ // On OS X outerHeight doesn't include 22px title bar and
+ // moveTo() positions popups 22px below the specified location
+ if (Zotero.isMac) {
+ bottom += (22 * 2);
+ }
+ }
+ else {
+ var right = progressWin.screen.width + X_OFFSET - X_WINDOWLESS_OFFSET;
+ var bottom = progressWin.screen.height + Y_OFFSET - Y_WINDOWLESS_OFFSET;
+ }
+
+ p.moveTo(right - p.outerWidth - X_OFFSET, bottom - y_sub);
+
+ y_sub += p.outerHeight + Y_SEPARATOR;
}
}
function remove(progressWin) {
- _numWindows--;
for (var i=0; i<_progressWindows.length; i++) {
- if (_progressWindows[i] == progressWin) {
+ if (_progressWindows[i].progressWindow == progressWin) {
_progressWindows.splice(i, 1);
}
}
}
+
+
+ function updateTimers() {
+ if (!_progressWindows.length) {
+ return;
+ }
+
+ for (var i=0; i<_progressWindows.length; i++) {
+ _progressWindows[i].instance.fade();
+ }
+ }
}
@@ -77,23 +107,6 @@ Zotero.ProgressWindowSet = new function() {
* Pass the active window into the constructor
*/
Zotero.ProgressWindow = function(_window){
- if (!_window){
- var _window =
- Components.classes["@mozilla.org/embedcomp/window-watcher;1"].
- getService(Components.interfaces.nsIWindowWatcher).
- activeWindow;
- }
-
- var _progressWindow = null;
- var _windowLoaded = false;
- var _windowLoading = false;
- // keep track of all of these things in case they're called before we're
- // done loading the progress window
- var _loadDescription = null;
- var _loadLines = new Array();
- var _loadIcons = new Array();
- var _loadHeadline = '';
-
this.show = show;
this.changeHeadline = changeHeadline;
this.addLines = addLines;
@@ -101,18 +114,49 @@ Zotero.ProgressWindow = function(_window){
this.fade = fade;
this.kill = kill;
+ var _window = null;
+
+ var _progressWindow = null;
+ var _windowLoaded = false;
+ var _windowLoading = false;
+ var _timeoutID = false;
+
+ // keep track of all of these things in case they're called before we're
+ // done loading the progress window
+ var _loadHeadline = '';
+ var _loadLines = [];
+ var _loadIcons = [];
+ var _loadDescription = null;
+
function show() {
if(_windowLoading || _windowLoaded) { // already loading or loaded
return false;
}
- _progressWindow = _window.openDialog("chrome://zotero/chrome/progressWindow.xul",
- "", "chrome,dialog=no,titlebar=no,popup=yes");
+ var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"].
+ getService(Components.interfaces.nsIWindowWatcher);
+
+ if (!_window){
+ _window = ww.activeWindow;
+ }
+
+ if (_window) {
+ _progressWindow = _window.openDialog("chrome://zotero/chrome/progressWindow.xul",
+ "", "chrome,dialog=no,titlebar=no,popup=yes");
+ }
+ else {
+ _progressWindow = ww.openWindow(null, "chrome://zotero/chrome/progressWindow.xul",
+ "", "chrome,dialog=no,titlebar=no,popup=yes", null);
+ }
_progressWindow.addEventListener("pageshow", _onWindowLoaded, false);
+ _progressWindow.addEventListener("mouseover", _onMouseOver, false);
+ _progressWindow.addEventListener("mouseout", _onMouseOut, false);
+ _progressWindow.addEventListener("mouseup", _onMouseUp, false);
+
_windowLoading = true;
- Zotero.ProgressWindowSet.add(_progressWindow);
+ Zotero.ProgressWindowSet.add(_progressWindow, this);
return true;
}
@@ -127,7 +171,7 @@ Zotero.ProgressWindow = function(_window){
function addLines(label, icon) {
if(_windowLoaded) {
- for(i in label) {
+ for (var i in label) {
var newLabel = _progressWindow.document.createElement("label");
newLabel.setAttribute("class", "zotero-progress-item-label");
newLabel.setAttribute("crop", "end");
@@ -153,15 +197,42 @@ Zotero.ProgressWindow = function(_window){
}
}
+
+ /*
+ * Add a description to the progress window
+ *
+ * elements are turned into XUL links
+ */
function addDescription(text) {
if(_windowLoaded) {
var newHB = _progressWindow.document.createElement("hbox");
newHB.setAttribute("class", "zotero-progress-item-hbox");
var newDescription = _progressWindow.document.createElement("description");
- newDescription.setAttribute("class", "zotero-progress-description");
- var newText = _progressWindow.document.createTextNode(text);
- newDescription.appendChild(newText);
+ var utils = new Zotero.Utilities();
+ var parts = utils.parseMarkup(text);
+ for each(var part in parts) {
+ if (part.type == 'text') {
+ var elem = _progressWindow.document.createTextNode(part.text);
+ }
+ else if (part.type == 'link') {
+ var elem = _progressWindow.document.createElement('label');
+ elem.setAttribute('value', part.text);
+ elem.setAttribute('class', 'text-link');
+ for (var i in part.attributes) {
+ elem.setAttribute(i, part.attributes[i]);
+
+ if (i == 'href') {
+ // DEBUG: As of Fx2, 'mouseup' seems to be the only
+ // way to detect a click in a popup window
+ elem.addEventListener('mouseup', _handleLinkClick, false);
+ }
+ }
+ }
+
+ newDescription.appendChild(elem);
+ }
+
newHB.appendChild(newDescription);
_progressWindow.document.getElementById("zotero-progress-text-box").appendChild(newHB);
@@ -171,13 +242,19 @@ Zotero.ProgressWindow = function(_window){
}
}
+
function fade() {
- if(_windowLoaded || _windowLoading) {
- _window.setTimeout(_timeout, 2500);
+ if (_windowLoaded || _windowLoading) {
+ if (_timeoutID) {
+ return;
+ }
+
+ _timeoutID = _progressWindow.setTimeout(_timeout, 2500);
}
}
function kill() {
+ _disableTimeout();
_windowLoaded = false;
_windowLoading = false;
Zotero.ProgressWindowSet.remove(_progressWindow);
@@ -194,15 +271,15 @@ Zotero.ProgressWindow = function(_window){
// do things we delayed because the window was loading
changeHeadline(_loadHeadline);
addLines(_loadLines, _loadIcons);
- if(_loadDescription) {
+ if (_loadDescription) {
addDescription(_loadDescription);
}
// reset parameters
- _loadDescription = null;
- _loadLines = new Array();
- _loadIcons = new Array();
_loadHeadline = '';
+ _loadLines = [];
+ _loadIcons = [];
+ _loadDescription = null;
}
function _move() {
@@ -213,5 +290,54 @@ Zotero.ProgressWindow = function(_window){
function _timeout() {
kill(); // could check to see if we're really supposed to fade yet
// (in case multiple scrapers are operating at once)
+ _timeoutID = false;
+ }
+
+ function _disableTimeout() {
+ _progressWindow.clearTimeout(_timeoutID);
+ _timeoutID = false;
+ }
+
+
+ /*
+ * Disable the fade timer when the mouse is over the window
+ */
+ function _onMouseOver(e) {
+ _disableTimeout();
+ }
+
+
+ /*
+ * Start the fade timer when the mouse leaves the window
+ *
+ * Note that this onmouseout doesn't work correctly on popups in Fx2,
+ * so 1) we have to calculate the window borders manually to avoid fading
+ * when the mouse is still over the box, and 2) this only does anything
+ * when the mouse is moved off of the browser window -- otherwise the fade
+ * is triggered by onmousemove on appcontent in overlay.xul.
+ */
+ function _onMouseOut(e) {
+ // |this| refers to progressWindow's XUL window
+ var top = this.screenY + (Zotero.isMac ? 22 : 0);
+ if ((e.screenX >= this.screenX && e.screenX <= (this.screenX + this.outerWidth))
+ && (e.screenY >= top) && e.screenY <= (top + this.outerHeight)) {
+ return;
+ }
+
+ fade();
+ }
+
+
+ function _onMouseUp(e) {
+ kill();
+ }
+
+
+ /*
+ * Open URL specified in target's href attribute in a new window
+ */
+ function _handleLinkClick(event) {
+ _progressWindow.open(event.target.getAttribute('href'), 'zotero-loaded-page',
+ 'menubar=yes,location=yes,toolbar=yes,personalbar=yes,resizable=yes,scrollbars=yes,status=yes');
}
}
diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js
index c9f63cc278..fcefa7d9bb 100644
--- a/chrome/content/zotero/xpcom/utilities.js
+++ b/chrome/content/zotero/xpcom/utilities.js
@@ -152,6 +152,54 @@ Zotero.Utilities.prototype.htmlSpecialChars = function(str) {
}
+/*
+ * Parses a text string for HTML/XUL markup and returns an array of parts
+ *
+ * Currently only finds HTML links ( tags)
+ *
+ * Returns an array of objects with the following form:
+ * {
+ * type: 'text'|'link',
+ * text: "text content",
+ * [ attributes: { key1: val [ , key2: val, ...] }
+ * }
+ */
+Zotero.Utilities.prototype.parseMarkup = function(str) {
+ var parts = [];
+ var splits = str.split(/(]+>[^<]*<\/a>)/);
+
+ for each(var split in splits) {
+ // Link
+ if (split.indexOf(']+)>([^<]*)<\/a>/);
+ if (matches) {
+ // Attribute pairs
+ var attributes = {};
+ var pairs = matches[1].match(/([^ =]+)="([^"]+")/g);
+ for each (var pair in pairs) {
+ var [key, val] = pair.split(/=/);
+ attributes[key] = val.substr(1, val.length - 2);
+ }
+
+ parts.push({
+ type: 'link',
+ text: matches[2],
+ attributes: attributes
+ });
+ continue;
+ }
+ }
+
+ parts.push({
+ type: 'text',
+ text: split
+ });
+ }
+
+ return parts;
+}
+
+
/*
* Test if a string is an integer
*/