Implement new New Collection dialog with parent menu

This commit is contained in:
Abe Jellinek 2024-01-09 23:41:06 -05:00 committed by Dan Stillman
parent 5b1fd4b628
commit d44b869420
8 changed files with 181 additions and 18 deletions

View file

@ -0,0 +1,79 @@
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2024 Corporation for Digital Scholarship
Vienna, Virginia, USA
http://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 *****
*/
var Zotero_New_Collection_Dialog = {
_handleLoad() {
let io = window.arguments[0];
document.querySelector('#name').value = io.name;
document.addEventListener('dialogaccept', () => this._handleAccept());
this._libraryID = io.libraryID;
this._parentCollectionID = io.parentCollectionID;
this._updateMenu();
},
_handleAccept() {
window.arguments[0].dataOut = {
name: document.querySelector('#name').value,
libraryID: this._libraryID,
parentCollectionID: this._parentCollectionID
};
},
_updateMenu() {
let createInField = document.querySelector('#create-in');
let menupopup = createInField.firstElementChild;
// Fascinatingly, clearing the children of the menupopup isn't enough here.
// We have to completely recreate it or it will no longer be willing to open.
menupopup.replaceWith(menupopup = document.createXULElement('menupopup'));
let createdNode = Zotero.Utilities.Internal.createMenuForTarget(
Zotero.Libraries.get(this._libraryID),
menupopup,
this._parentCollectionID ? 'C' + this._parentCollectionID : 'L' + this._libraryID,
(event, libraryOrCollection) => {
this._libraryID = libraryOrCollection.libraryID;
if (libraryOrCollection.objectType === 'collection') {
this._parentCollectionID = libraryOrCollection.id;
}
else {
this._parentCollectionID = null;
}
this._updateMenu();
},
null
);
// If createMenuForTarget() built a submenu, replace it with its child menuitems
if (createdNode.menupopup) {
createdNode.replaceWith(...createdNode.menupopup.children);
}
let checkedItem = menupopup.querySelector('[checked="true"]');
createInField.setAttribute('label', checkedItem?.label || '');
createInField.image = checkedItem?.image;
}
};

View file

@ -0,0 +1,67 @@
<?xml version="1.0"?>
<!--
***** BEGIN LICENSE BLOCK *****
Copyright © 2020 Corporation for Digital Scholarship
Vienna, Virginia, USA
http://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 *****
-->
<?xml-stylesheet href="chrome://global/skin/"?>
<?xml-stylesheet href="chrome://zotero/skin/zotero.css" type="text/css"?>
<?xml-stylesheet href="chrome://zotero/skin/overlay.css" type="text/css"?>
<?xml-stylesheet href="chrome://zotero-platform/content/overlay.css"?>
<?xml-stylesheet href="chrome://zotero-platform/content/zotero.css"?>
<window
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
id="new-collection-dialog"
data-l10n-id="new-collection-dialog"
data-l10n-attrs="title"
width="250"
onload="Zotero_New_Collection_Dialog._handleLoad()"
>
<script src="include.js"/>
<script src="newCollectionDialog.js"/>
<linkset>
<html:link rel="localization" href="branding/brand.ftl"/>
<html:link rel="localization" href="zotero.ftl"/>
</linkset>
<dialog
buttons="cancel,accept"
data-l10n-id="new-collection-dialog"
data-l10n-attrs="buttonlabelaccept"
>
<vbox>
<label data-l10n-id="new-collection-name" control="name"/>
<html:input id="name"/>
</vbox>
<vbox>
<label data-l10n-id="new-collection-create-in" control="create-in"/>
<menulist id="create-in" native="true">
<menupopup/>
</menulist>
</vbox>
</dialog>
</window>

View file

@ -1675,7 +1675,7 @@ Zotero.Utilities.Internal = {
collections = Zotero.Collections.getByParent(libraryOrCollection.id);
}
else {
collections = Zotero.Collections.getByLibrary(libraryOrCollection.id);
collections = Zotero.Collections.getByLibrary(libraryOrCollection.libraryID);
}
// If no subcollections, place menuitem for target directly in containing men

View file

@ -1356,7 +1356,7 @@ var ZoteroPane = new function()
}
this.newCollection = Zotero.Promise.coroutine(function* (parentKey) {
this.newCollection = async function (parentKey = null) {
if (!this.canEditLibrary()) {
this.displayCannotEditLibraryMessage();
return;
@ -1366,9 +1366,11 @@ var ZoteroPane = new function()
// Get a unique "Untitled" name for this level in the collection hierarchy
var collections;
var parentCollectionID = null;
if (parentKey) {
let parent = Zotero.Collections.getIDFromLibraryAndKey(libraryID, parentKey);
collections = Zotero.Collections.getByParent(parent);
parentCollectionID = parent;
}
else {
collections = Zotero.Collections.getByLibrary(libraryID);
@ -1379,25 +1381,24 @@ var ZoteroPane = new function()
collections.map(c => c.name).filter(n => n.startsWith(prefix))
);
var newName = { value: name };
var result = Services.prompt.prompt(window,
Zotero.getString('pane.collections.newCollection'),
Zotero.getString('pane.collections.name'), newName, "", {});
if (!result) {
var io = { name, libraryID, parentCollectionID };
window.openDialog("chrome://zotero/content/newCollectionDialog.xhtml",
"_blank", "chrome,modal,centerscreen,resizable=no", io);
var dataOut = io.dataOut;
if (!dataOut) {
return;
}
if (!newName.value) {
newName.value = name;
if (!dataOut.name) {
dataOut.name = name;
}
var collection = new Zotero.Collection;
collection.libraryID = libraryID;
collection.name = newName.value;
collection.parentKey = parentKey;
return collection.saveTx();
});
var collection = new Zotero.Collection();
collection.libraryID = dataOut.libraryID;
collection.name = dataOut.name;
collection.parentID = dataOut.parentCollectionID;
await collection.saveTx();
};
this.importFeedsFromOPML = async function (event) {
while (true) {
@ -4022,6 +4023,8 @@ var ZoteroPane = new function()
if (collection) {
throw new Error('collection must be null if createNew is true');
}
// Only allow targets within the current library for now
// TODO: Come back to this once we support copying items between libraries from the Add to Collection menu
let id = await this.newCollection();
if (!id) {
return;

View file

@ -349,3 +349,9 @@ tagselector-search =
context-notes-search =
.placeholder = Search Notes
new-collection-dialog =
.title = New Collection
.buttonlabelaccept = Create Collection
new-collection-name = Name:
new-collection-create-in = Create in:

View file

@ -260,8 +260,6 @@ pane.feed.deleteWithItems = Are you sure you want to unsubscribe from this feed?
pane.collections.deleteSearch.title = Delete Search
pane.collections.deleteSearch = Are you sure you want to delete the selected search?
pane.collections.emptyTrash = Are you sure you want to permanently remove items in the Trash?
pane.collections.newCollection = New Collection
pane.collections.name = Enter a name for this collection:
pane.collections.newSavedSeach = New Saved Search
pane.collections.savedSearchName = Enter a name for this saved search:
pane.collections.rename = Rename collection:

View file

@ -51,6 +51,7 @@
@import "components/toolbarbutton";
@import "components/virtualized-table";
@import "components/tabsMenu";
@import "components/newCollectionDialog";
// Elements
// --------------------------------------------------

View file

@ -0,0 +1,9 @@
:root#new-collection-dialog {
dialog > vbox {
margin-bottom: 10px;
}
menulist::part(icon) {
margin-inline-end: 3px;
}
}