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:
- Create the $$ singleton/namespace.
- Load (and merge) objects into the $$ namespace.
- Pass all objects through a hook function.
- Continue to perform the above, ad infinitum.
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.
- Automagical event binding
- Formalized models
- Node.js integration
- UI components
- Validators
- Whatever you can think of!
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