diff options
author | Nicolas LÅ“uillet <nicolas@loeuillet.org> | 2013-04-21 10:53:22 -0700 |
---|---|---|
committer | Nicolas LÅ“uillet <nicolas@loeuillet.org> | 2013-04-21 10:53:22 -0700 |
commit | 37c6ed4e7a75238504a28d6be5fbaad475689526 (patch) | |
tree | 69bfdf8ddbc09467be830274f434190b42979aa1 | |
parent | ff4d8c8c1efca0759330906419cb5f36de86d156 (diff) | |
parent | f0070a15e4725255dad967bde76155a39d189631 (diff) | |
download | wallabag-37c6ed4e7a75238504a28d6be5fbaad475689526.tar.gz wallabag-37c6ed4e7a75238504a28d6be5fbaad475689526.tar.zst wallabag-37c6ed4e7a75238504a28d6be5fbaad475689526.zip |
Merge pull request #67 from inthepoche/dev
tag 0.2
-rw-r--r-- | css/style-dark.css | 90 | ||||
-rw-r--r-- | css/style-light.css | 90 | ||||
-rw-r--r-- | css/style.css | 74 | ||||
-rw-r--r-- | img/dark/checkmark-off.png | bin | 0 -> 267 bytes | |||
-rw-r--r-- | img/dark/checkmark-on.png | bin | 0 -> 221 bytes | |||
-rw-r--r-- | img/dark/down.png | bin | 0 -> 223 bytes | |||
-rw-r--r-- | img/dark/logo.png | bin | 0 -> 786 bytes | |||
-rw-r--r-- | img/dark/remove.png | bin | 0 -> 265 bytes | |||
-rw-r--r-- | img/dark/star-off.png | bin | 0 -> 330 bytes | |||
-rw-r--r-- | img/dark/star-on.png | bin | 0 -> 277 bytes | |||
-rw-r--r-- | img/dark/up.png | bin | 0 -> 225 bytes | |||
-rw-r--r-- | img/light/checkmark-off.png (renamed from img/checkmark-off.png) | bin | 277 -> 277 bytes | |||
-rw-r--r-- | img/light/checkmark-on.png (renamed from img/checkmark-on.png) | bin | 235 -> 235 bytes | |||
-rw-r--r-- | img/light/remove.png (renamed from img/remove.png) | bin | 252 -> 252 bytes | |||
-rw-r--r-- | img/light/star-off.png (renamed from img/star-off.png) | bin | 314 -> 314 bytes | |||
-rw-r--r-- | img/light/star-on.png (renamed from img/star-on.png) | bin | 281 -> 281 bytes | |||
-rwxr-xr-x | img/messages/close.png | bin | 0 -> 662 bytes | |||
-rwxr-xr-x | img/messages/cross.png | bin | 0 -> 655 bytes | |||
-rwxr-xr-x | img/messages/help.png | bin | 0 -> 786 bytes | |||
-rwxr-xr-x | img/messages/tick.png | bin | 0 -> 537 bytes | |||
-rwxr-xr-x | img/messages/warning.png | bin | 0 -> 666 bytes | |||
-rw-r--r-- | inc/MyTool.class.php | 9 | ||||
-rw-r--r-- | inc/class.messages.php | 231 | ||||
-rw-r--r-- | inc/config.php | 17 | ||||
-rw-r--r-- | inc/db.php | 22 | ||||
-rw-r--r-- | inc/functions.php | 180 | ||||
-rw-r--r-- | inc/store/file.class.php | 51 | ||||
-rw-r--r-- | inc/store/sqlite.class.php | 144 | ||||
-rw-r--r-- | inc/store/store.class.php | 55 | ||||
-rw-r--r-- | index.php | 13 | ||||
-rw-r--r-- | js/poche.js | 31 | ||||
-rw-r--r-- | tpl/config.html | 8 | ||||
-rw-r--r-- | tpl/entries.html | 4 | ||||
-rw-r--r-- | tpl/export.html | 1 | ||||
-rw-r--r-- | tpl/footer.html | 4 | ||||
-rw-r--r-- | tpl/head.html | 11 | ||||
-rw-r--r-- | tpl/home.html | 11 | ||||
-rw-r--r-- | tpl/login.html | 10 | ||||
-rw-r--r-- | tpl/messages.html | 1 | ||||
-rw-r--r-- | tpl/view.html | 16 |
40 files changed, 831 insertions, 242 deletions
diff --git a/css/style-dark.css b/css/style-dark.css new file mode 100644 index 00000000..813c291d --- /dev/null +++ b/css/style-dark.css | |||
@@ -0,0 +1,90 @@ | |||
1 | /*** GENERAL ***/ | ||
2 | body { | ||
3 | color: #fff; | ||
4 | background-color: #0d0d0d; | ||
5 | } | ||
6 | |||
7 | a, a:hover, a:visited { | ||
8 | color: #fff; | ||
9 | } | ||
10 | |||
11 | #main ul#links li a.current { | ||
12 | background-color: #000; | ||
13 | color: #fff; | ||
14 | } | ||
15 | |||
16 | #links a:hover, .backhome a:hover{ | ||
17 | background-color: #fff; | ||
18 | color: #000; | ||
19 | } | ||
20 | |||
21 | input[type=submit].delete { | ||
22 | background : url('../img/dark/remove.png') no-repeat center center; | ||
23 | color : transparent; | ||
24 | } | ||
25 | |||
26 | #main .entrie { | ||
27 | color: #fff; | ||
28 | background-color: #000; | ||
29 | border: 1px solid #fff; | ||
30 | } | ||
31 | |||
32 | #main .entrie h2 a:hover { | ||
33 | color: #29B1E3; | ||
34 | } | ||
35 | |||
36 | a.fav span { | ||
37 | background: url('../img/dark/star-on.png') no-repeat; | ||
38 | } | ||
39 | |||
40 | a.fav span:hover { | ||
41 | background: url('../img/dark/star-off.png') no-repeat; | ||
42 | } | ||
43 | |||
44 | a.fav-off span { | ||
45 | background: url('../img/dark/star-off.png') no-repeat; | ||
46 | } | ||
47 | |||
48 | a.fav-off span:hover { | ||
49 | background: url('../img/dark/star-on.png') no-repeat; | ||
50 | } | ||
51 | |||
52 | a.archive span { | ||
53 | background: url('../img/dark/checkmark-on.png') no-repeat; | ||
54 | } | ||
55 | |||
56 | a.archive span:hover { | ||
57 | background: url('../img/dark/checkmark-off.png') no-repeat; | ||
58 | } | ||
59 | |||
60 | a.archive-off span { | ||
61 | background: url('../img/dark/checkmark-off.png') no-repeat; | ||
62 | } | ||
63 | |||
64 | a.archive-off span:hover { | ||
65 | background: url('../img/dark/checkmark-on.png') no-repeat; | ||
66 | } | ||
67 | |||
68 | /*** ***/ | ||
69 | /*** ARTICLE PAGE ***/ | ||
70 | |||
71 | body.article { | ||
72 | color: #fff; | ||
73 | background-color: #0d0d0d; | ||
74 | } | ||
75 | |||
76 | #article header { | ||
77 | border-bottom: 1px solid #222222; | ||
78 | } | ||
79 | |||
80 | #article article { | ||
81 | border-bottom: 1px solid #222222; | ||
82 | } | ||
83 | |||
84 | .vieworiginal a { | ||
85 | color: #888888; | ||
86 | } | ||
87 | |||
88 | .entrie { | ||
89 | background-color: #fff; | ||
90 | } | ||
diff --git a/css/style-light.css b/css/style-light.css new file mode 100644 index 00000000..5b9c6c11 --- /dev/null +++ b/css/style-light.css | |||
@@ -0,0 +1,90 @@ | |||
1 | /*** GENERAL ***/ | ||
2 | body { | ||
3 | color: #222222; | ||
4 | background-color: #F1F1F1; | ||
5 | } | ||
6 | |||
7 | a, a:hover, a:visited { | ||
8 | color: #000; | ||
9 | } | ||
10 | |||
11 | #main ul#links li a.current { | ||
12 | background-color: #000; | ||
13 | color: #fff; | ||
14 | } | ||
15 | |||
16 | #links a:hover, .backhome a:hover{ | ||
17 | background-color: #040707; | ||
18 | color: #F1F1F1; | ||
19 | } | ||
20 | |||
21 | input[type=submit].delete { | ||
22 | background : url('../img/light/remove.png') no-repeat center center; | ||
23 | color : transparent; | ||
24 | } | ||
25 | |||
26 | #main .entrie { | ||
27 | color: #2e2e2e; | ||
28 | background-color: #ffffff; | ||
29 | border: 1px solid #000; | ||
30 | } | ||
31 | |||
32 | #main .entrie h2 a:hover { | ||
33 | color: #F5BE00; | ||
34 | } | ||
35 | |||
36 | a.fav span { | ||
37 | background: url('../img/light/star-on.png') no-repeat; | ||
38 | } | ||
39 | |||
40 | a.fav span:hover { | ||
41 | background: url('../img/light/star-off.png') no-repeat; | ||
42 | } | ||
43 | |||
44 | a.fav-off span { | ||
45 | background: url('../img/light/star-off.png') no-repeat; | ||
46 | } | ||
47 | |||
48 | a.fav-off span:hover { | ||
49 | background: url('../img/light/star-on.png') no-repeat; | ||
50 | } | ||
51 | |||
52 | a.archive span { | ||
53 | background: url('../img/light/checkmark-on.png') no-repeat; | ||
54 | } | ||
55 | |||
56 | a.archive span:hover { | ||
57 | background: url('../img/light/checkmark-off.png') no-repeat; | ||
58 | } | ||
59 | |||
60 | a.archive-off span { | ||
61 | background: url('../img/light/checkmark-off.png') no-repeat; | ||
62 | } | ||
63 | |||
64 | a.archive-off span:hover { | ||
65 | background: url('../img/light/checkmark-on.png') no-repeat; | ||
66 | } | ||
67 | |||
68 | /*** ***/ | ||
69 | /*** ARTICLE PAGE ***/ | ||
70 | |||
71 | body.article { | ||
72 | color: #222222; | ||
73 | background-color: #F1F1F1; | ||
74 | } | ||
75 | |||
76 | #article header { | ||
77 | border-bottom: 1px solid #222222; | ||
78 | } | ||
79 | |||
80 | #article article { | ||
81 | border-bottom: 1px solid #222222; | ||
82 | } | ||
83 | |||
84 | .vieworiginal a { | ||
85 | color: #888888; | ||
86 | } | ||
87 | |||
88 | .entrie { | ||
89 | background-color: #fff; | ||
90 | } | ||
diff --git a/css/style.css b/css/style.css index 29dca289..36ebf85d 100644 --- a/css/style.css +++ b/css/style.css | |||
@@ -1,16 +1,10 @@ | |||
1 | /*** GENERAL ***/ | 1 | /*** GENERAL ***/ |
2 | body { | 2 | body { |
3 | color: #222222; | ||
4 | font: 20px/1.3em Palatino,Georgia,serif; | 3 | font: 20px/1.3em Palatino,Georgia,serif; |
5 | background-color: #F1F1F1; | ||
6 | margin: 10px; | 4 | margin: 10px; |
7 | } | 5 | } |
8 | 6 | ||
9 | 7 | ||
10 | a, a:hover, a:visited { | ||
11 | color: #000; | ||
12 | } | ||
13 | |||
14 | header { | 8 | header { |
15 | text-align: center; | 9 | text-align: center; |
16 | } | 10 | } |
@@ -28,8 +22,6 @@ header { | |||
28 | #main ul#links li a.current { | 22 | #main ul#links li a.current { |
29 | -webkit-border-radius: 2px; | 23 | -webkit-border-radius: 2px; |
30 | border-radius: 2px; | 24 | border-radius: 2px; |
31 | background-color: #040707; | ||
32 | color: #F1F1F1; | ||
33 | } | 25 | } |
34 | 26 | ||
35 | #main ul#sort { | 27 | #main ul#sort { |
@@ -58,8 +50,6 @@ header { | |||
58 | #links a:hover, .backhome a:hover{ | 50 | #links a:hover, .backhome a:hover{ |
59 | -webkit-border-radius: 2px; | 51 | -webkit-border-radius: 2px; |
60 | border-radius: 2px; | 52 | border-radius: 2px; |
61 | background-color: #040707; | ||
62 | color: #F1F1F1; | ||
63 | } | 53 | } |
64 | 54 | ||
65 | footer { | 55 | footer { |
@@ -80,11 +70,9 @@ ul#login li { | |||
80 | } | 70 | } |
81 | 71 | ||
82 | input[type=submit].delete { | 72 | input[type=submit].delete { |
83 | background : url('../img/remove.png') no-repeat center center; | ||
84 | width : 16px; | 73 | width : 16px; |
85 | height :16px; | 74 | height :16px; |
86 | border : none; | 75 | border : none; |
87 | color : transparent; | ||
88 | cursor: pointer; | 76 | cursor: pointer; |
89 | font-size : 0; | 77 | font-size : 0; |
90 | } | 78 | } |
@@ -94,8 +82,6 @@ input[type=submit].delete { | |||
94 | } | 82 | } |
95 | 83 | ||
96 | #main .entrie { | 84 | #main .entrie { |
97 | color: rgb(46, 46, 46); | ||
98 | background-color: #ffffff; | ||
99 | padding: 15px; | 85 | padding: 15px; |
100 | min-height: 8em; | 86 | min-height: 8em; |
101 | border: 1px solid; | 87 | border: 1px solid; |
@@ -105,10 +91,6 @@ input[type=submit].delete { | |||
105 | text-decoration: none; | 91 | text-decoration: none; |
106 | } | 92 | } |
107 | 93 | ||
108 | #main .entrie h2 a:hover { | ||
109 | color: #F5BE00; | ||
110 | } | ||
111 | |||
112 | .tools { | 94 | .tools { |
113 | text-align: right; | 95 | text-align: right; |
114 | } | 96 | } |
@@ -145,62 +127,23 @@ input[type=submit].delete { | |||
145 | height: 16px; | 127 | height: 16px; |
146 | } | 128 | } |
147 | 129 | ||
148 | a.fav span { | ||
149 | background: url('../img/star-on.png') no-repeat; | ||
150 | } | ||
151 | |||
152 | a.fav span:hover { | ||
153 | background: url('../img/star-off.png') no-repeat; | ||
154 | } | ||
155 | |||
156 | a.fav-off span { | ||
157 | background: url('../img/star-off.png') no-repeat; | ||
158 | } | ||
159 | |||
160 | a.fav-off span:hover { | ||
161 | background: url('../img/star-on.png') no-repeat; | ||
162 | } | ||
163 | |||
164 | a.archive span { | ||
165 | background: url('../img/checkmark-on.png') no-repeat; | ||
166 | } | ||
167 | |||
168 | a.archive span:hover { | ||
169 | background: url('../img/checkmark-off.png') no-repeat; | ||
170 | } | ||
171 | |||
172 | a.archive-off span { | ||
173 | background: url('../img/checkmark-off.png') no-repeat; | ||
174 | } | ||
175 | |||
176 | a.archive-off span:hover { | ||
177 | background: url('../img/checkmark-on.png') no-repeat; | ||
178 | } | ||
179 | 130 | ||
180 | /*** ***/ | 131 | /*** ***/ |
181 | /*** ARTICLE PAGE ***/ | 132 | /*** ARTICLE PAGE ***/ |
182 | 133 | ||
183 | body.article { | 134 | body.article { |
184 | color: #222222; | ||
185 | font: 20px/1.3em Palatino,Georgia,serif; | 135 | font: 20px/1.3em Palatino,Georgia,serif; |
186 | background-color: #F1F1F1; | ||
187 | } | 136 | } |
188 | 137 | ||
189 | #article header { | 138 | #article header { |
190 | text-align: left; | 139 | text-align: left; |
191 | border-bottom: 1px solid #222222; | ||
192 | } | 140 | } |
193 | 141 | ||
194 | #article header a { | 142 | #article header a { |
195 | text-decoration: none; | 143 | text-decoration: none; |
196 | } | 144 | } |
197 | 145 | ||
198 | #article article { | ||
199 | border-bottom: 1px solid #222222; | ||
200 | } | ||
201 | |||
202 | .vieworiginal a { | 146 | .vieworiginal a { |
203 | color: #888888; | ||
204 | text-decoration: none; | 147 | text-decoration: none; |
205 | } | 148 | } |
206 | 149 | ||
@@ -256,4 +199,19 @@ body.article { | |||
256 | } | 199 | } |
257 | } | 200 | } |
258 | 201 | ||
259 | 202 | /*** ***/ | |
203 | /*** MESSAGES ***/ | ||
204 | |||
205 | .messages { width: 100%; -moz-border-radius: 4px; border-radius: 4px; display: block; padding: 10px 0; margin: 10px auto 10px; clear: both; } | ||
206 | .messages a.closeMessage { margin: -14px -8px 0 0; display:none; width: 16px; height: 16px; float: right; background: url(../img/messages/close.png) no-repeat; } | ||
207 | /*.messages:hover a.closeMessage { visibility:visible; }*/ | ||
208 | .messages p { margin: 3px 0 3px 10px !important; padding: 0 10px 0 23px !important; font-size: 14px; line-height: 16px; } | ||
209 | .messages.error { border: 1px solid #C42608; color: #c00 !important; background: #FFF0EF; } | ||
210 | .messages.error p { background: url(../img/messages/cross.png ) no-repeat 0px 50%; color:#c00 !important; } | ||
211 | .messages.success {background: #E0FBCC; border: 1px solid #6DC70C; } | ||
212 | .messages.success p { background: url(../img/messages/tick.png) no-repeat 0px 50%; color: #2B6301 !important; } | ||
213 | .messages.warning { background: #FFFCD3; border: 1px solid #EBCD41; color: #000; } | ||
214 | .messages.warning p { background: url(../img/messages/warning.png ) no-repeat 0px 50%; color: #5F4E01; } | ||
215 | .messages.information, .messages.info { background: #DFEBFB; border: 1px solid #82AEE7; } | ||
216 | .messages.information p, .messages.info p { background: url(../img/messages/help.png ) no-repeat 0px 50%; color: #064393; } | ||
217 | .messages.information a { text-decoration: underline; } \ No newline at end of file | ||
diff --git a/img/dark/checkmark-off.png b/img/dark/checkmark-off.png new file mode 100644 index 00000000..efc3439f --- /dev/null +++ b/img/dark/checkmark-off.png | |||
Binary files differ | |||
diff --git a/img/dark/checkmark-on.png b/img/dark/checkmark-on.png new file mode 100644 index 00000000..24391c2e --- /dev/null +++ b/img/dark/checkmark-on.png | |||
Binary files differ | |||
diff --git a/img/dark/down.png b/img/dark/down.png new file mode 100644 index 00000000..41ea9604 --- /dev/null +++ b/img/dark/down.png | |||
Binary files differ | |||
diff --git a/img/dark/logo.png b/img/dark/logo.png new file mode 100644 index 00000000..9fba0642 --- /dev/null +++ b/img/dark/logo.png | |||
Binary files differ | |||
diff --git a/img/dark/remove.png b/img/dark/remove.png new file mode 100644 index 00000000..41786fd7 --- /dev/null +++ b/img/dark/remove.png | |||
Binary files differ | |||
diff --git a/img/dark/star-off.png b/img/dark/star-off.png new file mode 100644 index 00000000..90651b54 --- /dev/null +++ b/img/dark/star-off.png | |||
Binary files differ | |||
diff --git a/img/dark/star-on.png b/img/dark/star-on.png new file mode 100644 index 00000000..7fc14477 --- /dev/null +++ b/img/dark/star-on.png | |||
Binary files differ | |||
diff --git a/img/dark/up.png b/img/dark/up.png new file mode 100644 index 00000000..1679e18f --- /dev/null +++ b/img/dark/up.png | |||
Binary files differ | |||
diff --git a/img/checkmark-off.png b/img/light/checkmark-off.png index 3db5a06d..3db5a06d 100644 --- a/img/checkmark-off.png +++ b/img/light/checkmark-off.png | |||
Binary files differ | |||
diff --git a/img/checkmark-on.png b/img/light/checkmark-on.png index cd3abb2c..cd3abb2c 100644 --- a/img/checkmark-on.png +++ b/img/light/checkmark-on.png | |||
Binary files differ | |||
diff --git a/img/remove.png b/img/light/remove.png index f8ad56a3..f8ad56a3 100644 --- a/img/remove.png +++ b/img/light/remove.png | |||
Binary files differ | |||
diff --git a/img/star-off.png b/img/light/star-off.png index 6a0133a7..6a0133a7 100644 --- a/img/star-off.png +++ b/img/light/star-off.png | |||
Binary files differ | |||
diff --git a/img/star-on.png b/img/light/star-on.png index a9f96eaa..a9f96eaa 100644 --- a/img/star-on.png +++ b/img/light/star-on.png | |||
Binary files differ | |||
diff --git a/img/messages/close.png b/img/messages/close.png new file mode 100755 index 00000000..731aa018 --- /dev/null +++ b/img/messages/close.png | |||
Binary files differ | |||
diff --git a/img/messages/cross.png b/img/messages/cross.png new file mode 100755 index 00000000..1514d51a --- /dev/null +++ b/img/messages/cross.png | |||
Binary files differ | |||
diff --git a/img/messages/help.png b/img/messages/help.png new file mode 100755 index 00000000..5c870176 --- /dev/null +++ b/img/messages/help.png | |||
Binary files differ | |||
diff --git a/img/messages/tick.png b/img/messages/tick.png new file mode 100755 index 00000000..a9925a06 --- /dev/null +++ b/img/messages/tick.png | |||
Binary files differ | |||
diff --git a/img/messages/warning.png b/img/messages/warning.png new file mode 100755 index 00000000..628cf2da --- /dev/null +++ b/img/messages/warning.png | |||
Binary files differ | |||
diff --git a/inc/MyTool.class.php b/inc/MyTool.class.php index 8206f3f7..1f5051a4 100644 --- a/inc/MyTool.class.php +++ b/inc/MyTool.class.php | |||
@@ -1,4 +1,13 @@ | |||
1 | <?php | 1 | <?php |
2 | /** | ||
3 | * poche, a read it later open source system | ||
4 | * | ||
5 | * @category poche | ||
6 | * @author Nicolas LÅ“uillet <support@inthepoche.com> | ||
7 | * @copyright 2013 | ||
8 | * @license http://www.wtfpl.net/ see COPYING file | ||
9 | */ | ||
10 | |||
2 | class MyTool | 11 | class MyTool |
3 | { | 12 | { |
4 | public static function initPhp() | 13 | public static function initPhp() |
diff --git a/inc/class.messages.php b/inc/class.messages.php new file mode 100644 index 00000000..6d515bf6 --- /dev/null +++ b/inc/class.messages.php | |||
@@ -0,0 +1,231 @@ | |||
1 | <?php | ||
2 | //-------------------------------------------------------------------------------------------------- | ||
3 | // Session-Based Flash Messages v1.0 | ||
4 | // Copyright 2012 Mike Everhart (http://mikeeverhart.net) | ||
5 | // | ||
6 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
7 | // you may not use this file except in compliance with the License. | ||
8 | // You may obtain a copy of the License at | ||
9 | // | ||
10 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | // | ||
12 | // Unless required by applicable law or agreed to in writing, software | ||
13 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
15 | // See the License for the specific language governing permissions and | ||
16 | // limitations under the License. | ||
17 | // | ||
18 | //------------------------------------------------------------------------------ | ||
19 | // Description: | ||
20 | //------------------------------------------------------------------------------ | ||
21 | // | ||
22 | // Stores messages in Session data to be easily retrieved later on. | ||
23 | // This class includes four different types of messages: | ||
24 | // - Success | ||
25 | // - Error | ||
26 | // - Warning | ||
27 | // - Information | ||
28 | // | ||
29 | // See README for basic usage instructions, or see samples/index.php for more advanced samples | ||
30 | // | ||
31 | //-------------------------------------------------------------------------------------------------- | ||
32 | // Changelog | ||
33 | //-------------------------------------------------------------------------------------------------- | ||
34 | // | ||
35 | // 2011-05-15 - v1.0 - Initial Version | ||
36 | // | ||
37 | //-------------------------------------------------------------------------------------------------- | ||
38 | |||
39 | class Messages { | ||
40 | |||
41 | //----------------------------------------------------------------------------------------------- | ||
42 | // Class Variables | ||
43 | //----------------------------------------------------------------------------------------------- | ||
44 | var $msgId; | ||
45 | var $msgTypes = array( 'help', 'info', 'warning', 'success', 'error' ); | ||
46 | var $msgClass = 'messages'; | ||
47 | var $msgWrapper = "<div class='%s %s'><a href='#' class='closeMessage'></a>\n%s</div>\n"; | ||
48 | var $msgBefore = '<p>'; | ||
49 | var $msgAfter = "</p>\n"; | ||
50 | |||
51 | |||
52 | /** | ||
53 | * Constructor | ||
54 | * @author Mike Everhart | ||
55 | */ | ||
56 | public function __construct() { | ||
57 | |||
58 | // Generate a unique ID for this user and session | ||
59 | $this->msgId = md5(uniqid()); | ||
60 | |||
61 | // Create the session array if it doesnt already exist | ||
62 | if( !array_key_exists('flash_messages', $_SESSION) ) $_SESSION['flash_messages'] = array(); | ||
63 | |||
64 | } | ||
65 | |||
66 | /** | ||
67 | * Add a message to the queue | ||
68 | * | ||
69 | * @author Mike Everhart | ||
70 | * | ||
71 | * @param string $type The type of message to add | ||
72 | * @param string $message The message | ||
73 | * @param string $redirect_to (optional) If set, the user will be redirected to this URL | ||
74 | * @return bool | ||
75 | * | ||
76 | */ | ||
77 | public function add($type, $message, $redirect_to=null) { | ||
78 | |||
79 | if( !isset($_SESSION['flash_messages']) ) return false; | ||
80 | |||
81 | if( !isset($type) || !isset($message[0]) ) return false; | ||
82 | |||
83 | // Replace any shorthand codes with their full version | ||
84 | if( strlen(trim($type)) == 1 ) { | ||
85 | $type = str_replace( array('h', 'i', 'w', 'e', 's'), array('help', 'info', 'warning', 'error', 'success'), $type ); | ||
86 | |||
87 | // Backwards compatibility... | ||
88 | } elseif( $type == 'information' ) { | ||
89 | $type = 'info'; | ||
90 | } | ||
91 | |||
92 | // Make sure it's a valid message type | ||
93 | if( !in_array($type, $this->msgTypes) ) die('"' . strip_tags($type) . '" is not a valid message type!' ); | ||
94 | |||
95 | // If the session array doesn't exist, create it | ||
96 | if( !array_key_exists( $type, $_SESSION['flash_messages'] ) ) $_SESSION['flash_messages'][$type] = array(); | ||
97 | |||
98 | $_SESSION['flash_messages'][$type][] = $message; | ||
99 | |||
100 | if( !is_null($redirect_to) ) { | ||
101 | header("Location: $redirect_to"); | ||
102 | exit(); | ||
103 | } | ||
104 | |||
105 | return true; | ||
106 | |||
107 | } | ||
108 | |||
109 | //----------------------------------------------------------------------------------------------- | ||
110 | // display() | ||
111 | // print queued messages to the screen | ||
112 | //----------------------------------------------------------------------------------------------- | ||
113 | /** | ||
114 | * Display the queued messages | ||
115 | * | ||
116 | * @author Mike Everhart | ||
117 | * | ||
118 | * @param string $type Which messages to display | ||
119 | * @param bool $print True = print the messages on the screen | ||
120 | * @return mixed | ||
121 | * | ||
122 | */ | ||
123 | public function display($type='all', $print=true) { | ||
124 | $messages = ''; | ||
125 | $data = ''; | ||
126 | |||
127 | if( !isset($_SESSION['flash_messages']) ) return false; | ||
128 | |||
129 | if( $type == 'g' || $type == 'growl' ) { | ||
130 | $this->displayGrowlMessages(); | ||
131 | return true; | ||
132 | } | ||
133 | |||
134 | // Print a certain type of message? | ||
135 | if( in_array($type, $this->msgTypes) ) { | ||
136 | foreach( $_SESSION['flash_messages'][$type] as $msg ) { | ||
137 | $messages .= $this->msgBefore . $msg . $this->msgAfter; | ||
138 | } | ||
139 | |||
140 | $data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages); | ||
141 | |||
142 | // Clear the viewed messages | ||
143 | $this->clear($type); | ||
144 | |||
145 | // Print ALL queued messages | ||
146 | } elseif( $type == 'all' ) { | ||
147 | foreach( $_SESSION['flash_messages'] as $type => $msgArray ) { | ||
148 | $messages = ''; | ||
149 | foreach( $msgArray as $msg ) { | ||
150 | $messages .= $this->msgBefore . $msg . $this->msgAfter; | ||
151 | } | ||
152 | $data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages); | ||
153 | } | ||
154 | |||
155 | // Clear ALL of the messages | ||
156 | $this->clear(); | ||
157 | |||
158 | // Invalid Message Type? | ||
159 | } else { | ||
160 | return false; | ||
161 | } | ||
162 | |||
163 | // Print everything to the screen or return the data | ||
164 | if( $print ) { | ||
165 | echo $data; | ||
166 | } else { | ||
167 | return $data; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | |||
172 | /** | ||
173 | * Check to see if there are any queued error messages | ||
174 | * | ||
175 | * @author Mike Everhart | ||
176 | * | ||
177 | * @return bool true = There ARE error messages | ||
178 | * false = There are NOT any error messages | ||
179 | * | ||
180 | */ | ||
181 | public function hasErrors() { | ||
182 | return empty($_SESSION['flash_messages']['error']) ? false : true; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * Check to see if there are any ($type) messages queued | ||
187 | * | ||
188 | * @author Mike Everhart | ||
189 | * | ||
190 | * @param string $type The type of messages to check for | ||
191 | * @return bool | ||
192 | * | ||
193 | */ | ||
194 | public function hasMessages($type=null) { | ||
195 | if( !is_null($type) ) { | ||
196 | if( !empty($_SESSION['flash_messages'][$type]) ) return $_SESSION['flash_messages'][$type]; | ||
197 | } else { | ||
198 | foreach( $this->msgTypes as $type ) { | ||
199 | if( !empty($_SESSION['flash_messages']) ) return true; | ||
200 | } | ||
201 | } | ||
202 | return false; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * Clear messages from the session data | ||
207 | * | ||
208 | * @author Mike Everhart | ||
209 | * | ||
210 | * @param string $type The type of messages to clear | ||
211 | * @return bool | ||
212 | * | ||
213 | */ | ||
214 | public function clear($type='all') { | ||
215 | if( $type == 'all' ) { | ||
216 | unset($_SESSION['flash_messages']); | ||
217 | } else { | ||
218 | unset($_SESSION['flash_messages'][$type]); | ||
219 | } | ||
220 | return true; | ||
221 | } | ||
222 | |||
223 | public function __toString() { return $this->hasMessages(); } | ||
224 | |||
225 | public function __destruct() { | ||
226 | //$this->clear(); | ||
227 | } | ||
228 | |||
229 | |||
230 | } // end class | ||
231 | ?> \ No newline at end of file | ||
diff --git a/inc/config.php b/inc/config.php index c63b07b9..9d4b7fae 100644 --- a/inc/config.php +++ b/inc/config.php | |||
@@ -8,26 +8,32 @@ | |||
8 | * @license http://www.wtfpl.net/ see COPYING file | 8 | * @license http://www.wtfpl.net/ see COPYING file |
9 | */ | 9 | */ |
10 | 10 | ||
11 | define ('POCHE_VERSION', '0.11'); | 11 | define ('POCHE_VERSION', '0.2'); |
12 | 12 | ||
13 | if (!is_dir('db/')) { | 13 | if (!is_dir('db/')) { |
14 | @mkdir('db/',0705); | 14 | @mkdir('db/',0705); |
15 | } | 15 | } |
16 | 16 | ||
17 | define ('DB_PATH', 'sqlite:./db/poche.sqlite'); | ||
18 | define ('ABS_PATH', 'assets/'); | 17 | define ('ABS_PATH', 'assets/'); |
19 | define ('CONVERT_LINKS_FOOTNOTES', TRUE); | 18 | define ('CONVERT_LINKS_FOOTNOTES', TRUE); |
20 | define ('DOWNLOAD_PICTURES', TRUE); | 19 | define ('DOWNLOAD_PICTURES', TRUE); |
20 | $storage_type = 'sqlite'; # sqlite or file | ||
21 | 21 | ||
22 | include 'db.php'; | ||
23 | include 'functions.php'; | 22 | include 'functions.php'; |
24 | require_once 'Readability.php'; | 23 | require_once 'Readability.php'; |
25 | require_once 'Encoding.php'; | 24 | require_once 'Encoding.php'; |
26 | require_once 'rain.tpl.class.php'; | 25 | require_once 'rain.tpl.class.php'; |
27 | require_once 'MyTool.class.php'; | 26 | require_once 'MyTool.class.php'; |
28 | require_once 'Session.class.php'; | 27 | require_once 'Session.class.php'; |
28 | require_once 'store/store.class.php'; | ||
29 | require_once 'store/sqlite.class.php'; | ||
30 | require_once 'store/file.class.php'; | ||
31 | require_once 'class.messages.php'; | ||
29 | 32 | ||
30 | $db = new db(DB_PATH); | 33 | Session::init(); |
34 | |||
35 | $store = new $storage_type(); | ||
36 | $msg = new Messages(); | ||
31 | 37 | ||
32 | # initialisation de RainTPL | 38 | # initialisation de RainTPL |
33 | raintpl::$tpl_dir = './tpl/'; | 39 | raintpl::$tpl_dir = './tpl/'; |
@@ -35,4 +41,5 @@ raintpl::$cache_dir = './cache/'; | |||
35 | raintpl::$base_url = get_poche_url(); | 41 | raintpl::$base_url = get_poche_url(); |
36 | raintpl::configure('path_replace', false); | 42 | raintpl::configure('path_replace', false); |
37 | raintpl::configure('debug', false); | 43 | raintpl::configure('debug', false); |
38 | $tpl = new raintpl(); \ No newline at end of file | 44 | $tpl = new raintpl(); |
45 | $tpl->assign('msg', $msg); \ No newline at end of file | ||
diff --git a/inc/db.php b/inc/db.php deleted file mode 100644 index 60d7c108..00000000 --- a/inc/db.php +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | <?php | ||
2 | /** | ||
3 | * poche, a read it later open source system | ||
4 | * | ||
5 | * @category poche | ||
6 | * @author Nicolas LÅ“uillet <nicolas@loeuillet.org> | ||
7 | * @copyright 2013 | ||
8 | * @license http://www.wtfpl.net/ see COPYING file | ||
9 | */ | ||
10 | |||
11 | class db { | ||
12 | var $handle; | ||
13 | function __construct($path) { | ||
14 | $this->handle = new PDO($path); | ||
15 | $this->handle->exec('CREATE TABLE IF NOT EXISTS "entries" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE , "title" VARCHAR, "url" VARCHAR UNIQUE , "is_read" INTEGER DEFAULT 0, "is_fav" INTEGER DEFAULT 0, "content" BLOB)'); | ||
16 | $this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | ||
17 | } | ||
18 | |||
19 | public function getHandle() { | ||
20 | return $this->handle; | ||
21 | } | ||
22 | } \ No newline at end of file | ||
diff --git a/inc/functions.php b/inc/functions.php index ef1fc0e2..205f3968 100644 --- a/inc/functions.php +++ b/inc/functions.php | |||
@@ -1,4 +1,12 @@ | |||
1 | <?php | 1 | <?php |
2 | /** | ||
3 | * poche, a read it later open source system | ||
4 | * | ||
5 | * @category poche | ||
6 | * @author Nicolas LÅ“uillet <support@inthepoche.com> | ||
7 | * @copyright 2013 | ||
8 | * @license http://www.wtfpl.net/ see COPYING file | ||
9 | */ | ||
2 | 10 | ||
3 | /** | 11 | /** |
4 | * Permet de générer l'URL de poche pour le bookmarklet | 12 | * Permet de générer l'URL de poche pour le bookmarklet |
@@ -117,6 +125,7 @@ function prepare_url($url) | |||
117 | } | 125 | } |
118 | } | 126 | } |
119 | 127 | ||
128 | $msg->add('e', 'error during url preparation'); | ||
120 | logm('error during url preparation'); | 129 | logm('error during url preparation'); |
121 | return FALSE; | 130 | return FALSE; |
122 | } | 131 | } |
@@ -228,20 +237,35 @@ function remove_directory($directory) | |||
228 | 237 | ||
229 | function display_view($view, $id = 0, $full_head = 'yes') | 238 | function display_view($view, $id = 0, $full_head = 'yes') |
230 | { | 239 | { |
231 | global $tpl; | 240 | global $tpl, $store, $msg; |
232 | 241 | ||
233 | switch ($view) | 242 | switch ($view) |
234 | { | 243 | { |
244 | case 'export': | ||
245 | $entries = $store->retrieveAll(); | ||
246 | $tpl->assign('export', myTool::renderJson($entries)); | ||
247 | $tpl->draw('export'); | ||
248 | logm('export view'); | ||
249 | break; | ||
250 | case 'config': | ||
251 | $tpl->assign('load_all_js', 0); | ||
252 | $tpl->draw('head'); | ||
253 | $tpl->draw('home'); | ||
254 | $tpl->draw('config'); | ||
255 | $tpl->draw('js'); | ||
256 | $tpl->draw('footer'); | ||
257 | logm('config view'); | ||
258 | break; | ||
235 | case 'view': | 259 | case 'view': |
236 | $entry = get_article($id); | 260 | $entry = $store->retrieveOneById($id); |
237 | 261 | ||
238 | if ($entry != NULL) { | 262 | if ($entry != NULL) { |
239 | $tpl->assign('id', $entry[0]['id']); | 263 | $tpl->assign('id', $entry['id']); |
240 | $tpl->assign('url', $entry[0]['url']); | 264 | $tpl->assign('url', $entry['url']); |
241 | $tpl->assign('title', $entry[0]['title']); | 265 | $tpl->assign('title', $entry['title']); |
242 | $tpl->assign('content', $entry[0]['content']); | 266 | $tpl->assign('content', $entry['content']); |
243 | $tpl->assign('is_fav', $entry[0]['is_fav']); | 267 | $tpl->assign('is_fav', $entry['is_fav']); |
244 | $tpl->assign('is_read', $entry[0]['is_read']); | 268 | $tpl->assign('is_read', $entry['is_read']); |
245 | $tpl->assign('load_all_js', 0); | 269 | $tpl->assign('load_all_js', 0); |
246 | $tpl->draw('view'); | 270 | $tpl->draw('view'); |
247 | } | 271 | } |
@@ -252,7 +276,7 @@ function display_view($view, $id = 0, $full_head = 'yes') | |||
252 | logm('view link #' . $id); | 276 | logm('view link #' . $id); |
253 | break; | 277 | break; |
254 | default: # home view | 278 | default: # home view |
255 | $entries = get_entries($view); | 279 | $entries = $store->getEntriesByView($view); |
256 | 280 | ||
257 | $tpl->assign('entries', $entries); | 281 | $tpl->assign('entries', $entries); |
258 | 282 | ||
@@ -277,7 +301,7 @@ function display_view($view, $id = 0, $full_head = 'yes') | |||
277 | */ | 301 | */ |
278 | function action_to_do($action, $url, $id = 0) | 302 | function action_to_do($action, $url, $id = 0) |
279 | { | 303 | { |
280 | global $db; | 304 | global $store, $msg; |
281 | 305 | ||
282 | switch ($action) | 306 | switch ($action) |
283 | { | 307 | { |
@@ -285,140 +309,42 @@ function action_to_do($action, $url, $id = 0) | |||
285 | if ($url == '') | 309 | if ($url == '') |
286 | continue; | 310 | continue; |
287 | 311 | ||
288 | if($parametres_url = prepare_url($url)) { | 312 | if (MyTool::isUrl($url)) { |
289 | $sql_action = 'INSERT INTO entries ( url, title, content ) VALUES (?, ?, ?)'; | 313 | if($parametres_url = prepare_url($url)) { |
290 | $params_action = array($url, $parametres_url['title'], $parametres_url['content']); | 314 | $store->add($url, $parametres_url['title'], $parametres_url['content']); |
315 | $last_id = $store->getLastId(); | ||
316 | if (DOWNLOAD_PICTURES) { | ||
317 | $content = filtre_picture($parametres_url['content'], $url, $last_id); | ||
318 | } | ||
319 | $msg->add('s', 'the link has been added successfully'); | ||
320 | } | ||
321 | } | ||
322 | else { | ||
323 | $msg->add('e', 'the link has been added successfully'); | ||
324 | logm($url . ' is not a valid url'); | ||
291 | } | 325 | } |
292 | 326 | ||
293 | logm('add link ' . $url); | 327 | logm('add link ' . $url); |
294 | break; | 328 | break; |
295 | case 'delete': | 329 | case 'delete': |
296 | remove_directory(ABS_PATH . $id); | 330 | remove_directory(ABS_PATH . $id); |
297 | $sql_action = "DELETE FROM entries WHERE id=?"; | 331 | $store->deleteById($id); |
298 | $params_action = array($id); | 332 | $msg->add('s', 'the link has been deleted successfully'); |
299 | logm('delete link #' . $id); | 333 | logm('delete link #' . $id); |
300 | break; | 334 | break; |
301 | case 'toggle_fav' : | 335 | case 'toggle_fav' : |
302 | $sql_action = "UPDATE entries SET is_fav=~is_fav WHERE id=?"; | 336 | $store->favoriteById($id); |
303 | $params_action = array($id); | 337 | $msg->add('s', 'the favorite toggle has been done successfully'); |
304 | logm('mark as favorite link #' . $id); | 338 | logm('mark as favorite link #' . $id); |
305 | break; | 339 | break; |
306 | case 'toggle_archive' : | 340 | case 'toggle_archive' : |
307 | $sql_action = "UPDATE entries SET is_read=~is_read WHERE id=?"; | 341 | $store->archiveById($id); |
308 | $params_action = array($id); | 342 | $msg->add('s', 'the archive toggle has been done successfully'); |
309 | logm('archive link #' . $id); | 343 | logm('archive link #' . $id); |
310 | break; | 344 | break; |
311 | default: | 345 | default: |
312 | break; | 346 | break; |
313 | } | 347 | } |
314 | |||
315 | try | ||
316 | { | ||
317 | # action query | ||
318 | if (isset($sql_action)) | ||
319 | { | ||
320 | $query = $db->getHandle()->prepare($sql_action); | ||
321 | $query->execute($params_action); | ||
322 | # if we add a link, we have to download pictures | ||
323 | if ($action == 'add') { | ||
324 | $last_id = $db->getHandle()->lastInsertId(); | ||
325 | if (DOWNLOAD_PICTURES) { | ||
326 | $content = filtre_picture($parametres_url['content'], $url, $last_id); | ||
327 | $sql_update = "UPDATE entries SET content=? WHERE id=?"; | ||
328 | $params_update = array($content, $last_id); | ||
329 | $query_update = $db->getHandle()->prepare($sql_update); | ||
330 | $query_update->execute($params_update); | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | catch (Exception $e) | ||
336 | { | ||
337 | logm('action query error : '.$e->getMessage()); | ||
338 | } | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * Détermine quels liens afficher : home, fav ou archives | ||
343 | */ | ||
344 | function get_entries($view) | ||
345 | { | ||
346 | global $db; | ||
347 | |||
348 | switch ($_SESSION['sort']) | ||
349 | { | ||
350 | case 'ia': | ||
351 | $order = 'ORDER BY id'; | ||
352 | break; | ||
353 | case 'id': | ||
354 | $order = 'ORDER BY id DESC'; | ||
355 | break; | ||
356 | case 'ta': | ||
357 | $order = 'ORDER BY lower(title)'; | ||
358 | break; | ||
359 | case 'td': | ||
360 | $order = 'ORDER BY lower(title) DESC'; | ||
361 | break; | ||
362 | default: | ||
363 | $order = 'ORDER BY id'; | ||
364 | break; | ||
365 | } | ||
366 | |||
367 | switch ($view) | ||
368 | { | ||
369 | case 'archive': | ||
370 | $sql = "SELECT * FROM entries WHERE is_read=? " . $order; | ||
371 | $params = array(-1); | ||
372 | break; | ||
373 | case 'fav' : | ||
374 | $sql = "SELECT * FROM entries WHERE is_fav=? " . $order; | ||
375 | $params = array(-1); | ||
376 | break; | ||
377 | default: | ||
378 | $sql = "SELECT * FROM entries WHERE is_read=? " . $order; | ||
379 | $params = array(0); | ||
380 | break; | ||
381 | } | ||
382 | |||
383 | # view query | ||
384 | try | ||
385 | { | ||
386 | $query = $db->getHandle()->prepare($sql); | ||
387 | $query->execute($params); | ||
388 | $entries = $query->fetchAll(); | ||
389 | } | ||
390 | catch (Exception $e) | ||
391 | { | ||
392 | logm('view query error : '.$e->getMessage()); | ||
393 | } | ||
394 | |||
395 | return $entries; | ||
396 | } | ||
397 | |||
398 | /** | ||
399 | * Récupère un article en fonction d'un ID | ||
400 | */ | ||
401 | function get_article($id) | ||
402 | { | ||
403 | global $db; | ||
404 | |||
405 | $entry = NULL; | ||
406 | $sql = "SELECT * FROM entries WHERE id=?"; | ||
407 | $params = array(intval($id)); | ||
408 | |||
409 | # view article query | ||
410 | try | ||
411 | { | ||
412 | $query = $db->getHandle()->prepare($sql); | ||
413 | $query->execute($params); | ||
414 | $entry = $query->fetchAll(); | ||
415 | } | ||
416 | catch (Exception $e) | ||
417 | { | ||
418 | logm('get article query error : '.$e->getMessage()); | ||
419 | } | ||
420 | |||
421 | return $entry; | ||
422 | } | 348 | } |
423 | 349 | ||
424 | function logm($message) | 350 | function logm($message) |
diff --git a/inc/store/file.class.php b/inc/store/file.class.php new file mode 100644 index 00000000..ad20937d --- /dev/null +++ b/inc/store/file.class.php | |||
@@ -0,0 +1,51 @@ | |||
1 | <?php | ||
2 | /** | ||
3 | * poche, a read it later open source system | ||
4 | * | ||
5 | * @category poche | ||
6 | * @author Nicolas LÅ“uillet <support@inthepoche.com> | ||
7 | * @copyright 2013 | ||
8 | * @license http://www.wtfpl.net/ see COPYING file | ||
9 | */ | ||
10 | |||
11 | class File extends Store { | ||
12 | function __construct() { | ||
13 | |||
14 | } | ||
15 | |||
16 | public function add() { | ||
17 | |||
18 | } | ||
19 | |||
20 | public function retrieveOneById($id) { | ||
21 | |||
22 | } | ||
23 | |||
24 | public function retrieveOneByURL($url) { | ||
25 | |||
26 | } | ||
27 | |||
28 | public function deleteById($id) { | ||
29 | |||
30 | } | ||
31 | |||
32 | public function favoriteById($id) { | ||
33 | |||
34 | } | ||
35 | |||
36 | public function archiveById($id) { | ||
37 | |||
38 | } | ||
39 | |||
40 | public function getEntriesByView($view) { | ||
41 | |||
42 | } | ||
43 | |||
44 | public function getLastId() { | ||
45 | |||
46 | } | ||
47 | |||
48 | public function updateContentById($id) { | ||
49 | |||
50 | } | ||
51 | } | ||
diff --git a/inc/store/sqlite.class.php b/inc/store/sqlite.class.php new file mode 100644 index 00000000..d5208a29 --- /dev/null +++ b/inc/store/sqlite.class.php | |||
@@ -0,0 +1,144 @@ | |||
1 | <?php | ||
2 | /** | ||
3 | * poche, a read it later open source system | ||
4 | * | ||
5 | * @category poche | ||
6 | * @author Nicolas LÅ“uillet <support@inthepoche.com> | ||
7 | * @copyright 2013 | ||
8 | * @license http://www.wtfpl.net/ see COPYING file | ||
9 | */ | ||
10 | |||
11 | class Sqlite extends Store { | ||
12 | |||
13 | public static $db_path = 'sqlite:./db/poche.sqlite'; | ||
14 | var $handle; | ||
15 | |||
16 | function __construct() { | ||
17 | parent::__construct(); | ||
18 | |||
19 | $this->handle = new PDO(self::$db_path); | ||
20 | $this->handle->exec('CREATE TABLE IF NOT EXISTS "entries" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE , "title" VARCHAR, "url" VARCHAR UNIQUE , "is_read" INTEGER DEFAULT 0, "is_fav" INTEGER DEFAULT 0, "content" BLOB)'); | ||
21 | $this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | ||
22 | } | ||
23 | |||
24 | private function getHandle() { | ||
25 | return $this->handle; | ||
26 | } | ||
27 | |||
28 | private function executeQuery($sql, $params) { | ||
29 | try | ||
30 | { | ||
31 | $query = $this->getHandle()->prepare($sql); | ||
32 | $query->execute($params); | ||
33 | return $query; | ||
34 | } | ||
35 | catch (Exception $e) | ||
36 | { | ||
37 | logm('execute query error : '.$e->getMessage()); | ||
38 | } | ||
39 | } | ||
40 | |||
41 | public function retrieveAll() { | ||
42 | $sql = "SELECT * FROM entries ORDER BY id"; | ||
43 | $query = $this->executeQuery($sql, array()); | ||
44 | $entries = $query->fetchAll(); | ||
45 | |||
46 | return $entries; | ||
47 | } | ||
48 | |||
49 | public function retrieveOneById($id) { | ||
50 | parent::__construct(); | ||
51 | |||
52 | $entry = NULL; | ||
53 | $sql = "SELECT * FROM entries WHERE id=?"; | ||
54 | $params = array(intval($id)); | ||
55 | $query = $this->executeQuery($sql, $params); | ||
56 | $entry = $query->fetchAll(); | ||
57 | |||
58 | return $entry[0]; | ||
59 | } | ||
60 | |||
61 | public function getEntriesByView($view) { | ||
62 | parent::__construct(); | ||
63 | |||
64 | switch ($_SESSION['sort']) | ||
65 | { | ||
66 | case 'ia': | ||
67 | $order = 'ORDER BY id'; | ||
68 | break; | ||
69 | case 'id': | ||
70 | $order = 'ORDER BY id DESC'; | ||
71 | break; | ||
72 | case 'ta': | ||
73 | $order = 'ORDER BY lower(title)'; | ||
74 | break; | ||
75 | case 'td': | ||
76 | $order = 'ORDER BY lower(title) DESC'; | ||
77 | break; | ||
78 | default: | ||
79 | $order = 'ORDER BY id'; | ||
80 | break; | ||
81 | } | ||
82 | |||
83 | switch ($view) | ||
84 | { | ||
85 | case 'archive': | ||
86 | $sql = "SELECT * FROM entries WHERE is_read=? " . $order; | ||
87 | $params = array(-1); | ||
88 | break; | ||
89 | case 'fav' : | ||
90 | $sql = "SELECT * FROM entries WHERE is_fav=? " . $order; | ||
91 | $params = array(-1); | ||
92 | break; | ||
93 | default: | ||
94 | $sql = "SELECT * FROM entries WHERE is_read=? " . $order; | ||
95 | $params = array(0); | ||
96 | break; | ||
97 | } | ||
98 | |||
99 | $query = $this->executeQuery($sql, $params); | ||
100 | $entries = $query->fetchAll(); | ||
101 | |||
102 | return $entries; | ||
103 | } | ||
104 | |||
105 | public function add($url, $title, $content) { | ||
106 | parent::__construct(); | ||
107 | $sql_action = 'INSERT INTO entries ( url, title, content ) VALUES (?, ?, ?)'; | ||
108 | $params_action = array($url, $title, $content); | ||
109 | $query = $this->executeQuery($sql_action, $params_action); | ||
110 | } | ||
111 | |||
112 | public function deleteById($id) { | ||
113 | parent::__construct(); | ||
114 | $sql_action = "DELETE FROM entries WHERE id=?"; | ||
115 | $params_action = array($id); | ||
116 | $query = $this->executeQuery($sql_action, $params_action); | ||
117 | } | ||
118 | |||
119 | public function favoriteById($id) { | ||
120 | parent::__construct(); | ||
121 | $sql_action = "UPDATE entries SET is_fav=~is_fav WHERE id=?"; | ||
122 | $params_action = array($id); | ||
123 | $query = $this->executeQuery($sql_action, $params_action); | ||
124 | } | ||
125 | |||
126 | public function archiveById($id) { | ||
127 | parent::__construct(); | ||
128 | $sql_action = "UPDATE entries SET is_read=~is_read WHERE id=?"; | ||
129 | $params_action = array($id); | ||
130 | $query = $this->executeQuery($sql_action, $params_action); | ||
131 | } | ||
132 | |||
133 | public function getLastId() { | ||
134 | parent::__construct(); | ||
135 | return $this->getHandle()->lastInsertId(); | ||
136 | } | ||
137 | |||
138 | public function updateContentById($id) { | ||
139 | parent::__construct(); | ||
140 | $sql_update = "UPDATE entries SET content=? WHERE id=?"; | ||
141 | $params_update = array($content, $id); | ||
142 | $query = $this->executeQuery($sql_update, $params_update); | ||
143 | } | ||
144 | } | ||
diff --git a/inc/store/store.class.php b/inc/store/store.class.php new file mode 100644 index 00000000..360ff7c2 --- /dev/null +++ b/inc/store/store.class.php | |||
@@ -0,0 +1,55 @@ | |||
1 | <?php | ||
2 | /** | ||
3 | * poche, a read it later open source system | ||
4 | * | ||
5 | * @category poche | ||
6 | * @author Nicolas LÅ“uillet <support@inthepoche.com> | ||
7 | * @copyright 2013 | ||
8 | * @license http://www.wtfpl.net/ see COPYING file | ||
9 | */ | ||
10 | |||
11 | class Store { | ||
12 | function __construct() { | ||
13 | |||
14 | } | ||
15 | |||
16 | public function add() { | ||
17 | |||
18 | } | ||
19 | |||
20 | public function retrieveAll() { | ||
21 | |||
22 | } | ||
23 | |||
24 | public function retrieveOneById($id) { | ||
25 | |||
26 | } | ||
27 | |||
28 | public function retrieveOneByURL($url) { | ||
29 | |||
30 | } | ||
31 | |||
32 | public function deleteById($id) { | ||
33 | |||
34 | } | ||
35 | |||
36 | public function favoriteById($id) { | ||
37 | |||
38 | } | ||
39 | |||
40 | public function archiveById($id) { | ||
41 | |||
42 | } | ||
43 | |||
44 | public function getEntriesByView($view) { | ||
45 | |||
46 | } | ||
47 | |||
48 | public function getLastId() { | ||
49 | |||
50 | } | ||
51 | |||
52 | public function updateContentById($id) { | ||
53 | |||
54 | } | ||
55 | } | ||
@@ -10,8 +10,8 @@ | |||
10 | 10 | ||
11 | include dirname(__FILE__).'/inc/config.php'; | 11 | include dirname(__FILE__).'/inc/config.php'; |
12 | 12 | ||
13 | # initialize session | 13 | myTool::initPhp(); |
14 | Session::init(); | 14 | |
15 | # XSRF protection with token | 15 | # XSRF protection with token |
16 | if (!empty($_POST)) { | 16 | if (!empty($_POST)) { |
17 | if (!Session::isToken($_POST['token'])) { | 17 | if (!Session::isToken($_POST['token'])) { |
@@ -20,6 +20,8 @@ if (!empty($_POST)) { | |||
20 | unset($_SESSION['tokens']); | 20 | unset($_SESSION['tokens']); |
21 | } | 21 | } |
22 | 22 | ||
23 | $ref = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']; | ||
24 | |||
23 | if (isset($_GET['login'])) { | 25 | if (isset($_GET['login'])) { |
24 | // Login | 26 | // Login |
25 | if (!empty($_POST['login']) && !empty($_POST['password'])) { | 27 | if (!empty($_POST['login']) && !empty($_POST['password'])) { |
@@ -34,7 +36,7 @@ if (isset($_GET['login'])) { | |||
34 | } | 36 | } |
35 | session_regenerate_id(true); | 37 | session_regenerate_id(true); |
36 | 38 | ||
37 | MyTool::redirect(); | 39 | MyTool::redirect($ref); |
38 | } | 40 | } |
39 | logm('login failed'); | 41 | logm('login failed'); |
40 | die("Login failed !"); | 42 | die("Login failed !"); |
@@ -55,12 +57,11 @@ $action = (isset ($_REQUEST['action'])) ? htmlentities($_REQUEST['ac | |||
55 | $_SESSION['sort'] = (isset ($_REQUEST['sort'])) ? htmlentities($_REQUEST['sort']) : 'id'; | 57 | $_SESSION['sort'] = (isset ($_REQUEST['sort'])) ? htmlentities($_REQUEST['sort']) : 'id'; |
56 | $id = (isset ($_REQUEST['id'])) ? htmlspecialchars($_REQUEST['id']) : ''; | 58 | $id = (isset ($_REQUEST['id'])) ? htmlspecialchars($_REQUEST['id']) : ''; |
57 | $url = (isset ($_GET['url'])) ? $_GET['url'] : ''; | 59 | $url = (isset ($_GET['url'])) ? $_GET['url'] : ''; |
58 | $ref = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']; | ||
59 | 60 | ||
60 | $tpl->assign('isLogged', Session::isLogged()); | 61 | $tpl->assign('isLogged', Session::isLogged()); |
61 | $tpl->assign('referer', $ref); | 62 | $tpl->assign('referer', $ref); |
62 | $tpl->assign('view', $view); | 63 | $tpl->assign('view', $view); |
63 | $tpl->assign('poche_url', get_poche_url()); | 64 | $tpl->assign('poche_url', myTool::getUrl()); |
64 | $tpl->assign('title', 'poche, a read it later open source system'); | 65 | $tpl->assign('title', 'poche, a read it later open source system'); |
65 | 66 | ||
66 | if (Session::isLogged()) { | 67 | if (Session::isLogged()) { |
@@ -69,4 +70,4 @@ if (Session::isLogged()) { | |||
69 | } | 70 | } |
70 | else { | 71 | else { |
71 | $tpl->draw('login'); | 72 | $tpl->draw('login'); |
72 | } \ No newline at end of file | 73 | } |
diff --git a/js/poche.js b/js/poche.js index 6bc3c188..97d9911d 100644 --- a/js/poche.js +++ b/js/poche.js | |||
@@ -23,8 +23,35 @@ function toggle_archive(element, id, view_article) { | |||
23 | } | 23 | } |
24 | 24 | ||
25 | function sort_links(view, sort) { | 25 | function sort_links(view, sort) { |
26 | //$('#content').load('index.php', { view: view, sort: sort, full_head: 'no' } ); | ||
27 | $.get('index.php', { view: view, sort: sort, full_head: 'no' }, function(data) { | 26 | $.get('index.php', { view: view, sort: sort, full_head: 'no' }, function(data) { |
28 | $('#content').html(data); | 27 | $('#content').html(data); |
29 | }); | 28 | }); |
30 | } \ No newline at end of file | 29 | } |
30 | |||
31 | |||
32 | // ---------- Swith light or dark view | ||
33 | function setActiveStyleSheet(title) { | ||
34 | var i, a, main; | ||
35 | for(i=0; (a = document.getElementsByTagName("link")[i]); i++) { | ||
36 | if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) { | ||
37 | a.disabled = true; | ||
38 | if(a.getAttribute("title") == title) a.disabled = false; | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | $('#themeswitch').click(function() { | ||
43 | // we want the dark | ||
44 | if ($('body').hasClass('light-style')) { | ||
45 | setActiveStyleSheet('dark-style'); | ||
46 | $('body').addClass('dark-style'); | ||
47 | $('body').removeClass('light-style'); | ||
48 | $('#themeswitch').text('light'); | ||
49 | // we want the light | ||
50 | } else if ($('body').hasClass('dark-style')) { | ||
51 | setActiveStyleSheet('light-style'); | ||
52 | $('body').addClass('light-style'); | ||
53 | $('body').removeClass('dark-style'); | ||
54 | $('#themeswitch').text('dark'); | ||
55 | } | ||
56 | return false; | ||
57 | }); | ||
diff --git a/tpl/config.html b/tpl/config.html new file mode 100644 index 00000000..7d1c6afe --- /dev/null +++ b/tpl/config.html | |||
@@ -0,0 +1,8 @@ | |||
1 | <div id="content"> | ||
2 | <h2>Bookmarklet</h2> | ||
3 | <p>Thanks to the bookmarklet, you will be able to easily add a link to your poche. If you don't know how use a bookmarklet, <a href="http://support.mozilla.org/en-US/kb/bookmarklets-perform-common-web-page-tasks">have a look here</a>.</p> | ||
4 | <p>Drag & drop this link to your bookmarks bar and have fun with poche.</p> | ||
5 | <p><a style="cursor: move; border: 1px dashed grey; background: white;" title="i am a bookmarklet, use me !" href="javascript:(function(){var%20url%20=%20location.href%20||%20url;window.open('{$poche_url}?action=add&url='%20+%20encodeURIComponent(url),'_self');})();">poche it !</a></p> | ||
6 | <h2>Export</h2> | ||
7 | <p><a href="?view=export" target="_blank">Click here</a> to export your poche datas.</p> | ||
8 | </div> \ No newline at end of file | ||
diff --git a/tpl/entries.html b/tpl/entries.html index 648e1ce9..8526a3c9 100644 --- a/tpl/entries.html +++ b/tpl/entries.html | |||
@@ -1,3 +1,4 @@ | |||
1 | <div id="content"> | ||
1 | {loop="entries"} | 2 | {loop="entries"} |
2 | <div id="entry-{$value.id}" class="entrie mb2"> | 3 | <div id="entry-{$value.id}" class="entrie mb2"> |
3 | <span class="content"> | 4 | <span class="content"> |
@@ -13,4 +14,5 @@ | |||
13 | </div> | 14 | </div> |
14 | </span> | 15 | </span> |
15 | </div> | 16 | </div> |
16 | {/loop} \ No newline at end of file | 17 | {/loop} |
18 | </div> \ No newline at end of file | ||
diff --git a/tpl/export.html b/tpl/export.html new file mode 100644 index 00000000..d22d05fc --- /dev/null +++ b/tpl/export.html | |||
@@ -0,0 +1 @@ | |||
export {$export} \ No newline at end of file | |||
diff --git a/tpl/footer.html b/tpl/footer.html index 04bedabc..b8bd755c 100644 --- a/tpl/footer.html +++ b/tpl/footer.html | |||
@@ -1,6 +1,4 @@ | |||
1 | </div> | 1 | </div> |
2 | </div> | ||
3 | |||
4 | <footer class="mr2 mt3 smaller"> | 2 | <footer class="mr2 mt3 smaller"> |
5 | <p>powered by <a href="http://inthepoche.com">poche</a><br />follow us on <a href="https://twitter.com/getpoche" title="follow us on twitter">twitter</a></p> | 3 | <p>powered by <a href="http://inthepoche.com">poche</a><br />follow us on <a href="https://twitter.com/getpoche" title="follow us on twitter">twitter</a></p> |
6 | </footer> | 4 | </footer> |
diff --git a/tpl/head.html b/tpl/head.html index 6fcf9741..e95f6100 100644 --- a/tpl/head.html +++ b/tpl/head.html | |||
@@ -15,9 +15,8 @@ | |||
15 | <link rel="apple-touch-icon-precomposed" href="./img/apple-touch-icon-precomposed.png"> | 15 | <link rel="apple-touch-icon-precomposed" href="./img/apple-touch-icon-precomposed.png"> |
16 | <link rel="stylesheet" href="./css/knacss.css" media="all"> | 16 | <link rel="stylesheet" href="./css/knacss.css" media="all"> |
17 | <link rel="stylesheet" href="./css/style.css" media="all"> | 17 | <link rel="stylesheet" href="./css/style.css" media="all"> |
18 | </head> | 18 | <!-- Light Theme --> |
19 | <body> | 19 | <link rel="stylesheet" href="./css/style-light.css" media="all" title="light-style"> |
20 | <header> | 20 | <!-- Dark Theme --> |
21 | <h1><img src="./img/logo.png" alt="logo poche" />poche</h1> | 21 | <link rel="alternate stylesheet" href="./css/style-dark.css" media="all" title="dark-style"> |
22 | </header> | 22 | </head> \ No newline at end of file |
23 | <div id="main"> \ No newline at end of file | ||
diff --git a/tpl/home.html b/tpl/home.html index 6fb9444c..ad881997 100644 --- a/tpl/home.html +++ b/tpl/home.html | |||
@@ -1,12 +1,19 @@ | |||
1 | <body class="light-style"> | ||
2 | <header> | ||
3 | <h1><img src="./img/logo.png" alt="logo poche" />poche</h1> | ||
4 | </header> | ||
5 | <div id="main"> | ||
1 | <ul id="links"> | 6 | <ul id="links"> |
2 | <li><a href="index.php" {if="$view == 'index'"}class="current"{/if}>home</a></li> | 7 | <li><a href="index.php" {if="$view == 'index'"}class="current"{/if}>home</a></li> |
3 | <li><a href="?view=fav" {if="$view == 'fav'"}class="current"{/if}>favorites</a></li> | 8 | <li><a href="?view=fav" {if="$view == 'fav'"}class="current"{/if}>favorites</a></li> |
4 | <li><a href="?view=archive" {if="$view == 'archive'"}class="current"{/if}>archive</a></li> | 9 | <li><a href="?view=archive" {if="$view == 'archive'"}class="current"{/if}>archive</a></li> |
5 | <li><a style="cursor: move" title="i am a bookmarklet, use me !" href="javascript:(function(){var%20url%20=%20location.href%20||%20url;window.open('{$poche_url}?action=add&url='%20+%20encodeURIComponent(url),'_self');})();">poche it !</a></li> | 10 | <li><a href="?view=config" {if="$view == 'config'"}class="current"{/if}>config</a></li> |
6 | <li><a href="?logout" title="Logout">logout</a></li> | 11 | <li><a href="?logout" title="Logout">logout</a></li> |
7 | </ul> | 12 | </ul> |
13 | {if condition="isset($entries)"} | ||
8 | <ul id="sort"> | 14 | <ul id="sort"> |
9 | <li><img src="img/up.png" onclick="sort_links('{$view}', 'ia');" title="by date asc" /> by date <img src="img/down.png" onclick="sort_links('{$view}', 'id');" title="by date desc" /></li> | 15 | <li><img src="img/up.png" onclick="sort_links('{$view}', 'ia');" title="by date asc" /> by date <img src="img/down.png" onclick="sort_links('{$view}', 'id');" title="by date desc" /></li> |
10 | <li><img src="img/up.png" onclick="sort_links('{$view}', 'ta');" title="by title asc" /> by title <img src="img/down.png" onclick="sort_links('{$view}', 'td');" title="by title desc" /></li> | 16 | <li><img src="img/up.png" onclick="sort_links('{$view}', 'ta');" title="by title asc" /> by title <img src="img/down.png" onclick="sort_links('{$view}', 'td');" title="by title desc" /></li> |
11 | </ul> | 17 | </ul> |
12 | <div id="content"> \ No newline at end of file | 18 | {/if} |
19 | {include="messages"} \ No newline at end of file | ||
diff --git a/tpl/login.html b/tpl/login.html index d3139ab3..12927692 100644 --- a/tpl/login.html +++ b/tpl/login.html | |||
@@ -1,4 +1,9 @@ | |||
1 | {include="head"} | 1 | {include="head"} |
2 | <body class="light-style"> | ||
3 | <header> | ||
4 | <h1><img src="./img/logo.png" alt="logo poche" />poche</h1> | ||
5 | </header> | ||
6 | <div id="main"> | ||
2 | <form method="post" action="?login" name="loginform"> | 7 | <form method="post" action="?login" name="loginform"> |
3 | <fieldset> | 8 | <fieldset> |
4 | <h2>login to your poche</h2> | 9 | <h2>login to your poche</h2> |
@@ -20,4 +25,7 @@ | |||
20 | <input type="hidden" name="returnurl" value="<?php echo htmlspecialchars($referer);?>"> | 25 | <input type="hidden" name="returnurl" value="<?php echo htmlspecialchars($referer);?>"> |
21 | <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>"> | 26 | <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>"> |
22 | </form> | 27 | </form> |
23 | {include="footer"} \ No newline at end of file | 28 | <script type="text/javascript"> |
29 | window.onload = document.loginform.login.focus(); | ||
30 | </script> | ||
31 | {include="footer"} | ||
diff --git a/tpl/messages.html b/tpl/messages.html new file mode 100644 index 00000000..87af259b --- /dev/null +++ b/tpl/messages.html | |||
@@ -0,0 +1 @@ | |||
<div id="messages"><?php echo $msg->display(); ?></div> \ No newline at end of file | |||
diff --git a/tpl/view.html b/tpl/view.html index 4b8ce60f..4384631b 100644 --- a/tpl/view.html +++ b/tpl/view.html | |||
@@ -15,8 +15,12 @@ | |||
15 | <link rel="apple-touch-icon-precomposed" href="./img/apple-touch-icon-precomposed.png"> | 15 | <link rel="apple-touch-icon-precomposed" href="./img/apple-touch-icon-precomposed.png"> |
16 | <link rel="stylesheet" href="./css/knacss.css" media="all"> | 16 | <link rel="stylesheet" href="./css/knacss.css" media="all"> |
17 | <link rel="stylesheet" href="./css/style.css" media="all"> | 17 | <link rel="stylesheet" href="./css/style.css" media="all"> |
18 | <!-- Light Theme --> | ||
19 | <link rel="stylesheet" href="./css/style-light.css" media="all" title="light-style"> | ||
20 | <!-- Dark Theme --> | ||
21 | <link rel="alternate stylesheet" href="./css/style-dark.css" media="all" title="dark-style"> | ||
18 | </head> | 22 | </head> |
19 | <body class="article"> | 23 | <body class="article light-style"> |
20 | <div id="article" class="w600p"> | 24 | <div id="article" class="w600p"> |
21 | <div class="backhome"> | 25 | <div class="backhome"> |
22 | <a href="index.php" title="back to home">←</a> | 26 | <a href="index.php" title="back to home">←</a> |
@@ -24,6 +28,7 @@ | |||
24 | <div class="tools"> | 28 | <div class="tools"> |
25 | <ul> | 29 | <ul> |
26 | <li><a title="toggle mark as read" class="tool archive {if="$is_read == '0'"}archive-off{/if}" onclick="toggle_archive(this, {$id})"><span></span></a></li> | 30 | <li><a title="toggle mark as read" class="tool archive {if="$is_read == '0'"}archive-off{/if}" onclick="toggle_archive(this, {$id})"><span></span></a></li> |
31 | <li><a href="#" id="themeswitch">dark</a></li> | ||
27 | <li><a title="toggle favorite" class="tool fav {if="$is_fav == '0'"}fav-off{/if}" onclick="toggle_favorite(this, {$id})"><span></span></a></li> | 32 | <li><a title="toggle favorite" class="tool fav {if="$is_fav == '0'"}fav-off{/if}" onclick="toggle_favorite(this, {$id})"><span></span></a></li> |
28 | <li><form method="post" onsubmit="return confirm('Are you sure?')" style="display: inline;" action="index.php"><input type="hidden" name="token" id="token" value="<?php echo Session::getToken(); ?>" /><input type="hidden" id="view" name="view" value="index" /><input type="hidden" id="action" name="action" value="delete" /><input type="hidden" id="id" name="id" value="{$id}" /><input type="submit" class="delete" title="toggle delete" /></form></li> | 33 | <li><form method="post" onsubmit="return confirm('Are you sure?')" style="display: inline;" action="index.php"><input type="hidden" name="token" id="token" value="<?php echo Session::getToken(); ?>" /><input type="hidden" id="view" name="view" value="index" /><input type="hidden" id="action" name="action" value="delete" /><input type="hidden" id="id" name="id" value="{$id}" /><input type="submit" class="delete" title="toggle delete" /></form></li> |
29 | <li><a href="?logout" title="Logout">logout</a></li> | 34 | <li><a href="?logout" title="Logout">logout</a></li> |
@@ -42,13 +47,6 @@ | |||
42 | <div class="backhome"> | 47 | <div class="backhome"> |
43 | <a href="index.php" title="back to home">←</a> | 48 | <a href="index.php" title="back to home">←</a> |
44 | </div> | 49 | </div> |
45 | </div> | ||
46 | 50 | ||
47 | {include="js"} | 51 | {include="js"} |
48 | 52 | {include="footer"} \ No newline at end of file | |
49 | <footer class="mr2 mt3 smaller"> | ||
50 | <p>powered by <a href="http://inthepoche.com">poche</a><br />follow us on <a href="https://twitter.com/getpoche" title="follow us on twitter">twitter</a></p> | ||
51 | </footer> | ||
52 | |||
53 | </body> | ||
54 | </html> \ No newline at end of file | ||