Add ability to deactivate/reactivate soldier records; make hex clearing work with right-click and add a confirmation modal dialog
This commit is contained in:
parent
e746cfb216
commit
63fb4139d5
@ -132,6 +132,7 @@ button.set-firing-arc img {
|
|||||||
position: relative;
|
position: relative;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
transition: transform 0.25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.soldier-record span[slot] {
|
.soldier-record span[slot] {
|
||||||
|
@ -101,17 +101,17 @@
|
|||||||
<p class="grenades">
|
<p class="grenades">
|
||||||
<span>Hand Grenades</span>
|
<span>Hand Grenades</span>
|
||||||
<label><input type='checkbox' checked /><svg viewBox="-7 -7 14 14" xmlns="http://www.w3.org/2000/svg">
|
<label><input type='checkbox' checked /><svg viewBox="-7 -7 14 14" xmlns="http://www.w3.org/2000/svg">
|
||||||
<circle cx="0" cy="0" r="5" />
|
<circle cx="0" cy="0" r="5" />
|
||||||
</svg></label>
|
</svg></label>
|
||||||
<label><input type='checkbox' checked /><svg viewBox="-7 -7 14 14" xmlns="http://www.w3.org/2000/svg">
|
<label><input type='checkbox' checked /><svg viewBox="-7 -7 14 14" xmlns="http://www.w3.org/2000/svg">
|
||||||
<circle cx="0" cy="0" r="5" />
|
<circle cx="0" cy="0" r="5" />
|
||||||
</svg></label>
|
</svg></label>
|
||||||
<label><input type='checkbox' checked /><svg viewBox="-7 -7 14 14" xmlns="http://www.w3.org/2000/svg">
|
<label><input type='checkbox' checked /><svg viewBox="-7 -7 14 14" xmlns="http://www.w3.org/2000/svg">
|
||||||
<circle cx="0" cy="0" r="5" />
|
<circle cx="0" cy="0" r="5" />
|
||||||
</svg></label>
|
</svg></label>
|
||||||
<label><input type='checkbox' checked /><svg viewBox="-7 -7 14 14" xmlns="http://www.w3.org/2000/svg">
|
<label><input type='checkbox' checked /><svg viewBox="-7 -7 14 14" xmlns="http://www.w3.org/2000/svg">
|
||||||
<circle cx="0" cy="0" r="5" />
|
<circle cx="0" cy="0" r="5" />
|
||||||
</svg></label>
|
</svg></label>
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -361,9 +361,20 @@
|
|||||||
<dialog id="clear-hex">
|
<dialog id="clear-hex">
|
||||||
<p>Clear hex contents?</p>
|
<p>Clear hex contents?</p>
|
||||||
<div>
|
<div>
|
||||||
<form>
|
<form style="display: flex; flex-direction: row;">
|
||||||
<button value="cancel" formmethod="dialog">Cancel</button>
|
<div style="width: 50%;">
|
||||||
<button value="confirm" formmethod="dialog">Confirm</button>
|
<button
|
||||||
|
style="display: block; margin-right: auto;"
|
||||||
|
value="cancel"
|
||||||
|
formmethod="dialog"
|
||||||
|
>Cancel</button>
|
||||||
|
</div>
|
||||||
|
<div style="width: 50%;">
|
||||||
|
<button
|
||||||
|
style="display: block; margin-left: auto;"
|
||||||
|
value="confirm"
|
||||||
|
>Confirm</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
@ -145,7 +145,7 @@ async function load() {
|
|||||||
document.querySelectorAll('.end-turn').forEach(el =>
|
document.querySelectorAll('.end-turn').forEach(el =>
|
||||||
el.addEventListener('click', ({ target: { dataset: { allegiance: opponent }}}) => {
|
el.addEventListener('click', ({ target: { dataset: { allegiance: opponent }}}) => {
|
||||||
const dataSelector = `[data-allegiance="${opponent}"]`,
|
const dataSelector = `[data-allegiance="${opponent}"]`,
|
||||||
opponentRecords = Array.from(document.querySelectorAll(`.soldier-record${dataSelector}`)),
|
opponentRecords = Array.from(document.querySelectorAll(`.soldier-record${dataSelector}:not(.inactive)`)),
|
||||||
firstOpponentRecord = opponentRecords.sort((el1, el2) => el1.dataset.number > el2.dataset.number).at(0);
|
firstOpponentRecord = opponentRecords.sort((el1, el2) => el1.dataset.number > el2.dataset.number).at(0);
|
||||||
|
|
||||||
el.setAttribute('disabled', '');
|
el.setAttribute('disabled', '');
|
||||||
@ -154,7 +154,11 @@ document.querySelectorAll('.end-turn').forEach(el =>
|
|||||||
clearMoveEndedIndicators(opponentRecords);
|
clearMoveEndedIndicators(opponentRecords);
|
||||||
|
|
||||||
gameboard.clearFiringArcs(opponent);
|
gameboard.clearFiringArcs(opponent);
|
||||||
Observable.notify('select', firstOpponentRecord);
|
|
||||||
|
if (firstOpponentRecord) {
|
||||||
|
Observable.notify('select', firstOpponentRecord);
|
||||||
|
firstOpponentRecord.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -205,6 +205,14 @@ function endMove() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Work around webkit bug https://bugs.webkit.org/show_bug.cgi?id=233432
|
||||||
|
function workaroundForWebKitBug233432(listener) {
|
||||||
|
return e => {
|
||||||
|
const elUnderCursor = svg.parentNode.elementFromPoint(e.clientX, e.clientY);
|
||||||
|
if (!e.target.contains(elUnderCursor)) listener(e);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function start(el) {
|
export function start(el) {
|
||||||
svg = el;
|
svg = el;
|
||||||
const gridTop = svg.querySelector('.grid-top');
|
const gridTop = svg.querySelector('.grid-top');
|
||||||
@ -221,20 +229,20 @@ export function start(el) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
gridTop.addEventListener('pointerleave', e => {
|
clearHexDialog.querySelector('button[value="confirm"]').addEventListener('click', function(e) {
|
||||||
// Work around webkit bug https://bugs.webkit.org/show_bug.cgi?id=233432
|
e.preventDefault();
|
||||||
const elUnderCursor = svg.parentNode.elementFromPoint(e.clientX, e.clientY);
|
clearHexDialog.close(this.value);
|
||||||
if (!e.target.contains(elUnderCursor)) {
|
|
||||||
console.log(['pointerleave', gridTop]);
|
|
||||||
[...top.container.children].forEach(child => {
|
|
||||||
top.collection.get(child).parent.append(child);
|
|
||||||
top.collection.delete(child);
|
|
||||||
});
|
|
||||||
|
|
||||||
top.cell = null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gridTop.addEventListener('pointerleave', workaroundForWebKitBug233432(e => {
|
||||||
|
[...top.container.children].forEach(child => {
|
||||||
|
top.collection.get(child).parent.append(child);
|
||||||
|
top.collection.delete(child);
|
||||||
|
});
|
||||||
|
|
||||||
|
top.cell = null;
|
||||||
|
}));
|
||||||
|
|
||||||
topHex.addEventListener('click', clickHandler);
|
topHex.addEventListener('click', clickHandler);
|
||||||
|
|
||||||
topHex.addEventListener('contextmenu', e => {
|
topHex.addEventListener('contextmenu', e => {
|
||||||
@ -246,8 +254,6 @@ export function start(el) {
|
|||||||
startingLocations && getUnits(startingLocations).forEach(unit => unit.addEventListener('click', selectOffBoard));
|
startingLocations && getUnits(startingLocations).forEach(unit => unit.addEventListener('click', selectOffBoard));
|
||||||
|
|
||||||
function clickHandler(e) {
|
function clickHandler(e) {
|
||||||
console.log('top hex click event');
|
|
||||||
//const occupant = getCellOccupant(this);
|
|
||||||
const occupant = svg.querySelector('.grid-top .container .counter')
|
const occupant = svg.querySelector('.grid-top .container .counter')
|
||||||
let toPlace = placing.pop();
|
let toPlace = placing.pop();
|
||||||
|
|
||||||
@ -257,10 +263,8 @@ export function start(el) {
|
|||||||
if (isCounter(toPlace)) arrangeCounters(top.container);
|
if (isCounter(toPlace)) arrangeCounters(top.container);
|
||||||
removeEventListener("keydown", handleMechTemplateRotation);
|
removeEventListener("keydown", handleMechTemplateRotation);
|
||||||
} else if (toPlace && !occupant) {
|
} else if (toPlace && !occupant) {
|
||||||
//soldier.place(svg, toPlace, this);
|
|
||||||
top.collection.set(toPlace, { parent: top.cell });
|
top.collection.set(toPlace, { parent: top.cell });
|
||||||
top.container.prepend(toPlace);
|
top.container.prepend(toPlace);
|
||||||
//toPlace.removeEventListener('click', selectOffBoard);
|
|
||||||
placing.push(toPlace);
|
placing.push(toPlace);
|
||||||
getLockedSightLine(svg) ? updateSightLine(top.cell) : clearSightLine();
|
getLockedSightLine(svg) ? updateSightLine(top.cell) : clearSightLine();
|
||||||
} else if (toPlace && occupant) {
|
} else if (toPlace && occupant) {
|
||||||
@ -271,79 +275,14 @@ export function start(el) {
|
|||||||
}
|
}
|
||||||
} else if (!toPlace && occupant) {
|
} else if (!toPlace && occupant) {
|
||||||
Observable.notify('select', occupant);
|
Observable.notify('select', occupant);
|
||||||
} else {
|
|
||||||
console.log(['removing this contents', this]);
|
|
||||||
getCellContents(this).forEach(el => el.remove());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const selected = getSelected();
|
const selected = getSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
getCells(svg).forEach(cell => {
|
getCells(svg).forEach(cell => {
|
||||||
cell.addEventListener('click', e => {
|
|
||||||
console.log('cell clickevent');
|
|
||||||
const occupant = getCellOccupant(cell);
|
|
||||||
let toPlace = placing.pop();
|
|
||||||
|
|
||||||
if (isCounter(toPlace) || isMechTemplate(toPlace)) {
|
|
||||||
//getHex(cell).after(toPlace);
|
|
||||||
top.collection.set(toPlace, { parent: cell });
|
|
||||||
top.container.append(toPlace);
|
|
||||||
//if (isCounter(toPlace)) arrangeCounters(cell);
|
|
||||||
if (isCounter(toPlace)) arrangeCounters(top.container);
|
|
||||||
removeEventListener("keydown", handleMechTemplateRotation);
|
|
||||||
} else if (toPlace && !occupant) {
|
|
||||||
soldier.place(svg, toPlace, cell);
|
|
||||||
toPlace.removeEventListener('click', selectOffBoard);
|
|
||||||
placing.push(toPlace);
|
|
||||||
getLockedSightLine(svg) ? updateSightLine(cell) : clearSightLine();
|
|
||||||
} else if (toPlace && occupant) {
|
|
||||||
if (toPlace === occupant) {
|
|
||||||
if (hasPreviousMoveInHistory(toPlace)) {
|
|
||||||
toPlace = moveBackOneStepInHistory(toPlace);
|
|
||||||
placing.push(toPlace);
|
|
||||||
getLockedSightLine(svg) ? updateSightLine(toPlace.parentElement) : drawSightLine(toPlace.parentElement, cell);
|
|
||||||
} else {
|
|
||||||
Observable.notify('select');
|
|
||||||
}
|
|
||||||
} else if (!occupant.classList.contains('clone')) {
|
|
||||||
Observable.notify('select', occupant);
|
|
||||||
} else {
|
|
||||||
if (isClone(occupant).of(toPlace)) {
|
|
||||||
if (hasPreviousMoveInHistory(occupant)) {
|
|
||||||
deleteClone(occupant, toPlace, cell);
|
|
||||||
} else {
|
|
||||||
toPlace = clearMoveHistory(occupant, toPlace);
|
|
||||||
getLockedSightLine(svg) ? updateSightLine(cell) : clearSightLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
placing.push(toPlace);
|
|
||||||
}
|
|
||||||
} else if (!toPlace && occupant) {
|
|
||||||
Observable.notify('select', occupant);
|
|
||||||
} else {
|
|
||||||
console.log('removing cell contents', cell);
|
|
||||||
getCellContents(cell).forEach(el => el.remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
const selected = getSelected();
|
|
||||||
});
|
|
||||||
|
|
||||||
//cell.addEventListener('dblclick', e => {
|
|
||||||
// const toPlace = placing.pop(),
|
|
||||||
// occupant = getCellOccupant(cell);
|
|
||||||
//
|
|
||||||
// if (toPlace && occupant && toPlace === occupant) {
|
|
||||||
// const { number, allegiance } = toPlace.dataset,
|
|
||||||
// selector = `[data-allegiance="${allegiance}"][data-number="${number}"]`;
|
|
||||||
//
|
|
||||||
// svg.querySelectorAll(selector).forEach(el => el.remove());
|
|
||||||
// Observable.notify('select');
|
|
||||||
// }
|
|
||||||
//});
|
|
||||||
|
|
||||||
cell.addEventListener('pointerover', () => {
|
cell.addEventListener('pointerover', () => {
|
||||||
console.log(['pointerenter', cell]);
|
//console.log(['pointerenter', cell]);
|
||||||
|
|
||||||
top.cell = cell;
|
top.cell = cell;
|
||||||
|
|
||||||
|
@ -99,6 +99,45 @@ function createRecord(unit) {
|
|||||||
|
|
||||||
spans.forEach(el => div.appendChild(el));
|
spans.forEach(el => div.appendChild(el));
|
||||||
|
|
||||||
|
function makeInactiveDivider(parent) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.classList.add('inactive-divider');
|
||||||
|
div.textContent = 'Inactive';
|
||||||
|
parent.append(div);
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.addEventListener('contextmenu', e => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!div.classList.contains('inactive')) {
|
||||||
|
const inactiveDivider = div.parentElement.querySelector('.inactive-divider') || makeInactiveDivider(div.parentElement);
|
||||||
|
|
||||||
|
div.addEventListener('transitionend', e => {
|
||||||
|
inactiveDivider.after(div);
|
||||||
|
inactiveDivider.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
});
|
||||||
|
|
||||||
|
div.classList.add('inactive');
|
||||||
|
div.setAttributeNS(null, 'style', 'transform: scale(0.9);');
|
||||||
|
} else {
|
||||||
|
const squadRecords = div.parentElement.querySelectorAll(`.soldier-record:not(.inactive)[data-squad="${div.dataset.squad}"]`);
|
||||||
|
const sorted = [...squadRecords, div].sort(({dataset: { number: a }}, {dataset: { number: b }}) => +a > +b);
|
||||||
|
const index = sorted.findIndex(record => record === div);
|
||||||
|
|
||||||
|
if (index === 0)
|
||||||
|
div.parentElement.prepend(div);
|
||||||
|
else if (index === sorted.length - 1)
|
||||||
|
sorted[sorted.length - 2].after(div)
|
||||||
|
else
|
||||||
|
sorted[index - 1].after(div)
|
||||||
|
|
||||||
|
div.classList.remove('inactive');
|
||||||
|
div.removeAttributeNS(null, 'style');
|
||||||
|
div.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,6 +183,7 @@ function select(data) {
|
|||||||
if (isSelected || !data) return;
|
if (isSelected || !data) return;
|
||||||
|
|
||||||
record.classList.add('selected');
|
record.classList.add('selected');
|
||||||
|
record.scrollIntoView({ behavior: 'smooth' });
|
||||||
}
|
}
|
||||||
|
|
||||||
function endMove() {
|
function endMove() {
|
||||||
@ -151,9 +191,14 @@ function endMove() {
|
|||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
selected.classList.toggle('movement-ended');
|
selected.classList.toggle('movement-ended');
|
||||||
}
|
const next = selected.parentElement.querySelector(`.soldier-record[data-squad="${selected.dataset.squad}"]:not(.movement-ended, .inactive)`);
|
||||||
|
deselect();
|
||||||
|
|
||||||
deselect();
|
if (next) {
|
||||||
|
Observable.notify('select', next);
|
||||||
|
next.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractWeaponFromRecord(recordEl) {
|
export function extractWeaponFromRecord(recordEl) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user