Merge pull request #1298 from pnp/react-word-game-2
This commit is contained in:
commit
f2027a9dc1
|
@ -8,28 +8,24 @@ import {
|
||||||
PropertyPaneCheckbox
|
PropertyPaneCheckbox
|
||||||
} from '@microsoft/sp-webpart-base';
|
} from '@microsoft/sp-webpart-base';
|
||||||
|
|
||||||
import * as strings from 'WordGameWebPartStrings';
|
|
||||||
import WordGame from './components/WordGame';
|
import WordGame from './components/WordGame';
|
||||||
import { IWordGameProps } from './components/IWordGameProps';
|
import { IWordGameProps } from './components/IWordGameProps';
|
||||||
import { WordService } from './components/WordService';
|
|
||||||
|
|
||||||
export interface IWordGameWebPartProps {
|
export interface IWordGameWebPartProps {
|
||||||
gameTitle: string;
|
gameTitle: string;
|
||||||
enableHighScores: boolean
|
enableHighScores: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class WordGameWebPart extends BaseClientSideWebPart<IWordGameWebPartProps> {
|
export default class WordGameWebPart extends BaseClientSideWebPart<IWordGameWebPartProps> {
|
||||||
|
|
||||||
wordGame: WordGame;
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): void {
|
public render(): void {
|
||||||
if (!this.properties.gameTitle)
|
if (!this.properties.gameTitle) {
|
||||||
this.properties.gameTitle='Word Game';
|
this.properties.gameTitle = 'Word Game';
|
||||||
if (this.properties.enableHighScores==null)
|
}
|
||||||
this.properties.enableHighScores=true;
|
|
||||||
|
if (this.properties.enableHighScores === undefined) {
|
||||||
|
this.properties.enableHighScores = true;
|
||||||
|
}
|
||||||
|
|
||||||
const element: React.ReactElement<IWordGameProps> = React.createElement(
|
const element: React.ReactElement<IWordGameProps> = React.createElement(
|
||||||
WordGame,
|
WordGame,
|
||||||
|
@ -40,9 +36,7 @@ export default class WordGameWebPart extends BaseClientSideWebPart<IWordGameWebP
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
ReactDom.render(element, this.domElement);
|
ReactDom.render(element, this.domElement);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onDispose(): void {
|
protected onDispose(): void {
|
||||||
|
@ -53,9 +47,9 @@ export default class WordGameWebPart extends BaseClientSideWebPart<IWordGameWebP
|
||||||
return Version.parse('1.0');
|
return Version.parse('1.0');
|
||||||
}
|
}
|
||||||
|
|
||||||
//only refresh render after applying settings pane
|
// only refresh render after applying settings pane
|
||||||
protected get disableReactivePropertyChanges(): boolean {
|
protected get disableReactivePropertyChanges(): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||||
|
@ -74,7 +68,7 @@ export default class WordGameWebPart extends BaseClientSideWebPart<IWordGameWebP
|
||||||
}),
|
}),
|
||||||
PropertyPaneTextField('gameTitle', {
|
PropertyPaneTextField('gameTitle', {
|
||||||
label: 'Game Title'
|
label: 'Game Title'
|
||||||
}),
|
})
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { WordGameListItem } from "./WordService";
|
import { WordGameListItem } from './WordService';
|
||||||
import { GameState } from "./WordGame";
|
import { GameState } from './WordGame';
|
||||||
import { WebPartContext } from "@microsoft/sp-webpart-base";
|
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||||
|
|
||||||
export interface IWordGameProps {
|
export interface IWordGameProps {
|
||||||
description: string;
|
description: string;
|
||||||
|
@ -19,5 +19,4 @@ export interface IWordGameState {
|
||||||
lblMessage: string;
|
lblMessage: string;
|
||||||
highScores: WordGameListItem[];
|
highScores: WordGameListItem[];
|
||||||
mobileMode: boolean;
|
mobileMode: boolean;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import styles from './WordGame.module.scss';
|
import styles from './WordGame.module.scss';
|
||||||
import { IWordGameProps, IWordGameState } from './IWordGameProps';
|
import { IWordGameProps, IWordGameState } from './IWordGameProps';
|
||||||
import { escape, round } from '@microsoft/sp-lodash-subset';
|
|
||||||
import { WordService, Game } from './WordService';
|
import { WordService, Game } from './WordService';
|
||||||
import { Ref } from 'react';
|
|
||||||
import { WordGameListItem } from './WordService';
|
|
||||||
import WordHighScores from './WordHighScores';
|
import WordHighScores from './WordHighScores';
|
||||||
|
import { WordGameListItem } from '../../../../lib/webparts/wordGame/components/WordService';
|
||||||
|
|
||||||
|
// tslint:disable-next-line: no-any
|
||||||
const logo: any = require('../assets/ajax-loader.gif');
|
const logo: any = require('../assets/ajax-loader.gif');
|
||||||
require('./anims.css');
|
require('./anims.css');
|
||||||
|
|
||||||
|
@ -17,13 +17,7 @@ export enum GameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class WordGame extends React.Component<IWordGameProps, IWordGameState> {
|
export default class WordGame extends React.Component<IWordGameProps, IWordGameState> {
|
||||||
|
public state: IWordGameState =
|
||||||
wordService: WordService = new WordService();
|
|
||||||
currentGame: Game;
|
|
||||||
timerInterval: number = -1;
|
|
||||||
numTimer: number;
|
|
||||||
|
|
||||||
state: IWordGameState =
|
|
||||||
{
|
{
|
||||||
gamestate: GameState.GameLoading,
|
gamestate: GameState.GameLoading,
|
||||||
currentWord: '',
|
currentWord: '',
|
||||||
|
@ -37,6 +31,12 @@ export default class WordGame extends React.Component<IWordGameProps, IWordGameS
|
||||||
mobileMode: false
|
mobileMode: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private messageCounter: number = 0;
|
||||||
|
private wordService: WordService = new WordService();
|
||||||
|
private currentGame: Game;
|
||||||
|
private timerInterval: number = -1;
|
||||||
|
private numTimer: number;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
@ -44,81 +44,233 @@ export default class WordGame extends React.Component<IWordGameProps, IWordGameS
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
public async componentDidMount(): Promise<void> {
|
||||||
this.wordService.SetContext(this.props.context);
|
this.wordService.SetContext(this.props.context);
|
||||||
await this.wordService.loadWords();
|
await this.wordService.loadWords();
|
||||||
|
|
||||||
if (window.innerWidth<600)
|
if (window.innerWidth < 600) {
|
||||||
this.setState({mobileMode:true})
|
this.setState({ mobileMode: true });
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
gamestate: GameState.Title,
|
gamestate: GameState.Title
|
||||||
} as IWordGameState);
|
} as IWordGameState);
|
||||||
|
|
||||||
this.getHighScores();
|
this.getHighScores();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async redraw() {
|
public render(): React.ReactElement<IWordGameProps> {
|
||||||
this.forceUpdate();
|
// tslint:disable-next-line: no-string-literal
|
||||||
|
window['wordgame'] = this;
|
||||||
|
|
||||||
|
let body: JSX.Element;
|
||||||
|
switch (this.state.gamestate) {
|
||||||
|
case GameState.Title:
|
||||||
|
body =
|
||||||
|
<div>
|
||||||
|
<h1>{this.props.description}</h1>
|
||||||
|
{/* <h1>Word Game</h1> */}
|
||||||
|
{/* <h4>Count: {this.wordService.GetWordCount()}</h4> */}
|
||||||
|
<p>Unscramble as many words as you can before the time runs out</p>
|
||||||
|
<button className='blueButton' onClick={this.btnStartGame.bind(this)}>
|
||||||
|
Start Game
|
||||||
|
</button>
|
||||||
|
{
|
||||||
|
this.props.enableHighScores ?
|
||||||
|
<WordHighScores scores={this.state.highScores}></WordHighScores> : ''
|
||||||
|
}
|
||||||
|
</div>;
|
||||||
|
break;
|
||||||
|
case GameState.GameLoading:
|
||||||
|
body =
|
||||||
|
<div>
|
||||||
|
<img src={logo} alt='Loading...' />
|
||||||
|
<span style={{ marginLeft: '15px' }}>
|
||||||
|
Loading...
|
||||||
|
</span>
|
||||||
|
</div>;
|
||||||
|
break;
|
||||||
|
case GameState.GamePlaying:
|
||||||
|
body =
|
||||||
|
<div>
|
||||||
|
<div className='currentWord' style={{ position: 'relative' }}>
|
||||||
|
{this.state.currentWord}
|
||||||
|
{/* MOBILE TOAST */}
|
||||||
|
{
|
||||||
|
this.state.lblMessage !== '' && this.state.mobileMode ?
|
||||||
|
<div className={this.state.lblMessage === 'Incorrect' ?
|
||||||
|
'toastMiniRed word-fade-in'
|
||||||
|
: 'toastMiniGreen word-fade-in'}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
left: '0',
|
||||||
|
right: '0',
|
||||||
|
fontSize: '10pt',
|
||||||
|
top: '83px',
|
||||||
|
padding: '0'
|
||||||
|
}}>
|
||||||
|
{
|
||||||
|
this.state.lblMessage
|
||||||
|
}
|
||||||
|
</div> : ''
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<meta name='viewport'
|
||||||
|
content='width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=0'></meta>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
autoFocus={true}
|
||||||
|
placeholder='Enter Answer'
|
||||||
|
id='txtWordGameAnswer'
|
||||||
|
autoComplete='off'
|
||||||
|
autoCapitalize='off'
|
||||||
|
autoCorrect='off'
|
||||||
|
spellCheck={false}
|
||||||
|
value={this.state.txtAnswer}
|
||||||
|
onChange={this.answerChanged.bind(this)}
|
||||||
|
onKeyDown={this.keyDownAnswer.bind(this)} />
|
||||||
|
<div className='numAnswersTip'>{this.state.possibleAnswersText}</div>
|
||||||
|
<table style={{ marginLeft: 'Auto', marginRight: 'Auto' }}>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<button className='blueButton' style={{ marginTop: '20px' }} onClick={this.btnAnswer.bind(this)}>
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button className='greyButton' onClick={this.btnSkip.bind(this)} style={{ marginTop: '20px' }} >
|
||||||
|
Skip
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div className='timer'>{this.state.lblTimer}</div>
|
||||||
|
{/* DESKTOP TOAST */}
|
||||||
|
{
|
||||||
|
this.state.lblMessage !== '' && !this.state.mobileMode ?
|
||||||
|
<div className='toast word-fade-in' >
|
||||||
|
<div
|
||||||
|
className={this.state.lblMessage === 'Incorrect'
|
||||||
|
? 'toastRed' : 'toastGreen'}>{this.state.lblMessage}</div>
|
||||||
|
</div> : ''
|
||||||
|
}
|
||||||
|
</div>;
|
||||||
|
break;
|
||||||
|
case GameState.GameFinished:
|
||||||
|
|
||||||
|
body =
|
||||||
|
<div>
|
||||||
|
<h1>Well done! Score {this.state.score} out of 6</h1>
|
||||||
|
<p>See answers below to the current round</p>
|
||||||
|
<button className='blueButton' onClick={this.btnStartGame.bind(this)}
|
||||||
|
style={{ marginBottom: '20px' }}>Play Again</button>
|
||||||
|
<div className='gameReview'>
|
||||||
|
<ul>
|
||||||
|
{
|
||||||
|
this.currentGame.rounds.map(round => (
|
||||||
|
<li key={round.word + '_wordgame_word'}><b>Word </b><span>{round.word}</span>
|
||||||
|
{
|
||||||
|
round.answers.map(answer => (
|
||||||
|
<ul key={answer + '_wordgame_answer'}>
|
||||||
|
<b>Answer </b> {answer}
|
||||||
|
{
|
||||||
|
round.correctAnswer === answer ?
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
style={{
|
||||||
|
marginLeft: '5px'
|
||||||
|
}}
|
||||||
|
width='15'
|
||||||
|
height='15'
|
||||||
|
viewBox='0 0 24 24'
|
||||||
|
color='#155724'>
|
||||||
|
<path
|
||||||
|
fill='currentcolor'
|
||||||
|
d='M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z' /></svg>
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
this.props.enableHighScores ?
|
||||||
|
<WordHighScores scores={this.state.highScores}></WordHighScores> : ''
|
||||||
|
}
|
||||||
|
</div>;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const maindiv: JSX.Element = <div className='wordGameCustom' style={{ position: 'relative' }}>{body}</div>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.wordGame} style={{ textAlign: 'center' }} >
|
||||||
|
{maindiv}
|
||||||
|
</div >
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
answerChanged(event) {
|
// private async redraw(): Promise<void> {
|
||||||
|
// this.forceUpdate();
|
||||||
|
// }
|
||||||
|
|
||||||
|
private answerChanged(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||||
this.setState({ txtAnswer: event.target.value } as IWordGameState);
|
this.setState({ txtAnswer: event.target.value } as IWordGameState);
|
||||||
}
|
}
|
||||||
|
|
||||||
messageCounter = 0;
|
private showMessage(message: string): void {
|
||||||
|
|
||||||
showMessage(message: string) {
|
|
||||||
this.setState({ lblMessage: message } as IWordGameState);
|
this.setState({ lblMessage: message } as IWordGameState);
|
||||||
this.messageCounter = 3;
|
this.messageCounter = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
async btnAnswer() {
|
private async btnAnswer(): Promise<void> {
|
||||||
let answerFound: boolean = false;
|
let answerFound: boolean = false;
|
||||||
|
|
||||||
this.currentGame.rounds[this.state.currentRound].answers.forEach(answer => {
|
this.currentGame.rounds[this.state.currentRound].answers.forEach(answer => {
|
||||||
if (answer.toLowerCase() == this.state.txtAnswer.toLowerCase()) {
|
if (answer.toLowerCase() === this.state.txtAnswer.toLowerCase()) {
|
||||||
this.currentGame.rounds[this.state.currentRound].correctAnswer = this.state.txtAnswer;
|
this.currentGame.rounds[this.state.currentRound].correctAnswer = this.state.txtAnswer;
|
||||||
this.numTimer += 5;
|
this.numTimer += 5;
|
||||||
this.showMessage('Correct!! +5 Seconds');
|
this.showMessage('Correct!! +5 Seconds');
|
||||||
this.setState({
|
this.setState({
|
||||||
lblTimer: this.numTimer + " seconds",
|
lblTimer: this.numTimer + ' seconds',
|
||||||
score: this.state.score + 1
|
score: this.state.score + 1
|
||||||
} as IWordGameState);
|
} as IWordGameState);
|
||||||
answerFound = true;
|
answerFound = true;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!answerFound) {
|
if (!answerFound) {
|
||||||
this.showMessage('Incorrect');
|
this.showMessage('Incorrect');
|
||||||
this.currentGame.rounds[this.state.currentRound].incorrectAnswers.push(this.state.txtAnswer);
|
this.currentGame.rounds[this.state.currentRound].incorrectAnswers.push(this.state.txtAnswer);
|
||||||
this.setState({ txtAnswer: '' } as IWordGameState);
|
this.setState({ txtAnswer: '' } as IWordGameState);
|
||||||
this.focusOnTextbox();
|
this.focusOnTextbox();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
this.nextRound();
|
this.nextRound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
btnSkip() {
|
private btnSkip(): void {
|
||||||
this.nextRound();
|
this.nextRound();
|
||||||
this.focusOnTextbox();
|
this.focusOnTextbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
async nextRound() {
|
private async nextRound(): Promise<void> {
|
||||||
|
// state doesn't modify immediately
|
||||||
//state doesn't modify immediately
|
|
||||||
await this.setState({
|
await this.setState({
|
||||||
txtAnswer: '',
|
txtAnswer: '',
|
||||||
currentRound: this.state.currentRound + 1,
|
currentRound: this.state.currentRound + 1
|
||||||
} as IWordGameState);
|
} as IWordGameState);
|
||||||
|
|
||||||
if (this.state.currentRound >= this.currentGame.rounds.length) {
|
if (this.state.currentRound >= this.currentGame.rounds.length) {
|
||||||
this.finishGame();
|
this.finishGame();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
currentWord: this.currentGame.rounds[this.state.currentRound].word,
|
currentWord: this.currentGame.rounds[this.state.currentRound].word,
|
||||||
possibleAnswersText: this.getPossibleAnswersText(this.state.currentRound)
|
possibleAnswersText: this.getPossibleAnswersText(this.state.currentRound)
|
||||||
|
@ -126,59 +278,61 @@ export default class WordGame extends React.Component<IWordGameProps, IWordGameS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getPossibleAnswersText(currentRound:number):string{
|
private getPossibleAnswersText(currentRound: number): string {
|
||||||
let possibleAnswers = this.currentGame.rounds[currentRound].answers.length;
|
const possibleAnswers: number = this.currentGame.rounds[currentRound].answers.length;
|
||||||
let possibleAnswersText = possibleAnswers + ' Possible Answer';
|
let possibleAnswersText: string = possibleAnswers + ' Possible Answer';
|
||||||
if (possibleAnswers>1)
|
if (possibleAnswers > 1) {
|
||||||
possibleAnswersText = possibleAnswers + ' Possible Answers';
|
possibleAnswersText = possibleAnswers + ' Possible Answers';
|
||||||
return possibleAnswersText
|
}
|
||||||
|
return possibleAnswersText;
|
||||||
}
|
}
|
||||||
|
|
||||||
focusOnTextbox() {
|
private focusOnTextbox(): void {
|
||||||
let element = document.getElementById('txtWordGameAnswer');
|
const element: HTMLElement = document.getElementById('txtWordGameAnswer');
|
||||||
if (element)
|
if (element) {
|
||||||
element.focus();
|
element.focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
finishGame() {
|
private finishGame(): void {
|
||||||
this.sendScore(this.state.score, this.numTimer, JSON.stringify(this.currentGame));
|
this.sendScore(this.state.score, this.numTimer, JSON.stringify(this.currentGame));
|
||||||
this.stopTimer();
|
this.stopTimer();
|
||||||
this.setState({ gamestate: GameState.GameFinished } as IWordGameState);
|
this.setState({ gamestate: GameState.GameFinished } as IWordGameState);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendScore(score: number, seconds: number, details: string) {
|
private async sendScore(score: number, seconds: number, details: string): Promise<void> {
|
||||||
if (!this.props.enableHighScores)
|
if (!this.props.enableHighScores) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
await this.wordService.SubmitScore(score, seconds, details);
|
await this.wordService.SubmitScore(score, seconds, details);
|
||||||
this.getHighScores();
|
this.getHighScores();
|
||||||
}
|
}
|
||||||
|
|
||||||
async getHighScores(){
|
private async getHighScores(): Promise<void> {
|
||||||
if (!this.props.enableHighScores)
|
if (!this.props.enableHighScores) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let scores = await this.wordService.GetHighScores();
|
const scores: WordGameListItem[] = await this.wordService.GetHighScores();
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
highScores: scores
|
highScores: scores
|
||||||
} as IWordGameState);
|
} as IWordGameState);
|
||||||
}
|
}
|
||||||
|
|
||||||
keyDownAnswer(event: React.KeyboardEvent<HTMLInputElement>) {
|
private keyDownAnswer(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||||
if (event.keyCode == 13)
|
if (event.keyCode === 13) {
|
||||||
this.btnAnswer();
|
this.btnAnswer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async btnStartGame(): Promise<void> {
|
||||||
async btnStartGame() {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
gamestate: GameState.GameLoading
|
gamestate: GameState.GameLoading
|
||||||
} as IWordGameState);
|
} as IWordGameState);
|
||||||
|
|
||||||
this.currentGame = this.wordService.GenerateGame();
|
this.currentGame = this.wordService.GenerateGame();
|
||||||
|
|
||||||
|
|
||||||
await new Promise<void>(resolve => { setTimeout(resolve, 1000); });
|
await new Promise<void>(resolve => { setTimeout(resolve, 1000); });
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -192,159 +346,30 @@ export default class WordGame extends React.Component<IWordGameProps, IWordGameS
|
||||||
} as IWordGameState);
|
} as IWordGameState);
|
||||||
|
|
||||||
this.numTimer = 30;
|
this.numTimer = 30;
|
||||||
this.setState({ lblTimer: this.numTimer + " seconds" });
|
this.setState({ lblTimer: this.numTimer + ' seconds' });
|
||||||
this.timerInterval = setInterval(this.timerTick.bind(this), 1000);
|
this.timerInterval = setInterval(this.timerTick.bind(this), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
timerTick() {
|
private timerTick(): void {
|
||||||
//for debugging
|
// for debugging
|
||||||
// if (this.numTimer>25)
|
// if (this.numTimer>25)
|
||||||
this.numTimer--;
|
this.numTimer--;
|
||||||
this.setState({ lblTimer: this.numTimer + " seconds" });
|
this.setState({ lblTimer: this.numTimer + ' seconds' });
|
||||||
if (this.numTimer == 0) {
|
if (this.numTimer === 0) {
|
||||||
this.finishGame();
|
this.finishGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
//toast messages
|
// toast messages
|
||||||
if (this.messageCounter > 0) {
|
if (this.messageCounter > 0) {
|
||||||
this.messageCounter--;
|
this.messageCounter--;
|
||||||
if (this.messageCounter == 0)
|
if (this.messageCounter === 0) {
|
||||||
this.setState({ lblMessage: '' } as IWordGameState);
|
this.setState({ lblMessage: '' } as IWordGameState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stopTimer() {
|
private stopTimer(): void {
|
||||||
this.setState({ lblTimer: '' });
|
this.setState({ lblTimer: '' });
|
||||||
clearInterval(this.timerInterval);
|
clearInterval(this.timerInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): React.ReactElement<IWordGameProps> {
|
|
||||||
window["wordgame"] = this;
|
|
||||||
|
|
||||||
|
|
||||||
let body: JSX.Element;
|
|
||||||
switch (this.state.gamestate) {
|
|
||||||
case GameState.Title:
|
|
||||||
body =
|
|
||||||
<div>
|
|
||||||
<h1>{this.props.description}</h1>
|
|
||||||
{/* <h1>Word Game</h1> */}
|
|
||||||
{/* <h4>Count: {this.wordService.GetWordCount()}</h4> */}
|
|
||||||
<p>Unscramble as many words as you can before the time runs out</p>
|
|
||||||
<button className="blueButton" onClick={this.btnStartGame.bind(this)}>
|
|
||||||
Start Game
|
|
||||||
</button>
|
|
||||||
{
|
|
||||||
this.props.enableHighScores ?
|
|
||||||
<WordHighScores scores={this.state.highScores}></WordHighScores> : ''
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
break;
|
|
||||||
case GameState.GameLoading:
|
|
||||||
body =
|
|
||||||
<div>
|
|
||||||
<img src={logo} />
|
|
||||||
<span style={{ marginLeft: '15px' }}>
|
|
||||||
Loading...
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
break;
|
|
||||||
case GameState.GamePlaying:
|
|
||||||
body =
|
|
||||||
<div>
|
|
||||||
<div className="currentWord" style={{position:"relative"}}>
|
|
||||||
{this.state.currentWord}
|
|
||||||
{/* MOBILE TOAST */}
|
|
||||||
{
|
|
||||||
this.state.lblMessage != '' && this.state.mobileMode?
|
|
||||||
<div className={this.state.lblMessage == 'Incorrect' ? 'toastMiniRed word-fade-in' : 'toastMiniGreen word-fade-in'}
|
|
||||||
style={{position:"absolute",left:"0",right:"0",fontSize:"10pt",top:"83px",padding:"0"}}>
|
|
||||||
{
|
|
||||||
this.state.lblMessage
|
|
||||||
}
|
|
||||||
</div> : ''
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=0"></meta>
|
|
||||||
<input type="text" autoFocus={true} placeholder="Enter Answer" id="txtWordGameAnswer"
|
|
||||||
autoComplete="off" autoCapitalize="off" autoCorrect="off" spellCheck={false}
|
|
||||||
value={this.state.txtAnswer} onChange={this.answerChanged.bind(this)} onKeyDown={this.keyDownAnswer.bind(this)} />
|
|
||||||
<div className="numAnswersTip">{this.state.possibleAnswersText}</div>
|
|
||||||
<table style={{ marginLeft: 'Auto', marginRight: 'Auto' }}>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<button className="blueButton" style={{ marginTop: '20px' }} onClick={this.btnAnswer.bind(this)}>
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<button className="greyButton" onClick={this.btnSkip.bind(this)} style={{ marginTop: '20px' }} >
|
|
||||||
Skip
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div className="timer">{this.state.lblTimer}</div>
|
|
||||||
{/* DESKTOP TOAST */}
|
|
||||||
{
|
|
||||||
this.state.lblMessage != '' && !this.state.mobileMode?
|
|
||||||
<div className="toast word-fade-in" >
|
|
||||||
<div className={this.state.lblMessage == 'Incorrect' ? 'toastRed' : 'toastGreen'}>{this.state.lblMessage}</div>
|
|
||||||
</div> : ''
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
break;
|
|
||||||
case GameState.GameFinished:
|
|
||||||
|
|
||||||
body =
|
|
||||||
<div>
|
|
||||||
<h1>Well done! Score {this.state.score} out of 6</h1>
|
|
||||||
<p>See answers below to the current round</p>
|
|
||||||
<button className="blueButton" onClick={this.btnStartGame.bind(this)}
|
|
||||||
style={{ marginBottom: '20px' }}>Play Again</button>
|
|
||||||
<div className="gameReview">
|
|
||||||
<ul>
|
|
||||||
{
|
|
||||||
this.currentGame.rounds.map(round => (
|
|
||||||
<li key={round.word + '_wordgame_word'}><b>Word </b><span>{round.word}</span>
|
|
||||||
{
|
|
||||||
round.answers.map(answer => (
|
|
||||||
<ul key={answer + '_wordgame_answer'}>
|
|
||||||
<b>Answer </b> {answer}
|
|
||||||
{
|
|
||||||
round.correctAnswer == answer ?
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px' }} width="15" height="15" viewBox="0 0 24 24" color="#155724">
|
|
||||||
<path fill="currentcolor" d="M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z" /></svg>
|
|
||||||
: ''
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</li>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{
|
|
||||||
this.props.enableHighScores ?
|
|
||||||
<WordHighScores scores={this.state.highScores}></WordHighScores> : ''
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
let maindiv = <div className="wordGameCustom" style={{ position: 'relative' }}>{body}</div>;
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.wordGame} style={{ textAlign: 'center' }} >
|
|
||||||
{maindiv}
|
|
||||||
</div >
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +1,40 @@
|
||||||
import * as React from "react";
|
import * as React from 'react';
|
||||||
import { WordGameListItem } from "./WordService"
|
import { WordGameListItem } from './WordService';
|
||||||
|
|
||||||
export interface IWordHighScoresProps {
|
export interface IWordHighScoresProps {
|
||||||
scores: WordGameListItem[]
|
scores: WordGameListItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class WordHighScores extends React.Component<IWordHighScoresProps, {}> {
|
export default class WordHighScores extends React.Component<IWordHighScoresProps, {}> {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): React.ReactElement<IWordHighScoresProps> {
|
public render(): React.ReactElement<IWordHighScoresProps> {
|
||||||
let rank = 1;
|
let rank: number = 1;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
this.props.scores.length>0 ?
|
this.props.scores.length > 0 ?
|
||||||
<h3 style={{ textDecoration: 'underline' }}>High Scores</h3> : ''
|
<h3 style={{ textDecoration: 'underline' }}>High Scores</h3> : ''
|
||||||
|
}
|
||||||
}
|
<table style={{ marginLeft: 'Auto', marginRight: 'Auto' }}>
|
||||||
<table style={{ marginLeft: 'Auto', marginRight: 'Auto' }}>
|
<tbody>
|
||||||
<tbody>
|
{
|
||||||
{
|
this.props.scores.map(score => (
|
||||||
this.props.scores.map(score => (
|
<tr>
|
||||||
<tr>
|
<td><b>{rank++ + ') '}</b></td>
|
||||||
<td><b>{rank++ + ') '}</b></td>
|
<td><b>{score.Name} </b></td>
|
||||||
<td><b>{score.Name} </b></td>
|
<td><span style={{ marginLeft: '10px' }}>Score: {score.Score} </span></td>
|
||||||
<td><span style={{ marginLeft: '10px' }}>Score: {score.Score} </span></td>
|
<td><span style={{ marginLeft: '10px' }}>Seconds: {score.Seconds}</span></td>
|
||||||
<td><span style={{ marginLeft: '10px' }}>Seconds: {score.Seconds}</span></td>
|
</tr>
|
||||||
</tr>
|
))
|
||||||
))
|
}
|
||||||
}
|
</tbody>
|
||||||
</tbody>
|
</table>
|
||||||
</table>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,78 +1,110 @@
|
||||||
// import * as $ from '../assets/jquery.min';
|
// import * as $ from '../assets/jquery.min';
|
||||||
import { SPComponentLoader } from '@microsoft/sp-loader';
|
|
||||||
import WordGame from './WordGame';
|
|
||||||
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||||
import {
|
import {
|
||||||
SPHttpClient,
|
SPHttpClient,
|
||||||
SPHttpClientResponse,
|
SPHttpClientResponse,
|
||||||
HttpClientConfiguration,
|
|
||||||
ISPHttpClientOptions
|
ISPHttpClientOptions
|
||||||
} from '@microsoft/sp-http';
|
} from '@microsoft/sp-http';
|
||||||
|
|
||||||
|
// tslint:disable-next-line: no-any
|
||||||
const wordjpg: any = require('../assets/wordlist.jpg');
|
const wordjpg: any = require('../assets/wordlist.jpg');
|
||||||
|
|
||||||
|
// tslint:disable-next-line: no-any
|
||||||
const $: any = require('../assets/jquery.min');
|
const $: any = require('../assets/jquery.min');
|
||||||
// const wordlist: any = require('../assets/wordlist.json');
|
|
||||||
|
|
||||||
export class Game
|
export class Game {
|
||||||
{
|
public rounds: Round[] = [];
|
||||||
rounds:Round[] = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Round
|
export class Round {
|
||||||
{
|
public word: string = '';
|
||||||
word = "";
|
public answers: string[] = [];
|
||||||
answers:string[] = [];
|
public correctAnswer: string = '';
|
||||||
correctAnswer = "";
|
public incorrectAnswers: string[] = [];
|
||||||
incorrectAnswers:string[] = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class WordGameListItem {
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
public Name: string;
|
||||||
|
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
public Score: number;
|
||||||
|
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
public Seconds: number;
|
||||||
|
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
public Details: string;
|
||||||
|
|
||||||
|
constructor(name: string, score: number, seconds: number, details: string) {
|
||||||
|
this.Name = name;
|
||||||
|
this.Score = score;
|
||||||
|
this.Seconds = seconds;
|
||||||
|
this.Details = details;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class WordService {
|
export class WordService {
|
||||||
|
public allwords: string[] = [];
|
||||||
|
public words3: string[] = [];
|
||||||
|
public words4: string[] = [];
|
||||||
|
public words5: string[] = [];
|
||||||
|
public words6: string[] = [];
|
||||||
|
public words7: string[] = [];
|
||||||
|
public words8: string[] = [];
|
||||||
|
public context: WebPartContext;
|
||||||
|
|
||||||
allwords: string[] = [];
|
public GenerateGame(): Game {
|
||||||
words3: string[] = [];
|
|
||||||
words4: string[] = [];
|
|
||||||
words5: string[] = [];
|
|
||||||
words6: string[] = [];
|
|
||||||
words7: string[] = [];
|
|
||||||
words8: string[] = [];
|
|
||||||
context:WebPartContext;
|
|
||||||
|
|
||||||
GenerateGame():Game
|
const game: Game = new Game();
|
||||||
{
|
|
||||||
|
|
||||||
let game = new Game();
|
const round1: Round = new Round();
|
||||||
|
round1.word = this.GetRandomScrambledWord(5);
|
||||||
|
round1.answers = this.FindPossibleWords(round1.word);
|
||||||
|
|
||||||
let round1 = new Round(); round1.word = this.GetRandomScrambledWord(5); round1.answers = this.FindPossibleWords(round1.word);
|
const round2: Round = new Round();
|
||||||
let round2 = new Round(); round2.word = this.GetRandomScrambledWord(5); round2.answers = this.FindPossibleWords(round2.word);
|
round2.word = this.GetRandomScrambledWord(5);
|
||||||
let round3 = new Round(); round3.word = this.GetRandomScrambledWord(5); round3.answers = this.FindPossibleWords(round3.word);
|
round2.answers = this.FindPossibleWords(round2.word);
|
||||||
let round4 = new Round(); round4.word = this.GetRandomScrambledWord(6); round4.answers = this.FindPossibleWords(round4.word);
|
|
||||||
let round5 = new Round(); round5.word = this.GetRandomScrambledWord(6); round5.answers = this.FindPossibleWords(round5.word);
|
|
||||||
let round6 = new Round(); round6.word = this.GetRandomScrambledWord(6); round6.answers = this.FindPossibleWords(round6.word);
|
|
||||||
|
|
||||||
game.rounds.push(round1);
|
const round3: Round = new Round();
|
||||||
game.rounds.push(round2);
|
round3.word = this.GetRandomScrambledWord(5);
|
||||||
game.rounds.push(round3);
|
round3.answers = this.FindPossibleWords(round3.word);
|
||||||
game.rounds.push(round4);
|
|
||||||
game.rounds.push(round5);
|
|
||||||
game.rounds.push(round6);
|
|
||||||
|
|
||||||
return game;
|
const round4: Round = new Round();
|
||||||
|
round4.word = this.GetRandomScrambledWord(6);
|
||||||
|
round4.answers = this.FindPossibleWords(round4.word);
|
||||||
|
|
||||||
|
const round5: Round = new Round();
|
||||||
|
round5.word = this.GetRandomScrambledWord(6);
|
||||||
|
round5.answers = this.FindPossibleWords(round5.word);
|
||||||
|
|
||||||
|
const round6: Round = new Round();
|
||||||
|
round6.word = this.GetRandomScrambledWord(6);
|
||||||
|
round6.answers = this.FindPossibleWords(round6.word);
|
||||||
|
|
||||||
|
game.rounds.push(round1);
|
||||||
|
game.rounds.push(round2);
|
||||||
|
game.rounds.push(round3);
|
||||||
|
game.rounds.push(round4);
|
||||||
|
game.rounds.push(round5);
|
||||||
|
game.rounds.push(round6);
|
||||||
|
|
||||||
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async loadWords(): Promise<void> {
|
||||||
|
|
||||||
async loadWords() {
|
// tslint:disable-next-line: no-string-literal
|
||||||
|
window['wordService'] = this;
|
||||||
window["wordService"] = this;
|
|
||||||
|
|
||||||
/* SP Loader Implementation */
|
/* SP Loader Implementation */
|
||||||
// console.log(jquery);
|
// console.log(jquery);
|
||||||
// await SPComponentLoader.loadScript('../assets/jquery.min.js', { globalExportsName: "ScriptGlobal" });
|
// await SPComponentLoader.loadScript('../assets/jquery.min.js', { globalExportsName: "ScriptGlobal" });
|
||||||
// console.log('jquery loaded');
|
// console.log('jquery loaded');
|
||||||
|
|
||||||
|
|
||||||
/* JSON File Implementation
|
/* JSON File Implementation
|
||||||
If you have a custom word list you would like to use
|
If you have a custom word list you would like to use
|
||||||
add it as a JSON file in assets/wordlist.json and
|
add it as a JSON file in assets/wordlist.json and
|
||||||
uncomment the const wordlist at the top of this file.
|
uncomment the const wordlist at the top of this file.
|
||||||
Then comment out the Text File implementation below */
|
Then comment out the Text File implementation below */
|
||||||
// let wordvalues = (Object as any).values(wordlist) as any;
|
// let wordvalues = (Object as any).values(wordlist) as any;
|
||||||
|
@ -80,24 +112,25 @@ export class WordService {
|
||||||
// for(let i=0;i<wordlistlength;i++)
|
// for(let i=0;i<wordlistlength;i++)
|
||||||
// this.allwords.push(wordvalues[i]);
|
// this.allwords.push(wordvalues[i]);
|
||||||
|
|
||||||
|
|
||||||
/* Text File Implementation
|
/* Text File Implementation
|
||||||
Yields the smallest file download size vs JSON (700k vs 1.3mb)
|
Yields the smallest file download size vs JSON (700k vs 1.3mb)
|
||||||
The word list is a text file stored as wordlist.jpg and
|
The word list is a text file stored as wordlist.jpg and
|
||||||
loaded as text/plain using an overrided mime type */
|
loaded as text/plain using an overrided mime type */
|
||||||
var responseText = await $.ajax({
|
const responseText: string = await $.ajax({
|
||||||
url: wordjpg,
|
url: wordjpg,
|
||||||
beforeSend: function (xhr) {
|
beforeSend: (xhr) => {
|
||||||
xhr.overrideMimeType("text/plain; charset=x-user-defined");
|
xhr.overrideMimeType('text/plain; charset=x-user-defined');
|
||||||
}
|
}
|
||||||
}) as string;
|
}) as string;
|
||||||
this.allwords = responseText.split("\r\n");
|
this.allwords = responseText.split('\r\n');
|
||||||
|
|
||||||
this.allwords.forEach(word => {
|
this.allwords.forEach(word => {
|
||||||
if (word.indexOf("-") > -1)
|
if (word.indexOf('-') > -1) {
|
||||||
return;
|
return;
|
||||||
if (word.indexOf("-") > -1)
|
}
|
||||||
|
if (word.indexOf('-') > -1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
switch (word.length) {
|
switch (word.length) {
|
||||||
case 3:
|
case 3:
|
||||||
this.words3.push(word);
|
this.words3.push(word);
|
||||||
|
@ -126,13 +159,13 @@ export class WordService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GetWordCount(): number {
|
public GetWordCount(): number {
|
||||||
return this.allwords.length;
|
return this.allwords.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetRandomScrambledWord(level: number) {
|
public GetRandomScrambledWord(level: number): string {
|
||||||
let randomWord = "";
|
let randomWord: string = '';
|
||||||
let randwordnum = 0;
|
let randwordnum: number = 0;
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case 3:
|
case 3:
|
||||||
randwordnum = Math.floor(Math.random() * Math.floor(this.words3.length));
|
randwordnum = Math.floor(Math.random() * Math.floor(this.words3.length));
|
||||||
|
@ -162,128 +195,151 @@ export class WordService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let scrambledWord = this.ScrambleWord(randomWord);
|
const scrambledWord: string = this.ScrambleWord(randomWord);
|
||||||
return scrambledWord;
|
return scrambledWord;
|
||||||
}
|
}
|
||||||
|
|
||||||
FindPossibleWords(currentWord: string) {
|
public FindPossibleWords(currentWord: string): string[] {
|
||||||
//coati
|
// coati
|
||||||
//taco
|
// taco
|
||||||
|
|
||||||
//currentWord = "coati";
|
// currentWord = "coati";
|
||||||
let possibleWords: string[] = [];
|
const possibleWords: string[] = [];
|
||||||
this.allwords.forEach(word => {
|
this.allwords.forEach(word => {
|
||||||
let tempword = word;//taco
|
let tempword: string = word; // taco
|
||||||
for (let i = 0; i < currentWord.length; i++) {
|
for (let i: number = 0; i < currentWord.length; i++) {
|
||||||
|
|
||||||
let letter = currentWord[i];
|
const letter: string = currentWord[i];
|
||||||
if (tempword.indexOf(letter) > -1) {
|
if (tempword.indexOf(letter) > -1) {
|
||||||
tempword = tempword.slice(0, tempword.indexOf(letter)) + tempword.slice(tempword.indexOf(letter) + 1);
|
tempword = tempword.slice(0, tempword.indexOf(letter)) + tempword.slice(tempword.indexOf(letter) + 1);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
tempword = 'n';
|
tempword = 'n';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tempword.length == 0)
|
if (tempword.length === 0) {
|
||||||
possibleWords.push(word)
|
possibleWords.push(word);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return possibleWords;
|
return possibleWords;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//replace a character in a string
|
public ScrambleWord(word: string): string {
|
||||||
private replaceCharAt(orig:string, index:number, replacement:string): string {
|
let notScrambled: boolean = true;
|
||||||
return orig.substr(0, index) + replacement + orig.substr(index + replacement.length);
|
let scrambledWord: string = '';
|
||||||
}
|
let count: number = 0;
|
||||||
|
const originalword: string = word;
|
||||||
ScrambleWord(word: string): string {
|
|
||||||
let notScrambled = true;
|
|
||||||
let scrambledWord = "";
|
|
||||||
let count = 0;
|
|
||||||
var originalword = word;
|
|
||||||
while (notScrambled) {
|
while (notScrambled) {
|
||||||
word = originalword;
|
word = originalword;
|
||||||
let chars = '';
|
let chars: string = '';
|
||||||
for (let i = 0; i < word.length; i++)
|
for (let i: number = 0; i < word.length; i++) {
|
||||||
chars += ' ';
|
chars += ' ';
|
||||||
|
}
|
||||||
|
|
||||||
let index = 0;
|
let index: number = 0;
|
||||||
while (word.length > 0) {
|
while (word.length > 0) {
|
||||||
let next = Math.floor(Math.random() * Math.floor(word.length)); // Get a random number between 0 and the length of the word.
|
// Get a random number between 0 and the length of the word.
|
||||||
chars = this.replaceCharAt(chars, index, word[next]); // Take the character from the random position and add to our char array.
|
const next: number = Math.floor(Math.random() * Math.floor(word.length));
|
||||||
word = word.substr(0, next) + word.substr(next + 1); // Remove the character from the word.
|
|
||||||
|
// Take the character from the random position and add to our char array.
|
||||||
|
chars = this.replaceCharAt(chars, index, word[next]);
|
||||||
|
|
||||||
|
// Remove the character from the word.
|
||||||
|
word = word.substr(0, next) + word.substr(next + 1);
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
scrambledWord = chars.slice(0);
|
scrambledWord = chars.slice(0);
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
if (originalword!=scrambledWord)
|
if (originalword !== scrambledWord) {
|
||||||
notScrambled = false;
|
notScrambled = false;
|
||||||
|
}
|
||||||
|
|
||||||
//just in case there is a problem
|
// just in case there is a problem
|
||||||
if (count == 10)
|
if (count === 10) {
|
||||||
notScrambled = false;
|
notScrambled = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return scrambledWord;
|
return scrambledWord;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//SHAREPOINT APIS
|
// SHAREPOINT APIS
|
||||||
|
|
||||||
SetContext(context:WebPartContext){
|
public SetContext(context: WebPartContext): void {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async SubmitScore(score:number,seconds:number,details:string){
|
public async SubmitScore(score: number, seconds: number, details: string): Promise<void> {
|
||||||
try{
|
try {
|
||||||
await this.CreateListIfNotExists();
|
await this.CreateListIfNotExists();
|
||||||
await this.CreateListItem(score,seconds,details);
|
await this.CreateListItem(score, seconds, details);
|
||||||
}catch(error){}
|
} catch (error) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetHighScores():Promise<WordGameListItem[]>{
|
public async GetHighScores(): Promise<WordGameListItem[]> {
|
||||||
|
|
||||||
var scores:WordGameListItem[] = [];
|
let scores: WordGameListItem[] = [];
|
||||||
try{
|
try {
|
||||||
let result = await this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + "/_api/web/lists/GetByTitle('WordGameList')/items", SPHttpClient.configurations.v1);
|
const result: SPHttpClientResponse = await this.context.spHttpClient.get(
|
||||||
let json:any = await result.json();
|
this.context.pageContext.web.absoluteUrl
|
||||||
|
+ "/_api/web/lists/GetByTitle('WordGameList')/items",
|
||||||
|
SPHttpClient.configurations.v1);
|
||||||
|
// tslint:disable-next-line: no-any
|
||||||
|
const json: any = await result.json();
|
||||||
console.log(json);
|
console.log(json);
|
||||||
|
|
||||||
|
|
||||||
json.value.forEach(item => {
|
|
||||||
scores.push(new WordGameListItem(item.Title,item.Score,item.Seconds,item.Details));
|
|
||||||
});
|
|
||||||
|
|
||||||
scores.sort((a,b)=> {return b.Score-a.Score});
|
|
||||||
|
|
||||||
//top 10
|
json.value.forEach(item => {
|
||||||
if (scores.length>10)
|
scores.push(new WordGameListItem(item.Title,
|
||||||
scores = scores.slice(0,10);
|
item.Score,
|
||||||
|
item.Seconds,
|
||||||
console.log('high scores',scores);
|
item.Details));
|
||||||
}catch(error){
|
});
|
||||||
|
|
||||||
|
scores.sort((a, b) => {
|
||||||
|
return b.Score - a.Score;
|
||||||
|
});
|
||||||
|
|
||||||
|
// top 10
|
||||||
|
if (scores.length > 10) {
|
||||||
|
scores = scores.slice(0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('high scores', scores);
|
||||||
|
} catch (error) {
|
||||||
console.log('could not find list');
|
console.log('could not find list');
|
||||||
}
|
}
|
||||||
|
|
||||||
return scores;
|
return scores;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async CreateListIfNotExists(){
|
// replace a character in a string
|
||||||
let result = await this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + '/_api/web/lists', SPHttpClient.configurations.v1);
|
private replaceCharAt(orig: string, index: number, replacement: string): string {
|
||||||
let json:any = await result.json();
|
return orig.substr(0, index) + replacement + orig.substr(index + replacement.length);
|
||||||
let exists = false;
|
}
|
||||||
|
|
||||||
|
private async CreateListIfNotExists(): Promise<void> {
|
||||||
|
const result: SPHttpClientResponse = await this.context.spHttpClient.get(
|
||||||
|
this.context.pageContext.web.absoluteUrl
|
||||||
|
+ '/_api/web/lists',
|
||||||
|
SPHttpClient.configurations.v1);
|
||||||
|
|
||||||
|
// tslint:disable-next-line: no-any
|
||||||
|
const json: any = await result.json();
|
||||||
|
let exists: boolean = false;
|
||||||
json.value.forEach(list => {
|
json.value.forEach(list => {
|
||||||
if (list.Title=='WordGameList'){
|
if (list.Title === 'WordGameList') {
|
||||||
console.log('list found');
|
console.log('list found');
|
||||||
exists = true;
|
exists = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log(json);
|
console.log(json);
|
||||||
if (exists==false){
|
if (exists === false) {
|
||||||
console.log('Attempting to create list');
|
console.log('Attempting to create list');
|
||||||
await this.CreateList();
|
await this.CreateList();
|
||||||
await this.AddListColumnNumber('Score');
|
await this.AddListColumnNumber('Score');
|
||||||
|
@ -292,117 +348,111 @@ export class WordService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async CreateListItem(score:number,seconds:number,details:string){
|
private async CreateListItem(score: number, seconds: number, details: string): Promise<void> {
|
||||||
var listMetadata = {
|
const listMetadata: {} = {
|
||||||
"__metadata": {
|
'__metadata': {
|
||||||
"type": "SP.Data.WordGameListListItem"
|
'type': 'SP.Data.WordGameListListItem'
|
||||||
},
|
},
|
||||||
"Title": this.context.pageContext.user.displayName,
|
'Title': this.context.pageContext.user.displayName,
|
||||||
"Score": score,
|
'Score': score,
|
||||||
"Seconds": seconds,
|
'Seconds': seconds,
|
||||||
"Details": details
|
'Details': details
|
||||||
};
|
};
|
||||||
|
|
||||||
var options: ISPHttpClientOptions = {
|
const options: ISPHttpClientOptions = {
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "application/json;odata=verbose",
|
'Accept': 'application/json;odata=verbose',
|
||||||
"Content-Type": "application/json;odata=verbose",
|
'Content-Type': 'application/json;odata=verbose',
|
||||||
"OData-Version": "" //Really important to specify
|
'OData-Version': '' // Really important to specify
|
||||||
},
|
},
|
||||||
body: JSON.stringify(listMetadata)
|
body: JSON.stringify(listMetadata)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = await this.context.spHttpClient.post(
|
const result: SPHttpClientResponse = await this.context.spHttpClient.post(
|
||||||
this.context.pageContext.web.absoluteUrl + "/_api/web/lists/GetByTitle('WordGameList')/items", SPHttpClient.configurations.v1,options);
|
this.context.pageContext.web.absoluteUrl
|
||||||
let json:any = await result.json();
|
+ "/_api/web/lists/GetByTitle('WordGameList')/items",
|
||||||
|
SPHttpClient.configurations.v1, options);
|
||||||
|
// tslint:disable-next-line: no-any
|
||||||
|
const json: any = await result.json();
|
||||||
console.log(json);
|
console.log(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
async CreateList(){
|
private async CreateList(): Promise<void> {
|
||||||
var listMetadata = {
|
const listMetadata: {} = {
|
||||||
"__metadata": {
|
'__metadata': {
|
||||||
"type": "SP.List"
|
'type': 'SP.List'
|
||||||
},
|
},
|
||||||
"AllowContentTypes": true,
|
'AllowContentTypes': true,
|
||||||
"BaseTemplate": 100,
|
'BaseTemplate': 100,
|
||||||
"ContentTypesEnabled": true,
|
'ContentTypesEnabled': true,
|
||||||
"Description": "Holds high scores for the word game",
|
'Description': 'Holds high scores for the word game',
|
||||||
"Title": "WordGameList"
|
'Title': 'WordGameList'
|
||||||
};
|
};
|
||||||
|
|
||||||
var options: ISPHttpClientOptions = {
|
const options: ISPHttpClientOptions = {
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "application/json;odata=verbose",
|
'Accept': 'application/json;odata=verbose',
|
||||||
"Content-Type": "application/json;odata=verbose",
|
'Content-Type': 'application/json;odata=verbose',
|
||||||
"OData-Version": "" //Really important to specify
|
'OData-Version': '' // Really important to specify
|
||||||
},
|
},
|
||||||
body: JSON.stringify(listMetadata)
|
body: JSON.stringify(listMetadata)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = await this.context.spHttpClient.post(
|
const result: SPHttpClientResponse = await this.context.spHttpClient.post(
|
||||||
this.context.pageContext.web.absoluteUrl + '/_api/web/lists', SPHttpClient.configurations.v1,options);
|
this.context.pageContext.web.absoluteUrl + '/_api/web/lists', SPHttpClient.configurations.v1, options);
|
||||||
let json:any = await result.json();
|
// tslint:disable-next-line: no-any
|
||||||
|
const json: any = await result.json();
|
||||||
console.log(json);
|
console.log(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddListColumnMultiLineText(name:string){
|
private async AddListColumnMultiLineText(name: string): Promise<void> {
|
||||||
var listMetadata = {
|
const listMetadata: {} = {
|
||||||
'__metadata': {'type':'SP.FieldNumber'},
|
'__metadata': { 'type': 'SP.FieldNumber' },
|
||||||
'FieldTypeKind': 3,
|
'FieldTypeKind': 3,
|
||||||
'Title': name,
|
'Title': name
|
||||||
};
|
};
|
||||||
|
|
||||||
var options: ISPHttpClientOptions = {
|
const options: ISPHttpClientOptions = {
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "application/json;odata=verbose",
|
'Accept': 'application/json;odata=verbose',
|
||||||
"Content-Type": "application/json;odata=verbose",
|
'Content-Type': 'application/json;odata=verbose',
|
||||||
"OData-Version": "" //Really important to specify
|
'OData-Version': '' // Really important to specify
|
||||||
},
|
},
|
||||||
body: JSON.stringify(listMetadata)
|
body: JSON.stringify(listMetadata)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = await this.context.spHttpClient.post(
|
const result: SPHttpClientResponse = await this.context.spHttpClient.post(
|
||||||
this.context.pageContext.web.absoluteUrl + "/_api/web/lists/getbytitle('WordGameList')/fields", SPHttpClient.configurations.v1,options);
|
this.context.pageContext.web.absoluteUrl
|
||||||
let json:any = await result.json();
|
+ "/_api/web/lists/getbytitle('WordGameList')/fields",
|
||||||
|
SPHttpClient.configurations.v1, options);
|
||||||
|
// tslint:disable-next-line: no-any
|
||||||
|
const json: any = await result.json();
|
||||||
console.log(json);
|
console.log(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddListColumnNumber(name:string){
|
private async AddListColumnNumber(name: string): Promise<void> {
|
||||||
var listMetadata = {
|
const listMetadata: {} = {
|
||||||
'__metadata': {'type':'SP.FieldNumber'},
|
'__metadata': { 'type': 'SP.FieldNumber' },
|
||||||
'FieldTypeKind': 9,
|
'FieldTypeKind': 9,
|
||||||
'Title': name,
|
'Title': name,
|
||||||
'MinimumValue': 0,
|
'MinimumValue': 0,
|
||||||
'MaximumValue': 1000000
|
'MaximumValue': 1000000
|
||||||
};
|
};
|
||||||
|
|
||||||
var options: ISPHttpClientOptions = {
|
const options: ISPHttpClientOptions = {
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "application/json;odata=verbose",
|
'Accept': 'application/json;odata=verbose',
|
||||||
"Content-Type": "application/json;odata=verbose",
|
'Content-Type': 'application/json;odata=verbose',
|
||||||
"OData-Version": "" //Really important to specify
|
'OData-Version': '' // Really important to specify
|
||||||
},
|
},
|
||||||
body: JSON.stringify(listMetadata)
|
body: JSON.stringify(listMetadata)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = await this.context.spHttpClient.post(
|
const result: SPHttpClientResponse = await this.context.spHttpClient.post(
|
||||||
this.context.pageContext.web.absoluteUrl + "/_api/web/lists/getbytitle('WordGameList')/fields", SPHttpClient.configurations.v1,options);
|
this.context.pageContext.web.absoluteUrl + "/_api/web/lists/getbytitle('WordGameList')/fields",
|
||||||
let json:any = await result.json();
|
SPHttpClient.configurations.v1, options);
|
||||||
|
// tslint:disable-next-line: no-any
|
||||||
|
const json: any = await result.json();
|
||||||
console.log(json);
|
console.log(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WordGameListItem{
|
|
||||||
Name:string;
|
|
||||||
Score:number;
|
|
||||||
Seconds:number;
|
|
||||||
Details:string;
|
|
||||||
constructor(name:string,score:number,seconds:number,details:string){
|
|
||||||
this.Name = name;
|
|
||||||
this.Score = score;
|
|
||||||
this.Seconds = seconds;
|
|
||||||
this.Details = details;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue