Updated to the new version of keeper

This commit is contained in:
Martin Donnelly 2016-06-30 14:48:37 +01:00
parent 94db464463
commit e7c6b11bc4
51 changed files with 17786 additions and 0 deletions

32
.editorconfig Normal file
View File

@ -0,0 +1,32 @@
; http://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[*.txt]
insert_final_newline = false
trim_trailing_whitespace = false
[*.py]
indent_size = 4
[*.m]
indent_size = 4
[Makefile]
indent_style = tab
indent_size = 8
[*.{js,json}]
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false

46
.jscsrc Normal file
View File

@ -0,0 +1,46 @@
{
"disallowKeywords": ["with"],
"disallowKeywordsOnNewLine": ["else"],
"disallowMixedSpacesAndTabs": true,
"disallowMultipleVarDecl": "exceptUndefined",
"disallowNewlineBeforeBlockStatements": true,
"disallowQuotedKeysInObjects": true,
"disallowSpaceAfterObjectKeys": true,
"disallowSpaceAfterPrefixUnaryOperators": true,
"disallowSpacesInFunction": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInsideParentheses": true,
"disallowTrailingWhitespace": true,
"maximumLineLength": 120,
"requireCamelCaseOrUpperCaseIdentifiers": false,
"requireCapitalizedComments": true,
"requireCapitalizedConstructors": true,
"requireCurlyBraces": true,
"requireSpaceAfterKeywords": [
"if",
"else",
"for",
"while",
"do",
"switch",
"case",
"return",
"try",
"catch",
"typeof"
],
"requireSpaceAfterLineComment": true,
"requireSpaceAfterBinaryOperators": true,
"requireSpaceBeforeBinaryOperators": true,
"requireSpaceBeforeBlockStatements": true,
"requireSpaceBeforeObjectValues": true,
"requireSpacesInFunction": {
"beforeOpeningCurlyBrace": true
},
"requireTrailingComma": false,
"requireEarlyReturn": false,
"validateIndentation": 2,
"validateLineBreaks": "LF",
"validateQuoteMarks": "'"
}

123
app/css/gist.css Normal file
View File

@ -0,0 +1,123 @@
.code, .gist {
color: #000;
}
.code, .gist div {
padding: 0;
margin: 0;
}
.code, .gist .gist-file {
border: 1px solid #dedede; /* gray */
font-family: Monaco, "Courier New", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", monospace;
margin-bottom: 1em;
}
.code, .gist .gist-file .gist-meta {
overflow: hidden;
font-size: 85%;
padding: .5em;
color: #666;
background-color: #eaeaea;
}
.code, .gist .gist-file .gist-meta a {
color: #369;
}
.code, .gist .gist-file .gist-meta a:visited {
color: #737;
}
.code, .gist .gist-file .gist-data {
overflow: auto;
word-wrap: normal;
background-color: #f8f8ff;
border-bottom: 1px solid #ddd;
font-size: 100%;
}
.code, .gist .gist-file .gist-data pre {
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
background: transparent !important;
margin: 0 !important;
border: none !important;
padding: .25em .5em .5em .5em !important;
}
.code, .gist .gist-file .gist-data .gist-highlight {
background: transparent !important;
}
.code, .gist .gist-file .gist-data .gist-line-numbers {
background-color: #ececec;
color: #aaa;
border-right: 1px solid #ddd;
text-align: right;
}
.code, .gist .gist-file .gist-data .gist-line-numbers span {
clear: right;
display: block;
}
.gist-syntax { background: #ffffff; }
.gist-syntax .c { color: #999988; font-style: italic } /* Comment */
.gist-syntax .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.gist-syntax .k { color: #000000; font-weight: bold } /* Keyword */
.gist-syntax .o { color: #000000; font-weight: bold } /* Operator */
.gist-syntax .cm { color: #999988; font-style: italic } /* Comment.Multiline */
.gist-syntax .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
.gist-syntax .c1 { color: #999988; font-style: italic } /* Comment.Single */
.gist-syntax .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
.gist-syntax .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.gist-syntax .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
.gist-syntax .ge { color: #000000; font-style: italic } /* Generic.Emph */
.gist-syntax .gr { color: #aa0000 } /* Generic.Error */
.gist-syntax .gh { color: #999999 } /* Generic.Heading */
.gist-syntax .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.gist-syntax .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
.gist-syntax .go { color: #888888 } /* Generic.Output */
.gist-syntax .gp { color: #555555 } /* Generic.Prompt */
.gist-syntax .gs { font-weight: bold } /* Generic.Strong */
.gist-syntax .gu { color: #aaaaaa } /* Generic.Subheading */
.gist-syntax .gt { color: #aa0000 } /* Generic.Traceback */
.gist-syntax .kc { color: #000000; font-weight: bold } /* Keyword.Constant */
.gist-syntax .kd { color: #000000; font-weight: bold } /* Keyword.Declaration */
.gist-syntax .kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */
.gist-syntax .kr { color: #000000; font-weight: bold } /* Keyword.Reserved */
.gist-syntax .kt { color: #445588; font-weight: bold } /* Keyword.Type */
.gist-syntax .m { color: #009999 } /* Literal.Number */
.gist-syntax .s { color: #d14 } /* Literal.String */
.gist-syntax .na { color: #008080 } /* Name.Attribute */
.gist-syntax .nb { color: #0086B3 } /* Name.Builtin */
.gist-syntax .nc { color: #445588; font-weight: bold } /* Name.Class */
.gist-syntax .no { color: #008080 } /* Name.Constant */
.gist-syntax .ni { color: #800080 } /* Name.Entity */
.gist-syntax .ne { color: #990000; font-weight: bold } /* Name.Exception */
.gist-syntax .nf { color: #990000; font-weight: bold } /* Name.Function */
.gist-syntax .nn { color: #555555 } /* Name.Namespace */
.gist-syntax .nt { color: #000080 } /* Name.Tag */
.gist-syntax .nv { color: #008080 } /* Name.Variable */
.gist-syntax .ow { color: #000000; font-weight: bold } /* Operator.Word */
.gist-syntax .w { color: #bbbbbb } /* Text.Whitespace */
.gist-syntax .mf { color: #009999 } /* Literal.Number.Float */
.gist-syntax .mh { color: #009999 } /* Literal.Number.Hex */
.gist-syntax .mi { color: #009999 } /* Literal.Number.Integer */
.gist-syntax .mo { color: #009999 } /* Literal.Number.Oct */
.gist-syntax .sb { color: #d14 } /* Literal.String.Backtick */
.gist-syntax .sc { color: #d14 } /* Literal.String.Char */
.gist-syntax .sd { color: #d14 } /* Literal.String.Doc */
.gist-syntax .s2 { color: #d14 } /* Literal.String.Double */
.gist-syntax .se { color: #d14 } /* Literal.String.Escape */
.gist-syntax .sh { color: #d14 } /* Literal.String.Heredoc */
.gist-syntax .si { color: #d14 } /* Literal.String.Interpol */
.gist-syntax .sx { color: #d14 } /* Literal.String.Other */
.gist-syntax .sr { color: #009926 } /* Literal.String.Regex */
.gist-syntax .s1 { color: #d14 } /* Literal.String.Single */
.gist-syntax .ss { color: #990073 } /* Literal.String.Symbol */
.gist-syntax .bp { color: #999999 } /* Name.Builtin.Pseudo */
.gist-syntax .vc { color: #008080 } /* Name.Variable.Class */
.gist-syntax .vg { color: #008080 } /* Name.Variable.Global */
.gist-syntax .vi { color: #008080 } /* Name.Variable.Instance */
.gist-syntax .il { color: #009999 } /* Literal.Number.Integer.Long */

13673
app/css/read.css Normal file

File diff suppressed because it is too large Load Diff

2222
app/engadget.html Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 950 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

12
app/fav/browserconfig.xml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="/mstile-70x70.png"/>
<square150x150logo src="/mstile-150x150.png"/>
<square310x310logo src="/mstile-310x310.png"/>
<wide310x150logo src="/mstile-310x150.png"/>
<TileColor>#ffc40d</TileColor>
</tile>
</msapplication>
</browserconfig>

BIN
app/fav/favicon-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

BIN
app/fav/favicon-194x194.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
app/fav/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

BIN
app/fav/favicon-96x96.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 920 B

BIN
app/fav/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

41
app/fav/manifest.json Normal file
View File

@ -0,0 +1,41 @@
{
"name": "Keeper",
"icons": [
{
"src": "\/android-chrome-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": 0.75
},
{
"src": "\/android-chrome-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": 1
},
{
"src": "\/android-chrome-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": 1.5
},
{
"src": "\/android-chrome-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": 2
},
{
"src": "\/android-chrome-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": 3
},
{
"src": "\/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": 4
}
]
}

BIN
app/fav/mstile-144x144.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
app/fav/mstile-150x150.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
app/fav/mstile-310x150.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
app/fav/mstile-310x310.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
app/fav/mstile-70x70.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 912 B

View File

@ -0,0 +1,28 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata>
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M3897 4499 c-112 -17 -250 -74 -335 -139 -38 -29 -2117 -2106 -2159
-2157 -74 -89 -111 -197 -111 -322 0 -181 82 -329 236 -428 176 -113 417 -103
578 25 38 30 1467 1452 1587 1580 40 42 50 92 26 131 -30 49 -83 65 -132 39
-12 -6 -378 -367 -814 -802 -592 -592 -804 -798 -840 -816 -68 -34 -169 -39
-243 -11 -175 66 -249 289 -148 446 15 22 507 520 1095 1106 1147 1145 1094
1096 1233 1133 75 20 218 14 291 -12 292 -104 423 -428 288 -712 -29 -60 -129
-163 -1348 -1383 -1407 -1409 -1373 -1378 -1529 -1434 -90 -33 -128 -38 -262
-37 -93 1 -130 6 -192 26 -241 79 -417 264 -479 505 -20 80 -28 216 -15 288
10 63 38 155 47 161 5 3 9 12 9 20 0 9 21 48 46 87 36 57 267 293 1082 1109
569 570 1040 1044 1044 1053 29 50 10 113 -42 140 -31 16 -64 15 -97 -4 -10
-5 -489 -481 -1064 -1058 -679 -681 -1059 -1068 -1083 -1106 -39 -60 -106
-197 -106 -216 0 -6 -4 -19 -9 -29 -34 -66 -50 -280 -31 -399 107 -663 827
-997 1397 -648 68 42 253 222 1396 1364 725 724 1338 1343 1362 1376 48 67 83
140 111 230 29 93 26 297 -5 390 -45 134 -105 230 -199 317 -155 145 -382 217
-585 187z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
app/gfx/fm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

55
app/libs/microevent.js Normal file
View File

@ -0,0 +1,55 @@
/**
* MicroEvent - to make any js object an event emitter (server or browser)
*
* - pure javascript - server compatible, browser compatible
* - dont rely on the browser doms
* - super simple - you get it immediatly, no mistery, no magic involved
*
* - create a MicroEventDebug with goodies to debug
* - make it safer to use
*/
var MicroEvent = function(){};
MicroEvent.prototype = {
bind : function(event, fct){
this._events = this._events || {};
this._events[event] = this._events[event] || [];
this._events[event].push(fct);
},
unbind : function(event, fct){
this._events = this._events || {};
if( event in this._events === false ) return;
this._events[event].splice(this._events[event].indexOf(fct), 1);
},
trigger : function(event /* , args... */){
this._events = this._events || {};
if( event in this._events === false ) return;
for(var i = 0; i < this._events[event].length; i++){
this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
}
}
};
/**
* mixin will delegate all MicroEvent.js function in the destination object
*
* - require('MicroEvent').mixin(Foobar) will make Foobar able to use MicroEvent
*
* @param {Object} the object which will support MicroEvent
*/
MicroEvent.mixin = function(destObject){
var props = ['bind', 'unbind', 'trigger'];
for(var i = 0; i < props.length; i ++){
if( typeof destObject === 'function' ){
destObject.prototype[props[i]] = MicroEvent.prototype[props[i]];
}else{
destObject[props[i]] = MicroEvent.prototype[props[i]];
}
}
return destObject;
}
// export in common js
if( typeof module !== "undefined" && ('exports' in module)){
module.exports = MicroEvent;
}

4
app/partials/taglist.ejs Normal file
View File

@ -0,0 +1,4 @@
<li><a href="#?"><em>No tag</em></a></li>
<% for(var i=0; i<list.length; i++) {%>
<li><a href="#?<%= list[i] %>"><%= list[i] %></a></li>
<% } %>

36
app/partials/view.ejs Normal file
View File

@ -0,0 +1,36 @@
<div class="mui-container">
<div class="mui-panel">
<div class="mui--text-headline"><%= data.title %></div>
<div >
<span id='tags' class="mui--text-left">
<span id="visualTabs">
<span class="lnr lnr-tag"></span>
<% for(var i=0; i<data.tags.list.length; i++) {%>
<a class="mui--text-dark-secondary mui--text-button" href="#?<%=data.tags.list[i]%>"><%=data.tags.list[i]%></a>
<% } %>
<span class="lnr lnr-pencil" id="tageditmode"></span>
</span>
<span id="tagForm" style="display:none;">
<span class="mui-form--inline">
<span class="mui-textfield">
<input type="text" id="edittags" name="edittags" value="<%=data.tags.solid%>">
</span>
<button class="mui-btn" id="tagSave">Save</button>
</span>
</span>
</span>
<span id="othercontrols" class="mui--pull-right">
<span id="redo" class="mui--text-accent mui--text-button" style="cursor:pointer;">Redo <span class="lnr lnr-redo"></span></span>
<span class="mui--divider-left">&nbsp;<%= link_to('Link', data.url) %>&nbsp;<span class="lnr lnr-link"></span> </span>
</span>
</div>
</div>
</div>
<div class="mui-container">
<div class="mui-panel">
<%= data.reduced %>
</div>
</div>

109
app/pocket.html Normal file
View File

@ -0,0 +1,109 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="//cdn.linearicons.com/free/1.0.0/icon-font.min.css">
<link href="//cdn.muicss.com/mui-0.4.6/css/mui.min.css" rel="stylesheet" type="text/css" />
<!-- build:css -->
<!-- endbuild -->
<script src="libs/microevent.js"></script>
<script src="//cdn.muicss.com/mui-0.4.6/js/mui.min.js"></script>
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<!-- build:vendor -->
<script src="libs/ejs.js"></script>
<script src="libs/view.js"></script>
<!-- endbuild -->
<link rel="apple-touch-icon" sizes="57x57" href="fav/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="fav/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="fav/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="fav/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="fav/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="fav/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="fav/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="fav/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="fav/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="fav/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="fav/favicon-194x194.png" sizes="194x194">
<link rel="icon" type="image/png" href="fav/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="fav/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="fav/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="fav/manifest.json">
<link rel="mask-icon" href="fav/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#ffc40d">
<meta name="msapplication-TileImage" content="fav/mstile-144x144.png">
<meta name="theme-color" content="#ffc40d">
<title>Keeper Silvtree</title>
<style>
.item_content {
height: 100px;
/* border: 1px solid grey;*/
min-height: 100px;
overflow: hidden;
}
.item_content a.title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #313131;
}
.item_content div.body, .item_content div.site, .item_content div.tags {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #313131;
}
.item_content div.site {
font-size: 90%;
color: silver;
}
.item_content div.tags {
color:blue;
}
.mui-panel {
margin-bottom: 4px !important;
}
</style>
</head>
<body>
<div id="content" class="mui-container">
<div class="mui-panel">
<div class="mui-row">
<div class="mui-col-xs-4 mui-col-md-2"><img src="gfx/100.png"></div>
<div class="mui-col-xs-8 mui-col-md-10 item_content" style="border:1px solid red;">
<div class="mui-row">
<div class="mui--text-title "><a class='title'
href="#">Something long and text like which should fit ok</a>
</div>
</div>
<div class="mui-row">
<div class="mui--text-body1 body">
[13/Apr/2016:10:04:45 +0000] "GET / HTTP/1.1" 200 7784 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
</div>
<div class="mui--text-body1 site">
[13/Apr/2016:10:04:45 +0000] "GET / HTTP/1.1" 200 7784 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
</div>
<div class="mui--text-body1 tags">
[13/Apr/2016:10:04:45 +0000] "GET / HTTP/1.1" 200 7784 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

23
bower.json Normal file
View File

@ -0,0 +1,23 @@
{
"name": "Keeper",
"description": "",
"main": "keeper-server.js",
"authors": [
"Martin Donnelly <martind2000@gmail.com>"
],
"license": "ISC",
"homepage": "",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"src/bower_modules",
"test",
"tests"
],
"dependencies": {
"jquery": "^3.0.0",
"mui": "^0.6.5"
}
}

33
ecosystem.json Normal file
View File

@ -0,0 +1,33 @@
{
/**
* Application configuration section
* http://pm2.keymetrics.io/docs/usage/application-declaration/
*/
apps: [
// First application
{
"name": "Recipe",
"script": "recipe-server.js",
"cwd": "/var/www/recipes",
"watch": true,
"ignore_watch" : ["node_modules"],
"merge_logs" : true,
"autorestart" : true,
"restart_delay" : 3500,
"max_memory_restart" : "300M",
env: {
COMMON_VARIABLE: "true"
},
env_production: {
NODE_ENV: "production"
}
}
],
/**
* Deployment section
* http://pm2.keymetrics.io/docs/usage/deployment/
*/
deploy: {
}
}

911
server/keeper.js Normal file
View File

@ -0,0 +1,911 @@
'use strict';
/**
* Created by Martin on 22/02/2016.
*/
var express = require('express');
var http = require('http'), request = require('request'), cheerio = require(
'cheerio'), util = require('util');
var jsonfile = require('jsonfile'), fs = require('fs'), STRING = require(
'string');
var converter = require('html-to-markdown');
var markdown = require( "markdown" ).markdown;
var zlib = require('zlib');
var log4js = require('log4js');
var logger = log4js.getLogger();
var URL = require('url');
var router = express.Router();
var EventEmitter = require('events');
var nano = require('nano')('http://localhost:5984');
//var nano = require('nano')('http://martind2000:1V3D4m526i@localhost:5984');
var busEmitter = new EventEmitter();
var db_name = 'recipes';
var dbCouch = nano.use(db_name);
var jsonFile = __dirname + '/' + 'output.json';
var bodyfile = __dirname + '/' + 'body.html';
var htmlfile = __dirname + '/' + 'testoutput.html';
var generics = [
'ARTICLE',
'div.content_column',
'div.post',
'div.page',
'#recipe-single',
'div.content.body',
'div.container'
];
var specialHandlers = [{
url: 'www.reddit.com', fn: function(body, url) {
return doReddit(body, url);
}
},
{
url: 'developer.android.com', fn: function(body, url) {
return doAndroidDeveloper(body, url);
}
},
{
url: 'www.engadget.com', fn: function(body, url) {
return doEngadget(body, url);
}
}
,
{
url: 'www.bbcgoodfood.com', fn: function(body, url) {
return doBBCGoodFood(body, url);
}
}
];
function cleaner(b) {
var _b = b;
var unwanted = [
'LINK',
'META',
'TITLE',
'div#disqus_thread',
'SCRIPT',
'FOOTER',
'div.ssba',
'.shareaholic-canvas',
'.yarpp-related',
'div.dfad',
'div.postFooterShare',
'div#nextPrevLinks',
'.post-comments',
'HEADER',
'.post-title',
'#side-menu',
'.footer-container',
'#pre-footer',
'#cakephp-global-navigation',
'.masthead',
'.breadcrumb-header',
'.single-recipe-sidebar',
'#recipe-related-videos',
'#tnav',
'.footer',
'#tb-wrapper',
'#comments',
'#menu',
'aside',
'#ad-mpu-premium-1-mobile',
'#recipetools',
'.adsense-ads-separator',
'.comments',
'.related-content',
'.tip-wrapper',
'#recipe-related-video-mobile',
'.float-wrapper',
'.source-jamie',
'.ad.mobile',
'.foodity-wrapper',
'#ad-most-watched-mobile',
'#sticky',
'.nutrition-expand',
'.grid-list-wrapper',
'#recipe-finder__box',
'.browser-upgrade-alert-message',
'.main-menu',
'.recipe-media'
];
for (var i = 0; i < unwanted.length; i++) {
_b.find(unwanted[i]).remove();
}
return _b;
}
function insertBookmark(obj) {
logger.debug('Inserting into couch...');
logger.info(util.inspect(obj));
dbCouch.insert(obj, function(err, body, header) {
if (err) {
logger.error('Error inserting into couch');
return;
}
});
logger.debug('Insert done..');
}
function updateBookmark(obj, _id, _rev) {
logger.debug('Updating couch...');
var _obj = obj;
_obj._id = _id;
_obj._rev = _rev;
dbCouch.insert(_obj, function(err, body, header) {
if (err) {
logger.error('Error updating into couch');
return;
} else {
logger.info('I think we updated ok...');
busEmitter.emit('updateTagsDB');
}
});
logger.debug('Update done..');
}
var doInsertBookmark = (obj) => {
// Logger.info('sendSocket: ' + JSON.stringify(obj));
insertBookmark(obj);
};
var doUpdateBookmark = (obj, _id, _rev) => {
// Logger.info('sendSocket: ' + JSON.stringify(obj));
updateBookmark(obj, _id, _rev);
};
var doGetBookmark = (obj) => {
// Logger.info('sendSocket: ' + JSON.stringify(obj));
genericGrab(obj);
};
var doGetBookmarkRedo = (obj) => {
// Logger.info('sendSocket: ' + JSON.stringify(obj));
genericGrab(obj);
};
var doGetBookmarkRes = (url, res) => {
logger.debug('doGetBookmarkRes');
// Logger.info('sendSocket: ' + JSON.stringify(obj));
genericGrab(url, res);
};
var doSaveNew = (obj) => {
logger.debug('doGetBookmarkRes');
// Logger.info('sendSocket: ' + JSON.stringify(obj));
saveNew(obj);
};
var doUpdateTagsDB = () => {
logger.debug('Update the tags database...');
dbCouch.view('getAllTags', 'getAllTags', function(err, body) {
var masterList = [];
if (!err) {
body.rows.forEach(function(doc) {
masterList = masterList.concat(doc.value);
});
masterList = masterList.filter((value, index, self) => {
return self.indexOf(value) === index;
});
dbCouch.view('taglist', 'taglist', function(err, body) {
// Logger.debug(body);
if (!err) {
var outJSON = {};
body.rows.forEach(function(doc) {
doSaveTagsDB(doc.value, masterList);
});
} else {
logger.error('NO TAG LIST EXISTS');
}
});
} else {
}
});
};
var doSaveTagsDB = (orig, newList) => {
logger.debug('doSaveTagsDB');
var _obj = orig;
_obj.taglist = newList;
dbCouch.insert(_obj, function(err, body, header) {
if (err) {
logger.error('Error updating into couch');
return;
} else {
logger.info('Updated the tags list...');
}
});
};
// Events
busEmitter.on('saveBookmarkData', doInsertBookmark);
busEmitter.on('updateBookmarkData', doUpdateBookmark);
busEmitter.on('getBookmark', doGetBookmark);
busEmitter.on('getBookmarkRes', doGetBookmarkRes);
busEmitter.on('getBookmarkRedo', doGetBookmarkRedo);
busEmitter.on('updateTagsDB', doUpdateTagsDB);
busEmitter.on('saveTagsDB', doSaveTagsDB);
busEmitter.on('saveNew', doSaveNew);
function doBBCGoodFood(body, url) {
logger.info('GRABBING BBCGoodFood');
var obj = {}, tdihbody, i, urlObj, urlPrefix;
var $ = cheerio.load(body);
var title = $('TITLE').text();
tdihbody = $('DIV#main-content');
logger.debug('Length:' , tdihbody.length);
tdihbody = cleaner(tdihbody);
logger.debug('Title: ', title);
urlObj = URL.parse(url);
urlPrefix = urlObj.protocol + '//' + urlObj.host + '/';
try {
tdihbody.find('IMG').each(function(i, elem) {
let s, src = $(this).attr('src');
if (src !== null) {
if (!STRING(src).startsWith('http')) {
logger.debug('Stripping:' + src);
src = urlPrefix + STRING(src).stripLeft('/').trim().s;
}
if (typeof obj.thumbnail === 'undefined') {
obj.thumbnail = src;
}
s = 'http://image.silvrtree.co.uk/900,fit/' + src;
$(this).attr('src', s);
}
});
}
catch (e) {
logger.error(e);
}
obj.url = STRING(url).trim().s;
obj.html = $.html();
obj.reduced = STRING(tdihbody.html()).trim().s;
obj.nib = STRING(tdihbody.text()).collapseWhitespace().trim().left(300).s;
obj.title = STRING(title).collapseWhitespace().s;
obj.markdown = converter.convert(obj.reduced);
return obj;
}
function doEngadget(body, url) {
logger.info('GRABBING Engadget');
var obj = {}, tdihbody, i, urlObj, urlPrefix;
var $ = cheerio.load(body);
var title = $('TITLE').text();
tdihbody = $('DIV#page_body');
logger.debug('Length:' , tdihbody.length);
tdihbody = cleaner(tdihbody);
logger.debug('Title: ', title);
urlObj = URL.parse(url);
urlPrefix = urlObj.protocol + '//' + urlObj.host + '/';
try {
tdihbody.find('IMG').each(function(i, elem) {
let s, src = $(this).attr('src');
if (src !== null) {
if (!STRING(src).startsWith('http')) {
logger.debug('Stripping:' + src);
src = urlPrefix + STRING(src).stripLeft('/').trim().s;
}
if (typeof obj.thumbnail === 'undefined') {
obj.thumbnail = src;
}
s = 'http://image.silvrtree.co.uk/900,fit/' + src;
$(this).attr('src', s);
}
});
}
catch (e) {
logger.error(e);
}
obj.url = STRING(url).trim().s;
obj.html = $.html();
obj.reduced = STRING(tdihbody.html()).trim().s;
obj.nib = STRING(tdihbody.text()).collapseWhitespace().trim().left(300).s;
obj.title = STRING(title).collapseWhitespace().s;
obj.markdown = converter.convert(obj.reduced);
return obj;
}
function doAndroidDeveloper(body, url) {
logger.info('GRABBING AndroidDeveloper');
var obj = {}, tdihbody, i, urlObj, urlPrefix;
var $ = cheerio.load(body);
var title = $('TITLE').text();
tdihbody = $('DIV.jd-descr');
logger.debug(tdihbody.length);
tdihbody = cleaner(tdihbody);
logger.debug(title);
urlObj = URL.parse(url);
urlPrefix = urlObj.protocol + '//' + urlObj.host + '/';
try {
tdihbody.find('IMG').each(function(i, elem) {
let s, src = $(this).attr('src');
if (src !== null) {
if (!STRING(src).startsWith('http')) {
logger.debug('Stripping:' + src);
src = urlPrefix + STRING(src).stripLeft('/').trim().s;
}
if (typeof obj.thumbnail === 'undefined') {
obj.thumbnail = src;
}
s = 'http://image.silvrtree.co.uk/900,fit/' + src;
$(this).attr('src', s);
}
});
}
catch (e) {
logger.error(e);
}
obj.url = STRING(url).trim().s;
obj.html = $.html();
obj.reduced = STRING(tdihbody.html()).trim().s;
obj.nib = STRING(tdihbody.text()).collapseWhitespace().trim().left(300).s;
obj.title = STRING(title).collapseWhitespace().s;
obj.markdown = converter.convert(obj.reduced);
return obj;
}
function doReddit(body, url) {
logger.info('GRABBING REDDIT');
var obj = {}, tdihbody, i, urlObj, urlPrefix;
var $ = cheerio.load(body);
var title = $('TITLE').text();
tdihbody = $('DIV.entry');
tdihbody.find('A.thumbnail').each(function(i, elem) {
logger.warn($(this));
});
logger.info('++++++');
// Logger.debug(tdihbody.html());
logger.debug(tdihbody.length);
tdihbody = cleaner(tdihbody);
logger.debug(title);
obj.url = STRING(url).trim().s;
obj.html = $.html();
obj.reduced = STRING(tdihbody.html()).trim().s;
obj.nib = STRING(tdihbody.text()).collapseWhitespace().trim().left(300).s;
obj.title = STRING(title).collapseWhitespace().s;
obj.markdown = converter.convert(obj.reduced);
return obj;
}
function saveNew(obj) {
logger.info('Saving new page');
var md = markdown.toHTML(obj.body);
obj.url = '';
obj.html = md;
obj.reduced = STRING(md).trim().s;
obj.nib = STRING(md).collapseWhitespace().trim().left(300).s;
obj.title = STRING(obj.title).collapseWhitespace().s;
obj.markdown = obj.body;
busEmitter.emit('saveBookmarkData', obj);
}
function genericProcessor(body, url) {
logger.info('USING DEFAULT PROCESSOR');
var obj = {}, tdihbody, i, urlObj, urlPrefix;
var $ = cheerio.load(body);
var title = $('TITLE').text();
i = 0;
while (($(generics[i]).length == 0) && (i < generics.length)) {
i++;
}
logger.debug(i);
if (i < generics.length) {
logger.warn('Used a generic');
tdihbody = $(generics[i]);
logger.debug(tdihbody.length);
tdihbody = cleaner(tdihbody);
logger.debug(title);
} else {
logger.warn('Using whole body');
// Bah. nothing to reduce so just grab the body, tidy it and use that
tdihbody = $('BODY');
if (tdihbody.length === 0) {
tdihbody = $(':root');
}
logger.debug(tdihbody.length);
tdihbody = cleaner(tdihbody);
logger.debug(title);
}
// Logger.info(util.inspect(tdihbody));
urlObj = URL.parse(url);
urlPrefix = urlObj.protocol + '//' + urlObj.host + '/';
try {
tdihbody.find('IMG').each(function(i, elem) {
let s, src = $(this).attr('src');
console.log('!!!!' + src);
if (src !== null && typeof src !== 'undefined') {
if (!STRING(src).startsWith('http')) {
logger.debug('Stripping:' + src);
src = urlPrefix + STRING(src).stripLeft('/').trim().s;
}
if (typeof obj.thumbnail === 'undefined') {
obj.thumbnail = src;
}
s = 'http://image.silvrtree.co.uk/900,fit/' + src;
$(this).attr('src', s);
}
});
}
catch (e) {
logger.error(e);
}
obj.url = STRING(url).trim().s;
obj.html = $.html();
obj.reduced = STRING(tdihbody.html()).trim().s;
obj.nib = STRING(tdihbody.text()).collapseWhitespace().trim().left(300).s;
obj.title = STRING(title).collapseWhitespace().s;
obj.markdown = converter.convert(obj.reduced);
return obj;
}
function processBody(body, url, _id, _rev) {
var obj = {}, i, urlObj, urlPrefix;
// Try to find a body to grab
urlObj = URL.parse(url);
logger.debug('host:', urlObj.host);
var flag;
for (i = 0;i < specialHandlers.length;i++) {
if (urlObj.host === specialHandlers[i].url) {
flag = true;
obj = specialHandlers[i].fn(body,url);
}
}
if (!flag) {
// Do generic processing
obj = genericProcessor(body,url);
}
// Logger.warn(obj.reduced);
obj.host = urlObj.host;
/* Jsonfile.writeFile(jsonFile, obj, function (err) {
console.error(err);
});*/
if (_id !== null) {
busEmitter.emit('updateBookmarkData', obj, _id, _rev);
} else {
busEmitter.emit('saveBookmarkData', obj);
}
return obj;
}
function genericGrab(obj, res) {
var url, _id = null, _ver = null;
if (typeof obj === 'string') {
logger.info(obj);
url = obj;
} else {
url = obj.url;
_id = obj._id || null;
_ver = obj._rev || null;
}
logger.warn(typeof obj);
logger.info(url);
logger.info(_id);
logger.info(_ver);
var options = {
url: url,
headers: {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36'
},
jar: true,
followRedirect: true,
followAllRedirects: true
};
request(options, function(err, resp, body) {
if (err)
throw err;
if (resp.headers.hasOwnProperty('content-encoding')) {
logger.warn('content-encoding');
if (resp.headers['content-encoding'] == 'gzip') {
// to test http://chaosinthekitchen.com/2009/07/lime-and-coconut-chicken/
var gunzip = zlib.createGunzip();
var jsonString = '';
resp.pipe(gunzip);
gunzip.on('data', function(chunk) {
jsonString += chunk;
});
gunzip.on('end', function() {
// Console.log((jsonString));
callback(JSON.stringify(jsonString));
});
gunzip.on('error', function(e) {
console.log(e);
});
} else {
var b = processBody(body, url, _id, _ver);
if (res != null) {
res.render('grabbed');
}
}
} else {
var b = processBody(body, url, _id, _ver);
if (res != null) {
res.render('grabbed', {data: b});
}
}
});
}
router.get('/pocket', function(req, res) {
logger.debug('list..');
dbCouch.view('pocketList', 'pocketList', function(err, body) {
if (!err) {
var outJSON = [];
body.rows.forEach(function(doc) {
var obj = {id: doc.id, entry: doc.value};
console.log(typeof obj.entry.tn);
if (typeof obj.entry.tn === 'string') {
console.log('its a string:', typeof obj.entry.tn)
obj.entry.tn = 'http://image.silvrtree.co.uk/100,fit,q80/' + obj.entry.tn;
} else {
obj.entry.tn = 'gfx/fm.png';
}
outJSON.push(obj);
});
logger.debug(util.inspect(body));
logger.info(util.inspect(outJSON));
res.render('pocket', {data: outJSON});
} else {
res.writeHead(500, {ContentType: 'application/json'});
res.end(JSON.stringify({}));
}
});
});
router.get('/list', function(req, res) {
logger.debug('list..');
dbCouch.view('titles', 'titles', function(err, body) {
if (!err) {
var outJSON = [];
body.rows.forEach(function(doc) {
outJSON.push({id: doc.id, title: doc.value});
});
//Logger.debug(util.inspect(body));
res.writeHead(200, {ContentType: 'application/json'});
res.end(JSON.stringify({list: outJSON}));
} else {
res.writeHead(500, {ContentType: 'application/json'});
res.end(JSON.stringify({}));
}
});
});
router.get('/entry/:id', function(req, res) {
logger.debug('entry..');
logger.debug(req.params.id);
dbCouch.get(req.params.id, function(err, body) {
if (!err) {
var outJSON = {};
outJSON._id = body._id;
outJSON._rev = body._rev;
outJSON.title = body.title;
outJSON.reduced = body.reduced;
outJSON.url = body.url;
outJSON.tags = body.tags || {solid: '', list: []};
//Logger.debug(util.inspect(body));
res.writeHead(200, {ContentType: 'application/json'});
res.end(JSON.stringify(outJSON));
} else {
res.writeHead(500, {ContentType: 'application/json'});
res.end(JSON.stringify({}));
}
});
});
router.route('/tags')
.get(function(req, res, next) {
logger.debug('tag list..');
logger.debug(req.params.id);
dbCouch.view('taglist', 'taglist', function(err, body) {
if (!err) {
logger.debug(body);
var outJSON = [];
body.rows.forEach(function(doc) {
logger.info(doc.value.taglist);
if (doc.value[0] == req.params.id) {
outJSON = doc.value.taglist.sort();
}
});
//Logger.debug(util.inspect(body));
res.writeHead(200, {ContentType: 'application/json'});
res.end(JSON.stringify({list: outJSON}));
} else {
logger.error(err);
res.writeHead(500, {ContentType: 'application/json'});
res.end(JSON.stringify({}));
}
});
}).post(function(req, res, next) {
var t = req.body;
console.log(t);
logger.info('regetting:' + req.body._id);
dbCouch.get(req.body._id, function(err, body) {
if (!err) {
var obj = {};
obj.url = body.url;
obj.html = body.html;
obj.reduced = body.reduced;
obj.title = body.title;
obj.tags = req.body.tags;
logger.info('Updating...');
busEmitter.emit('updateBookmarkData', obj, body._id, body._rev, res);
var outJSON = {};
outJSON._id = body._id;
outJSON._rev = body._rev;
outJSON.title = body.title;
outJSON.reduced = body.reduced;
outJSON.url = body.url;
outJSON.tags = req.body.tags;
//Logger.debug(util.inspect(body));
res.writeHead(200, {ContentType: 'application/json'});
res.end(JSON.stringify(outJSON));
} else {
res.writeHead(500, {ContentType: 'application/json'});
res.end(JSON.stringify({}));
}
});
});
router.get('/tags/:id', function(req, res) {
logger.debug('entry..');
logger.debug(req.params.id);
dbCouch.view('getTagByKey', 'getTagByKey', function(err, body) {
if (!err) {
// Logger.debug(body);
var outJSON = [];
body.rows.forEach(function(doc) {
// Logger.debug(doc);
if (doc.value[0] == req.params.id) {
outJSON.push({id: doc.id, title: doc.value[1]})
}
});
//Logger.debug(util.inspect(body));
res.writeHead(200, {ContentType: 'application/json'});
res.end(JSON.stringify({list: outJSON}));
} else {
logger.error(err);
res.writeHead(500, {ContentType: 'application/json'});
res.end(JSON.stringify({}));
}
});
});
router.post('/add', function(req, res) {
logger.debug('add entry..');
var t = req.body;
if (t.hasOwnProperty('url')) {
var url = JSON.parse(t.url.toString());
logger.debug(url);
busEmitter.emit('getBookmark', t);
} else {
logger.error('No data block!');
}
res.writeHead(200, {ContentType: 'application/json'});
res.end(JSON.stringify({adding: url}));
});
router.post('/savenew', function(req, res) {
logger.debug('save new entry..');
var t = req.body;
logger.debug(t);
if (t.hasOwnProperty('title')) {
var title = t.title.toString();
logger.debug(title);
busEmitter.emit('saveNew', t);
} else {
logger.error('No data block!');
}
res.writeHead(200, {ContentType: 'application/json'});
res.end(JSON.stringify({}));
});
router.post('/redo', function(req, res) {
logger.debug('redoing entry..');
var t = req.body;
console.log(t);
if (t.hasOwnProperty('url')) {
var url = t.url.toString();
logger.debug(url);
busEmitter.emit('getBookmark', t);
} else {
logger.error('No data block!');
}
res.writeHead(200, {ContentType: 'application/json'});
res.end(JSON.stringify({adding: url}));
});
router.route('/new')
.get(function(req, res, next) {
logger.debug('Save new');
busEmitter.emit('getBookmarkRes', req.query.url, res);
}).post(function(req, res, next) {
logger.debug('Posted Save new');
logger.info(req.body);
if (Object.keys(req.body).length !== 0) {
busEmitter.emit('getBookmarkRes', req.body.url, res);
} else {
res.status(422).end();
}
});
busEmitter.emit('updateTagsDB');
module.exports = router;

62
server/maker.js Normal file
View File

@ -0,0 +1,62 @@
var nano = require('nano')('http://localhost:5984');
// clean up the database we created previously
nano.db.destroy('recipes', function () {
// create a new database
nano.db.create('recipes', function () {
// specify the database we are going to use
var recipes = nano.use('recipes');
// and insert a document in it
/* recipes.insert({ crazy: true }, 'rabbit', function(err, body, header) {
if (err) {
console.log('[alice.insert] ', err.message);
return;
}
console.log('you have inserted the rabbit.')
console.log(body);
});*/
recipes.insert(
{
"views": {
"titles": {
"map": function (doc) { emit(null, doc.title); }
}
}
}, '_design/titles', function (error, response) {
console.log("_design/titles added");
});
recipes.insert(
{
"views": {
"reducedView": {
"map": function (doc) { emit(null, [doc.title, doc.reduced]); }
}
}
}, '_design/reducedView', function (error, response) {
console.log("_design/reducedView added");
});
});
});
/**
* Created by Martin on 02/03/2016.
*/
/*
{
"getTagByKey": {
"map": function(doc) {
if (doc.tags.list.length > 0) {
for (var t = 0; t < doc.tags.list.length; t++) {
emit(doc._id, [doc.tags.list[t], doc.title]);
}
}
}
}
}
*/

1
server/output.json Normal file

File diff suppressed because one or more lines are too long

21
server/processor.js Normal file
View File

@ -0,0 +1,21 @@
var generics = [
'ARTICLE',
'div.content_column',
'div.post',
'div.page',
'#recipe-single',
'div.content.body'
];
var specialHandlers = [{
url: 'www.reddit.com', fn: function (body, url) {
return doReddit(body, url);
}
},
{
url: 'developer.android.com', fn: function (body, url) {
return doAndroidDeveloper(body, url);
}
}
];

13
server/seedtags.js Normal file
View File

@ -0,0 +1,13 @@
var nano = require('nano')('http://localhost:5984');
var logger = require('log4js').getLogger();
var db_name = 'keeper';
var keeper = nano.use(db_name);
keeper.insert({type:1,taglist:[]}, function(error, response) {
if (error) {
logger.error(error);
}
else {
logger.info(response);
}
});

128
server/viewinsert.js Normal file
View File

@ -0,0 +1,128 @@
var nano = require('nano')('http://localhost:5984');
var logger = require('log4js').getLogger();
var db_name = 'recipes';
var keeper = nano.use(db_name);
var tableList = [
{
name: '_design/titles', view: {
"titles": {
"map": function(doc) { emit(null, doc.title); }
}
}
}
, {
name: '_design/reducedView', view: {
"reducedView": {
"map": function(doc) { emit(null, [doc.title, doc.reduced]); }
}
}
}, {
name: '_design/taglist', view: {
"taglist": {
"map": function(doc) { if (doc.type == 1) { emit(null, doc); } }
}
}
}, {
name: '_design/getAllTags', view: {
"getAllTags": {
"map": function(doc) {
if (doc.tags.list.length > 0) {
emit(null, doc.tags.list);
}
}
}
}
}, {
name: '_design/getTagByKey', view: {
"getTagByKey": {
"map": function(doc) {
if (doc.tags.list.length > 0) {
for (var t = 0; t < doc.tags.list.length; t++) {
emit(doc._id, [doc.tags.list[t], doc.title]);
}
}
}
}
}
},
{
name: '_design/pocketList', view: {
"pocketList": {
"map":function (doc) { emit(doc._id, {'host':doc.host, 'tn':doc.thumbnail, 'title':doc.title, 'nib':doc.nib, 'tags':doc.tags}); }
}
}
}
];
var killTable = (table) => {
console.log(table.name);
keeper.get(table.name, {revs_info: true}, function(err, body) {
if (err)
console.log(err);
if (typeof body !== 'undefined') {
keeper.destroy(table.name, body._rev, function(_err, _body) {
if (err) {
console.log(_err);
}
else {
console.log(table.name + ' deleted');
console.log(_body);
}
});
}
});
};
var updateTable = (table) => {
logger.info(table.name);
keeper.get(table.name, {revs_info: true}, function(err, body) {
if (err)
logger.error(body);
if (typeof body !== 'undefined') {
logger.debug(body);
keeper.insert({_id: body._id, _rev: body._rev, views: table.view},
function(_err, _body) {
if (err) {
logger.error(_err);
}
else {
logger.info(table.name + ' updated');
logger.info(_body);
}
});
}
else {
keeper.insert({
"views": table.view
}, table.name, function(error, response) {
if (error) {
logger.error(error);
}
else {
logger.info(response);
}
});
}
});
};
for (var t = 0; t < tableList.length; t++) {
updateTable(tableList[t]);
}

48
test.md Normal file
View File

@ -0,0 +1,48 @@
![pic](https://s3-eu-west-1.amazonaws.com/rakh-images/e6768419-2953-4a19-903c-efb75016527c.jpeg)
* 3 Tbsp coconut oil
* 1 large red onion, diced
* 3 organic peppers (I like a mixture of red and green), diced
* 6 cloves garlic, minced
* 1 small butternut squash, diced
* 1 7 oz jar tomato paste (I like this brand)
* 2 lbs ground beef
* 1 26 oz tetra pack diced Pomi tomatoes (or whatever diced tomatoes you prefer)
* 1/2 quart homemade beef stock
* 2 Tbsp chili powder
* 2 Tbsp cumin
* 2 Tbsp cocoa powder (I got this idea from The Clothes Make the Girl she is genius!)
* 1 tsp crushed red pepper (add more or less depending on spice preference)
* 1 tsp sea salt
* 1/2 tsp ground black pepper
* 1/2 tsp all spice
* scallions (optional)
* avocado (optional)
#### Instructions ####
1. Melt coconut oil in a large pot over medium heat. Saute onion, peppers, squash, garlic, and tomato paste until soft.
2. Add ground beef and sauteed until browned stir frequently. Drain the fat if necessary.
3. Add tomatoes, stock, and seasonings. Simmer for a few hours over low heat.
4. Top with sliced scallions and avocado and enjoy.

20
views/grabbed.ejs Normal file
View File

@ -0,0 +1,20 @@
<html>
<head>
<link href="//cdn.muicss.com/mui-0.4.6/css/mui.min.css" rel="stylesheet" type="text/css" />
<script src="//cdn.muicss.com/mui-0.4.6/js/mui.min.js"></script>
</head>
<body>
<div class="mui-container">
<div class="mui-panel">
<div class="mui-text-headline mui-text-accent">Grabbed</div>
</div>
<div id="container" class="mui-panel">
<%= data.title %>
</div>
<div id="container" class="mui-panel">
<%- data.reduced %>
</div>
</div>
</body>
</html>

145
views/pocket.ejs Normal file
View File

@ -0,0 +1,145 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="//cdn.linearicons.com/free/1.0.0/icon-font.min.css">
<link href="//cdn.muicss.com/mui-0.4.6/css/mui.min.css" rel="stylesheet" type="text/css" />
<!-- build:css -->
<!-- endbuild -->
<script src="libs/microevent.js"></script>
<script src="//cdn.muicss.com/mui-0.4.6/js/mui.min.js"></script>
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<!-- build:vendor -->
<script src="libs/ejs.js"></script>
<script src="libs/view.js"></script>
<!-- endbuild -->
<link rel="apple-touch-icon" sizes="57x57" href="fav/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="fav/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="fav/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="fav/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="fav/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="fav/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="fav/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="fav/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="fav/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="fav/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="fav/favicon-194x194.png" sizes="194x194">
<link rel="icon" type="image/png" href="fav/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="fav/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="fav/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="fav/manifest.json">
<link rel="mask-icon" href="fav/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#ffc40d">
<meta name="msapplication-TileImage" content="fav/mstile-144x144.png">
<meta name="theme-color" content="#ffc40d">
<title>Keeper Silvtree</title>
<style>
.item_content {
height: 100px;
/* border: 1px solid grey;*/
min-height: 100px;
overflow: hidden;
}
.item_content a.title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #313131;
}
.item_content div.body, .item_content div.site, .item_content div.tags {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #313131;
}
.item_content div.site {
font-size: 90%;
color: silver;
}
.item_content div.tags {
color:blue;
}
.img100 {
width:100px;
border:1px solid grey;
max-width: 100px;
}
.mui-panel {
margin-bottom: 4px !important;
}
</style>
</head>
<body>
<div id="content" class="mui-container">
<% for(var i=0; i<data.length; i++) {%>
<div class="mui-panel">
<div class="mui-row">
<div class="mui-col-xs-4 mui-col-md-2"><img src="<%= data[i].entry.tn %>" class="img100"></div>
<div class="mui-col-xs-8 mui-col-md-10 item_content">
<div class="mui-row">
<div class="mui--text-title "><a class='title'
href="<%= data[i].id %>"><%= data[i].entry.title %></a>
</div>
</div>
<div class="mui-row">
<div class="mui--text-body1 body">
<%= data[i].entry.nib %>
</div>
<div class="mui--text-body1 site">
<%= data[i].entry.host %>
</div>
<div class="mui--text-body1 tags">
<% if (typeof data[i].entry.tags !== 'undefined') { %>
TAGS:
<%=data[i].entry.tags.solid %>
<% } %>
</div>
</div>
</div>
</div>
</div>
<% } %>
</div>
</body>
</html>