fx-compat: long tag fixer (#2649)
* Manual tag splitting from tag selector * Only apply split to the tag in current library * Preserve tag type
This commit is contained in:
parent
b1595cdd1d
commit
13cc393840
12 changed files with 406 additions and 251 deletions
chrome
content/zotero
locale/en-US/zotero
skin/default/zotero
scss
test/tests
|
@ -642,6 +642,46 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent {
|
|||
await Zotero.Tags.setColor(this.libraryID, io.name, io.color, io.position);
|
||||
}
|
||||
|
||||
async openTagSplitterWindow() {
|
||||
const oldTagName = this.contextTag.name; // contextTag contains { name, width, color }
|
||||
const dataIn = {
|
||||
oldTag: this.contextTag.name,
|
||||
isLongTag: false
|
||||
};
|
||||
const dataOut = { result: null };
|
||||
|
||||
window.openDialog(
|
||||
'chrome://zotero/content/longTagFixer.xhtml',
|
||||
'',
|
||||
'chrome,modal,centerscreen',
|
||||
dataIn, dataOut
|
||||
);
|
||||
|
||||
if (!dataOut.result) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldTagID = Zotero.Tags.getID(oldTagName);
|
||||
|
||||
if (dataOut.result.op === 'split') {
|
||||
const itemIDs = await Zotero.Tags.getTagItems(this.libraryID, oldTagID);
|
||||
await Zotero.DB.executeTransaction(async () => {
|
||||
for (const itemID of itemIDs) {
|
||||
const item = await Zotero.Items.getAsync(itemID);
|
||||
const tagType = item.getTagType(oldTagName);
|
||||
for (const newTagName of dataOut.result.tags) {
|
||||
item.addTag(newTagName, tagType);
|
||||
}
|
||||
item.removeTag(oldTagName);
|
||||
await item.save();
|
||||
}
|
||||
await Zotero.Tags.purge(oldTagID);
|
||||
});
|
||||
} else {
|
||||
throw new Error('Unsupported op: ' + dataOut.result.op);
|
||||
}
|
||||
}
|
||||
|
||||
async openRenamePrompt() {
|
||||
var promptService = Cc['@mozilla.org/embedcomp/prompt-service;1']
|
||||
.getService(Ci.nsIPromptService);
|
||||
|
|
|
@ -1,191 +1,212 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2009 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.org
|
||||
|
||||
|
||||
Copyright © 2022 Corporation for Digital Scholarship
|
||||
Vienna, Virginia, USA
|
||||
https://www.zotero.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
const HTML_NS = 'http://www.w3.org/1999/xhtml';
|
||||
|
||||
var Zotero_Long_Tag_Fixer = new function () {
|
||||
var _oldTag = window.arguments[0];
|
||||
var _dataOut = window.arguments[1];
|
||||
var Zotero_Long_Tag_Fixer = new function () { // eslint-disable-line camelcase, no-unused-vars
|
||||
const { oldTag, isLongTag } = window.arguments?.[0] ?? { isLongTag: true, oldTag: '' };
|
||||
const dataOut = window.arguments?.[1] || {};
|
||||
|
||||
this.init = function () {
|
||||
document.getElementById('zotero-old-tag').value = _oldTag;
|
||||
document.getElementById('zotero-old-tag-delimiter').nextSibling.value = Zotero.getString('general.character.singular');
|
||||
|
||||
var delimiter = Zotero.Prefs.get('lastLongTagDelimiter');
|
||||
document.getElementById('zotero-old-tag-delimiter').value = delimiter;
|
||||
|
||||
var lastMode = Zotero.Prefs.get('lastLongTagMode');
|
||||
if (!lastMode) {
|
||||
lastMode = 0;
|
||||
}
|
||||
this.switchMode(lastMode);
|
||||
}
|
||||
const lastMode = Zotero.Prefs.get('lastLongTagMode') || 0;
|
||||
const delimiter = Zotero.Prefs.get('lastLongTagDelimiter');
|
||||
|
||||
this.dialog = document.getElementById('zotero-long-tag-fixer');
|
||||
this.intro = document.getElementById('intro');
|
||||
this.tabs = document.getElementById('zotero-new-tag-actions');
|
||||
this.oldTagInput = document.getElementById('zotero-old-tag');
|
||||
this.oldTag = document.getElementById('zotero-old-tag');
|
||||
this.delimiterLabel = document.getElementById('delimiter-label');
|
||||
this.oldTagDelimiter = document.getElementById('zotero-old-tag-delimiter');
|
||||
this.listbox = document.getElementById('zotero-new-tag-list');
|
||||
this.newTagInput = document.getElementById('zotero-new-tag-editor');
|
||||
this.newTagCharacterCount = document.getElementById('zotero-new-tag-character-count');
|
||||
this.zoteroNewTagInfo = document.getElementById('zotero-new-tag-characters');
|
||||
|
||||
document.addEventListener('dialogaccept', () => this.accept());
|
||||
document.addEventListener('dialogcancel', () => this.cancel());
|
||||
this.tabs.addEventListener('select', (ev) => {
|
||||
if (ev.target === this.tabs.querySelector('tabpanels')) {
|
||||
this.switchMode(ev.currentTarget.selectedIndex);
|
||||
}
|
||||
});
|
||||
|
||||
this.dialog.classList.toggle('is-long-tag', isLongTag);
|
||||
|
||||
this.oldTagDelimiter.addEventListener('input', () => this.onUpdateDelimiter());
|
||||
this.newTagInput.addEventListener('input', ev => this.updateEditLength(ev.currentTarget.value.length));
|
||||
|
||||
this.oldTagInput.value = oldTag;
|
||||
this.oldTagDelimiter.value = delimiter;
|
||||
|
||||
this.updateLabel();
|
||||
this.switchMode(isLongTag ? lastMode : 0);
|
||||
};
|
||||
|
||||
this.switchMode = function (index) {
|
||||
var dialog = document.getElementById('zotero-long-tag-fixer');
|
||||
|
||||
document.getElementById('zotero-new-tag-actions').selectedIndex = index;
|
||||
this.tabs.selectedIndex = index;
|
||||
let buttonLabel = "";
|
||||
|
||||
switch (index) {
|
||||
default:
|
||||
case 0:
|
||||
var buttonLabel = "saveTags";
|
||||
buttonLabel = 'saveTags';
|
||||
this.updateTagList();
|
||||
document.getElementById('zotero-old-tag-delimiter').select();
|
||||
this.oldTagDelimiter.select();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
var buttonLabel = "saveTag";
|
||||
document.getElementById('zotero-new-tag-editor').value = _oldTag;
|
||||
this.updateEditLength(_oldTag.length)
|
||||
buttonLabel = 'saveTag';
|
||||
this.newTagInput.value = oldTag;
|
||||
this.updateEditLength(oldTag.length);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
var buttonLabel = "deleteTag";
|
||||
dialog.getButton('accept').disabled = false;
|
||||
buttonLabel = 'deleteTag';
|
||||
this.dialog.getButton('accept').disabled = false;
|
||||
break;
|
||||
}
|
||||
|
||||
document.getElementById('zotero-long-tag-fixer').getButton('accept').label = Zotero.getString('sync.longTagFixer.' + buttonLabel);
|
||||
this.dialog.getButton('accept').label = Zotero.getString('sync.longTagFixer.' + buttonLabel);
|
||||
window.sizeToContent();
|
||||
Zotero.Prefs.set('lastLongTagMode', index);
|
||||
}
|
||||
|
||||
if (isLongTag) {
|
||||
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);
|
||||
}
|
||||
let tags = [];
|
||||
|
||||
var delimiter = document.getElementById('zotero-old-tag-delimiter').value;
|
||||
const delimiter = document.getElementById('zotero-old-tag-delimiter').value;
|
||||
if (delimiter) {
|
||||
Zotero.Prefs.set('lastLongTagDelimiter', delimiter);
|
||||
var re = new RegExp("\\s*" + delimiter.replace(/([\.\-\[\]\(\)\?\*\+])/g, "\\$1") + "\\s*");
|
||||
var tags = _oldTag.split(re);
|
||||
const re = new RegExp("\\s*" + delimiter.replace(/([\.\-\[\]\(\)\?\*\+])/g, "\\$1") + "\\s*");
|
||||
tags = [...new Set(oldTag.split(re).filter(t => t.length > 0))];
|
||||
}
|
||||
|
||||
var acceptButton = document.getElementById('zotero-long-tag-fixer').getButton('accept');
|
||||
const acceptButton = document.getElementById('zotero-long-tag-fixer').getButton('accept');
|
||||
if (!delimiter || tags.length < 2) {
|
||||
acceptButton.disabled = true;
|
||||
return;
|
||||
// return;
|
||||
}
|
||||
else {
|
||||
acceptButton.disabled = false;
|
||||
}
|
||||
|
||||
tags.sort();
|
||||
for (var i=0; i<tags.length; i++) {
|
||||
if (i != 0 && tags[i] == tags[i-1]) {
|
||||
continue;
|
||||
}
|
||||
if (!tags[i]) {
|
||||
continue;
|
||||
}
|
||||
var li = listbox.appendItem(tags[i]);
|
||||
li.setAttribute('type', 'checkbox');
|
||||
li.setAttribute('checked', 'true');
|
||||
|
||||
while (this.listbox.childNodes.length) {
|
||||
this.listbox.removeChild(this.listbox.lastChild);
|
||||
}
|
||||
|
||||
tags.forEach((tag) => {
|
||||
const li = document.createElement('richlistitem');
|
||||
const div = document.createElement('div');
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.checked = true;
|
||||
checkbox.id = 'tag-' + tag;
|
||||
const label = document.createElement('label');
|
||||
label.setAttribute('for', 'tag-' + tag);
|
||||
label.textContent = tag;
|
||||
// Don't toggle checkbox for single-click on label
|
||||
|
||||
div.appendChild(checkbox);
|
||||
div.appendChild(label);
|
||||
li.appendChild(div);
|
||||
this.listbox.append(li);
|
||||
});
|
||||
|
||||
window.sizeToContent();
|
||||
}
|
||||
};
|
||||
|
||||
this.updateLabel = function () {
|
||||
this.delimiterLabel.innerHTML = this.oldTagDelimiter.value.length > 1
|
||||
? Zotero.getString('general.character.plural')
|
||||
: Zotero.getString('general.character.singular');
|
||||
};
|
||||
|
||||
this.onUpdateDelimiter = function () {
|
||||
this.updateLabel();
|
||||
this.updateTagList();
|
||||
};
|
||||
|
||||
|
||||
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.listbox.querySelectorAll('[type=checkbox]').forEach(checkbox => checkbox.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.listbox.querySelectorAll('[type=checkbox]').forEach(checkbox => checkbox.checked = true);
|
||||
};
|
||||
|
||||
|
||||
this.updateEditLength = function (len) {
|
||||
document.getElementById('zotero-new-tag-character-count').value = len;
|
||||
var invalid = len == 0 || len > Zotero.Tags.MAX_SYNC_LENGTH;
|
||||
document.getElementById('zotero-new-tag-characters').setAttribute('invalid', invalid);
|
||||
document.getElementById('zotero-long-tag-fixer').getButton('accept').disabled = invalid;
|
||||
}
|
||||
this.newTagCharacterCount.innerText = len;
|
||||
const invalid = len == 0 || len > Zotero.Tags.MAX_SYNC_LENGTH;
|
||||
this.zoteroNewTagInfo.classList.toggle('invalid', invalid);
|
||||
this.dialog.getButton('accept').disabled = invalid;
|
||||
};
|
||||
|
||||
|
||||
this.cancel = function () {
|
||||
_dataOut.result = false;
|
||||
}
|
||||
dataOut.result = false;
|
||||
};
|
||||
|
||||
|
||||
this.save = function () {
|
||||
this.accept = function () {
|
||||
try {
|
||||
|
||||
var result = {};
|
||||
|
||||
var index = document.getElementById('zotero-new-tag-actions').selectedIndex;
|
||||
|
||||
switch (index) {
|
||||
// Split
|
||||
case 0:
|
||||
// Get checked tags
|
||||
var listbox = document.getElementById('zotero-new-tag-list');
|
||||
var len = 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'));
|
||||
}
|
||||
}
|
||||
const result = {};
|
||||
switch (this.tabs.selectedIndex) {
|
||||
// Split
|
||||
case 0:
|
||||
result.op = 'split';
|
||||
result.tags = Array.from(this.listbox.querySelectorAll('[type=checkbox]'))
|
||||
.filter(c => c.checked)
|
||||
.map(n => n.nextSibling.textContent);
|
||||
break;
|
||||
// Edit
|
||||
case 1:
|
||||
result.op = 'edit';
|
||||
result.tag = this.newTagInput.value;
|
||||
break;
|
||||
|
||||
result.op = 'split';
|
||||
result.tags = newTags;
|
||||
break;
|
||||
|
||||
// Edit
|
||||
case 1:
|
||||
result.op = 'edit';
|
||||
result.tag = document.getElementById('zotero-new-tag-editor').value;
|
||||
break;
|
||||
|
||||
// Delete
|
||||
case 2:
|
||||
result.op = 'delete';
|
||||
break;
|
||||
}
|
||||
|
||||
_dataOut.result = result;
|
||||
|
||||
// Delete
|
||||
case 2:
|
||||
result.op = 'delete';
|
||||
break;
|
||||
}
|
||||
dataOut.result = result;
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug(e);
|
||||
throw (e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
65
chrome/content/zotero/longTagFixer.xhtml
Normal file
65
chrome/content/zotero/longTagFixer.xhtml
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://zotero-platform/content/zotero-react-client.css"?>
|
||||
|
||||
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
|
||||
|
||||
<window
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
title="&zotero.sync.error;"
|
||||
onload="Zotero_Long_Tag_Fixer.init()">
|
||||
<dialog
|
||||
id="zotero-long-tag-fixer"
|
||||
buttons="cancel,accept"
|
||||
>
|
||||
<html:div id="intro">
|
||||
<label value="&zotero.sync.longTagFixer.followingTagTooLong;"/>
|
||||
<html:textarea id="zotero-old-tag" readonly="readonly" />
|
||||
<label>&zotero.sync.longTagFixer.syncedTagSizeLimit;</label>
|
||||
<label value="&zotero.sync.longTagFixer.splitEditDelete;"/>
|
||||
</html:div>
|
||||
<tabbox id="zotero-new-tag-actions">
|
||||
<tabs>
|
||||
<tab label="&zotero.sync.longTagFixer.split;"/>
|
||||
<tab label="&zotero.general.edit;"/>
|
||||
<tab label="&zotero.general.delete;"/>
|
||||
</tabs>
|
||||
<tabpanels>
|
||||
<!-- Split -->
|
||||
<vbox class="split-tab">
|
||||
<hbox class="delimiter-input-wrap">
|
||||
<label>&zotero.sync.longTagFixer.splitAtThe;</label>
|
||||
<html:input
|
||||
type="text"
|
||||
class="delimiter-input"
|
||||
id="zotero-old-tag-delimiter" />
|
||||
<label id="delimiter-label"></label>
|
||||
</hbox>
|
||||
<richlistbox id="zotero-new-tag-list" class="tag-list" flex="1" tabindex="0" />
|
||||
<label value="&zotero.sync.longTagFixer.uncheckedTagsNotSaved;"/>
|
||||
<hbox>
|
||||
<button label="&zotero.general.deselectAll;" oncommand="Zotero_Long_Tag_Fixer.deselectAll()"/>
|
||||
<button label="&zotero.general.selectAll;" oncommand="Zotero_Long_Tag_Fixer.selectAll()"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
<!-- Edit -->
|
||||
<vbox class="edit-tab">
|
||||
<html:textarea id="zotero-new-tag-editor"/>
|
||||
<html:div id="zotero-new-tag-characters">
|
||||
<html:span id="zotero-new-tag-character-count" />
|
||||
<html:span>&zotero.sync.longTagFixer.characters;</html:span>
|
||||
</html:div>
|
||||
</vbox>
|
||||
|
||||
<!-- Delete -->
|
||||
<vbox align="center" pack="center">
|
||||
<label value="&zotero.sync.longTagFixer.tagWillBeDeleted;"/>
|
||||
</vbox>
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
<script src="include.js"/>
|
||||
<script src="longTagFixer.js"/>
|
||||
</dialog>
|
||||
</window>
|
|
@ -1,76 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://zotero/skin/longTagFixer.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://zotero-platform-version/content/style.css"?>
|
||||
|
||||
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
|
||||
|
||||
<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="&zotero.sync.error;">
|
||||
|
||||
<script src="include.js"/>
|
||||
<script src="longTagFixer.js"/>
|
||||
|
||||
<label value="&zotero.sync.longTagFixer.followingTagTooLong;"/>
|
||||
<groupbox>
|
||||
<textbox id="zotero-old-tag" multiline="true" rows="4" readonly="true" class="plain"/>
|
||||
</groupbox>
|
||||
<label>&zotero.sync.longTagFixer.syncedTagSizeLimit;</label>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<label value="&zotero.sync.longTagFixer.splitEditDelete;"/>
|
||||
|
||||
<separator/>
|
||||
|
||||
<tabbox id="zotero-new-tag-actions">
|
||||
<tabs oncommand="Zotero_Long_Tag_Fixer.switchMode(this.selectedIndex)">
|
||||
<tab label="&zotero.sync.longTagFixer.split;"/>
|
||||
<tab label="&zotero.general.edit;"/>
|
||||
<tab label="&zotero.general.delete;"/>
|
||||
</tabs>
|
||||
<tabpanels>
|
||||
<!-- Split -->
|
||||
<vbox>
|
||||
<hbox align="center">
|
||||
<label>&zotero.sync.longTagFixer.splitAtThe;</label>
|
||||
<textbox id="zotero-old-tag-delimiter" size="1"
|
||||
oninput="this.nextSibling.value = Zotero.getString('general.character.' + (this.value.length > 1 ? 'plural' : 'singular')); Zotero_Long_Tag_Fixer.updateTagList();"/>
|
||||
<label/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<listbox id="zotero-new-tag-list" rows="8"/>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<label value="&zotero.sync.longTagFixer.uncheckedTagsNotSaved;"/>
|
||||
|
||||
<hbox>
|
||||
<button label="&zotero.general.deselectAll;" oncommand="Zotero_Long_Tag_Fixer.deselectAll()"/>
|
||||
<button label="&zotero.general.selectAll;" 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="&zotero.sync.longTagFixer.characters;"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
<!-- Delete -->
|
||||
<vbox align="center" pack="center">
|
||||
<label value="&zotero.sync.longTagFixer.tagWillBeDeleted;"/>
|
||||
</vbox>
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
</dialog>
|
|
@ -1214,62 +1214,54 @@ Zotero.Sync.Runner_Module = function (options = {}) {
|
|||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var lastWin = wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
// Open long tag fixer for every long tag in every editable library we're syncing
|
||||
var editableLibraries = options.libraries
|
||||
.filter(x => Zotero.Libraries.get(x).editable);
|
||||
for (let libraryID of editableLibraries) {
|
||||
let oldTagIDs = yield Zotero.Tags.getLongTagsInLibrary(libraryID);
|
||||
for (let oldTagID of oldTagIDs) {
|
||||
let oldTag = Zotero.Tags.getName(oldTagID);
|
||||
let dataOut = { result: null };
|
||||
lastWin.openDialog(
|
||||
'chrome://zotero/content/longTagFixer.xul',
|
||||
'',
|
||||
'chrome,modal,centerscreen',
|
||||
oldTag,
|
||||
dataOut
|
||||
);
|
||||
// If dialog was cancelled, stop
|
||||
if (!dataOut.result) {
|
||||
return;
|
||||
}
|
||||
switch (dataOut.result.op) {
|
||||
// Open long tag fixer for library we're syncing
|
||||
let oldTagIDs = yield Zotero.Tags.getLongTagsInLibrary(object.libraryID);
|
||||
|
||||
for (let oldTagID of oldTagIDs) {
|
||||
let oldTag = Zotero.Tags.getName(oldTagID);
|
||||
let dataOut = { result: null };
|
||||
lastWin.openDialog(
|
||||
'chrome://zotero/content/longTagFixer.xhtml',
|
||||
'',
|
||||
'chrome,modal,centerscreen',
|
||||
{ oldTag, isLongTag: true },
|
||||
dataOut
|
||||
);
|
||||
// If dialog was cancelled, stop
|
||||
if (!dataOut.result) {
|
||||
return;
|
||||
}
|
||||
const itemIDs = yield Zotero.Tags.getTagItems(object.libraryID, oldTagID);
|
||||
|
||||
switch (dataOut.result.op) {
|
||||
case 'split':
|
||||
for (let libraryID of editableLibraries) {
|
||||
let itemIDs = yield Zotero.Tags.getTagItems(libraryID, oldTagID);
|
||||
yield Zotero.DB.executeTransaction(async function () {
|
||||
for (let itemID of itemIDs) {
|
||||
let item = await Zotero.Items.getAsync(itemID);
|
||||
for (let tag of dataOut.result.tags) {
|
||||
item.addTag(tag);
|
||||
}
|
||||
item.removeTag(oldTag);
|
||||
await item.save();
|
||||
yield Zotero.DB.executeTransaction(async function () {
|
||||
for (let itemID of itemIDs) {
|
||||
let item = await Zotero.Items.getAsync(itemID);
|
||||
let tagType = item.getTagType(oldTag);
|
||||
for (let tag of dataOut.result.tags) {
|
||||
item.addTag(tag, tagType);
|
||||
}
|
||||
await Zotero.Tags.purge(oldTagID);
|
||||
});
|
||||
}
|
||||
item.removeTag(oldTag);
|
||||
await item.save();
|
||||
}
|
||||
await Zotero.Tags.purge(oldTagID);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'edit':
|
||||
for (let libraryID of editableLibraries) {
|
||||
let itemIDs = yield Zotero.Tags.getTagItems(libraryID, oldTagID);
|
||||
yield Zotero.DB.executeTransaction(async function () {
|
||||
for (let itemID of itemIDs) {
|
||||
let item = await Zotero.Items.getAsync(itemID);
|
||||
item.replaceTag(oldTag, dataOut.result.tag);
|
||||
await item.save();
|
||||
}
|
||||
});
|
||||
}
|
||||
yield Zotero.DB.executeTransaction(async function () {
|
||||
for (let itemID of itemIDs) {
|
||||
let item = await Zotero.Items.getAsync(itemID);
|
||||
item.replaceTag(oldTag, dataOut.result.tag);
|
||||
await item.save();
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
for (let libraryID of editableLibraries) {
|
||||
yield Zotero.Tags.removeFromLibrary(libraryID, oldTagID);
|
||||
}
|
||||
yield Zotero.Tags.removeFromLibrary(object.libraryID, oldTagID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1202,6 +1202,8 @@
|
|||
oncommand="ZoteroPane.tagSelector.openColorPickerWindow(); event.stopPropagation();"/>
|
||||
<menuitem label="&zotero.tagSelector.renameTag;"
|
||||
oncommand="ZoteroPane.tagSelector.openRenamePrompt(); event.stopPropagation();"/>
|
||||
<menuitem id="split-tag" label="&zotero.tagSelector.splitTag;"
|
||||
oncommand="ZoteroPane.tagSelector.openTagSplitterWindow(event)"/>
|
||||
<menuitem label="&zotero.tagSelector.deleteTag;"
|
||||
oncommand="ZoteroPane.tagSelector.openDeletePrompt(); event.stopPropagation();"/>
|
||||
</menupopup>
|
||||
|
|
|
@ -139,6 +139,7 @@
|
|||
<!ENTITY zotero.tagSelector.assignColor "Assign Color…">
|
||||
<!ENTITY zotero.tagSelector.renameTag "Rename Tag…">
|
||||
<!ENTITY zotero.tagSelector.deleteTag "Delete Tag…">
|
||||
<!ENTITY zotero.tagSelector.splitTag "Split…">
|
||||
|
||||
<!ENTITY zotero.tagColorChooser.title "Choose a Tag Color and Position">
|
||||
<!ENTITY zotero.tagColorChooser.color "Color:">
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#zotero-new-tag-characters[invalid="true"] {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#zotero-new-tag-character-count {
|
||||
font-weight: bold;
|
||||
margin-right: 0;
|
||||
}
|
|
@ -25,11 +25,14 @@
|
|||
@import "components/autosuggest";
|
||||
@import "components/button";
|
||||
@import "components/clicky";
|
||||
@import "components/collection-tree";
|
||||
@import "components/createParent";
|
||||
@import "components/dictionaryManager";
|
||||
@import "components/editable";
|
||||
@import "components/exportOptions";
|
||||
@import "components/icons";
|
||||
@import "components/item-tree";
|
||||
@import "components/longTagFixer";
|
||||
@import "components/mainWindow";
|
||||
@import "components/notesList";
|
||||
@import "components/progressMeter";
|
||||
|
@ -38,9 +41,7 @@
|
|||
@import "components/tabBar";
|
||||
@import "components/tagsBox";
|
||||
@import "components/tagSelector";
|
||||
@import "components/collection-tree";
|
||||
@import "components/virtualized-table";
|
||||
@import "components/item-tree";
|
||||
|
||||
// Elements
|
||||
// --------------------------------------------------
|
||||
|
|
|
@ -2,3 +2,8 @@
|
|||
// Utilities
|
||||
// --------------------------------------------------
|
||||
|
||||
@mixin text-truncate($text-overflow: ellipsis) {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: $text-overflow;
|
||||
}
|
112
scss/components/_longTagFixer.scss
Normal file
112
scss/components/_longTagFixer.scss
Normal file
|
@ -0,0 +1,112 @@
|
|||
#zotero-long-tag-fixer {
|
||||
min-width: 400px; // with intro disabled, dialog tends to get to narrow
|
||||
|
||||
tab {
|
||||
display: none;
|
||||
|
||||
@include variant("#zotero-long-tag-fixer.is-long-tag") {
|
||||
display: revert;
|
||||
}
|
||||
}
|
||||
|
||||
tabpanels {
|
||||
padding-top: 15px;
|
||||
|
||||
@include variant("#zotero-long-tag-fixer.is-long-tag") {
|
||||
padding-top: 33px;
|
||||
}
|
||||
}
|
||||
|
||||
tab[visuallyselected="true"]:not(:-moz-window-inactive) {
|
||||
color: unset;
|
||||
}
|
||||
|
||||
#intro {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
|
||||
@include variant("#zotero-long-tag-fixer.is-long-tag") {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
> label {
|
||||
margin: .5em 0 0 0;
|
||||
}
|
||||
|
||||
> textarea {
|
||||
margin: 1em;
|
||||
height: 50px;
|
||||
border: none;
|
||||
padding: .5em;
|
||||
background-color: $shade-1;
|
||||
appearance: none;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
#zotero-new-tag-actions {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.split-tab {
|
||||
.tag-list {
|
||||
height: calc(8 * (1em + 10px));
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
|
||||
> richlistitem {
|
||||
display: block;
|
||||
height: calc(1em + 10px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
// width of the label is set to the width of the viewport minus sum of widths of
|
||||
// paddings, margins and a checkbox to produce ellipsis truncation.
|
||||
width: calc(100vw - 100px);
|
||||
@include text-truncate;
|
||||
}
|
||||
}
|
||||
|
||||
.delimiter-input {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.delimiter-input-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tag-list + label {
|
||||
padding: 0.5em 0;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-tab {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
#zotero-new-tag-editor {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
#zotero-new-tag-characters {
|
||||
flex: 0 1 auto;
|
||||
padding: .5em 0;
|
||||
}
|
||||
}
|
||||
|
||||
.invalid {
|
||||
color: $red;
|
||||
}
|
||||
|
||||
#zotero-new-tag-character-count {
|
||||
font-weight: bold;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
|
@ -1321,7 +1321,7 @@ describe("Zotero.Sync.Runner", function () {
|
|||
}
|
||||
});
|
||||
|
||||
waitForDialog(null, 'accept', 'chrome://zotero/content/longTagFixer.xul');
|
||||
waitForDialog(null, 'accept', 'chrome://zotero/content/longTagFixer.xhtml');
|
||||
yield runner.sync({ libraries: [Zotero.Libraries.userLibraryID] });
|
||||
|
||||
assert.isFalse(Zotero.Tags.getID(tag));
|
||||
|
@ -1391,9 +1391,9 @@ describe("Zotero.Sync.Runner", function () {
|
|||
}
|
||||
});
|
||||
|
||||
waitForDialog(function (dialog) {
|
||||
dialog.Zotero_Long_Tag_Fixer.switchMode(2);
|
||||
}, 'accept', 'chrome://zotero/content/longTagFixer.xul');
|
||||
waitForDialog(function (window) {
|
||||
window.Zotero_Long_Tag_Fixer.switchMode(2);
|
||||
}, 'accept', 'chrome://zotero/content/longTagFixer.xhtml');
|
||||
yield runner.sync({ libraries: [Zotero.Libraries.userLibraryID] });
|
||||
|
||||
assert.isFalse(Zotero.Tags.getID(tag));
|
||||
|
|
Loading…
Reference in a new issue