add upload dialog to web interface
This commit is contained in:
parent
30a9ecc06b
commit
53b064bc2f
@ -263,6 +263,31 @@ function get_collections(user, password, collection, callback) {
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} user
|
||||||
|
* @param {string} password
|
||||||
|
* @param {string} collection_href Must always start and end with /.
|
||||||
|
* @param {File} file
|
||||||
|
* @param {function(?string)} callback Returns error or null
|
||||||
|
* @return {XMLHttpRequest}
|
||||||
|
*/
|
||||||
|
function upload_collection(user, password, collection_href, file, callback) {
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open("PUT", SERVER + collection_href, true, user, password);
|
||||||
|
request.onreadystatechange = function() {
|
||||||
|
if (request.readyState !== 4) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (200 <= request.status && request.status < 300) {
|
||||||
|
callback(null);
|
||||||
|
} else {
|
||||||
|
callback(request.status + " " + request.statusText);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
request.send(file);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} user
|
* @param {string} user
|
||||||
* @param {string} password
|
* @param {string} password
|
||||||
@ -383,6 +408,13 @@ function edit_collection(user, password, collection, callback) {
|
|||||||
return create_edit_collection(user, password, collection, false, callback);
|
return create_edit_collection(user, password, collection, false, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function random_uuid() {
|
||||||
|
return randHex(8) + "-" + randHex(4) + "-" + randHex(4) + "-" + randHex(4) + "-" + randHex(12);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @interface
|
* @interface
|
||||||
*/
|
*/
|
||||||
@ -603,6 +635,7 @@ function CollectionsScene(user, password, collection, onerror) {
|
|||||||
var html_scene = document.getElementById("collectionsscene");
|
var html_scene = document.getElementById("collectionsscene");
|
||||||
var template = html_scene.querySelector("[name=collectiontemplate]");
|
var template = html_scene.querySelector("[name=collectiontemplate]");
|
||||||
var new_btn = html_scene.querySelector("[name=new]");
|
var new_btn = html_scene.querySelector("[name=new]");
|
||||||
|
var upload_btn = html_scene.querySelector("[name=upload]");
|
||||||
|
|
||||||
/** @type {?number} */ var scene_index = null;
|
/** @type {?number} */ var scene_index = null;
|
||||||
var saved_template_display = null;
|
var saved_template_display = null;
|
||||||
@ -611,6 +644,12 @@ function CollectionsScene(user, password, collection, onerror) {
|
|||||||
var from_update = false;
|
var from_update = false;
|
||||||
/** @type {?Array<Collection>} */ var collections = null;
|
/** @type {?Array<Collection>} */ var collections = null;
|
||||||
/** @type {Array<Node>} */ var nodes = [];
|
/** @type {Array<Node>} */ var nodes = [];
|
||||||
|
var filesInput = document.createElement("input");
|
||||||
|
filesInput.setAttribute("type", "file");
|
||||||
|
filesInput.setAttribute("accept", ".ics, .vcf");
|
||||||
|
filesInput.setAttribute("multiple", "");
|
||||||
|
var filesInputForm = document.createElement("form");
|
||||||
|
filesInputForm.appendChild(filesInput);
|
||||||
|
|
||||||
function onnew() {
|
function onnew() {
|
||||||
try {
|
try {
|
||||||
@ -622,6 +661,24 @@ function CollectionsScene(user, password, collection, onerror) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onupload() {
|
||||||
|
filesInput.click();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onfileschange(e) {
|
||||||
|
try {
|
||||||
|
var files = filesInput.files;
|
||||||
|
if (files.length > 0) {
|
||||||
|
var upload_scene = new UploadCollectionScene(user, password, collection, files);
|
||||||
|
push_scene(upload_scene);
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function onedit(collection) {
|
function onedit(collection) {
|
||||||
try {
|
try {
|
||||||
var edit_collection_scene = new CreateEditCollectionScene(user, password, collection);
|
var edit_collection_scene = new CreateEditCollectionScene(user, password, collection);
|
||||||
@ -722,6 +779,9 @@ function CollectionsScene(user, password, collection, onerror) {
|
|||||||
template.style.display = "none";
|
template.style.display = "none";
|
||||||
html_scene.style.display = "block";
|
html_scene.style.display = "block";
|
||||||
new_btn.onclick = onnew;
|
new_btn.onclick = onnew;
|
||||||
|
upload_btn.onclick = onupload;
|
||||||
|
filesInputForm.reset();
|
||||||
|
filesInput.onchange = onfileschange;
|
||||||
if (scene_index === null) {
|
if (scene_index === null) {
|
||||||
scene_index = scene_stack.length - 1;
|
scene_index = scene_stack.length - 1;
|
||||||
if (collections === null && collections_req !== null) {
|
if (collections === null && collections_req !== null) {
|
||||||
@ -744,6 +804,8 @@ function CollectionsScene(user, password, collection, onerror) {
|
|||||||
html_scene.style.display = "none";
|
html_scene.style.display = "none";
|
||||||
template.style.display = saved_template_display;
|
template.style.display = saved_template_display;
|
||||||
new_btn.onclick = null;
|
new_btn.onclick = null;
|
||||||
|
upload_btn.onclick = null;
|
||||||
|
filesInput.onchange = null;
|
||||||
if (timer !== null) {
|
if (timer !== null) {
|
||||||
window.clearTimeout(timer);
|
window.clearTimeout(timer);
|
||||||
timer = null;
|
timer = null;
|
||||||
@ -761,6 +823,137 @@ function CollectionsScene(user, password, collection, onerror) {
|
|||||||
collections_req.abort();
|
collections_req.abort();
|
||||||
collections_req = null;
|
collections_req = null;
|
||||||
}
|
}
|
||||||
|
filesInputForm.reset();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @implements {Scene}
|
||||||
|
* @param {string} user
|
||||||
|
* @param {string} password
|
||||||
|
* @param {Collection} collection parent collection
|
||||||
|
* @param {Array<File>} files
|
||||||
|
*/
|
||||||
|
function UploadCollectionScene(user, password, collection, files) {
|
||||||
|
var html_scene = document.getElementById("uploadcollectionscene");
|
||||||
|
var template = html_scene.querySelector("[name=filetemplate]");
|
||||||
|
var template_pending_form = template.querySelector("[name=pending]");
|
||||||
|
var template_success_form = template.querySelector("[name=success]");
|
||||||
|
var template_error_form = template.querySelector("[name=error]");
|
||||||
|
var saved_template_display = null;
|
||||||
|
var close_btn = html_scene.querySelector("[name=close]");
|
||||||
|
var saved_close_btn_display = null;
|
||||||
|
|
||||||
|
/** @type {?number} */ var scene_index = null;
|
||||||
|
/** @type {?XMLHttpRequest} */ var upload_req = null;
|
||||||
|
/** @type {Array<string>} */ var errors = [];
|
||||||
|
/** @type {?Array<Node>} */ var nodes = null;
|
||||||
|
|
||||||
|
function upload_next() {
|
||||||
|
try {
|
||||||
|
if (files.length === errors.length) {
|
||||||
|
if (errors.every(error => error === null)) {
|
||||||
|
pop_scene(scene_index - 1);
|
||||||
|
} else {
|
||||||
|
close_btn.style.display = saved_close_btn_display;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var file = files[errors.length];
|
||||||
|
var upload_href = collection.href + random_uuid() + "/";
|
||||||
|
upload_req = upload_collection(user, password, upload_href, file, function(error) {
|
||||||
|
if (scene_index === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
upload_req = null;
|
||||||
|
errors.push(error);
|
||||||
|
updateFileStatus(errors.length - 1);
|
||||||
|
upload_next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onclose() {
|
||||||
|
try {
|
||||||
|
pop_scene(scene_index - 1);
|
||||||
|
} catch(err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFileStatus(i) {
|
||||||
|
if (nodes === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(i);
|
||||||
|
console.log(nodes);
|
||||||
|
var pending_form = nodes[i].querySelector("[name=pending]");
|
||||||
|
var success_form = nodes[i].querySelector("[name=success]");
|
||||||
|
var error_form = nodes[i].querySelector("[name=error]");
|
||||||
|
if (errors.length > i) {
|
||||||
|
pending_form.style.display = "none";
|
||||||
|
if (errors[i]) {
|
||||||
|
success_form.style.display = "none";
|
||||||
|
error_form.textContent = "Error: " + errors[i];
|
||||||
|
error_form.style.display = template_error_form.style.display;
|
||||||
|
} else {
|
||||||
|
success_form.style.display = template_success_form.style.display;
|
||||||
|
error_form.style.display = "none";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pending_form.style.display = template_pending_form.style.display;
|
||||||
|
success_form.style.display = "none";
|
||||||
|
error_form.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.show = function() {
|
||||||
|
saved_template_display = template.style.display;
|
||||||
|
template.style.display = "none";
|
||||||
|
html_scene.style.display = "block";
|
||||||
|
saved_close_btn_display = close_btn.style.display;
|
||||||
|
if (errors.length < files.length) {
|
||||||
|
close_btn.style.display = "none";
|
||||||
|
}
|
||||||
|
close_btn.onclick = onclose;
|
||||||
|
nodes = [];
|
||||||
|
for (var i = 0; i < files.length; i++) {
|
||||||
|
var file = files[i];
|
||||||
|
var node = template.cloneNode(true);
|
||||||
|
var name_form = node.querySelector("[name=name]");
|
||||||
|
name_form.textContent = file.name;
|
||||||
|
node.style.display = saved_template_display;
|
||||||
|
nodes.push(node);
|
||||||
|
updateFileStatus(i);
|
||||||
|
template.parentNode.insertBefore(node,template);
|
||||||
|
}
|
||||||
|
if (scene_index === null) {
|
||||||
|
scene_index = scene_stack.length - 1;
|
||||||
|
upload_next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.hide = function() {
|
||||||
|
html_scene.style.display = "none";
|
||||||
|
template.style.display = saved_template_display;
|
||||||
|
close_btn.style.display = saved_close_btn_display;
|
||||||
|
close_btn.onclick = null;
|
||||||
|
nodes.forEach(function(node) {
|
||||||
|
template.parentNode.removeChild(node);
|
||||||
|
});
|
||||||
|
nodes = null;
|
||||||
|
};
|
||||||
|
this.release = function() {
|
||||||
|
scene_index = null;
|
||||||
|
if (upload_req !== null) {
|
||||||
|
upload_req.abort();
|
||||||
|
upload_req = null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -876,9 +1069,7 @@ function CreateEditCollectionScene(user, password, collection) {
|
|||||||
var error = "";
|
var error = "";
|
||||||
/** @type {?Element} */ var saved_type_form = null;
|
/** @type {?Element} */ var saved_type_form = null;
|
||||||
|
|
||||||
var href = edit ? collection.href : (
|
var href = edit ? collection.href : collection.href + random_uuid() + "/";
|
||||||
collection.href + randHex(8) + "-" + randHex(4) + "-" + randHex(4) +
|
|
||||||
"-" + randHex(4) + "-" + randHex(12) + "/");
|
|
||||||
var displayname = edit ? collection.displayname : "";
|
var displayname = edit ? collection.displayname : "";
|
||||||
var description = edit ? collection.description : "";
|
var description = edit ? collection.description : "";
|
||||||
var type = edit ? collection.type : CollectionType.CALENDAR_JOURNAL_TASKS;
|
var type = edit ? collection.type : CollectionType.CALENDAR_JOURNAL_TASKS;
|
||||||
|
@ -30,7 +30,10 @@
|
|||||||
</section>
|
</section>
|
||||||
<section id="collectionsscene" style="display: none;">
|
<section id="collectionsscene" style="display: none;">
|
||||||
<h1>Collections</h1>
|
<h1>Collections</h1>
|
||||||
<a href="" name="new">Create new addressbook or calendar</a>
|
<ul>
|
||||||
|
<li><a href="" name="new">Create new addressbook or calendar</a></li>
|
||||||
|
<li><a href="" name="upload">Upload addressbook or calendar</a></li>
|
||||||
|
</ul>
|
||||||
<article name="collectiontemplate">
|
<article name="collectiontemplate">
|
||||||
<h2><span name="color">█ </span><span name="title" style="word-wrap:break-word;">Title</span> <small>[<span name="ADDRESSBOOK">addressbook</span><span name="CALENDAR_JOURNAL_TASKS">calendar, journal and tasks</span><span name="CALENDAR_JOURNAL">calendar and journal</span><span name="CALENDAR_TASKS">calendar and tasks</span><span name="JOURNAL_TASKS">journal and tasks</span><span name="CALENDAR">calendar</span><span name="JOURNAL">journal</span><span name="TASKS">tasks</span>]</small></h2>
|
<h2><span name="color">█ </span><span name="title" style="word-wrap:break-word;">Title</span> <small>[<span name="ADDRESSBOOK">addressbook</span><span name="CALENDAR_JOURNAL_TASKS">calendar, journal and tasks</span><span name="CALENDAR_JOURNAL">calendar and journal</span><span name="CALENDAR_TASKS">calendar and tasks</span><span name="JOURNAL_TASKS">journal and tasks</span><span name="CALENDAR">calendar</span><span name="JOURNAL">journal</span><span name="TASKS">tasks</span>]</small></h2>
|
||||||
<span name="description" style="word-wrap:break-word;">Description</span>
|
<span name="description" style="word-wrap:break-word;">Description</span>
|
||||||
@ -92,6 +95,20 @@
|
|||||||
<button type="button" name="cancel">Cancel</button>
|
<button type="button" name="cancel">Cancel</button>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
<section id="uploadcollectionscene" style="display: none;">
|
||||||
|
<h1>Upload collection</h1>
|
||||||
|
<ul>
|
||||||
|
<li name="filetemplate">
|
||||||
|
<span name="name" style="word-wrap:break-word;">name</span><br>
|
||||||
|
<span name="pending">Please wait...</span>
|
||||||
|
<span style="color: #00A400;" name="success">Finished</span>
|
||||||
|
<span style="color: #A40000;" name="error"></span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<form>
|
||||||
|
<button type="button" name="close">Close</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
<section id="deletecollectionscene" style="display: none;">
|
<section id="deletecollectionscene" style="display: none;">
|
||||||
<h1>Delete collection</h1>
|
<h1>Delete collection</h1>
|
||||||
<h2>Delete <span name="title" style="word-wrap:break-word;">title</span>?</h2>
|
<h2>Delete <span name="title" style="word-wrap:break-word;">title</span>?</h2>
|
||||||
|
Loading…
Reference in New Issue
Block a user