/**
* A dialog box letting the user choose a remote open or save file.
*/
class RemoteFileDialog extends XUI.Dialog {
/**
* Displays a dialog box letting the user choose a remote open or save file.
*
* @param {XMLEditor} xmlEditor - the XML editor hosting this dialog box.
* @param {object} [options={}] options - dialog box options.
* See description in {@link ResourceStorage#openResource}.
* @param {boolean} [saveMode=false] saveMode - specify <code>true</code>
* to display a save file dialog, <code>false</code> to display
* an open file dialog.
* @return {Promise} A Promise containing info about the chosen file
* or <code>null</code> if user clicked <b>Cancel</b>.
* <dl>
* <dt><code>uri</code>
* <dd>Absolute URI of chosen file.
* <dt><code><i>option_name</i></code>
* <dd>Only when a dialog box "accessory" has been specified:
* <code>true</code> if corresponding check box is checked;
* <code>false</code> otherwise.
* </dl>
*/
static showDialog(xmlEditor, options={}, saveMode=false) {
return new Promise((resolve, reject) => {
let dialog = new RemoteFileDialog(xmlEditor, options, saveMode,
resolve);
dialog.open("center", xmlEditor);
});
}
constructor(xmlEditor, options, saveMode, resolve) {
super({ title: LocalFileDialog.titleDefaulted(options, saveMode),
movable: true, resizable: true, closeable: true,
template: RemoteFileDialog.TEMPLATE,
buttons: [ { label: "Cancel", action: "cancelAction" },
{ label: "OK", action: "okAction",
default: true } ] });
this._xmlEditor = xmlEditor;
this._resolve = resolve;
this._saveMode = saveMode;
this._isLastSelectedURI = false;
this._initialURI = !options.templateURI? null : options.templateURI;
if (this._initialURI === null) {
this._initialURI = window.localStorage.getItem(
"XXE.RemoteFileDialog.lastSelectedURI");
if (this._initialURI !== null) {
// In open mode, the basename is not used.
// In save mode, reusing the basename of last selected URI
// would not make sense.
this._initialURI = URIUtil.uriSetBasename(this._initialURI,
"Untitled.xml");
this._isLastSelectedURI = (this._initialURI !== null);
}
}
this._initialPath = null;
let content = this.contentPane.firstElementChild;
this._drivePane = content.firstElementChild;
let chooserPane = content.lastElementChild;
let folderPane = chooserPane.firstElementChild;
this._folderSelector = folderPane.firstElementChild /*label*/
.nextElementSibling;
this._folderSelector.onchange = this.folderSelected.bind(this);
this._folderUpButton = this._folderSelector.nextElementSibling;
this._folderUpButton.firstElementChild.textContent =
XUI.StockIcon["folder"];
this._folderUpButton.lastElementChild.textContent =
XUI.StockIcon["up-bold"];
this._folderUpButton.onclick = this.folderUpAction.bind(this);
this._folderNewButton = this._folderUpButton.nextElementSibling;
this._folderNewButton.firstElementChild.textContent =
XUI.StockIcon["folder"];
this._folderNewButton.lastElementChild.textContent =
XUI.StockIcon["plus"];
this._folderNewButton.onclick = this.folderNewAction.bind(this);
let fileScroll = folderPane.nextElementSibling;
this._fileTable = fileScroll.firstElementChild;
this._fileRows = this._fileTable.lastElementChild;
this._fileRows.onclick = this.fileRowClicked.bind(this);
let fileForm = fileScroll.nextElementSibling;
let fileFormChildren = fileForm.children;
this._fileNameText = fileFormChildren.item(1);
this._fileNameText.onfocus = this.fileNameTextFocused.bind(this);
this._selectingFileType = false;
this._fileTypeSelector = fileFormChildren.item(3);
RemoteFileDialog.addFileTypes(this._fileTypeSelector,
options.extensions);
this._fileTypeSelector.onchange = this.fileTypeSelected.bind(this);
this._optPane = fileForm.nextElementSibling;
this._optLabel = this._optPane.firstElementChild;
this._optToggle = this._optLabel.firstElementChild;
// ---
if (!options.option ||
!Array.isArray(options.option) || options.option.length !== 3) {
this._optionName = null;
this._optPane.style.display = "none";
} else {
this._optionName = options.option[0];
this._optToggle.checked = options.option[1];
this._optLabel.appendChild(
document.createTextNode(options.option[2]));
}
// ---
this.initDrives();
}
// ----------------------------------
// File types
// ----------------------------------
static addFileTypes(select, extensions) {
select.appendChild(RemoteFileDialog.createOption("*", "All files",
/*sel*/ true));
if (!Array.isArray(extensions)) {
return;
}
for (let extension of extensions) {
if (Array.isArray(extension) && extension.length >= 3) {
let list = [];
for (let i = 2; i < extension.length; ++i) {
let ext = extension[i].trim();
if (ext.startsWith(".")) {
ext = ext.substring(1);
}
if (ext.length > 0) {
list.push(ext);
}
}
if (list.length > 0) {
select.appendChild(
RemoteFileDialog.createOption(list.join(';').toLowerCase(),
/*desc*/ extension[0],
/*sel*/ false));
}
}
}
}
static createOption(value, text, selected) {
let option = document.createElement("option");
option.setAttribute("value", value);
if (selected) {
option.setAttribute("selected", "selected");
}
option.appendChild(document.createTextNode(text));
return option;
}
selectFileType(extension) {
this._selectingFileType = true;
let selectedIndex = -1;
if (extension === null || extension.length === 0 ||
extension === "*") {
selectedIndex = 0; // All files.
} else {
extension = extension.toLowerCase();
for (let option of this._fileTypeSelector.options) {
let exts = option.value;
if (exts.indexOf(';') >= 0) {
exts = exts.split(';');
} else {
exts = [ exts ];
}
if (exts.indexOf(extension) >= 0) {
selectedIndex = option.index;
break;
}
}
}
if (selectedIndex < 0) {
selectedIndex = this._fileTypeSelector.length;
this._fileTypeSelector.appendChild(
RemoteFileDialog.createOption(extension, "*." + extension,
/*selected*/ false));
}
this._fileTypeSelector.options[selectedIndex].selected = true;
this._selectingFileType = false;
}
// ----------------------------------
// Drives
// ----------------------------------
initDrives() {
this._drives = [];
this._selectedDrive = null;
return this._xmlEditor.listRootDirectories()
.then((drives) => {
this.setDrives(drives);
return drives;
},
(error) => {
XUI.Alert.showError(
`Cannot list root directories:\n${error}`,
this._xmlEditor);
return null;
});
}
setDrives(drives) {
this._drives = drives;
this._selectedDrive = null;
XUI.Util.removeAllChildren(this._drivePane);
let initialURI = this._initialURI;
this._initialURI = null; // Just used once.
this._initialPath = null;
if (drives.length > 0) {
let selectedDrive = null;
if (initialURI !== null) {
selectedDrive = RemoteFileDialog.findDrive(drives, initialURI);
if (selectedDrive === null) {
// Drive not found. This detail does not matter anymore.
this._isLastSelectedURI = false;
} else {
// Compute initialPath out of initialURI ---
// selectedDrive.uri assumed to end with "/".
this._initialPath =
"/" + initialURI.substring(selectedDrive.uri.length);
this._initialPath =
URIUtil.normalizePath(this._initialPath, '/');
if (this._initialPath.endsWith("/")) {
// In principle, initialURI specifies a file, not a
// directory, hence does not end with "/".
this._initialPath += "Untitled.xml";
}
}
}
let selectedDriveDiv = null;
for (let drive of drives) {
let driveDiv = this.appendDrive(drive, this._drivePane);
if (drive === selectedDrive) {
selectedDriveDiv = driveDiv;
}
}
if (selectedDrive === null) {
selectedDrive = drives[0];
selectedDriveDiv = this._drivePane.firstElementChild;
}
this.selectDrive(selectedDrive, selectedDriveDiv);
const maxDrives = 6;
if (drives.length > maxDrives) {
// Limit the height of this._drivePane to maxDrives drives.
const padding =
XUI.Util.getPxProperty(this._drivePane, "padding-top");
const driveDiv = this._drivePane.lastElementChild;
const margin = XUI.Util.getPxProperty(driveDiv, "margin-top");
const maxHeight = (2 * padding) +
(maxDrives * driveDiv.offsetHeight) +
((maxDrives - 1) * margin);
if (!isNaN(maxHeight)) {
this._drivePane.style.maxHeight = String(maxHeight) + "px";
}
}
}
}
static findDrive(drives, uri) {
uri = uri.toLowerCase();
let found = null;
for (let drive of drives) {
if (uri.startsWith(drive.uri.toLowerCase())) {
if (found === null ||
found.uri.length < drive.uri.length) { // Better match.
found = drive;
}
}
}
return found;
}
appendDrive(drive, drivePane) {
let driveDiv = document.createElement("div");
driveDiv.setAttribute("class", "xui-control xxe-rfd-drive");
let tooltip = drive.uri;
if (drive.readonly) {
tooltip += "\n(read-only)";
}
driveDiv.setAttribute("title", tooltip);
drivePane.appendChild(driveDiv);
driveDiv.onclick = (e) => {
XUI.Util.consumeEvent(e);
if (this._selectedDrive !== drive) {
this.selectDrive(drive, driveDiv);
}
};
if (drive.readonly) {
let badge = document.createElement("div");
badge.setAttribute("class", "xui-small-icon xxe-rfd-drive-badge");
badge.textContent = XUI.StockIcon["eye"];
driveDiv.appendChild(badge);
}
let icon = document.createElement("div");
icon.setAttribute("class", "xui-small-icon xxe-rfd-drive-icon");
let iconName;
let iconColor;
let iconLabel = drive.label.toLowerCase();
if (iconLabel === "home") {
iconName = iconLabel;
iconColor = "#318CE7"; // Bleu de France
} else if (iconLabel === "computer") {
iconName = iconLabel;
iconColor = "#D0417E"; // Magenta (Pantone)
} else {
if (!drive.uri.startsWith("file:")) {
iconName = "server";
iconColor = "#63B76C"; // Fern
} else {
iconName = "drive";
iconColor = "#6CB4EE"; // Argentinian Blue
}
}
icon.style.color = iconColor;
icon.textContent = XUI.StockIcon[iconName];
driveDiv.appendChild(icon);
let label = document.createElement("div");
label.setAttribute("class", "xxe-rfd-drive-label");
label.textContent = XUI.Util.shortenText(drive.label, 12);
driveDiv.appendChild(label);
return driveDiv;
}
selectDrive(drive, driveDiv) {
if (this._selectedDrive !== null) {
let sel = this._drivePane.querySelector(".xxe-rfd-sel-drive");
if (sel !== null) {
sel.classList.remove("xxe-rfd-sel-drive");
}
this._selectedDrive = null;
}
if (drive !== null) {
driveDiv.classList.add("xxe-rfd-sel-drive");
this._selectedDrive = drive;
let initialPath = this._initialPath;
this._initialURI = null;
this._initialPath = null; // Just used once.
let folderPath = null;
let fileName = null;
if (initialPath !== null) {
folderPath = URIUtil.pathParent(initialPath, '/',
/*trailingSepar*/ false);
if (this._saveMode) {
fileName = URIUtil.pathBasename(initialPath, '/');
}
}
if (folderPath === null) {
folderPath =
!drive.selectedFolder? "/" : drive.selectedFolder.path;
// Default folder path. This detail does not matter anymore.
this._isLastSelectedURI = false;
}
this.selectFolder(drive, folderPath, fileName);
}
}
// ----------------------------------
// Folders
// ----------------------------------
selectFolder(drive, folderPath, fileName=null) {
this.updateFileTable(drive, folderPath)
.then((result) => {
if (result !== null) {
let [actualPath, listing] = result;
drive.selectedFolder = { path: actualPath,
listing: listing };
this.updateFolderSelector(actualPath);
this.enableFolderButtons(drive, actualPath);
if (fileName !== null && actualPath === folderPath) {
this.selectRow(fileName);
}
}
});
}
updateFileTable(drive, folderPath) {
let folderPathFromLastSelectedURI = this._isLastSelectedURI;
this._isLastSelectedURI = false; // Just used once.
const folderInfo = {
path: folderPath,
uri: RemoteFileDialog.joinURI(drive, folderPath)
};
return this._xmlEditor.listFiles(folderInfo.uri)
.then((listing) => {
if (Array.isArray(listing)) {
return listing;
} else {
// Not a folder.
if (folderPath === "/") {
// Nothing to do. Error reported during next step.
return null;
} else {
if (!folderPathFromLastSelectedURI) {
this.reportListFolderError(folderInfo.path,
"not a folder");
}
// Otherwise, folder path comes from
// window.localStorage. Do not bother user with this
// error.
// Fallback to "/".
folderInfo.path = "/";
folderInfo.uri = RemoteFileDialog.joinURI(drive, "/");
return this._xmlEditor.listFiles(folderInfo.uri);
}
}
})
.then((listing) => {
if (!Array.isArray(listing)) {
this.reportListFolderError(folderInfo.path, "not a folder");
// Give up.
return null;
}
this.updateFileRows(listing, this.getAcceptedExtensions());
return [folderInfo.path, listing];
})
.catch((error) => {
this.reportListFolderError(folderInfo.path, error);
return null;
});
}
static joinURI(drive, filePath, fileName=null) {
if (fileName !== null) {
filePath = RemoteFileDialog.joinPath(filePath, fileName);
}
let uri = drive.uri;
if (!uri.endsWith("/")) {
uri += "/";
}
const parts = RemoteFileDialog.splitPath(filePath);
for (let i = 0; i < parts.length; ++i) {
if (i > 0) {
uri += "/";
}
uri += encodeURIComponent(parts[i]);
}
return uri;
}
static joinPath(folderPath, fileName) {
let path = folderPath;
if (!path.endsWith("/")) {
path += "/";
}
path += fileName;
return path;
}
static splitPath(path) {
// Note that all paths are absolute here.
if (path.startsWith("/")) {
path = path.substring(1);
}
if (path.endsWith("/")) {
path = path.substring(0, path.length - 1);
}
if (path.length > 0) {
return path.split("/");
} else {
return [];
}
}
reportListFolderError(folderPath, error) {
XUI.Alert.showError(`Cannot list folder\n"${folderPath}":\n${error}`,
this._xmlEditor);
}
// ----------------------------------
// Folder selector
// ----------------------------------
updateFolderSelector(folderPath) {
XUI.Util.removeAllChildren(this._folderSelector);
const parts = RemoteFileDialog.splitPath(folderPath);
const lastPart = parts.length-1;
folderPath = "/";
let prevOption =
RemoteFileDialog.createOption(folderPath, folderPath,
/*selected*/ (-1 === lastPart));
this._folderSelector.appendChild(prevOption);
for (let i = 0; i <= lastPart; ++i) {
if (i > 0) {
folderPath += "/";
}
folderPath += parts[i];
let option =
RemoteFileDialog.createOption(folderPath, folderPath,
/*selected*/ (i === lastPart));
this._folderSelector.insertBefore(option, prevOption);
prevOption = option;
}
}
folderSelected(event) {
this.selectFolder(this._selectedDrive, event.target.value);
}
// ----------------------------------
// Folder buttons
// ----------------------------------
enableFolderButtons(drive, folderPath) {
RemoteFileDialog.enableButton(this._folderUpButton, folderPath !== "/");
RemoteFileDialog.enableButton(this._folderNewButton, !drive.readonly);
}
static enableButton(button, enable) {
if (enable) {
button.removeAttribute("disabled");
button.classList.remove("xui-control-disabled");
} else {
button.setAttribute("disabled", "disabled");
button.classList.add("xui-control-disabled");
}
}
folderUpAction(event) {
let selectedFolder = this.getSelectedFolder();
if (selectedFolder === null) {
// Should not happen (unless we have no drive).
return;
}
let folderPath = selectedFolder.path;
if (folderPath === "/") {
// Nothing to do.
return;
}
folderPath = URIUtil.pathParent(folderPath, '/',
/*trailingSepar*/ false);
this.selectFolder(this._selectedDrive, folderPath);
}
getSelectedFolder() {
const selectedDrive = this._selectedDrive;
if (!selectedDrive) {
return null;
}
const selectedFolder = selectedDrive.selectedFolder;
if (!selectedFolder ||
!selectedFolder.path ||
!Array.isArray(selectedFolder.listing)) {
return null;
}
// This also ensures that there is a selected drive.
return selectedFolder;
}
folderNewAction(event) {
let selectedFolder = this.getSelectedFolder();
if (selectedFolder === null) {
// Should not happen (unless we have no drive).
return;
}
let folderName = [];
XUI.Prompt.showPrompt("Create New Folder", "Folder name:",
/*cols*/ 30, /*initValue*/ null,
/*values*/ null, /*checker*/ null,
this._xmlEditor)
.then((answer) => {
if (answer === null) {
// Canceled by user.
return false;
} else {
let error = null;
if (answer.indexOf("/") >= 0) {
error = `"${answer}" is not a file basename.`;
} else if (RemoteFileDialog.getFileInfo(selectedFolder,
answer) !== null) {
error = `File "${answer}" already exists.`;
}
if (error !== null) {
XUI.Alert.showError(error, this._xmlEditor);
// Will not attempt to create it.
return false;
}
folderName.push(answer);
return this._xmlEditor.createDirectory(
RemoteFileDialog.joinURI(this._selectedDrive,
selectedFolder.path,
folderName[0]));
}
})
.then((created) => {
if (created) {
this.selectFolder(this._selectedDrive, selectedFolder.path,
folderName[0]);
}
// Otherwise canceled by user or file exists.
})
.catch((error) => {
XUI.Alert.showError(
`Cannot create folder "${folderName[0]}":\n${error}`,
this._xmlEditor);
});
}
static getFileInfo(selectedFolder, fileName) {
let fileInfo = selectedFolder.listing.find((entry) => {
return (entry.name === fileName);
});
return !fileInfo? null : fileInfo;
}
// ----------------------------------
// File rows
// ----------------------------------
updateFileRows(listing, acceptedExts) {
XUI.Util.removeAllChildren(this._fileRows);
for (let file of listing) {
if (!file.directory &&
!RemoteFileDialog.acceptFileName(file.name, acceptedExts)) {
continue;
}
let row = document.createElement("tr");
// Custom property set on a tbody/tr.
row.xxeFileInfo = file;
let cell = document.createElement("td");
let fileIcon = document.createElement("span");
let fileIconClass, fileIconName;
if (file.directory) {
fileIconClass = "xxe-rfd-dir-icon";
fileIconName = "folder";
} else {
fileIconClass = "xxe-rfd-file-icon";
fileIconName = "file";
}
fileIcon.setAttribute("class", "xui-small-icon " + fileIconClass);
fileIcon.textContent = XUI.StockIcon[fileIconName];
cell.appendChild(fileIcon);
cell.appendChild(document.createTextNode(file.name));
row.appendChild(cell);
cell = document.createElement("td");
cell.textContent = URIUtil.formatFileSize(file.size, "\u00A0");
row.appendChild(cell);
cell = document.createElement("td");
cell.textContent = URIUtil.formatFileDate(file.date, "\u00A0");
row.appendChild(cell);
this._fileRows.appendChild(row);
}
this._fileTable.scrollIntoView({ block: "start", inline: "start" });
}
static acceptFileName(fileName, acceptedExts) {
if (acceptedExts === null || acceptedExts.length === 0) {
// No filter.
return true;
}
let ext = URIUtil.pathExtension(fileName, '/');
if (ext === null || (ext = ext.trim()).length === 0) {
return false;
}
ext = ext.toLowerCase();
return (acceptedExts.indexOf(ext) >= 0);
}
fileRowClicked(event) {
if (event.button === 0) { // primary button
XUI.Util.consumeEvent(event);
switch (event.detail) {
case 1: // First click.
this.fileRowSelected(event);
break;
case 2: // Second click.
this.okAction();
break;
}
}
}
fileRowSelected(event) {
let elem = event.target;
while (elem !== null) {
if ("xxeFileInfo" in elem) {
// Custom property set on a tbody/tr.
this.selectRow(elem.xxeFileInfo.name);
break;
}
if (elem.localName === "tbody") {
// No more rows.
break;
}
elem = elem.parentElement;
}
}
selectRow(fileName) {
this.unselectRow();
let row = null;
for (let r of this._fileRows.children) {
// Custom property set on a tbody/tr.
if (r.xxeFileInfo && r.xxeFileInfo.name === fileName) {
row = r;
break;
}
}
if (row !== null) {
row.classList.add("xxe-rfd-sel-file");
row.scrollIntoViewIfNeeded(/*center*/ true);
if (!row.xxeFileInfo.directory) {
this._fileNameText.value = fileName;
}
// Otherwise, leave typed file name as is.
}
}
unselectRow() {
let sel = this._fileRows.querySelector(".xxe-rfd-sel-file");
if (sel !== null) {
sel.classList.remove("xxe-rfd-sel-file");
}
}
// ----------------------------------
// File name and type controls
// ----------------------------------
fileNameTextFocused(event) {
// The user may type something which no longer matches selected row.
this.unselectRow();
}
fileTypeSelected(event) {
if (this._selectingFileType) {
return;
}
let selectedFolder = this.getSelectedFolder();
if (selectedFolder === null) {
// Should not happen (unless we have no drive).
return null;
}
this.updateFileRows(selectedFolder.listing,
this.getAcceptedExtensions());
}
getAcceptedExtensions() {
let sel = this._fileTypeSelector.selectedIndex;
if (sel < 0) {
// Should not happen.
return null;
}
let extList = this._fileTypeSelector.options[sel].value;
if (extList === "*") {
// No filter.
return null;
}
return extList.split(';');
}
// ----------------------------------
// Dialog buttons
// ----------------------------------
dialogClosed(result) {
// Close icon clicked ==> null result, which is just fine.
this._resolve(result);
}
cancelAction() {
this.close(null);
}
getFileChoice() {
let selectedFolder = this.getSelectedFolder();
if (selectedFolder === null) {
// Should not happen (unless we have no drive).
return null;
}
// If a folder is selected, visit it no matter what the user has typed
// as a file name. ---
let selectedFileInfo = null;
let sel = this._fileRows.querySelector(".xxe-rfd-sel-file");
if (sel !== null && sel.xxeFileInfo && sel.xxeFileInfo.name) {
selectedFileInfo = sel.xxeFileInfo;
}
if (selectedFileInfo !== null && selectedFileInfo.directory) {
const folderPath = RemoteFileDialog.joinPath(selectedFolder.path,
selectedFileInfo.name);
this.selectFolder(this._selectedDrive, folderPath);
return null;
}
// No selected row or selected row specifies a file, priority to what
// the user has typed as a file name (if any). ---
let fileInfo = null;
let fileName = this._fileNameText.value.trim();
if (fileName.length === 0 && selectedFileInfo !== null) {
// User has not typed a file name and a row specifying a file is
// selected. Use it.
fileName = selectedFileInfo.name;
fileInfo = selectedFileInfo;
}
if (fileName.length === 0 ||
fileName.indexOf('/') >= 0) { // Not supported.
// No usable file name. Give up.
XUI.Util.badTextField(this._fileNameText);
return null;
}
if (fileInfo === null) {
// No selected row specifying a file. User has just typed a file
// name.
fileInfo = RemoteFileDialog.getFileInfo(selectedFolder, fileName);
}
let choice = {};
if (fileInfo === null) {
// Specified file does not exist. ---
// May be user typed a wildcard?
if (fileName.indexOf('*') >= 0) {
let ext = null;
if (fileName === "*") {
fileName = "*.*";
}
if (fileName.startsWith("*.")) {
ext = URIUtil.pathExtension(fileName, '/');
if (ext === null || ext.length === 0) {
ext = null;
}
}
if (ext === null) {
// Not supported.
XUI.Util.badTextField(this._fileNameText);
} else {
this._fileNameText.value = ""; // Wildcard no longer useful.
this.selectFileType(ext);
this.fileTypeSelected(/*event*/ null);
}
return null;
}
if (!this._saveMode) {
// Cannot open a file which does not exist.
XUI.Util.badTextField(this._fileNameText);
return null;
}
} else {
// Specified file exists. ---
if (fileInfo.directory) {
this._fileNameText.value = ""; // Dir name no longer useful.
const folderPath =
RemoteFileDialog.joinPath(selectedFolder.path, fileName);
this.selectFolder(this._selectedDrive, folderPath);
return null;
}
if (this._saveMode) {
choice.confirmCanOverwrite = true;
}
}
choice.uri = RemoteFileDialog.joinURI(this._selectedDrive,
selectedFolder.path, fileName);
// ---
if (this._optionName !== null) {
choice[this._optionName] = this._optToggle.checked;
}
return choice;
}
okAction() {
let choice = this.getFileChoice();
if (choice === null) {
return;
}
window.localStorage.setItem("XXE.RemoteFileDialog.lastSelectedURI",
choice.uri);
if (choice.confirmCanOverwrite) {
delete choice.confirmCanOverwrite;
return XUI.Confirm.showConfirm(
`File\n${choice.uri}\nalready exists. Overwrite?`,
this._xmlEditor)
.then((confirmed) => {
if (confirmed) {
this.close(choice);
}
});
} else {
this.close(choice);
}
}
}
RemoteFileDialog.TEMPLATE = document.createElement("template");
RemoteFileDialog.TEMPLATE.innerHTML = `
<div class="xxe-rfd-pane">
<div class="xui-control xxe-rfd-drive-pane">
</div>
<div class="xxe-rfd-chooser-pane">
<div class="xxe-rfd-folder-pane">
<span class="xxe-rfd-folder-label">Folder:</span>
<select autocomplete="off"
class="xui-control xxe-rfd-folder-select"></select>
<button disabled="disabled" title="Up one level"
class="xui-control xui-control-disabled
xui-small-icon xxe-rfd-folder-up">
<span class="xxe-rfd-folder-icon"></span><span
class="xxe-rfd-folder-badge"></span>
</button>
<button disabled="disabled" title="Create new folder"
class="xui-control xui-control-disabled
xui-small-icon xxe-rfd-folder-new">
<span class="xxe-rfd-folder-icon"></span><span
class="xxe-rfd-folder-badge"></span>
</button>
</div>
<div class="xxe-rfd-file-scroll">
<table class="xxe-rfd-file-table">
<colgroup class="xxe-rfd-ncol"></colgroup>
<colgroup class="xxe-rfd-scol"></colgroup>
<colgroup class="xxe-rfd-dcol"></colgroup>
<thead><th>Name</th><th>Size</th><th>Last Modified</th></thead>
<tbody></tbody>
</table>
</div>
<div class="xxe-rfd-file-form">
<span class="xxe-rfd-file-nlabel">File name:</span>
<input type="text" class="xui-control xxe-rfd-file-name"
spellcheck="false" autocomplete="off" />
<span class="xxe-rfd-file-tlabel">File type:</span>
<select autocomplete="off"
class="xui-control xxe-rfd-file-type"></select>
</div>
<div class="xxe-rfd-opt-pane">
<label class="xxe-rfd-opt-label">
<input type="checkbox" class="xxe-rfd-opt-toggle"/>
</label>
</div>
</div>
</div>
`;