Web Dev Solutions

Catalin Mititiuc

aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/index.js5
-rw-r--r--src/modules/gameboard.js60
-rw-r--r--src/modules/observable.js19
-rw-r--r--src/modules/record_sheet.js59
4 files changed, 79 insertions, 64 deletions
diff --git a/src/index.js b/src/index.js
index b268b2b..298f961 100644
--- a/src/index.js
+++ b/src/index.js
@@ -116,7 +116,7 @@ function load() {
panzoom.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 =>
@@ -158,14 +158,13 @@ gameboard.setDistanceCallback((count = '-') => {
});
gameboard.setProneFlagCallback(checked => proneToggle.checked = checked);
-gameboard.setSelectCallback(data => recordSheet.select(data));
document.querySelectorAll('.end-move').forEach(el => el.addEventListener('click', () => {
recordSheet.endMove();
gameboard.endMove();
}));
-document.querySelector('#fullscreen').addEventListener('click', e => {
+document.querySelector('#fullscreen').addEventListener('click', () => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
} else if (document.exitFullscreen) {
diff --git a/src/modules/gameboard.js b/src/modules/gameboard.js
index abf37b0..8f03603 100644
--- a/src/modules/gameboard.js
+++ b/src/modules/gameboard.js
@@ -1,8 +1,9 @@
import * as firingArc from './game/firing_arc.js';
import * as sightLine from './game/sight_line.js';
import * as soldier from './game/soldier.js';
+import { Observable } from "./observable";
-let svg, distanceCallback, proneFlagCallback, selectCallback,
+let svg, distanceCallback, proneFlagCallback,
selected,
placing = [];
@@ -74,6 +75,17 @@ function getSelected() {
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() {
sightLine.setHexes([]);
sightLine.clear();
@@ -159,7 +171,7 @@ function hasPreviousMoveInHistory(counter) {
}
function selectOffBoard() {
- this.classList.contains(soldier.getSelectedClass()) ? unSelect() : select(this);
+ Observable.notify('select', this);
}
export function getUnits() {
@@ -174,10 +186,6 @@ export function setProneFlagCallback(callback) {
proneFlagCallback = callback;
}
-export function setSelectCallback(callback) {
- selectCallback = callback;
-}
-
export function start(el) {
svg = el;
@@ -202,10 +210,10 @@ export function start(el) {
placing.push(toPlace);
getLockedSightLine(svg) ? updateSightLine(toPlace.parentElement) : drawSightLine(toPlace.parentElement, cell);
} else {
- unSelect();
+ deselect();
}
} else if (!occupant.classList.contains('clone')) {
- select(occupant);
+ Observable.notify('select', occupant);
} else {
if (isClone(occupant).of(toPlace)) {
if (hasPreviousMoveInHistory(occupant)) {
@@ -218,7 +226,7 @@ export function start(el) {
placing.push(toPlace);
}
} else if (!toPlace && occupant) {
- select(occupant);
+ Observable.notify('select', occupant);
} else {
console.log('removing cell contents');
getCellContents(cell).forEach(el => el.remove());
@@ -234,7 +242,7 @@ export function start(el) {
selector = `[data-allegiance="${allegiance}"][data-number="${number}"]`;
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');
}
-export function select(selected) {
- unSelect();
- let counter = soldier.getCounter(svg, selected);
+export function select(data) {
+ if (!data) return;
- if (counter) {
- firingArc.get(svg, counter).forEach(el => el.removeAttribute('clip-path'));
- } else {
- counter = soldier.createCounter(selected);
- }
+ const counter = soldier.getCounter(svg, data) || soldier.createCounter(data);
+ const isSelected = counter.classList.contains(soldier.getSelectedClass());
- placing.push(counter);
- counter.classList.add(soldier.getSelectedClass());
- selectCallback && selectCallback({ prone: soldier.hasProne(counter), ...counter.dataset });
-}
+ deselect();
-export function unSelect() {
- const selected = getSelected();
- placing = [];
+ if (isSelected) return;
- if (selected) {
- getSelected().classList.remove(soldier.getSelectedClass());
- clearSightLine();
- firingArc.clipAll(svg);
- }
+ counter.classList.add(soldier.getSelectedClass());
+ firingArc.get(svg, counter).forEach(el => el.removeAttribute('clip-path'));
+ placing.push(counter);
}
export function endMove() {
@@ -305,7 +303,7 @@ export function endMove() {
if (selected) {
soldier.endMove(svg, selected);
- unSelect();
+ deselect();
}
}
diff --git a/src/modules/observable.js b/src/modules/observable.js
new file mode 100644
index 0000000..e4f6797
--- /dev/null
+++ b/src/modules/observable.js
@@ -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);
+ }
+ });
+ },
+});
diff --git a/src/modules/record_sheet.js b/src/modules/record_sheet.js
index bf28875..7b0a80f 100644
--- a/src/modules/record_sheet.js
+++ b/src/modules/record_sheet.js
@@ -1,3 +1,5 @@
+import { Observable } from "./observable";
+
const weapons = {
rifle: {
name: 'Rifle',
@@ -98,27 +100,19 @@ function createRecords(units) {
return grouped;
}
-function addEventListeners(unSelectCounter, selectCounter) {
- document.querySelectorAll('.soldier-record').forEach(el =>
- el.addEventListener('click', () => {
- if (el.classList.contains('selected')) {
- el.classList.remove('selected');
- unSelectCounter();
- unSelect();
- } else {
- selectCounter(el);
- }
- })
- );
+function getRecord({ dataset: { allegiance: al, number: n }}) {
+ const selector = `.soldier-record[data-number="${n}"][data-allegiance="${al}"]`;
+
+ return document.querySelector(selector);
}
-export function clear() {
- document.querySelectorAll('#record-sheet .soldier-record').forEach(el => el.remove());
- document.querySelector('#attacker-record .name').textContent = 'attacker';
- document.querySelector('#defender-record .name').textContent = 'defender';
+function addEventListeners() {
+ document.querySelectorAll('.soldier-record').forEach(el =>
+ el.addEventListener('click', () => Observable.notify('select', el))
+ );
}
-export function unSelect() {
+function deselect() {
const selected = getSelected();
if (selected) {
@@ -128,24 +122,28 @@ export function unSelect() {
document.getElementById('toggle-prone-counter').checked = false;
}
-export function getSelected() {
- return document.querySelector('.soldier-record.selected');
+function clear() {
+ 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) {
- unSelect();
+function select(data) {
+ const record = data && getRecord(data);
+ const isSelected = record?.classList.contains('selected');
- if (!data) {
- return;
- }
+ deselect();
- const { allegiance: al, number: n } = data,
- selector = `.soldier-record[data-number="${n}"][data-allegiance="${al}"]`;
+ if (isSelected || !data) return;
- document.querySelector(selector).classList.add('selected');
+ record.classList.add('selected');
document.querySelector('#toggle-prone-counter').checked = data.prone;
}
+export function getSelected() {
+ return document.querySelector('.soldier-record.selected');
+}
+
export function endMove() {
const selected = getSelected();
@@ -153,10 +151,10 @@ export function endMove() {
selected.classList.toggle('movement-ended');
}
- unSelect();
+ deselect();
}
-export function start(startLoc, units, gbUnSelect, gbSelect) {
+export function start(startLoc, units) {
clear();
const forces = createRecords(units);
@@ -171,5 +169,6 @@ export function start(startLoc, units, gbUnSelect, gbSelect) {
forces[affiliation].forEach(r => records.appendChild(r));
}
- addEventListeners(gbUnSelect, gbSelect);
+ Observable.subscribe('select', select);
+ addEventListeners();
}