mirror of https://github.com/OpenVidu/openvidu.git
openvidu-testapp first approach
parent
681309ecfb
commit
64a68bb42e
|
@ -32,7 +32,7 @@ var logger = window.Logger || console
|
|||
// }).eror(callback));
|
||||
// }
|
||||
|
||||
try {
|
||||
/*try {
|
||||
require('kurento-browser-extensions')
|
||||
} catch (error) {
|
||||
if (typeof getScreenConstraints === 'undefined') {
|
||||
|
@ -42,7 +42,7 @@ try {
|
|||
callback(new Error("This library is not enabled for screen sharing"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
var MEDIA_CONSTRAINTS = {
|
||||
audio: true,
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
import { OpenviduNgTestappPage } from './app.po';
|
||||
|
||||
describe('openvidu-ng-testapp App', () => {
|
||||
let page: OpenviduNgTestappPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new OpenviduNgTestappPage();
|
||||
});
|
||||
|
||||
it('should display message saying app works', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('app works!');
|
||||
});
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": [
|
||||
"es2016"
|
||||
],
|
||||
"outDir": "../dist/out-tsc-e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"types":[
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
{
|
||||
"name": "openvidu-ng-testapp",
|
||||
"version": "1.1.0",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "^2.4.0",
|
||||
"@angular/compiler": "^2.4.0",
|
||||
"@angular/core": "^2.4.0",
|
||||
"@angular/forms": "^2.4.0",
|
||||
"@angular/http": "^2.4.0",
|
||||
"@angular/platform-browser": "^2.4.0",
|
||||
"@angular/platform-browser-dynamic": "^2.4.0",
|
||||
"@angular/router": "^3.4.0",
|
||||
"core-js": "^2.4.1",
|
||||
"rxjs": "^5.1.0",
|
||||
"ts-helpers": "^1.1.1",
|
||||
"zone.js": "^0.7.6",
|
||||
"openvidu-browser": "1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.0.0-rc.1",
|
||||
"@angular/compiler-cli": "^2.4.0",
|
||||
"@types/jasmine": "2.5.38",
|
||||
"@types/node": "~6.0.60",
|
||||
"codelyzer": "~2.0.0",
|
||||
"jasmine-core": "~2.5.2",
|
||||
"jasmine-spec-reporter": "~3.2.0",
|
||||
"karma": "~1.4.1",
|
||||
"karma-chrome-launcher": "~2.0.0",
|
||||
"karma-cli": "~1.0.1",
|
||||
"karma-jasmine": "~1.1.0",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"karma-coverage-istanbul-reporter": "^0.2.0",
|
||||
"protractor": "~5.1.0",
|
||||
"ts-node": "~2.0.0",
|
||||
"tslint": "~4.4.2",
|
||||
"typescript": "~2.0.0"
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
<div *ngIf="!session">
|
||||
<h1>Join a video session</h1>
|
||||
<form (submit)="joinSession()" accept-charset="UTF-8">
|
||||
<div>
|
||||
<label>Participant:</label>
|
||||
<input type="text" name="participantId" [(ngModel)]="participantId" required>
|
||||
</div>
|
||||
<div>
|
||||
<label>Session:</label>
|
||||
<input type="text" name="sessionId" [(ngModel)]="sessionId" required>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" [(ngModel)]="joinWithVideo" id="join-with-video" name="join-with-video"> Send video
|
||||
<div *ngIf="joinWithVideo">
|
||||
<table>
|
||||
<tr>
|
||||
<th>Constraint</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>width</td>
|
||||
<td><input type="text" id="width" required></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>height</td>
|
||||
<td><input type="text" id="height" required></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>frameRate</td>
|
||||
<td><input type="text" id="frameRate" required></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" [(ngModel)]="joinWithAudio" id="join-with-audio" name="join-with-audio"> Send audio
|
||||
</div>
|
||||
<div>
|
||||
<input type="submit" name="commit" value="Join!">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div *ngIf="session">
|
||||
<h2>{{sessionId}}</h2>
|
||||
<input type="button" (click)="leaveSession()" value="Leave session">
|
||||
<input type="checkbox" id="toggle-video" name="toggle-video" [checked]="toggleVideo" (change)="updateToggleVideo($event)"> Toggle your video
|
||||
<input type="checkbox" id="toggle-audio" name="toggle-audio" [checked]="toggleAudio" (change)="updateToggleAudio($event)"> Toggle your audio
|
||||
<div>
|
||||
<div id="publisher"></div>
|
||||
<div id="subscriber"></div>
|
||||
<div *ngFor="let s of streams; let i = index">
|
||||
<div *ngIf="stats[i]">
|
||||
<div style="margin-left: 50px;">
|
||||
<input type="checkbox" id="toggle-state" name="toggle-state" [checked]="true" (change)="updateToggleState(i)"> Show conexion state
|
||||
<div [attr.id]="'state-' + i" style="display: block;">
|
||||
<p><b>Signaling state:</b> {{signalingState[i]}}</p>
|
||||
<p><b>ICE connection state:</b> {{iceConnectionState[i]}}</p>
|
||||
</div>
|
||||
<input type="checkbox" id="toggle-statistics" name="toggle-statistics" (change)="updateToggleStatistics(i)"> Show
|
||||
statistics
|
||||
<div>
|
||||
<h2 *ngIf="stats[i].bitrate">Bitrate: {{stats[i].bitrate}}</h2>
|
||||
<h2 *ngIf="stats[i].framerate">Framerate: {{stats[i].framerate}}</h2>
|
||||
</div>
|
||||
<table [attr.id]="'table-' + i" style="display: none;">
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Time</th>
|
||||
<th>Other attributes</th>
|
||||
</tr>
|
||||
<tr *ngFor="let st of stats[i].statsArray">
|
||||
<td>{{st.type}}</td>
|
||||
<td>{{st.timestamp}}</td>
|
||||
<td>{{getStatAttributes(st.res)}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,278 +0,0 @@
|
|||
import { Observable } from 'rxjs/Rx';
|
||||
import { enableDebugTools } from '@angular/platform-browser';
|
||||
import { Component } from '@angular/core';
|
||||
import { OpenVidu, Session, Publisher, Stream } from 'openvidu-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html'
|
||||
})
|
||||
export class AppComponent {
|
||||
|
||||
private openVidu: OpenVidu;
|
||||
private session: Session;
|
||||
private publisher: Publisher;
|
||||
|
||||
cameraOptions: any;
|
||||
|
||||
// Join form
|
||||
sessionId: string;
|
||||
participantId: string;
|
||||
|
||||
// Session
|
||||
streams: Stream[] = [];
|
||||
|
||||
// Publish options
|
||||
joinWithVideo: boolean = false;
|
||||
joinWithAudio: boolean = false;
|
||||
toggleVideo: boolean;
|
||||
toggleAudio: boolean;
|
||||
|
||||
//Statistics
|
||||
stats = [];
|
||||
bytesPrev = [];
|
||||
framesPrev = [];
|
||||
timestampPrev = [];
|
||||
signalingState = [];
|
||||
iceConnectionState = [];
|
||||
|
||||
|
||||
constructor() {
|
||||
this.generateParticipantInfo();
|
||||
//this.obtainSupportedConstraints();
|
||||
}
|
||||
|
||||
private generateParticipantInfo() {
|
||||
this.sessionId = "SessionA";
|
||||
this.participantId = "Participant" + Math.floor(Math.random() * 100);
|
||||
}
|
||||
|
||||
private addVideoTag(stream: Stream) {
|
||||
console.log("Stream added");
|
||||
let ind = (this.streams.push(stream) - 1);
|
||||
|
||||
this.signalingState[ind] = '';
|
||||
this.iceConnectionState[ind] = '';
|
||||
|
||||
//Connection events
|
||||
stream.getRTCPeerConnection().onsignalingstatechange = (event) => {
|
||||
this.signalingState[ind] += " => " + stream.getRTCPeerConnection().signalingState;
|
||||
console.info("Stream " + stream.getId() + " signaling state: " + stream.getRTCPeerConnection().signalingState);
|
||||
}
|
||||
|
||||
stream.getRTCPeerConnection().oniceconnectionstatechange = (event) => {
|
||||
/*if (stream.getRTCPeerConnection().iceconnectionstate === "failed" ||
|
||||
stream.getRTCPeerConnection().iceconnectionstate === "disconnected" ||
|
||||
stream.getRTCPeerConnection().iceconnectionstate === "closed") {
|
||||
// Handle the failure
|
||||
};*/
|
||||
this.iceConnectionState[ind] += " => " + stream.getRTCPeerConnection().iceConnectionState;
|
||||
console.info("Stream " + stream.getId() + " ice connection state: " + stream.getRTCPeerConnection().iceConnectionState);
|
||||
}
|
||||
|
||||
//For statistics
|
||||
this.timestampPrev.push(0);
|
||||
this.bytesPrev.push(0);
|
||||
this.framesPrev.push(0);
|
||||
}
|
||||
|
||||
private removeVideoTag(stream: Stream) {
|
||||
console.log("Stream removed");
|
||||
let index = this.streams.indexOf(stream);
|
||||
this.streams.splice(index, 1);
|
||||
|
||||
this.stats.splice(index, 1);
|
||||
this.timestampPrev.splice(index, 1);
|
||||
this.bytesPrev.splice(index, 1);
|
||||
this.framesPrev.splice(index, 1);
|
||||
|
||||
this.signalingState.splice(index, 1);
|
||||
this.iceConnectionState.splice(index, 1);
|
||||
}
|
||||
|
||||
joinSession() {
|
||||
let mediaConstraints = this.generateMediaConstraints();
|
||||
|
||||
console.log(mediaConstraints);
|
||||
|
||||
this.cameraOptions = {
|
||||
audio: this.joinWithAudio,
|
||||
video: this.joinWithVideo,
|
||||
data: true,
|
||||
mediaConstraints: mediaConstraints
|
||||
}
|
||||
this.joinSessionShared();
|
||||
}
|
||||
|
||||
joinSessionShared() {
|
||||
|
||||
this.toggleVideo = this.joinWithVideo;
|
||||
this.toggleAudio = this.joinWithAudio;
|
||||
|
||||
this.openVidu = new OpenVidu("wss://" + location.hostname + ":8443/");
|
||||
this.session = this.openVidu.initSession(this.sessionId);
|
||||
|
||||
this.session.on('streamCreated', (event) => {
|
||||
this.session.subscribe(event.stream, 'subscriber', {
|
||||
insertMode: 'append',
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
});
|
||||
this.addVideoTag(event.stream);
|
||||
});
|
||||
|
||||
this.session.on('streamDestroyed', (event) => {
|
||||
this.removeVideoTag(event.stream);
|
||||
});
|
||||
|
||||
this.session.connect(this.participantId, (error) => {
|
||||
|
||||
// If the connection is successful, initialize a publisher and publish to the session
|
||||
if (!error) {
|
||||
|
||||
// 4) Get your own camera stream with the desired resolution and publish it, only if the user is supposed to do so
|
||||
this.publisher = this.openVidu.initPublisher('publisher', this.cameraOptions);
|
||||
|
||||
// 5) Publish your stream
|
||||
this.session.publish(this.publisher);
|
||||
|
||||
this.intervalStats().subscribe();
|
||||
|
||||
} else {
|
||||
console.log('There was an error connecting to the session:', error.code, error.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
leaveSession() {
|
||||
this.session.disconnect();
|
||||
this.session = null;
|
||||
this.streams = [];
|
||||
this.generateParticipantInfo();
|
||||
}
|
||||
|
||||
updateToggleVideo(event) {
|
||||
this.publisher.publishVideo(event.target.checked);
|
||||
let msg = (event.target.checked) ? 'Publishing video...' : 'Unpublishing video...'
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
updateToggleAudio(event) {
|
||||
this.publisher.publishAudio(event.target.checked);
|
||||
let msg = (event.target.checked) ? 'Publishing audio...' : 'Unpublishing audio...'
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
updateToggleStatistics(i) {
|
||||
let table = (<HTMLInputElement>document.getElementById('table-' + i));
|
||||
(table.style.display == "none") ? table.style.display = "block" : table.style.display = "none";
|
||||
}
|
||||
|
||||
updateToggleState(i) {
|
||||
let state = (<HTMLInputElement>document.getElementById('state-' + i));
|
||||
(state.style.display == "none") ? state.style.display = "block" : state.style.display = "none";
|
||||
}
|
||||
|
||||
/*obtainSupportedConstraints() {
|
||||
let constraints = Object.keys(navigator.mediaDevices.getSupportedConstraints());
|
||||
this.supportedVideoContstraints = constraints.filter((e) => {
|
||||
return this.mediaTrackSettingsVideo.indexOf(e) > -1;
|
||||
});
|
||||
this.supportedAudioContstraints = constraints.filter((e) => {
|
||||
return this.mediaTrackSettingsAudio.indexOf(e) > -1;
|
||||
});
|
||||
|
||||
console.log(constraints);
|
||||
console.log(this.supportedVideoContstraints);
|
||||
console.log(this.supportedAudioContstraints);
|
||||
}*/
|
||||
|
||||
generateMediaConstraints() {
|
||||
let mediaConstraints = {
|
||||
audio: true,
|
||||
video: {}
|
||||
}
|
||||
if (this.joinWithVideo) {
|
||||
mediaConstraints.video['width'] = { exact: Number((<HTMLInputElement>document.getElementById('width')).value) };
|
||||
mediaConstraints.video['height'] = { exact: Number((<HTMLInputElement>document.getElementById('height')).value) };
|
||||
mediaConstraints.video['frameRate'] = { ideal: Number((<HTMLInputElement>document.getElementById('frameRate')).value) };
|
||||
}
|
||||
|
||||
return mediaConstraints;
|
||||
}
|
||||
|
||||
|
||||
intervalStats() {
|
||||
return Observable
|
||||
.interval(1000)
|
||||
.flatMap(() => {
|
||||
let i = 0;
|
||||
for (let str of this.streams) {
|
||||
if (str.getWebRtcPeer().peerConnection) {
|
||||
this.intervalStatsAux(i, str);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
intervalStatsAux(i: number, stream: Stream) {
|
||||
stream.getWebRtcPeer().peerConnection.getStats(null)
|
||||
.then((results) => {
|
||||
this.stats[i] = this.dumpStats(results, i);
|
||||
console.info(results);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
dumpStats(results, i) {
|
||||
var statsArray = [];
|
||||
let bitrate;
|
||||
let frames;
|
||||
|
||||
results.forEach((res) => {
|
||||
let date = new Date(res.timestamp);
|
||||
statsArray.push({ res: res, type: res.type, timestamp: date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() });
|
||||
|
||||
let now = res.timestamp;
|
||||
|
||||
if (res.type === 'inbound-rtp' && res.mediaType === 'video') {
|
||||
// firefox calculates the bitrate for us
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=951496
|
||||
bitrate = Math.floor(res.bitrateMean / 1024);
|
||||
if (res.framerateMean !== undefined && res.frameRate != "0") {
|
||||
frames = (res.framerateMean).toFixed(2);
|
||||
}
|
||||
|
||||
} else if (res.type === 'ssrc' && res.bytesReceived && res.googFrameRateReceived) {
|
||||
// chrome does not so we need to do it ourselves
|
||||
var bytes = res.bytesReceived;
|
||||
frames = (res.googFrameRateOutput == "0") ? Number(this.framesPrev[i]) : Number(res.googFrameRateOutput);
|
||||
if (this.timestampPrev[i]) {
|
||||
bitrate = 8 * (bytes - this.bytesPrev[i]) / (now - this.timestampPrev[i]);
|
||||
bitrate = Math.floor(bitrate);
|
||||
}
|
||||
this.bytesPrev[i] = bytes;
|
||||
this.timestampPrev[i] = now;
|
||||
}
|
||||
|
||||
});
|
||||
if (bitrate) {
|
||||
bitrate += ' kbits/sec';
|
||||
}
|
||||
if (frames) {
|
||||
this.framesPrev[i] = frames;
|
||||
frames += ' fps';
|
||||
}
|
||||
return { statsArray: statsArray, bitrate: bitrate, framerate: frames };
|
||||
}
|
||||
|
||||
getStatAttributes(stat) {
|
||||
let s = '';
|
||||
Object.keys(stat).forEach((key) => {
|
||||
if (key != 'type' && key != 'timestamp') s += (' | ' + key + ' | ');
|
||||
});
|
||||
return s;
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpModule } from '@angular/http';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { StreamComponent } from "./stream.component";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent, StreamComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
HttpModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
|
@ -1,2 +0,0 @@
|
|||
export * from './app.component';
|
||||
export * from './app.module';
|
|
@ -1,46 +0,0 @@
|
|||
import { Component, OnInit, Input, ViewChild } from '@angular/core';
|
||||
import { Stream, Session } from 'openvidu-browser';
|
||||
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'stream',
|
||||
styles: [`
|
||||
.participant {
|
||||
margin: 10px;
|
||||
}
|
||||
.participant video {
|
||||
|
||||
}`],
|
||||
template: `
|
||||
<div class='participant'>
|
||||
<p>{{stream.getId()}}</p>
|
||||
<video *ngIf="!stream.local" autoplay="true" [src]="videoSrc"></video>
|
||||
<video *ngIf="stream.local" autoplay="true" [src]="videoSrc" muted></video>
|
||||
</div>`
|
||||
})
|
||||
export class StreamComponent {
|
||||
|
||||
@Input()
|
||||
stream: Stream;
|
||||
|
||||
videoSrc: SafeUrl;
|
||||
|
||||
constructor(private sanitizer: DomSanitizer) { }
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
let int = setInterval(() => {
|
||||
if (this.stream.getWrStream()) {
|
||||
this.videoSrc = this.sanitizer.bypassSecurityTrustUrl(
|
||||
URL.createObjectURL(this.stream.getWrStream()));
|
||||
console.log("Video tag src=" + this.videoSrc);
|
||||
clearInterval(int);
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
//this.stream.addEventListener('src-added', () => {
|
||||
// this.video.src = this.sanitizer.bypassSecurityTrustUrl(URL.createObjectURL(this.stream.getWrStream())).toString();
|
||||
//});
|
||||
}
|
||||
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
// This file includes polyfills needed by Angular 2 and is loaded before
|
||||
// the app. You can add your own extra polyfills to this file.
|
||||
import 'core-js/es6/symbol';
|
||||
import 'core-js/es6/object';
|
||||
import 'core-js/es6/function';
|
||||
import 'core-js/es6/parse-int';
|
||||
import 'core-js/es6/parse-float';
|
||||
import 'core-js/es6/number';
|
||||
import 'core-js/es6/math';
|
||||
import 'core-js/es6/string';
|
||||
import 'core-js/es6/date';
|
||||
import 'core-js/es6/array';
|
||||
import 'core-js/es6/regexp';
|
||||
import 'core-js/es6/map';
|
||||
import 'core-js/es6/set';
|
||||
import 'core-js/es6/reflect';
|
||||
|
||||
import 'core-js/es7/reflect';
|
||||
import 'zone.js/dist/zone';
|
|
@ -1 +0,0 @@
|
|||
/* You can add global styles to this file, and also import other style files */
|
|
@ -1,34 +0,0 @@
|
|||
import './polyfills.ts';
|
||||
|
||||
import 'zone.js/dist/long-stack-trace-zone';
|
||||
import 'zone.js/dist/proxy.js';
|
||||
import 'zone.js/dist/sync-test';
|
||||
import 'zone.js/dist/jasmine-patch';
|
||||
import 'zone.js/dist/async-test';
|
||||
import 'zone.js/dist/fake-async-test';
|
||||
|
||||
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
|
||||
declare var __karma__: any;
|
||||
declare var require: any;
|
||||
|
||||
// Prevent Karma from running prematurely.
|
||||
__karma__.loaded = function () {};
|
||||
|
||||
|
||||
Promise.all([
|
||||
System.import('@angular/core/testing'),
|
||||
System.import('@angular/platform-browser-dynamic/testing')
|
||||
])
|
||||
// First, initialize the Angular testing environment.
|
||||
.then(([testing, testingBrowser]) => {
|
||||
testing.getTestBed().initTestEnvironment(
|
||||
testingBrowser.BrowserDynamicTestingModule,
|
||||
testingBrowser.platformBrowserDynamicTesting()
|
||||
);
|
||||
})
|
||||
// Then we find all the tests.
|
||||
.then(() => require.context('./', true, /\.spec\.ts/))
|
||||
// And load the modules.
|
||||
.then(context => context.keys().map(context))
|
||||
// Finally, start Karma to run the tests.
|
||||
.then(__karma__.start, __karma__.error);
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": [
|
||||
"es2016",
|
||||
"dom"
|
||||
],
|
||||
"outDir": "../out-tsc/app",
|
||||
"target": "es5",
|
||||
"module": "es2015",
|
||||
"baseUrl": "",
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": [
|
||||
"es2016"
|
||||
],
|
||||
"outDir": "../out-tsc/spec",
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"baseUrl": "",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
// Typings reference file, see links for more information
|
||||
// https://github.com/typings/typings
|
||||
// https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html
|
||||
|
||||
declare var System: any;
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"project": {
|
||||
"name": "openvidu-ng-testapp"
|
||||
"name": "openvidu-testapp"
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
|
@ -19,7 +19,8 @@
|
|||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
"styles": [
|
||||
"styles.css"
|
||||
"styles.css",
|
||||
"openvidu-theme.scss"
|
||||
],
|
||||
"scripts": [],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
|
@ -36,13 +37,16 @@
|
|||
},
|
||||
"lint": [
|
||||
{
|
||||
"project": "src/tsconfig.app.json"
|
||||
"project": "src/tsconfig.app.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "src/tsconfig.spec.json"
|
||||
"project": "src/tsconfig.spec.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "e2e/tsconfig.e2e.json"
|
||||
"project": "e2e/tsconfig.e2e.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
}
|
||||
],
|
||||
"test": {
|
|
@ -3,6 +3,7 @@
|
|||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
@ -26,7 +27,7 @@
|
|||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage/*
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
testem.log
|
||||
|
@ -36,6 +37,6 @@ testem.log
|
|||
/e2e/*.js
|
||||
/e2e/*.map
|
||||
|
||||
#System Files
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
|
@ -1,13 +1,14 @@
|
|||
# OpenviduNgTestapp
|
||||
# OpenviduTestApp
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.0.0-rc.1.
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.4.3.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`.
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
|
@ -20,7 +21,6 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.
|
|||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
Before running the tests make sure you are serving the app via `ng serve`.
|
||||
|
||||
## Further help
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import { AppPage } from './app.po';
|
||||
|
||||
describe('openvidu-testapp App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to app!');
|
||||
});
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
import { browser, element, by } from 'protractor';
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class OpenviduNgTestappPage {
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/0.13/config/configuration-file.html
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
|
@ -15,15 +15,6 @@ module.exports = function (config) {
|
|||
client:{
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
files: [
|
||||
{ pattern: './src/test.ts', watched: false }
|
||||
],
|
||||
preprocessors: {
|
||||
'./src/test.ts': ['@angular/cli']
|
||||
},
|
||||
mime: {
|
||||
'text/x-typescript': ['ts','tsx']
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
|
@ -31,9 +22,7 @@ module.exports = function (config) {
|
|||
angularCli: {
|
||||
environment: 'dev'
|
||||
},
|
||||
reporters: config.angularCli && config.angularCli.codeCoverage
|
||||
? ['progress', 'coverage-istanbul']
|
||||
: ['progress', 'kjhtml'],
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "openvidu-testapp",
|
||||
"version": "0.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^4.4.3",
|
||||
"@angular/cdk": "^2.0.0-beta.11",
|
||||
"@angular/common": "^4.2.4",
|
||||
"@angular/compiler": "^4.2.4",
|
||||
"@angular/core": "^4.2.4",
|
||||
"@angular/flex-layout": "^2.0.0-beta.9",
|
||||
"@angular/forms": "^4.2.4",
|
||||
"@angular/http": "^4.2.4",
|
||||
"@angular/material": "^2.0.0-beta.11",
|
||||
"@angular/platform-browser": "^4.2.4",
|
||||
"@angular/platform-browser-dynamic": "^4.2.4",
|
||||
"@angular/router": "^4.2.4",
|
||||
"core-js": "^2.4.1",
|
||||
"hammerjs": "^2.0.8",
|
||||
"openvidu-browser": "1.1.0",
|
||||
"openvidu-node-client": "1.1.0",
|
||||
"rxjs": "^5.4.2",
|
||||
"zone.js": "^0.8.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.4.3",
|
||||
"@angular/compiler-cli": "^4.2.4",
|
||||
"@angular/language-service": "^4.2.4",
|
||||
"@types/jasmine": "~2.5.53",
|
||||
"@types/jasminewd2": "~2.0.2",
|
||||
"@types/node": "~6.0.60",
|
||||
"codelyzer": "~3.1.1",
|
||||
"jasmine-core": "~2.6.2",
|
||||
"jasmine-spec-reporter": "~4.1.0",
|
||||
"karma": "~1.7.0",
|
||||
"karma-chrome-launcher": "~2.1.1",
|
||||
"karma-cli": "~1.0.1",
|
||||
"karma-coverage-istanbul-reporter": "^1.2.1",
|
||||
"karma-jasmine": "~1.1.0",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"protractor": "~5.1.2",
|
||||
"ts-node": "~3.2.0",
|
||||
"tslint": "~5.3.2",
|
||||
"typescript": "~2.3.3"
|
||||
}
|
||||
}
|
|
@ -19,12 +19,10 @@ exports.config = {
|
|||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
beforeLaunch: function() {
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
},
|
||||
onPrepare() {
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
#nav-img {
|
||||
height: 32px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 50px
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<md-sidenav-container fullscreen>
|
||||
<md-toolbar class="mat-elevation-z5" color="primary">
|
||||
<div layout-align='center center' layout='column'>
|
||||
<a routerLink="/"><img id="nav-img" src="assets/images/openvidu_vert_white_bg_trans_cropped.png"/> TestApp</a>
|
||||
</div>
|
||||
</md-toolbar>
|
||||
<main>
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
</md-sidenav-container>
|
|
@ -0,0 +1,27 @@
|
|||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
}));
|
||||
it('should create the app', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
}));
|
||||
it(`should have as title 'app'`, async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app.title).toEqual('app');
|
||||
}));
|
||||
it('should render title in a h1 tag', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
|
||||
}));
|
||||
});
|
|
@ -0,0 +1,17 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {
|
||||
|
||||
constructor(private router: Router) { }
|
||||
|
||||
isVideoSessionUrl() {
|
||||
return (this.router.url.substring(0, '/lesson/'.length) === '/lesson/');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import {
|
||||
MdButtonModule,
|
||||
MdIconModule,
|
||||
MdCheckboxModule,
|
||||
MdCardModule,
|
||||
MdInputModule,
|
||||
MdProgressSpinnerModule,
|
||||
MdTooltipModule,
|
||||
MdDialogModule,
|
||||
MdToolbarModule,
|
||||
MdTabsModule,
|
||||
MdSlideToggleModule
|
||||
} from '@angular/material';
|
||||
|
||||
@NgModule({
|
||||
exports: [
|
||||
BrowserAnimationsModule,
|
||||
MdButtonModule,
|
||||
MdIconModule,
|
||||
MdCheckboxModule,
|
||||
MdCardModule,
|
||||
MdInputModule,
|
||||
MdProgressSpinnerModule,
|
||||
MdTooltipModule,
|
||||
MdDialogModule,
|
||||
MdToolbarModule,
|
||||
MdTabsModule,
|
||||
MdSlideToggleModule
|
||||
],
|
||||
})
|
||||
export class AppMaterialModule { }
|
|
@ -0,0 +1,32 @@
|
|||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { AppMaterialModule } from './app.material.module';
|
||||
|
||||
import { routing } from './app.routing';
|
||||
import { AppComponent } from './app.component';
|
||||
import { DashboardComponent } from './components/dashboard/dashboard.component';
|
||||
import { SessionComponent } from './components/session/session.component';
|
||||
|
||||
import { OpenviduRestService } from './services/openvidu-rest.service';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
DashboardComponent,
|
||||
SessionComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
BrowserAnimationsModule,
|
||||
AppMaterialModule,
|
||||
FlexLayoutModule,
|
||||
routing
|
||||
],
|
||||
providers: [OpenviduRestService],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
|
@ -0,0 +1,18 @@
|
|||
import { ModuleWithProviders } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { DashboardComponent } from './components/dashboard/dashboard.component';
|
||||
import { SessionComponent } from './components/session/session.component';
|
||||
|
||||
const appRoutes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DashboardComponent
|
||||
},
|
||||
{
|
||||
path: 'session/:session-name',
|
||||
component: SessionComponent
|
||||
}
|
||||
];
|
||||
|
||||
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);
|
|
@ -0,0 +1,41 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import {
|
||||
MdButtonModule,
|
||||
MdIconModule,
|
||||
MdCheckboxModule,
|
||||
MdCardModule,
|
||||
MdInputModule,
|
||||
MdProgressSpinnerModule,
|
||||
MdTooltipModule,
|
||||
MdDialogModule,
|
||||
MdSlideToggleModule
|
||||
} from '@angular/material';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
MdButtonModule,
|
||||
MdIconModule,
|
||||
MdCheckboxModule,
|
||||
MdCardModule,
|
||||
MdInputModule,
|
||||
MdProgressSpinnerModule,
|
||||
MdTooltipModule,
|
||||
MdDialogModule,
|
||||
MdSlideToggleModule
|
||||
],
|
||||
exports: [
|
||||
BrowserAnimationsModule,
|
||||
MdButtonModule,
|
||||
MdIconModule,
|
||||
MdCheckboxModule,
|
||||
MdCardModule,
|
||||
MdInputModule,
|
||||
MdProgressSpinnerModule,
|
||||
MdTooltipModule,
|
||||
MdDialogModule,
|
||||
MdSlideToggleModule
|
||||
],
|
||||
})
|
||||
export class AppMaterialModule { }
|
|
@ -0,0 +1,93 @@
|
|||
#join-dialog h1 {
|
||||
color: #4d4d4d;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#img-div {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: 19%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
#img-div img {
|
||||
height: 15%;
|
||||
}
|
||||
|
||||
#join-dialog label {
|
||||
color: #0088aa;
|
||||
}
|
||||
|
||||
#join-dialog input.btn {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
#session-header {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#session-title {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#buttonLeaveSession {
|
||||
float: right;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#video-container video {
|
||||
position: relative;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#video-container p {
|
||||
display: inline-block;
|
||||
background: #f8f8f8;
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
color: #777777;
|
||||
font-weight: bold;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
video {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#main-video p {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
background: #f8f8f8;
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
left: 0;
|
||||
font-size: 22px;
|
||||
color: #777777;
|
||||
font-weight: bold;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
#main-video video {
|
||||
cursor: initial;
|
||||
}
|
||||
|
||||
#session img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: inline-block;
|
||||
object-fit: contain;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
#session #video-container img {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 50%;
|
||||
cursor: pointer;
|
||||
object-fit: cover;
|
||||
height: 180px;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
<md-tab-group class="demo-tab-group" dynamicHeight="true">
|
||||
<md-tab id="audio-video" label="Audio + Video">
|
||||
<div class="demo-tab-content">
|
||||
|
||||
</div>
|
||||
</md-tab>
|
||||
<md-tab id="audio-only" label="Audio only">
|
||||
<div class="demo-tab-content">
|
||||
|
||||
</div>
|
||||
</md-tab>
|
||||
<md-tab id="video-only" label="Video only">
|
||||
|
||||
</md-tab>
|
||||
<md-tab id="screen-audio" label="Screen + Audio">
|
||||
<div class="demo-tab-content">
|
||||
|
||||
</div>
|
||||
</md-tab>
|
||||
<md-tab id="screen-only" label="Screen only">
|
||||
|
||||
</md-tab>
|
||||
<md-tab id="api-rest" label="API REST">
|
||||
<button md-raised-button color="primary" (click)="getSessionId()">Get sessionId</button>
|
||||
<button md-raised-button color="primary" (click)="getToken()">Get token</button>
|
||||
</md-tab>
|
||||
</md-tab-group>
|
||||
|
||||
<!--<div id="join">
|
||||
<div id="img-div"><img src="assets/images/openvidu_grey_bg_transp_cropped.png" /></div>
|
||||
<div id="join-dialog" class="jumbotron vertical-center">
|
||||
<h1>Join a video session</h1>
|
||||
<form class="form-group" (submit)="joinSession()">
|
||||
<p>
|
||||
<label>Participant</label>
|
||||
<input class="form-control" type="text" id="clientData" name="clientData" [(ngModel)]="clientData" required>
|
||||
</p>
|
||||
<p>
|
||||
<label>Session</label>
|
||||
<input class="form-control" type="text" id="sessionName" name="sessionName" [(ngModel)]="sessionName" required>
|
||||
</p>
|
||||
<p class="text-center">
|
||||
<input class="btn btn-lg btn-success" type="submit" name="commit" value="Join!">
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>-->
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DashboardComponent } from './dashboard.component';
|
||||
|
||||
describe('DashboardComponent', () => {
|
||||
let component: DashboardComponent;
|
||||
let fixture: ComponentFixture<DashboardComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ DashboardComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DashboardComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,45 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { OpenviduRestService } from '../../services/openvidu-rest.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
templateUrl: './dashboard.component.html',
|
||||
styleUrls: ['./dashboard.component.css']
|
||||
})
|
||||
export class DashboardComponent implements OnInit {
|
||||
|
||||
// Join form
|
||||
sessionName: string;
|
||||
clientData: string;
|
||||
|
||||
constructor(private openviduRestService: OpenviduRestService) {
|
||||
this.generateSessionInfo();
|
||||
}
|
||||
|
||||
ngOnInit() { }
|
||||
|
||||
private generateSessionInfo() {
|
||||
this.sessionName = 'TestSession';
|
||||
this.clientData = 'RandomClient' + Math.floor(Math.random() * 100);
|
||||
}
|
||||
|
||||
private getSessionId() {
|
||||
this.openviduRestService.getSessionId()
|
||||
.then((sessionId) => {
|
||||
alert(sessionId);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error getting a sessionId', error);
|
||||
});
|
||||
}
|
||||
|
||||
private getToken() {
|
||||
this.openviduRestService.getToken()
|
||||
.then((token) => {
|
||||
alert(token);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error getting a token', error);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<div *ngIf="session" id="session">
|
||||
<div id="session-header">
|
||||
<h1 id="session-title">{{sessionName}}</h1>
|
||||
<input class="btn btn-large btn-danger" type="button" id="buttonLeaveSession" (click)="leaveSession()" value="Leave session">
|
||||
</div>
|
||||
<div id="main-video" class="col-md-6">
|
||||
<p></p>
|
||||
<video #mainVideoElement autoplay></video>
|
||||
</div>
|
||||
<div id="video-container" class="col-md-6"></div>
|
||||
</div>
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SessionComponent } from './session.component';
|
||||
|
||||
describe('SessionComponent', () => {
|
||||
let component: SessionComponent;
|
||||
let fixture: ComponentFixture<SessionComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SessionComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SessionComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,135 @@
|
|||
import { OpenVidu, Session } from 'openvidu-browser';
|
||||
import { Component, ElementRef, ViewChild, HostListener, OnDestroy } from '@angular/core';
|
||||
|
||||
declare var $: any;
|
||||
|
||||
@Component({
|
||||
selector: 'app-session',
|
||||
templateUrl: './session.component.html',
|
||||
styleUrls: ['./session.component.css']
|
||||
})
|
||||
export class SessionComponent implements OnDestroy {
|
||||
|
||||
@ViewChild('mainVideoElement') elementRef: ElementRef;
|
||||
mainVideoElement: HTMLVideoElement;
|
||||
|
||||
// OpenVidu objects
|
||||
OV: OpenVidu;
|
||||
session: Session;
|
||||
|
||||
// Join form
|
||||
sessionName: string;
|
||||
clientData: string;
|
||||
|
||||
constructor() { }
|
||||
|
||||
@HostListener('window:beforeunload')
|
||||
beforeunloadHandler() {
|
||||
// On window closed leave session
|
||||
this.leaveSession();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
// On component destroyed leave session
|
||||
this.leaveSession();
|
||||
}
|
||||
|
||||
joinSession() {
|
||||
|
||||
this.OV = new OpenVidu();
|
||||
|
||||
this.session = this.OV.initSession('wss://' + location.hostname + ':8443/' + this.sessionName + '?secret=MY_SECRET');
|
||||
|
||||
this.mainVideoElement = this.elementRef.nativeElement;
|
||||
|
||||
this.session.on('streamCreated', (event) => {
|
||||
const subscriber = this.session.subscribe(event.stream, 'video-container');
|
||||
subscriber.on('videoElementCreated', (e) => {
|
||||
this.appendUserData(e.element, subscriber.stream.connection);
|
||||
});
|
||||
});
|
||||
|
||||
this.session.on('streamDestroyed', (event) => {
|
||||
this.removeUserData(event.stream.connection);
|
||||
});
|
||||
|
||||
this.session.connect(null, this.clientData, (error) => {
|
||||
|
||||
if (!error) {
|
||||
const publisher = this.OV.initPublisher('video-container', {
|
||||
audio: true,
|
||||
video: true,
|
||||
quality: 'MEDIUM'
|
||||
});
|
||||
|
||||
publisher.on('videoElementCreated', (event) => {
|
||||
this.initMainVideo(event.element, this.clientData);
|
||||
this.appendUserData(event.element, this.clientData);
|
||||
event.element['muted'] = true;
|
||||
});
|
||||
|
||||
this.session.publish(publisher);
|
||||
|
||||
} else {
|
||||
console.log('There was an error connecting to the session:', error.code, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
leaveSession() {
|
||||
if (this.OV) {
|
||||
this.session.disconnect();
|
||||
}
|
||||
this.removeAllUserData();
|
||||
this.session = null;
|
||||
this.OV = null;
|
||||
}
|
||||
|
||||
private appendUserData(videoElement, connection) {
|
||||
let userData;
|
||||
let nodeId;
|
||||
if (typeof connection === 'string') {
|
||||
userData = connection;
|
||||
nodeId = connection;
|
||||
} else {
|
||||
userData = JSON.parse(connection.data).clientData;
|
||||
nodeId = connection.connectionId;
|
||||
}
|
||||
const dataNode = document.createElement('div');
|
||||
dataNode.className = 'data-node';
|
||||
dataNode.id = 'data-' + nodeId;
|
||||
dataNode.innerHTML = '<p>' + userData + '</p>';
|
||||
videoElement.parentNode.insertBefore(dataNode, videoElement.nextSibling);
|
||||
this.addClickListener(videoElement, userData);
|
||||
}
|
||||
|
||||
private removeUserData(connection) {
|
||||
const dataNode = $('#data-' + connection.connectionId);
|
||||
dataNode.parentNode.removeChild(dataNode);
|
||||
}
|
||||
|
||||
private removeAllUserData() {
|
||||
const nicknameElements = $('.data-node');
|
||||
while (nicknameElements[0]) {
|
||||
nicknameElements[0].parentNode.removeChild(nicknameElements[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private addClickListener(videoElement: HTMLVideoElement, userData) {
|
||||
videoElement.addEventListener('click', () => {
|
||||
const mainUserData = $('#main-video p');
|
||||
if (this.mainVideoElement.srcObject !== videoElement.srcObject) {
|
||||
mainUserData.innerHTML = userData;
|
||||
this.mainVideoElement.srcObject = videoElement.srcObject;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private initMainVideo(videoElement: HTMLVideoElement, userData) {
|
||||
this.mainVideoElement.srcObject = videoElement.srcObject;
|
||||
$('#main-video p').innerHTML = userData;
|
||||
this.mainVideoElement['muted'] = true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { OpenviduRestService } from './openvidu-rest.service';
|
||||
|
||||
describe('OpenviduRestService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [OpenviduRestService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([OpenviduRestService], (service: OpenviduRestService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
OpenVidu as OpenViduAPI,
|
||||
Session as SessionAPI,
|
||||
TokenOptions as TokenOptionsAPI,
|
||||
OpenViduRole as OpenViduRoleAPI
|
||||
} from 'openvidu-node-client';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable()
|
||||
export class OpenviduRestService {
|
||||
|
||||
constructor() { }
|
||||
|
||||
getSessionId(): Promise<String> {
|
||||
const OV = new OpenViduAPI(environment.OPENVIDU_URL, environment.OPENVIDU_SECRET);
|
||||
const session = OV.createSession();
|
||||
|
||||
return new Promise(resolve => {
|
||||
session.getSessionId((sessionId) => {
|
||||
resolve(sessionId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getToken(): Promise<String> {
|
||||
const OV = new OpenViduAPI(environment.OPENVIDU_URL, environment.OPENVIDU_SECRET);
|
||||
const session = OV.createSession();
|
||||
|
||||
return new Promise(resolve => {
|
||||
let tokenOptions: TokenOptionsAPI;
|
||||
session.generateToken((token) => {
|
||||
resolve(token);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { SessionConfService } from './session-conf.service';
|
||||
|
||||
describe('SessionConfService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [SessionConfService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([SessionConfService], (service: SessionConfService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
|
@ -0,0 +1,17 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
|
||||
@Injectable()
|
||||
export class SessionConfService {
|
||||
|
||||
private conf$ = new Subject();
|
||||
|
||||
getConf() {
|
||||
return this.conf$;
|
||||
}
|
||||
|
||||
updateConf(configuration: any) {
|
||||
this.conf$.next(configuration);
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -1,8 +1,10 @@
|
|||
// The file contents for the current environment will overwrite these during build.
|
||||
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||
// The list of which env maps to which file can be found in `angular-cli.json`.
|
||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false
|
||||
production: false,
|
||||
OPENVIDU_URL: 'https://localhost:8443',
|
||||
OPENVIDU_SECRET: 'MY_SECRET'
|
||||
};
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
@ -1,14 +1,20 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>OpenviduNg2Example</title>
|
||||
<title>OpenVidu TestApp</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/icon?family=Material+Icons" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<app-root>Loading...</app-root>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,12 +1,14 @@
|
|||
import './polyfills.ts';
|
||||
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
import { AppModule } from './app/';
|
||||
|
||||
import 'hammerjs';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.log(err));
|
|
@ -0,0 +1,57 @@
|
|||
@import '~@angular/material/theming';
|
||||
// Plus imports for other components in your app.
|
||||
|
||||
// Include the common styles for Angular Material. We include this here so that you only
|
||||
// have to load a single css file for Angular Material in your app.
|
||||
// Be sure that you only ever include this mixin once!
|
||||
@include mat-core();
|
||||
|
||||
$mat-openvidu: (
|
||||
50: #eaeaea,
|
||||
100: #cacaca,
|
||||
200: #a6a6a6,
|
||||
300: #828282,
|
||||
400: #686868,
|
||||
500: #4d4d4d,
|
||||
600: #464646,
|
||||
700: #3d3d3d,
|
||||
800: #343434,
|
||||
900: #252525,
|
||||
A100: #83E9B1,
|
||||
A200: #06D362,
|
||||
A400: #04C850,
|
||||
A700: #02B734,
|
||||
contrast: (
|
||||
50 : #fff9e0,
|
||||
100 : #fff0b3,
|
||||
200 : #ffe680,
|
||||
300 : #ffdb4d,
|
||||
400 : #ffd426,
|
||||
500 : #ffcc00,
|
||||
600 : #ffc700,
|
||||
700 : #ffc000,
|
||||
800 : #ffb900,
|
||||
900 : #ffad00,
|
||||
A100 : #ffffff,
|
||||
A200 : #fffaf2,
|
||||
A400 : #ffe8bf,
|
||||
A700 : #ffdfa6,
|
||||
)
|
||||
);
|
||||
|
||||
// Define the palettes for your theme using the Material Design palettes available in palette.scss
|
||||
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
|
||||
// hue.
|
||||
$openvidu-primary: mat-palette($mat-openvidu);
|
||||
$openvidu-accent: mat-palette($mat-openvidu, A200, A100, A400);
|
||||
|
||||
// The warn palette is optional (defaults to red).
|
||||
$openvidu-warn: mat-palette($mat-red);
|
||||
|
||||
// Create the theme object (a Sass map containing all of the palettes).
|
||||
$openvidu-theme: mat-light-theme($openvidu-primary, $openvidu-accent, $openvidu-warn);
|
||||
|
||||
// Include theme styles for core and each component used in your app.
|
||||
// Alternatively, you can import and @include the theme mixins for each component
|
||||
// that you are using.
|
||||
@include angular-material-theme($openvidu-theme);
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* 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/docs/ts/latest/guide/browser-support.html
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
|
||||
// import 'core-js/es6/symbol';
|
||||
// import 'core-js/es6/object';
|
||||
// import 'core-js/es6/function';
|
||||
// import 'core-js/es6/parse-int';
|
||||
// import 'core-js/es6/parse-float';
|
||||
// import 'core-js/es6/number';
|
||||
// import 'core-js/es6/math';
|
||||
// import 'core-js/es6/string';
|
||||
// import 'core-js/es6/date';
|
||||
// import 'core-js/es6/array';
|
||||
// import 'core-js/es6/regexp';
|
||||
// import 'core-js/es6/map';
|
||||
// import 'core-js/es6/weak-map';
|
||||
// import 'core-js/es6/set';
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/** Evergreen browsers require these. **/
|
||||
import 'core-js/es6/reflect';
|
||||
import 'core-js/es7/reflect';
|
||||
|
||||
|
||||
/**
|
||||
* Required to support Web Animations `@angular/platform-browser/animations`.
|
||||
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
|
||||
**/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Date, currency, decimal and percent pipes.
|
||||
* Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
|
||||
*/
|
||||
// import 'intl'; // Run `npm install --save intl`.
|
||||
/**
|
||||
* Need to import at least one locale-data with intl.
|
||||
*/
|
||||
// import 'intl/locale-data/jsonp/en';
|
|
@ -0,0 +1,79 @@
|
|||
* {
|
||||
font-family: 'Exo 2', sans-serif;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
cursor: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
|
||||
/* Elevation */
|
||||
|
||||
.z-depth-1 {
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.z-depth-1-half {
|
||||
box-shadow: 0 3px 3px 0 rgba(0, 0, 0, 0.14), 0 1px 7px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.z-depth-2 {
|
||||
box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.z-depth-3 {
|
||||
box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.z-depth-4 {
|
||||
box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.z-depth-5 {
|
||||
box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
|
||||
/* Colors of Deep Purple Material Theme */
|
||||
|
||||
.back-primary {
|
||||
background: #673ab7 !important;
|
||||
}
|
||||
|
||||
.back-accent {
|
||||
background: #ffd740;
|
||||
}
|
||||
|
||||
.back-warn {
|
||||
background: #f44336;
|
||||
}
|
||||
|
||||
.back-secondary {
|
||||
background: #D1C4E9;
|
||||
}
|
||||
|
||||
.color-primary {
|
||||
color: #673ab7 !important;
|
||||
}
|
||||
|
||||
.color-accent {
|
||||
color: #ffd740;
|
||||
}
|
||||
|
||||
.color-warn {
|
||||
color: #f44336;
|
||||
}
|
||||
|
||||
.color-secondary {
|
||||
color: #D1C4E9;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/long-stack-trace-zone';
|
||||
import 'zone.js/dist/proxy.js';
|
||||
import 'zone.js/dist/sync-test';
|
||||
import 'zone.js/dist/jasmine-patch';
|
||||
import 'zone.js/dist/async-test';
|
||||
import 'zone.js/dist/fake-async-test';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
|
||||
declare const __karma__: any;
|
||||
declare const require: any;
|
||||
|
||||
// Prevent Karma from running prematurely.
|
||||
__karma__.loaded = function () {};
|
||||
|
||||
// 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);
|
||||
// Finally, start Karma to run the tests.
|
||||
__karma__.start();
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"baseUrl": "./",
|
||||
"module": "es2015",
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/spec",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
/* SystemJS module definition */
|
||||
declare var module: NodeModule;
|
||||
interface NodeModule {
|
||||
id: string;
|
||||
}
|
|
@ -8,8 +8,11 @@
|
|||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es5",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
],
|
||||
"lib": [
|
||||
"es2016",
|
||||
"es2017",
|
||||
"dom"
|
||||
]
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
"node_modules/codelyzer"
|
||||
],
|
||||
"rules": {
|
||||
"arrow-return-shorthand": true,
|
||||
"callable-types": true,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
|
@ -12,7 +13,10 @@
|
|||
"curly": true,
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"import-blacklist": [true, "rxjs"],
|
||||
"import-blacklist": [
|
||||
true,
|
||||
"rxjs"
|
||||
],
|
||||
"import-spacing": true,
|
||||
"indent": [
|
||||
true,
|
||||
|
@ -27,8 +31,14 @@
|
|||
"member-access": false,
|
||||
"member-ordering": [
|
||||
true,
|
||||
"static-before-instance",
|
||||
"variables-before-functions"
|
||||
{
|
||||
"order": [
|
||||
"static-field",
|
||||
"instance-field",
|
||||
"static-method",
|
||||
"instance-method"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
|
@ -42,16 +52,22 @@
|
|||
],
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-duplicate-super": true,
|
||||
"no-empty": false,
|
||||
"no-empty-interface": true,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": [true, "ignore-params"],
|
||||
"no-inferrable-types": [
|
||||
true,
|
||||
"ignore-params"
|
||||
],
|
||||
"no-misused-new": true,
|
||||
"no-non-null-assertion": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": false,
|
||||
"no-string-throw": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unnecessary-initializer": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
|
@ -70,6 +86,7 @@
|
|||
],
|
||||
"radix": true,
|
||||
"semicolon": [
|
||||
true,
|
||||
"always"
|
||||
],
|
||||
"triple-equals": [
|
||||
|
@ -97,9 +114,18 @@
|
|||
"check-separator",
|
||||
"check-type"
|
||||
],
|
||||
|
||||
"directive-selector": [true, "attribute", "app", "camelCase"],
|
||||
"component-selector": [true, "element", "app", "kebab-case"],
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"app",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"app",
|
||||
"kebab-case"
|
||||
],
|
||||
"use-input-property-decorator": true,
|
||||
"use-output-property-decorator": true,
|
||||
"use-host-property-decorator": true,
|
||||
|
@ -109,8 +135,6 @@
|
|||
"use-pipe-transform-interface": true,
|
||||
"component-class-suffix": true,
|
||||
"directive-class-suffix": true,
|
||||
"no-access-missing-member": true,
|
||||
"templates-use-public": true,
|
||||
"invoke-injectable": true
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue