/**
* Refer to <span color = "yellow">{@link ve.Component}</span> for methods or fields inherited from this Component's parent such as `.options.attributes` or `.element`.
*
* Basic file input that can also accept folders. Note that if you need a file explorer, you should refer to {@link ve.FileExplorer}, though this component uses its subtype.
* - Functional binding: <span color=00ffff>veFile</span>().
*
* ##### Constructor:
* - `arg0_value`: {@link string} - The current file path, if any.
* - `arg1_options`: {@link Object}
* - `.do_not_display=false`: {@link boolean} - Whether to display the file name to the left of the select file prompt
* - `.is_folder=false`: {@link boolean} - Whether the input is asking for a folder.
* - `.multifile=false`: {@link boolean} - Whether the input can accept multiple files/folders.
* - `.save_function`: {@link function} - If set, the current component will be a save prompt.
*
* ##### Instance:
* - `.v`: {@link string}
*
* ##### Methods:
* - <span color=00ffff>{@link ve.FileExplorer.openModal|openModal}</span>()
*
* @augments ve.Component
* @memberof ve.Component
* @type {ve.File}
*/
ve.File = class extends ve.Component {
static demo_value = "./README.md";
constructor (arg0_value, arg1_options) {
//Convert from parameters
let value = arg0_value;
let options = (arg1_options) ? arg1_options : {};
super(options);
//Initialise options
options.attributes = (options.attributes) ? options.attributes : {};
//Declare local instance variables
this.element = document.createElement("div");
this.element.setAttribute("component", "ve-file");
this.element.instance = this;
this.options = options;
this.value = (value) ? value : [];
this.interface = new ve.RawInterface({
select_file_text: new ve.HTML(() => {
//Return statement
if (!this.options.do_not_display) {
if (this.v.length === 0) {
return "None";
} else if (this.v.length === 1) {
return `${this.v[0]}`;
} else {
return `${this.v[0]} and ${String.formatNumber(this.v.length - 1)} other(s)`;
}
} else {
return "";
}
}, {
style: { padding: 0 }
}),
select_file_button: new veButton(() => {
this.openModal();
}, {
name: (this.options.name) ? this.options.name : loc("ve.registry.localisation.File_select_file"),
style: {
marginLeft: (!this.options.do_not_display) ? `calc(var(--padding)*0.5)` : 0,
whiteSpace: "nowrap"
}
})
}, {
name: " ",
style: {
alignItems: "center",
display: "flex",
padding: 0
}
});
this.interface.bind(this.element);
this.v = this.value;
}
/**
* Returns the current file path pointed to by the component.
* - Accessor of: {@link ve.File}
*
* @alias v
* @memberof ve.Component.ve.Date
* @type {string[]}
*/
get v () {
//Return statement
return this.value;
}
/**
* Sets the current file path pointed to by the component.
* - Accessor of {@link ve.File}
*
* @alias v
* @memberof ve.Component.ve.Date
*
* @param {string[]} arg0_value
*/
set v (arg0_value) {
//Convert from parameters
let value = Array.toArray(arg0_value);
//Declare local instance variables
this.value = value;
this.fireFromBinding();
}
/**
* Opens the file explorer modal.
* - Method of: {@link ve.File}
*
* @alias openModal
* @memberof ve.Component.ve.File
*/
openModal () {
//Close window if already opened
if (this.file_explorer_modal) this.file_explorer_modal.close();
//Declare local instance variables
let window_name = loc("ve.registry.localisation.File_open_file");
if (this.options.multifile && !this.options.is_folder) {
window_name = loc("ve.registry.localisation.File_open_files");
} else if (this.options.multifile && this.options.is_folder) {
window_name = loc("ve.registry.localisation.File_open_folders");
} else if (this.options.is_folder) {
window_name = loc("ve.registry.localisation.File_open_folder");
}
if (this.options.save_function)
window_name = loc("ve.registry.localisation.File_save_file");
this.file_explorer_modal = new ve.Window({
file_explorer: new ve.FileExplorer((this.value[0]) ? path.dirname(this.value[0]) : process.cwd(), {
name: " ",
style: {
width: "24rem"
}
}),
actions_bar: new ve.RawInterface({
save_name: new ve.Text("", {
attributes: { placeholder: loc("ve.registry.localisation.File_save_file_as") },
limit: () => this.options.save_function
}),
confirm_button: new ve.Button(() => {
if (!this.options.save_function) {
let selected_paths = this.file_explorer_modal.file_explorer.selected;
//Internal guard clauses - Error handling
{
if (selected_paths.length === 0) {
veToast(`<icon>warning</icon> ${loc("ve.registry.localisation.File_must_select_valid_path")}`);
return;
}
if (!this.options.multifile && selected_paths.length > 1) {
veToast(`<icon>warning</icon> ${loc("ve.registry.localisation.File_can_only_select_one_file")}`);
return;
}
if (this.options.is_folder) {
let has_file = false;
//Iterate over all files to ensure validity
for (let i = 0; i < selected_paths.length; i++)
if (!fs.statSync(selected_paths[i]).isDirectory()) {
has_file = true;
veToast(`<icon>warning</icon> ${loc("ve.registry.localisation.File_can_only_select_folders")}`);
return;
}
} else {
let has_folder = false;
//Iterate over all files to ensure validity
for (let i = 0; i < selected_paths.length; i++)
if (fs.statSync(selected_paths[i]).isDirectory()) {
has_folder = true;
veToast(`<icon>warning</icon> ${loc("ve.registry.localisation.File_can_only_select_files")}`);
return;
}
}
}
//Set selected paths
this.v = selected_paths;
this.fireToBinding();
veToast(loc("ve.registry.localisation.File_selected_files", String.formatNumber(selected_paths.length)));
this.file_explorer_modal.close();
} else {
let save_name = this.file_explorer_modal.actions_bar.save_name.v;
//Internal guard clauses - Error handling
{
if (save_name.length === 0) {
veToast(`<icon>warning</icon> Save files must have a name.`);
return;
}
}
//Execute save function to directory name
let full_save_path = path.join(this.file_explorer_modal.file_explorer.v, save_name);
try {
let save_data = this.options.save_function();
if (typeof save_data === "object") {
save_data = JSON.stringify(save_data);
} else {
save_data = save_data.toString();
}
//Check if file already exists, if so send a confirmation prompt
let save_function = () => {
fs.writeFile(full_save_path, save_data, () => {
veToast(loc("ve.registry.localisation.File_successfully_saved_file", full_save_path));
this.file_explorer_modal.close();
})
this.v = [full_save_path];
this.fireToBinding();
};
(!fs.existsSync(full_save_path)) ?
save_function() :
veConfirm(loc("ve.registry.localisation.File_already_exists"), {
special_function: () => save_function()
});
} catch (e) {
console.error(e);
veWindow(`<span style = "align-items: center; display: flex"><icon>warning</icon><span style = "margin-left: var(--padding)">${loc("ve.registry.localisation.File_error_saving_file_desc", e)}</span></span>`, {
can_rename: false,
name: loc("ve.registry.localisation.File_error_saving_file"),
width: "20rem"
});
}
}
}, { name: loc("ve.registry.localisation.File_confirm") }),
cancel_button: new ve.Button(() => this.file_explorer_modal.close(), { name: loc("ve.registry.localisation.File_cancel") })
}, {
can_rename: false,
name: " ",
style: {
alignItems: "center",
display: "flex"
}
})
}, {
can_rename: false,
name: window_name,
width: "26rem"
});
}
};
//Functional binding
/**
* @returns {ve.File}
*/
veFile = function () {
//Return statement
return new ve.File(...arguments);
};