Merge 3dd96b41eb
into 31ec776fb3
This commit is contained in:
commit
d2ec32578b
|
@ -501,6 +501,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="center file-preview"></div>
|
<div class="center file-preview"></div>
|
||||||
|
<div class="column center wrap">
|
||||||
|
<div class="row center wrap">
|
||||||
|
<span class="m-1" data-i18n-key="dialogs.change-name" data-i18n-attrs="text"></span>
|
||||||
|
<div class="row center wrap">
|
||||||
|
<input id="file-name-input-1" class="textarea" type="text" value="" />
|
||||||
|
<span id="file-name-input-ext-1"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button id="reset-name-1" class="btn btn-rounded btn-grey" data-i18n-key="dialogs.reset-name" data-i18n-attrs="text"></button>
|
||||||
|
</div>
|
||||||
|
<span id="file-name-error-1" class="text-red text-center"></span>
|
||||||
<div class="row-reverse center btn-row wrap">
|
<div class="row-reverse center btn-row wrap">
|
||||||
<button id="accept-request" class="btn btn-rounded btn-grey" title="ENTER" data-i18n-key="dialogs.accept" data-i18n-attrs="text" autofocus disabled></button>
|
<button id="accept-request" class="btn btn-rounded btn-grey" title="ENTER" data-i18n-key="dialogs.accept" data-i18n-attrs="text" autofocus disabled></button>
|
||||||
<button id="decline-request" class="btn btn-rounded btn-grey" title="ESCAPE" data-i18n-key="dialogs.decline" data-i18n-attrs="text"></button>
|
<button id="decline-request" class="btn btn-rounded btn-grey" title="ESCAPE" data-i18n-key="dialogs.decline" data-i18n-attrs="text"></button>
|
||||||
|
@ -531,6 +542,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="center file-preview"></div>
|
<div class="center file-preview"></div>
|
||||||
|
<div class="column center wrap">
|
||||||
|
<div class="row center wrap">
|
||||||
|
<span class="m-1" data-i18n-key="dialogs.change-name" data-i18n-attrs="text"></span>
|
||||||
|
<div class="row center wrap">
|
||||||
|
<input id="file-name-input-2" class="textarea" type="text" value="" />
|
||||||
|
<span id="file-name-input-ext-2"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button id="reset-name-2" class="btn btn-rounded btn-grey" data-i18n-key="dialogs.reset-name" data-i18n-attrs="text"></button>
|
||||||
|
</div>
|
||||||
|
<span id="file-name-error-2" class="text-red text-center"></span>
|
||||||
<div class="row-reverse center btn-row wrap">
|
<div class="row-reverse center btn-row wrap">
|
||||||
<button id="share-btn" class="btn btn-rounded btn-grey" data-i18n-key="dialogs.share" data-i18n-attrs="text" hidden></button>
|
<button id="share-btn" class="btn btn-rounded btn-grey" data-i18n-key="dialogs.share" data-i18n-attrs="text" hidden></button>
|
||||||
<button id="download-btn" class="btn btn-rounded btn-grey" data-i18n-key="dialogs.download" data-i18n-attrs="text" autofocus disabled></button>
|
<button id="download-btn" class="btn btn-rounded btn-grey" data-i18n-key="dialogs.download" data-i18n-attrs="text" autofocus disabled></button>
|
||||||
|
|
|
@ -70,6 +70,8 @@
|
||||||
"join": "Join",
|
"join": "Join",
|
||||||
"leave": "Leave",
|
"leave": "Leave",
|
||||||
"would-like-to-share": "would like to share",
|
"would-like-to-share": "would like to share",
|
||||||
|
"change-name": "Change name :",
|
||||||
|
"reset-name": "Reset Name",
|
||||||
"accept": "Accept",
|
"accept": "Accept",
|
||||||
"decline": "Decline",
|
"decline": "Decline",
|
||||||
"has-sent": "has sent:",
|
"has-sent": "has sent:",
|
||||||
|
|
|
@ -826,6 +826,10 @@ class LanguageSelectDialog extends Dialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReceiveDialog extends Dialog {
|
class ReceiveDialog extends Dialog {
|
||||||
|
// These variables are made static so that they can be accessed and modified across child classes.
|
||||||
|
static fileNameInputValue = "";
|
||||||
|
static fileNameInputExtValue = "";
|
||||||
|
|
||||||
constructor(id) {
|
constructor(id) {
|
||||||
super(id);
|
super(id);
|
||||||
this.$fileDescription = this.$el.querySelector('.file-description');
|
this.$fileDescription = this.$el.querySelector('.file-description');
|
||||||
|
@ -836,6 +840,13 @@ class ReceiveDialog extends Dialog {
|
||||||
this.$fileSize = this.$el.querySelector('.file-size');
|
this.$fileSize = this.$el.querySelector('.file-size');
|
||||||
this.$previewBox = this.$el.querySelector('.file-preview');
|
this.$previewBox = this.$el.querySelector('.file-preview');
|
||||||
this.$receiveTitle = this.$el.querySelector('h2:first-of-type');
|
this.$receiveTitle = this.$el.querySelector('h2:first-of-type');
|
||||||
|
|
||||||
|
// Store reserved file names initially in an array
|
||||||
|
this.reservedNames = ["con", "prn", "aux", "nul"];
|
||||||
|
for (let i=1; i <= 9; i++) {
|
||||||
|
this.reservedNames.push(`com${i}`);
|
||||||
|
this.reservedNames.push(`lpt${i}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_formatFileSize(bytes) {
|
_formatFileSize(bytes) {
|
||||||
|
@ -855,6 +866,24 @@ class ReceiveDialog extends Dialog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetFileNameInput(files, fileNameInput, fileNameInputExt) {
|
||||||
|
// Reset file name inside input text box and file name extension.
|
||||||
|
const fileName = files[0].name;
|
||||||
|
const fileNameSplit = fileName.split('.');
|
||||||
|
const fileExtension = fileNameSplit.length > 1
|
||||||
|
? '.' + fileNameSplit[fileNameSplit.length - 1]
|
||||||
|
: '';
|
||||||
|
if (files.length === 1) {
|
||||||
|
fileNameInput.value = fileName.substring(0, fileName.length - fileExtension.length);
|
||||||
|
fileNameInputExt.innerText = fileExtension;
|
||||||
|
} else {
|
||||||
|
fileNameInput.value = "PairDrop_files_{YYYY}{MM}{DD}_{hh}{mm}";
|
||||||
|
fileNameInputExt.innerText = ".zip";
|
||||||
|
}
|
||||||
|
ReceiveDialog.fileNameInputValue = fileNameInput.value;
|
||||||
|
ReceiveDialog.fileNameInputExtValue = fileNameInputExt.innerText;
|
||||||
|
}
|
||||||
|
|
||||||
_parseFileData(displayName, connectionHash, files, imagesOnly, totalSize, badgeClassName) {
|
_parseFileData(displayName, connectionHash, files, imagesOnly, totalSize, badgeClassName) {
|
||||||
let fileOther = "";
|
let fileOther = "";
|
||||||
|
|
||||||
|
@ -882,7 +911,48 @@ class ReceiveDialog extends Dialog {
|
||||||
this.$displayName.innerText = displayName;
|
this.$displayName.innerText = displayName;
|
||||||
this.$displayName.title = connectionHash;
|
this.$displayName.title = connectionHash;
|
||||||
this.$displayName.classList.remove("badge-room-ip", "badge-room-secret", "badge-room-public-id");
|
this.$displayName.classList.remove("badge-room-ip", "badge-room-secret", "badge-room-public-id");
|
||||||
this.$displayName.classList.add(badgeClassName)
|
this.$displayName.classList.add(badgeClassName);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateFileNameInput(fileNameInput, fileNameError, btn) {
|
||||||
|
// File name with invalid characters ("/", "\", ":", "*", "?", """, "<" and ">") or reserved names or empty string is considered invalid.
|
||||||
|
// If the file name is invalid, then respective error is displayed and the button to download is disabled.
|
||||||
|
const fileNameInputVal = fileNameInput.value;
|
||||||
|
if (fileNameInputVal.includes("/")) {
|
||||||
|
fileNameError.innerText = "File name should not contain '/'.";
|
||||||
|
btn.setAttribute('disabled', true);
|
||||||
|
} else if (fileNameInputVal.includes("\\")) {
|
||||||
|
fileNameError.innerText = "File name should not contain '\\'.";
|
||||||
|
btn.setAttribute('disabled', true);
|
||||||
|
} else if (fileNameInputVal.includes(":")) {
|
||||||
|
fileNameError.innerText = "File name should not contain ':'.";
|
||||||
|
btn.setAttribute('disabled', true);
|
||||||
|
} else if (fileNameInputVal.includes("*")) {
|
||||||
|
fileNameError.innerText = "File name should not contain '*'.";
|
||||||
|
btn.setAttribute('disabled', true);
|
||||||
|
} else if (fileNameInputVal.includes("?")) {
|
||||||
|
fileNameError.innerText = "File name should not contain '?'.";
|
||||||
|
btn.setAttribute('disabled', true);
|
||||||
|
} else if (fileNameInputVal.includes("\"")) {
|
||||||
|
fileNameError.innerText = "File name should not contain '\"'.";
|
||||||
|
btn.setAttribute('disabled', true);
|
||||||
|
} else if (fileNameInputVal.includes("<")) {
|
||||||
|
fileNameError.innerText = "File name should not contain '<'.";
|
||||||
|
btn.setAttribute('disabled', true);
|
||||||
|
} else if (fileNameInputVal.includes(">")) {
|
||||||
|
fileNameError.innerText = "File name should not contain '>'.";
|
||||||
|
btn.setAttribute('disabled', true);
|
||||||
|
} else if (this.reservedNames.includes(fileNameInputVal.toLowerCase())) {
|
||||||
|
fileNameError.innerText = "Reserved names cannot be set as file names.";
|
||||||
|
btn.setAttribute('disabled', true);
|
||||||
|
} else if (fileNameInputVal.trim() === "") {
|
||||||
|
fileNameError.innerText = "File name cannot be empty.";
|
||||||
|
btn.setAttribute('disabled', true);
|
||||||
|
} else {
|
||||||
|
ReceiveDialog.fileNameInputValue = fileNameInputVal;
|
||||||
|
fileNameError.innerText = "";
|
||||||
|
btn.removeAttribute('disabled');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -893,6 +963,11 @@ class ReceiveFileDialog extends ReceiveDialog {
|
||||||
|
|
||||||
this.$downloadBtn = this.$el.querySelector('#download-btn');
|
this.$downloadBtn = this.$el.querySelector('#download-btn');
|
||||||
this.$shareBtn = this.$el.querySelector('#share-btn');
|
this.$shareBtn = this.$el.querySelector('#share-btn');
|
||||||
|
this.$fileNameInput = this.$el.querySelector('#file-name-input-2');
|
||||||
|
this.$fileNameInputExt = this.$el.querySelector('#file-name-input-ext-2');
|
||||||
|
this.$resetNameBtn = this.$el.querySelector('#reset-name-2');
|
||||||
|
this.$fileNameError = this.$el.querySelector('#file-name-error-2');
|
||||||
|
this.$fileNameInput.addEventListener('input', _ => this.validateFileNameInput(this.$fileNameInput, this.$fileNameError, this.$downloadBtn));
|
||||||
|
|
||||||
Events.on('files-received', e => this._onFilesReceived(e.detail.peerId, e.detail.files, e.detail.imagesOnly, e.detail.totalSize));
|
Events.on('files-received', e => this._onFilesReceived(e.detail.peerId, e.detail.files, e.detail.imagesOnly, e.detail.totalSize));
|
||||||
this._filesQueue = [];
|
this._filesQueue = [];
|
||||||
|
@ -960,9 +1035,42 @@ class ReceiveFileDialog extends ReceiveDialog {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adjustFileName(fileName) {
|
||||||
|
// Method to replace the placeholders inside file name with respective timestamp values
|
||||||
|
let newFileName = fileName;
|
||||||
|
let now = new Date(Date.now());
|
||||||
|
let year = now.getFullYear().toString();
|
||||||
|
let month = (now.getMonth()+1).toString();
|
||||||
|
month = month.length < 2 ? "0" + month : month;
|
||||||
|
let date = now.getDate().toString();
|
||||||
|
date = date.length < 2 ? "0" + date : date;
|
||||||
|
let hours = now.getHours().toString();
|
||||||
|
hours = hours.length < 2 ? "0" + hours : hours;
|
||||||
|
let minutes = now.getMinutes().toString();
|
||||||
|
minutes = minutes.length < 2 ? "0" + minutes : minutes;
|
||||||
|
newFileName = newFileName.replaceAll("{YYYY}", year);
|
||||||
|
newFileName = newFileName.replaceAll("{MM}", month);
|
||||||
|
newFileName = newFileName.replaceAll("{DD}", date);
|
||||||
|
newFileName = newFileName.replaceAll("{hh}", hours);
|
||||||
|
newFileName = newFileName.replaceAll("{mm}", minutes);
|
||||||
|
console.log(newFileName);
|
||||||
|
return newFileName;
|
||||||
|
}
|
||||||
|
|
||||||
async _displayFiles(peerId, displayName, connectionHash, files, imagesOnly, totalSize, badgeClassName) {
|
async _displayFiles(peerId, displayName, connectionHash, files, imagesOnly, totalSize, badgeClassName) {
|
||||||
this._parseFileData(displayName, connectionHash, files, imagesOnly, totalSize, badgeClassName);
|
this._parseFileData(displayName, connectionHash, files, imagesOnly, totalSize, badgeClassName);
|
||||||
|
|
||||||
|
// Adjust the input content initially
|
||||||
|
this.$fileNameInput.value = ReceiveDialog.fileNameInputValue;
|
||||||
|
this.$fileNameInputExt.innerText = ReceiveDialog.fileNameInputExtValue;
|
||||||
|
this.$fileNameError.innerText = "";
|
||||||
|
|
||||||
|
this.$resetNameBtn.addEventListener("click", _ => {
|
||||||
|
this.resetFileNameInput(files, this.$fileNameInput, this.$fileNameInputExt);
|
||||||
|
this.$fileNameError.innerText = "";
|
||||||
|
this.$downloadBtn.removeAttribute('disabled');
|
||||||
|
});
|
||||||
|
|
||||||
let descriptor, url, filenameDownload;
|
let descriptor, url, filenameDownload;
|
||||||
if (files.length === 1) {
|
if (files.length === 1) {
|
||||||
descriptor = imagesOnly
|
descriptor = imagesOnly
|
||||||
|
@ -1029,7 +1137,11 @@ class ReceiveFileDialog extends ReceiveDialog {
|
||||||
this.$downloadBtn.onclick = _ => {
|
this.$downloadBtn.onclick = _ => {
|
||||||
if (downloadZipped) {
|
if (downloadZipped) {
|
||||||
let tmpZipBtn = document.createElement("a");
|
let tmpZipBtn = document.createElement("a");
|
||||||
tmpZipBtn.download = filenameDownload;
|
if (ReceiveDialog.fileNameInputValue !== "") {
|
||||||
|
tmpZipBtn.download = this.adjustFileName(ReceiveDialog.fileNameInputValue)+ReceiveDialog.fileNameInputExtValue;
|
||||||
|
} else {
|
||||||
|
tmpZipBtn.download = filenameDownload;
|
||||||
|
}
|
||||||
tmpZipBtn.href = url;
|
tmpZipBtn.href = url;
|
||||||
tmpZipBtn.click();
|
tmpZipBtn.click();
|
||||||
}
|
}
|
||||||
|
@ -1080,7 +1192,11 @@ class ReceiveFileDialog extends ReceiveDialog {
|
||||||
_downloadFilesIndividually(files) {
|
_downloadFilesIndividually(files) {
|
||||||
let tmpBtn = document.createElement("a");
|
let tmpBtn = document.createElement("a");
|
||||||
for (let i=0; i<files.length; i++) {
|
for (let i=0; i<files.length; i++) {
|
||||||
tmpBtn.download = files[i].name;
|
if (ReceiveDialog.fileNameInputValue !== "") {
|
||||||
|
tmpBtn.download = this.adjustFileName(ReceiveDialog.fileNameInputValue)+ReceiveDialog.fileNameInputExtValue;
|
||||||
|
} else {
|
||||||
|
tmpBtn.download = files[i].name;
|
||||||
|
}
|
||||||
tmpBtn.href = URL.createObjectURL(files[i]);
|
tmpBtn.href = URL.createObjectURL(files[i]);
|
||||||
tmpBtn.click();
|
tmpBtn.click();
|
||||||
}
|
}
|
||||||
|
@ -1107,6 +1223,11 @@ class ReceiveRequestDialog extends ReceiveDialog {
|
||||||
this.$declineRequestBtn = this.$el.querySelector('#decline-request');
|
this.$declineRequestBtn = this.$el.querySelector('#decline-request');
|
||||||
this.$acceptRequestBtn.addEventListener('click', _ => this._respondToFileTransferRequest(true));
|
this.$acceptRequestBtn.addEventListener('click', _ => this._respondToFileTransferRequest(true));
|
||||||
this.$declineRequestBtn.addEventListener('click', _ => this._respondToFileTransferRequest(false));
|
this.$declineRequestBtn.addEventListener('click', _ => this._respondToFileTransferRequest(false));
|
||||||
|
this.$fileNameInput = this.$el.querySelector('#file-name-input-1');
|
||||||
|
this.$fileNameInputExt = this.$el.querySelector('#file-name-input-ext-1');
|
||||||
|
this.$resetNameBtn = this.$el.querySelector('#reset-name-1');
|
||||||
|
this.$fileNameError = this.$el.querySelector('#file-name-error-1');
|
||||||
|
this.$fileNameInput.addEventListener('input', _ => this.validateFileNameInput(this.$fileNameInput, this.$fileNameError, this.$acceptRequestBtn));
|
||||||
|
|
||||||
Events.on('files-transfer-request', e => this._onRequestFileTransfer(e.detail.request, e.detail.peerId))
|
Events.on('files-transfer-request', e => this._onRequestFileTransfer(e.detail.request, e.detail.peerId))
|
||||||
Events.on('keydown', e => this._onKeyDown(e));
|
Events.on('keydown', e => this._onKeyDown(e));
|
||||||
|
@ -1143,6 +1264,15 @@ class ReceiveRequestDialog extends ReceiveDialog {
|
||||||
|
|
||||||
this._parseFileData(displayName, connectionHash, request.header, request.imagesOnly, request.totalSize, badgeClassName);
|
this._parseFileData(displayName, connectionHash, request.header, request.imagesOnly, request.totalSize, badgeClassName);
|
||||||
|
|
||||||
|
// Initially reset the file name inside input textbox
|
||||||
|
this.resetFileNameInput(request.header, this.$fileNameInput, this.$fileNameInputExt);
|
||||||
|
|
||||||
|
this.$resetNameBtn.addEventListener("click", _ => {
|
||||||
|
this.resetFileNameInput(request.header, this.$fileNameInput, this.$fileNameInputExt);
|
||||||
|
this.$fileNameError.innerText = "";
|
||||||
|
this.$acceptRequestBtn.removeAttribute('disabled');
|
||||||
|
});
|
||||||
|
|
||||||
if (request.thumbnailDataUrl && request.thumbnailDataUrl.substring(0, 22) === "data:image/jpeg;base64") {
|
if (request.thumbnailDataUrl && request.thumbnailDataUrl.substring(0, 22) === "data:image/jpeg;base64") {
|
||||||
let element = document.createElement('img');
|
let element = document.createElement('img');
|
||||||
element.src = request.thumbnailDataUrl;
|
element.src = request.thumbnailDataUrl;
|
||||||
|
|
|
@ -297,6 +297,10 @@ h3 {
|
||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-red {
|
||||||
|
color: red !important;
|
||||||
|
}
|
||||||
|
|
||||||
.font-body1,
|
.font-body1,
|
||||||
body {
|
body {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -678,6 +682,11 @@ button::-moz-focus-inner {
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#reset-name-1, #reset-name-2 {
|
||||||
|
margin: 3px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Icon Button */
|
/* Icon Button */
|
||||||
.icon-button {
|
.icon-button {
|
||||||
|
|
Loading…
Reference in New Issue