diff options
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | .travis.yml | 15 | ||||
-rw-r--r-- | CREDITS | 12 | ||||
-rw-r--r-- | INSTALL.md | 53 | ||||
-rw-r--r-- | README.md | 30 | ||||
-rw-r--r-- | TODO.md | 11 | ||||
-rw-r--r-- | composer.json | 7 | ||||
-rw-r--r-- | composer.lock | 744 | ||||
-rw-r--r-- | css/style-dark.css | 90 | ||||
-rw-r--r-- | css/style-light.css | 100 | ||||
-rw-r--r-- | css/style.css | 215 | ||||
-rw-r--r-- | img/dark/checkmark-off.png | bin | 267 -> 0 bytes | |||
-rw-r--r-- | img/dark/checkmark-on.png | bin | 221 -> 0 bytes | |||
-rw-r--r-- | img/dark/down.png | bin | 223 -> 0 bytes | |||
-rw-r--r-- | img/dark/logo.png | bin | 786 -> 0 bytes | |||
-rw-r--r-- | img/dark/remove.png | bin | 265 -> 0 bytes | |||
-rw-r--r-- | img/dark/star-off.png | bin | 330 -> 0 bytes | |||
-rw-r--r-- | img/dark/star-on.png | bin | 277 -> 0 bytes | |||
-rw-r--r-- | img/dark/up.png | bin | 225 -> 0 bytes | |||
-rw-r--r-- | img/logo.png | bin | 911 -> 0 bytes | |||
-rw-r--r-- | import.php | 50 | ||||
-rw-r--r-- | inc/3rdparty/Encoding.php (renamed from inc/Encoding.php) | 0 | ||||
-rw-r--r-- | inc/3rdparty/JSLikeHTMLElement.php (renamed from inc/JSLikeHTMLElement.php) | 12 | ||||
-rw-r--r-- | inc/3rdparty/Readability.php (renamed from inc/Readability.php) | 198 | ||||
-rw-r--r-- | inc/3rdparty/Session.class.php (renamed from inc/Session.class.php) | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | inc/3rdparty/class.messages.php (renamed from inc/class.messages.php) | 460 | ||||
-rw-r--r-- | inc/3rdparty/paginator.php | 202 | ||||
-rw-r--r-- | inc/3rdparty/simple_html_dom.php (renamed from inc/simple_html_dom.php) | 0 | ||||
-rw-r--r-- | inc/MyTool.class.php | 265 | ||||
-rw-r--r-- | inc/config.php | 66 | ||||
-rw-r--r-- | inc/functions.php | 398 | ||||
-rw-r--r-- | inc/poche/Database.class.php | 216 | ||||
-rw-r--r-- | inc/poche/Poche.class.php | 485 | ||||
-rw-r--r-- | inc/poche/Tools.class.php | 226 | ||||
-rw-r--r-- | inc/poche/Url.class.php | 94 | ||||
-rw-r--r-- | inc/poche/User.class.php | 50 | ||||
-rw-r--r-- | inc/poche/config.inc.php | 61 | ||||
-rw-r--r-- | inc/poche/pochePictures.php | 110 | ||||
-rw-r--r-- | inc/rain.tpl.class.php | 1043 | ||||
-rw-r--r-- | inc/store/file.class.php | 51 | ||||
-rw-r--r-- | inc/store/sqlite.class.php | 202 | ||||
-rw-r--r-- | inc/store/store.class.php | 63 | ||||
-rw-r--r-- | index.php | 108 | ||||
-rw-r--r-- | install/mysql.sql | 34 | ||||
-rwxr-xr-x | install/poche.sqlite (renamed from db/poche.sqlite) | bin | 294912 -> 360448 bytes | |||
-rw-r--r-- | install/postgres.sql | 30 | ||||
-rw-r--r-- | install/update_sqlite_from_0_to_1.php | 72 | ||||
-rw-r--r-- | js/jquery-1.9.1.min.js | 5 | ||||
-rw-r--r-- | js/jquery.masonry.min.js | 10 | ||||
-rw-r--r-- | js/poche.js | 57 | ||||
-rw-r--r-- | locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.mo | bin | 0 -> 5699 bytes | |||
-rw-r--r-- | locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.po | 376 | ||||
-rw-r--r-- | phpunit.xml.dist | 0 | ||||
-rw-r--r-- | tpl/_bookmarklet.twig | 3 | ||||
-rw-r--r-- | tpl/_footer.twig | 4 | ||||
-rw-r--r-- | tpl/_head.twig | 9 | ||||
-rw-r--r-- | tpl/_menu.twig | 7 | ||||
-rw-r--r-- | tpl/_messages.twig | 1 | ||||
-rw-r--r-- | tpl/_top.twig | 3 | ||||
-rw-r--r-- | tpl/config.html | 27 | ||||
-rw-r--r-- | tpl/config.twig | 57 | ||||
-rw-r--r-- | tpl/css/knacss.css (renamed from css/knacss.css) | 0 | ||||
-rwxr-xr-x | tpl/css/messages.css | 13 | ||||
-rw-r--r-- | tpl/css/style-light.css | 53 | ||||
-rw-r--r-- | tpl/css/style.css | 244 | ||||
-rw-r--r-- | tpl/entries.html | 18 | ||||
-rw-r--r-- | tpl/export.html | 1 | ||||
-rw-r--r-- | tpl/export.twig | 1 | ||||
-rw-r--r-- | tpl/footer.html | 7 | ||||
-rw-r--r-- | tpl/head.html | 22 | ||||
-rw-r--r-- | tpl/home.html | 19 | ||||
-rw-r--r-- | tpl/home.twig | 29 | ||||
-rw-r--r-- | tpl/img/apple-touch-icon-144x144-precomposed.png (renamed from img/apple-touch-icon-144x144-precomposed.png) | bin | 7349 -> 7349 bytes | |||
-rw-r--r-- | tpl/img/apple-touch-icon-72x72-precomposed.png (renamed from img/apple-touch-icon-72x72-precomposed.png) | bin | 6168 -> 6168 bytes | |||
-rw-r--r-- | tpl/img/apple-touch-icon.png (renamed from img/apple-touch-icon.png) | bin | 5803 -> 5803 bytes | |||
-rw-r--r-- | tpl/img/favicon.ico (renamed from img/favicon.ico) | bin | 346 -> 346 bytes | |||
-rw-r--r-- | tpl/img/light/checkmark-off.png (renamed from img/light/checkmark-off.png) | bin | 277 -> 277 bytes | |||
-rw-r--r-- | tpl/img/light/checkmark-on.png (renamed from img/light/checkmark-on.png) | bin | 235 -> 235 bytes | |||
-rw-r--r-- | tpl/img/light/down.png (renamed from img/down.png) | bin | 216 -> 216 bytes | |||
-rwxr-xr-x | tpl/img/light/envelop.png | bin | 0 -> 285 bytes | |||
-rwxr-xr-x | tpl/img/light/left.png | bin | 0 -> 196 bytes | |||
-rw-r--r-- | tpl/img/light/remove.png (renamed from img/light/remove.png) | bin | 252 -> 252 bytes | |||
-rw-r--r-- | tpl/img/light/star-off.png (renamed from img/light/star-off.png) | bin | 314 -> 314 bytes | |||
-rw-r--r-- | tpl/img/light/star-on.png (renamed from img/light/star-on.png) | bin | 281 -> 281 bytes | |||
-rwxr-xr-x[-rw-r--r--] | tpl/img/light/top.png (renamed from img/up.png) | bin | 212 -> 212 bytes | |||
-rwxr-xr-x | tpl/img/light/twitter.png | bin | 0 -> 297 bytes | |||
-rw-r--r-- | tpl/img/logo.png | bin | 0 -> 454 bytes | |||
-rwxr-xr-x[-rw-r--r--] | tpl/img/messages/close.png (renamed from img/messages/close.png) | bin | 662 -> 662 bytes | |||
-rwxr-xr-x[-rw-r--r--] | tpl/img/messages/cross.png (renamed from img/messages/cross.png) | bin | 655 -> 655 bytes | |||
-rwxr-xr-x[-rw-r--r--] | tpl/img/messages/help.png (renamed from img/messages/help.png) | bin | 786 -> 786 bytes | |||
-rwxr-xr-x[-rw-r--r--] | tpl/img/messages/tick.png (renamed from img/messages/tick.png) | bin | 537 -> 537 bytes | |||
-rwxr-xr-x[-rw-r--r--] | tpl/img/messages/warning.png (renamed from img/messages/warning.png) | bin | 666 -> 666 bytes | |||
-rw-r--r-- | tpl/install.html | 30 | ||||
-rw-r--r-- | tpl/install.twig | 28 | ||||
-rw-r--r-- | tpl/js.html | 22 | ||||
-rw-r--r-- | tpl/layout.twig | 29 | ||||
-rw-r--r-- | tpl/login.html | 33 | ||||
-rw-r--r-- | tpl/login.twig | 32 | ||||
-rw-r--r-- | tpl/messages.html | 1 | ||||
-rw-r--r-- | tpl/view.html | 53 | ||||
-rw-r--r-- | tpl/view.twig | 40 |
101 files changed, 3733 insertions, 3281 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..5e992c2e --- /dev/null +++ b/.gitignore | |||
@@ -0,0 +1,5 @@ | |||
1 | vendor | ||
2 | composer.phar | ||
3 | db/poche.sqlite | ||
4 | output | ||
5 | phpdoc* \ No newline at end of file | ||
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..9d6ba132 --- /dev/null +++ b/.travis.yml | |||
@@ -0,0 +1,15 @@ | |||
1 | language: php | ||
2 | |||
3 | php: | ||
4 | - 5.4 | ||
5 | |||
6 | branches: | ||
7 | only: | ||
8 | - dev | ||
9 | |||
10 | before_script: | ||
11 | - composer install | ||
12 | |||
13 | notifications: | ||
14 | email: | ||
15 | - nicolas.loeuillet@gmail.com \ No newline at end of file | ||
@@ -1,16 +1,14 @@ | |||
1 | poche is based on : | 1 | poche is based on : |
2 | * ReadItYourself http://www.memiks.fr/readityourself/ | 2 | * PHP Readability https://bitbucket.org/fivefilters/php-readability |
3 | * PHP Readability http://www.keyvan.net/2010/08/php-readability/ | ||
4 | * Encoding https://github.com/neitanod/forceutf8 | 3 | * Encoding https://github.com/neitanod/forceutf8 |
5 | * logo by Brightmix http://www.iconfinder.com/icondetails/43256/128/jeans_monotone_pocket_icon | 4 | * logo by Brightmix http://www.iconfinder.com/icondetails/43256/128/jeans_monotone_pocket_icon |
6 | * icons http://icomoon.io | 5 | * icons http://icomoon.io |
7 | * PHP Simple HTML DOM Parser (for Pocket import) http://simplehtmldom.sourceforge.net/ | 6 | * PHP Simple HTML DOM Parser (for Pocket import) http://simplehtmldom.sourceforge.net/ |
8 | * Session https://github.com/tontof/kriss_feed/blob/master/src/class/Session.php | 7 | * Session https://github.com/tontof/kriss_feed/blob/master/src/class/Session.php |
8 | * Twig http://twig.sensiolabs.org | ||
9 | * Flash messages https://github.com/plasticbrain/PHP-Flash-Messages | ||
10 | * Pagination https://github.com/daveismyname/pagination | ||
9 | 11 | ||
10 | poche is developed by Nicolas LÅ“uillet under the Do What the Fuck You Want to Public License | 12 | poche is developed by Nicolas LÅ“uillet under the Do What the Fuck You Want to Public License |
11 | 13 | ||
12 | Contributors : | 14 | Contributors : https://github.com/inthepoche/poche/graphs/contributors \ No newline at end of file |
13 | Nicolas LÅ“uillet aka nico_somb | ||
14 | Tom.C. aka tmos | ||
15 | PeaceCopathe | ||
16 | Gregoire_M \ No newline at end of file | ||
diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 00000000..cf027282 --- /dev/null +++ b/INSTALL.md | |||
@@ -0,0 +1,53 @@ | |||
1 | # Installing poche | ||
2 | |||
3 | Get the [latest dev version](https://github.com/inthepoche/poche/archive/dev.zip) of poche on github. Unzip it and upload it on your server. | ||
4 | |||
5 | your datas can be stored on sqlite, postgres or mysql databases. | ||
6 | |||
7 | Edit /inc/poche/config.inc.php : | ||
8 | |||
9 | ```php | ||
10 | define ('STORAGE','sqlite'); # postgres, mysql, sqlite | ||
11 | define ('STORAGE_SERVER', 'localhost'); # leave blank for sqlite | ||
12 | define ('STORAGE_DB', 'poche'); # only for postgres & mysql | ||
13 | define ('STORAGE_SQLITE', './db/poche.sqlite'); | ||
14 | define ('STORAGE_USER', 'user'); # leave blank for sqlite | ||
15 | define ('STORAGE_PASSWORD', 'pass'); # leave blank for sqlite | ||
16 | ``` | ||
17 | |||
18 | poche must have write access on assets, cache and db directories. | ||
19 | |||
20 | [PHP cURL](http://www.php.net/manual/en/book.curl.php) & [tidy_parse_string](http://www.php.net/manual/en/tidy.parsestring.php) are recommended. | ||
21 | |||
22 | ## twig | ||
23 | poche now uses twig for templating. You have to install twig. | ||
24 | |||
25 | Install composer in your project : | ||
26 | ```bash | ||
27 | curl -s http://getcomposer.org/installer | php | ||
28 | ``` | ||
29 | Install via composer : | ||
30 | ```bash | ||
31 | php composer.phar install | ||
32 | ``` | ||
33 | |||
34 | If you don't want to install twig by yourself, you can download [this file](http://static.inthepoche.com/files/poche-1.0-latest-with-twig.zip). | ||
35 | |||
36 | ## storage in sqlite | ||
37 | You have to install [sqlite for php](http://www.php.net/manual/en/book.sqlite.php) on your server. | ||
38 | |||
39 | Copy /install/poche.sqlite in /db | ||
40 | |||
41 | ## storage in mysql | ||
42 | Execute /install/mysql.sql file in your database. | ||
43 | |||
44 | ## storage in postgres | ||
45 | Execute /install/postgres.sql file in your database. | ||
46 | |||
47 | ## upgrading from poche <= 0.3 | ||
48 | With poche <= 0.3, all your datas were stored in a sqlite file. The structure of this file changed. | ||
49 | |||
50 | You have to execute http://yourpoche/install/update_sqlite_from_0_to_1.php before using this new version. | ||
51 | |||
52 | ## installing poche | ||
53 | you can go on your poche http://yourpoche. You have to fill the fields and that's all ! \ No newline at end of file | ||
@@ -1,5 +1,5 @@ | |||
1 | # poche | 1 | # poche |
2 | Abandon Pocket, Instapaper and other Readability service : adopt poche. It is the same, but it is open source. | 2 | Abandon Pocket, Instapaper and other Readability service : adopt poche. It is the same, but it is open source. Moreover, you can migrate from Pocket & Readability. |
3 | 3 | ||
4 | ![poche](http://inthepoche.com/img/logo.png) | 4 | ![poche](http://inthepoche.com/img/logo.png) |
5 | 5 | ||
@@ -11,24 +11,6 @@ To get news from poche, [follow us on twitter](http://twitter.com/getpoche) or [ | |||
11 | 11 | ||
12 | [![flattr](http://api.flattr.com/button/flattr-badge-large.png)](http://flattr.com/thing/1265480/poche-a-read-it-later-open-source-system) | 12 | [![flattr](http://api.flattr.com/button/flattr-badge-large.png)](http://flattr.com/thing/1265480/poche-a-read-it-later-open-source-system) |
13 | 13 | ||
14 | ## Usage | ||
15 | You can easily add a "poched" page with the bookmarklet. | ||
16 | |||
17 | poche save the entire content of a poched links : text and pictures are stored on your server. | ||
18 | |||
19 | You can : | ||
20 | * read a page in a comfortable reading view | ||
21 | * archive a link | ||
22 | * put a link in favorite | ||
23 | * delete a link | ||
24 | |||
25 | ## Requirements & installation | ||
26 | You have to install [sqlite for php](http://www.php.net/manual/en/book.sqlite.php) on your server. | ||
27 | |||
28 | Get the [latest version](https://github.com/inthepoche/poche) of poche on github. Unzip it and upload it on your server. poche must have write access on assets, cache and db directories. | ||
29 | |||
30 | That's all, **poche works** ! | ||
31 | |||
32 | ## Security | 14 | ## Security |
33 | You **have** to protect your db/poche.sqlite file. Modify the virtual host of your website to add this condition : | 15 | You **have** to protect your db/poche.sqlite file. Modify the virtual host of your website to add this condition : |
34 | ```apache | 16 | ```apache |
@@ -46,12 +28,14 @@ location ~ /(db) { | |||
46 | } | 28 | } |
47 | ``` | 29 | ``` |
48 | 30 | ||
49 | ## Import from Pocket | 31 | ## Usage |
32 | See the documentation on our website : [inthepoche.com](http://inthepoche.com). | ||
50 | 33 | ||
51 | If you want to import your Pocket datas, [export them here](https://getpocket.com/export). Put the HTML file in your poche directory, execute import.php file locally by following instructions. Be careful, the script can take a very long time. | 34 | ## Travis |
35 | [![Build Status](https://api.travis-ci.org/inthepoche/poche.png?branch=dev)](http://travis-ci.org/#!/inthepoche/poche) | ||
52 | 36 | ||
53 | ## License | 37 | ## License |
54 | Copyright © 2010-2013 Nicolas Lœuillet <nicolas@loeuillet.org> | 38 | Copyright © 2010-2013 Nicolas Lœuillet <nicolas.loeuillet@gmail.com> |
55 | This work is free. You can redistribute it and/or modify it under the | 39 | This work is free. You can redistribute it and/or modify it under the |
56 | terms of the Do What The Fuck You Want To Public License, Version 2, | 40 | terms of the Do What The Fuck You Want To Public License, Version 2, |
57 | as published by Sam Hocevar. See the COPYING file for more details. | 41 | as published by Sam Hocevar. See the COPYING file for more details. \ No newline at end of file |
diff --git a/TODO.md b/TODO.md new file mode 100644 index 00000000..ac3c0e98 --- /dev/null +++ b/TODO.md | |||
@@ -0,0 +1,11 @@ | |||
1 | # TODO | ||
2 | |||
3 | pouvoir annuler la suppression | ||
4 | conventions codage ? phing ? vérifier error_log qui trainent | ||
5 | phpDocumentor | ||
6 | minifier css | ||
7 | revoir tous les css | ||
8 | barre fixe d'admin sur la page d'un billet ? | ||
9 | revoir export (export vers pocket &cie ? ) | ||
10 | raccourcis clavier | ||
11 | date d'ajout d'un lien \ No newline at end of file | ||
diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..6c69e48d --- /dev/null +++ b/composer.json | |||
@@ -0,0 +1,7 @@ | |||
1 | { | ||
2 | "require": { | ||
3 | "twig/twig": "1.*", | ||
4 | "twig/extensions": "1.0.*", | ||
5 | "umpirsky/twig-gettext-extractor": "1.1.*" | ||
6 | } | ||
7 | } \ No newline at end of file | ||
diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..9e17fca9 --- /dev/null +++ b/composer.lock | |||
@@ -0,0 +1,744 @@ | |||
1 | { | ||
2 | "_readme": [ | ||
3 | "This file locks the dependencies of your project to a known state", | ||
4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" | ||
5 | ], | ||
6 | "hash": "1c8badb14d91f4f3ef1cfae23252a2c4", | ||
7 | "packages": [ | ||
8 | { | ||
9 | "name": "symfony/event-dispatcher", | ||
10 | "version": "v2.3.2", | ||
11 | "target-dir": "Symfony/Component/EventDispatcher", | ||
12 | "source": { | ||
13 | "type": "git", | ||
14 | "url": "https://github.com/symfony/EventDispatcher.git", | ||
15 | "reference": "v2.3.2" | ||
16 | }, | ||
17 | "dist": { | ||
18 | "type": "zip", | ||
19 | "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.2", | ||
20 | "reference": "v2.3.2", | ||
21 | "shasum": "" | ||
22 | }, | ||
23 | "require": { | ||
24 | "php": ">=5.3.3" | ||
25 | }, | ||
26 | "require-dev": { | ||
27 | "symfony/dependency-injection": "~2.0" | ||
28 | }, | ||
29 | "suggest": { | ||
30 | "symfony/dependency-injection": "", | ||
31 | "symfony/http-kernel": "" | ||
32 | }, | ||
33 | "type": "library", | ||
34 | "extra": { | ||
35 | "branch-alias": { | ||
36 | "dev-master": "2.3-dev" | ||
37 | } | ||
38 | }, | ||
39 | "autoload": { | ||
40 | "psr-0": { | ||
41 | "Symfony\\Component\\EventDispatcher\\": "" | ||
42 | } | ||
43 | }, | ||
44 | "notification-url": "https://packagist.org/downloads/", | ||
45 | "license": [ | ||
46 | "MIT" | ||
47 | ], | ||
48 | "authors": [ | ||
49 | { | ||
50 | "name": "Fabien Potencier", | ||
51 | "email": "fabien@symfony.com" | ||
52 | }, | ||
53 | { | ||
54 | "name": "Symfony Community", | ||
55 | "homepage": "http://symfony.com/contributors" | ||
56 | } | ||
57 | ], | ||
58 | "description": "Symfony EventDispatcher Component", | ||
59 | "homepage": "http://symfony.com", | ||
60 | "time": "2013-05-13 14:36:40" | ||
61 | }, | ||
62 | { | ||
63 | "name": "symfony/filesystem", | ||
64 | "version": "v2.3.2", | ||
65 | "target-dir": "Symfony/Component/Filesystem", | ||
66 | "source": { | ||
67 | "type": "git", | ||
68 | "url": "https://github.com/symfony/Filesystem.git", | ||
69 | "reference": "v2.3.2" | ||
70 | }, | ||
71 | "dist": { | ||
72 | "type": "zip", | ||
73 | "url": "https://api.github.com/repos/symfony/Filesystem/zipball/v2.3.2", | ||
74 | "reference": "v2.3.2", | ||
75 | "shasum": "" | ||
76 | }, | ||
77 | "require": { | ||
78 | "php": ">=5.3.3" | ||
79 | }, | ||
80 | "type": "library", | ||
81 | "extra": { | ||
82 | "branch-alias": { | ||
83 | "dev-master": "2.3-dev" | ||
84 | } | ||
85 | }, | ||
86 | "autoload": { | ||
87 | "psr-0": { | ||
88 | "Symfony\\Component\\Filesystem\\": "" | ||
89 | } | ||
90 | }, | ||
91 | "notification-url": "https://packagist.org/downloads/", | ||
92 | "license": [ | ||
93 | "MIT" | ||
94 | ], | ||
95 | "authors": [ | ||
96 | { | ||
97 | "name": "Fabien Potencier", | ||
98 | "email": "fabien@symfony.com" | ||
99 | }, | ||
100 | { | ||
101 | "name": "Symfony Community", | ||
102 | "homepage": "http://symfony.com/contributors" | ||
103 | } | ||
104 | ], | ||
105 | "description": "Symfony Filesystem Component", | ||
106 | "homepage": "http://symfony.com", | ||
107 | "time": "2013-06-04 15:02:05" | ||
108 | }, | ||
109 | { | ||
110 | "name": "symfony/form", | ||
111 | "version": "v2.3.2", | ||
112 | "target-dir": "Symfony/Component/Form", | ||
113 | "source": { | ||
114 | "type": "git", | ||
115 | "url": "https://github.com/symfony/Form.git", | ||
116 | "reference": "v2.3.2" | ||
117 | }, | ||
118 | "dist": { | ||
119 | "type": "zip", | ||
120 | "url": "https://api.github.com/repos/symfony/Form/zipball/v2.3.2", | ||
121 | "reference": "v2.3.2", | ||
122 | "shasum": "" | ||
123 | }, | ||
124 | "require": { | ||
125 | "php": ">=5.3.3", | ||
126 | "symfony/event-dispatcher": "~2.1", | ||
127 | "symfony/intl": "~2.3", | ||
128 | "symfony/options-resolver": "~2.1", | ||
129 | "symfony/property-access": "~2.2" | ||
130 | }, | ||
131 | "require-dev": { | ||
132 | "symfony/http-foundation": "~2.2", | ||
133 | "symfony/validator": "~2.2" | ||
134 | }, | ||
135 | "suggest": { | ||
136 | "symfony/http-foundation": "", | ||
137 | "symfony/validator": "" | ||
138 | }, | ||
139 | "type": "library", | ||
140 | "extra": { | ||
141 | "branch-alias": { | ||
142 | "dev-master": "2.3-dev" | ||
143 | } | ||
144 | }, | ||
145 | "autoload": { | ||
146 | "psr-0": { | ||
147 | "Symfony\\Component\\Form\\": "" | ||
148 | } | ||
149 | }, | ||
150 | "notification-url": "https://packagist.org/downloads/", | ||
151 | "license": [ | ||
152 | "MIT" | ||
153 | ], | ||
154 | "authors": [ | ||
155 | { | ||
156 | "name": "Fabien Potencier", | ||
157 | "email": "fabien@symfony.com" | ||
158 | }, | ||
159 | { | ||
160 | "name": "Symfony Community", | ||
161 | "homepage": "http://symfony.com/contributors" | ||
162 | } | ||
163 | ], | ||
164 | "description": "Symfony Form Component", | ||
165 | "homepage": "http://symfony.com", | ||
166 | "time": "2013-07-01 12:24:43" | ||
167 | }, | ||
168 | { | ||
169 | "name": "symfony/icu", | ||
170 | "version": "v1.0.0", | ||
171 | "target-dir": "Symfony/Component/Icu", | ||
172 | "source": { | ||
173 | "type": "git", | ||
174 | "url": "https://github.com/symfony/Icu.git", | ||
175 | "reference": "v1.0.0" | ||
176 | }, | ||
177 | "dist": { | ||
178 | "type": "zip", | ||
179 | "url": "https://api.github.com/repos/symfony/Icu/zipball/v1.0.0", | ||
180 | "reference": "v1.0.0", | ||
181 | "shasum": "" | ||
182 | }, | ||
183 | "require": { | ||
184 | "php": ">=5.3.3", | ||
185 | "symfony/intl": ">=2.3,<3.0" | ||
186 | }, | ||
187 | "type": "library", | ||
188 | "autoload": { | ||
189 | "psr-0": { | ||
190 | "Symfony\\Component\\Icu\\": "" | ||
191 | } | ||
192 | }, | ||
193 | "notification-url": "https://packagist.org/downloads/", | ||
194 | "license": [ | ||
195 | "MIT" | ||
196 | ], | ||
197 | "authors": [ | ||
198 | { | ||
199 | "name": "Symfony Community", | ||
200 | "homepage": "http://symfony.com/contributors" | ||
201 | }, | ||
202 | { | ||
203 | "name": "Bernhard Schussek", | ||
204 | "email": "bschussek@gmail.com" | ||
205 | } | ||
206 | ], | ||
207 | "description": "Contains an excerpt of the ICU data and classes to load it.", | ||
208 | "homepage": "http://symfony.com", | ||
209 | "keywords": [ | ||
210 | "icu", | ||
211 | "intl" | ||
212 | ], | ||
213 | "time": "2013-06-03 18:32:07" | ||
214 | }, | ||
215 | { | ||
216 | "name": "symfony/intl", | ||
217 | "version": "v2.3.2", | ||
218 | "target-dir": "Symfony/Component/Intl", | ||
219 | "source": { | ||
220 | "type": "git", | ||
221 | "url": "https://github.com/symfony/Intl.git", | ||
222 | "reference": "v2.3.2" | ||
223 | }, | ||
224 | "dist": { | ||
225 | "type": "zip", | ||
226 | "url": "https://api.github.com/repos/symfony/Intl/zipball/v2.3.2", | ||
227 | "reference": "v2.3.2", | ||
228 | "shasum": "" | ||
229 | }, | ||
230 | "require": { | ||
231 | "php": ">=5.3.3", | ||
232 | "symfony/icu": "~1.0-RC" | ||
233 | }, | ||
234 | "require-dev": { | ||
235 | "symfony/filesystem": ">=2.1" | ||
236 | }, | ||
237 | "suggest": { | ||
238 | "ext-intl": "to use the component with locales other than \"en\"" | ||
239 | }, | ||
240 | "type": "library", | ||
241 | "extra": { | ||
242 | "branch-alias": { | ||
243 | "dev-master": "2.3-dev" | ||
244 | } | ||
245 | }, | ||
246 | "autoload": { | ||
247 | "psr-0": { | ||
248 | "Symfony\\Component\\Intl\\": "" | ||
249 | }, | ||
250 | "classmap": [ | ||
251 | "Symfony/Component/Intl/Resources/stubs" | ||
252 | ], | ||
253 | "files": [ | ||
254 | "Symfony/Component/Intl/Resources/stubs/functions.php" | ||
255 | ] | ||
256 | }, | ||
257 | "notification-url": "https://packagist.org/downloads/", | ||
258 | "license": [ | ||
259 | "MIT" | ||
260 | ], | ||
261 | "authors": [ | ||
262 | { | ||
263 | "name": "Symfony Community", | ||
264 | "homepage": "http://symfony.com/contributors" | ||
265 | }, | ||
266 | { | ||
267 | "name": "Igor Wiedler", | ||
268 | "email": "igor@wiedler.ch", | ||
269 | "homepage": "http://wiedler.ch/igor/" | ||
270 | }, | ||
271 | { | ||
272 | "name": "Bernhard Schussek", | ||
273 | "email": "bschussek@gmail.com" | ||
274 | }, | ||
275 | { | ||
276 | "name": "Eriksen Costa", | ||
277 | "email": "eriksen.costa@infranology.com.br" | ||
278 | } | ||
279 | ], | ||
280 | "description": "A PHP replacement layer for the C intl extension that includes additional data from the ICU library.", | ||
281 | "homepage": "http://symfony.com", | ||
282 | "keywords": [ | ||
283 | "i18n", | ||
284 | "icu", | ||
285 | "internationalization", | ||
286 | "intl", | ||
287 | "l10n", | ||
288 | "localization" | ||
289 | ], | ||
290 | "time": "2013-07-08 13:00:35" | ||
291 | }, | ||
292 | { | ||
293 | "name": "symfony/options-resolver", | ||
294 | "version": "v2.3.2", | ||
295 | "target-dir": "Symfony/Component/OptionsResolver", | ||
296 | "source": { | ||
297 | "type": "git", | ||
298 | "url": "https://github.com/symfony/OptionsResolver.git", | ||
299 | "reference": "v2.3.2" | ||
300 | }, | ||
301 | "dist": { | ||
302 | "type": "zip", | ||
303 | "url": "https://api.github.com/repos/symfony/OptionsResolver/zipball/v2.3.2", | ||
304 | "reference": "v2.3.2", | ||
305 | "shasum": "" | ||
306 | }, | ||
307 | "require": { | ||
308 | "php": ">=5.3.3" | ||
309 | }, | ||
310 | "type": "library", | ||
311 | "extra": { | ||
312 | "branch-alias": { | ||
313 | "dev-master": "2.3-dev" | ||
314 | } | ||
315 | }, | ||
316 | "autoload": { | ||
317 | "psr-0": { | ||
318 | "Symfony\\Component\\OptionsResolver\\": "" | ||
319 | } | ||
320 | }, | ||
321 | "notification-url": "https://packagist.org/downloads/", | ||
322 | "license": [ | ||
323 | "MIT" | ||
324 | ], | ||
325 | "authors": [ | ||
326 | { | ||
327 | "name": "Fabien Potencier", | ||
328 | "email": "fabien@symfony.com" | ||
329 | }, | ||
330 | { | ||
331 | "name": "Symfony Community", | ||
332 | "homepage": "http://symfony.com/contributors" | ||
333 | } | ||
334 | ], | ||
335 | "description": "Symfony OptionsResolver Component", | ||
336 | "homepage": "http://symfony.com", | ||
337 | "keywords": [ | ||
338 | "config", | ||
339 | "configuration", | ||
340 | "options" | ||
341 | ], | ||
342 | "time": "2013-04-11 06:50:46" | ||
343 | }, | ||
344 | { | ||
345 | "name": "symfony/property-access", | ||
346 | "version": "v2.3.2", | ||
347 | "target-dir": "Symfony/Component/PropertyAccess", | ||
348 | "source": { | ||
349 | "type": "git", | ||
350 | "url": "https://github.com/symfony/PropertyAccess.git", | ||
351 | "reference": "v2.3.2" | ||
352 | }, | ||
353 | "dist": { | ||
354 | "type": "zip", | ||
355 | "url": "https://api.github.com/repos/symfony/PropertyAccess/zipball/v2.3.2", | ||
356 | "reference": "v2.3.2", | ||
357 | "shasum": "" | ||
358 | }, | ||
359 | "require": { | ||
360 | "php": ">=5.3.3" | ||
361 | }, | ||
362 | "type": "library", | ||
363 | "extra": { | ||
364 | "branch-alias": { | ||
365 | "dev-master": "2.3-dev" | ||
366 | } | ||
367 | }, | ||
368 | "autoload": { | ||
369 | "psr-0": { | ||
370 | "Symfony\\Component\\PropertyAccess\\": "" | ||
371 | } | ||
372 | }, | ||
373 | "notification-url": "https://packagist.org/downloads/", | ||
374 | "license": [ | ||
375 | "MIT" | ||
376 | ], | ||
377 | "authors": [ | ||
378 | { | ||
379 | "name": "Fabien Potencier", | ||
380 | "email": "fabien@symfony.com" | ||
381 | }, | ||
382 | { | ||
383 | "name": "Symfony Community", | ||
384 | "homepage": "http://symfony.com/contributors" | ||
385 | } | ||
386 | ], | ||
387 | "description": "Symfony PropertyAccess Component", | ||
388 | "homepage": "http://symfony.com", | ||
389 | "keywords": [ | ||
390 | "access", | ||
391 | "array", | ||
392 | "extraction", | ||
393 | "index", | ||
394 | "injection", | ||
395 | "object", | ||
396 | "property", | ||
397 | "property path", | ||
398 | "reflection" | ||
399 | ], | ||
400 | "time": "2013-07-01 12:24:43" | ||
401 | }, | ||
402 | { | ||
403 | "name": "symfony/routing", | ||
404 | "version": "v2.3.2", | ||
405 | "target-dir": "Symfony/Component/Routing", | ||
406 | "source": { | ||
407 | "type": "git", | ||
408 | "url": "https://github.com/symfony/Routing.git", | ||
409 | "reference": "v2.3.2" | ||
410 | }, | ||
411 | "dist": { | ||
412 | "type": "zip", | ||
413 | "url": "https://api.github.com/repos/symfony/Routing/zipball/v2.3.2", | ||
414 | "reference": "v2.3.2", | ||
415 | "shasum": "" | ||
416 | }, | ||
417 | "require": { | ||
418 | "php": ">=5.3.3" | ||
419 | }, | ||
420 | "require-dev": { | ||
421 | "doctrine/common": "~2.2", | ||
422 | "psr/log": "~1.0", | ||
423 | "symfony/config": "~2.2", | ||
424 | "symfony/yaml": "~2.0" | ||
425 | }, | ||
426 | "suggest": { | ||
427 | "doctrine/common": "", | ||
428 | "symfony/config": "", | ||
429 | "symfony/yaml": "" | ||
430 | }, | ||
431 | "type": "library", | ||
432 | "extra": { | ||
433 | "branch-alias": { | ||
434 | "dev-master": "2.3-dev" | ||
435 | } | ||
436 | }, | ||
437 | "autoload": { | ||
438 | "psr-0": { | ||
439 | "Symfony\\Component\\Routing\\": "" | ||
440 | } | ||
441 | }, | ||
442 | "notification-url": "https://packagist.org/downloads/", | ||
443 | "license": [ | ||
444 | "MIT" | ||
445 | ], | ||
446 | "authors": [ | ||
447 | { | ||
448 | "name": "Fabien Potencier", | ||
449 | "email": "fabien@symfony.com" | ||
450 | }, | ||
451 | { | ||
452 | "name": "Symfony Community", | ||
453 | "homepage": "http://symfony.com/contributors" | ||
454 | } | ||
455 | ], | ||
456 | "description": "Symfony Routing Component", | ||
457 | "homepage": "http://symfony.com", | ||
458 | "time": "2013-06-23 08:16:02" | ||
459 | }, | ||
460 | { | ||
461 | "name": "symfony/translation", | ||
462 | "version": "v2.3.2", | ||
463 | "target-dir": "Symfony/Component/Translation", | ||
464 | "source": { | ||
465 | "type": "git", | ||
466 | "url": "https://github.com/symfony/Translation.git", | ||
467 | "reference": "v2.3.2" | ||
468 | }, | ||
469 | "dist": { | ||
470 | "type": "zip", | ||
471 | "url": "https://api.github.com/repos/symfony/Translation/zipball/v2.3.2", | ||
472 | "reference": "v2.3.2", | ||
473 | "shasum": "" | ||
474 | }, | ||
475 | "require": { | ||
476 | "php": ">=5.3.3" | ||
477 | }, | ||
478 | "require-dev": { | ||
479 | "symfony/config": "~2.0", | ||
480 | "symfony/yaml": "~2.2" | ||
481 | }, | ||
482 | "suggest": { | ||
483 | "symfony/config": "", | ||
484 | "symfony/yaml": "" | ||
485 | }, | ||
486 | "type": "library", | ||
487 | "extra": { | ||
488 | "branch-alias": { | ||
489 | "dev-master": "2.3-dev" | ||
490 | } | ||
491 | }, | ||
492 | "autoload": { | ||
493 | "psr-0": { | ||
494 | "Symfony\\Component\\Translation\\": "" | ||
495 | } | ||
496 | }, | ||
497 | "notification-url": "https://packagist.org/downloads/", | ||
498 | "license": [ | ||
499 | "MIT" | ||
500 | ], | ||
501 | "authors": [ | ||
502 | { | ||
503 | "name": "Fabien Potencier", | ||
504 | "email": "fabien@symfony.com" | ||
505 | }, | ||
506 | { | ||
507 | "name": "Symfony Community", | ||
508 | "homepage": "http://symfony.com/contributors" | ||
509 | } | ||
510 | ], | ||
511 | "description": "Symfony Translation Component", | ||
512 | "homepage": "http://symfony.com", | ||
513 | "time": "2013-05-13 14:36:40" | ||
514 | }, | ||
515 | { | ||
516 | "name": "symfony/twig-bridge", | ||
517 | "version": "v2.3.2", | ||
518 | "target-dir": "Symfony/Bridge/Twig", | ||
519 | "source": { | ||
520 | "type": "git", | ||
521 | "url": "https://github.com/symfony/TwigBridge.git", | ||
522 | "reference": "v2.3.2" | ||
523 | }, | ||
524 | "dist": { | ||
525 | "type": "zip", | ||
526 | "url": "https://api.github.com/repos/symfony/TwigBridge/zipball/v2.3.2", | ||
527 | "reference": "v2.3.2", | ||
528 | "shasum": "" | ||
529 | }, | ||
530 | "require": { | ||
531 | "php": ">=5.3.3", | ||
532 | "twig/twig": "~1.11" | ||
533 | }, | ||
534 | "require-dev": { | ||
535 | "symfony/form": "2.2.*", | ||
536 | "symfony/http-kernel": "~2.2", | ||
537 | "symfony/routing": "~2.2", | ||
538 | "symfony/security": "~2.0", | ||
539 | "symfony/templating": "~2.1", | ||
540 | "symfony/translation": "~2.2", | ||
541 | "symfony/yaml": "~2.0" | ||
542 | }, | ||
543 | "suggest": { | ||
544 | "symfony/form": "", | ||
545 | "symfony/http-kernel": "", | ||
546 | "symfony/routing": "", | ||
547 | "symfony/security": "", | ||
548 | "symfony/templating": "", | ||
549 | "symfony/translation": "", | ||
550 | "symfony/yaml": "" | ||
551 | }, | ||
552 | "type": "symfony-bridge", | ||
553 | "extra": { | ||
554 | "branch-alias": { | ||
555 | "dev-master": "2.3-dev" | ||
556 | } | ||
557 | }, | ||
558 | "autoload": { | ||
559 | "psr-0": { | ||
560 | "Symfony\\Bridge\\Twig\\": "" | ||
561 | } | ||
562 | }, | ||
563 | "notification-url": "https://packagist.org/downloads/", | ||
564 | "license": [ | ||
565 | "MIT" | ||
566 | ], | ||
567 | "authors": [ | ||
568 | { | ||
569 | "name": "Fabien Potencier", | ||
570 | "email": "fabien@symfony.com" | ||
571 | }, | ||
572 | { | ||
573 | "name": "Symfony Community", | ||
574 | "homepage": "http://symfony.com/contributors" | ||
575 | } | ||
576 | ], | ||
577 | "description": "Symfony Twig Bridge", | ||
578 | "homepage": "http://symfony.com", | ||
579 | "time": "2013-05-16 10:19:58" | ||
580 | }, | ||
581 | { | ||
582 | "name": "twig/extensions", | ||
583 | "version": "v1.0.0", | ||
584 | "source": { | ||
585 | "type": "git", | ||
586 | "url": "https://github.com/fabpot/Twig-extensions.git", | ||
587 | "reference": "v1.0.0" | ||
588 | }, | ||
589 | "dist": { | ||
590 | "type": "zip", | ||
591 | "url": "https://api.github.com/repos/fabpot/Twig-extensions/zipball/v1.0.0", | ||
592 | "reference": "v1.0.0", | ||
593 | "shasum": "" | ||
594 | }, | ||
595 | "require": { | ||
596 | "twig/twig": "1.*" | ||
597 | }, | ||
598 | "type": "library", | ||
599 | "extra": { | ||
600 | "branch-alias": { | ||
601 | "dev-master": "1.0.x-dev" | ||
602 | } | ||
603 | }, | ||
604 | "autoload": { | ||
605 | "psr-0": { | ||
606 | "Twig_Extensions_": "lib/" | ||
607 | } | ||
608 | }, | ||
609 | "notification-url": "https://packagist.org/downloads/", | ||
610 | "license": [ | ||
611 | "MIT" | ||
612 | ], | ||
613 | "authors": [ | ||
614 | { | ||
615 | "name": "Fabien Potencier", | ||
616 | "email": "fabien@symfony.com" | ||
617 | } | ||
618 | ], | ||
619 | "description": "Common additional features for Twig that do not directly belong in core", | ||
620 | "homepage": "https://github.com/fabpot/Twig-extensions", | ||
621 | "keywords": [ | ||
622 | "debug", | ||
623 | "i18n", | ||
624 | "text" | ||
625 | ], | ||
626 | "time": "2013-02-28 14:21:30" | ||
627 | }, | ||
628 | { | ||
629 | "name": "twig/twig", | ||
630 | "version": "v1.13.2", | ||
631 | "source": { | ||
632 | "type": "git", | ||
633 | "url": "https://github.com/fabpot/Twig.git", | ||
634 | "reference": "v1.13.2" | ||
635 | }, | ||
636 | "dist": { | ||
637 | "type": "zip", | ||
638 | "url": "https://api.github.com/repos/fabpot/Twig/zipball/v1.13.2", | ||
639 | "reference": "v1.13.2", | ||
640 | "shasum": "" | ||
641 | }, | ||
642 | "require": { | ||
643 | "php": ">=5.2.4" | ||
644 | }, | ||
645 | "type": "library", | ||
646 | "extra": { | ||
647 | "branch-alias": { | ||
648 | "dev-master": "1.13-dev" | ||
649 | } | ||
650 | }, | ||
651 | "autoload": { | ||
652 | "psr-0": { | ||
653 | "Twig_": "lib/" | ||
654 | } | ||
655 | }, | ||
656 | "notification-url": "https://packagist.org/downloads/", | ||
657 | "license": [ | ||
658 | "BSD-3-Clause" | ||
659 | ], | ||
660 | "authors": [ | ||
661 | { | ||
662 | "name": "Fabien Potencier", | ||
663 | "email": "fabien@symfony.com" | ||
664 | }, | ||
665 | { | ||
666 | "name": "Armin Ronacher", | ||
667 | "email": "armin.ronacher@active-4.com" | ||
668 | } | ||
669 | ], | ||
670 | "description": "Twig, the flexible, fast, and secure template language for PHP", | ||
671 | "homepage": "http://twig.sensiolabs.org", | ||
672 | "keywords": [ | ||
673 | "templating" | ||
674 | ], | ||
675 | "time": "2013-08-03 15:35:31" | ||
676 | }, | ||
677 | { | ||
678 | "name": "umpirsky/twig-gettext-extractor", | ||
679 | "version": "1.1.3", | ||
680 | "source": { | ||
681 | "type": "git", | ||
682 | "url": "https://github.com/umpirsky/Twig-Gettext-Extractor.git", | ||
683 | "reference": "1.1.3" | ||
684 | }, | ||
685 | "dist": { | ||
686 | "type": "zip", | ||
687 | "url": "https://api.github.com/repos/umpirsky/Twig-Gettext-Extractor/zipball/1.1.3", | ||
688 | "reference": "1.1.3", | ||
689 | "shasum": "" | ||
690 | }, | ||
691 | "require": { | ||
692 | "php": ">=5.3.3", | ||
693 | "symfony/filesystem": ">=2.0,<3.0", | ||
694 | "symfony/form": ">=2.0,<3.0", | ||
695 | "symfony/routing": ">=2.0,<3.0", | ||
696 | "symfony/translation": ">=2.0,<3.0", | ||
697 | "symfony/twig-bridge": ">=2.0,<3.0", | ||
698 | "twig/extensions": "1.0.*", | ||
699 | "twig/twig": ">=1.2.0,<2.0-dev" | ||
700 | }, | ||
701 | "require-dev": { | ||
702 | "symfony/config": "2.1.*" | ||
703 | }, | ||
704 | "bin": [ | ||
705 | "twig-gettext-extractor" | ||
706 | ], | ||
707 | "type": "application", | ||
708 | "autoload": { | ||
709 | "psr-0": { | ||
710 | "Twig\\Gettext": "." | ||
711 | } | ||
712 | }, | ||
713 | "notification-url": "https://packagist.org/downloads/", | ||
714 | "license": [ | ||
715 | "MIT" | ||
716 | ], | ||
717 | "authors": [ | ||
718 | { | ||
719 | "name": "Саша Стаменковић", | ||
720 | "email": "umpirsky@gmail.com", | ||
721 | "homepage": "http://umpirsky.com" | ||
722 | } | ||
723 | ], | ||
724 | "description": "The Twig Gettext Extractor is Poedit friendly tool which extracts translations from twig templates.", | ||
725 | "time": "2013-02-14 16:41:48" | ||
726 | } | ||
727 | ], | ||
728 | "packages-dev": [ | ||
729 | |||
730 | ], | ||
731 | "aliases": [ | ||
732 | |||
733 | ], | ||
734 | "minimum-stability": "stable", | ||
735 | "stability-flags": [ | ||
736 | |||
737 | ], | ||
738 | "platform": [ | ||
739 | |||
740 | ], | ||
741 | "platform-dev": [ | ||
742 | |||
743 | ] | ||
744 | } | ||
diff --git a/css/style-dark.css b/css/style-dark.css deleted file mode 100644 index 813c291d..00000000 --- a/css/style-dark.css +++ /dev/null | |||
@@ -1,90 +0,0 @@ | |||
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 deleted file mode 100644 index cd2384c3..00000000 --- a/css/style-light.css +++ /dev/null | |||
@@ -1,100 +0,0 @@ | |||
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 | .bouton { | ||
12 | background-color: #000; | ||
13 | color: #fff; | ||
14 | border: none; | ||
15 | } | ||
16 | .bouton:hover { | ||
17 | background-color: #222222; | ||
18 | color: #F1F1F1; | ||
19 | } | ||
20 | |||
21 | #main ul#links li a.current { | ||
22 | background-color: #000; | ||
23 | color: #fff; | ||
24 | } | ||
25 | |||
26 | #links a:hover, .backhome a:hover{ | ||
27 | background-color: #040707; | ||
28 | color: #F1F1F1; | ||
29 | } | ||
30 | |||
31 | input[type=submit].delete { | ||
32 | background : url('../img/light/remove.png') no-repeat center center; | ||
33 | color : transparent; | ||
34 | } | ||
35 | |||
36 | #main .entrie { | ||
37 | color: #2e2e2e; | ||
38 | background-color: #ffffff; | ||
39 | border: 1px solid #000; | ||
40 | } | ||
41 | |||
42 | #main .entrie h2 a:hover { | ||
43 | color: #F5BE00; | ||
44 | } | ||
45 | |||
46 | a.fav span { | ||
47 | background: url('../img/light/star-on.png') no-repeat; | ||
48 | } | ||
49 | |||
50 | a.fav span:hover { | ||
51 | background: url('../img/light/star-off.png') no-repeat; | ||
52 | } | ||
53 | |||
54 | a.fav-off span { | ||
55 | background: url('../img/light/star-off.png') no-repeat; | ||
56 | } | ||
57 | |||
58 | a.fav-off span:hover { | ||
59 | background: url('../img/light/star-on.png') no-repeat; | ||
60 | } | ||
61 | |||
62 | a.archive span { | ||
63 | background: url('../img/light/checkmark-on.png') no-repeat; | ||
64 | } | ||
65 | |||
66 | a.archive span:hover { | ||
67 | background: url('../img/light/checkmark-off.png') no-repeat; | ||
68 | } | ||
69 | |||
70 | a.archive-off span { | ||
71 | background: url('../img/light/checkmark-off.png') no-repeat; | ||
72 | } | ||
73 | |||
74 | a.archive-off span:hover { | ||
75 | background: url('../img/light/checkmark-on.png') no-repeat; | ||
76 | } | ||
77 | |||
78 | /*** ***/ | ||
79 | /*** ARTICLE PAGE ***/ | ||
80 | |||
81 | body.article { | ||
82 | color: #222222; | ||
83 | background-color: #F1F1F1; | ||
84 | } | ||
85 | |||
86 | #article header { | ||
87 | border-bottom: 1px solid #222222; | ||
88 | } | ||
89 | |||
90 | #article article { | ||
91 | border-bottom: 1px solid #222222; | ||
92 | } | ||
93 | |||
94 | .vieworiginal a { | ||
95 | color: #888888; | ||
96 | } | ||
97 | |||
98 | .entrie { | ||
99 | background-color: #fff; | ||
100 | } | ||
diff --git a/css/style.css b/css/style.css deleted file mode 100644 index 9fadfa96..00000000 --- a/css/style.css +++ /dev/null | |||
@@ -1,215 +0,0 @@ | |||
1 | /*** GENERAL ***/ | ||
2 | body { | ||
3 | font: 20px/1.3em Palatino,Georgia,serif; | ||
4 | margin: 10px; | ||
5 | } | ||
6 | |||
7 | header { | ||
8 | text-align: center; | ||
9 | } | ||
10 | |||
11 | .bouton { | ||
12 | border-radius: 2px; | ||
13 | } | ||
14 | |||
15 | #main ul#links { | ||
16 | padding: 0; | ||
17 | list-style-type: none; | ||
18 | text-align: center; | ||
19 | } | ||
20 | |||
21 | #main ul#links li { | ||
22 | display: inline; | ||
23 | } | ||
24 | |||
25 | #main ul#links li a.current { | ||
26 | -webkit-border-radius: 2px; | ||
27 | border-radius: 2px; | ||
28 | } | ||
29 | |||
30 | #main ul#sort { | ||
31 | padding: 0; | ||
32 | list-style-type: none; | ||
33 | text-align: center; | ||
34 | } | ||
35 | |||
36 | #main ul#sort li { | ||
37 | display: inline; | ||
38 | font-size: 0.9em; | ||
39 | } | ||
40 | |||
41 | #main ul#sort img:hover { | ||
42 | cursor: pointer; | ||
43 | } | ||
44 | |||
45 | #main, #article { | ||
46 | margin: 0 auto; | ||
47 | } | ||
48 | |||
49 | #links a, .backhome a{ | ||
50 | text-decoration: none; | ||
51 | padding: 5px 10px; | ||
52 | } | ||
53 | #links a:hover, .backhome a:hover{ | ||
54 | -webkit-border-radius: 2px; | ||
55 | border-radius: 2px; | ||
56 | } | ||
57 | |||
58 | footer { | ||
59 | text-align: right; | ||
60 | } | ||
61 | |||
62 | /*** ***/ | ||
63 | /*** LINKS DISPLAY ***/ | ||
64 | |||
65 | #main a.tool { | ||
66 | text-decoration: none; | ||
67 | cursor: pointer; | ||
68 | } | ||
69 | |||
70 | input[type=submit].delete { | ||
71 | width : 16px; | ||
72 | height :16px; | ||
73 | border : none; | ||
74 | cursor: pointer; | ||
75 | font-size : 0; | ||
76 | } | ||
77 | |||
78 | #main #content { | ||
79 | margin-top: 20px; | ||
80 | } | ||
81 | |||
82 | #main .entrie { | ||
83 | padding: 15px; | ||
84 | min-height: 8em; | ||
85 | border: 1px solid; | ||
86 | } | ||
87 | |||
88 | #main .entrie h2 a { | ||
89 | text-decoration: none; | ||
90 | } | ||
91 | |||
92 | .tools { | ||
93 | text-align: right; | ||
94 | } | ||
95 | |||
96 | .tools ul { | ||
97 | padding: 0; margin: 0; | ||
98 | list-style-type: none; | ||
99 | } | ||
100 | |||
101 | .tools ul li { | ||
102 | line-height: 20px; | ||
103 | } | ||
104 | |||
105 | .tools a.tool { | ||
106 | cursor: pointer; | ||
107 | } | ||
108 | |||
109 | #article .tools { | ||
110 | position: relative; | ||
111 | display: inline; | ||
112 | top: 0px; | ||
113 | right: 0px; | ||
114 | width: 100%; | ||
115 | text-align: left; | ||
116 | } | ||
117 | |||
118 | #article .tools ul li{ | ||
119 | display: inline; | ||
120 | } | ||
121 | |||
122 | #main .entrie .tools a.tool span, #article .tools a.tool span { | ||
123 | display: inline-block; | ||
124 | width: 16px; | ||
125 | height: 16px; | ||
126 | } | ||
127 | |||
128 | |||
129 | /*** ***/ | ||
130 | /*** ARTICLE PAGE ***/ | ||
131 | |||
132 | body.article { | ||
133 | font: 20px/1.3em Palatino,Georgia,serif; | ||
134 | } | ||
135 | |||
136 | #article header { | ||
137 | text-align: left; | ||
138 | } | ||
139 | |||
140 | #article header a { | ||
141 | text-decoration: none; | ||
142 | } | ||
143 | |||
144 | .vieworiginal a { | ||
145 | text-decoration: none; | ||
146 | } | ||
147 | |||
148 | .backhome { | ||
149 | display: inline; | ||
150 | } | ||
151 | |||
152 | /*** ***/ | ||
153 | |||
154 | #main | ||
155 | { | ||
156 | max-width: 60em; /* 960 px */ | ||
157 | margin: 0 auto; | ||
158 | } | ||
159 | #content | ||
160 | { | ||
161 | width: 103.125%; /* 990px */ | ||
162 | overflow: hidden; | ||
163 | margin-left: -1.562%; /* 15px */ | ||
164 | margin-bottom: -1.875em; /* 30px */ | ||
165 | } | ||
166 | |||
167 | .entrie | ||
168 | { | ||
169 | width: 30.303%; /* 300px */ | ||
170 | background-color: #fff; | ||
171 | float: left; | ||
172 | margin: 0 1.515% 1.875em; /* 15px 30px */ | ||
173 | } | ||
174 | |||
175 | @media only screen and ( max-width: 40em ) /* 640px */ | ||
176 | { | ||
177 | .entrie | ||
178 | { | ||
179 | width: 46.876%; /* 305px */ | ||
180 | margin-bottom: 0.938em; /* 15px */ | ||
181 | } | ||
182 | } | ||
183 | |||
184 | @media only screen and ( max-width: 20em ) /* 320px */ | ||
185 | { | ||
186 | #content | ||
187 | { | ||
188 | width: 100%; | ||
189 | margin-left: 0; | ||
190 | } | ||
191 | |||
192 | .entrie | ||
193 | { | ||
194 | width: 100%; | ||
195 | margin-left: 0; | ||
196 | margin-right: 0; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | /*** ***/ | ||
201 | /*** MESSAGES ***/ | ||
202 | |||
203 | .messages { width: 100%; -moz-border-radius: 4px; border-radius: 4px; display: block; padding: 10px 0; margin: 10px auto 10px; clear: both; } | ||
204 | .messages a.closeMessage { margin: -14px -8px 0 0; display:none; width: 16px; height: 16px; float: right; background: url(../img/messages/close.png) no-repeat; } | ||
205 | /*.messages:hover a.closeMessage { visibility:visible; }*/ | ||
206 | .messages p { margin: 3px 0 3px 10px !important; padding: 0 10px 0 23px !important; font-size: 14px; line-height: 16px; } | ||
207 | .messages.error { border: 1px solid #C42608; color: #c00 !important; background: #FFF0EF; } | ||
208 | .messages.error p { background: url(../img/messages/cross.png ) no-repeat 0px 50%; color:#c00 !important; } | ||
209 | .messages.success {background: #E0FBCC; border: 1px solid #6DC70C; } | ||
210 | .messages.success p { background: url(../img/messages/tick.png) no-repeat 0px 50%; color: #2B6301 !important; } | ||
211 | .messages.warning { background: #FFFCD3; border: 1px solid #EBCD41; color: #000; } | ||
212 | .messages.warning p { background: url(../img/messages/warning.png ) no-repeat 0px 50%; color: #5F4E01; } | ||
213 | .messages.information, .messages.info { background: #DFEBFB; border: 1px solid #82AEE7; } | ||
214 | .messages.information p, .messages.info p { background: url(../img/messages/help.png ) no-repeat 0px 50%; color: #064393; } | ||
215 | .messages.information a { text-decoration: underline; } | ||
diff --git a/img/dark/checkmark-off.png b/img/dark/checkmark-off.png deleted file mode 100644 index efc3439f..00000000 --- a/img/dark/checkmark-off.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/img/dark/checkmark-on.png b/img/dark/checkmark-on.png deleted file mode 100644 index 24391c2e..00000000 --- a/img/dark/checkmark-on.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/img/dark/down.png b/img/dark/down.png deleted file mode 100644 index 41ea9604..00000000 --- a/img/dark/down.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/img/dark/logo.png b/img/dark/logo.png deleted file mode 100644 index 9fba0642..00000000 --- a/img/dark/logo.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/img/dark/remove.png b/img/dark/remove.png deleted file mode 100644 index 41786fd7..00000000 --- a/img/dark/remove.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/img/dark/star-off.png b/img/dark/star-off.png deleted file mode 100644 index 90651b54..00000000 --- a/img/dark/star-off.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/img/dark/star-on.png b/img/dark/star-on.png deleted file mode 100644 index 7fc14477..00000000 --- a/img/dark/star-on.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/img/dark/up.png b/img/dark/up.png deleted file mode 100644 index 1679e18f..00000000 --- a/img/dark/up.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/img/logo.png b/img/logo.png deleted file mode 100644 index f917857f..00000000 --- a/img/logo.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/import.php b/import.php deleted file mode 100644 index 72e3eac7..00000000 --- a/import.php +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
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 | set_time_limit(0); | ||
12 | |||
13 | include dirname(__FILE__).'/inc/config.php'; | ||
14 | include dirname(__FILE__).'/inc/simple_html_dom.php'; | ||
15 | |||
16 | if (!isset($_GET['start'])) { | ||
17 | echo 'Please execute the import script locally, it can take a very long time. <br /><a href="import.php?start">Bye bye Pocket, let\'s go !</a>'; | ||
18 | } | ||
19 | else { | ||
20 | $html = new simple_html_dom(); | ||
21 | $html->load_file('ril_export.html'); | ||
22 | |||
23 | $read = 0; | ||
24 | $errors = array(); | ||
25 | foreach($html->find('ul') as $ul) | ||
26 | { | ||
27 | foreach($ul->find('li') as $li) | ||
28 | { | ||
29 | $a = $li->find('a'); | ||
30 | $url = $a[0]->href; | ||
31 | |||
32 | |||
33 | action_to_do('add', $url); | ||
34 | if ($read == '1') { | ||
35 | $last_id = $db->getHandle()->lastInsertId(); | ||
36 | $sql_update = "UPDATE entries SET is_read=~is_read WHERE id=?"; | ||
37 | $params_update = array($last_id); | ||
38 | $query_update = $db->getHandle()->prepare($sql_update); | ||
39 | $query_update->execute($params_update); | ||
40 | } | ||
41 | } | ||
42 | # Pocket génère un fichier HTML avec deux <ul> | ||
43 | # Le premier concerne les éléments non lus | ||
44 | # Le second concerne les éléments archivés | ||
45 | $read = 1; | ||
46 | } | ||
47 | |||
48 | echo 'Import from Pocket completed. <a href="index.php">Welcome to #poche !</a>'; | ||
49 | logm('import from pocket completed'); | ||
50 | } \ No newline at end of file | ||
diff --git a/inc/Encoding.php b/inc/3rdparty/Encoding.php index 577763b4..577763b4 100644 --- a/inc/Encoding.php +++ b/inc/3rdparty/Encoding.php | |||
diff --git a/inc/JSLikeHTMLElement.php b/inc/3rdparty/JSLikeHTMLElement.php index dfcc1be5..238ba8a8 100644 --- a/inc/JSLikeHTMLElement.php +++ b/inc/3rdparty/JSLikeHTMLElement.php | |||
@@ -4,7 +4,7 @@ | |||
4 | * | 4 | * |
5 | * This class extends PHP's DOMElement to allow | 5 | * This class extends PHP's DOMElement to allow |
6 | * users to get and set the innerHTML property of | 6 | * users to get and set the innerHTML property of |
7 | * HTML elements in the same way it's done in | 7 | * HTML elements in the same way it's done in |
8 | * JavaScript. | 8 | * JavaScript. |
9 | * | 9 | * |
10 | * Example usage: | 10 | * Example usage: |
@@ -15,16 +15,16 @@ | |||
15 | * $doc->registerNodeClass('DOMElement', 'JSLikeHTMLElement'); | 15 | * $doc->registerNodeClass('DOMElement', 'JSLikeHTMLElement'); |
16 | * $doc->loadHTML('<div><p>Para 1</p><p>Para 2</p></div>'); | 16 | * $doc->loadHTML('<div><p>Para 1</p><p>Para 2</p></div>'); |
17 | * $elem = $doc->getElementsByTagName('div')->item(0); | 17 | * $elem = $doc->getElementsByTagName('div')->item(0); |
18 | * | 18 | * |
19 | * // print innerHTML | 19 | * // print innerHTML |
20 | * echo $elem->innerHTML; // prints '<p>Para 1</p><p>Para 2</p>' | 20 | * echo $elem->innerHTML; // prints '<p>Para 1</p><p>Para 2</p>' |
21 | * echo "\n\n"; | 21 | * echo "\n\n"; |
22 | * | 22 | * |
23 | * // set innerHTML | 23 | * // set innerHTML |
24 | * $elem->innerHTML = '<a href="http://fivefilters.org">FiveFilters.org</a>'; | 24 | * $elem->innerHTML = '<a href="http://fivefilters.org">FiveFilters.org</a>'; |
25 | * echo $elem->innerHTML; // prints '<a href="http://fivefilters.org">FiveFilters.org</a>' | 25 | * echo $elem->innerHTML; // prints '<a href="http://fivefilters.org">FiveFilters.org</a>' |
26 | * echo "\n\n"; | 26 | * echo "\n\n"; |
27 | * | 27 | * |
28 | * // print document (with our changes) | 28 | * // print document (with our changes) |
29 | * echo $doc->saveXML(); | 29 | * echo $doc->saveXML(); |
30 | * @endcode | 30 | * @endcode |
@@ -59,7 +59,7 @@ class JSLikeHTMLElement extends DOMElement | |||
59 | $value = mb_convert_encoding($value, 'HTML-ENTITIES', 'UTF-8'); | 59 | $value = mb_convert_encoding($value, 'HTML-ENTITIES', 'UTF-8'); |
60 | // Using <htmlfragment> will generate a warning, but so will bad HTML | 60 | // Using <htmlfragment> will generate a warning, but so will bad HTML |
61 | // (and by this point, bad HTML is what we've got). | 61 | // (and by this point, bad HTML is what we've got). |
62 | // We use it (and suppress the warning) because an HTML fragment will | 62 | // We use it (and suppress the warning) because an HTML fragment will |
63 | // be wrapped around <html><body> tags which we don't really want to keep. | 63 | // be wrapped around <html><body> tags which we don't really want to keep. |
64 | // Note: despite the warning, if loadHTML succeeds it will return true. | 64 | // Note: despite the warning, if loadHTML succeeds it will return true. |
65 | $result = @$f->loadHTML('<htmlfragment>'.$value.'</htmlfragment>'); | 65 | $result = @$f->loadHTML('<htmlfragment>'.$value.'</htmlfragment>'); |
@@ -86,7 +86,7 @@ class JSLikeHTMLElement extends DOMElement | |||
86 | * @code | 86 | * @code |
87 | * $string = $div->innerHTML; | 87 | * $string = $div->innerHTML; |
88 | * @endcode | 88 | * @endcode |
89 | */ | 89 | */ |
90 | public function __get($name) | 90 | public function __get($name) |
91 | { | 91 | { |
92 | if ($name == 'innerHTML') { | 92 | if ($name == 'innerHTML') { |
diff --git a/inc/Readability.php b/inc/3rdparty/Readability.php index d28d28f9..e1e8738b 100644 --- a/inc/Readability.php +++ b/inc/3rdparty/Readability.php | |||
@@ -1,5 +1,5 @@ | |||
1 | <?php | 1 | <?php |
2 | /** | 2 | /** |
3 | * Arc90's Readability ported to PHP for FiveFilters.org | 3 | * Arc90's Readability ported to PHP for FiveFilters.org |
4 | * Based on readability.js version 1.7.1 (without multi-page support) | 4 | * Based on readability.js version 1.7.1 (without multi-page support) |
5 | * Updated to allow HTML5 parsing with html5lib | 5 | * Updated to allow HTML5 parsing with html5lib |
@@ -13,34 +13,34 @@ | |||
13 | * License: Apache License, Version 2.0 | 13 | * License: Apache License, Version 2.0 |
14 | * Requires: PHP5 | 14 | * Requires: PHP5 |
15 | * Date: 2012-09-19 | 15 | * Date: 2012-09-19 |
16 | * | 16 | * |
17 | * Differences between the PHP port and the original | 17 | * Differences between the PHP port and the original |
18 | * ------------------------------------------------------ | 18 | * ------------------------------------------------------ |
19 | * Arc90's Readability is designed to run in the browser. It works on the DOM | 19 | * Arc90's Readability is designed to run in the browser. It works on the DOM |
20 | * tree (the parsed HTML) after the page's CSS styles have been applied and | 20 | * tree (the parsed HTML) after the page's CSS styles have been applied and |
21 | * Javascript code executed. This PHP port does not run inside a browser. | 21 | * Javascript code executed. This PHP port does not run inside a browser. |
22 | * We use PHP's ability to parse HTML to build our DOM tree, but we cannot | 22 | * We use PHP's ability to parse HTML to build our DOM tree, but we cannot |
23 | * rely on CSS or Javascript support. As such, the results will not always | 23 | * rely on CSS or Javascript support. As such, the results will not always |
24 | * match Arc90's Readability. (For example, if a web page contains CSS style | 24 | * match Arc90's Readability. (For example, if a web page contains CSS style |
25 | * rules or Javascript code which hide certain HTML elements from display, | 25 | * rules or Javascript code which hide certain HTML elements from display, |
26 | * Arc90's Readability will dismiss those from consideration but our PHP port, | 26 | * Arc90's Readability will dismiss those from consideration but our PHP port, |
27 | * unable to understand CSS or Javascript, will not know any better.) | 27 | * unable to understand CSS or Javascript, will not know any better.) |
28 | * | 28 | * |
29 | * Another significant difference is that the aim of Arc90's Readability is | 29 | * Another significant difference is that the aim of Arc90's Readability is |
30 | * to re-present the main content block of a given web page so users can | 30 | * to re-present the main content block of a given web page so users can |
31 | * read it more easily in their browsers. Correct identification, clean up, | 31 | * read it more easily in their browsers. Correct identification, clean up, |
32 | * and separation of the content block is only a part of this process. | 32 | * and separation of the content block is only a part of this process. |
33 | * This PHP port is only concerned with this part, it does not include code | 33 | * This PHP port is only concerned with this part, it does not include code |
34 | * that relates to presentation in the browser - Arc90 already do | 34 | * that relates to presentation in the browser - Arc90 already do |
35 | * that extremely well, and for PDF output there's FiveFilters.org's | 35 | * that extremely well, and for PDF output there's FiveFilters.org's |
36 | * PDF Newspaper: http://fivefilters.org/pdf-newspaper/. | 36 | * PDF Newspaper: http://fivefilters.org/pdf-newspaper/. |
37 | * | 37 | * |
38 | * Finally, this class contains methods that might be useful for developers | 38 | * Finally, this class contains methods that might be useful for developers |
39 | * working on HTML document fragments. So without deviating too much from | 39 | * working on HTML document fragments. So without deviating too much from |
40 | * the original code (which I don't want to do because it makes debugging | 40 | * the original code (which I don't want to do because it makes debugging |
41 | * and updating more difficult), I've tried to make it a little more | 41 | * and updating more difficult), I've tried to make it a little more |
42 | * developer friendly. You should be able to use the methods here on | 42 | * developer friendly. You should be able to use the methods here on |
43 | * existing DOMElement objects without passing an entire HTML document to | 43 | * existing DOMElement objects without passing an entire HTML document to |
44 | * be parsed. | 44 | * be parsed. |
45 | */ | 45 | */ |
46 | 46 | ||
@@ -48,7 +48,7 @@ | |||
48 | require_once(dirname(__FILE__).'/JSLikeHTMLElement.php'); | 48 | require_once(dirname(__FILE__).'/JSLikeHTMLElement.php'); |
49 | 49 | ||
50 | // Alternative usage (for testing only!) | 50 | // Alternative usage (for testing only!) |
51 | // uncomment the lines below and call Readability.php in your browser | 51 | // uncomment the lines below and call Readability.php in your browser |
52 | // passing it the URL of the page you'd like content from, e.g.: | 52 | // passing it the URL of the page you'd like content from, e.g.: |
53 | // Readability.php?url=http://medialens.org/alerts/09/090615_the_guardian_climate.php | 53 | // Readability.php?url=http://medialens.org/alerts/09/090615_the_guardian_climate.php |
54 | 54 | ||
@@ -75,11 +75,11 @@ class Readability | |||
75 | public $url = null; // optional - URL where HTML was retrieved | 75 | public $url = null; // optional - URL where HTML was retrieved |
76 | public $debug = false; | 76 | public $debug = false; |
77 | public $lightClean = true; // preserves more content (experimental) added 2012-09-19 | 77 | public $lightClean = true; // preserves more content (experimental) added 2012-09-19 |
78 | protected $body = null; // | 78 | protected $body = null; // |
79 | protected $bodyCache = null; // Cache the body HTML in case we need to re-use it later | 79 | protected $bodyCache = null; // Cache the body HTML in case we need to re-use it later |
80 | protected $flags = 7; // 1 | 2 | 4; // Start with all flags set. | 80 | protected $flags = 7; // 1 | 2 | 4; // Start with all flags set. |
81 | protected $success = false; // indicates whether we were able to extract or not | 81 | protected $success = false; // indicates whether we were able to extract or not |
82 | 82 | ||
83 | /** | 83 | /** |
84 | * All of the regular expressions in use within readability. | 84 | * All of the regular expressions in use within readability. |
85 | * Defined up here so we don't instantiate them repeatedly in loops. | 85 | * Defined up here so we don't instantiate them repeatedly in loops. |
@@ -97,19 +97,19 @@ class Readability | |||
97 | 'killBreaks' => '/(<br\s*\/?>(\s| ?)*){1,}/', | 97 | 'killBreaks' => '/(<br\s*\/?>(\s| ?)*){1,}/', |
98 | 'video' => '!//(player\.|www\.)?(youtube|vimeo|viddler)\.com!i', | 98 | 'video' => '!//(player\.|www\.)?(youtube|vimeo|viddler)\.com!i', |
99 | 'skipFootnoteLink' => '/^\s*(\[?[a-z0-9]{1,2}\]?|^|edit|citation needed)\s*$/i' | 99 | 'skipFootnoteLink' => '/^\s*(\[?[a-z0-9]{1,2}\]?|^|edit|citation needed)\s*$/i' |
100 | ); | 100 | ); |
101 | 101 | ||
102 | /* constants */ | 102 | /* constants */ |
103 | const FLAG_STRIP_UNLIKELYS = 1; | 103 | const FLAG_STRIP_UNLIKELYS = 1; |
104 | const FLAG_WEIGHT_CLASSES = 2; | 104 | const FLAG_WEIGHT_CLASSES = 2; |
105 | const FLAG_CLEAN_CONDITIONALLY = 4; | 105 | const FLAG_CLEAN_CONDITIONALLY = 4; |
106 | 106 | ||
107 | /** | 107 | /** |
108 | * Create instance of Readability | 108 | * Create instance of Readability |
109 | * @param string UTF-8 encoded string | 109 | * @param string UTF-8 encoded string |
110 | * @param string (optional) URL associated with HTML (used for footnotes) | 110 | * @param string (optional) URL associated with HTML (used for footnotes) |
111 | * @param string which parser to use for turning raw HTML into a DOMDocument (either 'libxml' or 'html5lib') | 111 | * @param string which parser to use for turning raw HTML into a DOMDocument (either 'libxml' or 'html5lib') |
112 | */ | 112 | */ |
113 | function __construct($html, $url=null, $parser='libxml') | 113 | function __construct($html, $url=null, $parser='libxml') |
114 | { | 114 | { |
115 | $this->url = $url; | 115 | $this->url = $url; |
@@ -135,18 +135,18 @@ class Readability | |||
135 | public function getTitle() { | 135 | public function getTitle() { |
136 | return $this->articleTitle; | 136 | return $this->articleTitle; |
137 | } | 137 | } |
138 | 138 | ||
139 | /** | 139 | /** |
140 | * Get article content element | 140 | * Get article content element |
141 | * @return DOMElement | 141 | * @return DOMElement |
142 | */ | 142 | */ |
143 | public function getContent() { | 143 | public function getContent() { |
144 | return $this->articleContent; | 144 | return $this->articleContent; |
145 | } | 145 | } |
146 | 146 | ||
147 | /** | 147 | /** |
148 | * Runs readability. | 148 | * Runs readability. |
149 | * | 149 | * |
150 | * Workflow: | 150 | * Workflow: |
151 | * 1. Prep the document by removing script tags, css, etc. | 151 | * 1. Prep the document by removing script tags, css, etc. |
152 | * 2. Build readability's DOM tree. | 152 | * 2. Build readability's DOM tree. |
@@ -161,7 +161,7 @@ class Readability | |||
161 | if (!isset($this->dom->documentElement)) return false; | 161 | if (!isset($this->dom->documentElement)) return false; |
162 | $this->removeScripts($this->dom); | 162 | $this->removeScripts($this->dom); |
163 | //die($this->getInnerHTML($this->dom->documentElement)); | 163 | //die($this->getInnerHTML($this->dom->documentElement)); |
164 | 164 | ||
165 | // Assume successful outcome | 165 | // Assume successful outcome |
166 | $this->success = true; | 166 | $this->success = true; |
167 | 167 | ||
@@ -176,7 +176,7 @@ class Readability | |||
176 | } | 176 | } |
177 | 177 | ||
178 | $this->prepDocument(); | 178 | $this->prepDocument(); |
179 | 179 | ||
180 | //die($this->dom->documentElement->parentNode->nodeType); | 180 | //die($this->dom->documentElement->parentNode->nodeType); |
181 | //$this->setInnerHTML($this->dom->documentElement, $this->getInnerHTML($this->dom->documentElement)); | 181 | //$this->setInnerHTML($this->dom->documentElement, $this->getInnerHTML($this->dom->documentElement)); |
182 | //die($this->getInnerHTML($this->dom->documentElement)); | 182 | //die($this->getInnerHTML($this->dom->documentElement)); |
@@ -191,9 +191,9 @@ class Readability | |||
191 | $this->success = false; | 191 | $this->success = false; |
192 | $articleContent = $this->dom->createElement('div'); | 192 | $articleContent = $this->dom->createElement('div'); |
193 | $articleContent->setAttribute('id', 'readability-content'); | 193 | $articleContent->setAttribute('id', 'readability-content'); |
194 | $articleContent->innerHTML = '<p>Sorry, Readability was unable to parse this page for content.</p>'; | 194 | $articleContent->innerHTML = '<p>Sorry, Readability was unable to parse this page for content.</p>'; |
195 | } | 195 | } |
196 | 196 | ||
197 | $overlay->setAttribute('id', 'readOverlay'); | 197 | $overlay->setAttribute('id', 'readOverlay'); |
198 | $innerDiv->setAttribute('id', 'readInner'); | 198 | $innerDiv->setAttribute('id', 'readInner'); |
199 | 199 | ||
@@ -201,7 +201,7 @@ class Readability | |||
201 | $innerDiv->appendChild($articleTitle); | 201 | $innerDiv->appendChild($articleTitle); |
202 | $innerDiv->appendChild($articleContent); | 202 | $innerDiv->appendChild($articleContent); |
203 | $overlay->appendChild($innerDiv); | 203 | $overlay->appendChild($innerDiv); |
204 | 204 | ||
205 | /* Clear the old HTML, insert the new content. */ | 205 | /* Clear the old HTML, insert the new content. */ |
206 | $this->body->innerHTML = ''; | 206 | $this->body->innerHTML = ''; |
207 | $this->body->appendChild($overlay); | 207 | $this->body->appendChild($overlay); |
@@ -209,21 +209,21 @@ class Readability | |||
209 | $this->body->removeAttribute('style'); | 209 | $this->body->removeAttribute('style'); |
210 | 210 | ||
211 | $this->postProcessContent($articleContent); | 211 | $this->postProcessContent($articleContent); |
212 | 212 | ||
213 | // Set title and content instance variables | 213 | // Set title and content instance variables |
214 | $this->articleTitle = $articleTitle; | 214 | $this->articleTitle = $articleTitle; |
215 | $this->articleContent = $articleContent; | 215 | $this->articleContent = $articleContent; |
216 | 216 | ||
217 | return $this->success; | 217 | return $this->success; |
218 | } | 218 | } |
219 | 219 | ||
220 | /** | 220 | /** |
221 | * Debug | 221 | * Debug |
222 | */ | 222 | */ |
223 | protected function dbg($msg) { | 223 | protected function dbg($msg) { |
224 | if ($this->debug) echo '* ',$msg, "\n"; | 224 | if ($this->debug) echo '* ',$msg, "\n"; |
225 | } | 225 | } |
226 | 226 | ||
227 | /** | 227 | /** |
228 | * Run any post-process modifications to article content as necessary. | 228 | * Run any post-process modifications to article content as necessary. |
229 | * | 229 | * |
@@ -231,11 +231,11 @@ class Readability | |||
231 | * @return void | 231 | * @return void |
232 | */ | 232 | */ |
233 | public function postProcessContent($articleContent) { | 233 | public function postProcessContent($articleContent) { |
234 | if ($this->convertLinksToFootnotes && !preg_match('/wikipedia\.org/', @$this->url)) { | 234 | if ($this->convertLinksToFootnotes && !preg_match('/wikipedia\.org/', @$this->url)) { |
235 | $this->addFootnotes($articleContent); | 235 | $this->addFootnotes($articleContent); |
236 | } | 236 | } |
237 | } | 237 | } |
238 | 238 | ||
239 | /** | 239 | /** |
240 | * Get the article title as an H1. | 240 | * Get the article title as an H1. |
241 | * | 241 | * |
@@ -248,11 +248,11 @@ class Readability | |||
248 | try { | 248 | try { |
249 | $curTitle = $origTitle = $this->getInnerText($this->dom->getElementsByTagName('title')->item(0)); | 249 | $curTitle = $origTitle = $this->getInnerText($this->dom->getElementsByTagName('title')->item(0)); |
250 | } catch(Exception $e) {} | 250 | } catch(Exception $e) {} |
251 | 251 | ||
252 | if (preg_match('/ [\|\-] /', $curTitle)) | 252 | if (preg_match('/ [\|\-] /', $curTitle)) |
253 | { | 253 | { |
254 | $curTitle = preg_replace('/(.*)[\|\-] .*/i', '$1', $origTitle); | 254 | $curTitle = preg_replace('/(.*)[\|\-] .*/i', '$1', $origTitle); |
255 | 255 | ||
256 | if (count(explode(' ', $curTitle)) < 3) { | 256 | if (count(explode(' ', $curTitle)) < 3) { |
257 | $curTitle = preg_replace('/[^\|\-]*[\|\-](.*)/i', '$1', $origTitle); | 257 | $curTitle = preg_replace('/[^\|\-]*[\|\-](.*)/i', '$1', $origTitle); |
258 | } | 258 | } |
@@ -279,17 +279,17 @@ class Readability | |||
279 | if (count(explode(' ', $curTitle)) <= 4) { | 279 | if (count(explode(' ', $curTitle)) <= 4) { |
280 | $curTitle = $origTitle; | 280 | $curTitle = $origTitle; |
281 | } | 281 | } |
282 | 282 | ||
283 | $articleTitle = $this->dom->createElement('h1'); | 283 | $articleTitle = $this->dom->createElement('h1'); |
284 | $articleTitle->innerHTML = $curTitle; | 284 | $articleTitle->innerHTML = $curTitle; |
285 | 285 | ||
286 | return $articleTitle; | 286 | return $articleTitle; |
287 | } | 287 | } |
288 | 288 | ||
289 | /** | 289 | /** |
290 | * Prepare the HTML document for readability to scrape it. | 290 | * Prepare the HTML document for readability to scrape it. |
291 | * This includes things like stripping javascript, CSS, and handling terrible markup. | 291 | * This includes things like stripping javascript, CSS, and handling terrible markup. |
292 | * | 292 | * |
293 | * @return void | 293 | * @return void |
294 | **/ | 294 | **/ |
295 | protected function prepDocument() { | 295 | protected function prepDocument() { |
@@ -328,13 +328,13 @@ class Readability | |||
328 | $footnotesWrapper = $this->dom->createElement('div'); | 328 | $footnotesWrapper = $this->dom->createElement('div'); |
329 | $footnotesWrapper->setAttribute('id', 'readability-footnotes'); | 329 | $footnotesWrapper->setAttribute('id', 'readability-footnotes'); |
330 | $footnotesWrapper->innerHTML = '<h3>References</h3>'; | 330 | $footnotesWrapper->innerHTML = '<h3>References</h3>'; |
331 | 331 | ||
332 | $articleFootnotes = $this->dom->createElement('ol'); | 332 | $articleFootnotes = $this->dom->createElement('ol'); |
333 | $articleFootnotes->setAttribute('id', 'readability-footnotes-list'); | 333 | $articleFootnotes->setAttribute('id', 'readability-footnotes-list'); |
334 | $footnotesWrapper->appendChild($articleFootnotes); | 334 | $footnotesWrapper->appendChild($articleFootnotes); |
335 | 335 | ||
336 | $articleLinks = $articleContent->getElementsByTagName('a'); | 336 | $articleLinks = $articleContent->getElementsByTagName('a'); |
337 | 337 | ||
338 | $linkCount = 0; | 338 | $linkCount = 0; |
339 | for ($i = 0; $i < $articleLinks->length; $i++) | 339 | for ($i = 0; $i < $articleLinks->length; $i++) |
340 | { | 340 | { |
@@ -346,11 +346,11 @@ class Readability | |||
346 | if (!$linkDomain && isset($this->url)) $linkDomain = @parse_url($this->url, PHP_URL_HOST); | 346 | if (!$linkDomain && isset($this->url)) $linkDomain = @parse_url($this->url, PHP_URL_HOST); |
347 | //linkDomain = footnoteLink.host ? footnoteLink.host : document.location.host, | 347 | //linkDomain = footnoteLink.host ? footnoteLink.host : document.location.host, |
348 | $linkText = $this->getInnerText($articleLink); | 348 | $linkText = $this->getInnerText($articleLink); |
349 | 349 | ||
350 | if ((strpos($articleLink->getAttribute('class'), 'readability-DoNotFootnote') !== false) || preg_match($this->regexps['skipFootnoteLink'], $linkText)) { | 350 | if ((strpos($articleLink->getAttribute('class'), 'readability-DoNotFootnote') !== false) || preg_match($this->regexps['skipFootnoteLink'], $linkText)) { |
351 | continue; | 351 | continue; |
352 | } | 352 | } |
353 | 353 | ||
354 | $linkCount++; | 354 | $linkCount++; |
355 | 355 | ||
356 | /** Add a superscript reference after the article link */ | 356 | /** Add a superscript reference after the article link */ |
@@ -358,7 +358,7 @@ class Readability | |||
358 | $refLink->innerHTML = '<small><sup>[' . $linkCount . ']</sup></small>'; | 358 | $refLink->innerHTML = '<small><sup>[' . $linkCount . ']</sup></small>'; |
359 | $refLink->setAttribute('class', 'readability-DoNotFootnote'); | 359 | $refLink->setAttribute('class', 'readability-DoNotFootnote'); |
360 | $refLink->setAttribute('style', 'color: inherit;'); | 360 | $refLink->setAttribute('style', 'color: inherit;'); |
361 | 361 | ||
362 | //TODO: does this work or should we use DOMNode.isSameNode()? | 362 | //TODO: does this work or should we use DOMNode.isSameNode()? |
363 | if ($articleLink->parentNode->lastChild == $articleLink) { | 363 | if ($articleLink->parentNode->lastChild == $articleLink) { |
364 | $articleLink->parentNode->appendChild($refLink); | 364 | $articleLink->parentNode->appendChild($refLink); |
@@ -373,15 +373,15 @@ class Readability | |||
373 | 373 | ||
374 | $footnoteLink->innerHTML = ($footnoteLink->getAttribute('title') != '' ? $footnoteLink->getAttribute('title') : $linkText); | 374 | $footnoteLink->innerHTML = ($footnoteLink->getAttribute('title') != '' ? $footnoteLink->getAttribute('title') : $linkText); |
375 | $footnoteLink->setAttribute('name', 'readabilityFootnoteLink-' . $linkCount); | 375 | $footnoteLink->setAttribute('name', 'readabilityFootnoteLink-' . $linkCount); |
376 | 376 | ||
377 | $footnote->appendChild($footnoteLink); | 377 | $footnote->appendChild($footnoteLink); |
378 | if ($linkDomain) $footnote->innerHTML = $footnote->innerHTML . '<small> (' . $linkDomain . ')</small>'; | 378 | if ($linkDomain) $footnote->innerHTML = $footnote->innerHTML . '<small> (' . $linkDomain . ')</small>'; |
379 | 379 | ||
380 | $articleFootnotes->appendChild($footnote); | 380 | $articleFootnotes->appendChild($footnote); |
381 | } | 381 | } |
382 | 382 | ||
383 | if ($linkCount > 0) { | 383 | if ($linkCount > 0) { |
384 | $articleContent->appendChild($footnotesWrapper); | 384 | $articleContent->appendChild($footnotesWrapper); |
385 | } | 385 | } |
386 | } | 386 | } |
387 | 387 | ||
@@ -404,7 +404,7 @@ class Readability | |||
404 | //} | 404 | //} |
405 | } | 405 | } |
406 | } | 406 | } |
407 | 407 | ||
408 | /** | 408 | /** |
409 | * Prepare the article node for display. Clean out any inline styles, | 409 | * Prepare the article node for display. Clean out any inline styles, |
410 | * iframes, forms, strip extraneous <p> tags, etc. | 410 | * iframes, forms, strip extraneous <p> tags, etc. |
@@ -429,7 +429,7 @@ class Readability | |||
429 | * as a header and not a subheader, so remove it since we already have a header. | 429 | * as a header and not a subheader, so remove it since we already have a header. |
430 | ***/ | 430 | ***/ |
431 | if (!$this->lightClean && ($articleContent->getElementsByTagName('h2')->length == 1)) { | 431 | if (!$this->lightClean && ($articleContent->getElementsByTagName('h2')->length == 1)) { |
432 | $this->clean($articleContent, 'h2'); | 432 | $this->clean($articleContent, 'h2'); |
433 | } | 433 | } |
434 | $this->clean($articleContent, 'iframe'); | 434 | $this->clean($articleContent, 'iframe'); |
435 | 435 | ||
@@ -448,7 +448,7 @@ class Readability | |||
448 | $embedCount = $articleParagraphs->item($i)->getElementsByTagName('embed')->length; | 448 | $embedCount = $articleParagraphs->item($i)->getElementsByTagName('embed')->length; |
449 | $objectCount = $articleParagraphs->item($i)->getElementsByTagName('object')->length; | 449 | $objectCount = $articleParagraphs->item($i)->getElementsByTagName('object')->length; |
450 | $iframeCount = $articleParagraphs->item($i)->getElementsByTagName('iframe')->length; | 450 | $iframeCount = $articleParagraphs->item($i)->getElementsByTagName('iframe')->length; |
451 | 451 | ||
452 | if ($imgCount === 0 && $embedCount === 0 && $objectCount === 0 && $iframeCount === 0 && $this->getInnerText($articleParagraphs->item($i), false) == '') | 452 | if ($imgCount === 0 && $embedCount === 0 && $objectCount === 0 && $iframeCount === 0 && $this->getInnerText($articleParagraphs->item($i), false) == '') |
453 | { | 453 | { |
454 | $articleParagraphs->item($i)->parentNode->removeChild($articleParagraphs->item($i)); | 454 | $articleParagraphs->item($i)->parentNode->removeChild($articleParagraphs->item($i)); |
@@ -457,13 +457,13 @@ class Readability | |||
457 | 457 | ||
458 | try { | 458 | try { |
459 | $articleContent->innerHTML = preg_replace('/<br[^>]*>\s*<p/i', '<p', $articleContent->innerHTML); | 459 | $articleContent->innerHTML = preg_replace('/<br[^>]*>\s*<p/i', '<p', $articleContent->innerHTML); |
460 | //articleContent.innerHTML = articleContent.innerHTML.replace(/<br[^>]*>\s*<p/gi, '<p'); | 460 | //articleContent.innerHTML = articleContent.innerHTML.replace(/<br[^>]*>\s*<p/gi, '<p'); |
461 | } | 461 | } |
462 | catch (Exception $e) { | 462 | catch (Exception $e) { |
463 | $this->dbg("Cleaning innerHTML of breaks failed. This is an IE strict-block-elements bug. Ignoring.: " . $e); | 463 | $this->dbg("Cleaning innerHTML of breaks failed. This is an IE strict-block-elements bug. Ignoring.: " . $e); |
464 | } | 464 | } |
465 | } | 465 | } |
466 | 466 | ||
467 | /** | 467 | /** |
468 | * Initialize a node with the readability object. Also checks the | 468 | * Initialize a node with the readability object. Also checks the |
469 | * className/id for special names to add to its score. | 469 | * className/id for special names to add to its score. |
@@ -474,7 +474,7 @@ class Readability | |||
474 | protected function initializeNode($node) { | 474 | protected function initializeNode($node) { |
475 | $readability = $this->dom->createAttribute('readability'); | 475 | $readability = $this->dom->createAttribute('readability'); |
476 | $readability->value = 0; // this is our contentScore | 476 | $readability->value = 0; // this is our contentScore |
477 | $node->setAttributeNode($readability); | 477 | $node->setAttributeNode($readability); |
478 | 478 | ||
479 | switch (strtoupper($node->tagName)) { // unsure if strtoupper is needed, but using it just in case | 479 | switch (strtoupper($node->tagName)) { // unsure if strtoupper is needed, but using it just in case |
480 | case 'DIV': | 480 | case 'DIV': |
@@ -486,7 +486,7 @@ class Readability | |||
486 | case 'BLOCKQUOTE': | 486 | case 'BLOCKQUOTE': |
487 | $readability->value += 3; | 487 | $readability->value += 3; |
488 | break; | 488 | break; |
489 | 489 | ||
490 | case 'ADDRESS': | 490 | case 'ADDRESS': |
491 | case 'OL': | 491 | case 'OL': |
492 | case 'UL': | 492 | case 'UL': |
@@ -510,7 +510,7 @@ class Readability | |||
510 | } | 510 | } |
511 | $readability->value += $this->getClassWeight($node); | 511 | $readability->value += $this->getClassWeight($node); |
512 | } | 512 | } |
513 | 513 | ||
514 | /*** | 514 | /*** |
515 | * grabArticle - Using a variety of metrics (content score, classname, element types), find the content that is | 515 | * grabArticle - Using a variety of metrics (content score, classname, element types), find the content that is |
516 | * most likely to be the stuff a user wants to read. Then return it wrapped up in a div. | 516 | * most likely to be the stuff a user wants to read. Then return it wrapped up in a div. |
@@ -548,7 +548,7 @@ class Readability | |||
548 | $node->parentNode->removeChild($node); | 548 | $node->parentNode->removeChild($node); |
549 | $nodeIndex--; | 549 | $nodeIndex--; |
550 | continue; | 550 | continue; |
551 | } | 551 | } |
552 | } | 552 | } |
553 | 553 | ||
554 | if ($tagName == 'P' || $tagName == 'TD' || $tagName == 'PRE') { | 554 | if ($tagName == 'P' || $tagName == 'TD' || $tagName == 'PRE') { |
@@ -589,7 +589,7 @@ class Readability | |||
589 | } | 589 | } |
590 | } | 590 | } |
591 | } | 591 | } |
592 | 592 | ||
593 | /** | 593 | /** |
594 | * Loop through all paragraphs, and assign a score to them based on how content-y they look. | 594 | * Loop through all paragraphs, and assign a score to them based on how content-y they look. |
595 | * Then add their score to their parent node. | 595 | * Then add their score to their parent node. |
@@ -613,7 +613,7 @@ class Readability | |||
613 | } | 613 | } |
614 | 614 | ||
615 | /* Initialize readability data for the parent. */ | 615 | /* Initialize readability data for the parent. */ |
616 | if (!$parentNode->hasAttribute('readability')) | 616 | if (!$parentNode->hasAttribute('readability')) |
617 | { | 617 | { |
618 | $this->initializeNode($parentNode); | 618 | $this->initializeNode($parentNode); |
619 | $candidates[] = $parentNode; | 619 | $candidates[] = $parentNode; |
@@ -633,15 +633,15 @@ class Readability | |||
633 | 633 | ||
634 | /* Add points for any commas within this paragraph */ | 634 | /* Add points for any commas within this paragraph */ |
635 | $contentScore += count(explode(',', $innerText)); | 635 | $contentScore += count(explode(',', $innerText)); |
636 | 636 | ||
637 | /* For every 100 characters in this paragraph, add another point. Up to 3 points. */ | 637 | /* For every 100 characters in this paragraph, add another point. Up to 3 points. */ |
638 | $contentScore += min(floor(strlen($innerText) / 100), 3); | 638 | $contentScore += min(floor(strlen($innerText) / 100), 3); |
639 | 639 | ||
640 | /* Add the score to the parent. The grandparent gets half. */ | 640 | /* Add the score to the parent. The grandparent gets half. */ |
641 | $parentNode->getAttributeNode('readability')->value += $contentScore; | 641 | $parentNode->getAttributeNode('readability')->value += $contentScore; |
642 | 642 | ||
643 | if ($grandParentNode) { | 643 | if ($grandParentNode) { |
644 | $grandParentNode->getAttributeNode('readability')->value += $contentScore/2; | 644 | $grandParentNode->getAttributeNode('readability')->value += $contentScore/2; |
645 | } | 645 | } |
646 | } | 646 | } |
647 | 647 | ||
@@ -727,12 +727,12 @@ class Readability | |||
727 | { | 727 | { |
728 | $append = true; | 728 | $append = true; |
729 | } | 729 | } |
730 | 730 | ||
731 | if (strtoupper($siblingNode->nodeName) == 'P') { | 731 | if (strtoupper($siblingNode->nodeName) == 'P') { |
732 | $linkDensity = $this->getLinkDensity($siblingNode); | 732 | $linkDensity = $this->getLinkDensity($siblingNode); |
733 | $nodeContent = $this->getInnerText($siblingNode); | 733 | $nodeContent = $this->getInnerText($siblingNode); |
734 | $nodeLength = strlen($nodeContent); | 734 | $nodeLength = strlen($nodeContent); |
735 | 735 | ||
736 | if ($nodeLength > 80 && $linkDensity < 0.25) | 736 | if ($nodeLength > 80 && $linkDensity < 0.25) |
737 | { | 737 | { |
738 | $append = true; | 738 | $append = true; |
@@ -751,7 +751,7 @@ class Readability | |||
751 | $sibNodeName = strtoupper($siblingNode->nodeName); | 751 | $sibNodeName = strtoupper($siblingNode->nodeName); |
752 | if ($sibNodeName != 'DIV' && $sibNodeName != 'P') { | 752 | if ($sibNodeName != 'DIV' && $sibNodeName != 'P') { |
753 | /* We have a node that isn't a common block level element, like a form or td tag. Turn it into a div so it doesn't get filtered out later by accident. */ | 753 | /* We have a node that isn't a common block level element, like a form or td tag. Turn it into a div so it doesn't get filtered out later by accident. */ |
754 | 754 | ||
755 | $this->dbg('Altering siblingNode of ' . $sibNodeName . ' to div.'); | 755 | $this->dbg('Altering siblingNode of ' . $sibNodeName . ' to div.'); |
756 | $nodeToAppend = $this->dom->createElement('div'); | 756 | $nodeToAppend = $this->dom->createElement('div'); |
757 | try { | 757 | try { |
@@ -770,7 +770,7 @@ class Readability | |||
770 | $s--; | 770 | $s--; |
771 | $sl--; | 771 | $sl--; |
772 | } | 772 | } |
773 | 773 | ||
774 | /* To ensure a node does not interfere with readability styles, remove its classnames */ | 774 | /* To ensure a node does not interfere with readability styles, remove its classnames */ |
775 | $nodeToAppend->removeAttribute('class'); | 775 | $nodeToAppend->removeAttribute('class'); |
776 | 776 | ||
@@ -796,14 +796,14 @@ class Readability | |||
796 | // in the meantime, we check and create an empty element if it's not there. | 796 | // in the meantime, we check and create an empty element if it's not there. |
797 | if (!isset($this->body->childNodes)) $this->body = $this->dom->createElement('body'); | 797 | if (!isset($this->body->childNodes)) $this->body = $this->dom->createElement('body'); |
798 | $this->body->innerHTML = $this->bodyCache; | 798 | $this->body->innerHTML = $this->bodyCache; |
799 | 799 | ||
800 | if ($this->flagIsActive(self::FLAG_STRIP_UNLIKELYS)) { | 800 | if ($this->flagIsActive(self::FLAG_STRIP_UNLIKELYS)) { |
801 | $this->removeFlag(self::FLAG_STRIP_UNLIKELYS); | 801 | $this->removeFlag(self::FLAG_STRIP_UNLIKELYS); |
802 | return $this->grabArticle($this->body); | 802 | return $this->grabArticle($this->body); |
803 | } | 803 | } |
804 | else if ($this->flagIsActive(self::FLAG_WEIGHT_CLASSES)) { | 804 | else if ($this->flagIsActive(self::FLAG_WEIGHT_CLASSES)) { |
805 | $this->removeFlag(self::FLAG_WEIGHT_CLASSES); | 805 | $this->removeFlag(self::FLAG_WEIGHT_CLASSES); |
806 | return $this->grabArticle($this->body); | 806 | return $this->grabArticle($this->body); |
807 | } | 807 | } |
808 | else if ($this->flagIsActive(self::FLAG_CLEAN_CONDITIONALLY)) { | 808 | else if ($this->flagIsActive(self::FLAG_CLEAN_CONDITIONALLY)) { |
809 | $this->removeFlag(self::FLAG_CLEAN_CONDITIONALLY); | 809 | $this->removeFlag(self::FLAG_CLEAN_CONDITIONALLY); |
@@ -815,7 +815,7 @@ class Readability | |||
815 | } | 815 | } |
816 | return $articleContent; | 816 | return $articleContent; |
817 | } | 817 | } |
818 | 818 | ||
819 | /** | 819 | /** |
820 | * Remove script tags from document | 820 | * Remove script tags from document |
821 | * | 821 | * |
@@ -829,7 +829,7 @@ class Readability | |||
829 | $scripts->item($i)->parentNode->removeChild($scripts->item($i)); | 829 | $scripts->item($i)->parentNode->removeChild($scripts->item($i)); |
830 | } | 830 | } |
831 | } | 831 | } |
832 | 832 | ||
833 | /** | 833 | /** |
834 | * Get the inner text of a node. | 834 | * Get the inner text of a node. |
835 | * This also strips out any excess whitespace to be found. | 835 | * This also strips out any excess whitespace to be found. |
@@ -878,11 +878,11 @@ class Readability | |||
878 | $elem->removeAttribute('style'); | 878 | $elem->removeAttribute('style'); |
879 | } | 879 | } |
880 | } | 880 | } |
881 | 881 | ||
882 | /** | 882 | /** |
883 | * Get the density of links as a percentage of the content | 883 | * Get the density of links as a percentage of the content |
884 | * This is the amount of text that is inside a link divided by the total text in the node. | 884 | * This is the amount of text that is inside a link divided by the total text in the node. |
885 | * | 885 | * |
886 | * @param DOMElement $e | 886 | * @param DOMElement $e |
887 | * @return number (float) | 887 | * @return number (float) |
888 | */ | 888 | */ |
@@ -900,9 +900,9 @@ class Readability | |||
900 | return 0; | 900 | return 0; |
901 | } | 901 | } |
902 | } | 902 | } |
903 | 903 | ||
904 | /** | 904 | /** |
905 | * Get an elements class/id weight. Uses regular expressions to tell if this | 905 | * Get an elements class/id weight. Uses regular expressions to tell if this |
906 | * element looks good or bad. | 906 | * element looks good or bad. |
907 | * | 907 | * |
908 | * @param DOMElement $e | 908 | * @param DOMElement $e |
@@ -964,7 +964,7 @@ class Readability | |||
964 | public function clean($e, $tag) { | 964 | public function clean($e, $tag) { |
965 | $targetList = $e->getElementsByTagName($tag); | 965 | $targetList = $e->getElementsByTagName($tag); |
966 | $isEmbed = ($tag == 'iframe' || $tag == 'object' || $tag == 'embed'); | 966 | $isEmbed = ($tag == 'iframe' || $tag == 'object' || $tag == 'embed'); |
967 | 967 | ||
968 | for ($y=$targetList->length-1; $y >= 0; $y--) { | 968 | for ($y=$targetList->length-1; $y >= 0; $y--) { |
969 | /* Allow youtube and vimeo videos through as people usually want to see those. */ | 969 | /* Allow youtube and vimeo videos through as people usually want to see those. */ |
970 | if ($isEmbed) { | 970 | if ($isEmbed) { |
@@ -972,7 +972,7 @@ class Readability | |||
972 | for ($i=0, $il=$targetList->item($y)->attributes->length; $i < $il; $i++) { | 972 | for ($i=0, $il=$targetList->item($y)->attributes->length; $i < $il; $i++) { |
973 | $attributeValues .= $targetList->item($y)->attributes->item($i)->value . '|'; // DOMAttr? (TODO: test) | 973 | $attributeValues .= $targetList->item($y)->attributes->item($i)->value . '|'; // DOMAttr? (TODO: test) |
974 | } | 974 | } |
975 | 975 | ||
976 | /* First, check the elements attributes to see if any of them contain youtube or vimeo */ | 976 | /* First, check the elements attributes to see if any of them contain youtube or vimeo */ |
977 | if (preg_match($this->regexps['video'], $attributeValues)) { | 977 | if (preg_match($this->regexps['video'], $attributeValues)) { |
978 | continue; | 978 | continue; |
@@ -986,10 +986,10 @@ class Readability | |||
986 | $targetList->item($y)->parentNode->removeChild($targetList->item($y)); | 986 | $targetList->item($y)->parentNode->removeChild($targetList->item($y)); |
987 | } | 987 | } |
988 | } | 988 | } |
989 | 989 | ||
990 | /** | 990 | /** |
991 | * Clean an element of all tags of type "tag" if they look fishy. | 991 | * Clean an element of all tags of type "tag" if they look fishy. |
992 | * "Fishy" is an algorithm based on content length, classnames, | 992 | * "Fishy" is an algorithm based on content length, classnames, |
993 | * link density, number of images & embeds, etc. | 993 | * link density, number of images & embeds, etc. |
994 | * | 994 | * |
995 | * @param DOMElement $e | 995 | * @param DOMElement $e |
@@ -1013,7 +1013,7 @@ class Readability | |||
1013 | for ($i=$curTagsLength-1; $i >= 0; $i--) { | 1013 | for ($i=$curTagsLength-1; $i >= 0; $i--) { |
1014 | $weight = $this->getClassWeight($tagsList->item($i)); | 1014 | $weight = $this->getClassWeight($tagsList->item($i)); |
1015 | $contentScore = ($tagsList->item($i)->hasAttribute('readability')) ? (int)$tagsList->item($i)->getAttribute('readability') : 0; | 1015 | $contentScore = ($tagsList->item($i)->hasAttribute('readability')) ? (int)$tagsList->item($i)->getAttribute('readability') : 0; |
1016 | 1016 | ||
1017 | $this->dbg('Cleaning Conditionally ' . $tagsList->item($i)->tagName . ' (' . $tagsList->item($i)->getAttribute('class') . ':' . $tagsList->item($i)->getAttribute('id') . ')' . (($tagsList->item($i)->hasAttribute('readability')) ? (' with score ' . $tagsList->item($i)->getAttribute('readability')) : '')); | 1017 | $this->dbg('Cleaning Conditionally ' . $tagsList->item($i)->tagName . ' (' . $tagsList->item($i)->getAttribute('class') . ':' . $tagsList->item($i)->getAttribute('id') . ')' . (($tagsList->item($i)->hasAttribute('readability')) ? (' with score ' . $tagsList->item($i)->getAttribute('readability')) : '')); |
1018 | 1018 | ||
1019 | if ($weight + $contentScore < 0) { | 1019 | if ($weight + $contentScore < 0) { |
@@ -1034,13 +1034,13 @@ class Readability | |||
1034 | $embeds = $tagsList->item($i)->getElementsByTagName('embed'); | 1034 | $embeds = $tagsList->item($i)->getElementsByTagName('embed'); |
1035 | for ($ei=0, $il=$embeds->length; $ei < $il; $ei++) { | 1035 | for ($ei=0, $il=$embeds->length; $ei < $il; $ei++) { |
1036 | if (preg_match($this->regexps['video'], $embeds->item($ei)->getAttribute('src'))) { | 1036 | if (preg_match($this->regexps['video'], $embeds->item($ei)->getAttribute('src'))) { |
1037 | $embedCount++; | 1037 | $embedCount++; |
1038 | } | 1038 | } |
1039 | } | 1039 | } |
1040 | $embeds = $tagsList->item($i)->getElementsByTagName('iframe'); | 1040 | $embeds = $tagsList->item($i)->getElementsByTagName('iframe'); |
1041 | for ($ei=0, $il=$embeds->length; $ei < $il; $ei++) { | 1041 | for ($ei=0, $il=$embeds->length; $ei < $il; $ei++) { |
1042 | if (preg_match($this->regexps['video'], $embeds->item($ei)->getAttribute('src'))) { | 1042 | if (preg_match($this->regexps['video'], $embeds->item($ei)->getAttribute('src'))) { |
1043 | $embedCount++; | 1043 | $embedCount++; |
1044 | } | 1044 | } |
1045 | } | 1045 | } |
1046 | 1046 | ||
@@ -1058,7 +1058,7 @@ class Readability | |||
1058 | $toRemove = true; | 1058 | $toRemove = true; |
1059 | } else if ( $input > floor($p/3) ) { | 1059 | } else if ( $input > floor($p/3) ) { |
1060 | $this->dbg(' too many <input> elements'); | 1060 | $this->dbg(' too many <input> elements'); |
1061 | $toRemove = true; | 1061 | $toRemove = true; |
1062 | } else if ($contentLength < 25 && ($embedCount === 0 && ($img === 0 || $img > 2))) { | 1062 | } else if ($contentLength < 25 && ($embedCount === 0 && ($img === 0 || $img > 2))) { |
1063 | $this->dbg(' content length less than 25 chars, 0 embeds and either 0 images or more than 2 images'); | 1063 | $this->dbg(' content length less than 25 chars, 0 embeds and either 0 images or more than 2 images'); |
1064 | $toRemove = true; | 1064 | $toRemove = true; |
@@ -1082,7 +1082,7 @@ class Readability | |||
1082 | $toRemove = true; | 1082 | $toRemove = true; |
1083 | } else if ( $input > floor($p/3) ) { | 1083 | } else if ( $input > floor($p/3) ) { |
1084 | $this->dbg(' too many <input> elements'); | 1084 | $this->dbg(' too many <input> elements'); |
1085 | $toRemove = true; | 1085 | $toRemove = true; |
1086 | } else if ($contentLength < 25 && ($img === 0 || $img > 2) ) { | 1086 | } else if ($contentLength < 25 && ($img === 0 || $img > 2) ) { |
1087 | $this->dbg(' content length less than 25 chars and 0 images, or more than 2 images'); | 1087 | $this->dbg(' content length less than 25 chars and 0 images, or more than 2 images'); |
1088 | $toRemove = true; | 1088 | $toRemove = true; |
@@ -1126,11 +1126,11 @@ class Readability | |||
1126 | public function flagIsActive($flag) { | 1126 | public function flagIsActive($flag) { |
1127 | return ($this->flags & $flag) > 0; | 1127 | return ($this->flags & $flag) > 0; |
1128 | } | 1128 | } |
1129 | 1129 | ||
1130 | public function addFlag($flag) { | 1130 | public function addFlag($flag) { |
1131 | $this->flags = $this->flags | $flag; | 1131 | $this->flags = $this->flags | $flag; |
1132 | } | 1132 | } |
1133 | 1133 | ||
1134 | public function removeFlag($flag) { | 1134 | public function removeFlag($flag) { |
1135 | $this->flags = $this->flags & ~$flag; | 1135 | $this->flags = $this->flags & ~$flag; |
1136 | } | 1136 | } |
diff --git a/inc/Session.class.php b/inc/3rdparty/Session.class.php index eff924cc..3162f507 100644 --- a/inc/Session.class.php +++ b/inc/3rdparty/Session.class.php | |||
@@ -93,7 +93,7 @@ class Session | |||
93 | // Force logout | 93 | // Force logout |
94 | public static function logout() | 94 | public static function logout() |
95 | { | 95 | { |
96 | unset($_SESSION['uid'],$_SESSION['info'],$_SESSION['expires_on'],$_SESSION['tokens'], $_SESSION['login'], $_SESSION['pass']); | 96 | unset($_SESSION['uid'],$_SESSION['info'],$_SESSION['expires_on'],$_SESSION['tokens'], $_SESSION['login'], $_SESSION['pass'], $_SESSION['poche_user']); |
97 | } | 97 | } |
98 | 98 | ||
99 | // Make sure user is logged in. | 99 | // Make sure user is logged in. |
diff --git a/inc/class.messages.php b/inc/3rdparty/class.messages.php index 6d515bf6..e60bd3a1 100644..100755 --- a/inc/class.messages.php +++ b/inc/3rdparty/class.messages.php | |||
@@ -1,231 +1,231 @@ | |||
1 | <?php | 1 | <?php |
2 | //-------------------------------------------------------------------------------------------------- | 2 | //-------------------------------------------------------------------------------------------------- |
3 | // Session-Based Flash Messages v1.0 | 3 | // Session-Based Flash Messages v1.0 |
4 | // Copyright 2012 Mike Everhart (http://mikeeverhart.net) | 4 | // Copyright 2012 Mike Everhart (http://mikeeverhart.net) |
5 | // | 5 | // |
6 | // Licensed under the Apache License, Version 2.0 (the "License"); | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); |
7 | // you may not use this file except in compliance with 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 | 8 | // You may obtain a copy of the License at |
9 | // | 9 | // |
10 | // http://www.apache.org/licenses/LICENSE-2.0 | 10 | // http://www.apache.org/licenses/LICENSE-2.0 |
11 | // | 11 | // |
12 | // Unless required by applicable law or agreed to in writing, software | 12 | // Unless required by applicable law or agreed to in writing, software |
13 | // distributed under the License is distributed on an "AS IS" BASIS, | 13 | // distributed under the License is distributed on an "AS IS" BASIS, |
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15 | // See the License for the specific language governing permissions and | 15 | // See the License for the specific language governing permissions and |
16 | // limitations under the License. | 16 | // limitations under the License. |
17 | // | 17 | // |
18 | //------------------------------------------------------------------------------ | 18 | //------------------------------------------------------------------------------ |
19 | // Description: | 19 | // Description: |
20 | //------------------------------------------------------------------------------ | 20 | //------------------------------------------------------------------------------ |
21 | // | 21 | // |
22 | // Stores messages in Session data to be easily retrieved later on. | 22 | // Stores messages in Session data to be easily retrieved later on. |
23 | // This class includes four different types of messages: | 23 | // This class includes four different types of messages: |
24 | // - Success | 24 | // - Success |
25 | // - Error | 25 | // - Error |
26 | // - Warning | 26 | // - Warning |
27 | // - Information | 27 | // - Information |
28 | // | 28 | // |
29 | // See README for basic usage instructions, or see samples/index.php for more advanced samples | 29 | // See README for basic usage instructions, or see samples/index.php for more advanced samples |
30 | // | 30 | // |
31 | //-------------------------------------------------------------------------------------------------- | 31 | //-------------------------------------------------------------------------------------------------- |
32 | // Changelog | 32 | // Changelog |
33 | //-------------------------------------------------------------------------------------------------- | 33 | //-------------------------------------------------------------------------------------------------- |
34 | // | 34 | // |
35 | // 2011-05-15 - v1.0 - Initial Version | 35 | // 2011-05-15 - v1.0 - Initial Version |
36 | // | 36 | // |
37 | //-------------------------------------------------------------------------------------------------- | 37 | //-------------------------------------------------------------------------------------------------- |
38 | 38 | ||
39 | class Messages { | 39 | class Messages { |
40 | 40 | ||
41 | //----------------------------------------------------------------------------------------------- | 41 | //----------------------------------------------------------------------------------------------- |
42 | // Class Variables | 42 | // Class Variables |
43 | //----------------------------------------------------------------------------------------------- | 43 | //----------------------------------------------------------------------------------------------- |
44 | var $msgId; | 44 | var $msgId; |
45 | var $msgTypes = array( 'help', 'info', 'warning', 'success', 'error' ); | 45 | var $msgTypes = array( 'help', 'info', 'warning', 'success', 'error' ); |
46 | var $msgClass = 'messages'; | 46 | var $msgClass = 'messages'; |
47 | var $msgWrapper = "<div class='%s %s'><a href='#' class='closeMessage'></a>\n%s</div>\n"; | 47 | var $msgWrapper = "<div class='%s %s'><a href='#' class='closeMessage'>X</a>\n%s</div>\n"; |
48 | var $msgBefore = '<p>'; | 48 | var $msgBefore = '<p>'; |
49 | var $msgAfter = "</p>\n"; | 49 | var $msgAfter = "</p>\n"; |
50 | 50 | ||
51 | 51 | ||
52 | /** | 52 | /** |
53 | * Constructor | 53 | * Constructor |
54 | * @author Mike Everhart | 54 | * @author Mike Everhart |
55 | */ | 55 | */ |
56 | public function __construct() { | 56 | public function __construct() { |
57 | 57 | ||
58 | // Generate a unique ID for this user and session | 58 | // Generate a unique ID for this user and session |
59 | $this->msgId = md5(uniqid()); | 59 | $this->msgId = md5(uniqid()); |
60 | 60 | ||
61 | // Create the session array if it doesnt already exist | 61 | // Create the session array if it doesnt already exist |
62 | if( !array_key_exists('flash_messages', $_SESSION) ) $_SESSION['flash_messages'] = array(); | 62 | if( !array_key_exists('flash_messages', $_SESSION) ) $_SESSION['flash_messages'] = array(); |
63 | 63 | ||
64 | } | 64 | } |
65 | 65 | ||
66 | /** | 66 | /** |
67 | * Add a message to the queue | 67 | * Add a message to the queue |
68 | * | 68 | * |
69 | * @author Mike Everhart | 69 | * @author Mike Everhart |
70 | * | 70 | * |
71 | * @param string $type The type of message to add | 71 | * @param string $type The type of message to add |
72 | * @param string $message The message | 72 | * @param string $message The message |
73 | * @param string $redirect_to (optional) If set, the user will be redirected to this URL | 73 | * @param string $redirect_to (optional) If set, the user will be redirected to this URL |
74 | * @return bool | 74 | * @return bool |
75 | * | 75 | * |
76 | */ | 76 | */ |
77 | public function add($type, $message, $redirect_to=null) { | 77 | public function add($type, $message, $redirect_to=null) { |
78 | 78 | ||
79 | if( !isset($_SESSION['flash_messages']) ) return false; | 79 | if( !isset($_SESSION['flash_messages']) ) return false; |
80 | 80 | ||
81 | if( !isset($type) || !isset($message[0]) ) return false; | 81 | if( !isset($type) || !isset($message[0]) ) return false; |
82 | 82 | ||
83 | // Replace any shorthand codes with their full version | 83 | // Replace any shorthand codes with their full version |
84 | if( strlen(trim($type)) == 1 ) { | 84 | if( strlen(trim($type)) == 1 ) { |
85 | $type = str_replace( array('h', 'i', 'w', 'e', 's'), array('help', 'info', 'warning', 'error', 'success'), $type ); | 85 | $type = str_replace( array('h', 'i', 'w', 'e', 's'), array('help', 'info', 'warning', 'error', 'success'), $type ); |
86 | 86 | ||
87 | // Backwards compatibility... | 87 | // Backwards compatibility... |
88 | } elseif( $type == 'information' ) { | 88 | } elseif( $type == 'information' ) { |
89 | $type = 'info'; | 89 | $type = 'info'; |
90 | } | 90 | } |
91 | 91 | ||
92 | // Make sure it's a valid message type | 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!' ); | 93 | if( !in_array($type, $this->msgTypes) ) die('"' . strip_tags($type) . '" is not a valid message type!' ); |
94 | 94 | ||
95 | // If the session array doesn't exist, create it | 95 | // If the session array doesn't exist, create it |
96 | if( !array_key_exists( $type, $_SESSION['flash_messages'] ) ) $_SESSION['flash_messages'][$type] = array(); | 96 | if( !array_key_exists( $type, $_SESSION['flash_messages'] ) ) $_SESSION['flash_messages'][$type] = array(); |
97 | 97 | ||
98 | $_SESSION['flash_messages'][$type][] = $message; | 98 | $_SESSION['flash_messages'][$type][] = $message; |
99 | 99 | ||
100 | if( !is_null($redirect_to) ) { | 100 | if( !is_null($redirect_to) ) { |
101 | header("Location: $redirect_to"); | 101 | header("Location: $redirect_to"); |
102 | exit(); | 102 | exit(); |
103 | } | 103 | } |
104 | 104 | ||
105 | return true; | 105 | return true; |
106 | 106 | ||
107 | } | 107 | } |
108 | 108 | ||
109 | //----------------------------------------------------------------------------------------------- | 109 | //----------------------------------------------------------------------------------------------- |
110 | // display() | 110 | // display() |
111 | // print queued messages to the screen | 111 | // print queued messages to the screen |
112 | //----------------------------------------------------------------------------------------------- | 112 | //----------------------------------------------------------------------------------------------- |
113 | /** | 113 | /** |
114 | * Display the queued messages | 114 | * Display the queued messages |
115 | * | 115 | * |
116 | * @author Mike Everhart | 116 | * @author Mike Everhart |
117 | * | 117 | * |
118 | * @param string $type Which messages to display | 118 | * @param string $type Which messages to display |
119 | * @param bool $print True = print the messages on the screen | 119 | * @param bool $print True = print the messages on the screen |
120 | * @return mixed | 120 | * @return mixed |
121 | * | 121 | * |
122 | */ | 122 | */ |
123 | public function display($type='all', $print=true) { | 123 | public function display($type='all', $print=true) { |
124 | $messages = ''; | 124 | $messages = ''; |
125 | $data = ''; | 125 | $data = ''; |
126 | 126 | ||
127 | if( !isset($_SESSION['flash_messages']) ) return false; | 127 | if( !isset($_SESSION['flash_messages']) ) return false; |
128 | 128 | ||
129 | if( $type == 'g' || $type == 'growl' ) { | 129 | if( $type == 'g' || $type == 'growl' ) { |
130 | $this->displayGrowlMessages(); | 130 | $this->displayGrowlMessages(); |
131 | return true; | 131 | return true; |
132 | } | 132 | } |
133 | 133 | ||
134 | // Print a certain type of message? | 134 | // Print a certain type of message? |
135 | if( in_array($type, $this->msgTypes) ) { | 135 | if( in_array($type, $this->msgTypes) ) { |
136 | foreach( $_SESSION['flash_messages'][$type] as $msg ) { | 136 | foreach( $_SESSION['flash_messages'][$type] as $msg ) { |
137 | $messages .= $this->msgBefore . $msg . $this->msgAfter; | 137 | $messages .= $this->msgBefore . $msg . $this->msgAfter; |
138 | } | 138 | } |
139 | 139 | ||
140 | $data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages); | 140 | $data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages); |
141 | 141 | ||
142 | // Clear the viewed messages | 142 | // Clear the viewed messages |
143 | $this->clear($type); | 143 | $this->clear($type); |
144 | 144 | ||
145 | // Print ALL queued messages | 145 | // Print ALL queued messages |
146 | } elseif( $type == 'all' ) { | 146 | } elseif( $type == 'all' ) { |
147 | foreach( $_SESSION['flash_messages'] as $type => $msgArray ) { | 147 | foreach( $_SESSION['flash_messages'] as $type => $msgArray ) { |
148 | $messages = ''; | 148 | $messages = ''; |
149 | foreach( $msgArray as $msg ) { | 149 | foreach( $msgArray as $msg ) { |
150 | $messages .= $this->msgBefore . $msg . $this->msgAfter; | 150 | $messages .= $this->msgBefore . $msg . $this->msgAfter; |
151 | } | 151 | } |
152 | $data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages); | 152 | $data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages); |
153 | } | 153 | } |
154 | 154 | ||
155 | // Clear ALL of the messages | 155 | // Clear ALL of the messages |
156 | $this->clear(); | 156 | $this->clear(); |
157 | 157 | ||
158 | // Invalid Message Type? | 158 | // Invalid Message Type? |
159 | } else { | 159 | } else { |
160 | return false; | 160 | return false; |
161 | } | 161 | } |
162 | 162 | ||
163 | // Print everything to the screen or return the data | 163 | // Print everything to the screen or return the data |
164 | if( $print ) { | 164 | if( $print ) { |
165 | echo $data; | 165 | echo $data; |
166 | } else { | 166 | } else { |
167 | return $data; | 167 | return $data; |
168 | } | 168 | } |
169 | } | 169 | } |
170 | 170 | ||
171 | 171 | ||
172 | /** | 172 | /** |
173 | * Check to see if there are any queued error messages | 173 | * Check to see if there are any queued error messages |
174 | * | 174 | * |
175 | * @author Mike Everhart | 175 | * @author Mike Everhart |
176 | * | 176 | * |
177 | * @return bool true = There ARE error messages | 177 | * @return bool true = There ARE error messages |
178 | * false = There are NOT any error messages | 178 | * false = There are NOT any error messages |
179 | * | 179 | * |
180 | */ | 180 | */ |
181 | public function hasErrors() { | 181 | public function hasErrors() { |
182 | return empty($_SESSION['flash_messages']['error']) ? false : true; | 182 | return empty($_SESSION['flash_messages']['error']) ? false : true; |
183 | } | 183 | } |
184 | 184 | ||
185 | /** | 185 | /** |
186 | * Check to see if there are any ($type) messages queued | 186 | * Check to see if there are any ($type) messages queued |
187 | * | 187 | * |
188 | * @author Mike Everhart | 188 | * @author Mike Everhart |
189 | * | 189 | * |
190 | * @param string $type The type of messages to check for | 190 | * @param string $type The type of messages to check for |
191 | * @return bool | 191 | * @return bool |
192 | * | 192 | * |
193 | */ | 193 | */ |
194 | public function hasMessages($type=null) { | 194 | public function hasMessages($type=null) { |
195 | if( !is_null($type) ) { | 195 | if( !is_null($type) ) { |
196 | if( !empty($_SESSION['flash_messages'][$type]) ) return $_SESSION['flash_messages'][$type]; | 196 | if( !empty($_SESSION['flash_messages'][$type]) ) return $_SESSION['flash_messages'][$type]; |
197 | } else { | 197 | } else { |
198 | foreach( $this->msgTypes as $type ) { | 198 | foreach( $this->msgTypes as $type ) { |
199 | if( !empty($_SESSION['flash_messages']) ) return true; | 199 | if( !empty($_SESSION['flash_messages']) ) return true; |
200 | } | 200 | } |
201 | } | 201 | } |
202 | return false; | 202 | return false; |
203 | } | 203 | } |
204 | 204 | ||
205 | /** | 205 | /** |
206 | * Clear messages from the session data | 206 | * Clear messages from the session data |
207 | * | 207 | * |
208 | * @author Mike Everhart | 208 | * @author Mike Everhart |
209 | * | 209 | * |
210 | * @param string $type The type of messages to clear | 210 | * @param string $type The type of messages to clear |
211 | * @return bool | 211 | * @return bool |
212 | * | 212 | * |
213 | */ | 213 | */ |
214 | public function clear($type='all') { | 214 | public function clear($type='all') { |
215 | if( $type == 'all' ) { | 215 | if( $type == 'all' ) { |
216 | unset($_SESSION['flash_messages']); | 216 | unset($_SESSION['flash_messages']); |
217 | } else { | 217 | } else { |
218 | unset($_SESSION['flash_messages'][$type]); | 218 | unset($_SESSION['flash_messages'][$type]); |
219 | } | 219 | } |
220 | return true; | 220 | return true; |
221 | } | 221 | } |
222 | 222 | ||
223 | public function __toString() { return $this->hasMessages(); } | 223 | public function __toString() { return $this->hasMessages(); } |
224 | 224 | ||
225 | public function __destruct() { | 225 | public function __destruct() { |
226 | //$this->clear(); | 226 | //$this->clear(); |
227 | } | 227 | } |
228 | 228 | ||
229 | 229 | ||
230 | } // end class | 230 | } // end class |
231 | ?> \ No newline at end of file | 231 | ?> \ No newline at end of file |
diff --git a/inc/3rdparty/paginator.php b/inc/3rdparty/paginator.php new file mode 100644 index 00000000..306756c0 --- /dev/null +++ b/inc/3rdparty/paginator.php | |||
@@ -0,0 +1,202 @@ | |||
1 | <?php | ||
2 | /* | ||
3 | * PHP Pagination Class | ||
4 | * | ||
5 | * @author David Carr - dave@daveismyname.com - http://www.daveismyname.com | ||
6 | * @version 1.0 | ||
7 | * @date October 20, 2013 | ||
8 | */ | ||
9 | class Paginator{ | ||
10 | |||
11 | /** | ||
12 | * set the number of items per page. | ||
13 | * | ||
14 | * @var numeric | ||
15 | */ | ||
16 | private $_perPage; | ||
17 | |||
18 | /** | ||
19 | * set get parameter for fetching the page number | ||
20 | * | ||
21 | * @var string | ||
22 | */ | ||
23 | private $_instance; | ||
24 | |||
25 | /** | ||
26 | * sets the page number. | ||
27 | * | ||
28 | * @var numeric | ||
29 | */ | ||
30 | private $_page; | ||
31 | |||
32 | /** | ||
33 | * set the limit for the data source | ||
34 | * | ||
35 | * @var string | ||
36 | */ | ||
37 | private $_limit; | ||
38 | |||
39 | /** | ||
40 | * set the total number of records/items. | ||
41 | * | ||
42 | * @var numeric | ||
43 | */ | ||
44 | private $_totalRows = 0; | ||
45 | |||
46 | |||
47 | |||
48 | /** | ||
49 | * __construct | ||
50 | * | ||
51 | * pass values when class is istantiated | ||
52 | * | ||
53 | * @param numeric $_perPage sets the number of iteems per page | ||
54 | * @param numeric $_instance sets the instance for the GET parameter | ||
55 | */ | ||
56 | public function __construct($perPage,$instance){ | ||
57 | $this->_instance = $instance; | ||
58 | $this->_perPage = $perPage; | ||
59 | $this->set_instance(); | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * get_start | ||
64 | * | ||
65 | * creates the starting point for limiting the dataset | ||
66 | * @return numeric | ||
67 | */ | ||
68 | private function get_start(){ | ||
69 | return ($this->_page * $this->_perPage) - $this->_perPage; | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * set_instance | ||
74 | * | ||
75 | * sets the instance parameter, if numeric value is 0 then set to 1 | ||
76 | * | ||
77 | * @var numeric | ||
78 | */ | ||
79 | private function set_instance(){ | ||
80 | $this->_page = (int) (!isset($_GET[$this->_instance]) ? 1 : $_GET[$this->_instance]); | ||
81 | $this->_page = ($this->_page == 0 ? 1 : $this->_page); | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * set_total | ||
86 | * | ||
87 | * collect a numberic value and assigns it to the totalRows | ||
88 | * | ||
89 | * @var numeric | ||
90 | */ | ||
91 | public function set_total($_totalRows){ | ||
92 | $this->_totalRows = $_totalRows; | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * get_limit | ||
97 | * | ||
98 | * returns the limit for the data source, calling the get_start method and passing in the number of items perp page | ||
99 | * | ||
100 | * @return string | ||
101 | */ | ||
102 | public function get_limit(){ | ||
103 | if (STORAGE == 'postgres') { | ||
104 | return "LIMIT ".$this->_perPage." OFFSET ".$this->get_start(); | ||
105 | } else { | ||
106 | return "LIMIT ".$this->get_start().",".$this->_perPage; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * page_links | ||
112 | * | ||
113 | * create the html links for navigating through the dataset | ||
114 | * | ||
115 | * @var sting $path optionally set the path for the link | ||
116 | * @var sting $ext optionally pass in extra parameters to the GET | ||
117 | * @return string returns the html menu | ||
118 | */ | ||
119 | public function page_links($path='?',$ext=null) | ||
120 | { | ||
121 | $adjacents = "2"; | ||
122 | $prev = $this->_page - 1; | ||
123 | $next = $this->_page + 1; | ||
124 | $lastpage = ceil($this->_totalRows/$this->_perPage); | ||
125 | $lpm1 = $lastpage - 1; | ||
126 | |||
127 | $pagination = ""; | ||
128 | if($lastpage > 1) | ||
129 | { | ||
130 | $pagination .= "<div class='pagination'>"; | ||
131 | if ($this->_page > 1) | ||
132 | $pagination.= "<a href='".$path."$this->_instance=$prev"."$ext'>« previous</a>"; | ||
133 | else | ||
134 | $pagination.= "<span class='disabled'>« previous</span>"; | ||
135 | |||
136 | if ($lastpage < 7 + ($adjacents * 2)) | ||
137 | { | ||
138 | for ($counter = 1; $counter <= $lastpage; $counter++) | ||
139 | { | ||
140 | if ($counter == $this->_page) | ||
141 | $pagination.= "<span class='current'>$counter</span>"; | ||
142 | else | ||
143 | $pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>"; | ||
144 | } | ||
145 | } | ||
146 | elseif($lastpage > 5 + ($adjacents * 2)) | ||
147 | { | ||
148 | if($this->_page < 1 + ($adjacents * 2)) | ||
149 | { | ||
150 | for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) | ||
151 | { | ||
152 | if ($counter == $this->_page) | ||
153 | $pagination.= "<span class='current'>$counter</span>"; | ||
154 | else | ||
155 | $pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>"; | ||
156 | } | ||
157 | $pagination.= "..."; | ||
158 | $pagination.= "<a href='".$path."$this->_instance=$lpm1"."$ext'>$lpm1</a>"; | ||
159 | $pagination.= "<a href='".$path."$this->_instance=$lastpage"."$ext'>$lastpage</a>"; | ||
160 | } | ||
161 | elseif($lastpage - ($adjacents * 2) > $this->_page && $this->_page > ($adjacents * 2)) | ||
162 | { | ||
163 | $pagination.= "<a href='".$path."$this->_instance=1"."$ext'>1</a>"; | ||
164 | $pagination.= "<a href='".$path."$this->_instance=2"."$ext'>2</a>"; | ||
165 | $pagination.= "..."; | ||
166 | for ($counter = $this->_page - $adjacents; $counter <= $this->_page + $adjacents; $counter++) | ||
167 | { | ||
168 | if ($counter == $this->_page) | ||
169 | $pagination.= "<span class='current'>$counter</span>"; | ||
170 | else | ||
171 | $pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>"; | ||
172 | } | ||
173 | $pagination.= ".."; | ||
174 | $pagination.= "<a href='".$path."$this->_instance=$lpm1"."$ext'>$lpm1</a>"; | ||
175 | $pagination.= "<a href='".$path."$this->_instance=$lastpage"."$ext'>$lastpage</a>"; | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | $pagination.= "<a href='".$path."$this->_instance=1"."$ext'>1</a>"; | ||
180 | $pagination.= "<a href='".$path."$this->_instance=2"."$ext'>2</a>"; | ||
181 | $pagination.= ".."; | ||
182 | for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) | ||
183 | { | ||
184 | if ($counter == $this->_page) | ||
185 | $pagination.= "<span class='current'>$counter</span>"; | ||
186 | else | ||
187 | $pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>"; | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | |||
192 | if ($this->_page < $counter - 1) | ||
193 | $pagination.= "<a href='".$path."$this->_instance=$next"."$ext'>next »</a>"; | ||
194 | else | ||
195 | $pagination.= "<span class='disabled'>next »</span>"; | ||
196 | $pagination.= "</div>\n"; | ||
197 | } | ||
198 | |||
199 | |||
200 | return $pagination; | ||
201 | } | ||
202 | } | ||
diff --git a/inc/simple_html_dom.php b/inc/3rdparty/simple_html_dom.php index 43b94e57..43b94e57 100644 --- a/inc/simple_html_dom.php +++ b/inc/3rdparty/simple_html_dom.php | |||
diff --git a/inc/MyTool.class.php b/inc/MyTool.class.php deleted file mode 100644 index 1f5051a4..00000000 --- a/inc/MyTool.class.php +++ /dev/null | |||
@@ -1,265 +0,0 @@ | |||
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 MyTool | ||
12 | { | ||
13 | public static function initPhp() | ||
14 | { | ||
15 | define('START_TIME', microtime(true)); | ||
16 | |||
17 | if (phpversion() < 5) { | ||
18 | die("Argh you don't have PHP 5 !"); | ||
19 | } | ||
20 | |||
21 | error_reporting(E_ALL); | ||
22 | |||
23 | function stripslashesDeep($value) { | ||
24 | return is_array($value) | ||
25 | ? array_map('stripslashesDeep', $value) | ||
26 | : stripslashes($value); | ||
27 | } | ||
28 | |||
29 | if (get_magic_quotes_gpc()) { | ||
30 | $_POST = array_map('stripslashesDeep', $_POST); | ||
31 | $_GET = array_map('stripslashesDeep', $_GET); | ||
32 | $_COOKIE = array_map('stripslashesDeep', $_COOKIE); | ||
33 | } | ||
34 | |||
35 | ob_start(); | ||
36 | register_shutdown_function('ob_end_flush'); | ||
37 | } | ||
38 | |||
39 | public static function isUrl($url) | ||
40 | { | ||
41 | // http://neo22s.com/check-if-url-exists-and-is-online-php/ | ||
42 | $pattern='|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i'; | ||
43 | |||
44 | return preg_match($pattern, $url); | ||
45 | } | ||
46 | |||
47 | public static function isEmail($email) | ||
48 | { | ||
49 | $pattern = "/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2, 4}$/i"; | ||
50 | |||
51 | return (preg_match($pattern, $email)); | ||
52 | } | ||
53 | |||
54 | public static function formatBBCode($text) | ||
55 | { | ||
56 | $replace = array( | ||
57 | '/\[m\](.+?)\[\/m\]/is' | ||
58 | => '/* moderate */', | ||
59 | '/\[b\](.+?)\[\/b\]/is' | ||
60 | => '<strong>$1</strong>', | ||
61 | '/\[i\](.+?)\[\/i\]/is' | ||
62 | => '<em>$1</em>', | ||
63 | '/\[s\](.+?)\[\/s\]/is' | ||
64 | => '<del>$1</del>', | ||
65 | '/\[u\](.+?)\[\/u\]/is' | ||
66 | => '<span style="text-decoration: underline;">$1</span>', | ||
67 | '/\[url\](.+?)\[\/url]/is' | ||
68 | => '<a href="$1">$1</a>', | ||
69 | '/\[url=(\w+:\/\/[^\]]+)\](.+?)\[\/url]/is' | ||
70 | => '<a href="$1">$2</a>', | ||
71 | '/\[quote\](.+?)\[\/quote\]/is' | ||
72 | => '<blockquote>$1</blockquote>', | ||
73 | '/\[code\](.+?)\[\/code\]/is' | ||
74 | => '<code>$1</code>', | ||
75 | '/\[([^[]+)\|([^[]+)\]/is' | ||
76 | => '<a href="$2">$1</a>' | ||
77 | ); | ||
78 | $text = preg_replace( | ||
79 | array_keys($replace), | ||
80 | array_values($replace), | ||
81 | $text | ||
82 | ); | ||
83 | |||
84 | return $text; | ||
85 | } | ||
86 | |||
87 | public static function formatText($text) | ||
88 | { | ||
89 | $text = preg_replace_callback( | ||
90 | '/<code_html>(.*?)<\/code_html>/is', | ||
91 | create_function( | ||
92 | '$matches', | ||
93 | 'return htmlspecialchars($matches[1]);' | ||
94 | ), | ||
95 | $text | ||
96 | ); | ||
97 | $text = preg_replace_callback( | ||
98 | '/<code_php>(.*?)<\/code_php>/is', | ||
99 | create_function( | ||
100 | '$matches', | ||
101 | 'return highlight_string("<?php $matches[1] ?>", true);' | ||
102 | ), | ||
103 | $text | ||
104 | ); | ||
105 | $text = preg_replace('/<br \/>/is', '', $text); | ||
106 | |||
107 | $text = preg_replace( | ||
108 | '#(^|\s)([a-z]+://([^\s\w/]?[\w/])*)(\s|$)#im', | ||
109 | '\\1<a href="\\2">\\2</a>\\4', | ||
110 | $text | ||
111 | ); | ||
112 | $text = preg_replace( | ||
113 | '#(^|\s)wp:?([a-z]{2}|):([\w]+)#im', | ||
114 | '\\1<a href="http://\\2.wikipedia.org/wiki/\\3">\\3</a>', | ||
115 | $text | ||
116 | ); | ||
117 | $text = str_replace( | ||
118 | 'http://.wikipedia.org/wiki/', | ||
119 | 'http://www.wikipedia.org/wiki/', | ||
120 | $text | ||
121 | ); | ||
122 | $text = str_replace('\wp:', 'wp:', $text); | ||
123 | $text = str_replace('\http:', 'http:', $text); | ||
124 | $text = MyTool::formatBBCode($text); | ||
125 | $text = nl2br($text); | ||
126 | |||
127 | return $text; | ||
128 | } | ||
129 | |||
130 | public static function getUrl() | ||
131 | { | ||
132 | $https = (!empty($_SERVER['HTTPS']) | ||
133 | && (strtolower($_SERVER['HTTPS']) == 'on')) | ||
134 | || (isset($_SERVER["SERVER_PORT"]) | ||
135 | && $_SERVER["SERVER_PORT"] == '443'); // HTTPS detection. | ||
136 | $serverport = (!isset($_SERVER["SERVER_PORT"]) | ||
137 | || $_SERVER["SERVER_PORT"] == '80' | ||
138 | || ($https && $_SERVER["SERVER_PORT"] == '443') | ||
139 | ? '' | ||
140 | : ':' . $_SERVER["SERVER_PORT"]); | ||
141 | |||
142 | $scriptname = str_replace('/index.php', '/', $_SERVER["SCRIPT_NAME"]); | ||
143 | |||
144 | if (!isset($_SERVER["SERVER_NAME"])) { | ||
145 | return $scriptname; | ||
146 | } | ||
147 | |||
148 | return 'http' . ($https ? 's' : '') . '://' | ||
149 | . $_SERVER["SERVER_NAME"] . $serverport . $scriptname; | ||
150 | } | ||
151 | |||
152 | public static function rrmdir($dir) | ||
153 | { | ||
154 | if (is_dir($dir) && ($d = @opendir($dir))) { | ||
155 | while (($file = @readdir($d)) !== false) { | ||
156 | if ( $file == '.' || $file == '..' ) { | ||
157 | continue; | ||
158 | } else { | ||
159 | unlink($dir . '/' . $file); | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | public static function humanBytes($bytes) | ||
166 | { | ||
167 | $siPrefix = array( 'bytes', 'KB', 'MB', 'GB', 'TB', 'EB', 'ZB', 'YB' ); | ||
168 | $base = 1024; | ||
169 | $class = min((int) log($bytes, $base), count($siPrefix) - 1); | ||
170 | $val = sprintf('%1.2f', $bytes / pow($base, $class)); | ||
171 | |||
172 | return $val . ' ' . $siPrefix[$class]; | ||
173 | } | ||
174 | |||
175 | public static function returnBytes($val) | ||
176 | { | ||
177 | $val = trim($val); | ||
178 | $last = strtolower($val[strlen($val)-1]); | ||
179 | switch($last) | ||
180 | { | ||
181 | case 'g': $val *= 1024; | ||
182 | case 'm': $val *= 1024; | ||
183 | case 'k': $val *= 1024; | ||
184 | } | ||
185 | |||
186 | return $val; | ||
187 | } | ||
188 | |||
189 | public static function getMaxFileSize() | ||
190 | { | ||
191 | $sizePostMax = MyTool::returnBytes(ini_get('post_max_size')); | ||
192 | $sizeUploadMax = MyTool::returnBytes(ini_get('upload_max_filesize')); | ||
193 | |||
194 | // Return the smaller of two: | ||
195 | return min($sizePostMax, $sizeUploadMax); | ||
196 | } | ||
197 | |||
198 | public static function smallHash($text) | ||
199 | { | ||
200 | $t = rtrim(base64_encode(hash('crc32', $text, true)), '='); | ||
201 | // Get rid of characters which need encoding in URLs. | ||
202 | $t = str_replace('+', '-', $t); | ||
203 | $t = str_replace('/', '_', $t); | ||
204 | $t = str_replace('=', '@', $t); | ||
205 | |||
206 | return $t; | ||
207 | } | ||
208 | |||
209 | public static function renderJson($data) | ||
210 | { | ||
211 | header('Cache-Control: no-cache, must-revalidate'); | ||
212 | header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); | ||
213 | header('Content-type: application/json; charset=UTF-8'); | ||
214 | |||
215 | echo json_encode($data); | ||
216 | exit(); | ||
217 | } | ||
218 | |||
219 | public static function grabToLocal($url, $file, $force = false) | ||
220 | { | ||
221 | if ((!file_exists($file) || $force) && in_array('curl', get_loaded_extensions())){ | ||
222 | $ch = curl_init ($url); | ||
223 | curl_setopt($ch, CURLOPT_HEADER, false); | ||
224 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||
225 | curl_setopt($ch, CURLOPT_BINARYTRANSFER, true); | ||
226 | $raw = curl_exec($ch); | ||
227 | if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200) { | ||
228 | $fp = fopen($file, 'x'); | ||
229 | fwrite($fp, $raw); | ||
230 | fclose($fp); | ||
231 | } | ||
232 | curl_close ($ch); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | public static function redirect($rurl = '') | ||
237 | { | ||
238 | if ($rurl === '') { | ||
239 | // if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['SERVER_NAME'])==0) | ||
240 | $rurl = (empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']); | ||
241 | if (isset($_POST['returnurl'])) { | ||
242 | $rurl = $_POST['returnurl']; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | // prevent loop | ||
247 | if (empty($rurl) || parse_url($rurl, PHP_URL_QUERY) === $_SERVER['QUERY_STRING']) { | ||
248 | $rurl = MyTool::getUrl(); | ||
249 | } | ||
250 | |||
251 | if (substr($rurl, 0, 1) !== '?') { | ||
252 | $ref = MyTool::getUrl(); | ||
253 | if (substr($rurl, 0, strlen($ref)) !== $ref) { | ||
254 | $rurl = $ref; | ||
255 | } | ||
256 | } | ||
257 | header('Location: '.$rurl); | ||
258 | exit(); | ||
259 | } | ||
260 | |||
261 | public static function silence_errors($num, $str) | ||
262 | { | ||
263 | // No-op | ||
264 | } | ||
265 | } \ No newline at end of file | ||
diff --git a/inc/config.php b/inc/config.php deleted file mode 100644 index bd9287fe..00000000 --- a/inc/config.php +++ /dev/null | |||
@@ -1,66 +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 | define ('POCHE_VERSION', '0.2.1'); | ||
12 | |||
13 | if (!is_dir('db/')) { | ||
14 | @mkdir('db/',0705); | ||
15 | } | ||
16 | |||
17 | define ('MODE_DEMO', FALSE); | ||
18 | define ('ABS_PATH', 'assets/'); | ||
19 | define ('CONVERT_LINKS_FOOTNOTES', TRUE); | ||
20 | define ('REVERT_FORCED_PARAGRAPH_ELEMENTS',FALSE); | ||
21 | define ('DOWNLOAD_PICTURES', TRUE); | ||
22 | define ('SALT', '464v54gLLw928uz4zUBqkRJeiPY68zCX'); | ||
23 | $storage_type = 'sqlite'; # sqlite or file | ||
24 | |||
25 | include 'functions.php'; | ||
26 | require_once 'Readability.php'; | ||
27 | require_once 'Encoding.php'; | ||
28 | require_once 'rain.tpl.class.php'; | ||
29 | require_once 'MyTool.class.php'; | ||
30 | require_once 'Session.class.php'; | ||
31 | require_once 'store/store.class.php'; | ||
32 | require_once 'store/sqlite.class.php'; | ||
33 | require_once 'store/file.class.php'; | ||
34 | require_once 'class.messages.php'; | ||
35 | |||
36 | Session::init(); | ||
37 | |||
38 | $store = new $storage_type(); | ||
39 | # initialisation de RainTPL | ||
40 | raintpl::$tpl_dir = './tpl/'; | ||
41 | raintpl::$cache_dir = './cache/'; | ||
42 | raintpl::$base_url = get_poche_url(); | ||
43 | raintpl::configure('path_replace', false); | ||
44 | raintpl::configure('debug', false); | ||
45 | $tpl = new raintpl(); | ||
46 | |||
47 | if(!$store->isInstalled()) | ||
48 | { | ||
49 | logm('poche still not installed'); | ||
50 | $tpl->draw('install'); | ||
51 | if (isset($_GET['install'])) { | ||
52 | if (($_POST['password'] == $_POST['password_repeat']) | ||
53 | && $_POST['password'] != "" && $_POST['login'] != "") { | ||
54 | $store->install($_POST['login'], encode_string($_POST['password'] . $_POST['login'])); | ||
55 | Session::logout(); | ||
56 | MyTool::redirect(); | ||
57 | } | ||
58 | } | ||
59 | exit(); | ||
60 | } | ||
61 | |||
62 | $_SESSION['login'] = (isset ($_SESSION['login'])) ? $_SESSION['login'] : $store->getLogin(); | ||
63 | $_SESSION['pass'] = (isset ($_SESSION['pass'])) ? $_SESSION['pass'] : $store->getPassword(); | ||
64 | |||
65 | $msg = new Messages(); | ||
66 | $tpl->assign('msg', $msg); \ No newline at end of file | ||
diff --git a/inc/functions.php b/inc/functions.php deleted file mode 100644 index 73e591c5..00000000 --- a/inc/functions.php +++ /dev/null | |||
@@ -1,398 +0,0 @@ | |||
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 | /** | ||
12 | * Permet de générer l'URL de poche pour le bookmarklet | ||
13 | */ | ||
14 | function get_poche_url() | ||
15 | { | ||
16 | $protocol = "http"; | ||
17 | if(isset($_SERVER['HTTPS'])) { | ||
18 | if($_SERVER['HTTPS'] != "off" && $_SERVER['HTTPS'] != "") { | ||
19 | $protocol = "https"; | ||
20 | } | ||
21 | } | ||
22 | |||
23 | return $protocol . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; | ||
24 | } | ||
25 | |||
26 | function encode_string($string) | ||
27 | { | ||
28 | return sha1($string . SALT); | ||
29 | } | ||
30 | |||
31 | // function define to retrieve url content | ||
32 | function get_external_file($url) | ||
33 | { | ||
34 | $timeout = 15; | ||
35 | // spoofing FireFox 18.0 | ||
36 | $useragent="Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0"; | ||
37 | |||
38 | if (in_array ('curl', get_loaded_extensions())) { | ||
39 | // Fetch feed from URL | ||
40 | $curl = curl_init(); | ||
41 | curl_setopt($curl, CURLOPT_URL, $url); | ||
42 | curl_setopt($curl, CURLOPT_TIMEOUT, $timeout); | ||
43 | curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); | ||
44 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | ||
45 | curl_setopt($curl, CURLOPT_HEADER, false); | ||
46 | |||
47 | // FOR SSL do not verified certificate | ||
48 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); | ||
49 | curl_setopt($curl, CURLOPT_AUTOREFERER, TRUE ); | ||
50 | |||
51 | // FeedBurner requires a proper USER-AGENT... | ||
52 | curl_setopt($curl, CURL_HTTP_VERSION_1_1, true); | ||
53 | curl_setopt($curl, CURLOPT_ENCODING, "gzip, deflate"); | ||
54 | curl_setopt($curl, CURLOPT_USERAGENT, $useragent); | ||
55 | |||
56 | $data = curl_exec($curl); | ||
57 | |||
58 | $httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE); | ||
59 | |||
60 | $httpcodeOK = isset($httpcode) and ($httpcode == 200 or $httpcode == 301); | ||
61 | |||
62 | curl_close($curl); | ||
63 | } else { | ||
64 | |||
65 | // create http context and add timeout and user-agent | ||
66 | $context = stream_context_create(array( | ||
67 | 'http'=>array('timeout' => $timeout, | ||
68 | 'header'=> "User-Agent: ".$useragent, /*spoot Mozilla Firefox*/ | ||
69 | 'follow_location' => true), | ||
70 | // FOR SSL do not verified certificate | ||
71 | 'ssl' => array('verify_peer' => false, | ||
72 | 'allow_self_signed' => true) | ||
73 | ) | ||
74 | ); | ||
75 | |||
76 | // only download page lesser than 4MB | ||
77 | $data = @file_get_contents($url, false, $context, -1, 4000000); // We download at most 4 MB from source. | ||
78 | |||
79 | if(isset($http_response_header) and isset($http_response_header[0])) { | ||
80 | $httpcodeOK = isset($http_response_header) and isset($http_response_header[0]) and ((strpos($http_response_header[0], '200 OK') !== FALSE) or (strpos($http_response_header[0], '301 Moved Permanently') !== FALSE)); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | // if response is not empty and response is OK | ||
85 | if (isset($data) and isset($httpcodeOK) and $httpcodeOK ) { | ||
86 | |||
87 | // take charset of page and get it | ||
88 | preg_match('#<meta .*charset=.*>#Usi', $data, $meta); | ||
89 | |||
90 | // if meta tag is found | ||
91 | if (!empty($meta[0])) { | ||
92 | // retrieve encoding in $enc | ||
93 | preg_match('#charset="?(.*)"#si', $meta[0], $enc); | ||
94 | |||
95 | // if charset is found set it otherwise, set it to utf-8 | ||
96 | $html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : 'utf-8'; | ||
97 | |||
98 | } else { | ||
99 | $html_charset = 'utf-8'; | ||
100 | $enc[1] = ''; | ||
101 | } | ||
102 | |||
103 | // replace charset of url to charset of page | ||
104 | $data = str_replace('charset='.$enc[1], 'charset='.$html_charset, $data); | ||
105 | |||
106 | return $data; | ||
107 | } | ||
108 | else { | ||
109 | return FALSE; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * Préparation de l'URL avec récupération du contenu avant insertion en base | ||
115 | */ | ||
116 | function prepare_url($url) | ||
117 | { | ||
118 | $parametres = array(); | ||
119 | $url = html_entity_decode(trim($url)); | ||
120 | |||
121 | // We remove the annoying parameters added by FeedBurner and GoogleFeedProxy (?utm_source=...) | ||
122 | // from shaarli, by sebsauvage | ||
123 | $i=strpos($url,'&utm_source='); if ($i!==false) $url=substr($url,0,$i); | ||
124 | $i=strpos($url,'?utm_source='); if ($i!==false) $url=substr($url,0,$i); | ||
125 | $i=strpos($url,'#xtor=RSS-'); if ($i!==false) $url=substr($url,0,$i); | ||
126 | |||
127 | $title = $url; | ||
128 | $html = Encoding::toUTF8(get_external_file($url,15)); | ||
129 | // If get_external_file if not able to retrieve HTTPS content try the same URL with HTTP protocol | ||
130 | if (!preg_match('!^https?://!i', $url) && (!isset($html) || strlen($html) <= 0)) { | ||
131 | $url = 'http://' . $url; | ||
132 | $html = Encoding::toUTF8(get_external_file($url,15)); | ||
133 | } | ||
134 | |||
135 | if (function_exists('tidy_parse_string')) { | ||
136 | $tidy = tidy_parse_string($html, array(), 'UTF8'); | ||
137 | $tidy->cleanRepair(); | ||
138 | $html = $tidy->value; | ||
139 | } | ||
140 | |||
141 | if (isset($html) and strlen($html) > 0) | ||
142 | { | ||
143 | $r = new Readability($html, $url); | ||
144 | |||
145 | $r->convertLinksToFootnotes = CONVERT_LINKS_FOOTNOTES; | ||
146 | $r->revertForcedParagraphElements = REVERT_FORCED_PARAGRAPH_ELEMENTS; | ||
147 | |||
148 | if($r->init()) | ||
149 | { | ||
150 | $content = $r->articleContent->innerHTML; | ||
151 | $parametres['title'] = $r->articleTitle->innerHTML; | ||
152 | $parametres['content'] = $content; | ||
153 | return $parametres; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | return FALSE; | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * On modifie les URLS des images dans le corps de l'article | ||
162 | */ | ||
163 | function filtre_picture($content, $url, $id) | ||
164 | { | ||
165 | $matches = array(); | ||
166 | preg_match_all('#<\s*(img)[^>]+src="([^"]*)"[^>]*>#Si', $content, $matches, PREG_SET_ORDER); | ||
167 | foreach($matches as $i => $link) | ||
168 | { | ||
169 | $link[1] = trim($link[1]); | ||
170 | if (!preg_match('#^(([a-z]+://)|(\#))#', $link[1]) ) | ||
171 | { | ||
172 | $absolute_path = get_absolute_link($link[2],$url); | ||
173 | $filename = basename(parse_url($absolute_path, PHP_URL_PATH)); | ||
174 | $directory = create_assets_directory($id); | ||
175 | $fullpath = $directory . '/' . $filename; | ||
176 | download_pictures($absolute_path, $fullpath); | ||
177 | $content = str_replace($matches[$i][2], $fullpath, $content); | ||
178 | } | ||
179 | |||
180 | } | ||
181 | |||
182 | return $content; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * Retourne le lien absolu | ||
187 | */ | ||
188 | function get_absolute_link($relative_link, $url) | ||
189 | { | ||
190 | /* return if already absolute URL */ | ||
191 | if (parse_url($relative_link, PHP_URL_SCHEME) != '') return $relative_link; | ||
192 | |||
193 | /* queries and anchors */ | ||
194 | if ($relative_link[0]=='#' || $relative_link[0]=='?') return $url . $relative_link; | ||
195 | |||
196 | /* parse base URL and convert to local variables: | ||
197 | $scheme, $host, $path */ | ||
198 | extract(parse_url($url)); | ||
199 | |||
200 | /* remove non-directory element from path */ | ||
201 | $path = preg_replace('#/[^/]*$#', '', $path); | ||
202 | |||
203 | /* destroy path if relative url points to root */ | ||
204 | if ($relative_link[0] == '/') $path = ''; | ||
205 | |||
206 | /* dirty absolute URL */ | ||
207 | $abs = $host . $path . '/' . $relative_link; | ||
208 | |||
209 | /* replace '//' or '/./' or '/foo/../' with '/' */ | ||
210 | $re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#'); | ||
211 | for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {} | ||
212 | |||
213 | /* absolute URL is ready! */ | ||
214 | return $scheme.'://'.$abs; | ||
215 | } | ||
216 | |||
217 | /** | ||
218 | * Téléchargement des images | ||
219 | */ | ||
220 | |||
221 | function download_pictures($absolute_path, $fullpath) | ||
222 | { | ||
223 | $rawdata = get_external_file($absolute_path); | ||
224 | |||
225 | if(file_exists($fullpath)) { | ||
226 | unlink($fullpath); | ||
227 | } | ||
228 | $fp = fopen($fullpath, 'x'); | ||
229 | fwrite($fp, $rawdata); | ||
230 | fclose($fp); | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * Crée un répertoire de médias pour l'article | ||
235 | */ | ||
236 | function create_assets_directory($id) | ||
237 | { | ||
238 | $assets_path = ABS_PATH; | ||
239 | if(!is_dir($assets_path)) { | ||
240 | mkdir($assets_path, 0705); | ||
241 | } | ||
242 | |||
243 | $article_directory = $assets_path . $id; | ||
244 | if(!is_dir($article_directory)) { | ||
245 | mkdir($article_directory, 0705); | ||
246 | } | ||
247 | |||
248 | return $article_directory; | ||
249 | } | ||
250 | |||
251 | /** | ||
252 | * Suppression du répertoire d'images | ||
253 | */ | ||
254 | function remove_directory($directory) | ||
255 | { | ||
256 | if(is_dir($directory)) { | ||
257 | $files = array_diff(scandir($directory), array('.','..')); | ||
258 | foreach ($files as $file) { | ||
259 | (is_dir("$directory/$file")) ? remove_directory("$directory/$file") : unlink("$directory/$file"); | ||
260 | } | ||
261 | return rmdir($directory); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | function display_view($view, $id = 0, $full_head = 'yes') | ||
266 | { | ||
267 | global $tpl, $store, $msg; | ||
268 | |||
269 | switch ($view) | ||
270 | { | ||
271 | case 'export': | ||
272 | $entries = $store->retrieveAll(); | ||
273 | $tpl->assign('export', myTool::renderJson($entries)); | ||
274 | $tpl->draw('export'); | ||
275 | logm('export view'); | ||
276 | break; | ||
277 | case 'config': | ||
278 | $tpl->assign('load_all_js', 0); | ||
279 | $tpl->draw('head'); | ||
280 | $tpl->draw('home'); | ||
281 | $tpl->draw('config'); | ||
282 | $tpl->draw('js'); | ||
283 | $tpl->draw('footer'); | ||
284 | logm('config view'); | ||
285 | break; | ||
286 | case 'view': | ||
287 | $entry = $store->retrieveOneById($id); | ||
288 | |||
289 | if ($entry != NULL) { | ||
290 | $tpl->assign('id', $entry['id']); | ||
291 | $tpl->assign('url', $entry['url']); | ||
292 | $tpl->assign('title', $entry['title']); | ||
293 | $content = $entry['content']; | ||
294 | if (function_exists('tidy_parse_string')) { | ||
295 | $tidy = tidy_parse_string($content, array('indent'=>true, 'show-body-only' => true), 'UTF8'); | ||
296 | $tidy->cleanRepair(); | ||
297 | $content = $tidy->value; | ||
298 | } | ||
299 | $tpl->assign('content', $content); | ||
300 | $tpl->assign('is_fav', $entry['is_fav']); | ||
301 | $tpl->assign('is_read', $entry['is_read']); | ||
302 | $tpl->assign('load_all_js', 0); | ||
303 | $tpl->draw('view'); | ||
304 | } | ||
305 | else { | ||
306 | logm('error in view call : entry is NULL'); | ||
307 | } | ||
308 | |||
309 | logm('view link #' . $id); | ||
310 | break; | ||
311 | default: # home view | ||
312 | $entries = $store->getEntriesByView($view); | ||
313 | |||
314 | $tpl->assign('entries', $entries); | ||
315 | |||
316 | if ($full_head == 'yes') { | ||
317 | $tpl->assign('load_all_js', 1); | ||
318 | $tpl->draw('head'); | ||
319 | $tpl->draw('home'); | ||
320 | } | ||
321 | |||
322 | $tpl->draw('entries'); | ||
323 | |||
324 | if ($full_head == 'yes') { | ||
325 | $tpl->draw('js'); | ||
326 | $tpl->draw('footer'); | ||
327 | } | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | /** | ||
333 | * Appel d'une action (mark as fav, archive, delete) | ||
334 | */ | ||
335 | function action_to_do($action, $url, $id = 0) | ||
336 | { | ||
337 | global $store, $msg; | ||
338 | |||
339 | switch ($action) | ||
340 | { | ||
341 | case 'add': | ||
342 | if ($url == '') | ||
343 | continue; | ||
344 | |||
345 | if (MyTool::isUrl($url)) { | ||
346 | if($parametres_url = prepare_url($url)) { | ||
347 | if ($store->add($url, $parametres_url['title'], $parametres_url['content'])) { | ||
348 | $last_id = $store->getLastId(); | ||
349 | if (DOWNLOAD_PICTURES) { | ||
350 | $content = filtre_picture($parametres_url['content'], $url, $last_id); | ||
351 | } | ||
352 | $msg->add('s', 'the link has been added successfully'); | ||
353 | } | ||
354 | else { | ||
355 | $msg->add('e', 'error during insertion : the link wasn\'t added'); | ||
356 | } | ||
357 | } | ||
358 | else { | ||
359 | $msg->add('e', 'error during url preparation : the link wasn\'t added'); | ||
360 | logm('error during url preparation'); | ||
361 | } | ||
362 | } | ||
363 | else { | ||
364 | $msg->add('e', 'error during url preparation : the link is not valid'); | ||
365 | logm($url . ' is not a valid url'); | ||
366 | } | ||
367 | |||
368 | logm('add link ' . $url); | ||
369 | break; | ||
370 | case 'delete': | ||
371 | if ($store->deleteById($id)) { | ||
372 | remove_directory(ABS_PATH . $id); | ||
373 | $msg->add('s', 'the link has been deleted successfully'); | ||
374 | logm('delete link #' . $id); | ||
375 | } | ||
376 | else { | ||
377 | $msg->add('e', 'the link wasn\'t deleted'); | ||
378 | logm('error : can\'t delete link #' . $id); | ||
379 | } | ||
380 | break; | ||
381 | case 'toggle_fav' : | ||
382 | $store->favoriteById($id); | ||
383 | logm('mark as favorite link #' . $id); | ||
384 | break; | ||
385 | case 'toggle_archive' : | ||
386 | $store->archiveById($id); | ||
387 | logm('archive link #' . $id); | ||
388 | break; | ||
389 | default: | ||
390 | break; | ||
391 | } | ||
392 | } | ||
393 | |||
394 | function logm($message) | ||
395 | { | ||
396 | $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n"; | ||
397 | file_put_contents('./log.txt',$t,FILE_APPEND); | ||
398 | } | ||
diff --git a/inc/poche/Database.class.php b/inc/poche/Database.class.php new file mode 100644 index 00000000..cd5a9a31 --- /dev/null +++ b/inc/poche/Database.class.php | |||
@@ -0,0 +1,216 @@ | |||
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 Database { | ||
12 | var $handle; | ||
13 | |||
14 | function __construct() | ||
15 | { | ||
16 | switch (STORAGE) { | ||
17 | case 'sqlite': | ||
18 | $db_path = 'sqlite:' . STORAGE_SQLITE; | ||
19 | $this->handle = new PDO($db_path); | ||
20 | break; | ||
21 | case 'mysql': | ||
22 | $db_path = 'mysql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB; | ||
23 | $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD); | ||
24 | break; | ||
25 | case 'postgres': | ||
26 | $db_path = 'pgsql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB; | ||
27 | $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD); | ||
28 | break; | ||
29 | } | ||
30 | |||
31 | $this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | ||
32 | Tools::logm('storage type ' . STORAGE); | ||
33 | } | ||
34 | |||
35 | private function getHandle() { | ||
36 | return $this->handle; | ||
37 | } | ||
38 | |||
39 | public function isInstalled() { | ||
40 | $sql = "SELECT username FROM users"; | ||
41 | $query = $this->executeQuery($sql, array()); | ||
42 | $hasAdmin = count($query->fetchAll()); | ||
43 | |||
44 | if ($hasAdmin == 0) | ||
45 | return FALSE; | ||
46 | |||
47 | return TRUE; | ||
48 | } | ||
49 | |||
50 | public function install($login, $password) { | ||
51 | $sql = 'INSERT INTO users ( username, password, name, email) VALUES (?, ?, ?, ?)'; | ||
52 | $params = array($login, $password, $login, ' '); | ||
53 | $query = $this->executeQuery($sql, $params); | ||
54 | |||
55 | $sequence = ''; | ||
56 | if (STORAGE == 'postgres') { | ||
57 | $sequence = 'users_id_seq'; | ||
58 | } | ||
59 | |||
60 | $id_user = intval($this->getLastId($sequence)); | ||
61 | |||
62 | $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)'; | ||
63 | $params = array($id_user, 'pager', '10'); | ||
64 | $query = $this->executeQuery($sql, $params); | ||
65 | |||
66 | $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)'; | ||
67 | $params = array($id_user, 'language', 'en_EN.UTF8'); | ||
68 | $query = $this->executeQuery($sql, $params); | ||
69 | |||
70 | return TRUE; | ||
71 | } | ||
72 | |||
73 | private function getConfigUser($id) { | ||
74 | $sql = "SELECT * FROM users_config WHERE user_id = ?"; | ||
75 | $query = $this->executeQuery($sql, array($id)); | ||
76 | $result = $query->fetchAll(); | ||
77 | $user_config = array(); | ||
78 | |||
79 | foreach ($result as $key => $value) { | ||
80 | $user_config[$value['name']] = $value['value']; | ||
81 | } | ||
82 | |||
83 | return $user_config; | ||
84 | } | ||
85 | |||
86 | public function login($username, $password) { | ||
87 | $sql = "SELECT * FROM users WHERE username=? AND password=?"; | ||
88 | $query = $this->executeQuery($sql, array($username, $password)); | ||
89 | $login = $query->fetchAll(); | ||
90 | |||
91 | $user = array(); | ||
92 | if (isset($login[0])) { | ||
93 | $user['id'] = $login[0]['id']; | ||
94 | $user['username'] = $login[0]['username']; | ||
95 | $user['password'] = $login[0]['password']; | ||
96 | $user['name'] = $login[0]['name']; | ||
97 | $user['email'] = $login[0]['email']; | ||
98 | $user['config'] = $this->getConfigUser($login[0]['id']); | ||
99 | } | ||
100 | |||
101 | return $user; | ||
102 | } | ||
103 | |||
104 | public function updatePassword($id, $password) | ||
105 | { | ||
106 | $sql_update = "UPDATE users SET password=? WHERE id=?"; | ||
107 | $params_update = array($password, $id); | ||
108 | $query = $this->executeQuery($sql_update, $params_update); | ||
109 | } | ||
110 | |||
111 | private function executeQuery($sql, $params) { | ||
112 | try | ||
113 | { | ||
114 | $query = $this->getHandle()->prepare($sql); | ||
115 | $query->execute($params); | ||
116 | return $query; | ||
117 | } | ||
118 | catch (Exception $e) | ||
119 | { | ||
120 | Tools::logm('execute query error : '.$e->getMessage()); | ||
121 | return FALSE; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | public function retrieveAll($user_id) { | ||
126 | $sql = "SELECT * FROM entries WHERE user_id=? ORDER BY id"; | ||
127 | $query = $this->executeQuery($sql, array($user_id)); | ||
128 | $entries = $query->fetchAll(); | ||
129 | |||
130 | return $entries; | ||
131 | } | ||
132 | |||
133 | public function retrieveOneById($id, $user_id) { | ||
134 | $entry = NULL; | ||
135 | $sql = "SELECT * FROM entries WHERE id=? AND user_id=?"; | ||
136 | $params = array(intval($id), $user_id); | ||
137 | $query = $this->executeQuery($sql, $params); | ||
138 | $entry = $query->fetchAll(); | ||
139 | |||
140 | return $entry[0]; | ||
141 | } | ||
142 | |||
143 | public function getEntriesByView($view, $user_id, $limit = '') { | ||
144 | switch ($_SESSION['sort']) | ||
145 | { | ||
146 | case 'ia': | ||
147 | $order = 'ORDER BY id'; | ||
148 | break; | ||
149 | case 'id': | ||
150 | $order = 'ORDER BY id DESC'; | ||
151 | break; | ||
152 | case 'ta': | ||
153 | $order = 'ORDER BY lower(title)'; | ||
154 | break; | ||
155 | case 'td': | ||
156 | $order = 'ORDER BY lower(title) DESC'; | ||
157 | break; | ||
158 | default: | ||
159 | $order = 'ORDER BY id'; | ||
160 | break; | ||
161 | } | ||
162 | |||
163 | switch ($view) | ||
164 | { | ||
165 | case 'archive': | ||
166 | $sql = "SELECT * FROM entries WHERE user_id=? AND is_read=? " . $order; | ||
167 | $params = array($user_id, 1); | ||
168 | break; | ||
169 | case 'fav' : | ||
170 | $sql = "SELECT * FROM entries WHERE user_id=? AND is_fav=? " . $order; | ||
171 | $params = array($user_id, 1); | ||
172 | break; | ||
173 | default: | ||
174 | $sql = "SELECT * FROM entries WHERE user_id=? AND is_read=? " . $order; | ||
175 | $params = array($user_id, 0); | ||
176 | break; | ||
177 | } | ||
178 | |||
179 | $sql .= ' ' . $limit; | ||
180 | |||
181 | $query = $this->executeQuery($sql, $params); | ||
182 | $entries = $query->fetchAll(); | ||
183 | |||
184 | return $entries; | ||
185 | } | ||
186 | |||
187 | public function add($url, $title, $content, $user_id) { | ||
188 | $sql_action = 'INSERT INTO entries ( url, title, content, user_id ) VALUES (?, ?, ?, ?)'; | ||
189 | $params_action = array($url, $title, $content, $user_id); | ||
190 | $query = $this->executeQuery($sql_action, $params_action); | ||
191 | return $query; | ||
192 | } | ||
193 | |||
194 | public function deleteById($id, $user_id) { | ||
195 | $sql_action = "DELETE FROM entries WHERE id=? AND user_id=?"; | ||
196 | $params_action = array($id, $user_id); | ||
197 | $query = $this->executeQuery($sql_action, $params_action); | ||
198 | return $query; | ||
199 | } | ||
200 | |||
201 | public function favoriteById($id, $user_id) { | ||
202 | $sql_action = "UPDATE entries SET is_fav=NOT is_fav WHERE id=? AND user_id=?"; | ||
203 | $params_action = array($id, $user_id); | ||
204 | $query = $this->executeQuery($sql_action, $params_action); | ||
205 | } | ||
206 | |||
207 | public function archiveById($id, $user_id) { | ||
208 | $sql_action = "UPDATE entries SET is_read=NOT is_read WHERE id=? AND user_id=?"; | ||
209 | $params_action = array($id, $user_id); | ||
210 | $query = $this->executeQuery($sql_action, $params_action); | ||
211 | } | ||
212 | |||
213 | public function getLastId($column = '') { | ||
214 | return $this->getHandle()->lastInsertId($column); | ||
215 | } | ||
216 | } | ||
diff --git a/inc/poche/Poche.class.php b/inc/poche/Poche.class.php new file mode 100644 index 00000000..56910bc0 --- /dev/null +++ b/inc/poche/Poche.class.php | |||
@@ -0,0 +1,485 @@ | |||
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 Poche | ||
12 | { | ||
13 | public $user; | ||
14 | public $store; | ||
15 | public $tpl; | ||
16 | public $messages; | ||
17 | public $pagination; | ||
18 | |||
19 | function __construct() | ||
20 | { | ||
21 | $this->store = new Database(); | ||
22 | $this->init(); | ||
23 | $this->messages = new Messages(); | ||
24 | |||
25 | # installation | ||
26 | if(!$this->store->isInstalled()) | ||
27 | { | ||
28 | $this->install(); | ||
29 | } | ||
30 | } | ||
31 | |||
32 | private function init() | ||
33 | { | ||
34 | if (file_exists('./install') && !DEBUG_POCHE) { | ||
35 | Tools::logm('folder /install exists'); | ||
36 | die('the folder /install exists, you have to delete it before using poche.'); | ||
37 | } | ||
38 | |||
39 | Tools::initPhp(); | ||
40 | Session::init(); | ||
41 | |||
42 | if (isset($_SESSION['poche_user']) && $_SESSION['poche_user'] != array()) { | ||
43 | $this->user = $_SESSION['poche_user']; | ||
44 | } | ||
45 | else { | ||
46 | # fake user, just for install & login screens | ||
47 | $this->user = new User(); | ||
48 | $this->user->setConfig($this->getDefaultConfig()); | ||
49 | } | ||
50 | |||
51 | # l10n | ||
52 | $language = $this->user->getConfigValue('language'); | ||
53 | putenv('LC_ALL=' . $language); | ||
54 | setlocale(LC_ALL, $language); | ||
55 | bindtextdomain($language, LOCALE); | ||
56 | textdomain($language); | ||
57 | |||
58 | # template engine | ||
59 | $loader = new Twig_Loader_Filesystem(TPL); | ||
60 | if (DEBUG_POCHE) { | ||
61 | $twig_params = array(); | ||
62 | } | ||
63 | else { | ||
64 | $twig_params = array('cache' => CACHE); | ||
65 | } | ||
66 | $this->tpl = new Twig_Environment($loader, $twig_params); | ||
67 | $this->tpl->addExtension(new Twig_Extensions_Extension_I18n()); | ||
68 | # filter to display domain name of an url | ||
69 | $filter = new Twig_SimpleFilter('getDomain', 'Tools::getDomain'); | ||
70 | $this->tpl->addFilter($filter); | ||
71 | |||
72 | # Pagination | ||
73 | $this->pagination = new Paginator($this->user->getConfigValue('pager'), 'p'); | ||
74 | } | ||
75 | |||
76 | private function install() | ||
77 | { | ||
78 | Tools::logm('poche still not installed'); | ||
79 | echo $this->tpl->render('install.twig', array( | ||
80 | 'token' => Session::getToken() | ||
81 | )); | ||
82 | if (isset($_GET['install'])) { | ||
83 | if (($_POST['password'] == $_POST['password_repeat']) | ||
84 | && $_POST['password'] != "" && $_POST['login'] != "") { | ||
85 | # let's rock, install poche baby ! | ||
86 | $this->store->install($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login'])); | ||
87 | Session::logout(); | ||
88 | Tools::logm('poche is now installed'); | ||
89 | Tools::redirect(); | ||
90 | } | ||
91 | else { | ||
92 | Tools::logm('error during installation'); | ||
93 | Tools::redirect(); | ||
94 | } | ||
95 | } | ||
96 | exit(); | ||
97 | } | ||
98 | |||
99 | public function getDefaultConfig() | ||
100 | { | ||
101 | return array( | ||
102 | 'pager' => PAGINATION, | ||
103 | 'language' => LANG, | ||
104 | ); | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * Call action (mark as fav, archive, delete, etc.) | ||
109 | */ | ||
110 | public function action($action, Url $url, $id = 0, $import = FALSE) | ||
111 | { | ||
112 | switch ($action) | ||
113 | { | ||
114 | case 'add': | ||
115 | if($parametres_url = $url->fetchContent()) { | ||
116 | if ($this->store->add($url->getUrl(), $parametres_url['title'], $parametres_url['content'], $this->user->getId())) { | ||
117 | Tools::logm('add link ' . $url->getUrl()); | ||
118 | $sequence = ''; | ||
119 | if (STORAGE == 'postgres') { | ||
120 | $sequence = 'entries_id_seq'; | ||
121 | } | ||
122 | $last_id = $this->store->getLastId($sequence); | ||
123 | if (DOWNLOAD_PICTURES) { | ||
124 | $content = filtre_picture($parametres_url['content'], $url->getUrl(), $last_id); | ||
125 | } | ||
126 | if (!$import) { | ||
127 | $this->messages->add('s', _('the link has been added successfully')); | ||
128 | } | ||
129 | } | ||
130 | else { | ||
131 | if (!$import) { | ||
132 | $this->messages->add('e', _('error during insertion : the link wasn\'t added')); | ||
133 | Tools::logm('error during insertion : the link wasn\'t added ' . $url->getUrl()); | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | else { | ||
138 | if (!$import) { | ||
139 | $this->messages->add('e', _('error during fetching content : the link wasn\'t added')); | ||
140 | Tools::logm('error during content fetch ' . $url->getUrl()); | ||
141 | } | ||
142 | } | ||
143 | if (!$import) { | ||
144 | Tools::redirect(); | ||
145 | } | ||
146 | break; | ||
147 | case 'delete': | ||
148 | $msg = 'delete link #' . $id; | ||
149 | if ($this->store->deleteById($id, $this->user->getId())) { | ||
150 | if (DOWNLOAD_PICTURES) { | ||
151 | remove_directory(ABS_PATH . $id); | ||
152 | } | ||
153 | $this->messages->add('s', _('the link has been deleted successfully')); | ||
154 | } | ||
155 | else { | ||
156 | $this->messages->add('e', _('the link wasn\'t deleted')); | ||
157 | $msg = 'error : can\'t delete link #' . $id; | ||
158 | } | ||
159 | Tools::logm($msg); | ||
160 | Tools::redirect('?'); | ||
161 | break; | ||
162 | case 'toggle_fav' : | ||
163 | $this->store->favoriteById($id, $this->user->getId()); | ||
164 | Tools::logm('mark as favorite link #' . $id); | ||
165 | if (!$import) { | ||
166 | Tools::redirect(); | ||
167 | } | ||
168 | break; | ||
169 | case 'toggle_archive' : | ||
170 | $this->store->archiveById($id, $this->user->getId()); | ||
171 | Tools::logm('archive link #' . $id); | ||
172 | if (!$import) { | ||
173 | Tools::redirect(); | ||
174 | } | ||
175 | break; | ||
176 | default: | ||
177 | break; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | function displayView($view, $id = 0) | ||
182 | { | ||
183 | $tpl_vars = array(); | ||
184 | |||
185 | switch ($view) | ||
186 | { | ||
187 | case 'config': | ||
188 | $dev = $this->getPocheVersion('dev'); | ||
189 | $prod = $this->getPocheVersion('prod'); | ||
190 | $compare_dev = version_compare(POCHE_VERSION, $dev); | ||
191 | $compare_prod = version_compare(POCHE_VERSION, $prod); | ||
192 | $tpl_vars = array( | ||
193 | 'dev' => $dev, | ||
194 | 'prod' => $prod, | ||
195 | 'compare_dev' => $compare_dev, | ||
196 | 'compare_prod' => $compare_prod, | ||
197 | ); | ||
198 | Tools::logm('config view'); | ||
199 | break; | ||
200 | case 'view': | ||
201 | $entry = $this->store->retrieveOneById($id, $this->user->getId()); | ||
202 | if ($entry != NULL) { | ||
203 | Tools::logm('view link #' . $id); | ||
204 | $content = $entry['content']; | ||
205 | if (function_exists('tidy_parse_string')) { | ||
206 | $tidy = tidy_parse_string($content, array('indent'=>true, 'show-body-only' => true), 'UTF8'); | ||
207 | $tidy->cleanRepair(); | ||
208 | $content = $tidy->value; | ||
209 | } | ||
210 | $tpl_vars = array( | ||
211 | 'entry' => $entry, | ||
212 | 'content' => $content, | ||
213 | ); | ||
214 | } | ||
215 | else { | ||
216 | Tools::logm('error in view call : entry is NULL'); | ||
217 | } | ||
218 | break; | ||
219 | default: # home view | ||
220 | $entries = $this->store->getEntriesByView($view, $this->user->getId()); | ||
221 | $this->pagination->set_total(count($entries)); | ||
222 | $page_links = $this->pagination->page_links('?view=' . $view . '&sort=' . $_SESSION['sort'] . '&'); | ||
223 | $datas = $this->store->getEntriesByView($view, $this->user->getId(), $this->pagination->get_limit()); | ||
224 | $tpl_vars = array( | ||
225 | 'entries' => $datas, | ||
226 | 'page_links' => $page_links, | ||
227 | ); | ||
228 | Tools::logm('display ' . $view . ' view'); | ||
229 | break; | ||
230 | } | ||
231 | |||
232 | return $tpl_vars; | ||
233 | } | ||
234 | |||
235 | /** | ||
236 | * update the password of the current user. | ||
237 | * if MODE_DEMO is TRUE, the password can't be updated. | ||
238 | * @todo add the return value | ||
239 | * @todo set the new password in function header like this updatePassword($newPassword) | ||
240 | * @return boolean | ||
241 | */ | ||
242 | public function updatePassword() | ||
243 | { | ||
244 | if (MODE_DEMO) { | ||
245 | $this->messages->add('i', _('in demo mode, you can\'t update your password')); | ||
246 | Tools::logm('in demo mode, you can\'t do this'); | ||
247 | Tools::redirect('?view=config'); | ||
248 | } | ||
249 | else { | ||
250 | if (isset($_POST['password']) && isset($_POST['password_repeat'])) { | ||
251 | if ($_POST['password'] == $_POST['password_repeat'] && $_POST['password'] != "") { | ||
252 | $this->messages->add('s', _('your password has been updated')); | ||
253 | $this->store->updatePassword($this->user->getId(), Tools::encodeString($_POST['password'] . $this->user->getUsername())); | ||
254 | Session::logout(); | ||
255 | Tools::logm('password updated'); | ||
256 | Tools::redirect(); | ||
257 | } | ||
258 | else { | ||
259 | $this->messages->add('e', _('the two fields have to be filled & the password must be the same in the two fields')); | ||
260 | Tools::redirect('?view=config'); | ||
261 | } | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * checks if login & password are correct and save the user in session. | ||
268 | * it redirects the user to the $referer link | ||
269 | * @param string $referer the url to redirect after login | ||
270 | * @todo add the return value | ||
271 | * @return boolean | ||
272 | */ | ||
273 | public function login($referer) | ||
274 | { | ||
275 | if (!empty($_POST['login']) && !empty($_POST['password'])) { | ||
276 | $user = $this->store->login($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login'])); | ||
277 | if ($user != array()) { | ||
278 | # Save login into Session | ||
279 | Session::login($user['username'], $user['password'], $_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login']), array('poche_user' => new User($user))); | ||
280 | |||
281 | $this->messages->add('s', _('welcome to your poche')); | ||
282 | if (!empty($_POST['longlastingsession'])) { | ||
283 | $_SESSION['longlastingsession'] = 31536000; | ||
284 | $_SESSION['expires_on'] = time() + $_SESSION['longlastingsession']; | ||
285 | session_set_cookie_params($_SESSION['longlastingsession']); | ||
286 | } else { | ||
287 | session_set_cookie_params(0); | ||
288 | } | ||
289 | session_regenerate_id(true); | ||
290 | Tools::logm('login successful'); | ||
291 | Tools::redirect($referer); | ||
292 | } | ||
293 | $this->messages->add('e', _('login failed: bad login or password')); | ||
294 | Tools::logm('login failed'); | ||
295 | Tools::redirect(); | ||
296 | } else { | ||
297 | $this->messages->add('e', _('login failed: you have to fill all fields')); | ||
298 | Tools::logm('login failed'); | ||
299 | Tools::redirect(); | ||
300 | } | ||
301 | } | ||
302 | |||
303 | /** | ||
304 | * log out the poche user. It cleans the session. | ||
305 | * @todo add the return value | ||
306 | * @return boolean | ||
307 | */ | ||
308 | public function logout() | ||
309 | { | ||
310 | $this->user = array(); | ||
311 | Session::logout(); | ||
312 | $this->messages->add('s', _('see you soon!')); | ||
313 | Tools::logm('logout'); | ||
314 | Tools::redirect(); | ||
315 | } | ||
316 | |||
317 | /** | ||
318 | * import from Instapaper. poche needs a ./instapaper-export.html file | ||
319 | * @todo add the return value | ||
320 | * @return boolean | ||
321 | */ | ||
322 | private function importFromInstapaper() | ||
323 | { | ||
324 | # TODO gestion des articles favs | ||
325 | $html = new simple_html_dom(); | ||
326 | $html->load_file('./instapaper-export.html'); | ||
327 | Tools::logm('starting import from instapaper'); | ||
328 | |||
329 | $read = 0; | ||
330 | $errors = array(); | ||
331 | foreach($html->find('ol') as $ul) | ||
332 | { | ||
333 | foreach($ul->find('li') as $li) | ||
334 | { | ||
335 | $a = $li->find('a'); | ||
336 | $url = new Url(base64_encode($a[0]->href)); | ||
337 | $this->action('add', $url, 0, TRUE); | ||
338 | if ($read == '1') { | ||
339 | $sequence = ''; | ||
340 | if (STORAGE == 'postgres') { | ||
341 | $sequence = 'entries_id_seq'; | ||
342 | } | ||
343 | $last_id = $this->store->getLastId($sequence); | ||
344 | $this->action('toggle_archive', $url, $last_id, TRUE); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | # the second <ol> is for read links | ||
349 | $read = 1; | ||
350 | } | ||
351 | $this->messages->add('s', _('import from instapaper completed')); | ||
352 | Tools::logm('import from instapaper completed'); | ||
353 | Tools::redirect(); | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * import from Pocket. poche needs a ./ril_export.html file | ||
358 | * @todo add the return value | ||
359 | * @return boolean | ||
360 | */ | ||
361 | private function importFromPocket() | ||
362 | { | ||
363 | # TODO gestion des articles favs | ||
364 | $html = new simple_html_dom(); | ||
365 | $html->load_file('./ril_export.html'); | ||
366 | Tools::logm('starting import from pocket'); | ||
367 | |||
368 | $read = 0; | ||
369 | $errors = array(); | ||
370 | foreach($html->find('ul') as $ul) | ||
371 | { | ||
372 | foreach($ul->find('li') as $li) | ||
373 | { | ||
374 | $a = $li->find('a'); | ||
375 | $url = new Url(base64_encode($a[0]->href)); | ||
376 | $this->action('add', $url, 0, TRUE); | ||
377 | if ($read == '1') { | ||
378 | $sequence = ''; | ||
379 | if (STORAGE == 'postgres') { | ||
380 | $sequence = 'entries_id_seq'; | ||
381 | } | ||
382 | $last_id = $this->store->getLastId($sequence); | ||
383 | $this->action('toggle_archive', $url, $last_id, TRUE); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | # the second <ul> is for read links | ||
388 | $read = 1; | ||
389 | } | ||
390 | $this->messages->add('s', _('import from pocket completed')); | ||
391 | Tools::logm('import from pocket completed'); | ||
392 | Tools::redirect(); | ||
393 | } | ||
394 | |||
395 | /** | ||
396 | * import from Readability. poche needs a ./readability file | ||
397 | * @todo add the return value | ||
398 | * @return boolean | ||
399 | */ | ||
400 | private function importFromReadability() | ||
401 | { | ||
402 | # TODO gestion des articles lus / favs | ||
403 | $str_data = file_get_contents("./readability"); | ||
404 | $data = json_decode($str_data,true); | ||
405 | Tools::logm('starting import from Readability'); | ||
406 | |||
407 | foreach ($data as $key => $value) { | ||
408 | $url = ''; | ||
409 | foreach ($value as $attr => $attr_value) { | ||
410 | if ($attr == 'article__url') { | ||
411 | $url = new Url(base64_encode($attr_value)); | ||
412 | } | ||
413 | $sequence = ''; | ||
414 | if (STORAGE == 'postgres') { | ||
415 | $sequence = 'entries_id_seq'; | ||
416 | } | ||
417 | // if ($attr_value == 'favorite' && $attr_value == 'true') { | ||
418 | // $last_id = $this->store->getLastId($sequence); | ||
419 | // $this->store->favoriteById($last_id); | ||
420 | // $this->action('toogle_fav', $url, $last_id, TRUE); | ||
421 | // } | ||
422 | if ($attr_value == 'archive' && $attr_value == 'true') { | ||
423 | $last_id = $this->store->getLastId($sequence); | ||
424 | $this->action('toggle_archive', $url, $last_id, TRUE); | ||
425 | } | ||
426 | } | ||
427 | if ($url->isCorrect()) | ||
428 | $this->action('add', $url, 0, TRUE); | ||
429 | } | ||
430 | $this->messages->add('s', _('import from Readability completed')); | ||
431 | Tools::logm('import from Readability completed'); | ||
432 | Tools::redirect(); | ||
433 | } | ||
434 | |||
435 | /** | ||
436 | * import datas into your poche | ||
437 | * @param string $from name of the service to import : pocket, instapaper or readability | ||
438 | * @todo add the return value | ||
439 | * @return boolean | ||
440 | */ | ||
441 | public function import($from) | ||
442 | { | ||
443 | if ($from == 'pocket') { | ||
444 | return $this->importFromPocket(); | ||
445 | } | ||
446 | else if ($from == 'readability') { | ||
447 | return $this->importFromReadability(); | ||
448 | } | ||
449 | else if ($from == 'instapaper') { | ||
450 | return $this->importFromInstapaper(); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | /** | ||
455 | * export poche entries in json | ||
456 | * @return json all poche entries | ||
457 | */ | ||
458 | public function export() | ||
459 | { | ||
460 | $entries = $this->store->retrieveAll($this->user->getId()); | ||
461 | echo $this->tpl->render('export.twig', array( | ||
462 | 'export' => Tools::renderJson($entries), | ||
463 | )); | ||
464 | Tools::logm('export view'); | ||
465 | } | ||
466 | |||
467 | /** | ||
468 | * Checks online the latest version of poche and cache it | ||
469 | * @param string $which 'prod' or 'dev' | ||
470 | * @return string latest $which version | ||
471 | */ | ||
472 | private function getPocheVersion($which = 'prod') | ||
473 | { | ||
474 | $cache_file = CACHE . '/' . $which; | ||
475 | |||
476 | # checks if the cached version file exists | ||
477 | if (file_exists($cache_file) && (filemtime($cache_file) > (time() - 86400 ))) { | ||
478 | $version = file_get_contents($cache_file); | ||
479 | } else { | ||
480 | $version = file_get_contents('http://static.inthepoche.com/versions/' . $which); | ||
481 | file_put_contents($cache_file, $version, LOCK_EX); | ||
482 | } | ||
483 | return $version; | ||
484 | } | ||
485 | } \ No newline at end of file | ||
diff --git a/inc/poche/Tools.class.php b/inc/poche/Tools.class.php new file mode 100644 index 00000000..d0e43166 --- /dev/null +++ b/inc/poche/Tools.class.php | |||
@@ -0,0 +1,226 @@ | |||
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 Tools | ||
12 | { | ||
13 | public static function initPhp() | ||
14 | { | ||
15 | define('START_TIME', microtime(true)); | ||
16 | |||
17 | if (phpversion() < 5) { | ||
18 | die(_('Oops, it seems you don\'t have PHP 5.')); | ||
19 | } | ||
20 | |||
21 | error_reporting(E_ALL); | ||
22 | |||
23 | function stripslashesDeep($value) { | ||
24 | return is_array($value) | ||
25 | ? array_map('stripslashesDeep', $value) | ||
26 | : stripslashes($value); | ||
27 | } | ||
28 | |||
29 | if (get_magic_quotes_gpc()) { | ||
30 | $_POST = array_map('stripslashesDeep', $_POST); | ||
31 | $_GET = array_map('stripslashesDeep', $_GET); | ||
32 | $_COOKIE = array_map('stripslashesDeep', $_COOKIE); | ||
33 | } | ||
34 | |||
35 | ob_start(); | ||
36 | register_shutdown_function('ob_end_flush'); | ||
37 | } | ||
38 | |||
39 | public static function getPocheUrl() | ||
40 | { | ||
41 | $https = (!empty($_SERVER['HTTPS']) | ||
42 | && (strtolower($_SERVER['HTTPS']) == 'on')) | ||
43 | || (isset($_SERVER["SERVER_PORT"]) | ||
44 | && $_SERVER["SERVER_PORT"] == '443'); // HTTPS detection. | ||
45 | $serverport = (!isset($_SERVER["SERVER_PORT"]) | ||
46 | || $_SERVER["SERVER_PORT"] == '80' | ||
47 | || ($https && $_SERVER["SERVER_PORT"] == '443') | ||
48 | ? '' : ':' . $_SERVER["SERVER_PORT"]); | ||
49 | |||
50 | $scriptname = str_replace('/index.php', '/', $_SERVER["SCRIPT_NAME"]); | ||
51 | |||
52 | if (!isset($_SERVER["SERVER_NAME"])) { | ||
53 | return $scriptname; | ||
54 | } | ||
55 | |||
56 | return 'http' . ($https ? 's' : '') . '://' | ||
57 | . $_SERVER["SERVER_NAME"] . $serverport . $scriptname; | ||
58 | } | ||
59 | |||
60 | public static function redirect($url = '') | ||
61 | { | ||
62 | if ($url === '') { | ||
63 | $url = (empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']); | ||
64 | if (isset($_POST['returnurl'])) { | ||
65 | $url = $_POST['returnurl']; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | # prevent loop | ||
70 | if (empty($url) || parse_url($url, PHP_URL_QUERY) === $_SERVER['QUERY_STRING']) { | ||
71 | $url = Tools::getPocheUrl(); | ||
72 | } | ||
73 | |||
74 | if (substr($url, 0, 1) !== '?') { | ||
75 | $ref = Tools::getPocheUrl(); | ||
76 | if (substr($url, 0, strlen($ref)) !== $ref) { | ||
77 | $url = $ref; | ||
78 | } | ||
79 | } | ||
80 | self::logm('redirect to ' . $url); | ||
81 | header('Location: '.$url); | ||
82 | exit(); | ||
83 | } | ||
84 | |||
85 | public static function getTplFile($view) | ||
86 | { | ||
87 | $tpl_file = 'home.twig'; | ||
88 | switch ($view) | ||
89 | { | ||
90 | case 'install': | ||
91 | $tpl_file = 'install.twig'; | ||
92 | break; | ||
93 | case 'import'; | ||
94 | $tpl_file = 'import.twig'; | ||
95 | break; | ||
96 | case 'export': | ||
97 | $tpl_file = 'export.twig'; | ||
98 | break; | ||
99 | case 'config': | ||
100 | $tpl_file = 'config.twig'; | ||
101 | break; | ||
102 | case 'view': | ||
103 | $tpl_file = 'view.twig'; | ||
104 | break; | ||
105 | default: | ||
106 | break; | ||
107 | } | ||
108 | return $tpl_file; | ||
109 | } | ||
110 | |||
111 | public static function getFile($url) | ||
112 | { | ||
113 | $timeout = 15; | ||
114 | $useragent = "Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0"; | ||
115 | |||
116 | if (in_array ('curl', get_loaded_extensions())) { | ||
117 | # Fetch feed from URL | ||
118 | $curl = curl_init(); | ||
119 | curl_setopt($curl, CURLOPT_URL, $url); | ||
120 | curl_setopt($curl, CURLOPT_TIMEOUT, $timeout); | ||
121 | curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); | ||
122 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); | ||
123 | curl_setopt($curl, CURLOPT_HEADER, false); | ||
124 | |||
125 | # for ssl, do not verified certificate | ||
126 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); | ||
127 | curl_setopt($curl, CURLOPT_AUTOREFERER, TRUE ); | ||
128 | |||
129 | # FeedBurner requires a proper USER-AGENT... | ||
130 | curl_setopt($curl, CURL_HTTP_VERSION_1_1, true); | ||
131 | curl_setopt($curl, CURLOPT_ENCODING, "gzip, deflate"); | ||
132 | curl_setopt($curl, CURLOPT_USERAGENT, $useragent); | ||
133 | |||
134 | $data = curl_exec($curl); | ||
135 | $httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE); | ||
136 | $httpcodeOK = isset($httpcode) and ($httpcode == 200 or $httpcode == 301); | ||
137 | curl_close($curl); | ||
138 | } else { | ||
139 | # create http context and add timeout and user-agent | ||
140 | $context = stream_context_create( | ||
141 | array( | ||
142 | 'http' => array( | ||
143 | 'timeout' => $timeout, | ||
144 | 'header' => "User-Agent: " . $useragent, | ||
145 | 'follow_location' => true | ||
146 | ), | ||
147 | 'ssl' => array( | ||
148 | 'verify_peer' => false, | ||
149 | 'allow_self_signed' => true | ||
150 | ) | ||
151 | ) | ||
152 | ); | ||
153 | |||
154 | # only download page lesser than 4MB | ||
155 | $data = @file_get_contents($url, false, $context, -1, 4000000); | ||
156 | |||
157 | if (isset($http_response_header) and isset($http_response_header[0])) { | ||
158 | $httpcodeOK = isset($http_response_header) and isset($http_response_header[0]) and ((strpos($http_response_header[0], '200 OK') !== FALSE) or (strpos($http_response_header[0], '301 Moved Permanently') !== FALSE)); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | # if response is not empty and response is OK | ||
163 | if (isset($data) and isset($httpcodeOK) and $httpcodeOK) { | ||
164 | |||
165 | # take charset of page and get it | ||
166 | preg_match('#<meta .*charset=.*>#Usi', $data, $meta); | ||
167 | |||
168 | # if meta tag is found | ||
169 | if (!empty($meta[0])) { | ||
170 | preg_match('#charset="?(.*)"#si', $meta[0], $encoding); | ||
171 | # if charset is found set it otherwise, set it to utf-8 | ||
172 | $html_charset = (!empty($encoding[1])) ? strtolower($encoding[1]) : 'utf-8'; | ||
173 | } else { | ||
174 | $html_charset = 'utf-8'; | ||
175 | $encoding[1] = ''; | ||
176 | } | ||
177 | |||
178 | # replace charset of url to charset of page | ||
179 | $data = str_replace('charset=' . $encoding[1], 'charset=' . $html_charset, $data); | ||
180 | |||
181 | return $data; | ||
182 | } | ||
183 | else { | ||
184 | return FALSE; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | public static function renderJson($data) | ||
189 | { | ||
190 | header('Cache-Control: no-cache, must-revalidate'); | ||
191 | header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); | ||
192 | header('Content-type: application/json; charset=UTF-8'); | ||
193 | echo json_encode($data); | ||
194 | exit(); | ||
195 | } | ||
196 | |||
197 | public static function logm($message) | ||
198 | { | ||
199 | if (DEBUG_POCHE) { | ||
200 | $t = strval(date('Y/m/d_H:i:s')) . ' - ' . $_SERVER["REMOTE_ADDR"] . ' - ' . strval($message) . "\n"; | ||
201 | file_put_contents(CACHE . '/log.txt', $t, FILE_APPEND); | ||
202 | error_log('DEBUG POCHE : ' . $message); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | public static function encodeString($string) | ||
207 | { | ||
208 | return sha1($string . SALT); | ||
209 | } | ||
210 | |||
211 | public static function checkVar($var, $default = '') | ||
212 | { | ||
213 | return ((isset ($_REQUEST["$var"])) ? htmlentities($_REQUEST["$var"]) : $default); | ||
214 | } | ||
215 | |||
216 | public static function getDomain($url) | ||
217 | { | ||
218 | $pieces = parse_url($url); | ||
219 | $domain = isset($pieces['host']) ? $pieces['host'] : ''; | ||
220 | if (preg_match('/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i', $domain, $regs)) { | ||
221 | return $regs['domain']; | ||
222 | } | ||
223 | |||
224 | return FALSE; | ||
225 | } | ||
226 | } \ No newline at end of file | ||
diff --git a/inc/poche/Url.class.php b/inc/poche/Url.class.php new file mode 100644 index 00000000..f4a8f99e --- /dev/null +++ b/inc/poche/Url.class.php | |||
@@ -0,0 +1,94 @@ | |||
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 Url | ||
12 | { | ||
13 | public $url; | ||
14 | |||
15 | function __construct($url) | ||
16 | { | ||
17 | $this->url = base64_decode($url); | ||
18 | } | ||
19 | |||
20 | public function getUrl() { | ||
21 | return $this->url; | ||
22 | } | ||
23 | |||
24 | public function setUrl($url) { | ||
25 | $this->url = $url; | ||
26 | } | ||
27 | |||
28 | public function isCorrect() | ||
29 | { | ||
30 | $pattern = '|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i'; | ||
31 | |||
32 | return preg_match($pattern, $this->url); | ||
33 | } | ||
34 | |||
35 | public function clean() | ||
36 | { | ||
37 | $url = html_entity_decode(trim($this->url)); | ||
38 | |||
39 | $stuff = strpos($url,'&utm_source='); | ||
40 | if ($stuff !== FALSE) | ||
41 | $url = substr($url, 0, $stuff); | ||
42 | $stuff = strpos($url,'?utm_source='); | ||
43 | if ($stuff !== FALSE) | ||
44 | $url = substr($url, 0, $stuff); | ||
45 | $stuff = strpos($url,'#xtor=RSS-'); | ||
46 | if ($stuff !== FALSE) | ||
47 | $url = substr($url, 0, $stuff); | ||
48 | |||
49 | $this->url = $url; | ||
50 | } | ||
51 | |||
52 | public function fetchContent() | ||
53 | { | ||
54 | if ($this->isCorrect()) { | ||
55 | $this->clean(); | ||
56 | $html = Encoding::toUTF8(Tools::getFile($this->getUrl())); | ||
57 | |||
58 | # if Tools::getFile() if not able to retrieve HTTPS content, try the same URL with HTTP protocol | ||
59 | if (!preg_match('!^https?://!i', $this->getUrl()) && (!isset($html) || strlen($html) <= 0)) { | ||
60 | $this->setUrl('http://' . $this->getUrl()); | ||
61 | $html = Encoding::toUTF8(Tools::getFile($this->getUrl())); | ||
62 | } | ||
63 | |||
64 | if (function_exists('tidy_parse_string')) { | ||
65 | $tidy = tidy_parse_string($html, array(), 'UTF8'); | ||
66 | $tidy->cleanRepair(); | ||
67 | $html = $tidy->value; | ||
68 | } | ||
69 | |||
70 | $parameters = array(); | ||
71 | if (isset($html) and strlen($html) > 0) | ||
72 | { | ||
73 | $readability = new Readability($html, $this->getUrl()); | ||
74 | $readability->convertLinksToFootnotes = CONVERT_LINKS_FOOTNOTES; | ||
75 | $readability->revertForcedParagraphElements = REVERT_FORCED_PARAGRAPH_ELEMENTS; | ||
76 | |||
77 | if($readability->init()) | ||
78 | { | ||
79 | $content = $readability->articleContent->innerHTML; | ||
80 | $parameters['title'] = $readability->articleTitle->innerHTML; | ||
81 | $parameters['content'] = $content; | ||
82 | |||
83 | return $parameters; | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | else { | ||
88 | #$msg->add('e', _('error during url preparation : the link is not valid')); | ||
89 | Tools::logm($this->getUrl() . ' is not a valid url'); | ||
90 | } | ||
91 | |||
92 | return FALSE; | ||
93 | } | ||
94 | } \ No newline at end of file | ||
diff --git a/inc/poche/User.class.php b/inc/poche/User.class.php new file mode 100644 index 00000000..6dac7839 --- /dev/null +++ b/inc/poche/User.class.php | |||
@@ -0,0 +1,50 @@ | |||
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 User | ||
12 | { | ||
13 | public $id; | ||
14 | public $username; | ||
15 | public $name; | ||
16 | public $password; | ||
17 | public $email; | ||
18 | public $config; | ||
19 | |||
20 | function __construct($user = array()) | ||
21 | { | ||
22 | if ($user != array()) { | ||
23 | $this->id = $user['id']; | ||
24 | $this->username = $user['username']; | ||
25 | $this->name = $user['name']; | ||
26 | $this->password = $user['password']; | ||
27 | $this->email = $user['email']; | ||
28 | $this->config = $user['config']; | ||
29 | } | ||
30 | } | ||
31 | |||
32 | public function getId() | ||
33 | { | ||
34 | return $this->id; | ||
35 | } | ||
36 | |||
37 | public function getUsername() | ||
38 | { | ||
39 | return $this->username; | ||
40 | } | ||
41 | |||
42 | public function setConfig($config) | ||
43 | { | ||
44 | $this->config = $config; | ||
45 | } | ||
46 | |||
47 | public function getConfigValue($name) { | ||
48 | return (isset($this->config[$name])) ? $this->config[$name] : FALSE; | ||
49 | } | ||
50 | } \ No newline at end of file | ||
diff --git a/inc/poche/config.inc.php b/inc/poche/config.inc.php new file mode 100644 index 00000000..0958600f --- /dev/null +++ b/inc/poche/config.inc.php | |||
@@ -0,0 +1,61 @@ | |||
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 | # storage | ||
12 | define ('STORAGE','sqlite'); # postgres, mysql, sqlite | ||
13 | define ('STORAGE_SERVER', 'localhost'); # leave blank for sqlite | ||
14 | define ('STORAGE_DB', 'poche'); # only for postgres & mysql | ||
15 | define ('STORAGE_SQLITE', './db/poche.sqlite'); | ||
16 | define ('STORAGE_USER', 'postgres'); # leave blank for sqlite | ||
17 | define ('STORAGE_PASSWORD', 'postgres'); # leave blank for sqlite | ||
18 | |||
19 | define ('POCHE_VERSION', '1.0-beta1'); | ||
20 | define ('MODE_DEMO', FALSE); | ||
21 | define ('DEBUG_POCHE', TRUE); | ||
22 | define ('CONVERT_LINKS_FOOTNOTES', FALSE); | ||
23 | define ('REVERT_FORCED_PARAGRAPH_ELEMENTS', FALSE); | ||
24 | define ('DOWNLOAD_PICTURES', FALSE); | ||
25 | define ('SHARE_TWITTER', TRUE); | ||
26 | define ('SHARE_MAIL', TRUE); | ||
27 | define ('SALT', '464v54gLLw928uz4zUBqkRJeiPY68zCX'); | ||
28 | define ('ABS_PATH', 'assets/'); | ||
29 | define ('TPL', './tpl'); | ||
30 | define ('LOCALE', './locale'); | ||
31 | define ('CACHE', './cache'); | ||
32 | define ('LANG', 'en_EN.UTF8'); | ||
33 | define ('PAGINATION', '10'); | ||
34 | define ('THEME', 'light'); | ||
35 | |||
36 | # /!\ Be careful if you change the lines below /!\ | ||
37 | require_once './inc/poche/User.class.php'; | ||
38 | require_once './inc/poche/Tools.class.php'; | ||
39 | require_once './inc/poche/Url.class.php'; | ||
40 | require_once './inc/3rdparty/class.messages.php'; | ||
41 | require_once './inc/poche/Poche.class.php'; | ||
42 | require_once './inc/3rdparty/Readability.php'; | ||
43 | require_once './inc/3rdparty/Encoding.php'; | ||
44 | require_once './inc/poche/Database.class.php'; | ||
45 | require_once './vendor/autoload.php'; | ||
46 | require_once './inc/3rdparty/simple_html_dom.php'; | ||
47 | require_once './inc/3rdparty/paginator.php'; | ||
48 | require_once './inc/3rdparty/Session.class.php'; | ||
49 | |||
50 | if (DOWNLOAD_PICTURES) { | ||
51 | require_once './inc/poche/pochePictures.php'; | ||
52 | } | ||
53 | |||
54 | $poche = new Poche(); | ||
55 | #XSRF protection with token | ||
56 | // if (!empty($_POST)) { | ||
57 | // if (!Session::isToken($_POST['token'])) { | ||
58 | // die(_('Wrong token')); | ||
59 | // } | ||
60 | // unset($_SESSION['tokens']); | ||
61 | // } \ No newline at end of file | ||
diff --git a/inc/poche/pochePictures.php b/inc/poche/pochePictures.php new file mode 100644 index 00000000..4e4a0b08 --- /dev/null +++ b/inc/poche/pochePictures.php | |||
@@ -0,0 +1,110 @@ | |||
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 | /** | ||
12 | * On modifie les URLS des images dans le corps de l'article | ||
13 | */ | ||
14 | function filtre_picture($content, $url, $id) | ||
15 | { | ||
16 | $matches = array(); | ||
17 | preg_match_all('#<\s*(img)[^>]+src="([^"]*)"[^>]*>#Si', $content, $matches, PREG_SET_ORDER); | ||
18 | foreach($matches as $i => $link) { | ||
19 | $link[1] = trim($link[1]); | ||
20 | if (!preg_match('#^(([a-z]+://)|(\#))#', $link[1])) { | ||
21 | $absolute_path = get_absolute_link($link[2],$url); | ||
22 | $filename = basename(parse_url($absolute_path, PHP_URL_PATH)); | ||
23 | $directory = create_assets_directory($id); | ||
24 | $fullpath = $directory . '/' . $filename; | ||
25 | download_pictures($absolute_path, $fullpath); | ||
26 | $content = str_replace($matches[$i][2], $fullpath, $content); | ||
27 | } | ||
28 | |||
29 | } | ||
30 | |||
31 | return $content; | ||
32 | } | ||
33 | |||
34 | /** | ||
35 | * Retourne le lien absolu | ||
36 | */ | ||
37 | function get_absolute_link($relative_link, $url) { | ||
38 | /* return if already absolute URL */ | ||
39 | if (parse_url($relative_link, PHP_URL_SCHEME) != '') return $relative_link; | ||
40 | |||
41 | /* queries and anchors */ | ||
42 | if ($relative_link[0]=='#' || $relative_link[0]=='?') return $url . $relative_link; | ||
43 | |||
44 | /* parse base URL and convert to local variables: | ||
45 | $scheme, $host, $path */ | ||
46 | extract(parse_url($url)); | ||
47 | |||
48 | /* remove non-directory element from path */ | ||
49 | $path = preg_replace('#/[^/]*$#', '', $path); | ||
50 | |||
51 | /* destroy path if relative url points to root */ | ||
52 | if ($relative_link[0] == '/') $path = ''; | ||
53 | |||
54 | /* dirty absolute URL */ | ||
55 | $abs = $host . $path . '/' . $relative_link; | ||
56 | |||
57 | /* replace '//' or '/./' or '/foo/../' with '/' */ | ||
58 | $re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#'); | ||
59 | for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {} | ||
60 | |||
61 | /* absolute URL is ready! */ | ||
62 | return $scheme.'://'.$abs; | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * Téléchargement des images | ||
67 | */ | ||
68 | function download_pictures($absolute_path, $fullpath) | ||
69 | { | ||
70 | $rawdata = Tools::getFile($absolute_path); | ||
71 | |||
72 | if(file_exists($fullpath)) { | ||
73 | unlink($fullpath); | ||
74 | } | ||
75 | $fp = fopen($fullpath, 'x'); | ||
76 | fwrite($fp, $rawdata); | ||
77 | fclose($fp); | ||
78 | } | ||
79 | |||
80 | /** | ||
81 | * Crée un répertoire de médias pour l'article | ||
82 | */ | ||
83 | function create_assets_directory($id) | ||
84 | { | ||
85 | $assets_path = ABS_PATH; | ||
86 | if(!is_dir($assets_path)) { | ||
87 | mkdir($assets_path, 0705); | ||
88 | } | ||
89 | |||
90 | $article_directory = $assets_path . $id; | ||
91 | if(!is_dir($article_directory)) { | ||
92 | mkdir($article_directory, 0705); | ||
93 | } | ||
94 | |||
95 | return $article_directory; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * Suppression du répertoire d'images | ||
100 | */ | ||
101 | function remove_directory($directory) | ||
102 | { | ||
103 | if(is_dir($directory)) { | ||
104 | $files = array_diff(scandir($directory), array('.','..')); | ||
105 | foreach ($files as $file) { | ||
106 | (is_dir("$directory/$file")) ? remove_directory("$directory/$file") : unlink("$directory/$file"); | ||
107 | } | ||
108 | return rmdir($directory); | ||
109 | } | ||
110 | } \ No newline at end of file | ||
diff --git a/inc/rain.tpl.class.php b/inc/rain.tpl.class.php deleted file mode 100644 index 6522c798..00000000 --- a/inc/rain.tpl.class.php +++ /dev/null | |||
@@ -1,1043 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * RainTPL | ||
5 | * ------- | ||
6 | * Realized by Federico Ulfo & maintained by the Rain Team | ||
7 | * Distributed under GNU/LGPL 3 License | ||
8 | * | ||
9 | * @version 2.7.2 | ||
10 | */ | ||
11 | |||
12 | |||
13 | class RainTPL{ | ||
14 | |||
15 | // ------------------------- | ||
16 | // CONFIGURATION | ||
17 | // ------------------------- | ||
18 | |||
19 | /** | ||
20 | * Template directory | ||
21 | * | ||
22 | * @var string | ||
23 | */ | ||
24 | static $tpl_dir = "tpl/"; | ||
25 | |||
26 | |||
27 | /** | ||
28 | * Cache directory. Is the directory where RainTPL will compile the template and save the cache | ||
29 | * | ||
30 | * @var string | ||
31 | */ | ||
32 | static $cache_dir = "tmp/"; | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Template base URL. RainTPL will add this URL to the relative paths of element selected in $path_replace_list. | ||
37 | * | ||
38 | * @var string | ||
39 | */ | ||
40 | static $base_url = null; | ||
41 | |||
42 | |||
43 | /** | ||
44 | * Template extension. | ||
45 | * | ||
46 | * @var string | ||
47 | */ | ||
48 | static $tpl_ext = "html"; | ||
49 | |||
50 | |||
51 | /** | ||
52 | * Path replace is a cool features that replace all relative paths of images (<img src="...">), stylesheet (<link href="...">), script (<script src="...">) and link (<a href="...">) | ||
53 | * Set true to enable the path replace. | ||
54 | * | ||
55 | * @var unknown_type | ||
56 | */ | ||
57 | static $path_replace = true; | ||
58 | |||
59 | |||
60 | /** | ||
61 | * You can set what the path_replace method will replace. | ||
62 | * Avaible options: a, img, link, script, input | ||
63 | * | ||
64 | * @var array | ||
65 | */ | ||
66 | static $path_replace_list = array( 'a', 'img', 'link', 'script', 'input' ); | ||
67 | |||
68 | |||
69 | /** | ||
70 | * You can define in the black list what string are disabled into the template tags | ||
71 | * | ||
72 | * @var unknown_type | ||
73 | */ | ||
74 | static $black_list = array( '\$this', 'raintpl::', 'self::', '_SESSION', '_SERVER', '_ENV', 'eval', 'exec', 'unlink', 'rmdir' ); | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Check template. | ||
79 | * true: checks template update time, if changed it compile them | ||
80 | * false: loads the compiled template. Set false if server doesn't have write permission for cache_directory. | ||
81 | * | ||
82 | */ | ||
83 | static $check_template_update = true; | ||
84 | |||
85 | |||
86 | /** | ||
87 | * PHP tags <? ?> | ||
88 | * True: php tags are enabled into the template | ||
89 | * False: php tags are disabled into the template and rendered as html | ||
90 | * | ||
91 | * @var bool | ||
92 | */ | ||
93 | static $php_enabled = true; | ||
94 | |||
95 | |||
96 | /** | ||
97 | * Debug mode flag. | ||
98 | * True: debug mode is used, syntax errors are displayed directly in template. Execution of script is not terminated. | ||
99 | * False: exception is thrown on found error. | ||
100 | * | ||
101 | * @var bool | ||
102 | */ | ||
103 | static $debug = false; | ||
104 | |||
105 | // ------------------------- | ||
106 | |||
107 | |||
108 | // ------------------------- | ||
109 | // RAINTPL VARIABLES | ||
110 | // ------------------------- | ||
111 | |||
112 | /** | ||
113 | * Is the array where RainTPL keep the variables assigned | ||
114 | * | ||
115 | * @var array | ||
116 | */ | ||
117 | public $var = array(); | ||
118 | |||
119 | protected $tpl = array(), // variables to keep the template directories and info | ||
120 | $cache = false, // static cache enabled / disabled | ||
121 | $cache_id = null; // identify only one cache | ||
122 | |||
123 | protected static $config_name_sum = array(); // takes all the config to create the md5 of the file | ||
124 | |||
125 | // ------------------------- | ||
126 | |||
127 | |||
128 | |||
129 | const CACHE_EXPIRE_TIME = 3600; // default cache expire time = hour | ||
130 | |||
131 | |||
132 | |||
133 | /** | ||
134 | * Assign variable | ||
135 | * eg. $t->assign('name','mickey'); | ||
136 | * | ||
137 | * @param mixed $variable_name Name of template variable or associative array name/value | ||
138 | * @param mixed $value value assigned to this variable. Not set if variable_name is an associative array | ||
139 | */ | ||
140 | |||
141 | function assign( $variable, $value = null ){ | ||
142 | if( is_array( $variable ) ) | ||
143 | $this->var += $variable; | ||
144 | else | ||
145 | $this->var[ $variable ] = $value; | ||
146 | } | ||
147 | |||
148 | |||
149 | |||
150 | /** | ||
151 | * Draw the template | ||
152 | * eg. $html = $tpl->draw( 'demo', TRUE ); // return template in string | ||
153 | * or $tpl->draw( $tpl_name ); // echo the template | ||
154 | * | ||
155 | * @param string $tpl_name template to load | ||
156 | * @param boolean $return_string true=return a string, false=echo the template | ||
157 | * @return string | ||
158 | */ | ||
159 | |||
160 | function draw( $tpl_name, $return_string = false ){ | ||
161 | |||
162 | try { | ||
163 | // compile the template if necessary and set the template filepath | ||
164 | $this->check_template( $tpl_name ); | ||
165 | } catch (RainTpl_Exception $e) { | ||
166 | $output = $this->printDebug($e); | ||
167 | die($output); | ||
168 | } | ||
169 | |||
170 | // Cache is off and, return_string is false | ||
171 | // Rain just echo the template | ||
172 | |||
173 | if( !$this->cache && !$return_string ){ | ||
174 | extract( $this->var ); | ||
175 | include $this->tpl['compiled_filename']; | ||
176 | unset( $this->tpl ); | ||
177 | } | ||
178 | |||
179 | |||
180 | // cache or return_string are enabled | ||
181 | // rain get the output buffer to save the output in the cache or to return it as string | ||
182 | |||
183 | else{ | ||
184 | |||
185 | //---------------------- | ||
186 | // get the output buffer | ||
187 | //---------------------- | ||
188 | ob_start(); | ||
189 | extract( $this->var ); | ||
190 | include $this->tpl['compiled_filename']; | ||
191 | $raintpl_contents = ob_get_clean(); | ||
192 | //---------------------- | ||
193 | |||
194 | |||
195 | // save the output in the cache | ||
196 | if( $this->cache ) | ||
197 | file_put_contents( $this->tpl['cache_filename'], "<?php if(!class_exists('raintpl')){exit;}?>" . $raintpl_contents ); | ||
198 | |||
199 | // free memory | ||
200 | unset( $this->tpl ); | ||
201 | |||
202 | // return or print the template | ||
203 | if( $return_string ) return $raintpl_contents; else echo $raintpl_contents; | ||
204 | |||
205 | } | ||
206 | |||
207 | } | ||
208 | |||
209 | |||
210 | |||
211 | /** | ||
212 | * If exists a valid cache for this template it returns the cache | ||
213 | * | ||
214 | * @param string $tpl_name Name of template (set the same of draw) | ||
215 | * @param int $expiration_time Set after how many seconds the cache expire and must be regenerated | ||
216 | * @return string it return the HTML or null if the cache must be recreated | ||
217 | */ | ||
218 | |||
219 | function cache( $tpl_name, $expire_time = self::CACHE_EXPIRE_TIME, $cache_id = null ){ | ||
220 | |||
221 | // set the cache_id | ||
222 | $this->cache_id = $cache_id; | ||
223 | |||
224 | if( !$this->check_template( $tpl_name ) && file_exists( $this->tpl['cache_filename'] ) && ( time() - filemtime( $this->tpl['cache_filename'] ) < $expire_time ) ) | ||
225 | return substr( file_get_contents( $this->tpl['cache_filename'] ), 43 ); | ||
226 | else{ | ||
227 | //delete the cache of the selected template | ||
228 | if (file_exists($this->tpl['cache_filename'])) | ||
229 | unlink($this->tpl['cache_filename'] ); | ||
230 | $this->cache = true; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | |||
235 | |||
236 | /** | ||
237 | * Configure the settings of RainTPL | ||
238 | * | ||
239 | */ | ||
240 | static function configure( $setting, $value = null ){ | ||
241 | if( is_array( $setting ) ) | ||
242 | foreach( $setting as $key => $value ) | ||
243 | self::configure( $key, $value ); | ||
244 | else if( property_exists( __CLASS__, $setting ) ){ | ||
245 | self::$$setting = $value; | ||
246 | self::$config_name_sum[ $setting ] = $value; // take trace of all config | ||
247 | } | ||
248 | } | ||
249 | |||
250 | |||
251 | |||
252 | // check if has to compile the template | ||
253 | // return true if the template has changed | ||
254 | protected function check_template( $tpl_name ){ | ||
255 | |||
256 | if( !isset($this->tpl['checked']) ){ | ||
257 | |||
258 | $tpl_basename = basename( $tpl_name ); // template basename | ||
259 | $tpl_basedir = strpos($tpl_name,"/") ? dirname($tpl_name) . '/' : null; // template basedirectory | ||
260 | $tpl_dir = self::$tpl_dir . $tpl_basedir; // template directory | ||
261 | $this->tpl['tpl_filename'] = $tpl_dir . $tpl_basename . '.' . self::$tpl_ext; // template filename | ||
262 | $temp_compiled_filename = self::$cache_dir . $tpl_basename . "." . md5( $tpl_dir . serialize(self::$config_name_sum)); | ||
263 | $this->tpl['compiled_filename'] = $temp_compiled_filename . '.rtpl.php'; // cache filename | ||
264 | $this->tpl['cache_filename'] = $temp_compiled_filename . '.s_' . $this->cache_id . '.rtpl.php'; // static cache filename | ||
265 | |||
266 | // if the template doesn't exsist throw an error | ||
267 | if( self::$check_template_update && !file_exists( $this->tpl['tpl_filename'] ) ){ | ||
268 | $e = new RainTpl_NotFoundException( 'Template '. $tpl_basename .' not found!' ); | ||
269 | throw $e->setTemplateFile($this->tpl['tpl_filename']); | ||
270 | } | ||
271 | |||
272 | // file doesn't exsist, or the template was updated, Rain will compile the template | ||
273 | if( !file_exists( $this->tpl['compiled_filename'] ) || ( self::$check_template_update && filemtime($this->tpl['compiled_filename']) < filemtime( $this->tpl['tpl_filename'] ) ) ){ | ||
274 | $this->compileFile( $tpl_basename, $tpl_basedir, $this->tpl['tpl_filename'], self::$cache_dir, $this->tpl['compiled_filename'] ); | ||
275 | return true; | ||
276 | } | ||
277 | $this->tpl['checked'] = true; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | |||
282 | /** | ||
283 | * execute stripslaches() on the xml block. Invoqued by preg_replace_callback function below | ||
284 | * @access protected | ||
285 | */ | ||
286 | protected function xml_reSubstitution($capture) { | ||
287 | return "<?php echo '<?xml ".stripslashes($capture[1])." ?>'; ?>"; | ||
288 | } | ||
289 | |||
290 | /** | ||
291 | * Compile and write the compiled template file | ||
292 | * @access protected | ||
293 | */ | ||
294 | protected function compileFile( $tpl_basename, $tpl_basedir, $tpl_filename, $cache_dir, $compiled_filename ){ | ||
295 | |||
296 | //read template file | ||
297 | $this->tpl['source'] = $template_code = file_get_contents( $tpl_filename ); | ||
298 | |||
299 | //xml substitution | ||
300 | $template_code = preg_replace( "/<\?xml(.*?)\?>/s", "##XML\\1XML##", $template_code ); | ||
301 | |||
302 | //disable php tag | ||
303 | if( !self::$php_enabled ) | ||
304 | $template_code = str_replace( array("<?","?>"), array("<?","?>"), $template_code ); | ||
305 | |||
306 | //xml re-substitution | ||
307 | $template_code = preg_replace_callback ( "/##XML(.*?)XML##/s", array($this, 'xml_reSubstitution'), $template_code ); | ||
308 | |||
309 | //compile template | ||
310 | $template_compiled = "<?php if(!class_exists('raintpl')){exit;}?>" . $this->compileTemplate( $template_code, $tpl_basedir ); | ||
311 | |||
312 | |||
313 | // fix the php-eating-newline-after-closing-tag-problem | ||
314 | $template_compiled = str_replace( "?>\n", "?>\n\n", $template_compiled ); | ||
315 | |||
316 | // create directories | ||
317 | if( !is_dir( $cache_dir ) ) | ||
318 | mkdir( $cache_dir, 0755, true ); | ||
319 | |||
320 | if( !is_writable( $cache_dir ) ) | ||
321 | throw new RainTpl_Exception ('Cache directory ' . $cache_dir . 'doesn\'t have write permission. Set write permission or set RAINTPL_CHECK_TEMPLATE_UPDATE to false. More details on http://www.raintpl.com/Documentation/Documentation-for-PHP-developers/Configuration/'); | ||
322 | |||
323 | //write compiled file | ||
324 | file_put_contents( $compiled_filename, $template_compiled ); | ||
325 | } | ||
326 | |||
327 | |||
328 | |||
329 | /** | ||
330 | * Compile template | ||
331 | * @access protected | ||
332 | */ | ||
333 | protected function compileTemplate( $template_code, $tpl_basedir ){ | ||
334 | |||
335 | //tag list | ||
336 | $tag_regexp = array( 'loop' => '(\{loop(?: name){0,1}="\${0,1}[^"]*"\})', | ||
337 | 'loop_close' => '(\{\/loop\})', | ||
338 | 'if' => '(\{if(?: condition){0,1}="[^"]*"\})', | ||
339 | 'elseif' => '(\{elseif(?: condition){0,1}="[^"]*"\})', | ||
340 | 'else' => '(\{else\})', | ||
341 | 'if_close' => '(\{\/if\})', | ||
342 | 'function' => '(\{function="[^"]*"\})', | ||
343 | 'noparse' => '(\{noparse\})', | ||
344 | 'noparse_close'=> '(\{\/noparse\})', | ||
345 | 'ignore' => '(\{ignore\}|\{\*)', | ||
346 | 'ignore_close' => '(\{\/ignore\}|\*\})', | ||
347 | 'include' => '(\{include="[^"]*"(?: cache="[^"]*")?\})', | ||
348 | 'template_info'=> '(\{\$template_info\})', | ||
349 | 'function' => '(\{function="(\w*?)(?:.*?)"\})' | ||
350 | ); | ||
351 | |||
352 | $tag_regexp = "/" . join( "|", $tag_regexp ) . "/"; | ||
353 | |||
354 | //split the code with the tags regexp | ||
355 | $template_code = preg_split ( $tag_regexp, $template_code, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY ); | ||
356 | |||
357 | //path replace (src of img, background and href of link) | ||
358 | $template_code = $this->path_replace( $template_code, $tpl_basedir ); | ||
359 | |||
360 | //compile the code | ||
361 | $compiled_code = $this->compileCode( $template_code ); | ||
362 | |||
363 | //return the compiled code | ||
364 | return $compiled_code; | ||
365 | |||
366 | } | ||
367 | |||
368 | |||
369 | |||
370 | /** | ||
371 | * Compile the code | ||
372 | * @access protected | ||
373 | */ | ||
374 | protected function compileCode( $parsed_code ){ | ||
375 | |||
376 | //variables initialization | ||
377 | $compiled_code = $open_if = $comment_is_open = $ignore_is_open = null; | ||
378 | $loop_level = 0; | ||
379 | |||
380 | //read all parsed code | ||
381 | while( $html = array_shift( $parsed_code ) ){ | ||
382 | |||
383 | //close ignore tag | ||
384 | if( !$comment_is_open && ( strpos( $html, '{/ignore}' ) !== FALSE || strpos( $html, '*}' ) !== FALSE ) ) | ||
385 | $ignore_is_open = false; | ||
386 | |||
387 | //code between tag ignore id deleted | ||
388 | elseif( $ignore_is_open ){ | ||
389 | //ignore the code | ||
390 | } | ||
391 | |||
392 | //close no parse tag | ||
393 | elseif( strpos( $html, '{/noparse}' ) !== FALSE ) | ||
394 | $comment_is_open = false; | ||
395 | |||
396 | //code between tag noparse is not compiled | ||
397 | elseif( $comment_is_open ) | ||
398 | $compiled_code .= $html; | ||
399 | |||
400 | //ignore | ||
401 | elseif( strpos( $html, '{ignore}' ) !== FALSE || strpos( $html, '{*' ) !== FALSE ) | ||
402 | $ignore_is_open = true; | ||
403 | |||
404 | //noparse | ||
405 | elseif( strpos( $html, '{noparse}' ) !== FALSE ) | ||
406 | $comment_is_open = true; | ||
407 | |||
408 | //include tag | ||
409 | elseif( preg_match( '/\{include="([^"]*)"(?: cache="([^"]*)"){0,1}\}/', $html, $code ) ){ | ||
410 | |||
411 | //variables substitution | ||
412 | $include_var = $this->var_replace( $code[ 1 ], $left_delimiter = null, $right_delimiter = null, $php_left_delimiter = '".' , $php_right_delimiter = '."', $loop_level ); | ||
413 | |||
414 | // if the cache is active | ||
415 | if( isset($code[ 2 ]) ){ | ||
416 | |||
417 | //dynamic include | ||
418 | $compiled_code .= '<?php $tpl = new '.get_class($this).';' . | ||
419 | 'if( $cache = $tpl->cache( $template = basename("'.$include_var.'") ) )' . | ||
420 | ' echo $cache;' . | ||
421 | 'else{' . | ||
422 | ' $tpl_dir_temp = self::$tpl_dir;' . | ||
423 | ' $tpl->assign( $this->var );' . | ||
424 | ( !$loop_level ? null : '$tpl->assign( "key", $key'.$loop_level.' ); $tpl->assign( "value", $value'.$loop_level.' );' ). | ||
425 | ' $tpl->draw( dirname("'.$include_var.'") . ( substr("'.$include_var.'",-1,1) != "/" ? "/" : "" ) . basename("'.$include_var.'") );'. | ||
426 | '} ?>'; | ||
427 | } | ||
428 | else{ | ||
429 | |||
430 | //dynamic include | ||
431 | $compiled_code .= '<?php $tpl = new '.get_class($this).';' . | ||
432 | '$tpl_dir_temp = self::$tpl_dir;' . | ||
433 | '$tpl->assign( $this->var );' . | ||
434 | ( !$loop_level ? null : '$tpl->assign( "key", $key'.$loop_level.' ); $tpl->assign( "value", $value'.$loop_level.' );' ). | ||
435 | '$tpl->draw( dirname("'.$include_var.'") . ( substr("'.$include_var.'",-1,1) != "/" ? "/" : "" ) . basename("'.$include_var.'") );'. | ||
436 | '?>'; | ||
437 | |||
438 | |||
439 | } | ||
440 | |||
441 | } | ||
442 | |||
443 | //loop | ||
444 | elseif( preg_match( '/\{loop(?: name){0,1}="\${0,1}([^"]*)"\}/', $html, $code ) ){ | ||
445 | |||
446 | //increase the loop counter | ||
447 | $loop_level++; | ||
448 | |||
449 | //replace the variable in the loop | ||
450 | $var = $this->var_replace( '$' . $code[ 1 ], $tag_left_delimiter=null, $tag_right_delimiter=null, $php_left_delimiter=null, $php_right_delimiter=null, $loop_level-1 ); | ||
451 | |||
452 | //loop variables | ||
453 | $counter = "\$counter$loop_level"; // count iteration | ||
454 | $key = "\$key$loop_level"; // key | ||
455 | $value = "\$value$loop_level"; // value | ||
456 | |||
457 | //loop code | ||
458 | $compiled_code .= "<?php $counter=-1; if( isset($var) && is_array($var) && sizeof($var) ) foreach( $var as $key => $value ){ $counter++; ?>"; | ||
459 | |||
460 | } | ||
461 | |||
462 | //close loop tag | ||
463 | elseif( strpos( $html, '{/loop}' ) !== FALSE ) { | ||
464 | |||
465 | //iterator | ||
466 | $counter = "\$counter$loop_level"; | ||
467 | |||
468 | //decrease the loop counter | ||
469 | $loop_level--; | ||
470 | |||
471 | //close loop code | ||
472 | $compiled_code .= "<?php } ?>"; | ||
473 | |||
474 | } | ||
475 | |||
476 | //if | ||
477 | elseif( preg_match( '/\{if(?: condition){0,1}="([^"]*)"\}/', $html, $code ) ){ | ||
478 | |||
479 | //increase open if counter (for intendation) | ||
480 | $open_if++; | ||
481 | |||
482 | //tag | ||
483 | $tag = $code[ 0 ]; | ||
484 | |||
485 | //condition attribute | ||
486 | $condition = $code[ 1 ]; | ||
487 | |||
488 | // check if there's any function disabled by black_list | ||
489 | $this->function_check( $tag ); | ||
490 | |||
491 | //variable substitution into condition (no delimiter into the condition) | ||
492 | $parsed_condition = $this->var_replace( $condition, $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level ); | ||
493 | |||
494 | //if code | ||
495 | $compiled_code .= "<?php if( $parsed_condition ){ ?>"; | ||
496 | |||
497 | } | ||
498 | |||
499 | //elseif | ||
500 | elseif( preg_match( '/\{elseif(?: condition){0,1}="([^"]*)"\}/', $html, $code ) ){ | ||
501 | |||
502 | //tag | ||
503 | $tag = $code[ 0 ]; | ||
504 | |||
505 | //condition attribute | ||
506 | $condition = $code[ 1 ]; | ||
507 | |||
508 | //variable substitution into condition (no delimiter into the condition) | ||
509 | $parsed_condition = $this->var_replace( $condition, $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level ); | ||
510 | |||
511 | //elseif code | ||
512 | $compiled_code .= "<?php }elseif( $parsed_condition ){ ?>"; | ||
513 | } | ||
514 | |||
515 | //else | ||
516 | elseif( strpos( $html, '{else}' ) !== FALSE ) { | ||
517 | |||
518 | //else code | ||
519 | $compiled_code .= '<?php }else{ ?>'; | ||
520 | |||
521 | } | ||
522 | |||
523 | //close if tag | ||
524 | elseif( strpos( $html, '{/if}' ) !== FALSE ) { | ||
525 | |||
526 | //decrease if counter | ||
527 | $open_if--; | ||
528 | |||
529 | // close if code | ||
530 | $compiled_code .= '<?php } ?>'; | ||
531 | |||
532 | } | ||
533 | |||
534 | //function | ||
535 | elseif( preg_match( '/\{function="(\w*)(.*?)"\}/', $html, $code ) ){ | ||
536 | |||
537 | //tag | ||
538 | $tag = $code[ 0 ]; | ||
539 | |||
540 | //function | ||
541 | $function = $code[ 1 ]; | ||
542 | |||
543 | // check if there's any function disabled by black_list | ||
544 | $this->function_check( $tag ); | ||
545 | |||
546 | if( empty( $code[ 2 ] ) ) | ||
547 | $parsed_function = $function . "()"; | ||
548 | else | ||
549 | // parse the function | ||
550 | $parsed_function = $function . $this->var_replace( $code[ 2 ], $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level ); | ||
551 | |||
552 | //if code | ||
553 | $compiled_code .= "<?php echo $parsed_function; ?>"; | ||
554 | } | ||
555 | |||
556 | // show all vars | ||
557 | elseif ( strpos( $html, '{$template_info}' ) !== FALSE ) { | ||
558 | |||
559 | //tag | ||
560 | $tag = '{$template_info}'; | ||
561 | |||
562 | //if code | ||
563 | $compiled_code .= '<?php echo "<pre>"; print_r( $this->var ); echo "</pre>"; ?>'; | ||
564 | } | ||
565 | |||
566 | |||
567 | //all html code | ||
568 | else{ | ||
569 | |||
570 | //variables substitution (es. {$title}) | ||
571 | $html = $this->var_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true ); | ||
572 | //const substitution (es. {#CONST#}) | ||
573 | $html = $this->const_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true ); | ||
574 | //functions substitution (es. {"string"|functions}) | ||
575 | $compiled_code .= $this->func_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true ); | ||
576 | } | ||
577 | } | ||
578 | |||
579 | if( $open_if > 0 ) { | ||
580 | $e = new RainTpl_SyntaxException('Error! You need to close an {if} tag in ' . $this->tpl['tpl_filename'] . ' template'); | ||
581 | throw $e->setTemplateFile($this->tpl['tpl_filename']); | ||
582 | } | ||
583 | return $compiled_code; | ||
584 | } | ||
585 | |||
586 | |||
587 | /** | ||
588 | * Reduce a path, eg. www/library/../filepath//file => www/filepath/file | ||
589 | * @param type $path | ||
590 | * @return type | ||
591 | */ | ||
592 | protected function reduce_path( $path ){ | ||
593 | $path = str_replace( "://", "@not_replace@", $path ); | ||
594 | $path = str_replace( "//", "/", $path ); | ||
595 | $path = str_replace( "@not_replace@", "://", $path ); | ||
596 | return preg_replace('/\w+\/\.\.\//', '', $path ); | ||
597 | } | ||
598 | |||
599 | |||
600 | |||
601 | /** | ||
602 | * replace the path of image src, link href and a href. | ||
603 | * url => template_dir/url | ||
604 | * url# => url | ||
605 | * http://url => http://url | ||
606 | * | ||
607 | * @param string $html | ||
608 | * @return string html sostituito | ||
609 | */ | ||
610 | protected function path_replace( $html, $tpl_basedir ){ | ||
611 | |||
612 | if( self::$path_replace ){ | ||
613 | |||
614 | $tpl_dir = self::$base_url . self::$tpl_dir . $tpl_basedir; | ||
615 | |||
616 | // reduce the path | ||
617 | $path = $this->reduce_path($tpl_dir); | ||
618 | |||
619 | $exp = $sub = array(); | ||
620 | |||
621 | if( in_array( "img", self::$path_replace_list ) ){ | ||
622 | $exp = array( '/<img(.*?)src=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<img(.*?)src=(?:")([^"]+?)#(?:")/i', '/<img(.*?)src="(.*?)"/', '/<img(.*?)src=(?:\@)([^"]+?)(?:\@)/i' ); | ||
623 | $sub = array( '<img$1src=@$2://$3@', '<img$1src=@$2@', '<img$1src="' . $path . '$2"', '<img$1src="$2"' ); | ||
624 | } | ||
625 | |||
626 | if( in_array( "script", self::$path_replace_list ) ){ | ||
627 | $exp = array_merge( $exp , array( '/<script(.*?)src=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<script(.*?)src=(?:")([^"]+?)#(?:")/i', '/<script(.*?)src="(.*?)"/', '/<script(.*?)src=(?:\@)([^"]+?)(?:\@)/i' ) ); | ||
628 | $sub = array_merge( $sub , array( '<script$1src=@$2://$3@', '<script$1src=@$2@', '<script$1src="' . $path . '$2"', '<script$1src="$2"' ) ); | ||
629 | } | ||
630 | |||
631 | if( in_array( "link", self::$path_replace_list ) ){ | ||
632 | $exp = array_merge( $exp , array( '/<link(.*?)href=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<link(.*?)href=(?:")([^"]+?)#(?:")/i', '/<link(.*?)href="(.*?)"/', '/<link(.*?)href=(?:\@)([^"]+?)(?:\@)/i' ) ); | ||
633 | $sub = array_merge( $sub , array( '<link$1href=@$2://$3@', '<link$1href=@$2@' , '<link$1href="' . $path . '$2"', '<link$1href="$2"' ) ); | ||
634 | } | ||
635 | |||
636 | if( in_array( "a", self::$path_replace_list ) ){ | ||
637 | $exp = array_merge( $exp , array( '/<a(.*?)href=(?:")(http\:\/\/|https\:\/\/|javascript:)([^"]+?)(?:")/i', '/<a(.*?)href="(.*?)"/', '/<a(.*?)href=(?:\@)([^"]+?)(?:\@)/i' ) ); | ||
638 | $sub = array_merge( $sub , array( '<a$1href=@$2$3@', '<a$1href="' . self::$base_url . '$2"', '<a$1href="$2"' ) ); | ||
639 | } | ||
640 | |||
641 | if( in_array( "input", self::$path_replace_list ) ){ | ||
642 | $exp = array_merge( $exp , array( '/<input(.*?)src=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<input(.*?)src=(?:")([^"]+?)#(?:")/i', '/<input(.*?)src="(.*?)"/', '/<input(.*?)src=(?:\@)([^"]+?)(?:\@)/i' ) ); | ||
643 | $sub = array_merge( $sub , array( '<input$1src=@$2://$3@', '<input$1src=@$2@', '<input$1src="' . $path . '$2"', '<input$1src="$2"' ) ); | ||
644 | } | ||
645 | |||
646 | return preg_replace( $exp, $sub, $html ); | ||
647 | |||
648 | } | ||
649 | else | ||
650 | return $html; | ||
651 | |||
652 | } | ||
653 | |||
654 | |||
655 | |||
656 | |||
657 | |||
658 | // replace const | ||
659 | function const_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){ | ||
660 | // const | ||
661 | return preg_replace( '/\{\#(\w+)\#{0,1}\}/', $php_left_delimiter . ( $echo ? " echo " : null ) . '\\1' . $php_right_delimiter, $html ); | ||
662 | } | ||
663 | |||
664 | |||
665 | |||
666 | // replace functions/modifiers on constants and strings | ||
667 | function func_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){ | ||
668 | |||
669 | preg_match_all( '/' . '\{\#{0,1}(\"{0,1}.*?\"{0,1})(\|\w.*?)\#{0,1}\}' . '/', $html, $matches ); | ||
670 | |||
671 | for( $i=0, $n=count($matches[0]); $i<$n; $i++ ){ | ||
672 | |||
673 | //complete tag ex: {$news.title|substr:0,100} | ||
674 | $tag = $matches[ 0 ][ $i ]; | ||
675 | |||
676 | //variable name ex: news.title | ||
677 | $var = $matches[ 1 ][ $i ]; | ||
678 | |||
679 | //function and parameters associate to the variable ex: substr:0,100 | ||
680 | $extra_var = $matches[ 2 ][ $i ]; | ||
681 | |||
682 | // check if there's any function disabled by black_list | ||
683 | $this->function_check( $tag ); | ||
684 | |||
685 | $extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level ); | ||
686 | |||
687 | |||
688 | // check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value | ||
689 | $is_init_variable = preg_match( "/^(\s*?)\=[^=](.*?)$/", $extra_var ); | ||
690 | |||
691 | //function associate to variable | ||
692 | $function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null; | ||
693 | |||
694 | //variable path split array (ex. $news.title o $news[title]) or object (ex. $news->title) | ||
695 | $temp = preg_split( "/\.|\[|\-\>/", $var ); | ||
696 | |||
697 | //variable name | ||
698 | $var_name = $temp[ 0 ]; | ||
699 | |||
700 | //variable path | ||
701 | $variable_path = substr( $var, strlen( $var_name ) ); | ||
702 | |||
703 | //parentesis transform [ e ] in [" e in "] | ||
704 | $variable_path = str_replace( '[', '["', $variable_path ); | ||
705 | $variable_path = str_replace( ']', '"]', $variable_path ); | ||
706 | |||
707 | //transform .$variable in ["$variable"] | ||
708 | $variable_path = preg_replace('/\.\$(\w+)/', '["$\\1"]', $variable_path ); | ||
709 | |||
710 | //transform [variable] in ["variable"] | ||
711 | $variable_path = preg_replace('/\.(\w+)/', '["\\1"]', $variable_path ); | ||
712 | |||
713 | //if there's a function | ||
714 | if( $function_var ){ | ||
715 | |||
716 | // check if there's a function or a static method and separate, function by parameters | ||
717 | $function_var = str_replace("::", "@double_dot@", $function_var ); | ||
718 | |||
719 | // get the position of the first : | ||
720 | if( $dot_position = strpos( $function_var, ":" ) ){ | ||
721 | |||
722 | // get the function and the parameters | ||
723 | $function = substr( $function_var, 0, $dot_position ); | ||
724 | $params = substr( $function_var, $dot_position+1 ); | ||
725 | |||
726 | } | ||
727 | else{ | ||
728 | |||
729 | //get the function | ||
730 | $function = str_replace( "@double_dot@", "::", $function_var ); | ||
731 | $params = null; | ||
732 | |||
733 | } | ||
734 | |||
735 | // replace back the @double_dot@ with :: | ||
736 | $function = str_replace( "@double_dot@", "::", $function ); | ||
737 | $params = str_replace( "@double_dot@", "::", $params ); | ||
738 | |||
739 | |||
740 | } | ||
741 | else | ||
742 | $function = $params = null; | ||
743 | |||
744 | $php_var = $var_name . $variable_path; | ||
745 | |||
746 | // compile the variable for php | ||
747 | if( isset( $function ) ){ | ||
748 | if( $php_var ) | ||
749 | $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter; | ||
750 | else | ||
751 | $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $params ) )" : "$function()" ) . $php_right_delimiter; | ||
752 | } | ||
753 | else | ||
754 | $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter; | ||
755 | |||
756 | $html = str_replace( $tag, $php_var, $html ); | ||
757 | |||
758 | } | ||
759 | |||
760 | return $html; | ||
761 | |||
762 | } | ||
763 | |||
764 | |||
765 | |||
766 | function var_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){ | ||
767 | |||
768 | //all variables | ||
769 | if( preg_match_all( '/' . $tag_left_delimiter . '\$(\w+(?:\.\${0,1}[A-Za-z0-9_]+)*(?:(?:\[\${0,1}[A-Za-z0-9_]+\])|(?:\-\>\${0,1}[A-Za-z0-9_]+))*)(.*?)' . $tag_right_delimiter . '/', $html, $matches ) ){ | ||
770 | |||
771 | for( $parsed=array(), $i=0, $n=count($matches[0]); $i<$n; $i++ ) | ||
772 | $parsed[$matches[0][$i]] = array('var'=>$matches[1][$i],'extra_var'=>$matches[2][$i]); | ||
773 | |||
774 | foreach( $parsed as $tag => $array ){ | ||
775 | |||
776 | //variable name ex: news.title | ||
777 | $var = $array['var']; | ||
778 | |||
779 | //function and parameters associate to the variable ex: substr:0,100 | ||
780 | $extra_var = $array['extra_var']; | ||
781 | |||
782 | // check if there's any function disabled by black_list | ||
783 | $this->function_check( $tag ); | ||
784 | |||
785 | $extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level ); | ||
786 | |||
787 | // check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value | ||
788 | $is_init_variable = preg_match( "/^[a-z_A-Z\.\[\](\-\>)]*=[^=]*$/", $extra_var ); | ||
789 | |||
790 | //function associate to variable | ||
791 | $function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null; | ||
792 | |||
793 | //variable path split array (ex. $news.title o $news[title]) or object (ex. $news->title) | ||
794 | $temp = preg_split( "/\.|\[|\-\>/", $var ); | ||
795 | |||
796 | //variable name | ||
797 | $var_name = $temp[ 0 ]; | ||
798 | |||
799 | //variable path | ||
800 | $variable_path = substr( $var, strlen( $var_name ) ); | ||
801 | |||
802 | //parentesis transform [ e ] in [" e in "] | ||
803 | $variable_path = str_replace( '[', '["', $variable_path ); | ||
804 | $variable_path = str_replace( ']', '"]', $variable_path ); | ||
805 | |||
806 | //transform .$variable in ["$variable"] and .variable in ["variable"] | ||
807 | $variable_path = preg_replace('/\.(\${0,1}\w+)/', '["\\1"]', $variable_path ); | ||
808 | |||
809 | // if is an assignment also assign the variable to $this->var['value'] | ||
810 | if( $is_init_variable ) | ||
811 | $extra_var = "=\$this->var['{$var_name}']{$variable_path}" . $extra_var; | ||
812 | |||
813 | |||
814 | |||
815 | //if there's a function | ||
816 | if( $function_var ){ | ||
817 | |||
818 | // check if there's a function or a static method and separate, function by parameters | ||
819 | $function_var = str_replace("::", "@double_dot@", $function_var ); | ||
820 | |||
821 | |||
822 | // get the position of the first : | ||
823 | if( $dot_position = strpos( $function_var, ":" ) ){ | ||
824 | |||
825 | // get the function and the parameters | ||
826 | $function = substr( $function_var, 0, $dot_position ); | ||
827 | $params = substr( $function_var, $dot_position+1 ); | ||
828 | |||
829 | } | ||
830 | else{ | ||
831 | |||
832 | //get the function | ||
833 | $function = str_replace( "@double_dot@", "::", $function_var ); | ||
834 | $params = null; | ||
835 | |||
836 | } | ||
837 | |||
838 | // replace back the @double_dot@ with :: | ||
839 | $function = str_replace( "@double_dot@", "::", $function ); | ||
840 | $params = str_replace( "@double_dot@", "::", $params ); | ||
841 | } | ||
842 | else | ||
843 | $function = $params = null; | ||
844 | |||
845 | //if it is inside a loop | ||
846 | if( $loop_level ){ | ||
847 | //verify the variable name | ||
848 | if( $var_name == 'key' ) | ||
849 | $php_var = '$key' . $loop_level; | ||
850 | elseif( $var_name == 'value' ) | ||
851 | $php_var = '$value' . $loop_level . $variable_path; | ||
852 | elseif( $var_name == 'counter' ) | ||
853 | $php_var = '$counter' . $loop_level; | ||
854 | else | ||
855 | $php_var = '$' . $var_name . $variable_path; | ||
856 | }else | ||
857 | $php_var = '$' . $var_name . $variable_path; | ||
858 | |||
859 | // compile the variable for php | ||
860 | if( isset( $function ) ) | ||
861 | $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter; | ||
862 | else | ||
863 | $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter; | ||
864 | |||
865 | $html = str_replace( $tag, $php_var, $html ); | ||
866 | |||
867 | |||
868 | } | ||
869 | } | ||
870 | |||
871 | return $html; | ||
872 | } | ||
873 | |||
874 | |||
875 | |||
876 | /** | ||
877 | * Check if function is in black list (sandbox) | ||
878 | * | ||
879 | * @param string $code | ||
880 | * @param string $tag | ||
881 | */ | ||
882 | protected function function_check( $code ){ | ||
883 | |||
884 | $preg = '#(\W|\s)' . implode( '(\W|\s)|(\W|\s)', self::$black_list ) . '(\W|\s)#'; | ||
885 | |||
886 | // check if the function is in the black list (or not in white list) | ||
887 | if( count(self::$black_list) && preg_match( $preg, $code, $match ) ){ | ||
888 | |||
889 | // find the line of the error | ||
890 | $line = 0; | ||
891 | $rows=explode("\n",$this->tpl['source']); | ||
892 | while( !strpos($rows[$line],$code) ) | ||
893 | $line++; | ||
894 | |||
895 | // stop the execution of the script | ||
896 | $e = new RainTpl_SyntaxException('Unallowed syntax in ' . $this->tpl['tpl_filename'] . ' template'); | ||
897 | throw $e->setTemplateFile($this->tpl['tpl_filename']) | ||
898 | ->setTag($code) | ||
899 | ->setTemplateLine($line); | ||
900 | } | ||
901 | |||
902 | } | ||
903 | |||
904 | /** | ||
905 | * Prints debug info about exception or passes it further if debug is disabled. | ||
906 | * | ||
907 | * @param RainTpl_Exception $e | ||
908 | * @return string | ||
909 | */ | ||
910 | protected function printDebug(RainTpl_Exception $e){ | ||
911 | if (!self::$debug) { | ||
912 | throw $e; | ||
913 | } | ||
914 | $output = sprintf('<h2>Exception: %s</h2><h3>%s</h3><p>template: %s</p>', | ||
915 | get_class($e), | ||
916 | $e->getMessage(), | ||
917 | $e->getTemplateFile() | ||
918 | ); | ||
919 | if ($e instanceof RainTpl_SyntaxException) { | ||
920 | if (null != $e->getTemplateLine()) { | ||
921 | $output .= '<p>line: ' . $e->getTemplateLine() . '</p>'; | ||
922 | } | ||
923 | if (null != $e->getTag()) { | ||
924 | $output .= '<p>in tag: ' . htmlspecialchars($e->getTag()) . '</p>'; | ||
925 | } | ||
926 | if (null != $e->getTemplateLine() && null != $e->getTag()) { | ||
927 | $rows=explode("\n", htmlspecialchars($this->tpl['source'])); | ||
928 | $rows[$e->getTemplateLine()] = '<font color=red>' . $rows[$e->getTemplateLine()] . '</font>'; | ||
929 | $output .= '<h3>template code</h3>' . implode('<br />', $rows) . '</pre>'; | ||
930 | } | ||
931 | } | ||
932 | $output .= sprintf('<h3>trace</h3><p>In %s on line %d</p><pre>%s</pre>', | ||
933 | $e->getFile(), $e->getLine(), | ||
934 | nl2br(htmlspecialchars($e->getTraceAsString())) | ||
935 | ); | ||
936 | return $output; | ||
937 | } | ||
938 | } | ||
939 | |||
940 | |||
941 | /** | ||
942 | * Basic Rain tpl exception. | ||
943 | */ | ||
944 | class RainTpl_Exception extends Exception{ | ||
945 | /** | ||
946 | * Path of template file with error. | ||
947 | */ | ||
948 | protected $templateFile = ''; | ||
949 | |||
950 | /** | ||
951 | * Returns path of template file with error. | ||
952 | * | ||
953 | * @return string | ||
954 | */ | ||
955 | public function getTemplateFile() | ||
956 | { | ||
957 | return $this->templateFile; | ||
958 | } | ||
959 | |||
960 | /** | ||
961 | * Sets path of template file with error. | ||
962 | * | ||
963 | * @param string $templateFile | ||
964 | * @return RainTpl_Exception | ||
965 | */ | ||
966 | public function setTemplateFile($templateFile) | ||
967 | { | ||
968 | $this->templateFile = (string) $templateFile; | ||
969 | return $this; | ||
970 | } | ||
971 | } | ||
972 | |||
973 | /** | ||
974 | * Exception thrown when template file does not exists. | ||
975 | */ | ||
976 | class RainTpl_NotFoundException extends RainTpl_Exception{ | ||
977 | } | ||
978 | |||
979 | /** | ||
980 | * Exception thrown when syntax error occurs. | ||
981 | */ | ||
982 | class RainTpl_SyntaxException extends RainTpl_Exception{ | ||
983 | /** | ||
984 | * Line in template file where error has occured. | ||
985 | * | ||
986 | * @var int | null | ||
987 | */ | ||
988 | protected $templateLine = null; | ||
989 | |||
990 | /** | ||
991 | * Tag which caused an error. | ||
992 | * | ||
993 | * @var string | null | ||
994 | */ | ||
995 | protected $tag = null; | ||
996 | |||
997 | /** | ||
998 | * Returns line in template file where error has occured | ||
999 | * or null if line is not defined. | ||
1000 | * | ||
1001 | * @return int | null | ||
1002 | */ | ||
1003 | public function getTemplateLine() | ||
1004 | { | ||
1005 | return $this->templateLine; | ||
1006 | } | ||
1007 | |||
1008 | /** | ||
1009 | * Sets line in template file where error has occured. | ||
1010 | * | ||
1011 | * @param int $templateLine | ||
1012 | * @return RainTpl_SyntaxException | ||
1013 | */ | ||
1014 | public function setTemplateLine($templateLine) | ||
1015 | { | ||
1016 | $this->templateLine = (int) $templateLine; | ||
1017 | return $this; | ||
1018 | } | ||
1019 | |||
1020 | /** | ||
1021 | * Returns tag which caused an error. | ||
1022 | * | ||
1023 | * @return string | ||
1024 | */ | ||
1025 | public function getTag() | ||
1026 | { | ||
1027 | return $this->tag; | ||
1028 | } | ||
1029 | |||
1030 | /** | ||
1031 | * Sets tag which caused an error. | ||
1032 | * | ||
1033 | * @param string $tag | ||
1034 | * @return RainTpl_SyntaxException | ||
1035 | */ | ||
1036 | public function setTag($tag) | ||
1037 | { | ||
1038 | $this->tag = (string) $tag; | ||
1039 | return $this; | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | // -- end | ||
diff --git a/inc/store/file.class.php b/inc/store/file.class.php deleted file mode 100644 index ad20937d..00000000 --- a/inc/store/file.class.php +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
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 deleted file mode 100644 index 21081608..00000000 --- a/inc/store/sqlite.class.php +++ /dev/null | |||
@@ -1,202 +0,0 @@ | |||
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->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | ||
21 | } | ||
22 | |||
23 | private function getHandle() { | ||
24 | return $this->handle; | ||
25 | } | ||
26 | |||
27 | public function isInstalled() { | ||
28 | $sql = "SELECT name FROM sqlite_sequence WHERE name=?"; | ||
29 | $query = $this->executeQuery($sql, array('config')); | ||
30 | $hasConfig = $query->fetchAll(); | ||
31 | |||
32 | if (count($hasConfig) == 0) | ||
33 | return FALSE; | ||
34 | |||
35 | if (!$this->getLogin() || !$this->getPassword()) | ||
36 | return FALSE; | ||
37 | |||
38 | return TRUE; | ||
39 | } | ||
40 | |||
41 | public function install($login, $password) { | ||
42 | $this->getHandle()->exec('CREATE TABLE IF NOT EXISTS "config" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE , "name" VARCHAR UNIQUE, "value" BLOB)'); | ||
43 | |||
44 | $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)'); | ||
45 | |||
46 | if (!$this->getLogin()) { | ||
47 | $sql_login = 'INSERT INTO config ( name, value ) VALUES (?, ?)'; | ||
48 | $params_login = array('login', $login); | ||
49 | $query = $this->executeQuery($sql_login, $params_login); | ||
50 | } | ||
51 | |||
52 | if (!$this->getPassword()) { | ||
53 | $sql_pass = 'INSERT INTO config ( name, value ) VALUES (?, ?)'; | ||
54 | $params_pass = array('password', $password); | ||
55 | $query = $this->executeQuery($sql_pass, $params_pass); | ||
56 | } | ||
57 | |||
58 | return TRUE; | ||
59 | } | ||
60 | |||
61 | public function getLogin() { | ||
62 | $sql = "SELECT value FROM config WHERE name=?"; | ||
63 | $query = $this->executeQuery($sql, array('login')); | ||
64 | $login = $query->fetchAll(); | ||
65 | |||
66 | return isset($login[0]['value']) ? $login[0]['value'] : FALSE; | ||
67 | } | ||
68 | |||
69 | public function getPassword() { | ||
70 | $sql = "SELECT value FROM config WHERE name=?"; | ||
71 | $query = $this->executeQuery($sql, array('password')); | ||
72 | $pass = $query->fetchAll(); | ||
73 | |||
74 | return isset($pass[0]['value']) ? $pass[0]['value'] : FALSE; | ||
75 | } | ||
76 | |||
77 | public function updatePassword($password) | ||
78 | { | ||
79 | $sql_update = "UPDATE config SET value=? WHERE name='password'"; | ||
80 | $params_update = array($password); | ||
81 | $query = $this->executeQuery($sql_update, $params_update); | ||
82 | } | ||
83 | |||
84 | private function executeQuery($sql, $params) { | ||
85 | try | ||
86 | { | ||
87 | $query = $this->getHandle()->prepare($sql); | ||
88 | $query->execute($params); | ||
89 | return $query; | ||
90 | } | ||
91 | catch (Exception $e) | ||
92 | { | ||
93 | logm('execute query error : '.$e->getMessage()); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | public function retrieveAll() { | ||
98 | $sql = "SELECT * FROM entries ORDER BY id"; | ||
99 | $query = $this->executeQuery($sql, array()); | ||
100 | $entries = $query->fetchAll(); | ||
101 | |||
102 | return $entries; | ||
103 | } | ||
104 | |||
105 | public function retrieveOneById($id) { | ||
106 | parent::__construct(); | ||
107 | |||
108 | $entry = NULL; | ||
109 | $sql = "SELECT * FROM entries WHERE id=?"; | ||
110 | $params = array(intval($id)); | ||
111 | $query = $this->executeQuery($sql, $params); | ||
112 | $entry = $query->fetchAll(); | ||
113 | |||
114 | return $entry[0]; | ||
115 | } | ||
116 | |||
117 | public function getEntriesByView($view) { | ||
118 | parent::__construct(); | ||
119 | |||
120 | switch ($_SESSION['sort']) | ||
121 | { | ||
122 | case 'ia': | ||
123 | $order = 'ORDER BY id'; | ||
124 | break; | ||
125 | case 'id': | ||
126 | $order = 'ORDER BY id DESC'; | ||
127 | break; | ||
128 | case 'ta': | ||
129 | $order = 'ORDER BY lower(title)'; | ||
130 | break; | ||
131 | case 'td': | ||
132 | $order = 'ORDER BY lower(title) DESC'; | ||
133 | break; | ||
134 | default: | ||
135 | $order = 'ORDER BY id'; | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | switch ($view) | ||
140 | { | ||
141 | case 'archive': | ||
142 | $sql = "SELECT * FROM entries WHERE is_read=? " . $order; | ||
143 | $params = array(-1); | ||
144 | break; | ||
145 | case 'fav' : | ||
146 | $sql = "SELECT * FROM entries WHERE is_fav=? " . $order; | ||
147 | $params = array(-1); | ||
148 | break; | ||
149 | default: | ||
150 | $sql = "SELECT * FROM entries WHERE is_read=? " . $order; | ||
151 | $params = array(0); | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | $query = $this->executeQuery($sql, $params); | ||
156 | $entries = $query->fetchAll(); | ||
157 | |||
158 | return $entries; | ||
159 | } | ||
160 | |||
161 | public function add($url, $title, $content) { | ||
162 | parent::__construct(); | ||
163 | $sql_action = 'INSERT INTO entries ( url, title, content ) VALUES (?, ?, ?)'; | ||
164 | $params_action = array($url, $title, $content); | ||
165 | $query = $this->executeQuery($sql_action, $params_action); | ||
166 | return $query; | ||
167 | } | ||
168 | |||
169 | public function deleteById($id) { | ||
170 | parent::__construct(); | ||
171 | $sql_action = "DELETE FROM entries WHERE id=?"; | ||
172 | $params_action = array($id); | ||
173 | $query = $this->executeQuery($sql_action, $params_action); | ||
174 | return $query; | ||
175 | } | ||
176 | |||
177 | public function favoriteById($id) { | ||
178 | parent::__construct(); | ||
179 | $sql_action = "UPDATE entries SET is_fav=~is_fav WHERE id=?"; | ||
180 | $params_action = array($id); | ||
181 | $query = $this->executeQuery($sql_action, $params_action); | ||
182 | } | ||
183 | |||
184 | public function archiveById($id) { | ||
185 | parent::__construct(); | ||
186 | $sql_action = "UPDATE entries SET is_read=~is_read WHERE id=?"; | ||
187 | $params_action = array($id); | ||
188 | $query = $this->executeQuery($sql_action, $params_action); | ||
189 | } | ||
190 | |||
191 | public function getLastId() { | ||
192 | parent::__construct(); | ||
193 | return $this->getHandle()->lastInsertId(); | ||
194 | } | ||
195 | |||
196 | public function updateContentById($id) { | ||
197 | parent::__construct(); | ||
198 | $sql_update = "UPDATE entries SET content=? WHERE id=?"; | ||
199 | $params_update = array($content, $id); | ||
200 | $query = $this->executeQuery($sql_update, $params_update); | ||
201 | } | ||
202 | } | ||
diff --git a/inc/store/store.class.php b/inc/store/store.class.php deleted file mode 100644 index dd7d4cfe..00000000 --- a/inc/store/store.class.php +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
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 getLogin() { | ||
17 | |||
18 | } | ||
19 | |||
20 | public function getPassword() { | ||
21 | |||
22 | } | ||
23 | |||
24 | public function add() { | ||
25 | |||
26 | } | ||
27 | |||
28 | public function retrieveAll() { | ||
29 | |||
30 | } | ||
31 | |||
32 | public function retrieveOneById($id) { | ||
33 | |||
34 | } | ||
35 | |||
36 | public function retrieveOneByURL($url) { | ||
37 | |||
38 | } | ||
39 | |||
40 | public function deleteById($id) { | ||
41 | |||
42 | } | ||
43 | |||
44 | public function favoriteById($id) { | ||
45 | |||
46 | } | ||
47 | |||
48 | public function archiveById($id) { | ||
49 | |||
50 | } | ||
51 | |||
52 | public function getEntriesByView($view) { | ||
53 | |||
54 | } | ||
55 | |||
56 | public function getLastId() { | ||
57 | |||
58 | } | ||
59 | |||
60 | public function updateContentById($id) { | ||
61 | |||
62 | } | ||
63 | } | ||
@@ -8,83 +8,57 @@ | |||
8 | * @license http://www.wtfpl.net/ see COPYING file | 8 | * @license http://www.wtfpl.net/ see COPYING file |
9 | */ | 9 | */ |
10 | 10 | ||
11 | include dirname(__FILE__).'/inc/config.php'; | 11 | include dirname(__FILE__).'/inc/poche/config.inc.php'; |
12 | 12 | ||
13 | myTool::initPhp(); | 13 | # Parse GET & REFERER vars |
14 | 14 | $referer = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']; | |
15 | # XSRF protection with token | 15 | $view = Tools::checkVar('view', 'home'); |
16 | if (!empty($_POST)) { | 16 | $action = Tools::checkVar('action'); |
17 | if (!Session::isToken($_POST['token'])) { | 17 | $id = Tools::checkVar('id'); |
18 | die('Wrong token.'); | 18 | $_SESSION['sort'] = Tools::checkVar('sort', 'id'); |
19 | } | 19 | $url = new Url((isset ($_GET['url'])) ? $_GET['url'] : ''); |
20 | unset($_SESSION['tokens']); | ||
21 | } | ||
22 | |||
23 | $ref = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']; | ||
24 | 20 | ||
21 | # poche actions | ||
25 | if (isset($_GET['login'])) { | 22 | if (isset($_GET['login'])) { |
26 | // Login | 23 | # hello you |
27 | if (!empty($_POST['login']) && !empty($_POST['password'])) { | 24 | $poche->login($referer); |
28 | if (Session::login($_SESSION['login'], $_SESSION['pass'], $_POST['login'], encode_string($_POST['password'] . $_POST['login']))) { | ||
29 | logm('login successful'); | ||
30 | $msg->add('s', 'welcome in your poche!'); | ||
31 | if (!empty($_POST['longlastingsession'])) { | ||
32 | $_SESSION['longlastingsession'] = 31536000; | ||
33 | $_SESSION['expires_on'] = time() + $_SESSION['longlastingsession']; | ||
34 | session_set_cookie_params($_SESSION['longlastingsession']); | ||
35 | } else { | ||
36 | session_set_cookie_params(0); // when browser closes | ||
37 | } | ||
38 | session_regenerate_id(true); | ||
39 | |||
40 | MyTool::redirect($ref); | ||
41 | } | ||
42 | logm('login failed'); | ||
43 | die("Login failed !"); | ||
44 | } else { | ||
45 | logm('login failed'); | ||
46 | } | ||
47 | } | 25 | } |
48 | elseif (isset($_GET['logout'])) { | 26 | elseif (isset($_GET['logout'])) { |
49 | logm('logout'); | 27 | # see you soon ! |
50 | Session::logout(); | 28 | $poche->logout(); |
51 | MyTool::redirect(); | ||
52 | } | 29 | } |
53 | elseif (isset($_GET['config'])) { | 30 | elseif (isset($_GET['config'])) { |
54 | if (isset($_POST['password']) && isset($_POST['password_repeat'])) { | 31 | # Update password |
55 | if ($_POST['password'] == $_POST['password_repeat'] && $_POST['password'] != "") { | 32 | $poche->updatePassword(); |
56 | logm('password updated'); | 33 | } |
57 | if (!DEMO) { | 34 | elseif (isset($_GET['import'])) { |
58 | $store->updatePassword(encode_string($_POST['password'] . $_SESSION['login'])); | 35 | $import = $poche->import($_GET['from']); |
59 | $msg->add('s', 'your password has been updated'); | 36 | } |
60 | } | 37 | elseif (isset($_GET['export'])) { |
61 | else { | 38 | $poche->export(); |
62 | $msg->add('i', 'in demo mode, you can\'t update password'); | ||
63 | } | ||
64 | } | ||
65 | else | ||
66 | $msg->add('e', 'your password can\'t be empty and you have to repeat it in the second field'); | ||
67 | } | ||
68 | } | 39 | } |
69 | 40 | ||
70 | # Traitement des paramètres et déclenchement des actions | 41 | # vars to send to templates |
71 | $view = (isset ($_REQUEST['view'])) ? htmlentities($_REQUEST['view']) : 'index'; | 42 | $tpl_vars = array( |
72 | $full_head = (isset ($_REQUEST['full_head'])) ? htmlentities($_REQUEST['full_head']) : 'yes'; | 43 | 'referer' => $referer, |
73 | $action = (isset ($_REQUEST['action'])) ? htmlentities($_REQUEST['action']) : ''; | 44 | 'view' => $view, |
74 | $_SESSION['sort'] = (isset ($_REQUEST['sort'])) ? htmlentities($_REQUEST['sort']) : 'id'; | 45 | 'poche_url' => Tools::getPocheUrl(), |
75 | $id = (isset ($_REQUEST['id'])) ? htmlspecialchars($_REQUEST['id']) : ''; | 46 | 'title' => _('poche, a read it later open source system'), |
76 | $url = (isset ($_GET['url'])) ? $_GET['url'] : ''; | 47 | 'token' => Session::getToken(), |
77 | 48 | ); | |
78 | $tpl->assign('isLogged', Session::isLogged()); | ||
79 | $tpl->assign('referer', $ref); | ||
80 | $tpl->assign('view', $view); | ||
81 | $tpl->assign('poche_url', myTool::getUrl()); | ||
82 | $tpl->assign('title', 'poche, a read it later open source system'); | ||
83 | 49 | ||
84 | if (Session::isLogged()) { | 50 | if (Session::isLogged()) { |
85 | action_to_do($action, $url, $id); | 51 | $poche->action($action, $url, $id); |
86 | display_view($view, $id, $full_head); | 52 | $tpl_file = Tools::getTplFile($view); |
53 | $tpl_vars = array_merge($tpl_vars, $poche->displayView($view, $id)); | ||
87 | } | 54 | } |
88 | else { | 55 | else { |
89 | $tpl->draw('login'); | 56 | $tpl_file = 'login.twig'; |
90 | } | 57 | } |
58 | |||
59 | # because messages can be added in $poche->action(), we have to add this entry now (we can add it before) | ||
60 | $messages = $poche->messages->display('all', FALSE); | ||
61 | $tpl_vars = array_merge($tpl_vars, array('messages' => $messages)); | ||
62 | |||
63 | # display poche | ||
64 | echo $poche->tpl->render($tpl_file, $tpl_vars); \ No newline at end of file | ||
diff --git a/install/mysql.sql b/install/mysql.sql new file mode 100644 index 00000000..cb232a84 --- /dev/null +++ b/install/mysql.sql | |||
@@ -0,0 +1,34 @@ | |||
1 | CREATE TABLE IF NOT EXISTS `config` ( | ||
2 | `id` int(11) NOT NULL AUTO_INCREMENT, | ||
3 | `name` varchar(255) NOT NULL, | ||
4 | `value` varchar(255) NOT NULL, | ||
5 | PRIMARY KEY (`id`) | ||
6 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; | ||
7 | |||
8 | CREATE TABLE IF NOT EXISTS `entries` ( | ||
9 | `id` int(11) NOT NULL AUTO_INCREMENT, | ||
10 | `title` varchar(255) NOT NULL, | ||
11 | `url` varchar(255) NOT NULL, | ||
12 | `is_read` tinyint(1) NOT NULL, | ||
13 | `is_fav` tinyint(1) NOT NULL, | ||
14 | `content` blob NOT NULL, | ||
15 | `user_id` int(11) NOT NULL, | ||
16 | PRIMARY KEY (`id`) | ||
17 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; | ||
18 | |||
19 | CREATE TABLE IF NOT EXISTS `users` ( | ||
20 | `id` int(11) NOT NULL AUTO_INCREMENT, | ||
21 | `username` varchar(255) NOT NULL, | ||
22 | `password` varchar(255) NOT NULL, | ||
23 | `name` int(255) NOT NULL, | ||
24 | `email` varchar(255) NOT NULL, | ||
25 | PRIMARY KEY (`id`) | ||
26 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; | ||
27 | |||
28 | CREATE TABLE IF NOT EXISTS `users_config` ( | ||
29 | `id` int(11) NOT NULL AUTO_INCREMENT, | ||
30 | `user_id` int(11) NOT NULL, | ||
31 | `name` varchar(255) NOT NULL, | ||
32 | `value` varchar(255) NOT NULL, | ||
33 | PRIMARY KEY (`id`) | ||
34 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; \ No newline at end of file | ||
diff --git a/db/poche.sqlite b/install/poche.sqlite index 2aee61f4..c268223d 100755 --- a/db/poche.sqlite +++ b/install/poche.sqlite | |||
Binary files differ | |||
diff --git a/install/postgres.sql b/install/postgres.sql new file mode 100644 index 00000000..9e0e8276 --- /dev/null +++ b/install/postgres.sql | |||
@@ -0,0 +1,30 @@ | |||
1 | CREATE TABLE config ( | ||
2 | id bigserial primary key, | ||
3 | name varchar(255) NOT NULL, | ||
4 | value varchar(255) NOT NULL | ||
5 | ); | ||
6 | |||
7 | CREATE TABLE entries ( | ||
8 | id bigserial primary key, | ||
9 | title varchar(255) NOT NULL, | ||
10 | url varchar(255) NOT NULL, | ||
11 | is_read boolean DEFAULT false, | ||
12 | is_fav boolean DEFAULT false, | ||
13 | content TEXT, | ||
14 | user_id integer NOT NULL | ||
15 | ); | ||
16 | |||
17 | CREATE TABLE users ( | ||
18 | id bigserial primary key, | ||
19 | username varchar(255) NOT NULL, | ||
20 | password varchar(255) NOT NULL, | ||
21 | name varchar(255) NOT NULL, | ||
22 | email varchar(255) NOT NULL | ||
23 | ); | ||
24 | |||
25 | CREATE TABLE users_config ( | ||
26 | id bigserial primary key, | ||
27 | user_id integer NOT NULL, | ||
28 | name varchar(255) NOT NULL, | ||
29 | value varchar(255) NOT NULL | ||
30 | ); \ No newline at end of file | ||
diff --git a/install/update_sqlite_from_0_to_1.php b/install/update_sqlite_from_0_to_1.php new file mode 100644 index 00000000..299abf48 --- /dev/null +++ b/install/update_sqlite_from_0_to_1.php | |||
@@ -0,0 +1,72 @@ | |||
1 | <?php | ||
2 | # import script to upgrade from poche 0.3 | ||
3 | $db_path = 'sqlite:../db/poche.sqlite'; | ||
4 | $handle = new PDO($db_path); | ||
5 | $handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | ||
6 | |||
7 | # Requêtes à exécuter pour mettre à jour poche.sqlite en 1.x | ||
8 | |||
9 | # ajout d'un champ user_id sur la table entries | ||
10 | $sql = 'ALTER TABLE entries RENAME TO tempEntries;'; | ||
11 | $query = $handle->prepare($sql); | ||
12 | $query->execute(); | ||
13 | |||
14 | $sql = 'CREATE TABLE entries (id INTEGER PRIMARY KEY, title TEXT, url TEXT, is_read NUMERIC DEFAULT 0, is_fav NUMERIC DEFAULT 0, content BLOB, user_id NUMERIC);'; | ||
15 | $query = $handle->prepare($sql); | ||
16 | $query->execute(); | ||
17 | |||
18 | $sql = 'INSERT INTO entries (id, title, url, is_read, is_fav, content) SELECT id, title, url, is_read, is_fav, content FROM tempEntries;'; | ||
19 | $query = $handle->prepare($sql); | ||
20 | $query->execute(); | ||
21 | |||
22 | # Update tout pour mettre user_id = 1 | ||
23 | $sql = 'UPDATE entries SET user_id = 1;'; | ||
24 | $query = $handle->prepare($sql); | ||
25 | $query->execute(); | ||
26 | |||
27 | # Changement des flags pour les lus / favoris | ||
28 | $sql = 'UPDATE entries SET is_read = 1 WHERE is_read = -1;'; | ||
29 | $query = $handle->prepare($sql); | ||
30 | $query->execute(); | ||
31 | |||
32 | $sql = 'UPDATE entries SET is_fav = 1 WHERE is_fav = -1;'; | ||
33 | $query = $handle->prepare($sql); | ||
34 | $query->execute(); | ||
35 | |||
36 | # Création de la table users | ||
37 | $sql = 'CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT, password TEXT, name TEXT, email TEXT);'; | ||
38 | $query = $handle->prepare($sql); | ||
39 | $query->execute(); | ||
40 | |||
41 | $sql = 'INSERT INTO users (username) SELECT value FROM config WHERE name = "login";'; | ||
42 | $query = $handle->prepare($sql); | ||
43 | $query->execute(); | ||
44 | |||
45 | $sql = "UPDATE users SET password = (SELECT value FROM config WHERE name = 'password')"; | ||
46 | $query = $handle->prepare($sql); | ||
47 | $query->execute(); | ||
48 | |||
49 | # Création de la table users_config | ||
50 | $sql = 'CREATE TABLE users_config (id INTEGER PRIMARY KEY, user_id NUMERIC, name TEXT, value TEXT);'; | ||
51 | $query = $handle->prepare($sql); | ||
52 | $query->execute(); | ||
53 | |||
54 | $sql = 'INSERT INTO users_config (user_id, name, value) VALUES (1, "pager", "10");'; | ||
55 | $query = $handle->prepare($sql); | ||
56 | $query->execute(); | ||
57 | |||
58 | $sql = 'INSERT INTO users_config (user_id, name, value) VALUES (1, "language", "en_EN.UTF8");'; | ||
59 | $query = $handle->prepare($sql); | ||
60 | $query->execute(); | ||
61 | |||
62 | # Suppression de la table temporaire | ||
63 | $sql = 'DROP TABLE tempEntries;'; | ||
64 | $query = $handle->prepare($sql); | ||
65 | $query->execute(); | ||
66 | |||
67 | # Vidage de la table de config | ||
68 | $sql = 'DELETE FROM config;'; | ||
69 | $query = $handle->prepare($sql); | ||
70 | $query->execute(); | ||
71 | |||
72 | echo 'welcome to poche 1.0 !'; \ No newline at end of file | ||
diff --git a/js/jquery-1.9.1.min.js b/js/jquery-1.9.1.min.js deleted file mode 100644 index 006e9531..00000000 --- a/js/jquery-1.9.1.min.js +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | /*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license | ||
2 | //@ sourceMappingURL=jquery.min.map | ||
3 | */(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.getAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav></:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj; | ||
4 | return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getByName=at(function(e){e.id=x+0,e.innerHTML="<a name='"+x+"'></a><div name='"+x+"'></div>",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").length&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(null,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&>(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Nt=/^(?:checkbox|radio)$/i,Ct=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:b.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.test(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l) | ||
5 | }b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=ln(e,t),Pt.detach()),Gt[e]=n),n}function ln(e,t){var n=b(t.createElement(e)).appendTo(t.body),r=b.css(n[0],"display");return n.remove(),r}b.each(["height","width"],function(e,n){b.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(b.css(e,"display"))?b.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,i),i):0)}}}),b.support.opacity||(b.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=b.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===b.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),b(function(){b.support.reliableMarginRight||(b.cssHooks.marginRight={get:function(e,n){return n?b.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!b.support.pixelPosition&&b.fn.position&&b.each(["top","left"],function(e,n){b.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?b(e).position()[n]+"px":r):t}}})}),b.expr&&b.expr.filters&&(b.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!b.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||b.css(e,"display"))},b.expr.filters.visible=function(e){return!b.expr.filters.hidden(e)}),b.each({margin:"",padding:"",border:"Width"},function(e,t){b.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(b.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;b.fn.extend({serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=b.prop(this,"elements");return e?b.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!b(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Nt.test(e))}).map(function(e,t){var n=b(this).val();return null==n?null:b.isArray(n)?b.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),b.param=function(e,n){var r,i=[],o=function(e,t){t=b.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=b.ajaxSettings&&b.ajaxSettings.traditional),b.isArray(e)||e.jquery&&!b.isPlainObject(e))b.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(b.isArray(t))b.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==b.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}b.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){b.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),b.fn.hover=function(e,t){return this.mouseenter(e).mouseleave(t||e)};var mn,yn,vn=b.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Nn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Cn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=b.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=a.href}catch(Ln){yn=o.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(b.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(u){var l;return o[u]=!0,b.each(e[u]||[],function(e,u){var c=u(n,r,i);return"string"!=typeof c||a||o[c]?a?!(l=c):t:(n.dataTypes.unshift(c),s(c),!1)}),l}return s(n.dataTypes[0])||!o["*"]&&s("*")}function Mn(e,n){var r,i,o=b.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&b.extend(!0,e,r),e}b.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,u=e.indexOf(" ");return u>=0&&(i=e.slice(u,e.length),e=e.slice(0,u)),b.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&b.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?b("<div>").append(b.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},b.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){b.fn[t]=function(e){return this.on(t,e)}}),b.each(["get","post"],function(e,n){b[n]=function(e,r,i,o){return b.isFunction(r)&&(o=o||i,i=r,r=t),b.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),b.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Nn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Mn(Mn(e,b.ajaxSettings),t):Mn(b.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,u,l,c,p=b.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?b(f):b.event,h=b.Deferred(),g=b.Callbacks("once memory"),m=p.statusCode||{},y={},v={},x=0,T="canceled",N={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)m[t]=[m[t],e[t]];else N.always(e[N.status]);return this},abort:function(e){var t=e||T;return l&&l.abort(t),k(0,t),this}};if(h.promise(N).complete=g.add,N.success=N.done,N.error=N.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=b.trim(p.dataType||"*").toLowerCase().match(w)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?80:443))==(mn[3]||("http:"===mn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=b.param(p.data,p.traditional)),qn(An,p,n,N),2===x)return N;u=p.global,u&&0===b.active++&&b.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Cn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(b.lastModified[o]&&N.setRequestHeader("If-Modified-Since",b.lastModified[o]),b.etag[o]&&N.setRequestHeader("If-None-Match",b.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&N.setRequestHeader("Content-Type",p.contentType),N.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)N.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,N,p)===!1||2===x))return N.abort();T="abort";for(i in{success:1,error:1,complete:1})N[i](p[i]);if(l=qn(jn,p,n,N)){N.readyState=1,u&&d.trigger("ajaxSend",[N,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){N.abort("timeout")},p.timeout));try{x=1,l.send(y,k)}catch(C){if(!(2>x))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,C=n;2!==x&&(x=2,s&&clearTimeout(s),l=t,a=i||"",N.readyState=e>0?4:0,r&&(w=_n(p,N,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=N.getResponseHeader("Last-Modified"),T&&(b.lastModified[o]=T),T=N.getResponseHeader("etag"),T&&(b.etag[o]=T)),204===e?(c=!0,C="nocontent"):304===e?(c=!0,C="notmodified"):(c=Fn(p,w),C=c.state,y=c.data,v=c.error,c=!v)):(v=C,(e||!C)&&(C="error",0>e&&(e=0))),N.status=e,N.statusText=(n||C)+"",c?h.resolveWith(f,[y,C,N]):h.rejectWith(f,[N,C,v]),N.statusCode(m),m=t,u&&d.trigger(c?"ajaxSuccess":"ajaxError",[N,p,c?y:v]),g.fireWith(f,[N,C]),u&&(d.trigger("ajaxComplete",[N,p]),--b.active||b.event.trigger("ajaxStop")))}return N},getScript:function(e,n){return b.get(e,t,n,"script")},getJSON:function(e,t,n){return b.get(e,t,n,"json")}});function _n(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(s in c)s in r&&(n[c[s]]=r[s]);while("*"===l[0])l.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in u)if(u[s]&&u[s].test(o)){l.unshift(s);break}if(l[0]in r)a=l[0];else{for(s in r){if(!l[0]||e.converters[s+" "+l[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function Fn(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u[1])for(i in e.converters)a[i.toLowerCase()]=e.converters[i];for(;r=u[++s];)if("*"!==r){if("*"!==l&&l!==r){if(i=a[l+" "+r]||a["* "+r],!i)for(n in a)if(o=n.split(" "),o[1]===r&&(i=a[l+" "+o[0]]||a["* "+o[0]])){i===!0?i=a[n]:a[n]!==!0&&(r=o[0],u.splice(s--,0,r));break}if(i!==!0)if(i&&e["throws"])t=i(t);else try{t=i(t)}catch(c){return{state:"parsererror",error:i?c:"No conversion from "+l+" to "+r}}}l=r}return{state:"success",data:t}}b.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return b.globalEval(e),e}}}),b.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),b.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=o.head||b("head")[0]||o.documentElement;return{send:function(t,i){n=o.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var On=[],Bn=/(=)\?(?=&|$)|\?\?/;b.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=On.pop()||b.expando+"_"+vn++;return this[e]=!0,e}}),b.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=b.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||b.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,On.push(o)),s&&b.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}b.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=b.ajaxSettings.xhr(),b.support.cors=!!Rn&&"withCredentials"in Rn,Rn=b.support.ajax=!!Rn,Rn&&b.ajaxTransport(function(n){if(!n.crossDomain||b.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=b.noop,$n&&delete Pn[a]),i)4!==u.readyState&&u.abort();else{p={},s=u.status,l=u.getAllResponseHeaders(),"string"==typeof u.responseText&&(p.text=u.responseText);try{c=u.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,l)},n.async?4===u.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},b(e).unload($n)),Pn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+x+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=Yn.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(b.cssNumber[e]?"":"px"),"px"!==r&&s){s=b.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,b.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?s+(o[1]+1)*n:n}return i}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=b.now()}function Zn(e,t){b.each(t,function(t,n){var r=(Qn[t]||[]).concat(Qn["*"]),i=0,o=r.length;for(;o>i;i++)if(r[i].call(e,t,n))return})}function er(e,t,n){var r,i,o=0,a=Gn.length,s=b.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;for(;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:b.extend({},t),opts:b.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=b.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=l.props;for(tr(c,l.opts.specialEasing);a>o;o++)if(r=Gn[o].call(l,e,c,l.opts))return r;return Zn(l,c),b.isFunction(l.opts.start)&&l.opts.start.call(e,l),b.fx.timer(b.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function tr(e,t){var n,r,i,o,a;for(i in e)if(r=b.camelCase(i),o=t[r],n=e[i],b.isArray(n)&&(o=n[1],n=e[i]=n[0]),i!==r&&(e[r]=n,delete e[i]),a=b.cssHooks[r],a&&"expand"in a){n=a.expand(n),delete e[r];for(i in n)i in e||(e[i]=n[i],t[i]=o)}else t[r]=o}b.Animation=b.extend(er,{tweener:function(e,t){b.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,u,l,c,p,f=this,d=e.style,h={},g=[],m=e.nodeType&&nn(e);n.queue||(c=b._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,p=c.empty.fire,c.empty.fire=function(){c.unqueued||p()}),c.unqueued++,f.always(function(){f.always(function(){c.unqueued--,b.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===b.css(e,"display")&&"none"===b.css(e,"float")&&(b.support.inlineBlockNeedsLayout&&"inline"!==un(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",b.support.shrinkWrapBlocks||f.always(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(i in t)if(a=t[i],Vn.exec(a)){if(delete t[i],u=u||"toggle"===a,a===(m?"hide":"show"))continue;g.push(i)}if(o=g.length){s=b._data(e,"fxshow")||b._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?b(e).show():f.done(function(){b(e).hide()}),f.done(function(){var t;b._removeData(e,"fxshow");for(t in h)b.style(e,t,h[t])});for(i=0;o>i;i++)r=g[i],l=f.createTween(r,m?s[r]:0),h[r]=s[r]||b.style(e,r),r in s||(s[r]=l.start,m&&(l.end=l.start,l.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}b.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(b.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?b.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=b.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){b.fx.step[e.prop]?b.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[b.cssProps[e.prop]]||b.cssHooks[e.prop])?b.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},b.each(["toggle","show","hide"],function(e,t){var n=b.fn[t];b.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),b.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=b.isEmptyObject(e),o=b.speed(t,n,r),a=function(){var t=er(this,b.extend({},e),o);a.finish=function(){t.stop(!0)},(i||b._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=b.timers,a=b._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&b.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=b._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=b.timers,a=r?r.length:0;for(n.finish=!0,b.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}b.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){b.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),b.speed=function(e,t,n){var r=e&&"object"==typeof e?b.extend({},e):{complete:n||!n&&t||b.isFunction(e)&&e,duration:e,easing:n&&t||t&&!b.isFunction(t)&&t};return r.duration=b.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in b.fx.speeds?b.fx.speeds[r.duration]:b.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){b.isFunction(r.old)&&r.old.call(this),r.queue&&b.dequeue(this,r.queue)},r},b.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},b.timers=[],b.fx=rr.prototype.init,b.fx.tick=function(){var e,n=b.timers,r=0;for(Xn=b.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||b.fx.stop(),Xn=t},b.fx.timer=function(e){e()&&b.timers.push(e)&&b.fx.start()},b.fx.interval=13,b.fx.start=function(){Un||(Un=setInterval(b.fx.tick,b.fx.interval))},b.fx.stop=function(){clearInterval(Un),Un=null},b.fx.speeds={slow:600,fast:200,_default:400},b.fx.step={},b.expr&&b.expr.filters&&(b.expr.filters.animated=function(e){return b.grep(b.timers,function(t){return e===t.elem}).length}),b.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){b.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,b.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},b.offset={setOffset:function(e,t,n){var r=b.css(e,"position");"static"===r&&(e.style.position="relative");var i=b(e),o=i.offset(),a=b.css(e,"top"),s=b.css(e,"left"),u=("absolute"===r||"fixed"===r)&&b.inArray("auto",[a,s])>-1,l={},c={},p,f;u?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),b.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(l.top=t.top-o.top+p),null!=t.left&&(l.left=t.left-o.left+f),"using"in t?t.using.call(e,l):i.css(l)}},b.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===b.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),b.nodeName(e[0],"html")||(n=e.offset()),n.top+=b.css(e[0],"borderTopWidth",!0),n.left+=b.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-b.css(r,"marginTop",!0),left:t.left-n.left-b.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||o.documentElement;while(e&&!b.nodeName(e,"html")&&"static"===b.css(e,"position"))e=e.offsetParent;return e||o.documentElement})}}),b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);b.fn[e]=function(i){return b.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?b(a).scrollLeft():o,r?o:b(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return b.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}b.each({Height:"height",Width:"width"},function(e,n){b.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){b.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return b.access(this,function(n,r,i){var o;return b.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?b.css(n,r,s):b.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=b,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return b})})(window); \ No newline at end of file | ||
diff --git a/js/jquery.masonry.min.js b/js/jquery.masonry.min.js deleted file mode 100644 index 57c081c6..00000000 --- a/js/jquery.masonry.min.js +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | /** | ||
2 | * jQuery Masonry v2.1.08 | ||
3 | * A dynamic layout plugin for jQuery | ||
4 | * The flip-side of CSS Floats | ||
5 | * http://masonry.desandro.com | ||
6 | * | ||
7 | * Licensed under the MIT license. | ||
8 | * Copyright 2012 David DeSandro | ||
9 | */ | ||
10 | (function(e,t,n){"use strict";var r=t.event,i;r.special.smartresize={setup:function(){t(this).bind("resize",r.special.smartresize.handler)},teardown:function(){t(this).unbind("resize",r.special.smartresize.handler)},handler:function(e,t){var n=this,s=arguments;e.type="smartresize",i&&clearTimeout(i),i=setTimeout(function(){r.dispatch.apply(n,s)},t==="execAsap"?0:100)}},t.fn.smartresize=function(e){return e?this.bind("smartresize",e):this.trigger("smartresize",["execAsap"])},t.Mason=function(e,n){this.element=t(n),this._create(e),this._init()},t.Mason.settings={isResizable:!0,isAnimated:!1,animationOptions:{queue:!1,duration:500},gutterWidth:0,isRTL:!1,isFitWidth:!1,containerStyle:{position:"relative"}},t.Mason.prototype={_filterFindBricks:function(e){var t=this.options.itemSelector;return t?e.filter(t).add(e.find(t)):e},_getBricks:function(e){var t=this._filterFindBricks(e).css({position:"absolute"}).addClass("masonry-brick");return t},_create:function(n){this.options=t.extend(!0,{},t.Mason.settings,n),this.styleQueue=[];var r=this.element[0].style;this.originalStyle={height:r.height||""};var i=this.options.containerStyle;for(var s in i)this.originalStyle[s]=r[s]||"";this.element.css(i),this.horizontalDirection=this.options.isRTL?"right":"left";var o=this.element.css("padding-"+this.horizontalDirection),u=this.element.css("padding-top");this.offset={x:o?parseInt(o,10):0,y:u?parseInt(u,10):0},this.isFluid=this.options.columnWidth&&typeof this.options.columnWidth=="function";var a=this;setTimeout(function(){a.element.addClass("masonry")},0),this.options.isResizable&&t(e).bind("smartresize.masonry",function(){a.resize()}),this.reloadItems()},_init:function(e){this._getColumns(),this._reLayout(e)},option:function(e,n){t.isPlainObject(e)&&(this.options=t.extend(!0,this.options,e))},layout:function(e,t){for(var n=0,r=e.length;n<r;n++)this._placeBrick(e[n]);var i={};i.height=Math.max.apply(Math,this.colYs);if(this.options.isFitWidth){var s=0;n=this.cols;while(--n){if(this.colYs[n]!==0)break;s++}i.width=(this.cols-s)*this.columnWidth-this.options.gutterWidth}this.styleQueue.push({$el:this.element,style:i});var o=this.isLaidOut?this.options.isAnimated?"animate":"css":"css",u=this.options.animationOptions,a;for(n=0,r=this.styleQueue.length;n<r;n++)a=this.styleQueue[n],a.$el[o](a.style,u);this.styleQueue=[],t&&t.call(e),this.isLaidOut=!0},_getColumns:function(){var e=this.options.isFitWidth?this.element.parent():this.element,t=e.width();this.columnWidth=this.isFluid?this.options.columnWidth(t):this.options.columnWidth||this.$bricks.outerWidth(!0)||t,this.columnWidth+=this.options.gutterWidth,this.cols=Math.floor((t+this.options.gutterWidth)/this.columnWidth),this.cols=Math.max(this.cols,1)},_placeBrick:function(e){var n=t(e),r,i,s,o,u;r=Math.ceil(n.outerWidth(!0)/this.columnWidth),r=Math.min(r,this.cols);if(r===1)s=this.colYs;else{i=this.cols+1-r,s=[];for(u=0;u<i;u++)o=this.colYs.slice(u,u+r),s[u]=Math.max.apply(Math,o)}var a=Math.min.apply(Math,s),f=0;for(var l=0,c=s.length;l<c;l++)if(s[l]===a){f=l;break}var h={top:a+this.offset.y};h[this.horizontalDirection]=this.columnWidth*f+this.offset.x,this.styleQueue.push({$el:n,style:h});var p=a+n.outerHeight(!0),d=this.cols+1-c;for(l=0;l<d;l++)this.colYs[f+l]=p},resize:function(){var e=this.cols;this._getColumns(),(this.isFluid||this.cols!==e)&&this._reLayout()},_reLayout:function(e){var t=this.cols;this.colYs=[];while(t--)this.colYs.push(0);this.layout(this.$bricks,e)},reloadItems:function(){this.$bricks=this._getBricks(this.element.children())},reload:function(e){this.reloadItems(),this._init(e)},appended:function(e,t,n){if(t){this._filterFindBricks(e).css({top:this.element.height()});var r=this;setTimeout(function(){r._appended(e,n)},1)}else this._appended(e,n)},_appended:function(e,t){var n=this._getBricks(e);this.$bricks=this.$bricks.add(n),this.layout(n,t)},remove:function(e){this.$bricks=this.$bricks.not(e),e.remove()},destroy:function(){this.$bricks.removeClass("masonry-brick").each(function(){this.style.position="",this.style.top="",this.style.left=""});var n=this.element[0].style;for(var r in this.originalStyle)n[r]=this.originalStyle[r];this.element.unbind(".masonry").removeClass("masonry").removeData("masonry"),t(e).unbind(".masonry")}},t.fn.imagesLoaded=function(e){function u(){e.call(n,r)}function a(e){var n=e.target;n.src!==s&&t.inArray(n,o)===-1&&(o.push(n),--i<=0&&(setTimeout(u),r.unbind(".imagesLoaded",a)))}var n=this,r=n.find("img").add(n.filter("img")),i=r.length,s="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==",o=[];return i||u(),r.bind("load.imagesLoaded error.imagesLoaded",a).each(function(){var e=this.src;this.src=s,this.src=e}),n};var s=function(t){e.console&&e.console.error(t)};t.fn.masonry=function(e){if(typeof e=="string"){var n=Array.prototype.slice.call(arguments,1);this.each(function(){var r=t.data(this,"masonry");if(!r){s("cannot call methods on masonry prior to initialization; attempted to call method '"+e+"'");return}if(!t.isFunction(r[e])||e.charAt(0)==="_"){s("no such method '"+e+"' for masonry instance");return}r[e].apply(r,n)})}else this.each(function(){var n=t.data(this,"masonry");n?(n.option(e||{}),n._init()):t.data(this,"masonry",new t.Mason(e,this))});return this}})(window,jQuery); \ No newline at end of file | ||
diff --git a/js/poche.js b/js/poche.js deleted file mode 100644 index 97d9911d..00000000 --- a/js/poche.js +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
1 | function toggle_favorite(element, id) { | ||
2 | $(element).toggleClass('fav-off'); | ||
3 | $.ajax ({ | ||
4 | url: "index.php?action=toggle_fav", | ||
5 | data:{id:id} | ||
6 | }); | ||
7 | } | ||
8 | |||
9 | function toggle_archive(element, id, view_article) { | ||
10 | $(element).toggleClass('archive-off'); | ||
11 | $.ajax ({ | ||
12 | url: "index.php?action=toggle_archive", | ||
13 | data:{id:id} | ||
14 | }); | ||
15 | var obj = $('#entry-'+id); | ||
16 | |||
17 | // on vient de la vue de l'article, donc pas de gestion de grille | ||
18 | if (view_article != 1) { | ||
19 | $('#content').masonry('remove',obj); | ||
20 | $('#content').masonry('reloadItems'); | ||
21 | $('#content').masonry('reload'); | ||
22 | } | ||
23 | } | ||
24 | |||
25 | function sort_links(view, sort) { | ||
26 | $.get('index.php', { view: view, sort: sort, full_head: 'no' }, function(data) { | ||
27 | $('#content').html(data); | ||
28 | }); | ||
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/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.mo b/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.mo new file mode 100644 index 00000000..c0d4a9d6 --- /dev/null +++ b/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.mo | |||
Binary files differ | |||
diff --git a/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.po b/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.po new file mode 100644 index 00000000..7f8cf784 --- /dev/null +++ b/locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.po | |||
@@ -0,0 +1,376 @@ | |||
1 | msgid "" | ||
2 | msgstr "" | ||
3 | "Project-Id-Version: poche\n" | ||
4 | "POT-Creation-Date: 2013-08-06 08:35+0100\n" | ||
5 | "PO-Revision-Date: 2013-08-06 08:35+0100\n" | ||
6 | "Last-Translator: Nicolas LÅ“uillet <nicolas.loeuillet@gmail.com>\n" | ||
7 | "Language-Team: poche <support@inthepoche.com>\n" | ||
8 | "Language: Français\n" | ||
9 | "MIME-Version: 1.0\n" | ||
10 | "Content-Type: text/plain; charset=UTF-8\n" | ||
11 | "Content-Transfer-Encoding: 8bit\n" | ||
12 | "X-Generator: Poedit 1.5.4\n" | ||
13 | "X-Poedit-KeywordsList: _;gettext;gettext_noop\n" | ||
14 | "X-Poedit-Basepath: /\n" | ||
15 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" | ||
16 | "X-Poedit-SourceCharset: UTF-8\n" | ||
17 | "X-Poedit-SearchPath-0: /var/www/poche-i18n\n" | ||
18 | |||
19 | #: /var/www/poche-i18n/index.php:43 | ||
20 | msgid "poche, a read it later open source system" | ||
21 | msgstr "poche, a read it later open source system" | ||
22 | |||
23 | #: /var/www/poche-i18n/inc/poche/Poche.class.php:101 | ||
24 | msgid "the link has been added successfully" | ||
25 | msgstr "le lien a été ajouté avec succès" | ||
26 | |||
27 | #: /var/www/poche-i18n/inc/poche/Poche.class.php:104 | ||
28 | msgid "error during insertion : the link wasn't added" | ||
29 | msgstr "erreur durant l'insertion : le lien n'a pas été ajouté" | ||
30 | |||
31 | #: /var/www/poche-i18n/inc/poche/Poche.class.php:109 | ||
32 | msgid "error during fetching content : the link wasn't added" | ||
33 | msgstr "erreur durant la récupération du contenu : le lien n'a pas été ajouté" | ||
34 | |||
35 | #: /var/www/poche-i18n/inc/poche/Poche.class.php:119 | ||
36 | msgid "the link has been deleted successfully" | ||
37 | msgstr "le lien a été supprimé avec succès" | ||
38 | |||
39 | #: /var/www/poche-i18n/inc/poche/Poche.class.php:123 | ||
40 | msgid "the link wasn't deleted" | ||
41 | msgstr "le lien n'a pas été supprimé" | ||
42 | |||
43 | #: /var/www/poche-i18n/inc/poche/Tools.class.php:18 | ||
44 | msgid "Oops, it seems you don't have PHP 5." | ||
45 | msgstr "Oups, il semblerait que PHP 5 ne soit pas installé. " | ||
46 | |||
47 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:32 | ||
48 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:70 | ||
49 | #: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:50 | ||
50 | msgid "config" | ||
51 | msgstr "config" | ||
52 | |||
53 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:46 | ||
54 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:31 | ||
55 | #: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:26 | ||
56 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:34 | ||
57 | msgid "home" | ||
58 | msgstr "accueil" | ||
59 | |||
60 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:54 | ||
61 | #: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:34 | ||
62 | msgid "favorites" | ||
63 | msgstr "favoris" | ||
64 | |||
65 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:62 | ||
66 | #: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:42 | ||
67 | msgid "archive" | ||
68 | msgstr "archives" | ||
69 | |||
70 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:74 | ||
71 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:76 | ||
72 | #: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:54 | ||
73 | #: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:56 | ||
74 | msgid "logout" | ||
75 | msgstr "déconnexion" | ||
76 | |||
77 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:87 | ||
78 | msgid "Bookmarklet" | ||
79 | msgstr "Bookmarklet" | ||
80 | |||
81 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:91 | ||
82 | msgid "" | ||
83 | "Thanks to the bookmarklet, you will be able to easily add a link to your " | ||
84 | "poche." | ||
85 | msgstr "" | ||
86 | "Grâce au bookmarklet, vous pouvez ajouter facilement un lien dans votre " | ||
87 | "poche." | ||
88 | |||
89 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:93 | ||
90 | msgid "Have a look to this documentation:" | ||
91 | msgstr "Jetez un œil à la documentation :" | ||
92 | |||
93 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:97 | ||
94 | msgid "Drag & drop this link to your bookmarks bar and have fun with poche." | ||
95 | msgstr "" | ||
96 | "Glissez / déposez ce lien dans votre barre de favoris de votre navigateur et " | ||
97 | "prenez du bon temps avec poche." | ||
98 | |||
99 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:103 | ||
100 | msgid "poche it!" | ||
101 | msgstr "poche-le !" | ||
102 | |||
103 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:108 | ||
104 | msgid "Updating poche" | ||
105 | msgstr "Mettre à jour poche" | ||
106 | |||
107 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:113 | ||
108 | msgid "your version" | ||
109 | msgstr "votre version" | ||
110 | |||
111 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:119 | ||
112 | msgid "latest stable version" | ||
113 | msgstr "dernière version stable" | ||
114 | |||
115 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:125 | ||
116 | msgid "a more recent stable version is available." | ||
117 | msgstr "une version stable plus récente est disponible." | ||
118 | |||
119 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:128 | ||
120 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:142 | ||
121 | msgid "you are up to date." | ||
122 | msgstr "vous êtes à jour." | ||
123 | |||
124 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:133 | ||
125 | msgid "latest dev version" | ||
126 | msgstr "dernière version de développement" | ||
127 | |||
128 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:139 | ||
129 | msgid "a more recent development version is available." | ||
130 | msgstr "une version de développement plus récente est disponible." | ||
131 | |||
132 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:150 | ||
133 | msgid "Change your password" | ||
134 | msgstr "Modifier votre mot de passe" | ||
135 | |||
136 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:157 | ||
137 | msgid "New password:" | ||
138 | msgstr "Nouveau mot de passe :" | ||
139 | |||
140 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:161 | ||
141 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:171 | ||
142 | #: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:60 | ||
143 | #: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:68 | ||
144 | msgid "Password" | ||
145 | msgstr "Mot de passe" | ||
146 | |||
147 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:167 | ||
148 | msgid "Repeat your new password:" | ||
149 | msgstr "Répétez le nouveau mot de passe :" | ||
150 | |||
151 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:177 | ||
152 | msgid "Update" | ||
153 | msgstr "Mettre à jour" | ||
154 | |||
155 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:193 | ||
156 | msgid "Import" | ||
157 | msgstr "Import" | ||
158 | |||
159 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:197 | ||
160 | msgid "Please execute the import script locally, it can take a very long time." | ||
161 | msgstr "Merci d'exécuter l'import en local, cela peut prendre du temps. " | ||
162 | |||
163 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:201 | ||
164 | msgid "More infos in the official doc:" | ||
165 | msgstr "Plus d'infos sur la documentation officielle :" | ||
166 | |||
167 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:206 | ||
168 | msgid "import from Pocket" | ||
169 | msgstr "l'import depuis Pocket est terminé." | ||
170 | |||
171 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:210 | ||
172 | msgid "import from Readability" | ||
173 | msgstr "l'import depuis Readability est terminé." | ||
174 | |||
175 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:214 | ||
176 | msgid "import from Instapaper" | ||
177 | msgstr "Import depuis Instapaper" | ||
178 | |||
179 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:220 | ||
180 | msgid "Export your poche datas" | ||
181 | msgstr "Exporter vos données de poche" | ||
182 | |||
183 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:224 | ||
184 | msgid "Click here" | ||
185 | msgstr "Cliquez-ici" | ||
186 | |||
187 | #: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:226 | ||
188 | msgid "to export your poche datas." | ||
189 | msgstr "pour exporter vos données de poche." | ||
190 | |||
191 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:46 | ||
192 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:139 | ||
193 | #: /var/www/poche-i18n/cache/30/97/b548692380c89d047a16cec7af79.php:22 | ||
194 | msgid "back to home" | ||
195 | msgstr "retour à l'accueil" | ||
196 | |||
197 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:50 | ||
198 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:147 | ||
199 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:119 | ||
200 | msgid "toggle mark as read" | ||
201 | msgstr "marquer comme lu" | ||
202 | |||
203 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:60 | ||
204 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:157 | ||
205 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:129 | ||
206 | msgid "toggle favorite" | ||
207 | msgstr "favori" | ||
208 | |||
209 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:70 | ||
210 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:167 | ||
211 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:139 | ||
212 | msgid "delete" | ||
213 | msgstr "supprimer" | ||
214 | |||
215 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:82 | ||
216 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:179 | ||
217 | msgid "tweet" | ||
218 | msgstr "tweeter" | ||
219 | |||
220 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:93 | ||
221 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:190 | ||
222 | msgid "email" | ||
223 | msgstr "envoyer par email" | ||
224 | |||
225 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:109 | ||
226 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:125 | ||
227 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:153 | ||
228 | msgid "original" | ||
229 | msgstr "original" | ||
230 | |||
231 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:143 | ||
232 | msgid "back to top" | ||
233 | msgstr "retour en haut de page" | ||
234 | |||
235 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:198 | ||
236 | msgid "this article appears wrong?" | ||
237 | msgstr "cet article s'affiche mal ?" | ||
238 | |||
239 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:200 | ||
240 | msgid "create an issue" | ||
241 | msgstr "créer un ticket" | ||
242 | |||
243 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:202 | ||
244 | msgid "or" | ||
245 | msgstr "ou" | ||
246 | |||
247 | #: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:206 | ||
248 | msgid "contact us by mail" | ||
249 | msgstr "contactez-nous par email" | ||
250 | |||
251 | #: /var/www/poche-i18n/cache/88/8a/ee3b7080c13204391c14947a0c2c.php:22 | ||
252 | msgid "powered by" | ||
253 | msgstr "propulsé par" | ||
254 | |||
255 | #: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:31 | ||
256 | msgid "installation" | ||
257 | msgstr "installation" | ||
258 | |||
259 | #: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:42 | ||
260 | msgid "install your poche" | ||
261 | msgstr "installez votre poche" | ||
262 | |||
263 | #: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:47 | ||
264 | msgid "" | ||
265 | "poche is still not installed. Please fill the below form to install it. " | ||
266 | "Don't hesitate to <a href='http://inthepoche.com/?pages/Documentation'>read " | ||
267 | "the documentation on poche website</a>." | ||
268 | msgstr "" | ||
269 | "poche n'est pas encore installé. Merci de remplir les champs ci-dessous pour " | ||
270 | "l'installer. N'hésitez pas à <a href='http://inthepoche.com/?pages/" | ||
271 | "Documentation'>lire la documentation sur le site de poche</a>." | ||
272 | |||
273 | #: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:53 | ||
274 | #: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:55 | ||
275 | msgid "Login" | ||
276 | msgstr "Nom d'utilisateur" | ||
277 | |||
278 | #: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:67 | ||
279 | msgid "Repeat your password" | ||
280 | msgstr "Répétez votre mot de passe" | ||
281 | |||
282 | #: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:74 | ||
283 | msgid "Install" | ||
284 | msgstr "Installer" | ||
285 | |||
286 | #: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:31 | ||
287 | #: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:42 | ||
288 | msgid "login to your poche" | ||
289 | msgstr "Se connecter à votre poche" | ||
290 | |||
291 | #: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:48 | ||
292 | msgid "you are in demo mode, some features may be disabled." | ||
293 | msgstr "" | ||
294 | "vous êtes en mode démo, certaines fonctionnalités sont peut-être désactivées." | ||
295 | |||
296 | #: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:80 | ||
297 | msgid "Stay signed in" | ||
298 | msgstr "rester connecté" | ||
299 | |||
300 | #: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:86 | ||
301 | msgid "(Do not check on public computers)" | ||
302 | msgstr "(Ã ne pas cocher sur un ordinateur public)" | ||
303 | |||
304 | #: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:93 | ||
305 | msgid "Sign in" | ||
306 | msgstr "" | ||
307 | |||
308 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:55 | ||
309 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:57 | ||
310 | msgid "by date asc" | ||
311 | msgstr "par date asc" | ||
312 | |||
313 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:59 | ||
314 | msgid "by date" | ||
315 | msgstr "par date" | ||
316 | |||
317 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:65 | ||
318 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:67 | ||
319 | msgid "by date desc" | ||
320 | msgstr "par date desc" | ||
321 | |||
322 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:75 | ||
323 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:77 | ||
324 | msgid "by title asc" | ||
325 | msgstr "par titre asc" | ||
326 | |||
327 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:79 | ||
328 | msgid "by title" | ||
329 | msgstr "par titre" | ||
330 | |||
331 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:85 | ||
332 | #: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:87 | ||
333 | msgid "by title desc" | ||
334 | msgstr "par titre desc" | ||
335 | |||
336 | #~ msgid "Please choose between Pocket & Readabilty :" | ||
337 | #~ msgstr "Merci de choisir entre Pocket & Readability :" | ||
338 | |||
339 | #~ msgid "Bye bye Pocket, let's go !" | ||
340 | #~ msgstr "Bye bye Pocket, en route !" | ||
341 | |||
342 | #~ msgid "Bye bye Readability, let's go !" | ||
343 | #~ msgstr "Bye bye Readability, en route !" | ||
344 | |||
345 | #~ msgid "Welcome to poche !" | ||
346 | #~ msgstr "Bienvenue dans poche !" | ||
347 | |||
348 | #~ msgid "Error with the import." | ||
349 | #~ msgstr "Erreur durant l'import." | ||
350 | |||
351 | #~ msgid "Wrong token." | ||
352 | #~ msgstr "Mauvais jeton." | ||
353 | |||
354 | #~ msgid "Login failed !" | ||
355 | #~ msgstr "Connexion échouée." | ||
356 | |||
357 | #~ msgid "your password has been updated" | ||
358 | #~ msgstr "Votre mot de passe a été mis à jour. " | ||
359 | |||
360 | #~ msgid "in demo mode, you can't update password" | ||
361 | #~ msgstr "En mode démo, le mot de passe ne peut être modifié." | ||
362 | |||
363 | #~ msgid "" | ||
364 | #~ "your password can't be empty and you have to repeat it in the second field" | ||
365 | #~ msgstr "" | ||
366 | #~ "Votre mot de passe ne peut être vide et vous devez le répéter dans le " | ||
367 | #~ "second champ." | ||
368 | |||
369 | #~ msgid "error during url preparation : the link wasn't added" | ||
370 | #~ msgstr "erreur durant l'insertion : le lien n'a pas été ajouté" | ||
371 | |||
372 | #~ msgid "error during url preparation : the link is not valid" | ||
373 | #~ msgstr "erreur durant la préparation de l'URL : le lien n'est pas valide" | ||
374 | |||
375 | #~ msgid "TEST" | ||
376 | #~ msgstr "NICOLAS" | ||
diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/phpunit.xml.dist | |||
diff --git a/tpl/_bookmarklet.twig b/tpl/_bookmarklet.twig new file mode 100644 index 00000000..2f3b2d16 --- /dev/null +++ b/tpl/_bookmarklet.twig | |||
@@ -0,0 +1,3 @@ | |||
1 | <script type="text/javascript"> | ||
2 | top["bookmarklet-url@inthepoche.com"]=""+"<!DOCTYPE html>"+"<html>"+"<head>"+"<title>poche it !</title>"+'<link rel="icon" href="{{poche_url}}tpl/img/favicon.ico" />'+"</head>"+"<body>"+"<script>"+"window.onload=function(){"+"window.setTimeout(function(){"+"history.back();"+"},250);"+"};"+"</scr"+"ipt>"+"</body>"+"</html>" | ||
3 | </script> \ No newline at end of file | ||
diff --git a/tpl/_footer.twig b/tpl/_footer.twig new file mode 100644 index 00000000..6891756a --- /dev/null +++ b/tpl/_footer.twig | |||
@@ -0,0 +1,4 @@ | |||
1 | <footer class="w600p center mt3 smaller txtright"> | ||
2 | <p>{% trans "powered by" %} <a href="http://inthepoche.com">poche</a></p> | ||
3 | {% if constant('DEBUG_POCHE') == 1 %}<p><strong>{% trans "debug mode is on so cache is off." %} {% trans "your poche version:" %}{{constant('POCHE_VERSION')}}. {% trans "storage:" %} {{constant('STORAGE')}}</strong></p>{% endif %} | ||
4 | </footer> \ No newline at end of file | ||
diff --git a/tpl/_head.twig b/tpl/_head.twig new file mode 100644 index 00000000..f25f0471 --- /dev/null +++ b/tpl/_head.twig | |||
@@ -0,0 +1,9 @@ | |||
1 | <link rel="shortcut icon" type="image/x-icon" href="./tpl/img/favicon.ico" /> | ||
2 | <link rel="apple-touch-icon-precomposed" sizes="144x144" href="./tpl/img/apple-touch-icon-144x144-precomposed.png"> | ||
3 | <link rel="apple-touch-icon-precomposed" sizes="72x72" href="./tpl/img/apple-touch-icon-72x72-precomposed.png"> | ||
4 | <link rel="apple-touch-icon-precomposed" href="./tpl/img/apple-touch-icon-precomposed.png"> | ||
5 | <link rel="stylesheet" href="./tpl/css/knacss.css" media="all"> | ||
6 | <link rel="stylesheet" href="./tpl/css/style.css" media="all"> | ||
7 | <link rel="stylesheet" href="./tpl/css/style-{{ constant('THEME') }}.css" media="all" title="{{ constant('THEME') }} theme"> | ||
8 | <link rel="stylesheet" href="./tpl/css/messages.css" media="all"> | ||
9 | <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> \ No newline at end of file | ||
diff --git a/tpl/_menu.twig b/tpl/_menu.twig new file mode 100644 index 00000000..699d6a0c --- /dev/null +++ b/tpl/_menu.twig | |||
@@ -0,0 +1,7 @@ | |||
1 | <ul id="links"> | ||
2 | <li><a href="./" {% if view == 'home' %}class="current"{% endif %}>{% trans "home" %}</a></li> | ||
3 | <li><a href="./?view=fav" {% if view == 'fav' %}class="current"{% endif %}>{% trans "favorites" %}</a></li> | ||
4 | <li><a href="./?view=archive" {% if view == 'archive' %}class="current"{% endif %}>{% trans "archive" %}</a></li> | ||
5 | <li><a href="./?view=config" {% if view == 'config' %}class="current"{% endif %}>{% trans "config" %}</a></li> | ||
6 | <li><a href="./?logout" title="{% trans "logout" %}">{% trans "logout" %}</a></li> | ||
7 | </ul> \ No newline at end of file | ||
diff --git a/tpl/_messages.twig b/tpl/_messages.twig new file mode 100644 index 00000000..679aa098 --- /dev/null +++ b/tpl/_messages.twig | |||
@@ -0,0 +1 @@ | |||
{{ messages | raw }} \ No newline at end of file | |||
diff --git a/tpl/_top.twig b/tpl/_top.twig new file mode 100644 index 00000000..ae01cc3f --- /dev/null +++ b/tpl/_top.twig | |||
@@ -0,0 +1,3 @@ | |||
1 | <header class="w600p center mbm"> | ||
2 | <h1><a href="./" title="{% trans "back to home" %}" ><img src="./tpl/img/logo.png" alt="logo poche" /></a></h1> | ||
3 | </header> \ No newline at end of file | ||
diff --git a/tpl/config.html b/tpl/config.html deleted file mode 100644 index 1100d455..00000000 --- a/tpl/config.html +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
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 | |||
7 | <h2>Password</h2> | ||
8 | <form method="post" action="?config" name="loginform"> | ||
9 | <fieldset class="w500p"> | ||
10 | <div class="row"> | ||
11 | <label class="col w150p" for="password">New password</label> | ||
12 | <input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2"> | ||
13 | </div> | ||
14 | <div class="row"> | ||
15 | <label class="col w150p" for="password_repeat">Repeat your new password</label> | ||
16 | <input class="col" type="password" id="password_repeat" name="password_repeat" placeholder="Password" tabindex="3"> | ||
17 | </div> | ||
18 | <div class="row mts txtcenter"> | ||
19 | <button class="bouton" type="submit" tabindex="4">Update</button> | ||
20 | </div> | ||
21 | </fieldset> | ||
22 | <input type="hidden" name="returnurl" value="<?php echo htmlspecialchars($referer);?>"> | ||
23 | <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>"> | ||
24 | </form> | ||
25 | <h2>Export</h2> | ||
26 | <p><a href="?view=export" target="_blank">Click here</a> to export your poche datas.</p> | ||
27 | </div> \ No newline at end of file | ||
diff --git a/tpl/config.twig b/tpl/config.twig new file mode 100644 index 00000000..95d5d8cf --- /dev/null +++ b/tpl/config.twig | |||
@@ -0,0 +1,57 @@ | |||
1 | {% extends "layout.twig" %} | ||
2 | |||
3 | {% block title %}{% trans "config" %}{% endblock %} | ||
4 | {% block menu %} | ||
5 | <ul id="links"> | ||
6 | <li><a href="./" {% if view == 'home' %}class="current"{% endif %}>{% trans "home" %}</a></li> | ||
7 | <li><a href="./?view=fav" {% if view == 'fav' %}class="current"{% endif %}>{% trans "favorites" %}</a></li> | ||
8 | <li><a href="./?view=archive" {% if view == 'archive' %}class="current"{% endif %}>{% trans "archive" %}</a></li> | ||
9 | <li><a href="./?view=config" {% if view == 'config' %}class="current"{% endif %}>{% trans "config" %}</a></li> | ||
10 | <li><a href="./?logout" title="{% trans "logout" %}">{% trans "logout" %}</a></li> | ||
11 | </ul> | ||
12 | {% endblock %} | ||
13 | {% block content %} | ||
14 | <h2>{% trans "Bookmarklet" %}</h2> | ||
15 | <p>{% trans "Thanks to the bookmarklet, you will be able to easily add a link to your poche." %} {% trans "Have a look to this documentation:" %} <a href="http://inthepoche.com/?pages/Documentation">inthepoche.com</a>.</p> | ||
16 | <p>{% trans "Drag & drop this link to your bookmarks bar and have fun with poche." %}</p> | ||
17 | <p class="txtcenter"><a ondragend="this.click();" style="cursor: move; border: 1px dashed grey; background: white; padding: 5px;" title="i am a bookmarklet, use me !" href="javascript:if(top['bookmarklet-url@inthepoche.com']){top['bookmarklet-url@inthepoche.com'];}else{(function(){var%20url%20=%20location.href%20||%20url;window.open('{{ poche_url }}?action=add&url='%20+%20btoa(url),'_self');})();void(0);}">{% trans "poche it!" %}</a></p> | ||
18 | |||
19 | <h2>{% trans "Updating poche" %}</h2> | ||
20 | <p><ul> | ||
21 | <li>{% trans "your version" %} : <strong>{{ constant('POCHE_VERSION') }}</strong></li> | ||
22 | <li>{% trans "latest stable version" %} : {{ prod }}. {% if compare_prod == -1 %}<strong><a href="http://inthepoche.com/?pages/T%C3%A9l%C3%A9charger-poche">{% trans "a more recent stable version is available." %}</a></strong>{% else %}{% trans "you are up to date." %}{% endif %}</li> | ||
23 | <li>{% trans "latest dev version" %} : {{ dev }}. {% if compare_dev == -1 %}<strong><a href="http://inthepoche.com/?pages/T%C3%A9l%C3%A9charger-poche">{% trans "a more recent development version is available." %}</a></strong>{% else %}{% trans "you are up to date." %}{% endif %}</li> | ||
24 | </ul> | ||
25 | </p> | ||
26 | |||
27 | <h2>{% trans "Change your password" %}</h2> | ||
28 | <form method="post" action="?config" name="loginform"> | ||
29 | <fieldset class="w500p"> | ||
30 | <div class="row"> | ||
31 | <label class="col w150p" for="password">{% trans "New password:" %}</label> | ||
32 | <input class="col" type="password" id="password" name="password" placeholder="{% trans "Password" %}" tabindex="2"> | ||
33 | </div> | ||
34 | <div class="row"> | ||
35 | <label class="col w150p" for="password_repeat">{% trans "Repeat your new password:" %}</label> | ||
36 | <input class="col" type="password" id="password_repeat" name="password_repeat" placeholder="{% trans "Password" %}" tabindex="3"> | ||
37 | </div> | ||
38 | <div class="row mts txtcenter"> | ||
39 | <button class="bouton" type="submit" tabindex="4">{% trans "Update" %}</button> | ||
40 | </div> | ||
41 | </fieldset> | ||
42 | <input type="hidden" name="returnurl" value="{{ referer }}"> | ||
43 | <input type="hidden" name="token" value="{{ token }}"> | ||
44 | </form> | ||
45 | |||
46 | <h2>{% trans "Import" %}</h2> | ||
47 | <p>{% trans "Please execute the import script locally, it can take a very long time." %}</p> | ||
48 | <p>{% trans "More infos in the official doc:" %} <a href="http://inthepoche.com/?pages/Documentation">inthepoche.com</a></p> | ||
49 | <p><ul> | ||
50 | <li><a href="./?import&from=pocket">{% trans "import from Pocket" %}</a> (you must have a "ril_export.html" file on your server)</li> | ||
51 | <li><a href="./?import&from=readability">{% trans "import from Readability" %}</a> (you must have a "readability" file on your server)</li> | ||
52 | <li><a href="./?import&from=instapaper">{% trans "import from Instapaper" %}</a> (you must have a "instapaper-export.html" file on your server)</li> | ||
53 | </ul></p> | ||
54 | |||
55 | <h2>{% trans "Export your poche datas" %}</h2> | ||
56 | <p><a href="./?export" target="_blank">{% trans "Click here" %}</a> {% trans "to export your poche datas." %}</p> | ||
57 | {% endblock %} \ No newline at end of file | ||
diff --git a/css/knacss.css b/tpl/css/knacss.css index ca0696b7..ca0696b7 100644 --- a/css/knacss.css +++ b/tpl/css/knacss.css | |||
diff --git a/tpl/css/messages.css b/tpl/css/messages.css new file mode 100755 index 00000000..9222bb88 --- /dev/null +++ b/tpl/css/messages.css | |||
@@ -0,0 +1,13 @@ | |||
1 | .messages { width: 400px; -moz-border-radius: 4px; border-radius: 4px; display: block; padding: 10px 0; margin: 10px auto 10px; clear: both; } | ||
2 | .messages a.closeMessage { margin: -14px -8px 0 0; display:none; width: 16px; height: 16px; float: right; background: url(../img/messages/close.png) no-repeat; } | ||
3 | /*.messages:hover a.closeMessage { visibility:visible; }*/ | ||
4 | .messages p { margin: 3px 0 3px 10px !important; padding: 0 10px 0 23px !important; font-size: 14px; line-height: 16px; } | ||
5 | .messages.error { border: 1px solid #C42608; color: #c00 !important; background: #FFF0EF; } | ||
6 | .messages.error p { background: url(../img/messages/cross.png ) no-repeat 0px 50%; color:#c00 !important; } | ||
7 | .messages.success {background: #E0FBCC; border: 1px solid #6DC70C; } | ||
8 | .messages.success p { background: url(../img/messages/tick.png) no-repeat 0px 50%; color: #2B6301 !important; } | ||
9 | .messages.warning { background: #FFFCD3; border: 1px solid #EBCD41; color: #000; } | ||
10 | .messages.warning p { background: url(../img/messages/warning.png ) no-repeat 0px 50%; color: #5F4E01; } | ||
11 | .messages.information, .messages.info { background: #DFEBFB; border: 1px solid #82AEE7; } | ||
12 | .messages.information p, .messages.info p { background: url(../img/messages/help.png ) no-repeat 0px 50%; color: #064393; } | ||
13 | .messages.information a { text-decoration: underline; } \ No newline at end of file | ||
diff --git a/tpl/css/style-light.css b/tpl/css/style-light.css new file mode 100644 index 00000000..9ea7955a --- /dev/null +++ b/tpl/css/style-light.css | |||
@@ -0,0 +1,53 @@ | |||
1 | |||
2 | a.back span { | ||
3 | background: url('../img/light/left.png') no-repeat; | ||
4 | } | ||
5 | |||
6 | a.top span { | ||
7 | background: url('../img/light/top.png') no-repeat; | ||
8 | } | ||
9 | |||
10 | |||
11 | a.fav span { | ||
12 | background: url('../img/light/star-on.png') no-repeat; | ||
13 | } | ||
14 | |||
15 | a.fav span:hover { | ||
16 | background: url('../img/light/star-off.png') no-repeat; | ||
17 | } | ||
18 | |||
19 | a.fav-off span { | ||
20 | background: url('../img/light/star-off.png') no-repeat; | ||
21 | } | ||
22 | |||
23 | a.fav-off span:hover { | ||
24 | background: url('../img/light/star-on.png') no-repeat; | ||
25 | } | ||
26 | |||
27 | a.archive span { | ||
28 | background: url('../img/light/checkmark-on.png') no-repeat; | ||
29 | } | ||
30 | |||
31 | a.archive span:hover { | ||
32 | background: url('../img/light/checkmark-off.png') no-repeat; | ||
33 | } | ||
34 | |||
35 | a.archive-off span { | ||
36 | background: url('../img/light/checkmark-off.png') no-repeat; | ||
37 | } | ||
38 | |||
39 | a.archive-off span:hover { | ||
40 | background: url('../img/light/checkmark-on.png') no-repeat; | ||
41 | } | ||
42 | |||
43 | a.twitter span { | ||
44 | background: url('../img/light/twitter.png') no-repeat; | ||
45 | } | ||
46 | |||
47 | a.email span { | ||
48 | background: url('../img/light/envelop.png') no-repeat; | ||
49 | } | ||
50 | |||
51 | a.delete span { | ||
52 | background: url('../img/light/remove.png') no-repeat; | ||
53 | } \ No newline at end of file | ||
diff --git a/tpl/css/style.css b/tpl/css/style.css new file mode 100644 index 00000000..d23c1896 --- /dev/null +++ b/tpl/css/style.css | |||
@@ -0,0 +1,244 @@ | |||
1 | body { | ||
2 | font-size: 16px; | ||
3 | font-family: 'Roboto', sans-serif; | ||
4 | margin: 10px; | ||
5 | } | ||
6 | |||
7 | header { | ||
8 | text-align: center; | ||
9 | } | ||
10 | |||
11 | header h1 { | ||
12 | font-size: 1.3em; | ||
13 | } | ||
14 | |||
15 | .bouton { | ||
16 | border-radius: 2px; | ||
17 | } | ||
18 | |||
19 | #main { | ||
20 | margin: 0 auto; | ||
21 | } | ||
22 | |||
23 | #main ul#links { | ||
24 | padding: 0; | ||
25 | list-style-type: none; | ||
26 | text-align: center; | ||
27 | font-size: 0.9em; | ||
28 | } | ||
29 | |||
30 | #main ul#links li { | ||
31 | display: inline; | ||
32 | } | ||
33 | |||
34 | #main ul#links li a.current { | ||
35 | -webkit-border-radius: 2px; | ||
36 | border-radius: 2px; | ||
37 | } | ||
38 | |||
39 | #main ul#sort { | ||
40 | padding: 0; | ||
41 | list-style-type: none; | ||
42 | text-align: center; | ||
43 | opacity: 0.5; | ||
44 | } | ||
45 | |||
46 | #main ul#sort li { | ||
47 | display: inline; | ||
48 | font-size: 0.9em; | ||
49 | } | ||
50 | |||
51 | #main ul#sort img:hover { | ||
52 | cursor: pointer; | ||
53 | } | ||
54 | |||
55 | |||
56 | #links a{ | ||
57 | text-decoration: none; | ||
58 | padding: 5px 10px; | ||
59 | } | ||
60 | #links a:hover{ | ||
61 | -webkit-border-radius: 2px; | ||
62 | border-radius: 2px; | ||
63 | } | ||
64 | |||
65 | /*** ***/ | ||
66 | /*** LINKS DISPLAY ***/ | ||
67 | |||
68 | #main a.tool { | ||
69 | text-decoration: none; | ||
70 | cursor: pointer; | ||
71 | } | ||
72 | |||
73 | #main #content { | ||
74 | margin-top: 20px; | ||
75 | } | ||
76 | |||
77 | #main #content h2 { | ||
78 | font-size: 1.3em; | ||
79 | text-decoration: none; | ||
80 | } | ||
81 | |||
82 | #main #content .entrie { | ||
83 | border-bottom: 1px dashed #222222; | ||
84 | } | ||
85 | |||
86 | #main .entrie ul.tools { | ||
87 | list-style-type: none; | ||
88 | } | ||
89 | |||
90 | #main .entrie ul.tools li { | ||
91 | /*display: inline;*/ | ||
92 | } | ||
93 | |||
94 | .tools { | ||
95 | float: right; | ||
96 | text-align: right; | ||
97 | opacity: 0.5; | ||
98 | } | ||
99 | |||
100 | .tools p { | ||
101 | font-size: 0.8em;} | ||
102 | |||
103 | /* | ||
104 | .tools ul { | ||
105 | padding: 0; margin: 0; | ||
106 | list-style-type: none; | ||
107 | } | ||
108 | |||
109 | .tools ul li { | ||
110 | line-height: 20px; | ||
111 | } | ||
112 | |||
113 | .tools a.tool { | ||
114 | cursor: pointer; | ||
115 | }*/ | ||
116 | |||
117 | #main .entrie .tools a.tool span, #article .tools a.tool span { | ||
118 | display: inline-block; | ||
119 | width: 16px; | ||
120 | height: 16px; | ||
121 | } | ||
122 | |||
123 | #main .entrie .url { | ||
124 | font-size: 13px; | ||
125 | } | ||
126 | |||
127 | |||
128 | /*** ***/ | ||
129 | /*** ARTICLE PAGE ***/ | ||
130 | |||
131 | #article { | ||
132 | margin: 0 auto; | ||
133 | } | ||
134 | #article header { | ||
135 | text-align: left; | ||
136 | } | ||
137 | |||
138 | #article header a { | ||
139 | text-decoration: none; | ||
140 | } | ||
141 | |||
142 | .vieworiginal a, .vieworiginal a:hover, .vieworiginal a:visited { | ||
143 | text-decoration: none; | ||
144 | color: #888888; | ||
145 | } | ||
146 | |||
147 | .backhome { | ||
148 | display: inline; | ||
149 | } | ||
150 | |||
151 | #article .tools { | ||
152 | position: relative; | ||
153 | display: inline; | ||
154 | top: 0px; | ||
155 | right: 0px; | ||
156 | width: 100%; | ||
157 | } | ||
158 | |||
159 | #article .tools ul li{ | ||
160 | display: inline; | ||
161 | } | ||
162 | |||
163 | |||
164 | /*** GENERAL ***/ | ||
165 | body { | ||
166 | color: #000; | ||
167 | } | ||
168 | |||
169 | a, a:hover, a:visited { | ||
170 | color: #000; | ||
171 | } | ||
172 | |||
173 | .bouton { | ||
174 | background-color: #000; | ||
175 | color: #fff; | ||
176 | border: none; | ||
177 | } | ||
178 | .bouton:hover { | ||
179 | background-color: #222222; | ||
180 | color: #F1F1F1; | ||
181 | } | ||
182 | |||
183 | #main ul#links li a.current { | ||
184 | background-color: #000; | ||
185 | color: #fff; | ||
186 | } | ||
187 | |||
188 | #links a:hover{ | ||
189 | background-color: #040707; | ||
190 | color: #F1F1F1; | ||
191 | } | ||
192 | |||
193 | |||
194 | /*** ***/ | ||
195 | /*** ARTICLE PAGE ***/ | ||
196 | |||
197 | #article header, #article article { | ||
198 | border-bottom: 1px solid #222222; | ||
199 | } | ||
200 | |||
201 | |||
202 | /* Pagination */ | ||
203 | .pagination { | ||
204 | clear: both; | ||
205 | padding-bottom: 20px; | ||
206 | padding-top: 10px; | ||
207 | text-align: right; | ||
208 | } | ||
209 | .pagination a { | ||
210 | border: 1px solid #D5D5D5; | ||
211 | color: #333; | ||
212 | font-size: 11px; | ||
213 | font-weight: bold; | ||
214 | height: 25px; | ||
215 | padding: 4px 8px; | ||
216 | text-decoration: none; | ||
217 | margin:2px; | ||
218 | } | ||
219 | .pagination a:hover, .pagination a:active { | ||
220 | background:#efefef; | ||
221 | } | ||
222 | .pagination span.current { | ||
223 | background-color: #ccc; | ||
224 | border: 1px solid #D5D5D5; | ||
225 | color: #000; | ||
226 | font-size: 11px; | ||
227 | font-weight: bold; | ||
228 | height: 25px; | ||
229 | padding: 4px 8px; | ||
230 | text-decoration: none; | ||
231 | margin:2px; | ||
232 | } | ||
233 | .pagination span.disabled { | ||
234 | border: 1px solid #EEEEEE; | ||
235 | color: #DDDDDD; | ||
236 | margin:2px; | ||
237 | padding: 4px 8px; | ||
238 | font-size: 11px; | ||
239 | font-weight: bold; | ||
240 | } | ||
241 | |||
242 | footer { | ||
243 | clear: both; | ||
244 | } \ No newline at end of file | ||
diff --git a/tpl/entries.html b/tpl/entries.html deleted file mode 100644 index 8526a3c9..00000000 --- a/tpl/entries.html +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | <div id="content"> | ||
2 | {loop="entries"} | ||
3 | <div id="entry-{$value.id}" class="entrie mb2"> | ||
4 | <span class="content"> | ||
5 | <h2 class="h6-like"> | ||
6 | <a href="index.php?&view=view&id={$value.id}">{$value.title}</a> | ||
7 | </h2> | ||
8 | <div class="tools"> | ||
9 | <ul> | ||
10 | <li><a title="toggle mark as read" class="tool archive {if="$value.is_read == '0'"}archive-off{/if}" onclick="toggle_archive(this, {$value.id})"><span></span></a></li> | ||
11 | <li><a title="toggle favorite" class="tool fav {if="$value.is_fav == '0'"}fav-off{/if}" onclick="toggle_favorite(this, {$value.id})"><span></span></a></li> | ||
12 | <li><form method="post" onsubmit="return confirm('Are you sure?')" style="display: inline;"><input type="hidden" name="token" id="token" value="<?php echo Session::getToken(); ?>" /><input type="hidden" id="action" name="action" value="delete" /><input type="hidden" id="view" name="view" value="{$view}" /><input type="hidden" id="id" name="id" value="{$value.id}" /><input type="submit" class="delete" title="toggle delete" /></form></li> | ||
13 | </ul> | ||
14 | </div> | ||
15 | </span> | ||
16 | </div> | ||
17 | {/loop} | ||
18 | </div> \ No newline at end of file | ||
diff --git a/tpl/export.html b/tpl/export.html deleted file mode 100644 index d22d05fc..00000000 --- a/tpl/export.html +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | export {$export} \ No newline at end of file | ||
diff --git a/tpl/export.twig b/tpl/export.twig new file mode 100644 index 00000000..4adb9540 --- /dev/null +++ b/tpl/export.twig | |||
@@ -0,0 +1 @@ | |||
{{ export }} \ No newline at end of file | |||
diff --git a/tpl/footer.html b/tpl/footer.html deleted file mode 100644 index b8bd755c..00000000 --- a/tpl/footer.html +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | </div> | ||
2 | <footer class="mr2 mt3 smaller"> | ||
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> | ||
4 | </footer> | ||
5 | |||
6 | </body> | ||
7 | </html> \ No newline at end of file | ||
diff --git a/tpl/head.html b/tpl/head.html deleted file mode 100644 index e95f6100..00000000 --- a/tpl/head.html +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <!--[if lte IE 6]> <html class="no-js ie6 ie67 ie678" lang="en"> <![endif]--> | ||
3 | <!--[if lte IE 7]> <html class="no-js ie7 ie67 ie678" lang="en"> <![endif]--> | ||
4 | <!--[if IE 8]> <html class="no-js ie8 ie678" lang="en"> <![endif]--> | ||
5 | <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]--> | ||
6 | <html> | ||
7 | <head> | ||
8 | <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0"> | ||
9 | <meta charset="utf-8"> | ||
10 | <meta http-equiv="X-UA-Compatible" content="IE=10"> | ||
11 | <title>{$title}</title> | ||
12 | <link rel="shortcut icon" type="image/x-icon" href="./img/favicon.ico" /> | ||
13 | <link rel="apple-touch-icon-precomposed" sizes="144x144" href="./img/apple-touch-icon-144x144-precomposed.png"> | ||
14 | <link rel="apple-touch-icon-precomposed" sizes="72x72" href="./img/apple-touch-icon-72x72-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"> | ||
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"> | ||
22 | </head> \ No newline at end of file | ||
diff --git a/tpl/home.html b/tpl/home.html deleted file mode 100644 index 90e247f7..00000000 --- a/tpl/home.html +++ /dev/null | |||
@@ -1,19 +0,0 @@ | |||
1 | <body class="light-style"> | ||
2 | <header> | ||
3 | <h1><a href="index.php"><img src="./img/logo.png" alt="logo poche" /></a>poche</h1> | ||
4 | </header> | ||
5 | <div id="main"> | ||
6 | <ul id="links"> | ||
7 | <li><a href="index.php" {if="$view == 'index'"}class="current"{/if}>home</a></li> | ||
8 | <li><a href="?view=fav" {if="$view == 'fav'"}class="current"{/if}>favorites</a></li> | ||
9 | <li><a href="?view=archive" {if="$view == 'archive'"}class="current"{/if}>archive</a></li> | ||
10 | <li><a href="?view=config" {if="$view == 'config'"}class="current"{/if}>config</a></li> | ||
11 | <li><a href="?logout" title="Logout">logout</a></li> | ||
12 | </ul> | ||
13 | {if condition="isset($entries)"} | ||
14 | <ul id="sort"> | ||
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> | ||
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> | ||
17 | </ul> | ||
18 | {/if} | ||
19 | {include="messages"} \ No newline at end of file | ||
diff --git a/tpl/home.twig b/tpl/home.twig new file mode 100644 index 00000000..a6da641f --- /dev/null +++ b/tpl/home.twig | |||
@@ -0,0 +1,29 @@ | |||
1 | {% extends "layout.twig" %} | ||
2 | {% block title %}{% trans "home" %}{% endblock %} | ||
3 | {% block menu %} | ||
4 | {% include '_menu.twig' %} | ||
5 | {% endblock %} | ||
6 | {% block precontent %} | ||
7 | <ul id="sort"> | ||
8 | <li><a href="./?sort=ia&view={{ view }}"><img src="./tpl/img/{{ constant('THEME') }}/top.png" alt="{% trans "by date asc" %}" title="{% trans "by date asc" %}" /></a> {% trans "by date" %} <a href="./?sort=id&view={{ view }}"><img src="./tpl/img/{{ constant('THEME') }}/down.png" alt="{% trans "by date desc" %}" title="{% trans "by date desc" %}" /></a></li> | ||
9 | <li><a href="./?sort=ta&view={{ view }}"><img src="./tpl/img/{{ constant('THEME') }}/top.png" alt="{% trans "by title asc" %}" title="{% trans "by title asc" %}" /></a> {% trans "by title" %} <a href="./?sort=td&view={{ view }}"><img src="./tpl/img/{{ constant('THEME') }}/down.png" alt="{% trans "by title desc" %}" title="{% trans "by title desc" %}" /></a></li> | ||
10 | </ul> | ||
11 | {% endblock %} | ||
12 | {% block content %} | ||
13 | {{ page_links | raw }} | ||
14 | {% for entry in entries %} | ||
15 | <div id="entry-{{ entry.id|e }}" class="entrie"> | ||
16 | <h2><a href="index.php?view=view&id={{ entry.id|e }}">{{ entry.title|e }}</a></h2> | ||
17 | <ul class="tools"> | ||
18 | <li> | ||
19 | <a title="{% trans "toggle mark as read" %}" class="tool archive {% if entry.is_read == 0 %}archive-off{% endif %}" href="./?action=toggle_archive&id={{ entry.id|e }}"><span></span></a></li> | ||
20 | <li><a title="{% trans "toggle favorite" %}" class="tool fav {% if entry.is_fav == 0 %}fav-off{% endif %}" href="./?action=toggle_fav&id={{ entry.id|e }}"><span></span></a></li> | ||
21 | <li><a title="{% trans "delete" %}" class="tool delete" href="./?action=delete&id={{ entry.id|e }}"><span></span></a></li> | ||
22 | </li> | ||
23 | </ul> | ||
24 | <p>{{ entry.content|striptags|slice(0, 300) }}...</p> | ||
25 | <p class="vieworiginal txtright small"><a href="{{ entry.url|e }}" target="_blank" title="{% trans "original" %} : {{ entry.title|e }}">{{ entry.url | e | getDomain }}</a></p> | ||
26 | </div> | ||
27 | {% endfor %} | ||
28 | {{ page_links | raw }} | ||
29 | {% endblock %} \ No newline at end of file | ||
diff --git a/img/apple-touch-icon-144x144-precomposed.png b/tpl/img/apple-touch-icon-144x144-precomposed.png index 557b479c..557b479c 100644 --- a/img/apple-touch-icon-144x144-precomposed.png +++ b/tpl/img/apple-touch-icon-144x144-precomposed.png | |||
Binary files differ | |||
diff --git a/img/apple-touch-icon-72x72-precomposed.png b/tpl/img/apple-touch-icon-72x72-precomposed.png index e167d3a4..e167d3a4 100644 --- a/img/apple-touch-icon-72x72-precomposed.png +++ b/tpl/img/apple-touch-icon-72x72-precomposed.png | |||
Binary files differ | |||
diff --git a/img/apple-touch-icon.png b/tpl/img/apple-touch-icon.png index 4d222fba..4d222fba 100644 --- a/img/apple-touch-icon.png +++ b/tpl/img/apple-touch-icon.png | |||
Binary files differ | |||
diff --git a/img/favicon.ico b/tpl/img/favicon.ico index 0e9ff779..0e9ff779 100644 --- a/img/favicon.ico +++ b/tpl/img/favicon.ico | |||
Binary files differ | |||
diff --git a/img/light/checkmark-off.png b/tpl/img/light/checkmark-off.png index 3db5a06d..3db5a06d 100644 --- a/img/light/checkmark-off.png +++ b/tpl/img/light/checkmark-off.png | |||
Binary files differ | |||
diff --git a/img/light/checkmark-on.png b/tpl/img/light/checkmark-on.png index cd3abb2c..cd3abb2c 100644 --- a/img/light/checkmark-on.png +++ b/tpl/img/light/checkmark-on.png | |||
Binary files differ | |||
diff --git a/img/down.png b/tpl/img/light/down.png index b9d536a7..b9d536a7 100644 --- a/img/down.png +++ b/tpl/img/light/down.png | |||
Binary files differ | |||
diff --git a/tpl/img/light/envelop.png b/tpl/img/light/envelop.png new file mode 100755 index 00000000..6be1c886 --- /dev/null +++ b/tpl/img/light/envelop.png | |||
Binary files differ | |||
diff --git a/tpl/img/light/left.png b/tpl/img/light/left.png new file mode 100755 index 00000000..a0a53631 --- /dev/null +++ b/tpl/img/light/left.png | |||
Binary files differ | |||
diff --git a/img/light/remove.png b/tpl/img/light/remove.png index f8ad56a3..f8ad56a3 100644 --- a/img/light/remove.png +++ b/tpl/img/light/remove.png | |||
Binary files differ | |||
diff --git a/img/light/star-off.png b/tpl/img/light/star-off.png index 6a0133a7..6a0133a7 100644 --- a/img/light/star-off.png +++ b/tpl/img/light/star-off.png | |||
Binary files differ | |||
diff --git a/img/light/star-on.png b/tpl/img/light/star-on.png index a9f96eaa..a9f96eaa 100644 --- a/img/light/star-on.png +++ b/tpl/img/light/star-on.png | |||
Binary files differ | |||
diff --git a/img/up.png b/tpl/img/light/top.png index 954a8c0a..954a8c0a 100644..100755 --- a/img/up.png +++ b/tpl/img/light/top.png | |||
Binary files differ | |||
diff --git a/tpl/img/light/twitter.png b/tpl/img/light/twitter.png new file mode 100755 index 00000000..cfcfe419 --- /dev/null +++ b/tpl/img/light/twitter.png | |||
Binary files differ | |||
diff --git a/tpl/img/logo.png b/tpl/img/logo.png new file mode 100644 index 00000000..549b8466 --- /dev/null +++ b/tpl/img/logo.png | |||
Binary files differ | |||
diff --git a/img/messages/close.png b/tpl/img/messages/close.png index 731aa018..731aa018 100644..100755 --- a/img/messages/close.png +++ b/tpl/img/messages/close.png | |||
Binary files differ | |||
diff --git a/img/messages/cross.png b/tpl/img/messages/cross.png index 1514d51a..1514d51a 100644..100755 --- a/img/messages/cross.png +++ b/tpl/img/messages/cross.png | |||
Binary files differ | |||
diff --git a/img/messages/help.png b/tpl/img/messages/help.png index 5c870176..5c870176 100644..100755 --- a/img/messages/help.png +++ b/tpl/img/messages/help.png | |||
Binary files differ | |||
diff --git a/img/messages/tick.png b/tpl/img/messages/tick.png index a9925a06..a9925a06 100644..100755 --- a/img/messages/tick.png +++ b/tpl/img/messages/tick.png | |||
Binary files differ | |||
diff --git a/img/messages/warning.png b/tpl/img/messages/warning.png index 628cf2da..628cf2da 100644..100755 --- a/img/messages/warning.png +++ b/tpl/img/messages/warning.png | |||
Binary files differ | |||
diff --git a/tpl/install.html b/tpl/install.html deleted file mode 100644 index d11a7810..00000000 --- a/tpl/install.html +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | {include="head"} | ||
2 | <body class="light-style"> | ||
3 | <header> | ||
4 | <h1><a href="index.php"><img src="./img/logo.png" alt="logo poche" /></a>poche</h1> | ||
5 | </header> | ||
6 | <div id="main"> | ||
7 | <form method="post" action="?install" name="loginform"> | ||
8 | <fieldset class="w500p center"> | ||
9 | <h2 class="mbs txtcenter">install your poche</h2> | ||
10 | <div class="row"> | ||
11 | <label class="col w150p" for="login">Login</label> | ||
12 | <input class="col" type="text" id="login" name="login" placeholder="Login" tabindex="1" autofocus /> | ||
13 | </div> | ||
14 | <div class="row"> | ||
15 | <label class="col w150p" for="password">Password</label> | ||
16 | <input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2"> | ||
17 | </div> | ||
18 | <div class="row"> | ||
19 | <label class="col w150p" for="password_repeat">Repeat your password</label> | ||
20 | <input class="col" type="password" id="password_repeat" name="password_repeat" placeholder="Password" tabindex="3"> | ||
21 | </div> | ||
22 | <div class="row mts txtcenter"> | ||
23 | <button class="bouton" type="submit" tabindex="4">Install</button> | ||
24 | </div> | ||
25 | </fieldset> | ||
26 | <input type="hidden" name="returnurl" value="<?php echo htmlspecialchars($referer);?>"> | ||
27 | <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>"> | ||
28 | </form> | ||
29 | |||
30 | {include="footer"} | ||
diff --git a/tpl/install.twig b/tpl/install.twig new file mode 100644 index 00000000..8bcede0d --- /dev/null +++ b/tpl/install.twig | |||
@@ -0,0 +1,28 @@ | |||
1 | {% extends "layout.twig" %} | ||
2 | {% block title %}{% trans "installation" %}{% endblock %} | ||
3 | {% block content %} | ||
4 | <form method="post" action="?install" name="loginform"> | ||
5 | <fieldset class="w500p center"> | ||
6 | <h2 class="mbs txtcenter">{% trans "install your poche" %}</h2> | ||
7 | <p> | ||
8 | {% trans "poche is still not installed. Please fill the below form to install it. Don't hesitate to <a href='http://inthepoche.com/?pages/Documentation'>read the documentation on poche website</a>." %} | ||
9 | </p> | ||
10 | <div class="row"> | ||
11 | <label class="col w150p" for="login">{% trans "Login" %}</label> | ||
12 | <input class="col" type="text" id="login" name="login" placeholder="Login" tabindex="1" autofocus /> | ||
13 | </div> | ||
14 | <div class="row"> | ||
15 | <label class="col w150p" for="password">{% trans "Password" %}</label> | ||
16 | <input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2"> | ||
17 | </div> | ||
18 | <div class="row"> | ||
19 | <label class="col w150p" for="password_repeat">{% trans "Repeat your password" %}</label> | ||
20 | <input class="col" type="password" id="password_repeat" name="password_repeat" placeholder="Password" tabindex="3"> | ||
21 | </div> | ||
22 | <div class="row mts txtcenter"> | ||
23 | <button class="bouton" type="submit" tabindex="4">{% trans "Install" %}</button> | ||
24 | </div> | ||
25 | </fieldset> | ||
26 | <input type="hidden" name="token" value="{{ token }}"> | ||
27 | </form> | ||
28 | {% endblock %} \ No newline at end of file | ||
diff --git a/tpl/js.html b/tpl/js.html deleted file mode 100644 index a02212b0..00000000 --- a/tpl/js.html +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | <script type="text/javascript" src="js/jquery-1.9.1.min.js"></script> | ||
2 | <script type="text/javascript" src="js/poche.js"></script> | ||
3 | |||
4 | {if="$load_all_js == '1'"} | ||
5 | <script type="text/javascript" src="js/jquery.masonry.min.js"></script> | ||
6 | <script type="text/javascript"> | ||
7 | $( window ).load( function() | ||
8 | { | ||
9 | var columns = 3, | ||
10 | setColumns = function() { columns = $( window ).width() > 640 ? 3 : $( window ).width() > 320 ? 2 : 1; }; | ||
11 | |||
12 | setColumns(); | ||
13 | $( window ).resize( setColumns ); | ||
14 | |||
15 | $( '#content' ).masonry( | ||
16 | { | ||
17 | itemSelector: '.entrie', | ||
18 | columnWidth: function( containerWidth ) { return containerWidth / columns; } | ||
19 | }); | ||
20 | }); | ||
21 | </script> | ||
22 | {/if} \ No newline at end of file | ||
diff --git a/tpl/layout.twig b/tpl/layout.twig new file mode 100644 index 00000000..c4bbe779 --- /dev/null +++ b/tpl/layout.twig | |||
@@ -0,0 +1,29 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <!--[if lte IE 6]> <html class="no-js ie6 ie67 ie678" lang="en"> <![endif]--> | ||
3 | <!--[if lte IE 7]> <html class="no-js ie7 ie67 ie678" lang="en"> <![endif]--> | ||
4 | <!--[if IE 8]> <html class="no-js ie8 ie678" lang="en"> <![endif]--> | ||
5 | <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]--> | ||
6 | <html> | ||
7 | <head> | ||
8 | <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0"> | ||
9 | <meta charset="utf-8"> | ||
10 | <meta http-equiv="X-UA-Compatible" content="IE=10"> | ||
11 | <title>{% block title %}{% endblock %} - poche</title> | ||
12 | {% include '_head.twig' %} | ||
13 | {% include '_bookmarklet.twig' %} | ||
14 | </head> | ||
15 | <body> | ||
16 | {% include '_top.twig' %} | ||
17 | <div id="main"> | ||
18 | {% block menu %}{% endblock %} | ||
19 | {% block precontent %}{% endblock %} | ||
20 | {% block messages %} | ||
21 | {% include '_messages.twig' %} | ||
22 | {% endblock %} | ||
23 | <div id="content" class="w600p center"> | ||
24 | {% block content %}{% endblock %} | ||
25 | </div> | ||
26 | </div> | ||
27 | {% include '_footer.twig' %} | ||
28 | </body> | ||
29 | </html> \ No newline at end of file | ||
diff --git a/tpl/login.html b/tpl/login.html deleted file mode 100644 index 69c17a55..00000000 --- a/tpl/login.html +++ /dev/null | |||
@@ -1,33 +0,0 @@ | |||
1 | {include="head"} | ||
2 | <body class="light-style"> | ||
3 | <header> | ||
4 | <h1><a href="index.php"><img src="./img/logo.png" alt="logo poche" /></a>poche</h1> | ||
5 | </header> | ||
6 | <div id="main"> | ||
7 | <form method="post" action="?login" name="loginform"> | ||
8 | <fieldset class="w500p center"> | ||
9 | <h2 class="mbs txtcenter">login to your poche</h2> | ||
10 | <div class="row"> | ||
11 | <label class="col w150p" for="login">Login</label> | ||
12 | <input class="col" type="text" id="login" name="login" placeholder="Login" tabindex="1" autofocus /> | ||
13 | </div> | ||
14 | <div class="row"> | ||
15 | <label class="col w150p" for="password">Password</label> | ||
16 | <input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2"> | ||
17 | </div> | ||
18 | <div class="row"> | ||
19 | <label class="col w150p">Stay signed in</label> | ||
20 | <div class="col"> | ||
21 | <input type="checkbox" name="longlastingsession" tabindex="3"> | ||
22 | <small class="inbl">(Do not check on public computers)</small> | ||
23 | </div> | ||
24 | </div> | ||
25 | <div class="row mts txtcenter"> | ||
26 | <button class="bouton" type="submit" tabindex="4">Sign in</button> | ||
27 | </div> | ||
28 | </fieldset> | ||
29 | <input type="hidden" name="returnurl" value="<?php echo htmlspecialchars($referer);?>"> | ||
30 | <input type="hidden" name="token" value="<?php echo Session::getToken(); ?>"> | ||
31 | </form> | ||
32 | |||
33 | {include="footer"} | ||
diff --git a/tpl/login.twig b/tpl/login.twig new file mode 100644 index 00000000..0ae130bc --- /dev/null +++ b/tpl/login.twig | |||
@@ -0,0 +1,32 @@ | |||
1 | {% extends "layout.twig" %} | ||
2 | |||
3 | {% block title %}{% trans "login to your poche" %}{% endblock %} | ||
4 | {% block content %} | ||
5 | <form method="post" action="?login" name="loginform"> | ||
6 | <fieldset class="w500p center"> | ||
7 | <h2 class="mbs txtcenter">{% trans "login to your poche" %}</h2> | ||
8 | {% if constant('MODE_DEMO') == 1 %}<p>{% trans "you are in demo mode, some features may be disabled." %}</p>{% endif %} | ||
9 | <div class="row"> | ||
10 | <label class="col w150p" for="login">{% trans "Login" %}</label> | ||
11 | <input class="col" type="text" id="login" name="login" placeholder="Login" tabindex="1" autofocus {% if constant('MODE_DEMO') == 1 %}value="poche"{% endif %} /> | ||
12 | </div> | ||
13 | |||
14 | <div class="row"> | ||
15 | <label class="col w150p" for="password">{% trans "Password" %}</label> | ||
16 | <input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2" {% if constant('MODE_DEMO') == 1 %}value="poche"{% endif %} /> | ||
17 | </div> | ||
18 | <div class="row"> | ||
19 | <label class="col w150p" for="longlastingsession">{% trans "Stay signed in" %}</label> | ||
20 | <div class="col"> | ||
21 | <input type="checkbox" id="longlastingsession" name="longlastingsession" tabindex="3"> | ||
22 | <small class="inbl">{% trans "(Do not check on public computers)" %}</small> | ||
23 | </div> | ||
24 | </div> | ||
25 | <div class="row mts txtcenter"> | ||
26 | <button class="bouton" type="submit" tabindex="4">{% trans "Login" %}</button> | ||
27 | </div> | ||
28 | </fieldset> | ||
29 | <input type="hidden" name="returnurl" value="{{ referer }}"> | ||
30 | <input type="hidden" name="token" value="{{ token }}"> | ||
31 | </form> | ||
32 | {% endblock %} \ No newline at end of file | ||
diff --git a/tpl/messages.html b/tpl/messages.html deleted file mode 100644 index 87af259b..00000000 --- a/tpl/messages.html +++ /dev/null | |||
@@ -1 +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 deleted file mode 100644 index af94df2e..00000000 --- a/tpl/view.html +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <!--[if lte IE 6]> <html class="no-js ie6 ie67 ie678" lang="en"> <![endif]--> | ||
3 | <!--[if lte IE 7]> <html class="no-js ie7 ie67 ie678" lang="en"> <![endif]--> | ||
4 | <!--[if IE 8]> <html class="no-js ie8 ie678" lang="en"> <![endif]--> | ||
5 | <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]--> | ||
6 | <html> | ||
7 | <head> | ||
8 | <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0"> | ||
9 | <meta charset="utf-8"> | ||
10 | <meta http-equiv="X-UA-Compatible" content="IE=10"> | ||
11 | <title>{$title}</title> | ||
12 | <link rel="shortcut icon" type="image/x-icon" href="./img/favicon.ico" /> | ||
13 | <link rel="apple-touch-icon-precomposed" sizes="144x144" href="./img/apple-touch-icon-144x144-precomposed.png"> | ||
14 | <link rel="apple-touch-icon-precomposed" sizes="72x72" href="./img/apple-touch-icon-72x72-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"> | ||
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"> | ||
22 | </head> | ||
23 | <body class="article light-style"> | ||
24 | <div id="article" class="w600p"> | ||
25 | <div class="backhome"> | ||
26 | <a href="index.php" title="back to home">←</a> | ||
27 | </div> | ||
28 | <div class="tools"> | ||
29 | <ul> | ||
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> | ||
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> | ||
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> | ||
34 | <li><a href="?logout" title="Logout">logout</a></li> | ||
35 | </ul> | ||
36 | </div> | ||
37 | <header class="mbm"> | ||
38 | <h1><a href="{$url}">{$title}</a></h1> | ||
39 | <div class="vieworiginal txtright small"><a href="{$url}" target="_blank" title="original : {$title}">view original</a></div> | ||
40 | </header> | ||
41 | {include="messages"} | ||
42 | <article> | ||
43 | <div id="readityourselfcontent"> | ||
44 | {$content} | ||
45 | </div> | ||
46 | </article> | ||
47 | <div class="vieworiginal txtright small"><a href="{$url}" target="_blank" title="original : {$title}">view original</a></div> | ||
48 | <div class="backhome"> | ||
49 | <a href="index.php" title="back to home">←</a> | ||
50 | </div> | ||
51 | |||
52 | {include="js"} | ||
53 | {include="footer"} \ No newline at end of file | ||
diff --git a/tpl/view.twig b/tpl/view.twig new file mode 100644 index 00000000..e999afa1 --- /dev/null +++ b/tpl/view.twig | |||
@@ -0,0 +1,40 @@ | |||
1 | {% extends "layout.twig" %} | ||
2 | {% block title %}{% trans "home" %}{% endblock %} | ||
3 | {% block content %} | ||
4 | <div id="article"> | ||
5 | <div class="tools"> | ||
6 | <ul class="tools"> | ||
7 | <li> | ||
8 | <li><a href="{{ referer }}" title="{% trans "back to home" %}" class="tool back"><span></span></a></li> | ||
9 | <a title="{% trans "toggle mark as read" %}" class="tool archive {% if entry.is_read == 0 %}archive-off{% endif %}" href="./?action=toggle_archive&id={{ entry.id|e }}"><span></span></a></li> | ||
10 | <li><a title="{% trans "toggle favorite" %}" class="tool fav {% if entry.is_fav == 0 %}fav-off{% endif %}" href="./?action=toggle_fav&id={{ entry.id|e }}"><span></span></a></li> | ||
11 | <li><a title="{% trans "delete" %}" class="tool delete" href="./?action=delete&id={{ entry.id|e }}"><span></span></a></li> | ||
12 | {% if constant('SHARE_TWITTER') == 1 %}<li><a href="https://twitter.com/home?status={{entry.title}}%20{{ entry.url|e }}%20via%20@getpoche" target="_blank" class="tool twitter" title="{% trans "tweet" %}"><span></span></a></li>{% endif %} | ||
13 | {% if constant('SHARE_MAIL') == 1 %}<li><a href="mailto:?subject={{ entry.title|e }}&body={{ entry.url|e }} via @getpoche" class="tool email" title="{% trans "email" %}"><span></span></a></li>{% endif %} | ||
14 | </li> | ||
15 | </ul> | ||
16 | </div> | ||
17 | <header class="mbm"> | ||
18 | <h1>{{ entry.title|e }}</h1> | ||
19 | <div class="vieworiginal txtright small"><a href="{{ entry.url|e }}" target="_blank" title="{% trans "original" %} : {{ entry.title|e }}">{{ entry.url | e | getDomain }}</a></div> | ||
20 | </header> | ||
21 | <article> | ||
22 | {{ content | raw }} | ||
23 | <div class="vieworiginal txtright small"><a href="{{ entry.url|e }}" target="_blank" title="{% trans "original" %} : {{ entry.title|e }}">{{ entry.url | e | getDomain }}</a></div> | ||
24 | </article> | ||
25 | <div class="tools"> | ||
26 | <ul class="tools"> | ||
27 | <li> | ||
28 | <li><a href="{{ referer }}" title="{% trans "back to home" %}" class="tool back"><span></span></a></li> | ||
29 | <li><a href="#" title="{% trans "back to top" %}" class="tool top"><span></span></a></li> | ||
30 | <a title="{% trans "toggle mark as read" %}" class="tool archive {% if entry.is_read == 0 %}archive-off{% endif %}" href="./?action=toggle_archive&id={{ entry.id|e }}"><span></span></a></li> | ||
31 | <li><a title="{% trans "toggle favorite" %}" class="tool fav {% if entry.is_fav == 0 %}fav-off{% endif %}" href="./?action=toggle_fav&id={{ entry.id|e }}"><span></span></a></li> | ||
32 | <li><a title="{% trans "delete" %}" class="tool delete" href="./?action=delete&id={{ entry.id|e }}"><span></span></a></li> | ||
33 | {% if constant('SHARE_TWITTER') == 1 %}<li><a href="https://twitter.com/home?status={{entry.title}}%20{{ entry.url|e }}%20via%20@getpoche" target="_blank" class="tool twitter" title="{% trans "tweet" %}"><span></span></a></li>{% endif %} | ||
34 | {% if constant('SHARE_MAIL') == 1 %}<li><a href="mailto:?subject={{ entry.title|e }}&body={{ entry.url|e }} via @getpoche" class="tool email" title="{% trans "email" %}"><span></span></a></li>{% endif %} | ||
35 | </li> | ||
36 | </ul> | ||
37 | <p>{% trans "this article appears wrong?" %} <a href="https://github.com/inthepoche/poche/issues/new">{% trans "create an issue" %}</a> {% trans "or" %} <a href="mailto:support@inthepoche.com?subject=Wrong display in poche&body={{ entry.url|e }}">{% trans "contact us by mail" %}</a></p> | ||
38 | </div> | ||
39 | </div> | ||
40 | {% endblock %} \ No newline at end of file | ||