1
0
Fork 0
mirror of https://github.com/Kozea/Radicale.git synced 2025-06-26 16:45:52 +00:00

Merge pull request #1456 from MatthewHana/v3.2-devel

WEB UI: HREF for Upload, Refresh button, and CSS fixes
This commit is contained in:
Peter Bieringer 2024-03-18 18:41:54 +01:00 committed by GitHub
commit 95cd6938d9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 280 additions and 153 deletions

View file

@ -1,55 +1,72 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; display: block;" width="264px" height="264px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<g transform="rotate(0 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#4e9a06">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
<g transform="matrix(10.8 0 0 10.8 540 540)">
<g style="">
<g transform="matrix(2.64 0 0 2.64 0 -42.24)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(78,154,6); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="-0.8026755852842808s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(27.692307692307693 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#71cc1a">
</g>
<g transform="matrix(2.34 1.23 -1.23 2.34 19.63 -37.4)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(113,204,26); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="-0.7357859531772575s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(55.38461538461539 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#8ce139">
</g>
<g transform="matrix(1.5 2.17 -2.17 1.5 34.76 -24)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(140,225,57); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="-0.6688963210702341s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(83.07692307692308 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#cdff9c">
</g>
<g transform="matrix(0.32 2.62 -2.62 0.32 41.93 -5.09)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(205,255,156); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="-0.6020066889632106s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(110.76923076923077 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#cdf7a6">
</g>
<g transform="matrix(-0.94 2.47 -2.47 -0.94 39.5 14.98)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(205,247,166); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="-0.5351170568561873s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(138.46153846153845 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#fcfcfc">
</g>
<g transform="matrix(-1.98 1.75 -1.75 -1.98 28.01 31.62)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(252,252,252); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="-0.46822742474916385s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(166.15384615384616 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#fefefe">
</g>
<g transform="matrix(-2.56 0.63 -0.63 -2.56 10.11 41.01)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(254,254,254); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="-0.4013377926421404s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(193.84615384615384 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#f4f4f4">
</g>
<g transform="matrix(-2.56 -0.63 0.63 -2.56 -10.11 41.01)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(244,244,244); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="-0.33444816053511706s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(221.53846153846155 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#ffd6d6">
</g>
<g transform="matrix(-1.98 -1.75 1.75 -1.98 -28.01 31.62)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,214,214); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="-0.26755852842809363s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(249.23076923076923 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#f86f6f">
</g>
<g transform="matrix(-0.94 -2.47 2.47 -0.94 -39.5 14.98)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(248,111,111); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="-0.2006688963210702s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(276.9230769230769 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#e73c3c">
</g>
<g transform="matrix(0.32 -2.62 2.62 0.32 -41.93 -5.09)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(231,60,60); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="-0.13377926421404682s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(304.61538461538464 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#da2121">
</g>
<g transform="matrix(1.5 -2.17 2.17 1.5 -34.76 -24)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(218,33,33); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="-0.06688963210702341s" repeatCount="indefinite"></animate>
</rect>
</g><g transform="rotate(332.3076923076923 50 50)">
<rect x="45.5" y="32" rx="0" ry="0" width="9" height="4" fill="#a40000">
</g>
<g transform="matrix(2.34 -1.23 1.23 2.34 -19.63 -37.4)">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(164,0,0); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" x="-4.5" y="-2" rx="0" ry="0" width="9" height="4">
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="0.8695652173913042s" begin="0s" repeatCount="indefinite"></animate>
</rect>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Before After
Before After

View file

@ -103,11 +103,20 @@ main{
color: white;
text-decoration: none;
padding: 3px 10px;
position: absolute;
right: 25px;
position: relative;
border-radius: 4px;
}
#logoutview a[data-name=logout]{
right: 25px;
float: right;
}
#logoutview a[data-name=refresh]{
left: 25px;
float: left;
}
#collectionsscene{
display: flex;
flex-direction: row;
@ -116,11 +125,11 @@ main{
align-items: center;
margin-top: 50px;
width: 100%;
height: calc(100vh - 50px);
height: 100vh;
}
#collectionsscene article{
width: 250px;
width: 275px;
background: rgb(250, 250, 250);
border-radius: 8px;
box-shadow: 2px 2px 3px #0000001a;
@ -129,7 +138,7 @@ main{
padding-top: 0;
margin: 10px;
float: left;
height: 350px;
min-height: 375px;
overflow: hidden;
}
@ -170,11 +179,12 @@ main{
}
#collectionsscene article:hover ul{
display: flex !important;
visibility: visible;
}
#collectionsscene ul{
display: none;
visibility: hidden;
display: flex;
justify-content: space-evenly;
width: 60%;
margin: 0 20%;
@ -216,7 +226,7 @@ main{
#uploadcollectionscene ul{
margin: 10px -30px;
max-height: 600px;
overflow: overlay;
overflow-y: scroll;
}
#uploadcollectionscene li{
@ -225,6 +235,11 @@ main{
padding-bottom: 10px;
}
#uploadcollectionscene div[data-name=pending]{
width: 100%;
text-align: center;
}
#uploadcollectionscene .successmessage{
color: #4e9a06;
width: 100%;
@ -291,6 +306,11 @@ main{
padding-top: 15px;
}
img.loading{
width: 150px;
height: 150px;
}
.error::before{
content: "!";
height: 1em;
@ -391,7 +411,7 @@ button.blue:active, a.blue:active{
#collectionsscene article{
height: auto;
min-height: 350px;
min-height: 375px;
}
.container{
@ -399,10 +419,10 @@ button.blue:active, a.blue:active{
}
#collectionsscene ul{
display: flex !important;
visibility: visible !important;
}
#logoutview span{
text-align: left;
padding: 0 5px;
}
}

View file

@ -542,7 +542,8 @@ function LoginScene() {
let error_form = html_scene.querySelector("[data-name=error]");
let logout_view = document.getElementById("logoutview");
let logout_user_form = logout_view.querySelector("[data-name=user]");
let logout_btn = logout_view.querySelector("[data-name=link]");
let logout_btn = logout_view.querySelector("[data-name=logout]");
let refresh_btn = logout_view.querySelector("[data-name=refresh]");
/** @type {?number} */ let scene_index = null;
let user = "";
@ -573,6 +574,7 @@ function LoginScene() {
// setup logout
logout_view.classList.remove("hidden");
logout_btn.onclick = onlogout;
refresh_btn.onclick = refresh;
logout_user_form.textContent = user + "'s Collections";
// Fetch principal
let loading_scene = new LoadingScene();
@ -623,9 +625,17 @@ function LoginScene() {
function remove_logout() {
logout_view.classList.add("hidden");
logout_btn.onclick = null;
refresh_btn.onclick = null;
logout_user_form.textContent = "";
}
function refresh(){
//The easiest way to refresh is to push a LoadingScene onto the stack and then pop it
//forcing the scene below it, the Collections Scene to refresh itself.
push_scene(new LoadingScene(), false);
pop_scene(scene_stack.length-2);
}
this.show = function() {
remove_logout();
fill_form();
@ -684,12 +694,6 @@ function CollectionsScene(user, password, collection, onerror) {
/** @type {?XMLHttpRequest} */ let collections_req = null;
/** @type {?Array<Collection>} */ let collections = null;
/** @type {Array<Node>} */ let nodes = [];
let filesInput = document.createElement("input");
filesInput.setAttribute("type", "file");
filesInput.setAttribute("accept", ".ics, .vcf");
filesInput.setAttribute("multiple", "");
let filesInputForm = document.createElement("form");
filesInputForm.appendChild(filesInput);
function onnew() {
try {
@ -702,17 +706,9 @@ function CollectionsScene(user, password, collection, onerror) {
}
function onupload() {
filesInput.click();
return false;
}
function onfileschange() {
try {
let files = filesInput.files;
if (files.length > 0) {
let upload_scene = new UploadCollectionScene(user, password, collection, files);
let upload_scene = new UploadCollectionScene(user, password, collection);
push_scene(upload_scene);
}
} catch(err) {
console.error(err);
}
@ -740,6 +736,9 @@ function CollectionsScene(user, password, collection, onerror) {
}
function show_collections(collections) {
let heightOfNavBar = document.querySelector("#logoutview").offsetHeight + "px";
html_scene.style.marginTop = heightOfNavBar;
html_scene.style.height = "calc(100vh - " + heightOfNavBar +")";
collections.forEach(function (collection) {
let node = template.cloneNode(true);
node.classList.remove("hidden");
@ -820,8 +819,6 @@ function CollectionsScene(user, password, collection, onerror) {
html_scene.classList.remove("hidden");
new_btn.onclick = onnew;
upload_btn.onclick = onupload;
filesInputForm.reset();
filesInput.onchange = onfileschange;
if (collections === null) {
update();
} else {
@ -834,7 +831,6 @@ function CollectionsScene(user, password, collection, onerror) {
scene_index = scene_stack.length - 1;
new_btn.onclick = null;
upload_btn.onclick = null;
filesInput.onchange = null;
collections = null;
// remove collection
nodes.forEach(function(node) {
@ -849,7 +845,6 @@ function CollectionsScene(user, password, collection, onerror) {
collections_req = null;
}
collections = null;
filesInputForm.reset();
};
}
@ -861,43 +856,89 @@ function CollectionsScene(user, password, collection, onerror) {
* @param {Collection} collection parent collection
* @param {Array<File>} files
*/
function UploadCollectionScene(user, password, collection, files) {
function UploadCollectionScene(user, password, collection) {
let html_scene = document.getElementById("uploadcollectionscene");
let template = html_scene.querySelector("[data-name=filetemplate]");
let upload_btn = html_scene.querySelector("[data-name=submit]");
let close_btn = html_scene.querySelector("[data-name=close]");
let uploadfile_form = html_scene.querySelector("[data-name=uploadfile]");
let uploadfile_lbl = html_scene.querySelector("label[for=uploadfile]");
let href_form = html_scene.querySelector("[data-name=href]");
let href_label = html_scene.querySelector("label[for=href]");
let hreflimitmsg_html = html_scene.querySelector("[data-name=hreflimitmsg]");
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 href = random_uuid();
href_form.value = href;
/** @type {?number} */ let scene_index = null;
/** @type {?XMLHttpRequest} */ let upload_req = null;
/** @type {Array<string>} */ let errors = [];
/** @type {Array<string>} */ let results = [];
/** @type {?Array<Node>} */ let nodes = null;
function upload_next() {
function upload_start() {
try {
if (files.length === errors.length) {
if (errors.every(error => error === null)) {
pop_scene(scene_index - 1);
} else {
close_btn.classList.remove("hidden");
if(!read_form()){
return false;
}
} else {
let file = files[errors.length];
let upload_href = collection.href + random_uuid() + "/";
upload_req = upload_collection(user, password, upload_href, file, function(error) {
if (scene_index === null) {
return;
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 = 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_req = null;
errors.push(error);
updateFileStatus(errors.length - 1);
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);
@ -911,54 +952,77 @@ function UploadCollectionScene(user, password, collection, files) {
if (nodes === null) {
return;
}
let pending_form = nodes[i].querySelector("[data-name=pending]");
let success_form = nodes[i].querySelector("[data-name=success]");
let error_form = nodes[i].querySelector("[data-name=error]");
if (errors.length > i) {
pending_form.classList.add("hidden");
if (errors[i]) {
if (results.length > i) {
if (results[i]) {
success_form.classList.add("hidden");
error_form.textContent = "Error: " + errors[i];
error_form.textContent = "Error: " + results[i];
error_form.classList.remove("hidden");
} else {
success_form.classList.remove("hidden");
error_form.classList.add("hidden");
}
} else {
pending_form.classList.remove("hidden");
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;
}
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");
}else{
hreflimitmsg_html.classList.add("hidden");
href_form.classList.remove("hidden");
href_label.classList.remove("hidden");
}
return false;
}
this.show = function() {
html_scene.classList.remove("hidden");
if (errors.length < files.length) {
close_btn.classList.add("hidden");
}
close_btn.onclick = onclose;
nodes = [];
for (let i = 0; i < files.length; i++) {
let file = files[i];
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 (scene_index === null) {
scene_index = scene_stack.length - 1;
upload_next();
}
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);
});
@ -1142,7 +1206,7 @@ function CreateEditCollectionScene(user, password, collection) {
function read_form() {
if(!edit){
cleanHREFinput();
cleanHREFinput(href_form);
let newhreftxtvalue = href_form.value.trim().toLowerCase();
if(!isValidHREF(newhreftxtvalue)){
alert("You must enter a valid HREF");
@ -1226,12 +1290,6 @@ function CreateEditCollectionScene(user, password, collection) {
return false;
}
function cleanHREFinput(event){
let currentTxtVal = href_form.value.trim().toLowerCase();
//Clean the HREF to remove non lowercase letters and dashes
currentTxtVal = currentTxtVal.replace(/(?![0-9a-z\-\_])./g, '');
href_form.value = currentTxtVal;
}
function onTypeChange(e){
if(type_form.value == CollectionType.WEBCAL){
@ -1243,17 +1301,6 @@ function CreateEditCollectionScene(user, password, collection) {
}
}
function isValidHREF(href){
if(href.length < 1){
return false;
}
if(href.indexOf("/") != -1){
return false;
}
return true;
}
this.show = function() {
this.release();
scene_index = scene_stack.length - 1;
@ -1289,6 +1336,40 @@ function CreateEditCollectionScene(user, password, collection) {
};
}
/**
* Removed invalid HREF characters for a collection HREF.
*
* @param a A valid Input element or an onchange Event of an Input element.
*/
function cleanHREFinput(a) {
let href_form = a;
if (a.target) {
href_form = a.target;
}
let currentTxtVal = href_form.value.trim().toLowerCase();
//Clean the HREF to remove non lowercase letters and dashes
currentTxtVal = currentTxtVal.replace(/(?![0-9a-z\-\_])./g, '');
href_form.value = currentTxtVal;
}
/**
* Checks if a proposed HREF for a collection has a valid format and syntax.
*
* @param href String of the porposed HREF.
*
* @return Boolean results if the HREF is valid.
*/
function isValidHREF(href) {
if (href.length < 1) {
return false;
}
if (href.indexOf("/") != -1) {
return false;
}
return true;
}
/**
* Format bytes to human-readable text.
*

View file

@ -14,12 +14,13 @@
<body>
<nav id="logoutview" class="hidden">
<span data-name="user" style="word-wrap:break-word;"></span>
<a href="" class="red" data-name="link" title="Logout">Logout</a>
<a href="#" class="green" data-name="refresh" title="Refresh">Refresh</a>
<a href="#" class="red" data-name="logout" title="Logout">Logout</a>
</nav>
<main>
<section id="loadingscene">
<img src="css/loading.svg" alt="Loading">
<img src="css/loading.svg" alt="Loading..." class="loading">
<h2>Loading</h2>
<p>Please wait...</p>
<noscript>JavaScript is required</noscript>
@ -155,12 +156,20 @@
<ul>
<li data-name="filetemplate" class="hidden"> Uploading <span data-name="name">name</span>
<br>
<img data-name="pending" src="css/loading.svg" alt="Please wait...">
<span class="successmessage" data-name="success">Uploaded Successfully!</span>
<span class="error" data-name="error"></span>
</li>
</ul>
<div data-name="pending" class="hidden">
<img src="css/loading.svg" class="loading" alt="Please wait..."/>
</div>
<form>
<label for="uploadfile">File:</label>
<input data-name="uploadfile" type="file" accept=".ics, .vcf" multiple>
<label for="href">HREF:</label>
<input data-name="href" type="text">
<small data-name="hreflimitmsg" class="hidden">You can only specify the HREF if you upload 1 file.</small>
<button type="submit" class="green" data-name="submit">Upload</button>
<button type="button" class="red" data-name="close">Close</button>
</form>
</section>