export function ctrl(root: AnalyseCtrl) { const isOpen = prop(false), all = prop<any | null>(null); function loadGlyphs() { if (!all()) xhr.glyphs().then(function(gs) { all(gs); root.redraw(); }); }; const toggleGlyph = throttle(500, false, function(id) { root.study!.makeChange('toggleGlyph', root.study!.withPosition({ id })); }); function open() { loadGlyphs(); isOpen(true); }; return { root, all, open, isOpen, toggle() { if (isOpen()) isOpen(false); else open(); }, toggleGlyph, redraw: root.redraw }; }
export function ctrl(send: SocketSend, chapters: Prop<StudyChapterMeta[]>, setTab: () => void, root: AnalyseCtrl) { const multiPgnMax = 20; const vm = { variants: [], open: false, initial: prop(false), tab: storedProp('study.form.tab', 'init'), editor: null, editorFen: prop(null) }; function loadVariants() { if (!vm.variants.length) xhrVariants().then(function(vs) { vm.variants = vs; root.redraw(); }); }; function open() { vm.open = true; loadVariants(); vm.initial(false); } function close() { vm.open = false; } return { vm, open, root, openInitial() { open(); vm.initial(true); }, close, toggle() { if (vm.open) close(); else open(); }, submit(d) { d.initial = vm.initial(); d.sticky = root.study!.vm.mode.sticky; if (!d.pgn) send("addChapter", d); else importPgn(root.study!.data.id, d); close(); setTab(); }, chapters, startTour: () => chapterTour(tab => { vm.tab(tab); root.redraw(); }), multiPgnMax, redraw: root.redraw } }
export function ctrl(root: AnalyseCtrl): CommentForm { const current = prop<Current | null>(null), focus = prop(false), opening = prop(false); function submit(text: string): void { if (!current()) return; doSubmit(text); }; const doSubmit = throttle(500, (text: string) => { const cur = current(); if (cur) root.study!.makeChange('setComment', { ch: cur.chapterId, path: cur.path, text }); }); function start(chapterId: string, path: Tree.Path, node: Tree.Node): void { opening(true); current({ chapterId, path, node }); root.userJump(path); }; return { root, current, focus, opening, submit, start, onSetPath(chapterId: string, path: Tree.Path, node: Tree.Node, playedMyself: boolean): void { setTimeout(() => { const cur = current(); if (cur && (path !== cur.path || chapterId !== cur.chapterId) && (!focus() || playedMyself)) { cur.chapterId = chapterId; cur.path = path; cur.node = node; root.redraw(); } }, 100); }, redraw: root.redraw, delete(chapterId: string, path: Tree.Path, id: string) { root.study!.makeChange('deleteComment', { ch: chapterId, path, id }); } }; }
export function ctrl(root: AnalyseCtrl, chapterId: () => string): ServerEvalCtrl { const requested = prop(false), lastPly = prop<number | false>(false), chartEl = prop<HTMLElement | null>(null); function unselect(chart) { chart.getSelectedPoints().forEach(p => p.select(false)); } li.pubsub.on('analysis.change', (_fen: string, _path: string, mainlinePly: number | false) => { if (!li.advantageChart || lastPly() === mainlinePly) return; const lp = lastPly(typeof mainlinePly === 'undefined' ? lastPly() : mainlinePly), el = chartEl(); if (el && window.Highcharts) { const $chart = $(el); if ($chart.length) { const chart = $chart.highcharts(); if (chart) { if (lp === false) unselect(chart); else { const point = chart.series[0].data[lp - 1 - root.tree.root.ply]; if (defined(point)) point.select(); else unselect(chart); } } else lastPly(false); } } else lastPly(false); }); return { root, reset() { requested(false); lastPly(false); }, chapterId, onMergeAnalysisData() { if (li.advantageChart) li.advantageChart.update(root.data); }, request() { root.socket.send('requestAnalysis', chapterId()); requested(true); }, requested, lastPly, chartEl }; }
export function make(opts): EvalCache { const fenFetched: string[] = []; function hasFetched(node): boolean { return fenFetched.includes(node.fen); }; let upgradable = prop(false); return { onCeval: throttle(500, function() { const node = opts.getNode(), ev = node.ceval; if (ev && !ev.cloud && hasFetched(node) && qualityCheck(ev) && opts.canPut(node)) { opts.send("evalPut", toPutData(opts.variant, ev)); } }), fetch(path: Tree.Path, multiPv: number): void { const node = opts.getNode(); if ((node.ceval && node.ceval.cloud) || !opts.canGet(node)) return; if (hasFetched(node)) return; fenFetched.push(node.fen); const obj: any = { fen: node.fen, path }; if (opts.variant !== 'standard') obj.variant = opts.variant; if (multiPv > 1) obj.mpv = multiPv; if (upgradable()) obj.up = true; opts.send("evalGet", obj); }, onCloudEval(serverEval): void { opts.receive(toCeval(serverEval), serverEval.path); }, upgradable }; };
export function ctrl(save: (data: FormData, isNew: boolean) => void, getData: () => StudyData, redraw: () => void, relay?: RelayCtrl): StudyFormCtrl { const initAt = Date.now(); function isNew(): boolean { const d = getData(); return d.from === 'scratch' && !!d.isNew && Date.now() - initAt < 9000; } const open = prop(false); return { open, openIfNew() { if (isNew()) open(true); }, save(data: FormData, isNew: boolean) { save(data, isNew); open(false); }, getData, isNew, redraw, relay }; }
export function ctrl(root: AnalyseCtrl) { const all = prop<any | null>(null); function loadGlyphs() { if (!all()) xhr.glyphs().then(gs => { all(gs); root.redraw(); }); }; const toggleGlyph = throttle(500, (id: string) => { root.study!.makeChange('toggleGlyph', root.study!.withPosition({ id })); }); return { root, all, loadGlyphs, toggleGlyph, redraw: root.redraw }; }
export function ctrl(initChapters: StudyChapterMeta[], send: SocketSend, setTab: () => void, chapterConfig, root: AnalyseCtrl): StudyChaptersCtrl { const list: Prop<StudyChapterMeta[]> = prop(initChapters); const newForm = chapterNewForm(send, list, setTab, root); const editForm = chapterEditForm(send, chapterConfig, root.redraw); const localPaths: LocalPaths = {}; return { newForm, editForm, list, get(id) { return list().find(c => c.id === id); }, size() { return list().length; }, sort(ids) { send("sortChapters", ids); }, firstChapterId() { return list()[0].id; }, toggleNewForm() { if (newForm.vm.open || list().length < 64) newForm.toggle(); else alert("You have reached the limit of 64 chapters per study. Please create a new study."); }, localPaths }; }
export function ctrl(data: StudyData, currentChapter: () => StudyChapterMeta, currentNode: () => Tree.Node, redraw: () => void) { const open = prop(false); const withPly = prop(false); return { open, toggle() { open(!open()); }, studyId: data.id, chapter: currentChapter, isPublic() { return data.visibility === 'public'; }, currentNode, withPly, cloneable: data.features.cloneable, redraw } }
return (fen: Fen): JQueryPromise<OpeningData> => { if (masterCache[fen]) return $.Deferred().resolve(masterCache[fen]).promise() as JQueryPromise<OpeningData>; return xhr.opening(opts.endpoint, 'standard', fen, { db: { selected: prop('masters') } }, false).then((res: OpeningData) => { masterCache[fen] = res; return res; }); }