diff --git a/chrome.manifest b/chrome.manifest
index f8b8f8493f..8fb8da2b74 100644
--- a/chrome.manifest
+++ b/chrome.manifest
@@ -21,6 +21,7 @@ locale zotero gl-ES chrome/locale/gl-ES/zotero/
locale zotero he-IL chrome/locale/he-IL/zotero/
locale zotero hr-HR chrome/locale/hr-HR/zotero/
locale zotero hu-HU chrome/locale/hu-HU/zotero/
+locale zotero id-ID chrome/locale/id-ID/zotero/
locale zotero is-IS chrome/locale/is-IS/zotero/
locale zotero it-IT chrome/locale/it-IT/zotero/
locale zotero ja-JP chrome/locale/ja-JP/zotero/
diff --git a/chrome/content/zotero/fileInterface.js b/chrome/content/zotero/fileInterface.js
index 4367a36351..06a48b7c3c 100644
--- a/chrome/content/zotero/fileInterface.js
+++ b/chrome/content/zotero/fileInterface.js
@@ -241,30 +241,11 @@ var Zotero_File_Interface = new function() {
* Imports from clipboard
*/
this.importFromClipboard = function () {
- var clip = Components.classes["@mozilla.org/widget/clipboard;1"]
- .getService(Components.interfaces.nsIClipboard);
- if (!clip.hasDataMatchingFlavors(["text/unicode"], 1, clip.kGlobalClipboard)) {
+ var str = Zotero.Utilities.Internal.getClipboard("text/unicode");
+ if(!str) {
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
ps.alert(null, "", Zotero.getString('fileInterface.importClipboardNoDataError'));
- return;
- }
- var trans = Components.classes["@mozilla.org/widget/transferable;1"]
- .createInstance(Components.interfaces.nsITransferable);
- trans.addDataFlavor("text/unicode");
- clip.getData(trans, clip.kGlobalClipboard);
- var str = {};
- try {
- trans.getTransferData("text/unicode", str, {});
- str = str.value.QueryInterface(Components.interfaces.nsISupportsString).data;
- }
- catch (e) {
- Zotero.debug(e);
- return;
- }
- if (!str) {
- Zotero.debug("No clipboard text to import");
- return;
}
var translate = new Zotero.Translate.Import();
diff --git a/chrome/content/zotero/integration/quickFormat.js b/chrome/content/zotero/integration/quickFormat.js
index 1371cacc34..f3c0962a1c 100644
--- a/chrome/content/zotero/integration/quickFormat.js
+++ b/chrome/content/zotero/integration/quickFormat.js
@@ -22,6 +22,7 @@
***** END LICENSE BLOCK *****
*/
+Components.utils.import("resource://gre/modules/Services.jsm");
var Zotero_QuickFormat = new function () {
const pixelRe = /^([0-9]+)px$/
@@ -36,10 +37,8 @@ var Zotero_QuickFormat = new function () {
keepSorted, showEditor, referencePanel, referenceBox, referenceHeight = 0,
separatorHeight = 0, currentLocator, currentLocatorLabel, currentSearchTime, dragging,
panel, panelPrefix, panelSuffix, panelSuppressAuthor, panelLocatorLabel, panelLocator,
- panelLibraryLink, panelInfo, panelRefersToBubble, panelFrameHeight = 0, accepted = false;
-
- // A variable that contains the timeout object for the latest onKeyPress event
- var eventTimeout = null;
+ panelLibraryLink, panelInfo, panelRefersToBubble, panelFrameHeight = 0, accepted = false,
+ searchTimeout;
const SHOWN_REFERENCES = 7;
@@ -119,6 +118,8 @@ var Zotero_QuickFormat = new function () {
qfiDocument = qfi.contentDocument;
qfb.addEventListener("keypress", _onQuickSearchKeyPress, false);
qfe = qfiDocument.getElementById("quick-format-editor");
+ qfe.addEventListener("drop", _onBubbleDrop, false);
+ qfe.addEventListener("paste", _onPaste, false);
}
}
@@ -179,11 +180,17 @@ var Zotero_QuickFormat = new function () {
var range = selection.getRangeAt(0);
var node = range.startContainer;
- if(node !== range.endContainer || node.nodeType !== Node.TEXT_NODE ) {
- return false;
+ if(node !== range.endContainer) return false;
+ if(node.nodeType === Node.TEXT_NODE) return node;
+
+ // Range could be referenced to the body element
+ if(node === qfe) {
+ var offset = range.startOffset;
+ if(offset !== range.endOffset) return false;
+ node = qfe.childNodes[Math.min(qfe.childNodes.length-1, offset)];
+ if(node.nodeType === Node.TEXT_NODE) return node;
}
-
- return node;
+ return false;
}
/**
@@ -192,7 +199,7 @@ var Zotero_QuickFormat = new function () {
*/
function _getEditorContent(clear) {
var node = _getCurrentEditorTextNode();
- return node ? node.textContent : false;
+ return node ? node.wholeText : false;
}
/**
@@ -641,14 +648,18 @@ var Zotero_QuickFormat = new function () {
// It's entirely unintuitive why, but after trying a bunch of things, it looks like using
// a XUL label for these things works best. A regular span causes issues with moving the
// cursor.
- var bubble = qfiDocument.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "label");
+ var bubble = qfiDocument.createElement("span");
bubble.setAttribute("class", "quick-format-bubble");
- bubble.setAttribute("value", str);
+ bubble.setAttribute("draggable", "true");
+ bubble.textContent = str;
bubble.addEventListener("click", _onBubbleClick, false);
bubble.addEventListener("dragstart", _onBubbleDrag, false);
- bubble.addEventListener("dragend", _onBubbleDrop, false);
bubble.citationItem = citationItem;
- qfe.insertBefore(bubble, (nextNode ? nextNode : null));
+ if(nextNode && nextNode instanceof Range) {
+ nextNode.insertNode(bubble);
+ } else {
+ qfe.insertBefore(bubble, (nextNode ? nextNode : null));
+ }
// make sure that there are no rogue
s
var elements = qfe.getElementsByTagName("br");
@@ -725,12 +736,10 @@ var Zotero_QuickFormat = new function () {
}
}
- var qfeHeight = qfe.scrollHeight;
-
- if(qfeHeight > 30) {
+ if(qfe.scrollHeight > 30) {
qfe.setAttribute("multiline", true);
qfs.setAttribute("multiline", true);
- qfs.style.height = (4+qfeHeight)+"px";
+ qfs.style.height = (4+qfe.scrollHeight)+"px";
window.sizeToContent();
} else {
delete qfs.style.height;
@@ -971,6 +980,50 @@ var Zotero_QuickFormat = new function () {
io.accept();
}
}
+
+ /**
+ * Get bubbles within the current selection
+ */
+ function _getSelectedBubble(right) {
+ var selection = qfiWindow.getSelection(),
+ range = selection.getRangeAt(0);
+ qfe.normalize();
+
+ // Check whether the bubble is selected
+ // Not sure whether this ever happens anymore
+ var container = range.startContainer;
+ if(container !== qfe) {
+ if(container.citationItem) {
+ return container;
+ } else if(container.nodeType === Node.TEXT_NODE && container.wholeText == "") {
+ if(container.parentNode === qfe) {
+ var node = container;
+ while((node = container.previousSibling)) {
+ if(node.citationItem) {
+ return node;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ // Check whether there is a bubble anywhere to the left of this one
+ var offset = range.startOffset,
+ childNodes = qfe.childNodes,
+ node = childNodes[offset-(right ? 0 : 1)];
+ if(node && node.citationItem) return node;
+ return null;
+ }
+
+ /**
+ * Reset timer that controls when search takes place. We use this to avoid searching after each
+ * keypress, since searches can be slow.
+ */
+ function _resetSearchTimer() {
+ if(searchTimeout) clearTimeout(searchTimeout);
+ searchTimeout = setTimeout(_quickFormat, 250);
+ }
/**
* Handle return or escape
@@ -987,29 +1040,48 @@ var Zotero_QuickFormat = new function () {
} else if(keyCode === event.DOM_VK_TAB || event.charCode === 59 /* ; */) {
event.preventDefault();
_bubbleizeSelected();
- } else if(keyCode === event.DOM_VK_BACK_SPACE) {
+ } else if(keyCode === event.DOM_VK_BACK_SPACE || keyCode === event.DOM_VK_DELETE) {
+ var bubble = _getSelectedBubble(keyCode === event.DOM_VK_DELETE);
+
+ if(bubble) {
+ event.preventDefault();
+ bubble.parentNode.removeChild(bubble);
+ }
+
_resize();
-
- if(Zotero_QuickFormat.eventTimeout) clearTimeout(Zotero_QuickFormat.eventTimeout);
- Zotero_QuickFormat.eventTimeout = setTimeout(_quickFormat, 250);
-
+ _resetSearchTimer();
+ } else if(keyCode === event.DOM_VK_LEFT || keyCode === event.DOM_VK_RIGHT) {
+ var right = keyCode === event.DOM_VK_RIGHT,
+ bubble = _getSelectedBubble(right);
+ if(bubble) {
+ event.preventDefault();
+
+ var nodeRange = qfiDocument.createRange();
+ nodeRange.selectNode(bubble);
+ nodeRange.collapse(!right);
+
+ var selection = qfiWindow.getSelection();
+ selection.removeAllRanges();
+ selection.addRange(nodeRange);
+ }
+
} else if(keyCode === event.DOM_VK_UP) {
var selectedItem = referenceBox.selectedItem;
var previousSibling;
- //Seek the closet previous sibling that is not disabled
- while((previousSibling = selectedItem.previousSibling) && previousSibling.getAttribute("disabled")){
+ // Seek the closet previous sibling that is not disabled
+ while((previousSibling = selectedItem.previousSibling) && previousSibling.hasAttribute("disabled")) {
selectedItem = previousSibling;
}
- //If found, change to that
+ // If found, change to that
if(previousSibling) {
referenceBox.selectedItem = previousSibling;
- //If there are separators before this item, ensure that they are visible
+ // If there are separators before this item, ensure that they are visible
var visibleItem = previousSibling;
- while(visibleItem.previousSibling && visibleItem.previousSibling.getAttribute("disabled")){
+ while(visibleItem.previousSibling && visibleItem.previousSibling.hasAttribute("disabled")) {
visibleItem = visibleItem.previousSibling;
}
referenceBox.ensureElementIsVisible(visibleItem);
@@ -1018,54 +1090,20 @@ var Zotero_QuickFormat = new function () {
} else if(keyCode === event.DOM_VK_DOWN) {
if((Zotero.isMac ? event.metaKey : event.ctrlKey)) {
// If meta key is held down, show the citation properties panel
- var selection = qfiWindow.getSelection();
- var range = selection.getRangeAt(0);
-
- // Check whether the bubble is selected
- var endContainer = range.endContainer;
- if(endContainer !== qfe) {
- if(range.endContainer.citationItem) {
- _showCitationProperties(range.endContainer);
- } else if(endContainer.nodeType === Node.TEXT_NODE) {
- if(endContainer.parentNode === qfe) {
- var node = endContainer;
- while((node = endContainer.previousSibling)) {
- if(node.citationItem) {
- _showCitationProperties(node);
- event.preventDefault();
- return;
- }
- }
- }
- }
- event.preventDefault();
- return;
- }
-
- // Check whether there is a bubble in the range
- var endOffset = range.endOffset;
- var childNodes = qfe.childNodes;
- for(var i=Math.min(endOffset, childNodes.length-1); i>=0; i--) {
- var node = childNodes[i];
- if(node.citationItem) {
- _showCitationProperties(node);
- event.preventDefault();
- return;
- }
- }
-
+ var bubble = _getSelectedBubble();
+
+ if(bubble) _showCitationProperties(bubble);
event.preventDefault();
} else {
var selectedItem = referenceBox.selectedItem;
var nextSibling;
- //Seek the closet next sibling that is not disabled
- while((nextSibling = selectedItem.nextSibling) && nextSibling.getAttribute("disabled")){
+ // Seek the closet next sibling that is not disabled
+ while((nextSibling = selectedItem.nextSibling) && nextSibling.hasAttribute("disabled")) {
selectedItem = nextSibling;
}
- //If found, change to that
-
+ // If found, change to that
if(nextSibling){
referenceBox.selectedItem = nextSibling;
referenceBox.ensureElementIsVisible(nextSibling);
@@ -1073,9 +1111,7 @@ var Zotero_QuickFormat = new function () {
};
}
} else {
- // Use a timeout so that _quickFormat gets called after update
- if(Zotero_QuickFormat.eventTimeout) clearTimeout(Zotero_QuickFormat.eventTimeout);
- Zotero_QuickFormat.eventTimeout = setTimeout(_quickFormat, 250);
+ _resetSearchTimer();
}
}
@@ -1083,34 +1119,74 @@ var Zotero_QuickFormat = new function () {
* Adds a dummy element to make dragging work
*/
function _onBubbleDrag(event) {
- // just in case
- var el = qfiDocument.getElementById("zotero-drag");
- if(el) el.parentNode.removeChild(el);
-
- var dt = event.dataTransfer;
- dragging = event.target.citationItem;
- dt.setData("text/html", '');
+ dragging = event.currentTarget;
+ event.dataTransfer.setData("text/plain", '');
event.stopPropagation();
}
+
+ /**
+ * Get index of bubble in citations
+ */
+ function _getBubbleIndex(bubble) {
+ var nodes = qfe.childNodes, oldPosition = -1, index = 0;
+ for(var i=0, n=nodes.length; i
-
+
@@ -169,8 +169,8 @@
-
-
+
+
@@ -228,9 +228,9 @@
-
-
-
+
+
+
@@ -263,8 +263,8 @@