Merge pull request #8 from 45Drives/dev-josh
Select multiple items and custom right click menu
This commit is contained in:
commit
c980930f26
10
README.md
10
README.md
|
@ -19,16 +19,16 @@ With no command line use needed, you can:
|
|||
# Installation
|
||||
## From Github Release
|
||||
### Ubuntu
|
||||
1. `$ wget https://github.com/45Drives/cockpit-navigator/releases/download/v0.1.0/cockpit-navigator_0.1.0-1focal_all.deb`
|
||||
1. `# apt install ./cockpit-navigator_0.1.0-1focal_all.deb`
|
||||
1. `$ wget https://github.com/45Drives/cockpit-navigator/releases/download/v0.2.0/cockpit-navigator_0.2.0-1focal_all.deb`
|
||||
1. `# apt install ./cockpit-navigator_0.2.0-1focal_all.deb`
|
||||
### EL7
|
||||
1. `# yum install https://github.com/45Drives/cockpit-navigator/releases/download/v0.1.0/cockpit-navigator-0.1.0-1.el7.noarch.rpm`
|
||||
1. `# yum install https://github.com/45Drives/cockpit-navigator/releases/download/v0.2.0/cockpit-navigator-0.2.0-1.el7.noarch.rpm`
|
||||
### EL8
|
||||
1. `# dnf install https://github.com/45Drives/cockpit-navigator/releases/download/v0.1.0/cockpit-navigator-0.1.0-1.el8.noarch.rpm`
|
||||
1. `# dnf install https://github.com/45Drives/cockpit-navigator/releases/download/v0.2.0/cockpit-navigator-0.2.0-1.el8.noarch.rpm`
|
||||
## From Source
|
||||
1. `$ git clone https://github.com/45Drives/cockpit-navigator.git`
|
||||
1. `$ cd cockpit-navigator`
|
||||
1. `$ git checkout <version>` (v0.1.0 is latest)
|
||||
1. `$ git checkout <version>` (v0.2.0 is latest)
|
||||
1. `# make install`
|
||||
## From 45Drives Repositories
|
||||
### Ubuntu
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
cockpit-navigator (0.2.0-1focal) focal; urgency=medium
|
||||
|
||||
* Allow for batch editing permissions and deletion by
|
||||
holding shift or control while clicking to select multiple
|
||||
entries.
|
||||
* Add custom right click menu.
|
||||
|
||||
-- Josh Boudreau <jboudreau@45drives.com> Tue, 01 Jun 2021 13:46:00 -0300
|
||||
|
||||
|
||||
cockpit-navigator (0.1.0-1focal) focal; urgency=medium
|
||||
|
||||
* Initial packaging of cockpit-navigator for Ubuntu Focal.
|
||||
|
||||
-- Josh Boudreau <jboudreau@45drives.com> Fri, 28 May 2021 3:58:00 -0300
|
||||
-- Josh Boudreau <jboudreau@45drives.com> Fri, 28 May 2021 15:58:00 -0300
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Name: cockpit-navigator
|
||||
Version: 0.1.0
|
||||
Version: 0.2.0
|
||||
Release: 1%{?dist}
|
||||
Summary: A File System Browser for Cockpit.
|
||||
License: GPL-3.0+
|
||||
|
@ -32,5 +32,10 @@ rm -rf %{buildroot}
|
|||
/usr/share/cockpit/navigator/*
|
||||
|
||||
%changelog
|
||||
* Tue Jun 01 2021 Josh Boudreau <jboudreau@45drives.com> 0.2.0-1
|
||||
- Allow for batch editing permissions and deletion by
|
||||
holding shift or control while clicking to select multiple
|
||||
entries.
|
||||
- Add custom right click menu.
|
||||
* Fri May 28 2021 Josh Boudreau <jboudreau@45drives.com> 0.1.0-1
|
||||
- First Build
|
||||
|
|
|
@ -127,6 +127,15 @@ body::-webkit-scrollbar-thumb {
|
|||
border: 3px solid var(--scrollbar-bg);
|
||||
}
|
||||
|
||||
.no-select {
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-khtml-user-select: none; /* Konqueror HTML */
|
||||
-moz-user-select: none; /* Old versions of Firefox */
|
||||
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||
user-select: none; /* Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox */
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
@ -153,7 +162,7 @@ body::-webkit-scrollbar-thumb {
|
|||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.spacer-stretchy {
|
||||
.flex-grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
|
@ -262,7 +271,6 @@ input[type="text"] {
|
|||
}
|
||||
|
||||
.nav-info-column-filename {
|
||||
flex: 1;
|
||||
margin: 0 12px 0 12px;
|
||||
font-weight: bolder;
|
||||
font-size: 150%;
|
||||
|
@ -318,6 +326,20 @@ input[type="text"] {
|
|||
padding-left: 50%;
|
||||
}
|
||||
|
||||
#selected-files-list-header {
|
||||
margin-left: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#selected-files-list {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.monospace-sm {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.nav-btn-group {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
|
@ -447,3 +469,19 @@ input:checked + .slider:before {
|
|||
top: -10%;
|
||||
left: -30%;
|
||||
}
|
||||
|
||||
.nav-context-menu {
|
||||
position: absolute;
|
||||
background-color: var(--container);
|
||||
border: 1px solid var(--border);
|
||||
color: var(--font);
|
||||
}
|
||||
|
||||
.nav-context-menu-item {
|
||||
padding: 0 12px 0 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nav-context-menu-item:hover {
|
||||
background-color: var(--border);
|
||||
}
|
||||
|
|
|
@ -77,8 +77,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="horizontal-spacer"></div>
|
||||
<div class="nav-info-column min-width-0" id="nav-info-column">
|
||||
<div id="nav-show-properties">
|
||||
<div class="nav-info-column min-width-0 flex-col" id="nav-info-column">
|
||||
<div class="flex-col flex-grow" id="nav-show-properties">
|
||||
<div class="flex-row space-between">
|
||||
<div class="nav-info-column-filename"></div>
|
||||
<div class="nav-btn-group">
|
||||
|
@ -89,7 +89,7 @@
|
|||
</div>
|
||||
<div class="nav-info-column-properties" id="nav-info-column-properties"></div>
|
||||
</div>
|
||||
<div class="nav-hidden" id="nav-edit-properties">
|
||||
<div class="nav-hidden flex-col flex-grow" id="nav-edit-properties">
|
||||
<div class="nav-info-column-filename"></div>
|
||||
<div class="nav-property-pair">
|
||||
<span class="nav-property-pair-key">Name</span>
|
||||
|
@ -134,6 +134,9 @@
|
|||
<input type="checkbox" class="mode-checkbox" id="other-exec"></input>
|
||||
</div>
|
||||
<div class="vertical-spacer"></div>
|
||||
<div id="selected-files-list-header"></div>
|
||||
<div class="flex-grow monospace-sm" id="selected-files-list"></div>
|
||||
<div class="vertical-spacer"></div>
|
||||
<div class="nav-btn-group">
|
||||
<button class="pf-c-button pf-m-danger" id="nav-cancel-edit-btn" title="Cancel"><i class="fas fa-times"></i></button>
|
||||
<div class="horizontal-spacer"></div>
|
||||
|
@ -144,13 +147,13 @@
|
|||
</div>
|
||||
<div class="flex-row nav-footer">
|
||||
<div>
|
||||
<span id="nav-num-dirs">-</span> Directories, <span id="nav-num-files">-</span> Files
|
||||
<span id="nav-num-dirs">-</span> Directories, <span id="nav-num-files">-</span> Files (<span id="nav-num-bytes">-</span>)
|
||||
</div>
|
||||
<div class="spacer-stretchy"></div>
|
||||
<div class="flex-grow"></div>
|
||||
<a href="https://45drives.com" target="_blank" title="Visit 45Drives.com">
|
||||
<img src="branding/logo-light.svg" id="logo-45d"><span class="logo-45">45</span><span class="logo-drives">Drives</span>
|
||||
</a>
|
||||
<div class="spacer-stretchy"></div>
|
||||
<div class="flex-grow"></div>
|
||||
<div class="nav-toggle">
|
||||
<div class="nav-btn-group">
|
||||
<i class="fas fa-low-vision" id="nav-show-hidden-icon"></i>
|
||||
|
@ -175,4 +178,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<div class="nav-context-menu flex-col" id="nav-context-menu" hidden>
|
||||
</div>
|
||||
</html>
|
||||
|
|
|
@ -156,12 +156,13 @@ class NavEntry {
|
|||
let icon = this.dom_element.nav_item_icon = document.createElement("i");
|
||||
icon.classList.add("nav-item-icon");
|
||||
let title = this.dom_element.nav_item_title = document.createElement("div");
|
||||
title.classList.add("nav-item-title");
|
||||
title.classList.add("nav-item-title", "no-select");
|
||||
title.innerText = this.filename();
|
||||
this.dom_element.appendChild(icon);
|
||||
this.dom_element.appendChild(title);
|
||||
this.stat = stat;
|
||||
this.dom_element.addEventListener("click", this);
|
||||
this.dom_element.addEventListener("contextmenu", this);
|
||||
this.is_hidden_file = this.filename().startsWith('.');
|
||||
this.dom_element.title = this.filename();
|
||||
}
|
||||
|
@ -173,8 +174,13 @@ class NavEntry {
|
|||
handleEvent(e) {
|
||||
switch (e.type) {
|
||||
case "click":
|
||||
this.show_properties();
|
||||
this.nav_window_ref.set_selected(this);
|
||||
this.nav_window_ref.set_selected(this, e.shiftKey, e.ctrlKey);
|
||||
this.context_menu_ref.hide();
|
||||
e.stopPropagation();
|
||||
break;
|
||||
case "contextmenu":
|
||||
this.context_menu_ref.show(e, this);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
break;
|
||||
}
|
||||
|
@ -256,8 +262,21 @@ class NavEntry {
|
|||
* @param {string} new_group
|
||||
*/
|
||||
async chown(new_owner, new_group) {
|
||||
if (!new_owner && !new_group)
|
||||
return;
|
||||
var cmd = "";
|
||||
var arg = "";
|
||||
if (new_group && !new_owner) {
|
||||
cmd = "chgrp";
|
||||
arg = new_group;
|
||||
} else {
|
||||
cmd = "chown";
|
||||
arg = new_owner;
|
||||
if (new_group)
|
||||
arg += ":" + new_group;
|
||||
}
|
||||
var proc = cockpit.spawn(
|
||||
["chown", [new_owner, new_group].join(":"), this.path_str()],
|
||||
[cmd, arg, this.path_str()],
|
||||
{superuser: "try", err: "out"}
|
||||
);
|
||||
proc.fail((e, data) => {
|
||||
|
@ -568,14 +587,6 @@ class NavDir extends NavEntry {
|
|||
break;
|
||||
}
|
||||
});
|
||||
children.sort((first, second) => {
|
||||
if (first.nav_type === second.nav_type) {
|
||||
return first.filename().localeCompare(second.filename());
|
||||
}
|
||||
if (first.nav_type === "dir")
|
||||
return -1;
|
||||
return 1;
|
||||
});
|
||||
return children;
|
||||
}
|
||||
|
||||
|
@ -689,24 +700,140 @@ class NavDirLink extends NavDir{
|
|||
}
|
||||
}
|
||||
|
||||
class NavContextMenu {
|
||||
/**
|
||||
*
|
||||
* @param {string} id
|
||||
*/
|
||||
constructor(id, nav_window_ref) {
|
||||
this.dom_element = document.getElementById(id);
|
||||
this.nav_window_ref = nav_window_ref;
|
||||
this.menu_options = {};
|
||||
window.addEventListener("click", (event) => {
|
||||
if (event.target !== this.dom_element)
|
||||
this.hide();
|
||||
});
|
||||
|
||||
var functions = ["paste", "new_dir", "new_file", "new_link", "properties", "copy", "move", "delete"];
|
||||
for (let func of functions) {
|
||||
var elem = document.createElement("div");
|
||||
var name_list = func.split("_");
|
||||
name_list.forEach((word, index) => {name_list[index] = word.charAt(0).toUpperCase() + word.slice(1)});
|
||||
elem.innerText = name_list.join(" ");
|
||||
elem.addEventListener("click", (e) => {this[func].bind(this).apply()});
|
||||
elem.classList.add("nav-context-menu-item")
|
||||
elem.id = "nav-context-menu-" + func;
|
||||
this.dom_element.appendChild(elem);
|
||||
this.menu_options[func] = elem;
|
||||
}
|
||||
this.menu_options["paste"].hidden = true;
|
||||
}
|
||||
|
||||
paste() {
|
||||
this.nav_window_ref.paste_clipboard();
|
||||
this.hide_paste();
|
||||
}
|
||||
|
||||
new_dir() {
|
||||
this.nav_window_ref.mkdir();
|
||||
}
|
||||
|
||||
new_file() {
|
||||
this.nav_window_ref.touch();
|
||||
}
|
||||
|
||||
new_link() {
|
||||
this.nav_window_ref.ln();
|
||||
}
|
||||
|
||||
properties() {
|
||||
this.nav_window_ref.show_edit_selected();
|
||||
this.hide();
|
||||
}
|
||||
|
||||
copy() {
|
||||
this.nav_window_ref.clip_board = [...this.nav_window_ref.selected_entries];
|
||||
this.menu_options["paste"].hidden = false;
|
||||
this.nav_window_ref.copy_or_move = "copy";
|
||||
}
|
||||
|
||||
move() {
|
||||
this.nav_window_ref.clip_board = [...this.nav_window_ref.selected_entries];
|
||||
this.menu_options["paste"].hidden = false;
|
||||
this.nav_window_ref.copy_or_move = "move";
|
||||
}
|
||||
|
||||
delete() {
|
||||
this.nav_window_ref.delete_selected();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {NavEntry} target
|
||||
*/
|
||||
show(event, target) {
|
||||
if (this.nav_window_ref.selected_entries.size > 1) {
|
||||
if (event.shiftKey || event.ctrlKey)
|
||||
this.nav_window_ref.set_selected(target, event.shiftKey, event.ctrlKey);
|
||||
} else {
|
||||
this.nav_window_ref.set_selected(target, false, false);
|
||||
}
|
||||
if (target === this.nav_window_ref.pwd()) {
|
||||
this.menu_options["copy"].hidden = true;
|
||||
this.menu_options["move"].hidden = true;
|
||||
this.menu_options["delete"].hidden = true;
|
||||
} else {
|
||||
this.menu_options["copy"].hidden = false;
|
||||
this.menu_options["move"].hidden = false;
|
||||
this.menu_options["delete"].hidden = false;
|
||||
}
|
||||
this.dom_element.hidden = false;
|
||||
this.dom_element.style.left = event.clientX + "px";
|
||||
this.dom_element.style.top = event.clientY + "px";
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.dom_element.hidden = true;
|
||||
}
|
||||
|
||||
hide_paste() {
|
||||
this.menu_options["paste"].hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
class NavWindow {
|
||||
constructor() {
|
||||
this.path_stack = (localStorage.getItem('navigator-path') ?? '/').split('/');
|
||||
this.path_stack = this.path_stack.map((_, index) => new NavDir([...this.path_stack.slice(0, index + 1)].filter(part => part != ''), this));
|
||||
|
||||
this.path_stack_index = this.path_stack.length - 1;
|
||||
this.selected_entry = this.pwd();
|
||||
this.selected_entries = new Set([this.pwd()]);
|
||||
this.entries = [];
|
||||
this.window = document.getElementById("nav-contents-view");
|
||||
this.window.addEventListener("click", this);
|
||||
this.window.addEventListener("contextmenu", this);
|
||||
this.last_selected_index = -1;
|
||||
|
||||
this.context_menu = new NavContextMenu("nav-context-menu", this);
|
||||
|
||||
this.clip_board = [];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Event} e
|
||||
*/
|
||||
handleEvent(e) {
|
||||
switch (e.type) {
|
||||
case "click":
|
||||
this.set_selected(this.pwd());
|
||||
this.clear_selected();
|
||||
this.show_selected_properties();
|
||||
break;
|
||||
case "contextmenu":
|
||||
this.context_menu.show(e, this.pwd());
|
||||
e.preventDefault();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -715,6 +842,7 @@ class NavWindow {
|
|||
|
||||
var num_dirs = 0;
|
||||
var num_files = 0;
|
||||
var bytes_sum = 0;
|
||||
var show_hidden = document.getElementById("nav-show-hidden").checked;
|
||||
this.start_load();
|
||||
var files = await this.pwd().get_children(this);
|
||||
|
@ -722,20 +850,32 @@ class NavWindow {
|
|||
var entry = this.entries.pop();
|
||||
entry.destroy();
|
||||
}
|
||||
files.sort((first, second) => {
|
||||
if (first.nav_type === second.nav_type) {
|
||||
return first.filename().localeCompare(second.filename());
|
||||
}
|
||||
if (first.nav_type === "dir")
|
||||
return -1;
|
||||
return 1;
|
||||
});
|
||||
files.forEach((file) => {
|
||||
if (file.nav_type === "dir")
|
||||
num_dirs++;
|
||||
else
|
||||
else {
|
||||
num_files++;
|
||||
bytes_sum += file.stat["size"];
|
||||
}
|
||||
if(!file.is_hidden_file || show_hidden)
|
||||
file.show();
|
||||
this.entries.push(file);
|
||||
file.context_menu_ref = this.context_menu;
|
||||
});
|
||||
document.getElementById("pwd").value = this.pwd().path_str();
|
||||
this.set_selected(this.pwd());
|
||||
this.set_selected(this.pwd(), false, false);
|
||||
this.show_selected_properties();
|
||||
document.getElementById("nav-num-dirs").innerText = num_dirs.toString();
|
||||
document.getElementById("nav-num-files").innerText = num_files.toString();
|
||||
document.getElementById("nav-num-bytes"). innerText = format_bytes(bytes_sum);
|
||||
this.stop_load();
|
||||
}
|
||||
|
||||
|
@ -775,29 +915,72 @@ class NavWindow {
|
|||
this.cd(new NavDir(this.pwd().parent_dir()));
|
||||
}
|
||||
|
||||
show_selected_properties() {
|
||||
this.selected_entry.show_properties();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {NavEntry} entry
|
||||
* @param {Boolean} select_range
|
||||
* @param {Boolean} append
|
||||
*/
|
||||
set_selected(entry) {
|
||||
set_selected(entry, select_range, append) {
|
||||
this.hide_edit_selected();
|
||||
this.selected_entry.dom_element.classList.remove("nav-item-selected");
|
||||
if (this.selected_entry.nav_type === "dir") {
|
||||
this.selected_entry.dom_element.nav_item_icon.classList.remove("fa-folder-open");
|
||||
this.selected_entry.dom_element.nav_item_icon.classList.add("fa-folder");
|
||||
for (let i of this.selected_entries) {
|
||||
i.dom_element.classList.remove("nav-item-selected");
|
||||
if (i.nav_type === "dir") {
|
||||
i.dom_element.nav_item_icon.classList.remove("fa-folder-open");
|
||||
i.dom_element.nav_item_icon.classList.add("fa-folder");
|
||||
}
|
||||
}
|
||||
this.selected_entry = entry;
|
||||
this.selected_entry.dom_element.classList.add("nav-item-selected");
|
||||
if (this.selected_entry.nav_type === "dir") {
|
||||
this.selected_entry.dom_element.nav_item_icon.classList.remove("fa-folder");
|
||||
this.selected_entry.dom_element.nav_item_icon.classList.add("fa-folder-open");
|
||||
var to_be_selected = [];
|
||||
if (append && this.selected_entries.has(entry)) {
|
||||
this.selected_entries.delete(entry);
|
||||
} else if (select_range && this.last_selected_index !== -1) {
|
||||
var start = this.last_selected_index;
|
||||
var end = this.entries.indexOf(entry);
|
||||
if (end < start)
|
||||
[start, end] = [end, start];
|
||||
if (end === -1)
|
||||
return;
|
||||
to_be_selected = this.entries.slice(start, end + 1);
|
||||
} else {
|
||||
if (!append)
|
||||
this.selected_entries.clear();
|
||||
to_be_selected = [entry];
|
||||
}
|
||||
for (let i of to_be_selected) {
|
||||
this.selected_entries.add(i);
|
||||
}
|
||||
for (let i of this.selected_entries) {
|
||||
i.dom_element.classList.add("nav-item-selected");
|
||||
if (i.nav_type === "dir") {
|
||||
i.dom_element.nav_item_icon.classList.remove("fa-folder");
|
||||
i.dom_element.nav_item_icon.classList.add("fa-folder-open");
|
||||
}
|
||||
}
|
||||
if (this.selected_entries.size > 1){
|
||||
var name_fields = document.getElementsByClassName("nav-info-column-filename");
|
||||
for (let name_field of name_fields) {
|
||||
name_field.innerText = this.selected_entries.size.toString() + " selected"
|
||||
name_field.title = name_field.innerText;
|
||||
}
|
||||
document.getElementById("nav-info-column-properties").innerHTML = "";
|
||||
} else {
|
||||
this.show_selected_properties();
|
||||
}
|
||||
this.last_selected_index = this.entries.indexOf(entry);
|
||||
}
|
||||
|
||||
clear_selected() {
|
||||
this.set_selected(this.pwd(), false, false);
|
||||
}
|
||||
|
||||
selected_entry() {
|
||||
return [...this.selected_entries][this.selected_entries.size - 1];
|
||||
}
|
||||
|
||||
show_selected_properties() {
|
||||
this.selected_entry().show_properties();
|
||||
}
|
||||
|
||||
show_edit_selected() {
|
||||
var dangerous_dirs = [
|
||||
"/",
|
||||
|
@ -814,25 +997,71 @@ class NavWindow {
|
|||
"/usr/lib64",
|
||||
"/usr/sbin",
|
||||
];
|
||||
if (dangerous_dirs.includes(this.selected_entry.path_str())) {
|
||||
if (
|
||||
!window.confirm(
|
||||
"Warning: editing `" +
|
||||
this.selected_entry.path_str() +
|
||||
"` can be dangerous. Are you sure?"
|
||||
)
|
||||
) {
|
||||
var dangerous_selected = [];
|
||||
for (let i of this.selected_entries) {
|
||||
var path = i.path_str();
|
||||
if (dangerous_dirs.includes(path)) {
|
||||
dangerous_selected.push(path);
|
||||
}
|
||||
}
|
||||
if (dangerous_selected.length > 0) {
|
||||
var dangerous_selected_str = "";
|
||||
if (dangerous_selected.length > 2) {
|
||||
var last = dangerous_selected.pop();
|
||||
dangerous_selected_str = dangerous_selected.join(", ");
|
||||
dangerous_selected_str += ", and " + last;
|
||||
} else if (dangerous_selected.length === 2) {
|
||||
dangerous_selected_str = dangerous_selected.join(" and ");
|
||||
} else {
|
||||
dangerous_selected_str = dangerous_selected[0];
|
||||
}
|
||||
if (!window.confirm(
|
||||
"Warning: editing " +
|
||||
dangerous_selected_str +
|
||||
" can be dangerous. Are you sure?"
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
} else if (this.selected_entries.size > 1) {
|
||||
if (!window.confirm(
|
||||
"Warning: are you sure you want to edit permissions for " +
|
||||
this.selected_entries.size +
|
||||
" files?"
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.selected_entry.populate_edit_fields();
|
||||
if (this.selected_entries.size === 1) {
|
||||
this.selected_entry().populate_edit_fields();
|
||||
document.getElementById("selected-files-list-header").innerText = "";
|
||||
document.getElementById("selected-files-list").innerText = "";
|
||||
document.getElementById("nav-edit-filename").disabled = false;
|
||||
} else {
|
||||
for (let field of ["owner", "group"]) {
|
||||
document.getElementById("nav-edit-" + field).value = "";
|
||||
}
|
||||
var filename = document.getElementById("nav-edit-filename");
|
||||
filename.value = "N/A";
|
||||
filename.disabled = true;
|
||||
for (let checkbox of document.getElementsByClassName("mode-checkbox")) {
|
||||
checkbox.checked = false;
|
||||
}
|
||||
var targets = [];
|
||||
for (let target of this.selected_entries) {
|
||||
targets.push(target.filename());
|
||||
}
|
||||
var targets_str = targets.join(", ");
|
||||
document.getElementById("selected-files-list-header").innerText = "Applying edits to:";
|
||||
document.getElementById("selected-files-list").innerText = targets_str;
|
||||
}
|
||||
this.update_permissions_preview();
|
||||
document.getElementById("nav-edit-properties").style.display = "block";
|
||||
this.changed_mode = false;
|
||||
document.getElementById("nav-edit-properties").style.display = "flex";
|
||||
document.getElementById("nav-show-properties").style.display = "none";
|
||||
}
|
||||
|
||||
hide_edit_selected() {
|
||||
document.getElementById("nav-show-properties").style.display = "block";
|
||||
document.getElementById("nav-show-properties").style.display = "flex";
|
||||
document.getElementById("nav-edit-properties").style.display = "none";
|
||||
}
|
||||
|
||||
|
@ -860,39 +1089,49 @@ class NavWindow {
|
|||
var text = format_permissions(new_perms);
|
||||
text += " (" + (new_perms & 0o777).toString(8) + ")";
|
||||
document.getElementById("nav-mode-preview").innerText = text;
|
||||
this.changed_mode = true;
|
||||
}
|
||||
|
||||
async apply_edit_selected() {
|
||||
// do mv last so the rest don't fail from not finding path
|
||||
var new_owner = document.getElementById("nav-edit-owner").value;
|
||||
var new_group = document.getElementById("nav-edit-group").value;
|
||||
if (
|
||||
new_owner !== this.selected_entry.stat["owner"] ||
|
||||
new_group !== this.selected_entry.stat["group"]
|
||||
) {
|
||||
await this.selected_entry.chown(new_owner, new_group).catch(/*ignore, caught in chown*/);
|
||||
}
|
||||
var new_perms = this.get_new_permissions();
|
||||
if ((new_perms & 0o777) !== (this.selected_entry.stat["mode"] & 0o777)) {
|
||||
await this.selected_entry.chmod(new_perms).catch(/*ignore, caught in chmod*/);
|
||||
|
||||
for (let entry of this.selected_entries) {
|
||||
if (
|
||||
new_owner !== entry.stat["owner"] ||
|
||||
new_group !== entry.stat["group"]
|
||||
) {
|
||||
await entry.chown(new_owner, new_group).catch(/*ignore, caught in chown*/);
|
||||
}
|
||||
if (this.changed_mode && (new_perms & 0o777) !== (entry.stat["mode"] & 0o777)) {
|
||||
await entry.chmod(new_perms).catch(/*ignore, caught in chmod*/);
|
||||
}
|
||||
}
|
||||
var new_name = document.getElementById("nav-edit-filename").value;
|
||||
if (new_name !== this.selected_entry.filename()) {
|
||||
await this.selected_entry.mv(new_name).catch(/*ignore, caught in mv*/);
|
||||
if (this.selected_entries.size === 1) {
|
||||
var new_name = document.getElementById("nav-edit-filename").value;
|
||||
if (new_name !== this.selected_entry().filename()) {
|
||||
await this.selected_entry().mv(new_name).catch(/*ignore, caught in mv*/);
|
||||
}
|
||||
}
|
||||
this.refresh();
|
||||
this.hide_edit_selected();
|
||||
}
|
||||
|
||||
async delete_selected() {
|
||||
if (
|
||||
!window.confirm(
|
||||
"Deleting `" + this.selected_entry.path_str() + "` cannot be undone. Are you sure?"
|
||||
)
|
||||
) {
|
||||
var prompt = "";
|
||||
if (this.selected_entries.size > 1) {
|
||||
prompt = "Deleting " + this.selected_entries.size + " files. This cannot be undone. Are you sure?";
|
||||
} else {
|
||||
prompt = "Deleting `" + this.selected_entry().path_str() + "` cannot be undone. Are you sure?";
|
||||
}
|
||||
if (!window.confirm(prompt)) {
|
||||
return;
|
||||
}
|
||||
await this.selected_entry.rm().catch(/*ignore, caught in rm*/);
|
||||
for (let target of this.selected_entries) {
|
||||
await target.rm().catch(/*ignore, caught in rm*/);
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
|
@ -957,6 +1196,36 @@ class NavWindow {
|
|||
this.refresh();
|
||||
}
|
||||
|
||||
async paste_clipboard() {
|
||||
this.context_menu.hide_paste();
|
||||
var cmd = [];
|
||||
var dest = this.pwd().path_str();
|
||||
switch (this.copy_or_move) {
|
||||
case "copy":
|
||||
cmd = ["cp", "-an"];
|
||||
break;
|
||||
case "move":
|
||||
cmd = ["mv", "-n"];
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
for (let item of this.clip_board) {
|
||||
cmd.push(item.path_str());
|
||||
}
|
||||
cmd.push(dest);
|
||||
console.log(cmd);
|
||||
var proc = cockpit.spawn(
|
||||
cmd,
|
||||
{superuser: "try", err: "out"}
|
||||
);
|
||||
proc.fail((e, data) => {
|
||||
window.alert(data);
|
||||
})
|
||||
await proc;
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Event} e
|
||||
|
|
Loading…
Reference in New Issue