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);
|
collections = Zotero.Collections.getByParent(libraryOrCollection.id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
collections = Zotero.Collections.getByLibrary(libraryOrCollection.id);
|
collections = Zotero.Collections.getByLibrary(libraryOrCollection.libraryID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no subcollections, place menuitem for target directly in containing men
|
// 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()) {
|
if (!this.canEditLibrary()) {
|
||||||
this.displayCannotEditLibraryMessage();
|
this.displayCannotEditLibraryMessage();
|
||||||
return;
|
return;
|
||||||
|
@ -1366,9 +1366,11 @@ var ZoteroPane = new function()
|
||||||
|
|
||||||
// Get a unique "Untitled" name for this level in the collection hierarchy
|
// Get a unique "Untitled" name for this level in the collection hierarchy
|
||||||
var collections;
|
var collections;
|
||||||
|
var parentCollectionID = null;
|
||||||
if (parentKey) {
|
if (parentKey) {
|
||||||
let parent = Zotero.Collections.getIDFromLibraryAndKey(libraryID, parentKey);
|
let parent = Zotero.Collections.getIDFromLibraryAndKey(libraryID, parentKey);
|
||||||
collections = Zotero.Collections.getByParent(parent);
|
collections = Zotero.Collections.getByParent(parent);
|
||||||
|
parentCollectionID = parent;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
collections = Zotero.Collections.getByLibrary(libraryID);
|
collections = Zotero.Collections.getByLibrary(libraryID);
|
||||||
|
@ -1379,25 +1381,24 @@ var ZoteroPane = new function()
|
||||||
collections.map(c => c.name).filter(n => n.startsWith(prefix))
|
collections.map(c => c.name).filter(n => n.startsWith(prefix))
|
||||||
);
|
);
|
||||||
|
|
||||||
var newName = { value: name };
|
var io = { name, libraryID, parentCollectionID };
|
||||||
var result = Services.prompt.prompt(window,
|
window.openDialog("chrome://zotero/content/newCollectionDialog.xhtml",
|
||||||
Zotero.getString('pane.collections.newCollection'),
|
"_blank", "chrome,modal,centerscreen,resizable=no", io);
|
||||||
Zotero.getString('pane.collections.name'), newName, "", {});
|
var dataOut = io.dataOut;
|
||||||
|
if (!dataOut) {
|
||||||
if (!result) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newName.value) {
|
if (!dataOut.name) {
|
||||||
newName.value = name;
|
dataOut.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection();
|
||||||
collection.libraryID = libraryID;
|
collection.libraryID = dataOut.libraryID;
|
||||||
collection.name = newName.value;
|
collection.name = dataOut.name;
|
||||||
collection.parentKey = parentKey;
|
collection.parentID = dataOut.parentCollectionID;
|
||||||
return collection.saveTx();
|
await collection.saveTx();
|
||||||
});
|
};
|
||||||
|
|
||||||
this.importFeedsFromOPML = async function (event) {
|
this.importFeedsFromOPML = async function (event) {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -4022,6 +4023,8 @@ var ZoteroPane = new function()
|
||||||
if (collection) {
|
if (collection) {
|
||||||
throw new Error('collection must be null if createNew is true');
|
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();
|
let id = await this.newCollection();
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -349,3 +349,9 @@ tagselector-search =
|
||||||
|
|
||||||
context-notes-search =
|
context-notes-search =
|
||||||
.placeholder = Search Notes
|
.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.title = Delete Search
|
||||||
pane.collections.deleteSearch = Are you sure you want to delete the selected 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.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.newSavedSeach = New Saved Search
|
||||||
pane.collections.savedSearchName = Enter a name for this saved search:
|
pane.collections.savedSearchName = Enter a name for this saved search:
|
||||||
pane.collections.rename = Rename collection:
|
pane.collections.rename = Rename collection:
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
@import "components/toolbarbutton";
|
@import "components/toolbarbutton";
|
||||||
@import "components/virtualized-table";
|
@import "components/virtualized-table";
|
||||||
@import "components/tabsMenu";
|
@import "components/tabsMenu";
|
||||||
|
@import "components/newCollectionDialog";
|
||||||
|
|
||||||
// Elements
|
// 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…
Add table
Add a link
Reference in a new issue