mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
change tree node icon for selected notes to quickly bring up bulk action dialog
This commit is contained in:
parent
1bfc5fb77f
commit
4aaa0f8d8c
@ -1,48 +0,0 @@
|
|||||||
import utils from "../services/utils.js";
|
|
||||||
import bulkActionService from "../services/bulk_action.js";
|
|
||||||
import froca from "../services/froca.js";
|
|
||||||
|
|
||||||
const $dialog = $("#bulk-assign-attributes-dialog");
|
|
||||||
const $availableActionList = $("#bulk-available-action-list");
|
|
||||||
const $existingActionList = $("#bulk-existing-action-list");
|
|
||||||
|
|
||||||
$dialog.on('click', '[data-action-add]', async event => {
|
|
||||||
const actionName = $(event.target).attr('data-action-add');
|
|
||||||
|
|
||||||
await bulkActionService.addAction('bulkaction', actionName);
|
|
||||||
|
|
||||||
await refresh();
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const actionGroup of bulkActionService.ACTION_GROUPS) {
|
|
||||||
const $actionGroupList = $("<td>");
|
|
||||||
const $actionGroup = $("<tr>")
|
|
||||||
.append($("<td>").text(actionGroup.title + ": "))
|
|
||||||
.append($actionGroupList);
|
|
||||||
|
|
||||||
for (const action of actionGroup.actions) {
|
|
||||||
$actionGroupList.append(
|
|
||||||
$('<button class="btn btn-sm">')
|
|
||||||
.attr('data-action-add', action.actionName)
|
|
||||||
.text(action.actionTitle)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$availableActionList.append($actionGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function refresh() {
|
|
||||||
const bulkActionNote = await froca.getNote('bulkaction');
|
|
||||||
|
|
||||||
const actions = bulkActionService.parseActions(bulkActionNote);
|
|
||||||
|
|
||||||
$existingActionList
|
|
||||||
.empty()
|
|
||||||
.append(...actions.map(action => action.render()));
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function showDialog(nodes) {
|
|
||||||
await refresh();
|
|
||||||
|
|
||||||
utils.openDialog($dialog);
|
|
||||||
}
|
|
@ -91,7 +91,7 @@ class TreeContextMenu {
|
|||||||
enabled: notSearch && noSelectedNotes },
|
enabled: notSearch && noSelectedNotes },
|
||||||
{ title: "Import into note", command: "importIntoNote", uiIcon: "bx bx-empty",
|
{ title: "Import into note", command: "importIntoNote", uiIcon: "bx bx-empty",
|
||||||
enabled: notSearch && noSelectedNotes },
|
enabled: notSearch && noSelectedNotes },
|
||||||
{ title: "Bulk actions", command: "bulkActions", uiIcon: "bx bx-empty",
|
{ title: "Apply bulk actions", command: "openBulkActionsDialog", uiIcon: "bx bx-list-plus",
|
||||||
enabled: true }
|
enabled: true }
|
||||||
].filter(row => row !== null);
|
].filter(row => row !== null);
|
||||||
}
|
}
|
||||||
@ -130,16 +130,11 @@ class TreeContextMenu {
|
|||||||
this.treeWidget.triggerCommand("openNewNoteSplit", {ntxId, notePath});
|
this.treeWidget.triggerCommand("openNewNoteSplit", {ntxId, notePath});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const selectedOrActiveBranchIds = this.treeWidget.getSelectedOrActiveBranchIds(this.node);
|
|
||||||
const selectedOrActiveNoteIds = selectedOrActiveBranchIds
|
|
||||||
.map(branchId => froca.getBranch(branchId).noteId)
|
|
||||||
.filter(noteId => !!noteId);
|
|
||||||
|
|
||||||
this.treeWidget.triggerCommand(command, {
|
this.treeWidget.triggerCommand(command, {
|
||||||
node: this.node,
|
node: this.node,
|
||||||
notePath: notePath,
|
notePath: notePath,
|
||||||
selectedOrActiveBranchIds,
|
selectedOrActiveBranchIds: this.treeWidget.getSelectedOrActiveBranchIds(this.node),
|
||||||
selectedOrActiveNoteIds
|
selectedOrActiveNoteIds: this.treeWidget.getSelectedOrActiveNoteIds(this.node)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ const TPL = `
|
|||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<label class="form-check-label">
|
<label class="form-check-label">
|
||||||
<input class="include-descendants form-check-input" type="checkbox" value="">
|
<input class="include-descendants form-check-input" type="checkbox" value="">
|
||||||
Include descendant notes
|
Include descendants of the selected notes
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ export default class BulkActionsDialog extends BasicWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async bulkActionsEvent({selectedOrActiveNoteIds}) {
|
async openBulkActionsDialogEvent({selectedOrActiveNoteIds}) {
|
||||||
this.selectedOrActiveNoteIds = selectedOrActiveNoteIds;
|
this.selectedOrActiveNoteIds = selectedOrActiveNoteIds;
|
||||||
this.$includeDescendants.prop("checked", false);
|
this.$includeDescendants.prop("checked", false);
|
||||||
|
|
||||||
|
@ -307,7 +307,14 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
const targetType = data.targetType;
|
const targetType = data.targetType;
|
||||||
const node = data.node;
|
const node = data.node;
|
||||||
|
|
||||||
if (targetType === 'title' || targetType === 'icon') {
|
if (node.isSelected() && targetType === 'icon') {
|
||||||
|
this.triggerCommand('openBulkActionsDialog', {
|
||||||
|
selectedOrActiveNoteIds: this.getSelectedOrActiveNoteIds(node)
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (targetType === 'title' || targetType === 'icon') {
|
||||||
if (event.shiftKey) {
|
if (event.shiftKey) {
|
||||||
const activeNode = this.getActiveNode();
|
const activeNode = this.getActiveNode();
|
||||||
|
|
||||||
@ -540,8 +547,9 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
select: () => {
|
select: (event, {node}) => {
|
||||||
// TODO
|
$(node.span).find(".fancytree-custom-icon").attr("title",
|
||||||
|
node.isSelected() ? "Apply bulk actions on selected notes" : "");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1288,6 +1296,15 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
return nodes.map(node => node.data.branchId);
|
return nodes.map(node => node.data.branchId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {FancytreeNode} node
|
||||||
|
*/
|
||||||
|
getSelectedOrActiveNoteIds(node) {
|
||||||
|
const nodes = this.getSelectedOrActiveNodes(node);
|
||||||
|
|
||||||
|
return nodes.map(node => node.data.noteId);
|
||||||
|
}
|
||||||
|
|
||||||
async deleteNotesCommand({node}) {
|
async deleteNotesCommand({node}) {
|
||||||
const branchIds = this.getSelectedOrActiveBranchIds(node)
|
const branchIds = this.getSelectedOrActiveBranchIds(node)
|
||||||
.filter(branchId => !branchId.startsWith('virt-')); // search results can't be deleted
|
.filter(branchId => !branchId.startsWith('virt-')); // search results can't be deleted
|
||||||
|
@ -179,6 +179,12 @@ span.fancytree-selected .fancytree-title {
|
|||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.fancytree-selected .fancytree-custom-icon::before {
|
||||||
|
content: "\eb43";
|
||||||
|
border: 1px solid var(--main-border-color);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
span.fancytree-node:hover {
|
span.fancytree-node:hover {
|
||||||
border: 1px solid var(--main-border-color);
|
border: 1px solid var(--main-border-color);
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@
|
|||||||
<%- include('dialogs/sort_child_notes.ejs') %>
|
<%- include('dialogs/sort_child_notes.ejs') %>
|
||||||
<%- include('dialogs/delete_notes.ejs') %>
|
<%- include('dialogs/delete_notes.ejs') %>
|
||||||
<%- include('dialogs/password_not_set.ejs') %>
|
<%- include('dialogs/password_not_set.ejs') %>
|
||||||
<%- include('dialogs/bulk_assign_attributes.ejs') %>
|
|
||||||
<%- include('dialogs/note_type_chooser.ejs') %>
|
<%- include('dialogs/note_type_chooser.ejs') %>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
<style>
|
|
||||||
#bulk-assign-attributes-dialog .modal-body h4:not(:first-child) {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bulk-available-action-list button {
|
|
||||||
padding: 2px 7px;
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bulk-existing-action-list {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bulk-existing-action-list td {
|
|
||||||
padding: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bulk-existing-action-list .button-column {
|
|
||||||
/* minimal width so that table remains static sized and most space remains for middle column with settings */
|
|
||||||
width: 50px;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div id="bulk-assign-attributes-dialog" class="modal mx-auto" tabindex="-1" role="dialog">
|
|
||||||
<div class="modal-dialog modal-xl" role="document">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title mr-auto">Bulk assign attributes</h5>
|
|
||||||
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" style="margin-left: 0 !important;">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<h4>Affected notes: <span id="affected-note-count">0</span></h4>
|
|
||||||
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" value="" id="include-descendants">
|
|
||||||
<label class="form-check-label" for="include-descendants">
|
|
||||||
Include descendant notes
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h4>Available actions</h4>
|
|
||||||
|
|
||||||
<table id="bulk-available-action-list"></table>
|
|
||||||
|
|
||||||
<h4>Chosen actions</h4>
|
|
||||||
|
|
||||||
<table id="bulk-existing-action-list"></table>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-primary">Execute bulk actions</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
Loading…
x
Reference in New Issue
Block a user