Update: I see a few folks are coming here from Hacker News. This project was not ready for public release or review. Examples and docs need to be created etc. Should have been behind a firewall. However, since you're here please feel free to email jv@vip.ie with suggestions, feedback, etc. Thx.

Code, with a Clear Mind

DoubleDollar is a new kind of JavaScript Framework, that enables you to create pure JavaScript applications with beautiful Zen-like code. Built on jQuery, DoubleDollar is lightning fast, requires no compiler, and is infinitely extendable.

Demos

Hello World

This is how to code a Hello World application in DoubleDollar.

$$ ({ home : { route : { default : function() { $('body').html('Hello World'); } } } })

Routing

This is how to code a route in DoubleDollar. In this case user/login.

http://yourwebsite.com/#user/login

To activate the route, code this.

$$ ({ // Main namespace (maps to #user) user : { route : { // Login controller (maps to #user/login) login : function() { $('body').html("Login HTML goes here."); } } } }) Note: Browser back/forward buttons are automatically handled by DoubleDollar.

Default Routing

This is how to access a default route in DoubleDollar.

http://yourwebsite.com/#user

To hook into a default route code this.

$$ ({ user : { route : { // This acts like index.html for #user default : function() { $('body').html("I am the defaut route for user."); } } } })

Controllers

Controllers are initialized in the route namespace as described above. This is how to code a controller in DoubleDollar. In this case user/login.

http://yourwebsite.com/#user/login

To activate the controller, code this.

$$ ({ // Main namespace (maps to #user) user : { route : { // Login controller (maps to #user/login) login : function() { $('body').html("Login HTML goes here."); } } } })

Models

This is how to code a model in DoubleDollar.

$$ ({ user : { // The model namespace model : { login : function(username,password) { // .. code here to get a response from the server .. if ( isValidated ) { return 'OK'; } else { return 'You entered a bad password. Please try again.'; } } } } }) Note: Models are not formalized, or required.

UI

This is how to code UI logic in DoubleDollar.

$$ ({ home : { route : { default : function(routingParams) { // Default route code here } }, // The UI namespace. UI specific logic goes here. ui : { resizeContent : function() { $('#body #content').css({height:$$.state.winHeight-260}); } } // Bindings namespace. bind : { // In this case, we make use of our UI logic on app init. do_bind_resizeContent : function() { $(window).resize(function() { $$.home.ui.resizeContent(); }); $$.home.ui.resizeContent(); }, } } }) Note: The above code is used on this page.

Bindings

This is how to bind events in DoubleDoller. In this case, binding code to the login button.

$$ ({ user : { route : { login : function() { // Render the login screen $('body').html($$.user.tpl.login()); // Bind the login code $$.user.bind.loginButton(); } }, // The binding namespace bind : { loginButton : function() { $('.loginForm .loginButton').click(function() { // Login code goes here }); } } } }) Note: The dom is ripped apart and re-drawn. Bindings are added as needed. This ensures the dom, and browser, are processing a bare minimum of events. Which in turn minimize memory footprint and optimizes responsiveness.

Templates

Templates are best used for ui and chrome such as dialogs and popups (i.e not content). This is how to code a template in DoubleDollar.

$$ ({ user : { // Template namespace tpl : { login : function() { var html = '<div class="loginForm">Please Login:</div>'+ '<h1>Please Login:</h1>'+ '<input type="text" id="username"><br />'+ '<input type="text" id="password"><br />'+ '<a href="#" class="loginButton">Login</a>'+ '<div>'; return html; } } } }) Note: Templates are javascript functions that return HTML. They may contain conditional logic, and often do.

This is how to use a template.

$('body').html($$.user.tpl.login());

Content

This how to load html content directly into a page with DoubleDollar.

$$.content.loadPage ({ 'pagePath' : 'some/html/page.html', 'targetDiv' : '#someTargetDiv' }); Note: You will need to load the $$.js.(content) add-on in your $$._bootstrap.js file.

CSS

This is how to add CSS files on the fly with DoubleDollar.

$$ ({ user : { css_files : [ 'css/user.css', 'http://fonts.googleapis.com/css?family=Ubuntu|Lemon' ] } }) Note: Use this feature to create cohesion between frontend assets and controllers. Also use this feature for creating bundeled addons within a single folder.

Add-ons

All code (other than the $$.js Kernal) is an add-on. This includes routing, controllers, templates and public add-ons created by the community.

This is how to build an add-on in DoubleDollar.

$$ ({ timeStamp : function() { var date = new Date; return date.getTime(); } })

This is how to use the new add-on.

alert($$.timeStamp());

This is how to dynamically load an add-on on-the-fly.

$$.getAddOn ( // Serve add-on 'http://yourserver.com/addons/timeStamp', // Execute a function once the add-on is loaded function() { alert($$.timeStamp()); } ); Note: Any add-on may be dynamically loaded including routers, models, templates, etc.

Deep Add-ons

This is how create a multi-functional add-on.

$$ ({ time : { timeStamp : function() { var date = new Date; return date.getTime(); }, dateString : function() { var date = new Date; return date.toDateString(); } } })

This is how to use it.

alert($$.time.timeStamp()); alert($$.time.dateString());

Auto-running

This is how to auto-run some code when an add-on is being loaded.

$$ ({ time : { state : { todaysDate : false }, // Any function with the name do_* will be executed do_init : function() { $$.time.state.todaysDate = $$.time.dateString(); }, dateString : function() { var date = new Date; return date.toDateString(); } } }) Note: We are initializing $$.time.state.todaysDate with todays date. This works with dynamically loaded add-ons too. Note how we are referenceing functions in the add-on being loaded.

Overdubbing

Imagine you downloaded the above $$.time add-on from a public repository and loaded it into your app. While the add-on is running live, you can alter it in memory.

For example, to overdubb the dateString function to allow the passing of a custom date object you could code and run this in DoubleDollar.

$$ ({ time : { // Our new, improved, function dateString : function(passInDate) { var date = ( passInDate !== undefined ? passInDate : new Date); return date.toDateString(); } } }) Note: Overdubbing enables you to customize public add-ons without changing any code. Then, if the author releases an update, you can drop it in with very little chance of it breaking anything.

Constructors

With DoubleDollar you can add Constructors to any namespace. This allows you to abstract and functionalize code.

$$ ({ time : { dateString : { // Default will be executed when $$.time.dateString() is invoked __construct : function(passInDate) { var date = $$.time.dateString.dateFactory(); if ( passInDate !== undefined ) { date = passInDate; } return date.toDateString(); }, dateFactory : function() { return new Date; } } } }) Note: This can be achieved with basic JavaScript prototyping. We added this in to make it easy for folks to get started with the concept.

Lazy Loading

With lazy loading you can store huge swathes of your application server-side, and load functionality as needed. This reduces initial load and keeps the application memory footprint low.

Let's say you wanted to build an app like Microsoft Word, with hundreds of menues. You could do that with lazy loading. Simply load the required functionality as users select menu options.

We already said this in the add-ons section, but it's worth repeating. This is how to lazy load add-ons via ajax in DoubleDollar.

$$.getAddOn ( // Serve up a json add-on 'http://yourserver.com/addons/timeStamp', // Execute a function once the add-on is loaded function() { alert($$.timeStamp()); } ); Note: This includes controllers, models, templates,etc.

Device Targeting

This is how to target a specific device or operating system in DoubleDollar.

In JavaScript:

if ( $$.state.isPhone || $$.state.isOsx ) { // Do this }

In CSS:

<style> .isPhone, .isOsx { // Do this } </style>

DoubleDollar alters the <body> tag when it initializes. This is what it looks like after initilization.

<body class="isWebkit isChrome isMac">

This works nicely for sharing code between Android, iPhone, iPad etc on PhoneGap.

Routing Variables

This is how to pass variables via links in DoubleDollar. In this case, to the route #user/login.

http://yourwebsite.com/#user/login/userid:1/username:jv2222

To access routing variables, code this.

$$ ({ user : { route : { login : function(routingVars) { alert(routingVars.userid); alert(routingVars.username); } } } }) Note: This enables users to bookmark, or share deep links to your app. Routing variables also become part of the browser history by default. Try clicking back now!

State Variables

This is how to keep state in DoubleDollar.

$$ ({ user : { // State namespace state : { isLoggedIn : false } } })

This is how to chage state.

$$.user.state.isLoggedIn = true;

This is how to test state.

if ( ! $$.user.state.isLoggedIn ) { alert('Please login!'); }

Kernal Hooks

You can be adventurous, and add parsing hooks to the DoubleDollar Kernal like this.

$$ ({ hooks : { // Add a wildcard hook wildcard : { myWildCardHook_ : function(probablyUnusedKey,incomingHookFunction) { incomingHookFunction(); } }, // Add a name specific hook name : { myNameHook : function(probablyUnusedKey,incomingHookFunction) { incomingHookFunction(); } } } }) Note: Hooks will only work in code loaded sequentially after the hooks were added ;)

Your hooks will work exactly the same as Auto-running. Here's how you can use your new hooks.

$$ ({ // Invoke your wildcard hook myWildCardHook_anyNameIWant : function() { alert("Hello world!"); }, // Invoke your name specific hook myNameHook : function() { alert("Hello world!"); } })

Architecture

At it's core DoubleDollar is less than 50 lines of code and is built on a Kernal style architecture. The Kernal does "just enough" to make everything else possible. In DoubleDollar's case, the Kernal performs the following functions:

DoubleDollar's Kernal is not a front-loader (aka Ruby-on-Rails, Cake PHP etc.) as it has no delegate responsibilities of it's own, and as such its behavior entirely depends on the add-ons loaded at run-time.

These can be switched-up up as needed with $$._bootstrap.js. In general, DoubleDollar acts as a web client framework. However, it could just as easily act as a server-side framework in conjunction with node.js.

DoubleDollar's modular lazy-load add-on architecture means that you'll only ever load exactly what you need when you need it. This ensures faster load and an optimum user experience.

Convention

DoubleDollar makes strong use of naming and organization to make code easy to understand for you and your team. Code is generally sub-grouped into the following simple cohesive units.

$$ ({ user : // ie. $$.user, $$.dashboard , $$.myAddon, etc. { state : // ie. $$.user.state.isLoggedIn { }, route : // ie. $$.user.route.login() { }, do : // ie. $$.user.do.login() { }, tpl : // ie. $$.user.tpl.login() { }, ui : // ie. $$.user.ui.redrawLogin() { }, bind : // ie. $$.user.bind.login() { }, model : // ie. $$.user.model.login() { } } })

DoubleDollar follows Allman style indenting.

Enhancing

We would love you to cretae add-ons, components and even core functionality for DoubleDollar. Here are some examples of great add-ons just waiting to be built.

Mobile

One of the main use-cases for DoubleDollar is to build mobile applicatons. Right now we are laying the foundations for that work. We are building mobile awareness into appropriate add-ons, such as $$.js.(bindings), to optimize the mobile experience for end users.

We believe that building a native feeling mobile experience with JavaScript is as much about attention to detail and education, as it is about framework components.

About

Created by Justin Vincent