var remote_home_dir;
var svg_add_folder = ;
var svg_trash = ;
var svg_arrow = ;
var svg_home = ;
var svg_refresh = ;
var svg_cancel = ;
var svg_computer = ;
function getSize(type, size) {
if (!size) {
if (type <= 3) return "";
return "0B";
}
size = size.toFloat();
var toFixed = function(size) {
size = (size * 100).toInteger();
var a = (size / 100).toInteger();
if (size % 100 == 0) return a;
if (size % 10 == 0) return a + '.' + (size % 10);
var b = size % 100;
if (b < 10) b = '0' + b;
return a + '.' + b;
}
if (size < 1024) return size.toInteger() + "B";
if (size < 1024 * 1024) return toFixed(size / 1024) + "K";
if (size < 1024 * 1024 * 1024) return toFixed(size / (1024 * 1024)) + "M";
return toFixed(size / (1024 * 1024 * 1024)) + "G";
}
function getParentPath(is_remote, path) {
var sep = handler.get_path_sep(is_remote);
var res = path.lastIndexOf(sep);
if (res <= 0) return "/";
return path.substr(0, res);
}
function getFileName(is_remote, path) {
var sep = handler.get_path_sep(is_remote);
var res = path.lastIndexOf(sep);
return path.substr(res + 1);
}
function getExt(name) {
if (name.indexOf(".") == 0) {
return "";
}
var i = name.lastIndexOf(".");
if (i > 0) return name.substr(i + 1);
return "";
}
var jobIdCounter = 1;
class JobTable: Reactor.Component {
this var jobs = [];
this var job_map = {};
function render() {
var me = this;
var rows = this.jobs.map(function(job, i) { return me.renderRow(job, i); });
return ;
}
event click $(svg.cancel) (_, me) {
var job = this.jobs[me.parent.parent.index];
var id = job.id;
handler.cancel_job(id);
delete this.job_map[id];
var i = -1;
this.jobs.map(function(job, idx) {
if (job.id == id) i = idx;
});
this.jobs.splice(i, 1);
this.update();
var is_remote = job.is_remote;
if (job.type != "del-dir") is_remote = !is_remote;
refreshDir(is_remote);
}
function send(path, is_remote) {
var to;
var show_hidden;
if (is_remote) {
to = file_transfer.local_folder_view.fd.path;
show_hidden = file_transfer.remote_folder_view.show_hidden;
} else {
to = file_transfer.remote_folder_view.fd.path;
show_hidden = file_transfer.local_folder_view.show_hidden;
}
if (!to) return;
to += handler.get_path_sep(!is_remote) + getFileName(is_remote, path);
var id = jobIdCounter;
jobIdCounter += 1;
this.jobs.push({ type: "transfer",
id: id, path: path, to: to,
include_hidden: show_hidden,
is_remote: is_remote });
this.job_map[id] = this.jobs[this.jobs.length - 1];
handler.send_files(id, path, to, show_hidden, is_remote);
this.update();
}
function addDelDir(path, is_remote) {
var id = jobIdCounter;
jobIdCounter += 1;
this.jobs.push({ type: "del-dir", id: id, path: path, is_remote: is_remote });
this.job_map[id] = this.jobs[this.jobs.length - 1];
handler.remove_dir_all(id, path, is_remote);
this.update();
}
function getSvg(job) {
if (job.type == "transfer") {
return svg_send;
} else if (job.type == "del-dir") {
return svg_trash;
}
}
function getStatus(job) {
if (!job.entries) return "Waiting";
var i = job.file_num + 1;
var n = job.num_entries || job.entries.length;
if (i > n) i = n;
var res = i + ' / ' + n + " files";
if (job.total_size > 0) res += ", " + getSize(0, job.finished_size) + ' / ' + getSize(0, job.total_size);
// below has problem if some file skipped
var percent = (100. * job.finished_size / job.total_size).toInteger(); // (100. * i / (n || 1)).toInteger();
if (job.finished) percent = '100';
res += ", " + percent + "%";
if (job.finished) res = "Finished " + res;
if (job.speed) res += ", " + getSize(0, job.speed) + "/s";
return res;
}
function updateJob(job) {
var el = this.select("div[id=s" + job.id + "]");
if (el) el.text = this.getStatus(job);
}
function updateJobStatus(id, file_num = -1, err = null, speed = null, finished_size = 0) {
var job = this.job_map[id];
if (!job) return;
if (file_num < job.file_num) return;
job.file_num = file_num;
var n = job.num_entries || job.entries.length;
job.finished = job.file_num >= n - 1 || err == "cancel";
job.finished_size = finished_size;
job.speed = speed || 0;
this.updateJob(job);
if (job.type == "del-dir") {
if (job.finished) {
if (!err) {
handler.remove_dir(job.id, job.path, job.is_remote);
refreshDir(job.is_remote);
}
} else if (!job.no_confirm) {
handler.confirm_delete_files(id, job.file_num + 1);
}
} else if (job.finished || file_num == -1) {
refreshDir(!job.is_remote);
}
}
function renderRow(job, i) {
var svg = this.getSvg(job);
return
{svg}
{job.path}
{this.getStatus(job)}
{svg_cancel}
|
;
}
}
class FolderView : Reactor.Component {
this var fd = {};
this var history = [];
this var show_hidden = false;
function sep() {
return handler.get_path_sep(this.is_remote);
}
function this(params) {
this.is_remote = params.is_remote;
if (this.is_remote) {
this.show_hidden = !!handler.get_option("remote_show_hidden");
} else {
this.show_hidden = !!handler.get_option("local_show_hidden");
}
if (!this.is_remote) {
var dir = handler.get_option("local_dir");
if (dir) {
this.fd = handler.read_dir(dir, this.show_hidden);
if (this.fd) return;
}
this.fd = handler.read_dir(handler.get_home_dir(), this.show_hidden);
}
}
// sort predicate
function foldersFirst(a, b) {
if (a.type <= 3 && b.type > 3) return -1;
if (a.type > 3 && b.type <= 3) return +1;
if (a.name == b.name) return 0;
return a.name.toLowerCase().lexicalCompare(b.name.toLowerCase());
}
function render()
{
return
{this.renderTitle()}
{this.renderNavBar()}
{this.renderOpBar()}
{this.renderTable()}
;
}
function renderTitle() {
return
{svg_computer}
{platformSvg(handler.get_platform(this.is_remote), "white")}
{this.is_remote ? "Remote Computer" : "Local Computer"}
}
function renderNavBar() {
return
{svg_home}
{svg_arrow}
{svg_arrow}
{this.renderSelect()}
{svg_refresh}
;
}
function renderSelect() {
return ;
}
function renderOpBar() {
if (this.is_remote) {
return
{svg_send}Receive
{svg_add_folder}
{svg_trash}
;
}
return
{svg_add_folder}
{svg_trash}
Send{svg_send}
;
}
function get_updated() {
this.table.sortRows(false);
if (this.fd && this.fd.path) this.select_dir.value = this.fd.path;
}
function renderTable() {
var fd = this.fd;
var entries = fd.entries || [];
var table = this.table;
if (!table || !table.sortBy) {
entries.sort(this.foldersFirst);
}
var me = this;
var path = fd.path;
if (path != "/" && path) {
entries = [{ name: "..", type: 1 }].concat(entries);
}
var rows = entries.map(function(e) { return me.renderRow(e); });
var id = (this.is_remote ? "remote" : "local") + "-folder-view";
return
| Name | Modified | Size |
{rows}
{svg_checkmark}Show Hidden Files
;
}
function joinPath(name) {
var path = this.fd.path;
if (path == "/") {
if (this.sep() == "/") return this.sep() + name;
else return name;
}
return path + (path[path.length - 1] == this.sep() ? "" : this.sep()) + name;
}
function attached() {
var me = this;
this.table.onRowDoubleClick = function (row) {
var type = row[0].attributes["type"];
if (type > 3) return;
var name = row[1].text;
var path = name == ".." ? getParentPath(me.is_remote, me.fd.path) : me.joinPath(name);
me.goto(path, true);
}
this.get_updated();
}
function goto(path, push) {
if (!path) return;
if (this.sep() == "\\" && path.length == 2) { // windows drive
path += "\\";
}
if (push) this.pushHistory();
if (this.is_remote) {
handler.read_remote_dir(path, this.show_hidden);
} else {
var fd = handler.read_dir(path, this.show_hidden);
this.refresh({ fd: fd });
}
}
function refresh(data) {
if (!data.fd || !data.fd.path) return;
if (this.is_remote && !remote_home_dir) {
remote_home_dir = data.fd.path;
}
this.update(data);
var me = this;
self.timer(1ms, function() { me.get_updated(); });
}
function renderRow(entry) {
var path;
if (this.is_remote) {
path = handler.get_icon_path(entry.type, getExt(entry.name));
} else {
path = this.joinPath(entry.name);
}
var tm = entry.time ? new Date(entry.time.toFloat() * 1000.).toLocaleString() : 0;
return
|
{entry.name} |
{tm || ""} |
{getSize(entry.type, entry.size)} |
;
}
event click $(#switch-hidden) {
this.show_hidden = !this.show_hidden;
this.refreshDir();
}
event click $(.goup) () {
var path = this.fd.path;
if (!path || path == "/") return;
path = getParentPath(this.is_remote, path);
this.goto(path, true);
}
event click $(.goback) () {
var path = this.history.pop();
if (!path) return;
this.goto(path, false);
}
event click $(.trash) () {
var row = this.getCurrentRow();
if (!row) return;
var path = row[0];
var type = row[1];
var new_history = [];
for (var i = 0; i < this.history.length; ++i) {
var h = this.history[i];
if ((h + this.sep()).indexOf(path + this.sep()) == -1) new_history.push(h);
}
this.history = new_history;
if (type == 1) {
file_transfer.job_table.addDelDir(path, this.is_remote);
} else {
confirmDelete(path, this.is_remote);
}
}
event click $(.add-folder) () {
var me = this;
handler.msgbox("custom", "Create Folder", " \
Please enter the folder name:
\
\
", function(res=null) {
if (!res) return;
if (!res.name) return;
var name = res.name.trim();
if (!name) return;
if (name.indexOf(me.sep()) >= 0) {
handler.msgbox("custom-error", "Create Folder", "Invalid folder name");
return;
}
var path = me.joinPath(name);
handler.create_dir(jobIdCounter, path, me.is_remote);
create_dir_jobs[jobIdCounter] = { is_remote: me.is_remote, path: path };
jobIdCounter += 1;
});
}
function refreshDir() {
this.goto(this.fd.path, false);
}
event click $(.refresh) () {
this.refreshDir();
}
event click $(.home) () {
var path = this.is_remote ? remote_home_dir : handler.get_home_dir();
if (!path) return;
if (path == this.fd.path) return;
this.goto(path, true);
}
function getCurrentRow() {
var row = this.table.getCurrentRow();
if (!row) return;
var name = row[1].text;
if (!name || name == "..") return;
var type = row[0].attributes["type"];
return [this.joinPath(name), type];
}
event click $(.send) () {
var cur = this.getCurrentRow();
if (!cur) return;
file_transfer.job_table.send(cur[0], this.is_remote);
}
event change $(.select-dir) (_, el) {
var x = getTime() - last_key_time;
if (x < 1000) return;
if (this.fd.path != el.value) {
this.goto(el.value, true);
}
}
event keydown $(.select-dir) (evt, me) {
if (evt.keyCode == Event.VK_ENTER ||
(view.mediaVar("platform") == "OSX" && evt.keyCode == 0x4C)) {
this.goto(me.value, true);
}
}
function pushHistory() {
var path = this.fd.path;
if (!path) return;
if (path != this.history[this.history.length - 1]) this.history.push(path);
}
}
var file_transfer;
class FileTransfer: Reactor.Component {
function this(params) {
file_transfer = this;
}
function render() {
return
;
}
}
function initializeFileTransfer()
{
$(#file-transfer-wrapper).content();
$(#video-wrapper).style.set { visibility: "hidden", position: "absolute" };
$(#file-transfer-wrapper).style.set { display: "block" };
}
handler.updateFolderFiles = function(fd) {
fd.entries = fd.entries || [];
if (fd.id > 0) {
var jt = file_transfer.job_table;
var job = jt.job_map[fd.id];
if (job) {
job.file_num = -1;
job.total_size = fd.total_size;
job.entries = fd.entries;
job.num_entries = fd.num_entries;
file_transfer.job_table.updateJobStatus(job.id);
}
} else {
file_transfer.remote_folder_view.refresh({ fd: fd });
}
}
handler.jobProgress = function(id, file_num, speed, finished_size) {
file_transfer.job_table.updateJobStatus(id, file_num, null, speed, finished_size);
}
handler.jobDone = function(id, file_num = -1) {
var job = deleting_single_file_jobs[id] || create_dir_jobs[id];
if (job) {
refreshDir(job.is_remote);
return;
}
file_transfer.job_table.updateJobStatus(id, file_num);
}
handler.jobError = function(id, err, file_num = -1) {
var job = deleting_single_file_jobs[id];
if (job) {
handler.msgbox("custom-error", "Delete File", err);
return;
}
job = create_dir_jobs[id];
if (job) {
handler.msgbox("custom-error", "Create Folder", err);
return;
}
if (file_num < 0) {
handler.msgbox("custom-error", "Failed", err);
}
file_transfer.job_table.updateJobStatus(id, file_num, err);
}
function refreshDir(is_remote) {
if (is_remote) file_transfer.remote_folder_view.refreshDir();
else file_transfer.local_folder_view.refreshDir();
}
var deleting_single_file_jobs = {};
var create_dir_jobs = {}
function confirmDelete(path, is_remote) {
handler.msgbox("custom-skip", "Confirm Delete", " \
Are you sure you want to deelte this file?
\
" + path + " \
", function(res=null) {
if (res) {
handler.remove_file(jobIdCounter, path, 0, is_remote);
deleting_single_file_jobs[jobIdCounter] = { is_remote: is_remote, path: path };
jobIdCounter += 1;
}
});
}
handler.confirmDeleteFiles = function(id, i, name) {
var jt = file_transfer.job_table;
var job = jt.job_map[id];
if (!job) return;
var n = job.num_entries;
if (i >= n) return;
var file_path = job.path;
if (name) file_path += handler.get_path_sep(job.is_remote) + name;
handler.msgbox("custom-skip", "Confirm Delete", " \
Deleting #" + (i + 1) + " of " + n + " files.
\
Are you sure you want to deelte this file?
\
" + name + " \
\
", function(res=null) {
if (!res) {
jt.updateJobStatus(id, i - 1, "cancel");
} else if (res.skip) {
if (res.remember) jt.updateJobStatus(id, i, "cancel");
else handler.jobDone(id, i);
} else {
job.no_confirm = res.remember;
if (job.no_confirm) handler.set_no_confirm(id);
handler.remove_file(id, file_path, i, job.is_remote);
}
});
}
function save_file_transfer_close_state() {
var local_dir = file_transfer.local_folder_view.fd.path || "";
var local_show_hidden = file_transfer.local_folder_view.show_hidden ? "Y" : "";
var remote_dir = file_transfer.remote_folder_view.fd.path || "";
var remote_show_hidden = file_transfer.remote_folder_view.show_hidden ? "Y" : "";
handler.save_close_state("local_dir", local_dir);
handler.save_close_state("local_show_hidden", local_show_hidden);
handler.save_close_state("remote_dir", remote_dir);
handler.save_close_state("remote_show_hidden", remote_show_hidden);
}