diff --git a/radicale/web/internal_data/CollectionsScene.js b/radicale/web/internal_data/CollectionsScene.js index b1b56ba7..bfbea540 100644 --- a/radicale/web/internal_data/CollectionsScene.js +++ b/radicale/web/internal_data/CollectionsScene.js @@ -21,9 +21,9 @@ import { CreateEditCollectionScene } from "./CreateEditCollectionScene.js"; import { DeleteCollectionScene } from "./DeleteCollectionScene.js"; import { LoadingScene } from "./LoadingScene.js"; -import { CreateShareCollectionScene } from "./ShareCollectionScene.js"; +import { CreateShareCollectionScene, maybe_enable_sharing_options } from "./ShareCollectionScene.js"; import { UploadCollectionScene } from "./UploadCollectionScene.js"; -import { get_collections } from "./api.js"; +import { discover_server_features, get_collections } from "./api.js"; import { SERVER } from "./constants.js"; import { Collection, CollectionType } from "./models.js"; import { Scene, pop_scene, push_scene, scene_stack } from "./scene_manager.js"; @@ -189,6 +189,7 @@ export class CollectionsScene { upload_btn.onclick = onupload; if (collections === null) { update(); + discover_server_features(user, password, maybe_enable_sharing_options); } else { // from update loading scene show_collections(collections); diff --git a/radicale/web/internal_data/CreateEditCollectionScene.js b/radicale/web/internal_data/CreateEditCollectionScene.js index 49982734..903c7e13 100644 --- a/radicale/web/internal_data/CreateEditCollectionScene.js +++ b/radicale/web/internal_data/CreateEditCollectionScene.js @@ -18,12 +18,12 @@ * along with this program. If not, see . */ -import { Scene, push_scene, pop_scene, scene_stack } from "./scene_manager.js"; -import { Collection, CollectionType } from "./models.js"; -import { random_uuid, random_hex, cleanHREFinput, isValidHREF } from "./utils.js"; import { LoadingScene } from "./LoadingScene.js"; -import { COLOR_RE } from "./constants.js"; 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"; /** * @constructor @@ -34,191 +34,193 @@ import { create_collection, edit_collection } from "./api.js"; * collection will be created inside of it. * Otherwise the collection will be edited. */ -export function CreateEditCollectionScene(user, password, collection) { - let edit = collection.type !== CollectionType.PRINCIPAL; - let html_scene = document.getElementById(edit ? "editcollectionscene" : "createcollectionscene"); - /** @type {HTMLElement} */ let title_form = edit ? html_scene.querySelector("[data-name=title]") : null; - /** @type {HTMLElement} */ let error_form = html_scene.querySelector("[data-name=error]"); - /** @type {HTMLInputElement} */ let href_form = html_scene.querySelector("[data-name=href]"); - /** @type {HTMLElement} */ let href_label = html_scene.querySelector("label[for=href]"); - /** @type {HTMLInputElement} */ let displayname_form = html_scene.querySelector("[data-name=displayname]"); - /** @type {HTMLElement} */ let displayname_label = html_scene.querySelector("label[for=displayname]"); - /** @type {HTMLInputElement} */ let description_form = html_scene.querySelector("[data-name=description]"); - /** @type {HTMLElement} */ let description_label = html_scene.querySelector("label[for=description]"); - /** @type {HTMLInputElement} */ let source_form = html_scene.querySelector("[data-name=source]"); - /** @type {HTMLElement} */ let source_label = html_scene.querySelector("label[for=source]"); - /** @type {HTMLSelectElement} */ let type_form = html_scene.querySelector("[data-name=type]"); - /** @type {HTMLElement} */ let type_label = html_scene.querySelector("label[for=type]"); - /** @type {HTMLInputElement} */ let color_form = html_scene.querySelector("[data-name=color]"); - /** @type {HTMLElement} */ let color_label = html_scene.querySelector("label[for=color]"); - /** @type {HTMLElement} */ let submit_btn = html_scene.querySelector("[data-name=submit]"); - /** @type {HTMLElement} */ let cancel_btn = html_scene.querySelector("[data-name=cancel]"); +export class CreateEditCollectionScene { + constructor(user, password, collection) { + let edit = collection.type !== CollectionType.PRINCIPAL; + let html_scene = document.getElementById(edit ? "editcollectionscene" : "createcollectionscene"); + /** @type {HTMLElement} */ let title_form = edit ? html_scene.querySelector("[data-name=title]") : null; + /** @type {HTMLElement} */ let error_form = html_scene.querySelector("[data-name=error]"); + /** @type {HTMLInputElement} */ let href_form = html_scene.querySelector("[data-name=href]"); + /** @type {HTMLElement} */ let href_label = html_scene.querySelector("label[for=href]"); + /** @type {HTMLInputElement} */ let displayname_form = html_scene.querySelector("[data-name=displayname]"); + /** @type {HTMLElement} */ let displayname_label = html_scene.querySelector("label[for=displayname]"); + /** @type {HTMLInputElement} */ let description_form = html_scene.querySelector("[data-name=description]"); + /** @type {HTMLElement} */ let description_label = html_scene.querySelector("label[for=description]"); + /** @type {HTMLInputElement} */ let source_form = html_scene.querySelector("[data-name=source]"); + /** @type {HTMLElement} */ let source_label = html_scene.querySelector("label[for=source]"); + /** @type {HTMLSelectElement} */ let type_form = html_scene.querySelector("[data-name=type]"); + /** @type {HTMLElement} */ let type_label = html_scene.querySelector("label[for=type]"); + /** @type {HTMLInputElement} */ let color_form = html_scene.querySelector("[data-name=color]"); + /** @type {HTMLElement} */ let color_label = html_scene.querySelector("label[for=color]"); + /** @type {HTMLElement} */ let submit_btn = html_scene.querySelector("[data-name=submit]"); + /** @type {HTMLElement} */ let cancel_btn = html_scene.querySelector("[data-name=cancel]"); - /** @type {?number} */ let scene_index = null; - /** @type {?XMLHttpRequest} */ let create_edit_req = null; - let error = ""; - /** @type {?HTMLSelectElement} */ let saved_type_form = null; + /** @type {?number} */ let scene_index = null; + /** @type {?XMLHttpRequest} */ let create_edit_req = null; + let error = ""; + /** @type {?HTMLSelectElement} */ let saved_type_form = null; - let href = edit ? collection.href : collection.href + random_uuid() + "/"; - let displayname = edit ? collection.displayname : ""; - let description = edit ? collection.description : ""; - let source = edit ? collection.source : ""; - let type = edit ? collection.type : CollectionType.CALENDAR_JOURNAL_TASKS; - let color = edit && collection.color ? collection.color : "#" + random_hex(6); + let href = edit ? collection.href : collection.href + random_uuid() + "/"; + let displayname = edit ? collection.displayname : ""; + let description = edit ? collection.description : ""; + let source = edit ? collection.source : ""; + let type = edit ? collection.type : CollectionType.CALENDAR_JOURNAL_TASKS; + let color = edit && collection.color ? collection.color : "#" + random_hex(6); - if(!edit){ - href_form.addEventListener("keydown", cleanHREFinput); - } - - function remove_invalid_types() { if (!edit) { - return; + href_form.addEventListener("keydown", cleanHREFinput); } - /** @type {HTMLOptionsCollection} */ let options = type_form.options; - // remove all options that are not supersets - let valid_type_options = CollectionType.valid_options_for_type(type); - for (let i = options.length - 1; i >= 0; i--) { - if (valid_type_options.indexOf(options[i].value) < 0) { - options.remove(i); + + function remove_invalid_types() { + if (!edit) { + return; + } + /** @type {HTMLOptionsCollection} */ let options = type_form.options; + // remove all options that are not supersets + let valid_type_options = CollectionType.valid_options_for_type(type); + for (let i = options.length - 1; i >= 0; i--) { + if (valid_type_options.indexOf(options[i].value) < 0) { + options.remove(i); + } } } - } - function read_form() { - if(!edit){ - cleanHREFinput(href_form); - let newhreftxtvalue = href_form.value.trim().toLowerCase(); - if(!isValidHREF(newhreftxtvalue)){ - alert("You must enter a valid HREF"); - return false; - } - href = collection.href + newhreftxtvalue + "/"; - } - displayname = displayname_form.value; - description = description_form.value; - source = source_form.value; - type = type_form.value; - color = color_form.value; - return true; - } - - function fill_form() { - if(!edit){ - href_form.value = random_uuid(); - } - displayname_form.value = displayname; - description_form.value = description; - source_form.value = source; - type_form.value = type; - color_form.value = color; - if(error){ - error_form.textContent = "Error: " + error; - error_form.classList.remove("hidden"); - } - error_form.classList.add("hidden"); - onTypeChange(); - type_form.addEventListener("change", onTypeChange); - } - - function onsubmit() { - try { - if(!read_form()){ - return false; - } - let sane_color = color.trim(); - if (sane_color) { - let color_match = COLOR_RE.exec(sane_color); - if (!color_match) { - error = "Invalid color"; - fill_form(); + function read_form() { + if (!edit) { + cleanHREFinput(href_form); + let newhreftxtvalue = href_form.value.trim().toLowerCase(); + if (!isValidHREF(newhreftxtvalue)) { + alert("You must enter a valid HREF"); return false; } - sane_color = color_match[1]; + href = collection.href + newhreftxtvalue + "/"; } - let loading_scene = new LoadingScene(); - push_scene(loading_scene, false); - let collection = new Collection(href, type, displayname, description, sane_color, 0, 0, source); - let callback = function(error1) { - if (scene_index === null) { - return; - } - create_edit_req = null; - if (error1) { - error = error1; - pop_scene(scene_index); - } else { - pop_scene(scene_index - 1); - } - }; - if (edit) { - create_edit_req = edit_collection(user, password, collection, callback); - } else { - create_edit_req = create_collection(user, password, collection, callback); + displayname = displayname_form.value; + description = description_form.value; + source = source_form.value; + type = type_form.value; + color = color_form.value; + return true; + } + + function fill_form() { + if (!edit) { + href_form.value = random_uuid(); + } + displayname_form.value = displayname; + description_form.value = description; + source_form.value = source; + type_form.value = type; + color_form.value = color; + if (error) { + error_form.textContent = "Error: " + error; + error_form.classList.remove("hidden"); } - } catch(err) { - console.error(err); - } - return false; - } - - function oncancel() { - try { - pop_scene(scene_index - 1); - } catch(err) { - console.error(err); - } - return false; - } - - - function onTypeChange(e){ - if(type_form.value == CollectionType.WEBCAL){ - source_label.classList.remove("hidden"); - source_form.classList.remove("hidden"); - }else{ - source_label.classList.add("hidden"); - source_form.classList.add("hidden"); - } - } - - this.show = function() { - this.release(); - scene_index = scene_stack.length - 1; - // Clone type_form because it's impossible to hide options without removing them - saved_type_form = type_form; - type_form = type_form.cloneNode(true); - saved_type_form.parentNode.replaceChild(type_form, saved_type_form); - remove_invalid_types(); - html_scene.classList.remove("hidden"); - if (edit) { - title_form.textContent = collection.displayname || collection.href; - } - fill_form(); - submit_btn.onclick = onsubmit; - cancel_btn.onclick = oncancel; - if(error){ - error_form.textContent = "Error: " + error; - error_form.classList.remove("hidden"); - }else{ error_form.classList.add("hidden"); + onTypeChange(); + type_form.addEventListener("change", onTypeChange); } - }; - this.hide = function() { - read_form(); - html_scene.classList.add("hidden"); - // restore type_form - type_form.parentNode.replaceChild(saved_type_form, type_form); - type_form = saved_type_form; - saved_type_form = null; - submit_btn.onclick = null; - cancel_btn.onclick = null; - }; - this.release = function() { - scene_index = null; - if (create_edit_req !== null) { - create_edit_req.abort(); - create_edit_req = null; + + function onsubmit() { + try { + if (!read_form()) { + return false; + } + let sane_color = color.trim(); + if (sane_color) { + let color_match = COLOR_RE.exec(sane_color); + if (!color_match) { + error = "Invalid color"; + fill_form(); + return false; + } + sane_color = color_match[1]; + } + let loading_scene = new LoadingScene(); + push_scene(loading_scene, false); + let collection = new Collection(href, type, displayname, description, sane_color, 0, 0, source); + let callback = function (error1) { + if (scene_index === null) { + return; + } + create_edit_req = null; + if (error1) { + error = error1; + pop_scene(scene_index); + } else { + pop_scene(scene_index - 1); + } + }; + if (edit) { + create_edit_req = edit_collection(user, password, collection, callback); + } else { + create_edit_req = create_collection(user, password, collection, callback); + } + } catch (err) { + console.error(err); + } + return false; } - }; + + function oncancel() { + try { + pop_scene(scene_index - 1); + } catch (err) { + console.error(err); + } + return false; + } + + + function onTypeChange(e) { + if (type_form.value == CollectionType.WEBCAL) { + source_label.classList.remove("hidden"); + source_form.classList.remove("hidden"); + } else { + source_label.classList.add("hidden"); + source_form.classList.add("hidden"); + } + } + + this.show = function () { + this.release(); + scene_index = scene_stack.length - 1; + // Clone type_form because it's impossible to hide options without removing them + saved_type_form = type_form; + type_form = /** @type {HTMLSelectElement} */ (type_form.cloneNode(true)); + saved_type_form.parentNode.replaceChild(type_form, saved_type_form); + remove_invalid_types(); + html_scene.classList.remove("hidden"); + if (edit) { + title_form.textContent = collection.displayname || collection.href; + } + fill_form(); + submit_btn.onclick = onsubmit; + cancel_btn.onclick = oncancel; + if (error) { + error_form.textContent = "Error: " + error; + error_form.classList.remove("hidden"); + } else { + error_form.classList.add("hidden"); + } + }; + this.hide = function () { + read_form(); + html_scene.classList.add("hidden"); + // restore type_form + type_form.parentNode.replaceChild(saved_type_form, type_form); + type_form = saved_type_form; + saved_type_form = null; + submit_btn.onclick = null; + cancel_btn.onclick = null; + }; + this.release = function () { + scene_index = null; + if (create_edit_req !== null) { + create_edit_req.abort(); + create_edit_req = null; + } + }; + } } \ No newline at end of file diff --git a/radicale/web/internal_data/LoginScene.js b/radicale/web/internal_data/LoginScene.js index b6f1a68e..8ab9ef08 100644 --- a/radicale/web/internal_data/LoginScene.js +++ b/radicale/web/internal_data/LoginScene.js @@ -18,139 +18,139 @@ * along with this program. If not, see . */ -import { Scene, push_scene, pop_scene, scene_stack } from "./scene_manager.js"; -import { LoadingScene } from "./LoadingScene.js"; -import { get_principal, discover_server_features } from "./api.js"; +import { get_principal } from "./api.js"; import { CollectionsScene } from "./CollectionsScene.js"; -import { maybe_enable_sharing_options } from "./ShareCollectionScene.js"; +import { LoadingScene } from "./LoadingScene.js"; +import { Scene, pop_scene, push_scene, scene_stack } from "./scene_manager.js"; /** * @constructor * @implements {Scene} */ -export function LoginScene() { - /** @type {HTMLElement} */ let html_scene = document.getElementById("loginscene"); - /** @type {HTMLElement} */ let form = html_scene.querySelector("[data-name=form]"); - /** @type {HTMLInputElement} */ let user_form = html_scene.querySelector("[data-name=user]"); - /** @type {HTMLInputElement} */ let password_form = html_scene.querySelector("[data-name=password]"); - /** @type {HTMLElement} */ let error_form = html_scene.querySelector("[data-name=error]"); - /** @type {HTMLElement} */ let logout_view = document.getElementById("logoutview"); - /** @type {HTMLElement} */ let logout_user_form = logout_view.querySelector("[data-name=user]"); - /** @type {HTMLElement} */ let logout_btn = logout_view.querySelector("[data-name=logout]"); - /** @type {HTMLElement} */ let refresh_btn = logout_view.querySelector("[data-name=refresh]"); +export class LoginScene { + constructor() { + /** @type {HTMLElement} */ let html_scene = document.getElementById("loginscene"); + /** @type {HTMLElement} */ let form = html_scene.querySelector("[data-name=form]"); + /** @type {HTMLInputElement} */ let user_form = html_scene.querySelector("[data-name=user]"); + /** @type {HTMLInputElement} */ let password_form = html_scene.querySelector("[data-name=password]"); + /** @type {HTMLElement} */ let error_form = html_scene.querySelector("[data-name=error]"); + /** @type {HTMLElement} */ let logout_view = document.getElementById("logoutview"); + /** @type {HTMLElement} */ let logout_user_form = logout_view.querySelector("[data-name=user]"); + /** @type {HTMLElement} */ let logout_btn = logout_view.querySelector("[data-name=logout]"); + /** @type {HTMLElement} */ let refresh_btn = logout_view.querySelector("[data-name=refresh]"); - /** @type {?number} */ let scene_index = null; - let user = ""; - let error = ""; - /** @type {?XMLHttpRequest} */ let principal_req = null; + /** @type {?number} */ let scene_index = null; + let user = ""; + let error = ""; + /** @type {?XMLHttpRequest} */ let principal_req = null; - function read_form() { - user = user_form.value; - } - - function fill_form() { - user_form.value = user; - password_form.value = ""; - if(error){ - error_form.textContent = "Error: " + error; - error_form.classList.remove("hidden"); - }else{ - error_form.classList.add("hidden"); + function read_form() { + user = user_form.value; } - } - function onlogin() { - try { - read_form(); - let password = password_form.value; - if (user) { - error = ""; - // 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(); - push_scene(loading_scene, false); - principal_req = get_principal(user, password, function(collection, error1) { - if (scene_index === null) { - return; - } - principal_req = null; - if (error1) { - error = error1; - pop_scene(scene_index); - } else { - // show collections - let saved_user = user; - user = ""; - let collections_scene = new CollectionsScene( - saved_user, password, collection, function(error1) { - error = error1; - user = saved_user; - }); - discover_server_features(saved_user, password, maybe_enable_sharing_options); - push_scene(collections_scene, true); - } - }); + function fill_form() { + user_form.value = user; + password_form.value = ""; + if (error) { + error_form.textContent = "Error: " + error; + error_form.classList.remove("hidden"); } else { - error = "Username is empty"; - fill_form(); + error_form.classList.add("hidden"); } - } catch(err) { - console.error(err); } - return false; - } - function onlogout() { - try { - if (scene_index === null) { - return false; + function onlogin() { + try { + read_form(); + let password = password_form.value; + if (user) { + error = ""; + // 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(); + push_scene(loading_scene, false); + principal_req = get_principal(user, password, function (collection, error1) { + if (scene_index === null) { + return; + } + principal_req = null; + if (error1) { + error = error1; + pop_scene(scene_index); + } else { + // show collections + let saved_user = user; + user = ""; + let collections_scene = new CollectionsScene( + saved_user, password, collection, function (error1) { + error = error1; + user = saved_user; + }); + push_scene(collections_scene, true); + } + }); + } else { + error = "Username is empty"; + fill_form(); + } + } catch (err) { + console.error(err); } - user = ""; - pop_scene(scene_index); - } catch (err) { - console.error(err); + return false; } - return false; - } - 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(); - form.onsubmit = onlogin; - html_scene.classList.remove("hidden"); - scene_index = scene_stack.length - 1; - user_form.focus(); - }; - this.hide = function() { - read_form(); - html_scene.classList.add("hidden"); - form.onsubmit = null; - }; - this.release = function() { - scene_index = null; - // cancel pending requests - if (principal_req !== null) { - principal_req.abort(); - principal_req = null; + function onlogout() { + try { + if (scene_index === null) { + return false; + } + user = ""; + pop_scene(scene_index); + } catch (err) { + console.error(err); + } + return false; } - remove_logout(); - }; + + 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(); + form.onsubmit = onlogin; + html_scene.classList.remove("hidden"); + scene_index = scene_stack.length - 1; + user_form.focus(); + }; + this.hide = function () { + read_form(); + html_scene.classList.add("hidden"); + form.onsubmit = null; + }; + this.release = function () { + scene_index = null; + // cancel pending requests + if (principal_req !== null) { + principal_req.abort(); + principal_req = null; + } + remove_logout(); + }; + } } \ No newline at end of file diff --git a/radicale/web/internal_data/ShareCollectionScene.js b/radicale/web/internal_data/ShareCollectionScene.js index 1a610a29..7ae02a80 100644 --- a/radicale/web/internal_data/ShareCollectionScene.js +++ b/radicale/web/internal_data/ShareCollectionScene.js @@ -83,12 +83,14 @@ export class CreateShareCollectionScene { scene_index = scene_stack.length - 1; html_scene.classList.remove("hidden"); cancel_btn.onclick = oncancel; - if (server_features["sharing"]["FeatureEnabledCollectionByToken"]) { + if (server_features["sharing"]["PermittedCreateCollectionByToken"]) { + share_by_token_btn_ro.classList.remove("hidden"); + share_by_token_btn_rw.classList.remove("hidden"); 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); + share_by_token_btn_ro.classList.add("hidden"); + share_by_token_btn_rw.classList.add("hidden"); } title.textContent = collection.displayname || collection.href; update_share_list(user, password, collection); diff --git a/radicale/web/internal_data/api.js b/radicale/web/internal_data/api.js index eaf818ac..46d52ff1 100644 --- a/radicale/web/internal_data/api.js +++ b/radicale/web/internal_data/api.js @@ -28,7 +28,7 @@ export let server_features = {}; * Find the principal collection. * @param {string} user * @param {string} password - * @param {function(?Collection, ?string)} callback Returns result or error + * @param {function(?Collection, ?string):void} callback Returns result or error * @return {XMLHttpRequest} */ export function get_principal(user, password, callback) { @@ -48,6 +48,7 @@ export function get_principal(user, password, callback) { CollectionType.PRINCIPAL, displayname_element ? displayname_element.textContent : "", "", + "", 0, ""), null); } else { @@ -72,7 +73,7 @@ export function get_principal(user, password, callback) { * @param {string} user * @param {string} password * @param {Collection} collection - * @param {function(?Array, ?string)} callback Returns result or error + * @param {function(?Array, ?string):void} callback Returns result or error * @return {XMLHttpRequest} */ export function get_collections(user, password, collection, callback) { @@ -195,7 +196,7 @@ export function get_collections(user, password, collection, callback) { * @param {string} password * @param {string} collection_href Must always start and end with /. * @param {File} file - * @param {function(?string)} callback Returns error or null + * @param {function(?string):void} callback Returns error or null * @return {XMLHttpRequest} */ export function upload_collection(user, password, collection_href, file, callback) { @@ -220,7 +221,7 @@ export function upload_collection(user, password, collection_href, file, callbac * @param {string} user * @param {string} password * @param {Collection} collection - * @param {function(?string)} callback Returns error or null + * @param {function(?string):void} callback Returns error or null * @return {XMLHttpRequest} */ export function delete_collection(user, password, collection, callback) { @@ -245,7 +246,7 @@ export function delete_collection(user, password, collection, callback) { * @param {string} password * @param {Collection} collection * @param {boolean} create - * @param {function(?string)} callback Returns error or null + * @param {function(?string):void} callback Returns error or null * @return {XMLHttpRequest} */ function create_edit_collection(user, password, collection, create, callback) { @@ -325,7 +326,7 @@ function create_edit_collection(user, password, collection, create, callback) { * @param {string} user * @param {string} password * @param {Collection} collection - * @param {function(?string)} callback Returns error or null + * @param {function(?string):void} callback Returns error or null * @return {XMLHttpRequest} */ export function create_collection(user, password, collection, callback) { @@ -336,7 +337,7 @@ export function create_collection(user, password, collection, callback) { * @param {string} user * @param {string} password * @param {Collection} collection - * @param {function(?string)} callback Returns error or null + * @param {function(?string):void} callback Returns error or null * @return {XMLHttpRequest} */ export function edit_collection(user, password, collection, callback) {