2025-01-05 12:21:01 +02:00
|
|
|
import Component, { TypedComponent } from "../components/component.js";
|
2024-10-24 18:47:16 +03:00
|
|
|
import froca from "../services/froca.js";
|
2024-07-27 12:26:35 +03:00
|
|
|
import { t } from "../services/i18n.js";
|
|
|
|
import toastService from "../services/toast.js";
|
2023-08-21 04:15:53 -04:00
|
|
|
|
2025-01-05 12:21:01 +02:00
|
|
|
export class TypedBasicWidget<T extends TypedComponent<any>> extends TypedComponent<T> {
|
2025-01-04 12:44:40 +02:00
|
|
|
protected attrs: Record<string, string>;
|
2024-12-21 15:09:52 +02:00
|
|
|
private classes: string[];
|
|
|
|
private childPositionCounter: number;
|
|
|
|
private cssEl?: string;
|
|
|
|
_noteId!: string;
|
|
|
|
|
2020-03-01 18:57:13 +01:00
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
|
|
|
|
this.attrs = {
|
|
|
|
style: ''
|
|
|
|
};
|
|
|
|
this.classes = [];
|
2022-09-18 14:57:44 +02:00
|
|
|
|
|
|
|
this.children = [];
|
|
|
|
this.childPositionCounter = 10;
|
|
|
|
}
|
|
|
|
|
2025-01-05 12:21:01 +02:00
|
|
|
child(...components: T[]) {
|
2022-09-18 14:57:44 +02:00
|
|
|
if (!components) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
super.child(...components);
|
|
|
|
|
|
|
|
for (const component of components) {
|
|
|
|
if (component.position === undefined) {
|
|
|
|
component.position = this.childPositionCounter;
|
|
|
|
this.childPositionCounter += 10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-03 01:11:47 +01:00
|
|
|
this.children.sort((a, b) => a.position - b.position);
|
2022-09-18 14:57:44 +02:00
|
|
|
|
|
|
|
return this;
|
2020-03-01 18:57:13 +01:00
|
|
|
}
|
|
|
|
|
2024-11-22 20:36:08 +02:00
|
|
|
/**
|
|
|
|
* Conditionally adds the given components as children to this component.
|
2024-12-22 16:22:10 +02:00
|
|
|
*
|
2024-12-21 15:09:52 +02:00
|
|
|
* @param condition whether to add the components.
|
2024-12-22 16:22:10 +02:00
|
|
|
* @param components the components to be added as children to this component provided the condition is truthy.
|
2024-11-22 20:36:08 +02:00
|
|
|
* @returns self for chaining.
|
|
|
|
*/
|
2025-01-05 12:21:01 +02:00
|
|
|
optChild(condition: boolean, ...components: T[]) {
|
2024-11-22 20:36:08 +02:00
|
|
|
if (condition) {
|
|
|
|
return this.child(...components);
|
|
|
|
} else {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-21 15:09:52 +02:00
|
|
|
id(id: string) {
|
2020-03-01 18:57:13 +01:00
|
|
|
this.attrs.id = id;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2024-12-21 15:09:52 +02:00
|
|
|
class(className: string) {
|
2020-03-01 18:57:13 +01:00
|
|
|
this.classes.push(className);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2024-11-23 10:01:49 +02:00
|
|
|
/**
|
|
|
|
* Sets the CSS attribute of the given name to the given value.
|
2024-12-22 16:22:10 +02:00
|
|
|
*
|
2024-12-21 15:09:52 +02:00
|
|
|
* @param name the name of the CSS attribute to set (e.g. `padding-left`).
|
|
|
|
* @param value the value of the CSS attribute to set (e.g. `12px`).
|
2024-11-23 10:01:49 +02:00
|
|
|
* @returns self for chaining.
|
|
|
|
*/
|
2024-12-21 15:09:52 +02:00
|
|
|
css(name: string, value: string) {
|
2020-03-01 18:57:13 +01:00
|
|
|
this.attrs.style += `${name}: ${value};`;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2024-11-23 10:01:49 +02:00
|
|
|
/**
|
|
|
|
* Sets the CSS attribute of the given name to the given value, but only if the condition provided is truthy.
|
2024-12-22 16:22:10 +02:00
|
|
|
*
|
2024-12-21 15:09:52 +02:00
|
|
|
* @param condition `true` in order to apply the CSS, `false` to ignore it.
|
|
|
|
* @param name the name of the CSS attribute to set (e.g. `padding-left`).
|
|
|
|
* @param value the value of the CSS attribute to set (e.g. `12px`).
|
2024-11-23 10:01:49 +02:00
|
|
|
* @returns self for chaining.
|
|
|
|
*/
|
2024-12-21 15:09:52 +02:00
|
|
|
optCss(condition: boolean, name: string, value: string) {
|
2024-11-23 09:59:48 +02:00
|
|
|
if (condition) {
|
|
|
|
return this.css(name, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2020-08-16 22:57:48 +02:00
|
|
|
contentSized() {
|
2021-06-13 22:55:31 +02:00
|
|
|
this.css("contain", "none");
|
2021-06-05 22:07:15 +02:00
|
|
|
|
2020-08-16 22:57:48 +02:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2020-03-01 18:57:13 +01:00
|
|
|
collapsible() {
|
|
|
|
this.css('min-height', '0');
|
2021-06-13 22:55:31 +02:00
|
|
|
this.css('min-width', '0');
|
2020-03-01 18:57:13 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2020-05-12 12:45:32 +02:00
|
|
|
filling() {
|
|
|
|
this.css('flex-grow', '1');
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2023-08-21 04:15:53 -04:00
|
|
|
/**
|
|
|
|
* Accepts a string of CSS to add with the widget.
|
2024-12-21 15:09:52 +02:00
|
|
|
* @returns for chaining
|
2023-08-21 04:15:53 -04:00
|
|
|
*/
|
2024-12-21 15:09:52 +02:00
|
|
|
cssBlock(block: string) {
|
2020-03-01 18:57:13 +01:00
|
|
|
this.cssEl = block;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2020-01-11 21:19:56 +01:00
|
|
|
render() {
|
2024-07-27 12:26:35 +03:00
|
|
|
try {
|
|
|
|
this.doRender();
|
2024-12-22 16:22:10 +02:00
|
|
|
} catch (e: any) {
|
2024-10-25 19:57:31 +03:00
|
|
|
this.logRenderingError(e);
|
2024-07-27 12:26:35 +03:00
|
|
|
}
|
2020-01-20 22:35:52 +01:00
|
|
|
|
2022-12-11 13:20:37 +01:00
|
|
|
this.$widget.attr('data-component-id', this.componentId);
|
2023-11-03 10:44:14 +01:00
|
|
|
this.$widget
|
|
|
|
.addClass('component')
|
2020-02-16 10:50:48 +01:00
|
|
|
.prop('component', this);
|
|
|
|
|
2020-07-14 23:29:37 +02:00
|
|
|
if (!this.isEnabled()) {
|
|
|
|
this.toggleInt(false);
|
|
|
|
}
|
2020-02-08 21:54:39 +01:00
|
|
|
|
2020-03-01 18:57:13 +01:00
|
|
|
if (this.cssEl) {
|
|
|
|
const css = this.cssEl.trim().startsWith('<style>') ? this.cssEl : `<style>${this.cssEl}</style>`;
|
|
|
|
|
2020-06-26 22:17:39 +02:00
|
|
|
this.$widget.append(css);
|
2020-03-01 18:57:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (const key in this.attrs) {
|
2020-04-07 22:53:03 +02:00
|
|
|
if (key === 'style') {
|
2020-04-08 10:19:15 +02:00
|
|
|
if (this.attrs[key]) {
|
2020-06-26 22:17:39 +02:00
|
|
|
let style = this.$widget.attr('style');
|
2020-04-25 11:09:07 +02:00
|
|
|
style = style ? `${style}; ${this.attrs[key]}` : this.attrs[key];
|
|
|
|
|
2020-06-26 22:17:39 +02:00
|
|
|
this.$widget.attr(key, style);
|
2020-04-08 10:19:15 +02:00
|
|
|
}
|
2020-04-07 22:53:03 +02:00
|
|
|
}
|
|
|
|
else {
|
2020-06-26 22:17:39 +02:00
|
|
|
this.$widget.attr(key, this.attrs[key]);
|
2020-04-07 22:53:03 +02:00
|
|
|
}
|
2020-03-01 18:57:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (const className of this.classes) {
|
2020-06-26 22:17:39 +02:00
|
|
|
this.$widget.addClass(className);
|
2020-03-01 18:57:13 +01:00
|
|
|
}
|
|
|
|
|
2020-06-26 22:17:39 +02:00
|
|
|
return this.$widget;
|
2020-01-11 21:19:56 +01:00
|
|
|
}
|
|
|
|
|
2024-12-21 15:09:52 +02:00
|
|
|
logRenderingError(e: Error) {
|
2024-10-25 19:57:31 +03:00
|
|
|
console.log("Got issue in widget ", this);
|
|
|
|
console.error(e);
|
|
|
|
|
|
|
|
let noteId = this._noteId;
|
|
|
|
if (this._noteId) {
|
|
|
|
froca.getNote(noteId, true).then((note) => {
|
|
|
|
toastService.showPersistent({
|
|
|
|
title: t("toast.widget-error.title"),
|
|
|
|
icon: "alert",
|
|
|
|
message: t("toast.widget-error.message-custom", {
|
|
|
|
id: noteId,
|
2024-12-21 15:09:52 +02:00
|
|
|
title: note?.title,
|
2024-10-25 19:57:31 +03:00
|
|
|
message: e.message
|
|
|
|
})
|
|
|
|
});
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
toastService.showPersistent({
|
|
|
|
title: t("toast.widget-error.title"),
|
|
|
|
icon: "alert",
|
|
|
|
message: t("toast.widget-error.message-unknown", {
|
|
|
|
message: e.message
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-08-16 21:41:15 +03:00
|
|
|
/**
|
|
|
|
* Indicates if the widget is enabled. Widgets are enabled by default. Generally setting this to `false` will cause the widget not to be displayed, however it will still be available on the DOM but hidden.
|
2024-12-11 18:31:29 +02:00
|
|
|
* @returns whether the widget is enabled.
|
2024-08-16 21:41:15 +03:00
|
|
|
*/
|
2020-02-08 21:54:39 +01:00
|
|
|
isEnabled() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-01-11 21:19:56 +01:00
|
|
|
/**
|
2023-08-21 04:15:53 -04:00
|
|
|
* Method used for rendering the widget.
|
2023-11-03 01:11:47 +01:00
|
|
|
*
|
2023-08-21 04:15:53 -04:00
|
|
|
* Your class should override this method.
|
2023-11-03 10:44:14 +01:00
|
|
|
* The method is expected to create a this.$widget containing jQuery object
|
2020-01-11 21:19:56 +01:00
|
|
|
*/
|
2020-01-19 09:02:18 +01:00
|
|
|
doRender() {}
|
2020-01-11 21:19:56 +01:00
|
|
|
|
2024-12-21 15:09:52 +02:00
|
|
|
toggleInt(show: boolean) {
|
2020-03-06 22:17:07 +01:00
|
|
|
this.$widget.toggleClass('hidden-int', !show);
|
|
|
|
}
|
|
|
|
|
2022-05-30 17:45:59 +02:00
|
|
|
isHiddenInt() {
|
|
|
|
return this.$widget.hasClass('hidden-int');
|
|
|
|
}
|
|
|
|
|
2024-12-21 15:09:52 +02:00
|
|
|
toggleExt(show: boolean) {
|
2020-03-06 22:17:07 +01:00
|
|
|
this.$widget.toggleClass('hidden-ext', !show);
|
2020-01-14 20:27:40 +01:00
|
|
|
}
|
|
|
|
|
2022-05-30 17:45:59 +02:00
|
|
|
isHiddenExt() {
|
|
|
|
return this.$widget.hasClass('hidden-ext');
|
|
|
|
}
|
|
|
|
|
|
|
|
canBeShown() {
|
|
|
|
return !this.isHiddenInt() && !this.isHiddenExt();
|
|
|
|
}
|
|
|
|
|
2020-02-04 22:46:17 +01:00
|
|
|
isVisible() {
|
|
|
|
return this.$widget.is(":visible");
|
|
|
|
}
|
|
|
|
|
2020-03-16 21:16:09 +01:00
|
|
|
getPosition() {
|
|
|
|
return this.position;
|
|
|
|
}
|
|
|
|
|
2020-01-19 21:12:53 +01:00
|
|
|
remove() {
|
|
|
|
if (this.$widget) {
|
|
|
|
this.$widget.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-03 23:10:13 +02:00
|
|
|
getClosestNtxId() {
|
2021-05-24 21:05:44 +02:00
|
|
|
if (this.$widget) {
|
|
|
|
return this.$widget.closest("[data-ntx-id]").attr("data-ntx-id");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-11 21:19:56 +01:00
|
|
|
cleanup() {}
|
|
|
|
}
|
|
|
|
|
2025-01-05 12:21:01 +02:00
|
|
|
/**
|
|
|
|
* This is the base widget for all other widgets.
|
|
|
|
*
|
|
|
|
* For information on using widgets, see the tutorial {@tutorial widget_basics}.
|
|
|
|
*/
|
|
|
|
export default class BasicWidget extends TypedBasicWidget<Component> {
|
|
|
|
|
|
|
|
}
|