make localStorage pubsub more robust (fixes #5832)
Safari sometimes fires the StorageEvent in the same document as well. Move lichess.StrongSocket.sri to lichess.sri and use the unique id to filter events.pull/5836/head
parent
c2981fca90
commit
c40772dee6
|
@ -13,7 +13,7 @@ $(function() {
|
||||||
...lichess.formAjax($form),
|
...lichess.formAjax($form),
|
||||||
success: function() {
|
success: function() {
|
||||||
$form.find('.saved').fadeIn();
|
$form.find('.saved').fadeIn();
|
||||||
lichess.storage.set('reload-round-tabs', Math.random());
|
lichess.storage.fire('reload-round-tabs');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -59,8 +59,6 @@ function localStorageInfo() {
|
||||||
'analyse.ceval.threads',
|
'analyse.ceval.threads',
|
||||||
'analyse.ceval.hash-size',
|
'analyse.ceval.hash-size',
|
||||||
'analyse.ceval.infinite',
|
'analyse.ceval.infinite',
|
||||||
'ceval.pool.start',
|
|
||||||
'ceval.fen',
|
|
||||||
'just-notified',
|
'just-notified',
|
||||||
'push-subscribed',
|
'push-subscribed',
|
||||||
'grid',
|
'grid',
|
||||||
|
|
|
@ -5,6 +5,7 @@ interface Lichess {
|
||||||
requestIdleCallback(f: () => void): void;
|
requestIdleCallback(f: () => void): void;
|
||||||
dispatchEvent(el: HTMLElement | Window, eventName: string): void;
|
dispatchEvent(el: HTMLElement | Window, eventName: string): void;
|
||||||
hasTouchEvents: boolean;
|
hasTouchEvents: boolean;
|
||||||
|
sri: string;
|
||||||
isCol1(): boolean;
|
isCol1(): boolean;
|
||||||
storage: LichessStorageHelper;
|
storage: LichessStorageHelper;
|
||||||
tempStorage: LichessStorageHelper; // TODO: unused
|
tempStorage: LichessStorageHelper; // TODO: unused
|
||||||
|
@ -47,7 +48,6 @@ interface Lichess {
|
||||||
|
|
||||||
// socket.js
|
// socket.js
|
||||||
StrongSocket: {
|
StrongSocket: {
|
||||||
sri: string
|
|
||||||
(url: string, version: number, cfg: any): any;
|
(url: string, version: number, cfg: any): any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +124,7 @@ interface LichessStorageHelper {
|
||||||
makeBoolean(k: string): LichessBooleanStorage;
|
makeBoolean(k: string): LichessBooleanStorage;
|
||||||
get(k: string): string | null;
|
get(k: string): string | null;
|
||||||
set(k: string, v: string): void;
|
set(k: string, v: string): void;
|
||||||
|
fire(k: string, v?: string): void;
|
||||||
remove(k: string): void;
|
remove(k: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +132,8 @@ interface LichessStorage {
|
||||||
get(): string | null;
|
get(): string | null;
|
||||||
set(v: any): void;
|
set(v: any): void;
|
||||||
remove(): void;
|
remove(): void;
|
||||||
listen(f: (e: StorageEvent) => void): void;
|
listen(f: (e: LichessStorageEvent) => void): void;
|
||||||
|
fire(v?: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LichessBooleanStorage {
|
interface LichessBooleanStorage {
|
||||||
|
@ -140,6 +142,12 @@ interface LichessBooleanStorage {
|
||||||
toggle(): void;
|
toggle(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LichessStorageEvent {
|
||||||
|
sri: string;
|
||||||
|
nonce: number;
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface Window {
|
interface Window {
|
||||||
lichess: Lichess
|
lichess: Lichess
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ export function ctrl(send: SocketSend, chapters: Prop<StudyChapterMeta[]>, setTa
|
||||||
d.initial = vm.initial();
|
d.initial = vm.initial();
|
||||||
d.sticky = study.vm.mode.sticky;
|
d.sticky = study.vm.mode.sticky;
|
||||||
if (!d.pgn) send("addChapter", d);
|
if (!d.pgn) send("addChapter", d);
|
||||||
else importPgn(study.data.id, d, study.sri);
|
else importPgn(study.data.id, d);
|
||||||
close();
|
close();
|
||||||
setTab();
|
setTab();
|
||||||
},
|
},
|
||||||
|
|
|
@ -58,7 +58,6 @@ export interface StudyCtrl {
|
||||||
onPremoveSet(): void;
|
onPremoveSet(): void;
|
||||||
redraw: Redraw;
|
redraw: Redraw;
|
||||||
trans: Trans;
|
trans: Trans;
|
||||||
sri: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Tab = 'intro' | 'members' | 'chapters';
|
export type Tab = 'intro' | 'members' | 'chapters';
|
||||||
|
|
|
@ -31,8 +31,6 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
||||||
const send = ctrl.socket.send;
|
const send = ctrl.socket.send;
|
||||||
const redraw = ctrl.redraw;
|
const redraw = ctrl.redraw;
|
||||||
|
|
||||||
const sri: string = li.StrongSocket ? li.StrongSocket.sri : '';
|
|
||||||
|
|
||||||
const vm: StudyVm = (() => {
|
const vm: StudyVm = (() => {
|
||||||
const isManualChapter = data.chapter.id !== data.position.chapterId;
|
const isManualChapter = data.chapter.id !== data.position.chapterId;
|
||||||
const sticked = data.features.sticky && !ctrl.initialPath && !isManualChapter && !practiceData;
|
const sticked = data.features.sticky && !ctrl.initialPath && !isManualChapter && !practiceData;
|
||||||
|
@ -294,7 +292,7 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
||||||
return xhrReload();
|
return xhrReload();
|
||||||
}
|
}
|
||||||
data.position.path = position.path;
|
data.position.path = position.path;
|
||||||
if (who && who.s === sri) return;
|
if (who && who.s === li.sri) return;
|
||||||
ctrl.userJump(position.path);
|
ctrl.userJump(position.path);
|
||||||
redraw();
|
redraw();
|
||||||
},
|
},
|
||||||
|
@ -310,7 +308,7 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
||||||
if (sticky && !vm.mode.sticky) redraw();
|
if (sticky && !vm.mode.sticky) redraw();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sticky && who && who.s === sri) {
|
if (sticky && who && who.s === li.sri) {
|
||||||
data.position.path = position.path + node.id;
|
data.position.path = position.path + node.id;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -331,7 +329,7 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
||||||
setMemberActive(who);
|
setMemberActive(who);
|
||||||
if (wrongChapter(d)) return;
|
if (wrongChapter(d)) return;
|
||||||
// deleter already has it done
|
// deleter already has it done
|
||||||
if (who && who.s === sri) return;
|
if (who && who.s === li.sri) return;
|
||||||
if (!ctrl.tree.pathExists(d.p.path)) return xhrReload();
|
if (!ctrl.tree.pathExists(d.p.path)) return xhrReload();
|
||||||
ctrl.tree.deleteNodeAt(position.path);
|
ctrl.tree.deleteNodeAt(position.path);
|
||||||
if (vm.mode.sticky) ctrl.jump(ctrl.path);
|
if (vm.mode.sticky) ctrl.jump(ctrl.path);
|
||||||
|
@ -342,7 +340,7 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
||||||
who = d.w;
|
who = d.w;
|
||||||
setMemberActive(who);
|
setMemberActive(who);
|
||||||
if (wrongChapter(d)) return;
|
if (wrongChapter(d)) return;
|
||||||
if (who && who.s === sri) return;
|
if (who && who.s === li.sri) return;
|
||||||
if (!ctrl.tree.pathExists(d.p.path)) return xhrReload();
|
if (!ctrl.tree.pathExists(d.p.path)) return xhrReload();
|
||||||
ctrl.tree.promoteAt(position.path, d.toMainline);
|
ctrl.tree.promoteAt(position.path, d.toMainline);
|
||||||
if (vm.mode.sticky) ctrl.jump(ctrl.path);
|
if (vm.mode.sticky) ctrl.jump(ctrl.path);
|
||||||
|
@ -362,7 +360,7 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
||||||
},
|
},
|
||||||
descChapter(d) {
|
descChapter(d) {
|
||||||
setMemberActive(d.w);
|
setMemberActive(d.w);
|
||||||
if (d.w && d.w.s === sri) return;
|
if (d.w && d.w.s === li.sri) return;
|
||||||
if (data.chapter.id === d.chapterId) {
|
if (data.chapter.id === d.chapterId) {
|
||||||
data.chapter.description = d.desc;
|
data.chapter.description = d.desc;
|
||||||
chapterDesc.set(d.desc);
|
chapterDesc.set(d.desc);
|
||||||
|
@ -371,7 +369,7 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
||||||
},
|
},
|
||||||
descStudy(d) {
|
descStudy(d) {
|
||||||
setMemberActive(d.w);
|
setMemberActive(d.w);
|
||||||
if (d.w && d.w.s === sri) return;
|
if (d.w && d.w.s === li.sri) return;
|
||||||
data.description = d.desc;
|
data.description = d.desc;
|
||||||
studyDesc.set(d.desc);
|
studyDesc.set(d.desc);
|
||||||
redraw();
|
redraw();
|
||||||
|
@ -380,7 +378,7 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
||||||
setMemberActive(d.w);
|
setMemberActive(d.w);
|
||||||
if (d.s && !vm.mode.sticky) vm.behind++;
|
if (d.s && !vm.mode.sticky) vm.behind++;
|
||||||
if (d.s) data.position = d.p;
|
if (d.s) data.position = d.p;
|
||||||
else if (d.w && d.w.s === sri) {
|
else if (d.w && d.w.s === li.sri) {
|
||||||
vm.mode.write = true;
|
vm.mode.write = true;
|
||||||
vm.chapterId = d.p.chapterId;
|
vm.chapterId = d.p.chapterId;
|
||||||
}
|
}
|
||||||
|
@ -404,7 +402,7 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
||||||
who = d.w;
|
who = d.w;
|
||||||
setMemberActive(who);
|
setMemberActive(who);
|
||||||
if (wrongChapter(d)) return;
|
if (wrongChapter(d)) return;
|
||||||
if (who && who.s === sri) return;
|
if (who && who.s === li.sri) return;
|
||||||
ctrl.tree.setShapes(d.s, ctrl.path);
|
ctrl.tree.setShapes(d.s, ctrl.path);
|
||||||
if (ctrl.path === position.path) ctrl.withCg(cg => cg.setShapes(d.s));
|
if (ctrl.path === position.path) ctrl.withCg(cg => cg.setShapes(d.s));
|
||||||
redraw();
|
redraw();
|
||||||
|
@ -465,7 +463,7 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
||||||
},
|
},
|
||||||
liking(d) {
|
liking(d) {
|
||||||
data.likes = d.l.likes;
|
data.likes = d.l.likes;
|
||||||
if (d.w && d.w.s === sri) data.liked = d.l.me;
|
if (d.w && d.w.s === li.sri) data.liked = d.l.me;
|
||||||
redraw();
|
redraw();
|
||||||
},
|
},
|
||||||
following_onlines: members.inviteForm.setFollowings,
|
following_onlines: members.inviteForm.setFollowings,
|
||||||
|
@ -606,6 +604,5 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
||||||
}
|
}
|
||||||
return !!relay && relay.socketHandler(t, d);
|
return !!relay && relay.socketHandler(t, d);
|
||||||
},
|
},
|
||||||
sri
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,10 +44,10 @@ export function practiceComplete(chapterId: string, nbMoves: number) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function importPgn(studyId: string, data: any, sri: string) {
|
export function importPgn(studyId: string, data: any) {
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: `/study/${studyId}/import-pgn?sri=${sri}`,
|
url: `/study/${studyId}/import-pgn?sri=${window.lichess.sri}`,
|
||||||
data: data,
|
data: data,
|
||||||
headers
|
headers
|
||||||
});
|
});
|
||||||
|
|
|
@ -143,7 +143,7 @@ export default function(opts: CevalOpts): CevalCtrl {
|
||||||
opts.emit(ev, work);
|
opts.emit(ev, work);
|
||||||
if (ev.fen !== lastEmitFen) {
|
if (ev.fen !== lastEmitFen) {
|
||||||
lastEmitFen = ev.fen;
|
lastEmitFen = ev.fen;
|
||||||
li.storage.set('ceval.fen', ev.fen);
|
li.storage.fire('ceval.fen', ev.fen);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ export default function(opts: CevalOpts): CevalCtrl {
|
||||||
|
|
||||||
// ask other tabs if a game is in progress
|
// ask other tabs if a game is in progress
|
||||||
if (enabled()) {
|
if (enabled()) {
|
||||||
li.storage.set('ceval.fen', 'start:' + Math.random());
|
li.storage.fire('ceval.fen', 'start');
|
||||||
li.storage.make('round.ongoing').listen(_ => {
|
li.storage.make('round.ongoing').listen(_ => {
|
||||||
enabled(false);
|
enabled(false);
|
||||||
opts.redraw();
|
opts.redraw();
|
||||||
|
|
|
@ -14,8 +14,7 @@ export function isEvalBetter(a: Tree.ClientEval, b?: Tree.ClientEval): boolean {
|
||||||
// stop when another tab starts. Listen only once here,
|
// stop when another tab starts. Listen only once here,
|
||||||
// as the ctrl can be instanciated several times.
|
// as the ctrl can be instanciated several times.
|
||||||
// gotta do the click on the toggle to have it visually change.
|
// gotta do the click on the toggle to have it visually change.
|
||||||
window.lichess.storage.make('ceval.pool.start').listen(() => {
|
window.lichess.storage.make('ceval.pool.start').listen(_ => {
|
||||||
console.log('received ceval.pool.start');
|
|
||||||
const toggle = document.getElementById('analyse-toggle-ceval');
|
const toggle = document.getElementById('analyse-toggle-ceval');
|
||||||
if (toggle && (toggle as HTMLInputElement).checked) toggle.click();
|
if (toggle && (toggle as HTMLInputElement).checked) toggle.click();
|
||||||
});
|
});
|
||||||
|
|
|
@ -141,8 +141,7 @@ export class Pool {
|
||||||
};
|
};
|
||||||
|
|
||||||
start = (work: Work) => {
|
start = (work: Work) => {
|
||||||
console.log('sending ceval.pool.start');
|
window.lichess.storage.fire('ceval.pool.start');
|
||||||
window.lichess.storage.set('ceval.pool.start', Date.now().toString());
|
|
||||||
this.getWorker().then(function(worker) {
|
this.getWorker().then(function(worker) {
|
||||||
worker.start(work);
|
worker.start(work);
|
||||||
}).catch(function(error) {
|
}).catch(function(error) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ module.exports = function(cfg, element) {
|
||||||
var onFirstConnect = function() {
|
var onFirstConnect = function() {
|
||||||
var gameId = getParameterByName('hook_like');
|
var gameId = getParameterByName('hook_like');
|
||||||
if (!gameId) return;
|
if (!gameId) return;
|
||||||
$.post('/setup/hook/' + lichess.StrongSocket.sri + '/like/' + gameId);
|
$.post('/setup/hook/' + lichess.sri + '/like/' + gameId);
|
||||||
lobby.setTab('real_time');
|
lobby.setTab('real_time');
|
||||||
history.replaceState(null, null, '/');
|
history.replaceState(null, null, '/');
|
||||||
};
|
};
|
||||||
|
@ -266,7 +266,7 @@ module.exports = function(cfg, element) {
|
||||||
var poolMember = hookToPoolMember(color, $form.serializeArray());
|
var poolMember = hookToPoolMember(color, $form.serializeArray());
|
||||||
$.modal.close();
|
$.modal.close();
|
||||||
var call = {
|
var call = {
|
||||||
url: $form.attr('action').replace(/sri-placeholder/, lichess.StrongSocket.sri),
|
url: $form.attr('action').replace(/sri-placeholder/, lichess.sri),
|
||||||
data: $form.serialize() + "&color=" + color,
|
data: $form.serialize() + "&color=" + color,
|
||||||
type: 'post'
|
type: 'post'
|
||||||
};
|
};
|
||||||
|
|
|
@ -53,7 +53,7 @@ export default class LobbyController {
|
||||||
this.trans = opts.trans;
|
this.trans = opts.trans;
|
||||||
|
|
||||||
this.poolInStorage = li.storage.make('lobby.pool-in');
|
this.poolInStorage = li.storage.make('lobby.pool-in');
|
||||||
this.poolInStorage.listen(() => { // when another tab joins a pool
|
this.poolInStorage.listen(_ => { // when another tab joins a pool
|
||||||
this.leavePool();
|
this.leavePool();
|
||||||
redraw();
|
redraw();
|
||||||
});
|
});
|
||||||
|
@ -186,7 +186,7 @@ export default class LobbyController {
|
||||||
|
|
||||||
poolIn = () => {
|
poolIn = () => {
|
||||||
if (!this.poolMember) return;
|
if (!this.poolMember) return;
|
||||||
this.poolInStorage.set(li.StrongSocket.sri);
|
this.poolInStorage.fire();
|
||||||
this.socket.poolIn(this.poolMember);
|
this.socket.poolIn(this.poolMember);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ export function sort(ctrl: LobbyController, hooks: Hook[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function init(hook: Hook) {
|
export function init(hook: Hook) {
|
||||||
hook.action = hook.sri === window.lichess.StrongSocket.sri ? 'cancel' : 'join';
|
hook.action = hook.sri === window.lichess.sri ? 'cancel' : 'join';
|
||||||
hook.variant = hook.variant || 'standard';
|
hook.variant = hook.variant || 'standard';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ export function nowPlaying() {
|
||||||
export function anonPoolSeek(pool) {
|
export function anonPoolSeek(pool) {
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/setup/hook/' + window.lichess.StrongSocket.sri,
|
url: '/setup/hook/' + window.lichess.sri,
|
||||||
data: {
|
data: {
|
||||||
variant: 1,
|
variant: 1,
|
||||||
timeMode: 1,
|
timeMode: 1,
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default function ctrl(opts: NotifyOpts, redraw: Redraw): Ctrl {
|
||||||
|
|
||||||
const readAllStorage = li.storage.make('notify-read-all');
|
const readAllStorage = li.storage.make('notify-read-all');
|
||||||
|
|
||||||
readAllStorage.listen(() => {
|
readAllStorage.listen(_ => {
|
||||||
if (data) {
|
if (data) {
|
||||||
data.unread = 0;
|
data.unread = 0;
|
||||||
opts.setCount(0);
|
opts.setCount(0);
|
||||||
|
@ -25,7 +25,7 @@ export default function ctrl(opts: NotifyOpts, redraw: Redraw): Ctrl {
|
||||||
if (data.pager.currentPage === 1 && data.unread && opts.isVisible()) {
|
if (data.pager.currentPage === 1 && data.unread && opts.isVisible()) {
|
||||||
opts.setNotified();
|
opts.setNotified();
|
||||||
data.unread = 0;
|
data.unread = 0;
|
||||||
readAllStorage.set('' + Math.random()); // tell other tabs
|
readAllStorage.fire();
|
||||||
}
|
}
|
||||||
initiating = false;
|
initiating = false;
|
||||||
scrolling = false;
|
scrolling = false;
|
||||||
|
|
|
@ -16,13 +16,11 @@ export function subscribe(ctrl: RoundController): void {
|
||||||
if (!ctrl.data.game.rated && ctrl.opts.userId) return;
|
if (!ctrl.data.game.rated && ctrl.opts.userId) return;
|
||||||
// bots can cheat alright
|
// bots can cheat alright
|
||||||
if (ctrl.data.player.user && ctrl.data.player.user.title === 'BOT') return;
|
if (ctrl.data.player.user && ctrl.data.player.user.title === 'BOT') return;
|
||||||
li.storage.make('ceval.fen').listen(ev => {
|
li.storage.make('ceval.fen').listen(e => {
|
||||||
const v = ev.newValue;
|
if (e.value === 'start') return li.storage.fire('round.ongoing');
|
||||||
if (!v) return;
|
|
||||||
else if (v.startsWith('start:')) return li.storage.set('round.ongoing', v);
|
|
||||||
const d = ctrl.data, step = lastStep(ctrl.data);
|
const d = ctrl.data, step = lastStep(ctrl.data);
|
||||||
if (!found && step.ply > 14 && ctrl.isPlaying() &&
|
if (!found && step.ply > 14 && ctrl.isPlaying() &&
|
||||||
truncateFen(step.fen) === truncateFen(v)) {
|
e.value && truncateFen(step.fen) === truncateFen(e.value)) {
|
||||||
$.post('/jslog/' + d.game.id + d.player.id + '?n=ceval');
|
$.post('/jslog/' + d.game.id + d.player.id + '?n=ceval');
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
@ -31,5 +29,5 @@ export function subscribe(ctrl: RoundController): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function publish(d: RoundData, move: ApiMove) {
|
export function publish(d: RoundData, move: ApiMove) {
|
||||||
if (d.opponent.ai) li.storage.set('ceval.fen', move.fen);
|
if (d.opponent.ai) li.storage.fire('ceval.fen', move.fen);
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,13 +269,6 @@ lichess.StrongSocket = function(url, version, settings) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
|
||||||
const data = window.crypto.getRandomValues(new Uint8Array(9));
|
|
||||||
lichess.StrongSocket.sri = btoa(String.fromCharCode(...data)).replace(/[/+]/g, '_');
|
|
||||||
} catch(_) {
|
|
||||||
lichess.StrongSocket.sri = Math.random().toString(36).slice(2, 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
lichess.StrongSocket.defaults = {
|
lichess.StrongSocket.defaults = {
|
||||||
events: {
|
events: {
|
||||||
fen: function(e) {
|
fen: function(e) {
|
||||||
|
@ -291,7 +284,7 @@ lichess.StrongSocket.defaults = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
sri: lichess.StrongSocket.sri
|
sri: lichess.sri
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
name: "unnamed",
|
name: "unnamed",
|
||||||
|
|
|
@ -8,6 +8,13 @@ lichess.dispatchEvent = (el, eventName) => el.dispatchEvent(new Event(eventName)
|
||||||
|
|
||||||
lichess.hasTouchEvents = 'ontouchstart' in window;
|
lichess.hasTouchEvents = 'ontouchstart' in window;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = window.crypto.getRandomValues(new Uint8Array(9));
|
||||||
|
lichess.sri = btoa(String.fromCharCode(...data)).replace(/[/+]/g, '_');
|
||||||
|
} catch(_) {
|
||||||
|
lichess.sri = Math.random().toString(36).slice(2, 12);
|
||||||
|
}
|
||||||
|
|
||||||
lichess.isCol1 = (() => {
|
lichess.isCol1 = (() => {
|
||||||
let isCol1Cache = 'init'; // 'init' | 'rec' | boolean
|
let isCol1Cache = 'init'; // 'init' | 'rec' | boolean
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -28,15 +35,22 @@ lichess.isCol1 = (() => {
|
||||||
const api = {
|
const api = {
|
||||||
get: k => storage.getItem(k),
|
get: k => storage.getItem(k),
|
||||||
set: (k, v) => storage.setItem(k, v),
|
set: (k, v) => storage.setItem(k, v),
|
||||||
|
fire: (k, v) => storage.setItem(k, JSON.stringify({sri: lichess.sri, nonce: Math.random(), value: v})),
|
||||||
remove: k => storage.removeItem(k),
|
remove: k => storage.removeItem(k),
|
||||||
make: k => ({
|
make: k => ({
|
||||||
get: () => api.get(k),
|
get: () => api.get(k),
|
||||||
set: v => api.set(k, v),
|
set: v => api.set(k, v),
|
||||||
|
fire: v => api.fire(k, v),
|
||||||
remove: () => api.remove(k),
|
remove: () => api.remove(k),
|
||||||
listen: f => window.addEventListener('storage', e => {
|
listen: f => window.addEventListener('storage', e => {
|
||||||
if (e.key === k &&
|
if (e.key !== k || e.storageArea !== storage || e.newValue === null) return;
|
||||||
e.storageArea === storage &&
|
let parsed;
|
||||||
e.newValue !== null) f(e);
|
try {
|
||||||
|
parsed = JSON.parse(e.newValue);
|
||||||
|
} catch(_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (parsed.sri && parsed.sri !== lichess.sri) f(parsed);
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
makeBoolean: k => ({
|
makeBoolean: k => ({
|
||||||
|
|
Loading…
Reference in New Issue