Remove select callbacks and use observable instead

This commit is contained in:
Catalin Constantin Mititiuc 2024-05-21 21:05:54 -07:00
parent d01e0aa92b
commit 7395df376d
4 changed files with 80 additions and 65 deletions

View File

@ -116,7 +116,7 @@ function load() {
panzoom.start(svg); panzoom.start(svg);
gameboard.start(svg); gameboard.start(svg);
recordSheet.start(startLocs, gameboard.getUnits(), gameboard.unSelect, gameboard.select); recordSheet.start(startLocs, gameboard.getUnits());
} }
document.querySelectorAll('.end-turn').forEach(el => document.querySelectorAll('.end-turn').forEach(el =>
@ -158,14 +158,13 @@ gameboard.setDistanceCallback((count = '-') => {
}); });
gameboard.setProneFlagCallback(checked => proneToggle.checked = checked); gameboard.setProneFlagCallback(checked => proneToggle.checked = checked);
gameboard.setSelectCallback(data => recordSheet.select(data));
document.querySelectorAll('.end-move').forEach(el => el.addEventListener('click', () => { document.querySelectorAll('.end-move').forEach(el => el.addEventListener('click', () => {
recordSheet.endMove(); recordSheet.endMove();
gameboard.endMove(); gameboard.endMove();
})); }));
document.querySelector('#fullscreen').addEventListener('click', e => { document.querySelector('#fullscreen').addEventListener('click', () => {
if (!document.fullscreenElement) { if (!document.fullscreenElement) {
document.documentElement.requestFullscreen(); document.documentElement.requestFullscreen();
} else if (document.exitFullscreen) { } else if (document.exitFullscreen) {

View File

@ -1,8 +1,9 @@
import * as firingArc from './game/firing_arc.js'; import * as firingArc from './game/firing_arc.js';
import * as sightLine from './game/sight_line.js'; import * as sightLine from './game/sight_line.js';
import * as soldier from './game/soldier.js'; import * as soldier from './game/soldier.js';
import { Observable } from "./observable";
let svg, distanceCallback, proneFlagCallback, selectCallback, let svg, distanceCallback, proneFlagCallback,
selected, selected,
placing = []; placing = [];
@ -74,6 +75,17 @@ function getSelected() {
return svg.querySelector(`.counter.selected[data-allegiance][data-number]`); return svg.querySelector(`.counter.selected[data-allegiance][data-number]`);
} }
function deselect() {
const selected = getSelected();
placing = [];
if (selected) {
selected.classList.remove(soldier.getSelectedClass());
clearSightLine();
firingArc.clipAll(svg);
}
}
function clearSightLine() { function clearSightLine() {
sightLine.setHexes([]); sightLine.setHexes([]);
sightLine.clear(); sightLine.clear();
@ -159,7 +171,7 @@ function hasPreviousMoveInHistory(counter) {
} }
function selectOffBoard() { function selectOffBoard() {
this.classList.contains(soldier.getSelectedClass()) ? unSelect() : select(this); Observable.notify('select', this);
} }
export function getUnits() { export function getUnits() {
@ -174,10 +186,6 @@ export function setProneFlagCallback(callback) {
proneFlagCallback = callback; proneFlagCallback = callback;
} }
export function setSelectCallback(callback) {
selectCallback = callback;
}
export function start(el) { export function start(el) {
svg = el; svg = el;
@ -202,10 +210,10 @@ export function start(el) {
placing.push(toPlace); placing.push(toPlace);
getLockedSightLine(svg) ? updateSightLine(toPlace.parentElement) : drawSightLine(toPlace.parentElement, cell); getLockedSightLine(svg) ? updateSightLine(toPlace.parentElement) : drawSightLine(toPlace.parentElement, cell);
} else { } else {
unSelect(); deselect();
} }
} else if (!occupant.classList.contains('clone')) { } else if (!occupant.classList.contains('clone')) {
select(occupant); Observable.notify('select', occupant);
} else { } else {
if (isClone(occupant).of(toPlace)) { if (isClone(occupant).of(toPlace)) {
if (hasPreviousMoveInHistory(occupant)) { if (hasPreviousMoveInHistory(occupant)) {
@ -218,7 +226,7 @@ export function start(el) {
placing.push(toPlace); placing.push(toPlace);
} }
} else if (!toPlace && occupant) { } else if (!toPlace && occupant) {
select(occupant); Observable.notify('select', occupant);
} else { } else {
console.log('removing cell contents'); console.log('removing cell contents');
getCellContents(cell).forEach(el => el.remove()); getCellContents(cell).forEach(el => el.remove());
@ -234,7 +242,7 @@ export function start(el) {
selector = `[data-allegiance="${allegiance}"][data-number="${number}"]`; selector = `[data-allegiance="${allegiance}"][data-number="${number}"]`;
svg.querySelectorAll(selector).forEach(el => el.remove()); svg.querySelectorAll(selector).forEach(el => el.remove());
selectCallback(); Observable.notify('select');
} }
}); });
@ -271,33 +279,23 @@ export function start(el) {
}); });
}); });
Observable.subscribe('select', select);
console.log('gameboard.js loaded'); console.log('gameboard.js loaded');
} }
export function select(selected) { export function select(data) {
unSelect(); if (!data) return;
let counter = soldier.getCounter(svg, selected);
if (counter) { const counter = soldier.getCounter(svg, data) || soldier.createCounter(data);
firingArc.get(svg, counter).forEach(el => el.removeAttribute('clip-path')); const isSelected = counter.classList.contains(soldier.getSelectedClass());
} else {
counter = soldier.createCounter(selected); deselect();
}
if (isSelected) return;
placing.push(counter);
counter.classList.add(soldier.getSelectedClass()); counter.classList.add(soldier.getSelectedClass());
selectCallback && selectCallback({ prone: soldier.hasProne(counter), ...counter.dataset }); firingArc.get(svg, counter).forEach(el => el.removeAttribute('clip-path'));
} placing.push(counter);
export function unSelect() {
const selected = getSelected();
placing = [];
if (selected) {
getSelected().classList.remove(soldier.getSelectedClass());
clearSightLine();
firingArc.clipAll(svg);
}
} }
export function endMove() { export function endMove() {
@ -305,7 +303,7 @@ export function endMove() {
if (selected) { if (selected) {
soldier.endMove(svg, selected); soldier.endMove(svg, selected);
unSelect(); deselect();
} }
} }

19
src/modules/observable.js Normal file
View File

@ -0,0 +1,19 @@
const observers = {};
export const Observable = Object.freeze({
notify: (event, data) => {
observers[event].forEach((observer) => observer(data))
},
subscribe: (event, func) => {
(observers[event] ??= []).push(func);
},
unsubscribe: (event, func) => {
[...observers[event] || []].forEach((observer, index) => {
if (observer === func) {
observers[event].splice(index, 1);
}
});
},
});

View File

@ -1,3 +1,5 @@
import { Observable } from "./observable";
const weapons = { const weapons = {
rifle: { rifle: {
name: 'Rifle', name: 'Rifle',
@ -98,27 +100,19 @@ function createRecords(units) {
return grouped; return grouped;
} }
function addEventListeners(unSelectCounter, selectCounter) { function getRecord({ dataset: { allegiance: al, number: n }}) {
const selector = `.soldier-record[data-number="${n}"][data-allegiance="${al}"]`;
return document.querySelector(selector);
}
function addEventListeners() {
document.querySelectorAll('.soldier-record').forEach(el => document.querySelectorAll('.soldier-record').forEach(el =>
el.addEventListener('click', () => { el.addEventListener('click', () => Observable.notify('select', el))
if (el.classList.contains('selected')) {
el.classList.remove('selected');
unSelectCounter();
unSelect();
} else {
selectCounter(el);
}
})
); );
} }
export function clear() { function deselect() {
document.querySelectorAll('#record-sheet .soldier-record').forEach(el => el.remove());
document.querySelector('#attacker-record .name').textContent = 'attacker';
document.querySelector('#defender-record .name').textContent = 'defender';
}
export function unSelect() {
const selected = getSelected(); const selected = getSelected();
if (selected) { if (selected) {
@ -128,24 +122,28 @@ export function unSelect() {
document.getElementById('toggle-prone-counter').checked = false; document.getElementById('toggle-prone-counter').checked = false;
} }
export function getSelected() { function clear() {
return document.querySelector('.soldier-record.selected'); document.querySelectorAll('#record-sheet .soldier-record').forEach(el => el.remove());
document.querySelector('#attacker-record .name').textContent = 'attacker';
document.querySelector('#defender-record .name').textContent = 'defender';
} }
export function select(data) { function select(data) {
unSelect(); const record = data && getRecord(data);
const isSelected = record?.classList.contains('selected');
if (!data) { deselect();
return;
}
const { allegiance: al, number: n } = data, if (isSelected || !data) return;
selector = `.soldier-record[data-number="${n}"][data-allegiance="${al}"]`;
document.querySelector(selector).classList.add('selected'); record.classList.add('selected');
document.querySelector('#toggle-prone-counter').checked = data.prone; document.querySelector('#toggle-prone-counter').checked = data.prone;
} }
export function getSelected() {
return document.querySelector('.soldier-record.selected');
}
export function endMove() { export function endMove() {
const selected = getSelected(); const selected = getSelected();
@ -153,10 +151,10 @@ export function endMove() {
selected.classList.toggle('movement-ended'); selected.classList.toggle('movement-ended');
} }
unSelect(); deselect();
} }
export function start(startLoc, units, gbUnSelect, gbSelect) { export function start(startLoc, units) {
clear(); clear();
const forces = createRecords(units); const forces = createRecords(units);
@ -171,5 +169,6 @@ export function start(startLoc, units, gbUnSelect, gbSelect) {
forces[affiliation].forEach(r => records.appendChild(r)); forces[affiliation].forEach(r => records.appendChild(r));
} }
addEventListeners(gbUnSelect, gbSelect); Observable.subscribe('select', select);
addEventListeners();
} }