initial checkin

This commit is contained in:
s2
2013-04-06 00:30:43 +02:00
commit e6e0d9e081
21 changed files with 22994 additions and 0 deletions

1109
app/bootstrap/css/bootstrap-responsive.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

6158
app/bootstrap/css/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load Diff

9
app/bootstrap/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

2276
app/bootstrap/js/bootstrap.js vendored Normal file

File diff suppressed because it is too large Load Diff

6
app/bootstrap/js/bootstrap.min.js vendored Normal file

File diff suppressed because one or more lines are too long

8
app/css/custom.css Normal file
View File

@@ -0,0 +1,8 @@
body { /* background-color:gray; */
margin-top: 40px;
}
.word-button {
width: 200px;
margin: 20px;
}

36
app/index.html Normal file
View File

@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>Similar Words</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="stylesheet" type="text/css" href="bootstrap/css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="bootstrap/css/bootstrap-responsive.css" />
<link rel="stylesheet" type="text/css" href="css/custom.css" />
<script type="text/javascript" charset="utf-8" src="js/jquery-1.9.1.js"></script>
<script type="text/javascript" charset="utf-8" src="js/moment.js"></script>
<script type="text/javascript" charset="utf-8" src="js/routie.js"></script>
<script type="text/javascript" charset="utf-8" src="js/ejs.js"></script>
<script type="text/javascript" charset="utf-8" src="bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" charset="utf-8" src="js/config.js"></script>
<script type="text/javascript" charset="utf-8" src="js/index.js"></script>
</head>
<body>
<div id="main" class=container>
<div class="hero-unit" style="text-align: center;">
<h1>Similar Words!</h1>
<hr />
<p>
<a class="btn btn-primary btn-large disabled start" style="opacity: 0.25;"> Loading... </a>
</p>
</div>
</div>
</body>
</html>

2
app/js/config.js Normal file
View File

@@ -0,0 +1,2 @@
var sw = {};
sw.apiPrefix = './';

2
app/js/config.prod.js Normal file
View File

@@ -0,0 +1,2 @@
var sw = {};
sw.apiPrefix = '/';

1777
app/js/ejs.js Normal file

File diff suppressed because it is too large Load Diff

123
app/js/index.js Normal file
View File

@@ -0,0 +1,123 @@
if (typeof(sw) == 'undefined') {
var sw = {};
sw.apiPrefix = '/';
}
(function($) {
//helper functions
var pulse = function pulse(elem, duration, easing, props_to, props_from, until) {
elem.animate(props_to, duration, easing, function() {
if (until() == false) {
pulse(elem, duration, easing, props_from, props_to, until);
}
});
};
var shuffle = function(obj) {
return obj.sort( function() { return 0.5 - Math.random(); } );
};
var getKey = function(obj) {
var word = [];
for(var k in obj) word.push(k);
return word[0];
};
var selectWordsForGame = function() {
//select a random word from the list
var words = sw.words[Math.round(Math.random() * sw.words.length)];
var word = getKey(words);
var similar = words[word];
//i really should include _
var filtered = [];
for(var i=0; i<similar.length; i++) {
if(similar[i] != word) {
filtered.push(similar[i]);
}
}
filtered = shuffle(filtered);
filtered = filtered.slice(0, 3);
filtered.push(word);
filtered = shuffle(filtered);
sw.currentWord = word;
return {word: word, similar: filtered};
};
var startGame = function() {
$("#main").empty().html('views/index.ejs', selectWordsForGame());
};
//start app
var w = $.ajax({
url: sw.apiPrefix + "words.json",
dataType: 'json'
});
w.done(function(words) {
var start = $('.start');
start.removeClass('disabled');
start.html(' Start ');
start.animate({
opacity : 1
}, 1000, 'linear');
sw.words = words.words;
});
//events
$(document).on('click', '.start', function() {
startGame();
});
$(document).on('click', '.word-button', function(ev, el) {
el = $(ev.currentTarget);
if(sw.currentWord == el.html()) {
el.addClass('btn-success');
} else {
el.addClass('btn-danger');
}
setTimeout(function() {
$('.word-button[data-word="' + sw.currentWord + '"]').addClass('btn-success');
setTimeout(function() {
startGame();
}, 1000);
}, 1000);
});
//globals
sw.words = [];
sw.currentWord;
})(jQuery);
//utils
(function() {
window.Utils = {};
Utils.ellipsis = function(text, maxLength){
if(typeof maxLength === 'undefined'){
maxLength = 9000; //a large number
}
if (text.length <= maxLength)
return text;
var xMaxFit = maxLength - 1;
var xTruncateAt = text.lastIndexOf(' ', xMaxFit);
if (xTruncateAt == -1 || xTruncateAt < maxLength / 2)
xTruncateAt = xMaxFit;
return text.substr(0, xTruncateAt) + "…";
};
})();

9597
app/js/jquery-1.9.1.js vendored Normal file

File diff suppressed because it is too large Load Diff

1400
app/js/moment.js Normal file

File diff suppressed because it is too large Load Diff

202
app/js/routie.js Normal file
View File

@@ -0,0 +1,202 @@
/*!
* routie - a tiny hash router
* v0.3.0
* https://github.com/jgallen23/routie
* copyright JGA 2012
* MIT License
*/
(function(w) {
var routes = [];
var map = {};
var Route = function(path, name) {
this.name = name;
this.path = path;
this.keys = [];
this.fns = [];
this.params = {};
this.regex = pathToRegexp(this.path, this.keys, false, false);
};
Route.prototype.addHandler = function(fn) {
this.fns.push(fn);
//check against current hash
var hash = getHash();
checkRoute(hash, this);
};
Route.prototype.removeHandler = function(fn) {
for (var i = 0, c = this.fns.length; i < c; i++) {
var f = this.fns[i];
if (fn == f) {
this.fns.splice(i, 1);
return;
}
}
};
Route.prototype.run = function(params) {
for (var i = 0, c = this.fns.length; i < c; i++) {
this.fns[i].apply(this, params);
}
};
Route.prototype.match = function(path, params){
var m = this.regex.exec(path);
if (!m) return false;
for (var i = 1, len = m.length; i < len; ++i) {
var key = this.keys[i - 1];
var val = ('string' == typeof m[i]) ? decodeURIComponent(m[i]) : m[i];
if (key) {
this.params[key.name] = val;
}
params.push(val);
}
return true;
};
Route.prototype.toURL = function(params) {
var path = this.path;
for (var param in params) {
path = path.replace('/:'+param, '/'+params[param]);
}
path = path.replace(/\/:.*\?/g, '/').replace(/\?/g, '');
if (path.indexOf(':') != -1) {
throw new Error('missing parameters for url: '+path);
}
return path;
};
var pathToRegexp = function(path, keys, sensitive, strict) {
if (path instanceof RegExp) return path;
if (path instanceof Array) path = '(' + path.join('|') + ')';
path = path
.concat(strict ? '' : '/?')
.replace(/\/\(/g, '(?:/')
.replace(/\+/g, '__plus__')
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){
keys.push({ name: key, optional: !! optional });
slash = slash || '';
return '' + (optional ? '' : slash) + '(?:' + (optional ? slash : '') + (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')' + (optional || '');
})
.replace(/([\/.])/g, '\\$1')
.replace(/__plus__/g, '(.+)')
.replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
};
var addHandler = function(path, fn) {
var s = path.split(' ');
var name = (s.length == 2) ? s[0] : null;
path = (s.length == 2) ? s[1] : s[0];
if (!map[path]) {
map[path] = new Route(path, name);
routes.push(map[path]);
}
map[path].addHandler(fn);
};
var routie = function(path, fn) {
if (typeof fn == 'function') {
addHandler(path, fn);
} else if (typeof path == 'object') {
for (var p in path) {
addHandler(p, path[p]);
}
} else if (typeof fn === 'undefined') {
routie.navigate(path);
}
};
routie.lookup = function(name, obj) {
for (var i = 0, c = routes.length; i < c; i++) {
var route = routes[i];
if (route.name == name) {
return route.toURL(obj);
}
}
};
routie.remove = function(path, fn) {
var route = map[path];
if (!route)
return;
route.removeHandler(fn);
};
routie.removeAll = function() {
map = {};
routes = [];
};
routie.navigate = function(path, options) {
options = options || {};
var silent = options.silent || false;
if (silent) {
removeListener();
}
setTimeout(function() {
window.location.hash = path;
if (silent) {
setTimeout(function() {
addListener();
}, 1);
}
}, 1);
};
var getHash = function() {
return window.location.hash.substring(1);
};
var checkRoute = function(hash, route) {
var params = [];
if (route.match(hash, params)) {
route.run(params);
return true;
}
return false;
};
var hashChanged = routie.reload = function() {
var hash = getHash();
for (var i = 0, c = routes.length; i < c; i++) {
var route = routes[i];
if (checkRoute(hash, route))
return;
}
};
var addListener = function() {
if (w.addEventListener) {
w.addEventListener('hashchange', hashChanged);
} else {
w.attachEvent('onhashchange', hashChanged);
}
};
var removeListener = function() {
if (w.removeEventListener) {
w.removeEventListener('hashchange', hashChanged);
} else {
w.detachEvent('onhashchange', hashChanged);
}
};
addListener();
w.routie = routie;
})(window);

200
app/js/view.js Normal file
View File

@@ -0,0 +1,200 @@
EJS.Helpers.prototype.date_tag = function(name, value , html_options) {
if(! (value instanceof Date))
value = new Date()
var month_names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var years = [], months = [], days =[];
var year = value.getFullYear();
var month = value.getMonth();
var day = value.getDate();
for(var y = year - 15; y < year+15 ; y++)
{
years.push({value: y, text: y})
}
for(var m = 0; m < 12; m++)
{
months.push({value: (m), text: month_names[m]})
}
for(var d = 0; d < 31; d++)
{
days.push({value: (d+1), text: (d+1)})
}
var year_select = this.select_tag(name+'[year]', year, years, {id: name+'[year]'} )
var month_select = this.select_tag(name+'[month]', month, months, {id: name+'[month]'})
var day_select = this.select_tag(name+'[day]', day, days, {id: name+'[day]'})
return year_select+month_select+day_select;
}
EJS.Helpers.prototype.form_tag = function(action, html_options) {
html_options = html_options || {};
html_options.action = action
if(html_options.multipart == true) {
html_options.method = 'post';
html_options.enctype = 'multipart/form-data';
}
return this.start_tag_for('form', html_options)
}
EJS.Helpers.prototype.form_tag_end = function() { return this.tag_end('form'); }
EJS.Helpers.prototype.hidden_field_tag = function(name, value, html_options) {
return this.input_field_tag(name, value, 'hidden', html_options);
}
EJS.Helpers.prototype.input_field_tag = function(name, value , inputType, html_options) {
html_options = html_options || {};
html_options.id = html_options.id || name;
html_options.value = value || '';
html_options.type = inputType || 'text';
html_options.name = name;
return this.single_tag_for('input', html_options)
}
EJS.Helpers.prototype.is_current_page = function(url) {
return (window.location.href == url || window.location.pathname == url ? true : false);
}
EJS.Helpers.prototype.link_to = function(name, url, html_options) {
if(!name) var name = 'null';
if(!html_options) var html_options = {}
if(html_options.confirm){
html_options.onclick =
" var ret_confirm = confirm(\""+html_options.confirm+"\"); if(!ret_confirm){ return false;} "
html_options.confirm = null;
}
html_options.href=url
return this.start_tag_for('a', html_options)+name+ this.tag_end('a');
}
EJS.Helpers.prototype.submit_link_to = function(name, url, html_options){
if(!name) var name = 'null';
if(!html_options) var html_options = {}
html_options.onclick = html_options.onclick || '' ;
if(html_options.confirm){
html_options.onclick =
" var ret_confirm = confirm(\""+html_options.confirm+"\"); if(!ret_confirm){ return false;} "
html_options.confirm = null;
}
html_options.value = name;
html_options.type = 'submit'
html_options.onclick=html_options.onclick+
(url ? this.url_for(url) : '')+'return false;';
//html_options.href='#'+(options ? Routes.url_for(options) : '')
return this.start_tag_for('input', html_options)
}
EJS.Helpers.prototype.link_to_if = function(condition, name, url, html_options, post, block) {
return this.link_to_unless((condition == false), name, url, html_options, post, block);
}
EJS.Helpers.prototype.link_to_unless = function(condition, name, url, html_options, block) {
html_options = html_options || {};
if(condition) {
if(block && typeof block == 'function') {
return block(name, url, html_options, block);
} else {
return name;
}
} else
return this.link_to(name, url, html_options);
}
EJS.Helpers.prototype.link_to_unless_current = function(name, url, html_options, block) {
html_options = html_options || {};
return this.link_to_unless(this.is_current_page(url), name, url, html_options, block)
}
EJS.Helpers.prototype.password_field_tag = function(name, value, html_options) { return this.input_field_tag(name, value, 'password', html_options); }
EJS.Helpers.prototype.select_tag = function(name, value, choices, html_options) {
html_options = html_options || {};
html_options.id = html_options.id || name;
html_options.value = value;
html_options.name = name;
var txt = ''
txt += this.start_tag_for('select', html_options)
for(var i = 0; i < choices.length; i++)
{
var choice = choices[i];
var optionOptions = {value: choice.value}
if(choice.value == value)
optionOptions.selected ='selected'
txt += this.start_tag_for('option', optionOptions )+choice.text+this.tag_end('option')
}
txt += this.tag_end('select');
return txt;
}
EJS.Helpers.prototype.single_tag_for = function(tag, html_options) { return this.tag(tag, html_options, '/>');}
EJS.Helpers.prototype.start_tag_for = function(tag, html_options) { return this.tag(tag, html_options); }
EJS.Helpers.prototype.submit_tag = function(name, html_options) {
html_options = html_options || {};
//html_options.name = html_options.id || 'commit';
html_options.type = html_options.type || 'submit';
html_options.value = name || 'Submit';
return this.single_tag_for('input', html_options);
}
EJS.Helpers.prototype.tag = function(tag, html_options, end) {
if(!end) var end = '>'
var txt = ' '
for(var attr in html_options) {
if(html_options[attr] != null)
var value = html_options[attr].toString();
else
var value=''
if(attr == "Class") // special case because "class" is a reserved word in IE
attr = "class";
if( value.indexOf("'") != -1 )
txt += attr+'=\"'+value+'\" '
else
txt += attr+"='"+value+"' "
}
return '<'+tag+txt+end;
}
EJS.Helpers.prototype.tag_end = function(tag) { return '</'+tag+'>'; }
EJS.Helpers.prototype.text_area_tag = function(name, value, html_options) {
html_options = html_options || {};
html_options.id = html_options.id || name;
html_options.name = html_options.name || name;
value = value || ''
if(html_options.size) {
html_options.cols = html_options.size.split('x')[0]
html_options.rows = html_options.size.split('x')[1];
delete html_options.size
}
html_options.cols = html_options.cols || 50;
html_options.rows = html_options.rows || 4;
return this.start_tag_for('textarea', html_options)+value+this.tag_end('textarea')
}
EJS.Helpers.prototype.text_tag = EJS.Helpers.prototype.text_area_tag
EJS.Helpers.prototype.text_field_tag = function(name, value, html_options) { return this.input_field_tag(name, value, 'text', html_options); }
EJS.Helpers.prototype.url_for = function(url) {
return 'window.location="'+url+'";'
}
EJS.Helpers.prototype.img_tag = function(image_location, alt, options){
options = options || {};
options.src = image_location
options.alt = alt
return this.single_tag_for('img', options)
}

11
app/views/index.ejs Normal file
View File

@@ -0,0 +1,11 @@
<div class="hero-unit" style="text-align: center;">
<h1><%= word %></h1>
<hr />
<p>
<% for(var i=0; i<similar.length; i++) { %>
<a href="javascript://" data-word="<%= similar[i] %>" class="word-button btn btn-primary btn-large"><%= similar[i] %></a>
<% } %>
</p>
</div>

1
app/words.json Normal file

File diff suppressed because one or more lines are too long

68
createwordlist.js Normal file
View File

@@ -0,0 +1,68 @@
fs = require('fs');
fs.readFile('/usr/share/dict/ngerman', 'utf8', function(err, data) {
if (err) {
return console.log(err);
}
var lines = data.split('\n');
console.log(lines.length + ' words in dictionary');
var word = '';
var words = [];
for(var i=0; i<lines.length; i++) {
word = lines[i];
if (word.length > 6 && word.length < 10) {
//console.log('using ' + word);
words.push(word);
};
}
console.log('using ' + words.length + ' words out of the dictionary');
var wildcardWord = function(word) {
var words = [];
for(var i=1; i<word.length; i++) {
words.push(word.substr(0, i) + '.' + word.substr(i + 1));
}
return words;
};
var matchingWordlist = [];
for(var w=0; w<words.length; w++) {
var word = words[w];
var wildcardedWords = wildcardWord(word);
var matches = [];
for(var i=0; i<wildcardedWords.length; i++) {
wildcardedWord = wildcardedWords[i];
for(var j=0; j<words.length; j++) {
//console.log('match ' + words[j] + ' with ' + wildcardedWord);
if(word.length == words[j].length && words[j].match(wildcardedWord) && word != words[j]) {
matches.push(words[j]);
//console.log(word + ' -> ' + words[j]);
}
}
}
//add to dictionary?
if(matches.length >= 4) {
console.log('using ' + word);
var mw = {};
mw[word] = matches;
matchingWordlist.push(mw);
}
if(w % 5000 == 0) {
console.log('intermediary results...');
console.log(matchingWordlist);
}
}
console.log('final result');
console.log(matchingWordlist);
process.exit(0);
});