Skip to content

Commit

Permalink
Added real-time search example.
Browse files Browse the repository at this point in the history
  • Loading branch information
cskr committed Sep 4, 2010
1 parent 8465e4e commit b6f0937
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 0 deletions.
35 changes: 35 additions & 0 deletions examples/realtime_search/app/controllers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
var gh = require('grasshopper'),
Item = require('./item').Item;

gh.get('/', function() {
this.render('search');
});

gh.get('/search', function() {
this.model['items'] = this.repo.search(this.params['tags']);
this.model['searchTags'] = this.params['tags'];
this.render('results');
});

gh.post('/watch', function() {
var self = this;
this.repo.watch(this.params['tags'], function(item) {
self.renderText(item.name());
});
});

gh.get('/items/add', function() {
this.model['item'] = new Item();
this.render('add');
});

gh.post('/items', function() {
var item = new Item().update(this.params['item']);
if(item.isValid()) {
this.repo.add(item);
this.redirect('/');
} else {
this.model['item'] = item;
this.render('add');
}
});
12 changes: 12 additions & 0 deletions examples/realtime_search/app/item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
var gh = require('grasshopper');

function Item() {
};

Item.prototype.validate = function() {
this.validateRequired('name');
this.validateRequired('tags');
this.validatePattern('tags', /[^\s,]/);
};

exports.Item = gh.initModel(Item, 'name', 'tags');
50 changes: 50 additions & 0 deletions examples/realtime_search/app/itemRepo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
var EventEmitter = require('events').EventEmitter,
sys = require('sys');

function ItemRepo() {
EventEmitter.call(this);
this.items = {};
}

sys.inherits(ItemRepo, EventEmitter);

ItemRepo.prototype.add = function(item) {
var self = this;

forEachTag(item.tags(), function(tag) {
if(self.items[tag]) {
self.items[tag].push(item);
} else {
self.items[tag] = [item];
}

self.emit(tag, item);
self.removeAllListeners(tag);
});
};

ItemRepo.prototype.search = function(tags) {
var items = [], self = this;
forEachTag(tags, function(tag) {
if(self.items[tag])
items = items.concat(self.items[tag]);
});
return items;
};

ItemRepo.prototype.watch = function(tags, cb) {
var self = this;
forEachTag(tags, function(tag) {
self.on(tag, cb);
});
};

function forEachTag(tagString, cb) {
tagString.split(',').forEach(function (tag) {
var trimmedTag = tag.trim();
if(trimmedTag.length > 0)
cb(tag.trim());
});
}

exports.ItemRepo = ItemRepo;
17 changes: 17 additions & 0 deletions examples/realtime_search/boot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
var gh = require('grasshopper'),
ItemRepo = require('./app/itemRepo').ItemRepo;

gh.configure({
viewsDir: './views',
staticsDir: './statics',
layout: 'layout',
locales: require('./locales').locales
});

gh.addToContext({
repo: new ItemRepo()
});

require('./app/controllers');

gh.serve(8080);
10 changes: 10 additions & 0 deletions examples/realtime_search/layout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<html>
<head>
<title>Real-time Search</title>
</head>
<body>
<div id="content">
<%= include(view) %>
</div>
</body>
</html>
7 changes: 7 additions & 0 deletions examples/realtime_search/locales.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
exports.locales = {
'en-us': {
'Item.name.required': 'Give a name for the item.',
'Item.tags.required': 'Specify atleast one tag for the item.',
'Item.tags.pattern': 'Tag specification is invalid.'
}
};
15 changes: 15 additions & 0 deletions examples/realtime_search/statics/js/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
function watch(tags) {
$.ajax({
url: '/watch',
data: {tags: tags},
type: 'POST',
dataType: 'text',
success: function(item, status) {
watch(tags);
if(item != '') {
$('#itemsList').prepend($('<li></li>').text(item));
}
}
});
}

11 changes: 11 additions & 0 deletions examples/realtime_search/views/add.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<h1>Add an Item</h1>
<form action="/items" method="post">
Name: <input name="item.name" value="<%= item.name() %>" />
<span style="color: red"><%= error(item, 'name', locale) %></span>
<p />
Tags: <input name="item.tags" value="<%= item.tags() %>" />
<span style="color: red"><%= error(item, 'tags', locale) %></span>
<p />
<input type="submit" value="Save" />
<a href="/">Back</a>
</form>
13 changes: 13 additions & 0 deletions examples/realtime_search/views/results.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<h1>Real-time Results for "<%= searchTags %>"</h1>
<ul id="itemsList">
<% items.forEach(function(item) { %>
<li><%= h(item.name()) %></li>
<% }); %>
</ul>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="js/script.js"></script>
<script type="text/javascript">
setTimeout(function() {
watch('<%= searchTags %>');
}, 0);
</script>
7 changes: 7 additions & 0 deletions examples/realtime_search/views/search.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<h1>Real-time Search</h1>
<form action="/search" method="get">
<input name="tags" />
<input type="submit" value="Search" />
<a href="/items/add">Add Item</a>
</form>

0 comments on commit b6f0937

Please sign in to comment.