Update framework

This commit is contained in:
2022-11-26 02:22:02 +01:00
parent 9a6ce1f832
commit ae057940af
508 changed files with 26011 additions and 14248 deletions

1
framework/ui/index.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
export * from './menu/index';

2
framework/ui/index.js Normal file
View File

@@ -0,0 +1,2 @@
export * from './menu/index';
// export * as Text from './text';

39
framework/ui/menu/index.d.ts vendored Normal file
View File

@@ -0,0 +1,39 @@
import { BaseItem } from './items/base-item';
import { SoundSet } from './interfaces/sound-set';
import * as EventEmitter from 'eventemitter3';
export declare class Menu extends EventEmitter {
private title;
private menuItems;
private soundSet;
private defaultAction;
private cancelAction;
private titleContainer;
private currentItem;
private currentIndex;
private container;
private element;
private DOMNodes;
private soundManager;
private keyboardManager;
constructor(title?: string, menuItems?: BaseItem[], soundSet?: SoundSet, defaultAction?: string, cancelAction?: string);
private init;
addItem(item: BaseItem): this;
setTitle(title: string): this;
setSoundSet(soundSet: SoundSet): this;
setDefaultAction(id: string): this;
setCancelAction(id: string): this;
run(element: HTMLElement): Promise<any>;
close(): void;
private appendToContainer;
private handleItemUpdate;
private onItemFocus;
focusNext(): void;
focusPrevious(): void;
private focusCurrentIndex;
getCurrentFocus(): BaseItem;
getContainer(): HTMLElement;
clickDefaultAction(): void;
clickCancelAction(): void;
private compile;
}
export * from './items';

145
framework/ui/menu/index.js Normal file
View File

@@ -0,0 +1,145 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import * as EventEmitter from 'eventemitter3';
import { SoundManager } from './sound-manager';
import { KeyboardManager } from './keyboard-manager';
export class Menu extends EventEmitter {
constructor(title = 'Menu', menuItems = [], soundSet = null, defaultAction = null, cancelAction = null) {
super();
this.title = title;
this.menuItems = menuItems;
this.soundSet = soundSet;
this.defaultAction = defaultAction;
this.cancelAction = cancelAction;
this.currentIndex = 0;
this.DOMNodes = [];
this.currentIndex = 0;
this.currentItem = null;
this.soundManager = new SoundManager(soundSet);
this.keyboardManager = new KeyboardManager(this);
this.init();
}
init() {
this.menuItems[this.currentIndex] &&
this.menuItems[this.currentIndex].focus();
this.emit('init');
}
addItem(item) {
this.menuItems.push(item);
this.emit('item.add', item);
return this;
}
setTitle(title) {
this.title = title;
return this;
}
setSoundSet(soundSet) {
this.soundSet = soundSet;
this.soundManager.setSoundSet(this.soundSet);
return this;
}
setDefaultAction(id) {
this.defaultAction = id;
return this;
}
setCancelAction(id) {
this.cancelAction = id;
return this;
}
run(element) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
this.element = element;
this.container = document.createElement('div');
this.titleContainer = document.createElement('h1');
this.titleContainer.textContent = this.title;
this.container.appendChild(this.titleContainer);
this.menuItems.forEach((item) => {
this.appendToContainer(item.getDOMNode());
item.on('update', this.handleItemUpdate.bind(this));
item.on('focus', this.onItemFocus.bind(this));
item.on('choose', (event) => {
const menuMap = this.compile();
this.soundManager.handleSound('choose');
this.emit('choose', menuMap);
resolve(menuMap);
});
});
element.appendChild(this.container);
this.soundManager.handleSound('open');
this.keyboardManager.init();
// push some data onto the history stack so that we can use the browser's back button to exit out of the menu.
history.pushState({ menu: true }, null, null);
});
});
}
close() {
this.container.remove();
this.soundManager.handleSound('close');
this.keyboardManager.release();
this.DOMNodes.forEach((item) => {
this.container.removeChild(item);
});
this.emit('close');
}
appendToContainer(node) {
this.container.appendChild(node);
this.DOMNodes.push(node);
}
handleItemUpdate(value) {
this.soundManager.handleSound(value.type, value.value);
this.emit('update', this.compile());
}
onItemFocus(id) {
this.soundManager.handleSound('focus');
this.currentIndex = this.menuItems.indexOf(this.menuItems.find((item) => item.getID() == id));
this.emit('focus', this.menuItems[this.currentIndex]);
}
focusNext() {
if (this.currentIndex < this.menuItems.length - 1) {
this.currentIndex++;
}
this.focusCurrentIndex();
}
focusPrevious() {
if (this.currentIndex > 0) {
this.currentIndex--;
}
this.focusCurrentIndex();
}
focusCurrentIndex() {
this.menuItems[this.currentIndex].focus();
}
getCurrentFocus() {
return this.menuItems[this.currentIndex];
}
getContainer() {
return this.container;
}
clickDefaultAction() {
if (!this.defaultAction)
return;
const item = this.menuItems.find((item) => item.getID() === this.defaultAction);
item.click();
}
clickCancelAction() {
if (!this.cancelAction)
return;
const node = this.menuItems.find((item) => item.getID() === this.cancelAction);
node.click();
}
compile() {
const menuMap = new Map();
this.menuItems.forEach((item) => menuMap.set(item.getID(), item.getContents()));
menuMap.set('selected', this.menuItems[this.currentIndex].getID());
return menuMap;
}
}
export * from './items';

View File

@@ -0,0 +1,3 @@
export interface IPlayableSound {
play(): any;
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,17 @@
import { IPlayableSound } from './playable-sound';
export interface SoundSet {
open?: IPlayableSound;
close?: IPlayableSound;
boundary?: IPlayableSound;
choose?: IPlayableSound;
move?: IPlayableSound;
scroller?: IPlayableSound;
sliderLeft?: IPlayableSound;
sliderRight?: IPlayableSound;
wrap?: IPlayableSound;
char?: IPlayableSound;
delete?: IPlayableSound;
enter?: IPlayableSound;
checked?: IPlayableSound;
unchecked?: IPlayableSound;
}

View File

@@ -0,0 +1 @@
export {};

13
framework/ui/menu/items/base-item.d.ts vendored Normal file
View File

@@ -0,0 +1,13 @@
import * as EventEmitter from 'eventemitter3';
export declare class BaseItem extends EventEmitter {
protected id: string;
protected title: string;
protected container: HTMLElement;
constructor(id: string, title: string);
getDOMNode(): HTMLElement;
getContents(): void;
protected onFocus(event: Event): void;
focus(): void;
click(): void;
getID(): string;
}

View File

@@ -0,0 +1,29 @@
import * as EventEmitter from 'eventemitter3';
export class BaseItem extends EventEmitter {
constructor(id, title) {
super();
this.id = id;
this.title = title;
}
getDOMNode() {
let node = document.createTextNode(this.title);
let element = document.createElement('div');
element.appendChild(node);
return element;
}
getContents() {
return;
}
onFocus(event) {
this.emit('focus', this.id);
}
focus() {
this.container && this.container.focus();
}
click() {
return;
}
getID() {
return this.id;
}
}

View File

@@ -0,0 +1,10 @@
import { BaseItem } from './base-item';
export declare class CheckboxItem extends BaseItem {
private checkboxElement;
private label;
constructor(id: string, title: string);
getDOMNode(): HTMLElement;
getContents(): boolean;
private onChange;
focus(): void;
}

View File

@@ -0,0 +1,32 @@
import { BaseItem } from './base-item';
export class CheckboxItem extends BaseItem {
constructor(id, title) {
super(id, title);
}
getDOMNode() {
this.container = document.createElement('div');
this.label = document.createElement('label');
this.label.setAttribute('for', `chkbx_${this.id}`);
this.label.textContent = this.title;
this.checkboxElement = document.createElement('input');
this.checkboxElement.setAttribute('type', 'checkbox');
this.checkboxElement.setAttribute('id', `chkbx_${this.id}`);
this.checkboxElement.addEventListener('focus', this.onFocus.bind(this));
this.checkboxElement.addEventListener('change', this.onChange.bind(this));
this.container.appendChild(this.label);
this.container.appendChild(this.checkboxElement);
return this.container;
}
getContents() {
return this.checkboxElement.checked;
}
onChange(event) {
this.emit('update', {
type: 'checkbox',
value: this.checkboxElement.checked
});
}
focus() {
this.checkboxElement.focus();
}
}

13
framework/ui/menu/items/edit-item.d.ts vendored Normal file
View File

@@ -0,0 +1,13 @@
import { BaseItem } from './base-item';
export declare class EditItem extends BaseItem {
private initialText;
private isPassword;
private contents;
private label;
private editField;
constructor(id: string, title: string, initialText: string, isPassword?: boolean);
getDOMNode(): HTMLElement;
getContents(): string;
private onChange;
focus(): void;
}

View File

@@ -0,0 +1,42 @@
import { BaseItem } from './base-item';
export class EditItem extends BaseItem {
constructor(id, title, initialText, isPassword = false) {
super(id, title);
this.initialText = initialText;
this.isPassword = isPassword;
this.contents = initialText;
}
getDOMNode() {
const node = document.createElement('div');
const label = document.createElement('label');
label.setAttribute('for', `edit_${this.id}`);
label.textContent = this.title;
const editField = document.createElement('input');
editField.id = `edit_${this.id}`;
editField.value = this.contents;
editField.addEventListener('keydown', this.onChange.bind(this));
editField.addEventListener('focus', this.onFocus.bind(this));
if (this.isPassword) {
editField.type = 'password';
}
node.appendChild(label);
node.appendChild(editField);
node.addEventListener('focus', this.onFocus.bind(this));
this.editField = editField;
this.label = label;
this.container = node;
return node;
}
getContents() {
return this.editField.value;
}
onChange(event) {
this.emit('update', {
type: 'edit',
value: this.editField.value
});
}
focus() {
this.editField && this.editField.focus();
}
}

6
framework/ui/menu/items/index.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
export { BaseItem } from './base-item';
export { EditItem } from './edit-item';
export { MenuItem } from './menu-item';
export { SelectorItem } from './selector-item';
export { SliderItem } from './slider-item';
export { CheckboxItem } from './checkbox-item';

View File

@@ -0,0 +1,6 @@
export { BaseItem } from './base-item';
export { EditItem } from './edit-item';
export { MenuItem } from './menu-item';
export { SelectorItem } from './selector-item';
export { SliderItem } from './slider-item';
export { CheckboxItem } from './checkbox-item';

10
framework/ui/menu/items/menu-item.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
import { BaseItem } from './base-item';
export declare class MenuItem extends BaseItem {
private button;
constructor(id: string, title: string);
getDOMNode(): HTMLElement;
getContents(): string;
private handleClick;
focus(): void;
click(): void;
}

View File

@@ -0,0 +1,29 @@
import { BaseItem } from './base-item';
export class MenuItem extends BaseItem {
constructor(id, title) {
super(id, title);
}
getDOMNode() {
const container = document.createElement('div');
const button = document.createElement('button');
button.textContent = this.title;
button.addEventListener('click', this.handleClick.bind(this));
button.addEventListener('focus', this.onFocus.bind(this));
container.appendChild(button);
this.container = container;
this.button = button;
return container;
}
getContents() {
return this.id;
}
handleClick(event) {
this.emit('choose', this.id);
}
focus() {
this.button && this.button.focus();
}
click() {
this.button.click();
}
}

View File

@@ -0,0 +1,21 @@
import { BaseItem } from './base-item';
export declare class SelectorItem extends BaseItem {
private items;
private listContainer;
private fieldSet;
private label;
private entries;
private currentValue;
constructor(id: string, title: string, items: SelectorEntry[]);
getDOMNode(): HTMLElement;
private buildEntries;
private onItemFocus;
getContents(): any;
private onSelectItem;
private onChangeItem;
focus(): void;
}
export interface SelectorEntry {
id: string;
title: string;
}

View File

@@ -0,0 +1,62 @@
import { BaseItem } from './base-item';
export class SelectorItem extends BaseItem {
constructor(id, title, items) {
super(id, title);
this.items = items;
this.entries = [];
}
getDOMNode() {
this.container = document.createElement('div');
this.listContainer = document.createElement('ul');
this.label = document.createElement('legend');
this.fieldSet = document.createElement('fieldset');
this.fieldSet.setAttribute('class', 'radiogroup');
this.fieldSet.id = `fs_selector_${this.id}`;
const name = document.createTextNode(this.title);
this.label.appendChild(name);
this.fieldSet.appendChild(this.label);
this.buildEntries();
this.container.appendChild(this.fieldSet);
this.container.addEventListener('focus', this.onFocus.bind(this));
return this.container;
}
buildEntries() {
this.items.forEach((item, index) => {
const node = document.createElement('input');
node.type = 'radio';
node.id = `${this.id}_${item.id}`;
node.name = this.id;
node.value = item.id || `${index}`;
node.addEventListener('focus', this.onItemFocus.bind(this));
node.addEventListener('select', this.onSelectItem.bind(this));
node.addEventListener('change', this.onChangeItem.bind(this));
this.entries.push(node);
const label = document.createElement('label');
label.setAttribute('for', `${this.id}_${item.id}`);
label.textContent = item.title;
this.fieldSet.append(node);
this.fieldSet.append(label);
});
}
onItemFocus(event) {
console.log(`Item focused: `, event);
this.emit('focus', this.id);
}
getContents() {
return this.currentValue;
}
onSelectItem(event) { }
onChangeItem(event) {
const node = document.querySelector(`input[name = "${this.id}"]:checked`);
this.currentValue = this.items.find((item) => `${this.id}_${item.id}` === node.id);
this.emit('update', {
type: 'selector',
value: this.currentValue
});
}
focus() {
const node = document.querySelector(`input[name = "${this.id}"]:checked`) ||
this.entries[0];
node.focus();
}
}

View File

@@ -0,0 +1,15 @@
import { BaseItem } from './base-item';
export declare class SliderItem extends BaseItem {
private min;
private max;
private step;
private defaultValue;
private slider;
private label;
private currentValue;
constructor(id: string, title: string, min: number, max: number, step: number, defaultValue?: number);
getDOMNode(): HTMLElement;
getContents(): string;
private onChange;
focus(): void;
}

View File

@@ -0,0 +1,42 @@
import { BaseItem } from './base-item';
export class SliderItem extends BaseItem {
constructor(id, title, min, max, step, defaultValue = null) {
super(id, title);
this.min = min;
this.max = max;
this.step = step;
this.defaultValue = defaultValue;
}
getDOMNode() {
this.container = document.createElement('div');
this.label = document.createElement('label');
this.label.textContent = this.title;
this.label.setAttribute('for', `slider_${this.id}`);
this.slider = document.createElement('input');
this.slider.id = `slider_${this.id}`;
this.slider.type = 'range';
this.slider.setAttribute('min', this.min.toString());
this.slider.setAttribute('max', this.max.toString());
this.slider.setAttribute('step', this.step.toString());
if (this.defaultValue)
this.slider.value = this.defaultValue.toString();
this.slider.addEventListener('change', this.onChange.bind(this));
this.slider.addEventListener('focus', this.onFocus.bind(this));
this.container.appendChild(this.label);
this.container.appendChild(this.slider);
this.container.addEventListener('focus', this.onFocus.bind(this));
return this.container;
}
getContents() {
return this.slider.value;
}
onChange(event) {
this.emit('update', {
type: 'slider',
value: this.slider.value
});
}
focus() {
this.slider && this.slider.focus();
}
}

View File

@@ -0,0 +1,8 @@
import { Menu } from '.';
export declare class KeyboardManager {
private menu;
constructor(menu: Menu);
init(): void;
private handler;
release(): void;
}

View File

@@ -0,0 +1,40 @@
export class KeyboardManager {
constructor(menu) {
this.menu = menu;
}
init() {
this.menu
.getContainer()
.addEventListener('keydown', this.handler.bind(this));
// This trick let's us detect the press of the back or forward buttons to exit out of the menu.
window.onpopstate = () => this.menu.clickCancelAction();
}
handler(event) {
switch (event.key) {
case 'ArrowDown':
event.preventDefault();
this.menu.focusNext();
break;
case 'ArrowUp':
event.preventDefault();
this.menu.focusPrevious();
break;
case 'Enter':
event.preventDefault();
this.menu.clickDefaultAction();
break;
case 'Escape':
event.preventDefault();
this.menu.clickCancelAction();
break;
default:
break;
}
}
release() {
this.menu
.getContainer()
.removeEventListener('keydown', this.handler.bind(this));
window.onpopstate = null;
}
}

0
framework/ui/menu/menu.d.ts vendored Normal file
View File

View File

16
framework/ui/menu/sound-manager.d.ts vendored Normal file
View File

@@ -0,0 +1,16 @@
import { SoundSet } from './interfaces/sound-set';
export declare class SoundManager {
private soundSet;
private data;
constructor(soundSet?: SoundSet);
setSoundSet(soundSet: SoundSet): void;
handleSound(type: string, data?: any): void;
private handleEditSound;
private handleSelectorSound;
private handleSliderSound;
private handleFocusSound;
private handleOpenSound;
private handleCloseSound;
private handleChooseSound;
private handleCheckboxSound;
}

View File

@@ -0,0 +1,84 @@
export class SoundManager {
constructor(soundSet = null) {
this.soundSet = null;
this.data = new Map();
this.soundSet = soundSet;
}
setSoundSet(soundSet) {
this.soundSet = soundSet;
}
handleSound(type, data = null) {
switch (type) {
case 'edit':
this.handleEditSound(data);
break;
case 'slider':
this.handleSliderSound(data);
break;
case 'selector':
this.handleSelectorSound(data);
break;
case 'checkbox':
this.handleCheckboxSound(data);
break;
case 'focus':
this.handleFocusSound();
break;
case 'choose':
this.handleChooseSound();
break;
case 'open':
this.handleOpenSound();
break;
case 'close':
this.handleCloseSound();
break;
default:
return;
break;
}
}
handleEditSound(data) {
const prevData = this.data.get('edit') || '';
if (data.length <= prevData.length) {
this.soundSet.delete && this.soundSet.delete.play();
}
else {
this.soundSet.char && this.soundSet.char.play();
}
this.data.set('edit', data);
}
handleSelectorSound(data) {
this.soundSet.scroller && this.soundSet.scroller.play();
}
handleSliderSound(data) {
const prevData = this.data.get('slider');
if (data < prevData) {
this.soundSet.sliderLeft && this.soundSet.sliderLeft.play();
}
else {
this.soundSet.sliderRight && this.soundSet.sliderRight.play();
}
this.data.set('slider', data);
}
handleFocusSound() {
this.soundSet.move && this.soundSet.move.play();
}
handleOpenSound() {
this.soundSet.open && this.soundSet.open.play();
}
handleCloseSound() {
this.soundSet.close && this.soundSet.close.play();
}
handleChooseSound() {
this.soundSet.choose && this.soundSet.choose.play();
}
handleCheckboxSound(data) {
if (data === true) {
this.soundSet.checked && this.soundSet.checked.play();
}
else {
this.soundSet.unchecked && this.soundSet.unchecked.play();
}
}
}

28
framework/ui/text/index.d.ts vendored Normal file
View File

@@ -0,0 +1,28 @@
import * as EventEmitter from 'eventemitter3';
import { SoundSet } from '../menu/interfaces/sound-set';
import { Line } from './line';
export declare class ScrollingText extends EventEmitter {
private text;
private delimiter;
private soundSet;
private appearingCharacters;
private characterAppearSpeed;
private currentLineIndex;
private currentLine;
private lines;
private wrapper;
private container;
private soundManager;
private keyboardManager;
constructor(text?: string, delimiter?: string, soundSet?: SoundSet, appearingCharacters?: boolean, characterAppearSpeed?: number);
setText(text: string): this;
setSoundSet(soundSet: SoundSet): this;
setDelimiter(delimiter: string): this;
setAppearingCharacters(appearing: boolean): this;
setAppearingCharacterSpeed(speed: number): this;
init(): void;
run(element: HTMLElement): Promise<void>;
displayLine(index: number): Promise<void>;
getContainer(): HTMLElement;
getCurrentLine(): Line;
}

102
framework/ui/text/index.js Normal file
View File

@@ -0,0 +1,102 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import * as EventEmitter from 'eventemitter3';
import { Line } from './line';
import { SoundManager } from './sound-manager';
import { KeyboardManager } from './keyboard-manager';
export class ScrollingText extends EventEmitter {
constructor(text = null, delimiter = '\n', soundSet = null, appearingCharacters = false, characterAppearSpeed = 0) {
super();
this.text = text;
this.delimiter = delimiter;
this.soundSet = soundSet;
this.appearingCharacters = appearingCharacters;
this.characterAppearSpeed = characterAppearSpeed;
this.lines = [];
this.soundManager = new SoundManager(this, this.soundSet);
this.keyboardManager = new KeyboardManager(this);
this.init();
}
setText(text) {
this.text = text;
this.init();
return this;
}
setSoundSet(soundSet) {
this.soundSet = soundSet;
this.init();
this.soundManager.setSoundSet(this.soundSet);
return this;
}
setDelimiter(delimiter) {
this.delimiter = delimiter;
this.init();
return this;
}
setAppearingCharacters(appearing) {
this.appearingCharacters = appearing;
this.init();
return this;
}
setAppearingCharacterSpeed(speed) {
this.characterAppearSpeed = speed;
this.init();
return this;
}
init() {
const split = this.text.split(this.delimiter);
this.lines = split.map((line) => new Line(line));
}
run(element) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
this.wrapper = document.createElement('div');
this.wrapper.setAttribute('aria-role', 'polite');
this.container = document.createElement('div');
this.wrapper.appendChild(this.container);
element.appendChild(this.wrapper);
this.soundManager.init();
this.keyboardManager.init();
this.emit('open');
let index = 0;
this.currentLineIndex = 0;
while (index < this.lines.length) {
this.currentLineIndex = index;
yield this.displayLine(index);
index++;
}
this.emit('close');
this.keyboardManager.release();
this.container.remove();
resolve();
}));
});
}
displayLine(index) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
this.container.innerHTML = '';
this.container.appendChild(this.lines[index].getDOMNode());
this.lines[index].display(this.container, this.appearingCharacters, this.characterAppearSpeed);
this.lines[index].on('character.appear', (event) => this.emit('character.appear', event));
this.lines[index].on('advance', () => {
this.emit('advance');
resolve();
});
});
});
}
getContainer() {
return this.wrapper;
}
getCurrentLine() {
return this.lines[this.currentLineIndex];
}
}

View File

@@ -0,0 +1,3 @@
export interface IPlayableSound {
play(): any;
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,7 @@
import { IPlayableSound } from './playable-sound';
export interface SoundSet {
open?: IPlayableSound;
close?: IPlayableSound;
scroll?: IPlayableSound;
characterAppear?: IPlayableSound;
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,8 @@
import { ScrollingText } from '.';
export declare class KeyboardManager {
private scrollingText;
constructor(scrollingText: ScrollingText);
init(): void;
release(): void;
private handler;
}

View File

@@ -0,0 +1,25 @@
export class KeyboardManager {
constructor(scrollingText) {
this.scrollingText = scrollingText;
}
init() {
this.scrollingText
.getContainer()
.addEventListener('keydown', (event) => this.handler(event));
}
release() {
this.scrollingText
.getContainer()
.removeEventListener('keydown', (event) => this.handler(event));
}
handler(event) {
switch (event.key) {
case 'Enter':
event.preventDefault();
this.scrollingText.getCurrentLine().getAdvanceButton().click();
break;
default:
break;
}
}
}

13
framework/ui/text/line.d.ts vendored Normal file
View File

@@ -0,0 +1,13 @@
import * as EventEmitter from 'eventemitter3';
export declare class Line extends EventEmitter {
private text;
private container;
private textField;
private advanceButton;
private active;
constructor(text: string);
getDOMNode(): HTMLElement;
display(element: HTMLElement, appearingCharacters?: boolean, appearingCharacterSpeed?: number): void;
private fillText;
getAdvanceButton(): HTMLElement;
}

45
framework/ui/text/line.js Normal file
View File

@@ -0,0 +1,45 @@
import * as EventEmitter from 'eventemitter3';
export class Line extends EventEmitter {
constructor(text) {
super();
this.text = text;
this.active = false;
}
getDOMNode() {
this.container = document.createElement('div');
this.container.setAttribute('aria-role', 'polite');
this.textField = document.createElement('div');
this.container.appendChild(this.textField);
this.advanceButton = document.createElement('button');
this.advanceButton.textContent = 'Advance';
this.advanceButton.addEventListener('click', (event) => {
this.emit('advance');
this.active = false;
});
this.container.appendChild(this.advanceButton);
return this.container;
}
display(element, appearingCharacters = false, appearingCharacterSpeed = 0) {
this.active = true;
this.textField.focus();
if (!appearingCharacters) {
this.textField.textContent = this.text;
}
else {
this.fillText(0, appearingCharacterSpeed);
}
}
fillText(index, speed) {
if (!this.active)
return;
if (index > this.text.length) {
return;
}
this.textField.textContent += this.text.charAt(index);
this.emit('character.appear', this.textField.textContent);
setTimeout(() => this.fillText((index += 1), speed), speed);
}
getAdvanceButton() {
return this.advanceButton;
}
}

13
framework/ui/text/sound-manager.d.ts vendored Normal file
View File

@@ -0,0 +1,13 @@
import { SoundSet } from './interfaces/sound-set';
import { ScrollingText } from '.';
export declare class SoundManager {
private instance;
private soundSet;
constructor(instance: ScrollingText, soundSet: SoundSet);
setSoundSet(soundSet: SoundSet): void;
init(): void;
private handleOpen;
private handleCharacterAppear;
private handleAdvance;
private handleClose;
}

View File

@@ -0,0 +1,27 @@
export class SoundManager {
constructor(instance, soundSet) {
this.instance = instance;
this.soundSet = soundSet;
}
setSoundSet(soundSet) {
this.soundSet = soundSet;
}
init() {
this.instance.on('character.appear', this.handleCharacterAppear.bind(this));
this.instance.on('open', this.handleOpen.bind(this));
this.instance.on('close', this.handleClose.bind(this));
this.instance.on('advance', this.handleAdvance.bind(this));
}
handleOpen() {
this.soundSet.open && this.soundSet.open.play();
}
handleCharacterAppear() {
this.soundSet.characterAppear && this.soundSet.characterAppear.play();
}
handleAdvance() {
this.soundSet.scroll && this.soundSet.scroll.play();
}
handleClose() {
this.soundSet.close && this.soundSet.close.play();
}
}