New feed viewer

This commit is contained in:
unknown 2015-07-27 13:49:21 +01:00
parent 43d658da71
commit bcab492f95
18 changed files with 6936 additions and 2665 deletions

3
html/ejs/list.ejs Normal file
View File

@ -0,0 +1,3 @@
<% list.forEach(function (item) { %>
<li id="<%=item.name%>"><%=item.name%></li>
<% }) %>

12
html/ejs/runner.ejs Normal file
View File

@ -0,0 +1,12 @@
<h1><%= d.title %></h1>
<% d.items.forEach(function (item) { %>
<div class='row entry'>
<h4><a href='<%=item.url%>'><%=item.title %></a></h4>
<div class='u-full-width content' style='overflow:hidden;'><%-item.description-%></div>
<div class='info' style='font-size:75%;color:#bbbbbb;'>
<span class='author' ><%=item.author%></span>
<span class='date' ><%=item.date%></span>
</div>
</div>
<% }) %>

11
html/ejs/test.ejs Normal file
View File

@ -0,0 +1,11 @@
<h1><%= d.title %></h1>
<% d.items.forEach(function (item) { %>
<div class='row entry'>
<h4><a href='<%=item.url%>'><%=item.title %></a></h4>
<div class='u-full-width content' style='overflow:hidden;'><%=item.description%></div>
<div class='info' style='font-size:75%;color:#bbbbbb;'>
<span class='author' ><%=item.author%></span>
<span class='date' ><%=item.date%></span>
</div>
</div>
<% }) %>

69
html/feeds.html Normal file
View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html>
<head>
<title>
Feedmaster
</title>
<meta charset="UTF-8">
<meta name="viewport" content="user-scalable=no,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"/>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css">
<!-- CSS
-->
<link rel="stylesheet" href="css/normalize-min.css">
<link rel="stylesheet" href="css/skeleton-min.css">
<style>
.info {
border-bottom: 1px solid #bbbbbb;
padding-bottom:
}
.entry {
padding-bottom: 16px;
}
img {
max-width: 960px;
}
</style>
<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#9f00a7">
<meta name="msapplication-TileImage" content="/mstile-144x144.png">
<meta name="theme-color" content="#ffffff">
</head>
<body>
<div>Last update: <span id="lastupdate">x</span>
<button id="refresh">Refresh</button>
</div>
<ul id="list"></ul>
<div id='feedcontent' class="container">
</div>
<!-- <script type="text/javascript" src="js/zepto.js"></script>
<script type="text/javascript" src="js/moment.js"></script>
<script type="text/javascript" src="js/ejs.js"></script>-->
<script type="text/javascript" src="js/output.min.js"></script>
<script type="text/javascript" src="js/app.prod.js"></script>
</body>
</html>

126
html/js/app.js Normal file
View File

@ -0,0 +1,126 @@
var APP = {
refreshStep: 0,
preUrl: '/html/',
_storage: {
lastupdated: null,
feeds: {}
},
feeds: ['paleo','lifestyle'],
lastUpdated: null,
init: function() {
$('#refresh').on('click', $.proxy(this.refresh, this));
console.log('app starting...');
this.doLoad();
this.getLastUpdateDate();
console.log('Last updated: ' + this.lastUpdated);
},
getLastUpdateDate: function() {
var formatted, dt;
// this.lastUpdated = localStorage.getItem('lastUpdated') || null;
if (this.lastUpdated == null)
$('#lastupdate').empty().append('Never');
else
{
dt = new Date(this.lastUpdated);
formatted = moment(dt).startOf('minute').fromNow();
console.log(formatted);
$('#lastupdate').empty().append(formatted);
}
},
refresh: function() {
this.refreshStep = 0;
console.log('refresh');
console.log(this);
console.log('get ' + this.feeds[this.refreshStep]);
$('#lastupdate').empty().append('Refreshing...');
this.doRefresh();
},
doRefresh: function() {
var self = this;
if (this.refreshStep < this.feeds.length) {
var feedUrl = this.preUrl + this.feeds[this.refreshStep] + '.json';
$('#lastupdate').empty().append('Refreshing: ' + this.feeds[this.refreshStep]);
$.getJSON(feedUrl, function(data) {
console.log(self);
self.doUpdate(data);
});
} else {
console.log('Done');
this.doSave();
}
},
doUpdate: function(data) {
console.log(this);
console.log(data);
this._storage.feeds[this.feeds[this.refreshStep]] = data;
console.log(this._storage);
this.refreshStep++;
this.doRefresh();
},
doSave: function() {
console.log('Saving...');
this.lastUpdated = new Date();
this._storage.lastupdated = this.lastUpdated;
localStorage.setItem('lastUpdated',this.lastUpdated);
localStorage.setItem('_storage',JSON.stringify(this._storage));
this.getLastUpdateDate();
},
doLoad: function() {
$('#lastupdate').empty().append('Loading...');
this._storage = JSON.parse(localStorage.getItem('_storage'));
this.lastUpdated = this._storage.lastupdated;
this.showList();
},
showList: function() {
var output,d={},list = [];
for(var key in this._storage.feeds)
{
console.log(key);
list.push({name:key});
}
d.list = list;
var output = new EJS({url: 'ejs/list.ejs'}).render(d);
$('#list').empty().append(output);
for(var key in this._storage.feeds)
{
$('#' + key).on('click', $.proxy(this.showFeed, this, key));
}
},
showFeed: function(opt) {
var output, d;
console.log('show feed ' + opt);
$('#feedcontent').empty();
d = {d:this._storage.feeds[opt]};
var output = new EJS({url: 'ejs/test.ejs'}).render(d);
$('#feedcontent').append(output);
}
};
Zepto(function($) {
console.log('Start app');
if (typeof(Storage) !== "undefined") {
APP.init();
} else {
// Sorry! No Web Storage support..
alert('No local storage');
}
});

129
html/js/app.prod.js Normal file
View File

@ -0,0 +1,129 @@
var APP = {
refreshStep: 0,
preUrl: '/',
_storage: {
lastupdated: null,
feeds: {}
},
feeds: ['paleo', 'lifestyle'],
lastUpdated: null,
init: function() {
$('#refresh').on('click', $.proxy(this.refresh, this));
console.log('app starting...');
this.doLoad();
this.getLastUpdateDate();
console.log('Last updated: ' + this.lastUpdated);
},
getLastUpdateDate: function() {
var formatted, dt;
// this.lastUpdated = localStorage.getItem('lastUpdated') || null;
if (this.lastUpdated == null)
$('#lastupdate').empty().append('Never');
else {
dt = new Date(this.lastUpdated);
formatted = moment(dt).startOf('minute').fromNow();
console.log(formatted);
$('#lastupdate').empty().append(formatted);
}
},
refresh: function() {
this.refreshStep = 0;
console.log('refresh');
console.log(this);
console.log('get ' + this.feeds[this.refreshStep]);
$('#lastupdate').empty().append('Refreshing...');
this.doRefresh();
},
doRefresh: function() {
var self = this;
if (this.refreshStep < this.feeds.length) {
var feedUrl = this.preUrl + this.feeds[this.refreshStep] + '.json';
$('#lastupdate').empty().append('Refreshing: ' + this.feeds[this.refreshStep]);
$.getJSON(feedUrl, function(data) {
console.log(self);
self.doUpdate(data);
});
} else {
console.log('Done');
this.doSave();
}
},
doUpdate: function(data) {
console.log(this);
console.log(data);
this._storage.feeds[this.feeds[this.refreshStep]] = data;
console.log(this._storage);
this.refreshStep++;
this.doRefresh();
},
doSave: function() {
console.log('Saving...');
this.lastUpdated = new Date();
this._storage.lastupdated = this.lastUpdated;
localStorage.setItem('lastUpdated', this.lastUpdated);
localStorage.setItem('_storage', JSON.stringify(this._storage));
this.getLastUpdateDate();
},
doLoad: function() {
$('#lastupdate').empty().append('Loading...');
this._storage = JSON.parse(localStorage.getItem('_storage'));
this.lastUpdated = this._storage.lastupdated;
this.showList();
},
showList: function() {
var output, d = {},
list = [];
for (var key in this._storage.feeds) {
console.log(key);
list.push({
name: key
});
}
d.list = list;
var output = new EJS({
url: 'ejs/list.ejs'
}).render(d);
$('#list').empty().append(output);
for (var key in this._storage.feeds) {
$('#' + key).on('click', $.proxy(this.showFeed, this, key));
}
},
showFeed: function(opt) {
var output, d;
console.log('show feed ' + opt);
$('#feedcontent').empty();
d = {
d: this._storage.feeds[opt]
};
var output = new EJS({
url: 'ejs/test.ejs'
}).render(d);
$('#feedcontent').append(output);
}
};
Zepto(function($) {
console.log('Start app');
if (typeof(Storage) !== "undefined") {
APP.init();
} else {
// Sorry! No Web Storage support..
alert('No local storage');
}
});

505
html/js/ejs.js Normal file
View File

@ -0,0 +1,505 @@
(function(){
var rsplit = function(string, regex) {
var result = regex.exec(string),retArr = new Array(), first_idx, last_idx, first_bit;
while (result != null)
{
first_idx = result.index; last_idx = regex.lastIndex;
if ((first_idx) != 0)
{
first_bit = string.substring(0,first_idx);
retArr.push(string.substring(0,first_idx));
string = string.slice(first_idx);
}
retArr.push(result[0]);
string = string.slice(result[0].length);
result = regex.exec(string);
}
if (! string == '')
{
retArr.push(string);
}
return retArr;
},
chop = function(string){
return string.substr(0, string.length - 1);
},
extend = function(d, s){
for(var n in s){
if(s.hasOwnProperty(n)) d[n] = s[n]
}
}
EJS = function( options ){
options = typeof options == "string" ? {view: options} : options
this.set_options(options);
if(options.precompiled){
this.template = {};
this.template.process = options.precompiled;
EJS.update(this.name, this);
return;
}
if(options.element)
{
if(typeof options.element == 'string'){
var name = options.element
options.element = document.getElementById( options.element )
if(options.element == null) throw name+'does not exist!'
}
if(options.element.value){
this.text = options.element.value
}else{
this.text = options.element.innerHTML
}
this.name = options.element.id
this.type = '['
}else if(options.url){
options.url = EJS.endExt(options.url, this.extMatch);
this.name = this.name ? this.name : options.url;
var url = options.url
//options.view = options.absolute_url || options.view || options.;
var template = EJS.get(this.name /*url*/, this.cache);
if (template) return template;
if (template == EJS.INVALID_PATH) return null;
try{
this.text = EJS.request( url+(this.cache ? '' : '?'+Math.random() ));
}catch(e){}
if(this.text == null){
throw( {type: 'EJS', message: 'There is no template at '+url} );
}
//this.name = url;
}
var template = new EJS.Compiler(this.text, this.type);
template.compile(options, this.name);
EJS.update(this.name, this);
this.template = template;
};
/* @Prototype*/
EJS.prototype = {
/**
* Renders an object with extra view helpers attached to the view.
* @param {Object} object data to be rendered
* @param {Object} extra_helpers an object with additonal view helpers
* @return {String} returns the result of the string
*/
render : function(object, extra_helpers){
object = object || {};
this._extra_helpers = extra_helpers;
var v = new EJS.Helpers(object, extra_helpers || {});
return this.template.process.call(object, object,v);
},
update : function(element, options){
if(typeof element == 'string'){
element = document.getElementById(element)
}
if(options == null){
_template = this;
return function(object){
EJS.prototype.update.call(_template, element, object)
}
}
if(typeof options == 'string'){
params = {}
params.url = options
_template = this;
params.onComplete = function(request){
var object = eval( request.responseText )
EJS.prototype.update.call(_template, element, object)
}
EJS.ajax_request(params)
}else
{
element.innerHTML = this.render(options)
}
},
out : function(){
return this.template.out;
},
/**
* Sets options on this view to be rendered with.
* @param {Object} options
*/
set_options : function(options){
this.type = options.type || EJS.type;
this.cache = options.cache != null ? options.cache : EJS.cache;
this.text = options.text || null;
this.name = options.name || null;
this.ext = options.ext || EJS.ext;
this.extMatch = new RegExp(this.ext.replace(/\./, '\.'));
}
};
EJS.endExt = function(path, match){
if(!path) return null;
match.lastIndex = 0
return path+ (match.test(path) ? '' : this.ext )
}
/* @Static*/
EJS.Scanner = function(source, left, right) {
extend(this,
{left_delimiter: left +'%',
right_delimiter: '%'+right,
double_left: left+'%%',
double_right: '%%'+right,
left_equal: left+'%=',
left_comment: left+'%#'})
this.SplitRegexp = left=='[' ? /(\[%%)|(%%\])|(\[%=)|(\[%#)|(\[%)|(%\]\n)|(%\])|(\n)/ : new RegExp('('+this.double_left+')|(%%'+this.double_right+')|('+this.left_equal+')|('+this.left_comment+')|('+this.left_delimiter+')|('+this.right_delimiter+'\n)|('+this.right_delimiter+')|(\n)') ;
this.source = source;
this.stag = null;
this.lines = 0;
};
EJS.Scanner.to_text = function(input){
if(input == null || input === undefined)
return '';
if(input instanceof Date)
return input.toDateString();
if(input.toString)
return input.toString();
return '';
};
EJS.Scanner.prototype = {
scan: function(block) {
scanline = this.scanline;
regex = this.SplitRegexp;
if (! this.source == '')
{
var source_split = rsplit(this.source, /\n/);
for(var i=0; i<source_split.length; i++) {
var item = source_split[i];
this.scanline(item, regex, block);
}
}
},
scanline: function(line, regex, block) {
this.lines++;
var line_split = rsplit(line, regex);
for(var i=0; i<line_split.length; i++) {
var token = line_split[i];
if (token != null) {
try{
block(token, this);
}catch(e){
throw {type: 'EJS.Scanner', line: this.lines};
}
}
}
}
};
EJS.Buffer = function(pre_cmd, post_cmd) {
this.line = new Array();
this.script = "";
this.pre_cmd = pre_cmd;
this.post_cmd = post_cmd;
for (var i=0; i<this.pre_cmd.length; i++)
{
this.push(pre_cmd[i]);
}
};
EJS.Buffer.prototype = {
push: function(cmd) {
this.line.push(cmd);
},
cr: function() {
this.script = this.script + this.line.join('; ');
this.line = new Array();
this.script = this.script + "\n";
},
close: function() {
if (this.line.length > 0)
{
for (var i=0; i<this.post_cmd.length; i++){
this.push(pre_cmd[i]);
}
this.script = this.script + this.line.join('; ');
line = null;
}
}
};
EJS.Compiler = function(source, left) {
this.pre_cmd = ['var ___ViewO = [];'];
this.post_cmd = new Array();
this.source = ' ';
if (source != null)
{
if (typeof source == 'string')
{
source = source.replace(/\r\n/g, "\n");
source = source.replace(/\r/g, "\n");
this.source = source;
}else if (source.innerHTML){
this.source = source.innerHTML;
}
if (typeof this.source != 'string'){
this.source = "";
}
}
left = left || '<';
var right = '>';
switch(left) {
case '[':
right = ']';
break;
case '<':
break;
default:
throw left+' is not a supported deliminator';
break;
}
this.scanner = new EJS.Scanner(this.source, left, right);
this.out = '';
};
EJS.Compiler.prototype = {
compile: function(options, name) {
options = options || {};
this.out = '';
var put_cmd = "___ViewO.push(";
var insert_cmd = put_cmd;
var buff = new EJS.Buffer(this.pre_cmd, this.post_cmd);
var content = '';
var clean = function(content)
{
content = content.replace(/\\/g, '\\\\');
content = content.replace(/\n/g, '\\n');
content = content.replace(/"/g, '\\"');
return content;
};
this.scanner.scan(function(token, scanner) {
if (scanner.stag == null)
{
switch(token) {
case '\n':
content = content + "\n";
buff.push(put_cmd + '"' + clean(content) + '");');
buff.cr();
content = '';
break;
case scanner.left_delimiter:
case scanner.left_equal:
case scanner.left_comment:
scanner.stag = token;
if (content.length > 0)
{
buff.push(put_cmd + '"' + clean(content) + '")');
}
content = '';
break;
case scanner.double_left:
content = content + scanner.left_delimiter;
break;
default:
content = content + token;
break;
}
}
else {
switch(token) {
case scanner.right_delimiter:
switch(scanner.stag) {
case scanner.left_delimiter:
if (content[content.length - 1] == '\n')
{
content = chop(content);
buff.push(content);
buff.cr();
}
else {
buff.push(content);
}
break;
case scanner.left_equal:
buff.push(insert_cmd + "(EJS.Scanner.to_text(" + content + ")))");
break;
}
scanner.stag = null;
content = '';
break;
case scanner.double_right:
content = content + scanner.right_delimiter;
break;
default:
content = content + token;
break;
}
}
});
if (content.length > 0)
{
// Chould be content.dump in Ruby
buff.push(put_cmd + '"' + clean(content) + '")');
}
buff.close();
this.out = buff.script + ";";
var to_be_evaled = '/*'+name+'*/this.process = function(_CONTEXT,_VIEW) { try { with(_VIEW) { with (_CONTEXT) {'+this.out+" return ___ViewO.join('');}}}catch(e){e.lineNumber=null;throw e;}};";
try{
eval(to_be_evaled);
}catch(e){
if(typeof JSLINT != 'undefined'){
JSLINT(this.out);
for(var i = 0; i < JSLINT.errors.length; i++){
var error = JSLINT.errors[i];
if(error.reason != "Unnecessary semicolon."){
error.line++;
var e = new Error();
e.lineNumber = error.line;
e.message = error.reason;
if(options.view)
e.fileName = options.view;
throw e;
}
}
}else{
throw e;
}
}
}
};
//type, cache, folder
/**
* Sets default options for all views
* @param {Object} options Set view with the following options
* <table class="options">
<tbody><tr><th>Option</th><th>Default</th><th>Description</th></tr>
<tr>
<td>type</td>
<td>'<'</td>
<td>type of magic tags. Options are '&lt;' or '['
</td>
</tr>
<tr>
<td>cache</td>
<td>true in production mode, false in other modes</td>
<td>true to cache template.
</td>
</tr>
</tbody></table>
*
*/
EJS.config = function(options){
EJS.cache = options.cache != null ? options.cache : EJS.cache;
EJS.type = options.type != null ? options.type : EJS.type;
EJS.ext = options.ext != null ? options.ext : EJS.ext;
var templates_directory = EJS.templates_directory || {}; //nice and private container
EJS.templates_directory = templates_directory;
EJS.get = function(path, cache){
if(cache == false) return null;
if(templates_directory[path]) return templates_directory[path];
return null;
};
EJS.update = function(path, template) {
if(path == null) return;
templates_directory[path] = template ;
};
EJS.INVALID_PATH = -1;
};
EJS.config( {cache: true, type: '<', ext: '.ejs' } );
/**
* @constructor
* By adding functions to EJS.Helpers.prototype, those functions will be available in the
* views.
* @init Creates a view helper. This function is called internally. You should never call it.
* @param {Object} data The data passed to the view. Helpers have access to it through this._data
*/
EJS.Helpers = function(data, extras){
this._data = data;
this._extras = extras;
extend(this, extras );
};
/* @prototype*/
EJS.Helpers.prototype = {
/**
* Renders a new view. If data is passed in, uses that to render the view.
* @param {Object} options standard options passed to a new view.
* @param {optional:Object} data
* @return {String}
*/
view: function(options, data, helpers){
if(!helpers) helpers = this._extras
if(!data) data = this._data;
return new EJS(options).render(data, helpers);
},
/**
* For a given value, tries to create a human representation.
* @param {Object} input the value being converted.
* @param {Object} null_text what text should be present if input == null or undefined, defaults to ''
* @return {String}
*/
to_text: function(input, null_text) {
if(input == null || input === undefined) return null_text || '';
if(input instanceof Date) return input.toDateString();
if(input.toString) return input.toString().replace(/\n/g, '<br />').replace(/''/g, "'");
return '';
}
};
EJS.newRequest = function(){
var factories = [function() { return new ActiveXObject("Msxml2.XMLHTTP"); },function() { return new XMLHttpRequest(); },function() { return new ActiveXObject("Microsoft.XMLHTTP"); }];
for(var i = 0; i < factories.length; i++) {
try {
var request = factories[i]();
if (request != null) return request;
}
catch(e) { continue;}
}
}
EJS.request = function(path){
var request = new EJS.newRequest()
request.open("GET", path, false);
try{request.send(null);}
catch(e){return null;}
if ( request.status == 404 || request.status == 2 ||(request.status == 0 && request.responseText == '') ) return null;
return request.responseText
}
EJS.ajax_request = function(params){
params.method = ( params.method ? params.method : 'GET')
var request = new EJS.newRequest();
request.onreadystatechange = function(){
if(request.readyState == 4){
if(request.status == 200){
params.onComplete(request)
}else
{
params.onComplete(request)
}
}
}
request.open(params.method, params.url)
request.send(null)
}
})();

File diff suppressed because one or more lines are too long

3195
html/js/moment.js Normal file

File diff suppressed because it is too large Load Diff

7
html/js/moment.min.js vendored Normal file

File diff suppressed because one or more lines are too long

3
html/js/output.min.js vendored Normal file

File diff suppressed because one or more lines are too long

200
html/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)
}

1587
html/js/zepto.js Normal file

File diff suppressed because it is too large Load Diff

2
html/js/zepto.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -9,28 +9,107 @@
<!-- CSS
-->
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/skeleton.css">
<link rel="stylesheet" href="css/normalize-min.css">
<link rel="stylesheet" href="css/skeleton-min.css">
<style>
.info {border-bottom:1px solid #bbbbbb;}
.info {border-bottom:1px solid #bbbbbb; padding-bottom:}
.entry {padding-bottom:16px;}
img {max-width:960px;}
</style>
<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#9f00a7">
<meta name="msapplication-TileImage" content="/mstile-144x144.png">
<meta name="theme-color" content="#ffffff">
</head>
<body>
<div class="container">
<h1>Paleo</h1>
<div class='row entry'>
<h4><a href='http://ultimatepaleoguide.com/recipe/lemon-and-thyme-roasted-chicken-breast/'>Lemon and Thyme Roasted Chicken Breast</a></h4>
<div class='u-full-width content' style='overflow:hidden;'>This is a simple and delicious recipe for a weeknight dinner. You could even marinate the chicken ahead and just pop it in the oven for dinner. The lemon adds a tang that is mouth-watering and marries well with the thyme. Lemon and Thyme Roasted Chicken Breast CourseDinner CuisinePaleo, Primal Servings 2 Cook Time 35minutes [&#8230;]</div> <div class='info' style='font-size:75%;color:#bbbbbb;'>
<span class='author' >Rachel Chiu</span>
<span class='date' >2015-07-27T09:00:05.000Z</span>
</div>
</div>
<div class='row entry'>
<h4><a href='http://feedproxy.google.com/~r/PaleoPlan/~3/_bCdUmpXE3I/'>Hopper Crunch A Paleo Snack Food Review</a></h4>
<div class='u-full-width content'><p>I just ate 40 crickets. Its true! I just enjoyed a few handfuls of Hopper Crunch, the new and innovative Paleo granola that incorporates 40 crickets as cricket flour in each ½ cup serving. Its kind of weird to think I just chowed down 40 recently creepy crawly arthropods, but why shouldnt bugs be on &#8230; <a href="http://www.paleoplan.com/2015/07-20/hopper-crunch-a-paleo-snack-food-review/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a rel="nofollow" href="http://www.paleoplan.com/2015/07-20/hopper-crunch-a-paleo-snack-food-review/">Hopper Crunch &#8211; A Paleo Snack Food Review</a> appeared first on <a rel="nofollow" href="http://www.paleoplan.com">Paleo Plan</a>.</p></div> <div class='info' style='font-size:75%;'>
<span class='author' >Sally Barden Johnson</span>
<span class='date' >2015-07-20T15:06:39.000Z</span>
<h4><a href='http://thepaleodiet.com/african-vegetables-a-welcome-addition-to-paleo-and-healthy-living/'>African Vegetables: A Welcome Addition to Paleo and Healthy Living</a></h4>
<div class='u-full-width content' style='overflow:hidden;'><p>A great aspect about Paleo is that it transcends geographic and physical boundaries. Indeed it is a global healthy living lifestyle. In recent years, many are gaining awareness about the tremendous benefits that come from eating Paleo. On the other hand, for many in Sub-Saharan Africa, the Paleo way of life may be quite familiar. [&#8230;]</p>
<p>The post <a rel="nofollow" href="http://thepaleodiet.com/african-vegetables-a-welcome-addition-to-paleo-and-healthy-living/">African Vegetables: A Welcome Addition to Paleo and Healthy Living</a> appeared first on <a rel="nofollow" href="http://thepaleodiet.com">The Paleo Diet™</a>.</p></div> <div class='info' style='font-size:75%;color:#bbbbbb;'>
<span class='author' >OH Okoye</span>
<span class='date' >2015-07-27T08:01:45.000Z</span>
</div>
</div>
<div class='row entry'>
<h4><a href='http://paleoleap.com/sausage-grilled-vegetables/'>Sausage With Grilled Vegetables</a></h4>
<div class='u-full-width content' style='overflow:hidden;'><p>Cant decide which vegetables you want for dinner tonight? Have them all at once! This recipe is the barbecue equivalent...</p>
<p>The post <a rel="nofollow" href="http://paleoleap.com/sausage-grilled-vegetables/">Sausage With Grilled Vegetables</a> appeared first on <a rel="nofollow" href="http://paleoleap.com">Paleo Leap | Paleo diet Recipes &amp; Tips</a>.</p></div> <div class='info' style='font-size:75%;color:#bbbbbb;'>
<span class='author' >Paleo Leaper</span>
<span class='date' >2015-07-26T17:36:51.000Z</span>
</div>
</div>
<div class='row entry'>
<h4><a href='http://paleoleap.com/infographic-sugar-reality-check/'>Infographic: Sugar Reality Check</a></h4>
<div class='u-full-width content' style='overflow:hidden;'><p>Can&#8217;t view the infographic? Click here for an alternate version.</p>
<p>The post <a rel="nofollow" href="http://paleoleap.com/infographic-sugar-reality-check/">Infographic: Sugar Reality Check</a> appeared first on <a rel="nofollow" href="http://paleoleap.com">Paleo Leap | Paleo diet Recipes &amp; Tips</a>.</p></div> <div class='info' style='font-size:75%;color:#bbbbbb;'>
<span class='author' >Paleo Leaper</span>
<span class='date' >2015-07-25T19:14:42.000Z</span>
</div>
</div>
<div class='row entry'>
<h4><a href='http://paleoleap.com/whats-happening-its-personal/'>Whats Happening: Its Personal</a></h4>
<div class='u-full-width content' style='overflow:hidden;'><p>Personal experience isnt a substitution for scientific research; its a compliment to it. Science can tell us what works in...</p>
<p>The post <a rel="nofollow" href="http://paleoleap.com/whats-happening-its-personal/">Whats Happening: Its Personal</a> appeared first on <a rel="nofollow" href="http://paleoleap.com">Paleo Leap | Paleo diet Recipes &amp; Tips</a>.</p></div> <div class='info' style='font-size:75%;color:#bbbbbb;'>
<span class='author' >Paleo Leaper</span>
<span class='date' >2015-07-25T17:20:47.000Z</span>
</div>
</div>
<div class='row entry'>
<h4><a href='http://paleoleap.com/orange-cranberry-relish/'>Orange And Cranberry Relish</a></h4>
<div class='u-full-width content' style='overflow:hidden;'><p>Cranberry relish is typically a condiment that appears around Thanksgiving, but its just as delicious in the summertime a...</p>
<p>The post <a rel="nofollow" href="http://paleoleap.com/orange-cranberry-relish/">Orange And Cranberry Relish</a> appeared first on <a rel="nofollow" href="http://paleoleap.com">Paleo Leap | Paleo diet Recipes &amp; Tips</a>.</p></div> <div class='info' style='font-size:75%;color:#bbbbbb;'>
<span class='author' >Paleo Leaper</span>
<span class='date' >2015-07-24T16:35:31.000Z</span>
</div>
</div>
<div class='row entry'>
<h4><a href='http://elanaspantry.com/strawberry-lemonade/'>Strawberry Lemonade</a></h4>
<div class='u-full-width content' style='overflow:hidden;'><p>This refreshing sugar-free Strawberry Lemonade is a favorite around my house on a hot summer day. I&#8217;ve been making homemade lemonade for the boys since they were wee little ones. In order to cut back on the amount of unnecessary sugar (including natural sweeteners) that my family consumes, I&#8217;ve been sweetening my homemade lemonade with<a class="more-link" href="http://elanaspantry.com/strawberry-lemonade/">Read More &#8594;</a></p>
<p>The post <a rel="nofollow" href="http://elanaspantry.com/strawberry-lemonade/">Strawberry Lemonade</a> appeared first on <a rel="nofollow" href="http://elanaspantry.com">Elana&#039;s Pantry</a>.</p></div> <div class='info' style='font-size:75%;color:#bbbbbb;'>
<span class='author' >Elana Amsterdam</span>
<span class='date' >2015-07-24T16:14:41.000Z</span>
</div>
</div>
<div class='row entry'>
<h4><a href='http://paleomg.com/fashion-fridays-engagement-photos/'>Fashion Fridays + Engagement Photos</a></h4>
<div class='u-full-width content' style='overflow:hidden;'><img width="150" height="150" src="http://media.paleomg.com/2015/07/0041-150x150.jpg" class="attachment-thumbnail wp-post-image" alt="Fashion Fridays + Engagement Photos" title="Fashion Fridays + Engagement Photos" style="float:right;" />Happy happy Friday, you lovely soul! I&#8217;m just over here shopping for swimsuits, gearing up for our annual trip to Lake Powell. Ok ok, and for our wedding&#8230;even... <a href="http://paleomg.com/fashion-fridays-engagement-photos/">Read More &#187;</a></div> <div class='info' style='font-size:75%;color:#bbbbbb;'>
<span class='author' >juli</span>
<span class='date' >2015-07-24T14:24:26.000Z</span>
</div>
</div>
</div>
</body>

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@ feeds.simple_test_feed = {
"description": "Combined Lifestyle Feed",
'site_url': 'http://pipes.silvrtree.co.uk/lifestyle.xml'
},
"plugins" : ['filter_today_only' ],
"plugins" : ['filter_3_days' ],
"sources" : [
{