@mideind/netskrafl-react 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +8 -0
- package/.eslintrc.json +13 -0
- package/README.md +63 -0
- package/dist/cjs/index.css +6837 -0
- package/dist/cjs/index.js +3046 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/index.css +6837 -0
- package/dist/esm/index.js +3046 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/types.d.ts +41 -0
- package/package.json +63 -0
- package/rollup.config.js +60 -0
- package/src/components/index.ts +2 -0
- package/src/components/netskrafl/Netskrafl.stories.tsx +66 -0
- package/src/components/netskrafl/Netskrafl.tsx +135 -0
- package/src/components/netskrafl/Netskrafl.types.ts +7 -0
- package/src/components/netskrafl/index.ts +2 -0
- package/src/css/fonts.css +4 -0
- package/src/css/glyphs.css +224 -0
- package/src/css/skrafl-explo.css +6616 -0
- package/src/fonts/glyphicons-regular.eot +0 -0
- package/src/fonts/glyphicons-regular.ttf +0 -0
- package/src/fonts/glyphicons-regular.woff +0 -0
- package/src/index.ts +2 -0
- package/src/messages/messages.json +1576 -0
- package/src/mithril/actions.ts +319 -0
- package/src/mithril/bag.ts +65 -0
- package/src/mithril/bestdisplay.ts +74 -0
- package/src/mithril/blankdialog.ts +94 -0
- package/src/mithril/board.ts +336 -0
- package/src/mithril/buttons.ts +303 -0
- package/src/mithril/challengedialog.ts +186 -0
- package/src/mithril/channel.ts +162 -0
- package/src/mithril/chat.ts +228 -0
- package/src/mithril/components.ts +496 -0
- package/src/mithril/dragdrop.ts +219 -0
- package/src/mithril/elopage.ts +180 -0
- package/src/mithril/friend.ts +227 -0
- package/src/mithril/game.ts +1378 -0
- package/src/mithril/gameview.ts +111 -0
- package/src/mithril/globalstate.ts +33 -0
- package/src/mithril/i18n.ts +186 -0
- package/src/mithril/localstorage.ts +133 -0
- package/src/mithril/login.ts +122 -0
- package/src/mithril/logo.ts +270 -0
- package/src/mithril/main.ts +737 -0
- package/src/mithril/mithril.ts +29 -0
- package/src/mithril/model.ts +817 -0
- package/src/mithril/movelistitem.ts +226 -0
- package/src/mithril/page.ts +852 -0
- package/src/mithril/playername.ts +91 -0
- package/src/mithril/promodialog.ts +82 -0
- package/src/mithril/recentlist.ts +148 -0
- package/src/mithril/request.ts +52 -0
- package/src/mithril/review.ts +634 -0
- package/src/mithril/rightcolumn.ts +398 -0
- package/src/mithril/searchbutton.ts +118 -0
- package/src/mithril/statsdisplay.ts +109 -0
- package/src/mithril/tabs.ts +169 -0
- package/src/mithril/tile.ts +145 -0
- package/src/mithril/twoletter.ts +76 -0
- package/src/mithril/types.ts +379 -0
- package/src/mithril/userinfodialog.ts +171 -0
- package/src/mithril/util.ts +304 -0
- package/src/mithril/wait.ts +246 -0
- package/src/mithril/wordcheck.ts +102 -0
- package/tsconfig.json +28 -0
- package/vite.config.ts +12 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|
|
3
|
+
Types.ts
|
|
4
|
+
|
|
5
|
+
Common type definitions for the Explo/Netskrafl user interface
|
|
6
|
+
|
|
7
|
+
Copyright (C) 2024 Miðeind ehf.
|
|
8
|
+
Author: Vilhjalmur Thorsteinsson
|
|
9
|
+
|
|
10
|
+
The Creative Commons Attribution-NonCommercial 4.0
|
|
11
|
+
International Public License (CC-BY-NC 4.0) applies to this software.
|
|
12
|
+
For further information, see https://github.com/mideind/Netskrafl
|
|
13
|
+
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { VnodeChildren } from "./mithril";
|
|
17
|
+
import { GlobalState } from "./globalstate";
|
|
18
|
+
|
|
19
|
+
// Global constants
|
|
20
|
+
|
|
21
|
+
export const RACK_SIZE = 7;
|
|
22
|
+
export const ROWIDS = "ABCDEFGHIJKLMNO";
|
|
23
|
+
export const BOARD_SIZE = ROWIDS.length;
|
|
24
|
+
export const EXTRA_WIDE_LETTERS = "q";
|
|
25
|
+
export const WIDE_LETTERS = "zxmæ";
|
|
26
|
+
|
|
27
|
+
export const ERROR_MESSAGES: { [key: string]: string } = {
|
|
28
|
+
// Translations are found in /static/assets/messages.json
|
|
29
|
+
1: "Enginn stafur lagður niður",
|
|
30
|
+
2: "Fyrsta orð verður að liggja um byrjunarreitinn",
|
|
31
|
+
3: "Orð verður að vera samfellt á borðinu",
|
|
32
|
+
4: "Orð verður að tengjast orði sem fyrir er",
|
|
33
|
+
5: "Reitur þegar upptekinn",
|
|
34
|
+
6: "Ekki má vera eyða í orði",
|
|
35
|
+
7: "word_not_found",
|
|
36
|
+
8: "word_not_found",
|
|
37
|
+
9: "Of margir stafir lagðir niður",
|
|
38
|
+
10: "Stafur er ekki í rekkanum",
|
|
39
|
+
11: "Of fáir stafir eftir, skipting ekki leyfð",
|
|
40
|
+
12: "Of mörgum stöfum skipt",
|
|
41
|
+
13: "Leik vantar á borðið - notið F5/Refresh",
|
|
42
|
+
14: "Notandi ekki innskráður - notið F5/Refresh",
|
|
43
|
+
15: "Rangur eða óþekktur notandi",
|
|
44
|
+
16: "Viðureign finnst ekki",
|
|
45
|
+
17: "Viðureign er ekki utan tímamarka",
|
|
46
|
+
18: "Netþjónn gat ekki tekið við leiknum - reyndu aftur",
|
|
47
|
+
19: "Véfenging er ekki möguleg í þessari viðureign",
|
|
48
|
+
20: "Síðasti leikur er ekki véfengjanlegur",
|
|
49
|
+
21: "Aðeins véfenging eða pass leyfileg",
|
|
50
|
+
"server": "Netþjónn gat ekki tekið við leiknum - reyndu aftur"
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Items in a list of users
|
|
54
|
+
export interface UserListItem {
|
|
55
|
+
rank: number;
|
|
56
|
+
rank_yesterday: number;
|
|
57
|
+
rank_week_ago: number;
|
|
58
|
+
userid: string;
|
|
59
|
+
nick: string;
|
|
60
|
+
fullname: string;
|
|
61
|
+
inactive: boolean;
|
|
62
|
+
chall: boolean;
|
|
63
|
+
fairplay: boolean;
|
|
64
|
+
ready: boolean;
|
|
65
|
+
ready_timed: boolean;
|
|
66
|
+
fav: boolean;
|
|
67
|
+
ratio: number;
|
|
68
|
+
avgpts: number;
|
|
69
|
+
games: number;
|
|
70
|
+
games_yesterday: number;
|
|
71
|
+
games_week_ago: number;
|
|
72
|
+
games_month_ago: number;
|
|
73
|
+
elo: number;
|
|
74
|
+
human_elo: number;
|
|
75
|
+
elo_yesterday: number;
|
|
76
|
+
elo_week_ago: number;
|
|
77
|
+
elo_month_ago: number;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Items in a game list
|
|
81
|
+
export interface GameListItem {
|
|
82
|
+
uuid: string;
|
|
83
|
+
fullname: string;
|
|
84
|
+
my_turn: boolean;
|
|
85
|
+
timed: boolean;
|
|
86
|
+
manual: boolean;
|
|
87
|
+
zombie: boolean;
|
|
88
|
+
overdue: boolean;
|
|
89
|
+
oppid: string;
|
|
90
|
+
opp: string;
|
|
91
|
+
sc0: number;
|
|
92
|
+
sc1: number;
|
|
93
|
+
url: string;
|
|
94
|
+
tile_count: number;
|
|
95
|
+
ts: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Items in a list of recent games
|
|
99
|
+
export interface RecentListItem {
|
|
100
|
+
opp: string;
|
|
101
|
+
opp_is_robot: boolean;
|
|
102
|
+
sc0: number;
|
|
103
|
+
sc1: number;
|
|
104
|
+
ts_last_move: string;
|
|
105
|
+
manual: boolean;
|
|
106
|
+
duration: number;
|
|
107
|
+
days: number;
|
|
108
|
+
hours: number;
|
|
109
|
+
minutes: number;
|
|
110
|
+
elo_adj: number;
|
|
111
|
+
human_elo_adj: number;
|
|
112
|
+
url: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Items in a list of challenges (sent or received)
|
|
116
|
+
export interface ChallengeListItem {
|
|
117
|
+
key: string;
|
|
118
|
+
userid: string;
|
|
119
|
+
received: boolean;
|
|
120
|
+
opp: string;
|
|
121
|
+
fullname: string;
|
|
122
|
+
prefs: any;
|
|
123
|
+
ts: string;
|
|
124
|
+
opp_ready: boolean;
|
|
125
|
+
live: boolean;
|
|
126
|
+
image: string;
|
|
127
|
+
fav: boolean;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// User preferences, typically edited in a modal dialog
|
|
131
|
+
export interface UserPrefs {
|
|
132
|
+
nickname: string;
|
|
133
|
+
full_name: string;
|
|
134
|
+
email: string;
|
|
135
|
+
beginner: boolean;
|
|
136
|
+
fairplay: boolean;
|
|
137
|
+
audio: boolean;
|
|
138
|
+
fanfare: boolean;
|
|
139
|
+
logout_url: string;
|
|
140
|
+
// The following is currently read-only, i.e. only displayed
|
|
141
|
+
// and not directly modified in the user preferences dialog
|
|
142
|
+
friend: boolean;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Information about a move in a move list
|
|
146
|
+
export interface MoveInfo {
|
|
147
|
+
key: string;
|
|
148
|
+
leftTotal: number;
|
|
149
|
+
rightTotal: number;
|
|
150
|
+
player: 0 | 1;
|
|
151
|
+
co: string;
|
|
152
|
+
tiles: string;
|
|
153
|
+
score: number;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface MovesRequest {
|
|
157
|
+
locale: string;
|
|
158
|
+
board_type: string;
|
|
159
|
+
board: string[];
|
|
160
|
+
rack: string;
|
|
161
|
+
limit: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface MoveWithScore {
|
|
165
|
+
co: string;
|
|
166
|
+
w: string;
|
|
167
|
+
sc: number;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// The data returned from the /bestmoves API endpoint
|
|
171
|
+
export interface BestMoves {
|
|
172
|
+
version: string;
|
|
173
|
+
count: number;
|
|
174
|
+
moves: MoveWithScore[];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface UserErrors {
|
|
178
|
+
nickname?: string;
|
|
179
|
+
full_name?: string;
|
|
180
|
+
email?: string;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export interface TileData {
|
|
184
|
+
player: 0 | 1;
|
|
185
|
+
tile: string;
|
|
186
|
+
letter: string;
|
|
187
|
+
score: number;
|
|
188
|
+
freshtile: boolean;
|
|
189
|
+
draggable: boolean;
|
|
190
|
+
review?: boolean;
|
|
191
|
+
index: number;
|
|
192
|
+
xchg: boolean;
|
|
193
|
+
highlight?: 0 | 1;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export interface UserStats extends Record<string, any> {
|
|
197
|
+
favorite?: boolean;
|
|
198
|
+
friend?: boolean;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export type TileDict = { [index: string]: TileData; };
|
|
202
|
+
|
|
203
|
+
export type RackTile = [
|
|
204
|
+
tile: string,
|
|
205
|
+
score: number
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
export interface SavedTile {
|
|
209
|
+
sq: string;
|
|
210
|
+
tile: string;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export type TileScoreDict = { [index: string]: number; };
|
|
214
|
+
|
|
215
|
+
export type Move = [
|
|
216
|
+
player: 0 | 1,
|
|
217
|
+
summary: [coord: string, tiles: string, score: number],
|
|
218
|
+
highlighted: boolean,
|
|
219
|
+
];
|
|
220
|
+
|
|
221
|
+
export type MoveDetail = [string];
|
|
222
|
+
|
|
223
|
+
export interface MoveListener {
|
|
224
|
+
notifyMove: () => void;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export interface Message {
|
|
228
|
+
from_userid: string;
|
|
229
|
+
msg: string;
|
|
230
|
+
ts: string;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface ServerGame {
|
|
234
|
+
result: number;
|
|
235
|
+
msg: string;
|
|
236
|
+
newmoves: Move[];
|
|
237
|
+
two_letter_words: string[][];
|
|
238
|
+
num_moves: number;
|
|
239
|
+
// Several other properties are also sent from the server,
|
|
240
|
+
// but they are copied using key/value enumeration
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export type ChallengeAction = "issue" | "retract" | "decline" | "accept";
|
|
244
|
+
|
|
245
|
+
export type DialogViewEnum = "userprefs" | "userinfo" | "challenge" | "promo" | "friend" | "thanks" | "cancel" | "confirm" | "wait" | "accept";
|
|
246
|
+
|
|
247
|
+
export interface ChallengeParameters {
|
|
248
|
+
action: ChallengeAction;
|
|
249
|
+
destuser: string;
|
|
250
|
+
duration?: number;
|
|
251
|
+
fairplay?: boolean;
|
|
252
|
+
manual?: boolean;
|
|
253
|
+
key?: string;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export interface UserListCriteria {
|
|
257
|
+
query: string;
|
|
258
|
+
spec: string;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export interface StatsType extends Record<string, any> {
|
|
262
|
+
scores: [number, number];
|
|
263
|
+
bingoes0: number;
|
|
264
|
+
bingoes1: number;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export interface IGame {
|
|
268
|
+
uuid: string;
|
|
269
|
+
locale: string;
|
|
270
|
+
tiles: TileDict;
|
|
271
|
+
showingDialog: string | null;
|
|
272
|
+
selectedSq: string | null;
|
|
273
|
+
sel: string;
|
|
274
|
+
over: boolean;
|
|
275
|
+
userid: [string, string];
|
|
276
|
+
autoplayer: [boolean, boolean];
|
|
277
|
+
nickname: [string, string];
|
|
278
|
+
fullname: [string, string];
|
|
279
|
+
player: number | null; // null means that the current user is not a participant
|
|
280
|
+
moves: Move[];
|
|
281
|
+
currentScore: number | undefined;
|
|
282
|
+
wordGood: boolean;
|
|
283
|
+
wordBad: boolean;
|
|
284
|
+
localturn: boolean;
|
|
285
|
+
moveInProgress: boolean;
|
|
286
|
+
chatLoading: boolean;
|
|
287
|
+
congratulate: boolean;
|
|
288
|
+
bag: string;
|
|
289
|
+
newbag: boolean;
|
|
290
|
+
clockText0: string;
|
|
291
|
+
clockText1: string;
|
|
292
|
+
runningOut0: boolean;
|
|
293
|
+
runningOut1: boolean;
|
|
294
|
+
blinking0: boolean;
|
|
295
|
+
blinking1: boolean;
|
|
296
|
+
chatSeen: boolean;
|
|
297
|
+
fairplay: boolean;
|
|
298
|
+
manual: boolean;
|
|
299
|
+
askingForBlank: { from: string; to: string; } | null;
|
|
300
|
+
alphabet: string;
|
|
301
|
+
startSquare: string;
|
|
302
|
+
currentError: string | number | null;
|
|
303
|
+
currentMessage: string | null;
|
|
304
|
+
messages: Message[] | null;
|
|
305
|
+
stats: StatsType | null | undefined;
|
|
306
|
+
buttonState: () => Record<string, boolean>;
|
|
307
|
+
twoLetterWords: () => string[][][];
|
|
308
|
+
showClock: () => boolean;
|
|
309
|
+
displayScore: (player: 0 | 1) => number;
|
|
310
|
+
attemptMove: (from: string, to: string) => void;
|
|
311
|
+
placeBlank: (letter: string) => void;
|
|
312
|
+
cancelBlankDialog: () => void;
|
|
313
|
+
squareClass: (coord: string) => string | undefined;
|
|
314
|
+
submitResign: () => void;
|
|
315
|
+
submitChallenge: () => void;
|
|
316
|
+
submitMove: () => void;
|
|
317
|
+
submitPass: () => void;
|
|
318
|
+
submitExchange: () => void;
|
|
319
|
+
forceResign: () => Promise<void>;
|
|
320
|
+
resetRack: () => void;
|
|
321
|
+
rescrambleRack: () => void;
|
|
322
|
+
resetError: () => void;
|
|
323
|
+
sendMessage: (msg: string) => Promise<void>;
|
|
324
|
+
markChatShown: () => boolean;
|
|
325
|
+
setSelectedTab: (tab: string) => boolean;
|
|
326
|
+
placeTiles: (move?: number, noHighlight?: boolean) => void;
|
|
327
|
+
tilescore: (tile: string) => number;
|
|
328
|
+
loadStats: () => Promise<void>;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export interface IModel {
|
|
332
|
+
state: GlobalState | null;
|
|
333
|
+
game: IGame | null;
|
|
334
|
+
friendHTML: string | null;
|
|
335
|
+
numGames: number;
|
|
336
|
+
numChallenges: number;
|
|
337
|
+
oppReady: number;
|
|
338
|
+
gameList: GameListItem[] | null;
|
|
339
|
+
loadingGameList: boolean;
|
|
340
|
+
maxFreeGames: number;
|
|
341
|
+
ownStats: Record<string, any> | null;
|
|
342
|
+
challengeList: ChallengeListItem[] | null;
|
|
343
|
+
recentList: RecentListItem[] | null;
|
|
344
|
+
userListCriteria: UserListCriteria | null | undefined;
|
|
345
|
+
userList: UserListItem[] | null | undefined;
|
|
346
|
+
reviewMove: number | null;
|
|
347
|
+
bestMoves: Move[] | null;
|
|
348
|
+
highlightedMove: number | null;
|
|
349
|
+
moreGamesAllowed: () => boolean;
|
|
350
|
+
newGame: (oppid: string, reverse: boolean) => Promise<void>;
|
|
351
|
+
modifyChallenge: (parameters: ChallengeParameters) => Promise<void>;
|
|
352
|
+
loadFriendPromo: () => Promise<void>;
|
|
353
|
+
setUserPref: (pref: Record<string, any>) => Promise<void>;
|
|
354
|
+
markFavorite: (userId: string, status: boolean) => Promise<void>;
|
|
355
|
+
loadChallengeList: () => Promise<void>;
|
|
356
|
+
loadRecentList: () => Promise<void>;
|
|
357
|
+
loadGameList: () => Promise<void>;
|
|
358
|
+
loadUserList: (criteria: UserListCriteria, activateSpinner: boolean) => Promise<void>;
|
|
359
|
+
loadOwnStats: () => Promise<void>;
|
|
360
|
+
loadUserStats: (userid: string, readyFunc: (json: UserStats) => void) => Promise<void>;
|
|
361
|
+
loadUserRecentList: (userid: string, versus: string | null, readyFunc: (json: any) => void) => Promise<void>;
|
|
362
|
+
loadPromoContent: (key: string, readyFunc: (html: string) => void) => Promise<void>;
|
|
363
|
+
loadBestMoves: (moveIndex: number) => Promise<void>;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export interface IView {
|
|
367
|
+
model: IModel;
|
|
368
|
+
boardScale: number;
|
|
369
|
+
popDialog: () => void;
|
|
370
|
+
pushDialog: (dialogName: DialogViewEnum, dialogArgs?: any) => void;
|
|
371
|
+
showUserInfo: (userid: string, nick: string, fullname: string) => void;
|
|
372
|
+
showFriendPromo: () => void;
|
|
373
|
+
showAcceptDialog: (oppId: string, oppNick: string, challengeKey: string) => void;
|
|
374
|
+
cancelFriendship: () => Promise<void>;
|
|
375
|
+
updateScale: () => void;
|
|
376
|
+
resetScale: () => void;
|
|
377
|
+
isDialogShown: () => boolean;
|
|
378
|
+
vwDialogs: () => VnodeChildren;
|
|
379
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|
|
3
|
+
UserInfoDialog.ts
|
|
4
|
+
|
|
5
|
+
User information dialog component
|
|
6
|
+
|
|
7
|
+
Copyright (C) 2024 Miðeind ehf.
|
|
8
|
+
Author: Vilhjalmur Thorsteinsson
|
|
9
|
+
|
|
10
|
+
The Creative Commons Attribution-NonCommercial 4.0
|
|
11
|
+
International Public License (CC-BY-NC 4.0) applies to this software.
|
|
12
|
+
For further information, see https://github.com/mideind/Netskrafl
|
|
13
|
+
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { IView, RecentListItem, UserStats } from "./types";
|
|
17
|
+
import { ComponentFunc, m } from "./mithril";
|
|
18
|
+
import { glyph, glyphGrayed, nbsp } from "./util";
|
|
19
|
+
import { mt, t, ts } from "./i18n";
|
|
20
|
+
import { RecentList } from "./recentlist";
|
|
21
|
+
import { StatsDisplay } from "./statsdisplay";
|
|
22
|
+
import { BestDisplay } from "./bestdisplay";
|
|
23
|
+
import { DialogButton } from "./components";
|
|
24
|
+
|
|
25
|
+
interface IAttributes {
|
|
26
|
+
view: IView;
|
|
27
|
+
userid: string;
|
|
28
|
+
nick: string;
|
|
29
|
+
fullname: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const UserInfoDialog: ComponentFunc<IAttributes> = (initialVnode) => {
|
|
33
|
+
|
|
34
|
+
// A dialog showing the track record of a given user, including
|
|
35
|
+
// recent games and total statistics
|
|
36
|
+
|
|
37
|
+
const view = initialVnode.attrs.view;
|
|
38
|
+
const model = view.model;
|
|
39
|
+
let stats: UserStats = {};
|
|
40
|
+
let recentList: RecentListItem[] = [];
|
|
41
|
+
let versusAll = true; // Show games against all opponents or just the current user?
|
|
42
|
+
|
|
43
|
+
function _updateStats(vnode: typeof initialVnode) {
|
|
44
|
+
// Fetch the statistics of the given user
|
|
45
|
+
model.loadUserStats(vnode.attrs.userid,
|
|
46
|
+
(json: UserStats | { result: number; }) => {
|
|
47
|
+
if (json && json.result === 0)
|
|
48
|
+
stats = json;
|
|
49
|
+
else
|
|
50
|
+
stats = {};
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function _updateRecentList(vnode: typeof initialVnode) {
|
|
56
|
+
// Fetch the recent game list of the given user
|
|
57
|
+
model.loadUserRecentList(vnode.attrs.userid,
|
|
58
|
+
versusAll ? null : model.state?.userId ?? "",
|
|
59
|
+
(json: { result: number; recentlist: RecentListItem[]; }) => {
|
|
60
|
+
if (json && json.result === 0)
|
|
61
|
+
recentList = json.recentlist;
|
|
62
|
+
else
|
|
63
|
+
recentList = [];
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function _setVersus(vnode: typeof initialVnode, vsState: boolean) {
|
|
69
|
+
if (versusAll != vsState) {
|
|
70
|
+
versusAll = vsState;
|
|
71
|
+
_updateRecentList(vnode);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
|
|
77
|
+
oninit: (vnode) => {
|
|
78
|
+
_updateRecentList(vnode);
|
|
79
|
+
_updateStats(vnode);
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
view: (vnode) => {
|
|
83
|
+
return m(".modal-dialog",
|
|
84
|
+
{ id: 'usr-info-dialog', style: { visibility: "visible" } },
|
|
85
|
+
m(".ui-widget.ui-widget-content.ui-corner-all", { id: 'usr-info-form' },
|
|
86
|
+
[
|
|
87
|
+
m(".usr-info-hdr",
|
|
88
|
+
[
|
|
89
|
+
m("h1.usr-info-icon",
|
|
90
|
+
[
|
|
91
|
+
stats.friend ?
|
|
92
|
+
glyph("coffee-cup", { title: ts('Vinur Netskrafls') }) :
|
|
93
|
+
glyph("user"), nbsp()
|
|
94
|
+
]
|
|
95
|
+
),
|
|
96
|
+
m("h1[id='usr-info-nick']", vnode.attrs.nick),
|
|
97
|
+
m("span.vbar", "|"),
|
|
98
|
+
m("h2[id='usr-info-fullname']", vnode.attrs.fullname),
|
|
99
|
+
m(".usr-info-fav",
|
|
100
|
+
{
|
|
101
|
+
title: ts('Uppáhald'),
|
|
102
|
+
onclick: (ev: Event) => {
|
|
103
|
+
// Toggle the favorite setting
|
|
104
|
+
ev.preventDefault();
|
|
105
|
+
stats.favorite = !stats.favorite;
|
|
106
|
+
model.markFavorite(vnode.attrs.userid, stats.favorite);
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
stats.favorite ? glyph("star") : glyph("star-empty")
|
|
110
|
+
)
|
|
111
|
+
]
|
|
112
|
+
),
|
|
113
|
+
m("p",
|
|
114
|
+
[
|
|
115
|
+
m("strong", t("Nýjustu viðureignir")),
|
|
116
|
+
nbsp(),
|
|
117
|
+
m("span.versus-cat",
|
|
118
|
+
[
|
|
119
|
+
m("span",
|
|
120
|
+
{
|
|
121
|
+
class: versusAll ? "shown" : "",
|
|
122
|
+
onclick: () => { _setVersus(vnode, true); } // Set this.versusAll to true
|
|
123
|
+
},
|
|
124
|
+
t(" gegn öllum ")
|
|
125
|
+
),
|
|
126
|
+
m("span",
|
|
127
|
+
{
|
|
128
|
+
class: versusAll ? "" : "shown",
|
|
129
|
+
onclick: () => { _setVersus(vnode, false); } // Set this.versusAll to false
|
|
130
|
+
},
|
|
131
|
+
t(" gegn þér ")
|
|
132
|
+
)
|
|
133
|
+
]
|
|
134
|
+
)
|
|
135
|
+
]
|
|
136
|
+
),
|
|
137
|
+
m(".listitem.listheader",
|
|
138
|
+
[
|
|
139
|
+
m("span.list-win", glyphGrayed("bookmark", { title: ts('Sigur') })),
|
|
140
|
+
mt("span.list-ts-short", "Viðureign lauk"),
|
|
141
|
+
mt("span.list-nick", "Andstæðingur"),
|
|
142
|
+
mt("span.list-scorehdr", "Úrslit"),
|
|
143
|
+
m("span.list-elo-hdr",
|
|
144
|
+
[
|
|
145
|
+
m("span.glyphicon.glyphicon-user.elo-hdr-left", { title: ts('Mennskir andstæðingar') }),
|
|
146
|
+
"Elo",
|
|
147
|
+
m("span.glyphicon.glyphicon-cog.elo-hdr-right", { title: ts('Allir andstæðingar') })
|
|
148
|
+
]
|
|
149
|
+
),
|
|
150
|
+
mt("span.list-duration", "Lengd"),
|
|
151
|
+
m("span.list-manual", glyphGrayed("lightbulb", { title: ts('Keppnishamur') }))
|
|
152
|
+
]
|
|
153
|
+
),
|
|
154
|
+
m(RecentList, { view, id: 'usr-recent', recentList }), // Recent game list
|
|
155
|
+
m(StatsDisplay, { view, id: 'usr-stats', ownStats: stats }),
|
|
156
|
+
m(BestDisplay, { id: 'usr-best', ownStats: stats, myself: false }), // Highest word and game scores
|
|
157
|
+
m(DialogButton,
|
|
158
|
+
{
|
|
159
|
+
id: 'usr-info-close',
|
|
160
|
+
title: ts('Loka'),
|
|
161
|
+
onclick: (ev: Event) => { view.popDialog(); ev.preventDefault(); }
|
|
162
|
+
},
|
|
163
|
+
glyph("ok")
|
|
164
|
+
)
|
|
165
|
+
]
|
|
166
|
+
)
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
}
|