frontend: Move collection creation to dialog

This commit is contained in:
Lennart
2025-06-18 18:09:19 +02:00
parent 9e8c218308
commit 1a2f3b8f8a
7 changed files with 265 additions and 120 deletions

View File

@@ -1,5 +1,6 @@
import { html, LitElement } from "lit"; import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import { Ref, createRef, ref } from 'lit/directives/ref.js';
import { createClient } from "webdav"; import { createClient } from "webdav";
@customElement("create-addressbook-form") @customElement("create-addressbook-form")
@@ -24,12 +25,15 @@ export class CreateAddressbookForm extends LitElement {
@property() @property()
description: String = '' description: String = ''
dialog: Ref<HTMLDialogElement> = createRef()
form: Ref<HTMLFormElement> = createRef()
override render() { override render() {
return html` return html`
<section> <button @click=${() => this.dialog.value.showModal()}>Create addressbook</button>
<h3>Create calendar</h3> <dialog ${ref(this.dialog)}>
<form @submit=${this.submit}> <h3>Create addressbook</h3>
<form @submit=${this.submit} ${ref(this.form)}>
<label> <label>
id id
<input type="text" name="id" @change=${e => this.id = e.target.value} /> <input type="text" name="id" @change=${e => this.id = e.target.value} />
@@ -46,8 +50,9 @@ export class CreateAddressbookForm extends LitElement {
</label> </label>
<br> <br>
<button type="submit">Create</button> <button type="submit">Create</button>
<button type="submit" @click=${event => { event.preventDefault(); this.dialog.value.close(); this.form.value.reset() }}> Cancel </button>
</form> </form>
</section> </dialog>
` `
} }

View File

@@ -1,5 +1,6 @@
import { html, LitElement } from "lit"; import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import { Ref, createRef, ref } from 'lit/directives/ref.js';
import { createClient } from "webdav"; import { createClient } from "webdav";
@customElement("create-calendar-form") @customElement("create-calendar-form")
@@ -30,12 +31,16 @@ export class CreateCalendarForm extends LitElement {
@property() @property()
components: Set<"VEVENT" | "VTODO" | "VJOURNAL"> = new Set() components: Set<"VEVENT" | "VTODO" | "VJOURNAL"> = new Set()
dialog: Ref<HTMLDialogElement> = createRef()
form: Ref<HTMLFormElement> = createRef()
override render() { override render() {
return html` return html`
<section> <button @click=${() => this.dialog.value.showModal()}>Create calendar</button>
<dialog ${ref(this.dialog)}>
<h3>Create calendar</h3> <h3>Create calendar</h3>
<form @submit=${this.submit}> <form @submit=${this.submit} ${ref(this.form)}>
<label> <label>
id id
<input type="text" name="id" @change=${e => this.id = e.target.value} /> <input type="text" name="id" @change=${e => this.id = e.target.value} />
@@ -69,9 +74,10 @@ export class CreateCalendarForm extends LitElement {
`)} `)}
<br> <br>
<button type="submit">Create</button> <button type="submit">Create</button>
</form> <button type="submit" @click=${event => { event.preventDefault(); this.dialog.value.close(); this.form.value.reset() }}> Cancel </button>
</section> </form>
` </dialog>
`
} }
async submit(e: SubmitEvent) { async submit(e: SubmitEvent) {
@@ -89,7 +95,7 @@ export class CreateCalendarForm extends LitElement {
alert("No calendar components selected") alert("No calendar components selected")
return return
} }
await this.client.createDirectory(`/principal/${this.user}/${this.id}`, { await this.client.createDirectory(`/ principal / ${this.user}/${this.id}`, {
data: ` data: `
<mkcol xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CS="http://calendarserver.org/ns/" xmlns:ICAL="http://apple.com/ns/ical/"> <mkcol xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CS="http://calendarserver.org/ns/" xmlns:ICAL="http://apple.com/ns/ical/">
<set> <set>

View File

@@ -1,45 +1,49 @@
import { i as d, x as m } from "./lit-Dq9MfRDi.mjs"; import { i as c, x as u } from "./lit-CWlWuEHk.mjs";
import { n, t as c } from "./property-DwhV4xIV.mjs"; import { e as d, n as m, a as o, t as h } from "./ref-DuYNkSJ_.mjs";
import { a as u } from "./webdav-Bz4I5vNH.mjs"; import { a as b } from "./webdav-Bz4I5vNH.mjs";
var h = Object.defineProperty, y = Object.getOwnPropertyDescriptor, r = (e, a, o, s) => { var y = Object.defineProperty, f = Object.getOwnPropertyDescriptor, a = (t, s, l, r) => {
for (var t = s > 1 ? void 0 : s ? y(a, o) : a, p = e.length - 1, l; p >= 0; p--) for (var e = r > 1 ? void 0 : r ? f(s, l) : s, n = t.length - 1, p; n >= 0; n--)
(l = e[p]) && (t = (s ? l(a, o, t) : l(t)) || t); (p = t[n]) && (e = (r ? p(s, l, e) : p(e)) || e);
return s && t && h(a, o, t), t; return r && e && y(s, l, e), e;
}; };
let i = class extends d { let i = class extends c {
constructor() { constructor() {
super(), this.client = u("/carddav"), this.user = "", this.id = "", this.displayname = "", this.description = ""; super(), this.client = b("/carddav"), this.user = "", this.id = "", this.displayname = "", this.description = "", this.dialog = d(), this.form = d();
} }
createRenderRoot() { createRenderRoot() {
return this; return this;
} }
render() { render() {
return m` return u`
<section> <button @click=${() => this.dialog.value.showModal()}>Create addressbook</button>
<h3>Create calendar</h3> <dialog ${m(this.dialog)}>
<form @submit=${this.submit}> <h3>Create addressbook</h3>
<form @submit=${this.submit} ${m(this.form)}>
<label> <label>
id id
<input type="text" name="id" @change=${(e) => this.id = e.target.value} /> <input type="text" name="id" @change=${(t) => this.id = t.target.value} />
</label> </label>
<br> <br>
<label> <label>
Displayname Displayname
<input type="text" name="displayname" value=${this.displayname} @change=${(e) => this.displayname = e.target.value} /> <input type="text" name="displayname" value=${this.displayname} @change=${(t) => this.displayname = t.target.value} />
</label> </label>
<br> <br>
<label> <label>
Description Description
<input type="text" name="description" @change=${(e) => this.description = e.target.value} /> <input type="text" name="description" @change=${(t) => this.description = t.target.value} />
</label> </label>
<br> <br>
<button type="submit">Create</button> <button type="submit">Create</button>
<button type="submit" @click=${(t) => {
t.preventDefault(), this.dialog.value.close(), this.form.value.reset();
}}> Cancel </button>
</form> </form>
</section> </dialog>
`; `;
} }
async submit(e) { async submit(t) {
if (console.log(this.displayname), e.preventDefault(), !this.id) { if (console.log(this.displayname), t.preventDefault(), !this.id) {
alert("Empty id"); alert("Empty id");
return; return;
} }
@@ -61,20 +65,20 @@ let i = class extends d {
}), window.location.reload(), null; }), window.location.reload(), null;
} }
}; };
r([ a([
n() o()
], i.prototype, "user", 2); ], i.prototype, "user", 2);
r([ a([
n() o()
], i.prototype, "id", 2); ], i.prototype, "id", 2);
r([ a([
n() o()
], i.prototype, "displayname", 2); ], i.prototype, "displayname", 2);
r([ a([
n() o()
], i.prototype, "description", 2); ], i.prototype, "description", 2);
i = r([ i = a([
c("create-addressbook-form") h("create-addressbook-form")
], i); ], i);
export { export {
i as CreateAddressbookForm i as CreateAddressbookForm

View File

@@ -1,62 +1,66 @@
import { i as m, x as c } from "./lit-Dq9MfRDi.mjs"; import { i as u, x as c } from "./lit-CWlWuEHk.mjs";
import { n as s, t as d } from "./property-DwhV4xIV.mjs"; import { e as d, n as m, a as o, t as h } from "./ref-DuYNkSJ_.mjs";
import { a as u } from "./webdav-Bz4I5vNH.mjs"; import { a as b } from "./webdav-Bz4I5vNH.mjs";
var h = Object.defineProperty, b = Object.getOwnPropertyDescriptor, a = (e, t, o, n) => { var y = Object.defineProperty, $ = Object.getOwnPropertyDescriptor, a = (t, e, l, s) => {
for (var i = n > 1 ? void 0 : n ? b(t, o) : t, l = e.length - 1, p; l >= 0; l--) for (var i = s > 1 ? void 0 : s ? $(e, l) : e, n = t.length - 1, p; n >= 0; n--)
(p = e[l]) && (i = (n ? p(t, o, i) : p(i)) || i); (p = t[n]) && (i = (s ? p(e, l, i) : p(i)) || i);
return n && i && h(t, o, i), i; return s && i && y(e, l, i), i;
}; };
let r = class extends m { let r = class extends u {
constructor() { constructor() {
super(), this.client = u("/caldav"), this.user = "", this.id = "", this.displayname = "", this.description = "", this.color = "", this.subscriptionUrl = "", this.components = /* @__PURE__ */ new Set(); super(), this.client = b("/caldav"), this.user = "", this.id = "", this.displayname = "", this.description = "", this.color = "", this.subscriptionUrl = "", this.components = /* @__PURE__ */ new Set(), this.dialog = d(), this.form = d();
} }
createRenderRoot() { createRenderRoot() {
return this; return this;
} }
render() { render() {
return c` return c`
<section> <button @click=${() => this.dialog.value.showModal()}>Create calendar</button>
<dialog ${m(this.dialog)}>
<h3>Create calendar</h3> <h3>Create calendar</h3>
<form @submit=${this.submit}> <form @submit=${this.submit} ${m(this.form)}>
<label> <label>
id id
<input type="text" name="id" @change=${(e) => this.id = e.target.value} /> <input type="text" name="id" @change=${(t) => this.id = t.target.value} />
</label> </label>
<br> <br>
<label> <label>
Displayname Displayname
<input type="text" name="displayname" value=${this.displayname} @change=${(e) => this.displayname = e.target.value} /> <input type="text" name="displayname" value=${this.displayname} @change=${(t) => this.displayname = t.target.value} />
</label> </label>
<br> <br>
<label> <label>
Description Description
<input type="text" name="description" @change=${(e) => this.description = e.target.value} /> <input type="text" name="description" @change=${(t) => this.description = t.target.value} />
</label> </label>
<br> <br>
<label> <label>
Color Color
<input type="color" name="color" @change=${(e) => this.color = e.target.value} /> <input type="color" name="color" @change=${(t) => this.color = t.target.value} />
</label> </label>
<br> <br>
<label> <label>
Subscription URL Subscription URL
<input type="text" name="subscription_url" @change=${(e) => this.subscriptionUrl = e.target.value} /> <input type="text" name="subscription_url" @change=${(t) => this.subscriptionUrl = t.target.value} />
</label> </label>
<br> <br>
${["VEVENT", "VTODO", "VJOURNAL"].map((e) => c` ${["VEVENT", "VTODO", "VJOURNAL"].map((t) => c`
<label> <label>
Support ${e} Support ${t}
<input type="checkbox" value=${e} @change=${(t) => t.target.checked ? this.components.add(t.target.value) : this.components.delete(t.target.value)} /> <input type="checkbox" value=${t} @change=${(e) => e.target.checked ? this.components.add(e.target.value) : this.components.delete(e.target.value)} />
</label> </label>
`)} `)}
<br> <br>
<button type="submit">Create</button> <button type="submit">Create</button>
</form> <button type="submit" @click=${(t) => {
</section> t.preventDefault(), this.dialog.value.close(), this.form.value.reset();
`; }}> Cancel </button>
</form>
</dialog>
`;
} }
async submit(e) { async submit(t) {
if (console.log(this.displayname), e.preventDefault(), !this.id) { if (console.log(this.displayname), t.preventDefault(), !this.id) {
alert("Empty id"); alert("Empty id");
return; return;
} }
@@ -68,7 +72,7 @@ let r = class extends m {
alert("No calendar components selected"); alert("No calendar components selected");
return; return;
} }
return await this.client.createDirectory(`/principal/${this.user}/${this.id}`, { return await this.client.createDirectory(`/ principal / ${this.user}/${this.id}`, {
data: ` data: `
<mkcol xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CS="http://calendarserver.org/ns/" xmlns:ICAL="http://apple.com/ns/ical/"> <mkcol xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CS="http://calendarserver.org/ns/" xmlns:ICAL="http://apple.com/ns/ical/">
<set> <set>
@@ -78,7 +82,7 @@ let r = class extends m {
${this.color ? `<ICAL:calendar-color>${this.color}</ICAL:calendar-color>` : ""} ${this.color ? `<ICAL:calendar-color>${this.color}</ICAL:calendar-color>` : ""}
${this.subscriptionUrl ? `<CS:source>${this.subscriptionUrl}</CS:source>` : ""} ${this.subscriptionUrl ? `<CS:source>${this.subscriptionUrl}</CS:source>` : ""}
<CAL:supported-calendar-component-set> <CAL:supported-calendar-component-set>
${Array.from(this.components.keys()).map((t) => `<CAL:comp name="${t}" />`).join(` ${Array.from(this.components.keys()).map((e) => `<CAL:comp name="${e}" />`).join(`
`)} `)}
</CAL:supported-calendar-component-set> </CAL:supported-calendar-component-set>
</prop> </prop>
@@ -89,28 +93,28 @@ let r = class extends m {
} }
}; };
a([ a([
s() o()
], r.prototype, "user", 2); ], r.prototype, "user", 2);
a([ a([
s() o()
], r.prototype, "id", 2); ], r.prototype, "id", 2);
a([ a([
s() o()
], r.prototype, "displayname", 2); ], r.prototype, "displayname", 2);
a([ a([
s() o()
], r.prototype, "description", 2); ], r.prototype, "description", 2);
a([ a([
s() o()
], r.prototype, "color", 2); ], r.prototype, "color", 2);
a([ a([
s() o()
], r.prototype, "subscriptionUrl", 2); ], r.prototype, "subscriptionUrl", 2);
a([ a([
s() o()
], r.prototype, "components", 2); ], r.prototype, "components", 2);
r = a([ r = a([
d("create-calendar-form") h("create-calendar-form")
], r); ], r);
export { export {
r as CreateCalendarForm r as CreateCalendarForm

View File

@@ -543,6 +543,7 @@ const z = y.litElementPolyfillSupport;
z == null || z({ LitElement: T }); z == null || z({ LitElement: T });
(y.litElementVersions ?? (y.litElementVersions = [])).push("4.2.0"); (y.litElementVersions ?? (y.litElementVersions = [])).push("4.2.0");
export { export {
d as E,
et as f, et as f,
T as i, T as i,
j as u, j as u,

View File

@@ -1,47 +0,0 @@
import { f as d, u as l } from "./lit-Dq9MfRDi.mjs";
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const f = (t) => (r, e) => {
e !== void 0 ? e.addInitializer(() => {
customElements.define(t, r);
}) : customElements.define(t, r);
};
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const p = { attribute: !0, type: String, converter: l, reflect: !1, hasChanged: d }, u = (t = p, r, e) => {
const { kind: i, metadata: a } = e;
let n = globalThis.litPropertyMetadata.get(a);
if (n === void 0 && globalThis.litPropertyMetadata.set(a, n = /* @__PURE__ */ new Map()), i === "setter" && ((t = Object.create(t)).wrapped = !0), n.set(e.name, t), i === "accessor") {
const { name: o } = e;
return { set(s) {
const c = r.get.call(this);
r.set.call(this, s), this.requestUpdate(o, c, t);
}, init(s) {
return s !== void 0 && this.C(o, void 0, t, s), s;
} };
}
if (i === "setter") {
const { name: o } = e;
return function(s) {
const c = this[o];
r.call(this, s), this.requestUpdate(o, c, t);
};
}
throw Error("Unsupported decorator location: " + i);
};
function m(t) {
return (r, e) => typeof e == "object" ? u(t, r, e) : ((i, a, n) => {
const o = a.hasOwnProperty(n);
return a.constructor.createProperty(n, i), o ? Object.getOwnPropertyDescriptor(a, n) : void 0;
})(t, r, e);
}
export {
m as n,
f as t
};

View File

@@ -0,0 +1,172 @@
import { f, u as _, E as $ } from "./lit-CWlWuEHk.mjs";
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const T = (t) => (e, s) => {
s !== void 0 ? s.addInitializer(() => {
customElements.define(t, e);
}) : customElements.define(t, e);
};
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const A = { attribute: !0, type: String, converter: _, reflect: !1, hasChanged: f }, p = (t = A, e, s) => {
const { kind: i, metadata: n } = s;
let r = globalThis.litPropertyMetadata.get(n);
if (r === void 0 && globalThis.litPropertyMetadata.set(n, r = /* @__PURE__ */ new Map()), i === "setter" && ((t = Object.create(t)).wrapped = !0), r.set(s.name, t), i === "accessor") {
const { name: o } = s;
return { set(h) {
const l = e.get.call(this);
e.set.call(this, h), this.requestUpdate(o, l, t);
}, init(h) {
return h !== void 0 && this.C(o, void 0, t, h), h;
} };
}
if (i === "setter") {
const { name: o } = s;
return function(h) {
const l = this[o];
e.call(this, h), this.requestUpdate(o, l, t);
};
}
throw Error("Unsupported decorator location: " + i);
};
function O(t) {
return (e, s) => typeof s == "object" ? p(t, e, s) : ((i, n, r) => {
const o = n.hasOwnProperty(r);
return n.constructor.createProperty(r, i), o ? Object.getOwnPropertyDescriptor(n, r) : void 0;
})(t, e, s);
}
/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const v = (t) => t.strings === void 0;
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const g = { CHILD: 2 }, C = (t) => (...e) => ({ _$litDirective$: t, values: e });
class m {
constructor(e) {
}
get _$AU() {
return this._$AM._$AU;
}
_$AT(e, s, i) {
this._$Ct = e, this._$AM = s, this._$Ci = i;
}
_$AS(e, s) {
return this.update(e, s);
}
update(e, s) {
return this.render(...s);
}
}
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const c = (t, e) => {
var i;
const s = t._$AN;
if (s === void 0) return !1;
for (const n of s) (i = n._$AO) == null || i.call(n, e, !1), c(n, e);
return !0;
}, a = (t) => {
let e, s;
do {
if ((e = t._$AM) === void 0) break;
s = e._$AN, s.delete(t), t = e;
} while ((s == null ? void 0 : s.size) === 0);
}, u = (t) => {
for (let e; e = t._$AM; t = e) {
let s = e._$AN;
if (s === void 0) e._$AN = s = /* @__PURE__ */ new Set();
else if (s.has(t)) break;
s.add(t), M(e);
}
};
function y(t) {
this._$AN !== void 0 ? (a(this), this._$AM = t, u(this)) : this._$AM = t;
}
function G(t, e = !1, s = 0) {
const i = this._$AH, n = this._$AN;
if (n !== void 0 && n.size !== 0) if (e) if (Array.isArray(i)) for (let r = s; r < i.length; r++) c(i[r], !1), a(i[r]);
else i != null && (c(i, !1), a(i));
else c(this, t);
}
const M = (t) => {
t.type == g.CHILD && (t._$AP ?? (t._$AP = G), t._$AQ ?? (t._$AQ = y));
};
class b extends m {
constructor() {
super(...arguments), this._$AN = void 0;
}
_$AT(e, s, i) {
super._$AT(e, s, i), u(this), this.isConnected = e._$AU;
}
_$AO(e, s = !0) {
var i, n;
e !== this.isConnected && (this.isConnected = e, e ? (i = this.reconnected) == null || i.call(this) : (n = this.disconnected) == null || n.call(this)), s && (c(this, e), a(this));
}
setValue(e) {
if (v(this._$Ct)) this._$Ct._$AI(e, this);
else {
const s = [...this._$Ct._$AH];
s[this._$Ci] = e, this._$Ct._$AI(s, this, 0);
}
}
disconnected() {
}
reconnected() {
}
}
/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const P = () => new w();
class w {
}
const d = /* @__PURE__ */ new WeakMap(), U = C(class extends b {
render(t) {
return $;
}
update(t, [e]) {
var i;
const s = e !== this.G;
return s && this.G !== void 0 && this.rt(void 0), (s || this.lt !== this.ct) && (this.G = e, this.ht = (i = t.options) == null ? void 0 : i.host, this.rt(this.ct = t.element)), $;
}
rt(t) {
if (this.isConnected || (t = void 0), typeof this.G == "function") {
const e = this.ht ?? globalThis;
let s = d.get(e);
s === void 0 && (s = /* @__PURE__ */ new WeakMap(), d.set(e, s)), s.get(this.G) !== void 0 && this.G.call(this.ht, void 0), s.set(this.G, t), t !== void 0 && this.G.call(this.ht, t);
} else this.G.value = t;
}
get lt() {
var t, e;
return typeof this.G == "function" ? (t = d.get(this.ht ?? globalThis)) == null ? void 0 : t.get(this.G) : (e = this.G) == null ? void 0 : e.value;
}
disconnected() {
this.lt === this.ct && this.rt(void 0);
}
reconnected() {
this.rt(this.ct);
}
});
export {
O as a,
P as e,
U as n,
T as t
};