[Coding] JavaScript Lessons (1)

Posted by Khatharsis on July 17, 2013

I’ve been working on a new project. (Famous last words?) The past two days, I’ve been diving back into JavaScript after my foray into C#. I have a definite outcome in mind for this project (a text-based game similar to A Dark Room), but story-wise and gameplay-wise, I’m at a loss. So, I’ve been keeping busy implementing utility functions that will add some “sparkle” to this project and I’ve learned a couple of lessons so far.

1. Dynamic namespacing and using “that”
I was wavering between which JavaScript pattern to use, global namespace or sandbox. I was moving towards the sandbox pattern just because I haven’t used it before and I had a notion of using modules, but I went back to Crawford’s text (JavaScript: The Good Parts) and he said to avoid using the keyword new. So, I threw out the sandbox pattern and fell back to the pattern I use in Thai Sorting, which is dynamic namespacing using this as a proxy (see #5). I won’t go into the details and you can read for yourself how it is implemented.

Actually, I realized I wasn’t implementing the pattern correctly and had to go through and change all of the instances of APP to this. Of course, this realization was after releasing the project to the world, so I felt a little embarrassed at the large mistake, but it is now corrected. One of the problems I ran into was retaining the value of this, referring to APP, particularly when handling the drag-and-drop interaction. The value of this got lost in the callback event and for the first time, I understood what Crawford meant by the use of that.

I didn’t do a lot of research on the best practice of using that, so I tried to keep my usage consistent. I use this for function definitions that will be applied to the namespace (APP) and that for function calls within those function definitions.

Interlude
So, up to this point, the resulting code I have is separated into three files: game.preload.js, game.utilities.js, and game.js.
-game.preload.js: simply declares the global namespace variable
-game.utilities.js: implements a text animation for dialog, similar to the old RPGs on the Gameboy; uses dynamic namespacing
-game.js: connects together contents on the HTML page to the JavaScript; also uses dynamic namespacing

A brief peek into the last two files:

(function() {
	this.utilities = (function() {
		var textObj = $({count:0}),
			textCache = "";
		
		// http://stackoverflow.com/questions/6703255/adding-text-character-by-character-using-animate-jquery
		function animateText (domObj, text) {
			$(domObj).text(text);
			textCache = text;
			textObj.animate(
				{ count: text.length },
				{
					duration: 1500,
					step: function() {
						$(domObj).text(text.substring(0, Math.round(this.count)));
					}
				}
			);
		}

function stopAnimateText (domObj) {
	textObj.stop(true, true);
	$(domObj).text(textCache);
		}

		return {
			startDialog: animateText,
			stopDialog: stopAnimateText
		}
	})();
}).apply(GAME);


(game.utilities.js): I can’t take credit for the actual animation text, but I did spend some time figuring out how to properly stop the animation. In old RPGs, tapping A (or another button) during a slowly-revealing dialogue would quickly reveal the rest or speed up the animation itself. I opted to just finish off the dialog. But, you can see here the self-invoking function being applied to the GAME context. In addition, I’m adding the utilities “namespace” to the GAME object, sort of like a module.

The next file:

(function() {
	var that = this;
	var util = that.utilities;
	
	this.init = function() {
		$('#clickme').click(function() {
			util.startDialog('#mydiv', 'Lorem ipsum dolor sit amet');
		});

		$('#stopme').click(function() {
			util.stopDialog('#mydiv');
		});
	};
}).apply(GAME);


(game.js): This is what I mean by connecting together the HTML with the JavaScript – items “clickme” and “stopme” are buttons on the HTML page. I assign the utilities “module” to a local variable and use that to call the utilities functions. Again, you can see the dynamic namespacing pattern in this file.

Ideally, I will combine all of the files for this project into one and minify it, but I imagine all of my files will be using this pattern. In a broader sense, it is easy to copy and paste the innards for whatever other use there might be for the modules, but a better use would be to replace the namespace GAME with something else. I actually think if there was a way to not use the immediate function invocation, it would feel a little less sloppy to me, but short of using a different pattern, I think I’m stuck with this for now.

2. Animating a cooldown bar within a button
The next utility function I wrote is deceptively simple – a cooldown bar within a button, similar to what you’d see in A Dark Room (ADR). I didn’t copy the code entirely, but after fiddling around with the CSS (I’m not an avid fan of design so this took me longer than I wanted) and looking up other solutions, I eventually found a way to simulate a similar effect to ADR. While ADR uses divs, I use an actual button element with two divs encased inside, one containing the text and the other containing an empty div but styled for cooldown:

<style>
	/* http://stackoverflow.com/questions/3213664/why-does-absolute-positionining-within-button-works-differently-from-div */
	button {
		/*background:none repeat scroll 0 0 transparent;*/
		border: 1px solid;
		font-family:inherit;
		font-size:inherit;
		font-weight:inherit;
		margin:0;
		overflow:visible;
		padding:0;
		position:relative;
	}

	button.cooldown {
		color: #000000;
		font: 1.5em Courier, serif;
		background-color: #efefef;
	}
	
	button.cooldown div.active {
		color: #000000;
	}
	
	button.cooldown div.disabled {
		color: #888888;
	}

	button.cooldown div.cooldown {
		position: absolute;
		top: 0px;
		left: 0px;
		z-index: 2;
		height: 100%;
		background-color: rgba(96, 96, 96, .25);
	}	
</style>



<button type="button" class='cooldown' id='cooldownButton'>
	<div id='cooldown' class='active'>
		Cooldown
	</div>
	<div class='cooldown'></div>
</button>


The styling for the button turns out to work in the versions of FF, IE, and Chrome that I have on my computer (the latest). Without the stylization on the button element, the inner div would not take up the entire button element but have some padding on the side. The only thing I’m afraid of is when I put the button (and its nested elements) into another div, whether it will still play nice or not. Currently I’m just doing proof-of-concepts and I have had several experiences where the proof-of-concepts work nice in the root of the body tag, but act strangely if inside another element.

The JavaScript side of the animation I borrowed from ADR with some modifications to account for my implementation of the button itself:

function animateCooldownButton (domObj, cooldownTime) {
	var parent = $(domObj).parent();
	parent.attr('disabled', 'disabled');
	$(domObj).removeClass('active').addClass('disabled');
	$('div.cooldown', parent).stop(true, true).width('100%').animate(
		{ width: 0 }, 
		{ 
			duration: cooldownTime * 1000, 
			complete: function() {
				$(domObj).removeClass('disabled').addClass('active');
				$(parent).removeAttr('disabled');
			}
		}
	);
}


Since I nested the divs inside of a button, I need access to the button to disable and enable it. One of the first things I do is make a local variable containing the button element. Then, I make sure to disable the button and set the div containing the text to the disabled color scheme. The jQuery animation is set on the cooldown div, which in the HTML code is simply an empty div. The second parameter, parent, tells jQuery exactly where to look for this div. jQuery then sets the width of the div to 100% of the button and animates it down to nothing within the time passed to the function in seconds. On completion, the text div is set to the enabled color scheme and the button itself is re-enabled, allowing subsequent clicks to run through the animation again.

It’s simple things like these that get me fired up when they finally work. I did hit a point where I was getting frustrated with the CSS, and I’m sure there’s probably a more elegant way of implementing it rather than the hacked together solution I have, but it all came together. I still don’t have anything very interesting to show off as a proof-of-concept pre-alpha demo, but I hope to have something substantial soon.