Add: PhaserInputMaster plugin
This commit is contained in:
+184
@@ -0,0 +1,184 @@
|
||||
module PhaserInput {
|
||||
|
||||
export enum InputType {
|
||||
text,
|
||||
password,
|
||||
number
|
||||
}
|
||||
|
||||
export class InputElement {
|
||||
private element: HTMLInputElement;
|
||||
|
||||
private keyUpCallback: () => void;
|
||||
|
||||
private inputChangeCallback: () => void;
|
||||
|
||||
private type: InputType;
|
||||
|
||||
private id: string;
|
||||
|
||||
private game: Phaser.Game;
|
||||
|
||||
private focusIn: Phaser.Signal;
|
||||
|
||||
private focusOut: Phaser.Signal;
|
||||
|
||||
constructor(game: Phaser.Game, id: string, type: InputType = InputType.text, value: string = '', focusIn?: Phaser.Signal, focusOut?: Phaser.Signal) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.game = game;
|
||||
this.focusIn = focusIn;
|
||||
this.focusOut = focusOut;
|
||||
|
||||
let canvasTopX: number = this.game.canvas.getBoundingClientRect().top + document.body.scrollTop;
|
||||
|
||||
this.element = document.createElement('input');
|
||||
|
||||
this.element.id = id;
|
||||
this.element.style.position = 'absolute';
|
||||
this.element.style.top = canvasTopX + 'px';
|
||||
this.element.style.left = (-40).toString() + 'px';
|
||||
this.element.style.width = (10).toString() + 'px';
|
||||
this.element.style.height = (10).toString() + 'px';
|
||||
this.element.style.border = '0px';
|
||||
this.element.value = this.value;
|
||||
this.element.type = InputType[type];
|
||||
|
||||
this.element.addEventListener('focusin', (): void => {
|
||||
if (this.focusIn instanceof Phaser.Signal) {
|
||||
this.focusIn.dispatch();
|
||||
}
|
||||
});
|
||||
this.element.addEventListener('focusout', (): void => {
|
||||
if (this.focusOut instanceof Phaser.Signal) {
|
||||
this.focusOut.dispatch();
|
||||
}
|
||||
});
|
||||
|
||||
document.body.appendChild(this.element);
|
||||
}
|
||||
|
||||
public addKeyUpListener(callback: () => void): void {
|
||||
this.keyUpCallback = callback;
|
||||
document.addEventListener('keyup', this.keyUpCallback);
|
||||
this.element.addEventListener('input', this.keyUpCallback);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the keyboard event on keydown, used to prevent it going from input field to sprite
|
||||
**/
|
||||
public blockKeyDownEvents(): void {
|
||||
document.addEventListener('keydown', this.preventKeyPropagation);
|
||||
}
|
||||
|
||||
/**
|
||||
* To prevent bubbling of keyboard event from input field to sprite
|
||||
**/
|
||||
private preventKeyPropagation(evt: KeyboardEvent): void{
|
||||
if(evt.stopPropagation){
|
||||
evt.stopPropagation();
|
||||
} else {
|
||||
//for IE < 9
|
||||
event.cancelBubble = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove listener that captures keydown keyboard events
|
||||
**/
|
||||
public unblockKeyDownEvents(): void {
|
||||
document.removeEventListener('keydown', this.preventKeyPropagation);
|
||||
}
|
||||
|
||||
public removeEventListener(): void {
|
||||
document.removeEventListener('keyup', this.keyUpCallback);
|
||||
this.element.removeEventListener('input', this.keyUpCallback);
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
document.body.removeChild(this.element);
|
||||
}
|
||||
|
||||
public setMax(max: string, min?: string) {
|
||||
if (max === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.type === InputType.text || this.type === InputType.password) {
|
||||
this.element.maxLength = parseInt(max, 10);
|
||||
} else if (this.type === InputType.number) {
|
||||
this.element.max = max;
|
||||
if (min === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.element.min = min;
|
||||
}
|
||||
}
|
||||
|
||||
get value(): string {
|
||||
return this.element.value;
|
||||
}
|
||||
|
||||
set value(value: string) {
|
||||
this.element.value = value;
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
this.element.focus();
|
||||
if (!this.game.device.desktop && this.game.device.chrome) {
|
||||
let originalWidth = window.innerWidth,
|
||||
originalHeight = window.innerHeight;
|
||||
|
||||
let kbAppeared: boolean = false;
|
||||
let interval: number = setInterval((): void => {
|
||||
if (originalWidth > window.innerWidth || originalHeight > window.innerHeight) {
|
||||
kbAppeared = true;
|
||||
}
|
||||
|
||||
if (kbAppeared && originalWidth === window.innerWidth && originalHeight === window.innerHeight) {
|
||||
if (this.focusOut instanceof Phaser.Signal) {
|
||||
this.focusOut.dispatch();
|
||||
}
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
|
||||
public blur(): void {
|
||||
this.element.blur();
|
||||
}
|
||||
|
||||
get hasSelection () {
|
||||
if (this.type === InputType.number) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.element.selectionStart !== this.element.selectionEnd;
|
||||
}
|
||||
|
||||
get caretStart() {
|
||||
return this.element.selectionEnd;
|
||||
}
|
||||
|
||||
get caretEnd() {
|
||||
return this.element.selectionStart;
|
||||
}
|
||||
|
||||
public getCaretPosition() {
|
||||
if (this.type === InputType.number) {
|
||||
return -1;
|
||||
}
|
||||
return this.element.selectionStart;
|
||||
}
|
||||
|
||||
public setCaretPosition(pos: number) {
|
||||
if (this.type === InputType.number) {
|
||||
return ;
|
||||
}
|
||||
this.element.setSelectionRange(pos, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
+565
@@ -0,0 +1,565 @@
|
||||
module PhaserInput {
|
||||
import Text = Phaser.Text;
|
||||
|
||||
export enum ForceCase {
|
||||
none,
|
||||
lower,
|
||||
upper
|
||||
}
|
||||
|
||||
export interface InputOptions extends Phaser.PhaserTextStyle {
|
||||
x?: number;
|
||||
y?: number;
|
||||
placeHolder?: string;
|
||||
fillAlpha?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
padding?: number;
|
||||
borderWidth?: number;
|
||||
borderColor?: string;
|
||||
borderRadius?: number;
|
||||
cursorColor?: string;
|
||||
placeHolderColor?: string;
|
||||
type?: InputType;
|
||||
forceCase?: ForceCase;
|
||||
min?: string;
|
||||
max?: string;
|
||||
textAlign?: string;
|
||||
selectionColor?: string;
|
||||
zoom?: boolean;
|
||||
}
|
||||
|
||||
export class InputField extends Phaser.Sprite {
|
||||
public focusOutOnEnter: boolean = true;
|
||||
|
||||
private placeHolder:Phaser.Text = null;
|
||||
|
||||
private box: InputBox = null;
|
||||
|
||||
private textMask: TextMask;
|
||||
|
||||
private focus:boolean = false;
|
||||
|
||||
private cursor:Phaser.Text;
|
||||
|
||||
private text:Phaser.Text;
|
||||
|
||||
private offscreenText: Phaser.Text;
|
||||
|
||||
public value:string = '';
|
||||
|
||||
private inputOptions: InputOptions;
|
||||
|
||||
private domElement: InputElement;
|
||||
|
||||
private selection: SelectionHighlight;
|
||||
|
||||
private windowScale: number = 1;
|
||||
|
||||
public blockInput: boolean = true;
|
||||
|
||||
public focusIn: Phaser.Signal = new Phaser.Signal();
|
||||
|
||||
public focusOut: Phaser.Signal = new Phaser.Signal();
|
||||
|
||||
get width(): number {
|
||||
return this.inputOptions.width;
|
||||
}
|
||||
|
||||
set width(width: number) {
|
||||
this.inputOptions.width = width;
|
||||
this.box.resize(width);
|
||||
this.textMask.resize(width);
|
||||
this.updateTextAlignment();
|
||||
}
|
||||
|
||||
constructor(game:Phaser.Game, x:number, y:number, inputOptions:InputOptions = {}) {
|
||||
super(game, x, y);
|
||||
|
||||
//Parse the options
|
||||
this.inputOptions = inputOptions;
|
||||
this.inputOptions.width = (typeof inputOptions.width === 'number') ? inputOptions.width : 150;
|
||||
this.inputOptions.padding = (typeof inputOptions.padding === 'number') ? inputOptions.padding : 0;
|
||||
this.inputOptions.textAlign = inputOptions.textAlign || 'left';
|
||||
this.inputOptions.type = inputOptions.type || InputType.text;
|
||||
this.inputOptions.forceCase = (inputOptions.forceCase) ? inputOptions.forceCase : ForceCase.none;
|
||||
this.inputOptions.borderRadius = (typeof inputOptions.borderRadius === 'number') ? inputOptions.borderRadius : 0;
|
||||
this.inputOptions.height = (typeof inputOptions.height === 'number') ? inputOptions.height : 14;
|
||||
this.inputOptions.fillAlpha = (inputOptions.fillAlpha === undefined) ? 1 : inputOptions.fillAlpha;
|
||||
this.inputOptions.selectionColor = inputOptions.selectionColor || 'rgba(179, 212, 253, 0.8)';
|
||||
this.inputOptions.zoom = (!game.device.desktop) ? inputOptions.zoom || false : false;
|
||||
|
||||
//create the input box
|
||||
this.box = new InputBox(this.game, inputOptions);
|
||||
this.setTexture(this.box.generateTexture());
|
||||
|
||||
//create the mask that will be used for the texts
|
||||
this.textMask = new TextMask(this.game, inputOptions);
|
||||
this.addChild(this.textMask);
|
||||
|
||||
//Create the hidden dom elements
|
||||
this.domElement = new InputElement(this.game, 'phaser-input-' + (Math.random() * 10000 | 0).toString(),
|
||||
this.inputOptions.type, this.value, this.focusIn, this.focusOut);
|
||||
this.domElement.setMax(this.inputOptions.max, this.inputOptions.min);
|
||||
|
||||
this.selection = new SelectionHighlight(this.game, this.inputOptions);
|
||||
this.selection.mask = this.textMask;
|
||||
this.addChild(this.selection);
|
||||
|
||||
if (inputOptions.placeHolder && inputOptions.placeHolder.length > 0) {
|
||||
this.placeHolder = new Phaser.Text(game, this.inputOptions.padding, this.inputOptions.padding,
|
||||
inputOptions.placeHolder, <Phaser.PhaserTextStyle>{
|
||||
font: inputOptions.font || '14px Arial',
|
||||
fontWeight: inputOptions.fontWeight || 'normal',
|
||||
fill: inputOptions.placeHolderColor || '#bfbebd'
|
||||
});
|
||||
this.placeHolder.mask = this.textMask;
|
||||
this.addChild(this.placeHolder);
|
||||
}
|
||||
|
||||
this.cursor = new Phaser.Text(game, this.inputOptions.padding, this.inputOptions.padding - 2, '|', <Phaser.PhaserTextStyle>{
|
||||
font: inputOptions.font || '14px Arial',
|
||||
fontWeight: inputOptions.fontWeight || 'normal',
|
||||
fill: inputOptions.cursorColor || '#000000'
|
||||
});
|
||||
this.cursor.visible = false;
|
||||
this.addChild(this.cursor);
|
||||
|
||||
this.text = new Phaser.Text(game, this.inputOptions.padding, this.inputOptions.padding, '', <Phaser.PhaserTextStyle>{
|
||||
font: inputOptions.font || '14px Arial',
|
||||
fontWeight: inputOptions.fontWeight || 'normal',
|
||||
fill: inputOptions.fill || '#000000'
|
||||
});
|
||||
this.text.mask = this.textMask;
|
||||
this.addChild(this.text);
|
||||
|
||||
this.offscreenText = new Phaser.Text(game, this.inputOptions.padding, this.inputOptions.padding, '', <Phaser.PhaserTextStyle>{
|
||||
font: inputOptions.font || '14px Arial',
|
||||
fontWeight: inputOptions.fontWeight || 'normal',
|
||||
fill: inputOptions.fill || '#000000'
|
||||
});
|
||||
|
||||
this.updateTextAlignment();
|
||||
|
||||
this.inputEnabled = true;
|
||||
this.input.useHandCursor = true;
|
||||
|
||||
this.game.input.onDown.add(this.checkDown, this);
|
||||
this.focusOut.add((): void => {
|
||||
if (PhaserInput.KeyboardOpen) {
|
||||
this.endFocus();
|
||||
if (this.inputOptions.zoom) {
|
||||
this.zoomOut();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private updateTextAlignment(): void {
|
||||
switch (this.inputOptions.textAlign) {
|
||||
case 'left':
|
||||
this.text.anchor.set(0, 0);
|
||||
this.text.x = this.inputOptions.padding;
|
||||
if (null !== this.placeHolder) {
|
||||
this.placeHolder.anchor.set(0, 0);
|
||||
}
|
||||
this.cursor.x = this.inputOptions.padding + this.getCaretPosition();
|
||||
break;
|
||||
case 'center':
|
||||
this.text.anchor.set(0.5, 0);
|
||||
this.text.x = this.inputOptions.padding + this.inputOptions.width / 2;
|
||||
if (null !== this.placeHolder) {
|
||||
this.placeHolder.anchor.set(0.5, 0);
|
||||
this.placeHolder.x = this.inputOptions.padding + this.inputOptions.width / 2;
|
||||
}
|
||||
this.cursor.x = this.inputOptions.padding + this.inputOptions.width / 2 - this.text.width / 2 + this.getCaretPosition();
|
||||
break;
|
||||
case 'right':
|
||||
this.text.anchor.set(1, 0);
|
||||
this.text.x = this.inputOptions.padding + this.inputOptions.width;
|
||||
if (null !== this.placeHolder) {
|
||||
this.placeHolder.anchor.set(1, 0);
|
||||
this.placeHolder.x = this.inputOptions.padding + this.inputOptions.width;
|
||||
}
|
||||
this.cursor.x = this.inputOptions.padding + this.inputOptions.width;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a generic input down handler for the game.
|
||||
* if the input object is clicked, we gain focus on it and create the dom element
|
||||
*
|
||||
* If there was focus on the element previously, but clicked outside of it, the element will loose focus
|
||||
* and no keyboard events will be registered anymore
|
||||
*
|
||||
* @param e Phaser.Pointer
|
||||
*/
|
||||
private checkDown(e: Phaser.Pointer): void
|
||||
{
|
||||
if(!this.value){
|
||||
this.resetText();
|
||||
}
|
||||
if (this.input.checkPointerOver(e)) {
|
||||
if (this.focus) {
|
||||
this.setCaretOnclick(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.inputOptions.zoom && !PhaserInput.Zoomed) {
|
||||
this.zoomIn();
|
||||
}
|
||||
this.startFocus();
|
||||
} else {
|
||||
if (this.focus === true) {
|
||||
this.endFocus();
|
||||
if (this.inputOptions.zoom) {
|
||||
this.zoomOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update function makes the cursor blink, it uses two private properties to make it toggle
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
private blink:boolean = true;
|
||||
private cnt: number = 0;
|
||||
public update() {
|
||||
this.text.update();
|
||||
if (this.placeHolder) {
|
||||
this.placeHolder.update();
|
||||
}
|
||||
if (!this.focus) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.cnt !== 30) {
|
||||
return this.cnt++;
|
||||
}
|
||||
|
||||
this.cursor.visible = this.blink;
|
||||
this.blink = !this.blink;
|
||||
this.cnt = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus is lost on the input element, we disable the cursor and remove the hidden input element
|
||||
*/
|
||||
public endFocus() {
|
||||
if(!this.focus){
|
||||
return;
|
||||
}
|
||||
|
||||
this.domElement.removeEventListener();
|
||||
|
||||
if(this.blockInput === true) {
|
||||
this.domElement.unblockKeyDownEvents();
|
||||
}
|
||||
|
||||
this.focus = false;
|
||||
if (this.value.length === 0 && null !== this.placeHolder) {
|
||||
this.placeHolder.visible = true;
|
||||
}
|
||||
this.cursor.visible = false;
|
||||
|
||||
if (this.game.device.desktop) {
|
||||
//Timeout is a chrome hack
|
||||
setTimeout(() => {
|
||||
this.domElement.blur();
|
||||
}, 0);
|
||||
} else {
|
||||
this.domElement.blur();
|
||||
}
|
||||
|
||||
if (!this.game.device.desktop) {
|
||||
PhaserInput.KeyboardOpen = false;
|
||||
PhaserInput.onKeyboardClose.dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public startFocus() {
|
||||
this.focus = true;
|
||||
|
||||
if (null !== this.placeHolder) {
|
||||
this.placeHolder.visible = false;
|
||||
}
|
||||
|
||||
if (this.game.device.desktop) {
|
||||
//Timeout is a chrome hack
|
||||
setTimeout(() => {
|
||||
this.keyUpProcessor();
|
||||
}, 0);
|
||||
} else {
|
||||
this.keyUpProcessor();
|
||||
}
|
||||
|
||||
if (!this.game.device.desktop) {
|
||||
PhaserInput.KeyboardOpen = true;
|
||||
PhaserInput.onKeyboardOpen.dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
private keyUpProcessor():void {
|
||||
this.domElement.addKeyUpListener(this.keyListener.bind(this));
|
||||
this.domElement.focus();
|
||||
|
||||
if(this.blockInput === true) {
|
||||
this.domElement.blockKeyDownEvents();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the text value in the box, and make sure the cursor is positioned correctly
|
||||
*/
|
||||
private updateText()
|
||||
{
|
||||
var text: string = '';
|
||||
if (this.inputOptions.type === InputType.password) {
|
||||
for (let i = 0; i < this.value.length; i++) {
|
||||
text += '*';
|
||||
}
|
||||
}else if (this.inputOptions.type === InputType.number) {
|
||||
var val = parseInt(this.value);
|
||||
if (val < parseInt(this.inputOptions.min)) {
|
||||
text = this.value = this.domElement.value = this.inputOptions.min;
|
||||
} else if (val > parseInt(this.inputOptions.max)) {
|
||||
text = this.value = this.domElement.value = this.inputOptions.max;
|
||||
} else {
|
||||
text = this.value;
|
||||
}
|
||||
} else {
|
||||
text = this.value;
|
||||
}
|
||||
|
||||
this.text.setText(text);
|
||||
|
||||
if (this.text.width > this.inputOptions.width) {
|
||||
this.text.anchor.x = 1;
|
||||
this.text.x = this.inputOptions.padding + this.inputOptions.width;
|
||||
} else {
|
||||
switch (this.inputOptions.textAlign) {
|
||||
case 'left':
|
||||
this.text.anchor.set(0, 0);
|
||||
this.text.x = this.inputOptions.padding;
|
||||
break;
|
||||
case 'center':
|
||||
this.text.anchor.set(0.5, 0);
|
||||
this.text.x = this.inputOptions.padding + this.inputOptions.width / 2;
|
||||
break;
|
||||
case 'right':
|
||||
this.text.anchor.set(1, 0);
|
||||
this.text.x = this.inputOptions.padding + this.inputOptions.width;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the position of the caret in the phaser input field
|
||||
*/
|
||||
private updateCursor() {
|
||||
if (this.text.width > this.inputOptions.width || this.inputOptions.textAlign === 'right') {
|
||||
this.cursor.x = this.inputOptions.padding + this.inputOptions.width;
|
||||
} else {
|
||||
switch (this.inputOptions.textAlign) {
|
||||
case 'left':
|
||||
this.cursor.x = this.inputOptions.padding + this.getCaretPosition();
|
||||
break;
|
||||
case 'center':
|
||||
this.cursor.x = this.inputOptions.padding + this.inputOptions.width / 2 - this.text.width / 2 + this.getCaretPosition();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the carrot position from the dom element. This one changes when you use the keyboard to navigate the element
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
private getCaretPosition() {
|
||||
var caretPosition: number = this.domElement.getCaretPosition();
|
||||
if (-1 === caretPosition) {
|
||||
return this.text.width;
|
||||
}
|
||||
|
||||
var text = this.value;
|
||||
if (this.inputOptions.type === InputType.password) {
|
||||
text = '';
|
||||
for (let i = 0; i < this.value.length; i++) {
|
||||
text += '*';
|
||||
}
|
||||
}
|
||||
|
||||
this.offscreenText.setText(text.slice(0, caretPosition));
|
||||
|
||||
return this.offscreenText.width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the caret when a click was made in the input field
|
||||
*
|
||||
* @param e
|
||||
*/
|
||||
private setCaretOnclick(e: Phaser.Pointer) {
|
||||
var localX: number = (this.text.toLocal(new PIXI.Point(e.x, e.y), this.game.world)).x;
|
||||
if (this.inputOptions.textAlign && this.inputOptions.textAlign === 'center') {
|
||||
localX += this.text.width / 2;
|
||||
}
|
||||
|
||||
var characterWidth: number = this.text.width / this.value.length;
|
||||
var index: number = 0;
|
||||
for (let i: number = 0; i < this.value.length; i++) {
|
||||
if (localX >= i * characterWidth && localX <= (i + 1) * characterWidth) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (localX > (this.value.length - 1) * characterWidth) {
|
||||
index = this.value.length;
|
||||
}
|
||||
|
||||
this.startFocus();
|
||||
|
||||
this.domElement.setCaretPosition(index);
|
||||
|
||||
this.updateCursor();
|
||||
}
|
||||
|
||||
/**
|
||||
* This checks if a select has been made, and if so highlight it with blue
|
||||
*/
|
||||
private updateSelection(): void {
|
||||
if (this.domElement.hasSelection) {
|
||||
var text = this.value;
|
||||
if (this.inputOptions.type === InputType.password) {
|
||||
text = '';
|
||||
for (let i = 0; i < this.value.length; i++) {
|
||||
text += '*';
|
||||
}
|
||||
}
|
||||
text = text.substring(this.domElement.caretStart, this.domElement.caretEnd);
|
||||
this.offscreenText.setText(text);
|
||||
|
||||
this.selection.updateSelection(this.offscreenText.getBounds());
|
||||
|
||||
switch (this.inputOptions.textAlign) {
|
||||
case 'left':
|
||||
this.selection.x = this.inputOptions.padding;
|
||||
break;
|
||||
case 'center':
|
||||
this.selection.x = this.inputOptions.padding + this.inputOptions.width / 2 - this.text.width / 2;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this.selection.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private zoomIn(): void {
|
||||
if (PhaserInput.Zoomed) {
|
||||
return;
|
||||
}
|
||||
|
||||
let bounds: PIXI.Rectangle = this.getBounds();
|
||||
if (window.innerHeight > window.innerWidth) {
|
||||
this.windowScale = this.game.width / (bounds.width * 1.5);
|
||||
} else {
|
||||
this.windowScale = (this.game.width / 2) / (bounds.width * 1.5);
|
||||
}
|
||||
|
||||
let offsetX: number = ((this.game.width - bounds.width * 1.5) / 2) / this.windowScale;
|
||||
this.game.world.scale.set(this.game.world.scale.x * this.windowScale, this.game.world.scale.y * this.windowScale);
|
||||
this.game.world.pivot.set(bounds.x - offsetX, bounds.y - this.inputOptions.padding * 2);
|
||||
PhaserInput.Zoomed = true;
|
||||
}
|
||||
|
||||
private zoomOut(): void {
|
||||
if (!PhaserInput.Zoomed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.game.world.scale.set(this.game.world.scale.x / this.windowScale, this.game.world.scale.y / this.windowScale);
|
||||
this.game.world.pivot.set(0, 0);
|
||||
PhaserInput.Zoomed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event fired when a key is pressed, it takes the value from the hidden input field and adds it as its own
|
||||
*/
|
||||
private keyListener(evt: KeyboardEvent)
|
||||
{
|
||||
this.value = this.getFormattedText(this.domElement.value);
|
||||
if (evt.keyCode === 13) {
|
||||
if(this.focusOutOnEnter) {
|
||||
this.endFocus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateText();
|
||||
this.updateCursor();
|
||||
this.updateSelection();
|
||||
|
||||
evt.preventDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* We overwrite the destroy method because we want to delete the (hidden) dom element when the inputField was removed
|
||||
*/
|
||||
public destroy(destroyChildren?: boolean) {
|
||||
this.game.input.onDown.remove(this.checkDown, this);
|
||||
this.focusIn.removeAll();
|
||||
this.focusOut.removeAll();
|
||||
this.domElement.destroy();
|
||||
|
||||
super.destroy(destroyChildren);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the text to an empty value
|
||||
*/
|
||||
public resetText() {
|
||||
this.setText();
|
||||
}
|
||||
|
||||
public setText(text: string = ''): void {
|
||||
if (null !== this.placeHolder) {
|
||||
if (text.length > 0) {
|
||||
this.placeHolder.visible = false;
|
||||
} else {
|
||||
this.placeHolder.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.value = this.getFormattedText(text);
|
||||
this.domElement.value = this.value;
|
||||
this.updateText();
|
||||
this.updateCursor();
|
||||
this.endFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns text formatted by rules stated in inputOptions
|
||||
* @param text
|
||||
*/
|
||||
private getFormattedText(text: string): string {
|
||||
switch (this.inputOptions.forceCase) {
|
||||
default:
|
||||
case ForceCase.none:
|
||||
return text;
|
||||
case ForceCase.lower:
|
||||
return text.toLowerCase();
|
||||
case ForceCase.upper:
|
||||
return text.toUpperCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
module PhaserInput {
|
||||
export class InputBox extends Phaser.Graphics {
|
||||
private bgColor: number;
|
||||
private borderRadius: number;
|
||||
private borderColor: number;
|
||||
private borderWidth: number;
|
||||
private boxAlpha: number;
|
||||
private boxHeight: number;
|
||||
private padding: number;
|
||||
private boxWidth: number;
|
||||
|
||||
constructor(game: Phaser.Game, inputOptions: InputOptions) {
|
||||
super(game, 0, 0);
|
||||
|
||||
this.bgColor = (inputOptions.backgroundColor) ? parseInt(inputOptions.backgroundColor.slice(1), 16) : 0xffffff;
|
||||
this.borderRadius = inputOptions.borderRadius || 0;
|
||||
this.borderWidth = inputOptions.borderWidth || 1;
|
||||
this.borderColor = (inputOptions.borderColor) ? parseInt(inputOptions.borderColor.slice(1), 16) : 0x959595;
|
||||
this.boxAlpha = inputOptions.fillAlpha;
|
||||
this.padding = inputOptions.padding;
|
||||
|
||||
var height: number = inputOptions.height;
|
||||
var width: number = inputOptions.width;
|
||||
|
||||
var height: number;
|
||||
if (inputOptions.font) {
|
||||
//fetch height from font;
|
||||
height = Math.max(parseInt(inputOptions.font.substr(0, inputOptions.font.indexOf('px')), 10), height);
|
||||
}
|
||||
|
||||
this.boxHeight = this.padding * 2 + height;
|
||||
var width = inputOptions.width;
|
||||
this.boxWidth = this.padding * 2 + width;
|
||||
|
||||
this.drawBox();
|
||||
}
|
||||
|
||||
public resize(newWidth: number): void {
|
||||
this.boxWidth = this.padding * 2 + newWidth;
|
||||
|
||||
this.drawBox();
|
||||
}
|
||||
|
||||
private drawBox(): void {
|
||||
this.clear()
|
||||
.beginFill(this.bgColor, this.boxAlpha)
|
||||
.lineStyle(this.borderWidth, this.borderColor, this.boxAlpha);
|
||||
|
||||
if (this.borderRadius > 0) {
|
||||
this.drawRoundedRect(0, 0, this.boxWidth, this.boxHeight, this.borderRadius);
|
||||
} else {
|
||||
this.drawRect(0, 0, this.boxWidth, this.boxHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
module PhaserInput {
|
||||
export class SelectionHighlight extends Phaser.Graphics {
|
||||
private inputOptions: InputOptions;
|
||||
|
||||
constructor(game: Phaser.Game, inputOptions: InputOptions) {
|
||||
super(game, inputOptions.padding, inputOptions.padding);
|
||||
|
||||
this.inputOptions = inputOptions;
|
||||
}
|
||||
|
||||
public updateSelection(rect: PIXI.Rectangle): void {
|
||||
var color = Phaser.Color.webToColor(this.inputOptions.selectionColor);
|
||||
|
||||
this.clear();
|
||||
this.beginFill(SelectionHighlight.rgb2hex(color), color.a);
|
||||
this.drawRect(rect.x, rect.y, rect.width, rect.height - this.inputOptions.padding);
|
||||
}
|
||||
|
||||
public static rgb2hex(color: {r: number, g: number, b: number, a: number}): number {
|
||||
return parseInt(("0" + color.r.toString(16)).slice(-2) +
|
||||
("0" + color.g.toString(16)).slice(-2) +
|
||||
("0" + color.b.toString(16)).slice(-2), 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
module PhaserInput {
|
||||
export class TextMask extends Phaser.Graphics {
|
||||
private maskWidth: number;
|
||||
private maskHeight: number;
|
||||
|
||||
constructor(game: Phaser.Game, inputOptions: InputOptions) {
|
||||
super(game, inputOptions.padding, inputOptions.padding);
|
||||
|
||||
var height = inputOptions.height;
|
||||
|
||||
if (inputOptions.font) {
|
||||
//fetch height from font;
|
||||
height = Math.max(parseInt(inputOptions.font.substr(0, inputOptions.font.indexOf('px')), 10), height);
|
||||
}
|
||||
this.maskWidth = inputOptions.width;
|
||||
this.maskHeight = height * 1.3;
|
||||
this.drawMask();
|
||||
}
|
||||
|
||||
public resize(newWidth: number): void {
|
||||
this.maskWidth = newWidth;
|
||||
this.drawMask();
|
||||
}
|
||||
|
||||
private drawMask(): void {
|
||||
this.clear()
|
||||
.beginFill(0x000000)
|
||||
.drawRect(0, 0, this.maskWidth, this.maskHeight)
|
||||
.endFill();
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
module PhaserInput {
|
||||
export var Zoomed: boolean = false;
|
||||
export var KeyboardOpen: boolean = false;
|
||||
export const onKeyboardOpen: Phaser.Signal = new Phaser.Signal();
|
||||
export const onKeyboardClose: Phaser.Signal = new Phaser.Signal()
|
||||
|
||||
export interface InputFieldObjectFactory extends Phaser.GameObjectFactory {
|
||||
inputField: (x: number, y: number, inputOptions?: PhaserInput.InputOptions, group?: Phaser.Group) => PhaserInput.InputField;
|
||||
}
|
||||
|
||||
export interface InputFieldObjectCreator extends Phaser.GameObjectCreator {
|
||||
inputField: (x: number, y: number, inputOptions?: PhaserInput.InputOptions) => PhaserInput.InputField;
|
||||
}
|
||||
|
||||
export interface InputFieldGame extends Phaser.Game {
|
||||
add: InputFieldObjectFactory;
|
||||
make: InputFieldObjectCreator;
|
||||
}
|
||||
|
||||
export class Plugin extends Phaser.Plugin {
|
||||
public static Zoomed: boolean = false;
|
||||
public static KeyboardOpen: boolean = false;
|
||||
public static onKeyboardOpen: Phaser.Signal = new Phaser.Signal();
|
||||
public static onKeyboardClose: Phaser.Signal = new Phaser.Signal();
|
||||
|
||||
constructor(game: Phaser.Game, parent: Phaser.PluginManager) {
|
||||
super(game, parent);
|
||||
|
||||
this.addInputFieldFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends the GameObjectFactory prototype with the support of adding InputField. this allows us to add InputField methods to the game just like any other object:
|
||||
* game.add.InputField();
|
||||
*/
|
||||
private addInputFieldFactory() {
|
||||
(<PhaserInput.InputFieldObjectFactory>Phaser.GameObjectFactory.prototype).inputField = function (x: number, y: number, inputOptions: PhaserInput.InputOptions, group?: Phaser.Group): PhaserInput.InputField {
|
||||
if (group === undefined) {
|
||||
group = this.world;
|
||||
}
|
||||
|
||||
var nineSliceObject = new PhaserInput.InputField(this.game, x, y, inputOptions);
|
||||
|
||||
return group.add(nineSliceObject);
|
||||
};
|
||||
|
||||
(<PhaserInput.InputFieldObjectCreator>Phaser.GameObjectCreator.prototype).inputField = function (x: number, y: number, inputOptions: PhaserInput.InputOptions): PhaserInput.InputField {
|
||||
return new PhaserInput.InputField(this.game, x, y, inputOptions);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
/// <reference path='../node_modules/phaser/typescript/pixi.d.ts'/>
|
||||
/// <reference path='../node_modules/phaser/typescript/phaser.d.ts'/>
|
||||
Reference in New Issue
Block a user