www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit 481d84795111af162eeb94e530d5c2629bad4752
parent 921fa8c0fa5606eb27de43d0fcca12b98479d9fd
Author: Dan Stillman <dstillman@zotero.org>
Date:   Fri, 29 May 2009 11:49:55 +0000

Long tag fixer tool -- runs automatically if server returns a long tag error, giving the option to split, edit, or delete the offending tag

Needs testing and refinement

- Also fixes server unlock after sync errors



Diffstat:
Achrome/content/zotero/longTagFixer.js | 185+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Achrome/content/zotero/longTagFixer.xul | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mchrome/content/zotero/xpcom/sync.js | 49++++++++++++++++++++++++++++++++++++-------------
Achrome/skin/default/zotero/longTagFixer.css | 8++++++++
Mdefaults/preferences/zotero.js | 1+
5 files changed, 304 insertions(+), 13 deletions(-)

diff --git a/chrome/content/zotero/longTagFixer.js b/chrome/content/zotero/longTagFixer.js @@ -0,0 +1,185 @@ +var Zotero_Long_Tag_Fixer = new function () { + var _oldTag = window.arguments[0]; + var _callback = window.arguments[1]; + + this.init = function () { + document.getElementById('zotero-old-tag').value = _oldTag; + + var lastMode = Zotero.Prefs.get('lastLongTagMode'); + if (!lastMode) { + lastMode = 0; + } + this.switchMode(lastMode); + } + + this.switchMode = function (index) { + var dialog = document.getElementById('zotero-long-tag-fixer'); + + document.getElementById('zotero-new-tag-actions').selectedIndex = index; + + // TODO: localize + switch (index) { + case 0: + var buttonLabel = "Save Tags"; + this.updateTagList(); + break; + + case 1: + var buttonLabel = "Save Tag"; + document.getElementById('zotero-new-tag-editor').value = _oldTag; + this.updateEditLength(_oldTag.length) + break; + + case 2: + var buttonLabel = "Delete Tag"; + dialog.getButton('accept').disabled = false; + break; + } + + document.getElementById('zotero-long-tag-fixer').getButton('accept').label = buttonLabel; + + Zotero.Prefs.set('lastLongTagMode', index); + } + + + /** + * Split tags and populate list + */ + this.updateTagList = function () { + var listbox = document.getElementById('zotero-new-tag-list'); + while (listbox.childNodes.length) { + listbox.removeChild(listbox.lastChild); + } + + var delimiter = document.getElementById('zotero-old-tag-delimiter').value; + if (delimiter) { + var re = new RegExp("\\s*" + delimiter + "\\s*"); + var tags = _oldTag.split(re); + } + + var acceptButton = document.getElementById('zotero-long-tag-fixer').getButton('accept'); + if (!delimiter || tags.length < 2) { + acceptButton.disabled = true; + return; + } + else { + acceptButton.disabled = false; + } + + tags.sort(); + for (var i=0; i<tags.length; i++) { + if (i==0 || tags[i] == tags[i-1]) { + continue; + } + var li = listbox.appendItem(tags[i]); + li.setAttribute('type', 'checkbox'); + li.setAttribute('checked', 'true'); + } + } + + + this.deselectAll = function () { + var lis = document.getElementById('zotero-new-tag-list').getElementsByTagName('listitem'); + for (var i=0; i<lis.length; i++) { + lis[i].checked = false; + } + } + + + this.selectAll = function () { + var lis = document.getElementById('zotero-new-tag-list').getElementsByTagName('listitem'); + for (var i=0; i<lis.length; i++) { + lis[i].checked = true; + } + } + + + this.updateEditLength = function (len) { + document.getElementById('zotero-new-tag-character-count').value = len; + var invalid = len == 0 || len > 255; + document.getElementById('zotero-new-tag-characters').setAttribute('invalid', invalid); + document.getElementById('zotero-long-tag-fixer').getButton('accept').disabled = invalid; + } + + + this.cancel = function () { + if (_callback) { + _callback(false); + } + } + + + this.save = function () { + try { + + var index = document.getElementById('zotero-new-tag-actions').selectedIndex; + + // Search for all matching tags across all libraries + var sql = "SELECT tagID FROM tags WHERE name=?"; + var oldTagIDs = Zotero.DB.columnQuery(sql, _oldTag); + + switch (index) { + // Split + case 0: + // Get checked tags + var listbox = document.getElementById('zotero-new-tag-list'); + var len = Zotero.isFx3 ? listbox.childNodes.length : listbox.childElementCount; + var newTags = []; + for (var i=0; i<len; i++) { + var li = listbox.childNodes[i]; + if (li.getAttribute('checked') == 'true') { + newTags.push(li.getAttribute('label')); + } + } + + Zotero.DB.beginTransaction(); + + // Add new tags to all items linked to each matching old tag + for (var i=0; i<oldTagIDs.length; i++) { + var tag = Zotero.Tags.get(oldTagIDs[i]); + var items = tag.getLinkedItems(); + if (items) { + for (var j=0; j<items.length; j++) { + items[j].addTags(newTags, tag.type); + } + } + } + + // Remove old tags + Zotero.Tags.erase(oldTagIDs); + Zotero.Tags.purge(); + Zotero.DB.commitTransaction(); + break; + + // Edit + case 1: + var value = document.getElementById('zotero-new-tag-editor').value; + Zotero.DB.beginTransaction(); + for (var i=0; i<oldTagIDs.length; i++) { + var tag = Zotero.Tags.get(oldTagIDs[i]); + tag.name = value; + tag.save(); + } + Zotero.DB.commitTransaction(); + break; + + // Delete + case 2: + Zotero.DB.beginTransaction(); + Zotero.Tags.erase(oldTagIDs); + Zotero.Tags.purge(); + Zotero.DB.commitTransaction(); + break; + } + + if (_callback) { + _callback(true); + } + + } + catch (e) { + Zotero.debug(e); + throw (e); + } + } +} diff --git a/chrome/content/zotero/longTagFixer.xul b/chrome/content/zotero/longTagFixer.xul @@ -0,0 +1,74 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> +<?xml-stylesheet href="chrome://zotero/skin/longTagFixer.css" type="text/css"?> + +<dialog id="zotero-long-tag-fixer" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + buttons="accept,cancel" + onload="Zotero_Long_Tag_Fixer.init()" + ondialogcancel="Zotero_Long_Tag_Fixer.cancel()" + ondialogaccept="Zotero_Long_Tag_Fixer.save()" + title="Sync Error"> <!-- TODO: localize --> + + <script src="include.js"/> + <script src="longTagFixer.js"/> + + <!-- TODO: localize --> + <label value="The following tag in your Zotero library is too long to sync to the server:"/> + <groupbox> + <textbox id="zotero-old-tag" multiline="true" rows="4" readonly="true" class="plain"/> + </groupbox> + <label>Synced tags must be shorter than 256 characters.</label> + + <separator class="thin"/> + + <label value="You can either split the tag into multiple tags, edit the tag manually to shorten it, or delete it."/> + + <separator/> + + <tabbox id="zotero-new-tag-actions"> + <tabs oncommand="Zotero_Long_Tag_Fixer.switchMode(this.selectedIndex)"> + <tab label="Split"/> + <tab label="Edit"/> + <tab label="Delete"/> + </tabs> + <tabpanels> + <!-- Split --> + <vbox> + <hbox align="center"> + <label>Split at the </label> + <textbox id="zotero-old-tag-delimiter" size="1" maxLength="1" value=";" + oninput="Zotero_Long_Tag_Fixer.updateTagList()"/> + <label>character</label> + </hbox> + + <separator class="thin"/> + + <listbox id="zotero-new-tag-list" rows="8"/> + + <separator class="thin"/> + + <label value="Unchecked tags will not be saved."/> + + <hbox> + <button label="Deselect All" oncommand="Zotero_Long_Tag_Fixer.deselectAll()"/> + <button label="Select All" oncommand="Zotero_Long_Tag_Fixer.selectAll()"/> + </hbox> + </vbox> + + <!-- Edit --> + <vbox> + <textbox id="zotero-new-tag-editor" multiline="true" flex="1" + oninput="Zotero_Long_Tag_Fixer.updateEditLength(this.value.length)"/> + <hbox id="zotero-new-tag-characters"> + <label id="zotero-new-tag-character-count"/> + <label value="characters"/> + </hbox> + </vbox> + + <!-- Delete --> + <vbox align="center" pack="center"> + <label value="The tag will be deleted from all items."/> + </vbox> + </tabpanels> + </tabbox> +</dialog> diff --git a/chrome/content/zotero/xpcom/sync.js b/chrome/content/zotero/xpcom/sync.js @@ -951,6 +951,8 @@ Zotero.Sync.Server = new function () { _error(response.firstChild.firstChild.nodeValue); } + _sessionLock = true; + // Strip XML declaration and convert to E4X var xml = new XML(xmlhttp.responseText.replace(/<\?xml.*\?>/, '')); @@ -1463,15 +1465,40 @@ Zotero.Sync.Server = new function () { } - if (firstChild.localName == 'error' && firstChild.getAttribute('code') == 'ITEM_MISSING') { - var [libraryID, key] = firstChild.getAttribute('missingItem').split('/'); - if (libraryID == Zotero.libraryID) { - libraryID = null; - } - var item = Zotero.Items.getByLibraryAndKey(libraryID, key); - if (item) { - Zotero.DB.rollbackAllTransactions(); - item.updateClientDateModified(); + if (firstChild.localName == 'error') { + switch (firstChild.getAttribute('code')) { + case 'ITEM_MISSING': + var [libraryID, key] = firstChild.getAttribute('missingItem').split('/'); + if (libraryID == Zotero.libraryID) { + libraryID = null; + } + var item = Zotero.Items.getByLibraryAndKey(libraryID, key); + if (item) { + Zotero.DB.rollbackAllTransactions(); + item.updateClientDateModified(); + } + break; + + case 'TAG_TOO_LONG': + var tag = xmlhttp.responseXML.firstChild.getElementsByTagName('tag'); + if (tag.length) { + Zotero.DB.rollbackAllTransactions(); + + var tag = tag[0].firstChild.nodeValue; + setTimeout(function () { + var callback = function (success) { + if (success) { + Zotero.Sync.Runner.sync(); + } + }; + + var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] + .getService(Components.interfaces.nsIWindowMediator); + var lastWin = wm.getMostRecentWindow("navigator:browser"); + lastWin.openDialog('chrome://zotero/content/longTagFixer.xul', '', 'chrome,modal,centerscreen', tag, callback); + }, 1); + } + break; } } } @@ -1925,8 +1952,6 @@ Zotero.Sync.Server.Data = new function() { case 'item': var diff = obj.diff(remoteObj, false, ["dateModified"]); - Zotero.debug('diff'); - Zotero.debug(diff); if (!diff) { // Check if creators changed var creatorsChanged = false; @@ -1944,11 +1969,9 @@ Zotero.Sync.Server.Data = new function() { var r = remoteCreatorStore[Zotero.Creators.getLibraryKeyHash(creator.ref)]; // Doesn't include dateModified if (r && !r.equals(creator.ref)) { - Zotero.debug('='); creatorsChanged = true; break; } - Zotero.debug('-'); } } if (!creatorsChanged) { diff --git a/chrome/skin/default/zotero/longTagFixer.css b/chrome/skin/default/zotero/longTagFixer.css @@ -0,0 +1,8 @@ +#zotero-new-tag-characters[invalid="true"] { + color: red; +} + +#zotero-new-tag-character-count { + font-weight: bold; + margin-right: 0; +} diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js @@ -42,6 +42,7 @@ pref("extensions.zotero.lastCreatorFieldMode",0); pref("extensions.zotero.lastAbstractExpand",0); pref("extensions.zotero.lastRenameAssociatedFile", false); pref("extensions.zotero.lastViewedFolder", 'L'); +pref("extensions.zotero.lastLongTagMode", 0); //Tag Cloud pref("extensions.zotero.tagCloud", false);