Skip to content

Commit 06d7f06

Browse files
committed
Chrome specific changes to allow for cloud types
1 parent 72f6d15 commit 06d7f06

File tree

4 files changed

+253
-3
lines changed

4 files changed

+253
-3
lines changed

app/app/index.html

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
<body>
1212
<section class="word-cloud-app" ng-controller="WordCloudCtrl">
1313
<header class="header">
14-
<h1 title="Generate wordclouds for any language and any Unicode charset, with automatic language detection">word clouds <small hidden>beta</small></h1>
14+
<h1 title="Generate wordclouds for any language and any Unicode charset, with automatic language detection">{{wordClouds[0].
15+
cloudType}} <small hidden>beta</small></h1>
1516
<form id="word-cloud-form" ng-submit="addWordCloud()">
1617
<input class="new-word-cloud" placeholder="Paste your text here..." ng-model="newWordCloud" autofocus>
1718
</form>

app/app/scripts/controllers/word-cloud-controller.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99
WordCloudApp.controller('WordCloudCtrl', function WordCloudCtrl($scope, $location, $filter, wordCloudStorage, $rootScope, $timeout) {
1010
var wordClouds = $scope.wordClouds = [];
11+
$scope.cloudType = 'page load';
1112

1213
// If there is saved data in storage, use it.
1314
// https://developer.chrome.com/apps/app_codelab5_data
@@ -89,19 +90,22 @@ WordCloudApp.controller('WordCloudCtrl', function WordCloudCtrl($scope, $locatio
8990
cloudToSave.title = cloudToSave.orthography.substring(0, titleLength) + '...';
9091
}
9192

93+
94+
95+
9296
while (wordClouds.length > 0) {
9397
wordClouds.pop();
9498
}
9599
$timeout(function() {
96100
wordClouds.unshift(cloudToSave);
101+
97102
}, 500);
98103
cloudToSave.unsaved = true;
99104
cloudToSave.save();
100105

101106
$scope.newWordCloud = '';
102107
$scope.remainingCount++;
103108
};
104-
105109
$rootScope.editingCloudInList = function(wordCloud) {
106110
$scope.editedWordCloud = wordCloud;
107111
};

app/app/scripts/services/word-cloud-storage.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ WordCloudApp.factory('wordCloudStorage', function() {
5151
authUrl: 'https://localhost:6984/_session',
5252
password: 'testtest'
5353
}).then(function() {
54-
window.db.fetchCollection('_design/clouds/_view/clouds?descending=true&limit=10').then(function(someclouds) {
54+
window.db.fetchCollection('_design/clouds/_view/clouds?descending=true&limit=2').then(function(someclouds) {
5555
console.log(someclouds);
5656
for (var cloudIndex = 0; cloudIndex < someclouds.length; cloudIndex++) {
5757
someclouds[cloudIndex].caseInsensitive = false;

webserver.js

+245
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
#!/usr/bin/env node
2+
3+
var util = require('util'),
4+
http = require('http'),
5+
fs = require('fs'),
6+
url = require('url'),
7+
events = require('events');
8+
9+
var DEFAULT_PORT = 8000;
10+
11+
function main(argv) {
12+
new HttpServer({
13+
'GET': createServlet(StaticServlet),
14+
'HEAD': createServlet(StaticServlet)
15+
}).start(Number(argv[2]) || DEFAULT_PORT);
16+
}
17+
18+
function escapeHtml(value) {
19+
return value.toString().
20+
replace('<', '&lt;').
21+
replace('>', '&gt;').
22+
replace('"', '&quot;');
23+
}
24+
25+
function createServlet(Class) {
26+
var servlet = new Class();
27+
return servlet.handleRequest.bind(servlet);
28+
}
29+
30+
/**
31+
* An Http server implementation that uses a map of methods to decide
32+
* action routing.
33+
*
34+
* @param {Object} Map of method => Handler function
35+
*/
36+
function HttpServer(handlers) {
37+
this.handlers = handlers;
38+
this.server = http.createServer(this.handleRequest_.bind(this));
39+
}
40+
41+
HttpServer.prototype.start = function(port) {
42+
this.port = port;
43+
this.server.listen(port);
44+
util.puts('Http Server running at http://localhost:' + port + '/');
45+
};
46+
47+
HttpServer.prototype.parseUrl_ = function(urlString) {
48+
var parsed = url.parse(urlString);
49+
parsed.pathname = url.resolve('/', parsed.pathname);
50+
return url.parse(url.format(parsed), true);
51+
};
52+
53+
HttpServer.prototype.handleRequest_ = function(req, res) {
54+
var logEntry = req.method + ' ' + req.url;
55+
if (req.headers['user-agent']) {
56+
logEntry += ' ' + req.headers['user-agent'];
57+
}
58+
util.puts(logEntry);
59+
req.url = this.parseUrl_(req.url);
60+
var handler = this.handlers[req.method];
61+
if (!handler) {
62+
res.writeHead(501);
63+
res.end();
64+
} else {
65+
handler.call(this, req, res);
66+
}
67+
};
68+
69+
/**
70+
* Handles static content.
71+
*/
72+
function StaticServlet() {}
73+
74+
StaticServlet.MimeMap = {
75+
'txt': 'text/plain',
76+
'html': 'text/html',
77+
'css': 'text/css',
78+
'xml': 'application/xml',
79+
'json': 'application/json',
80+
'js': 'application/javascript',
81+
'jpg': 'image/jpeg',
82+
'jpeg': 'image/jpeg',
83+
'gif': 'image/gif',
84+
'png': 'image/png',
85+
  'svg': 'image/svg+xml'
86+
};
87+
88+
StaticServlet.prototype.handleRequest = function(req, res) {
89+
var self = this;
90+
var path = ('./' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(match, hex){
91+
return String.fromCharCode(parseInt(hex, 16));
92+
});
93+
var parts = path.split('/');
94+
if (parts[parts.length-1].charAt(0) === '.')
95+
return self.sendForbidden_(req, res, path);
96+
fs.stat(path, function(err, stat) {
97+
if (err)
98+
return self.sendMissing_(req, res, path);
99+
if (stat.isDirectory())
100+
return self.sendDirectory_(req, res, path);
101+
return self.sendFile_(req, res, path);
102+
});
103+
}
104+
105+
StaticServlet.prototype.sendError_ = function(req, res, error) {
106+
res.writeHead(500, {
107+
'Content-Type': 'text/html'
108+
});
109+
res.write('<!doctype html>\n');
110+
res.write('<title>Internal Server Error</title>\n');
111+
res.write('<h1>Internal Server Error</h1>');
112+
res.write('<pre>' + escapeHtml(util.inspect(error)) + '</pre>');
113+
util.puts('500 Internal Server Error');
114+
util.puts(util.inspect(error));
115+
};
116+
117+
StaticServlet.prototype.sendMissing_ = function(req, res, path) {
118+
path = path.substring(1);
119+
res.writeHead(404, {
120+
'Content-Type': 'text/html'
121+
});
122+
res.write('<!doctype html>\n');
123+
res.write('<title>404 Not Found</title>\n');
124+
res.write('<h1>Not Found</h1>');
125+
res.write(
126+
'<p>The requested URL ' +
127+
escapeHtml(path) +
128+
' was not found on this server.</p>'
129+
);
130+
res.end();
131+
util.puts('404 Not Found: ' + path);
132+
};
133+
134+
StaticServlet.prototype.sendForbidden_ = function(req, res, path) {
135+
path = path.substring(1);
136+
res.writeHead(403, {
137+
'Content-Type': 'text/html'
138+
});
139+
res.write('<!doctype html>\n');
140+
res.write('<title>403 Forbidden</title>\n');
141+
res.write('<h1>Forbidden</h1>');
142+
res.write(
143+
'<p>You do not have permission to access ' +
144+
escapeHtml(path) + ' on this server.</p>'
145+
);
146+
res.end();
147+
util.puts('403 Forbidden: ' + path);
148+
};
149+
150+
StaticServlet.prototype.sendRedirect_ = function(req, res, redirectUrl) {
151+
res.writeHead(301, {
152+
'Content-Type': 'text/html',
153+
'Location': redirectUrl
154+
});
155+
res.write('<!doctype html>\n');
156+
res.write('<title>301 Moved Permanently</title>\n');
157+
res.write('<h1>Moved Permanently</h1>');
158+
res.write(
159+
'<p>The document has moved <a href="' +
160+
redirectUrl +
161+
'">here</a>.</p>'
162+
);
163+
res.end();
164+
util.puts('301 Moved Permanently: ' + redirectUrl);
165+
};
166+
167+
StaticServlet.prototype.sendFile_ = function(req, res, path) {
168+
var self = this;
169+
var file = fs.createReadStream(path);
170+
res.writeHead(200, {
171+
'Content-Type': StaticServlet.
172+
MimeMap[path.split('.').pop()] || 'text/plain'
173+
});
174+
if (req.method === 'HEAD') {
175+
res.end();
176+
} else {
177+
file.on('data', res.write.bind(res));
178+
file.on('close', function() {
179+
res.end();
180+
});
181+
file.on('error', function(error) {
182+
self.sendError_(req, res, error);
183+
});
184+
}
185+
};
186+
187+
StaticServlet.prototype.sendDirectory_ = function(req, res, path) {
188+
var self = this;
189+
if (path.match(/[^\/]$/)) {
190+
req.url.pathname += '/';
191+
var redirectUrl = url.format(url.parse(url.format(req.url)));
192+
return self.sendRedirect_(req, res, redirectUrl);
193+
}
194+
fs.readdir(path, function(err, files) {
195+
if (err)
196+
return self.sendError_(req, res, error);
197+
198+
if (!files.length)
199+
return self.writeDirectoryIndex_(req, res, path, []);
200+
201+
var remaining = files.length;
202+
files.forEach(function(fileName, index) {
203+
fs.stat(path + '/' + fileName, function(err, stat) {
204+
if (err)
205+
return self.sendError_(req, res, err);
206+
if (stat.isDirectory()) {
207+
files[index] = fileName + '/';
208+
}
209+
if (!(--remaining))
210+
return self.writeDirectoryIndex_(req, res, path, files);
211+
});
212+
});
213+
});
214+
};
215+
216+
StaticServlet.prototype.writeDirectoryIndex_ = function(req, res, path, files) {
217+
path = path.substring(1);
218+
res.writeHead(200, {
219+
'Content-Type': 'text/html'
220+
});
221+
if (req.method === 'HEAD') {
222+
res.end();
223+
return;
224+
}
225+
res.write('<!doctype html>\n');
226+
res.write('<title>' + escapeHtml(path) + '</title>\n');
227+
res.write('<style>\n');
228+
res.write(' ol { list-style-type: none; font-size: 1.2em; }\n');
229+
res.write('</style>\n');
230+
res.write('<h1>Directory: ' + escapeHtml(path) + '</h1>');
231+
res.write('<ol>');
232+
files.forEach(function(fileName) {
233+
if (fileName.charAt(0) !== '.') {
234+
res.write('<li><a href="' +
235+
escapeHtml(fileName) + '">' +
236+
escapeHtml(fileName) + '</a></li>');
237+
}
238+
});
239+
res.write('</ol>');
240+
res.end();
241+
};
242+
243+
// Must be last,
244+
main(process.argv);
245+

0 commit comments

Comments
 (0)