Allow only valid hrefs in newShare for map
This commit is contained in:
@@ -23,18 +23,19 @@ import { create_collection, edit_collection } from "./api.js";
|
||||
import { COLOR_RE } from "./constants.js";
|
||||
import { Collection, CollectionType } from "./models.js";
|
||||
import { Scene, pop_scene, push_scene, scene_stack } from "./scene_manager.js";
|
||||
import { cleanHREFinput, isValidHREF, random_hex, random_uuid } from "./utils.js";
|
||||
import { cleanHREFinput, isValidHREF, onCleanHREFinput, random_hex, random_uuid } from "./utils.js";
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @implements {Scene}
|
||||
* @param {string} user
|
||||
* @param {string} password
|
||||
* @param {Collection} collection if it's a principal collection, a new
|
||||
* collection will be created inside of it.
|
||||
* Otherwise the collection will be edited.
|
||||
*/
|
||||
export class CreateEditCollectionScene {
|
||||
/**
|
||||
* @param {string} user
|
||||
* @param {string} password
|
||||
* @param {Collection} collection if it's a principal collection, a new
|
||||
* collection will be created inside of it.
|
||||
* Otherwise the collection will be edited.
|
||||
*/
|
||||
constructor(user, password, collection) {
|
||||
let edit = collection.type !== CollectionType.PRINCIPAL;
|
||||
let html_scene = document.getElementById(edit ? "editcollectionscene" : "createcollectionscene");
|
||||
@@ -69,7 +70,7 @@ export class CreateEditCollectionScene {
|
||||
let color = edit && collection.color ? collection.color : "#" + random_hex(6);
|
||||
|
||||
if (!edit) {
|
||||
href_form.addEventListener("keydown", cleanHREFinput);
|
||||
href_form.addEventListener("input", onCleanHREFinput);
|
||||
}
|
||||
|
||||
function remove_invalid_types() {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
import { add_share_by_map, add_share_by_token } from "./api.js";
|
||||
import { Scene, pop_scene, scene_stack } from "./scene_manager.js";
|
||||
import { onCleanHREFinput } from "./utils.js";
|
||||
|
||||
/**
|
||||
* @implements {Scene}
|
||||
@@ -45,6 +46,8 @@ export class NewShareScene {
|
||||
/** @type {HTMLInputElement} */ let properties_input = html_scene.querySelector("[data-name=properties]");
|
||||
/** @type {HTMLElement} */ let cancel_btn = html_scene.querySelector("[data-name=cancel]");
|
||||
|
||||
sharehref_input.addEventListener("input", onCleanHREFinput);
|
||||
|
||||
/** @type {?number} */ let scene_index = null;
|
||||
|
||||
function oncancel() {
|
||||
|
||||
@@ -20,195 +20,198 @@
|
||||
|
||||
import { Scene, pop_scene, scene_stack } from "./scene_manager.js";
|
||||
import { Collection } from "./models.js";
|
||||
import { cleanHREFinput, isValidHREF, random_uuid } from "./utils.js";
|
||||
import { cleanHREFinput, isValidHREF, onCleanHREFinput, random_uuid } from "./utils.js";
|
||||
import { upload_collection } from "./api.js";
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @implements {Scene}
|
||||
* @param {string} user
|
||||
* @param {string} password
|
||||
* @param {Collection} collection parent collection
|
||||
*/
|
||||
export function UploadCollectionScene(user, password, collection) {
|
||||
/** @type {HTMLElement} */ let html_scene = document.getElementById("uploadcollectionscene");
|
||||
/** @type {HTMLElement} */ let template = html_scene.querySelector("[data-name=filetemplate]");
|
||||
/** @type {HTMLElement} */ let upload_btn = html_scene.querySelector("[data-name=submit]");
|
||||
/** @type {HTMLElement} */ let close_btn = html_scene.querySelector("[data-name=close]");
|
||||
/** @type {HTMLInputElement} */ let uploadfile_form = html_scene.querySelector("[data-name=uploadfile]");
|
||||
/** @type {HTMLElement} */ let uploadfile_lbl = html_scene.querySelector("label[for=uploadfile]");
|
||||
/** @type {HTMLInputElement} */ let href_form = html_scene.querySelector("[data-name=href]");
|
||||
/** @type {HTMLElement} */ let href_label = html_scene.querySelector("label[for=href]");
|
||||
/** @type {HTMLElement} */ let hreflimitmsg_html = html_scene.querySelector("[data-name=hreflimitmsg]");
|
||||
/** @type {HTMLElement} */ let pending_html = html_scene.querySelector("[data-name=pending]");
|
||||
export class UploadCollectionScene {
|
||||
/**
|
||||
* @param {string} user
|
||||
* @param {string} password
|
||||
* @param {Collection} collection parent collection
|
||||
*/
|
||||
constructor(user, password, collection) {
|
||||
/** @type {HTMLElement} */ let html_scene = document.getElementById("uploadcollectionscene");
|
||||
/** @type {HTMLElement} */ let template = html_scene.querySelector("[data-name=filetemplate]");
|
||||
/** @type {HTMLElement} */ let upload_btn = html_scene.querySelector("[data-name=submit]");
|
||||
/** @type {HTMLElement} */ let close_btn = html_scene.querySelector("[data-name=close]");
|
||||
/** @type {HTMLInputElement} */ let uploadfile_form = html_scene.querySelector("[data-name=uploadfile]");
|
||||
/** @type {HTMLElement} */ let uploadfile_lbl = html_scene.querySelector("label[for=uploadfile]");
|
||||
/** @type {HTMLInputElement} */ let href_form = html_scene.querySelector("[data-name=href]");
|
||||
/** @type {HTMLElement} */ let href_label = html_scene.querySelector("label[for=href]");
|
||||
/** @type {HTMLElement} */ let hreflimitmsg_html = html_scene.querySelector("[data-name=hreflimitmsg]");
|
||||
/** @type {HTMLElement} */ let pending_html = html_scene.querySelector("[data-name=pending]");
|
||||
|
||||
let files = uploadfile_form.files;
|
||||
href_form.addEventListener("keydown", cleanHREFinput);
|
||||
upload_btn.onclick = upload_start;
|
||||
uploadfile_form.onchange = onfileschange;
|
||||
let files = uploadfile_form.files;
|
||||
href_form.addEventListener("input", onCleanHREFinput);
|
||||
upload_btn.onclick = upload_start;
|
||||
uploadfile_form.onchange = onfileschange;
|
||||
|
||||
href_form.value = "";
|
||||
let href = "";
|
||||
href_form.value = "";
|
||||
let href = "";
|
||||
|
||||
/** @type {?number} */ let scene_index = null;
|
||||
/** @type {?XMLHttpRequest} */ let upload_req = null;
|
||||
/** @type {Array<string>} */ let results = [];
|
||||
/** @type {?Array<HTMLElement>} */ let nodes = null;
|
||||
/** @type {?number} */ let scene_index = null;
|
||||
/** @type {?XMLHttpRequest} */ let upload_req = null;
|
||||
/** @type {Array<string>} */ let results = [];
|
||||
/** @type {?Array<HTMLElement>} */ let nodes = null;
|
||||
|
||||
function upload_start() {
|
||||
try {
|
||||
if(!read_form()){
|
||||
function upload_start() {
|
||||
try {
|
||||
if (!read_form()) {
|
||||
return false;
|
||||
}
|
||||
uploadfile_form.classList.add("hidden");
|
||||
uploadfile_lbl.classList.add("hidden");
|
||||
href_form.classList.add("hidden");
|
||||
href_label.classList.add("hidden");
|
||||
hreflimitmsg_html.classList.add("hidden");
|
||||
upload_btn.classList.add("hidden");
|
||||
close_btn.classList.add("hidden");
|
||||
|
||||
pending_html.classList.remove("hidden");
|
||||
|
||||
nodes = [];
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
let file = files[i];
|
||||
let node = /** @type {HTMLElement} */ (template.cloneNode(true));
|
||||
node.classList.remove("hidden");
|
||||
let name_form = node.querySelector("[data-name=name]");
|
||||
name_form.textContent = file.name;
|
||||
node.classList.remove("hidden");
|
||||
nodes.push(node);
|
||||
updateFileStatus(i);
|
||||
template.parentNode.insertBefore(node, template);
|
||||
}
|
||||
upload_next();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function upload_next() {
|
||||
try {
|
||||
if (files.length === results.length) {
|
||||
pending_html.classList.add("hidden");
|
||||
close_btn.classList.remove("hidden");
|
||||
return;
|
||||
} else {
|
||||
let file = files[results.length];
|
||||
if (files.length > 1 || href.length == 0) {
|
||||
href = random_uuid();
|
||||
}
|
||||
let upload_href = collection.href + href + "/";
|
||||
upload_req = upload_collection(user, password, upload_href, file, function (result) {
|
||||
upload_req = null;
|
||||
results.push(result);
|
||||
updateFileStatus(results.length - 1);
|
||||
upload_next();
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
function onclose() {
|
||||
try {
|
||||
pop_scene(scene_index - 1);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function updateFileStatus(i) {
|
||||
if (nodes === null) {
|
||||
return;
|
||||
}
|
||||
let success_form = nodes[i].querySelector("[data-name=success]");
|
||||
let error_form = nodes[i].querySelector("[data-name=error]");
|
||||
if (results.length > i) {
|
||||
if (results[i]) {
|
||||
success_form.classList.add("hidden");
|
||||
error_form.textContent = "Error: " + results[i];
|
||||
error_form.classList.remove("hidden");
|
||||
} else {
|
||||
success_form.classList.remove("hidden");
|
||||
error_form.classList.add("hidden");
|
||||
}
|
||||
} else {
|
||||
success_form.classList.add("hidden");
|
||||
error_form.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function read_form() {
|
||||
cleanHREFinput(href_form);
|
||||
let newhreftxtvalue = href_form.value.trim().toLowerCase();
|
||||
if (!isValidHREF(newhreftxtvalue)) {
|
||||
alert("You must enter a valid HREF");
|
||||
return false;
|
||||
}
|
||||
uploadfile_form.classList.add("hidden");
|
||||
uploadfile_lbl.classList.add("hidden");
|
||||
href_form.classList.add("hidden");
|
||||
href_label.classList.add("hidden");
|
||||
hreflimitmsg_html.classList.add("hidden");
|
||||
upload_btn.classList.add("hidden");
|
||||
close_btn.classList.add("hidden");
|
||||
href = newhreftxtvalue;
|
||||
|
||||
pending_html.classList.remove("hidden");
|
||||
|
||||
nodes = [];
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
let file = files[i];
|
||||
/** @type {HTMLElement} */ let node = template.cloneNode(true);
|
||||
node.classList.remove("hidden");
|
||||
let name_form = node.querySelector("[data-name=name]");
|
||||
name_form.textContent = file.name;
|
||||
node.classList.remove("hidden");
|
||||
nodes.push(node);
|
||||
updateFileStatus(i);
|
||||
template.parentNode.insertBefore(node, template);
|
||||
if (uploadfile_form.files.length == 0) {
|
||||
alert("You must select at least one file to upload");
|
||||
return false;
|
||||
}
|
||||
upload_next();
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
files = uploadfile_form.files;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function upload_next(){
|
||||
try{
|
||||
if (files.length === results.length) {
|
||||
pending_html.classList.add("hidden");
|
||||
close_btn.classList.remove("hidden");
|
||||
return;
|
||||
function onfileschange() {
|
||||
files = uploadfile_form.files;
|
||||
if (files.length > 1) {
|
||||
hreflimitmsg_html.classList.remove("hidden");
|
||||
href_form.classList.add("hidden");
|
||||
href_label.classList.add("hidden");
|
||||
href_form.value = random_uuid(); // dummy, will be replaced on upload
|
||||
} else {
|
||||
let file = files[results.length];
|
||||
if(files.length > 1 || href.length == 0){
|
||||
href = random_uuid();
|
||||
}
|
||||
let upload_href = collection.href + href + "/";
|
||||
upload_req = upload_collection(user, password, upload_href, file, function(result) {
|
||||
upload_req = null;
|
||||
results.push(result);
|
||||
updateFileStatus(results.length - 1);
|
||||
upload_next();
|
||||
});
|
||||
hreflimitmsg_html.classList.add("hidden");
|
||||
href_form.classList.remove("hidden");
|
||||
href_label.classList.remove("hidden");
|
||||
href_form.value = files[0].name.replace(/\.(ics|vcf)$/, '');
|
||||
}
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
function onclose() {
|
||||
try {
|
||||
pop_scene(scene_index - 1);
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function updateFileStatus(i) {
|
||||
if (nodes === null) {
|
||||
return;
|
||||
}
|
||||
let success_form = nodes[i].querySelector("[data-name=success]");
|
||||
let error_form = nodes[i].querySelector("[data-name=error]");
|
||||
if (results.length > i) {
|
||||
if (results[i]) {
|
||||
success_form.classList.add("hidden");
|
||||
error_form.textContent = "Error: " + results[i];
|
||||
error_form.classList.remove("hidden");
|
||||
} else {
|
||||
success_form.classList.remove("hidden");
|
||||
error_form.classList.add("hidden");
|
||||
}
|
||||
} else {
|
||||
success_form.classList.add("hidden");
|
||||
error_form.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function read_form() {
|
||||
cleanHREFinput(href_form);
|
||||
let newhreftxtvalue = href_form.value.trim().toLowerCase();
|
||||
if(!isValidHREF(newhreftxtvalue)){
|
||||
alert("You must enter a valid HREF");
|
||||
return false;
|
||||
}
|
||||
href = newhreftxtvalue;
|
||||
|
||||
if(uploadfile_form.files.length == 0){
|
||||
alert("You must select at least one file to upload");
|
||||
return false;
|
||||
}
|
||||
files = uploadfile_form.files;
|
||||
return true;
|
||||
}
|
||||
this.show = function () {
|
||||
scene_index = scene_stack.length - 1;
|
||||
html_scene.classList.remove("hidden");
|
||||
close_btn.onclick = onclose;
|
||||
};
|
||||
|
||||
function onfileschange() {
|
||||
files = uploadfile_form.files;
|
||||
if(files.length > 1){
|
||||
hreflimitmsg_html.classList.remove("hidden");
|
||||
href_form.classList.add("hidden");
|
||||
href_label.classList.add("hidden");
|
||||
href_form.value = random_uuid(); // dummy, will be replaced on upload
|
||||
}else{
|
||||
hreflimitmsg_html.classList.add("hidden");
|
||||
this.hide = function () {
|
||||
html_scene.classList.add("hidden");
|
||||
close_btn.classList.remove("hidden");
|
||||
upload_btn.classList.remove("hidden");
|
||||
uploadfile_form.classList.remove("hidden");
|
||||
uploadfile_lbl.classList.remove("hidden");
|
||||
href_form.classList.remove("hidden");
|
||||
href_label.classList.remove("hidden");
|
||||
href_form.value = files[0].name.replace(/\.(ics|vcf)$/, '');
|
||||
}
|
||||
return false;
|
||||
hreflimitmsg_html.classList.add("hidden");
|
||||
pending_html.classList.add("hidden");
|
||||
close_btn.onclick = null;
|
||||
upload_btn.onclick = null;
|
||||
href_form.value = "";
|
||||
uploadfile_form.value = "";
|
||||
if (nodes == null) {
|
||||
return;
|
||||
}
|
||||
nodes.forEach(function (node) {
|
||||
node.parentNode.removeChild(node);
|
||||
});
|
||||
nodes = null;
|
||||
};
|
||||
this.release = function () {
|
||||
scene_index = null;
|
||||
if (upload_req !== null) {
|
||||
upload_req.abort();
|
||||
upload_req = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
this.show = function() {
|
||||
scene_index = scene_stack.length - 1;
|
||||
html_scene.classList.remove("hidden");
|
||||
close_btn.onclick = onclose;
|
||||
};
|
||||
|
||||
this.hide = function() {
|
||||
html_scene.classList.add("hidden");
|
||||
close_btn.classList.remove("hidden");
|
||||
upload_btn.classList.remove("hidden");
|
||||
uploadfile_form.classList.remove("hidden");
|
||||
uploadfile_lbl.classList.remove("hidden");
|
||||
href_form.classList.remove("hidden");
|
||||
href_label.classList.remove("hidden");
|
||||
hreflimitmsg_html.classList.add("hidden");
|
||||
pending_html.classList.add("hidden");
|
||||
close_btn.onclick = null;
|
||||
upload_btn.onclick = null;
|
||||
href_form.value = "";
|
||||
uploadfile_form.value = "";
|
||||
if(nodes == null){
|
||||
return;
|
||||
}
|
||||
nodes.forEach(function(node) {
|
||||
node.parentNode.removeChild(node);
|
||||
});
|
||||
nodes = null;
|
||||
};
|
||||
this.release = function() {
|
||||
scene_index = null;
|
||||
if (upload_req !== null) {
|
||||
upload_req.abort();
|
||||
upload_req = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -25,11 +25,11 @@
|
||||
*/
|
||||
export function escape_xml(s) {
|
||||
return (s
|
||||
.replace(/&/g, "&")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">"));
|
||||
.replace(/&/g, "&")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,19 +47,18 @@ export function random_uuid() {
|
||||
export function random_hex(length) {
|
||||
let bytes = new Uint8Array(Math.ceil(length / 2));
|
||||
window.crypto.getRandomValues(bytes);
|
||||
return bytes.reduce((s, b) => s + b.toString(16).padStart(2, "0"), "").substring(0, length);
|
||||
// Fallback for compatibility with older browsers which may not have padStart
|
||||
return bytes.reduce((s, b) => {
|
||||
let hex = b.toString(16);
|
||||
return s + (String.prototype["padStart"] ? hex["padStart"](2, "0") : ("0" + hex).slice(-2));
|
||||
}, "").substring(0, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removed invalid HREF characters for a collection HREF.
|
||||
*
|
||||
* @param a A valid Input element or an onchange Event of an Input element.
|
||||
* @param {HTMLInputElement} href_form A valid Input element or an onchange Event of an Input element.
|
||||
*/
|
||||
export function cleanHREFinput(a) {
|
||||
let href_form = a;
|
||||
if (a.target) {
|
||||
href_form = a.target;
|
||||
}
|
||||
export function cleanHREFinput(href_form) {
|
||||
let currentTxtVal = href_form.value.trim().toLowerCase();
|
||||
//Clean the HREF to remove not permitted chars
|
||||
currentTxtVal = currentTxtVal.replace(/(?![0-9a-z\-\_\.])./g, '');
|
||||
@@ -68,11 +67,19 @@ export function cleanHREFinput(a) {
|
||||
href_form.value = currentTxtVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event listener for cleaning HREF input.
|
||||
* @param {Event} event
|
||||
*/
|
||||
export function onCleanHREFinput(event) {
|
||||
if (event.target instanceof HTMLInputElement) {
|
||||
cleanHREFinput(event.target);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a proposed HREF for a collection has a valid format and syntax.
|
||||
*
|
||||
* @param href String of the porposed HREF.
|
||||
*
|
||||
* @param {string} href String of the proposed HREF.
|
||||
* @return Boolean results if the HREF is valid.
|
||||
*/
|
||||
export function isValidHREF(href) {
|
||||
@@ -88,16 +95,15 @@ export function isValidHREF(href) {
|
||||
|
||||
/**
|
||||
* Format bytes to human-readable text.
|
||||
*
|
||||
* @param bytes Number of bytes.
|
||||
*
|
||||
* @param {number} bytes Number of bytes.
|
||||
* @return Formatted string.
|
||||
*/
|
||||
export function bytesToHumanReadable(bytes, dp=1) {
|
||||
let isNumber = !isNaN(parseFloat(bytes)) && !isNaN(bytes - 0);
|
||||
if(!isNumber){
|
||||
export function bytesToHumanReadable(bytes) {
|
||||
if (isNaN(bytes - 0)) {
|
||||
return "";
|
||||
}
|
||||
var i = bytes == 0 ? 0 : Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
return (bytes / Math.pow(1024, i)).toFixed(dp) * 1 + ' ' + ['b', 'kb', 'mb', 'gb', 'tb'][i];
|
||||
const units = ['b', 'kb', 'mb', 'gb', 'tb'];
|
||||
let i = bytes == 0 ? 0 : Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
i = Math.min(i, units.length - 1);
|
||||
return (bytes / Math.pow(1024, i)) + ' ' + units[i];
|
||||
}
|
||||
Reference in New Issue
Block a user