Modular JavaScript with require.js

JavaScript based projects are getting larger with more code, they are now quite often complete applications. One way to organise and divide your code into manageable chunks is to split the classes into separate files. This soon creates problems of dependency as each file might rely on another and how do you know when it's loaded and ready.

Asynchronous Module Definition (AMD) is a standard way to define each JavaScript module into a separate file. You then register each class using a generic 'define' function which ensures they are loaded in the correct order and dependencies are handled. The added bonus of this is that your classes are name spaced which reduces chances of conflicts and they support crossdomain loading.

The main advantages are
- modular code (easier to maintain, in separate files)
- asynchronous (modules can load in different orders, once their dependencies load they init with options)
- code is loaded on demand (if the user doesn't request a feature, it isn't loaded!)
- modules are crossdomain (load a module from another server!)
- no global variables means no chance of conflicts with other libraries/code
- easily minified (if we want one file minified we can do that automatically too)
it's a standard!! (potentially future proof?)

So now you probably want to know how complicated it is to set up? Well it is actually so simple you will be amazed:

AMD MVC Example

models/Fields.js
define('models/Fields', function(require) {
// return your object/function class code here
return function(name) {
this.name = name || 'default';
this.getName = function() {
return this.name;
}

};
});

views/Inputs.js
define('views/Inputs', function(require) {
// return your object/function class code here
return {
init: function(value) {
var el = document.getElementById('form');
 el .innerHTML = '<input id="'+value+'" />';
}
}
});

controllers/Form.js
define('controllers/Form', function(require) {

// require two modules are loaded before this class will load
var view = require('views/Inputs');
var model = require('models/Fields');

// return your object/function class code here
return {
init: function(name) {
var item = new model(name);
view.init( item.getName());
}
};
});

Main.js
define('Main', function(require) {
var form = require('controllers/Form');
form.init();
});

Once you have created your Module classes, you then add a loader script to load the module classes into the browser dynamically. There are lots of options because they use the same standard:
Download and include the loader file in the head of your html page, pointing to the Main controller:
<script src="js/plugins/require.js" data-main="js/app/Main"></script>

Note you will have to get your paths correct as require.js uses the path of your Main file as the root of your app. If you don't specify a root path then it will default to the directory of require.js

If you want to minify and compact down to one file you can use r.js with java rhino and java google compiler. You have to define the module name as I have in the other code examples e.g. define('controllers/Form' as when they are compiled they will lose their filenames/paths.
- Create a shell script which points to the java files with your build options e.g:
java -classpath plugins/js.jar;plugins/compiler.jar org.mozilla.javascript.tools.shell.Main plugins/r.js -o baseUrl=app name=Main out=app.min.js
pause

How does it look when you put it all together?

Example MVC Todo list:

Minified example:

Download it all including minify setup files:
https://github.com/kmturley/require-js-mvc/zipball/master

Further Reading, Articles & Examples:

Cross browser background opacity

If you want to create a semi-transparent background you can either use png image files or use this useful css:


background: rgba(0,0,0,0.6);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)";

Web Fonts Vs Commercial Fonts

This is a great site showing some similar web and commercial fonts

Can you tell the difference?

findfont02

http://www.webdesignshock.com/web-fonts

Google Frontend Coding Standards


These two links are very useful summaries of some of the best practices in frontend coding.

Html & Css: http://google-styleguide.googlecode.com/svn/trunk/htmlcssguide.xml
JavaScript: http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml

Dynamically including JavaScript & CSS files

When creating JavaScript applications that run from multiple libraries, themes and files, you will hit a common problem.

- Including all of the files in your html page is a huge waste on download speeds and performance (when only half are actually used)

- Including the files when needed improves the download speeds but the users see a lag as they wait for that feature to show

The simplest solution to get around this is to run your feature/theme detection before the html page has loaded and append the additional resources to the page. This means the browser loads them as soon as possible and still gives you the flexibility of running your own logic.

The Google Analytics embed code is a good example which looks something like this:


<script>
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>


However This code inserts the new files before the others in the page. With themes in particular you want to include them after the page files so you can overwrite styles. Here is my modified code for css and js:


<script>
(function() {
var e = document.createElement('link'); e.href = 'css/theme.css'; e.rel = 'stylesheet';
var h = document.getElementsByTagName('head')[0]; h.appendChild(e);
})();
</script>



<script>
(function() {
var f = document.createElement('script'); f.src = 'js/theme.js';
var h = document.getElementsByTagName('head')[0]; h.appendChild(f);
})();
</script>

And if you want to switch the css and js theme based on a url parameter:


<script>
(function() {
var theme = new RegExp('lang=([^&]*)', 'i').exec(window.location.search)[1] || 'default-theme';
var e = document.createElement('link'); e.href = 'css/'+theme+'.css'; e.rel = 'stylesheet';
var f = document.createElement('script'); f.src = 'js/'+theme+'.js';
var h = document.getElementsByTagName('head')[0]; h.appendChild(e); h.appendChild(f);
})();
</script>

HTML5 video events


When developing an html5 video player you use events to know when the player is ready, and to get the length of the video. You will also need to make them work cross browser and cross device.

This page is really useful for seeing the events fire with their relevant commands:
http://www.w3.org/2010/05/video/mediaevents.html

Here is an example using the three most used events:
(note that iOS devices the video metadata is not available until you've manually triggered play on the video player)

// setup the video player

var view = document.createElement('video');
view.addEventListener('loadedmetadata', onMetaData, false);
view.addEventListener('timeupdate', onTimeUpdate, false);
view.addEventListener('ended', onEnded, false);
document.getElementById('player').appendChild(view);

// load the video

view.autoplay = true;
view.controls = true;
view.setAttribute('src', 'example.mp4');
view.load();


function onMetaData(e) {
console.log('onMetaData', view.duration);
}

function onTimeUpdate(e) {
console.log('onTimeUpdate', view.currentTime);
}

function onEnded(e) {
console.log('onEnded');
}

Testing touch events using your mouse

If you aren't running xCode then you can test touch events using this bookmarklet

Also Chrome has added some useful touch/device features.
1) Open your developer tools F12
2) Click the bottom right cog to open the settings panel
3) Click 'Emulate touch events' to make Chrome fire Touch Events (note it doesn't emulate page scroll)
4) Click 'Override User Agent' to choose a mobile device and emulate its user agent settings and screen width/height

Ace open source code editor

If you're planning to include a live code editor in one of your projects you may have a hard time working out how to validate code within a text field and replicate formatting.

The hard work has been done for you with Ace code editor. This open source project gives you all the functionality including:

  • Syntax highlighting
  • Automatic indent and outdent
  • An optional command line
  • Handles huge documents (100,000 lines and more are no problem)
  • Fully customizable key bindings including VIM and Emacs modes
  • Themes (TextMate themes can be imported)
  • Search and replace with regular expressions
  • Highlight matching parentheses
  • Toggle between soft tabs and real tabs
  • Displays hidden characters
  • Drag and drop text using the mouse
  • Line wrapping
  • Code folding
  • Multiple selections
  • Live syntax checker (currently JavaScript/CoffeeScript/Css/XQuery)
It's so good it's used by a number of sites including the very interesting cloud coding site Cloud9:

You can view the demo at:

Or grab the source at:

GIT programs and tutorial

If you want to store your code in the cloud, then GIT is one of the best options out there. GITHub is a site that allows you to store your code for free and collaborate with other users which has really been useful to me.

However GIT is not simple to pick-up and use, as most of the features can only be accessed by command line or another program such as GITTower.

If you're wanting to learn the command line approach then this is a really useful interactive tutorial:
http://try.github.com/levels/1/challenges/1

Otherwise go for something such as:
http://www.git-tower.com/

or you can go for GITHub's own programs for Windows and Mac at:
http://windows.github.com/
http://mac.github.com/

Controlling multiple YouTube Players at once

I'm constantly using the YouTube Player API to embed videos on sites with special functionality such as hidden controls, looping or synching to live feeds.

Howver one function always seemed to be elusivein the API. This was the ability to control all of the players on a page, regardless of whether they have been embeded using JavaScript on not.

I made a little helper function which stops all youtube players it can find on the current page:

function players(func, args) {
var iframes = document.getElementsByTagName('iframe');
for (var i=0; i<iframes.length; ++i) {
if (iframes[i]) {
var src = iframes[i].getAttribute('src');
if (src) {
if (src.indexOf('youtube.com/embed') != -1) {
iframes[i].contentWindow.postMessage(JSON.stringify({'event': 'command','func': func,'args': args || []}), "*");
}
}
}
}
}

// example usage
players('stopVideo');
This search for all iframes with youtube embeds. It then posts a message with the value you want:
https://developers.google.com/youtube/js_api_reference#Functions