Nearly finished the Excel Password Remover revamp, Only the download is missing
Update commons.yml, excel-password-remover.yml, and 14 more files...
This commit is contained in:
@@ -1,14 +1,20 @@
|
||||
import {initCore} from "../../js/nibblepoker-core.mjs"
|
||||
// Implied Globals: JSZip
|
||||
if(JSZip == null) {
|
||||
alert("JSZip isn't available !");
|
||||
}
|
||||
|
||||
const excelFileRegex = /^.*\.xls[xm]$/gi;
|
||||
const excelWorksheetRegex = /^xl\/worksheets\/.*.xml$/gi;
|
||||
import {initCore} from "../../js/nibblepoker-core.mjs"
|
||||
import {cloneTemplate} from "../../js/nibblepoker-template.mjs"
|
||||
|
||||
export const excelFileRegex = /^.*\.xls[xm]$/gi;
|
||||
export const excelWorksheetRegex = /^xl\/worksheets\/.*.xml$/gi;
|
||||
|
||||
/**
|
||||
* Checks if the given filename appears to be for an Excel file.
|
||||
* @param fileName {string} Filename to be checked
|
||||
* @returns {boolean} `true` if it appears to be an Excel file, `false` otherwise.
|
||||
*/
|
||||
function isExcelExtension(fileName) {
|
||||
export function isExcelExtension(fileName) {
|
||||
return fileName.match(excelFileRegex) !== null;
|
||||
}
|
||||
|
||||
@@ -16,43 +22,269 @@ function isExcelExtension(fileName) {
|
||||
{
|
||||
initCore();
|
||||
|
||||
var outputZip;
|
||||
var outputZipFilename = "default-filename.error.zip";
|
||||
var filesTotalCount = 0;
|
||||
var filesProcessedCount = 0;
|
||||
var passwordsRemoved = 0;
|
||||
//let outputZip;
|
||||
//let outputZipFilename = "default-filename.error.zip";
|
||||
//let filesTotalCount = 0;
|
||||
//let filesProcessedCount = 0;
|
||||
//let passwordsRemoved = 0;
|
||||
|
||||
/** @type {string} */
|
||||
const appletId = "excel-password-remover";
|
||||
|
||||
/** @type {HTMLElement} */
|
||||
const eEulaContainer = document.querySelector(`#${appletId}-eula`);
|
||||
///** @type {HTMLInputElement} */
|
||||
//const eEulaDontAskAgainOption = document.querySelector(`input#${appletId}-eula-remember`);
|
||||
///** @type {HTMLButtonElement} */
|
||||
//const eEulaAcceptButton = document.querySelector(`button#${appletId}-eula-accept`);
|
||||
|
||||
/** @type {HTMLInputElement} */
|
||||
const eFileInput = document.querySelector(`input[type=file]#${appletId}-input-file`);
|
||||
/** @type {HTMLButtonElement} */
|
||||
const eFileInputClearButton = document.querySelector(`button#${appletId}-input-file-reset`);
|
||||
|
||||
/*function acceptTerms() {
|
||||
document.getElementById("warning").hidden = true;
|
||||
document.getElementById("file-select").hidden = false;
|
||||
}*/
|
||||
/** @type {HTMLElement} */
|
||||
const eResultEmptyText = document.querySelector(`#${appletId}-details-empty`);
|
||||
/** @type {HTMLElement} */
|
||||
const eResultPopulatedText = document.querySelector(`#${appletId}-details-populated`);
|
||||
|
||||
/** @type {HTMLElement} */
|
||||
const eResultContainer = document.querySelector(`#${appletId}-result-container`);
|
||||
|
||||
/** @type {HTMLTemplateElement} */
|
||||
const eSuccessTemplate = document.querySelector(`template#tmpl-success-root`);
|
||||
/** @type {HTMLTemplateElement} */
|
||||
const eWarningTemplate = document.querySelector(`template#tmpl-warning-root`);
|
||||
/** @type {HTMLTemplateElement} */
|
||||
const eErrorTemplate = document.querySelector(`template#tmpl-error-root`);
|
||||
|
||||
/** @type {HTMLButtonElement} */
|
||||
const eFileDownloadAllButton = document.querySelector(`button#${appletId}-files-download-all`);
|
||||
/** @type {HTMLButtonElement} */
|
||||
const eFileClearButton = document.querySelector(`button#${appletId}-files-clear`);
|
||||
|
||||
class ExcelFileData {
|
||||
/** @type {File} */
|
||||
originalFile;
|
||||
|
||||
/** @type {any} */
|
||||
processedZipFile;
|
||||
|
||||
filesTotalCount = 0;
|
||||
filesProcessedCount = 0;
|
||||
passwordsRemoved = 0;
|
||||
|
||||
constructor(originalFile) {
|
||||
this.originalFile = originalFile;
|
||||
}
|
||||
|
||||
/** @returns {string} */
|
||||
getOutputName() {
|
||||
let outputZipExtension = "." + this.originalFile.name.split(".").pop();
|
||||
let outputZipFilename = this.originalFile.name.substring(0, this.originalFile.name.length - outputZipExtension.length);
|
||||
return outputZipFilename + "_no-password" + outputZipExtension;
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {ExcelFileData[]} */
|
||||
let rawWorksheetFiles = [];
|
||||
|
||||
function onFileAddedToDom() {
|
||||
eResultEmptyText.hidden = true;
|
||||
eResultPopulatedText.hidden = false;
|
||||
}
|
||||
|
||||
function onFilesRemovedFromDom() {
|
||||
eResultEmptyText.hidden = false;
|
||||
eResultPopulatedText.hidden = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param excelFile {ExcelFileData}
|
||||
*/
|
||||
function onFileHavingPasswordRemoved(excelFile) {
|
||||
console.debug(`Removed ${excelFile.passwordsRemoved} password(s) from '${excelFile.originalFile.name}'`);
|
||||
|
||||
cloneTemplate(
|
||||
eSuccessTemplate,
|
||||
{
|
||||
"tmpl-success-filename": excelFile.originalFile.name,
|
||||
"tmpl-success-password-count": excelFile.passwordsRemoved
|
||||
},
|
||||
true
|
||||
).then(eFragment => {
|
||||
console.debug(eFragment);
|
||||
|
||||
const uuid = crypto.randomUUID();
|
||||
console.debug(eFragment.children);
|
||||
eFragment.children.id = uuid;
|
||||
|
||||
eResultContainer.appendChild(eFragment);
|
||||
onFileAddedToDom();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param excelFile {ExcelFileData}
|
||||
*/
|
||||
function onFileWithoutPasswords(excelFile) {
|
||||
console.warn(`No password(s) were found in ${excelFile.originalFile.name} !`);
|
||||
|
||||
cloneTemplate(
|
||||
eWarningTemplate,
|
||||
{
|
||||
"tmpl-warning-filename": excelFile.originalFile.name,
|
||||
"tmpl-warning-message-extension": "",
|
||||
//"tmpl-warning-message-no-password": "",
|
||||
},
|
||||
true
|
||||
).then(eFragment => {
|
||||
console.debug(eFragment);
|
||||
eResultContainer.appendChild(eFragment);
|
||||
onFileAddedToDom();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param excelFile {ExcelFileData}
|
||||
*/
|
||||
function onFileWithInvalidExtension(excelFile) {
|
||||
console.warn(`The given file '${excelFile.originalFile.name}' doesn't have an Excel extension`);
|
||||
|
||||
cloneTemplate(
|
||||
eWarningTemplate,
|
||||
{
|
||||
"tmpl-warning-filename": excelFile.originalFile.name,
|
||||
//"tmpl-warning-message-extension": "",
|
||||
"tmpl-warning-message-no-password": "",
|
||||
},
|
||||
true
|
||||
).then(eFragment => {
|
||||
console.debug(eFragment);
|
||||
eResultContainer.appendChild(eFragment);
|
||||
onFileAddedToDom();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param excelFile {ExcelFileData}
|
||||
* @param error {any}
|
||||
*/
|
||||
function onExtractionFailure(excelFile, error) {
|
||||
console.error("Failed to extract the content of the file in the browser ! ("+error.message+")");
|
||||
|
||||
cloneTemplate(
|
||||
eErrorTemplate,
|
||||
{
|
||||
"tmpl-error-filename": excelFile.originalFile.name,
|
||||
//"tmpl-error-message-jszip": ""
|
||||
},
|
||||
true
|
||||
).then(eFragment => {
|
||||
console.debug(eFragment);
|
||||
eResultContainer.appendChild(eFragment);
|
||||
onFileAddedToDom();
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
|
||||
eFileInput.addEventListener('change', function(e) {
|
||||
let fileCount = e.target.files.length;
|
||||
eFileDownloadAllButton.addEventListener("click", function() {
|
||||
|
||||
console.log(fileCount);
|
||||
});
|
||||
|
||||
/*console.log(eEulaContainer);
|
||||
console.log(eEulaDontAskAgainOption);
|
||||
console.log(eEulaAcceptButton);
|
||||
eEulaAcceptButton.addEventListener("click", function() {
|
||||
eEulaContainer.hidden = true;
|
||||
});*/
|
||||
eFileClearButton.addEventListener("click", function() {
|
||||
while (eResultContainer.firstChild) {
|
||||
eResultContainer.firstChild.remove();
|
||||
}
|
||||
onFilesRemovedFromDom();
|
||||
rawWorksheetFiles = [];
|
||||
eFileInputClearButton.click();
|
||||
});
|
||||
|
||||
eFileInput.addEventListener('change', function(e) {
|
||||
rawWorksheetFiles = [];
|
||||
|
||||
for (let i = 0; i < e.target.files.length; i++) {
|
||||
console.debug(e.target.files[i]);
|
||||
rawWorksheetFiles.push(new ExcelFileData(e.target.files[i]));
|
||||
}
|
||||
|
||||
rawWorksheetFiles.forEach(excelFile => {
|
||||
if(!isExcelExtension(excelFile.originalFile.name)) {
|
||||
onFileWithInvalidExtension(excelFile);
|
||||
return;
|
||||
}
|
||||
|
||||
JSZip.loadAsync(excelFile.originalFile).then(function(zip) {
|
||||
console.group(`JSZip - ${excelFile.originalFile.name}`);
|
||||
|
||||
excelFile.processedZipFile = new JSZip();
|
||||
excelFile.filesTotalCount = 0;
|
||||
excelFile.filesProcessedCount = 0;
|
||||
excelFile.passwordsRemoved = 0;
|
||||
|
||||
for(const[fileKey, fileValue] of Object.entries(zip.files)) {
|
||||
excelFile.filesTotalCount++;
|
||||
|
||||
if(fileKey.match(excelWorksheetRegex)) {
|
||||
console.debug("Checking: "+fileKey);
|
||||
|
||||
fileValue.async("string").then(function(fileText) {
|
||||
console.group(`JSZip - ${excelFile.originalFile.name} - ${fileKey}`);
|
||||
|
||||
let startIndex = fileText.indexOf('<sheetProtection ');
|
||||
|
||||
if(startIndex === -1) {
|
||||
// No password found.
|
||||
excelFile.processedZipFile.file(fileKey, fileText);
|
||||
console.debug("Analysed: "+fileKey);
|
||||
} else {
|
||||
// Removing the password.
|
||||
let endIndex = fileText.indexOf('/>', startIndex) + 2;
|
||||
fileText = fileText.replace(fileText.substr(startIndex, endIndex-startIndex), "");
|
||||
excelFile.processedZipFile.file(fileKey, fileText);
|
||||
console.debug("Processed: "+fileKey);
|
||||
excelFile.passwordsRemoved++;
|
||||
}
|
||||
|
||||
excelFile.filesProcessedCount++;
|
||||
|
||||
console.groupEnd();
|
||||
});
|
||||
} else {
|
||||
// Other files.
|
||||
console.debug("Ignoring: "+fileKey);
|
||||
fileValue.async("string").then(function(fileText) {
|
||||
console.group(`JSZip - ${excelFile.originalFile.name} - ${fileKey}`);
|
||||
console.debug(`Copying as-is`);
|
||||
|
||||
excelFile.processedZipFile.file(fileKey, fileText);
|
||||
excelFile.filesProcessedCount++;
|
||||
|
||||
console.groupEnd();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.debug("Waiting for all the files to be processed !");
|
||||
|
||||
function waitFilesBeingProcessed() {
|
||||
console.debug("Processed "+excelFile.filesProcessedCount+" file(s) out of "+excelFile.filesTotalCount);
|
||||
|
||||
if(excelFile.filesTotalCount !== excelFile.filesProcessedCount) {
|
||||
setTimeout(waitFilesBeingProcessed, 50);
|
||||
} else {
|
||||
console.debug("Done, now switching the page !");
|
||||
if(excelFile.passwordsRemoved > 0) {
|
||||
onFileHavingPasswordRemoved(excelFile);
|
||||
} else {
|
||||
onFileWithoutPasswords(excelFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(waitFilesBeingProcessed, 50);
|
||||
|
||||
console.groupEnd();
|
||||
}, function (e) {
|
||||
onExtractionFailure(excelFile, e);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@
|
||||
/**
|
||||
* @param eTemplate {HTMLTemplateElement | string} The template to be cloned, or its ID.
|
||||
* @param subParts {Object.<string, Node | string | number | boolean>}
|
||||
* @param ignoreMissingParts {bool}
|
||||
* @param ignoreMissingParts {boolean}
|
||||
* @returns {Promise<DocumentFragment>}
|
||||
*/
|
||||
export function cloneTemplate(eTemplate,
|
||||
@@ -34,14 +34,22 @@ export function cloneTemplate(eTemplate,
|
||||
reject(`Unable to find sub-element with id '${key}' !`);
|
||||
}
|
||||
|
||||
ePart.removeAttribute('id');
|
||||
|
||||
if(value instanceof Node) {
|
||||
ePart.innerHTML = "";
|
||||
ePart.appendChild(value);
|
||||
} else {
|
||||
ePart.innerHTML += value;
|
||||
ePart.innerHTML = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const childElements = eClone.querySelectorAll('*');
|
||||
childElements.forEach(eChild => {
|
||||
eChild.removeAttribute('id');
|
||||
});
|
||||
|
||||
resolve(eClone);
|
||||
}
|
||||
});
|
||||
|
@@ -1,6 +1,7 @@
|
||||
// NibblePoker - UI Scripts
|
||||
// NibblePoker - Mandatory Scripts
|
||||
// Author: Herwin Bozet (@NibblePoker)
|
||||
// License: Public Domain (This code)
|
||||
// Remark: This modules contains all the scripts that are globally required on this website
|
||||
|
||||
export const animationStepCount = 10;
|
||||
|
||||
|
1
static/resources/Standalone/.gitignore
vendored
Normal file
1
static/resources/Standalone/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
jszip.min.js
|
Reference in New Issue
Block a user