Pseudo language generator

The usual method of placing filler text on page or on a web design was to copy the Lorem Ipsum text found all over the place. The one down side to this was making sure the text wasn’t too recognizable, considering everyone uses it, and making sure you have enough of it for a particularly big layout or dummy text range.

For some reason this didn’t seem particularly elegant, especially since the afore mentinoed commonality and the only other alternative was to create actual posts with, you know, a post. Well that didn’t seem elegant either since those posts tend to look contrived and stupid… a lot like a most of the “real” posts on the internet, sadly.

So I set about creating my own pseudo language generator in JavaScript that I can plug anywhere and generate as many as needed and not worry about repeating myself. I’m home today thanks to doctor’s orders and bored to death of walking up and down the apartment so might as well do it now…

First step : Wikipedia

Apparently,  in English, ETAON RISHD LFCMU GYPWB VKXJQ Z is the alphabet arranged from the most frequently used letter to the least. While this seems logical to me, it didn’t make sense to mix the vowels in with the consonants since I needed to match a consonant with at least one vowel and in my own cursory observation of Lorem Ipsum, the vowels tended to have even distribution, but since I’m trying to match English as much as possible, I sorted the vowels by decreasing frequency: eaoiu and the consonants as well : tnrshdlfcmgypwbvkxjqz.

To make it easier to pair them with a consonant, I figured I’d put all the vowels together and randomly pick one from the pool, but that leaves their frequency.

The easiest way to make sure the most frequent letters are picked more than the least frequent was to multiply the occurence of the most frequent letters in the pool. I could have repeated the letter a number of times in the pool, but that felt hackish, so for this I wrote a simple multiply function.

function multFrequency(chars) {
	var cn = '';
	for(var i = chars.length; i > 0; i--) {
		var ch = chars.charAt(chars.length - i);
		for(var j = i; j >= 0; j--) {
			cn += ch;
		}
	}
	return cn;
}

What’s going on here? Well, we first we iterate through the pool starting with the character length and decrement by one. Each letter is selected using charAt using i. At each letter, we repeatedly add it to the new pool, “cn”, i number of times. Since i decreases as the loop continues, characters further down the pool get added fewer number of times. We want to add up to and including the last letter, which is why the inner loop is set to j >= 0. (Remember, the index is 1 less than the length.)

Pairing ending letters

According to the Wikipedia article, English also has common pairings. TH HE AN RE ER IN ON AT ND ST ES EN OF TE ED OR TI HI AS TO.

I figured it will be easier to again split these up by pairings that start with vowels and those that start with consonants. So that leaves :

Consonant pairs : “th”, “he”, “nd”, “st”, “te”, “ti”, “hi”, “to”.
Vowel pairs : “an”, “er”, “in”, “on”, “at”, “es”, “en”, “of”, “ed”, “or”, “as”

So we need another function that will take the first letter of each pool and randomly select a pairing ending letter. This is actually a lot easier than it sounds. First part of this problem is making a little helper function that will randomly give a number between a minimum and maximum.

// Random number helper
function rnd(min, max) {
	return Math.floor(Math.random() * (max - min)) + min
}

Now we’re going to create the pair matching helper.

function fromPair(pairs, p) {
	var nc = '';
	for(var i = 0; i < pairs.length - 1; i++) {
		if (pairs[i].charAt(0) == p)
			nc += pairs[i].charAt(1);
	}
	if (nc == '')
		return nc;
	
	// Or else...
	return fromRange(nc);
}

What this does is iterate through each pair in the pool and take the second letter of each pair matching the first letter and create a new pool, “nc”. If “nc” is empty, then it didn’t find a matching pair and returns an empty string, but if at least one pair was found, it will randomly select from this pool… using the function below.

We need a function that will avoid letter duplications. I could be wrong, but in the original Lorem Ipsum, I don’t recall seeing double vowels. I think this makes sense in our new pseudo language.

function fromRange(chars, p) {
	var c;
	if (arguments.length > 1) {
		do {
			c = chars.charAt(rnd(0, chars.length -1));
		} while(c == p);
	} else {
		c = chars.charAt(rnd(0, chars.length -1));
	}
	
	return c;
}

This function is what we’ll use to randomly select characters from any pool. It also doubles as a duplicate remover if the second parameter is specified. Basically, it will retry a random pick from the pool until it skips the given parameter.

Building the language

To give this the look and feel of true randomness, I put all the above constants (vowels, consonants, pairings) into variables. I also created a minimum and maximum value set for word length, sentence sizes and paragraph sizes to give the impression of random entries.

var vowels = "eaoiu";

// The consonants are placed in the order of their appearence
var consonants = "tnrshdlfcmgypwbvkxjqz";

// Letters commonly paired (with consonants first and vowels next)
var consonantPairs = ["th", "he", "nd", "st", "te", "ti", "hi", "to"];
var vowelPairs = ["an", "er", "in", "on", "at", "es", "en", "of", "ed", "or", "as"];

var wMin = 2;		// Minimum word length
var wMax = 10;		// Maximum word length
var sMin = 4;		// Minimum sentence size
var sMax = 20;		// Maximum sentence size
var pMin = 1;		// Minimum sentences per paragraph
var pMax = 3;		// Maximum sentences per paragraph
var vFreq = 3;		// Every x characters must be a vowel

That last variable, vFreq, is what I think will really make or break this; I think having every 3rd character a vowel will make this seem realistic.

Now we need a function to generate a realistic sounding word…

function getWord(u) {
	if(arguments.length > 1)
		u = true;
	
	var r = rnd(wMin, wMax);
	
	var w = '';	// Completed word holder
	var c = '';	// Generated letter holder
	
	for(var i = 0; i < r; i++) {
		// Every x characters is a vowel
		if (i % vFreq == 0) {
			c = fromRange(consonants);
		} else {
			c = fromRange(vowels, c);
		}
			
		 // First letter of the word requested in uppercase
		if(u == true && i == 0)
			c = c.toUpperCase();
		w +=  c;
	}
	
	// Commonly paired letters
	if (consonants.indexOf(c) > -1 ) {
		w += fromPair(consonantPairs, c);
	} else {
		w += fromPair(vowelPairs, c);
	}
	
	return w;
}

This function has an argument to make the first letter upper case for use in the beginning of a sentence. Note the wMin and wMax variables we declared earlier between which the word lengths alternate. Also note in the for loop, we’re using that fromRange function with the second parameter (to skip duplicates) specified for vowels. I’m also making use of the fromPair function depending on whether the last character in the word ends in a consonant or vowel.

Now that we have the word generator we need a function that creates a sentence by repeatedly calling the above getWord function. Note the sMin and sMax variables that allow the sentence length to fluctuate.

// Creates a sentence (bunch of words ending in '. ');
function getSentence() {
	var r = rnd(sMin, sMax);
	var s = '';
	for(var i = 0; i < r; i++) {
		if(i == 0) // First letter in first word is uppercase
			s += getWord(true) + ' ';
		else
			s += getWord() + ' ';
	}
	
	return s.substring(0, s.length - 1) + '. ';
}

Finally a very simple paragraph generator that calls getSentence between pMin and pMax.

// Creates a paragraph (bunch of sentences wrapped in <p>)
function getParagraph() {
	var r = rnd(pMin, pMax);
	var p =  '<p>';
	
	for(var i = 0; i < r; i++) {
		p += getSentence();
	}
	
	return p + '</p>';
}

Putting these functions together, I created a paragraph that looks less like faux Latin and more like a Scandanavian language…

Buedaehain ges seist gieneof yauteof moareon noisoin daeceolan peobuohen rieyeiher sieqeawof cuekuaxeof deuliukan roapen teahan noifaogu liacon. Daogeadan rin xaegiehin can qeoviof dairin toefoatean rion teiceivean naijaeton riof rain hiakeof weawean.

But, oh well. For what it is, it does a well enough job, I think. Here’s a running demo of everything together.

For some reason, Modernizr kept throwing an error which means it doesn’t work in Firefox.

Update

Thanks to a very helpful comment by Lin, the code now works on Firefox. Turned out to be an encoding issue (Firefox doesn’t like ANSI and UTF dancing together).

Also a minor imporvement:
I changed the following line in the multFrequency function..

for(var j = i; j >= 0; j--)

Into…

for(var j = (i * i + 1); j >= 0; j--)

This yielded much better distribution of letters for both vowels and consonants.

Advertisements

Basic: The community version

A little while ago, I created a theme called “Basic” for corporate-ish websites and I’ve been getting requests for a community version; basically a version that would accomodate a blog/forum. I decided to reuse 90% – 95% of the original backend JavaScript to the discussion forum mockup (which I’ve renamed “Road”) including a lot of similar functionality. Except this time, I’m going for a more “component” oriented layout that I can easily turn into tabs. I created a simple tab plugin in jQuery to turn page elements into tabs with minimal overhead and I’m reusing a slightly modified version of the code formatting plugin in the topic page example .

Community index

 

Community tag browsing

 

Most of the changes really went to the topic view page. I made some changes to the code format snippet and moved the user info and avatar away to the side for clarity. The darker colors were partly inspired by the Sublime text editor (thanks to Shannon for mentioning it) as I found it easier to read large blocks of code on a darker background although I’m still not doing any syntax highlighting.

Forum topic view

 

Haven’t change much of the backend code of the add topic form, but I have changed the styling and streamlined things a bit.

Reworded instructions

Font reference revamp

A while ago, I created a single small HTML page with a bunch of easy to read fonts for web publishing. This afternoon, I got some free time so I did a rewrite of the whole thing as a web application.

Font reference

The biggest problem with the old version is that every font was displayed all on one page which would have made expanding the list more cumbersome. Also, a lot of people had started to hotlink to the old font images (not just these, but a lot of other images on my server which was starting to affect my bandwith), so I’ve instead added permalinks to each font and the letter index as an alternative.

There’s no server-side scripting and the whole thing is basically JavaScript courtesy of jQuery. You can take a look at the old version at the end of this post.

Sourcecode of “fref.js” (please be advised that I may change the actual running version at any time and this is only current as of this post).

$(function() {
	var pIndex, pFont, fCanvas;
	var ta = [];

	Init();

	function Init() {

		fCanvas = $("#fonts");

		// Titles list
		var t = $('<ul />');

		// Unique index
		for(var i = 0; i < fonts.length; i++) {
			var f = fonts[i];
			var ni = true;

			for(var j = 0; j < ta.length; j++) {
				if(ta[j] == f[0])
					ni = false;
			}

			if(ni)
				ta[ta.length] = f[0];
		}

		for(var i = 0; i < ta.length; i++) {
			t.append('<li><a href="#'+ ta[i] +'">'+ ta[i] +'</a></li>');
			var s = $('<div id="'+ ta[i] +'" />');
			var u = $('<ul />');

			for(var j = 0; j < fonts.length; j++) {
				if(fonts[j][0] == ta[i]) {
					var f = fonts[j];
					u.append(felement(f));
				}
			}

			s.append('<h2>“'+ ta[i] +'” Fonts '+
				'<span><a href="http://eksith.com/experiments/fontreference/?i='+
				ta[i] +'">Permalink</a></span></h2>');
			s.append(u);
			fCanvas.append(s);
		}

		fCanvas.prepend(t);
		fCanvas.tabs({
			create: function(e, ui) {
				searchValidate();
				findFont(pIndex, pFont);
			}
		});
	}

	function searchValidate() {
		if(window.location.search.indexOf("?i=") > -1) {

			var pn = $.trim(window.location.search)
					.replace(/\s/g, "");

			var s = pn.indexOf("?i=") + 3;
			var e = pn.indexOf("&f=");

			if(e > s)
				pIndex = pn.substr(s, e - 3);
			else
				pIndex = pn.substr(s);

			pIndex = (!pIndex)? "0-9" : pIndex;

			if((e > 0) && (e + 3 < pn.length))
				pFont = pn.substr(e + 3, pn.length);
		}

		if(ta.indexOf(pIndex) < 0)
			pIndex = ta[0];
	}

	function findFont(i, f) {
		fCanvas.tabs("option", "selected", ta.indexOf(i));
		var fnt = $('#' + f);

		if(fnt.length > 0) {
			$('html,body').animate({ scrollTop: fnt.offset().top - 10 }, 1000);
			fnt.effect("highlight", {}, 5000);
		}
	}

	function felement(f) {
		var a = f[2].replace(".png", ""); // Image without .png extension becomes font ID
		var st = '<li id="'+ a +'">' +
			'<ul><li>'+ f[1] +'</li>';

		// Additional attributes
		for(var i = 0; i < f[3].length; i++)
			st += '<li>'+ f[3][i] +'</li>';

		// Permalink
		st += '<li><a href="http://eksith.com/experiments/fontreference/?i='+ f[0] +'&f='+ a +'">Permalink</a></li></ul>' +
			'<img src="fonts/'+ f[2] +'" alt="'+ a +'" /><hr /></li>';

		return st;
	}
});

The data is stored in a single “data.js” file as an array. I may change this to JSON in the future.

// Convention : index, title, font image, description array (new item per line)
var fonts = [
	["A", "Am Sans light", "am-sans-light.png", ["20pt", "Sans-serif"]],
	["A", "Andalé Mono", "andale-mono.png", ["20pt", "Monospace", "Sans-serif"]],
	["A", "Arial", "arial.png", ["20pt", "Sans-serif"]],
	["A", "Avenir - Book <strong>Commercial</strong>", "avenir-book.png", ["20pt", "Sans-serif"]],
	["B", "Bitstream Vera Sans (Roman)", "bitstream-vera-sans-roman.png", ["20pt", "Roman", "Sans-serif"]],
	["B", "Bitstream Vera Sans Mono (Roman)", "bitstream-vera-sans-m-roman.png", ["20pt", "Roman", "Monospace", "Sans-serif"]],
	["B", "Book Antiqua", "book-antiqua.png", ["20pt"]],
	["B", "Bank Gothic Lt BT", "bank-gothic-light-bt.png", ["20pt", "Small caps", "Sans-serif"]],
	["C", "Calibri", "calibri.png", ["20pt", "Sans-serif"]],
	["C", "Candara", "candara.png", ["20pt", "Sans-serif"]],
	["C", "Century Gothic", "century-gothic.png", ["20pt", "Modern, Geometric, Bold", "Sans-serif"]],
	["C", "Consolas", "consolas.png", ["20pt", "Sans-serif"]],
	["C", "Courier Std", "courier-std.png", ["20pt", "Monospace"]],
	["D", "Dutch801 Rm BT <strong>Commercial</strong>", "dutch801-rm-bt.png", ["20pt"]],
	["E", "Eurostile", "consolas.png", ["20pt", "Modern", "Sans-serif"]],
	["F", "Florencesans", "florencesans.png", ["20pt", "Sans-serif"]],
	["F", "Franklin Gothic Book", "franklin-gothic-book.png", ["20pt", "Modern, Geometric", "Sans-serif"]],
	["G", "Georgia", "georgia.png", ["20pt"]],
	["G", "Gill Sans MT", "gill-sans-mt.png", ["20pt",  "Sans-serif"]],
	["G", "Gotham Light <strong>Commercial</strong>", "gotham-light.png", ["20pt", "Mdoern, Geometric", "Light", "Sans-serif"]],
	["H", "Humanist521 BT (Roman) <strong>Commercial</strong>", "humanist521-bt-roman.png", ["20pt", "Roman", "Sans-serif"]],
	["L", "Lucida Sans", "lucida-sans.png", ["20pt", "Sans-serif"]],
	["L", "Lucida Unicode", "lucida-unicode.png", ["20pt", "Unicode", "Sans-serif"]],
	["M", "Microsoft Sans Serif <strong>*</strong>", "microsoft-sans-serif.png", ["<strong>* Not the same as MS Sans Serif</strong>", "20pt", "Sans-Serif"]],
	["M", "Monaco", "monaco.png", ["20pt", "Modern, Condensed", "Sans-serif"]],
	["M", "MS Sans Serif <strong>*</strong>", "ms-sans-serif.png", ["<strong>* Not the same as Microsoft Sans Serif</strong>", "20pt", "Sans-serif"]],
	["M", "Myriad", "myriad.png", ["20pt", "Sans-serif"]],
	["T", "Tahoma", "tahoma.png", ["20pt", "Sans-serif"]],
	["T", "Trebuchet MS", "trebuchet-ms.png", ["20pt", "Sans-serif"]],
	["U", "Univers <strong>Commercial</strong>", "univers.png", ["20pt", "Sans-serif"]],
	["V", "Verdana", "verdana.png", ["20pt", "Sans-serif"]]
];

It still leaves a lot of work to be done; most obviously, the reference phrase “The quick brown fox jumps over the dirty dog” is wrong. It should be “The quick brown fox jumps over the lazy dog”. Also the list is pretty small and limited only to a handful of fonts I’ve used. I’m planning to add a full collection of possibly every font I’ve used in the past (even perhaps the stylish and not-so-easy-to-read variety)

Old font reference index

I’m thinking of writing a very basic discussion board in ASP.Net MVC and I may use the new design in that. The CSS is very minimal and most of the extra jQuery UI styles are from the customized Smoothness theme.

Building a jQuery UI Dashboard

Sometimes you have an existing website or template that needs to function as a dashboard. The only solution then is to create drop-in widget functionality without necessarily modifying the HTML. This is a bit of an update to a much older post

The good news is that if the layout is by and large uncluttered and follows a predictable set of elements (key issue), it’s fairly straightforward to give a layout dashboard functionality without actually touching the HTML structure. jQuery and jQuery UI are perfect for this.

The tricky bit is adding any additional elements for control while handling each segment of content as a widget. In this case, every “widget” can be any element that has the CSS class column applied to it which means we can use the existing <h5> title element as the header for it.

Take as an example, my Simply theme which has no “widget-like” functionality whatsoever and the only JavaScript is Modernizr for backwards compatibility since it was recently rewritten in HTML5. But because all the content elements are predictable (there are sections and one level of nested sections that act as columns), it can be turned into a dashboard without touching the rest of the HTML.

You can take a look at a running demo of it and see below for an explanation of what’s going on.

A running demo of "Simply" turned into a dashboard

For this example, I needed the dashboard widgets to be able to be moved around on each row, have the title, content and the article icon changed and of course be able to close them. Naturally, this is only a client-side example. The final version would need to post these changes server-side for saving.

The Procedure

We can first start by adding the jQuery UI theme CSS file right above the original stylesheet. I’m using a customized version of the Smoothness theme. Just a few tweaks to make it match mine.

<link rel="stylesheet" type="text/css" href="themes/jQueryUI/ui-style.css" id="ui-theme" />
<link rel="stylesheet" type="text/css" href="themes/Simply/style.css" id="theme" />

After that we can add the jQuery and jQuery UI libraries to the template. In my project, there was also a need to add a wysiwyg and I had to use their propietary one, but for this example, I can simply use TinyMCE.

For this example, I’m going to put all the scripts into a folder called /lib. This is also where I’ll extract TinyMCE (the jQuery plugin version).

Modernizr, very usefully, can load other scripts by URL, so we can simply do the following right after adding its JS own file :

<script type="text/javascript" src="lib/modernizr.custom.js"></script>
<script type="text/javascript">
	Modernizr.load([{
		load: "https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"
	}, {
		load: "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"
	}, {
		load: "lib/tiny_mce/jquery.tinymce.js"
	}, {
		load: "lib/dash.js"
	}]);
</script>

And that’s all we need to do on the template itself. That last file being called, “dash.js” in the /lib folder is where we’ll put everything else.

dash.js

I’m going to start by adding some custom CSS to this file rather than cluttering up the head section of the template. These are just a few added classes to make the content more presentable.

All this will be added inside the jQuery $(fuction() { }); section.

$('head').append('<style type="text/css">' +
	'.icon { width:75px; height:75px; }' +
	'.ticon { float:left; margin: .3em .5em; width:25px; height:25px; box-shadow:1px 1px 1px #aaa; }' +
	'.ui-dialog { text-align:left; }'+
	'.ui-dialog input[type="text"], .ui-dialog textarea { display:block; width:90%; }' +
	'</style>');

Next, since we’re working with TinyMCE, we’ll store those settings in a variable.

var tinySettings = {
	script_url : 'lib/tiny_mce/tiny_mce.js',
	plugins: "inlinepopups",
	theme: "advanced",
	theme_advanced_buttons1 : "bold,italic,underline,strikethrough," +
		"separator,cut,copy,paste,separator,bullist,numlist," +
		"separator,undo,redo,separator,link,unlink,image",
	theme_advanced_buttons2 : "",
	theme_advanced_buttons3 : "",
	theme_advanced_toolbar_location : "top",
	theme_advanced_toolbar_align : "left",
	theme_advanced_statusbar_location : "bottom",
	width: "100%",
	height: 250,
	content_css : "content.css",
};

You’ll notice the last line refers to a “content.css” file. This basically styles the wysiwyg content as it’s being edited. In my case, this is all it contained…

body {
	font: normal 90% Sans-serif,tahoma,verdana;
	color: #575757;
}

p {
	line-height:170%;
}

Dialogs

Dashboards frequently use dialogs when making changes, presenting confirmations etc… In this case, I just created two dialogs for editing content and to confirm when removing the widget…

function initDialogs() {
	// Close widget dialog
	$('article').append('<div id="dialog-confirm-close-widget" title="Close widget" style="display:none;">' +
		'<span class="ui-icon ui-icon-alert" style="float:left;"></span>' +
		'You are about to delete this widget. Are you sure?</div>');

	// Config widget dialog
	$('article').append('<div id="dialog-config-widget" title="Modify" style="display:none;">' +
		'<form><fieldset><legend>Change widget content</legend>' +
		'<p><label>Title <input type="text" id="widget-title-text" /></label></p>'+
		'<p><label>Content <textarea rows="5" cols="50" id="widget-content-text">Some test content</textarea></label></p>'+
		'<p id="icon-field"><label>Icon URL <span>Will be resized to 75x75 pixels</span><input type="text" id="widget-icon-text" /></label></p>'+
		'</fieldset></form></div>');

	// Create and destroy these dialogs to hide them
	$('#dialog-confirm-close-widget').dialog("destroy");
	$('#dialog-config-widget').dialog("destroy");
}

That textarea will be replaced with TinyMCE later.

3 Little Helpers

Often overlooked, helpers can save a lot of time and help unclutter your JS quite a bit.

The following three check for null or empty strings, initializes and applies TinyMCE to an element with the given settings and removes the wysiwyg after sending the changes back to the textarea… in that order.

function notEmpty(t) {
	if(t) {
		if($.trim(t) != "")
			return true;
	}
	return false
}

function initTiny(t, s) {
	t.tinymce(s);
}

function closeTiny(t) {
	var e = t.attr('id');
	t.val(tinyMCE.get(e).getContent());
	tinyMCE.execCommand('mceRemoveControl', false, e);
}

Widget controls

In jQuery UI, there are ui-icons that we can use here without having to invest extra time to create our own. This also means we can apply our controls to these icons by using something like the “title” or “alt” attribute as the command string. In this case, I opted to use the “title” attribute since I’ll be using these icons in <span> tags.

function setControls(ui) {
	ui = (ui)? ui : $('.ui-icon');
	ui.click(function() {
		var b = $(this);
		var p = b.parentsUntil('.column').parent();
		var i = p.children('img[alt="icon"]:first').eq(0);

		var h = p.children('.ui-widget-header h5:first').eq(0);

		// Control functionality
		switch(b.attr('title').toLowerCase()) {
			case 'config':
				widgetConfig(b, p);
				break;

			case 'toggle':
				widgetToggle(b, p, i);
				break;

			case 'close':
				widgetClose(b, p);
				break;
		}
	});
}

Note, the three widget functions that will “config” (as in edit the content), “toggle” (collapse/expand) and “close” the widgets.

The toggle function is pretty simple. I wanted to minimize the .widget-content class (which we’ll add later), change the minus into a plus on the side of the widget after collapsing and turn the big image icon seen on most of those segments into a smaller one that fits on the header. The .ticon class is what we added to the head earlier.

// Toggle widget
function widgetToggle(b, p, i) {
	// Change the + into - and visa versa
	b.toggleClass('ui-icon-minus').toggleClass('ui-icon-plus');

	// Turn the big icon into a small one or visa versa
	if(i.hasClass('icon'))
		i.switchClass('icon', 'ticon', '300');
	else
		i.switchClass('ticon', 'icon', '300');

	// Show/Hide widget content
	p.children('.widget-content').eq(0).toggle(300);
};

Closing a widget is also pretty straightforward. We’ll be using the closing dialog we added earlier.

// Close widget with dialog
function widgetClose(w, p) {
	$("#dialog-confirm-close-widget").dialog({
		resizable: false,
		modal: true,
		buttons: {
			"Close widget": function() {
				p.toggle('slide', {}, 500, function() {
					p.remove();
				});
				$(this).dialog("close");
			},
			Cancel: function() {
				$(this).dialog("close");
			}
		}
	});
}

The last of the widgets is the config. This is the trickiest part, since we’ll need to create and destroy TinyMCE instances and get input from the dialog and push to the content.

// Modify widget
function widgetConfig(w, p) {

	// Input elements in the dialog
	var dt = $('#widget-title-text');
	var dc = $('#widget-content-text');
	var du = $('#widget-icon-text');

	// Widget elements to change
	var wt = p.children('h5:first').eq(0);
	var wc = p.children('.widget-content').eq(0);

	// If there is no icon on the widget, there's nothing to change
	var wi = p.children('img[alt="icon"]:first');
	if(wi.length > 0) {
		wi = p.children('img[alt="icon"]:first').eq(0);
			$('#icon-field').show();
	}
	else {
		$('#icon-field').hide();
	}

	$("#dialog-config-widget").dialog({
		resizable: false,
		modal: true,
		width: 500,
		open: function() {
			if(wi != null)
				du.val(wi.attr('src'));

			dt.val(wt.text());
			dc.val(wc.html());

			// Initialize TinyMCE
			initTiny(dc, tinySettings);
		},
		buttons: {
			"Save changes": function(e, ui) {

				// Some widgets don't have an icon
				if(wi.length > 0) {
					if(notEmpty(du.val()))
						wi.attr('src', du.val());
				}

				// Remove editor (also gets content from TinyMCE back to textarea)
				closeTiny(dc);

				// Update
				if(notEmpty(dc.val()))
					wc.html(dc.val());

				// Careful here, don't wanna lose the control icons
				if(notEmpty(dt.val())) {
					var ci = wt.children('span.ui-icon');
					wt.html(dt.val());

					// Reset controls
					wt.prepend(ci);
					setControls(ci);
				}

				$(this).dialog("close");
			},
			Cancel: function() {

				// Destroy TinyMCE
				closeTiny(dc);

				$(this).dialog("close");
			}
		}
	});
}

Basically, the above function grabs the text fields from the dialog and puts the existing content on page into them. The user makes some edits and clicks on “Save changes” which causes the script to take the changed content and apply it back to the page. In a real-world example, this content will actually be posted back to the server.

Note: Since the control icons are also located in the title, when we change the title text, we have to make sure that the control icons are spared from any edits.

The Initialization.

This basically takes every section with a “column” class that has a <h5> element inside into a sortable widget. It adds the control icons as <span> tags and wraps the content in a widget-content <div> (which we can minimize) and adds the ui-widget classes from jQuery UI to aid with sorting.

function Init() {

	// Initialize dialogs
	initDialogs();

	// Portlet and sort related CSS classes
	var sortClasses = "ui-widget ui-widget-content ui-helper-clearfix";

	// Set every column segment with h5 element as a sortable widget
	$('.column:has(h5)').each(function() {

		var s = $(this);
		var p = s.parentsUntil('section').parent();
		var h = s.children('h5:first').eq(0);

		if(!p.hasClass('ui-widget'))
			p.addClass(sortClasses);

		// Function icons
		h.addClass('ui-widget-header')
			.prepend('<span class="ui-icon ui-icon-gear" title="Config"></span>')
			.prepend('<span class="ui-icon ui-icon-minus" title="Toggle"></span>')
			.prepend('<span class="ui-icon ui-icon-close" title="Close"></span>');

		// Need this to drag not highlight
		h.disableSelection();

		// Interaction cues
		h.css('cursor', 'move');
		$('.ui-icon').css('cursor', 'pointer');

		// Wrap control stuff (like icons and headers) in a widget-header div
		// and the rest in a widget-content div
		s.children().not('img[alt="icon"], .ui-widget-header, .ui-icon')
			.wrapAll('<div class="widget-content" />');

		s.children().not('widget-content').wrapAll('<div class="widget-header" />');
	});

	// Group sortable widgets in each section to one sort-area
	$('section').has('.column').each(function() {
		$(this).children().not('header,hr')
			.wrapAll('<div class="sort-area" />');
	});

	// Trigger control initialization
	setControls();
}

And lastly, if we don’t have sorting ability, we can’t really call this a dashboard. Ironically the most defining characteristic in dashboards is the most simple to implement once all the wrapper divs are in place.

$(".sort-area").sortable({
	connectWith: ".sort-area",
	opacity: 0.6,
	helper: 'clone',
	dropOnEmpty: true
});

This post was prompted by yet another example of why I have a dim view of project managers.

Can you put together a dashboard for us?

OK, no problem.

We already have the backend completed and a template in place although it doesn’t have any widget markup. Except for the head tag, we need you to not touch the rest of it because we do have other stuff on the page. BTW… We need it in an hour.

@$#& me!

I wish the above was an exaggeration, but sadly, it happens more often than I care to tolerate.

The problem is easy enough to come by. Someone first builds a backend thinking they’ll have all sorts of widget like functionality in the future, but doesn’t develop the front end for any of it. Time goes by… The next developer comes along and decides that since the template is already in place, they’ll finagle the output to be more “widget-like” and create a separate handler to manage user changes. This also explains why so many “legacy” dashboards are notoriously slow.

So now they bring in someone else to drop in a dashboard where there previously existed no frontend for it… And they want it yesterday.

Oh, right New Year resolution…
Less grumpy. Less grumpy. Less grumpy.

Update

Changed the notEmpty(t) function line if(t != “”) into if($.trim(t) != “”).

An Encrypted Christmas Greeting

A little while ago, I wrote a simple one-time pad utility in JavaScript that can be used to send encrypted messages with relative security. One-time-pad is technically cryptographically secure, however it’s only as secure as how it’s used and the strength of the random number generator used to create the pad. My script must rely on the strength of the psudo random number generator of the browser scripting engine, so security is relatively weak and this must be taken into consideration before using it for anything important.

I’ve been getting some emails asking about using the utility and I think there was some added confusion since my version uses numbers as well. We’ll here’s a little tutorial on how to use a one-time pad…

Encrypting the message

Take the following simple message for example, and take the corresponding number from the values list on the one-time-pad.

 

M E R R Y C H R I S T M A S
13 05 18 18 25 03 08 18 09 19 20 13 01 19

 

Now, using the one-time pad, I got the following set of random characters and their corresonding values.

 

D 9 D F D B L M L W W 8 8 A
04 35 04 06 04 02 12 13 12 23 23 34 34 01

 

If I take the corresponding value of each character from both lists and add them together, I can get the new ciphertext that can be sent securely to the recipient. Obviously we can’t use the numbers in green because our list of available characters only go up to 36, however, we can subtract 36 from these numbers (mod 36) so it will cycle back to the available pool.

 

13 05 18 18 25 03 08 18 09 19 20 13 01 19 +
04 35 04 06 04 02 12 13 12 23 23 34 34 01
17 40 22 24 29 05 20 31 21 42 43 47 35 20 =
17 04 22 24 29 05 20 31 21 06 07 11 35 20 mod 36

 

This new set of numbers can be turned into the ciphertext using that same values list.

 

17 04 22 24 29 05 20 31 21 06 07 11 35 20
Q D V X 3 E T 5 U F G K 9 T

Decrypting the message

So, our recipient got the encrypted ciphertext, QDVX3ET5UFGK9T, and now he/she must take these charaters and turn them into a list of values in order to decrypt it.

 

Q D V X 3 E T 5 U F G K 9 T
17 04 22 24 29 05 20 31 21 06 07 11 35 20

 

Then, using the same one-time pad key values (since they’ll both be using the same sheet) the recipient will get the random characters and their associated values. Same as above.

 

D 9 D F D B L M L W W 8 8 A
04 35 04 06 04 02 12 13 12 23 23 34 34 01

 

The recipient will then subtract the one-time pad values from the encrypted message text. Basically the reverse of what the sender did. Again, this may result in some numbers going out of bounds of the available values list and become negative (marked in red), which we can fix by adding 36, again the opposite of what we did above, to bring it back to the available character pool.

 

17 04 22 24 29 05 20 31 21 06 07 11 35 20
04 35 04 06 04 02 12 13 12 23 23 34 34 01
13 31 18 18 25 03 08 18 09 17 16 23 01 19 =
13 05 18 18 25 03 08 18 09 19 20 13 01 19 mod 36

 

And when we turn those numbers back into the original text using the values list, we get :

 

13 05 18 18 25 03 08 18 09 19 20 13 01 19
M E R R Y C H R I S T M A S

 

… And a very Happy New Year!