The dialog element represents a conversation, meeting minutes, a chat transcript, a dialog in a screenplay, an instant message log, or some other construct in which different players take turns in discourse.
Thursday, May 12, 2011
HTML5 Dialog Element Styling For Pleasure and Profit
Sunday, February 20, 2011
Our Goal
Knockout is a great combination of jQuery templates and data binding that allows for one-way and two-way binding back to a Javascript object. I've put together an example project with an ugly looking stopwatch, and we'll go through some parts of it in this blog post (just want the code, bro? get it here)
The timer() class with Knockout Observables
/// The timer class.
var timer = function () {
this.started = new ko.observable(false);
this.totalSeconds = new ko.observable(0);
this.seconds = new ko.dependentObservable(function () {
return (this.totalSeconds() % 60).toFixed(0);
}, this);
this.secondsDisplay = new ko.dependentObservable(function () {
var secs = this.seconds();
var display = '' + secs;
if (secs < 10) { display = '0' + secs; }
// Hack for weird edge case because of setInterval.
if (display == '010') { display = '10'; }
return display;
}, this);
this.minutes = new ko.dependentObservable(function () {
return ((this.totalSeconds() / 60) % 60).toFixed(0);
}, this);
this.hours = new ko.dependentObservable(function () {
return (((this.totalSeconds() / 60) / 60) % 60).toFixed(0);
}, this);
this.secondHandAngle = new ko.dependentObservable(function () {
return this.seconds() * 6;
}, this);
this.minuteHandAngle = new ko.dependentObservable(function () {
return this.minutes() * 6;
}, this);
this.hourHandAngle = new ko.dependentObservable(function () {
return this.hours() * 6;
}, this);
this.alarm = function () {
log('alarm fired');
};
};
// timer.start
timer.prototype.start = function () {
this.started(true);
this.startTime = new Date();
var self = this;
this.intervalId = setInterval(function () {
var oldTime = self.startTime;
self.startTime = new Date();
var diff = secondsBetween(self.startTime, oldTime);
var currSeconds = self.totalSeconds();
self.totalSeconds(currSeconds + diff);
}, 100);
};
// timer.stop
timer.prototype.stop = function () {
this.started(false);
if (this.intervalId) {
clearInterval(this.intervalId);
}
};
// helper...
function secondsBetween(date1, date2) {
return (date1.getTime() - date2.getTime()) / 1000;
};
From the timer class code you can see that we declare our fields as ko.observable()'s. These are wrappers around our values that help with notifying our bound elements when the values change. The function() syntax for accessing the fields does take a little getting used to; evidently it's necessary since IE doesn't implement property setters and getters. Other than the new syntax, our class is pretty basic. We have a started field and a totalSeconds field that drive the rest of our fields by way of the dependentObservable() functionality. The dependentObservable() is a nifty way of declaring fields that are computed based on other observable() fields. For us, we do some quick math to determine our seconds, minutes and hours based on the totalSeconds that have passed while running the timer. We also create some fields for the angle of our timer hands based on the computed underlying second/minute/hour values.
The ViewModel and View DataBinding
@{
Page.Title = "Home Page";
}
@section ScriptSection {
<script id="faceTemplate" type="text/x-jquery-tmpl">
@* Our SVG Code in a partial view *@
@Html.Partial("_WatchFace")
<div id="timerInfo" style="font-weight: bold; font-size: 24px; float: left;">
<span class="minutes" data-bind="text: minutes()"></span>
<span>:</span>
<span class="seconds" data-bind="text: secondsDisplay()"></span>
</div>
</script>
<script type="text/javascript">
// Our custom svg Rotate transform binding...
ko.bindingHandlers.svgRotate = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
// This will be called when the binding is first applied to an element
// Set up any initial state, event handlers, etc. here
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
// This will be called once when the binding is first applied to an element,
// and again whenever the associated observable changes value.
// Update the DOM element based on the supplied values here.
var value = valueAccessor(), allBindings = allBindingsAccessor();
var rotation = ko.utils.unwrapObservable(value);
var originX = allBindings.originX || 0;
var originY = allBindings.originY || 0;
var rotateText = 'rotate(' + rotation + ', ' + originX + ', ' + originY + ')';
var id = $(element).attr('id');
// Using the old school doc getElement because jquery's attr() is not setting the value correctly
var elem = document.getElementById(id);
if (!elem) { log('rotate binding element not found'); return; }
elem.setAttribute('transform', rotateText);
}
};
// Our page ViewModel
var viewModel = {
watch: new ko.observable(new timer()),
start: function () {
this.watch().start();
},
stop: function () {
this.watch().stop();
},
toggleTimer: function () {
this.watch().started() ? this.stop() : this.start();
}
};
ko.applyBindings(viewModel);
</script>
}
<p>
This is an example project using <a href="http://html5boilerplate.com">HTML5 Boilerplate</a> patterns, <a href="http://knockoutjs.com">Knockout.js</a> MVVM Binding and Templating, <a href="http://docs.jquery.com/Qunit">QUnit</a> unit tests and SVG Graphics.
</p><br />
<div id="watchContainer" style="cursor: pointer;" data-bind='template: { name: "faceTemplate", data: watch()}, click: toggleTimer'>
</div>
The main parts of this code are the ViewModel which we bind our HTML Elements to, and the jQuery templates that define our stopwatch and second/minute hands. At the top, I declare my SVG Stopwatch with a custom knockout binding (you can see the code for the special binding at lines 10-20) I created to update the transform of the path based on the angle in the timer.
Next, the script section for our page creates a special binding that updates the transform attribute of the Path SVG Element to rotate the hands of the clock. Also in the script section, we declare our ViewModel for the page. The ViewModel creates a timer and some utility functions for toggling the timer between start and stop. After declaring our ViewModel, we use Knockout's ko.applyBindings() function to setup the page's templates and apply our data bindings.
The MotherEffin Clock Demo Project
I've put together a Demo Project for download using my MotherEffin HTML5 Boilerplate project template for MVC3. I highly recommend visiting the KnockoutJS documentation for more information about templates, custom bindings and observables.
Next time, we'll go through Unit Testing and Object Oriented Javascript with QUnit.
Now Playing - LL Cool J - Momma Said Knock You Out
Thursday, October 30, 2008
JTemplates template file cached workaround
I've been using a lot of JQuery and JTemplates after reading a couple really helpful JQuery and MVC posts at Encosia.com. One problem I ran into while doing some development on a new .Net MVC Project that was using JQuery extensively was that my template files were being cached by my browser. I tried clearing the cache but that wasn't helping, so here's a workaround I came up with.
If you take a look at how JQuery's $.ajax(...) function handles the caching problem you can see that they append a random query string parameter to each request.

So that is what I basically did to workaround the caching problem with the template files. I created a function called cacheBust() that just returned the current times milliseconds value and used that to generate my random query string. Here's some sample code:
function cacheBust() {return new Date().getMilliseconds().toString();}
function GetTimeEntries(day) {
// Show the loady
showLoady();
$.ajax({
type: "GET",
cache: false,
url: "/TimeEntry/" + day.replace(/\//g, "-"),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
// This method loads the HTML template and
// prepares the container div to accept data.
$('#TimeWrapper').setTemplateURL('/scripts/timeentry.vw?_=' + cacheBust());
// This method applies the JSON array to the
// container's template and renders it.
$('#TimeWrapper').processTemplate(msg);
// Hide the loady.
hideLoady();
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
// typically only one of textStatus or errorThrown
// will have info, I'm not using either.
hideLoady();
$('#TimeWrapper').empty();
$('#TimeWrapper').append("<p class='errord'>There was a problem loading the data from the server. Sorry I got nothing else.</p>");
}
});
}

And now we get the most up to the second versions of our templates. Once I'm done with development it will be beneficial to have the templates be cached. I figure once that happens I'll change my cacheBust() function to return a constant (something like, "ItCompilesSoShipIt").
Now Playing: Snow Patrol - Open Your Eyes
