initial merge of both repos
23
UNO-Angular/src/app/app-routing.module.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { StartComponent } from './start/start.component';
|
||||
import { GameComponent } from './game/game.component';
|
||||
import { BrowserComponent } from './browser/browser.component';
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'start', component: StartComponent },
|
||||
{ path: 'game', component: GameComponent },
|
||||
{ path: 'browser', component: BrowserComponent },
|
||||
{
|
||||
path: '',
|
||||
redirectTo: '/start',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
7
UNO-Angular/src/app/app.component.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<nav class="navbar navbar-light bg-light">
|
||||
<a class="navbar-brand" href="#"><b>UNO.DENNISGUNIA.DE</b> - Version 1.0</a>
|
||||
</nav>
|
||||
|
||||
<router-outlet #outlet="outlet"></router-outlet>
|
||||
|
||||
|
||||
3
UNO-Angular/src/app/app.component.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
.navbar{
|
||||
opacity: 0.7;
|
||||
}
|
||||
75
UNO-Angular/src/app/app.component.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { trigger, transition, style, query, animateChild, animate, group } from '@angular/animations';
|
||||
|
||||
|
||||
|
||||
|
||||
const slideInAnimation =
|
||||
trigger('routeAnimations', [
|
||||
transition('HomePage <=> AboutPage', [
|
||||
style({ position: 'relative' }),
|
||||
query(':enter, :leave', [
|
||||
style({
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%'
|
||||
})
|
||||
]),
|
||||
query(':enter', [
|
||||
style({ left: '-100%'})
|
||||
]),
|
||||
query(':leave', animateChild()),
|
||||
group([
|
||||
query(':leave', [
|
||||
animate('300ms ease-out', style({ left: '100%'}))
|
||||
]),
|
||||
query(':enter', [
|
||||
animate('300ms ease-out', style({ left: '0%'}))
|
||||
])
|
||||
]),
|
||||
query(':enter', animateChild()),
|
||||
]),
|
||||
transition('* <=> FilterPage', [
|
||||
style({ position: 'relative' }),
|
||||
query(':enter, :leave', [
|
||||
style({
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%'
|
||||
})
|
||||
]),
|
||||
query(':enter', [
|
||||
style({ left: '-100%'})
|
||||
]),
|
||||
query(':leave', animateChild()),
|
||||
group([
|
||||
query(':leave', [
|
||||
animate('200ms ease-out', style({ left: '100%'}))
|
||||
]),
|
||||
query(':enter', [
|
||||
animate('300ms ease-out', style({ left: '0%'}))
|
||||
])
|
||||
]),
|
||||
query(':enter', animateChild()),
|
||||
])
|
||||
]);
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss'],
|
||||
animations: [
|
||||
slideInAnimation
|
||||
// animation triggers go here
|
||||
]
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'uno';
|
||||
prepareRoute(outlet: RouterOutlet) {
|
||||
return outlet && outlet.activatedRouteData && outlet.activatedRouteData['animation'];
|
||||
}
|
||||
}
|
||||
38
UNO-Angular/src/app/app.module.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { StartComponent } from './start/start.component';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { MDBBootstrapModule } from 'angular-bootstrap-md';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { GameComponent } from './game/game.component';
|
||||
import { BrowserComponent } from './browser/browser.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
StartComponent,
|
||||
GameComponent,
|
||||
BrowserComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
BrowserAnimationsModule,
|
||||
AppRoutingModule,
|
||||
NgbModule,
|
||||
MDBBootstrapModule.forRoot(),
|
||||
FormsModule,
|
||||
HttpClientModule,
|
||||
ReactiveFormsModule,
|
||||
|
||||
],
|
||||
providers: [{provide: Window, useValue: window},],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
107
UNO-Angular/src/app/browser/browser.component.html
Normal file
@@ -0,0 +1,107 @@
|
||||
<div>
|
||||
<div class="card lobby-card">
|
||||
<div class="card-header">
|
||||
<h1><b>UNO Sitzungen</b> - {{nick}}</h1>
|
||||
<hr />
|
||||
<button class="btn btn-success btn-sm" (click)="prepareModal()" data-toggle="modal" data-target="#basicExampleModal" style="margin-right: 1rem;"><i class="fas fa-magic mr-1"></i> Sitzung erstellen</button>
|
||||
<button class="btn btn-success btn-sm" style="margin-right: 1rem;"><i class="fas fa-random mr-1"></i> Zufäliger Sitzung beitreten</button>
|
||||
<button class="btn btn-primary btn-sm" (click)="loadLobbies()"><i class="fas fa-sync mr-1"></i> Übersicht Aktualisieren</button>
|
||||
<button class="btn btn-warning btn-sm" routerLink="/start" style="position:absolute; right: 1.25rem;"><i class="fas fa-edit mr-1"></i>Benutzernamen ändern</button>
|
||||
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" *ngIf="lobbies.length > 0">
|
||||
<li class="list-group-item" *ngFor="let lobby of lobbies">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm btn-align" style="font-weight: 500;">
|
||||
{{lobby.properties.serverName}}
|
||||
<span *ngIf="lobby.status">(Im Spiel)</span>
|
||||
<span *ngIf="!lobby.status">(in Lobby)</span>
|
||||
</div>
|
||||
<div class="col-sm btn-align">
|
||||
{{lobby.players}} Spieler
|
||||
</div>
|
||||
<div class="col-sm btn-align">
|
||||
<ul>
|
||||
<li *ngIf="!(lobby.properties.startcards == 7)">{{lobby.properties.startcards}} Karten zu Spielbeginn</li>
|
||||
<li *ngIf="!(lobby.properties.sw_stacking == 7)">Kumulieren</li>
|
||||
<li *ngIf="!(lobby.properties.sw_jumpin == 7)">Jump-In</li>
|
||||
<li *ngIf="!(lobby.properties.sw_double == 7)">Doppeln</li>
|
||||
<li *ngIf="!(lobby.properties.sw_sleep == 7)">Pennen</li>
|
||||
<li *ngIf="!(lobby.properties.sw_seveno == 7)">Seven-O (Sieben-Null)</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<button class="btn btn-success btn-sm" [disabled]="lobby.status" (click)="joinGame(lobby)"><i class="fas fa-caret-square-right mr-1"></i>Spiel Beitreten</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<ul class="list-group list-group-flush" *ngIf="lobbies.length == 0">
|
||||
<li class="list-group-item text-muted" >
|
||||
Es gibt keine aktiven Sitzungen.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<div class="card-footer text-muted">
|
||||
Programmiert von Dennis Gunia (2020) - Open Source UNO - <a href="https://www.dennisgunia.de">dennisgunia.de</a> - Repo: <a href="https://git.dennis-gunia.de/dennisgunia/UNO-Backend">git.dennis-gunia.de</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="basicExampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Neue Sitzung erstellen</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form [formGroup]="createForm" (ngSubmit)="createLobby()">
|
||||
<div class="modal-body">
|
||||
<label for="sessionname">Sitzungsname</label>
|
||||
<input type="text" id="sessionname" [className]="createForm.controls.serverName.invalid ? ' form-control is-invalid' : 'form-control is-valid'" formControlName="serverName"> <br />
|
||||
<label for="startcards">Karten zu beginn</label>
|
||||
<input type="number" id="startcards" min="2" max="20" [className]="createForm.controls.startcards.invalid ? ' form-control is-invalid' : 'form-control is-valid'" formControlName="startcards"> <br />
|
||||
<label >Sonderregeln</label>
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" class="custom-control-input" id="sw_stacking" formControlName="sw_stacking">
|
||||
<label class="custom-control-label" for="sw_stacking">Kumulieren</label>
|
||||
</div>
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" class="custom-control-input" id="sw_jumpin" formControlName="sw_jumpin">
|
||||
<label class="custom-control-label" for="sw_jumpin">Jump-In</label>
|
||||
</div>
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" class="custom-control-input" id="sw_double" formControlName="sw_double">
|
||||
<label class="custom-control-label" for="sw_double">Doppeln</label>
|
||||
</div>
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" class="custom-control-input" id="sw_sleep" formControlName="sw_sleep">
|
||||
<label class="custom-control-label" for="sw_sleep">Pennen</label>
|
||||
</div>
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" class="custom-control-input" id="sw_seveno" formControlName="sw_seveno">
|
||||
<label class="custom-control-label" for="sw_seveno">Seven-O (Sieben-Null)</label>
|
||||
</div>
|
||||
<a href="https://www.uno-kartenspiel.de/uno-spielvarianten/" target="_blank">Infos zu den Sonderregeln</a>
|
||||
<button id="closeModalButton" [hidden]="true" data-toggle="modal"
|
||||
data-target="#myModal" class="btn btn-default"
|
||||
data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-danger" data-dismiss="modal">Abbrechen</button>
|
||||
<button type="button" type="submit" class="btn btn-success">Sitzung erstellen</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
11
UNO-Angular/src/app/browser/browser.component.scss
Normal file
@@ -0,0 +1,11 @@
|
||||
.lobby-card{
|
||||
margin: 0 auto;
|
||||
margin-top: 1rem;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.btn-align {
|
||||
padding: 6px 12px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: middle;
|
||||
}
|
||||
25
UNO-Angular/src/app/browser/browser.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { BrowserComponent } from './browser.component';
|
||||
|
||||
describe('BrowserComponent', () => {
|
||||
let component: BrowserComponent;
|
||||
let fixture: ComponentFixture<BrowserComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ BrowserComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(BrowserComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
105
UNO-Angular/src/app/browser/browser.component.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Router } from '@angular/router';
|
||||
import { FormBuilder,ReactiveFormsModule, FormControl, Validators } from '@angular/forms';
|
||||
|
||||
export interface UnoLobbyProperties {
|
||||
serverName: string;
|
||||
startcards: number;
|
||||
|
||||
}
|
||||
|
||||
export interface UnoLobbyElement {
|
||||
id: string;
|
||||
properties?: UnoLobbyProperties;
|
||||
status?: boolean;
|
||||
players?: number;
|
||||
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-browser',
|
||||
templateUrl: './browser.component.html',
|
||||
styleUrls: ['./browser.component.scss']
|
||||
})
|
||||
export class BrowserComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private router: Router,
|
||||
private formBuilder: FormBuilder,
|
||||
) {
|
||||
this.lobbies = []
|
||||
}
|
||||
|
||||
createForm;
|
||||
nick: string;
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
this.createForm = this.formBuilder.group({
|
||||
serverName: ['Neue Sitzung', [<any>Validators.required, <any>Validators.minLength(3), <any>Validators.maxLength(20)]],
|
||||
startcards: [7, [<any>Validators.required, <any>Validators.min(2), <any>Validators.max(20)]],
|
||||
sw_stacking: [false, [<any>Validators.required]],
|
||||
sw_jumpin: [false, [<any>Validators.required]],
|
||||
sw_double: [false, [<any>Validators.required]],
|
||||
sw_sleep: [false, [<any>Validators.required]],
|
||||
sw_seveno: [false, [<any>Validators.required]],
|
||||
});
|
||||
|
||||
|
||||
this.nick = localStorage.getItem('username')
|
||||
if (!this.nick){
|
||||
this.router.navigate(['/start']);
|
||||
}
|
||||
this.loadLobbies();
|
||||
}
|
||||
|
||||
lobbies: UnoLobbyElement[];
|
||||
|
||||
loadLobbies(){
|
||||
this.httpClient.get("/unogame/lobbies").subscribe(result => {
|
||||
const cres: any = result;
|
||||
if (cres.success) {
|
||||
console.log(cres.data)
|
||||
this.lobbies = cres.data ? cres.data : [];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prepareModal(){
|
||||
|
||||
}
|
||||
|
||||
createLobby(){
|
||||
|
||||
console.log("create" , this.createForm.value);
|
||||
if(this.createForm.valid){
|
||||
document.getElementById("closeModalButton").click();
|
||||
this.httpClient.post("/unogame/create",this.createForm.value).subscribe(result => {
|
||||
const cres: any = result;
|
||||
if (cres.success) {
|
||||
console.log(cres.data.id)
|
||||
this.joinGame({id: cres.data.id})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
joinGame(lobby: UnoLobbyElement){
|
||||
this.httpClient.post("/unogame/join", {
|
||||
nick: localStorage.getItem('username'),
|
||||
lid: lobby.id
|
||||
}).subscribe(result => {
|
||||
const cres: any = result;
|
||||
if (cres.success) {
|
||||
console.log(cres.data)
|
||||
localStorage.setItem('uid', cres.data.userId);
|
||||
localStorage.setItem('session', lobby.id);
|
||||
this.router.navigate(['/game']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
10
UNO-Angular/src/app/game-state.service.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
|
||||
export class GameStateService {
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
202
UNO-Angular/src/app/game/game.component.html
Normal file
@@ -0,0 +1,202 @@
|
||||
<div class="wrapper fill">
|
||||
<!-- Sidebar -->
|
||||
<nav id="sidebar" class="playerlist">
|
||||
<h1 style="padding:0.5rem;">Hallo, {{thisPlayer.nickname}}</h1>
|
||||
<div class="player card" *ngFor="let player of winnerList; let i = index">
|
||||
<div class="card-body" style="padding: 0px;">
|
||||
<div id="textbox">
|
||||
<p class="alignleft lessspace playername">{{player.nickname}}</p>
|
||||
<p class="alignright lessspace">
|
||||
<span *ngIf="!(player.uno && player.cards == 1)" class="badge badge-warning">{{i + 1}}.</span>
|
||||
</p>
|
||||
</div><br />
|
||||
<div id="textbox" class="lessspace">
|
||||
<p> Spiel beendet </p>
|
||||
</div>
|
||||
<div id="textbox" class="lessspace" style="margin-top:-12px;">
|
||||
<p class="alignleft lessspace ">Runde {{player.rounds}}</p>
|
||||
<p class="alignright lessspace">{{player.score}} Punkte</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr *ngIf="winnerList?.length > 0" />
|
||||
<div class="player card" *ngFor="let player of playerList" [style.background-color]="player.userId == currentPlayer.userId?'#90EE90':(nextPlayerId == player.userId ?'#FFFFE0':'#FFF')">
|
||||
<div class="card-body" style="padding: 0px;">
|
||||
<div id="textbox">
|
||||
<p class="alignleft lessspace playername">{{player.nickname}}</p>
|
||||
<p class="alignright lessspace">
|
||||
<span *ngIf="player.uno && player.cards == 1" class="badge badge-danger">UNO</span>
|
||||
<span *ngIf="!(player.uno && player.cards == 1)" class="badge badge-secondary">{{player.cards}}</span>
|
||||
</p>
|
||||
</div><br />
|
||||
<div id="textbox" class="lessspace">
|
||||
<p>
|
||||
<span>{{player.state}}</span>
|
||||
-
|
||||
<span *ngIf="!gameStarted && !player.ready">In Lobby (Nicht bereit)</span>
|
||||
<span *ngIf="!gameStarted && player.ready">In Lobby (Bereit)</span>
|
||||
<span *ngIf="gameStarted && !(player.userId == currentPlayer.userId)">Wartet</span>
|
||||
<span *ngIf="gameStarted && player.userId == currentPlayer.userId">Am Zug</span>
|
||||
</p>
|
||||
</div>
|
||||
<div id="textbox" class="lessspace" style="margin-top:-12px;">
|
||||
<p class="alignleft lessspace ">Runde {{player.rounds}}</p>
|
||||
<p class="alignright lessspace">{{player.score}} Punkte</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<button mdbBtn type="button" *ngIf="!thisPlayer.ready" rounded="true" mdbWavesEffect class="btn btn_btm btn-success" (click)="ready()">Bereit</button>
|
||||
<button mdbBtn type="button" rounded="true" mdbWavesEffect class="btn btn_btm btn-warning" (click)="leave()">Verlassen</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Page Content -->
|
||||
<div id="content">
|
||||
<!-- We'll fill this with dummy content -->
|
||||
<div class="gamefield">
|
||||
<div class="footer2" [innerHTML]="chatText" #scrollMe [scrollTop]="scrollMe.scrollHeight"></div>
|
||||
<div class="card countdown" *ngIf="timer >= 0">
|
||||
<p><i class="fas fa-stopwatch"></i> {{timer}}</p>
|
||||
</div>
|
||||
|
||||
<div class="card votebox" [@simpleFadeAnimation]="'in'" *ngIf="currentVote">
|
||||
<div class="card-header">
|
||||
{{currentVote.questions[0].question}}
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
|
||||
<li class="list-group-item vote-option" (click)="vote(i)" *ngFor="let opt of currentVote.questions[0].options; let i = index">
|
||||
<div class="progress" [style.width]="((currentVote.questions[0].counter[i] / currentVote.all )*100) + '%'"></div>{{opt}}
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="text-header" *ngIf="gameStarted">
|
||||
<p class="text-header-current" *ngIf="!(currentPlayer.userId == thisPlayer.userId)">{{currentPlayer.nickname}} ist am Zug</p>
|
||||
<p class="text-header-current" *ngIf="currentPlayer.userId == thisPlayer.userId">Du bist am Zug</p>
|
||||
<p class="text-header-detail" *ngIf="topCard.color=='blue'">Aktuell wird <span style="color:#0095da">Blau</span> gespielt</p>
|
||||
<p class="text-header-detail" *ngIf="topCard.color=='green'">Aktuell wird <span style="color:#00ab67">Grün</span> gespielt</p>
|
||||
<p class="text-header-detail" *ngIf="topCard.color=='red'">Aktuell wird <span style="color:#ed1c24">Rot</span> gespielt</p>
|
||||
<p class="text-header-detail" *ngIf="topCard.color=='yellow'">Aktuell wird <span style="color:#ffde00">Gelb</span> gespielt</p>
|
||||
<p class="text-header-detail" *ngIf="topCard.color=='wild'">{{currentPlayer.nickname}} sucht sich eine Farbe aus</p>
|
||||
</div>
|
||||
<div class="text-header" *ngIf="!gameStarted">
|
||||
<p class="text-header-current">Warte bis alle Spieler bereit sind</p>
|
||||
</div>
|
||||
<div class="play-field" *ngIf="gameStarted">
|
||||
<div class="cards-center">
|
||||
<button type="button" class="btn uno-card" style="margin-right:8rem;" [style.background]="'url('+ topCard.tx +')'"></button>
|
||||
<button type="button" class="btn uno-card" style="margin-right:0;" [style.background]="'url(/assets/cards/000.png)'" placement="bottom" ngbTooltip="Karte ziehen" (click)="pull()"></button>
|
||||
<br /><br />
|
||||
<button mdbBtn type="button" rounded="true" mdbWavesEffect class="btn btn-skip btn-warning" (click)="skip()" *ngIf="(currentPlayer.userId == thisPlayer.userId) && pulled">Aussetzen</button>
|
||||
<button mdbBtn type="button" rounded="true" mdbWavesEffect class="btn btn-skip btn-danger" (click)="uno()" *ngIf="(currentPlayer.userId == thisPlayer.userId)">UNO!</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="notify-banner" *ngIf="bannerShow && !bannerError" [@simpleFadeAnimation]="'in'">
|
||||
{{bannerText}}
|
||||
</div>
|
||||
<div class="notify-banner" *ngIf="bannerShow && bannerError" style="color:#ed1c24" [@simpleFadeAnimation]="'in'">
|
||||
{{bannerText}}
|
||||
</div>
|
||||
<div class="footer3">
|
||||
<div *ngFor="let card of handCards" [@flyInOut]="'in'">
|
||||
<button *ngIf="!((card.number == 'wild+4') || (card.number == 'wild'))" type="button" class="btn uno-card uno-overlap " [style.background]="'url('+ card.tx +')'" placement="bottom" ngbTooltip="Karte legen" (click)="selectedCard=card;play(card)"></button>
|
||||
<button *ngIf="card.number == 'wild+4'" type="button" class="btn uno-card uno-overlap " [style.background]="'url('+ card.tx +')'" placement="bottom" ngbTooltip="Karte legen" data-toggle="modal" data-target="#modal_plus4" (click)="selectedCard=card"></button>
|
||||
<button *ngIf="card.number == 'wild'" type="button" class="btn uno-card uno-overlap " [style.background]="'url('+ card.tx +')'" placement="bottom" ngbTooltip="Karte legen" data-toggle="modal" data-target="#modal_wild" (click)="selectedCard=card"></button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="modal_plus4" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="cards-center">
|
||||
<button type="button" class="btn uno-card" style="margin-right:0;" [style.background]="'url(/assets/cards/312.png)'" placement="bottom" ngbTooltip="Blau wünschen" (click)="playwild('wild+4','blue')" data-dismiss="modal"></button>
|
||||
<button type="button" class="btn uno-card" style="margin-right:0;" [style.background]="'url(/assets/cards/322.png)'" placement="bottom" ngbTooltip="Grün wünschen" (click)="playwild('wild+4','green')" data-dismiss="modal"></button>
|
||||
<button type="button" class="btn uno-card" style="margin-right:0;" [style.background]="'url(/assets/cards/332.png)'" placement="bottom" ngbTooltip="Rot wünschen" (click)="playwild('wild+4','red')" data-dismiss="modal"></button>
|
||||
<button type="button" class="btn uno-card" style="margin-right:0;" [style.background]="'url(/assets/cards/342.png)'" placement="bottom" ngbTooltip="Gelb wünschen" (click)="playwild('wild+4','yellow')" data-dismiss="modal"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="modal_wild" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="cards-center">
|
||||
<button type="button" class="btn uno-card" style="margin-right:0;" [style.background]="'url(/assets/cards/311.png)'" placement="bottom" ngbTooltip="Blau wünschen" (click)="playwild('wild','blue')" data-dismiss="modal"></button>
|
||||
<button type="button" class="btn uno-card" style="margin-right:0;" [style.background]="'url(/assets/cards/321.png)'" placement="bottom" ngbTooltip="Grün wünschen" (click)="playwild('wild','green')" data-dismiss="modal"></button>
|
||||
<button type="button" class="btn uno-card" style="margin-right:0;" [style.background]="'url(/assets/cards/331.png)'" placement="bottom" ngbTooltip="Rot wünschen" (click)="playwild('wild','red')" data-dismiss="modal"></button>
|
||||
<button type="button" class="btn uno-card" style="margin-right:0;" [style.background]="'url(/assets/cards/341.png)'" placement="bottom" ngbTooltip="Gelb wünschen" (click)="playwild('wild','yellow')" data-dismiss="modal"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--Rules Modal-->
|
||||
<!-- Button trigger modal -->
|
||||
<button type="button" class="btn btn-primary" id="open_rules_modal" data-toggle="modal" data-target="#rulesModal" [hidden]="true">
|
||||
Launch modal
|
||||
</button>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="rulesModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Aktive Sonderregeln</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div style="text-align: left;">
|
||||
<span class="rule"><b>Mehr Karten</b> Jeder hat zu Beginn {{options.cards}} statt 7 Karten. </span><br />
|
||||
<span class="rule"><b>Doppeln</b> Hat ein Spieler zwei Karten von der selben Farbe und Zahl auf der Hand, so darf er diese zusammen ablegen. Dies gilt jedoch nicht für die +2- und +4-Karten. Diese müssen weiterhin nacheinander abgelegt werden. </span><br />
|
||||
<span class="rule"><b>Kumulieren</b> Kann ein Spieler, der von eine +2-Karte betroffen ist, selbst mit einer solchen Karte aufwarten, so i8st dies erlaubt und der nächste Spieler nach ihm muss nun 4 Karten ziehen. Hat dieser ebenfalls eine +2-Karte, so ist auch dies zulässig. Gleiches gilt entsprechend für die +4-Karten. Die Karten dürfen allerdings nicht kombiniert werden. </span><br />
|
||||
<span class="rule"><b>Jump-In</b> Wenn ein Spieler exakt die gleiche Karte auf der Hand hat, welche soeben ausgespielt wurde (gleiche Farbe und Zahl), so kann er diese sofort ablegen – auch wenn er nicht am Zug ist. Die Runde geht jedoch bei dem Spieler weiter, welcher regulär an der Reihe gewesen wäre. </span><br />
|
||||
<span class="rule"><b>Pennen</b> Wer seinen Einsatz verpasst, muss eine Strafkarte ziehen. </span><br />
|
||||
<span class="rule"><b>Seven-O (Sieben-Null)</b> Wird eine Null gespielt, so muss jeder Spieler sein komplettes Blatt an den Spielnachbarn in Uhrzeigerrichtugn weitergeben. Wird dagegen eine Sieben ausgespielt, so darf dieser Spieler sein komplettes Blatt mit einem anderen Spieler seiner Wahl tauschen. </span><br />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-success" data-dismiss="modal">Alles klar!</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--double modal-->
|
||||
<!-- Button trigger modal -->
|
||||
<button type="button" class="btn btn-primary" id="open_rdouble_modal" data-toggle="modal" data-target="#modal_double" [hidden]="true">
|
||||
Launch modal
|
||||
</button>
|
||||
|
||||
<div class="modal fade" id="modal_double" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="cards-center">
|
||||
<button type="button" class="btn uno-card double-card" style="margin-right:0;" (click)="playSingle()" [style.background]="'url('+ selectedCard?.tx +')'" placement="bottom" ngbTooltip="Einzelne Karte legen" data-dismiss="modal">1x</button>
|
||||
<button type="button" class="btn uno-card double-card" style="margin-right:0;" (click)="playDouble()" [style.background]="'url('+ selectedCard?.tx +')'" placement="bottom" ngbTooltip="Doppelt legen" data-dismiss="modal">2x</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
264
UNO-Angular/src/app/game/game.component.scss
Normal file
@@ -0,0 +1,264 @@
|
||||
|
||||
|
||||
.playerlist {
|
||||
background-color: rgb(247, 247, 249);
|
||||
border-right: solid 1px rgb(128, 128, 128);
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
min-width: 250px;
|
||||
max-width: 250px;
|
||||
background-color: rgba(247, 247, 249,0.3);
|
||||
}
|
||||
|
||||
.fill {
|
||||
top: 46px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.player {
|
||||
margin: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
|
||||
}
|
||||
|
||||
.alignleft {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.alignright {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.lessspace {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.playername {
|
||||
font-weight:500;
|
||||
}
|
||||
|
||||
.player:hover {
|
||||
background-color: #DCDCDC;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 249px;
|
||||
border-top: solid 1px rgb(128, 128, 128);
|
||||
text-align: center;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
.footer2 {
|
||||
position: fixed;
|
||||
width: 35%;
|
||||
bottom: 15rem;
|
||||
right: 0;
|
||||
//top: 46px;
|
||||
height: 200px;
|
||||
text-align: center;
|
||||
padding: 0.5rem;
|
||||
text-shadow: 0px 0px 12px #000000;
|
||||
font-size: 1rem;
|
||||
text-align: right;
|
||||
color: white;
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
//opacity: 0.75;
|
||||
}
|
||||
|
||||
|
||||
.footer3 {
|
||||
position: fixed;
|
||||
left: 250px;
|
||||
bottom: 0rem;
|
||||
right: 0;
|
||||
text-align: left;
|
||||
border-top: solid 5px #2e1a12;
|
||||
padding: 0.5rem;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
height: 15rem;
|
||||
background-image: url('/assets/felt.jpg');
|
||||
box-shadow: inset 0 0 10px #000000;
|
||||
}
|
||||
|
||||
.btn_btm {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
margin-top: 0;
|
||||
width: calc(100% - 1rem);
|
||||
}
|
||||
|
||||
.uno-card {
|
||||
height: 150px;
|
||||
width: 100px;
|
||||
float: left;
|
||||
margin-right: 0.5rem;
|
||||
background: white;
|
||||
border: 0;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 10px #000000;
|
||||
}
|
||||
|
||||
.uno-card:hover {
|
||||
transform: scale(1.1); /* (150% zoom - Note: if the zoom is too large, it will go outside of the viewport) */
|
||||
}
|
||||
|
||||
.gamefield {
|
||||
position: fixed;
|
||||
left: 250px;
|
||||
bottom: 15rem;
|
||||
right: 0;
|
||||
text-align: left;
|
||||
padding: 0.5rem;
|
||||
top: 46px;
|
||||
background-image: url('/assets/felt.jpg');
|
||||
box-shadow: inset 0 0 10px #000000;
|
||||
}
|
||||
|
||||
.text-header {
|
||||
left: 250px;
|
||||
top: 46px;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
|
||||
color: snow;
|
||||
text-shadow: 0px 0px 7px #000000;
|
||||
}
|
||||
|
||||
.text-header-current {
|
||||
padding-top: 1.5rem;
|
||||
font-size: 4rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.text-header-detail {
|
||||
padding-top: 1.0rem;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.play-field {
|
||||
position: fixed;
|
||||
|
||||
left: 250px;
|
||||
top: 180px;
|
||||
right: 0;
|
||||
bottom: 20rem;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.cards-center {
|
||||
display: inline-block;
|
||||
text-align: center
|
||||
}
|
||||
|
||||
.btn-skip {
|
||||
margin-top:3rem;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
display: inline-block;
|
||||
text-align: center
|
||||
}
|
||||
|
||||
|
||||
.notify-banner {
|
||||
position: fixed;
|
||||
left: 250px;
|
||||
bottom: 21rem;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
padding: 0.5rem;
|
||||
color: snow;
|
||||
text-shadow: 0px 0px 7px #000000;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.uno-overlap {
|
||||
margin-bottom: -100px;
|
||||
}
|
||||
:host span.chat-line-date {
|
||||
padding-right: 2rem;
|
||||
color:red;
|
||||
}
|
||||
|
||||
.chat-line-msg{
|
||||
|
||||
}
|
||||
|
||||
.votebox {
|
||||
//background-color: rgba($color: red, $alpha: 0.5);
|
||||
position: fixed;
|
||||
left: 260px;
|
||||
bottom: calc(15rem + 10px );
|
||||
//padding: 0.5rem;
|
||||
//color: snow;
|
||||
}
|
||||
|
||||
.vote-option{
|
||||
transition: 0.4s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vote-option:hover{
|
||||
background-color: lightgrey;
|
||||
|
||||
}
|
||||
|
||||
.progress{
|
||||
position:absolute; left:0px; top:0;
|
||||
background-color: rgba($color: red, $alpha: .2);
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
border-radius: 0px;
|
||||
transition: 1s;
|
||||
}
|
||||
.vote-opt-b{
|
||||
position:absolute; right: -27px; top:-18px;
|
||||
}
|
||||
|
||||
.rule {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.countdown {
|
||||
position:absolute; left: 10px; top:10px;
|
||||
padding: 0.5rem;
|
||||
padding-bottom: 0;
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
|
||||
.double-card{
|
||||
font-size: 3.5rem;
|
||||
padding: 0;
|
||||
text-shadow: 0px 0px 4px #FFF;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 42em) and (max-width: 64em) {
|
||||
/* min-width 672px / max-width 1024px */
|
||||
/* hier vermuten wir Tabletts */
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 42em) and (max-width: 42em) {
|
||||
/* min-width 672px / max-width 1024px */
|
||||
/* hier vermuten wir Handy */
|
||||
|
||||
}
|
||||
460
UNO-Angular/src/app/game/game.component.ts
Normal file
@@ -0,0 +1,460 @@
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Router } from '@angular/router';
|
||||
import { trigger, state, style, transition, animate } from '@angular/animations';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { webSocket } from "rxjs/webSocket";
|
||||
|
||||
interface UnoCard {
|
||||
id: number;
|
||||
number: string;
|
||||
color: string;
|
||||
tx: string;
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-game',
|
||||
templateUrl: './game.component.html',
|
||||
styleUrls: ['./game.component.scss'],
|
||||
animations: [
|
||||
// the fade-in/fade-out animation.
|
||||
trigger('simpleFadeAnimation', [
|
||||
|
||||
// the "in" style determines the "resting" state of the element when it is visible.
|
||||
state('in', style({ opacity: 1 })),
|
||||
|
||||
// fade in when created. this could also be written as transition('void => *')
|
||||
transition(':enter', [
|
||||
style({ opacity: 0 }),
|
||||
animate(150)
|
||||
]),
|
||||
|
||||
// fade out when destroyed. this could also be written as transition('void => *')
|
||||
transition(':leave',
|
||||
animate(300, style({ opacity: 0 })))
|
||||
]),
|
||||
trigger('flyInOut', [
|
||||
state('in', style({ transform: 'translateX(0)' })),
|
||||
transition('void => *', [
|
||||
style({ transform: 'translateX(100%)' }),
|
||||
animate(100)
|
||||
]),
|
||||
transition('* => void', [
|
||||
animate(100, style({ opacity: 0}))
|
||||
])
|
||||
])
|
||||
]
|
||||
})
|
||||
|
||||
export class GameComponent implements OnInit {
|
||||
|
||||
pulled: boolean = false;
|
||||
nextPlayerId: string = '';
|
||||
conn;
|
||||
myLastId: number = -1;
|
||||
|
||||
//new objects
|
||||
playerList: any = [];
|
||||
winnerList: any = [];
|
||||
topCard: any = {};
|
||||
currentPlayer: any = {};
|
||||
lastPlayer: any = {};
|
||||
direction: number;
|
||||
gameStarted: boolean = false;
|
||||
thisPlayer: any = {};
|
||||
handCards: UnoCard[] = [];
|
||||
|
||||
bannerText: string = "test";
|
||||
bannerShow: boolean = false;
|
||||
bannerError: boolean = false;
|
||||
bannerTimer;
|
||||
|
||||
chatText = "";
|
||||
selectedCard: UnoCard;
|
||||
doubleCard: UnoCard;
|
||||
|
||||
currentVote: any = undefined;
|
||||
|
||||
options:any;
|
||||
|
||||
timer: number = -1;
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private router: Router,
|
||||
private titleService: Title,
|
||||
@Inject(Window) private _window: Window
|
||||
) {
|
||||
this.conn = webSocket(`ws${location.origin.replace(/http/,'')}/stream/uno.io`);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
setInterval(() => {
|
||||
this.conn.next({action: 'heartbeat'});
|
||||
console.log("players", this.playerList)
|
||||
}, 4000);
|
||||
this.openSocket();
|
||||
}
|
||||
|
||||
private showBanner(message, type) {
|
||||
if (this.bannerTimer) {
|
||||
clearTimeout(this.bannerTimer);
|
||||
}
|
||||
this.bannerError = type;
|
||||
this.bannerText = message;
|
||||
this.bannerShow = true;
|
||||
|
||||
this.bannerTimer = setTimeout(() => {
|
||||
this.bannerShow = false;
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
private openSocket(){
|
||||
|
||||
|
||||
this.conn.subscribe(
|
||||
msg => this.processMessage(msg), // Called whenever there is a message from the server.
|
||||
err => {
|
||||
console.log(err)
|
||||
this.router.navigate(['/browser'])
|
||||
}, // Called if at any point WebSocket API signals some kind of error.
|
||||
() => this.router.navigate(['/browser']) // Called when connection is closed (for whatever reason).
|
||||
);
|
||||
|
||||
this.conn.next({
|
||||
action: 'register',
|
||||
id: localStorage.getItem('uid'),
|
||||
lobby: localStorage.getItem('session'),
|
||||
});
|
||||
this.conn.next({action: 'initData'});
|
||||
//this.conn.emit('new-message', "RAS@" + localStorage.getItem('uid'));
|
||||
}
|
||||
|
||||
private processMessage(msg){
|
||||
if (msg.notify){ this.showBanner(msg.notify,!msg.warning); return; }
|
||||
if (msg.player){ this.processPlayerList(msg); return; }
|
||||
if (msg.chat){ this.chatText += msg.chat; return; }
|
||||
if (msg.initClientData){this.processInitClient(msg); return; }
|
||||
if (msg.kick){
|
||||
this.conn.complete();
|
||||
this.router.navigate(['/browser']);
|
||||
}
|
||||
if (msg.gameUpdate){this.processGameUpdate(msg); return;}
|
||||
if (msg.hand){this.processHand(msg); return; }
|
||||
if (msg.vote){this.startVote(msg); return; }
|
||||
if (msg.voteres){this.updateVote(msg); return; }
|
||||
if (msg.endvote){this.stopVote(); return; }
|
||||
if (msg.timer || msg.timer == 0){this.updateTimer(msg); return; }
|
||||
if (msg.sound){this.playSound(msg); return; }
|
||||
if (msg.changprop){
|
||||
if (msg.changprop == 'canskip'){
|
||||
this.pulled = true; // kann jetzt uno sagen
|
||||
}
|
||||
}
|
||||
}
|
||||
//new update functions
|
||||
|
||||
private playSound(msg){
|
||||
let audio = new Audio();
|
||||
audio.src = msg.sound;
|
||||
audio.load();
|
||||
audio.play();
|
||||
}
|
||||
|
||||
private updateTimer(msg){
|
||||
if (msg.timer >= 0){
|
||||
let audio = new Audio();
|
||||
audio.src = "../assets/tick.wav";
|
||||
audio.load();
|
||||
audio.play();
|
||||
}
|
||||
this.timer = msg.timer;
|
||||
}
|
||||
|
||||
private startVote(msg){
|
||||
this.currentVote = {
|
||||
...msg,
|
||||
voted: false,
|
||||
all: 0,
|
||||
timer: setTimeout(() => this.stopVote(),msg.time)
|
||||
}
|
||||
|
||||
console.log("startvote",this.currentVote )
|
||||
}
|
||||
|
||||
private stopVote(){
|
||||
clearTimeout(this.currentVote.timer)
|
||||
this.currentVote = undefined;
|
||||
console.log("stopvote",this.currentVote )
|
||||
}
|
||||
|
||||
private updateVote(msg){
|
||||
this.currentVote.questions[0].counter = msg.voteres[0].counter;
|
||||
this.currentVote.all = msg.voteres[0].counter.reduce((a, b) => a + b, 0)
|
||||
console.log("updatevote",this.currentVote )
|
||||
|
||||
}
|
||||
|
||||
public vote(id){
|
||||
console.log("vote")
|
||||
this.conn.next({vote: id + 1});
|
||||
|
||||
}
|
||||
|
||||
private processPlayerList(msg){
|
||||
if(msg.player == 'modify'){
|
||||
let pfound: boolean= false;
|
||||
//search winner
|
||||
this.winnerList.forEach((player, ix) => {
|
||||
if(player.userId == msg.data.userId){
|
||||
pfound = true;
|
||||
this.winnerList[ix] = msg.data;
|
||||
console.log("update winner",msg.data)
|
||||
}
|
||||
});
|
||||
if (!pfound){
|
||||
this.playerList.forEach((player, ix) => {
|
||||
if(player.userId == msg.data.userId){
|
||||
pfound = true;
|
||||
this.playerList[ix] = msg.data;
|
||||
console.log("update player",msg.data)
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!pfound){
|
||||
console.log("add player to list",msg.data )
|
||||
this.playerList.push(msg.data);
|
||||
}
|
||||
}else if(msg.player == 'remove'){
|
||||
this.playerList = this.playerList.filter(el => el.userId != msg.data.userId);
|
||||
console.log("remove player from list",msg.data )
|
||||
}else if(msg.player == 'winners'){
|
||||
this.winnerList = msg.data
|
||||
}else if(msg.player == 'all'){
|
||||
this.playerList = msg.players
|
||||
this.winnerList = msg.winners
|
||||
|
||||
}
|
||||
this.processPlayerUpdate();
|
||||
this.playerChangeEvent();
|
||||
}
|
||||
|
||||
private processHand(msg){
|
||||
if(msg.hand == 'add'){
|
||||
this.handCards.push(msg.card)
|
||||
let audio = new Audio();
|
||||
audio.src = "../assets/cardSlide7.wav";
|
||||
audio.load();
|
||||
audio.play();
|
||||
}else if(msg.hand == 'remove'){
|
||||
this.handCards = this.handCards.filter(el => el.id != msg.card.id);
|
||||
}else if(msg.hand == 'all'){
|
||||
this.handCards = msg.cards;
|
||||
}
|
||||
}
|
||||
|
||||
private processInitClient(msg){
|
||||
this.playerList = msg.initClientData.players;
|
||||
this.winnerList = msg.initClientData.winners;
|
||||
//karten
|
||||
this.topCard = msg.initClientData.cardsPlayed[msg.initClientData.cardsPlayed.length -1 ];
|
||||
for (let pi = 0; pi < this.playerList.length; pi++) {
|
||||
if (this.playerList[pi].userId == msg.initClientData.currentPlayer) {
|
||||
this.currentPlayer = this.playerList[pi];
|
||||
}
|
||||
}
|
||||
this.handCards = msg.initClientData.hand;
|
||||
this.direction = msg.initClientData.direction;
|
||||
this.updateCardColor();
|
||||
this.processPlayerUpdate();
|
||||
this.playerChangeEvent();
|
||||
this.gameStarted = msg.initClientData.started;
|
||||
this.options = msg.initClientData.extraRules;
|
||||
document.getElementById("open_rules_modal").click();
|
||||
|
||||
}
|
||||
|
||||
private processGameUpdate(msg){
|
||||
switch(msg.gameUpdate){
|
||||
case 'playedStack':
|
||||
this.topCard = msg.card[msg.card.length -1 ];
|
||||
this.updateCardColor();
|
||||
let audio = new Audio();
|
||||
audio.src = "../assets/cardPlace1.wav";
|
||||
audio.load();
|
||||
audio.play();
|
||||
break;
|
||||
case 'currentPlayer':
|
||||
for (let pi = 0; pi < this.playerList.length; pi++) {
|
||||
if (this.playerList[pi].userId == msg.currentplayer) {
|
||||
this.currentPlayer = this.playerList[pi];
|
||||
}
|
||||
}
|
||||
this.direction = msg.direction;
|
||||
this.playerChangeEvent();
|
||||
break;
|
||||
case 'status':
|
||||
this.gameStarted = msg.started;
|
||||
this.processPlayerUpdate();
|
||||
this.playerChangeEvent();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//helper functions
|
||||
private updateCardColor(){
|
||||
if (this.topCard){
|
||||
if (this.topCard.number == 'wild') {
|
||||
switch (this.topCard.color) {
|
||||
case 'blue': this.topCard.tx = "/assets/cards/311.png"; break;
|
||||
case 'green': this.topCard.tx = "/assets/cards/321.png"; break;
|
||||
case 'red': this.topCard.tx = "/assets/cards/331.png"; break;
|
||||
case 'yellow': this.topCard.tx = "/assets/cards/341.png"; break;
|
||||
}
|
||||
}
|
||||
if (this.topCard.number == 'wild+4') {
|
||||
switch (this.topCard.color) {
|
||||
case 'blue': this.topCard.tx = "/assets/cards/312.png"; break;
|
||||
case 'green': this.topCard.tx = "/assets/cards/322.png"; break;
|
||||
case 'red': this.topCard.tx = "/assets/cards/332.png"; break;
|
||||
case 'yellow': this.topCard.tx = "/assets/cards/342.png"; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private playerChangeEvent(){
|
||||
|
||||
|
||||
if (this.currentPlayer.userId != this.thisPlayer.userId) {
|
||||
this.pulled = false;
|
||||
this.titleService.setTitle("UNO - " + this.thisPlayer.nickname);
|
||||
} else {
|
||||
this.titleService.setTitle("DU BIST DRAN! - UNO - " + this.thisPlayer.nickname);
|
||||
|
||||
}
|
||||
//get next player
|
||||
let index = 0;
|
||||
this.playerList.forEach((obj, ix) => {
|
||||
if (obj.userId == this.currentPlayer.userId) {index = ix;}
|
||||
});
|
||||
let newIndex = index + this.direction;
|
||||
if (newIndex < 0) { newIndex += this.playerList.length }
|
||||
if (newIndex > ( this.playerList.length - 1)) { newIndex -= this.playerList.length }
|
||||
this.nextPlayerId = this.playerList[newIndex].userId;
|
||||
|
||||
if (this.currentPlayer.userId != this.lastPlayer){
|
||||
if (this.currentPlayer.userId == this.thisPlayer.userId){
|
||||
let audio = new Audio();
|
||||
audio.src = "../assets/when.mp3";
|
||||
audio.load();
|
||||
audio.play();
|
||||
}
|
||||
this.lastPlayer = this.currentPlayer.userId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private processPlayerUpdate(){
|
||||
const userId = localStorage.getItem('uid');
|
||||
for (let pi = 0; pi < this.playerList.length; pi++) {
|
||||
if (this.playerList[pi].userId == userId) {
|
||||
this.thisPlayer = this.playerList[pi];
|
||||
}
|
||||
}
|
||||
for (let pi = 0; pi < this.winnerList.length; pi++) {
|
||||
if (this.winnerList[pi].userId == userId) {
|
||||
this.thisPlayer = this.winnerList[pi];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//old
|
||||
|
||||
private comparer(otherArray) {
|
||||
return function (current) {
|
||||
return otherArray.filter(function (other) {
|
||||
return other.value == current.value && other.display == current.display
|
||||
}).length == 0;
|
||||
}
|
||||
}
|
||||
|
||||
private updateHand(newCards) {
|
||||
if (!newCards) { return; } //wenn fertig oder nicht begonnen tue nichts
|
||||
//prüfe differenz
|
||||
|
||||
newCards.forEach(el => {
|
||||
if ((this.handCards.filter(nel => el.id == nel.id)).length == 0) {
|
||||
this.handCards.push(el);
|
||||
}
|
||||
});
|
||||
this.handCards.forEach(el => {
|
||||
if ((newCards.filter(nel => el.id == nel.id)).length == 0) {
|
||||
this.handCards = this.handCards.filter(fel => fel.id != el.id);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
public leave() {
|
||||
this.conn.next({action: 'uibutton',button:'leave'});
|
||||
this.conn.complete();
|
||||
}
|
||||
|
||||
public ready() {
|
||||
this.conn.next({action: 'uibutton',button:'ready'});
|
||||
}
|
||||
|
||||
public skip() {
|
||||
this.conn.next({action: 'uibutton',button:'skip'});
|
||||
}
|
||||
|
||||
public uno() {
|
||||
this.conn.next({action: 'uibutton',button:'uno'});
|
||||
}
|
||||
|
||||
public pull() {
|
||||
this.conn.next({action: 'uibutton',button:'pull'});
|
||||
}
|
||||
|
||||
public play(card) {
|
||||
//
|
||||
let doubleFound = -1;
|
||||
this.handCards.forEach(el => {
|
||||
if (el.id != card.id && el.color == card.color && el.number == card.number && card.number != '+2' && card.number != 'wild+4'){
|
||||
doubleFound = el.id;
|
||||
this.doubleCard = el;
|
||||
}
|
||||
})
|
||||
console.log(doubleFound)
|
||||
if (doubleFound > -1){
|
||||
document.getElementById("open_rdouble_modal").click();
|
||||
}else{
|
||||
this.playSingle();
|
||||
}
|
||||
}
|
||||
|
||||
public playSingle() {
|
||||
console.log("play single ", this.selectedCard)
|
||||
this.conn.next({action: 'uibutton',button:'play',card:this.selectedCard});
|
||||
}
|
||||
|
||||
public playDouble(){
|
||||
console.log("play double ", this.selectedCard)
|
||||
this.conn.next({action: 'uibutton',button:'double',card:[this.selectedCard,this.doubleCard]});
|
||||
}
|
||||
|
||||
public playwild(number, color) {
|
||||
this.conn.next({action: 'uibutton',button:'play',card:{
|
||||
id: this.selectedCard.id,
|
||||
number: number,
|
||||
color: color,
|
||||
tx: this.selectedCard.tx,
|
||||
}});
|
||||
}
|
||||
|
||||
}
|
||||
22
UNO-Angular/src/app/start/start.component.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<div class="row h-100">
|
||||
<div class="col-sm-12 h-100 d-table">
|
||||
<div class="card card-block d-table-cell align-middle">
|
||||
<div class="start-box">
|
||||
<h1>Wie heißt du ?</h1>
|
||||
<br />
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="basic-addon1">@</span>
|
||||
</div>
|
||||
<input mdbInput type="text" class="form-control" placeholder="Username" aria-label="Username" aria-describedby="basic-addon1" [(ngModel)]="nick">
|
||||
</div>
|
||||
<span class="error" *ngIf="nick.length > 15">Der Benutzername ist zu lange</span>
|
||||
<span class="error" *ngIf="nick.length < 3">Der Benutzername ist zu kurz</span>
|
||||
<div class="input-group mb-3 ">
|
||||
<button block="true" [disabled]="!buttonEnabled || (nick.length > 15) || (nick.length < 3)" mdbBtn type="button" gradient="peach" rounded="true" mdbWavesEffect class="btn" (click)="start()">Abfahrt!</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
18
UNO-Angular/src/app/start/start.component.scss
Normal file
@@ -0,0 +1,18 @@
|
||||
.start-box {
|
||||
max-width: 500px;
|
||||
float: none;
|
||||
margin: 0 auto;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
font-weight: 500;
|
||||
padding-bottom: 2rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
49
UNO-Angular/src/app/start/start.component.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-start',
|
||||
templateUrl: './start.component.html',
|
||||
styleUrls: ['./start.component.scss']
|
||||
})
|
||||
export class StartComponent implements OnInit {
|
||||
|
||||
nick: string = "";
|
||||
buttonEnabled: boolean = true;
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private router: Router
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
let uname = localStorage.getItem('username');
|
||||
if (uname) {
|
||||
this.nick = uname;
|
||||
}
|
||||
}
|
||||
|
||||
public start() {
|
||||
//this.buttonEnabled = false;
|
||||
localStorage.setItem('username', this.nick);
|
||||
this.router.navigate(['/browser']);
|
||||
/*
|
||||
setTimeout(() => {
|
||||
console.log("start " + this.nick);
|
||||
this.httpClient.post("/unogame/join", { nick: this.nick }).subscribe(result => {
|
||||
const cres: any = result;
|
||||
this.buttonEnabled = true;
|
||||
if (cres.success) {
|
||||
console.log(cres.data)
|
||||
localStorage.setItem('uid', cres.data.userId);
|
||||
localStorage.setItem('username', this.nick);
|
||||
this.router.navigate(['/game']);
|
||||
}
|
||||
});
|
||||
}, 200);
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
0
UNO-Angular/src/assets/.gitkeep
Normal file
BIN
UNO-Angular/src/assets/cardPlace1.wav
Normal file
BIN
UNO-Angular/src/assets/cardSlide7.wav
Normal file
BIN
UNO-Angular/src/assets/cards/000.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
UNO-Angular/src/assets/cards/110.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/111.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
UNO-Angular/src/assets/cards/112.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
UNO-Angular/src/assets/cards/113.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/114.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
UNO-Angular/src/assets/cards/115.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
UNO-Angular/src/assets/cards/116.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
UNO-Angular/src/assets/cards/117.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
UNO-Angular/src/assets/cards/118.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/119.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
UNO-Angular/src/assets/cards/120.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/121.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
UNO-Angular/src/assets/cards/122.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
UNO-Angular/src/assets/cards/123.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/124.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
UNO-Angular/src/assets/cards/125.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
UNO-Angular/src/assets/cards/126.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
UNO-Angular/src/assets/cards/127.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
UNO-Angular/src/assets/cards/128.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/129.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
UNO-Angular/src/assets/cards/130.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/131.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
UNO-Angular/src/assets/cards/132.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/133.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/134.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
UNO-Angular/src/assets/cards/135.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/136.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
UNO-Angular/src/assets/cards/137.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
UNO-Angular/src/assets/cards/138.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
UNO-Angular/src/assets/cards/139.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
UNO-Angular/src/assets/cards/140.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
UNO-Angular/src/assets/cards/141.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
UNO-Angular/src/assets/cards/142.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
UNO-Angular/src/assets/cards/143.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
UNO-Angular/src/assets/cards/144.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
UNO-Angular/src/assets/cards/145.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
UNO-Angular/src/assets/cards/146.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/147.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
UNO-Angular/src/assets/cards/148.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
UNO-Angular/src/assets/cards/149.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/211.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
UNO-Angular/src/assets/cards/212.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/213.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
UNO-Angular/src/assets/cards/221.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
UNO-Angular/src/assets/cards/222.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
UNO-Angular/src/assets/cards/223.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
UNO-Angular/src/assets/cards/231.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
UNO-Angular/src/assets/cards/232.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
UNO-Angular/src/assets/cards/233.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
UNO-Angular/src/assets/cards/241.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
UNO-Angular/src/assets/cards/242.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
UNO-Angular/src/assets/cards/243.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
UNO-Angular/src/assets/cards/301.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
UNO-Angular/src/assets/cards/302.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
UNO-Angular/src/assets/cards/311.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
UNO-Angular/src/assets/cards/312.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
UNO-Angular/src/assets/cards/321.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
UNO-Angular/src/assets/cards/322.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
UNO-Angular/src/assets/cards/331.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
UNO-Angular/src/assets/cards/332.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
UNO-Angular/src/assets/cards/341.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
UNO-Angular/src/assets/cards/342.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
UNO-Angular/src/assets/cards/felt.jpg
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
UNO-Angular/src/assets/felt.jpg
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
UNO-Angular/src/assets/skip.wav
Normal file
BIN
UNO-Angular/src/assets/tick.wav
Normal file
BIN
UNO-Angular/src/assets/when.mp3
Normal file
3
UNO-Angular/src/environments/environment.prod.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const environment = {
|
||||
production: true
|
||||
};
|
||||
16
UNO-Angular/src/environments/environment.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false
|
||||
};
|
||||
|
||||
/*
|
||||
* For easier debugging in development mode, you can import the following file
|
||||
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
|
||||
*
|
||||
* This import should be commented out in production mode because it will have a negative impact
|
||||
* on performance if an error is thrown.
|
||||
*/
|
||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
||||
BIN
UNO-Angular/src/favicon.ico
Normal file
|
After Width: | Height: | Size: 948 B |
16
UNO-Angular/src/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Uno</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Playfair+Display&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body class="mat-typography" style="background : url(/assets/felt.jpg);">
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
12
UNO-Angular/src/main.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
69
UNO-Angular/src/polyfills.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
/***************************************************************************************************
|
||||
* Load `$localize` onto the global scope - used if i18n tags appear in Angular templates.
|
||||
*/
|
||||
import '@angular/localize/init';
|
||||
/**
|
||||
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||
* You can add your own extra polyfills to this file.
|
||||
*
|
||||
* This file is divided into 2 sections:
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
*
|
||||
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/guide/browser-support
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/**
|
||||
* Web Animations `@angular/platform-browser/animations`
|
||||
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
|
||||
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
|
||||
*/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||
* because those flags need to be set before `zone.js` being loaded, and webpack
|
||||
* will put import in the top of bundle, so user need to create a separate file
|
||||
* in this directory (for example: zone-flags.ts), and put the following flags
|
||||
* into that file, and then add the following code before importing zone.js.
|
||||
* import './zone-flags';
|
||||
*
|
||||
* The flags allowed in zone-flags.ts are listed here.
|
||||
*
|
||||
* The following flags will work for all browsers.
|
||||
*
|
||||
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
*
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
*
|
||||
* (window as any).__Zone_enable_cross_context_check = true;
|
||||
*
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
||||
|
||||
(window as any).global = window;
|
||||
4
UNO-Angular/src/styles.scss
Normal file
@@ -0,0 +1,4 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
|
||||
html, body { height: 100%; }
|
||||
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
||||
25
UNO-Angular/src/test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(path: string, deep?: boolean, filter?: RegExp): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||