2021-07-15 19:45:42 +02:00
|
|
|
/*
|
|
|
|
Cockpit Navigator - A File System Browser for Cockpit.
|
|
|
|
Copyright (C) 2021 Josh Boudreau <jboudreau@45drives.com>
|
|
|
|
Copyright (C) 2021 Sam Silver <ssilver@45drives.com>
|
|
|
|
Copyright (C) 2021 Dawson Della Valle <ddellavalle@45drives.com>
|
|
|
|
|
|
|
|
This file is part of Cockpit Navigator.
|
|
|
|
Cockpit Navigator is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
Cockpit Navigator 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Cockpit Navigator. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2021-07-14 18:12:09 +02:00
|
|
|
import {NavEntry} from "./NavEntry.js";
|
|
|
|
import {NavDownloader} from "./NavDownloader.js";
|
|
|
|
import {NavWindow} from "./NavWindow.js";
|
|
|
|
import {property_entry_html} from "../functions.js";
|
|
|
|
|
|
|
|
export class NavFile extends NavEntry {
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {string|string[]} path
|
|
|
|
* @param {object} stat
|
|
|
|
* @param {NavWindow} nav_window_ref
|
|
|
|
*/
|
|
|
|
constructor(path, stat, nav_window_ref) {
|
|
|
|
super(path, stat, nav_window_ref);
|
|
|
|
this.nav_type = "file";
|
|
|
|
this.dom_element.nav_item_icon.classList.add("fas", "fa-file");
|
|
|
|
this.double_click = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {Event} e
|
|
|
|
*/
|
|
|
|
handleEvent(e) {
|
|
|
|
switch(e.type){
|
|
|
|
case "click":
|
2021-07-19 17:17:11 +02:00
|
|
|
if (this.double_click) {
|
2021-07-14 18:12:09 +02:00
|
|
|
this.open();
|
2021-07-19 17:17:11 +02:00
|
|
|
return;
|
|
|
|
} else { // single click
|
2021-07-14 18:12:09 +02:00
|
|
|
this.double_click = true;
|
|
|
|
if(this.timeout)
|
|
|
|
clearTimeout(this.timeout)
|
|
|
|
this.timeout = setTimeout(() => {
|
|
|
|
this.double_click = false;
|
|
|
|
}, 500);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "keydown":
|
|
|
|
if (e.keyCode === 83 && e.ctrlKey === true) {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
this.write_to_file();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
super.handleEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
*/
|
|
|
|
rm() {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
var proc = cockpit.spawn(
|
|
|
|
["rm", "-f", this.path_str()],
|
|
|
|
{superuser: "try", err: "out"}
|
|
|
|
);
|
|
|
|
proc.done((data) => {
|
|
|
|
resolve();
|
|
|
|
});
|
|
|
|
proc.fail((e, data) => {
|
|
|
|
reject(data);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async open() {
|
|
|
|
var proc_output = await cockpit.spawn(["file", "--mime-type", this.path_str()], {superuser: "try"});
|
|
|
|
var fields = proc_output.split(/:(?=[^:]+$)/); // ensure it's the last : with lookahead
|
|
|
|
var type = fields[1].trim();
|
|
|
|
|
|
|
|
if ((/^text/.test(type) || /^inode\/x-empty$/.test(type) || this.stat["size"] === 0)) {
|
|
|
|
this.show_edit_file_contents();
|
|
|
|
} else {
|
|
|
|
console.log("Unknown mimetype: " + type);
|
2021-07-19 19:36:49 +02:00
|
|
|
if (await this.nav_window_ref.modal_prompt.confirm("Can't open " + this.filename + " for editing.", "Download it instead?")) {
|
2021-07-14 18:12:09 +02:00
|
|
|
var download = new NavDownloader(this);
|
|
|
|
download.download();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async show_edit_file_contents() {
|
|
|
|
window.removeEventListener("keydown", this.nav_window_ref);
|
|
|
|
this.nav_window_ref.disable_buttons_for_editing();
|
|
|
|
var contents = "";
|
|
|
|
try {
|
|
|
|
contents = await cockpit.file(this.path_str(), {superuser: "try"}).read();
|
|
|
|
} catch (e) {
|
|
|
|
this.nav_window_ref.enable_buttons();
|
2021-07-14 19:57:58 +02:00
|
|
|
this.nav_window_ref.modal_prompt.alert(e.message);
|
2021-07-14 18:12:09 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
var text_area = document.getElementById("nav-edit-contents-textarea");
|
|
|
|
text_area.value = contents;
|
|
|
|
text_area.addEventListener("keydown", this);
|
|
|
|
document.getElementById("nav-cancel-edit-contents-btn").onclick = this.hide_edit_file_contents.bind(this);
|
|
|
|
document.getElementById("nav-continue-edit-contents-btn").onclick = this.write_to_file.bind(this);
|
|
|
|
document.getElementById("nav-edit-contents-header").innerText = "Editing " + this.path_str();
|
|
|
|
document.getElementById("nav-contents-view").style.display = "none";
|
|
|
|
document.getElementById("nav-edit-contents-view").style.display = "flex";
|
|
|
|
}
|
|
|
|
|
|
|
|
async write_to_file() {
|
|
|
|
var new_contents = document.getElementById("nav-edit-contents-textarea").value;
|
|
|
|
try {
|
|
|
|
if (new_contents.length)
|
|
|
|
await cockpit.file(this.path_str(), {superuser: "try"}).replace(new_contents);
|
|
|
|
else
|
|
|
|
await cockpit.script("echo -n > $1", [this.path_str()], {superuser: "try"});
|
|
|
|
} catch (e) {
|
2021-07-14 19:57:58 +02:00
|
|
|
this.nav_window_ref.modal_prompt.alert(e.message);
|
2021-07-14 18:12:09 +02:00
|
|
|
}
|
|
|
|
this.nav_window_ref.refresh();
|
|
|
|
this.hide_edit_file_contents();
|
|
|
|
}
|
|
|
|
|
|
|
|
hide_edit_file_contents() {
|
|
|
|
window.addEventListener("keydown", this.nav_window_ref);
|
|
|
|
document.getElementById("nav-edit-contents-textarea").removeEventListener("keydown", this);
|
|
|
|
document.getElementById("nav-edit-contents-view").style.display = "none";
|
|
|
|
document.getElementById("nav-contents-view").style.display = "flex";
|
|
|
|
this.nav_window_ref.enable_buttons();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class NavFileLink extends NavFile{
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {string} path
|
|
|
|
* @param {object} stat
|
|
|
|
* @param {NavWindow} nav_window_ref
|
|
|
|
* @param {string} link_target
|
|
|
|
*/
|
|
|
|
constructor(path, stat, nav_window_ref, link_target) {
|
|
|
|
super(path, stat, nav_window_ref);
|
|
|
|
var link_icon = this.dom_element.nav_item_icon.link_icon = document.createElement("i");
|
|
|
|
link_icon.classList.add("fas", "fa-link", "nav-item-symlink-symbol-file");
|
|
|
|
this.dom_element.nav_item_icon.appendChild(link_icon);
|
|
|
|
this.double_click = false;
|
|
|
|
this.link_target = link_target;
|
|
|
|
this.dom_element.nav_item_title.style.fontStyle = "italic";
|
|
|
|
if (nav_window_ref.item_display === "list")
|
|
|
|
this.dom_element.nav_item_title.innerHTML += " → " + this.link_target;
|
|
|
|
}
|
|
|
|
|
|
|
|
show_properties() {
|
|
|
|
var extra_properties = property_entry_html("Link Target", this.link_target);
|
|
|
|
super.show_properties(extra_properties);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
get_link_target_path() {
|
|
|
|
var target = "";
|
|
|
|
if (this.link_target.charAt(0) === '/')
|
|
|
|
target = this.link_target;
|
|
|
|
else
|
|
|
|
target = this.parent_dir().join("/") + "/" + this.link_target;
|
|
|
|
if (target.charAt(0) !== '/')
|
|
|
|
target = '/' + target;
|
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
|
|
|
async open() {
|
|
|
|
var target_path = this.get_link_target_path();
|
|
|
|
var proc_output = await cockpit.spawn(["file", "--mime-type", target_path], {superuser: "try"});
|
|
|
|
var fields = proc_output.split(/:(?=[^:]+$)/); // ensure it's the last : with lookahead
|
|
|
|
var type = fields[1].trim();
|
|
|
|
|
|
|
|
if ((/^text/.test(type) || /^inode\/x-empty$/.test(type) || this.stat["size"] === 0)) {
|
|
|
|
this.show_edit_file_contents();
|
|
|
|
} else {
|
|
|
|
console.log("Unknown mimetype: " + type);
|
2021-07-19 19:36:49 +02:00
|
|
|
this.nav_window_ref.modal_prompt.alert("Can't open " + this.filename + " for editing.");
|
2021-07-14 18:12:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async show_edit_file_contents() {
|
|
|
|
window.removeEventListener("keydown", this.nav_window_ref);
|
|
|
|
this.nav_window_ref.disable_buttons_for_editing();
|
|
|
|
document.getElementById("pwd").disabled = true;
|
|
|
|
var target_path = this.get_link_target_path();
|
|
|
|
var contents = "";
|
|
|
|
try {
|
|
|
|
contents = await cockpit.file(target_path, {superuser: "try"}).read();
|
|
|
|
} catch(e) {
|
|
|
|
this.nav_window_ref.enable_buttons();
|
2021-07-14 19:57:58 +02:00
|
|
|
this.nav_window_ref.modal_prompt.alert(e.message);
|
2021-07-14 18:12:09 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
var text_area = document.getElementById("nav-edit-contents-textarea");
|
|
|
|
text_area.value = contents;
|
|
|
|
text_area.addEventListener("keydown", this);
|
|
|
|
document.getElementById("nav-cancel-edit-contents-btn").onclick = this.hide_edit_file_contents.bind(this);
|
|
|
|
document.getElementById("nav-continue-edit-contents-btn").onclick = this.write_to_file.bind(this);
|
|
|
|
document.getElementById("nav-edit-contents-header").innerHTML = "Editing " + this.path_str() + ' <i class="fas fa-long-arrow-alt-right"></i> ' + this.get_link_target_path();
|
|
|
|
document.getElementById("nav-contents-view").style.display = "none";
|
|
|
|
document.getElementById("nav-edit-contents-view").style.display = "flex";
|
|
|
|
}
|
|
|
|
|
|
|
|
async write_to_file() {
|
|
|
|
var target_path = this.get_link_target_path();
|
|
|
|
var new_contents = document.getElementById("nav-edit-contents-textarea").value;
|
|
|
|
try {
|
|
|
|
await cockpit.file(target_path, {superuser: "try"}).replace(new_contents);
|
|
|
|
} catch (e) {
|
2021-07-14 19:57:58 +02:00
|
|
|
this.nav_window_ref.modal_prompt.alert(e.message);
|
2021-07-14 18:12:09 +02:00
|
|
|
}
|
|
|
|
this.nav_window_ref.refresh();
|
|
|
|
this.hide_edit_file_contents();
|
|
|
|
}
|
|
|
|
}
|