mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-08-11 19:22:31 +08:00
chore(types): allow containers to constrain children
This commit is contained in:
parent
4cfb0d6161
commit
6d41af98fd
@ -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
|
* - 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()`.
|
* event / command is executed in all components - by simply awaiting the `triggerEvent()`.
|
||||||
*/
|
*/
|
||||||
export default class Component {
|
export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
|
||||||
$widget!: JQuery<HTMLElement>;
|
$widget!: JQuery<HTMLElement>;
|
||||||
componentId: string;
|
componentId: string;
|
||||||
children: Component[];
|
children: ChildT[];
|
||||||
initialized: Promise<void> | null;
|
initialized: Promise<void> | null;
|
||||||
parent?: Component;
|
parent?: TypedComponent<any>;
|
||||||
position!: number;
|
position!: number;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -31,12 +31,12 @@ export default class Component {
|
|||||||
return this.constructor.name.replace(/[^A-Z0-9]/ig, "_");
|
return this.constructor.name.replace(/[^A-Z0-9]/ig, "_");
|
||||||
}
|
}
|
||||||
|
|
||||||
setParent(parent: Component) {
|
setParent(parent: TypedComponent<any>) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
child(...components: Component[]) {
|
child(...components: ChildT[]) {
|
||||||
for (const component of components) {
|
for (const component of components) {
|
||||||
component.setParent(this);
|
component.setParent(this);
|
||||||
|
|
||||||
@ -122,3 +122,5 @@ export default class Component {
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default class Component extends TypedComponent<Component> {}
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
import Component from "../components/component.js";
|
import Component, { TypedComponent } from "../components/component.js";
|
||||||
import froca from "../services/froca.js";
|
import froca from "../services/froca.js";
|
||||||
import { t } from "../services/i18n.js";
|
import { t } from "../services/i18n.js";
|
||||||
import toastService from "../services/toast.js";
|
import toastService from "../services/toast.js";
|
||||||
|
|
||||||
/**
|
export class TypedBasicWidget<T extends TypedComponent<any>> extends TypedComponent<T> {
|
||||||
* This is the base widget for all other widgets.
|
|
||||||
*
|
|
||||||
* For information on using widgets, see the tutorial {@tutorial widget_basics}.
|
|
||||||
*/
|
|
||||||
class BasicWidget extends Component {
|
|
||||||
protected attrs: Record<string, string>;
|
protected attrs: Record<string, string>;
|
||||||
private classes: string[];
|
private classes: string[];
|
||||||
private childPositionCounter: number;
|
private childPositionCounter: number;
|
||||||
@ -27,7 +22,7 @@ class BasicWidget extends Component {
|
|||||||
this.childPositionCounter = 10;
|
this.childPositionCounter = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
child(...components: Component[]) {
|
child(...components: T[]) {
|
||||||
if (!components) {
|
if (!components) {
|
||||||
return this;
|
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.
|
* @param components the components to be added as children to this component provided the condition is truthy.
|
||||||
* @returns self for chaining.
|
* @returns self for chaining.
|
||||||
*/
|
*/
|
||||||
optChild(condition: boolean, ...components: Component[]) {
|
optChild(condition: boolean, ...components: T[]) {
|
||||||
if (condition) {
|
if (condition) {
|
||||||
return this.child(...components);
|
return this.child(...components);
|
||||||
} else {
|
} else {
|
||||||
@ -259,4 +254,11 @@ class BasicWidget extends Component {
|
|||||||
cleanup() {}
|
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<Component> {
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
import BasicWidget from "../basic_widget.js";
|
|
||||||
|
|
||||||
export default class Container extends BasicWidget {
|
|
||||||
doRender() {
|
|
||||||
this.$widget = $(`<div>`);
|
|
||||||
this.renderChildren();
|
|
||||||
}
|
|
||||||
|
|
||||||
renderChildren() {
|
|
||||||
for (const widget of this.children) {
|
|
||||||
try {
|
|
||||||
this.$widget.append(widget.render());
|
|
||||||
} catch (e) {
|
|
||||||
widget.logRenderingError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
30
src/public/app/widgets/containers/container.ts
Normal file
30
src/public/app/widgets/containers/container.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import Component, { TypedComponent } from "../../components/component.js";
|
||||||
|
import BasicWidget, { TypedBasicWidget } from "../basic_widget.js";
|
||||||
|
|
||||||
|
export default class Container<T extends TypedComponent<any>> extends TypedBasicWidget<T> {
|
||||||
|
|
||||||
|
doRender() {
|
||||||
|
this.$widget = $(`<div>`);
|
||||||
|
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<any>;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ("render" in widget) {
|
||||||
|
this.$widget.append(typedWidget.render());
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e: any) {
|
||||||
|
typedWidget.logRenderingError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
|
import { TypedComponent } from "../../components/component.js";
|
||||||
import Container from "./container.js";
|
import Container from "./container.js";
|
||||||
|
|
||||||
export type FlexDirection = "row" | "column";
|
export type FlexDirection = "row" | "column";
|
||||||
|
|
||||||
export default class FlexContainer extends Container {
|
export default class FlexContainer<T extends TypedComponent<any>> extends Container<T> {
|
||||||
|
|
||||||
constructor(direction: FlexDirection) {
|
constructor(direction: FlexDirection) {
|
||||||
super();
|
super();
|
||||||
@ -13,4 +14,5 @@ export default class FlexContainer extends Container {
|
|||||||
|
|
||||||
this.attrs.style = `display: flex; flex-direction: ${direction};`;
|
this.attrs.style = `display: flex; flex-direction: ${direction};`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import appContext, { EventData } from "../../components/app_context.js";
|
|||||||
import LauncherWidget from "./launcher.js";
|
import LauncherWidget from "./launcher.js";
|
||||||
import utils from "../../services/utils.js";
|
import utils from "../../services/utils.js";
|
||||||
|
|
||||||
export default class LauncherContainer extends FlexContainer {
|
export default class LauncherContainer extends FlexContainer<LauncherWidget> {
|
||||||
private isHorizontalLayout: boolean;
|
private isHorizontalLayout: boolean;
|
||||||
|
|
||||||
constructor(isHorizontalLayout: boolean) {
|
constructor(isHorizontalLayout: boolean) {
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import FlexContainer from "./flex_container.js";
|
import FlexContainer from "./flex_container.js";
|
||||||
import splitService from "../../services/resizer.js";
|
import splitService from "../../services/resizer.js";
|
||||||
|
import RightPanelWidget from "../right_panel_widget.js";
|
||||||
|
|
||||||
|
export default class RightPaneContainer extends FlexContainer<RightPanelWidget> {
|
||||||
|
|
||||||
|
private rightPaneHidden: boolean;
|
||||||
|
|
||||||
export default class RightPaneContainer extends FlexContainer {
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super('column');
|
super('column');
|
||||||
|
|
||||||
@ -19,7 +23,7 @@ export default class RightPaneContainer extends FlexContainer {
|
|||||||
&& !!this.children.find(ch => ch.isEnabled() && ch.canBeShown());
|
&& !!this.children.find(ch => ch.isEnabled() && ch.canBeShown());
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEventInChildren(name, data) {
|
handleEventInChildren(name: string, data: unknown) {
|
||||||
const promise = super.handleEventInChildren(name, data);
|
const promise = super.handleEventInChildren(name, data);
|
||||||
|
|
||||||
if (['activeContextChanged', 'noteSwitchedAndActivated', 'noteSwitched'].includes(name)) {
|
if (['activeContextChanged', 'noteSwitchedAndActivated', 'noteSwitched'].includes(name)) {
|
@ -1,5 +1,6 @@
|
|||||||
import { EventData } from "../../components/app_context.js";
|
import { EventData } from "../../components/app_context.js";
|
||||||
import { Screen } from "../../components/mobile_screen_switcher.js";
|
import { Screen } from "../../components/mobile_screen_switcher.js";
|
||||||
|
import BasicWidget from "../basic_widget.js";
|
||||||
import FlexContainer, { FlexDirection } from "../containers/flex_container.js";
|
import FlexContainer, { FlexDirection } from "../containers/flex_container.js";
|
||||||
|
|
||||||
const DRAG_STATE_NONE = 0;
|
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. */
|
/** 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;
|
const DRAG_OPENED_START_THRESHOLD = 80;
|
||||||
|
|
||||||
export default class SidebarContainer extends FlexContainer {
|
export default class SidebarContainer extends FlexContainer<BasicWidget> {
|
||||||
|
|
||||||
private screenName: Screen;
|
private screenName: Screen;
|
||||||
/** The screen name that is currently active, according to the screen changed event. */
|
/** The screen name that is currently active, according to the screen changed event. */
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
import BasicWidget from "./basic_widget.js";
|
||||||
import NoteContextAwareWidget from "./note_context_aware_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 = `
|
const WIDGET_TPL = `
|
||||||
<div class="card widget">
|
<div class="card widget">
|
||||||
@ -19,6 +18,12 @@ const WIDGET_TPL = `
|
|||||||
* @extends {NoteContextAwareWidget}
|
* @extends {NoteContextAwareWidget}
|
||||||
*/
|
*/
|
||||||
class RightPanelWidget extends NoteContextAwareWidget {
|
class RightPanelWidget extends NoteContextAwareWidget {
|
||||||
|
|
||||||
|
private $bodyWrapper!: JQuery<HTMLElement>;
|
||||||
|
$body!: JQuery<HTMLElement>;
|
||||||
|
private $title!: JQuery<HTMLElement>;
|
||||||
|
private $buttons!: JQuery<HTMLElement>;
|
||||||
|
|
||||||
/** Title to show in the panel. */
|
/** Title to show in the panel. */
|
||||||
get widgetTitle() { return "Untitled widget"; }
|
get widgetTitle() { return "Untitled widget"; }
|
||||||
|
|
||||||
@ -53,7 +58,7 @@ class RightPanelWidget extends NoteContextAwareWidget {
|
|||||||
this.$buttons.empty();
|
this.$buttons.empty();
|
||||||
|
|
||||||
for (const buttonWidget of this.children) {
|
for (const buttonWidget of this.children) {
|
||||||
this.$buttons.append(buttonWidget.render());
|
this.$buttons.append((buttonWidget as BasicWidget).render());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initialized = this.doRenderBody().catch(e => {
|
this.initialized = this.doRenderBody().catch(e => {
|
Loading…
x
Reference in New Issue
Block a user