dasher WIP / should have Prop<DasherData>

This commit is contained in:
Thibault Duplessis 2017-05-03 18:10:11 +02:00
parent 8e35253852
commit da484d3824
10 changed files with 122 additions and 37 deletions

View file

@ -1,5 +1,6 @@
package controllers
import scala.collection.breakOut
import play.api.mvc._
import lila.api.Context
@ -26,6 +27,10 @@ object Dasher extends LilaController {
case Some(me) => Env.pref.api.getPref(me) map { prefs =>
Ok {
lila.common.LightUser.lightUserWrites.writes(me.light) ++ Json.obj(
"lang" -> Json.obj(
"current" -> Env.i18n.pool.lang(ctx.req).language.toString,
"accepted" -> (ctx.req.acceptLanguages.map(_.language.toString)(breakOut): List[String]).distinct
),
"kid" -> me.kid,
"coach" -> isGranted(_.Coach),
"prefs" -> prefs,

View file

@ -53,9 +53,6 @@ trait I18nHelper {
def commonDomain(implicit ctx: UserContext): String =
I18nDomain(ctx.req.domain).commonDomain
def acceptLanguages(implicit ctx: UserContext): List[String] =
(ctx.req.acceptLanguages.map(_.language.toString)(breakOut): List[String]).distinct
def acceptsLanguage(lang: Lang)(implicit ctx: UserContext): Boolean =
ctx.req.acceptLanguages exists (_.language == lang.language)

View file

@ -74,7 +74,6 @@ asyncJs: Boolean = false)(body: Html)(implicit ctx: Context)
data-bg="@ctx.currentBg"
data-asset-url="@assetBaseUrl"
data-asset-version="@ctx.pageData.assetVersion"
data-accept-languages="@acceptLanguages.mkString(",")"
@ctx.zoom.map { zoom => data-zoom="@zoom" }>
<form id="blind_mode" action="@routes.Main.toggleBlindMode" method="POST">
<input type="hidden" name="enable" value="@ctx.blindMode.fold(0,1)" />

View file

@ -1,10 +1,11 @@
import { PingCtrl, ctrl as pingCtrl } from './ping'
import { LangsCtrl, ctrl as langsCtrl } from './langs'
import { Redraw, Prop, prop } from './util'
import { load } from './xhr'
import { get } from './xhr'
export interface Ctrl {
export interface DasherCtrl {
mode: Prop<Mode>
setMode: (m: Mode) => void
data: Prop<DasherData>
trans: Prop<Trans>
ping: PingCtrl
@ -20,25 +21,32 @@ export interface DasherOpts {
playing: boolean
}
export function makeCtrl(opts: DasherOpts, redraw: Redraw): Ctrl {
export function makeCtrl(opts: DasherOpts, redraw: Redraw): DasherCtrl {
let mode: Prop<Mode> = prop('links' as Mode);
let data: Prop<DasherData | undefined> = prop(undefined);
let trans: Prop<Trans> = prop(window.lichess.trans({}));
function setMode(m: Mode) {
mode(m);
redraw();
}
function close() { setMode('links'); }
const ping = pingCtrl(trans, redraw);
const langs = langsCtrl(redraw);
const langs = langsCtrl('', [], redraw, close);
function update(d: DasherData) {
data = d;
if (d.i18n) trans = window.lichess.trans(d.i18n);
if (data()) trans(window.lichess.trans(d.i18n));
data(d);
redraw();
}
load().then(update);
get('/dasher').then(update);
return {
mode,
setMode,
data,
trans,
ping,

View file

@ -1,28 +1,72 @@
import { h } from 'snabbdom'
import { VNode } from 'snabbdom/vnode'
import { Redraw, Prop, prop } from './util'
export interface LangsCtrl {
}
import { Redraw, Close, Prop, prop, spinner, bind } from './util'
import { get } from './xhr'
export interface Lang {
0: string,
0: Code,
1: string
}
export function ctrl(redraw: Redraw): LangsCtrl {
type Code = string;
export interface LangsCtrl {
data: Prop<Lang[] | undefined>
current: Code,
accepted: Code[],
load(): void
close: Close
}
export function ctrl(current: Code, accepted: Code[], redraw: Redraw, close: Close): LangsCtrl {
const data: Prop<Lang[] | undefined> = prop(undefined);
return {
data
data,
current,
accepted,
load() {
get(window.lichess.assetUrl('/assets/trans/refs.json'), true).then(d => {
data(d);
redraw();
});
},
close
};
}
export function view(ctrl: LangsCtrl): VNode[] {
export function view(ctrl: LangsCtrl): VNode {
return [
h('div', 'langs')
];
const d = ctrl.data();
if (!d) {
ctrl.load();
return spinner();
}
return h('div.sub.langs', [
h('a.head.text', {
attrs: { 'data-icon': 'I' },
hook: bind('click', ctrl.close)
}, 'Language'),
h('form', {
attrs: { method: 'post', action: '/translation/select' }
}, [
h('ul', d.map(langView(ctrl.current, ctrl.accepted)))
])
]);
}
function langView(current: Code, accepted: Code[]) {
return (l: Lang) => h('li', [
h('button', {
attrs: {
type: 'submit',
name: 'lang',
value: l[0]
},
}, l[1])
]);
}

View file

@ -1,10 +1,11 @@
import { h } from 'snabbdom'
import { VNode } from 'snabbdom/vnode'
import { Ctrl, DasherData } from './ctrl'
import { DasherCtrl, DasherData, Mode } from './dasher'
import { view as pingView } from './ping'
import { bind } from './util'
export default function(ctrl: Ctrl, d: DasherData): VNode[] {
export default function(ctrl: DasherCtrl, d: DasherData): VNode {
const trans = ctrl.trans();
@ -28,21 +29,27 @@ export default function(ctrl: Ctrl, d: DasherData): VNode[] {
linkCfg('/coach/edit', ':'),
'Coach manager');
const langs = h(
'a.sub',
modeCfg(ctrl, 'langs'),
'Language')
const logout = h(
'a.text',
linkCfg('/logout', 'w'),
trans.noarg('logOut'));
return [
return h('div', [
h('div.links', [
profile,
inbox,
prefs,
coach,
langs,
logout
]),
pingView(ctrl.ping)
];
]);
}
function linkCfg(href: string, icon: string, more: any = undefined): any {
@ -55,3 +62,12 @@ function linkCfg(href: string, icon: string, more: any = undefined): any {
if (more) for(let i in more) cfg.attrs[i] = more[i];
return cfg;
}
function modeCfg(ctrl: DasherCtrl, m: Mode): any {
return {
hook: bind('click', () => ctrl.setMode(m)),
attrs: {
'data-icon': 'H'
}
};
}

View file

@ -2,7 +2,7 @@
import { Redraw } from './util'
import { Ctrl, DasherOpts, makeCtrl } from './ctrl';
import { DasherCtrl, DasherOpts, makeCtrl } from './dasher';
import view from './view';
import { init } from 'snabbdom';
@ -13,7 +13,7 @@ const patch = init([klass, attributes]);
export default function LichessDasher(element: Element, opts: DasherOpts) {
let vnode: VNode, ctrl: Ctrl
let vnode: VNode, ctrl: DasherCtrl
const redraw: Redraw = () => {
vnode = patch(vnode, view(ctrl));

View file

@ -1,6 +1,8 @@
import { h } from 'snabbdom'
import { VNode } from 'snabbdom/vnode'
export type Redraw = () => void
export type Close = () => void
export interface Prop<T> {
(): T
@ -19,7 +21,20 @@ export function prop<A>(initialValue: A): Prop<A> {
return value;
};
return fun as Prop<A>;
};
}
export function bind(eventName: string, f: (e: Event) => void, redraw: Redraw | undefined = undefined) {
return {
insert: (vnode: VNode) => {
(vnode.elm as HTMLElement).addEventListener(eventName, e => {
e.stopPropagation();
f(e);
if (redraw) redraw();
return false;
});
}
};
}
export function spinner() {
return h('div.spinner', [

View file

@ -1,15 +1,15 @@
import { h } from 'snabbdom'
import { VNode } from 'snabbdom/vnode'
import { Ctrl } from './ctrl'
import { DasherCtrl } from './dasher'
import links from './links'
import { view as langsView } from './langs'
import { spinner } from './util'
export default function(ctrl: Ctrl): VNode {
export default function(ctrl: DasherCtrl): VNode {
let d = ctrl.data();
let content: VNode[] | undefined;
if (!d) content = [h('div.initiating', spinner())];
let content: VNode | undefined;
if (!d) content = h('div.initiating', spinner());
else switch(ctrl.mode()) {
case 'langs':
content = langsView(ctrl.langs);

View file

@ -2,9 +2,10 @@ const headers = {
'Accept': 'application/vnd.lichess.v2+json'
};
export function load() {
export function get(url: string, cache: boolean = false) {
return $.ajax({
url: '/dasher',
headers: headers
})
url: url,
headers: headers,
cache: cache
});
}