Skip to content

Commit 4aca369

Browse files
committed
Merge pull request #84 from TF2Stadium/dev
Version v0.3.2-alpha
2 parents 5fdad80 + 6b26809 commit 4aca369

17 files changed

+363
-44
lines changed

.eslintrc.json

-4
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@
2525
2,
2626
"single"
2727
],
28-
"linebreak-style": [
29-
2,
30-
"unix"
31-
],
3228
"semi": [
3329
2,
3430
"always"

bower.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@
1515
"clipboard": "~1.5.3",
1616
"wsevent.js": "~0.0.4"
1717
},
18-
"devDependencies": {}
18+
"devDependencies": {
19+
"angular-mocks": "~1.4.7"
20+
}
1921
}

circle.yml

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ dependencies:
1010
test:
1111
override:
1212
- gulp lint
13+
- gulp test
1314
deployment:
1415
master:
1516
branch: master

gulp/build.js

+23-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
'use strict';
22

3+
var fs = require('fs');
4+
var glob = require('glob');
35
var path = require('path');
6+
var _ = require('lodash');
7+
var runSequence = require('run-sequence');
48
var gulp = require('gulp');
59
var conf = require('./conf');
610

@@ -109,8 +113,24 @@ gulp.task('clean', function (done) {
109113
$.del([path.join(conf.paths.dist, '/'), path.join(conf.paths.tmp, '/')], done);
110114
});
111115

112-
gulp.task('build-after-cleaned', ['html', 'fonts', 'other']);
116+
// Return only base file name without dir
117+
function getMostRecentMtimeSync(dir) {
118+
var files = glob.sync(path.join(dir, '**/*'));
113119

114-
gulp.task('build', ['clean'], function () {
115-
gulp.start('build-after-cleaned');
120+
return _.max(_.map(files, function (f) {
121+
return fs.statSync(f).mtime;
122+
}));
123+
}
124+
125+
gulp.task('rebuild', function (cb) {
126+
runSequence('clean', ['html', 'fonts', 'other'], cb);
127+
});
128+
129+
gulp.task('build', function (cb) {
130+
if (getMostRecentMtimeSync(conf.paths.src) <= getMostRecentMtimeSync(conf.paths.dist)) {
131+
$.util.log('No modified files: not building');
132+
cb();
133+
} else {
134+
runSequence('rebuild', cb);
135+
}
116136
});

gulp/conf.js

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var gutil = require('gulp-util');
1414
exports.paths = {
1515
src: 'src',
1616
dist: 'dist',
17+
test: 'test',
1718
tmp: '.tmp',
1819
e2e: 'e2e'
1920
};

gulp/test.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict';
2+
3+
var path = require('path');
4+
var runSequence = require('run-sequence');
5+
var mainBowerFiles = require('main-bower-files');
6+
var gulp = require('gulp');
7+
var conf = require('./conf');
8+
var karma = require('karma');
9+
10+
var $ = require('gulp-load-plugins')();
11+
12+
gulp.task('test:unit', function (done) {
13+
var server = new karma.Server({
14+
browsers: ['PhantomJS'],
15+
frameworks: ['mocha', 'chai-sinon'],
16+
files: mainBowerFiles({ includeDev: true }).concat([
17+
'dist/scripts/app-*.js',
18+
'test/karma/**/*.js'
19+
]),
20+
logLevel: 'DEBUG',
21+
singleRun: true
22+
});
23+
24+
server.on('run_complete', function (browsers, results) {
25+
// NB If the argument of done() is not null or not undefined,
26+
// e.g. a string, the next task in a series won't run.
27+
done(results.error ? 'There are test failures' : null);
28+
});
29+
30+
server.start();
31+
});
32+
33+
gulp.task('test', function (cb) {
34+
runSequence('build', 'test:unit', cb);
35+
});

package.json

+16-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"license": "GPL-3.0",
55
"repository": "https://github.com/TF2Stadium/Frontend",
66
"readme": "readme.md",
7-
"version": "0.3.1",
7+
"version": "0.3.2",
88
"dependencies": {
99
"del": "~1.2.0",
1010
"uglify-save-license": "~0.4.1",
@@ -36,18 +36,32 @@
3636
"devDependencies": {
3737
"browser-sync": "~2.7.12",
3838
"browser-sync-spa": "~1.0.2",
39+
"chai": "^3.4.1",
40+
"chai-as-promised": "^5.1.0",
3941
"chalk": "^1.1.1",
4042
"concat-stream": "~1.5.0",
4143
"connect-history-api-fallback": "^1.1.0",
4244
"eslint": "^1.10.1",
4345
"eslint-plugin-angular": "^0.14.0",
46+
"glob": "^6.0.1",
4447
"gulp-eslint": "^1.1.1",
48+
"gulp-karma": "0.0.5",
49+
"gulp-mocha": "^2.2.0",
4550
"gulp-protractor": "~1.0.0",
4651
"gulp-rename": "~1.2.2",
4752
"gulp-replace": "~0.5.3",
4853
"http-proxy-middleware": "~0.0.5",
54+
"karma": "^0.13.15",
55+
"karma-chai-sinon": "^0.1.5",
56+
"karma-mocha": "^0.2.1",
57+
"karma-phantomjs-launcher": "^0.2.1",
4958
"merge-stream": "~0.1.7",
50-
"require-dir": "~0.3.0"
59+
"mocha": "^2.3.4",
60+
"phantomjs": "^1.9.19",
61+
"require-dir": "~0.3.0",
62+
"run-sequence": "^1.1.5",
63+
"selenium-webdriver": "^2.48.2",
64+
"sinon": "^1.17.2"
5165
},
5266
"engines": {
5367
"node": ">=0.10.0"

src/app/app.run.js

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
$rootScope.config = Config;
3939
Settings.getSettings(function (settings) {
4040
$rootScope.currentTheme = settings.currentTheme;
41+
$rootScope.currentTimestampsOption = settings.timestamps;
4142
$rootScope.themeLoaded = true;
4243
});
4344

src/app/app.settings.js

+7
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,19 @@
5353
dark: {name: 'TF2Stadium Dark', selector: 'dark-theme'}
5454
};
5555

56+
SettingsProvider.constants.timestampOptions = {
57+
hours12: {name: '12-hour'},
58+
hours24: {name: '24-hour'},
59+
none: {name: 'None'}
60+
};
61+
5662
SettingsProvider.constants.sound = {
5763
soundVolume: {name: 'Notifications volume'}
5864
};
5965

6066
function setDefaultValues() {
6167
SettingsProvider.settings.currentTheme = 'default-theme';
68+
SettingsProvider.settings.timestamps = 'hours12';
6269

6370
/*
6471
Defaults every value found in the filters to true.
+15-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
<div class="settings-section">
22
<h1>Theme</h1>
3-
{{settings.current}}
43
<md-radio-group ng-model="$root.currentTheme"
54
ng-change="settings.saveSetting('currentTheme', $root.currentTheme)">
6-
<md-radio-button ng-value="theme.selector"
7-
ng-repeat="theme in settings.sections.theme track by theme.selector">
5+
<md-radio-button ng-value="theme.selector"
6+
ng-repeat="theme in settings.sections.theme.theme track by theme.selector">
87
{{theme.name}}
98
</md-radio-button>
109
</md-radio-group>
11-
</div>
10+
11+
<h1>Chat</h1>
12+
<h2>Timestamps</h2>
13+
<md-radio-group
14+
ng-model="$root.currentTimestampsOption"
15+
ng-change="settings.saveSetting('timestamps', $root.currentTimestampsOption)">
16+
<md-radio-button
17+
ng-repeat="(key, opt) in settings.sections.theme.timestamps track by opt.name"
18+
ng-value="key">
19+
{{opt.name}}
20+
</md-radio-button>
21+
</md-radio-group>
22+
</div>

src/app/pages/settings/settings-sidebar.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ <h1 class="steps-title">
44
</h1>
55
<md-button class="sidebar-link"
66
ng-class="{'active' : $root.currentState==settingSection}"
7-
ng-repeat="settingSection in settings.sections"
7+
ng-repeat="(settingSection, _) in settings.sections"
88
ui-sref="{{::settingSection}}">
99
{{::settingSection}}
1010
</md-button>

src/app/pages/settings/settings.provider.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,18 @@
3535

3636
var settingsPageProvider = {};
3737

38-
settingsPageProvider.sections = [];
38+
settingsPageProvider.sections = {};
3939

4040
/** @ngInject */
4141
var settingsPageService = function (Settings) {
42-
settingsPageProvider.sections.theme = Settings.getConstants('themesList');
43-
settingsPageProvider.sections.filters = Settings.getConstants('filters');
44-
settingsPageProvider.sections.sound = Settings.getConstants('sound');
42+
settingsPageProvider.sections = {
43+
theme: {
44+
theme: Settings.getConstants('themesList'),
45+
timestamps: Settings.getConstants('timestampOptions')
46+
},
47+
filters: Settings.getConstants('filters'),
48+
sound: Settings.getConstants('sound')
49+
};
4550

4651
settingsPageService.getSections = function () {
4752
return settingsPageProvider.sections;

src/app/shared/comment-box/chat.service.js

+47-24
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,33 @@
44
angular.module('tf2stadium.services')
55
.factory('ChatService', ChatService);
66

7-
// Persistent map of room id -> messages list
8-
var chatRoomLogs = Object.create(null);
9-
function getChatRoom(id) {
10-
if (angular.isUndefined(chatRoomLogs[id])) {
11-
chatRoomLogs[id] = [];
12-
}
13-
return chatRoomLogs[id];
14-
}
7+
/** @ngInject */
8+
function ChatService(Websocket, $rootScope, LobbyService) {
9+
var factory = {};
1510

16-
function ChatRoom(id) {
17-
this.changeRoom(angular.isDefined(id)? id : -1);
18-
}
11+
// Persistent map of room id -> messages list
12+
var chatRoomLogs = Object.create(null);
13+
function getChatRoom(id) {
14+
if (angular.isUndefined(chatRoomLogs[id])) {
15+
chatRoomLogs[id] = [];
16+
}
17+
return chatRoomLogs[id];
18+
}
1919

20-
ChatRoom.prototype.changeRoom = function chageRoom(id) {
21-
if (id !== this.id) {
22-
this.id = id;
23-
this.messages = getChatRoom(id);
20+
function ChatRoom(id) {
21+
this.changeRoom(angular.isDefined(id)? id : -1);
2422
}
25-
};
2623

27-
ChatRoom.prototype.leave = function leave() {
28-
this.changeRoom(-1);
29-
};
24+
ChatRoom.prototype.changeRoom = function chageRoom(id) {
25+
if (id !== this.id) {
26+
this.id = id;
27+
this.messages = getChatRoom(id);
28+
}
29+
};
3030

31-
/** @ngInject */
32-
function ChatService(Websocket, $rootScope, LobbyService) {
33-
var factory = {};
31+
ChatRoom.prototype.leave = function leave() {
32+
this.changeRoom(-1);
33+
};
3434

3535
var globalChatRoom = new ChatRoom(0);
3636

@@ -67,11 +67,34 @@
6767
});
6868

6969
Websocket.onJSON('chatReceive', function (message) {
70-
getChatRoom(message.room).push(message);
70+
message.timestamp = new Date(message.timestamp * 1000);
71+
72+
var log = getChatRoom(message.room);
73+
74+
// Insert messages in sorted order (sorted by message id)
75+
if (log.length === 0 || log[log.length - 1].id < message.id) {
76+
log.push(message);
77+
} else {
78+
// performance likely isn't an issue, but since the log is
79+
// sorted by id, it would be better to use a binary search
80+
// here (also, use ES6 findIndex when available).
81+
var insertIdx = 0;
82+
while (log[insertIdx].id < message.id) {
83+
insertIdx++;
84+
}
85+
if (log[insertIdx].id === message.id) {
86+
// Same message id? Overwrite the logged message
87+
log[insertIdx] = message;
88+
} else {
89+
// else insert it into the array (yeah, splice is far from
90+
// efficient, but this should be very rare).
91+
log.splice(insertIdx, 0, message);
92+
}
93+
}
94+
7195
$rootScope.$emit('chat-message', message);
7296
});
7397

74-
7598
Websocket.onJSON('chatHistoryClear', function (data) {
7699
// Note: ChatRooms may have pointers to the arrays in
77100
// chatRoomLogs, so we have to mutate the actual logs rather

src/app/shared/comment-box/comment-box.html

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
<md-content scroll-glue>
2323
<div ng-repeat="message in room.messages track by $index"
2424
class="chat-message">
25+
<span class="chat-message-time"
26+
ng-if="message.player.steamid != room.messages[$index-1].player.steamid && $root.currentTimestampsOption !== 'none'">{{message.timestamp | date:($root.currentTimestampsOption === 'hours12'? 'shortTime' : 'H:mm')}}</span>
2527
<md-menu
2628
ng-if="message.player.steamid != room.messages[$index-1].player.steamid">
2729
<md-button

src/scss/main/_theme.scss

+10-1
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,12 @@ $themes-list: (
131131
}
132132
}
133133

134-
.md-button:not(.md-action) {
134+
.md-button {
135135
color: $text-color-medium;
136+
137+
&.md-action {
138+
color: white;
139+
}
136140
}
137141

138142
.md-button.md-primary.md-raised {
@@ -223,6 +227,11 @@ $themes-list: (
223227
&:nth-child(3) {
224228
color: $secondary-color;
225229
}
230+
231+
}
232+
233+
.chat-message-time {
234+
color: $text-color-medium;
226235
}
227236

228237
.chat-player-name {

src/scss/pages/shared/_commentbox.scss

+8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@
2626
}
2727
}
2828

29+
.chat-message-time {
30+
display: inline-block;
31+
max-width: 100%;
32+
overflow: hidden;
33+
vertical-align: top;
34+
margin: 0 18px 0 -15px;
35+
}
36+
2937
.chat-message-text {
3038
display: inline-block;
3139
max-width: 100%;

0 commit comments

Comments
 (0)