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:
Tom Najdek 2023-03-17 02:20:11 +01:00 committed by GitHub
parent b1595cdd1d
commit 13cc393840
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 406 additions and 251 deletions

View file

@ -642,6 +642,46 @@ Zotero.TagSelector = class TagSelectorContainer extends React.PureComponent {
await Zotero.Tags.setColor(this.libraryID, io.name, io.color, io.position); 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() { async openRenamePrompt() {
var promptService = Cc['@mozilla.org/embedcomp/prompt-service;1'] var promptService = Cc['@mozilla.org/embedcomp/prompt-service;1']
.getService(Ci.nsIPromptService); .getService(Ci.nsIPromptService);

View file

@ -1,191 +1,212 @@
/* /*
***** BEGIN LICENSE BLOCK ***** ***** BEGIN LICENSE BLOCK *****
Copyright © 2009 Center for History and New Media Copyright © 2022 Corporation for Digital Scholarship
George Mason University, Fairfax, Virginia, USA Vienna, Virginia, USA
http://zotero.org https://www.zotero.org
This file is part of Zotero. This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify 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 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 the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Zotero is distributed in the hope that it will be useful, Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>. along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK ***** ***** END LICENSE BLOCK *****
*/ */
const HTML_NS = 'http://www.w3.org/1999/xhtml';
var Zotero_Long_Tag_Fixer = new function () { var Zotero_Long_Tag_Fixer = new function () { // eslint-disable-line camelcase, no-unused-vars
var _oldTag = window.arguments[0]; const { oldTag, isLongTag } = window.arguments?.[0] ?? { isLongTag: true, oldTag: '' };
var _dataOut = window.arguments[1]; const dataOut = window.arguments?.[1] || {};
this.init = function () { this.init = function () {
document.getElementById('zotero-old-tag').value = _oldTag; const lastMode = Zotero.Prefs.get('lastLongTagMode') || 0;
document.getElementById('zotero-old-tag-delimiter').nextSibling.value = Zotero.getString('general.character.singular'); const delimiter = Zotero.Prefs.get('lastLongTagDelimiter');
var delimiter = Zotero.Prefs.get('lastLongTagDelimiter'); this.dialog = document.getElementById('zotero-long-tag-fixer');
document.getElementById('zotero-old-tag-delimiter').value = delimiter; this.intro = document.getElementById('intro');
this.tabs = document.getElementById('zotero-new-tag-actions');
var lastMode = Zotero.Prefs.get('lastLongTagMode'); this.oldTagInput = document.getElementById('zotero-old-tag');
if (!lastMode) { this.oldTag = document.getElementById('zotero-old-tag');
lastMode = 0; this.delimiterLabel = document.getElementById('delimiter-label');
} this.oldTagDelimiter = document.getElementById('zotero-old-tag-delimiter');
this.switchMode(lastMode); 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) { this.switchMode = function (index) {
var dialog = document.getElementById('zotero-long-tag-fixer'); this.tabs.selectedIndex = index;
let buttonLabel = "";
document.getElementById('zotero-new-tag-actions').selectedIndex = index;
switch (index) { switch (index) {
default:
case 0: case 0:
var buttonLabel = "saveTags"; buttonLabel = 'saveTags';
this.updateTagList(); this.updateTagList();
document.getElementById('zotero-old-tag-delimiter').select(); this.oldTagDelimiter.select();
break; break;
case 1: case 1:
var buttonLabel = "saveTag"; buttonLabel = 'saveTag';
document.getElementById('zotero-new-tag-editor').value = _oldTag; this.newTagInput.value = oldTag;
this.updateEditLength(_oldTag.length) this.updateEditLength(oldTag.length);
break; break;
case 2: case 2:
var buttonLabel = "deleteTag"; buttonLabel = 'deleteTag';
dialog.getButton('accept').disabled = false; this.dialog.getButton('accept').disabled = false;
break; 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(); window.sizeToContent();
Zotero.Prefs.set('lastLongTagMode', index); if (isLongTag) {
} Zotero.Prefs.set('lastLongTagMode', index);
}
};
/** /**
* Split tags and populate list * Split tags and populate list
*/ */
this.updateTagList = function () { this.updateTagList = function () {
var listbox = document.getElementById('zotero-new-tag-list'); let tags = [];
while (listbox.childNodes.length) {
listbox.removeChild(listbox.lastChild);
}
var delimiter = document.getElementById('zotero-old-tag-delimiter').value; const delimiter = document.getElementById('zotero-old-tag-delimiter').value;
if (delimiter) { if (delimiter) {
Zotero.Prefs.set('lastLongTagDelimiter', delimiter); Zotero.Prefs.set('lastLongTagDelimiter', delimiter);
var re = new RegExp("\\s*" + delimiter.replace(/([\.\-\[\]\(\)\?\*\+])/g, "\\$1") + "\\s*"); const re = new RegExp("\\s*" + delimiter.replace(/([\.\-\[\]\(\)\?\*\+])/g, "\\$1") + "\\s*");
var tags = _oldTag.split(re); 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) { if (!delimiter || tags.length < 2) {
acceptButton.disabled = true; acceptButton.disabled = true;
return; // return;
} }
else { else {
acceptButton.disabled = false; acceptButton.disabled = false;
} }
tags.sort(); tags.sort();
for (var i=0; i<tags.length; i++) {
if (i != 0 && tags[i] == tags[i-1]) { while (this.listbox.childNodes.length) {
continue; this.listbox.removeChild(this.listbox.lastChild);
}
if (!tags[i]) {
continue;
}
var li = listbox.appendItem(tags[i]);
li.setAttribute('type', 'checkbox');
li.setAttribute('checked', 'true');
} }
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(); 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 () { this.deselectAll = function () {
var lis = document.getElementById('zotero-new-tag-list').getElementsByTagName('listitem'); this.listbox.querySelectorAll('[type=checkbox]').forEach(checkbox => checkbox.checked = false);
for (var i=0; i<lis.length; i++) { };
lis[i].checked = false;
}
}
this.selectAll = function () { this.selectAll = function () {
var lis = document.getElementById('zotero-new-tag-list').getElementsByTagName('listitem'); this.listbox.querySelectorAll('[type=checkbox]').forEach(checkbox => checkbox.checked = true);
for (var i=0; i<lis.length; i++) { };
lis[i].checked = true;
}
}
this.updateEditLength = function (len) { this.updateEditLength = function (len) {
document.getElementById('zotero-new-tag-character-count').value = len; this.newTagCharacterCount.innerText = len;
var invalid = len == 0 || len > Zotero.Tags.MAX_SYNC_LENGTH; const invalid = len == 0 || len > Zotero.Tags.MAX_SYNC_LENGTH;
document.getElementById('zotero-new-tag-characters').setAttribute('invalid', invalid); this.zoteroNewTagInfo.classList.toggle('invalid', invalid);
document.getElementById('zotero-long-tag-fixer').getButton('accept').disabled = invalid; this.dialog.getButton('accept').disabled = invalid;
} };
this.cancel = function () { this.cancel = function () {
_dataOut.result = false; dataOut.result = false;
} };
this.save = function () { this.accept = function () {
try { try {
const result = {};
var result = {}; switch (this.tabs.selectedIndex) {
// Split
var index = document.getElementById('zotero-new-tag-actions').selectedIndex; case 0:
result.op = 'split';
switch (index) { result.tags = Array.from(this.listbox.querySelectorAll('[type=checkbox]'))
// Split .filter(c => c.checked)
case 0: .map(n => n.nextSibling.textContent);
// Get checked tags break;
var listbox = document.getElementById('zotero-new-tag-list'); // Edit
var len = listbox.childElementCount; case 1:
var newTags = []; result.op = 'edit';
for (var i=0; i<len; i++) { result.tag = this.newTagInput.value;
var li = listbox.childNodes[i]; break;
if (li.getAttribute('checked') == 'true') {
newTags.push(li.getAttribute('label'));
}
}
result.op = 'split'; // Delete
result.tags = newTags; case 2:
break; result.op = 'delete';
break;
// Edit }
case 1: dataOut.result = result;
result.op = 'edit';
result.tag = document.getElementById('zotero-new-tag-editor').value;
break;
// Delete
case 2:
result.op = 'delete';
break;
}
_dataOut.result = result;
} }
catch (e) { catch (e) {
Zotero.debug(e); Zotero.debug(e);
throw (e); throw (e);
} }
} };
} };

View 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>

View file

@ -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>

View file

@ -1214,62 +1214,54 @@ Zotero.Sync.Runner_Module = function (options = {}) {
.getService(Components.interfaces.nsIWindowMediator); .getService(Components.interfaces.nsIWindowMediator);
var lastWin = wm.getMostRecentWindow("navigator:browser"); var lastWin = wm.getMostRecentWindow("navigator:browser");
// Open long tag fixer for every long tag in every editable library we're syncing // Open long tag fixer for library we're syncing
var editableLibraries = options.libraries let oldTagIDs = yield Zotero.Tags.getLongTagsInLibrary(object.libraryID);
.filter(x => Zotero.Libraries.get(x).editable);
for (let libraryID of editableLibraries) { for (let oldTagID of oldTagIDs) {
let oldTagIDs = yield Zotero.Tags.getLongTagsInLibrary(libraryID); let oldTag = Zotero.Tags.getName(oldTagID);
for (let oldTagID of oldTagIDs) { let dataOut = { result: null };
let oldTag = Zotero.Tags.getName(oldTagID); lastWin.openDialog(
let dataOut = { result: null }; 'chrome://zotero/content/longTagFixer.xhtml',
lastWin.openDialog( '',
'chrome://zotero/content/longTagFixer.xul', 'chrome,modal,centerscreen',
'', { oldTag, isLongTag: true },
'chrome,modal,centerscreen', dataOut
oldTag, );
dataOut // If dialog was cancelled, stop
); if (!dataOut.result) {
// If dialog was cancelled, stop return;
if (!dataOut.result) { }
return; const itemIDs = yield Zotero.Tags.getTagItems(object.libraryID, oldTagID);
}
switch (dataOut.result.op) { switch (dataOut.result.op) {
case 'split': case 'split':
for (let libraryID of editableLibraries) { yield Zotero.DB.executeTransaction(async function () {
let itemIDs = yield Zotero.Tags.getTagItems(libraryID, oldTagID); for (let itemID of itemIDs) {
yield Zotero.DB.executeTransaction(async function () { let item = await Zotero.Items.getAsync(itemID);
for (let itemID of itemIDs) { let tagType = item.getTagType(oldTag);
let item = await Zotero.Items.getAsync(itemID); for (let tag of dataOut.result.tags) {
for (let tag of dataOut.result.tags) { item.addTag(tag, tagType);
item.addTag(tag);
}
item.removeTag(oldTag);
await item.save();
} }
await Zotero.Tags.purge(oldTagID); item.removeTag(oldTag);
}); await item.save();
} }
await Zotero.Tags.purge(oldTagID);
});
break; break;
case 'edit': case 'edit':
for (let libraryID of editableLibraries) { yield Zotero.DB.executeTransaction(async function () {
let itemIDs = yield Zotero.Tags.getTagItems(libraryID, oldTagID); for (let itemID of itemIDs) {
yield Zotero.DB.executeTransaction(async function () { let item = await Zotero.Items.getAsync(itemID);
for (let itemID of itemIDs) { item.replaceTag(oldTag, dataOut.result.tag);
let item = await Zotero.Items.getAsync(itemID); await item.save();
item.replaceTag(oldTag, dataOut.result.tag); }
await item.save(); });
}
});
}
break; break;
case 'delete': case 'delete':
for (let libraryID of editableLibraries) { yield Zotero.Tags.removeFromLibrary(object.libraryID, oldTagID);
yield Zotero.Tags.removeFromLibrary(libraryID, oldTagID);
}
break; break;
}
} }
} }

View file

@ -1202,6 +1202,8 @@
oncommand="ZoteroPane.tagSelector.openColorPickerWindow(); event.stopPropagation();"/> oncommand="ZoteroPane.tagSelector.openColorPickerWindow(); event.stopPropagation();"/>
<menuitem label="&zotero.tagSelector.renameTag;" <menuitem label="&zotero.tagSelector.renameTag;"
oncommand="ZoteroPane.tagSelector.openRenamePrompt(); event.stopPropagation();"/> oncommand="ZoteroPane.tagSelector.openRenamePrompt(); event.stopPropagation();"/>
<menuitem id="split-tag" label="&zotero.tagSelector.splitTag;"
oncommand="ZoteroPane.tagSelector.openTagSplitterWindow(event)"/>
<menuitem label="&zotero.tagSelector.deleteTag;" <menuitem label="&zotero.tagSelector.deleteTag;"
oncommand="ZoteroPane.tagSelector.openDeletePrompt(); event.stopPropagation();"/> oncommand="ZoteroPane.tagSelector.openDeletePrompt(); event.stopPropagation();"/>
</menupopup> </menupopup>

View file

@ -139,6 +139,7 @@
<!ENTITY zotero.tagSelector.assignColor "Assign Color…"> <!ENTITY zotero.tagSelector.assignColor "Assign Color…">
<!ENTITY zotero.tagSelector.renameTag "Rename Tag…"> <!ENTITY zotero.tagSelector.renameTag "Rename Tag…">
<!ENTITY zotero.tagSelector.deleteTag "Delete 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.title "Choose a Tag Color and Position">
<!ENTITY zotero.tagColorChooser.color "Color:"> <!ENTITY zotero.tagColorChooser.color "Color:">

View file

@ -1,8 +0,0 @@
#zotero-new-tag-characters[invalid="true"] {
color: red;
}
#zotero-new-tag-character-count {
font-weight: bold;
margin-right: 0;
}

View file

@ -25,11 +25,14 @@
@import "components/autosuggest"; @import "components/autosuggest";
@import "components/button"; @import "components/button";
@import "components/clicky"; @import "components/clicky";
@import "components/collection-tree";
@import "components/createParent"; @import "components/createParent";
@import "components/dictionaryManager"; @import "components/dictionaryManager";
@import "components/editable"; @import "components/editable";
@import "components/exportOptions"; @import "components/exportOptions";
@import "components/icons"; @import "components/icons";
@import "components/item-tree";
@import "components/longTagFixer";
@import "components/mainWindow"; @import "components/mainWindow";
@import "components/notesList"; @import "components/notesList";
@import "components/progressMeter"; @import "components/progressMeter";
@ -38,9 +41,7 @@
@import "components/tabBar"; @import "components/tabBar";
@import "components/tagsBox"; @import "components/tagsBox";
@import "components/tagSelector"; @import "components/tagSelector";
@import "components/collection-tree";
@import "components/virtualized-table"; @import "components/virtualized-table";
@import "components/item-tree";
// Elements // Elements
// -------------------------------------------------- // --------------------------------------------------

View file

@ -2,3 +2,8 @@
// Utilities // Utilities
// -------------------------------------------------- // --------------------------------------------------
@mixin text-truncate($text-overflow: ellipsis) {
white-space: nowrap;
overflow: hidden;
text-overflow: $text-overflow;
}

View 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;
}
}

View file

@ -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] }); yield runner.sync({ libraries: [Zotero.Libraries.userLibraryID] });
assert.isFalse(Zotero.Tags.getID(tag)); assert.isFalse(Zotero.Tags.getID(tag));
@ -1391,9 +1391,9 @@ describe("Zotero.Sync.Runner", function () {
} }
}); });
waitForDialog(function (dialog) { waitForDialog(function (window) {
dialog.Zotero_Long_Tag_Fixer.switchMode(2); window.Zotero_Long_Tag_Fixer.switchMode(2);
}, 'accept', 'chrome://zotero/content/longTagFixer.xul'); }, 'accept', 'chrome://zotero/content/longTagFixer.xhtml');
yield runner.sync({ libraries: [Zotero.Libraries.userLibraryID] }); yield runner.sync({ libraries: [Zotero.Libraries.userLibraryID] });
assert.isFalse(Zotero.Tags.getID(tag)); assert.isFalse(Zotero.Tags.getID(tag));