Skip to content

Commit 562ef2d

Browse files
committed
Initial commit
0 parents  commit 562ef2d

File tree

6 files changed

+236
-0
lines changed

6 files changed

+236
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bower_components

README.markdown

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
A sample recipe search.
2+
3+
## Installing
4+
5+
You'll need [bower](http://bower.io/) to install the javascript dependencies.
6+
After you get it, just run
7+
8+
bower install
9+
10+
in the root directory.
11+
12+
You'll also need elasticsearch loaded up with recipes and accepting connections on
13+
localhost:9200 for this example.
14+
15+
When all those ducks are in a row, just open index.html in a browser.

bower.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "openrecipesearch-demo",
3+
"version": "0.0.0",
4+
"authors": [
5+
6+
],
7+
"license": "MIT",
8+
"ignore": [
9+
"**/.*",
10+
"node_modules",
11+
"bower_components",
12+
"test",
13+
"tests"
14+
],
15+
"dependencies": {
16+
"angular": "~1.2.15",
17+
"elasticsearch": "~2.1.0"
18+
}
19+
}

css/screen.css

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* Base styles */
2+
3+
body{
4+
font-family: "Arial";
5+
color: #444;
6+
font-size: 18px;
7+
line-height: 24px;
8+
}
9+
10+
p, li, h1, h2, h3, h4, h5, h6{
11+
margin-top: 24px;
12+
line-height: 24px;
13+
}
14+
15+
li+li{
16+
margin-top: 0px;
17+
}
18+
19+
.container{
20+
width: 728px;
21+
margin: 0px auto;
22+
}
23+
24+
/* Block styles */
25+
26+
header, section, footer{
27+
margin: 48px 0;
28+
}
29+

index.html

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset='utf-8'>
5+
<meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible'>
6+
<title>
7+
MyOpenRecipes: An openrecipe search
8+
</title>
9+
<link href="css/screen.css" media="screen" rel="stylesheet" type="text/css" />
10+
</head>
11+
<body class='index'>
12+
<div class='container'>
13+
<div ng-app='myOpenRecipes' ng-controller='recipeCtrl'>
14+
<header>
15+
<h1>OpenRecipe Search</h1>
16+
</header>
17+
<section class='searchField'>
18+
<form ng-submit='search()'>
19+
<input ng-model='searchTerm' type='text'>
20+
<input type='submit' value='Search for recipes'>
21+
</form>
22+
</section>
23+
<section class='results'>
24+
<div class='no-recipes' ng-hide='recipes.length'>No results</div>
25+
<article class='recipe' ng-cloak ng-repeat='recipe in recipes'>
26+
<h2>
27+
<a ng-href='{{recipe.url}}'>{{recipe.name}}</a>
28+
</h2>
29+
<ul>
30+
<li ng-repeat='ingredient in recipe.ingredients'>{{ ingredient }}</li>
31+
</ul>
32+
<p>
33+
{{recipe.description}}
34+
<a ng-href='{{recipe.url}}'>... more at {{recipe.source}}</a>
35+
</p>
36+
</article>
37+
<div class='load-more' ng-cloak ng-hide='allResults'>
38+
<a ng-click='loadMore()'>More...</a>
39+
</div>
40+
</section>
41+
<footer>
42+
Made By
43+
<a href='http://adambard.com/'>Handsome Web Developer Adam Bard,</a>
44+
powered by
45+
<a href='http://openrecip.es/'>OpenRecipes</a>
46+
</footer>
47+
</div>
48+
</div>
49+
<script src="bower_components/angular/angular.js" type="text/javascript"></script>
50+
<script src="bower_components/elasticsearch/elasticsearch.angular.js" type="text/javascript"></script>
51+
<script src="js/script.js" type="text/javascript"></script>
52+
</body>
53+
</html>

js/script.js

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/**
2+
* Create the module. Set it up to use html5 mode.
3+
*/
4+
window.MyOpenRecipes = angular.module('myOpenRecipes', ['elasticsearch'],
5+
['$locationProvider', function($locationProvider){
6+
$locationProvider.html5Mode(true);
7+
}]
8+
);
9+
10+
/**
11+
* Create a service to power calls to Elasticsearch. We only need to
12+
* use the _search endpoint.
13+
*/
14+
MyOpenRecipes.factory('recipeService',
15+
['$q', 'esFactory', '$location', function($q, elasticsearch, $location){
16+
var client = elasticsearch({
17+
host: $location.host() + ":9200"
18+
});
19+
20+
/**
21+
* Given a term and an offset, load another round of 10 recipes.
22+
*
23+
* Returns a promise.
24+
*/
25+
var search = function(term, offset){
26+
var deferred = $q.defer();
27+
var query = {
28+
"match": {
29+
"_all": term
30+
}
31+
};
32+
33+
client.search({
34+
"index": 'recipes',
35+
"type": 'recipe',
36+
"body": {
37+
"size": 10,
38+
"from": (offset || 0) * 10,
39+
"query": query
40+
}
41+
}).then(function(result) {
42+
var ii = 0, hits_in, hits_out = [];
43+
hits_in = (result.hits || {}).hits || [];
44+
for(;ii < hits_in.length; ii++){
45+
hits_out.push(hits_in[ii]._source);
46+
}
47+
deferred.resolve(hits_out);
48+
}, deferred.reject);
49+
50+
return deferred.promise;
51+
};
52+
53+
54+
return {
55+
"search": search
56+
};
57+
}]
58+
);
59+
60+
/**
61+
* Create a controller to interact with the UI.
62+
*/
63+
MyOpenRecipes.controller('recipeCtrl',
64+
['recipeService', '$scope', '$location', function(recipes, $scope, $location){
65+
// Provide some nice initial choices
66+
var initChoices = [
67+
"rendang",
68+
"nasi goreng",
69+
"pad thai",
70+
"pizza",
71+
"lasagne",
72+
"ice cream",
73+
"schnitzel",
74+
"hummous"
75+
];
76+
var idx = Math.floor(Math.random() * initChoices.length);
77+
78+
// Initialize the scope defaults.
79+
$scope.recipes = []; // An array of recipe results to display
80+
$scope.page = 0; // A counter to keep track of our current page
81+
$scope.allResults = false; // Whether or not all results have been found.
82+
83+
// And, a random search term to start if none was present on page load.
84+
$scope.searchTerm = $location.search().q || initChoices[idx];
85+
86+
/**
87+
* A fresh search. Reset the scope variables to their defaults, set
88+
* the q query parameter, and load more results.
89+
*/
90+
$scope.search = function(){
91+
$scope.page = 0;
92+
$scope.recipes = [];
93+
$scope.allResults = false;
94+
$location.search({'q': $scope.searchTerm});
95+
$scope.loadMore();
96+
};
97+
98+
/**
99+
* Load the next page of results, incrementing the page counter.
100+
* When query is finished, push results onto $scope.recipes and decide
101+
* whether all results have been returned (i.e. were 10 results returned?)
102+
*/
103+
$scope.loadMore = function(){
104+
recipes.search($scope.searchTerm, $scope.page++).then(function(results){
105+
if(results.length !== 10){
106+
$scope.allResults = true;
107+
}
108+
109+
var ii = 0;
110+
for(;ii < results.length; ii++){
111+
$scope.recipes.push(results[ii]);
112+
}
113+
});
114+
};
115+
116+
// Load results on first run
117+
$scope.loadMore();
118+
}]
119+
);

0 commit comments

Comments
 (0)