diff --git a/web/game.html b/web/game.html
index a87994a3..c2e81398 100644
--- a/web/game.html
+++ b/web/game.html
@@ -115,6 +115,7 @@
+
@@ -124,13 +125,13 @@
+
+
+
-
-
-
diff --git a/web/js/controller.js b/web/js/controller.js
index a61ba3b5..9026992a 100644
--- a/web/js/controller.js
+++ b/web/js/controller.js
@@ -175,11 +175,11 @@
input.poll().enable();
};
- // !to add debounce
- const popup = (msg) => {
- popupBox.html(msg);
- popupBox.fadeIn().delay(0).fadeOut();
- };
+ const saveGame = utils.debounce(socket.saveGame, 1000);
+ const loadGame = utils.debounce(socket.loadGame, 1000);
+
+ const _popup = (message) => popupBox.html(message).fadeIn().fadeOut();
+ const popup = utils.throttle(_popup, 1000);
const _dpadArrowKeys = [KEY.UP, KEY.DOWN, KEY.LEFT, KEY.RIGHT];
@@ -329,10 +329,10 @@
popup('You are already in menu screen!');
break;
case KEY.LOAD:
- popup('Lets play to load game!');
+ popup('Loading the game.');
break;
case KEY.SAVE:
- popup('Lets play to save game!');
+ popup('Saving the game.');
break;
case KEY.STATS:
event.pub(STATS_TOGGLE);
@@ -366,10 +366,10 @@
popup('Copy link to clipboard!');
break;
case KEY.SAVE:
- socket.saveGame();
+ saveGame();
break;
case KEY.LOAD:
- socket.loadGame();
+ loadGame();
break;
case KEY.FULL:
env.display().toggleFullscreen(gameScreen.height() !== window.innerHeight, gameScreen[0]);
@@ -464,4 +464,4 @@
// initial app state
setState(app.state.eden);
-})($, document, event, env, gameList, input, KEY, log, room, settings, stats);
+})($, document, event, env, gameList, input, KEY, log, room, settings, socket, stats, utils);
diff --git a/web/js/utils.js b/web/js/utils.js
new file mode 100644
index 00000000..28f557ab
--- /dev/null
+++ b/web/js/utils.js
@@ -0,0 +1,58 @@
+/**
+ * Utility module.
+ * @version 1
+ */
+const utils = (() => {
+ return {
+ /**
+ * A decorator that passes the call to function at maximum once per specified milliseconds.
+ * @param f The function to call.
+ * @param ms The amount of time in milliseconds to ignore the function calls.
+ * @returns {Function}
+ * @example
+ * const showMessage = () => { alert('00001'); }
+ * const showOnlyOnceASecond = debounce(showMessage, 1000);
+ */
+ debounce: (f, ms) => {
+ let wait = false;
+
+ return function () {
+ if (wait) return;
+
+ f.apply(this, arguments);
+ wait = true;
+ setTimeout(() => wait = false, ms);
+ };
+ },
+
+ /**
+ * A decorator that blocks and calls the last function until the specified amount of milliseconds.
+ * @param f The function to call.
+ * @param ms The amount of time in milliseconds to ignore the function calls.
+ * @returns {Function}
+ */
+ throttle: (f, ms) => {
+ let lastCall;
+ let lastTime;
+
+ return function () {
+ // could be a stack
+ const lastContext = this;
+ const lastArguments = arguments;
+
+ if (!lastTime) {
+ f.apply(lastContext, lastArguments);
+ lastTime = Date.now()
+ } else {
+ clearTimeout(lastCall);
+ lastCall = setTimeout(() => {
+ if (Date.now() - lastTime >= ms) {
+ f.apply(lastContext, lastArguments);
+ lastTime = Date.now()
+ }
+ }, ms - (Date.now() - lastTime))
+ }
+ }
+ }
+ }
+})();