Skip to content

Commit 28a2724

Browse files
committed
This example is buggy now.
Use page `posts/del/:id` as example. If you go to the page directly (copy and paste the url to the browser), the server side-syncer would be triggered. On the other hand, if you click through the page, then the client-side syncer would be triggered. The bugs are aucsed by the difference between the syncers: 1. The `:id` param could be got by `req.param('id')` when triggering server-side syncer. But when triggering client-side syncer, `req.param('id')` returns nothing. 2. If triggering client-side syncer, then calling `getTemplateDate` of the view would return the result from the syncer. But it returns undefined when using server-side syncer.
1 parent 3ba6991 commit 28a2724

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+7920
-0
lines changed

Gruntfile.js

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
var path = require('path');
2+
3+
var stylesheetsDir = 'assets/stylesheets';
4+
var rendrDir = 'node_modules/rendr';
5+
var rendrModulesDir = rendrDir + '/node_modules';
6+
7+
module.exports = function(grunt) {
8+
// Project configuration.
9+
grunt.initConfig({
10+
pkg: grunt.file.readJSON('package.json'),
11+
12+
bgShell: {
13+
runNode: {
14+
cmd: './node_modules/nodemon/nodemon.js index.js',
15+
bg: true
16+
}
17+
},
18+
19+
stylus: {
20+
compile: {
21+
options: {
22+
paths: [stylesheetsDir],
23+
'include css': true
24+
},
25+
files: {
26+
'public/styles.css': stylesheetsDir + '/index.styl'
27+
}
28+
}
29+
},
30+
31+
handlebars: {
32+
compile: {
33+
options: {
34+
namespace: false,
35+
commonjs: true,
36+
processName: function(filename) {
37+
return filename.replace('app/templates/', '').replace('.hbs', '');
38+
}
39+
},
40+
src: "app/templates/*.hbs",
41+
dest: "app/templates/compiledTemplates.js",
42+
filter: function(filepath) {
43+
var filename = path.basename(filepath);
44+
// Exclude files that begin with '__' from being sent to the client,
45+
// i.e. __layout.hbs.
46+
return filename.slice(0, 2) !== '__';
47+
}
48+
}
49+
},
50+
51+
watch: {
52+
scripts: {
53+
files: 'app/**/*.js',
54+
tasks: ['rendr_stitch'],
55+
options: {
56+
interrupt: true
57+
}
58+
},
59+
templates: {
60+
files: 'app/**/*.hbs',
61+
tasks: ['handlebars'],
62+
options: {
63+
interrupt: true
64+
}
65+
},
66+
stylesheets: {
67+
files: stylesheetsDir + '/**/*.styl',
68+
tasks: ['stylus'],
69+
options: {
70+
interrupt: true
71+
}
72+
}
73+
},
74+
75+
rendr_stitch: {
76+
compile: {
77+
options: {
78+
dependencies: [
79+
rendrDir + '/assets/vendor/**/*.js',
80+
'assets/vendor/**/*.js',
81+
rendrModulesDir + '/underscore/underscore.js',
82+
rendrModulesDir + '/backbone/backbone.js',
83+
rendrModulesDir + '/async/lib/async.js'
84+
],
85+
aliases: [
86+
{from: rendrDir + '/client', to: 'rendr/client'},
87+
{from: rendrDir + '/shared', to: 'rendr/shared'}
88+
]
89+
},
90+
files: [{
91+
dest: 'public/mergedAssets.js',
92+
src: [
93+
'app/**/*.js',
94+
rendrDir + '/client/**/*.coffee',
95+
rendrDir + '/shared/**/*.coffee'
96+
]
97+
}]
98+
}
99+
}
100+
});
101+
102+
grunt.loadNpmTasks('grunt-contrib-stylus');
103+
grunt.loadNpmTasks('grunt-contrib-watch');
104+
grunt.loadNpmTasks('grunt-contrib-handlebars');
105+
grunt.loadNpmTasks('grunt-bg-shell');
106+
grunt.loadNpmTasks('grunt-rendr-stitch');
107+
108+
grunt.registerTask('compile', ['handlebars', 'rendr_stitch', 'stylus']);
109+
110+
// Run the server and watch for file changes
111+
grunt.registerTask('server', ['bgShell:runNode', 'compile', 'watch']);
112+
113+
// Default task(s).
114+
grunt.registerTask('default', ['compile']);
115+
};

app/app.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
var BaseApp = require('rendr/shared/app');
2+
3+
module.exports = BaseApp.extend({
4+
defaults: {
5+
loading: false
6+
},
7+
8+
// @client
9+
start: function() {
10+
// Show a loading indicator when the app is fetching.
11+
this.router.on('action:start', function() { this.set({loading: true}); }, this);
12+
this.router.on('action:end', function() { this.set({loading: false}); }, this);
13+
14+
// Call 'super'.
15+
BaseApp.prototype.start.call(this);
16+
}
17+
18+
});

app/collections/base.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
var RendrBase = require('rendr/shared/base/collection');
2+
3+
module.exports = RendrBase.extend({});

app/collections/posts.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
var Post = require('../models/post')
2+
, Base = require('./base');
3+
4+
module.exports = Base.extend({
5+
model: Post,
6+
url: function() {
7+
return '/posts';
8+
}
9+
});
10+
module.exports.id = 'Posts';

app/controllers/posts_controller.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
module.exports = {
2+
index: function(params, callback) {
3+
var spec = {
4+
collection: {collection: 'posts', params: params}
5+
};
6+
this.app.fetch(spec, function(err, result) {
7+
callback(err, 'posts_index_view', result);
8+
});
9+
},
10+
11+
add: function(params, callback) {
12+
callback(null, 'posts_add_view');
13+
},
14+
15+
show: function(params, callback) {
16+
var spec = {
17+
model: {model: 'post', params: params, ensureKeys: ['title']}
18+
};
19+
this.app.fetch(spec, function(err, result) {
20+
console.log(result, 2222);
21+
callback(err, 'posts_show_view', result);
22+
});
23+
},
24+
25+
edit: function(params, callback) {
26+
var spec = {
27+
model: {model: 'post', params: params, ensureKeys: ['title']}
28+
};
29+
this.app.fetch(spec, function(err, result) {
30+
callback(err, 'posts_show_view', result);
31+
});
32+
},
33+
34+
del: function(params, callback) {
35+
var spec = {
36+
model: {model: 'post', params: params, ensureKeys: ['title']}
37+
};
38+
this.app.fetch(spec, function(err, result) {
39+
callback(err, 'posts_del_view', result);
40+
});
41+
}
42+
};

app/models/base.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
var RendrBase = require('rendr/shared/base/model');
2+
3+
module.exports = RendrBase.extend({});

app/models/post.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
var Base = require('./base');
2+
3+
module.exports = Base.extend({
4+
url: '/posts/:id',
5+
idAttribute: 'id'
6+
});
7+
module.exports.id = 'Post';

app/router.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
var BaseClientRouter = require('rendr/client/router');
2+
3+
var Router = module.exports = function Router(options) {
4+
BaseClientRouter.call(this, options);
5+
};
6+
7+
Router.prototype.__proto__ = BaseClientRouter.prototype;
8+
9+
Router.prototype.postInitialize = function() {
10+
this.on('action:start', this.trackImpression, this);
11+
};
12+
13+
Router.prototype.trackImpression = function() {
14+
if (window._gaq) {
15+
_gaq.push(['_trackPageview']);
16+
}
17+
};

app/routes.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module.exports = function(match) {
2+
match('' , 'posts#index');
3+
match('posts' , 'posts#index');
4+
match('posts/edit' , 'posts#add');
5+
match('posts/edit/:id' , 'posts#edit');
6+
match('posts/del/:id' , 'posts#del');
7+
match('posts/:id' , 'posts#show');
8+
};

app/templates/__layout.hbs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!doctype html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset='utf-8'/>
6+
<title>Rendr Example Blog</title>
7+
8+
<link href="/styles.css" media="screen" rel="stylesheet" type="text/css" />
9+
</head>
10+
11+
<body class="">
12+
<div class="navbar navbar-inverse navbar-fixed-top">
13+
<div class="navbar-inner">
14+
<div class="container">
15+
<a class="brand" href="/">Rendr Example Blog</a>
16+
<div class="nav-collapse collapse">
17+
<ul class="nav">
18+
<li class="active"><a href="/">Home</a></li>
19+
</ul>
20+
</div>
21+
<div class="loading-indicator">Loading&hellip;</div>
22+
</div>
23+
</div>
24+
</div>
25+
26+
<section id=content class=container>
27+
{{{body}}}
28+
</section>
29+
30+
<script src="/mergedAssets.js"></script>
31+
<script>
32+
(function() {
33+
var App = window.App = new (require('app/app'))({{json appData}});
34+
App.bootstrapData({{json bootstrappedData}});
35+
App.start();
36+
})();
37+
</script>
38+
39+
</body>
40+
41+
</html>

app/templates/compiledTemplates.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
module.exports = function(Handlebars) {
2+
3+
var templates = {};
4+
5+
templates["posts_add_view"] = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
6+
this.compilerInfo = [2,'>= 1.0.0-rc.3'];
7+
helpers = helpers || Handlebars.helpers; data = data || {};
8+
9+
10+
11+
return "<form class=\"form-horizontal\">\n <legend>New Post</legend>\n <div class=\"control-group\">\n <label class=\"control-label\" for=\"title\">Email</label>\n <div class=\"controls\">\n <input type=\"text\" id=\"title\" placeholder=\"Title\">\n </div>\n </div>\n <div class=\"control-group\">\n <label class=\"control-label\" for=\"body\">Password</label>\n <div class=\"controls\">\n <textarea type=\"password\" id=\"body\" placeholder=\"Body\"></textarea>\n </div>\n </div>\n <div class=\"form-actions\">\n <button type=\"submit\" class=\"btn btn-primary\">Save post</button>\n <a href=\"/posts\" type=\"button\" class=\"btn\">Cancel</a>\n </div>\n</form>\n";
12+
});
13+
14+
templates["posts_del_view"] = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
15+
this.compilerInfo = [2,'>= 1.0.0-rc.3'];
16+
helpers = helpers || Handlebars.helpers; data = data || {};
17+
var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression;
18+
19+
20+
buffer += "<p>Sure to delete?</p>\n<div>\n<button class=\"btn btn-danger del\">Delete it!</button>\n<a href=\"/posts/";
21+
if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
22+
else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
23+
buffer += escapeExpression(stack1)
24+
+ "\" class=\"btn\">Cancel</a>\n</div>\n";
25+
return buffer;
26+
});
27+
28+
templates["posts_edit_view"] = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
29+
this.compilerInfo = [2,'>= 1.0.0-rc.3'];
30+
helpers = helpers || Handlebars.helpers; data = data || {};
31+
var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression;
32+
33+
34+
buffer += "<a class=\"btn\" href=\"/posts/edit\">Create a post</a>\n\n<br>\n<h3>Stats</h3>\n<div class=\"row-fluid\">\n <div class=\"span6\">\n <table class=\"table\">\n <tr>\n <th>Description</th>\n <td>";
35+
if (stack1 = helpers.description) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
36+
else { stack1 = depth0.description; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
37+
buffer += escapeExpression(stack1)
38+
+ "</td>\n </tr>\n <tr>\n <th>Language</th>\n <td>";
39+
if (stack1 = helpers.language) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
40+
else { stack1 = depth0.language; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
41+
buffer += escapeExpression(stack1)
42+
+ "</td>\n </tr>\n <tr>\n <th>Watchers</th>\n <td>";
43+
if (stack1 = helpers.watchers_count) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
44+
else { stack1 = depth0.watchers_count; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
45+
buffer += escapeExpression(stack1)
46+
+ "</td>\n </tr>\n <tr>\n <th>Forks</th>\n <td>";
47+
if (stack1 = helpers.forks_count) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
48+
else { stack1 = depth0.forks_count; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
49+
buffer += escapeExpression(stack1)
50+
+ "</td>\n </tr>\n <tr>\n <th>Open Issues</th>\n <td>";
51+
if (stack1 = helpers.open_issues_count) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
52+
else { stack1 = depth0.open_issues_count; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
53+
buffer += escapeExpression(stack1)
54+
+ "</td>\n </tr>\n </table>\n </div>\n</div>\n";
55+
return buffer;
56+
});
57+
58+
templates["posts_index_view"] = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
59+
this.compilerInfo = [2,'>= 1.0.0-rc.3'];
60+
helpers = helpers || Handlebars.helpers; data = data || {};
61+
var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, self=this;
62+
63+
function program1(depth0,data) {
64+
65+
var buffer = "", stack1;
66+
buffer += "\n <li>\n <a href=\"/posts/";
67+
if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
68+
else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
69+
buffer += escapeExpression(stack1)
70+
+ "\">";
71+
if (stack1 = helpers.title) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
72+
else { stack1 = depth0.title; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
73+
buffer += escapeExpression(stack1)
74+
+ "</a>\n </li>\n ";
75+
return buffer;
76+
}
77+
78+
buffer += "<h3>Posts</h3>\n\n<div class=\"well\">\n <ul>\n ";
79+
stack1 = helpers.each.call(depth0, depth0.models, {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
80+
if(stack1 || stack1 === 0) { buffer += stack1; }
81+
buffer += "\n </ul>\n</div>\n\n<a class=\"btn\" href=\"/posts/edit\">New post</a>\n";
82+
return buffer;
83+
});
84+
85+
templates["posts_show_view"] = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
86+
this.compilerInfo = [2,'>= 1.0.0-rc.3'];
87+
helpers = helpers || Handlebars.helpers; data = data || {};
88+
var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression;
89+
90+
91+
buffer += "<div class=\"well\">\n <h3>";
92+
if (stack1 = helpers.title) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
93+
else { stack1 = depth0.title; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
94+
buffer += escapeExpression(stack1)
95+
+ "</h3>\n <p>";
96+
if (stack1 = helpers.body) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
97+
else { stack1 = depth0.body; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
98+
buffer += escapeExpression(stack1)
99+
+ "</p>\n</div>\n<div class=\"well\">\n <a href=\"/posts\" class=\"btn btn-primary\">Back to posts</a>\n <a href=\"/posts/del/";
100+
if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
101+
else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
102+
buffer += escapeExpression(stack1)
103+
+ "\" class=\"btn btn-danger del\">Delete</a>\n</div>\n";
104+
return buffer;
105+
});
106+
107+
return templates;
108+
109+
};

0 commit comments

Comments
 (0)