From 59c17a3c6c26d6b487e2ec5e02caa3fb26f9ff9c Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 27 Sep 2014 08:20:13 -0400 Subject: Fix read all shortcut Before, the read all shortcut raised a javascript exception when we use the confirmation option. The confirmation was not even displayed. The code was failling since there was a missing variable. Now, the shortcut ask for confirmation when the option is selected in the reading configuration page. The definition of the shortcut was buggy since the confirmation was handled properly in an other location. I simplified the code by removing the confirmation code in the shortcut. --- p/scripts/main.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'p') diff --git a/p/scripts/main.js b/p/scripts/main.js index f6d5d2907..8a45ae896 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -538,14 +538,7 @@ function init_shortcuts() { }); shortcut.add("shift+" + shortcuts.mark_read, function () { // on marque tout comme lu - var btn = $(".nav_menu .read_all"); - if (btn.hasClass('confirm')) { - if (confirm(str_confirmation)) { - btn.click(); - } - } else { - btn.click(); - } + $(".nav_menu .read_all").click(); }, { 'disable_in_input': true }); -- cgit v1.2.3 From 46ae0a3f5ada751c9442eca275e15450fad85509 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 30 Sep 2014 14:33:28 +0200 Subject: BREAK CATEGORIZE SYSTEM! And begin big changes. See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/views/configure/categorize.phtml | 102 +++++++++++++++++++---------------- p/themes/base-theme/template.css | 20 +++++++ 2 files changed, 75 insertions(+), 47 deletions(-) (limited to 'p') diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml index 23d1c9fa1..7091ff1cf 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -1,55 +1,63 @@ -partial ('aside_feed'); ?> +partial('aside_feed'); ?> -
- +
+ -
- +
+
-

defaultCategory->name ()); ?>

- - categories as $cat) { $i++; ?> -
- -
-
- - - nbFeed () > 0) { ?> - - - - - -
- (nbFeed ()); ?>) - - id () === $this->defaultCategory->id ()) { ?> - - - - -
+
+ + + +
- - -
- -
- +
+ + categories as $cat) { + $feeds = $cat->feeds(); + ?> +
+
+ +
-
-
- - -
-
- +
    + + inError() ? ' error' : ''; + $empty = $feed->nbEntries() == 0 ? ' empty' : ''; + ?> +
  • + + ✇ name(); ?> +
  • + +
  • Empty
  • + +
+
+
diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index dc011503d..792eac299 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -559,6 +559,8 @@ br + br + br { /*=== GLOBAL VIEW */ /*================*/ /*=== Category boxes */ + +/* TODO */ #stream.global .box-category { display: inline-block; width: 19em; @@ -581,6 +583,24 @@ br + br + br { width: 19em; max-width: 90%; } +/* TODO Date: Tue, 30 Sep 2014 19:45:49 +0200 Subject: Improve design of .box See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/layout/aside_feed.phtml | 16 ----------- app/views/configure/categorize.phtml | 24 +++++++++-------- p/themes/Dark/dark.css | 29 ++++++++++++++++++++ p/themes/Flat/flat.css | 30 +++++++++++++++++++++ p/themes/Origine/origine.css | 30 +++++++++++++++++++++ p/themes/Pafat/pafat.css | 29 ++++++++++++++++++++ p/themes/Screwdriver/screwdriver.css | 34 ++++++++++++++++++++++++ p/themes/base-theme/base.css | 24 +++++++++++++++++ p/themes/base-theme/template.css | 51 ++++++++++++++++++++++++------------ 9 files changed, 223 insertions(+), 44 deletions(-) (limited to 'p') diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index c72710c2d..c028c4918 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -57,20 +57,4 @@
  • - -
  • - - feeds)) { ?> - feeds as $feed) { ?> - nbEntries(); ?> -
  • - - ✇ - name(); ?> - -
  • - - -
  • - diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml index b9d04ddb8..8f77f9724 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -12,12 +12,12 @@
    -
    +
      - - +
    • +
    • -
    +
    @@ -27,10 +27,9 @@ $feeds = $cat->feeds(); ?>
    -
    +
    - diff --git a/p/themes/Dark/dark.css b/p/themes/Dark/dark.css index 10f6e655b..f3790614e 100644 --- a/p/themes/Dark/dark.css +++ b/p/themes/Dark/dark.css @@ -435,6 +435,35 @@ a.btn { font-size: 0; } +/*=== Boxes */ +.box { + border: 1px solid #000; + border-radius: 5px; +} +.box .box-title { + margin: 0; + padding: 5px 10px; + background: #26303F; + border-bottom: 1px solid #000; + border-radius: 5px 5px 0 0; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/Flat/flat.css b/p/themes/Flat/flat.css index 484cee9f3..d0ac46fd5 100644 --- a/p/themes/Flat/flat.css +++ b/p/themes/Flat/flat.css @@ -438,6 +438,36 @@ a.btn { background: url("loader.gif") center center no-repeat #34495e; } +/*=== Boxes */ +.box { + border: 1px solid #ddd; + border-radius: 5px; +} +.box .box-title { + margin: 0; + padding: 5px 10px; + background: #ecf0f1; + color: #333; + border-bottom: 1px solid #ddd; + border-radius: 5px 5px 0 0; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/Origine/origine.css b/p/themes/Origine/origine.css index 08fc08379..e3ae85075 100644 --- a/p/themes/Origine/origine.css +++ b/p/themes/Origine/origine.css @@ -467,6 +467,36 @@ a.btn { font-size: 0; } +/*=== Boxes */ +.box { + background: #fff; + border-radius: 5px; + box-shadow: 0 0 3px #bbb; +} +.box .box-title { + margin: 0; + padding: 5px 10px; + background: #f6f6f6; + border-bottom: 1px solid #ddd; + border-radius: 5px 5px 0 0; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/Pafat/pafat.css b/p/themes/Pafat/pafat.css index a35ac861d..28b17e15f 100644 --- a/p/themes/Pafat/pafat.css +++ b/p/themes/Pafat/pafat.css @@ -491,6 +491,35 @@ a.btn { font-size: 0; } +/*=== Boxes */ +.box { + border: 1px solid #aaa; + border-radius: 5px; +} +.box .box-title { + margin: 0; + padding: 5px 10px; + background: #f6f6f6; + border-bottom: 1px solid #aaa; + border-radius: 5px 5px 0 0; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/Screwdriver/screwdriver.css b/p/themes/Screwdriver/screwdriver.css index 37fa18e10..6206504d1 100644 --- a/p/themes/Screwdriver/screwdriver.css +++ b/p/themes/Screwdriver/screwdriver.css @@ -497,6 +497,40 @@ a.btn { font-size: 0; } +/*=== Boxes */ +.box { + background: #EDE7DE; + border-radius: 4px 4px 0 0; +} +.box .box-title { + margin: 0; + padding: 5px 10px; + background: linear-gradient(0deg, #EDE7DE 0%, #fff 100%) #171717; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #fff 100%); + box-shadow: 0px -1px #fff inset,0 -2px #ccc inset; + color: #888; + text-shadow: 0 1px #ccc; + border-radius: 4px 4px 0 0; + font-size: 1.1rem; + font-weight: normal; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/base-theme/base.css b/p/themes/base-theme/base.css index ccfab10df..3f6ae956d 100644 --- a/p/themes/base-theme/base.css +++ b/p/themes/base-theme/base.css @@ -329,6 +329,30 @@ a.btn { font-size: 0; } +/*=== Boxes */ +.box { +} +.box .box-title { + margin: 0; + padding: 5px 10px; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 792eac299..a5a29ab23 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -280,6 +280,40 @@ a.btn { width: 100px; } +/*=== Boxes */ +.box { + display: inline-block; + width: 20rem; + max-width: 95%; + margin: 20px 10px; + border: 1px solid #ccc; + vertical-align: top; +} +.box .box-title { + font-size: 1.2rem; + font-weight: bold; + text-align: center; +} +.box .box-title form { + margin: 0; +} +.box .box-content { + display: block; + overflow: auto; +} +.box .box-content .item { + display: block; +} + +.box .box-content-centered { + padding: 30px 5px; + text-align: center; +} +.box .box-content-centered .btn { + margin: 20px 0 0; +} + + /*=== STRUCTURE */ /*===============*/ /*=== Header */ @@ -585,23 +619,6 @@ br + br + br { } /* TODO Date: Wed, 1 Oct 2014 10:06:04 +0200 Subject: Load feed configuration on the same page Need improvements See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/configureController.php | 4 ++++ app/views/configure/categorize.phtml | 5 ++++- app/views/configure/feed.phtml | 8 ++++++-- p/scripts/main.js | 30 ++++++++++++++++++++++++++++++ p/themes/base-theme/template.css | 5 +++++ 5 files changed, 49 insertions(+), 3 deletions(-) (limited to 'p') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index a7def6d9a..dd7a0a441 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -90,6 +90,10 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * Default values are empty strings unless specified. */ public function feedAction() { + if (Minz_Request::param('ajax')) { + $this->view->_useLayout(false); + } + $catDAO = new FreshRSS_CategoryDAO(); $this->view->categories = $catDAO->listCategories(false); diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml index 8f77f9724..008dc8c98 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -73,7 +73,7 @@ $empty = $feed->nbEntries() == 0 ? ' empty' : ''; ?>
  • - + ✇ name(); ?>
  • + +
    +
    diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml index e96a28739..f58ac65af 100644 --- a/app/views/configure/feed.phtml +++ b/app/views/configure/feed.phtml @@ -1,8 +1,12 @@ -partial ('aside_feed'); ?> +partial('aside_feed'); + } +?> flux) { ?>
    - +

    flux->name (); ?>

    flux->description (); ?> diff --git a/p/scripts/main.js b/p/scripts/main.js index f6d5d2907..7fed7a819 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1240,6 +1240,35 @@ function faviconNbUnread(n) { } } +function init_slider_observers() { + var slider = $('#slider'); + if (slider.length < 1) { + return; + } + + $('.open-slider').on('click', function() { + if (ajax_loading) { + return false; + } + + ajax_loading = true; + + var url_slide = $(this).attr('href'); + + $.ajax({ + type: 'GET', + url: url_slide, + data : { ajax: true } + }).done(function (data) { + slider.html(data); + slider.show(); + ajax_loading = false; + }); + + return false; + }) +} + function init_all() { if (!(window.$ && window.url_freshrss)) { if (window.console) { @@ -1275,6 +1304,7 @@ function init_all() { init_feed_observers(); init_password_observers(); init_stats_observers(); + init_slider_observers(); } if (window.console) { diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index a5a29ab23..397f943a6 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -645,6 +645,11 @@ br + br + br { display: none; } +/*=== Slider */ +#slider { + min-height: 50px; +} + /*=== DIVERS */ /*===========*/ .nav-login, -- cgit v1.2.3 From 1eef7893068655f8d145a3e06061a9e6296ac1f3 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 1 Oct 2014 11:27:41 +0200 Subject: Reorganize subscription management code There is still a lot of work to do. Some links are broken. See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/configureController.php | 116 ------------------ app/Controllers/subscriptionController.php | 130 ++++++++++++++++++++ app/Models/Themes.php | 1 + app/layout/aside_feed.phtml | 60 ---------- app/layout/aside_flux.phtml | 4 +- app/layout/aside_subscription.phtml | 17 +++ app/views/configure/categorize.phtml | 90 -------------- app/views/configure/feed.phtml | 186 ----------------------------- app/views/importExport/index.phtml | 2 +- app/views/subscription/feed.phtml | 186 +++++++++++++++++++++++++++++ app/views/subscription/index.phtml | 132 ++++++++++++++++++++ p/themes/icons/import.svg | 9 ++ 12 files changed, 478 insertions(+), 455 deletions(-) create mode 100644 app/Controllers/subscriptionController.php delete mode 100644 app/layout/aside_feed.phtml create mode 100644 app/layout/aside_subscription.phtml delete mode 100644 app/views/configure/categorize.phtml delete mode 100644 app/views/configure/feed.phtml create mode 100644 app/views/subscription/feed.phtml create mode 100644 app/views/subscription/index.phtml create mode 100644 p/themes/icons/import.svg (limited to 'p') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 3fd1d5149..b7b88b3ba 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -8,9 +8,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * This action is called before every other action in that class. It is * the common boiler plate for every action. It is triggered by the * underlying framework. - * - * @todo see if the category default configuration is needed here or if - * we can move it to the categorize action */ public function firstAction() { if (!$this->view->loginOk) { @@ -19,119 +16,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { array('error' => array(_t('access_denied'))) ); } - - $catDAO = new FreshRSS_CategoryDAO(); - $catDAO->checkDefault(); - } - - /** - * This action handles the category configuration page - * - * It displays the category configuration page. - */ - public function categorizeAction() { - $catDAO = new FreshRSS_CategoryDAO(); - - $this->view->categories = $catDAO->listCategories(false); - $this->view->default_category = $catDAO->getDefault(); - - Minz_View::prependTitle(_t('categories_management') . ' · '); - } - - /** - * This action handles the feed configuration page. - * - * It displays the feed configuration page. - * If this action is reached through a POST request, it stores all new - * configuraiton values then sends a notification to the user. - * - * The options available on the page are: - * - name - * - description - * - website URL - * - feed URL - * - category id (default: default category id) - * - CSS path to article on website - * - display in main stream (default: 0) - * - HTTP authentication - * - number of article to retain (default: -2) - * - refresh frequency (default: -2) - * Default values are empty strings unless specified. - */ - public function feedAction() { - if (Minz_Request::param('ajax')) { - $this->view->_useLayout(false); - } - - $catDAO = new FreshRSS_CategoryDAO(); - $this->view->categories = $catDAO->listCategories(false); - - $feedDAO = FreshRSS_Factory::createFeedDao(); - $this->view->feeds = $feedDAO->listFeeds(); - - $id = Minz_Request::param('id'); - if ($id == false && !empty($this->view->feeds)) { - $id = current($this->view->feeds)->id(); - } - - $this->view->flux = false; - if ($id != false) { - $this->view->flux = $this->view->feeds[$id]; - - if (!$this->view->flux) { - Minz_Error::error( - 404, - array('error' => array(_t('page_not_found'))) - ); - } else { - if (Minz_Request::isPost() && $this->view->flux) { - $user = Minz_Request::param('http_user', ''); - $pass = Minz_Request::param('http_pass', ''); - - $httpAuth = ''; - if ($user != '' || $pass != '') { - $httpAuth = $user . ':' . $pass; - } - - $cat = intval(Minz_Request::param('category', 0)); - - $values = array( - 'name' => Minz_Request::param('name', ''), - 'description' => sanitizeHTML(Minz_Request::param('description', '', true)), - 'website' => Minz_Request::param('website', ''), - 'url' => Minz_Request::param('url', ''), - 'category' => $cat, - 'pathEntries' => Minz_Request::param('path_entries', ''), - 'priority' => intval(Minz_Request::param('priority', 0)), - 'httpAuth' => $httpAuth, - 'keep_history' => intval(Minz_Request::param('keep_history', -2)), - 'ttl' => intval(Minz_Request::param('ttl', -2)), - ); - - if ($feedDAO->updateFeed($id, $values)) { - $this->view->flux->_category($cat); - $this->view->flux->faviconPrepare(); - $notif = array( - 'type' => 'good', - 'content' => _t('feed_updated') - ); - } else { - $notif = array( - 'type' => 'bad', - 'content' => _t('error_occurred_update') - ); - } - invalidateHttpCache(); - - Minz_Session::_param('notification', $notif); - Minz_Request::forward(array('c' => 'configure', 'a' => 'feed', 'params' => array('id' => $id)), true); - } - - Minz_View::prependTitle(_t('rss_feed_management') . ' — ' . $this->view->flux->name() . ' · '); - } - } else { - Minz_View::prependTitle(_t('rss_feed_management') . ' · '); - } } /** diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php new file mode 100644 index 000000000..ab00f3e6a --- /dev/null +++ b/app/Controllers/subscriptionController.php @@ -0,0 +1,130 @@ +view->loginOk) { + Minz_Error::error( + 403, + array('error' => array(_t('access_denied'))) + ); + } + } + + /** + * This action handles the main subscription page + * + * It displays categories and associated feeds. + */ + public function indexAction() { + $catDAO = new FreshRSS_CategoryDAO(); + + $this->view->categories = $catDAO->listCategories(false); + $this->view->default_category = $catDAO->getDefault(); + + Minz_View::prependTitle(_t('subscription_management') . ' · '); + } + + /** + * This action handles the feed configuration page. + * + * It displays the feed configuration page. + * If this action is reached through a POST request, it stores all new + * configuraiton values then sends a notification to the user. + * + * The options available on the page are: + * - name + * - description + * - website URL + * - feed URL + * - category id (default: default category id) + * - CSS path to article on website + * - display in main stream (default: 0) + * - HTTP authentication + * - number of article to retain (default: -2) + * - refresh frequency (default: -2) + * Default values are empty strings unless specified. + */ + public function feedAction() { + if (Minz_Request::param('ajax')) { + $this->view->_useLayout(false); + } + + $catDAO = new FreshRSS_CategoryDAO(); + $this->view->categories = $catDAO->listCategories(false); + + $feedDAO = FreshRSS_Factory::createFeedDao(); + $this->view->feeds = $feedDAO->listFeeds(); + + $id = Minz_Request::param('id'); + if ($id == false && !empty($this->view->feeds)) { + $id = current($this->view->feeds)->id(); + } + + $this->view->flux = false; + if ($id != false) { + $this->view->flux = $this->view->feeds[$id]; + + if (!$this->view->flux) { + Minz_Error::error( + 404, + array('error' => array(_t('page_not_found'))) + ); + } else { + if (Minz_Request::isPost() && $this->view->flux) { + $user = Minz_Request::param('http_user', ''); + $pass = Minz_Request::param('http_pass', ''); + + $httpAuth = ''; + if ($user != '' || $pass != '') { + $httpAuth = $user . ':' . $pass; + } + + $cat = intval(Minz_Request::param('category', 0)); + + $values = array( + 'name' => Minz_Request::param('name', ''), + 'description' => sanitizeHTML(Minz_Request::param('description', '', true)), + 'website' => Minz_Request::param('website', ''), + 'url' => Minz_Request::param('url', ''), + 'category' => $cat, + 'pathEntries' => Minz_Request::param('path_entries', ''), + 'priority' => intval(Minz_Request::param('priority', 0)), + 'httpAuth' => $httpAuth, + 'keep_history' => intval(Minz_Request::param('keep_history', -2)), + 'ttl' => intval(Minz_Request::param('ttl', -2)), + ); + + if ($feedDAO->updateFeed($id, $values)) { + $this->view->flux->_category($cat); + $this->view->flux->faviconPrepare(); + $notif = array( + 'type' => 'good', + 'content' => _t('feed_updated') + ); + } else { + $notif = array( + 'type' => 'bad', + 'content' => _t('error_occurred_update') + ); + } + invalidateHttpCache(); + + Minz_Session::_param('notification', $notif); + Minz_Request::forward(array('c' => 'subscription'), true); + } + + Minz_View::prependTitle(_t('rss_feed_management') . ' · ' . $this->view->flux->name() . ' · '); + } + } else { + Minz_View::prependTitle(_t('rss_feed_management') . ' · '); + } + } +} diff --git a/app/Models/Themes.php b/app/Models/Themes.php index 68fc17a2b..e3b260261 100644 --- a/app/Models/Themes.php +++ b/app/Models/Themes.php @@ -82,6 +82,7 @@ class FreshRSS_Themes extends Minz_Model { 'favorite' => '★', 'help' => 'ⓘ', 'icon' => '⊚', + 'import' => '⤓', 'key' => '⚿', 'link' => '↗', 'login' => '🔒', diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml deleted file mode 100644 index c028c4918..000000000 --- a/app/layout/aside_feed.phtml +++ /dev/null @@ -1,60 +0,0 @@ - diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index aac3c0896..341697103 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -7,8 +7,8 @@
  • - - + +
  • diff --git a/app/layout/aside_subscription.phtml b/app/layout/aside_subscription.phtml new file mode 100644 index 000000000..9a95763c3 --- /dev/null +++ b/app/layout/aside_subscription.phtml @@ -0,0 +1,17 @@ + diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml deleted file mode 100644 index f5030ef2c..000000000 --- a/app/views/configure/categorize.phtml +++ /dev/null @@ -1,90 +0,0 @@ -partial('aside_feed'); ?> - -
    - - -

    - -

    - default_category->name()); ?> -

    - -
    -
    - -
      -
      -
    • -
    • -
      -
    -
    - - - - categories as $cat) { - $feeds = $cat->feeds(); - ?> -
    -
    -
    - - - -
    -
    - -
      - - inError() ? ' error' : ''; - $empty = $feed->nbEntries() == 0 ? ' empty' : ''; - ?> -
    • - - ✇ name(); ?> -
    • - -
    • - -
    -
    - -
    - -
    -
    diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml deleted file mode 100644 index f58ac65af..000000000 --- a/app/views/configure/feed.phtml +++ /dev/null @@ -1,186 +0,0 @@ -partial('aside_feed'); - } -?> - -flux) { ?> -
    - - -

    flux->name (); ?>

    - flux->description (); ?> - - flux->nbEntries (); ?> - - flux->inError ()) { ?> -

    - -

    - - -
    - -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    -
    - - -
    -
    -
    -
    - -
    -
    - - -
    - - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - - - -
    -
    -
    -
    - - -
    -
    - - - -
    -
    -
    - - - - -
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - - -
    -
    - - - flux->httpAuth (false); ?> -
    - -
    - - -
    - - -
    - -
    -
    - -
    -
    - - -
    -
    - - -
    - -
    - - -
    -
    - -
    -
    - - -
    -
    -
    -
    - - -
    - diff --git a/app/views/importExport/index.phtml b/app/views/importExport/index.phtml index 35371faca..36c0eab4e 100644 --- a/app/views/importExport/index.phtml +++ b/app/views/importExport/index.phtml @@ -1,4 +1,4 @@ -partial('aside_feed'); ?> +partial('aside_subscription'); ?>
    diff --git a/app/views/subscription/feed.phtml b/app/views/subscription/feed.phtml new file mode 100644 index 000000000..e047741a1 --- /dev/null +++ b/app/views/subscription/feed.phtml @@ -0,0 +1,186 @@ +partial('aside_subscription'); + } +?> + +flux) { ?> +
    + + +

    flux->name (); ?>

    + flux->description (); ?> + + flux->nbEntries (); ?> + + flux->inError ()) { ?> +

    + +

    + + +
    + +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + +
    +
    + + +
    + + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + + +
    +
    +
    +
    + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + +
    +
    + + + flux->httpAuth (false); ?> +
    + +
    + + +
    + + +
    + +
    +
    + +
    +
    + + +
    +
    + + +
    + +
    + + +
    +
    + +
    +
    + + +
    +
    +
    +
    + + +
    + diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml new file mode 100644 index 000000000..444dc9d9b --- /dev/null +++ b/app/views/subscription/index.phtml @@ -0,0 +1,132 @@ +partial('aside_subscription'); ?> + +
    + + +

    + +
    +
    + + + +
    +
    + +

    + default_category->name()); ?> +

    + +
    +
    + +
      +
      +
    • +
    • +
      +
    +
    + + + + categories as $cat) { + $feeds = $cat->feeds(); + ?> +
    +
    +
    + + + +
    +
    + +
      + + inError() ? ' error' : ''; + $empty = $feed->nbEntries() == 0 ? ' empty' : ''; + ?> +
    • + + ✇ name(); ?> +
    • + +
    • + +
    +
    + +
    + +
    +
    diff --git a/p/themes/icons/import.svg b/p/themes/icons/import.svg new file mode 100644 index 000000000..a7f20c909 --- /dev/null +++ b/p/themes/icons/import.svg @@ -0,0 +1,9 @@ + + + + + + + + + -- cgit v1.2.3 From 405f23050b18e8388edb6f8be90aa59c17ada421 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 1 Oct 2014 13:55:30 +0200 Subject: Design of the slider See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/views/subscription/index.phtml | 5 +++-- p/scripts/main.js | 14 ++++++++++---- p/themes/base-theme/template.css | 24 +++++++++++++++++++++++- 3 files changed, 36 insertions(+), 7 deletions(-) (limited to 'p') diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml index 2d55890f7..10578bdd3 100644 --- a/app/views/subscription/index.phtml +++ b/app/views/subscription/index.phtml @@ -134,9 +134,10 @@
    -
    + +
    feed) ? ' class="active"' : ''; ?>> feed) && $this->feed) { + if (isset($this->feed)) { $this->renderHelper('feed/update'); } ?> diff --git a/p/scripts/main.js b/p/scripts/main.js index 7fed7a819..925a93650 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1241,7 +1241,8 @@ function faviconNbUnread(n) { } function init_slider_observers() { - var slider = $('#slider'); + var slider = $('#slider'), + closer = $('#close-slider'); if (slider.length < 1) { return; } @@ -1252,7 +1253,6 @@ function init_slider_observers() { } ajax_loading = true; - var url_slide = $(this).attr('href'); $.ajax({ @@ -1261,12 +1261,18 @@ function init_slider_observers() { data : { ajax: true } }).done(function (data) { slider.html(data); - slider.show(); + closer.addClass('active'); + slider.addClass('active'); ajax_loading = false; }); return false; - }) + }); + + closer.on('click', function() { + closer.removeClass('active'); + slider.removeClass('active'); + }); } function init_all() { diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 397f943a6..e6c832ee4 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -647,7 +647,29 @@ br + br + br { /*=== Slider */ #slider { - min-height: 50px; + position: fixed; + top: 0; bottom: 0; + left: 100%; right: 0; + overflow: auto; + background: #fff; + border-left: 1px solid #aaa; + transition: left 200ms linear; + -moz-transition: left 200ms linear; + -webkit-transition: left 200ms linear; + -o-transition: left 200ms linear; + -ms-transition: left 200ms linear; +} +#slider.active { + left: 40%; +} +#close-slider { + position: fixed; + top: 0; bottom: 0; + left: 100%; right: 0; + cursor: pointer; +} +#close-slider.active { + left: 0; } /*=== DIVERS */ -- cgit v1.2.3 From fe655e0d9d2fb1173099d77c478bbb2f7ac8b1e1 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 1 Oct 2014 13:58:09 +0200 Subject: Fix close slider when a feed is selected See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/views/subscription/index.phtml | 5 +++-- p/scripts/main.js | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'p') diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml index 10578bdd3..577ddd972 100644 --- a/app/views/subscription/index.phtml +++ b/app/views/subscription/index.phtml @@ -134,8 +134,9 @@
    - -
    feed) ? ' class="active"' : ''; ?>> +feed) ? ' class="active"' : ''; ?> +> +
    > feed)) { $this->renderHelper('feed/update'); diff --git a/p/scripts/main.js b/p/scripts/main.js index 925a93650..005dc961b 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1272,6 +1272,7 @@ function init_slider_observers() { closer.on('click', function() { closer.removeClass('active'); slider.removeClass('active'); + return false; }); } -- cgit v1.2.3 From bbedca510bb0b88850476bf2e2aa6af8c02ac741 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 09:21:08 +0200 Subject: Better import icon See https://github.com/marienfressinaud/FreshRSS/issues/646 --- p/themes/icons/import.svg | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'p') diff --git a/p/themes/icons/import.svg b/p/themes/icons/import.svg index a7f20c909..18a54ab59 100644 --- a/p/themes/icons/import.svg +++ b/p/themes/icons/import.svg @@ -1,9 +1 @@ - - - - - - - - - + -- cgit v1.2.3 From 9b2ad32e98e4720d5ee422fccd3069f086ee8563 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 10:05:26 +0200 Subject: Fix a bug in main.js In global view, there is no ".category.all>a" element so we tried to apply str2int on an undefined value. In consequence, we were not able to mark several articles as read This patch need to apply on 0.8.1 and 0.9.1 See https://github.com/marienfressinaud/FreshRSS/issues/649 --- p/scripts/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'p') diff --git a/p/scripts/main.js b/p/scripts/main.js index 7cd53c745..c9e8dd299 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -33,7 +33,7 @@ function needsScroll($elem) { } function str2int(str) { - if (str == '') { + if (str == '' || str === undefined) { return 0; } return parseInt(str.replace(/\D/g, ''), 10) || 0; -- cgit v1.2.3 From db4da3babc0864099c5ab48e3583d0546a2759d8 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 11:39:51 +0200 Subject: First draft for drag and drop We can change feed category by drag and drop! Need improvements... See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/feedController.php | 15 ++++++++ app/Controllers/subscriptionController.php | 2 ++ app/views/subscription/index.phtml | 4 +-- p/scripts/category.js | 55 ++++++++++++++++++++++++++++++ p/scripts/main.js | 2 +- p/themes/Origine/origine.css | 9 +++++ 6 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 p/scripts/category.js (limited to 'p') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index e4859b110..315665ef3 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -378,6 +378,21 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } + public function moveAction() { + if (Minz_Request::isPost()) { + $feed_id = Minz_Request::param('f_id'); + $cat_id = Minz_Request::param('c_id'); + + $feedDAO = FreshRSS_Factory::createFeedDao(); + + $values = array( + 'category' => $cat_id, + ); + + $feedDAO->updateFeed($feed_id, $values); + } + } + public function deleteAction() { if (Minz_Request::isPost()) { $id = Minz_Request::param('id'); diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php index aabae7b8f..7cc8179a0 100644 --- a/app/Controllers/subscriptionController.php +++ b/app/Controllers/subscriptionController.php @@ -30,6 +30,8 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { * It displays categories and associated feeds. */ public function indexAction() { + Minz_View::appendScript(Minz_Url::display('/scripts/category.js?' . + @filemtime(PUBLIC_PATH . '/scripts/category.js'))); Minz_View::prependTitle(_t('subscription_management') . ' · '); $id = Minz_Request::param('id'); diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml index 577ddd972..3a79a34e6 100644 --- a/app/views/subscription/index.phtml +++ b/app/views/subscription/index.phtml @@ -113,14 +113,14 @@
    -
      +
        inError() ? ' error' : ''; $empty = $feed->nbEntries() == 0 ? ' empty' : ''; ?> -
      • +
      • ✇ name(); ?>
      • diff --git a/p/scripts/category.js b/p/scripts/category.js new file mode 100644 index 000000000..fe80c3b22 --- /dev/null +++ b/p/scripts/category.js @@ -0,0 +1,55 @@ +"use strict"; + + +function init_draggable() { + var feeds_draggable = '.box-content > .feed', + box_dropzone = '.box-content'; + + $('.box').on('dragstart', feeds_draggable, function(e) { + e.originalEvent.dataTransfer.effectAllowed = 'move'; + e.originalEvent.dataTransfer.setData('html', e.target.outerHTML); + e.originalEvent.dataTransfer.setData('feed-id', e.target.getAttribute('data-feed-id')); + }); + $('.box').on('dragend', feeds_draggable, function(e) { + var parent = e.target.parentNode; + parent.removeChild(e.target); + }); + + $('.box').on('dragenter', box_dropzone, function(e) { + $(e.target).addClass('drag-hover'); + }); + $('.box').on('dragleave', box_dropzone, function(e) { + $(e.target).removeClass('drag-hover'); + }); + $('.box').on('dragover', box_dropzone, function(e) { + e.originalEvent.dataTransfer.dropEffect = "move"; + + return false; + }); + $('.box').on('drop', box_dropzone, function(e) { + var feed_id = e.originalEvent.dataTransfer.getData('feed-id'), + cat_id = e.target.parentNode.getAttribute('data-cat-id'); + + $.ajax({ + type: 'POST', + url: './?c=feed&a=move', + data : { + f_id: feed_id, + c_id: cat_id + } + }); + + $(e.target).after(e.originalEvent.dataTransfer.getData('html')); + $(e.target).removeClass('drag-hover'); + return false; + }); +} + + +if (document.readyState && document.readyState !== 'loading') { + init_draggable(); +} else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', function () { + init_draggable(); + }, false); +} diff --git a/p/scripts/main.js b/p/scripts/main.js index 005dc961b..e8055e00f 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1247,7 +1247,7 @@ function init_slider_observers() { return; } - $('.open-slider').on('click', function() { + $('.post').on('click', '.open-slider', function() { if (ajax_loading) { return false; } diff --git a/p/themes/Origine/origine.css b/p/themes/Origine/origine.css index e3ae85075..cf6c9a2ef 100644 --- a/p/themes/Origine/origine.css +++ b/p/themes/Origine/origine.css @@ -497,6 +497,15 @@ a.btn { visibility: visible; } +/*=== Draggable */ +.drag-hover { + background: #dfd; + transition: all linear 0.2s; +} +[draggable=true] { + cursor: grab; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ -- cgit v1.2.3 From 50f07febaed5e839d4e7d56a664c8a208bc2aaf5 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 12:13:16 +0200 Subject: Add dataTransfer property to event for JQuery See https://github.com/marienfressinaud/FreshRSS/issues/646 --- p/scripts/category.js | 15 +++++++++------ p/themes/Origine/origine.css | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'p') diff --git a/p/scripts/category.js b/p/scripts/category.js index fe80c3b22..4378aa9cd 100644 --- a/p/scripts/category.js +++ b/p/scripts/category.js @@ -2,17 +2,20 @@ function init_draggable() { + $.event.props.push('dataTransfer'); + var feeds_draggable = '.box-content > .feed', box_dropzone = '.box-content'; $('.box').on('dragstart', feeds_draggable, function(e) { - e.originalEvent.dataTransfer.effectAllowed = 'move'; - e.originalEvent.dataTransfer.setData('html', e.target.outerHTML); - e.originalEvent.dataTransfer.setData('feed-id', e.target.getAttribute('data-feed-id')); + e.dataTransfer.effectAllowed = 'move'; + e.dataTransfer.setData('html', e.target.outerHTML); + e.dataTransfer.setData('feed-id', e.target.getAttribute('data-feed-id')); }); $('.box').on('dragend', feeds_draggable, function(e) { var parent = e.target.parentNode; parent.removeChild(e.target); + }); $('.box').on('dragenter', box_dropzone, function(e) { @@ -22,12 +25,12 @@ function init_draggable() { $(e.target).removeClass('drag-hover'); }); $('.box').on('dragover', box_dropzone, function(e) { - e.originalEvent.dataTransfer.dropEffect = "move"; + e.dataTransfer.dropEffect = "move"; return false; }); $('.box').on('drop', box_dropzone, function(e) { - var feed_id = e.originalEvent.dataTransfer.getData('feed-id'), + var feed_id = e.dataTransfer.getData('feed-id'), cat_id = e.target.parentNode.getAttribute('data-cat-id'); $.ajax({ @@ -39,7 +42,7 @@ function init_draggable() { } }); - $(e.target).after(e.originalEvent.dataTransfer.getData('html')); + $(e.target).after(e.dataTransfer.getData('html')); $(e.target).removeClass('drag-hover'); return false; }); diff --git a/p/themes/Origine/origine.css b/p/themes/Origine/origine.css index cf6c9a2ef..c79f6cc4c 100644 --- a/p/themes/Origine/origine.css +++ b/p/themes/Origine/origine.css @@ -481,6 +481,7 @@ a.btn { border-radius: 5px 5px 0 0; } .box .box-content { + min-height: 2.5em; max-height: 260px; } -- cgit v1.2.3 From 6effa82cef4ea8fd98178e72b270de6ea4f9f80f Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 15:02:42 +0200 Subject: Improve drag and drop - Refactoring - Better design - Item doesn't disappear if action is not completed See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/views/subscription/index.phtml | 11 ++++--- p/scripts/category.js | 63 +++++++++++++++++++++++++++++--------- p/themes/Origine/origine.css | 9 ------ p/themes/base-theme/template.css | 12 ++++++++ 4 files changed, 67 insertions(+), 28 deletions(-) (limited to 'p') diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml index 3a79a34e6..2c56f79ed 100644 --- a/app/views/subscription/index.phtml +++ b/app/views/subscription/index.phtml @@ -1,6 +1,6 @@ partial('aside_subscription'); ?> -
        +

        @@ -113,21 +113,24 @@
        -
          +
            inError() ? ' error' : ''; $empty = $feed->nbEntries() == 0 ? ' empty' : ''; ?> -
          • +
          • ✇ name(); ?>
          • -
          • +
        diff --git a/p/scripts/category.js b/p/scripts/category.js index 4378aa9cd..37ad36b17 100644 --- a/p/scripts/category.js +++ b/p/scripts/category.js @@ -1,38 +1,66 @@ "use strict"; +var loading = false, + dnd_successful = false; + +function dragend_process(t) { + if (loading) { + window.setTimeout(function() { + dragend_process(t); + }, 50); + } + + if (!dnd_successful) { + t.style.opacity = 1.0; + } else { + t.parentNode.removeChild(t); + } +} + function init_draggable() { + if (!(window.$ && window.url_freshrss)) { + if (window.console) { + console.log('FreshRSS waiting for JS…'); + } + window.setTimeout(init_draggable, 50); + return; + } + $.event.props.push('dataTransfer'); - var feeds_draggable = '.box-content > .feed', - box_dropzone = '.box-content'; + var draggable = '[draggable="true"]', + dropzone = '[dropzone="move"]'; - $('.box').on('dragstart', feeds_draggable, function(e) { + $('.drop-section').on('dragstart', draggable, function(e) { e.dataTransfer.effectAllowed = 'move'; - e.dataTransfer.setData('html', e.target.outerHTML); - e.dataTransfer.setData('feed-id', e.target.getAttribute('data-feed-id')); + e.dataTransfer.setData('text/html', e.target.outerHTML); + e.dataTransfer.setData('text', e.target.getAttribute('data-feed-id')); + e.target.style.opacity = 0.3; + + dnd_successful = false; }); - $('.box').on('dragend', feeds_draggable, function(e) { - var parent = e.target.parentNode; - parent.removeChild(e.target); - + $('.drop-section').on('dragend', draggable, function(e) { + dragend_process(e.target); }); - $('.box').on('dragenter', box_dropzone, function(e) { + $('.drop-section').on('dragenter', dropzone, function(e) { $(e.target).addClass('drag-hover'); }); - $('.box').on('dragleave', box_dropzone, function(e) { + $('.drop-section').on('dragleave', dropzone, function(e) { $(e.target).removeClass('drag-hover'); }); - $('.box').on('dragover', box_dropzone, function(e) { + $('.drop-section').on('dragover', dropzone, function(e) { e.dataTransfer.dropEffect = "move"; return false; }); - $('.box').on('drop', box_dropzone, function(e) { - var feed_id = e.dataTransfer.getData('feed-id'), + $('.drop-section').on('drop', dropzone, function(e) { + var feed_id = e.dataTransfer.getData('text'), cat_id = e.target.parentNode.getAttribute('data-cat-id'); + loading = true; + $.ajax({ type: 'POST', url: './?c=feed&a=move', @@ -40,10 +68,15 @@ function init_draggable() { f_id: feed_id, c_id: cat_id } + }).success(function() { + $(e.target).after(e.dataTransfer.getData('text/html')); + loading = false; + }).complete(function() { + dnd_successful = true; }); - $(e.target).after(e.dataTransfer.getData('html')); $(e.target).removeClass('drag-hover'); + return false; }); } diff --git a/p/themes/Origine/origine.css b/p/themes/Origine/origine.css index c79f6cc4c..b25deab0c 100644 --- a/p/themes/Origine/origine.css +++ b/p/themes/Origine/origine.css @@ -498,15 +498,6 @@ a.btn { visibility: visible; } -/*=== Draggable */ -.drag-hover { - background: #dfd; - transition: all linear 0.2s; -} -[draggable=true] { - cursor: grab; -} - /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index e6c832ee4..06874c9fe 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -304,6 +304,10 @@ a.btn { .box .box-content .item { display: block; } +.box .box-content .item.disabled { + text-align: center; + font-style: italic; +} .box .box-content-centered { padding: 30px 5px; @@ -313,6 +317,14 @@ a.btn { margin: 20px 0 0; } +/*=== Draggable */ +.drag-hover { + margin: 0 0 5px; + border-bottom: 2px solid #ccc; +} +[draggable=true] { + cursor: grab; +} /*=== STRUCTURE */ /*===============*/ -- cgit v1.2.3 From 408ac31dd8751eba037db216243958d396df1c8e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 19:02:43 +0200 Subject: Hack for dragleave (triggered on children!) See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/feedController.php | 7 ++++++- p/scripts/category.js | 33 ++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) (limited to 'p') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 315665ef3..b2b53185e 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -389,7 +389,12 @@ class FreshRSS_feed_Controller extends Minz_ActionController { 'category' => $cat_id, ); - $feedDAO->updateFeed($feed_id, $values); + if (!$feedDAO->updateFeed($feed_id, $values)) { + Minz_Error::error( + 404, + array('error' => array(_t('error_occurred'))) + ); + } } } diff --git a/p/scripts/category.js b/p/scripts/category.js index 37ad36b17..872d14490 100644 --- a/p/scripts/category.js +++ b/p/scripts/category.js @@ -4,6 +4,8 @@ var loading = false, dnd_successful = false; function dragend_process(t) { + t.style.display = 'none'; + if (loading) { window.setTimeout(function() { dragend_process(t); @@ -11,13 +13,13 @@ function dragend_process(t) { } if (!dnd_successful) { + t.style.display = 'block'; t.style.opacity = 1.0; } else { t.parentNode.removeChild(t); } } - function init_draggable() { if (!(window.$ && window.url_freshrss)) { if (window.console) { @@ -45,14 +47,31 @@ function init_draggable() { }); $('.drop-section').on('dragenter', dropzone, function(e) { - $(e.target).addClass('drag-hover'); + $(this).addClass('drag-hover'); + + e.preventDefault(); }); $('.drop-section').on('dragleave', dropzone, function(e) { - $(e.target).removeClass('drag-hover'); + var pos_this = $(this).position(), + scroll_top = $(document).scrollTop(), + top = pos_this.top, + left = pos_this.left, + right = left + $(this).width(), + bottom = top + $(this).height(), + mouse_x = e.originalEvent.screenX, + mouse_y = e.originalEvent.clientY + scroll_top; + + if (left <= mouse_x && mouse_x <= right && + top <= mouse_y && mouse_y <= bottom) { + // HACK because dragleave is triggered when hovering children! + return; + } + $(this).removeClass('drag-hover'); }); $('.drop-section').on('dragover', dropzone, function(e) { e.dataTransfer.dropEffect = "move"; + e.preventDefault(); return false; }); $('.drop-section').on('drop', dropzone, function(e) { @@ -70,14 +89,14 @@ function init_draggable() { } }).success(function() { $(e.target).after(e.dataTransfer.getData('text/html')); - loading = false; - }).complete(function() { dnd_successful = true; + }).complete(function() { + loading = false; }); - $(e.target).removeClass('drag-hover'); + $(this).removeClass('drag-hover'); - return false; + e.preventDefault(); }); } -- cgit v1.2.3 From ce43b1761b810c89e5e8660e8ae2638e97ca6339 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 19:47:02 +0200 Subject: Fix box when no feed in category See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/views/helpers/javascript_vars.phtml | 1 + p/scripts/category.js | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'p') diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 1139eb446..71798369d 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -54,6 +54,7 @@ echo 'authType="', $authType, '",', echo 'str_confirmation_default="', Minz_Translate::t('confirm_action'), '"', ",\n"; echo 'str_notif_title_articles="', Minz_Translate::t('notif_title_new_articles'), '"', ",\n"; echo 'str_notif_body_articles="', Minz_Translate::t('notif_body_new_articles'), '"', ",\n"; +echo 'str_category_empty="', Minz_Translate::t('category_empty'), '"', ",\n"; echo 'html5_notif_timeout=', $this->conf->html5_notif_timeout,",\n"; diff --git a/p/scripts/category.js b/p/scripts/category.js index 872d14490..dc5df67e4 100644 --- a/p/scripts/category.js +++ b/p/scripts/category.js @@ -16,7 +16,12 @@ function dragend_process(t) { t.style.display = 'block'; t.style.opacity = 1.0; } else { - t.parentNode.removeChild(t); + var parent = $(t.parentNode); + $(t).remove(); + + if (parent.children().length <= 0) { + parent.append('
      • ' + str_category_empty + '
      • '); + } } } @@ -89,6 +94,9 @@ function init_draggable() { } }).success(function() { $(e.target).after(e.dataTransfer.getData('text/html')); + if ($(e.target).hasClass('disabled')) { + $(e.target).remove(); + } dnd_successful = true; }).complete(function() { loading = false; -- cgit v1.2.3 From 9f8d3d0527988b768f739fd4c0e61de68dfdd822 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 3 Oct 2014 12:18:43 +0200 Subject: Fix configure icon on Flat design See https://github.com/marienfressinaud/FreshRSS/issues/468 --- p/themes/Flat/flat.css | 5 +++++ p/themes/base-theme/template.css | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'p') diff --git a/p/themes/Flat/flat.css b/p/themes/Flat/flat.css index d0ac46fd5..7b2695781 100644 --- a/p/themes/Flat/flat.css +++ b/p/themes/Flat/flat.css @@ -464,6 +464,11 @@ a.btn { .box .box-content .item .configure { visibility: hidden; } +.box .box-content .item .configure .icon { + vertical-align: middle; + background-color: #95a5a6; + border-radius: 3px; +} .box .box-content .item:hover .configure { visibility: visible; } diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 06874c9fe..1a96f1e2f 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -73,7 +73,9 @@ label { input { width: 180px; } -textarea { +textarea, +input[type="file"], +input.extend:focus { width: 300px; } input, select, textarea { @@ -85,9 +87,6 @@ input[type="checkbox"] { width: 15px !important; min-height: 15px !important; } -input.extend:focus { - width: 300px; -} button.as-link, button.as-link:hover, button.as-link:active { -- cgit v1.2.3 From 783171011dc6256f37cbd4365f5405b5e8a4b44e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 4 Oct 2014 10:30:40 +0200 Subject: Fix icon not appearing (Flat theme) See https://github.com/marienfressinaud/FreshRSS/issues/651 --- p/themes/Flat/flat.css | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'p') diff --git a/p/themes/Flat/flat.css b/p/themes/Flat/flat.css index 7b2695781..e2151b1f9 100644 --- a/p/themes/Flat/flat.css +++ b/p/themes/Flat/flat.css @@ -652,6 +652,12 @@ a.btn { padding: 5px 0; } +#dropdown-query ~ .dropdown-menu .dropdown-header .icon { + vertical-align: middle; + background-color: #95a5a6; + border-radius: 3px; +} + /*=== Feed articles */ .flux { border-left: 2px solid #ecf0f1; -- cgit v1.2.3 From 91cc88209c710e64cd8a10397e56d006d4566624 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 4 Oct 2014 08:45:57 -0400 Subject: Remove debugging code --- p/scripts/main.js | 2 -- 1 file changed, 2 deletions(-) (limited to 'p') diff --git a/p/scripts/main.js b/p/scripts/main.js index 37281a907..02d16ca64 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -384,8 +384,6 @@ function collapse_entry() { } function user_filter(key) { - console.log('user filter'); - console.warn(key); var filter = $('#dropdown-query'); var filters = filter.siblings('.dropdown-menu').find('.item.query a'); if (typeof key === "undefined") { -- cgit v1.2.3 From 7a59568dfc20589c0495235679a96a375e36cfee Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 4 Oct 2014 08:46:11 -0400 Subject: Fix library with code provided in the comments of the library page. The fix was given by the owner of the project (I assume) but was never integrated in the code. There is no bug tracker so I couldn't open a ticket. It looks like the project is dead since there is modification to the library. --- p/scripts/shortcut.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'p') diff --git a/p/scripts/shortcut.js b/p/scripts/shortcut.js index debaffbaa..4137172c3 100644 --- a/p/scripts/shortcut.js +++ b/p/scripts/shortcut.js @@ -43,7 +43,9 @@ shortcut = { //Find Which key is pressed if (e.keyCode) code = e.keyCode; else if (e.which) code = e.which; - var character = String.fromCharCode(code).toLowerCase(); + if( code == 32 || (code >= 48 && code <= 90) || (code >= 96 && code <= 111) || (code >= 186 && code <= 192) || (code >= 219 && code <= 222)) { + var character = String.fromCharCode(code).toLowerCase(); + } if(code == 188) character=","; //If the user presses , when the type is onkeydown if(code == 190) character="."; //If the user presses , when the type is onkeydown -- cgit v1.2.3 From 38a6f0c4b29e5a53c21f345dd839a4fa0b2a6f47 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 4 Oct 2014 09:06:35 -0400 Subject: Add a shortcut to close drop-down lists --- app/Models/Configuration.php | 1 + app/i18n/en.php | 1 + app/i18n/fr.php | 1 + app/views/configure/shortcut.phtml | 7 +++++++ app/views/helpers/javascript_vars.phtml | 3 ++- p/scripts/main.js | 6 ++++++ 6 files changed, 18 insertions(+), 1 deletion(-) (limited to 'p') diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 95f819779..feba3d2f6 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -47,6 +47,7 @@ class FreshRSS_Configuration { 'focus_search' => 'a', 'user_filter' => 'u', 'help' => 'f1', + 'close_dropdown' => 'escape', ), 'topline_read' => true, 'topline_favorite' => true, diff --git a/app/i18n/en.php b/app/i18n/en.php index 28104196e..0456049a9 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -191,6 +191,7 @@ return array ( 'user_filter' => 'Access user filters', 'user_filter_help' => 'If there is only one user filter, it is used. Else filters are accessible by their number.', 'help' => 'Display documentation', + 'close_dropdown' => 'Close drop-down lists', 'file_to_import' => 'File to import
        (OPML, Json or Zip)', 'file_to_import_no_zip' => 'File to import
        (OPML or Json)', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index c72fc3e93..adc79d0e2 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -191,6 +191,7 @@ return array ( 'user_filter' => 'Accéder aux filtres utilisateur', 'user_filter_help' => 'S’il n’y a qu’un filtre utilisateur, celui ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', 'help' => 'Afficher la documentation', + 'close_dropdown' => 'Fermer les listes déroulantes', 'file_to_import' => 'Fichier à importer
        (OPML, Json ou Zip)', 'file_to_import_no_zip' => 'Fichier à importer
        (OPML ou Json)', diff --git a/app/views/configure/shortcut.phtml b/app/views/configure/shortcut.phtml index a4029b676..44727e62b 100644 --- a/app/views/configure/shortcut.phtml +++ b/app/views/configure/shortcut.phtml @@ -111,6 +111,13 @@
    +
    + +
    + +
    +
    +
    diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 71798369d..4f7e3db0c 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -28,7 +28,8 @@ echo ',shortcuts={', 'auto_share:"', $s['auto_share'], '",', 'focus_search:"', $s['focus_search'], '",', 'user_filter:"', $s['user_filter'], '",', - 'help:"', $s['help'], '"', + 'help:"', $s['help'], '",', + 'close_dropdown:"', $s['close_dropdown'], '"', "},\n"; if (Minz_Request::param ('output') === 'global') { diff --git a/p/scripts/main.js b/p/scripts/main.js index 37281a907..0d90d3d39 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -663,6 +663,12 @@ function init_shortcuts() { 'disable_in_input': true }); + shortcut.add(shortcuts.close_dropdown, function () { + window.location.hash = null; + }, { + 'disable_in_input': true + }); + } function init_stream(divStream) { -- cgit v1.2.3 From 6e6d7b3c870975b2981f653b6f53a31f800f56ec Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 5 Oct 2014 01:43:29 +0200 Subject: Minor JavaScript --- p/scripts/main.js | 2 +- p/scripts/shortcut.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'p') diff --git a/p/scripts/main.js b/p/scripts/main.js index 79a34ec29..5793bb50b 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -33,7 +33,7 @@ function needsScroll($elem) { } function str2int(str) { - if (str == '' || str === undefined) { + if (!str) { return 0; } return parseInt(str.replace(/\D/g, ''), 10) || 0; diff --git a/p/scripts/shortcut.js b/p/scripts/shortcut.js index 4137172c3..e78cf6f5e 100644 --- a/p/scripts/shortcut.js +++ b/p/scripts/shortcut.js @@ -43,7 +43,7 @@ shortcut = { //Find Which key is pressed if (e.keyCode) code = e.keyCode; else if (e.which) code = e.which; - if( code == 32 || (code >= 48 && code <= 90) || (code >= 96 && code <= 111) || (code >= 186 && code <= 192) || (code >= 219 && code <= 222)) { + if (code == 32 || (code >= 48 && code <= 90) || (code >= 96 && code <= 111) || (code >= 186 && code <= 192) || (code >= 219 && code <= 222)) { //FreshRSS var character = String.fromCharCode(code).toLowerCase(); } -- cgit v1.2.3 From febabccdd5e6db573ab80bd5c1758d136b91cd78 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 5 Oct 2014 12:14:22 +0200 Subject: Primitive extension system https://github.com/marienfressinaud/FreshRSS/issues/252 I have been using this extension system for a little while, in particular to include custom CSS and/or JavaScript (inclusion of PHP code is not done yet). There is very little code and it does not impact performances. I hurry to post it before https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/FreshRSS.php | 21 +++++++++++++++++++++ extensions/.gitignore | 1 + extensions/Read-me.txt | 15 +++++++++++++++ p/ext.php | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 extensions/.gitignore create mode 100644 extensions/Read-me.txt create mode 100644 p/ext.php (limited to 'p') diff --git a/app/FreshRSS.php b/app/FreshRSS.php index cdf8962cb..58aac4059 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -17,6 +17,7 @@ class FreshRSS extends Minz_FrontController { Minz_View::_param('loginOk', $loginOk); $this->loadStylesAndScripts($loginOk); //TODO: Do not load that when not needed, e.g. some Ajax requests $this->loadNotifications(); + $this->loadExtensions(); } private static function getCredentialsFromLongTermCookie() { @@ -179,4 +180,24 @@ class FreshRSS extends Minz_FrontController { Minz_Session::_param ('notification'); } } + + private function loadExtensions() { + $extensionPath = FRESHRSS_PATH . '/extensions/'; + //TODO: Add a preference to load only user-selected extensions + foreach (scandir($extensionPath) as $key => $extension) { + if (ctype_alpha($extension)) { + $mtime = @filemtime($extensionPath . $extension . '/style.css'); + if ($mtime !== false) { + Minz_View::appendStyle(Minz_Url::display('/ext.php?c&e=' . $extension . '&' . $mtime)); + } + $mtime = @filemtime($extensionPath . $extension . '/script.js'); + if ($mtime !== false) { + Minz_View::appendScript(Minz_Url::display('/ext.php?j&e=' . $extension . '&' . $mtime)); + } + if (file_exists($extensionPath . $extension . '/module.php')) { + //TODO: include + } + } + } + } } diff --git a/extensions/.gitignore b/extensions/.gitignore new file mode 100644 index 000000000..d93e5e396 --- /dev/null +++ b/extensions/.gitignore @@ -0,0 +1 @@ +/[xX] diff --git a/extensions/Read-me.txt b/extensions/Read-me.txt new file mode 100644 index 000000000..e7b66d5bc --- /dev/null +++ b/extensions/Read-me.txt @@ -0,0 +1,15 @@ +== FreshRSS extensions == + +You may place in this directory some custom extensions for FreshRSS. + +The structure must be: + +./FreshRSS/extensions/ + ./NameOfExtensionAlphanumeric/ + ./style.css + ./script.js + ./module.php + +Each file is optional. + +The name of non-official extensions should start by an 'x'. diff --git a/p/ext.php b/p/ext.php new file mode 100644 index 000000000..cff194343 --- /dev/null +++ b/p/ext.php @@ -0,0 +1,35 @@ + Date: Sun, 5 Oct 2014 12:38:13 +0200 Subject: Primitive extension system: minor change https://github.com/marienfressinaud/FreshRSS/issues/252 --- p/ext.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'p') diff --git a/p/ext.php b/p/ext.php index cff194343..a1dde2f93 100644 --- a/p/ext.php +++ b/p/ext.php @@ -20,6 +20,9 @@ if (isset($_GET['j'])) { header('Content-Type: text/css; charset=UTF-8'); header('Content-Disposition: inline; filename="style.css"'); $filename .= 'style.css'; +} else { + header('HTTP/1.1 400 Bad Request'); + die(); } $mtime = @filemtime($filename); -- cgit v1.2.3 From d8ed718aab99ad47897fb70ea9086fa704bb912b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 5 Oct 2014 17:29:09 +0200 Subject: Refactor javascript_vars.phtml Introduce kind of context objectin JavaScript See https://github.com/marienfressinaud/FreshRSS/issues/634 See https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/views/helpers/javascript_vars.phtml | 79 ++++++++++++++++----------------- p/scripts/category.js | 4 +- p/scripts/global_view.js | 2 +- p/scripts/main.js | 66 ++++++++++++--------------- 4 files changed, 70 insertions(+), 81 deletions(-) (limited to 'p') diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 011b17b7a..cdbf24eab 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -1,21 +1,30 @@ +"use strict"; conf->mark_when; -echo 'var ', - 'help_url="', FRESHRSS_WIKI, '"', - ',hide_posts=', ($this->conf->display_posts || Minz_Request::param('output') === 'reader') ? 'false' : 'true', - ',display_order="', Minz_Request::param('order', $this->conf->sort_order), '"', - ',auto_mark_article=', $mark['article'] ? 'true' : 'false', - ',auto_mark_site=', $mark['site'] ? 'true' : 'false', - ',auto_mark_scroll=', $mark['scroll'] ? 'true' : 'false', - ',auto_load_more=', $this->conf->auto_load_more ? 'true' : 'false', - ',does_lazyload=', $this->conf->lazyload ? 'true' : 'false', - ',sticky_post=', $this->conf->sticky_post ? 'true' : 'false'; - +$mail = Minz_Session::param ('mail', false); +$auto_actualize = Minz_Session::param('actualize_feeds', false); +$hide_posts = ($this->conf->display_posts || + Minz_Request::param('output') === 'reader'); $s = $this->conf->shortcuts; -echo ',shortcuts={', + +echo 'var context={', + 'hide_posts:', $hide_posts ? 'false' : 'true', ',', + 'display_order:"', Minz_Request::param('order', $this->conf->sort_order), '",', + 'auto_mark_article:', $mark['article'] ? 'true' : 'false', ',', + 'auto_mark_site:', $mark['site'] ? 'true' : 'false', ',', + 'auto_mark_scroll:', $mark['scroll'] ? 'true' : 'false', ',', + 'auto_load_more:', $this->conf->auto_load_more ? 'true' : 'false', ',', + 'auto_actualize_feeds:', $auto_actualize ? 'true' : 'false', ',', + 'does_lazyload:', $this->conf->lazyload ? 'true' : 'false', ',', + 'sticky_post:', $this->conf->sticky_post ? 'true' : 'false', ',', + 'html5_notif_timeout:', $this->conf->html5_notif_timeout, ',', + 'auth_type:"', Minz_Configuration::authType(), '",', + 'current_user_mail:', $mail ? ('"' . $mail . '"') : 'null', ',', + 'current_view:"', Minz_Request::param('output', 'normal'), '"', +"},\n"; + +echo 'shortcuts={', 'mark_read:"', $s['mark_read'], '",', 'mark_favorite:"', $s['mark_favorite'], '",', 'go_website:"', $s['go_website'], '",', @@ -32,32 +41,20 @@ echo ',shortcuts={', 'close_dropdown:"', $s['close_dropdown'], '"', "},\n"; -if (Minz_Request::param ('output') === 'global') { - echo "iconClose='", _i('close'), "',\n"; -} - -$authType = Minz_Configuration::authType(); -if ($authType === 'persona') { - // If user is disconnected, current_user_mail MUST be null - $mail = Minz_Session::param ('mail', false); - if ($mail) { - echo 'current_user_mail="' . $mail . '",'; - } else { - echo 'current_user_mail=null,'; - } -} - -echo 'authType="', $authType, '",', - 'url_freshrss="', _url ('index', 'index'), '",', - 'url_login="', _url ('index', 'login'), '",', - 'url_logout="', _url ('index', 'logout'), '",'; - -echo 'str_confirmation_default="', _t('confirm_action'), '"', ",\n"; -echo 'str_notif_title_articles="', _t('notif_title_new_articles'), '"', ",\n"; -echo 'str_notif_body_articles="', _t('notif_body_new_articles'), '"', ",\n"; -echo 'str_category_empty="', _t('category_empty'), '"', ",\n"; -echo 'html5_notif_timeout=', $this->conf->html5_notif_timeout,",\n"; +echo 'url={', + 'index:"', _url('index', 'index'), '",', + 'login:"', _url('index', 'login'), '",', + 'logout:"', _url('index', 'logout'), '",', + 'help:"', FRESHRSS_WIKI, '"', +"},\n"; +echo 'i18n={', + 'confirmation_default:"', _t('confirm_action'), '",', + 'notif_title_articles:"', _t('notif_title_new_articles'), '",', + 'notif_body_articles:"', _t('notif_body_new_articles'), '",', + 'category_empty:"', _t('category_empty'), '"', +"},\n"; -$autoActualise = Minz_Session::param('actualize_feeds', false); -echo 'auto_actualize_feeds=', $autoActualise ? 'true' : 'false', ";\n"; +echo 'icons={', + 'close:\'', _i('close'), '\'', +"}\n"; \ No newline at end of file diff --git a/p/scripts/category.js b/p/scripts/category.js index dc5df67e4..c33e68528 100644 --- a/p/scripts/category.js +++ b/p/scripts/category.js @@ -20,13 +20,13 @@ function dragend_process(t) { $(t).remove(); if (parent.children().length <= 0) { - parent.append('
  • ' + str_category_empty + '
  • '); + parent.append('
  • ' + i18n['category_empty'] + '
  • '); } } } function init_draggable() { - if (!(window.$ && window.url_freshrss)) { + if (!(window.$ && window.i18n)) { if (window.console) { console.log('FreshRSS waiting for JS…'); } diff --git a/p/scripts/global_view.js b/p/scripts/global_view.js index 7105520a6..6e1f61066 100644 --- a/p/scripts/global_view.js +++ b/p/scripts/global_view.js @@ -40,7 +40,7 @@ function load_panel(link) { function init_close_panel() { $("#panel .close").click(function () { - $("#panel").html('' + window.iconClose + ''); + $("#panel").html('' + icons['close'] + ''); init_close_panel(); $("#panel").slideToggle(); $("#overlay").fadeOut(); diff --git a/p/scripts/main.js b/p/scripts/main.js index 5793bb50b..ad33f6c57 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -4,14 +4,6 @@ var $stream = null, shares = 0, ajax_loading = false; -function is_normal_mode() { - return $stream.hasClass('normal'); -} - -function is_global_mode() { - return $stream.hasClass('global'); -} - function redirect(url, new_tab) { if (url) { if (new_tab) { @@ -226,7 +218,7 @@ function toggleContent(new_active, old_active) { return; } - if (does_lazyload) { + if (context['does_lazyload']) { new_active.find('img[data-original], iframe[data-original]').each(function () { this.setAttribute('src', this.getAttribute('data-original')); this.removeAttribute('data-original'); @@ -245,12 +237,12 @@ function toggleContent(new_active, old_active) { var box_to_move = "html,body", relative_move = false; - if (is_global_mode()) { + if (context['current_view'] == 'global') { box_to_move = "#panel"; relative_move = true; } - if (sticky_post) { + if (context['sticky_post']) { var prev_article = new_active.prevAll('.flux'), new_pos = new_active.position().top, old_scroll = $(box_to_move).scrollTop(); @@ -259,7 +251,7 @@ function toggleContent(new_active, old_active) { new_pos = prev_article.position().top; } - if (hide_posts) { + if (context['hide_posts']) { if (relative_move) { new_pos += old_scroll; } @@ -278,7 +270,7 @@ function toggleContent(new_active, old_active) { } } - if (auto_mark_article && new_active.hasClass('active')) { + if (context['auto_mark_article'] && new_active.hasClass('active')) { mark_read(new_active, true); } } @@ -378,7 +370,7 @@ function collapse_entry() { var flux_current = $(".flux.current"); flux_current.toggleClass("active"); - if (isCollapsed && auto_mark_article) { + if (isCollapsed && context['auto_mark_article']) { mark_read(flux_current, true); } } @@ -457,12 +449,12 @@ function inMarkViewport(flux, box_to_follow, relative_follow) { function init_posts() { var box_to_follow = $(window), relative_follow = false; - if (is_global_mode()) { + if (context['current_view'] == 'global') { box_to_follow = $("#panel"); relative_follow = true; } - if (auto_mark_scroll) { + if (context['auto_mark_scroll']) { box_to_follow.scroll(function () { $('.not_read:visible').each(function () { if ($(this).children(".flux_content").is(':visible') && inMarkViewport($(this), box_to_follow, relative_follow)) { @@ -472,7 +464,7 @@ function init_posts() { }); } - if (auto_load_more) { + if (context['auto_load_more']) { box_to_follow.scroll(function () { var load_more = $("#load_more"); if (!load_more.is(':visible')) { @@ -492,7 +484,7 @@ function init_posts() { } function init_column_categories() { - if (!is_normal_mode()) { + if (context['current_view'] !== 'normal') { return; } $('#aside_flux').on('click', '.category>a.dropdown-toggle', function () { @@ -632,7 +624,7 @@ function init_shortcuts() { shortcut.add(shortcuts.go_website, function () { var url_website = $('.flux.current > .flux_header > .title > a').attr("href"); - if (auto_mark_site) { + if (context['auto_mark_site']) { $(".flux.current").each(function () { mark_read($(this), true); }); @@ -656,7 +648,7 @@ function init_shortcuts() { }); shortcut.add(shortcuts.help, function () { - redirect(help_url, true); + redirect(url['help'], true); }, { 'disable_in_input': true }); @@ -678,7 +670,7 @@ function init_stream(divStream) { new_active = $(this).parent(); isCollapsed = true; if (e.target.tagName.toUpperCase() === 'A') { //Leave real links alone - if (auto_mark_article) { + if (context['auto_mark_article']) { mark_read(new_active, true); } return true; @@ -724,7 +716,7 @@ function init_stream(divStream) { $(this).attr('target', '_blank'); }); - if (auto_mark_site) { + if (context['auto_mark_site']) { // catch mouseup instead of click so we can have the correct behaviour // with middle button click (scroll button). divStream.on('mouseup', '.flux .link > a', function (e) { @@ -784,7 +776,7 @@ function init_actualize() { return false; }); - if (auto_actualize_feeds) { + if (context['auto_actualize_feeds']) { auto = true; $("#actualize").click(); } @@ -855,9 +847,9 @@ function notifs_html5_show(nb) { return } - var notification = new window.Notification(str_notif_title_articles, { + var notification = new window.Notification(i18n['notif_title_articles'], { icon: "../themes/icons/favicon-256.png", - body: str_notif_body_articles.replace("\d", nb), + body: i18n['notif_body_articles.replace("\d", nb)'], tag: "freshRssNewArticles" }); @@ -865,10 +857,10 @@ function notifs_html5_show(nb) { window.location.reload(); } - if (html5_notif_timeout !== 0){ + if (context['html5_notif_timeout'] !== 0){ setTimeout(function() { notification.close(); - }, html5_notif_timeout * 1000); + }, context['html5_notif_timeout'] * 1000); } } @@ -922,7 +914,7 @@ function load_more_posts() { $.get(url_load_more, function (data) { box_load_more.children('.flux:last').after($('#stream', data).children('.flux, .day')); $('.pagination').replaceWith($('.pagination', data)); - if (display_order === 'ASC') { + if (context['display_order'] === 'ASC') { $('#nav_menu_read_all > .read_all').attr( 'formaction', $('#bigMarkAsRead').attr('formaction') ); @@ -953,7 +945,7 @@ function focus_search() { function init_load_more(box) { box_load_more = box; - if (!does_lazyload) { + if (!context['does_lazyload']) { $('img[postpone], audio[postpone], iframe[postpone], video[postpone]').each(function () { this.removeAttribute('postpone'); }); @@ -1062,7 +1054,7 @@ function init_persona() { }); navigator.id.watch({ - loggedInUser: current_user_mail, + loggedInUser: context['current_user_mail'], onlogin: function(assertion) { // A user has logged in! Here you need to: @@ -1070,13 +1062,13 @@ function init_persona() { // 2. Update your UI. $.ajax ({ type: 'POST', - url: url_login, + url: url['login'], data: {assertion: assertion}, success: function(res, status, xhr) { /*if (res.status === 'failure') { alert (res_obj.reason); } else*/ if (res.status === 'okay') { - location.href = url_freshrss; + location.href = url['index']; } }, error: function(res, status, xhr) { @@ -1091,9 +1083,9 @@ function init_persona() { // (That's a literal JavaScript null. Not false, 0, or undefined. null.) $.ajax ({ type: 'POST', - url: url_logout, + url: url['logout'], success: function(res, status, xhr) { - location.href = url_freshrss; + location.href = url['index']; }, error: function(res, status, xhr) { //alert("logout failure" + res); @@ -1108,7 +1100,7 @@ function init_confirm_action() { $('body').on('click', '.confirm', function () { var str_confirmation = $(this).attr('data-str-confirm'); if (!str_confirmation) { - str_confirmation = str_confirmation_default; + str_confirmation = i18n['confirmation_default']; } return confirm(str_confirmation); @@ -1274,7 +1266,7 @@ function init_slider_observers() { } function init_all() { - if (!(window.$ && window.url_freshrss)) { + if (!(window.$ && window.context)) { if (window.console) { console.log('FreshRSS waiting for JS…'); } @@ -1282,7 +1274,7 @@ function init_all() { return; } init_notifications(); - switch (authType) { + switch (context['auth_type']) { case 'persona': init_persona(); break; -- cgit v1.2.3 From 3831961b2e515ff7d8d352c0f7b6a15b3a613c25 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 5 Oct 2014 18:03:32 +0200 Subject: Fix bug of i18n in JavaScript See https://github.com/marienfressinaud/FreshRSS/issues/655 --- p/scripts/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'p') diff --git a/p/scripts/main.js b/p/scripts/main.js index ad33f6c57..b01a3a34d 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -849,7 +849,7 @@ function notifs_html5_show(nb) { var notification = new window.Notification(i18n['notif_title_articles'], { icon: "../themes/icons/favicon-256.png", - body: i18n['notif_body_articles.replace("\d", nb)'], + body: i18n['notif_body_articles'].replace("\d", nb), tag: "freshRssNewArticles" }); -- cgit v1.2.3 From d8f4681382986524b91acb0500847e9f24badf20 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 5 Oct 2014 19:35:29 +0200 Subject: Replace Minz_Log::record by corresponding methods Please not use Minz_Log::record anymore! See https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/Controllers/entryController.php | 2 +- app/Controllers/feedController.php | 14 +++++++------- app/Controllers/indexController.php | 20 ++++++++++---------- app/Controllers/javascriptController.php | 2 +- app/FreshRSS.php | 2 +- app/Models/CategoryDAO.php | 6 +++--- app/Models/EntryDAO.php | 30 +++++++++++++++--------------- app/Models/EntryDAOSQLite.php | 14 +++++++------- app/Models/FeedDAO.php | 20 ++++++++++---------- app/Models/FeedDAOSQLite.php | 2 +- app/Models/UserDAO.php | 4 ++-- app/views/index/index.phtml | 2 +- lib/Minz/FrontController.php | 4 ++-- lib/Minz/View.php | 12 +++--------- p/api/greader.php | 6 +++--- p/i/index.php | 2 +- 16 files changed, 68 insertions(+), 74 deletions(-) (limited to 'p') diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index ec90666ed..d7be05663 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -143,7 +143,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $nb = $feedDAO->cleanOldEntries($feed->id(), $date_min, $feedHistory); if ($nb > 0) { $nbTotal += $nb; - Minz_Log::record($nb . ' old entries cleaned in feed [' . $feed->url() . ']', Minz_Log::DEBUG); + Minz_Log::debug($nb . ' old entries cleaned in feed [' . $feed->url() . ']'); //$feedDAO->updateLastUpdate($feed->id()); } } diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 93a8d7c2e..70d5c4e22 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -140,14 +140,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } } catch (FreshRSS_BadUrl_Exception $e) { - Minz_Log::record($e->getMessage(), Minz_Log::WARNING); + Minz_Log::warning($e->getMessage()); $notif = array( 'type' => 'bad', 'content' => _t('invalid_url', $url) ); Minz_Session::_param('notification', $notif); } catch (FreshRSS_Feed_Exception $e) { - Minz_Log::record($e->getMessage(), Minz_Log::WARNING); + Minz_Log::warning($e->getMessage()); $notif = array( 'type' => 'bad', 'content' => _t('internal_problem_feed', @@ -156,7 +156,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Session::_param('notification', $notif); } catch (Minz_FileNotExistException $e) { // Répertoire de cache n'existe pas - Minz_Log::record($e->getMessage(), Minz_Log::ERROR); + Minz_Log::error($e->getMessage()); $notif = array( 'type' => 'bad', 'content' => _t('internal_problem_feed', @@ -258,7 +258,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $is_read = $this->view->conf->mark_when['reception'] ? 1 : 0; foreach ($feeds as $feed) { if (!$feed->lock()) { - Minz_Log::record('Feed already being actualized: ' . $feed->url(), Minz_Log::NOTICE); + Minz_Log::notice('Feed already being actualized: ' . $feed->url()); continue; } try { @@ -307,7 +307,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } $nb = $feedDAO->cleanOldEntries($feed->id(), $date_min, max($feedHistory, count($entries) + 10)); if ($nb > 0) { - Minz_Log::record($nb . ' old entries cleaned in feed [' . $feed->url() . ']', Minz_Log::DEBUG); + Minz_Log::debug($nb . ' old entries cleaned in feed [' . $feed->url() . ']'); } } @@ -318,11 +318,11 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } $flux_update++; if (($feed->url() !== $url)) { //HTTP 301 Moved Permanently - Minz_Log::record('Feed ' . $url . ' moved permanently to ' . $feed->url(), Minz_Log::NOTICE); + Minz_Log::notice('Feed ' . $url . ' moved permanently to ' . $feed->url()); $feedDAO->updateFeed($feed->id(), array('url' => $feed->url())); } } catch (FreshRSS_Feed_Exception $e) { - Minz_Log::record($e->getMessage(), Minz_Log::NOTICE); + Minz_Log::notice($e->getMessage()); $feedDAO->updateLastUpdate($feed->id(), 1); } diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 73638acb3..0d2eff700 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -59,7 +59,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $getType = $get[0]; $getId = substr($get, 2); if (!$this->checkAndProcessType($getType, $getId)) { - Minz_Log::record('Not found [' . $getType . '][' . $getId . ']', Minz_Log::DEBUG); + Minz_Log::debug('Not found [' . $getType . '][' . $getId . ']'); Minz_Error::error( 404, array('error' => array(_t('page_not_found'))) @@ -122,12 +122,12 @@ class FreshRSS_index_Controller extends Minz_ActionController { // Si on a récupéré aucun article "non lus" // on essaye de récupérer tous les articles if ($this->view->state === FreshRSS_Entry::STATE_NOT_READ && empty($entries) && ($state_param === null) && ($filter == '')) { - Minz_Log::record('Conflicting information about nbNotRead!', Minz_Log::DEBUG); + Minz_Log::debug('Conflicting information about nbNotRead!'); $feedDAO = FreshRSS_Factory::createFeedDao(); try { $feedDAO->updateCachedValues(); } catch (Exception $ex) { - Minz_Log::record('Failed to automatically correct nbNotRead! ' + $ex->getMessage(), Minz_Log::NOTICE); + Minz_Log::notice('Failed to automatically correct nbNotRead! ' + $ex->getMessage()); } $this->view->state = FreshRSS_Entry::STATE_ALL; $entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb, $first, $filter); @@ -143,7 +143,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $this->view->entries = $entries; } catch (FreshRSS_EntriesGetter_Exception $e) { - Minz_Log::record($e->getMessage(), Minz_Log::NOTICE); + Minz_Log::notice($e->getMessage()); Minz_Error::error( 404, array('error' => array(_t('page_not_found'))) @@ -281,7 +281,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $res = array(); $res['status'] = 'failure'; $res['reason'] = $reason == '' ? _t('invalid_login') : $reason; - Minz_Log::record('Persona: ' . $res['reason'], Minz_Log::WARNING); + Minz_Log::warning('Persona: ' . $res['reason']); } header('Content-Type: application/json; charset=UTF-8'); @@ -358,13 +358,13 @@ class FreshRSS_index_Controller extends Minz_ActionController { self::deleteLongTermCookie(); } } else { - Minz_Log::record('Password mismatch for user ' . $username . ', nonce=' . $nonce . ', c=' . $c, Minz_Log::WARNING); + Minz_Log::warning('Password mismatch for user ' . $username . ', nonce=' . $nonce . ', c=' . $c); } } catch (Minz_Exception $me) { - Minz_Log::record('Login failure: ' . $me->getMessage(), Minz_Log::WARNING); + Minz_Log::warning('Login failure: ' . $me->getMessage()); } } else { - Minz_Log::record('Invalid credential parameters: user=' . $username . ' challenge=' . $c . ' nonce=' . $nonce, Minz_Log::DEBUG); + Minz_Log::debug('Invalid credential parameters: user=' . $username . ' challenge=' . $c . ' nonce=' . $nonce); } if (!$ok) { $notif = array( @@ -395,10 +395,10 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Session::_param('currentUser', $username); Minz_Session::_param('passwordHash', $s); } else { - Minz_Log::record('Unsafe password mismatch for user ' . $username, Minz_Log::WARNING); + Minz_Log::warning('Unsafe password mismatch for user ' . $username); } } catch (Minz_Exception $me) { - Minz_Log::record('Unsafe login failure: ' . $me->getMessage(), Minz_Log::WARNING); + Minz_Log::warning('Unsafe login failure: ' . $me->getMessage()); } Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); } elseif (!Minz_Configuration::canLogIn()) { diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index 2a0dbd3d9..14e6f36de 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -37,7 +37,7 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { return; //Success } } catch (Minz_Exception $me) { - Minz_Log::record('Nonce failure: ' . $me->getMessage(), Minz_Log::WARNING); + Minz_Log::warning('Nonce failure: ' . $me->getMessage()); } } $this->view->nonce = ''; //Failure diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 61e8d83f0..efd302ecc 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -101,7 +101,7 @@ class FreshRSS extends Minz_FrontController { 'content' => 'Invalid configuration for user [' . $currentUser . ']!', ); Minz_Session::_param('notification', $notif); - Minz_Log::record($notif['content'] . ' ' . $me->getMessage(), Minz_Log::WARNING); + Minz_Log::warning($notif['content'] . ' ' . $me->getMessage()); Minz_Session::_param('currentUser', ''); } catch (Exception $e) { die($e->getMessage()); diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index ce1babfdd..2e333d2f1 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -13,7 +13,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { return $this->bd->lastInsertId(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error addCategory: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error addCategory: ' . $info[2] ); return false; } } @@ -44,7 +44,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateCategory: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateCategory: ' . $info[2]); return false; } } @@ -59,7 +59,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error deleteCategory: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error deleteCategory: ' . $info[2]); return false; } } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 34717123c..5a136499a 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -40,11 +40,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); if ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries - Minz_Log::record('SQL error addEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] - . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title'], Minz_Log::ERROR); + Minz_Log::error('SQL error addEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] + . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title']); } /*else { - Minz_Log::record ('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] - . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title'], Minz_Log::DEBUG); + Minz_Log::debug('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] + . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title']); }*/ return false; } @@ -94,7 +94,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markFavorite: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markFavorite: ' . $info[2]); return false; } } @@ -124,7 +124,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return true; } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateCacheUnreads: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateCacheUnreads: ' . $info[2]); return false; } } @@ -147,7 +147,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markRead: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markRead: ' . $info[2]); return false; } $affected = $stm->rowCount(); @@ -166,7 +166,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markRead: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markRead: ' . $info[2]); return false; } } @@ -175,7 +175,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record('Calling markReadEntries(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::debug('Calling markReadEntries(0) is deprecated!'); } $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id ' @@ -190,7 +190,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markReadEntries: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markReadEntries: ' . $info[2]); return false; } $affected = $stm->rowCount(); @@ -203,7 +203,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function markReadCat($id, $idMax = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record('Calling markReadCat(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::debug('Calling markReadCat(0) is deprecated!'); } $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id ' @@ -213,7 +213,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markReadCat: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markReadCat: ' . $info[2]); return false; } $affected = $stm->rowCount(); @@ -226,7 +226,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function markReadFeed($id, $idMax = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record('Calling markReadFeed(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::debug('Calling markReadFeed(0) is deprecated!'); } $this->bd->beginTransaction(); @@ -237,7 +237,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markReadFeed: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markReadFeed: ' . $info[2]); $this->bd->rollBack(); return false; } @@ -251,7 +251,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markReadFeed: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markReadFeed: ' . $info[2]); $this->bd->rollBack(); return false; } diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php index 9dc395c3c..66078aca9 100644 --- a/app/Models/EntryDAOSQLite.php +++ b/app/Models/EntryDAOSQLite.php @@ -26,7 +26,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { return true; } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateCacheUnreads: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateCacheUnreads: ' . $info[2]); return false; } } @@ -47,7 +47,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markRead 1: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markRead 1: ' . $info[2]); $this->bd->rollBack(); return false; } @@ -59,7 +59,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markRead 2: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markRead 2: ' . $info[2]); $this->bd->rollBack(); return false; } @@ -72,7 +72,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record('Calling markReadEntries(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::debug('Calling markReadEntries(0) is deprecated!'); } $sql = 'UPDATE `' . $this->prefix . 'entry` SET is_read=1 WHERE is_read=0 AND id <= ?'; @@ -85,7 +85,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markReadEntries: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markReadEntries: ' . $info[2]); return false; } $affected = $stm->rowCount(); @@ -98,7 +98,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { public function markReadCat($id, $idMax = 0) { if ($idMax == 0) { $idMax = time() . '000000'; - Minz_Log::record('Calling markReadCat(0) is deprecated!', Minz_Log::DEBUG); + Minz_Log::debug('Calling markReadCat(0) is deprecated!'); } $sql = 'UPDATE `' . $this->prefix . 'entry` ' @@ -109,7 +109,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error markReadCat: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error markReadCat: ' . $info[2]); return false; } $affected = $stm->rowCount(); diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index b89ae2045..852de6e36 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -19,7 +19,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $this->bd->lastInsertId(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error addFeed: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error addFeed: ' . $info[2]); return false; } } @@ -77,7 +77,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateFeed: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateFeed: ' . $info[2]); return false; } } @@ -107,7 +107,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateLastUpdate: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateLastUpdate: ' . $info[2]); return false; } } @@ -131,7 +131,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error changeCategory: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error changeCategory: ' . $info[2]); return false; } } @@ -146,7 +146,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error deleteFeed: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error deleteFeed: ' . $info[2]); return false; } } @@ -160,7 +160,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error deleteFeedByCategory: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error deleteFeedByCategory: ' . $info[2]); return false; } } @@ -289,7 +289,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateCachedValues: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateCachedValues: ' . $info[2]); return false; } } @@ -301,7 +301,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $this->bd->beginTransaction(); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error truncate: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error truncate: ' . $info[2]); $this->bd->rollBack(); return false; } @@ -313,7 +313,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error truncate: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error truncate: ' . $info[2]); $this->bd->rollBack(); return false; } @@ -338,7 +338,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error cleanOldEntries: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error cleanOldEntries: ' . $info[2]); return false; } } diff --git a/app/Models/FeedDAOSQLite.php b/app/Models/FeedDAOSQLite.php index 0d1872389..7599fda53 100644 --- a/app/Models/FeedDAOSQLite.php +++ b/app/Models/FeedDAOSQLite.php @@ -11,7 +11,7 @@ class FreshRSS_FeedDAOSQLite extends FreshRSS_FeedDAO { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record('SQL error updateCachedValues: ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error updateCachedValues: ' . $info[2]); return false; } } diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index 0c96d7175..15215258c 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -28,7 +28,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { return true; } else { $info = empty($stm) ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error : ' . $info[2]); return false; } } @@ -48,7 +48,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { return true; } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); + Minz_Log::error('SQL error : ' . $info[2]); return false; } } diff --git a/app/views/index/index.phtml b/app/views/index/index.phtml index 5e935b81e..584792e29 100644 --- a/app/views/index/index.phtml +++ b/app/views/index/index.phtml @@ -21,5 +21,5 @@ if ($this->loginOk || Minz_Configuration::allowAnonymous()) { $this->renderHelper('view/rss_view'); } else { // Normally, it should not happen, but log it anyway - Minz_Log::record('Something is wrong in ' . __FILE__ . ' line ' . __LINE__, Minz_Log::ERROR); + Minz_Log::error('Something is wrong in ' . __FILE__ . ' line ' . __LINE__); } diff --git a/lib/Minz/FrontController.php b/lib/Minz/FrontController.php index f13882801..e95c56bf3 100644 --- a/lib/Minz/FrontController.php +++ b/lib/Minz/FrontController.php @@ -46,7 +46,7 @@ class Minz_FrontController { ); Minz_Request::forward ($url); } catch (Minz_Exception $e) { - Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); + Minz_Log::error($e->getMessage()); $this->killApp ($e->getMessage ()); } @@ -85,7 +85,7 @@ class Minz_FrontController { $this->dispatcher->run(); } catch (Minz_Exception $e) { try { - Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); + Minz_Log::error($e->getMessage()); } catch (Minz_PermissionDeniedException $e) { $this->killApp ($e->getMessage ()); } diff --git a/lib/Minz/View.php b/lib/Minz/View.php index a0dec1824..b40448491 100644 --- a/lib/Minz/View.php +++ b/lib/Minz/View.php @@ -71,9 +71,7 @@ class Minz_View { */ public function render () { if ((include($this->view_filename)) === false) { - Minz_Log::record ('File not found: `' - . $this->view_filename . '`', - Minz_Log::NOTICE); + Minz_Log::notice('File not found: `' . $this->view_filename . '`'); } } @@ -87,9 +85,7 @@ class Minz_View { . $part . '.phtml'; if ((include($fic_partial)) === false) { - Minz_Log::record ('File not found: `' - . $fic_partial . '`', - Minz_Log::WARNING); + Minz_Log::warning('File not found: `' . $fic_partial . '`'); } } @@ -103,9 +99,7 @@ class Minz_View { . $helper . '.phtml'; if ((include($fic_helper)) === false) {; - Minz_Log::record ('File not found: `' - . $fic_helper . '`', - Minz_Log::WARNING); + Minz_Log::warning('File not found: `' . $fic_helper . '`'); } } diff --git a/p/api/greader.php b/p/api/greader.php index 5a6fdad7d..1a66c30fb 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -160,7 +160,7 @@ function authorizationToUserConf() { return $conf; } else { logMe('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1] . "\n"); - Minz_Log::record('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1], Minz_Log::WARNING); + Minz_Log::warning('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1]); unauthorized(); } } else { @@ -181,7 +181,7 @@ function clientLogin($email, $pass) { //http://web.archive.org/web/2013060409104 $conf = new FreshRSS_Configuration($email); } catch (Exception $e) { logMe($e->getMessage() . "\n"); - Minz_Log::record('Invalid API user ' . $email, Minz_Log::WARNING); + Minz_Log::warning('Invalid API user ' . $email); unauthorized(); } if ($conf->apiPasswordHash != '' && password_verify($pass, $conf->apiPasswordHash)) { @@ -191,7 +191,7 @@ function clientLogin($email, $pass) { //http://web.archive.org/web/2013060409104 'Auth=', $auth, "\n"; exit(); } else { - Minz_Log::record('Password API mismatch for user ' . $email, Minz_Log::WARNING); + Minz_Log::warning('Password API mismatch for user ' . $email); unauthorized(); } } else { diff --git a/p/i/index.php b/p/i/index.php index 7b34eefd1..ec969c159 100755 --- a/p/i/index.php +++ b/p/i/index.php @@ -46,7 +46,7 @@ if (file_exists(DATA_PATH . '/do-install.txt')) { $front_controller->run(); } catch (Exception $e) { echo '### Fatal error! ###
    ', "\n"; - Minz_Log::record($e->getMessage(), Minz_Log::ERROR); + Minz_Log::error($e->getMessage()); echo 'See logs files.'; } } -- cgit v1.2.3 From 1252b3dd867e59917cf303f0c39c7da938b8ce32 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 7 Oct 2014 16:37:10 +0200 Subject: Authentication system moved + Persona comes back! AuthController is dedicated to auhentication. Persona is back, greater than ever! See https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/Controllers/authController.php | 182 ++++++++++++++++++++++++++++++++ app/Controllers/indexController.php | 90 +--------------- app/FreshRSS.php | 8 ++ app/Models/Auth.php | 21 +++- app/layout/header.phtml | 23 ++-- app/views/auth/formLogin.phtml | 28 +++++ app/views/auth/logout.phtml | 0 app/views/auth/personaLogin.phtml | 24 +++++ app/views/helpers/javascript_vars.phtml | 13 ++- app/views/index/formLogin.phtml | 46 -------- p/scripts/main.js | 65 ------------ p/scripts/persona.js | 76 +++++++++++++ 12 files changed, 356 insertions(+), 220 deletions(-) create mode 100644 app/Controllers/authController.php create mode 100644 app/views/auth/formLogin.phtml create mode 100644 app/views/auth/logout.phtml create mode 100644 app/views/auth/personaLogin.phtml delete mode 100644 app/views/index/formLogin.phtml create mode 100644 p/scripts/persona.js (limited to 'p') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php new file mode 100644 index 000000000..2b67e34b8 --- /dev/null +++ b/app/Controllers/authController.php @@ -0,0 +1,182 @@ + 'index', 'a' => 'index'), true); + } + + $auth_type = Minz_Configuration::authType(); + switch ($auth_type) { + case 'form': + Minz_Request::forward(array('c' => 'auth', 'a' => 'formLogin')); + break; + case 'persona': + Minz_Request::forward(array('c' => 'auth', 'a' => 'personaLogin')); + break; + case 'http_auth': + case 'none': + // It should not happened! + Minz_Error::error(404); + default: + // TODO load plugin instead + Minz_Error::error(404); + } + } + + /** + * This action handles form login page. + * + * If this action is reached through a POST request, username and password + * are compared to login the current user. + * + * Parameters are: + * - nonce (default: false) + * - username (default: '') + * - challenge (default: '') + * - keep_logged_in (default: false) + */ + public function formLoginAction() { + invalidateHttpCache(); + + $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js'); + Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . $file_mtime)); + + if (Minz_Request::isPost()) { + $nonce = Minz_Session::param('nonce'); + $username = Minz_Request::param('username', ''); + $challenge = Minz_Request::param('challenge', ''); + try { + $conf = new FreshRSS_Configuration($username); + } catch(Minz_Exception $e) { + // $username is not a valid user, nor the configuration file! + Minz_Log::warning('Login failure: ' . $e->getMessage()); + Minz_Request::bad(_t('invalid_login'), + array('c' => 'auth', 'a' => 'login')); + } + + $ok = FreshRSS_FormAuth::checkCredentials( + $username, $conf->passwordHash, $nonce, $challenge + ); + if ($ok) { + // Set session parameter to give access to the user. + Minz_Session::_param('currentUser', $username); + Minz_Session::_param('passwordHash', $conf->passwordHash); + FreshRSS_Auth::giveAccess(); + + // Set cookie parameter if nedded. + if (Minz_Request::param('keep_logged_in')) { + FreshRSS_FormAuth::makeCookie($username, $conf->passwordHash); + } else { + FreshRSS_FormAuth::deleteCookie(); + } + + // All is good, go back to the index. + Minz_Request::good(_t('login'), + array('c' => 'index', 'a' => 'index')); + } else { + Minz_Log::warning('Password mismatch for' . + ' user=' . $username . + ', nonce=' . $nonce . + ', c=' . $challenge); + Minz_Request::bad(_t('invalid_login'), + array('c' => 'auth', 'a' => 'login')); + } + } + } + + /** + * This action handles Persona login page. + * + * If this action is reached through a POST request, assertion from Persona + * is verificated and user connected if all is ok. + * + * Parameter is: + * - assertion (default: false) + * + * @todo: Persona system should be moved to a plugin + */ + public function personaLoginAction() { + $this->view->res = false; + + if (Minz_Request::isPost()) { + $this->view->_useLayout(false); + + $assert = Minz_Request::param('assertion'); + $url = 'https://verifier.login.persona.org/verify'; + $params = 'assertion=' . $assert . '&audience=' . + urlencode(Minz_Url::display(null, 'php', true)); + $ch = curl_init(); + $options = array( + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => TRUE, + CURLOPT_POST => 2, + CURLOPT_POSTFIELDS => $params + ); + curl_setopt_array($ch, $options); + $result = curl_exec($ch); + curl_close($ch); + + $res = json_decode($result, true); + + $login_ok = false; + $reason = ''; + if ($res['status'] === 'okay') { + $email = filter_var($res['email'], FILTER_VALIDATE_EMAIL); + if ($email != '') { + $persona_file = DATA_PATH . '/persona/' . $email . '.txt'; + if (($current_user = @file_get_contents($persona_file)) !== false) { + $current_user = trim($current_user); + try { + $conf = new FreshRSS_Configuration($current_user); + $login_ok = strcasecmp($email, $conf->mail_login) === 0; + } catch (Minz_Exception $e) { + //Permission denied or conf file does not exist + $reason = 'Invalid configuration for user ' . + '[' . $current_user . '] ' . $e->getMessage(); + } + } + } else { + $reason = 'Invalid email format [' . $res['email'] . ']'; + } + } else { + $reason = $res['reason']; + } + + if ($login_ok) { + Minz_Session::_param('currentUser', $current_user); + Minz_Session::_param('mail', $email); + FreshRSS_Auth::giveAccess(); + invalidateHttpCache(); + } else { + Minz_Log::error($reason); + + $res = array(); + $res['status'] = 'failure'; + $res['reason'] = _t('invalid_login'); + } + + header('Content-Type: application/json; charset=UTF-8'); + $this->view->res = $res; + } + } + + /** + * This action removes all accesses of the current user. + */ + public function logoutAction() { + invalidateHttpCache(); + FreshRSS_Auth::removeAccess(); + Minz_Request::good(_t('disconnected'), + array('c' => 'index', 'a' => 'index')); + } +} diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 3006480f9..5b490e672 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -20,7 +20,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } elseif ($output !== 'rss') { // "hard" redirection is not required, just ask dispatcher to // forward to the login form without 302 redirection - Minz_Request::forward(array('c' => 'index', 'a' => 'login')); + Minz_Request::forward(array('c' => 'auth', 'a' => 'login')); return; } } @@ -228,92 +228,4 @@ class FreshRSS_index_Controller extends Minz_ActionController { $this->view->logsPaginator->_nbItemsPerPage(50); $this->view->logsPaginator->_currentPage($page); } - - /** - * This action handles the login page. - */ - public function loginAction() { - if (FreshRSS_Auth::hasAccess()) { - Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); - } - - invalidateHttpCache(); - - $auth_type = Minz_Configuration::authType(); - switch ($auth_type) { - case 'form': - Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin')); - break; - case 'http_auth': - case 'none': - // It should not happened! - Minz_Error::error(404); - default: - // TODO load plugin instead - Minz_Error::error(404); - } - } - - /** - * - */ - public function formLoginAction() { - if (FreshRSS_Auth::hasAccess()) { - Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); - } - - invalidateHttpCache(); - - $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js'); - Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . $file_mtime)); - - if (Minz_Request::isPost()) { - $nonce = Minz_Session::param('nonce'); - $username = Minz_Request::param('username', ''); - $challenge = Minz_Request::param('challenge', ''); - try { - $conf = new FreshRSS_Configuration($username); - } catch(Minz_Exception $e) { - // $username is not a valid user, nor the configuration file! - Minz_Log::warning('Login failure: ' . $e->getMessage()); - Minz_Request::bad(_t('invalid_login'), - array('c' => 'index', 'a' => 'login')); - } - - $ok = FreshRSS_FormAuth::checkCredentials( - $username, $conf->passwordHash, $nonce, $challenge - ); - if ($ok) { - // Set session parameter to give access to the user. - Minz_Session::_param('currentUser', $username); - Minz_Session::_param('passwordHash', $conf->passwordHash); - FreshRSS_Auth::giveAccess(); - - // Set cookie parameter if nedded. - if (Minz_Request::param('keep_logged_in', false)) { - FreshRSS_FormAuth::makeCookie($username, $conf->passwordHash); - } else { - FreshRSS_FormAuth::deleteCookie(); - } - - // All is good, go back to the index. - Minz_Request::good(_t('login'), - array('c' => 'index', 'a' => 'index')); - } else { - Minz_Log::warning('Password mismatch for' . - ' user=' . $username . - ', nonce=' . $nonce . - ', c=' . $challenge); - Minz_Request::bad(_t('invalid_login'), - array('c' => 'index', 'a' => 'login')); - } - } - } - - public function logoutAction() { - invalidateHttpCache(); - FreshRSS_Auth::removeAccess(); - Minz_Request::good(_t('disconnected'), - array('c' => 'index', 'a' => 'index')); - } } diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 35a37b887..6b7a813bf 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -64,6 +64,14 @@ class FreshRSS extends Minz_FrontController { Minz_View::appendScript(Minz_Url::display('/scripts/jquery.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.min.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/main.js?' . @filemtime(PUBLIC_PATH . '/scripts/main.js'))); + + if (Minz_Configuration::authType() === 'persona') { + // TODO move it in a plugin + // Needed for login AND logout with Persona. + Minz_View::appendScript('https://login.persona.org/include.js'); + $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/persona.js'); + Minz_View::appendScript(Minz_Url::display('/scripts/persona.js?' . $file_mtime)); + } } private function loadNotifications() { diff --git a/app/Models/Auth.php b/app/Models/Auth.php index 992b444a5..cc23d7974 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -20,7 +20,7 @@ class FreshRSS_Auth { Minz_Session::_param('currentUser', $current_user); } - $access_ok = self::accessControl($current_user); + $access_ok = self::accessControl(); if ($access_ok) { self::giveAccess(); @@ -36,10 +36,9 @@ class FreshRSS_Auth { * Required session parameters are also set in this method (such as * currentUser). * - * @param string $username username of the user to check access. * @return boolean true if user can be connected, false else. */ - public static function accessControl($username) { + public static function accessControl() { if (self::$login_ok) { return true; } @@ -61,6 +60,16 @@ class FreshRSS_Auth { Minz_Session::_param('currentUser', $current_user); } return $login_ok; + case 'persona': + $email = filter_var(Minz_Session::param('mail'), FILTER_VALIDATE_EMAIL); + $persona_file = DATA_PATH . '/persona/' . $email . '.txt'; + if (($current_user = @file_get_contents($persona_file)) !== false) { + $current_user = trim($current_user); + Minz_Session::_param('currentUser', $current_user); + Minz_Session::_param('mail', $email); + return true; + } + return false; case 'none': return true; default: @@ -87,6 +96,9 @@ class FreshRSS_Auth { case 'http_auth': self::$login_ok = strcasecmp($current_user, httpAuthUser()) === 0; break; + case 'persona': + self::$login_ok = strcasecmp(Minz_Session::param('mail'), $conf->mail_login) === 0; + break; case 'none': self::$login_ok = true; break; @@ -131,6 +143,9 @@ class FreshRSS_Auth { Minz_Session::_param('passwordHash'); FreshRSS_FormAuth::deleteCookie(); break; + case 'persona': + Minz_Session::_param('mail'); + break; case 'http_auth': case 'none': // Nothing to do... diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 12c86d61d..deb21edc9 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -2,9 +2,9 @@ if (Minz_Configuration::canLogIn()) { ?>
  • -
  • -
    + +
    + +
    +
    diff --git a/app/views/auth/formLogin.phtml b/app/views/auth/formLogin.phtml new file mode 100644 index 000000000..0194a11a5 --- /dev/null +++ b/app/views/auth/formLogin.phtml @@ -0,0 +1,28 @@ +
    +

    + +
    +
    + + +
    +
    + + +
    + +
    +
    + +
    +
    +
    + +
    +
    + +

    +
    diff --git a/app/views/auth/logout.phtml b/app/views/auth/logout.phtml new file mode 100644 index 000000000..e69de29bb diff --git a/app/views/auth/personaLogin.phtml b/app/views/auth/personaLogin.phtml new file mode 100644 index 000000000..d62fe5818 --- /dev/null +++ b/app/views/auth/personaLogin.phtml @@ -0,0 +1,24 @@ +res === false) { ?> +
    +

    + +

    + + +

    + + + + + +

    + +

    +
    +res); +} +?> diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 8f615ed87..3bbcc3848 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -8,6 +8,15 @@ $hide_posts = ($this->conf->display_posts || Minz_Request::param('output') === 'reader'); $s = $this->conf->shortcuts; +$url_login = Minz_Url::display(array( + 'c' => 'auth', + 'a' => 'login' +), 'php'); +$url_logout = Minz_Url::display(array( + 'c' => 'auth', + 'a' => 'logout' +), 'php'); + echo 'var context={', 'hide_posts:', $hide_posts ? 'false' : 'true', ',', 'display_order:"', Minz_Request::param('order', $this->conf->sort_order), '",', @@ -43,8 +52,8 @@ echo 'shortcuts={', echo 'url={', 'index:"', _url('index', 'index'), '",', - 'login:"', _url('index', 'login'), '",', - 'logout:"', _url('index', 'logout'), '",', + 'login:"', $url_login, '",', + 'logout:"', $url_logout, '",', 'help:"', FRESHRSS_WIKI, '"', "},\n"; diff --git a/app/views/index/formLogin.phtml b/app/views/index/formLogin.phtml deleted file mode 100644 index b05cdced4..000000000 --- a/app/views/index/formLogin.phtml +++ /dev/null @@ -1,46 +0,0 @@ -
    -

    -
    - - -
    -
    - - -
    - -
    -
    - -
    -
    -
    - -
    -

    -

    - - - - - -

    - -

    -
    diff --git a/p/scripts/main.js b/p/scripts/main.js index b01a3a34d..77e1e3f77 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1034,67 +1034,7 @@ function init_crypto_form() { } // -// -function init_persona() { - if (!(navigator.id)) { - if (window.console) { - console.log('FreshRSS waiting for Persona…'); - } - window.setTimeout(init_persona, 100); - return; - } - $('a.signin').click(function() { - navigator.id.request(); - return false; - }); - - $('a.signout').click(function() { - navigator.id.logout(); - return false; - }); - navigator.id.watch({ - loggedInUser: context['current_user_mail'], - - onlogin: function(assertion) { - // A user has logged in! Here you need to: - // 1. Send the assertion to your backend for verification and to create a session. - // 2. Update your UI. - $.ajax ({ - type: 'POST', - url: url['login'], - data: {assertion: assertion}, - success: function(res, status, xhr) { - /*if (res.status === 'failure') { - alert (res_obj.reason); - } else*/ if (res.status === 'okay') { - location.href = url['index']; - } - }, - error: function(res, status, xhr) { - alert("Login failure: " + res); - } - }); - }, - onlogout: function() { - // A user has logged out! Here you need to: - // Tear down the user's session by redirecting the user or making a call to your backend. - // Also, make sure loggedInUser will get set to null on the next page load. - // (That's a literal JavaScript null. Not false, 0, or undefined. null.) - $.ajax ({ - type: 'POST', - url: url['logout'], - success: function(res, status, xhr) { - location.href = url['index']; - }, - error: function(res, status, xhr) { - //alert("logout failure" + res); - } - }); - } - }); -} -// function init_confirm_action() { $('body').on('click', '.confirm', function () { @@ -1274,11 +1214,6 @@ function init_all() { return; } init_notifications(); - switch (context['auth_type']) { - case 'persona': - init_persona(); - break; - } init_confirm_action(); $stream = $('#stream'); if ($stream.length > 0) { diff --git a/p/scripts/persona.js b/p/scripts/persona.js new file mode 100644 index 000000000..36aeeaf56 --- /dev/null +++ b/p/scripts/persona.js @@ -0,0 +1,76 @@ +"use strict"; + +function init_persona() { + if (!(navigator.id && window.$)) { + if (window.console) { + console.log('FreshRSS (Persona) waiting for JS…'); + } + window.setTimeout(init_persona, 100); + return; + } + + $('a.signin').click(function() { + navigator.id.request(); + return false; + }); + + $('a.signout').click(function() { + navigator.id.logout(); + return false; + }); + + navigator.id.watch({ + loggedInUser: context['current_user_mail'], + + onlogin: function(assertion) { + // A user has logged in! Here you need to: + // 1. Send the assertion to your backend for verification and to create a session. + // 2. Update your UI. + $.ajax ({ + type: 'POST', + url: url['login'], + data: {assertion: assertion}, + success: function(res, status, xhr) { + if (res.status === 'failure') { + openNotification(res.reason, 'bad'); + } else if (res.status === 'okay') { + location.href = url['index']; + } + }, + error: function(res, status, xhr) { + // alert(res); + } + }); + }, + onlogout: function() { + // A user has logged out! Here you need to: + // Tear down the user's session by redirecting the user or making a call to your backend. + // Also, make sure loggedInUser will get set to null on the next page load. + // (That's a literal JavaScript null. Not false, 0, or undefined. null.) + $.ajax ({ + type: 'POST', + url: url['logout'], + success: function(res, status, xhr) { + location.href = url['index']; + }, + error: function(res, status, xhr) { + // alert(res); + } + }); + } + }); +} + +if (document.readyState && document.readyState !== 'loading') { + if (window.console) { + console.log('FreshRSS (Persona) immediate init…'); + } + init_persona(); +} else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', function () { + if (window.console) { + console.log('FreshRSS (Persona) waiting for DOMContentLoaded…'); + } + init_persona(); + }, false); +} -- cgit v1.2.3 From 2796cc9ae559842a90fa15cba65c94a11b29195e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 16 Oct 2014 16:43:37 +0200 Subject: User list load a new page Beginning of more options for administrator! --- app/Controllers/userController.php | 4 ++++ app/views/stats/repartition.phtml | 2 +- app/views/user/manage.phtml | 41 +++++++++++++++++++------------------- p/scripts/main.js | 2 +- 4 files changed, 26 insertions(+), 23 deletions(-) (limited to 'p') diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index c516246c9..00b51cc3d 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -88,6 +88,10 @@ class FreshRSS_user_Controller extends Minz_ActionController { */ public function manageAction() { Minz_View::prependTitle(_t('users.manage') . ' · '); + + $this->view->current_user = Minz_Request::param( + 'u', Minz_Session::param('currentUser', '_') + ); } public function createAction() { diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index 670714707..32268a546 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -5,7 +5,7 @@

    - categories as $category) { $feeds = $category->feeds(); diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index 03746cabb..fb569872b 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -3,27 +3,6 @@
    -
    - - -
    - -
    - -
    -
    - -
    -
    - -
    -
    -
    -
    @@ -71,6 +50,26 @@
    + + +
    + +
    + +
    + +
    +
    + +
    +
    + +
    +
    diff --git a/p/scripts/main.js b/p/scripts/main.js index 77e1e3f77..1e13ff16a 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1086,7 +1086,7 @@ function init_share_observers() { } function init_stats_observers() { - $('#feed_select').on('change', function(e) { + $('.select-change').on('change', function(e) { redirect($(this).find(':selected').data('url')); }); } -- cgit v1.2.3 From 8a7bab3a55442f85553ab1d897084e89c10f7e05 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 20 Oct 2014 19:35:22 +0200 Subject: Refactoring of indexController Global view has been moved to a different action (all is not working) See https://github.com/marienfressinaud/FreshRSS/issues/634 and https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/Controllers/errorController.php | 2 +- app/Controllers/indexController.php | 33 +++++++++++++++----- app/layout/nav_menu.phtml | 2 +- app/views/helpers/view/global_view.phtml | 53 -------------------------------- app/views/index/global.phtml | 46 +++++++++++++++++++++++++++ app/views/index/index.phtml | 2 -- lib/lib_rss.php | 4 +++ p/scripts/global_view.js | 3 +- 8 files changed, 79 insertions(+), 66 deletions(-) delete mode 100644 app/views/helpers/view/global_view.phtml create mode 100644 app/views/index/global.phtml (limited to 'p') diff --git a/app/Controllers/errorController.php b/app/Controllers/errorController.php index 76ab930e0..6c080bea8 100644 --- a/app/Controllers/errorController.php +++ b/app/Controllers/errorController.php @@ -37,7 +37,7 @@ class FreshRSS_error_Controller extends Minz_ActionController { if ($this->view->errorMessage == '') { switch($code_int) { case 403: - $this->view->errorMessage = _t('forbidden_access'); + $this->view->errorMessage = _t('access_denied'); break; case 404: default: diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index f994e257c..e1ce71b28 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -1,5 +1,8 @@ array(_t('access_denied'))) - ); + Minz_Error::error(403); return; } elseif ($output !== 'rss') { // "hard" redirection is not required, just ask dispatcher to @@ -201,17 +201,34 @@ class FreshRSS_index_Controller extends Minz_ActionController { return false; } } + + /** + * This action displays the global view of FreshRSS. + */ + public function globalAction() { + if (!FreshRSS_Auth::hasAccess() && !Minz_Configuration::allowAnonymous()) { + Minz_Error::error(403); + } + + Minz_View::appendScript(Minz_Url::display('/scripts/global_view.js?' . @filemtime(PUBLIC_PATH . '/scripts/global_view.js'))); + + $catDAO = new FreshRSS_CategoryDAO(); + $this->view->categories = $catDAO->listCategories(); + } + /** + * This action displays the about page of FreshRSS. + */ public function aboutAction() { Minz_View::prependTitle(_t('about') . ' · '); } + /** + * This action displays logs of FreshRSS for the current user. + */ public function logsAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } Minz_View::prependTitle(_t('logs') . ' · '); diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index bb9468ab1..1a26422df 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -240,7 +240,7 @@ - + diff --git a/app/views/helpers/view/global_view.phtml b/app/views/helpers/view/global_view.phtml deleted file mode 100644 index ae8af820d..000000000 --- a/app/views/helpers/view/global_view.phtml +++ /dev/null @@ -1,53 +0,0 @@ -partial('nav_menu'); ?> - -entries)) { ?> -
    - 'index', 'a' => 'index', 'params' => array()); - if (FreshRSS_Context::$conf->view_mode !== 'normal') { - $arUrl['params']['output'] = 'normal'; - } - $p = Minz_Request::param('state', ''); - if (($p != '') && (FreshRSS_Context::$conf->default_view !== $p)) { - $arUrl['params']['state'] = $p; - } - - foreach ($this->cat_aside as $cat) { - $feeds = $cat->feeds(); - if (!empty($feeds)) { -?> -
    - - -
    - -
    - -
    -
    display_posts ? '' : ' class="hide_posts"'; ?>> - -
    - - -
    -

    -

    -
    - diff --git a/app/views/index/global.phtml b/app/views/index/global.phtml new file mode 100644 index 000000000..a72e431df --- /dev/null +++ b/app/views/index/global.phtml @@ -0,0 +1,46 @@ +partial('nav_menu'); ?> + +
    + 'index', + 'a' => 'index', + 'params' => array( + 'state' => FreshRSS_Context::$state + ) + ); + + foreach ($this->categories as $cat) { + $feeds = $cat->feeds(); + $url_base['params']['get'] = 'c_' . $cat->id(); + + if (!empty($feeds)) { +?> +
    + + +
      + nbNotRead(); + $error = $feed->inError() ? 'error ' : ''; + $empty = $feed->nbEntries() === 0 ? 'empty ' : ''; + $url_base['params']['get'] = 'f_' . $feed->id(); + ?> +
    • + ✇ + name(); ?> +
    • + +
    +
    + +
    + +
    +
    display_posts ? '' : ' class="hide_posts"'; ?>> + +
    diff --git a/app/views/index/index.phtml b/app/views/index/index.phtml index a59063557..8b93461dd 100644 --- a/app/views/index/index.phtml +++ b/app/views/index/index.phtml @@ -7,8 +7,6 @@ if (FreshRSS_Auth::hasAccess() || Minz_Configuration::allowAnonymous()) { $this->renderHelper('view/normal_view'); } elseif ($output === 'reader') { $this->renderHelper('view/reader_view'); - } elseif ($output === 'global') { - $this->renderHelper('view/global_view'); } elseif ($output === 'rss') { $this->renderHelper('view/rss_view'); } else { diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 9abdf18ce..80eb206d2 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -60,6 +60,10 @@ function formatNumber($n, $precision = 0) { return str_replace(' ', ' ', //Espace insécable //TODO: remplacer par une espace _fine_ insécable number_format($n, $precision, '.', ' ')); //number_format does not seem to be Unicode-compatible } +function format_number($n, $precision = 0) { + // TODO: coding style, prefer THIS function. Remove formatNumber. + return formatNumber($n, $precision); +} function formatBytes($bytes, $precision = 2, $system = 'IEC') { if ($system === 'IEC') { diff --git a/p/scripts/global_view.js b/p/scripts/global_view.js index 6e1f61066..8c2e6c1a2 100644 --- a/p/scripts/global_view.js +++ b/p/scripts/global_view.js @@ -50,7 +50,8 @@ function init_close_panel() { } function init_global_view() { - $("#stream .box-category a").click(function () { + // TODO: should be based on generic classes. + $(".box a").click(function () { var link = $(this).attr("href"); load_panel(link); -- cgit v1.2.3 From e37a126b9de20a11f306d29c8f3d5052eb4310dd Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 22 Oct 2014 23:41:36 +0200 Subject: Fix some parts of aside_flux See https://github.com/marienfressinaud/FreshRSS/issues/634 --- app/layout/aside_flux.phtml | 37 ++++++++++++++++++------ p/themes/base-theme/base.css | 16 +++++++++++ p/themes/base-theme/template.css | 61 ++++++++++++++++++++-------------------- 3 files changed, 75 insertions(+), 39 deletions(-) (limited to 'p') diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index e572e9d48..30f362348 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -1,4 +1,13 @@ -
    +hide_read_feeds && + FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_NOT_READ) && + !FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_READ)) { + $class = ' state_unread'; + } +?> + +
    @@ -14,24 +23,36 @@
    • - +
      + +
    • - +
      + +
    • categories as $cat) { $feeds = $cat->feeds(); if (!empty($feeds)) { + $c_active = FreshRSS_Context::isCurrentGet('c_' . $cat->id()); + $c_show = $c_active && (!FreshRSS_Context::$conf->display_categories || + FreshRSS_Context::$current_get['feed']); ?> -
    • - name(); ?> +
    • + -
        - -
      • +
          + id()); + ?> +
        • diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index aab511fb9..80f76e80b 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -692,6 +692,7 @@ br + br + br { position: relative; min-width: 260px; max-width: 640px; + margin-bottom: 30px; } .slides * { user-select: none; @@ -740,26 +741,19 @@ br + br + br { padding: 0; } .properties { - bottom: 15px; + bottom: -35px; + position: absolute; + width: 100%; display: none; - left: 15%; - padding: 5px; +} +.properties .page-number { + right: 0; + top: 0; position: absolute; - text-align: center; - width: 70%; - font-size: 15pt; - text-shadow: 0px 0px 15px rgb(119, 119, 119); - border-radius: 5px; - box-shadow: 5px 5px 10px; - border: 1px solid; - background-color: #fff; } .slide:hover + .nav label { opacity: 0.5; } -.slide:hover ~ .properties { - display: block; -} .nav label:hover { opacity: 1; } @@ -774,6 +768,9 @@ input:checked + .slide-container .slide { input:checked + .slide-container .nav label { display: block; } +input:checked + .slide-container .properties { + display: block; +} /*=== DIVERS */ /*===========*/ -- cgit v1.2.3 From 7781add6dab45e890bb873e7fd42f83a6227e62c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 24 Nov 2014 15:45:47 +0100 Subject: Update Screwdriver theme --- p/themes/Screwdriver/icons/favicon-16-32-48-64.ico | Bin 0 -> 1150 bytes p/themes/Screwdriver/icons/favicon-256.png | Bin 0 -> 15724 bytes p/themes/Screwdriver/icons/favicon.svg | 280 +++++++++++++++++++++ p/themes/Screwdriver/icons/icon.svg | 271 ++++++++++++++++++++ p/themes/Screwdriver/screwdriver.css | 105 ++++---- 5 files changed, 610 insertions(+), 46 deletions(-) create mode 100644 p/themes/Screwdriver/icons/favicon-16-32-48-64.ico create mode 100644 p/themes/Screwdriver/icons/favicon-256.png create mode 100644 p/themes/Screwdriver/icons/favicon.svg create mode 100644 p/themes/Screwdriver/icons/icon.svg (limited to 'p') diff --git a/p/themes/Screwdriver/icons/favicon-16-32-48-64.ico b/p/themes/Screwdriver/icons/favicon-16-32-48-64.ico new file mode 100644 index 000000000..7c5eb5517 Binary files /dev/null and b/p/themes/Screwdriver/icons/favicon-16-32-48-64.ico differ diff --git a/p/themes/Screwdriver/icons/favicon-256.png b/p/themes/Screwdriver/icons/favicon-256.png new file mode 100644 index 000000000..235b18c97 Binary files /dev/null and b/p/themes/Screwdriver/icons/favicon-256.png differ diff --git a/p/themes/Screwdriver/icons/favicon.svg b/p/themes/Screwdriver/icons/favicon.svg new file mode 100644 index 000000000..aaab5de99 --- /dev/null +++ b/p/themes/Screwdriver/icons/favicon.svg @@ -0,0 +1,280 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/Screwdriver/icons/icon.svg b/p/themes/Screwdriver/icons/icon.svg new file mode 100644 index 000000000..7f3d76af2 --- /dev/null +++ b/p/themes/Screwdriver/icons/icon.svg @@ -0,0 +1,271 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/Screwdriver/screwdriver.css b/p/themes/Screwdriver/screwdriver.css index b6c2e670e..8dbd2ec34 100644 --- a/p/themes/Screwdriver/screwdriver.css +++ b/p/themes/Screwdriver/screwdriver.css @@ -52,7 +52,7 @@ input, select, textarea { color: #222; line-height: 25px; vertical-align: middle; - box-shadow: 0 2px 2px #eee inset, 0 1px #fff; + box-shadow: 0 1px 2px #ccc inset, 0 1px #fff; } option { padding: 0 .5em; @@ -121,30 +121,14 @@ form th { } /*=== Buttons */ -form#add_rss .stick input, .dropdown-menu select{ - background:#393939; - box-shadow: 0 2px 2px #171717 inset,0 1px rgba(255,255,255,0.08); - border-left:solid 1px #171717; - border-top:solid 1px #171717; - border-bottom:solid 1px #171717; - border-right:none; + +.dropdown-menu .input select, .dropdown-menu .input input { + background:#444; color:#fff; + box-shadow:0 2px 2px #222 inset, 0px 1px rgba(255, 255, 255, 0.08); + border:solid 1px #171717; } -form#add_rss .stick .btn{ - background:linear-gradient(180deg, #222 0%, #171717 100%) #171717; - background: -webkit-linear-gradient(top, #222 0%, #171717 100%); - box-shadow:0 1px rgba(255,255,255,0.08), 0px 1px rgba(255, 255, 255, 0.08) inset; - border-right:solid 1px #171717; - border-top:solid 1px #171717; - border-bottom:solid 1px #171717; - border-left:none; -} -form#add_rss .stick .btn.dropdown-toggle{ - border-right:solid 1px #171717; - border-top:solid 1px #171717; - border-bottom:solid 1px #171717; - border-left:solid 1px #171717; -} + .stick { vertical-align: middle; font-size: 0; @@ -206,14 +190,13 @@ a.btn { background: linear-gradient(180deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; background: -webkit-linear-gradient(top, #EDE7DE 0%, #FFF 100%); } -#loginButton.btn{ - border:none; - box-shadow: 0px 1px rgba(255, 255, 255, 0.08) inset,0 -1px #171717,0px 1px rgba(255, 255, 255, 0.08); -} + .nav_menu .btn.active, .nav_menu .btn:active, .nav_menu .dropdown-target:target ~ .btn.dropdown-toggle{ - box-shadow: 0px 2px #E2972A; - border-radius: 0; - background:transparent; + box-shadow: 0 1px #fff; + border-radius: 4px; + background: linear-gradient(180deg, #EDE7DE 0%, #F6F6F6 100%) #EDE7DE; + background: -webkit-linear-gradient(top, #EDE7DE 0%, #F6F6F6 100%); + border: solid 1px #ccc; } .nav_menu .btn { border: 0; @@ -500,7 +483,8 @@ a.btn { /*=== Boxes */ .box { background: #EDE7DE; - border-radius: 4px 4px 0 0; + border-radius: 4px; + box-shadow: 0 1px #fff; } .box .box-title { margin: 0; @@ -575,6 +559,7 @@ a.btn { .tree-folder-items > .item > a { text-decoration: none; color: #fff; + font-size: 0.92em; } .tree-folder-items > .item.active > a { } @@ -593,7 +578,8 @@ a.btn { text-align: center; } .header > .item.title .logo { - display: none; + height: 60px; + width: 60px; } .header > .item.title{ width: 250px; @@ -603,9 +589,9 @@ a.btn { } .header > .item.title h1 a { text-decoration: none; - font-size: 38px; - color:#ccc; - text-shadow: 0 1px #fff, 0 -1px rgba(162, 162, 162, 1); + font-size: 28px; + color:#222; + text-shadow: 0 1px #fff; } .header > .item.search input { width: 230px; @@ -681,11 +667,8 @@ a.btn { /*=== Prompt (centered) */ .prompt { text-align: center; - color: #FFF; - background: #222; padding: 14px 0px; - box-shadow: 0px -1px #FFF, 0px 1px #FFF, 0px 2px 2px #171717 inset, 0px -2px 2px #171717 inset; - text-shadow: 0 -1px #171717, 0 1px rgba(255,255,255,0.08); + text-shadow: 0 1px rgba(255,255,255,0.08); } .prompt label { text-align: left; @@ -702,9 +685,9 @@ a.btn { margin: 20px 0; } .prompt input#username,.prompt input#passwordPlain{ - border:none; - box-shadow: 0px 1px rgba(255, 255, 255, 0.08) inset,0 -1px #171717,0px 1px rgba(255, 255, 255, 0.08); - background:#EDE7DE; + border:solid 1px #ccc; + box-shadow: 0 4px -4px #ccc inset,0px 1px rgba(255, 255, 255, 0.08); + background:#fff; } .prompt input#username:focus,.prompt input#passwordPlain:focus{ border: solid 1px #E7AB34; @@ -734,7 +717,11 @@ a.btn { padding: 0 10px; font-style:italic; line-height: 3em; - background: #fff; + box-shadow: 0 1px #BDB7AE inset, 0 -1px rgba(255,255,255,0.28) inset; + background: linear-gradient(0deg, #EDE7DE 0%, #C2BCB3 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #C2BCB3 0%, #FFF 100%); + color: #666; + text-shadow: 0 1px rgba(255,255,255,0.28); text-align: center; } #new-article + .day { @@ -748,10 +735,26 @@ a.btn { .nav_menu { background: #EDE7DE; border-bottom: 1px solid #ccc; - box-shadow:0 -1px #fff inset; + box-shadow:0 -1px rgba(255, 255, 255, 0.28) inset; text-align: center; padding: 5px 0; } +#panel >.nav_menu{ + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); +} +#panel > .nav_menu > #nav_menu_read_all{ + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); + border-radius: 4px; + border: 1px solid #CCC; + box-shadow: 0px 1px #FFF; +} +#panel > .nav_menu > #nav_menu_read_all > .dropdown > .btn.dropdown-toggle{ + border-radius: 0 4px 4px 0; + border:none; + border-left: solid 1px #ccc; +} /*=== Feed articles */ .flux_content { @@ -810,6 +813,7 @@ opacity: 1; border-top: 1px solid #ddd; font-size: 0.8rem; cursor: pointer; + box-shadow: 0 -1px rgba(255,255,255,0.28) inset; } .flux_header .title { font-size: 0.9rem; @@ -917,6 +921,7 @@ opacity: 1; text-shadow: 0 -1px 0 #aaa; color: #666; background: #EDE7DE; + box-shadow: 0 1px rgba(255,255,255,0.28)inset; } #bigMarkAsRead:hover { color: #000; @@ -956,9 +961,8 @@ opacity: 1; /*=== GLOBAL VIEW */ /*================*/ #stream.global { - background: #222; padding: 24px 0; - box-shadow: 0 1px #fff, 0 -2px 2px #171717 inset, 0 2px 2px #171717 inset; + box-shadow: 0px 8px 8px #C2BCB3 inset; } .box.category .box-title { @@ -1004,6 +1008,7 @@ opacity: 1; #panel { box-shadow: 0px 0px 4px #000; border-radius: 8px; + background:#EDE7DE; } /*=== DIVERS */ /*===========*/ @@ -1084,6 +1089,14 @@ opacity: 1; color: #eee; } +#slider.active { + box-shadow: -4px 0 4px rgba(15, 15, 15, 0.55); + background: #F8F8F8; +} +#close-slider.active { + background: rgba(15, 15, 15, 0.35); +} + /*=== MOBILE */ /*===========*/ @media screen and (max-width: 840px) { -- cgit v1.2.3 From b9b3e963b49b255dd694b001b303e75f58519b67 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 24 Nov 2014 15:49:13 +0100 Subject: Add BlueLagoon theme --- p/themes/BlueLagoon/BlueLagoon.css | 1210 +++++++++++++++++++++ p/themes/BlueLagoon/README.md | 38 + p/themes/BlueLagoon/icons/bookmark.svg | 61 ++ p/themes/BlueLagoon/icons/favicon-16-32-48-64.ico | Bin 0 -> 1150 bytes p/themes/BlueLagoon/icons/favicon-256.png | Bin 0 -> 16517 bytes p/themes/BlueLagoon/icons/favicon.svg | 273 +++++ p/themes/BlueLagoon/icons/icon.svg | 291 +++++ p/themes/BlueLagoon/icons/non-starred.svg | 59 + p/themes/BlueLagoon/icons/read.svg | 72 ++ p/themes/BlueLagoon/icons/starred.svg | 60 + p/themes/BlueLagoon/icons/unread.svg | 65 ++ p/themes/BlueLagoon/loader.gif | Bin 0 -> 3164 bytes p/themes/BlueLagoon/metadata.json | 7 + p/themes/BlueLagoon/template.css | 695 ++++++++++++ p/themes/BlueLagoon/thumbs/original.png | Bin 0 -> 153829 bytes 15 files changed, 2831 insertions(+) create mode 100644 p/themes/BlueLagoon/BlueLagoon.css create mode 100644 p/themes/BlueLagoon/README.md create mode 100644 p/themes/BlueLagoon/icons/bookmark.svg create mode 100644 p/themes/BlueLagoon/icons/favicon-16-32-48-64.ico create mode 100644 p/themes/BlueLagoon/icons/favicon-256.png create mode 100644 p/themes/BlueLagoon/icons/favicon.svg create mode 100644 p/themes/BlueLagoon/icons/icon.svg create mode 100644 p/themes/BlueLagoon/icons/non-starred.svg create mode 100644 p/themes/BlueLagoon/icons/read.svg create mode 100644 p/themes/BlueLagoon/icons/starred.svg create mode 100644 p/themes/BlueLagoon/icons/unread.svg create mode 100644 p/themes/BlueLagoon/loader.gif create mode 100644 p/themes/BlueLagoon/metadata.json create mode 100644 p/themes/BlueLagoon/template.css create mode 100644 p/themes/BlueLagoon/thumbs/original.png (limited to 'p') diff --git a/p/themes/BlueLagoon/BlueLagoon.css b/p/themes/BlueLagoon/BlueLagoon.css new file mode 100644 index 000000000..ae1c24604 --- /dev/null +++ b/p/themes/BlueLagoon/BlueLagoon.css @@ -0,0 +1,1210 @@ +@charset "UTF-8"; + +/*=== FONTS */ +@font-face { + font-family: "OpenSans"; + src: url("../fonts/openSans.woff") format("woff"); +} + +/*=== GENERAL */ +/*============*/ +html, body { + height: 100%; + font-family: "OpenSans", "Cantarell", "Helvetica", "Arial", sans-serif; + background: #fafafa; + font-size: 92%; +} + +/*=== Links */ +a, button.as-link { + color: #0062BE; + outline: none; +} + +/*=== Forms */ +.form-group{ + width: 100%; + float: left; + height: auto; + display: inline-block; +} +legend { + margin: 20px 0 5px; + padding: 5px 0; + border-bottom: 1px solid #ddd; + font-size: 1.4em; +} +label { + min-height: 25px; + padding: 5px 0; + cursor: pointer; +} +textarea { + width: 360px; + height: 100px; +} +input, select, textarea { + min-height: 25px; + padding: 5px; + background: #fff; + border: 1px solid #ccc; + border-radius: 3px; + color: #222; + line-height: 25px; + vertical-align: middle; + box-shadow: 0 1px 2px #ccc inset, 0 1px #fff; +} +option { + padding: 0 .5em; +} +input:focus, select:focus, textarea:focus { + color: #0F0F0F; + box-shadow: 0 0 3px #0062BF; + border: solid 1px #0062BF; +} +input:invalid, select:invalid { + border-color: #f00; + box-shadow: 0 0 2px 2px #fdd inset; +} +input:disabled, select:disabled { + background: #eee; +} +input.extend { + transition: width 200ms linear; + -moz-transition: width 200ms linear; + -webkit-transition: width 200ms linear; + -o-transition: width 200ms linear; + -ms-transition: width 200ms linear; +} + +/*=== Tables */ +table { + border-collapse: collapse; +} + +tr, th, td { + padding: 0.5em; + border: 1px solid #ddd; +} +th { + background: #f6f6f6; +} +form td, +form th { + font-weight: normal; + text-align: center; +} + +/*=== COMPONENTS */ +/*===============*/ +/*=== Forms */ +.form-group.form-actions { + padding: 5px 0; + background: #f4f4f4; + border-top: 1px solid #ddd; +} +.form-group.form-actions .btn { + margin: 0 10px; + border-radius: 4px; + box-shadow:0 1px rgba(255,255,255,0.08) inset; +} +.form-group .group-name { + padding: 10px 0; + text-align: right; +} +.form-group .group-controls { + min-height: 25px; + padding: 5px 0; +} +.form-group table { + margin: 10px 0 0 220px; +} + +/*=== Buttons */ + +.dropdown-menu .input select, .dropdown-menu .input input { + background:#444; + color:#fff; + box-shadow:0 2px 2px #222 inset, 0px 1px rgba(255, 255, 255, 0.08); + border:solid 1px #171717; +} + +.stick { + vertical-align: middle; + font-size: 0; +} +.stick input, +.stick .btn { + border-radius: 0; +} +.stick .btn:first-child,.stick input:first-child { + border-radius: 6px 0 0 6px; +} +.stick .btn-important:first-child { +} +.stick .btn:last-child, .stick input:last-child { + border-radius: 0 6px 6px 0; +} +.stick .btn + .btn, +.stick .btn + input, +.stick .btn + .dropdown > .btn, +.stick input + .btn, +.stick input + input, +.stick input + .dropdown > .btn, +.stick .dropdown + .btn, +.stick .dropdown + input, +.stick .dropdown + .dropdown > .btn { + border-left: none; +} +.stick .btn + .dropdown > .btn { + border-left: none; + border-radius: 0 3px 3px 0; +} + +.btn { + display: inline-block; + min-height: 37px; + min-width: 15px; + margin: 0; + padding: 5px 10px; + color:#222; + border: solid 1px #ccc; + border-radius: 4px; + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); + text-shadow: 0px -1px rgba(255,255,255,0.08); + font-size: 0.9rem; + vertical-align: middle; + cursor: pointer; + overflow: hidden; +} +a.btn { + min-height: 25px; + line-height: 25px; +} +.btn:hover { + text-shadow: 0 0 2px #fff; + text-decoration:none; +} +.btn.active,.btn:active,.dropdown-target:target ~ .btn.dropdown-toggle { + background: linear-gradient(180deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(top, #EDE7DE 0%, #FFF 100%); +} + +.nav_menu .btn.active, .nav_menu .btn:active, .nav_menu .dropdown-target:target ~ .btn.dropdown-toggle{ + box-shadow: 0 1px #fff; + border-radius: 4px; + background: linear-gradient(180deg, #EDE7DE 0%, #F6F6F6 100%) #EDE7DE; + background: -webkit-linear-gradient(top, #EDE7DE 0%, #F6F6F6 100%); + border: solid 1px #ccc; +} +.nav_menu .btn { + border: 0; + background:transparent; +} + +.read_all { + color:#222; +} +.btn.dropdown-toggle[href="#dropdown-configure"]{ + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); + border-radius: 4px; + border: solid 1px #ccc; + box-shadow: 0 1px #fff; +} +.btn.dropdown-toggle:active { + background:transparent; +} +.btn-important { + background: linear-gradient(180deg, #0090FF 0%, #0062BE 100%) #E4992C; + background: -webkit-linear-gradient(top, #0090FF 0%, #0062BE 100%); + color: #FFF; + box-shadow: 0 1px rgba(255,255,255,0.08) inset; + border-radius: 4px; + text-shadow: 0px -1px rgba(255,255,255,0.08); + font-weight: normal; +} +.btn-important:hover { +} +.btn-important:active { + background: linear-gradient(0deg, #E4992C 0%, #D18114 100%) #E4992C; + background: -webkit-linear-gradient(bottom, #E4992C 0%, #D18114 100%); +} + +.btn-attention { + background: #E95B57; + background: linear-gradient(to bottom, #E95B57, #BD362F); + background: -webkit-linear-gradient(top, #E95B57 0%, #BD362F 100%); + color: #fff; + border: 1px solid #C44742; + text-shadow: 0px -1px 0px #666; +} +.btn-attention:hover { + background: linear-gradient(to bottom, #D14641, #BD362F); + background: -webkit-linear-gradient(top, #D14641 0%, #BD362F 100%); +} +.btn-attention:active { + background: #BD362F; + box-shadow: none; +} +.btn[type="reset"]{ + color: #fff; + background:linear-gradient(180deg, #222 0%, #171717 100%) #171717; + background: -webkit-linear-gradient(top, #222 0%, #171717 100%); + box-shadow:0 -1px rgba(255,255,255,0.08) inset; +} +/*=== Navigation */ +.nav-list .nav-header, +.nav-list .item { + height: 2.5em; + line-height: 2.5em; + font-size: 0.9rem; +} +.nav-list .item:hover { + text-shadow: 0 0 2px rgba(255,255,255,0.28); + color:#fff; +} + +.nav-list .item.active { + background: linear-gradient(180deg, #0090FF 0%, #0062BE 100%) #E4992C; + background: -webkit-linear-gradient(top, #0090FF 0%, #0062BE 100%); + border-width: medium medium 1px; + border-style: none none solid; + border-color: -moz-use-text-color -moz-use-text-color #171717; + box-shadow: -1px 2px 2px #171717, 0px 1px rgba(255, 255, 255, 0.08) inset; + margin: 0; +} +.nav-list .item.active a { + color: #fff; +} +.nav-list .disable { + color: #aaa; + background: #fafafa; + text-align: center; +} +.nav-list .item > a { + padding: 0 10px; + color:#ccc; +} +.nav-list a:hover { + text-decoration: none; +} +.nav-list .item.empty a { + color: #f39c12; +} +.nav-list .item.active.empty a { + color: #fff; + background: linear-gradient(180deg, #E4992C 0%, #D18114 100%) #E4992C; + background: -webkit-linear-gradient(180deg, #E4992C 0%, #D18114 100%); +} +.nav-list .item.error a { + color: #BD362F; +} +.nav-list .item.active.error a { + color: #fff; + background: #BD362F; +} + +.nav-list .nav-header { + padding: 0 10px; + color: #222; + background: transparent; +} + +.nav-list .nav-form { + padding: 3px; + text-align: center; +} + +.nav-head { + margin: 0; + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); + text-align: right; +} +.nav-head .item { + padding: 5px 10px; + font-size: 0.9rem; + line-height: 1.5rem; +} + +/*=== Horizontal-list */ +.horizontal-list { + margin: 0; + padding: 0; +} +.horizontal-list .item { + vertical-align: middle; +} + +/*=== Dropdown */ +.dropdown-menu { + margin: 5px 0 0; + padding: 5px 0; + border: 1px solid #171717; + border-radius: 4px; + box-shadow: 0 0 3px #000; + font-size: 0.8rem; + text-align: left; + background: #222; +} +.dropdown-menu:after { + content: ""; + position: absolute; + top: -6px; + right: 13px; + width: 10px; + height: 10px; + background: #222; + border-top: 1px solid #171717; + border-left: 1px solid #171717; + z-index: -10; + transform: rotate(45deg); + -moz-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); +} +.dropdown-header { + display:none; +} +.dropdown-menu > .item > a { + padding: 0 25px; + line-height: 2.5em; + color: #ccc; +} +.dropdown-menu > .item > span, +.dropdown-menu > .item > .as-link { + padding: 0 22px; + line-height: 2em; + color: #ccc; +} +.dropdown-menu > .item:hover { + background: linear-gradient(180deg, #0090FF 0%, #0062BE 100%) #E4992C; + background: -webkit-linear-gradient(top, #0090FF 0%, #0062BE 100%); + color: #fff; +} +.dropdown-menu > .item[aria-checked="true"] > a:before { + font-weight: bold; + margin: 0 0 0 -14px; +} +.dropdown-menu > .item:hover > a { + color: #fff; + text-decoration: none; +} +.dropdown-menu .input select, +.dropdown-menu .input input { + margin: 0 auto 5px; + padding: 2px 5px; + border-radius: 3px; +} + +.separator { + margin: 5px 0; + border-bottom: 1px solid #171717; + box-shadow: 0 1px rgba(255,255,255,0.08); +} + +/*=== Alerts */ +.alert { + margin: 15px auto; + padding: 10px 15px; + background: #f4f4f4; + border: 1px solid #ccc; + border-right: 1px solid #aaa; + border-bottom: 1px solid #aaa; + border-radius: 5px; + color: #aaa; + text-shadow: 0 0 1px #eee; + font-size: 0.9em; +} +.alert-head { + font-size: 1.15em; +} +.alert > a { + color: inherit; + text-decoration: underline; +} +.alert-warn { + background: #ffe; + border: 1px solid #eeb; + color: #c95; +} +.alert-success { + background: #dfd; + border: 1px solid #cec; + color: #484; +} +.alert-error { + background: #fdd; + border: 1px solid #ecc; + color: #844; +} + +/*=== Pagination */ +.pagination { + background: #fafafa; + text-align: center; + color: #333; + font-size: 0.8em; +} +.content .pagination { + margin: 0; + padding: 0; +} +.pagination .item.pager-current { + font-weight: bold; + font-size: 1.5em; +} +.pagination .item a { + display: block; + color: #333; + font-style: italic; + line-height: 3em; + text-decoration: none; +} +.pagination .item a:hover { + background: #ddd; +} +.pagination:first-child .item { + border-bottom: 1px solid #aaa; +} +.pagination:last-child .item { + border-top: 1px solid #ddd; +} + +.pagination .loading, +.pagination a:hover.loading { + background: url("loader.gif") center center no-repeat #fff; + font-size: 0; + height:55px +} + +/*=== Boxes */ +.box { + background: #F9F7F4; + border-radius: 4px; + box-shadow: 0 1px #fff; +} +.box .box-title { + margin: 0; + padding: 5px 10px; + background: linear-gradient(0deg, #EDE7DE 0%, #fff 100%) #171717; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #fff 100%); + box-shadow: 0px -1px #fff inset,0 -2px #ccc inset; + color: #888; + text-shadow: 0 1px #ccc; + border-radius: 4px 4px 0 0; + font-size: 1.1rem; + font-weight: normal; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + +/*=== Tree */ +.tree { + margin: 10px 0; +} +.tree-folder-title { + position: relative; + padding: 0 10px; + line-height: 2.5rem; + font-size: 0.9rem; +} +.tree-folder-title .title { + background: inherit; + color: #fff; +} +.tree-folder-title .title:hover { + text-decoration: none; +} +.tree-folder.active .tree-folder-title { + background: linear-gradient(180deg, #222 0%, #171717 100%) #171717; + background: -webkit-linear-gradient(top, #222 0%, #171717 100%); + box-shadow: 0px 1px #171717, 0px 1px rgba(255, 255, 255, 0.08) inset; + text-shadow: 0 0 2px rgba(255,255,255,0.28); + color: #fff; +} +.tree-folder.active > .tree-folder-title > a.title{ + color: #0090FF; + text-shadow: 0 1px rgba(255,255,255,0.08); +} +.tree-folder-items { + background: #171717; + padding: 8px 0; + box-shadow: 0 4px 4px #171717 inset, 0 1px rgba(255,255,255,0.08),0 -1px rgba(255,255,255,0.08); +} +.tree-folder-items > .item { + padding: 0 10px; + line-height: 2.5rem; + font-size: 0.8rem; +} +.tree-folder-items > .item.active { + background: linear-gradient(180deg, #222 0%, #171717 100%) #171717; + background: -webkit-linear-gradient(top, #222 0%, #171717 100%); + border-radius: 4px; + margin: 0px 8px; + box-shadow: 0px 1px #171717, 0px 1px rgba(255, 255, 255, 0.08) inset, 0 2px 2px #111; +} +.tree-folder-items > .item > a { + text-decoration: none; + color: #fff; + font-size: 0.92em; +} +.tree-folder-items > .item.active > a { + color: #0090FF +} + +/*=== STRUCTURE */ +/*===============*/ +/*=== Header */ +.header { + height: 55px; + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); + border-bottom: solid 1px #BDB7AE; + box-shadow: 0 -1px rgba(255,255,255,0.28) inset; +} +.header > .item { + padding: 0; + vertical-align: middle; + text-align: center; +} +.header > .item.title .logo { + height: 60px; + width: 60px; +} +.header > .item.title{ + width: 250px; +} +.header > .item.title h1 { + margin: 0.5em 0; +} +.header > .item.title h1 a { + text-decoration: none; + font-size: 28px; + color:#222; + text-shadow: 0 1px #fff; +} +.header > .item.search input { + width: 230px; +} +.header .item.search input:focus { + width: 350px; +} + +/*=== Body */ +#global { + background:#F9F7F4; + height: calc(100% - 60px); +} +.aside { + box-shadow: 0 2px 2px #171717 inset; + background: #222; + width: 235px; +} +.aside.aside_feed { + padding: 10px 0; + text-align: center; +} +.aside.aside_feed .tree { + position: sticky; + top: 0; + margin: 10px 0 50px; +} + +/*=== Aside main page (categories) */ +.aside_feed .tree-folder-title > .title:not([data-unread="0"]):after { + position: absolute; + right: 3px; + padding: 1px 5px; + color: #fff; + text-shadow: 0 1px rgba(255,255,255,0.08); +} +.aside_feed .btn-important { + border: none; +} + +/*=== Aside main page (feeds) */ +.feed.item.empty, +.feed.item.empty > a { + color: #e67e22; +} +.feed.item.error, +.feed.item.error > a { + color: #BD362F; +} +.aside_feed .tree-folder-items .dropdown-menu:after { + left: 2px; +} +.aside_feed .tree-folder-items .item .dropdown-target:target ~ .dropdown-toggle > .icon, +.aside_feed .tree-folder-items .item:hover .dropdown-toggle > .icon, +.aside_feed .tree-folder-items .item.active .dropdown-toggle > .icon { + border-radius: 3px; +} + +/*=== Configuration pages */ +.post { + padding: 10px 50px; + font-size: 0.9em; +} +.post form { + margin: 10px 0; +} +.post.content { + max-width: 550px; +} + +/*=== Prompt (centered) */ +.prompt { + text-align: center; + padding: 14px 0px; + text-shadow: 0 1px rgba(255,255,255,0.08); +} +.prompt label { + text-align: left; +} +.prompt form { + margin: 10px auto 20px auto; + width: 180px; +} +.prompt input { + margin: 5px auto; + width: 100%; +} +.prompt p { + margin: 20px 0; +} +.prompt input#username,.prompt input#passwordPlain{ + border:solid 1px #ccc; + box-shadow: 0 4px -4px #ccc inset,0px 1px rgba(255, 255, 255, 0.08); + background:#fff; +} +.prompt input#username:focus,.prompt input#passwordPlain:focus{ + border: solid 1px #0062BE; + box-shadow: 0 0 3px #0062BE; +} + +/*=== New article notification */ +#new-article { + background: #0084CC; + text-align: center; + font-size: 0.9em; +} +#new-article:hover { + background: #0066CC; +} +#new-article > a { + line-height: 3em; + color: #fff; + font-weight: bold; +} +#new-article > a:hover { + text-decoration: none; +} + +/*=== Day indication */ +.day { + padding: 0 10px; + font-style:italic; + line-height: 3em; + box-shadow: 0 -1px #ccc, 0 -1px rgba(255,255,255,0.28) inset; + background: #F9F7F4; + color: #666; + text-shadow: 0 1px rgba(255,255,255,0.28); + text-align: center; +} +#new-article + .day { + border-top: none; +} +.day .name { + display: none; +} + +/*=== Index menu */ +.nav_menu { + background: linear-gradient(0deg, #EDE7DE 0%, #C2BCB3 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #C2BCB3 100%); + border-bottom: 1px solid #ccc; + box-shadow:0 -1px rgba(255, 255, 255, 0.28) inset; + text-align: center; + padding: 5px 0; +} +#panel >.nav_menu{ + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); +} +#panel > .nav_menu > #nav_menu_read_all{ + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); + border-radius: 4px; + border: 1px solid #CCC; + box-shadow: 0px 1px #FFF; +} +#panel > .nav_menu > #nav_menu_read_all > .dropdown > .btn.dropdown-toggle{ + border-radius: 0 4px 4px 0; + border:none; + border-left: solid 1px #ccc; +} + +/*=== Feed articles */ +.flux_content { + background: #FFF; +} +.flux { + background: #F9F7F4; +} +.flux:hover { + background: #F9F7F4; +} +.flux:not(.current):hover .item.title { + background: #F9F7F4; +} +.flux.current .flux .item.title a { + text-shadow:0 0 2px #ccc; +} +.flux.not_read:not(.current):hover .item.title { + opacity:0.85; +} +.flux.favorite { + background: #FFF6DA; +} +.flux.favorite:not(.current):hover{ + background: #F9F7F4; +} +.flux.favorite:not(.current):hover .item.title { + background: #F9F7F4; +} +.flux.current { + background: linear-gradient(0deg, #DAD4CB 0%, #FFF 100%) #DAD4CB; + background: -webkit-linear-gradient(bottom, #DAD4CB 0%, #FFF 100%); + box-shadow: 0 -1px #fff inset, 0 2px #ccc; + border-left: solid 4px #0062BF; +} + +.flux .item.title { +opacity: 0.35; +} +.flux.favorite .item.title { +opacity: 1; +} +.flux.not_read .item.title { +opacity: 1; +} +.flux.current .item.title a { + color: #0f0f0f; +} +.flux .item.title a { + color: #333; +} + +.flux_header { + border-top: 1px solid #ddd; + font-size: 0.8rem; + cursor: pointer; + box-shadow: 0 -1px rgba(255,255,255,0.28) inset; +} +.flux_header .title { + font-size: 0.9rem; +} +.flux .website .favicon { + padding: 5px; +} +.flux .date { + color: #666; + font-size: 0.7rem; +} + +.flux .bottom { + font-size: 0.8rem; + text-align: center; +} + +/*=== Content of feed articles */ +.content { + padding: 20px 10px; +} +.content > h1.title > a { + color: #000; +} + +.content hr { + margin: 30px 10px; + height: 1px; + background: #ddd; + border: 0; + box-shadow: 0 2px 5px #ccc; +} + +.content pre { + margin: 10px auto; + padding: 10px 20px; + overflow: auto; + background: #222; + color: #fff; + font-size: 0.9rem; + border-radius: 3px; +} +.content code { + padding: 2px 5px; + color: #dd1144; + background: #fafafa; + border: 1px solid #eee; + border-radius: 3px; +} +.content pre code { + background: transparent; + color: #fff; + border: none; +} + +.content blockquote { + display: block; + margin: 0; + padding: 5px 20px; + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + background: #fafafa; + color: #333; +} +.content blockquote p { + margin: 0; +} + +/*=== Notification and actualize notification */ +.notification { + padding: 0 0 0 5px; + text-align: center; + background:#222; + border: none; + border-radius: 0 0 6px 6px; + box-shadow: 0px 0px 4px rgba(0,0,0,0.45), 0 -1px rgba(255,255,255,0.08) inset, 0 2px 2px #171717 inset; + color:#fff; + font-weight: bold; + font-size: 0.9em; + line-height: 3em; + position:absolute; + top:0; + z-index: 10; + vertical-align: middle; +} +.notification.good { + color: #fff; +} +.notification.bad { + background: #222222; + color: #EB2901; +} +.notification a.close { + padding: 0 15px; + line-height: 3em; +} +.notification#actualizeProgress { + line-height: 2em; +} + +/*=== "Load more" part */ +#bigMarkAsRead { + text-align: center; + text-decoration: none; + text-shadow: 0 -1px 0 #aaa; + color: #666; + background: #F9F7F4; + box-shadow: 0 1px rgba(255,255,255,0.28)inset; +} +#bigMarkAsRead:hover { + color: #000; + background: #F9F7F4; + background: radial-gradient(circle at 50% -25% , #ccc 0%, #F9F7F4 50%); +} +#bigMarkAsRead:hover .bigTick { + text-shadow: 0 0 10px #666; +} + +/*=== Navigation menu (for articles) */ +#nav_entries { + background: linear-gradient(180deg, #222 0%, #171717 100%) #222; + background: -webkit-linear-gradient(top, #222 0%, #171717 100%); + border-top: 1px solid #171717; + text-align: center; + line-height: 3em; + table-layout: fixed; + box-shadow: 0 1px rgba(255,255,255,0.08) inset, 0 -2px 2px #171717; + width:235px; +} + +/*=== READER VIEW */ +/*================*/ +#stream.reader .flux { + padding: 0 0 50px; + border: none; + background: #f0f0f0; + color: #333; +} +#stream.reader .flux .author { + margin: 0 0 10px; + font-size: 90%; + color: #666; +} + +/*=== GLOBAL VIEW */ +/*================*/ +#stream.global { + padding: 24px 0; +} + +.box.category .box-title { + background: linear-gradient(0deg, #EDE7DE 0%, #fff 100%) #171717; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #fff 100%); + box-shadow: 0px -1px #fff inset,0 -2px #ccc inset; + border-radius: none; + line-height: 2em; + font-size: 1.2rem; + text-shadow:0 1px #ccc; +} +.box.category .box-title .title { + font-weight: normal; + text-decoration: none; + text-align: left; + color: #888; +} +.box.category:not([data-unread="0"]) .box-title { +} +.box.category:not([data-unread="0"]) .box-title:active { +} +.box.category:not([data-unread="0"]) .box-title .title { + color: #222; + font-weight: bold; +} +.box.category .title:not([data-unread="0"]):after { + position: absolute; + top: 5px; right: 10px; + border: 0; + background: none; + font-weight: bold; +} +.box.category .item.feed { + padding: 2px 10px; + font-size: 0.8rem; +} +.box.category .item.feed:not(.empty):not(.error) .item-title { + color: #222; +} + +/*=== PANEL */ +/*===========*/ +#panel { + box-shadow: 0px 0px 4px #000; + border-radius: 8px; + background:#F9F7F4; +} +/*=== DIVERS */ +/*===========*/ +.aside.aside_feed .nav-form input,.aside.aside_feed .nav-form select { + width: 130px; +} +.aside.aside_feed .nav-form .dropdown .dropdown-menu { + right: -20px; +} +.aside.aside_feed .nav-form .dropdown .dropdown-menu:after { + right: 33px; +} + +/*=== STATISTICS */ +/*===============*/ +.stat { + margin: 10px 0 20px; +} + +.stat th, +.stat td, +.stat tr { + border: none; +} +.stat > table td, +.stat > table th { + border-bottom: 1px solid #ccc; + background: rgba(255,255,255,0.38); + box-shadow: 0 1px #fff; +} + +.stat > .horizontal-list { + margin: 0 0 5px; +} +.stat > .horizontal-list .item { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.stat > .horizontal-list .item:first-child { + width: 250px; +} + +/*=== LOGS */ +/*=========*/ +.logs { + border: 1px solid #aaa; + border-radius: 5px; + overflow: hidden; +} +.log { + padding: 5px 10px; + background: #fafafa; + color: #333; + font-size: 0.8rem; +} +.log+.log { + border-top: 1px solid #aaa; +} +.log .date { + display: block; + font-weight: bold; +} +.log.error { + background: #fdd; + color: #844; +} +.log.warning { + background: #ffe; + color: #c95; +} +.log.notice { + background: #f4f4f4; + color: #aaa; +} +.log.debug { + background: #333; + color: #eee; +} + +#slider.active { + box-shadow: -4px 0 4px rgba(15, 15, 15, 0.55); + background: #F8F8F8; +} +#close-slider.active { + background: rgba(15, 15, 15, 0.35); +} + +/*=== MOBILE */ +/*===========*/ +@media screen and (max-width: 840px) { + .header { + display: table; + } + .nav-login { + display: none; + } + + .aside { + width: 0; + border-top: none; + box-shadow: 3px 0 3px #000; + transition: width 200ms linear; + -moz-transition: width 200ms linear; + -webkit-transition: width 200ms linear; + -o-transition: width 200ms linear; + -ms-transition: width 200ms linear; + } + .aside:target { + width: 235px; + } + .aside .toggle_aside, + #panel .close { + display: block; + width: 100%; + height: 40px; + line-height: 40px; + text-align: center; + background: #171717; + box-shadow: 0 1px rgba(255,255,255,0.08); + } + .aside .btn-important { + display: inline-block; + margin: 20px 0 0; + } + + .aside.aside_feed { + padding: 0; + } + .aside.aside_feed .tree { + position: static; + } + + .nav_menu .btn { + margin: 5px 10px; + } + .nav_menu .stick { + margin: 0 10px; + } + .nav_menu .stick .btn { + margin: 5px 0; + } + .nav_menu .search { + display: inline-block; + max-width: 97%; + } + .nav_menu .search input { + max-width: 97%; + width: 90px; + } + .nav_menu .search input:focus { + width: 400px; + } + + .day .name { + display: none; + } + + .pagination { + margin: 0 0 3.5em; + } + + .notification a.close { + display: block; + left: 0; + background: transparent; + } + .notification a.close:hover { + opacity: 0.5; + } + .notification a.close .icon { + display: none; + } + .nav_menu .search { + display: none; + } + + #nav_entries { + width: 100%; + } +} + +@media (max-width: 700px) { + .header{ + display: none; + } + .nav-login { + display: inline-block; + width: 100%; + } + .nav_menu .search { + display: inline-block; + } + .aside .btn-important { + display: none; + } +} diff --git a/p/themes/BlueLagoon/README.md b/p/themes/BlueLagoon/README.md new file mode 100644 index 000000000..62afc234b --- /dev/null +++ b/p/themes/BlueLagoon/README.md @@ -0,0 +1,38 @@ +Blue Lagoon +======= + +**C'est un cocktail (bis)! C'est la version plus "fresh" de [Screwdriver](https://github.com/misterair/Screwdriver). C'est... c'est... un thème pour l'agrégateur de flux RSS [FreshRSS](https://github.com/marienfressinaud/FreshRSS/)** + + +En toute modestie, ce thème tue du Nyan Cat. + +![screenshot](https://raw.githubusercontent.com/misterair/BlueLagoon/master/screenshot.png) + + +Installation +----------------- +1. Placez le dossier du thème dans ledossier /FreshRSS/p/themes/Screwdriver de votre FreshRSS; +2. Allez dans les paramètres d'Affichage et changez de thème; +3. Profitez de votre Blue Laggon sans modération! +4. Remontez les problèmes sur Github (*facultatif mais fortement apprécié*) + + + +Blue Lagoon est distribué sous license AlcoholWare: +----------------- + +« LICENCE ALCOHOLWARE » (Révision 42): + +mister.air@gmail.com a créé ce fichier. Tant que vous conservez cet avertissement, + +vous pouvez faire ce que vous voulez de ce truc. Si on se rencontre un jour et + +que vous pensez que ce truc vaut le coup, vous pouvez me payer un verre (rempli) en retour. + +*Mister aiR* + + + + + + diff --git a/p/themes/BlueLagoon/icons/bookmark.svg b/p/themes/BlueLagoon/icons/bookmark.svg new file mode 100644 index 000000000..b77dc5518 --- /dev/null +++ b/p/themes/BlueLagoon/icons/bookmark.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/favicon-16-32-48-64.ico b/p/themes/BlueLagoon/icons/favicon-16-32-48-64.ico new file mode 100644 index 000000000..7c5eb5517 Binary files /dev/null and b/p/themes/BlueLagoon/icons/favicon-16-32-48-64.ico differ diff --git a/p/themes/BlueLagoon/icons/favicon-256.png b/p/themes/BlueLagoon/icons/favicon-256.png new file mode 100644 index 000000000..dbe4ec4b7 Binary files /dev/null and b/p/themes/BlueLagoon/icons/favicon-256.png differ diff --git a/p/themes/BlueLagoon/icons/favicon.svg b/p/themes/BlueLagoon/icons/favicon.svg new file mode 100644 index 000000000..ac816d68c --- /dev/null +++ b/p/themes/BlueLagoon/icons/favicon.svg @@ -0,0 +1,273 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/icon.svg b/p/themes/BlueLagoon/icons/icon.svg new file mode 100644 index 000000000..083eeb685 --- /dev/null +++ b/p/themes/BlueLagoon/icons/icon.svg @@ -0,0 +1,291 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/non-starred.svg b/p/themes/BlueLagoon/icons/non-starred.svg new file mode 100644 index 000000000..2762b060a --- /dev/null +++ b/p/themes/BlueLagoon/icons/non-starred.svg @@ -0,0 +1,59 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/read.svg b/p/themes/BlueLagoon/icons/read.svg new file mode 100644 index 000000000..28980576b --- /dev/null +++ b/p/themes/BlueLagoon/icons/read.svg @@ -0,0 +1,72 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/starred.svg b/p/themes/BlueLagoon/icons/starred.svg new file mode 100644 index 000000000..4c749ce26 --- /dev/null +++ b/p/themes/BlueLagoon/icons/starred.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/unread.svg b/p/themes/BlueLagoon/icons/unread.svg new file mode 100644 index 000000000..596dec0ac --- /dev/null +++ b/p/themes/BlueLagoon/icons/unread.svg @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/p/themes/BlueLagoon/loader.gif b/p/themes/BlueLagoon/loader.gif new file mode 100644 index 000000000..a0839dcc7 Binary files /dev/null and b/p/themes/BlueLagoon/loader.gif differ diff --git a/p/themes/BlueLagoon/metadata.json b/p/themes/BlueLagoon/metadata.json new file mode 100644 index 000000000..2c415a613 --- /dev/null +++ b/p/themes/BlueLagoon/metadata.json @@ -0,0 +1,7 @@ +{ + "name": "Blue Lagoon", + "author": "Mister aiR", + "description": "C'est un cocktail (bis)! C'est la version plus fresh de Screwdriver. C'est... c'est... un thème pour l'agrégateur de flux RSS FreshRSS. En toute modestie, ce thème tue du Nyan Cat.", + "version": 1.0, + "files": ["_template.css","BlueLagoon.css"] +} diff --git a/p/themes/BlueLagoon/template.css b/p/themes/BlueLagoon/template.css new file mode 100644 index 000000000..bf421e322 --- /dev/null +++ b/p/themes/BlueLagoon/template.css @@ -0,0 +1,695 @@ +@charset "UTF-8"; + +/*=== GENERAL */ +/*============*/ +html, body { + margin: 0; + padding: 0; + font-size: 92%; +} + +/*=== Links */ +a { + text-decoration: none; +} +a:hover { + text-decoration: underline; +} + +/*=== Lists */ +ul, ol, dd { + margin: 0; + padding: 0; +} + +/*=== Titles */ +h1 { + margin: 0.6em 0 0.3em; + font-size: 1.5em; + line-height: 1.6em; +} +h2 { + margin: 0.5em 0 0.25em; + font-size: 1.3em; + line-height: 2em; +} +h3 { + margin: 0.5em 0 0.25em; + font-size: 1.1em; + line-height: 2em; +} + +/*=== Paragraphs */ +p { + margin: 1em 0 0.5em; + font-size: 1em; +} + +/*=== Images */ +img { + height: auto; + max-width: 100%; +} +img.favicon { + height: 16px; + width: 16px; + vertical-align: middle; +} + +/*=== Videos */ +iframe, embed, object, video { + max-width: 100%; +} + +/*=== Forms */ +legend { + display: block; + width: 100%; + clear: both; +} +label { + display: block; +} +input { + width: 180px; +} +textarea { + width: 300px; +} +input, select, textarea { + display: inline-block; + max-width: 100%; +} +input[type="radio"], +input[type="checkbox"] { + width: 15px !important; + min-height: 15px !important; +} +input.extend:focus { + width: 300px; +} + +/*=== COMPONENTS */ +/*===============*/ +/*=== Forms */ +.form-group:after { + content: ""; + display: block; + clear: both; +} +.form-group.form-actions { + min-width: 250px; +} +.form-group .group-name { + display: block; + float: left; + width: 200px; +} +.form-group .group-controls { + min-width: 250px; + margin: 0 0 0 220px; +} +.form-group .group-controls .control { + display: block; +} + +/*=== Buttons */ +.stick { + display: inline-block; + white-space: nowrap; +} +.btn, +a.btn { + display: inline-block; + cursor: pointer; + overflow: hidden; +} +.btn-important { + font-weight: bold; +} + +/*=== Navigation */ +.nav-list .nav-header, +.nav-list .item { + display: block; +} +.nav-list .item, +.nav-list .item > a { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.nav-head { + display: block; +} +.nav-head .item { + display: inline-block; +} + +/*=== Horizontal-list */ +.horizontal-list { + display: table; + table-layout: fixed; + width: 100%; +} +.horizontal-list .item { + display: table-cell; +} + +/*=== Dropdown */ +.dropdown { + position: relative; + display: inline-block; +} +.dropdown-target { + display: none; +} +.dropdown-menu { + display: none; + min-width: 200px; + margin: 0; + position: absolute; + right: 0; + background: #fff; + border: 1px solid #aaa; +} +.dropdown-header { + display: block; +} +.dropdown-menu > .item { + display: block; +} +.dropdown-menu > .item > a, +.dropdown-menu > .item > span { + display: block; +} +.dropdown-menu > .item[aria-checked="true"] > a:before { + content: '✓'; +} +.dropdown-menu .input { + display: block; +} +.dropdown-menu .input select, +.dropdown-menu .input input { + display: block; + max-width: 95%; +} +.dropdown-target:target ~ .dropdown-menu { + display: block; + z-index: 10; +} +.dropdown-close { + display: inline; +} +.dropdown-close a { + font-size: 0; + position: fixed; + top: 0; bottom: 0; + left: 0; right: 0; + display: block; + z-index: -10; +} +.separator { + display: block; + height: 0; + border-bottom: 1px solid #aaa; +} + +/*=== Alerts */ +.alert { + display: block; + width: 90%; +} +.group-controls .alert { + width: 100% +} +.alert-head { + margin: 0; + font-weight: bold; +} +.alert ul { + margin: 5px 20px; +} + +/*=== Icons */ +.icon { + display: inline-block; + width: 16px; + height: 16px; + vertical-align: middle; + line-height: 16px; +} + +/*=== Pagination */ +.pagination { + display: table; + width: 100%; + margin: 0; + padding: 0; + table-layout: fixed; +} +.pagination .item { + display: table-cell; +} +.pagination .pager-first, +.pagination .pager-previous, +.pagination .pager-next, +.pagination .pager-last { + width: 100px; +} + +/*=== STRUCTURE */ +/*===============*/ +/*=== Header */ +.header { + display: table; + width: 100%; + table-layout: fixed; +} +.header > .item { + display: table-cell; +} +.header > .item.title { + width: 250px; + white-space: nowrap; +} +.header > .item.title h1 { + display: inline-block; +} +.header > .item.title .logo { + display: inline-block; + height: 32px; + width: 32px; + vertical-align: middle; +} +.header > .item.configure { + width: 100px; +} + +/*=== Body */ +#global { + display: table; + width: 100%; + height: 100%; + table-layout: fixed; +} +.aside { + display: table-cell; + height: 100%; + width: 250px; + vertical-align: top; +} +.aside.aside_flux { + background: #fff; +} + +/*=== Aside main page (categories) */ +.categories { + list-style: none; + margin: 0; +} +.category { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.category .btn:not([data-unread="0"]):after { + content: attr(data-unread); +} + +/*=== Aside main page (feeds) */ +.categories .feeds { + width: 100%; + list-style: none; +} +.categories .feeds:not(.active) { + display: none; +} +.categories .feeds .feed { + display: inline-block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + vertical-align: middle; +} +.categories .feeds .feed:not([data-unread="0"]):before { + content: "(" attr(data-unread) ") "; +} +.categories .feeds .dropdown-menu { + left: 0; +} +.categories .feeds .item .dropdown-toggle > .icon { + visibility: hidden; + cursor: pointer; + vertical-align: top; +} +.categories .feeds .item .dropdown-target:target ~ .dropdown-toggle > .icon, +.categories .feeds .item:hover .dropdown-toggle > .icon, +.categories .feeds .item.active .dropdown-toggle > .icon { + visibility: visible; +} + +/*=== New article notification */ +#new-article { + display: none; +} +#new-article > a { + display: block; +} + +/*=== Day indication */ +.day .name { + position: absolute; + right: 0; + width: 50%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +/*=== Feed article header and footer */ +.flux_header { + position: relative; +} +.flux .item { + line-height: 40px; + white-space: nowrap; +} +.flux .item.manage, +.flux .item.link { + width: 40px; + text-align: center; +} +.flux .item.website { + width: 200px; +} +.flux.not_read .item.title, +.flux.current .item.title { + font-weight: bold; +} +.flux:not(.current):hover .item.title { + position: absolute; + max-width: calc(100% - 320px); + background: #fff; +} +.flux .item.title a { + color: #000; + text-decoration: none; +} +.flux .item.date { + width: 145px; + text-align: right; +} +.flux .item > a { + display: block; +} +.flux .item > a { + display: block; + text-decoration: none; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} +.flux .item.share > a { + display: list-item; + list-style-position: inside; + list-style-type: decimal; +} + +/*=== Feed article content */ +.hide_posts > .flux:not(.active) > .flux_content { + display: none; +} +.content { + min-height: 20em; + margin: auto; + line-height: 1.7em; + word-wrap: break-word; +} +.content.large { + max-width: 1000px; +} +.content.medium { + max-width: 800px; +} +.content.thin { + max-width: 550px; +} +.content ul, +.content ol, +.content dd { + margin: 0 0 0 15px; + padding: 0 0 5px 15px; +} +.content pre { + overflow: auto; +} + +/*=== Notification and actualize notification */ +.notification { + position: absolute; + top: 1em; + left: 25%; right: 25%; + z-index: 10; + background: #fff; + border: 1px solid #aaa; +} +.notification.closed { + display: none; +} +.notification a.close { + position: absolute; + top: 0; bottom: 0; + right: 0; + display: inline-block; +} + +#actualizeProgress { + position: fixed; +} +#actualizeProgress progress { + max-width: 100%; + vertical-align: middle; +} +#actualizeProgress .progress { + vertical-align: middle; +} + +/*=== Navigation menu (for articles) */ +#nav_entries { + position: fixed; + bottom: 0; left: 0; + display: table; + width: 250px; + background: #fff; + table-layout: fixed; +} +#nav_entries .item { + display: table-cell; + width: 30%; +} +#nav_entries a { + display: block; +} + +/*=== "Load more" part */ +#load_more { + min-height: 40px; +} +.loading { + background: url("loader.gif") center center no-repeat; + font-size: 0; +} +#bigMarkAsRead { + display: block; + padding: 3em 0; + text-align: center; +} +.bigTick { + font-size: 7em; + line-height: 1.6em; +} + +/*=== Statistiques */ +.stat > table { + width: 100%; +} + +/*=== GLOBAL VIEW */ +/*================*/ +/*=== Category boxes */ +#stream.global .box-category { + display: inline-block; + width: 19em; + max-width: 95%; + margin: 20px 10px; + border: 1px solid #ccc; + vertical-align: top; +} +#stream.global .category { + width: 100%; +} +#stream.global .btn { + display: block; +} +#stream.global .box-category .feeds { + display: block; + overflow: auto; +} +#stream.global .box-category .feed { + width: 19em; + max-width: 90%; +} + +/*=== Panel */ +#overlay { + display: none; + position: fixed; + top: 0; bottom: 0; + left: 0; right: 0; + background: rgba(0, 0, 0, 0.9); +} +#panel { + display: none; + position: fixed; + top: 1em; bottom: 1em; + left: 2em; right: 2em; + overflow: auto; + background: #fff; +} +#panel .close { + position: fixed; + top: 0; bottom: 0; + left: 0; right: 0; + display: block; +} +#panel .close img { + display: none; +} + +/*=== DIVERS */ +/*===========*/ +.nav-login, +.nav_menu .search, +.nav_menu .toggle_aside { + display: none; +} + +.aside .toggle_aside { + position: absolute; + right: 0; + display: none; + width: 30px; + height: 30px; + line-height: 30px; + text-align: center; +} + +/*=== MOBILE */ +/*===========*/ +@media(max-width: 840px) { + .header, + .aside .btn-important, + .aside .feeds .dropdown, + .flux_header .item.website span, + .item.date, .day .date, + .dropdown-menu > .no-mobile, + .no-mobile { + display: none; + } + .nav-login { + display: block; + } + .nav_menu .toggle_aside, + .aside .toggle_aside, + .nav_menu .search, + #panel .close img { + display: inline-block; + } + + .aside { + position: fixed; + top: 0; bottom: 0; + left: 0; + width: 0; + overflow: hidden; + z-index: 100; + } + .aside:target { + width: 90%; + overflow: auto; + } + .aside .categories { + margin: 10px 0 75px; + } + + .flux_header .item.website { + width: 40px; + } + + .flux:not(.current):hover .item.title { + position: relative; + width: auto; + white-space: nowrap; + } + + .notification { + top: 0; + left: 0; + right: 0; + } + + #nav_entries { + width: 100%; + } + + #stream.global .box-category { + margin: 10px 0; + } + + #panel { + top: 0; bottom: 0; + left: 0; right: 0; + } + #panel .close { + top: 0; right: 0; + left: auto; bottom: auto; + display: inline-block; + width: 30px; + height: 30px; + } +} + +/*=== PRINTER */ +/*============*/ +@media print { + .header, .aside, + .nav_menu, .day, + .flux_header, + .flux_content .bottom, + .pagination, + #nav_entries { + display: none; + } + html, body { + background: #fff; + color: #000; + font-family: Serif; + } + #global, + .flux_content { + display: block !important; + } + .flux_content .content { + width: 100% !important; + } + .flux_content .content a { + color: #000; + } + .flux_content .content a:after { + content: " [" attr(href) "] "; + font-style: italic; + } +} diff --git a/p/themes/BlueLagoon/thumbs/original.png b/p/themes/BlueLagoon/thumbs/original.png new file mode 100644 index 000000000..bb8695945 Binary files /dev/null and b/p/themes/BlueLagoon/thumbs/original.png differ -- cgit v1.2.3 From 498f8315f724a5e85b28907c3bc4dc08699d679e Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Wed, 26 Nov 2014 17:54:41 -0500 Subject: Optimize bluelagoon theme icons. In the future, we should pay attention to those icons since I've done that a couple of time now. We should have some documentation for new contributions. --- p/themes/BlueLagoon/icons/bookmark.svg | 64 +----- p/themes/BlueLagoon/icons/favicon.svg | 303 +++------------------------- p/themes/BlueLagoon/icons/icon.svg | 321 +++--------------------------- p/themes/BlueLagoon/icons/non-starred.svg | 62 +----- p/themes/BlueLagoon/icons/read.svg | 74 +------ p/themes/BlueLagoon/icons/starred.svg | 63 +----- p/themes/BlueLagoon/icons/unread.svg | 66 +----- 7 files changed, 80 insertions(+), 873 deletions(-) (limited to 'p') diff --git a/p/themes/BlueLagoon/icons/bookmark.svg b/p/themes/BlueLagoon/icons/bookmark.svg index b77dc5518..7f33d9753 100644 --- a/p/themes/BlueLagoon/icons/bookmark.svg +++ b/p/themes/BlueLagoon/icons/bookmark.svg @@ -1,61 +1,5 @@ - - - - - - image/svg+xml - - - - - - - - - + + + + diff --git a/p/themes/BlueLagoon/icons/favicon.svg b/p/themes/BlueLagoon/icons/favicon.svg index ac816d68c..1b6801a26 100644 --- a/p/themes/BlueLagoon/icons/favicon.svg +++ b/p/themes/BlueLagoon/icons/favicon.svg @@ -1,273 +1,32 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/icon.svg b/p/themes/BlueLagoon/icons/icon.svg index 083eeb685..8abfea179 100644 --- a/p/themes/BlueLagoon/icons/icon.svg +++ b/p/themes/BlueLagoon/icons/icon.svg @@ -1,291 +1,34 @@ - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/non-starred.svg b/p/themes/BlueLagoon/icons/non-starred.svg index 2762b060a..d5c1f5ee0 100644 --- a/p/themes/BlueLagoon/icons/non-starred.svg +++ b/p/themes/BlueLagoon/icons/non-starred.svg @@ -1,59 +1,5 @@ - - - - - - image/svg+xml - - - - - - - - - + + + + diff --git a/p/themes/BlueLagoon/icons/read.svg b/p/themes/BlueLagoon/icons/read.svg index 28980576b..269b75738 100644 --- a/p/themes/BlueLagoon/icons/read.svg +++ b/p/themes/BlueLagoon/icons/read.svg @@ -1,72 +1,4 @@ - - - - - - image/svg+xml - - - - - - - - - - - + + + diff --git a/p/themes/BlueLagoon/icons/starred.svg b/p/themes/BlueLagoon/icons/starred.svg index 4c749ce26..10a16f04a 100644 --- a/p/themes/BlueLagoon/icons/starred.svg +++ b/p/themes/BlueLagoon/icons/starred.svg @@ -1,60 +1,5 @@ - - - - - - image/svg+xml - - - - - - - - - + + + + diff --git a/p/themes/BlueLagoon/icons/unread.svg b/p/themes/BlueLagoon/icons/unread.svg index 596dec0ac..bd39d683a 100644 --- a/p/themes/BlueLagoon/icons/unread.svg +++ b/p/themes/BlueLagoon/icons/unread.svg @@ -1,65 +1,3 @@ - - - - - - image/svg+xml - - - - - - - - - - + + -- cgit v1.2.3 From 82745a509a1284a9fe6a7f8d5d153eda953d9e11 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Wed, 26 Nov 2014 18:14:17 -0500 Subject: Optimize screwdriver theme icons. --- p/themes/Screwdriver/icons/favicon.svg | 312 ++++----------------------------- p/themes/Screwdriver/icons/icon.svg | 303 ++++---------------------------- 2 files changed, 66 insertions(+), 549 deletions(-) (limited to 'p') diff --git a/p/themes/Screwdriver/icons/favicon.svg b/p/themes/Screwdriver/icons/favicon.svg index aaab5de99..895a727bb 100644 --- a/p/themes/Screwdriver/icons/favicon.svg +++ b/p/themes/Screwdriver/icons/favicon.svg @@ -1,280 +1,34 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/Screwdriver/icons/icon.svg b/p/themes/Screwdriver/icons/icon.svg index 7f3d76af2..268814463 100644 --- a/p/themes/Screwdriver/icons/icon.svg +++ b/p/themes/Screwdriver/icons/icon.svg @@ -1,271 +1,34 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From adaec6176ca04ee38306bd348eba9a8350f19405 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Tue, 2 Dec 2014 23:34:31 -0500 Subject: Add article auto-remove after clicking on the read link --- p/scripts/main.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'p') diff --git a/p/scripts/main.js b/p/scripts/main.js index d1d31c801..19eba206d 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -690,6 +690,9 @@ function init_stream(divStream) { divStream.on('click', '.flux a.read', function () { var active = $(this).parents(".flux"); mark_read(active, false); + if (context['auto_remove_article']) { + active.remove(); + } return false; }); -- cgit v1.2.3 From 93af0cf61e6e9368888eedb2d2e36397da3f87bd Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Wed, 3 Dec 2014 18:13:59 -0500 Subject: Fix behavior when marking an article as unread --- p/scripts/main.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'p') diff --git a/p/scripts/main.js b/p/scripts/main.js index 19eba206d..32cf55a3c 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -144,6 +144,7 @@ function mark_read(active, only_not_read) { inc = 0; if (active.hasClass("not_read")) { active.removeClass("not_read"); + hide_article(active); inc--; } else if (only_not_read !== true || active.hasClass("not_read")) { active.addClass("not_read"); @@ -231,14 +232,7 @@ function toggleContent(new_active, old_active) { } old_active.removeClass("active current"); new_active.addClass("current"); - if (context['auto_remove_article'] && !old_active.hasClass('not_read')) { - var p = old_active.prev(); - var n = old_active.next(); - if (p.hasClass('day') && n.hasClass('day')) { - p.remove(); - } - old_active.remove(); - } + hide_article(old_active); } else { new_active.toggleClass('active'); } @@ -283,6 +277,17 @@ function toggleContent(new_active, old_active) { } } +function hide_article(article) { + if (context['auto_remove_article'] && !article.hasClass('not_read')) { + var p = article.prev(); + var n = article.next(); + if (p.hasClass('day') && n.hasClass('day')) { + p.remove(); + } + article.remove(); + } +} + function prev_entry() { var old_active = $(".flux.current"), new_active = old_active.length === 0 ? $(".flux:last") : old_active.prevAll(".flux:first"); @@ -690,9 +695,6 @@ function init_stream(divStream) { divStream.on('click', '.flux a.read', function () { var active = $(this).parents(".flux"); mark_read(active, false); - if (context['auto_remove_article']) { - active.remove(); - } return false; }); -- cgit v1.2.3 From 5617911644bf85718430bb096c4ae9a0a0e8c75c Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Wed, 3 Dec 2014 18:35:42 -0500 Subject: Revert "Fix behavior when marking an article as unread" This reverts commit 93af0cf61e6e9368888eedb2d2e36397da3f87bd. --- p/scripts/main.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'p') diff --git a/p/scripts/main.js b/p/scripts/main.js index 32cf55a3c..19eba206d 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -144,7 +144,6 @@ function mark_read(active, only_not_read) { inc = 0; if (active.hasClass("not_read")) { active.removeClass("not_read"); - hide_article(active); inc--; } else if (only_not_read !== true || active.hasClass("not_read")) { active.addClass("not_read"); @@ -232,7 +231,14 @@ function toggleContent(new_active, old_active) { } old_active.removeClass("active current"); new_active.addClass("current"); - hide_article(old_active); + if (context['auto_remove_article'] && !old_active.hasClass('not_read')) { + var p = old_active.prev(); + var n = old_active.next(); + if (p.hasClass('day') && n.hasClass('day')) { + p.remove(); + } + old_active.remove(); + } } else { new_active.toggleClass('active'); } @@ -277,17 +283,6 @@ function toggleContent(new_active, old_active) { } } -function hide_article(article) { - if (context['auto_remove_article'] && !article.hasClass('not_read')) { - var p = article.prev(); - var n = article.next(); - if (p.hasClass('day') && n.hasClass('day')) { - p.remove(); - } - article.remove(); - } -} - function prev_entry() { var old_active = $(".flux.current"), new_active = old_active.length === 0 ? $(".flux:last") : old_active.prevAll(".flux:first"); @@ -695,6 +690,9 @@ function init_stream(divStream) { divStream.on('click', '.flux a.read', function () { var active = $(this).parents(".flux"); mark_read(active, false); + if (context['auto_remove_article']) { + active.remove(); + } return false; }); -- cgit v1.2.3 From 53410887c94157f3d11f2c30d92ff5d3d8a3a9bd Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Wed, 3 Dec 2014 18:57:53 -0500 Subject: Fix behavior to hide articles I do not like it since it is partly duplicated. We need to find something better. --- p/scripts/main.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'p') diff --git a/p/scripts/main.js b/p/scripts/main.js index 19eba206d..e48630d89 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -689,10 +689,15 @@ function init_stream(divStream) { divStream.on('click', '.flux a.read', function () { var active = $(this).parents(".flux"); - mark_read(active, false); - if (context['auto_remove_article']) { + if (context['auto_remove_article'] && active.hasClass('not_read')) { + var p = active.prev(); + var n = active.next(); + if (p.hasClass('day') && n.hasClass('day')) { + p.remove(); + } active.remove(); } + mark_read(active, false); return false; }); -- cgit v1.2.3 From f9b037742a0aeb49cab86782d1a59913c2de47bf Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 4 Dec 2014 20:41:01 +0100 Subject: Update ext.php to serve any file from extensions Add an extension->getFileUrl() method to facilitate url generation --- lib/Minz/Extension.php | 23 +++++++++++++++++++++++ p/ext.php | 37 +++++++++++++++++++------------------ 2 files changed, 42 insertions(+), 18 deletions(-) (limited to 'p') diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index f442344a3..72a375a6d 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -75,6 +75,9 @@ class Minz_Extension { public function getEntrypoint() { return $this->entrypoint; } + public function getPath() { + return $this->path; + } public function getAuthor() { return $this->author; } @@ -93,4 +96,24 @@ class Minz_Extension { } $this->type = $type; } + + /** + * Return the url for a given file. + * + * @param $filename name of the file to serve. + * @param $type the type (js or css) of the file to serve. + * @return the url corresponding to the file. + */ + public function getFileUrl($filename, $type) { + $dir = end(explode('/', $this->path)); + $file_name_url = urlencode($dir . '/' . $filename); + + $absolute_path = $this->path . '/' . $filename; + $mtime = @filemtime($absolute_path); + + $url = '/ext.php?f=' . $file_name_url . + '&t=' . $type . + '&' . $mtime; + return Minz_Url::display($url); + } } diff --git a/p/ext.php b/p/ext.php index a1dde2f93..39c224a84 100644 --- a/p/ext.php +++ b/p/ext.php @@ -1,32 +1,33 @@ Date: Fri, 5 Dec 2014 10:51:34 +0100 Subject: Fix security hole from ext.php script. Now, ext.php can only serve file under a EXTENSIONS_PATH/ext_dir/static/ directory. A 400 Bad Request error will be returned for other files. See https://github.com/FreshRSS/FreshRSS/issues/252 And https://github.com/FreshRSS/FreshRSS/commit/f9b037742a0aeb49cab86782d1a59913c2de47b --- lib/Minz/Extension.php | 4 ++-- p/ext.php | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) (limited to 'p') diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index 72a375a6d..ecf510ea2 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -106,9 +106,9 @@ class Minz_Extension { */ public function getFileUrl($filename, $type) { $dir = end(explode('/', $this->path)); - $file_name_url = urlencode($dir . '/' . $filename); + $file_name_url = urlencode($dir . '/static/' . $filename); - $absolute_path = $this->path . '/' . $filename; + $absolute_path = $this->path . '/static/' . $filename; $mtime = @filemtime($absolute_path); $url = '/ext.php?f=' . $file_name_url . diff --git a/p/ext.php b/p/ext.php index 39c224a84..5c9f9125f 100644 --- a/p/ext.php +++ b/p/ext.php @@ -7,10 +7,42 @@ if (!isset($_GET['f']) || require('../constants.php'); +/** + * Check if a file can be served by ext.php. A valid file is under a + * EXTENSIONS_PATH/extension_name/static/ directory. + * + * You should sanitize path by using the realpath() function. + * + * @param $path the path to the file we want to serve. + * @return true if it can be served, false else. + * + */ +function is_valid_path($path) { + // It must be under the extension path. + $in_ext_path = (substr($path, 0, strlen(EXTENSIONS_PATH)) === EXTENSIONS_PATH); + if (!$in_ext_path) { + return false; + } + + // File to serve must be under a `ext_dir/static/` directory. + $path_relative_to_ext = substr($path, strlen(EXTENSIONS_PATH) + 1); + $path_splitted = explode('/', $path_relative_to_ext); + if (count($path_splitted) < 3 || $path_splitted[1] !== 'static') { + return false; + } + + return true; +} + $file_name = urldecode($_GET['f']); $file_type = $_GET['t']; -$absolute_filename = EXTENSIONS_PATH . '/' . $file_name; +$absolute_filename = realpath(EXTENSIONS_PATH . '/' . $file_name); + +if (!is_valid_path($absolute_filename)) { + header('HTTP/1.1 400 Bad Request'); + die(); +} switch ($file_type) { case 'css': -- cgit v1.2.3 From c1c0011d04bdef525c85cfd67e34058080d5f5ce Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 12 Dec 2014 12:40:11 +0100 Subject: Quick fix for theme slider Bluelagoon description was overflowed by its screenshot --- p/themes/base-theme/template.css | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'p') diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 80f76e80b..535a80a22 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -741,10 +741,15 @@ br + br + br { padding: 0; } .properties { - bottom: -35px; + display: none; + bottom: 0; position: absolute; width: 100%; - display: none; + padding: 5px; + background: rgba(255, 255, 255, 0.7); + color: #000; + border-top: 1px solid #aaa; + z-index: 10; } .properties .page-number { right: 0; -- cgit v1.2.3 From bf87db31d90ef18871045f1c815443e162e06e46 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 12 Dec 2014 12:43:34 +0100 Subject: Second fix for theme slider --- p/themes/base-theme/template.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'p') diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 535a80a22..280b9b332 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -693,6 +693,7 @@ br + br + br { min-width: 260px; max-width: 640px; margin-bottom: 30px; + border: 1px solid #aaa; } .slides * { user-select: none; @@ -743,8 +744,8 @@ br + br + br { .properties { display: none; bottom: 0; + left: 0; right: 0; position: absolute; - width: 100%; padding: 5px; background: rgba(255, 255, 255, 0.7); color: #000; @@ -752,7 +753,7 @@ br + br + br { z-index: 10; } .properties .page-number { - right: 0; + right: 5px; top: 0; position: absolute; } -- cgit v1.2.3 From 6078888de631ea105410079888838503fd7acb3d Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 12 Dec 2014 14:27:50 +0100 Subject: Remove user-select: none in theme selector See https://github.com/FreshRSS/FreshRSS/issues/571 --- p/themes/base-theme/template.css | 8 -------- 1 file changed, 8 deletions(-) (limited to 'p') diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 280b9b332..25f206106 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -695,14 +695,6 @@ br + br + br { margin-bottom: 30px; border: 1px solid #aaa; } -.slides * { - user-select: none; - -ms-user-select: none; - -moz-user-select: none; - -khtml-user-select: none; - -webkit-user-select: none; - -webkit-touch-callout: none; -} .slides input { display: none; } -- cgit v1.2.3 From c804a30140ecad805f5e1e757ce27612ff7f7022 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 18 Dec 2014 18:42:21 +0100 Subject: jQuery update from 2.1.1 to 2.1.3 http://blog.jquery.com/2014/12/18/jquery-1-11-2-and-2-1-3-released-safari-fail-safe-edition/ --- p/scripts/jquery.min.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'p') diff --git a/p/scripts/jquery.min.js b/p/scripts/jquery.min.js index e5ace116b..25714ed29 100644 --- a/p/scripts/jquery.min.js +++ b/p/scripts/jquery.min.js @@ -1,4 +1,4 @@ -/*! jQuery v2.1.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.1",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
          ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+Math.random()}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b) -},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
          "],col:[2,"","
          "],tr:[2,"","
          "],td:[3,"","
          "],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("