Add more main view implementations
This commit is contained in:
parent
1afa39bc04
commit
860398a340
54
src/main.ts
54
src/main.ts
@ -1,13 +1,47 @@
|
||||
import { Lexer } from './parser/Lexer'
|
||||
import { BinaryExpression } from './parser/ast/BinaryExpression'
|
||||
import { Expression } from './parser/ast/Expression'
|
||||
import { Operator } from './parser/ast/Operator'
|
||||
import { ValueExpression } from './parser/ast/ValueExpression'
|
||||
import { Parser } from './parser/Parser'
|
||||
import { MainView } from './view/MainView'
|
||||
|
||||
let expr1: Expression = new ValueExpression(10)
|
||||
let expr2: Expression = new ValueExpression(20)
|
||||
let exprAdd: Expression = new BinaryExpression(Operator.ADD, expr1, expr2)
|
||||
console.log(exprAdd.eval());
|
||||
function run(data: string): void {
|
||||
const tokens = new Lexer(data).process().getTokens();
|
||||
const parser = new Parser(tokens);
|
||||
const view = new MainView(parser, false);
|
||||
parser.setView(view);
|
||||
view.init();
|
||||
parser.next();
|
||||
}
|
||||
|
||||
const tokens = new Lexer("10 / 2").process().getTokens();
|
||||
console.log(tokens)
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
run(`scene bg black
|
||||
"Основные теги:\n{b}жирный{/b} {i}курсив{/i} {u}подчёркнутый{/u}"
|
||||
"{big}большой{/big} нормальный {small}маленький{/small}"
|
||||
"{center}текст по центру"
|
||||
sl "{center}текст по центру"
|
||||
"{html}{center}<h1>HTML</h1>"
|
||||
"{html}<big>Большой big</big>"
|
||||
"{html}<small>Маленький small</small>"
|
||||
"{html}<b>Жирный bold</b> <strong>strong</strong>"
|
||||
"{html}<i>Курсив i</i> <em>em</em> <cite>cite</cite> <dfn>dfn</dfn>"
|
||||
"{html}<u>Подчёркнутый</u>"
|
||||
"{html}<blockquote><p>Длинная цитата</p>blockquote</blockquote>"
|
||||
"{html}<br/><br/>Переносы<br/><br/>строк<br/><br/><br/><br/>br<br/>"
|
||||
"{html}<tt>Моноширинный tt</tt>"
|
||||
"{html}<sub>Подстрочный sub</sub> Нормальный <sup>Надстрочный sup</sup>"
|
||||
'{html}<a href="http://rpy.annimon.com/">Ссылка a href</a>'
|
||||
"{html}<h1>Заголовок h1</h1>
|
||||
<h2>Заголовок h2</h2>
|
||||
<h3>Заголовок h3</h3>
|
||||
<h4>Заголовок h4</h4>
|
||||
<h5>Заголовок h5</h5>
|
||||
<h6>Заголовок h6</h6>"
|
||||
'{html}<font color="red">font color="red"</font>
|
||||
<font color="purple">font color="purple"</font>
|
||||
<font color="#336699">font color="#336699"</font>
|
||||
<font color="#ffffff">font color="#ffffff"</font>'
|
||||
'{html}<font face="serif">font face="serif"</font>
|
||||
<font face="sans-serif">font face="sans-serif"</font>
|
||||
<font face="monospace">font face="monospace"</font>'
|
||||
'{html}<font face="monospace" color="#7f7f7f">font face="monospace" color="#7f7f7f"</font>'
|
||||
"{html}<p>Параграф</p><p>p</p>"
|
||||
"{html}<div>Блок div</div>"`)
|
||||
});
|
@ -34,10 +34,7 @@ export class Parser implements Navigable {
|
||||
/** Optimization, if there no endmenu/endif => don't search them */
|
||||
this.hasEndMenu = false;
|
||||
this.hasEndIf = false;
|
||||
}
|
||||
|
||||
public getInstance(): Parser {
|
||||
return this;
|
||||
this.preScan();
|
||||
}
|
||||
|
||||
public setView(view: ViewModel): void {
|
||||
|
@ -1,7 +1,19 @@
|
||||
export class TextUtils {
|
||||
public static isEmpty(str: string|null) {
|
||||
public static isEmpty(str: string|null): boolean {
|
||||
if (typeof str === 'undefined') return true;
|
||||
if (str === undefined) return true;
|
||||
return str.length === 0;
|
||||
}
|
||||
|
||||
public static equalsIgnoreCase(str: string, text: string): boolean {
|
||||
return str.toLowerCase() == text.toLowerCase();
|
||||
}
|
||||
|
||||
public static contains(str: string, text: string): boolean {
|
||||
return str.indexOf(text) >= 0;
|
||||
}
|
||||
|
||||
public static replaceAll(str: string, find: string, replace: string): string {
|
||||
return str.replace(new RegExp(find, 'g'), replace);
|
||||
}
|
||||
}
|
311
src/view/MainView.ts
Normal file
311
src/view/MainView.ts
Normal file
@ -0,0 +1,311 @@
|
||||
import { TextUtils } from "../utils/TextUtils";
|
||||
import { Characters } from "./model/Characters";
|
||||
import { FadeInfo } from "./model/FadeInfo";
|
||||
import { Menu } from "./model/Menu";
|
||||
import { Navigable } from "./model/Navigable";
|
||||
import { Transition } from "./model/Transition";
|
||||
import { TransitionType } from "./model/TransitionType";
|
||||
import { ViewModel } from "./model/ViewModel";
|
||||
|
||||
export class MainView implements ViewModel {
|
||||
private static readonly NO_FADE = new FadeInfo();
|
||||
|
||||
private windowTag: HTMLElement;
|
||||
private textAuthorTag: HTMLElement;
|
||||
private textContentTag: HTMLElement;
|
||||
|
||||
private musicPlayerAudio: HTMLAudioElement;
|
||||
private soundPlayerAudio: HTMLAudioElement;
|
||||
private soundLoopPlayerAudio: HTMLAudioElement;
|
||||
private ambiencePlayerAudio: HTMLAudioElement;
|
||||
private musicQueue: Array<string>;
|
||||
private soundQueue: Array<string>;
|
||||
|
||||
private backgroundName: string;
|
||||
private backgroundType: string;
|
||||
private characters: Characters;
|
||||
|
||||
private useSpriteTransitions: boolean;
|
||||
private spriteInContainer: {};
|
||||
|
||||
private blockTap: boolean;
|
||||
private cancelNextStep: boolean;
|
||||
private nextCommandRunnable: () => void;
|
||||
|
||||
constructor(private navigable: Navigable, private debug: boolean = false) {
|
||||
this.windowTag = document.getElementById('window');
|
||||
this.textAuthorTag = document.getElementById('textAuthor');
|
||||
this.textContentTag = document.getElementById('textContent');
|
||||
|
||||
this.musicPlayerAudio = new Audio();
|
||||
this.soundPlayerAudio = new Audio();
|
||||
this.soundLoopPlayerAudio = new Audio();
|
||||
this.ambiencePlayerAudio = new Audio();
|
||||
this.musicQueue = new Array();
|
||||
this.soundQueue = new Array();
|
||||
|
||||
this.backgroundName = "";
|
||||
this.backgroundType = "";
|
||||
this.characters = new Characters();
|
||||
this.characters.makeNamesUnknown();
|
||||
this.characters.makeNamesKnown();
|
||||
|
||||
// this.places = new MapPlaces(); // TODO
|
||||
|
||||
this.useSpriteTransitions = true;
|
||||
this.spriteInContainer = {};
|
||||
|
||||
this.blockTap = false;
|
||||
this.cancelNextStep = false;
|
||||
this.nextCommandRunnable = () => {
|
||||
this.blockTap = false;
|
||||
if (!this.cancelNextStep) navigable.next();
|
||||
};
|
||||
}
|
||||
|
||||
public init(): void {
|
||||
document.getElementById('menu').style.display = 'none';
|
||||
document.getElementById('mainMenuButton').onclick = (e) => this.showMainMenu();
|
||||
document.getElementById('background').onclick = (e) => this.onTouch(e);
|
||||
}
|
||||
|
||||
private onTouch(e: MouseEvent): void {
|
||||
if (this.blockTap) return;
|
||||
if (document.getElementById('menu').style.display !== 'none') return;
|
||||
if ((e.target as HTMLElement).tagName.toLowerCase() === 'li') return;
|
||||
if ((e.target as HTMLElement).id === 'mainMenuButton') return;
|
||||
|
||||
this.cancelNextStep = true;
|
||||
this.navigable.next();
|
||||
}
|
||||
|
||||
private showMainMenu(): void {
|
||||
}
|
||||
|
||||
public text(text: string): void {
|
||||
this.textAuthorTag.innerText = '';
|
||||
if (TextUtils.isEmpty(text)) this.windowHide("");
|
||||
else {
|
||||
this.windowShow("");
|
||||
this.formatString(this.textContentTag, text);
|
||||
}
|
||||
}
|
||||
|
||||
public textW(whoid: string, text: string): void {
|
||||
if (TextUtils.equalsIgnoreCase(whoid, 'th')) this.text("~ " + text + " ~");
|
||||
else if (!this.characters.contains(whoid)) this.text(text);
|
||||
else {
|
||||
this.windowShow("");
|
||||
const person = this.characters.get(whoid);
|
||||
this.textAuthorTag.textContent = person.name;
|
||||
this.textAuthorTag.style.color = this.toColor(person.color);
|
||||
this.formatString(this.textContentTag, text);
|
||||
}
|
||||
}
|
||||
|
||||
private formatString(tag: HTMLElement, text: string) {
|
||||
let edited = TextUtils.replaceAll(text, "\\{w.*?\\}", "");
|
||||
if (TextUtils.contains(edited, "{center}")) {
|
||||
edited = TextUtils.replaceAll(edited, "\\{center\\}", "");
|
||||
this.textContentTag.style.textAlign = "center";
|
||||
} else {
|
||||
this.textContentTag.style.textAlign = "left";
|
||||
}
|
||||
if (TextUtils.contains(edited, "{html}")) {
|
||||
edited = TextUtils.replaceAll(edited, "\\{html\\}", "");
|
||||
tag.innerHTML = edited;
|
||||
return;
|
||||
}
|
||||
const codes = ["b", "i", "s", "u", "big", "small"];
|
||||
let html = false;
|
||||
for (let i = 0; i < codes.length; i++) {
|
||||
const ch = codes[i];
|
||||
if (TextUtils.contains(edited, "{" + ch + "}")) {
|
||||
edited = TextUtils.replaceAll(edited, "{" + ch + "}", "<" + ch + ">");
|
||||
edited = TextUtils.replaceAll(edited, "{/" + ch + "}", "</" + ch + ">");
|
||||
html = true;
|
||||
}
|
||||
}
|
||||
if (html) {
|
||||
edited = edited.replace("\n", "<br/>");
|
||||
tag.innerHTML = edited;
|
||||
} else {
|
||||
tag.textContent = edited;
|
||||
// TODO
|
||||
// const tmp = $(tag).text(edited);
|
||||
// tmp.html(tmp.html().replace(/\n/g, '<br/>'));
|
||||
}
|
||||
}
|
||||
|
||||
public background(type: string, name: string, effect: string): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public sprite(whoid: string, params: string, position: string, alias: string, effect: string): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public hideSprite(whoid: string, effect: string): void {
|
||||
if (!(whoid in this.spriteInContainer)) return;
|
||||
this.hide(whoid, effect);
|
||||
}
|
||||
|
||||
private hide(whoid: string, effect: string): void {
|
||||
const img = this.spriteInContainer[whoid];
|
||||
if (img == null) return;
|
||||
if (effect in Transition.DEFAULT) {
|
||||
const transition = Transition.DEFAULT[effect];
|
||||
if (transition["type"] === TransitionType.TYPE_FADE) {
|
||||
// TODO
|
||||
//img.fadeOut(transition["outTime"], function () {
|
||||
// $(this).remove();
|
||||
//});
|
||||
img.remove();
|
||||
} else {
|
||||
img.remove();
|
||||
}
|
||||
} else {
|
||||
img.remove();
|
||||
}
|
||||
delete this.spriteInContainer[whoid];
|
||||
}
|
||||
|
||||
private spritesClear() : void {
|
||||
document.getElementById('container').innerHTML = '';
|
||||
this.spriteInContainer = {};
|
||||
}
|
||||
|
||||
public menu(menu: Menu): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public showMap(): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public setZone(zone: string, label: string): void {
|
||||
// this.places.setZone(name, label);
|
||||
}
|
||||
|
||||
public resetZone(zone: string): void {
|
||||
// this.places.resetZone(zone);
|
||||
}
|
||||
|
||||
public disableCurrentZone(): void {
|
||||
// this.places.disableCurrentZone();
|
||||
}
|
||||
|
||||
public disableAllZones(): void {
|
||||
// this.places.disableAllZones();
|
||||
}
|
||||
|
||||
public makeNamesKnown(): void {
|
||||
this.characters.makeNamesKnown();
|
||||
}
|
||||
|
||||
public makeNamesUnknown(): void {
|
||||
this.characters.makeNamesUnknown();
|
||||
}
|
||||
|
||||
public meet(whoid: string, name: string): void {
|
||||
this.characters.setName(whoid, name);
|
||||
}
|
||||
|
||||
public music(name: string, fade: FadeInfo): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public ambience(name: string, fade: FadeInfo): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public sound(name: string, fade: FadeInfo): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public soundLoop(name: string, fade: FadeInfo): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public addSoundToQueue(name: string): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public addMusicToQueue(name: string): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public stopAmbience(fade: FadeInfo): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public stopSoundLoop(fade: FadeInfo): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public stopSound(fade: FadeInfo): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public stopMusic(fade: FadeInfo): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
public windowShow(effect: string): boolean {
|
||||
if (this.windowTag.style.visibility !== "visible") {
|
||||
this.windowTag.style.visibility = "visible";
|
||||
}
|
||||
if (!TextUtils.isEmpty(effect)) {
|
||||
this.background(this.backgroundType, this.backgroundName, effect);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public windowHide(effect: string): boolean {
|
||||
if (this.windowTag.style.visibility !== "hidden") {
|
||||
this.windowTag.style.visibility = "hidden";
|
||||
}
|
||||
if (!TextUtils.isEmpty(effect)) {
|
||||
this.background(this.backgroundType, this.backgroundName, effect);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private windowSwitchVisibility(): void {
|
||||
if (this.windowTag.style.visibility === "hidden") {
|
||||
this.windowTag.style.visibility = "visible";
|
||||
} else {
|
||||
this.windowTag.style.visibility = "hidden";
|
||||
}
|
||||
}
|
||||
|
||||
public pause(duration: number, isHard: boolean): void {
|
||||
this.blockTap = isHard;
|
||||
this.cancelNextStep = false;
|
||||
setTimeout(this.nextCommandRunnable, duration);
|
||||
}
|
||||
|
||||
public finish(): void {
|
||||
if (this.debug) {
|
||||
this.stopMusic(MainView.NO_FADE);
|
||||
this.stopSound(MainView.NO_FADE);
|
||||
this.stopSoundLoop(MainView.NO_FADE);
|
||||
this.stopAmbience(MainView.NO_FADE);
|
||||
this.spritesClear();
|
||||
this.text('{center}{html}<span style="color: white">Сценарий завершён</span>');
|
||||
} else {
|
||||
this.text('{center}{html}<a style="color: white" href="/">Вернуться на главную</a>');
|
||||
}
|
||||
}
|
||||
|
||||
private toColor(num: number): string {
|
||||
num >>>= 0;
|
||||
const b = num & 0xFF,
|
||||
g = (num & 0xFF00) >>> 8,
|
||||
r = (num & 0xFF0000) >>> 16,
|
||||
a = ( (num & 0xFF000000) >>> 24 ) / 255 ;
|
||||
return "rgba(" + [r, g, b, a].join(",") + ")";
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@ import { Menu } from "./Menu"
|
||||
export interface ViewModel {
|
||||
text(text: string): void
|
||||
textW(whoid: string, text: string): void
|
||||
meet(whoid: string, name: string): void
|
||||
background(type: string, name: string, effect: string): void
|
||||
sprite(whoid: string, params: string, position: string, alias: string, effect: string): void
|
||||
hideSprite(whoid: string, effect: string): void
|
||||
@ -12,12 +11,13 @@ export interface ViewModel {
|
||||
menu(menu: Menu): void
|
||||
showMap(): void
|
||||
setZone(zone: string, label: string): void
|
||||
resetZone(zone: string): void
|
||||
disableCurrentZone(): void
|
||||
disableAllZones(): void
|
||||
resetZone(zone: string): void
|
||||
|
||||
makeNamesUnknown(): void
|
||||
meet(whoid: string, name: string): void
|
||||
makeNamesKnown(): void
|
||||
makeNamesUnknown(): void
|
||||
|
||||
music(name: string, fade: FadeInfo): void
|
||||
ambience(name: string, fade: FadeInfo): void
|
||||
|
Loading…
Reference in New Issue
Block a user