Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

port js to ts #1270

Merged
merged 3 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 0 additions & 56 deletions src/public/app/widgets/bookmark_buttons.js

This file was deleted.

78 changes: 78 additions & 0 deletions src/public/app/widgets/bookmark_buttons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import FlexContainer from "./containers/flex_container.js";
import OpenNoteButtonWidget from "./buttons/open_note_button_widget.js";
import BookmarkFolderWidget from "./buttons/bookmark_folder.js";
import froca from "../services/froca.js";
import utils from "../services/utils.js";
import type { EventData } from "../components/app_context.js";
import type Component from "../components/component.js";

interface BookmarkButtonsSettings {
titlePlacement?: string;
}

export default class BookmarkButtons extends FlexContainer<Component> {
private settings: BookmarkButtonsSettings;
private noteIds: string[];

constructor(isHorizontalLayout: boolean) {
super(isHorizontalLayout ? "row" : "column");

this.contentSized();
this.settings = {};
this.noteIds = [];
}

async refresh(): Promise<void> {
this.$widget.empty();
this.children = [];
this.noteIds = [];

const bookmarkParentNote = await froca.getNote("_lbBookmarks");

if (!bookmarkParentNote) {
return;
}

for (const note of await bookmarkParentNote.getChildNotes()) {
this.noteIds.push(note.noteId);

let buttonWidget: OpenNoteButtonWidget | BookmarkFolderWidget = note.isLabelTruthy("bookmarkFolder")
? new BookmarkFolderWidget(note)
: new OpenNoteButtonWidget(note).class("launcher-button");

if (this.settings.titlePlacement) {
if (!('settings' in buttonWidget)) {
(buttonWidget as any).settings = {};
}

(buttonWidget as any).settings.titlePlacement = this.settings.titlePlacement;
}

this.child(buttonWidget);

this.$widget.append(buttonWidget.render());

buttonWidget.refreshIcon();
}

utils.reloadTray();
}

initialRenderCompleteEvent(): void {
this.refresh();
}

entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">): void {
if (loadResults.getBranchRows().find((branch) => branch.parentNoteId === "_lbBookmarks")) {
this.refresh();
}

if (loadResults.getAttributeRows().find((attr) =>
attr.type === "label" &&
attr.name && ["iconClass", "workspaceIconClass", "bookmarkFolder"].includes(attr.name) &&
attr.noteId && this.noteIds.includes(attr.noteId)
)) {
this.refresh();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import RightDropdownButtonWidget from "./right_dropdown_button.js";
import linkService from "../../services/link.js";
import utils from "../../services/utils.js";
import type FNote from "../../entities/fnote.js";

const DROPDOWN_TPL = `
<div class="bookmark-folder-widget">
Expand Down Expand Up @@ -43,25 +44,35 @@ const DROPDOWN_TPL = `
<ul class="children-notes"></ul>
</div>`;

interface LinkOptions {
showTooltip: boolean;
showNoteIcon: boolean;
}

export default class BookmarkFolderWidget extends RightDropdownButtonWidget {
constructor(note) {
private note: FNote;
private $parentNote!: JQuery<HTMLElement>;
private $childrenNotes!: JQuery<HTMLElement>;
declare $dropdownContent: JQuery<HTMLElement>;

constructor(note: FNote) {
super(utils.escapeHtml(note.title), note.getIcon(), DROPDOWN_TPL);

this.note = note;
}

doRender() {
doRender(): void {
super.doRender();

this.$parentNote = this.$dropdownContent.find(".parent-note");
this.$childrenNotes = this.$dropdownContent.find(".children-notes");
}

async dropdownShown() {
async dropdownShown(): Promise<void> {
this.$parentNote.empty();
this.$childrenNotes.empty();

const linkOptions = {
const linkOptions: LinkOptions = {
showTooltip: false,
showNoteIcon: true
};
Expand All @@ -73,5 +84,5 @@ export default class BookmarkFolderWidget extends RightDropdownButtonWidget {
}
}

refreshIcon() {}
refreshIcon(): void {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import appContext from "../../components/app_context.js";
import attributeService from "../../services/attributes.js";
import protectedSessionHolder from "../../services/protected_session_holder.js";
import { t } from "../../services/i18n.js";
import LoadResults from "../../services/load_results.js";
import type { AttributeRow } from "../../services/load_results.js";
import FNote from "../../entities/fnote.js";

export default class EditButton extends OnClickButtonWidget {
isEnabled() {
return super.isEnabled() && this.note && this.noteContext.viewScope.viewMode === "default";
isEnabled(): boolean {
return Boolean(super.isEnabled() && this.note && this.noteContext?.viewScope?.viewMode === "default");
}

constructor() {
Expand All @@ -16,15 +19,15 @@ export default class EditButton extends OnClickButtonWidget {
.title(t("edit_button.edit_this_note"))
.titlePlacement("bottom")
.onClick((widget) => {
this.noteContext.viewScope.readOnlyTemporarilyDisabled = true;

appContext.triggerEvent("readOnlyTemporarilyDisabled", { noteContext: this.noteContext });

if (this.noteContext?.viewScope) {
this.noteContext.viewScope.readOnlyTemporarilyDisabled = true;
appContext.triggerEvent("readOnlyTemporarilyDisabled", { noteContext: this.noteContext });
}
this.refresh();
});
}

async refreshWithNote(note) {
async refreshWithNote(note: FNote): Promise<void> {
if (note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) {
this.toggleInt(false);
} else {
Expand All @@ -34,31 +37,38 @@ export default class EditButton extends OnClickButtonWidget {
const wasVisible = this.isVisible();

// can't do this in isEnabled() since isReadOnly is async
this.toggleInt(await this.noteContext.isReadOnly());
const isReadOnly = await this.noteContext?.isReadOnly();
this.toggleInt(Boolean(isReadOnly));

// make the edit button stand out on the first display, otherwise
// it's difficult to notice that the note is readonly
if (this.isVisible() && !wasVisible) {
if (this.isVisible() && !wasVisible && this.$widget) {
this.$widget.addClass("bx-tada bx-lg");

setTimeout(() => {
this.$widget.removeClass("bx-tada bx-lg");
this.$widget?.removeClass("bx-tada bx-lg");
}, 1700);
}
}

await super.refreshWithNote(note);
}

entitiesReloadedEvent({ loadResults }) {
if (loadResults.getAttributeRows().find((attr) => attr.type === "label" && attr.name.toLowerCase().includes("readonly") && attributeService.isAffecting(attr, this.note))) {
this.noteContext.viewScope.readOnlyTemporarilyDisabled = false;

entitiesReloadedEvent({ loadResults }: { loadResults: LoadResults }): void {
if (loadResults.getAttributeRows().find((attr: AttributeRow) =>
attr.type === "label" &&
attr.name?.toLowerCase().includes("readonly") &&
this.note &&
attributeService.isAffecting(attr, this.note)
)) {
if (this.noteContext?.viewScope) {
this.noteContext.viewScope.readOnlyTemporarilyDisabled = false;
}
this.refresh();
}
}

async noteTypeMimeChangedEvent({ noteId }) {
async noteTypeMimeChangedEvent({ noteId }: { noteId: string }): Promise<void> {
if (this.isNote(noteId)) {
await this.refresh();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
import BasicWidget from "../basic_widget.js";
import { Tooltip, Dropdown } from "bootstrap";
type PopoverPlacement = Tooltip.PopoverPlacement;

const TPL = `
<div class="dropdown right-dropdown-widget dropend">
<button type="button" data-bs-toggle="dropdown"
aria-haspopup="true" aria-expanded="false"
aria-haspopup="true" aria-expanded="false"
class="bx right-dropdown-button launcher-button"></button>

<div class="tooltip-trigger"></div>

<div class="dropdown-menu dropdown-menu-right"></div>
</div>
`;

export default class RightDropdownButtonWidget extends BasicWidget {
constructor(title, iconClass, dropdownTpl) {
protected iconClass: string;
protected title: string;
protected dropdownTpl: string;
protected settings: { titlePlacement: PopoverPlacement };
protected $dropdownMenu!: JQuery<HTMLElement>;
protected dropdown!: Dropdown;
protected $tooltip!: JQuery<HTMLElement>;
protected tooltip!: Tooltip;
public $dropdownContent!: JQuery<HTMLElement>;

constructor(title: string, iconClass: string, dropdownTpl: string) {
super();

this.iconClass = iconClass;
Expand All @@ -26,13 +37,13 @@ export default class RightDropdownButtonWidget extends BasicWidget {
};
}

doRender() {
doRender(): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's a need to explicitly declare the return type of functions here.
I personally don't mind it, but I haven't seen that being done across the TriliumNext codebase, but I'll leave it to @eliandoran to decide :-)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pano9000 , indeed generally it's not needed.
The only case when we should add is when the return type is non-obvious (i.e. there are multiple return points, each forming the data in a different way).

this.$widget = $(TPL);
this.$dropdownMenu = this.$widget.find(".dropdown-menu");
this.dropdown = Dropdown.getOrCreateInstance(this.$widget.find("[data-bs-toggle='dropdown']"));
this.dropdown = Dropdown.getOrCreateInstance(this.$widget.find("[data-bs-toggle='dropdown']")[0]);

this.$tooltip = this.$widget.find(".tooltip-trigger").attr("title", this.title);
this.tooltip = new Tooltip(this.$tooltip, {
this.tooltip = new Tooltip(this.$tooltip[0], {
placement: this.settings.titlePlacement,
fallbackPlacements: [this.settings.titlePlacement]
});
Expand All @@ -48,7 +59,8 @@ export default class RightDropdownButtonWidget extends BasicWidget {
await this.dropdownShown();

const rect = this.$dropdownMenu[0].getBoundingClientRect();
const pixelsToBottom = $(window).height() - rect.bottom;
const windowHeight = $(window).height() || 0;
const pixelsToBottom = windowHeight - rect.bottom;

if (pixelsToBottom < 0) {
this.$dropdownMenu.css("top", pixelsToBottom);
Expand All @@ -60,5 +72,5 @@ export default class RightDropdownButtonWidget extends BasicWidget {
}

// to be overridden
async dropdownShow() {}
async dropdownShown(): Promise<void> {}
}

This file was deleted.

Loading