Implement new New Collection dialog with parent menu
This commit is contained in:
parent
5b1fd4b628
commit
d44b869420
8 changed files with 181 additions and 18 deletions
79
chrome/content/zotero/newCollectionDialog.js
Normal file
79
chrome/content/zotero/newCollectionDialog.js
Normal 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;
|
||||
}
|
||||
};
|
||||
|
67
chrome/content/zotero/newCollectionDialog.xhtml
Normal file
67
chrome/content/zotero/newCollectionDialog.xhtml
Normal 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>
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
@import "components/toolbarbutton";
|
||||
@import "components/virtualized-table";
|
||||
@import "components/tabsMenu";
|
||||
@import "components/newCollectionDialog";
|
||||
|
||||
// Elements
|
||||
// --------------------------------------------------
|
||||
|
|
9
scss/components/_newCollectionDialog.scss
Normal file
9
scss/components/_newCollectionDialog.scss
Normal file
|
@ -0,0 +1,9 @@
|
|||
:root#new-collection-dialog {
|
||||
dialog > vbox {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
menulist::part(icon) {
|
||||
margin-inline-end: 3px;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue