Made Dialog reusable.

This commit is contained in:
Daan Vanden Bosch 2020-01-07 17:40:01 +01:00
parent 10d6eb68d9
commit b93b22a223
4 changed files with 62 additions and 39 deletions

View File

@ -1,4 +1,5 @@
.core_ResultPopup { .core_Dialog {
z-index: 20;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
outline: none; outline: none;
@ -9,34 +10,43 @@
box-shadow: black 0 0 10px -2px; box-shadow: black 0 0 10px -2px;
} }
.core_ResultPopup:focus-within { .core_Dialog:focus-within {
border: var(--border-focus); border: var(--border-focus);
} }
.core_ResultPopup h1 { .core_Dialog h1 {
font-size: 20px; font-size: 20px;
margin: 0 0 10px 0; margin: 0 0 10px 0;
padding-bottom: 4px; padding-bottom: 4px;
border-bottom: var(--border); border-bottom: var(--border);
} }
.core_ResultPopup_description { .core_Dialog_description {
user-select: text; user-select: text;
cursor: text; cursor: text;
} }
.core_ResultPopup_body { .core_Dialog_body {
user-select: text; user-select: text;
overflow: auto; overflow: auto;
margin: 4px 0; margin: 4px 0;
} }
.core_ResultPopup_body ul { .core_Dialog_footer {
cursor: text;
}
.core_ResultPopup_footer {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: flex-end; justify-content: flex-end;
} }
.core_Dialog_modal_overlay {
outline: none;
z-index: 10;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: black;
opacity: 50%;
backdrop-filter: blur(5px);
}

View File

@ -1,55 +1,62 @@
import { ResizableWidget } from "./ResizableWidget"; import { ResizableWidget } from "./ResizableWidget";
import { Widget } from "./Widget"; import { Widget } from "./Widget";
import { div, h1, li, section, ul } from "./dom"; import { div, h1, li, section, ul } from "./dom";
import { Problem, Result } from "../Result"; import { Result } from "../Result";
import { Button } from "./Button"; import { Button } from "./Button";
import "./ResultPopup.css"; import "./Dialog.css";
const POPUP_WIDTH = 500; const DIALOG_WIDTH = 500;
const POPUP_HEIGHT = 500; const DIALOG_MAX_HEIGHT = 500;
export class ResultPopup extends ResizableWidget { export class Dialog extends ResizableWidget {
private x = 0; private x = 0;
private y = 0; private y = 0;
private prev_mouse_x = 0; private prev_mouse_x = 0;
private prev_mouse_y = 0; private prev_mouse_y = 0;
private readonly overlay_element: HTMLElement;
readonly element: HTMLElement; readonly element: HTMLElement;
readonly children: readonly Widget[] = []; readonly children: readonly Widget[] = [];
readonly dismiss_button = this.disposable(new Button({ text: "Dismiss" })); readonly dismiss_button = this.disposable(new Button({ text: "Dismiss" }));
constructor(title: string, description: string, problems: readonly Problem[] = []) { constructor(title: string, description: string, content: Node | string) {
super(); super();
let header_element: HTMLElement; let header_element: HTMLElement;
this.element = section( this.element = section(
{ className: "core_ResultPopup", tabIndex: 0 }, { className: "core_Dialog", tabIndex: 0 },
(header_element = h1(title)), (header_element = h1(title)),
div({ className: "core_ResultPopup_description" }, description), div({ className: "core_Dialog_description" }, description),
div( div({ className: "core_Dialog_body" }, content),
{ className: "core_ResultPopup_body" }, div({ className: "core_Dialog_footer" }, this.dismiss_button.element),
ul(...problems.map(problem => li(problem.ui_message))),
),
div({ className: "core_ResultPopup_footer" }, this.dismiss_button.element),
); );
this.element.style.width = `${POPUP_WIDTH}px`; this.element.style.width = `${DIALOG_WIDTH}px`;
this.element.style.maxHeight = `${POPUP_HEIGHT}px`; this.element.style.maxHeight = `${DIALOG_MAX_HEIGHT}px`;
this.set_position( this.set_position(
(window.innerWidth - POPUP_WIDTH) / 2, (window.innerWidth - DIALOG_WIDTH) / 2,
(window.innerHeight - POPUP_HEIGHT) / 2, (window.innerHeight - DIALOG_MAX_HEIGHT) / 2,
); );
this.element.addEventListener("keydown", this.keydown); this.element.addEventListener("keydown", this.keydown);
header_element.addEventListener("mousedown", this.mousedown); header_element.addEventListener("mousedown", this.mousedown);
this.overlay_element = div({ className: "core_Dialog_modal_overlay", tabIndex: -1 });
this.overlay_element.addEventListener("focus", () => this.element.focus());
document.body.append(this.overlay_element);
this.disposables(this.dismiss_button.onclick.observe(() => this.dispose())); this.disposables(this.dismiss_button.onclick.observe(() => this.dispose()));
this.finalize_construction(); this.finalize_construction();
} }
dispose(): void {
super.dispose();
this.overlay_element.remove();
}
set_position(x: number, y: number): void { set_position(x: number, y: number): void {
this.x = x; this.x = x;
this.y = y; this.y = y;
@ -87,27 +94,33 @@ export class ResultPopup extends ResizableWidget {
} }
/** /**
* Shows a popup if `result` failed or succeeded with problems. * Shows a dialog window if `result` failed or succeeded with problems.
* *
* @param result * @param result
* @param problems_message - Message to show if problems occurred when result is successful. * @param problems_message - Message to show if problems occurred when result is successful.
* @param error_message - Message to show if result failed. * @param error_message - Message to show if result failed.
*/ */
export function show_result_popup( export function show_result_dialog(
result: Result<unknown>, result: Result<unknown>,
problems_message: string, problems_message: string,
error_message: string, error_message: string,
): void { ): void {
let popup: ResultPopup | undefined; let dialog: Dialog | undefined;
if (!result.success) { if (!result.success) {
popup = new ResultPopup("Error", error_message, result.problems); dialog = new Dialog("Error", error_message, create_result_body(result));
} else if (result.problems.length) { } else if (result.problems.length) {
popup = new ResultPopup("Problems", problems_message, result.problems); dialog = new Dialog("Problems", problems_message, create_result_body(result));
} }
if (popup) { if (dialog) {
document.body.append(popup.element); document.body.append(dialog.element);
popup.focus(); dialog.focus();
} }
} }
function create_result_body(result: Result<unknown>): HTMLElement {
const body = ul(...result.problems.map(problem => li(problem.ui_message)));
body.style.cursor = "text";
return body;
}

View File

@ -11,8 +11,8 @@ import { list_property } from "../../core/observable";
import { ListProperty } from "../../core/observable/property/list/ListProperty"; import { ListProperty } from "../../core/observable/property/list/ListProperty";
import { prs_decompress } from "../../core/data_formats/compression/prs/decompress"; import { prs_decompress } from "../../core/data_formats/compression/prs/decompress";
import { failure, Result, result_builder } from "../../core/Result"; import { failure, Result, result_builder } from "../../core/Result";
import { show_result_popup } from "../../core/gui/ResultPopup";
import { Severity } from "../../core/Severity"; import { Severity } from "../../core/Severity";
import { show_result_dialog } from "../../core/gui/Dialog";
const logger = LogManager.get("viewer/controllers/TextureController"); const logger = LogManager.get("viewer/controllers/TextureController");
@ -75,7 +75,7 @@ export class TextureController extends Controller {
result = failure(); result = failure();
} }
show_result_popup( show_result_dialog(
result, result,
`Encountered some problems while opening "${file.name}".`, `Encountered some problems while opening "${file.name}".`,
`Couldn't open "${file.name}".`, `Couldn't open "${file.name}".`,

View File

@ -11,8 +11,8 @@ import { parse_afs } from "../../../core/data_formats/parsing/afs";
import { LogManager } from "../../../core/Logger"; import { LogManager } from "../../../core/Logger";
import { prs_decompress } from "../../../core/data_formats/compression/prs/decompress"; import { prs_decompress } from "../../../core/data_formats/compression/prs/decompress";
import { failure, Result, result_builder, success } from "../../../core/Result"; import { failure, Result, result_builder, success } from "../../../core/Result";
import { show_result_popup } from "../../../core/gui/ResultPopup";
import { Severity } from "../../../core/Severity"; import { Severity } from "../../../core/Severity";
import { show_result_dialog } from "../../../core/gui/Dialog";
const logger = LogManager.get("viewer/controllers/model/ModelToolBarController"); const logger = LogManager.get("viewer/controllers/model/ModelToolBarController");
@ -136,7 +136,7 @@ export class ModelToolBarController extends Controller {
result = failure(); result = failure();
} }
show_result_popup( show_result_dialog(
result, result,
`Encountered some problems while opening "${file.name}".`, `Encountered some problems while opening "${file.name}".`,
`Couldn't open "${file.name}".`, `Couldn't open "${file.name}".`,