Vertebrae framework

built with Backbone.js and RequireJS using AMD

Hello World Code Demo Using Layout Manager and Controller

Overview of Hello World “Layout”

Code demonstration of adding a route, route handler function in App, new “hello” package with a template and view. The package controller file hello.js extends the Controller.prototype and is based on a (template) copy of the Controller.prototype in src/controller.js. The WelcomeSectionView prototype extends the SectionView prototype (class) and requries both name and destination properties when instantiated. The application.js method ‘showHello’ is mapped to the route ‘/hello/:name’ and the showHello method instantiates a controller object

Files edited in the application:

src/application.js  
src/main.js  

Files added as a new package:

src/packages/hello.js  [returns: HelloController]  
src/packages/hello/models/welcome.js  
src/packages/hello/templates/layout.html  [HTML used by layout, has section element]  
src/packages/hello/templates/welcome.html  
src/packages/hello/views/welcome.js  [returns: WelcomeSectionView, with article element] 
src/packages/hello/welcome.css

New Route added in src/application.js

1
'hello/:name': 'showHello'

New Package added in src/main.js

1
2
// ** Packages **
'hello'        : HL.prependBuild('/packages/hello'),

Add dependency to application.js

1
2
3
define([ /*... ,*/ "hello" ], function ( /*... ,*/ HelloController ) {
    // BTW this is the AMD module format with "hello" file as dependecy  
});

Add Method for new ‘/hello/:name’ route handler

1
2
3
4
5
6
7
showHello: function (name) {
    controller = new HelloController({
        "params": { "name": name },
        "route": "/hello" + name,
        "appStates" : this.states
    });
},

The parameters hash is added as an option above for the controller object to deal with.

(layout.html) download
1
<section id="welcome"></section>
(hello.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Hello Controller
// ---------------
// module as controller for 'hello' package
// Returns {HelloController} constructor

define([
        "vendor",
        "controller",
        "models",
        "views",
        "text!hello/templates/layout.html",
        "hello/models/welcome",
        "hello/views/welcome",
        "utils"
        ],
function (
        vendor,
        Controller,
        models,
        views,
        layoutTemplate,
        WelcomeModel,
        WelcomeSectionView,
        utils
        ) {

    var HelloController,
        LayoutView = views.LayoutView,
        BaseModel = models.BaseModel,
        $ = vendor.$,
        _ = vendor._,
        debug = utils.debug,
        Channel = utils.baselib.Channel,
        cssArr = [
            HL.prependBuild("/packages/hello/welcome.css")
        ];

    HelloController = Controller.extend(    {

            initialize: function (options) {
                Channel('load:css').publish(cssArr);

                _.bindAll(this);

                this.handleOptions(options);
                this.handleDeferreds();

                return this;
            },

            setupSections: function () {
                var welcomeView, welcomeModel;

                welcomeModel = new WelcomeModel(this.params);

                welcomeView = new WelcomeSectionView({
                    model: welcomeModel,
                    name: "Welcome",
                    destination: '#welcome'
                });

                debug.log("hello controller setup welcomeView");
                this.sections["Welcome"] = welcomeView;
                this.meta.activeViews.push("Welcome");
            },

            setupScheme: function () {
                this.scheme.push(this.sections[this.meta.activeViews[0]]);
            },

            setupLayout: function () {
                var helloLayout;

                helloLayout = new LayoutView({
                    scheme: this.scheme,
                    destination: "#content",
                    // require a html page layout template with text! prefix
                    template: layoutTemplate,
                    displayWhen: "ready"
                });
                this.layout = helloLayout;

                return this.layout;
            },

            handleDeferreds: function () {
                var controller = this;

                $.when(
                    null // or deferred objects, comma separated e.g. this.eventData.request 
                ).then(function () {
                    controller.setupSections();
                    controller.setupScheme();
                    controller.setupLayout().render();
                });
            },

            handleOptions: function (options) {
                if (options.params) {
                    this.params = options.params;
                }
                Controller.prototype.handleOptions(options);
            }

        });

    return HelloController;
});
(welcome.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Welcome Model
// -------------

// Requires define  
// Return {WelcomeModel} model constructor object  

define(['models'], function (models) {

    var WelcomeModel,
        BaseModel = models.BaseModel;

    WelcomeModel = BaseModel.extend({

        defaults: {
            name: null
        }

    });

    return WelcomeModel;
});
(welcome.html) download
1
<p>Hello {{name}}!</p>
(welcome.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Welcome Section View
// ------------------

// Package Hello
// Requires define
// Returns {WelcomeSectionView} constructor

// Contrete prototype extends SectionView.prototype (class) to be used in a LayoutView.

define([
        'views',
        'hello/models/welcome',
        'text!hello/templates/welcome.html'
        ],
function (
        views,
        WelcomeModel,
        welcomeTemplate
        ) {

    var WelcomeSectionView,
        SectionView = views.SectionView;

    WelcomeSectionView = SectionView.extend({

        tagName: 'article',

        className: 'welcome',

        model: WelcomeModel,

        template: welcomeTemplate // "Hello {{name}}!"

    });

    return WelcomeSectionView;
});
(welcome.css) download
1
2
3
4
5
6
7
8
9
10
11
/* Welcome styles */

#welcome {
    margin: 0 50%;
    padding: 5em 0;
    font: normal 2em/1.5em monospace;
}
.article p {
    color: blue;
    text-align: center;
}

Part 2: Get JSON data for content using AJAX

To get the ‘About’ section data a fixture (JSON file) was added in the test directory.

(101) download
1
2
3
4
5
6
7
8
9
{
    "_links": {
        "self": "/test/fixtures/hello/101",
        "shop": "http://www.hautelook.com/"
    },
    "title": "About HauteLook",
    "content": "Welcome to HauteLook, where you will discover thousands of the top fashion and lifestyle brands at amazing savings. Each day at 8 AM Pacific, shop new sale events featuring the best names in women's and men's fashion and accessories, beauty, kids' apparel and toys, and home décor at up to 75% off. Membership is free and everyone is welcome!",
    "callToAction": "To start shopping, go to: <a href=\"www.hautelook.com\">www.hautelook.com</a>"
}

application.js updated with…

1
2
3
4
5
routes: {
    'hello': 'showHello',
    'hello/': 'showHello',
    'hello/:name': 'showHello'
},
1
2
3
4
5
6
7
8
showHello: function (name) {
    controller = new HelloController({
        "params": { "name": name },
        "route": (name) ? "/hello" + name : "/hello",
        "appStates" : this.states,
        "useFixtures" : true
    });
},

Some files have changed…

src/packages/hello.js  
src/packages/hello/models/about.js  
src/packages/hello/templates/about.html  
src/packages/hello/templates/layout.html  
src/packages/hello/templates/welcome.html  
src/packages/hello/views/about.js  
src/packages/hello/views/welcome.js  
src/packages/hello/welcome.css

See the source code below and see how the new “About” section view is added in addition to the simple hello name view created by the welcome view.

(layout.html) download
1
2
3
4
<div id="welcome">
    <section id="greeting"></section>
    <section id="about"></section>
</div>
(hello2.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Hello Controller
// ---------------
// module as controller for 'hello' package
// Returns {HelloController} constructor

define([
        "vendor",
        "controller",
        "models",
        "views",
        "text!hello/templates/layout.html",
        "hello/models/welcome",
        "hello/views/welcome",
        "hello/models/about",
        "hello/views/about",
        "utils"
        ],
function (
        vendor,
        Controller,
        models,
        views,
        layoutTemplate,
        WelcomeModel,
        WelcomeSectionView,
        AboutModel,
        AboutSectionView,
        utils
        ) {

    var HelloController,
        LayoutView = views.LayoutView,
        BaseModel = models.BaseModel,
        $ = vendor.$,
        _ = vendor._,
        debug = utils.debug,
        Channel = utils.baselib.Channel,
        cssArr = [
            HL.prependBuild("/packages/hello/welcome.css")
        ];

    HelloController = Controller.extend(    {

            initialize: function (options) {
                Channel('load:css').publish(cssArr);

                _.bindAll(this);

                this.handleOptions(options);
                this.setupSections();
                this.handleDeferreds();

                return this;
            },

            setupWelcomeSection: function () {
                var welcomeView, welcomeModel;

                welcomeModel = new WelcomeModel(this.params);

                welcomeView = new WelcomeSectionView({
                    model: welcomeModel,
                    name: "Welcome",
                    destination: '#greeting'
                });

                debug.log("hello controller setup welcomeView");
                this.sections["Welcome"] = welcomeView;
            },

            setupAboutSection: function () {
                var aboutView, aboutModel,
                    webservice = this.webServices.hello;

                aboutModel = new AboutModel(
                    {id: 101}, // attributes
                    {urlRoot: webservice} // options
                );
                aboutModel.request = aboutModel.fetch();

                aboutView = new AboutSectionView({
                    model: aboutModel,
                    name: "About",
                    destination: '#about'
                });

                debug.log("hello controller setup aboutView");
                this.sections["About"] = aboutView;
            },

            setupSections: function () {
                var params = this.params;

                if (params && params.name && _.isString(params.name)) {
                    this.setupWelcomeSection();
                    this.meta.activeViews.push("Welcome");
                }
                this.setupAboutSection();
                this.meta.activeViews.push("About");
            },

            setupScheme: function () {
                var i, params = this.params;

                for (i = 0; i < this.meta.activeViews.length; i++) {
                    this.scheme.push(this.sections[this.meta.activeViews[i]]);
                };
            },

            setupLayout: function () {
                var helloLayout;

                helloLayout = new LayoutView({
                    scheme: this.scheme,
                    destination: "#content",
                    // require a html page layout template with text! prefix
                    template: layoutTemplate,
                    displayWhen: "ready"
                });
                this.layout = helloLayout;

                return this.layout;
            },

            handleDeferreds: function () {
                var controller = this;
                    aboutRequest = (this.sections["About"]) ? this.sections["About"].model.request : null;

                $.when(aboutRequest).then(function () {
                    controller.setupScheme();
                    controller.setupLayout().render();
                });
            },

            handleOptions: function (options) {
                if (options.params) {
                    this.params = options.params;
                }
                Controller.prototype.handleOptions(options);
            }

        });

    return HelloController;
});
(welcome.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Welcome Model
// -------------

// Requires define  
// Return {WelcomeModel} model constructor object  

define(['models'], function (models) {

    var WelcomeModel,
        BaseModel = models.BaseModel;

    WelcomeModel = BaseModel.extend({

        defaults: {
            name: null
        }

    });

    return WelcomeModel;
});
(welcome.html) download
1
<code>Hello {{name}}!</code>
(welcome.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Welcome Section View
// ------------------

// Package Hello
// Requires define
// Returns {WelcomeSectionView} constructor

// Contrete prototype extends SectionView.prototype (class) to be used in a LayoutView.

define([
        'views',
        'hello/models/welcome',
        'text!hello/templates/welcome.html'
        ],
function (
        views,
        WelcomeModel,
        welcomeTemplate
        ) {

    var WelcomeSectionView,
        SectionView = views.SectionView;

    WelcomeSectionView = SectionView.extend({

        tagName: 'article',

        className: 'greeting',

        model: WelcomeModel,

        template: welcomeTemplate // "Hello {{name}}!"

    });

    return WelcomeSectionView;
});
(about.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Welcome Model
// -------------

// Requires define  
// Return {AboutModel} model constructor object  

define(['models'], function (models) {

    var AboutModel,
        BaseModel = models.BaseModel;

    AboutModel = BaseModel.extend({

        initialize: function (attributes, options) {
            BaseModel.prototype.initialize.call(this, attributes, options);
        },

        defaults: {
            _links: {
                "self": "/test/fixtures/hello/101",
                "shop": null
            },
            title: null,
            callToAction : null
        }

    });

    return AboutModel;
});
(about.html) download
1
2
3
4
5
<h1>{{title}}</h1>
<code>{{content}}</code>
<p>
    <strong>{{{callToAction}}}</strong>
</p>
(about.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// About '101' Section View
// ------------------

// Package Hello
// Requires define
// Returns {AboutSectionView} constructor

// Contrete prototype extends SectionView.prototype (class) to be used in a LayoutView.

define([
        'views',
        'hello/models/about',
        'text!hello/templates/about.html'
        ],
function (
        views,
        AboutModel,
        aboutTemplate
        ) {

    var AboutSectionView,
        SectionView = views.SectionView;

    AboutSectionView = SectionView.extend({

        tagName: 'article',

        className: 'about',

        model: AboutModel,

        template: aboutTemplate

    });

    return AboutSectionView;
});
(welcome.css) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* Welcome styles */

#welcome {
    margin: 0 20%;
    padding: 5em 0;
    font: normal 2em/1.5em monospace;
}
#welcome code {
    margin: 0 0 1em;
}
#welcome p {
    color: blue;
    text-align: center;
}