Get rid of some todos / fixmes

This commit is contained in:
tobspr 2020-10-08 19:47:27 +02:00
parent 1025bede1f
commit 8260edb373
13 changed files with 496 additions and 539 deletions

View File

@ -71,10 +71,6 @@ releaseUploader.gulptasksReleaseUploader($, gulp, buildFolder);
const translations = require("./translations"); const translations = require("./translations");
translations.gulptasksTranslations($, gulp, buildFolder); translations.gulptasksTranslations($, gulp, buildFolder);
// FIXME
// const cordova = require("./cordova");
// cordova.gulptasksCordova($, gulp, buildFolder);
///////////////////// BUILD TASKS ///////////////////// ///////////////////// BUILD TASKS /////////////////////
// Cleans up everything // Cleans up everything

View File

@ -1,467 +1,465 @@
import { createLogger } from "../core/logging"; import { createLogger } from "../core/logging";
import { Signal } from "../core/signal"; import { Signal } from "../core/signal";
import { fastArrayDelete, fastArrayDeleteValueIfContained } from "./utils"; import { fastArrayDelete, fastArrayDeleteValueIfContained } from "./utils";
import { Vector } from "./vector"; import { Vector } from "./vector";
import { IS_MOBILE, SUPPORT_TOUCH } from "./config"; import { IS_MOBILE, SUPPORT_TOUCH } from "./config";
import { SOUNDS } from "../platform/sound"; import { SOUNDS } from "../platform/sound";
import { GLOBAL_APP } from "./globals"; import { GLOBAL_APP } from "./globals";
const logger = createLogger("click_detector"); const logger = createLogger("click_detector");
export const MAX_MOVE_DISTANCE_PX = IS_MOBILE ? 20 : 80; export const MAX_MOVE_DISTANCE_PX = IS_MOBILE ? 20 : 80;
// For debugging // For debugging
const registerClickDetectors = G_IS_DEV && true; const registerClickDetectors = G_IS_DEV && true;
if (registerClickDetectors) { if (registerClickDetectors) {
/** @type {Array<ClickDetector>} */ /** @type {Array<ClickDetector>} */
window.activeClickDetectors = []; window.activeClickDetectors = [];
} }
// Store active click detectors so we can cancel them // Store active click detectors so we can cancel them
/** @type {Array<ClickDetector>} */ /** @type {Array<ClickDetector>} */
const ongoingClickDetectors = []; const ongoingClickDetectors = [];
// Store when the last touch event was registered, to avoid accepting a touch *and* a click event // Store when the last touch event was registered, to avoid accepting a touch *and* a click event
export let clickDetectorGlobals = { export let clickDetectorGlobals = {
lastTouchTime: -1000, lastTouchTime: -1000,
}; };
/** /**
* Click detector creation payload typehints * Click detector creation payload typehints
* @typedef {{ * @typedef {{
* consumeEvents?: boolean, * consumeEvents?: boolean,
* preventDefault?: boolean, * preventDefault?: boolean,
* applyCssClass?: string, * applyCssClass?: string,
* captureTouchmove?: boolean, * captureTouchmove?: boolean,
* targetOnly?: boolean, * targetOnly?: boolean,
* maxDistance?: number, * maxDistance?: number,
* clickSound?: string, * clickSound?: string,
* preventClick?: boolean, * preventClick?: boolean,
* }} ClickDetectorConstructorArgs * }} ClickDetectorConstructorArgs
*/ */
// Detects clicks // Detects clicks
export class ClickDetector { export class ClickDetector {
/** /**
* *
* @param {Element} element * @param {Element} element
* @param {object} param1 * @param {object} param1
* @param {boolean=} param1.consumeEvents Whether to call stopPropagation * @param {boolean=} param1.consumeEvents Whether to call stopPropagation
* (Useful for nested elements where the parent has a click handler as wel) * (Useful for nested elements where the parent has a click handler as wel)
* @param {boolean=} param1.preventDefault Whether to call preventDefault (Usually makes the handler faster) * @param {boolean=} param1.preventDefault Whether to call preventDefault (Usually makes the handler faster)
* @param {string=} param1.applyCssClass The css class to add while the element is pressed * @param {string=} param1.applyCssClass The css class to add while the element is pressed
* @param {boolean=} param1.captureTouchmove Whether to capture touchmove events as well * @param {boolean=} param1.captureTouchmove Whether to capture touchmove events as well
* @param {boolean=} param1.targetOnly Whether to also accept clicks on child elements (e.target !== element) * @param {boolean=} param1.targetOnly Whether to also accept clicks on child elements (e.target !== element)
* @param {number=} param1.maxDistance The maximum distance in pixels to accept clicks * @param {number=} param1.maxDistance The maximum distance in pixels to accept clicks
* @param {string=} param1.clickSound Sound key to play on touchdown * @param {string=} param1.clickSound Sound key to play on touchdown
* @param {boolean=} param1.preventClick Whether to prevent click events * @param {boolean=} param1.preventClick Whether to prevent click events
*/ */
constructor( constructor(
element, element,
{ {
consumeEvents = false, consumeEvents = false,
preventDefault = true, preventDefault = true,
applyCssClass = "pressed", applyCssClass = "pressed",
captureTouchmove = false, captureTouchmove = false,
targetOnly = false, targetOnly = false,
maxDistance = MAX_MOVE_DISTANCE_PX, maxDistance = MAX_MOVE_DISTANCE_PX,
clickSound = SOUNDS.uiClick, clickSound = SOUNDS.uiClick,
preventClick = false, preventClick = false,
} }
) { ) {
assert(element, "No element given!"); assert(element, "No element given!");
this.clickDownPosition = null; this.clickDownPosition = null;
this.consumeEvents = consumeEvents; this.consumeEvents = consumeEvents;
this.preventDefault = preventDefault; this.preventDefault = preventDefault;
this.applyCssClass = applyCssClass; this.applyCssClass = applyCssClass;
this.captureTouchmove = captureTouchmove; this.captureTouchmove = captureTouchmove;
this.targetOnly = targetOnly; this.targetOnly = targetOnly;
this.clickSound = clickSound; this.clickSound = clickSound;
this.maxDistance = maxDistance; this.maxDistance = maxDistance;
this.preventClick = preventClick; this.preventClick = preventClick;
// Signals // Signals
this.click = new Signal(); this.click = new Signal();
this.rightClick = new Signal(); this.rightClick = new Signal();
this.touchstart = new Signal(); this.touchstart = new Signal();
this.touchmove = new Signal(); this.touchmove = new Signal();
this.touchend = new Signal(); this.touchend = new Signal();
this.touchcancel = new Signal(); this.touchcancel = new Signal();
// Simple signals which just receive the touch position // Simple signals which just receive the touch position
this.touchstartSimple = new Signal(); this.touchstartSimple = new Signal();
this.touchmoveSimple = new Signal(); this.touchmoveSimple = new Signal();
this.touchendSimple = new Signal(); this.touchendSimple = new Signal();
// Store time of touch start // Store time of touch start
this.clickStartTime = null; this.clickStartTime = null;
// A click can be cancelled if another detector registers a click // A click can be cancelled if another detector registers a click
this.cancelled = false; this.cancelled = false;
this.internalBindTo(/** @type {HTMLElement} */ (element)); this.internalBindTo(/** @type {HTMLElement} */ (element));
} }
/** /**
* Cleans up all event listeners of this detector * Cleans up all event listeners of this detector
*/ */
cleanup() { cleanup() {
if (this.element) { if (this.element) {
if (registerClickDetectors) { if (registerClickDetectors) {
const index = window.activeClickDetectors.indexOf(this); const index = window.activeClickDetectors.indexOf(this);
if (index < 0) { if (index < 0) {
logger.error("Click detector cleanup but is not active"); logger.error("Click detector cleanup but is not active");
} else { } else {
window.activeClickDetectors.splice(index, 1); window.activeClickDetectors.splice(index, 1);
} }
} }
const options = this.internalGetEventListenerOptions(); const options = this.internalGetEventListenerOptions();
if (SUPPORT_TOUCH) { if (SUPPORT_TOUCH) {
this.element.removeEventListener("touchstart", this.handlerTouchStart, options); this.element.removeEventListener("touchstart", this.handlerTouchStart, options);
this.element.removeEventListener("touchend", this.handlerTouchEnd, options); this.element.removeEventListener("touchend", this.handlerTouchEnd, options);
this.element.removeEventListener("touchcancel", this.handlerTouchCancel, options); this.element.removeEventListener("touchcancel", this.handlerTouchCancel, options);
} }
this.element.removeEventListener("mouseup", this.handlerTouchStart, options); this.element.removeEventListener("mouseup", this.handlerTouchStart, options);
this.element.removeEventListener("mousedown", this.handlerTouchEnd, options); this.element.removeEventListener("mousedown", this.handlerTouchEnd, options);
this.element.removeEventListener("mouseout", this.handlerTouchCancel, options); this.element.removeEventListener("mouseout", this.handlerTouchCancel, options);
if (this.captureTouchmove) { if (this.captureTouchmove) {
if (SUPPORT_TOUCH) { if (SUPPORT_TOUCH) {
this.element.removeEventListener("touchmove", this.handlerTouchMove, options); this.element.removeEventListener("touchmove", this.handlerTouchMove, options);
} }
this.element.removeEventListener("mousemove", this.handlerTouchMove, options); this.element.removeEventListener("mousemove", this.handlerTouchMove, options);
} }
if (this.preventClick) { if (this.preventClick) {
this.element.removeEventListener("click", this.handlerPreventClick, options); this.element.removeEventListener("click", this.handlerPreventClick, options);
} }
this.click.removeAll(); this.click.removeAll();
this.touchstart.removeAll(); this.touchstart.removeAll();
this.touchmove.removeAll(); this.touchmove.removeAll();
this.touchend.removeAll(); this.touchend.removeAll();
this.touchcancel.removeAll(); this.touchcancel.removeAll();
// TODO: Remove pointer captures this.element = null;
}
this.element = null; }
}
} // INTERNAL METHODS
// INTERNAL METHODS /**
*
/** * @param {Event} event
* */
* @param {Event} event internalPreventClick(event) {
*/ window.focus();
internalPreventClick(event) { event.preventDefault();
window.focus(); }
event.preventDefault();
} /**
* Internal method to get the options to pass to an event listener
/** */
* Internal method to get the options to pass to an event listener internalGetEventListenerOptions() {
*/ return {
internalGetEventListenerOptions() { capture: this.consumeEvents,
return { passive: !this.preventDefault,
capture: this.consumeEvents, };
passive: !this.preventDefault, }
};
} /**
* Binds the click detector to an element
/** * @param {HTMLElement} element
* Binds the click detector to an element */
* @param {HTMLElement} element internalBindTo(element) {
*/ const options = this.internalGetEventListenerOptions();
internalBindTo(element) {
const options = this.internalGetEventListenerOptions(); this.handlerTouchStart = this.internalOnPointerDown.bind(this);
this.handlerTouchEnd = this.internalOnPointerEnd.bind(this);
this.handlerTouchStart = this.internalOnPointerDown.bind(this); this.handlerTouchMove = this.internalOnPointerMove.bind(this);
this.handlerTouchEnd = this.internalOnPointerEnd.bind(this); this.handlerTouchCancel = this.internalOnTouchCancel.bind(this);
this.handlerTouchMove = this.internalOnPointerMove.bind(this);
this.handlerTouchCancel = this.internalOnTouchCancel.bind(this); if (this.preventClick) {
this.handlerPreventClick = this.internalPreventClick.bind(this);
if (this.preventClick) { element.addEventListener("click", this.handlerPreventClick, options);
this.handlerPreventClick = this.internalPreventClick.bind(this); }
element.addEventListener("click", this.handlerPreventClick, options);
} if (SUPPORT_TOUCH) {
element.addEventListener("touchstart", this.handlerTouchStart, options);
if (SUPPORT_TOUCH) { element.addEventListener("touchend", this.handlerTouchEnd, options);
element.addEventListener("touchstart", this.handlerTouchStart, options); element.addEventListener("touchcancel", this.handlerTouchCancel, options);
element.addEventListener("touchend", this.handlerTouchEnd, options); }
element.addEventListener("touchcancel", this.handlerTouchCancel, options);
} element.addEventListener("mousedown", this.handlerTouchStart, options);
element.addEventListener("mouseup", this.handlerTouchEnd, options);
element.addEventListener("mousedown", this.handlerTouchStart, options); element.addEventListener("mouseout", this.handlerTouchCancel, options);
element.addEventListener("mouseup", this.handlerTouchEnd, options);
element.addEventListener("mouseout", this.handlerTouchCancel, options); if (this.captureTouchmove) {
if (SUPPORT_TOUCH) {
if (this.captureTouchmove) { element.addEventListener("touchmove", this.handlerTouchMove, options);
if (SUPPORT_TOUCH) { }
element.addEventListener("touchmove", this.handlerTouchMove, options); element.addEventListener("mousemove", this.handlerTouchMove, options);
} }
element.addEventListener("mousemove", this.handlerTouchMove, options);
} if (registerClickDetectors) {
window.activeClickDetectors.push(this);
if (registerClickDetectors) { }
window.activeClickDetectors.push(this); this.element = element;
} }
this.element = element;
} /**
* Returns if the bound element is currently in the DOM.
/** */
* Returns if the bound element is currently in the DOM. internalIsDomElementAttached() {
*/ return this.element && document.documentElement.contains(this.element);
internalIsDomElementAttached() { }
return this.element && document.documentElement.contains(this.element);
} /**
* Checks if the given event is relevant for this detector
/** * @param {TouchEvent|MouseEvent} event
* Checks if the given event is relevant for this detector */
* @param {TouchEvent|MouseEvent} event internalEventPreHandler(event, expectedRemainingTouches = 1) {
*/ if (!this.element) {
internalEventPreHandler(event, expectedRemainingTouches = 1) { // Already cleaned up
if (!this.element) { return false;
// Already cleaned up }
return false;
} if (this.targetOnly && event.target !== this.element) {
// Clicked a child element
if (this.targetOnly && event.target !== this.element) { return false;
// Clicked a child element }
return false;
} // Stop any propagation and defaults if configured
if (this.consumeEvents && event.cancelable) {
// Stop any propagation and defaults if configured event.stopPropagation();
if (this.consumeEvents && event.cancelable) { }
event.stopPropagation();
} if (this.preventDefault && event.cancelable) {
event.preventDefault();
if (this.preventDefault && event.cancelable) { }
event.preventDefault();
} if (window.TouchEvent && event instanceof TouchEvent) {
clickDetectorGlobals.lastTouchTime = performance.now();
if (window.TouchEvent && event instanceof TouchEvent) {
clickDetectorGlobals.lastTouchTime = performance.now(); // console.log("Got touches", event.targetTouches.length, "vs", expectedRemainingTouches);
if (event.targetTouches.length !== expectedRemainingTouches) {
// console.log("Got touches", event.targetTouches.length, "vs", expectedRemainingTouches); return false;
if (event.targetTouches.length !== expectedRemainingTouches) { }
return false; }
}
} if (event instanceof MouseEvent) {
if (performance.now() - clickDetectorGlobals.lastTouchTime < 1000.0) {
if (event instanceof MouseEvent) { return false;
if (performance.now() - clickDetectorGlobals.lastTouchTime < 1000.0) { }
return false; }
}
} return true;
}
return true;
} /**
* Extracts the mous position from an event
/** * @param {TouchEvent|MouseEvent} event
* Extracts the mous position from an event * @returns {Vector} The client space position
* @param {TouchEvent|MouseEvent} event */
* @returns {Vector} The client space position static extractPointerPosition(event) {
*/ if (window.TouchEvent && event instanceof TouchEvent) {
static extractPointerPosition(event) { if (event.changedTouches.length !== 1) {
if (window.TouchEvent && event instanceof TouchEvent) { logger.warn(
if (event.changedTouches.length !== 1) { "Got unexpected target touches:",
logger.warn( event.targetTouches.length,
"Got unexpected target touches:", "->",
event.targetTouches.length, event.targetTouches
"->", );
event.targetTouches return new Vector(0, 0);
); }
return new Vector(0, 0);
} const touch = event.changedTouches[0];
return new Vector(touch.clientX, touch.clientY);
const touch = event.changedTouches[0]; }
return new Vector(touch.clientX, touch.clientY);
} if (event instanceof MouseEvent) {
return new Vector(event.clientX, event.clientY);
if (event instanceof MouseEvent) { }
return new Vector(event.clientX, event.clientY);
} assertAlways(false, "Got unknown event: " + event);
assertAlways(false, "Got unknown event: " + event); return new Vector(0, 0);
}
return new Vector(0, 0);
} /**
* Cacnels all ongoing events on this detector
/** */
* Cacnels all ongoing events on this detector cancelOngoingEvents() {
*/ if (this.applyCssClass && this.element) {
cancelOngoingEvents() { this.element.classList.remove(this.applyCssClass);
if (this.applyCssClass && this.element) { }
this.element.classList.remove(this.applyCssClass); this.clickDownPosition = null;
} this.clickStartTime = null;
this.clickDownPosition = null; this.cancelled = true;
this.clickStartTime = null; fastArrayDeleteValueIfContained(ongoingClickDetectors, this);
this.cancelled = true; }
fastArrayDeleteValueIfContained(ongoingClickDetectors, this);
} /**
* Internal pointer down handler
/** * @param {TouchEvent|MouseEvent} event
* Internal pointer down handler */
* @param {TouchEvent|MouseEvent} event internalOnPointerDown(event) {
*/ window.focus();
internalOnPointerDown(event) {
window.focus(); if (!this.internalEventPreHandler(event, 1)) {
return false;
if (!this.internalEventPreHandler(event, 1)) { }
return false;
} const position = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event);
const position = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event); if (event instanceof MouseEvent) {
const isRightClick = event.button === 2;
if (event instanceof MouseEvent) { if (isRightClick) {
const isRightClick = event.button === 2; // Ignore right clicks
if (isRightClick) { this.rightClick.dispatch(position, event);
// Ignore right clicks this.cancelled = true;
this.rightClick.dispatch(position, event); this.clickDownPosition = null;
this.cancelled = true; return;
this.clickDownPosition = null; }
return; }
}
} if (this.clickDownPosition) {
logger.warn("Ignoring double click");
if (this.clickDownPosition) { return false;
logger.warn("Ignoring double click"); }
return false;
} this.cancelled = false;
this.touchstart.dispatch(event);
this.cancelled = false;
this.touchstart.dispatch(event); // Store where the touch started
this.clickDownPosition = position;
// Store where the touch started this.clickStartTime = performance.now();
this.clickDownPosition = position; this.touchstartSimple.dispatch(this.clickDownPosition.x, this.clickDownPosition.y);
this.clickStartTime = performance.now();
this.touchstartSimple.dispatch(this.clickDownPosition.x, this.clickDownPosition.y); // If we are not currently within a click, register it
if (ongoingClickDetectors.indexOf(this) < 0) {
// If we are not currently within a click, register it ongoingClickDetectors.push(this);
if (ongoingClickDetectors.indexOf(this) < 0) { } else {
ongoingClickDetectors.push(this); logger.warn("Click detector got pointer down of active pointer twice");
} else { }
logger.warn("Click detector got pointer down of active pointer twice");
} // If we should apply any classes, do this now
if (this.applyCssClass) {
// If we should apply any classes, do this now this.element.classList.add(this.applyCssClass);
if (this.applyCssClass) { }
this.element.classList.add(this.applyCssClass);
} // If we should play any sound, do this
if (this.clickSound) {
// If we should play any sound, do this GLOBAL_APP.sound.playUiSound(this.clickSound);
if (this.clickSound) { }
GLOBAL_APP.sound.playUiSound(this.clickSound);
} return false;
}
return false;
} /**
* Internal pointer move handler
/** * @param {TouchEvent|MouseEvent} event
* Internal pointer move handler */
* @param {TouchEvent|MouseEvent} event internalOnPointerMove(event) {
*/ if (!this.internalEventPreHandler(event, 1)) {
internalOnPointerMove(event) { return false;
if (!this.internalEventPreHandler(event, 1)) { }
return false; this.touchmove.dispatch(event);
} const pos = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event);
this.touchmove.dispatch(event); this.touchmoveSimple.dispatch(pos.x, pos.y);
const pos = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event); return false;
this.touchmoveSimple.dispatch(pos.x, pos.y); }
return false;
} /**
* Internal pointer end handler
/** * @param {TouchEvent|MouseEvent} event
* Internal pointer end handler */
* @param {TouchEvent|MouseEvent} event internalOnPointerEnd(event) {
*/ window.focus();
internalOnPointerEnd(event) {
window.focus(); if (!this.internalEventPreHandler(event, 0)) {
return false;
if (!this.internalEventPreHandler(event, 0)) { }
return false;
} if (this.cancelled) {
// warn(this, "Not dispatching touchend on cancelled listener");
if (this.cancelled) { return false;
// warn(this, "Not dispatching touchend on cancelled listener"); }
return false;
} if (event instanceof MouseEvent) {
const isRightClick = event.button === 2;
if (event instanceof MouseEvent) { if (isRightClick) {
const isRightClick = event.button === 2; return;
if (isRightClick) { }
return; }
}
} const index = ongoingClickDetectors.indexOf(this);
if (index < 0) {
const index = ongoingClickDetectors.indexOf(this); logger.warn("Got pointer end but click detector is not in pressed state");
if (index < 0) { } else {
logger.warn("Got pointer end but click detector is not in pressed state"); fastArrayDelete(ongoingClickDetectors, index);
} else { }
fastArrayDelete(ongoingClickDetectors, index);
} let dispatchClick = false;
let dispatchClickPos = null;
let dispatchClick = false;
let dispatchClickPos = null; // Check for correct down position, otherwise must have pinched or so
if (this.clickDownPosition) {
// Check for correct down position, otherwise must have pinched or so const pos = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event);
if (this.clickDownPosition) { const distance = pos.distance(this.clickDownPosition);
const pos = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event); if (!IS_MOBILE || distance <= this.maxDistance) {
const distance = pos.distance(this.clickDownPosition); dispatchClick = true;
if (!IS_MOBILE || distance <= this.maxDistance) { dispatchClickPos = pos;
dispatchClick = true; } else {
dispatchClickPos = pos; console.warn("[ClickDetector] Touch does not count as click:", "(was", distance, ")");
} else { }
console.warn("[ClickDetector] Touch does not count as click:", "(was", distance, ")"); }
}
} this.clickDownPosition = null;
this.clickStartTime = null;
this.clickDownPosition = null;
this.clickStartTime = null; if (this.applyCssClass) {
this.element.classList.remove(this.applyCssClass);
if (this.applyCssClass) { }
this.element.classList.remove(this.applyCssClass);
} // Dispatch in the end to avoid the element getting invalidated
// Also make sure that the element is still in the dom
// Dispatch in the end to avoid the element getting invalidated if (this.internalIsDomElementAttached()) {
// Also make sure that the element is still in the dom this.touchend.dispatch(event);
if (this.internalIsDomElementAttached()) { this.touchendSimple.dispatch();
this.touchend.dispatch(event);
this.touchendSimple.dispatch(); if (dispatchClick) {
const detectors = ongoingClickDetectors.slice();
if (dispatchClick) { for (let i = 0; i < detectors.length; ++i) {
const detectors = ongoingClickDetectors.slice(); detectors[i].cancelOngoingEvents();
for (let i = 0; i < detectors.length; ++i) { }
detectors[i].cancelOngoingEvents(); this.click.dispatch(dispatchClickPos, event);
} }
this.click.dispatch(dispatchClickPos, event); }
} return false;
} }
return false;
} /**
* Internal touch cancel handler
/** * @param {TouchEvent|MouseEvent} event
* Internal touch cancel handler */
* @param {TouchEvent|MouseEvent} event internalOnTouchCancel(event) {
*/ if (!this.internalEventPreHandler(event, 0)) {
internalOnTouchCancel(event) { return false;
if (!this.internalEventPreHandler(event, 0)) { }
return false;
} if (this.cancelled) {
// warn(this, "Not dispatching touchcancel on cancelled listener");
if (this.cancelled) { return false;
// warn(this, "Not dispatching touchcancel on cancelled listener"); }
return false;
} this.cancelOngoingEvents();
this.touchcancel.dispatch(event);
this.cancelOngoingEvents(); this.touchendSimple.dispatch(event);
this.touchcancel.dispatch(event); return false;
this.touchendSimple.dispatch(event); }
return false; }
}
}

View File

@ -1,26 +1,25 @@
import { globalConfig } from "./config"; import { globalConfig } from "./config";
/** /**
* @typedef {import("../game/root").GameRoot} GameRoot * @typedef {import("../game/root").GameRoot} GameRoot
* @typedef {import("./rectangle").Rectangle} Rectangle * @typedef {import("./rectangle").Rectangle} Rectangle
*/ */
export class DrawParameters { export class DrawParameters {
constructor({ context, visibleRect, desiredAtlasScale, zoomLevel, root }) { constructor({ context, visibleRect, desiredAtlasScale, zoomLevel, root }) {
/** @type {CanvasRenderingContext2D} */ /** @type {CanvasRenderingContext2D} */
this.context = context; this.context = context;
/** @type {Rectangle} */ /** @type {Rectangle} */
this.visibleRect = visibleRect; this.visibleRect = visibleRect;
/** @type {string} */ /** @type {string} */
this.desiredAtlasScale = desiredAtlasScale; this.desiredAtlasScale = desiredAtlasScale;
/** @type {number} */ /** @type {number} */
this.zoomLevel = zoomLevel; this.zoomLevel = zoomLevel;
// FIXME: Not really nice /** @type {GameRoot} */
/** @type {GameRoot} */ this.root = root;
this.root = root; }
} }
}

View File

@ -44,7 +44,6 @@ export class RestrictionManager extends ReadWriteProxy {
* @param {any} data * @param {any} data
*/ */
migrate(data) { migrate(data) {
// Todo
return ExplainedResult.good(); return ExplainedResult.good();
} }

View File

@ -41,7 +41,7 @@ const variantsCache = new Map();
export function registerBuildingVariant( export function registerBuildingVariant(
code, code,
meta, meta,
variant = "default" /* FIXME: Circular dependency, actually its defaultBuildingVariant */, variant = "default" /* @TODO: Circular dependency, actually its defaultBuildingVariant */,
rotationVariant = 0 rotationVariant = 0
) { ) {
assert(!gBuildingVariants[code], "Duplicate id: " + code); assert(!gBuildingVariants[code], "Duplicate id: " + code);

View File

@ -191,7 +191,6 @@ export class MetaUndergroundBeltBuilding extends MetaBuilding {
) { ) {
tile = tile.addScalars(searchVector.x, searchVector.y); tile = tile.addScalars(searchVector.x, searchVector.y);
/* WIRES: FIXME */
const contents = root.map.getTileContent(tile, "regular"); const contents = root.map.getTileContent(tile, "regular");
if (contents) { if (contents) {
const undergroundComp = contents.components.UndergroundBelt; const undergroundComp = contents.components.UndergroundBelt;

View File

@ -182,23 +182,6 @@ export class EntityManager extends BasicSerializableObject {
return this.componentToEntity[componentHandle.getId()] || []; return this.componentToEntity[componentHandle.getId()] || [];
} }
/**
* Return all of a given class. This is SLOW!
* @param {object} entityClass
* @returns {Array<Entity>} entities
*/
getAllOfClass(entityClass) {
// FIXME: Slow
const result = [];
for (let i = 0; i < this.entities.length; ++i) {
const entity = this.entities[i];
if (entity instanceof entityClass) {
result.push(entity);
}
}
return result;
}
/** /**
* Unregisters all components of an entity from the component to entity mapping * Unregisters all components of an entity from the component to entity mapping
* @param {Entity} entity * @param {Entity} entity

View File

@ -11,6 +11,7 @@ import { ShapeItem } from "../../items/shape_item";
import { WireComponent } from "../../components/wire"; import { WireComponent } from "../../components/wire";
import { LeverComponent } from "../../components/lever"; import { LeverComponent } from "../../components/lever";
// @todo: Make dictionary
const tutorialsByLevel = [ const tutorialsByLevel = [
// Level 1 // Level 1
[ [

View File

@ -225,8 +225,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
*/ */
tryPassOverItem(item, receiver, slotIndex) { tryPassOverItem(item, receiver, slotIndex) {
// Try figuring out how what to do with the item // Try figuring out how what to do with the item
// TODO: Kinda hacky. How to solve this properly? Don't want to go through inheritance hell. // @TODO: Kinda hacky. How to solve this properly? Don't want to go through inheritance hell.
// Also its just a few cases (hope it stays like this .. :x).
const beltComp = receiver.components.Belt; const beltComp = receiver.components.Belt;
if (beltComp) { if (beltComp) {

View File

@ -55,7 +55,7 @@ export const enumHubGoalRewardsToContentUnlocked = {
]), ]),
[enumHubGoalRewards.reward_logic_gates]: typed([[MetaLogicGateBuilding, defaultBuildingVariant]]), [enumHubGoalRewards.reward_logic_gates]: typed([[MetaLogicGateBuilding, defaultBuildingVariant]]),
[enumHubGoalRewards.reward_filter]: typed([[MetaFilterBuilding, defaultBuildingVariant]]), [enumHubGoalRewards.reward_filter]: typed([[MetaFilterBuilding, defaultBuildingVariant]]),
[enumHubGoalRewards.reward_virtual_processing]: null, // @TODO! [enumHubGoalRewards.reward_virtual_processing]: null,
[enumHubGoalRewards.reward_wires_painter_and_levers]: typed([ [enumHubGoalRewards.reward_wires_painter_and_levers]: typed([
[MetaPainterBuilding, enumPainterVariants.quad], [MetaPainterBuilding, enumPainterVariants.quad],

View File

@ -41,7 +41,7 @@ export class SavegameManager extends ReadWriteProxy {
} }
verify(data) { verify(data) {
// TODO / FIXME!!!! // @TODO
return ExplainedResult.good(); return ExplainedResult.good();
} }

View File

@ -21,10 +21,6 @@ export class PreloadState extends GameState {
<div class="loadingImage"></div> <div class="loadingImage"></div>
<div class="loadingStatus"> <div class="loadingStatus">
<span class="desc">Booting</span> <span class="desc">Booting</span>
<span class="bar">
<span class="inner" style="width: 0%"></span>
<span class="status">0%</span>
</span>
</div> </div>
</div> </div>
<span class="prefab_GameHint"></span> <span class="prefab_GameHint"></span>
@ -56,10 +52,6 @@ export class PreloadState extends GameState {
/** @type {HTMLElement} */ /** @type {HTMLElement} */
this.statusText = this.htmlElement.querySelector(".loadingStatus > .desc"); this.statusText = this.htmlElement.querySelector(".loadingStatus > .desc");
/** @type {HTMLElement} */
this.statusBar = this.htmlElement.querySelector(".loadingStatus > .bar > .inner");
/** @type {HTMLElement} */
this.statusBarText = this.htmlElement.querySelector(".loadingStatus > .bar > .status");
/** @type {HTMLElement} */ /** @type {HTMLElement} */
this.hintsText = this.htmlElement.querySelector(".prefab_GameHint"); this.hintsText = this.htmlElement.querySelector(".prefab_GameHint");
@ -67,7 +59,6 @@ export class PreloadState extends GameState {
this.nextHintDuration = 0; this.nextHintDuration = 0;
this.currentStatus = "booting"; this.currentStatus = "booting";
this.currentIndex = 0;
this.startLoading(); this.startLoading();
} }
@ -259,16 +250,8 @@ export class PreloadState extends GameState {
*/ */
setStatus(text) { setStatus(text) {
logger.log("✅ " + text); logger.log("✅ " + text);
this.currentIndex += 1;
this.currentStatus = text; this.currentStatus = text;
this.statusText.innerText = text; this.statusText.innerText = text;
const numSteps = 10; // FIXME
const percentage = (this.currentIndex / numSteps) * 100.0;
this.statusBar.style.width = percentage + "%";
this.statusBarText.innerText = findNiceValue(percentage) + "%";
return Promise.resolve(); return Promise.resolve();
} }

View File

@ -36,7 +36,7 @@ function match(originalObj, translatedObj, path = "/") {
if (typeof valueOriginal === "object") { if (typeof valueOriginal === "object") {
match(valueOriginal, valueMatching, path + key + "/"); match(valueOriginal, valueMatching, path + key + "/");
} else if (typeof valueOriginal === "string") { } else if (typeof valueOriginal === "string") {
// todo // @todo
const originalPlaceholders = matchAll(valueOriginal, placeholderRegexp).toArray(); const originalPlaceholders = matchAll(valueOriginal, placeholderRegexp).toArray();
const translatedPlaceholders = matchAll(valueMatching, placeholderRegexp).toArray(); const translatedPlaceholders = matchAll(valueMatching, placeholderRegexp).toArray();