diff --git a/src/public/app/components/component.ts b/src/public/app/components/component.ts index 2761bfdc6..9300b1f86 100644 --- a/src/public/app/components/component.ts +++ b/src/public/app/components/component.ts @@ -12,12 +12,12 @@ import { CommandMappings, CommandNames } from './app_context.js'; * - although the execution is async, we are collecting all the promises, and therefore it is possible to wait until the * event / command is executed in all components - by simply awaiting the `triggerEvent()`. */ -export default class Component { +export class TypedComponent> { $widget!: JQuery; componentId: string; - children: Component[]; + children: ChildT[]; initialized: Promise | null; - parent?: Component; + parent?: TypedComponent; position!: number; constructor() { @@ -31,12 +31,12 @@ export default class Component { return this.constructor.name.replace(/[^A-Z0-9]/ig, "_"); } - setParent(parent: Component) { + setParent(parent: TypedComponent) { this.parent = parent; return this; } - child(...components: Component[]) { + child(...components: ChildT[]) { for (const component of components) { component.setParent(this); @@ -122,3 +122,5 @@ export default class Component { return promise; } } + +export default class Component extends TypedComponent {} diff --git a/src/public/app/widgets/basic_widget.ts b/src/public/app/widgets/basic_widget.ts index 7be37a00a..bbf734775 100644 --- a/src/public/app/widgets/basic_widget.ts +++ b/src/public/app/widgets/basic_widget.ts @@ -1,14 +1,9 @@ -import Component from "../components/component.js"; +import Component, { TypedComponent } from "../components/component.js"; import froca from "../services/froca.js"; import { t } from "../services/i18n.js"; import toastService from "../services/toast.js"; -/** - * This is the base widget for all other widgets. - * - * For information on using widgets, see the tutorial {@tutorial widget_basics}. - */ -class BasicWidget extends Component { +export class TypedBasicWidget> extends TypedComponent { protected attrs: Record; private classes: string[]; private childPositionCounter: number; @@ -27,7 +22,7 @@ class BasicWidget extends Component { this.childPositionCounter = 10; } - child(...components: Component[]) { + child(...components: T[]) { if (!components) { return this; } @@ -53,7 +48,7 @@ class BasicWidget extends Component { * @param components the components to be added as children to this component provided the condition is truthy. * @returns self for chaining. */ - optChild(condition: boolean, ...components: Component[]) { + optChild(condition: boolean, ...components: T[]) { if (condition) { return this.child(...components); } else { @@ -259,4 +254,11 @@ class BasicWidget extends Component { cleanup() {} } -export default BasicWidget; +/** + * 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 { + +} diff --git a/src/public/app/widgets/containers/container.js b/src/public/app/widgets/containers/container.js deleted file mode 100644 index 07c759bb0..000000000 --- a/src/public/app/widgets/containers/container.js +++ /dev/null @@ -1,18 +0,0 @@ -import BasicWidget from "../basic_widget.js"; - -export default class Container extends BasicWidget { - doRender() { - this.$widget = $(`
`); - this.renderChildren(); - } - - renderChildren() { - for (const widget of this.children) { - try { - this.$widget.append(widget.render()); - } catch (e) { - widget.logRenderingError(e); - } - } - } -} diff --git a/src/public/app/widgets/containers/container.ts b/src/public/app/widgets/containers/container.ts new file mode 100644 index 000000000..8f488a552 --- /dev/null +++ b/src/public/app/widgets/containers/container.ts @@ -0,0 +1,30 @@ +import Component, { TypedComponent } from "../../components/component.js"; +import BasicWidget, { TypedBasicWidget } from "../basic_widget.js"; + +export default class Container> extends TypedBasicWidget { + + doRender() { + this.$widget = $(`
`); + this.renderChildren(); + } + + renderChildren() { + for (const widget of this.children) { + if (!("render" in widget)) { + throw "Non-renderable widget encountered."; + } + + const typedWidget = widget as unknown as TypedBasicWidget; + + try { + if ("render" in widget) { + this.$widget.append(typedWidget.render()); + } + + } catch (e: any) { + typedWidget.logRenderingError(e); + } + } + } + +} diff --git a/src/public/app/widgets/containers/flex_container.ts b/src/public/app/widgets/containers/flex_container.ts index 095bc35b6..cb70b1181 100644 --- a/src/public/app/widgets/containers/flex_container.ts +++ b/src/public/app/widgets/containers/flex_container.ts @@ -1,8 +1,9 @@ +import { TypedComponent } from "../../components/component.js"; import Container from "./container.js"; export type FlexDirection = "row" | "column"; -export default class FlexContainer extends Container { +export default class FlexContainer> extends Container { constructor(direction: FlexDirection) { super(); @@ -13,4 +14,5 @@ export default class FlexContainer extends Container { this.attrs.style = `display: flex; flex-direction: ${direction};`; } + } diff --git a/src/public/app/widgets/containers/launcher_container.ts b/src/public/app/widgets/containers/launcher_container.ts index 3748819de..e0f574027 100644 --- a/src/public/app/widgets/containers/launcher_container.ts +++ b/src/public/app/widgets/containers/launcher_container.ts @@ -4,7 +4,7 @@ import appContext, { EventData } from "../../components/app_context.js"; import LauncherWidget from "./launcher.js"; import utils from "../../services/utils.js"; -export default class LauncherContainer extends FlexContainer { +export default class LauncherContainer extends FlexContainer { private isHorizontalLayout: boolean; constructor(isHorizontalLayout: boolean) { diff --git a/src/public/app/widgets/containers/right_pane_container.js b/src/public/app/widgets/containers/right_pane_container.ts similarity index 87% rename from src/public/app/widgets/containers/right_pane_container.js rename to src/public/app/widgets/containers/right_pane_container.ts index c62ea9ca6..9612aceff 100644 --- a/src/public/app/widgets/containers/right_pane_container.js +++ b/src/public/app/widgets/containers/right_pane_container.ts @@ -1,7 +1,11 @@ import FlexContainer from "./flex_container.js"; import splitService from "../../services/resizer.js"; +import RightPanelWidget from "../right_panel_widget.js"; + +export default class RightPaneContainer extends FlexContainer { + + private rightPaneHidden: boolean; -export default class RightPaneContainer extends FlexContainer { constructor() { super('column'); @@ -19,7 +23,7 @@ export default class RightPaneContainer extends FlexContainer { && !!this.children.find(ch => ch.isEnabled() && ch.canBeShown()); } - handleEventInChildren(name, data) { + handleEventInChildren(name: string, data: unknown) { const promise = super.handleEventInChildren(name, data); if (['activeContextChanged', 'noteSwitchedAndActivated', 'noteSwitched'].includes(name)) { diff --git a/src/public/app/widgets/mobile_widgets/sidebar_container.ts b/src/public/app/widgets/mobile_widgets/sidebar_container.ts index 0c89bbd78..1183f366c 100644 --- a/src/public/app/widgets/mobile_widgets/sidebar_container.ts +++ b/src/public/app/widgets/mobile_widgets/sidebar_container.ts @@ -1,5 +1,6 @@ import { EventData } from "../../components/app_context.js"; import { Screen } from "../../components/mobile_screen_switcher.js"; +import BasicWidget from "../basic_widget.js"; import FlexContainer, { FlexDirection } from "../containers/flex_container.js"; const DRAG_STATE_NONE = 0; @@ -14,7 +15,7 @@ const DRAG_CLOSED_START_THRESHOLD = 10; /** The number of pixels the user has to drag across the screen to the left when the sidebar is opened to trigger the drag close animation. */ const DRAG_OPENED_START_THRESHOLD = 80; -export default class SidebarContainer extends FlexContainer { +export default class SidebarContainer extends FlexContainer { private screenName: Screen; /** The screen name that is currently active, according to the screen changed event. */ diff --git a/src/public/app/widgets/right_panel_widget.js b/src/public/app/widgets/right_panel_widget.ts similarity index 87% rename from src/public/app/widgets/right_panel_widget.js rename to src/public/app/widgets/right_panel_widget.ts index 019d5f4c2..6a68619ff 100644 --- a/src/public/app/widgets/right_panel_widget.js +++ b/src/public/app/widgets/right_panel_widget.ts @@ -1,6 +1,5 @@ +import BasicWidget from "./basic_widget.js"; import NoteContextAwareWidget from "./note_context_aware_widget.js"; -import toastService from "../services/toast.js"; -import { t } from "../services/i18n.js"; const WIDGET_TPL = `
@@ -19,6 +18,12 @@ const WIDGET_TPL = ` * @extends {NoteContextAwareWidget} */ class RightPanelWidget extends NoteContextAwareWidget { + + private $bodyWrapper!: JQuery; + $body!: JQuery; + private $title!: JQuery; + private $buttons!: JQuery; + /** Title to show in the panel. */ get widgetTitle() { return "Untitled widget"; } @@ -53,7 +58,7 @@ class RightPanelWidget extends NoteContextAwareWidget { this.$buttons.empty(); for (const buttonWidget of this.children) { - this.$buttons.append(buttonWidget.render()); + this.$buttons.append((buttonWidget as BasicWidget).render()); } this.initialized = this.doRenderBody().catch(e => {