diff --git a/radicale/web/internal_data/CollectionsScene.js b/radicale/web/internal_data/CollectionsScene.js index 50ac10e3..b1b56ba7 100644 --- a/radicale/web/internal_data/CollectionsScene.js +++ b/radicale/web/internal_data/CollectionsScene.js @@ -18,16 +18,16 @@ * along with this program. If not, see . */ -import { Scene, push_scene, pop_scene, scene_stack } from "./scene_manager.js"; import { CreateEditCollectionScene } from "./CreateEditCollectionScene.js"; -import { CreateShareCollectionScene } from "./ShareCollectionScene.js"; -import { UploadCollectionScene } from "./UploadCollectionScene.js"; import { DeleteCollectionScene } from "./DeleteCollectionScene.js"; import { LoadingScene } from "./LoadingScene.js"; +import { CreateShareCollectionScene } from "./ShareCollectionScene.js"; +import { UploadCollectionScene } from "./UploadCollectionScene.js"; import { get_collections } from "./api.js"; -import { Collection, CollectionType } from "./models.js"; -import { bytesToHumanReadable } from "./utils.js"; import { SERVER } from "./constants.js"; +import { Collection, CollectionType } from "./models.js"; +import { Scene, pop_scene, push_scene, scene_stack } from "./scene_manager.js"; +import { bytesToHumanReadable } from "./utils.js"; /** * @constructor @@ -38,178 +38,181 @@ import { SERVER } from "./constants.js"; * @param {function(string):void} onerror Called when an error occurs, before the * scene is popped. */ -export function CollectionsScene(user, password, collection, onerror) { - /** @type {HTMLElement} */ let html_scene = document.getElementById("collectionsscene"); - /** @type {HTMLElement} */ let template = html_scene.querySelector("[data-name=collectiontemplate]"); - /** @type {HTMLElement} */ let new_btn = html_scene.querySelector("[data-name=new]"); - /** @type {HTMLElement} */ let upload_btn = html_scene.querySelector("[data-name=upload]"); +export class CollectionsScene { + constructor(user, password, collection, onerror) { + /** @type {HTMLElement} */ let html_scene = document.getElementById("collectionsscene"); + /** @type {HTMLElement} */ let template = html_scene.querySelector("[data-name=collectiontemplate]"); + /** @type {HTMLElement} */ let new_btn = html_scene.querySelector("[data-name=new]"); + /** @type {HTMLElement} */ let upload_btn = html_scene.querySelector("[data-name=upload]"); - /** @type {?number} */ let scene_index = null; - /** @type {?XMLHttpRequest} */ let collections_req = null; - /** @type {?Array} */ let collections = null; - /** @type {Array} */ let nodes = []; + /** @type {?number} */ let scene_index = null; + /** @type {?XMLHttpRequest} */ let collections_req = null; + /** @type {?Array} */ let collections = null; + /** @type {Array} */ let nodes = []; - function onnew() { - try { - let create_collection_scene = new CreateEditCollectionScene(user, password, collection); - push_scene(create_collection_scene, false); - } catch(err) { - console.error(err); - } - return false; - } - - function onupload() { - try { - let upload_scene = new UploadCollectionScene(user, password, collection); - push_scene(upload_scene, false); - } catch(err) { - console.error(err); - } - return false; - } - - function onedit(collection) { - try { - let edit_collection_scene = new CreateEditCollectionScene(user, password, collection); - push_scene(edit_collection_scene, false); - } catch(err) { - console.error(err); - } - return false; - } - - function onshare(collection) { - try { - let share_collection_scene = new CreateShareCollectionScene(user, password, collection); - push_scene(share_collection_scene, false); - } catch(err) { - console.error(err); - } - return false; - } - - function ondelete(collection) { - try { - let delete_collection_scene = new DeleteCollectionScene(user, password, collection); - push_scene(delete_collection_scene, false); - } catch(err) { - console.error(err); - } - return false; - } - - 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) { - /** @type {HTMLElement} */ let node = template.cloneNode(true); - node.classList.remove("hidden"); - /** @type {HTMLElement} */ let title_form = node.querySelector("[data-name=title]"); - /** @type {HTMLElement} */ let description_form = node.querySelector("[data-name=description]"); - /** @type {HTMLElement} */ let contentcount_form = node.querySelector("[data-name=contentcount]"); - /** @type {HTMLElement} */ let url_form = node.querySelector("[data-name=url]"); - /** @type {HTMLElement} */ let color_form = node.querySelector("[data-name=color]"); - /** @type {HTMLElement} */ let delete_btn = node.querySelector("[data-name=delete]"); - /** @type {HTMLElement} */ let edit_btn = node.querySelector("[data-name=edit]"); - /** @type {HTMLElement} */ let share_btn = node.querySelector("[data-name=share]"); - /** @type {HTMLAnchorElement} */ let download_btn = node.querySelector("[data-name=download]"); - if (collection.color) { - color_form.style.background = collection.color; + function onnew() { + try { + let create_collection_scene = new CreateEditCollectionScene(user, password, collection); + push_scene(create_collection_scene, false); + } catch (err) { + console.error(err); } - let possible_types = [CollectionType.ADDRESSBOOK, CollectionType.WEBCAL]; - [CollectionType.CALENDAR, ""].forEach(function(e) { - [CollectionType.union(e, CollectionType.JOURNAL), e].forEach(function(e) { - [CollectionType.union(e, CollectionType.TASKS), e].forEach(function(e) { - if (e) { - possible_types.push(e); - } + return false; + } + + function onupload() { + try { + let upload_scene = new UploadCollectionScene(user, password, collection); + push_scene(upload_scene, false); + } catch (err) { + console.error(err); + } + return false; + } + + function onedit(collection) { + try { + let edit_collection_scene = new CreateEditCollectionScene(user, password, collection); + push_scene(edit_collection_scene, false); + } catch (err) { + console.error(err); + } + return false; + } + + function onshare(collection) { + try { + let share_collection_scene = new CreateShareCollectionScene(user, password, collection); + push_scene(share_collection_scene, false); + } catch (err) { + console.error(err); + } + return false; + } + + function ondelete(collection) { + try { + let delete_collection_scene = new DeleteCollectionScene(user, password, collection); + push_scene(delete_collection_scene, false); + } catch (err) { + console.error(err); + } + return false; + } + + function show_collections(collections) { + /** @type {HTMLElement} */ let navBar = document.querySelector("#logoutview"); + let heightOfNavBar = navBar.offsetHeight + "px"; + html_scene.style.marginTop = heightOfNavBar; + html_scene.style.height = "calc(100vh - " + heightOfNavBar + ")"; + collections.forEach(function (collection) { + /** @type {HTMLElement} */ let node = /** @type {HTMLElement} */(template.cloneNode(true)); + node.classList.remove("hidden"); + /** @type {HTMLElement} */ let title_form = node.querySelector("[data-name=title]"); + /** @type {HTMLElement} */ let description_form = node.querySelector("[data-name=description]"); + /** @type {HTMLElement} */ let contentcount_form = node.querySelector("[data-name=contentcount]"); + /** @type {HTMLInputElement} */ let url_form = node.querySelector("[data-name=url]"); + /** @type {HTMLElement} */ let color_form = node.querySelector("[data-name=color]"); + /** @type {HTMLElement} */ let delete_btn = node.querySelector("[data-name=delete]"); + /** @type {HTMLElement} */ let edit_btn = node.querySelector("[data-name=edit]"); + /** @type {HTMLElement} */ let share_btn = node.querySelector("[data-name=share]"); + /** @type {HTMLAnchorElement} */ let download_btn = node.querySelector("[data-name=download]"); + if (collection.color) { + color_form.style.background = collection.color; + } + let possible_types = [CollectionType.ADDRESSBOOK, CollectionType.WEBCAL]; + [CollectionType.CALENDAR, ""].forEach(function (e) { + [CollectionType.union(e, CollectionType.JOURNAL), e].forEach(function (e) { + [CollectionType.union(e, CollectionType.TASKS), e].forEach(function (e) { + if (e) { + possible_types.push(e); + } + }); }); }); - }); - possible_types.forEach(function(e) { - if (e !== collection.type) { - node.querySelector("[data-name=" + e + "]").classList.add("hidden"); + possible_types.forEach(function (e) { + if (e !== collection.type) { + node.querySelector("[data-name=" + e + "]").classList.add("hidden"); + } + }); + title_form.textContent = collection.displayname || collection.href; + if (title_form.textContent.length > 30) { + title_form.classList.add("smalltext"); } - }); - title_form.textContent = collection.displayname || collection.href; - if(title_form.textContent.length > 30){ - title_form.classList.add("smalltext"); - } - description_form.textContent = collection.description; - if(description_form.textContent.length > 150){ - description_form.classList.add("smalltext"); - } - if(collection.type != CollectionType.WEBCAL){ - let contentcount_form_txt = (collection.contentcount > 0 ? Number(collection.contentcount).toLocaleString() : "No") + " item" + (collection.contentcount == 1 ? "" : "s") + " in collection"; - if(collection.contentcount > 0){ - contentcount_form_txt += " (" + bytesToHumanReadable(collection.size) + ")"; + description_form.textContent = collection.description; + if (description_form.textContent.length > 150) { + description_form.classList.add("smalltext"); } - contentcount_form.textContent = contentcount_form_txt; - } - let href = SERVER + collection.href; - url_form.value = href; - download_btn.href = href; - if(collection.type == CollectionType.WEBCAL){ - download_btn.parentElement.classList.add("hidden"); - } - delete_btn.onclick = function() {return ondelete(collection);}; - edit_btn.onclick = function() {return onedit(collection);}; - share_btn.onclick = function() {return onshare(collection);}; - node.classList.remove("hidden"); - nodes.push(node); - template.parentNode.insertBefore(node, template); - }); - } + if (collection.type != CollectionType.WEBCAL) { + let contentcount_form_txt = (collection.contentcount > 0 ? Number(collection.contentcount).toLocaleString() : "No") + " item" + (collection.contentcount == 1 ? "" : "s") + " in collection"; + if (collection.contentcount > 0) { + contentcount_form_txt += " (" + bytesToHumanReadable(collection.size) + ")"; + } + contentcount_form.textContent = contentcount_form_txt; + } + let href = SERVER + collection.href; + url_form.value = href; + download_btn.href = href; + if (collection.type == CollectionType.WEBCAL) { + download_btn.parentElement.classList.add("hidden"); + } + delete_btn.onclick = function () { return ondelete(collection); }; + edit_btn.onclick = function () { return onedit(collection); }; + share_btn.onclick = function () { return onshare(collection); }; + node.classList.remove("hidden"); + nodes.push(node); + template.parentNode.insertBefore(node, template); + }); + } - function update() { - let loading_scene = new LoadingScene(); - push_scene(loading_scene, false); - collections_req = get_collections(user, password, collection, function(collections1, error) { - if (scene_index === null) { - return; - } - collections_req = null; - if (error) { - onerror(error); - pop_scene(scene_index - 1); + function update() { + let loading_scene = new LoadingScene(); + push_scene(loading_scene, false); + collections_req = get_collections(user, password, collection, function (collections1, error) { + if (scene_index === null) { + return; + } + collections_req = null; + if (error) { + onerror(error); + pop_scene(scene_index - 1); + } else { + collections = collections1; + pop_scene(scene_index); + } + }); + } + + this.show = function () { + html_scene.classList.remove("hidden"); + new_btn.onclick = onnew; + upload_btn.onclick = onupload; + if (collections === null) { + update(); } else { - collections = collections1; - pop_scene(scene_index); + // from update loading scene + show_collections(collections); } - }); + }; + this.hide = function () { + html_scene.classList.add("hidden"); + scene_index = scene_stack.length - 1; + new_btn.onclick = null; + upload_btn.onclick = null; + collections = null; + // remove collection + nodes.forEach(function (node) { + node.parentNode.removeChild(node); + }); + nodes = []; + }; + this.release = function () { + scene_index = null; + if (collections_req !== null) { + collections_req.abort(); + collections_req = null; + } + collections = null; + }; } - - this.show = function() { - html_scene.classList.remove("hidden"); - new_btn.onclick = onnew; - upload_btn.onclick = onupload; - if (collections === null) { - update(); - } else { - // from update loading scene - show_collections(collections); - } - }; - this.hide = function() { - html_scene.classList.add("hidden"); - scene_index = scene_stack.length - 1; - new_btn.onclick = null; - upload_btn.onclick = null; - collections = null; - // remove collection - nodes.forEach(function(node) { - node.parentNode.removeChild(node); - }); - nodes = []; - }; - this.release = function() { - scene_index = null; - if (collections_req !== null) { - collections_req.abort(); - collections_req = null; - } - collections = null; - }; } \ No newline at end of file diff --git a/radicale/web/internal_data/ShareCollectionScene.js b/radicale/web/internal_data/ShareCollectionScene.js index ec357bc7..1a610a29 100644 --- a/radicale/web/internal_data/ShareCollectionScene.js +++ b/radicale/web/internal_data/ShareCollectionScene.js @@ -25,7 +25,7 @@ import { server_features, } from "./api.js"; import { Collection } from "./models.js"; -import { pop_scene, scene_stack } from "./scene_manager.js"; +import { Scene, pop_scene, scene_stack } from "./scene_manager.js"; /** * @constructor @@ -34,64 +34,73 @@ import { pop_scene, scene_stack } from "./scene_manager.js"; * @param {string} password * @param {Collection} collection The collection on which to edit sharing setting. Must exist. */ -export function CreateShareCollectionScene(user, password, collection) { - /** @type {?number} */ let scene_index = null; +/** + * @constructor + * @implements {Scene} + * @param {string} user + * @param {string} password + * @param {Collection} collection The collection on which to edit sharing setting. Must exist. + */ +export class CreateShareCollectionScene { + constructor(user, password, collection) { + /** @type {?number} */ let scene_index = null; - let html_scene = document.getElementById("sharecollectionscene"); + let html_scene = document.getElementById("sharecollectionscene"); - /** @type {HTMLElement} */ let cancel_btn = html_scene.querySelector("[data-name=cancel]"); - /** @type {HTMLElement} */ let share_by_token_btn_ro = html_scene.querySelector( - "[data-name=sharebytoken_ro]", - ); - /** @type {HTMLElement} */ let share_by_token_btn_rw = html_scene.querySelector( - "[data-name=sharebytoken_rw]", - ); + /** @type {HTMLElement} */ let cancel_btn = html_scene.querySelector("[data-name=cancel]"); + /** @type {HTMLElement} */ let share_by_token_btn_ro = html_scene.querySelector( + "[data-name=sharebytoken_ro]" + ); + /** @type {HTMLElement} */ let share_by_token_btn_rw = html_scene.querySelector( + "[data-name=sharebytoken_rw]" + ); - /** @type {HTMLElement} */ let title = html_scene.querySelector("[data-name=title]"); + /** @type {HTMLElement} */ let title = html_scene.querySelector("[data-name=title]"); - function oncancel() { - try { - pop_scene(scene_index - 1); - } catch (err) { - console.error(err); + function oncancel() { + try { + pop_scene(scene_index - 1); + } catch (err) { + console.error(err); + } + return false; } - return false; - } - function onsharebytoken_rw() { - add_share_by_token(user, password, collection, "rw", function () { - update_share_list(user, password, collection); - }); - } - - function onsharebytoken_ro() { - add_share_by_token(user, password, collection, "r", function () { - update_share_list(user, password, collection); - }); - } - - this.show = function () { - this.release(); - scene_index = scene_stack.length - 1; - html_scene.classList.remove("hidden"); - cancel_btn.onclick = oncancel; - if (server_features["sharing"]["FeatureEnabledCollectionByToken"]) { - share_by_token_btn_ro.onclick = onsharebytoken_ro; - share_by_token_btn_rw.onclick = onsharebytoken_rw; - } else { - share_by_token_btn_ro.parentElement.removeChild(share_by_token_btn_ro); - share_by_token_btn_rw.parentElement.removeChild(share_by_token_btn_rw); + function onsharebytoken_rw() { + add_share_by_token(user, password, collection, "rw", function () { + update_share_list(user, password, collection); + }); } - title.textContent = collection.displayname || collection.href; - update_share_list(user, password, collection); - }; - this.hide = function () { - html_scene.classList.add("hidden"); - cancel_btn.onclick = null; - }; - this.release = function () { - scene_index = null; - }; + + function onsharebytoken_ro() { + add_share_by_token(user, password, collection, "r", function () { + update_share_list(user, password, collection); + }); + } + + this.show = function () { + this.release(); + scene_index = scene_stack.length - 1; + html_scene.classList.remove("hidden"); + cancel_btn.onclick = oncancel; + if (server_features["sharing"]["FeatureEnabledCollectionByToken"]) { + share_by_token_btn_ro.onclick = onsharebytoken_ro; + share_by_token_btn_rw.onclick = onsharebytoken_rw; + } else { + share_by_token_btn_ro.parentElement.removeChild(share_by_token_btn_ro); + share_by_token_btn_rw.parentElement.removeChild(share_by_token_btn_rw); + } + title.textContent = collection.displayname || collection.href; + update_share_list(user, password, collection); + }; + this.hide = function () { + html_scene.classList.add("hidden"); + cancel_btn.onclick = null; + }; + this.release = function () { + scene_index = null; + }; + } } function update_share_list(user, password, collection) { diff --git a/radicale/web/internal_data/scene_manager.js b/radicale/web/internal_data/scene_manager.js index bb489257..2f4b416c 100644 --- a/radicale/web/internal_data/scene_manager.js +++ b/radicale/web/internal_data/scene_manager.js @@ -21,19 +21,21 @@ /** * @interface */ -export function Scene() {} -/** - * Scene is on top of stack and visible. - */ -Scene.prototype.show = function() {}; -/** - * Scene is no longer visible. - */ -Scene.prototype.hide = function() {}; -/** - * Scene is removed from scene stack. - */ -Scene.prototype.release = function() {}; +export class Scene { + constructor() { } + /** + * Scene is on top of stack and visible. + */ + show() { } + /** + * Scene is no longer visible. + */ + hide() { } + /** + * Scene is removed from scene stack. + */ + release() { } +} /**