Amplify - Knockout - MVVM breakout

by johnpapa

HTML

<script src="https://raw.github.com/appendto/amplify/master/core/amplify.core.js"></script>
<script src="https://raw.github.com/appendto/amplify/master/store/amplify.store.js"></script>
<script src="https://raw.github.com/appendto/amplify/master/request/amplify.request.js"></script>
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap-responsive.css">
<script src="https://raw.github.com/mennovanslooten/mockJSON/master/js/jquery.mockjson.js"></script>
<script src="https://raw.github.com/timrwood/moment/1.5.0/min/moment.min.js"></script>
<script src="https://github.com/downloads/SteveSanderson/knockout/knockout-2.1.0.js"></script>
<script src="http://codeseven.github.com/toastr/toastr.js"></script>
<link rel="stylesheet" href="http://codeseven.github.com/toastr/toastr.css">
<link rel="stylesheet" href="http://codeseven.github.com/toastr/toastr-responsive.css">
    <form class="form-horizontal">
        <div class="control-group">
            <label for="userName" class="control-label">User name</label>
            <div class="controls">
                <div class="input-prepend input-append">
                    <span class="add-on">@</span><input id="userName" class="input-medium" placeholder="Twitter Name Here …" data-bind="value:userName, hasfocus:true, valueUpdate: 'afterkeydown'"/><button class="btn"><i class="icon-remove icon-input-append-btn" data-bind="click:clearSearch"></i></button><button 
                    type="submit"
                    class="btn btn-primary" 
                    id="getButton"
                    data-bind="click:loadTweets">Load Tweets</button>
                    <!--, enable:!loadTweetsCommand.isExecuting()-->
                </div>
            </div>
        </div>
    </form>

    <div class="hide" data-bind="css: { show: tweets().length }">
        <div>
            <h4 class="caption">Tweets</h4>
   ...

CSS

body {  margin: 30px; }

.dialog {
    width: 550px;
}

.icon-input-append-btn {
    height:16px;
    margin-top: 0px;
}

.json-container{
    margin-top: 20px;
    width: 600px;
}

.twitter-item{
    color:#444;
    font-size:12px;
    min-height: 51px;
    padding: 12px 12px 12px 12px;
    border: 1px solid #E8E8E8;
    background-color:#F9F9F9;
}
.twitter-group {
    /*margin: 20px 8px 8px 8px;*/
    width: 600px;    
 }
.twitter-group > div:first-child
{ 
    -moz-border-radius-topright: 15px;
    -moz-border-radius-topleft: 15px;
    -webkit-border-top-right-radius: 15px;
    -webkit-border-top-left-radius: 15px;
    border-top-right-radius: 15px;
    border-top-left-radius: 15px;
}
.twitter-group > div:last-child
{ 
    -moz-border-radius-bottomright: 15px;
    -moz-border-radius-bottomleft: 15px;
    -webkit-border-bottom-right-radius: 15px;
    -webkit-border-bottom-left-radius: 15px;
    border-bottom-right-radius: 15px;
    border-bottom-left-radius: 15px;
}

/*.twitter_container a{
    color:#0066CC;
    font-weight:bold;
}
*/
.twitter-status{
    height:60px;
    padding:6px;
    border-bottom:solid 1px #DEDEDE;
}
.twitter-image{
    float:left;
    margin-right:14px;
    border:solid 2px #DEDEDE;
    width:50px;
    height:50px;
}
.twitter-posted-at{
    font-size:11px;
    padding-top:4px;
    color:#999;
}
.notifier {
    left: 0px;
    position: fixed;
    top: -5px;
    width: 100%;
    z-index: 1100;
    /*float: left;*/
    margin-left: auto;
    margin-right: auto;
}
.notifier-inner 
{
    /*margin: 0;*/
    position: relative;
}
.alert {
    padding-top: 10px;
    margin-top: 0;
    margin-bottom: 0;
    margin-left: auto;
    margin-right: auto;
    width: 400px;
}
.close {
    margin-top: 3px;
}

JavaScript

var my = my || {}

my.defineRequests = (function () {
    // Define what a getTweets request looks like... url, dataType, etc
    // Typically put all of these in their own script file
    amplify.request.define("getTweets", "ajax", {
        url: "https://twitter.com/status/user_timeline/{userName}.json?count={count}&exclude_replies=false&include_rts=1&callback=?",
        //url: "http://api.twitter.com/1/statuses/user_timeline.json?include_rts=true&screen_name={userName}&count={count}",
        dataType: "json",
        type: "GET"
    })

    // Uncomment this to redefine the getTweets request with hard-coded data
    // Typically put all of these mock definitions in their own script file
    /*
    amplify.request.define( "getTweets", function ( settings ) {
    settings.success([
    { id: 0, created_at: "Mon Apr 11 8:00:00 +0000 2012", text: "Test Tweet 1", favorited: false, retweeted: false, user: { name: "User 1" } },
    { id: 1, created_at: "Mon Apr 11 9:00:00 +0000 2012", text: "Test Tweet 2", favorited: true, retweeted: true, user: { name: "User 2" } },
    { id: 2, created_at: "Mon Apr 11 10:00:00 +0000 2012", text: "Test Tweet 3", favorited: false, retweeted: true, user: { name: "User 3" } },
    { id: 3, created_at: "Mon Apr 11 11:00:00 +0000 2012", text: "Test Tweet 4", favorited: true, retweeted: false, user: { name: "User 4" } },
    { id: 4, created_at: "Mon Apr 11 12:00:00 +0000 2012", text: "Test Tweet 5", favorited: true, retweeted: true, user: { name: "User 5" } },
    ])    
    })
    */

    // Uncomment this to redefine the getTweets request with prototype data
    amplify.request.define("getTweets", function (settings) {
        var mockData = $.mockJSON.generateFromTemplate({
            "tweets|2-4": [{
                "id|+1": 0,
                "created_at": "Mon Apr 11 @TIME_HH:@TIME_MM:@TIME_SS +0000 2012",
                "text": "@LOREM_IPSUM",
                "favorited|0-1": false,
                "retweeted|0-1": false,
    ...