From 4bbe82ff01145f22f20eef90a612dbd588ae1689 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 13 Oct 2013 17:11:13 +0200 Subject: Remplace main.phtml non-cachable par main.js cachable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amélioration des performances en permettant la mise en cache de 10Ko de JavaScript et en évitant une requête HTTP à chaque action de l'utilisateur. --- app/views/javascript/main.phtml | 428 ++-------------------------------------- 1 file changed, 16 insertions(+), 412 deletions(-) (limited to 'app/views/javascript') diff --git a/app/views/javascript/main.phtml b/app/views/javascript/main.phtml index 03c60cc52..82ed8ff18 100644 --- a/app/views/javascript/main.phtml +++ b/app/views/javascript/main.phtml @@ -1,415 +1,19 @@ -conf->displayPosts () == 'no') { ?> -var hide_posts = true; - -var hide_posts = false; - - conf->shortcuts (); $mark = $this->conf->markWhen (); - $auto_load_more = $this->conf->autoLoadMore () -?> - -function is_reader_mode() { - var stream = $("#stream.reader"); - return stream.html() != null; -} - -function is_normal_mode() { - var stream = $("#stream.normal"); - return stream.html() != null; -} - -function is_global_mode() { - var stream = $("#stream.global"); - return stream.html() != null; -} - -function redirect (url, new_tab) { - if (url) { - if (new_tab) { - window.open (url); - } else { - location.href = url; - } - } -} - -function toggleContent (new_active, old_active) { - old_active.removeClass ("active"); - if (old_active[0] != new_active[0]) { - new_active.addClass ("active"); - } - - var box_to_move = "html,body"; - var relative_move = false; - if(is_global_mode()) { - box_to_move = "#panel"; - relative_move = true; - } - - var new_pos = new_active.position ().top, - old_scroll = $(box_to_move).scrollTop (), - new_scroll = old_scroll; - if (hide_posts) { - old_active.children (".flux_content").toggle (0); - - new_pos = new_active.position ().top; - old_scroll = $(box_to_move).scrollTop (); - - if(relative_move) { - new_pos += old_scroll; - } - - if (old_active[0] != new_active[0]) { - new_active.children (".flux_content").toggle (0, function () { - new_scroll = $(box_to_move).scrollTop (new_pos).scrollTop (); - }); - } - } else { - if(relative_move) { - new_pos += old_scroll; - } - - new_scroll = $(box_to_move).scrollTop (new_pos).scrollTop (); - } - - if ((new_scroll === old_scroll) && $.fn.lazyload) { - $(window).trigger ("scroll"); //When no scroll was done, generate fake scroll event for LazyLoad to load images - } - - - mark_read(new_active, true); - -} - -function mark_read (active, only_not_read) { - if (active[0] === undefined || ( - only_not_read === true && !active.hasClass("not_read"))) { - return false; - } - - url = active.find ("a.read").attr ("href"); - if (url === undefined) { - return false; - } - - $.ajax ({ - type: 'POST', - url: url, - data : { ajax: true } - }).done (function (data) { - res = jQuery.parseJSON(data); - - active.find ("a.read").attr ("href", res.url); - - if (active.hasClass ("not_read")) { - active.removeClass ("not_read"); - } else if(only_not_read !== true || active.hasClass("not_read")) { - active.addClass ("not_read"); - } - }); -} - -function mark_favorite (active) { - if (active[0] === undefined) { - return false; - } - - url = active.find ("a.bookmark").attr ("href"); - if (url === undefined) { - return false; - } - - $.ajax ({ - type: 'POST', - url: url, - data : { ajax: true } - }).done (function (data) { - res = jQuery.parseJSON(data); - - active.find ("a.bookmark").attr ("href", res.url); - if (active.hasClass ("favorite")) { - active.removeClass ("favorite"); - } else { - active.addClass ("favorite"); - } - }); -} - -function prev_entry() { - old_active = $(".flux.active"); - last_active = $(".flux:last"); - new_active = old_active.prevAll (".flux:first"); - - if (new_active.hasClass("flux")) { - toggleContent (new_active, old_active); - } else if (old_active[0] === undefined && - new_active[0] === undefined) { - toggleContent (last_active, old_active); - } -} - -function next_entry() { - old_active = $(".flux.active"); - first_active = $(".flux:first"); - last_active = $(".flux:last"); - new_active = old_active.nextAll (".flux:first"); - - if (new_active.hasClass("flux")) { - toggleContent (new_active, old_active); - } else if (old_active[0] === undefined && - new_active[0] === undefined) { - toggleContent (first_active, old_active); - } - - - if(last_active.attr("id") == new_active.attr("id")) { - load_more_posts (); - } - -} - -function init_img () { - var maxWidth = $(".flux_content .content").width() / 2; - $(".flux_content .content img").each (function () { - if ($(this).width () > maxWidth) { - $(this).addClass("big"); - } - }); -} - -function inMarkViewport(flux, box_to_follow, relative_follow) { - var top = flux.position().top; - if(relative_follow) { - top += box_to_follow.scrollTop(); - } - var height = flux.height(); - var begin = top + 3 * height / 4; - var bot = Math.min(begin + 75, top + height); + echo 'var ', + 'hide_posts=', $this->conf->displayPosts () === 'no' ? 'true,' : 'false,', + 'hide_posts=', $this->conf->displayPosts () === 'no' ? 'true,' : 'false,', + 'auto_mark_article=', $mark['article'] === 'yes' ? 'true,' : 'false,', + 'auto_mark_site=', $mark['site'] === 'yes' ? 'true,' : 'false,', + 'auto_mark_scroll=', $mark['scroll'] === 'yes' ? 'true,' : 'false,', + 'auto_load_more=', $this->conf->autoLoadMore () === 'yes' ? 'true,' : 'false,', + 'does_lazyload=', $this->conf->lazyload() === 'yes' ? 'true' : 'false', ";\n"; - var windowTop = box_to_follow.scrollTop(); - var windowBot = windowTop + box_to_follow.height() / 2; - - return (windowBot >= begin && windowBot <= bot); -} - -function init_posts () { - init_img (); - conf->lazyload() == 'yes') { ?> - if(is_global_mode()) { - $(".flux .content img").lazyload({ - container: $("#panel") - }); - } else { - $(".flux .content img").lazyload(); - } - - - if (hide_posts) { - $(".flux:not(.active) .flux_content").hide (); - } - - var box_to_follow = $(window); - var relative_follow = false; - if(is_global_mode()) { - box_to_follow = $("#panel"); - relative_follow = true; - } - - - box_to_follow.scroll(function() { - $('.flux.not_read:visible').each(function() { - if($(this).children(".flux_content").is(':visible') && - inMarkViewport($(this), box_to_follow, relative_follow)) { - mark_read($(this), true); - } - }); - }); - - - - box_to_follow.scroll(function() { - var load_more = $("#load_more"); - if (!load_more.is(':visible')) return; - var boxBot = box_to_follow.scrollTop() + box_to_follow.height(); - var load_more_top = load_more.position().top; - if(relative_follow) { - load_more_top += box_to_follow.scrollTop(); - } - - if(boxBot >= load_more_top) { - load_more_posts (); - } - }); - -} - -function init_column_categories () { - if(!is_normal_mode()) { - return; - } - - $(".category").addClass ("stick"); - $(".categories .category .btn:first-child").width ("160px"); - $(".category").append (""); - - $(".category + .feeds").not(".active").hide(); - $(".category.active a.dropdown-toggle i").toggleClass ("i_up"); - - $(".category a.dropdown-toggle").click (function () { - $(this).children ().toggleClass ("i_up"); - $(this).parent ().next (".feeds").slideToggle(); - return false; - }); -} - -function init_shortcuts () { - // Touches de manipulation - shortcut.add("", function () { - // on marque comme lu ou non lu - active = $(".flux.active"); - mark_read (active, false); - }, { - 'disable_in_input':true - }); - shortcut.add("shift+", function () { - // on marque tout comme lu - url = $(".nav_menu a.read_all").attr ("href"); - redirect (url, false); - }, { - 'disable_in_input':true - }); - shortcut.add("", function () { - // on marque comme favori ou non favori - active = $(".flux.active"); - mark_favorite (active); - }, { - 'disable_in_input':true - }); - - // Touches de navigation - shortcut.add("", prev_entry, { - 'disable_in_input':true - }); - shortcut.add("shift+", function () { - old_active = $(".flux.active"); - first = $(".flux:first"); - - if (first.hasClass("flux")) { - toggleContent (first, old_active); - } - }, { - 'disable_in_input':true - }); - shortcut.add("", next_entry, { - 'disable_in_input':true - }); - shortcut.add("shift+", function () { - old_active = $(".flux.active"); - last = $(".flux:last"); - - if (last.hasClass("flux")) { - toggleContent (last, old_active); - } - }, { - 'disable_in_input':true - }); - shortcut.add("", function () { - url_website = $(".flux.active .link a").attr ("href"); - - - $(".flux.active").each (function () { - mark_read($(this), true); - }); - - - redirect (url_website, true); - }, { - 'disable_in_input':true - }); -} - -function init_stream_delegates(divStream) { - divStream.on('click', '.flux_header .item.title, .flux_header .item.date', function (e) { //flux_header_toggle - old_active = $(".flux.active"); - new_active = $(this).parent ().parent (); - if (e.target.tagName.toUpperCase() === 'A') { //Leave real links alone - - mark_read(new_active, true); - - return true; - } - toggleContent (new_active, old_active); - }); - - divStream.on('click', '.flux a.read', function () { - active = $(this).parents (".flux"); - mark_read (active, false); - - return false; - }); - - divStream.on('click', '.flux a.bookmark', function () { - active = $(this).parents (".flux"); - mark_favorite (active); - - return false; - }); - - divStream.on('click', '.flux .content a', function () { - $(this).attr ('target', '_blank'); - }); - - divStream.on('click', '.item.title>a',function (e) { - if (e.ctrlKey) return true; //Allow default control-click behaviour such as open in backround-tab - $(this).parent ().click (); //Will perform toggle flux_content - return false; - }); - - divStream.on('click', '.bigMarkAsRead', function() { - url = $(".nav_menu a.read_all").attr ("href"); - redirect (url, false); - return false; - }); - - - divStream.on('click', '.flux .link a', function () { - mark_read($(this).parent().parent().parent(), true); - }); - -} - -function init_nav_entries() { - $('.nav_entries a.previous_entry').click(function() { - prev_entry(); - return false; - }); - $('.nav_entries a.next_entry').click(function() { - next_entry(); - return false; - }); - $('.nav_entries a.up').click(function() { - var active_item = $(".flux.active"); - var windowTop = $(window).scrollTop(); - var item_top = active_item.position ().top; - - if(windowTop > item_top) { - $("html,body").scrollTop (item_top); - } else { - $("html,body").scrollTop (0); - } - return false; - }); -} - -$(document).ready (function () { - if(is_reader_mode()) { - hide_posts = false; - } - init_posts (); - init_column_categories (); - init_shortcuts (); - init_stream_delegates($('#stream')); - init_nav_entries(); -}); + $s = $this->conf->shortcuts (); + echo 'var shortcuts={', + 'mark_read:"', $s['mark_read'], '",', + 'mark_favorite:"', $s['mark_favorite'], '",', + 'go_website:"', $s['go_website'], '",', + 'prev_entry:"', $s['prev_entry'], '",', + 'next_entry:"', $s['next_entry'], '"', + "};\n"; -- cgit v1.2.3 From c447e65c5aa4e5de52ffb11b4bddcacd615caf51 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 13 Oct 2013 17:53:00 +0200 Subject: Chargement à la volée de actualize.phtml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Au lieu de faire une requête systématiquement à chaque action de l'utilisateur vers actualize.phtml (qui est lourd à générer et à lire), cette requête se fait maintenant uniquement lors de son utilisation. --- app/controllers/indexController.php | 2 -- app/views/javascript/actualize.phtml | 7 ------- 2 files changed, 9 deletions(-) (limited to 'app/views/javascript') diff --git a/app/controllers/indexController.php b/app/controllers/indexController.php index ce1a188e7..9f71c0e57 100755 --- a/app/controllers/indexController.php +++ b/app/controllers/indexController.php @@ -11,8 +11,6 @@ class indexController extends ActionController { if ($output == 'rss') { $this->view->_useLayout (false); } else { - View::appendScript (Url::display (array ('c' => 'javascript', 'a' => 'actualize'))); - if(!$output) { $output = $this->view->conf->viewMode(); Request::_param ('output', $output); diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index fa6e67ddb..f39540a9a 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -36,10 +36,3 @@ function updateFeeds () { }); } } - -$(document).ready (function () { - $("#actualize").click (function () { - updateFeeds (); - return false; - }); -}); -- cgit v1.2.3 From 231516f5238b6023001bed548569077c61411a4e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 3 Nov 2013 19:22:59 +0100 Subject: Grosse optimisation JavaScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fusion de endless_mode.js dans main.js car endless_mode.js est toujours chargé et assez petit. * Suppression des changements de style en JavaScript lors du chargement (genre boucle de .hide(), ou d'ajout de classe ".stick") et implémentation en PHP + CSS à la place. * Chargement JavaScript asynchrone (defer + async) pour de meilleurs performances. * Utilisation préférable des événements globaux plutôt que des événements pour chaque élément avec jQuery.on(events, selector) pour un chargement plus rapide et moins de mémoire utilisée. * Optimisation manuelle du JavaScript (sélecteurs CSS plus performants, méthodes jQuery plus appropriées, etc.). * Désactivation de init_img() qui était coûteux, lancé à un moment où les images ne sont de toute manière pas encore chargées, et qui n'apporte rien car il y a déjà un img {max-width:100%} en CSS. * JavaScript en mode strict. * Enfin, passage du code JavaScript dans JSLint et du coup nombreuses corrections (syntaxe, variables, méthodes dépréciées...). * Devrait permettre de fermer https://github.com/marienfressinaud/FreshRSS/issues/121 * Au passage, quelques simplifications CSS pour de meilleures performances. --- app/controllers/indexController.php | 1 - app/layout/aside_flux.phtml | 3 +- app/layout/layout.phtml | 1 + app/layout/nav_entries.phtml | 2 +- app/models/Feed.php | 2 +- app/views/helpers/view/global_view.phtml | 2 +- app/views/helpers/view/normal_view.phtml | 9 +- app/views/javascript/main.phtml | 14 +- lib/minz/View.php | 28 +- public/scripts/endless_mode.js | 44 --- public/scripts/global_view.js | 18 +- public/scripts/main.js | 495 ++++++++++++++++--------------- public/themes/default/freshrss.css | 40 ++- public/themes/default/global.css | 62 ++-- public/themes/flat-design/freshrss.css | 24 +- public/themes/flat-design/global.css | 48 +-- 16 files changed, 402 insertions(+), 391 deletions(-) delete mode 100644 public/scripts/endless_mode.js (limited to 'app/views/javascript') diff --git a/app/controllers/indexController.php b/app/controllers/indexController.php index 9f71c0e57..15b0b1d18 100755 --- a/app/controllers/indexController.php +++ b/app/controllers/indexController.php @@ -18,7 +18,6 @@ class indexController extends ActionController { View::appendScript (Url::display ('/scripts/shortcut.js')); View::appendScript (Url::display ('/scripts/main.js')); - View::appendScript (Url::display ('/scripts/endless_mode.js')); if ($output == 'global') { View::appendScript (Url::display ('/scripts/global_view.js')); diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index 22f52d25a..f661eadd4 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -51,8 +51,9 @@
  • get_c == $cat->id ()) { $c_active = true; } ?> -
    +
      diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index 7f389463e..cfbdc4a2e 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -8,6 +8,7 @@ + diff --git a/app/layout/nav_entries.phtml b/app/layout/nav_entries.phtml index 5501f1725..3c3c3ae5e 100644 --- a/app/layout/nav_entries.phtml +++ b/app/layout/nav_entries.phtml @@ -1,4 +1,4 @@ -
    -
    +
    conf->displayPosts () === 'no' ? ' class="hide_posts"' : ''; ?>>
    \ No newline at end of file diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index 88fc602f6..46547587f 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -7,7 +7,7 @@ if (isset ($this->entryPaginator) && !$this->entryPaginator->isEmpty ()) { $items = $this->entryPaginator->items (); ?> -
    +
    entryPaginator) && !$this->entryPaginator->isEmpty ()) { $link = urlencode ($item->link ()); $title = urlencode ($item->title () . ' - ' . $feed->name ()); ?> -
  • conf->urlShaarli (); - if ((!login_is_conf ($this->conf) || is_logged ()) && $shaarli) { + $shaarli = $this->conf->urlShaarli (); + if ((!login_is_conf ($this->conf) || is_logged ()) && $shaarli) { ?>
  • @@ -128,7 +128,6 @@ if (isset ($this->entryPaginator) && !$this->entryPaginator->isEmpty ()) { diff --git a/app/views/helpers/pagination.phtml b/app/views/helpers/pagination.phtml index 408cfca1b..d4983a32e 100755 --- a/app/views/helpers/pagination.phtml +++ b/app/views/helpers/pagination.phtml @@ -1,25 +1,25 @@
    • nextId)) { ?> nextId; ?> - + -
      +

      - +
      -
      +
    • diff --git a/app/views/helpers/view/global_view.phtml b/app/views/helpers/view/global_view.phtml index ac17d608a..bc6e24e37 100644 --- a/app/views/helpers/view/global_view.phtml +++ b/app/views/helpers/view/global_view.phtml @@ -32,5 +32,5 @@
      conf->displayPosts () === 'no' ? ' class="hide_posts"' : ''; ?>> - +
      \ No newline at end of file diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index 1a7efa58f..094017957 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -24,23 +24,23 @@ if (!empty($this->entries)) { ?> entries as $item) { ?> - isDay (Days::TODAY)) { ?> + isDay (FreshRSS_Days::TODAY)) { ?>
      - + - currentName; ?>
      - isDay (Days::YESTERDAY)) { ?> + isDay (FreshRSS_Days::YESTERDAY)) { ?>
      - + - currentName; ?>
      - isDay (Days::BEFORE_YESTERDAY)) { ?> + isDay (FreshRSS_Days::BEFORE_YESTERDAY)) { ?>
      - + currentName; ?>
      @@ -51,13 +51,13 @@ if (!empty($this->entries)) { if ($this->conf->toplineRead ()) { ?>
    • isRead () ? 'read' : 'unread'); ?>isRead () ? 'read' : 'unread'); ?>
    • conf->toplineFavorite ()) { ?>
    • isFavorite () ? 'starred' : 'non-starred'); ?>isFavorite () ? 'starred' : 'non-starred'); ?>
    • entries)) {
    • ✇ name(); ?>
    • title (); ?>
    • conf->toplineDate ()) { ?>
    • date (); ?> 
    • - conf->toplineLink ()) { ?> + conf->toplineLink ()) { ?>
    @@ -75,7 +75,7 @@ if (!empty($this->entries)) {

    title (); ?>

    author (); - echo $author != '' ? '
    ' . Translate::t ('by_author', $author) . '
    ' : ''; + echo $author != '' ? '
    ' . Minz_Translate::t ('by_author', $author) . '
    ' : ''; if($this->conf->lazyload() == 'yes') { echo lazyimg($item->content ()); } else { @@ -83,19 +83,18 @@ if (!empty($this->entries)) { } ?>
    -
      conf) || is_logged ()) { if ($this->conf->bottomlineRead ()) { ?>
    • isRead () ? 'read' : 'unread'); ?>isRead () ? 'read' : 'unread'); ?>
    • conf->bottomlineFavorite ()) { ?>
    • isFavorite () ? 'starred' : 'non-starred'); ?>isFavorite () ? 'starred' : 'non-starred'); ?>
    • @@ -111,8 +110,8 @@ if (!empty($this->entries)) { @@ -204,6 +203,6 @@ if (!empty($this->entries)) {
      - +
      \ No newline at end of file diff --git a/app/views/helpers/view/reader_view.phtml b/app/views/helpers/view/reader_view.phtml index 30226af42..29b2be04c 100644 --- a/app/views/helpers/view/reader_view.phtml +++ b/app/views/helpers/view/reader_view.phtml @@ -21,7 +21,7 @@ if (!empty($this->entries)) {
      author (); ?> - + date (); ?>
      @@ -42,6 +42,6 @@ if (!empty($this->entries)) {
      - +
      \ No newline at end of file diff --git a/app/views/helpers/view/rss_view.phtml b/app/views/helpers/view/rss_view.phtml index 460146dc0..620bf1388 100755 --- a/app/views/helpers/view/rss_view.phtml +++ b/app/views/helpers/view/rss_view.phtml @@ -2,11 +2,11 @@ <?php echo $this->rss_title; ?> - - rss_title); ?> + + rss_title); ?> GMT - + entries as $item) { ?> diff --git a/app/views/index/about.phtml b/app/views/index/about.phtml index fa799154b..b5c00a1ed 100644 --- a/app/views/index/about.phtml +++ b/app/views/index/about.phtml @@ -1,24 +1,24 @@
      - + -

      +

      -
      +
      -
      -
      Marien Fressinaud -
      +
      +
      Marien Fressinaud -
      -
      -
      +
      +
      -
      -
      +
      +
      -

      +

      -

      -

      +

      +

      diff --git a/app/views/index/index.phtml b/app/views/index/index.phtml index bd18d2d77..cf98060c4 100644 --- a/app/views/index/index.phtml +++ b/app/views/index/index.phtml @@ -1,8 +1,8 @@ conf->token(); -$token_param = Request::param ('token', ''); +$token_param = Minz_Request::param ('token', ''); $token_is_ok = ($token != '' && $token == $token_param); if(!login_is_conf ($this->conf) || @@ -21,9 +21,9 @@ if(!login_is_conf ($this->conf) || } else { ?>
      -

      -

      -

      +

      +

      +

      - + -

      +

      - +

      logsPaginator->items (); ?> @@ -20,6 +20,6 @@ logsPaginator->render ('logs_pagination.phtml','page'); ?> -

      +

      diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index f39540a9a..69689133c 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -1,12 +1,12 @@ var feeds = new Array (); feeds as $feed) { ?> -feeds.push (" 'feed', 'a' => 'actualize', 'params' => array ('id' => $feed->id (), 'ajax' => '1')), 'php'); ?>"); +feeds.push (" 'feed', 'a' => 'actualize', 'params' => array ('id' => $feed->id (), 'ajax' => '1')), 'php'); ?>"); function initProgressBar (init) { if (init) { $("body").after ("\
      \ - 0 / " + feeds.length + "
      \ + 0 / " + feeds.length + "
      \ \
      "); } else { diff --git a/lib/Minz/ActionException.php b/lib/Minz/ActionException.php new file mode 100644 index 000000000..c566a076f --- /dev/null +++ b/lib/Minz/ActionException.php @@ -0,0 +1,9 @@ + +*/ + +/** + * La classe Cache permet de gérer facilement les pages en cache + */ +class Minz_Cache { + /** + * $expire timestamp auquel expire le cache de $url + */ + private $expire = 0; + + /** + * $file est le nom du fichier de cache + */ + private $file = ''; + + /** + * $enabled permet de déterminer si le cache est activé + */ + private static $enabled = true; + + /** + * Constructeur + */ + public function __construct () { + $this->_fileName (); + $this->_expire (); + } + + /** + * Setteurs + */ + public function _fileName () { + $file = md5 (Minz_Request::getURI ()); + + $this->file = CACHE_PATH . '/'.$file; + } + + public function _expire () { + if ($this->exist ()) { + $this->expire = filemtime ($this->file) + + Minz_Configuration::delayCache (); + } + } + + /** + * Permet de savoir si le cache est activé + * @return true si activé, false sinon + */ + public static function isEnabled () { + return Minz_Configuration::cacheEnabled () && self::$enabled; + } + + /** + * Active / désactive le cache + */ + public static function switchOn () { + self::$enabled = true; + } + public static function switchOff () { + self::$enabled = false; + } + + /** + * Détermine si le cache de $url a expiré ou non + * @return true si il a expiré, false sinon + */ + public function expired () { + return time () > $this->expire; + } + + /** + * Affiche le contenu du cache + * @print le code html du cache + */ + public function render () { + if ($this->exist ()) { + include ($this->file); + } + } + + /** + * Enregistre $html en cache + * @param $html le html à mettre en cache + */ + public function cache ($html) { + file_put_contents ($this->file, $html); + } + + /** + * Permet de savoir si le cache existe + * @return true si il existe, false sinon + */ + public function exist () { + return file_exists ($this->file); + } + + /** + * Nettoie le cache en supprimant tous les fichiers + */ + public static function clean () { + $files = opendir (CACHE_PATH); + + while ($fic = readdir ($files)) { + if ($fic != '.' && $fic != '..') { + unlink (CACHE_PATH.'/'.$fic); + } + } + + closedir ($files); + } +} diff --git a/lib/Minz/ControllerNotActionControllerException.php b/lib/Minz/ControllerNotActionControllerException.php new file mode 100644 index 000000000..535a1377e --- /dev/null +++ b/lib/Minz/ControllerNotActionControllerException.php @@ -0,0 +1,9 @@ + +*/ + +/** + * La classe Log permet de logger des erreurs + */ +class Minz_Log { + /** + * Les différents niveau de log + * ERROR erreurs bloquantes de l'application + * WARNING erreurs pouvant géner le bon fonctionnement, mais non bloquantes + * NOTICE erreurs mineures ou messages d'informations + * DEBUG Informations affichées pour le déboggage + */ + const ERROR = 2; + const WARNING = 4; + const NOTICE = 8; + const DEBUG = 16; + + /** + * Enregistre un message dans un fichier de log spécifique + * Message non loggué si + * - environment = SILENT + * - level = WARNING et environment = PRODUCTION + * - level = NOTICE et environment = PRODUCTION + * @param $information message d'erreur / information à enregistrer + * @param $level niveau d'erreur + * @param $file_name fichier de log, par défaut LOG_PATH/application.log + */ + public static function record ($information, $level, $file_name = null) { + $env = Minz_Configuration::environment (); + + if (! ($env === Minz_Configuration::SILENT + || ($env === Minz_Configuration::PRODUCTION + && ($level >= Minz_Log::NOTICE)))) { + if (is_null ($file_name)) { + $file_name = LOG_PATH . '/application.log'; + } + + switch ($level) { + case Minz_Log::ERROR : + $level_label = 'error'; + break; + case Minz_Log::WARNING : + $level_label = 'warning'; + break; + case Minz_Log::NOTICE : + $level_label = 'notice'; + break; + case Minz_Log::DEBUG : + $level_label = 'debug'; + break; + default : + $level_label = 'unknown'; + } + + if ($env == Minz_Configuration::PRODUCTION) { + $file = @fopen ($file_name, 'a'); + } else { + $file = fopen ($file_name, 'a'); + } + + if ($file !== false) { + $log = '[' . date('r') . ']'; + $log .= ' [' . $level_label . ']'; + $log .= ' --- ' . $information . "\n"; + fwrite ($file, $log); + fclose ($file); + } else { + throw new Minz_PermissionDeniedException ( + $file_name, + Minz_Exception::ERROR + ); + } + } + } + + /** + * Automatise le log des variables globales $_GET et $_POST + * Fait appel à la fonction record(...) + * Ne fonctionne qu'en environnement "development" + * @param $file_name fichier de log, par défaut LOG_PATH/application.log + */ + public static function recordRequest($file_name = null) { + $msg_get = str_replace("\n", '', '$_GET content : ' . print_r($_GET, true)); + $msg_post = str_replace("\n", '', '$_POST content : ' . print_r($_POST, true)); + + self::record($msg_get, Minz_Log::DEBUG, $file_name); + self::record($msg_post, Minz_Log::DEBUG, $file_name); + } +} diff --git a/lib/Minz/ModelArray.php b/lib/Minz/ModelArray.php new file mode 100644 index 000000000..4ba022143 --- /dev/null +++ b/lib/Minz/ModelArray.php @@ -0,0 +1,122 @@ + +*/ + +/** + * La classe Model_array représente le modèle interragissant avec les fichiers de type texte gérant des tableaux php + */ +class Minz_ModelArray extends Minz_ModelTxt { + /** + * $array Le tableau php contenu dans le fichier $nameFile + */ + protected $array = array (); + + /** + * Ouvre le fichier indiqué, charge le tableau dans $array et le $nameFile + * @param $nameFile le nom du fichier à ouvrir contenant un tableau + * Remarque : $array sera obligatoirement un tableau + */ + public function __construct ($nameFile) { + parent::__construct ($nameFile); + + if (!$this->getLock ('read')) { + throw new Minz_PermissionDeniedException ($this->filename); + } else { + $this->array = include ($this->filename); + $this->releaseLock (); + + if (!is_array ($this->array)) { + $this->array = array (); + } + + $this->array = $this->decodeArray ($this->array); + } + } + + /** + * Écrit un tableau dans le fichier $nameFile + * @param $array le tableau php à enregistrer + **/ + public function writeFile ($array) { + if (!$this->getLock ('write')) { + throw new Minz_PermissionDeniedException ($this->namefile); + } else { + $this->erase (); + + $this->writeLine ('writeLine ('return ', false); + $this->writeArray ($array); + $this->writeLine (';'); + + $this->releaseLock (); + } + } + + private function writeArray ($array, $profondeur = 0) { + $tab = ''; + for ($i = 0; $i < $profondeur; $i++) { + $tab .= "\t"; + } + $this->writeLine ('array ('); + + foreach ($array as $key => $value) { + if (is_int ($key)) { + $this->writeLine ($tab . "\t" . $key . ' => ', false); + } else { + $this->writeLine ($tab . "\t" . '\'' . $key . '\'' . ' => ', false); + } + + if (is_array ($value)) { + $this->writeArray ($value, $profondeur + 1); + $this->writeLine (','); + } else { + if (is_numeric ($value)) { + $this->writeLine ($value . ','); + } else { + $this->writeLine ('\'' . addslashes ($value) . '\','); + } + } + } + + $this->writeLine ($tab . ')', false); + } + + private function decodeArray ($array) { + $new_array = array (); + + foreach ($array as $key => $value) { + if (is_array ($value)) { + $new_array[$key] = $this->decodeArray ($value); + } else { + $new_array[$key] = stripslashes ($value); + } + } + + return $new_array; + } + + private function getLock ($type) { + if ($type == 'write') { + $lock = LOCK_EX; + } else { + $lock = LOCK_SH; + } + + $count = 1; + while (!flock ($this->file, $lock) && $count <= 50) { + $count++; + } + + if ($count >= 50) { + return false; + } else { + return true; + } + } + + private function releaseLock () { + flock ($this->file, LOCK_UN); + } +} diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php new file mode 100644 index 000000000..9655539b2 --- /dev/null +++ b/lib/Minz/ModelPdo.php @@ -0,0 +1,111 @@ + +*/ + +/** + * La classe Model_sql représente le modèle interragissant avec les bases de données + * Seul la connexion MySQL est prise en charge pour le moment + */ +class Minz_ModelPdo { + + /** + * Partage la connexion à la base de données entre toutes les instances. + */ + public static $useSharedBd = true; + private static $sharedBd = null; + private static $sharedPrefix; + + /** + * $bd variable représentant la base de données + */ + protected $bd; + + protected $prefix; + + /** + * Créé la connexion à la base de données à l'aide des variables + * HOST, BASE, USER et PASS définies dans le fichier de configuration + */ + public function __construct () { + if (self::$useSharedBd && self::$sharedBd != null) { + $this->bd = self::$sharedBd; + $this->prefix = self::$sharedPrefix; + return; + } + + $db = Minz_Configuration::dataBase (); + $driver_options = null; + + try { + $type = $db['type']; + if($type == 'mysql') { + $string = $type + . ':host=' . $db['host'] + . ';dbname=' . $db['base'] + . ';charset=utf8'; + $driver_options = array( + PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8' + ); + } elseif($type == 'sqlite') { + $string = $type . ':/' . DATA_PATH . $db['base'] . '.sqlite'; //TODO: DEBUG UTF-8 http://www.siteduzero.com/forum/sujet/sqlite-connexion-utf-8-18797 + } + + $this->bd = new FreshPDO ( + $string, + $db['user'], + $db['password'], + $driver_options + ); + self::$sharedBd = $this->bd; + + $userPrefix = Minz_Configuration::currentUser (); + $this->prefix = $db['prefix'] . (empty($userPrefix) ? '' : ($userPrefix . '_')); + self::$sharedPrefix = $this->prefix; + } catch (Exception $e) { + throw new Minz_PDOConnectionException ( + $string, + $db['user'], Minz_Exception::ERROR + ); + } + } + + public function beginTransaction() { + $this->bd->beginTransaction(); + } + public function commit() { + $this->bd->commit(); + } + public function rollBack() { + $this->bd->rollBack(); + } + + public function size() { + $db = Minz_Configuration::dataBase (); + $sql = 'SELECT SUM(data_length + index_length) FROM information_schema.TABLES WHERE table_schema = ?'; + $stm = $this->bd->prepare ($sql); + $values = array ($db['base']); + $stm->execute ($values); + $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); + return $res[0]; + } +} + +class FreshPDO extends PDO { + private static function check($statement) { + if (preg_match('/^(?:UPDATE|INSERT|DELETE)/i', $statement)) { + invalidateHttpCache(); + } + } + + public function prepare ($statement, $driver_options = array()) { + FreshPDO::check($statement); + return parent::prepare($statement, $driver_options); + } + + public function exec ($statement) { + FreshPDO::check($statement); + return parent::exec($statement); + } +} diff --git a/lib/Minz/ModelTxt.php b/lib/Minz/ModelTxt.php new file mode 100644 index 000000000..8c5973f4d --- /dev/null +++ b/lib/Minz/ModelTxt.php @@ -0,0 +1,84 @@ + +*/ + +/** + * La classe Model_txt représente le modèle interragissant avec les fichiers de type texte + */ +class Minz_ModelTxt { + /** + * $file représente le fichier à ouvrir + */ + protected $file; + + /** + * $filename est le nom du fichier + */ + protected $filename; + + /** + * Ouvre un fichier dans $file + * @param $nameFile nom du fichier à ouvrir + * @param $mode mode d'ouverture du fichier ('a+' par défaut) + * @exception FileNotExistException si le fichier n'existe pas + * > ou ne peux pas être ouvert + */ + public function __construct ($nameFile, $mode = 'a+') { + $this->filename = $nameFile; + if (!file_exists($this->filename)) { + throw new Minz_FileNotExistException ( + $this->filename, + Minz_Exception::WARNING + ); + } + + $this->file = @fopen ($this->filename, $mode); + + if (!$this->file) { + throw new Minz_PermissionDeniedException ( + $this->filename, + Minz_Exception::WARNING + ); + } + } + + /** + * Lit une ligne de $file + * @return une ligne du fichier + */ + public function readLine () { + return fgets ($this->file); + } + + /** + * Écrit une ligne dans $file + * @param $line la ligne à écrire + */ + public function writeLine ($line, $newLine = true) { + $char = ''; + if ($newLine) { + $char = "\n"; + } + + fwrite ($this->file, $line . $char); + } + + /** + * Efface le fichier $file + * @return true en cas de succès, false sinon + */ + public function erase () { + return ftruncate ($this->file, 0); + } + + /** + * Ferme $file + */ + public function __destruct () { + if (isset ($this->file)) { + fclose ($this->file); + } + } +} diff --git a/lib/Minz/PDOConnectionException.php b/lib/Minz/PDOConnectionException.php new file mode 100644 index 000000000..faf2e0fe9 --- /dev/null +++ b/lib/Minz/PDOConnectionException.php @@ -0,0 +1,9 @@ +route = $route; + + $message = 'Route `' . $route . '` not found'; + + parent::__construct ($message, $code); + } + + public function route () { + return $this->route; + } +} diff --git a/lib/SimplePie_autoloader.php b/lib/SimplePie_autoloader.php deleted file mode 100644 index 3f67635b0..000000000 --- a/lib/SimplePie_autoloader.php +++ /dev/null @@ -1,86 +0,0 @@ -path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'SimplePie'; - } - - /** - * Autoloader - * - * @param string $class The name of the class to attempt to load. - */ - public function autoload($class) - { - // Only load the class if it starts with "SimplePie" - if (strpos($class, 'SimplePie') !== 0) - { - return; - } - - $filename = $this->path . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php'; - include $filename; - } -} diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 4f5b90b61..2fdfd4bd8 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -15,6 +15,31 @@ if (!function_exists('json_encode')) { } } +// +function classAutoloader($class) { + if (strpos($class, 'FreshRSS') === 0) { + $components = explode('_', $class); + switch (count($components)) { + case 1: + include(APP_PATH . '/' . $components[0] . '.php'); + return; + case 2: + include(APP_PATH . '/Models/' . $components[1] . '.php'); + return; + case 3: //Controllers, Exceptions + include(APP_PATH . '/' . $components[2] . 's/' . $components[1] . $components[2] . '.php'); + return; + } + } elseif (strpos($class, 'Minz') === 0) { + include(LIB_PATH . '/' . str_replace('_', '/', $class) . '.php'); + } elseif (strpos($class, 'SimplePie') === 0) { + include(LIB_PATH . '/SimplePie/' . str_replace('_', '/', $class) . '.php'); + } +} + +spl_autoload_register('classAutoloader'); +// + function checkUrl($url) { if (empty ($url)) { return ''; @@ -33,7 +58,7 @@ function checkUrl($url) { // vérifie qu'on est connecté function is_logged () { - return Session::param ('mail') != false; + return Minz_Session::param ('mail') != false; } // vérifie que le système d'authentification est configuré @@ -63,11 +88,11 @@ function formatBytes($bytes, $precision = 2, $system = 'IEC') { } function timestamptodate ($t, $hour = true) { - $month = Translate::t (date('M', $t)); + $month = Minz_Translate::t (date('M', $t)); if ($hour) { - $date = Translate::t ('format_date_hour', $month); + $date = Minz_Translate::t ('format_date_hour', $month); } else { - $date = Translate::t ('format_date', $month); + $date = Minz_Translate::t ('format_date', $month); } return @date ($date, $t); @@ -123,10 +148,10 @@ function opml_import ($xml) { $opml = simplexml_import_dom($dom); if (!$opml) { - throw new OpmlException (); + throw new FreshRSS_Opml_Exception (); } - $catDAO = new CategoryDAO(); + $catDAO = new FreshRSS_CategoryDAO(); $catDAO->checkDefault(); $defCat = $catDAO->getDefault(); @@ -152,10 +177,10 @@ function opml_import ($xml) { // Y ne sera pas ajouté et le flux non plus vu que l'id // de sa catégorie n'exisera pas $title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); - $catDAO = new CategoryDAO (); + $catDAO = new FreshRSS_CategoryDAO (); $cat = $catDAO->searchByName ($title); if ($cat === false) { - $cat = new Category ($title); + $cat = new FreshRSS_Category ($title); $values = array ( 'name' => $cat->name (), 'color' => $cat->color () @@ -204,7 +229,7 @@ function getFeed ($outline, $cat_id) { $title = (string) $outline['title']; } $title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); - $feed = new Feed ($url); + $feed = new FreshRSS_Feed ($url); $feed->_category ($cat_id); $feed->_name ($title); if (isset($outline['htmlUrl'])) { @@ -250,7 +275,7 @@ function get_content_by_parsing ($url, $path) { function lazyimg($content) { return preg_replace( '/]+?)src=[\'"]([^"\']+)[\'"]([^>]*)>/i', - '', + '', $content ); } diff --git a/lib/minz/ActionController.php b/lib/minz/ActionController.php index ab9389dbd..409d9611f 100755 --- a/lib/minz/ActionController.php +++ b/lib/minz/ActionController.php @@ -7,7 +7,7 @@ /** * La classe ActionController représente le contrôleur de l'application */ -class ActionController { +class Minz_ActionController { protected $router; protected $view; @@ -18,7 +18,7 @@ class ActionController { */ public function __construct ($router) { $this->router = $router; - $this->view = new View (); + $this->view = new Minz_View (); $this->view->attributeParams (); } diff --git a/lib/minz/Configuration.php b/lib/minz/Configuration.php index 7d6e3743e..9fc913964 100755 --- a/lib/minz/Configuration.php +++ b/lib/minz/Configuration.php @@ -7,7 +7,7 @@ /** * La classe Configuration permet de gérer la configuration de l'application */ -class Configuration { +class Minz_Configuration { const CONF_PATH_NAME = '/application.ini'; /** @@ -43,7 +43,7 @@ class Configuration { * - base le nom de la base de données */ private static $sel_application = ''; - private static $environment = Configuration::PRODUCTION; + private static $environment = Minz_Configuration::PRODUCTION; private static $base_url = ''; private static $use_url_rewriting = false; private static $title = ''; @@ -99,30 +99,30 @@ class Configuration { /** * Initialise les variables de configuration - * @exception FileNotExistException si le CONF_PATH_NAME n'existe pas - * @exception BadConfigurationException si CONF_PATH_NAME mal formaté + * @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas + * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté */ public static function init () { try { self::parseFile (); self::setReporting (); - } catch (FileNotExistException $e) { + } catch (Minz_FileNotExistException $e) { throw $e; - } catch (BadConfigurationException $e) { + } catch (Minz_BadConfigurationException $e) { throw $e; } } /** * Parse un fichier de configuration de type ".ini" - * @exception FileNotExistException si le CONF_PATH_NAME n'existe pas - * @exception BadConfigurationException si CONF_PATH_NAME mal formaté + * @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas + * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté */ private static function parseFile () { if (!file_exists (DATA_PATH . self::CONF_PATH_NAME)) { - throw new FileNotExistException ( + throw new Minz_FileNotExistException ( DATA_PATH . self::CONF_PATH_NAME, - MinzException::ERROR + Minz_Exception::ERROR ); } @@ -132,17 +132,17 @@ class Configuration { ); if (!$ini_array) { - throw new PermissionDeniedException ( + throw new Minz_PermissionDeniedException ( DATA_PATH . self::CONF_PATH_NAME, - MinzException::ERROR + Minz_Exception::ERROR ); } // [general] est obligatoire if (!isset ($ini_array['general'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( '[general]', - MinzException::ERROR + Minz_Exception::ERROR ); } $general = $ini_array['general']; @@ -150,9 +150,9 @@ class Configuration { // sel_application est obligatoire if (!isset ($general['sel_application'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'sel_application', - MinzException::ERROR + Minz_Exception::ERROR ); } self::$sel_application = $general['sel_application']; @@ -160,18 +160,18 @@ class Configuration { if (isset ($general['environment'])) { switch ($general['environment']) { case 'silent': - self::$environment = Configuration::SILENT; + self::$environment = Minz_Configuration::SILENT; break; case 'development': - self::$environment = Configuration::DEVELOPMENT; + self::$environment = Minz_Configuration::DEVELOPMENT; break; case 'production': - self::$environment = Configuration::PRODUCTION; + self::$environment = Minz_Configuration::PRODUCTION; break; default: - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'environment', - MinzException::ERROR + Minz_Exception::ERROR ); } @@ -194,7 +194,7 @@ class Configuration { if (CACHE_PATH === false && self::$cache_enabled) { throw new FileNotExistException ( 'CACHE_PATH', - MinzException::ERROR + Minz_Exception::ERROR ); } } @@ -213,27 +213,27 @@ class Configuration { } if ($db) { if (!isset ($db['host'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'host', - MinzException::ERROR + Minz_Exception::ERROR ); } if (!isset ($db['user'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'user', - MinzException::ERROR + Minz_Exception::ERROR ); } if (!isset ($db['password'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'password', - MinzException::ERROR + Minz_Exception::ERROR ); } if (!isset ($db['base'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'base', - MinzException::ERROR + Minz_Exception::ERROR ); } diff --git a/lib/minz/Dispatcher.php b/lib/minz/Dispatcher.php index 0cfdd8e75..2898b5f00 100644 --- a/lib/minz/Dispatcher.php +++ b/lib/minz/Dispatcher.php @@ -9,8 +9,8 @@ * déterminée dans la Request * C'est un singleton */ -class Dispatcher { - const CONTROLLERS_PATH_NAME = '/controllers'; +class Minz_Dispatcher { + const CONTROLLERS_PATH_NAME = '/Controllers'; /* singleton */ private static $instance = null; @@ -23,7 +23,7 @@ class Dispatcher { */ public static function getInstance ($router) { if (is_null (self::$instance)) { - self::$instance = new Dispatcher ($router); + self::$instance = new Minz_Dispatcher ($router); } return self::$instance; } @@ -38,7 +38,7 @@ class Dispatcher { /** * Lance le controller indiqué dans Request * Remplit le body de Response à partir de la Vue - * @exception MinzException + * @exception Minz_Exception */ public function run () { $cache = new Minz_Cache(); @@ -53,29 +53,25 @@ class Dispatcher { $cache->render (); $text = ob_get_clean(); } else { - while (Request::$reseted) { - Request::$reseted = false; + while (Minz_Request::$reseted) { + Minz_Request::$reseted = false; try { - $this->createController ( - Request::controllerName () - . 'Controller' - ); - + $this->createController ('FreshRSS_' . Minz_Request::controllerName () . '_Controller'); $this->controller->init (); $this->controller->firstAction (); $this->launchAction ( - Request::actionName () + Minz_Request::actionName () . 'Action' ); $this->controller->lastAction (); - if (!Request::$reseted) { + if (!Minz_Request::$reseted) { ob_start (); $this->controller->view ()->build (); $text = ob_get_clean(); } - } catch (MinzException $e) { + } catch (Minz_Exception $e) { throw $e; } } @@ -85,14 +81,12 @@ class Dispatcher { } } - Response::setBody ($text); + Minz_Response::setBody ($text); } /** * Instancie le Controller * @param $controller_name le nom du controller à instancier - * @exception FileNotExistException le fichier correspondant au - * > controller n'existe pas * @exception ControllerNotExistException le controller n'existe pas * @exception ControllerNotActionControllerException controller n'est * > pas une instance de ActionController @@ -101,26 +95,18 @@ class Dispatcher { $filename = APP_PATH . self::CONTROLLERS_PATH_NAME . '/' . $controller_name . '.php'; - if (!file_exists ($filename)) { - throw new FileNotExistException ( - $filename, - MinzException::ERROR - ); - } - require_once ($filename); - if (!class_exists ($controller_name)) { - throw new ControllerNotExistException ( + throw new Minz_ControllerNotExistException ( $controller_name, - MinzException::ERROR + Minz_Exception::ERROR ); } $this->controller = new $controller_name ($this->router); - if (! ($this->controller instanceof ActionController)) { - throw new ControllerNotActionControllerException ( + if (! ($this->controller instanceof Minz_ActionController)) { + throw new Minz_ControllerNotActionControllerException ( $controller_name, - MinzException::ERROR + Minz_Exception::ERROR ); } } @@ -129,18 +115,18 @@ class Dispatcher { * Lance l'action sur le controller du dispatcher * @param $action_name le nom de l'action * @exception ActionException si on ne peut pas exécuter l'action sur - * > le controller + * le controller */ private function launchAction ($action_name) { - if (!Request::$reseted) { + if (!Minz_Request::$reseted) { if (!is_callable (array ( $this->controller, $action_name ))) { - throw new ActionException ( + throw new Minz_ActionException ( get_class ($this->controller), $action_name, - MinzException::ERROR + Minz_Exception::ERROR ); } call_user_func (array ( diff --git a/lib/minz/Error.php b/lib/minz/Error.php index 0e8c2f60b..1ad0d313c 100755 --- a/lib/minz/Error.php +++ b/lib/minz/Error.php @@ -1,5 +1,5 @@ */ @@ -7,7 +7,7 @@ /** * La classe Error permet de lancer des erreurs HTTP */ -class Error { +class Minz_Error { public function __construct () { } /** @@ -21,28 +21,28 @@ class Error { */ public static function error ($code = 404, $logs = array (), $redirect = false) { $logs = self::processLogs ($logs); - $error_filename = APP_PATH . '/controllers/errorController.php'; - + $error_filename = APP_PATH . '/Controllers/ErrorController.php'; + if (file_exists ($error_filename)) { $params = array ( 'code' => $code, 'logs' => $logs ); - - Response::setHeader ($code); + + Minz_Response::setHeader ($code); if ($redirect) { - Request::forward (array ( + Minz_Request::forward (array ( 'c' => 'error' ), true); } else { - Request::forward (array ( + Minz_Request::forward (array ( 'c' => 'error', 'params' => $params ), false); } } else { $text = '

      An error occured

      '."\n"; - + if (!empty ($logs)) { $text .= '
        '."\n"; foreach ($logs as $log) { @@ -50,14 +50,14 @@ class Error { } $text .= '
      '."\n"; } - - Response::setHeader ($code); - Response::setBody ($text); - Response::send (); + + Minz_Response::setHeader ($code); + Minz_Response::setBody ($text); + Minz_Response::send (); exit (); } } - + /** * Permet de retourner les logs de façon à n'avoir que * ceux que l'on veut réellement @@ -66,12 +66,12 @@ class Error { * > en fonction de l'environment */ private static function processLogs ($logs) { - $env = Configuration::environment (); + $env = Minz_Configuration::environment (); $logs_ok = array (); $error = array (); $warning = array (); $notice = array (); - + if (isset ($logs['error'])) { $error = $logs['error']; } @@ -81,14 +81,14 @@ class Error { if (isset ($logs['notice'])) { $notice = $logs['notice']; } - - if ($env == Configuration::PRODUCTION) { + + if ($env == Minz_Configuration::PRODUCTION) { $logs_ok = $error; } - if ($env == Configuration::DEVELOPMENT) { + if ($env == Minz_Configuration::DEVELOPMENT) { $logs_ok = array_merge ($error, $warning, $notice); } - + return $logs_ok; } } diff --git a/lib/minz/FrontController.php b/lib/minz/FrontController.php index d48d43d04..eb9835fe5 100755 --- a/lib/minz/FrontController.php +++ b/lib/minz/FrontController.php @@ -2,109 +2,79 @@ # ***** BEGIN LICENSE BLOCK ***** # MINZ - a free PHP Framework like Zend Framework # Copyright (C) 2011 Marien Fressinaud -# +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. -# +# # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # # ***** END LICENSE BLOCK ***** /** - * La classe FrontController est le noyau du framework, elle lance l'application + * La classe FrontController est le Dispatcher du framework, elle lance l'application * Elle est appelée en général dans le fichier index.php à la racine du serveur */ -class FrontController { +class Minz_FrontController { protected $dispatcher; protected $router; - + /** * Constructeur * Initialise le router et le dispatcher */ public function __construct () { - $this->loadLib (); - if (LOG_PATH === false) { $this->killApp ('Path doesn\'t exist : LOG_PATH'); } - + try { - Configuration::init (); + Minz_Configuration::init (); - Request::init (); + Minz_Request::init (); - $this->router = new Router (); + $this->router = new Minz_Router (); $this->router->init (); - } catch (RouteNotFoundException $e) { + } catch (Minz_RouteNotFoundException $e) { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); - Error::error ( + Minz_Error::error ( 404, array ('error' => array ($e->getMessage ())) ); - } catch (MinzException $e) { + } catch (Minz_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); $this->killApp ($e->getMessage ()); } - - $this->dispatcher = Dispatcher::getInstance ($this->router); - } - - /** - * Inclue les fichiers de la librairie - */ - private function loadLib () { - require ('ActionController.php'); - require ('Minz_Cache.php'); - require ('Configuration.php'); - require ('Dispatcher.php'); - require ('Error.php'); - require ('Helper.php'); - require ('Minz_Log.php'); - require ('Model.php'); - require ('Paginator.php'); - require ('Request.php'); - require ('Response.php'); - require ('Router.php'); - require ('Session.php'); - require ('Translate.php'); - require ('Url.php'); - require ('View.php'); - - require ('dao/Model_pdo.php'); - require ('dao/Model_txt.php'); - require ('dao/Model_array.php'); - - require ('exceptions/MinzException.php'); + + $this->dispatcher = Minz_Dispatcher::getInstance ($this->router); } - + /** * Démarre l'application (lance le dispatcher et renvoie la réponse */ public function run () { try { $this->dispatcher->run (); - Response::send (); - } catch (MinzException $e) { + Minz_Response::send (); + } catch (Minz_Exception $e) { try { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); - } catch (PermissionDeniedException $e) { + } catch (Minz_PermissionDeniedException $e) { $this->killApp ($e->getMessage ()); } - if ($e instanceof FileNotExistException || - $e instanceof ControllerNotExistException || - $e instanceof ControllerNotActionControllerException || - $e instanceof ActionException) { - Error::error ( + if ($e instanceof Minz_FileNotExistException || + $e instanceof Minz_ControllerNotExistException || + $e instanceof Minz_ControllerNotActionControllerException || + $e instanceof Minz_ActionException) { + Minz_Error::error ( 404, array ('error' => array ($e->getMessage ())), true @@ -114,7 +84,7 @@ class FrontController { } } } - + /** * Permet d'arrêter le programme en urgence */ diff --git a/lib/minz/Helper.php b/lib/minz/Helper.php index 4f64ba218..b058211d3 100755 --- a/lib/minz/Helper.php +++ b/lib/minz/Helper.php @@ -7,7 +7,7 @@ /** * La classe Helper représente une aide pour des tâches récurrentes */ -class Helper { +class Minz_Helper { /** * Annule les effets des magic_quotes pour une variable donnée * @param $var variable à traiter (tableau ou simple variable) diff --git a/lib/minz/Minz_Cache.php b/lib/minz/Minz_Cache.php deleted file mode 100644 index 6848e3350..000000000 --- a/lib/minz/Minz_Cache.php +++ /dev/null @@ -1,116 +0,0 @@ - -*/ - -/** - * La classe Cache permet de gérer facilement les pages en cache - */ -class Minz_Cache { - /** - * $expire timestamp auquel expire le cache de $url - */ - private $expire = 0; - - /** - * $file est le nom du fichier de cache - */ - private $file = ''; - - /** - * $enabled permet de déterminer si le cache est activé - */ - private static $enabled = true; - - /** - * Constructeur - */ - public function __construct () { - $this->_fileName (); - $this->_expire (); - } - - /** - * Setteurs - */ - public function _fileName () { - $file = md5 (Request::getURI ()); - - $this->file = CACHE_PATH . '/'.$file; - } - - public function _expire () { - if ($this->exist ()) { - $this->expire = filemtime ($this->file) - + Configuration::delayCache (); - } - } - - /** - * Permet de savoir si le cache est activé - * @return true si activé, false sinon - */ - public static function isEnabled () { - return Configuration::cacheEnabled () && self::$enabled; - } - - /** - * Active / désactive le cache - */ - public static function switchOn () { - self::$enabled = true; - } - public static function switchOff () { - self::$enabled = false; - } - - /** - * Détermine si le cache de $url a expiré ou non - * @return true si il a expiré, false sinon - */ - public function expired () { - return time () > $this->expire; - } - - /** - * Affiche le contenu du cache - * @print le code html du cache - */ - public function render () { - if ($this->exist ()) { - include ($this->file); - } - } - - /** - * Enregistre $html en cache - * @param $html le html à mettre en cache - */ - public function cache ($html) { - file_put_contents ($this->file, $html); - } - - /** - * Permet de savoir si le cache existe - * @return true si il existe, false sinon - */ - public function exist () { - return file_exists ($this->file); - } - - /** - * Nettoie le cache en supprimant tous les fichiers - */ - public static function clean () { - $files = opendir (CACHE_PATH); - - while ($fic = readdir ($files)) { - if ($fic != '.' && $fic != '..') { - unlink (CACHE_PATH.'/'.$fic); - } - } - - closedir ($files); - } -} diff --git a/lib/minz/Minz_Log.php b/lib/minz/Minz_Log.php deleted file mode 100644 index 12005aa88..000000000 --- a/lib/minz/Minz_Log.php +++ /dev/null @@ -1,94 +0,0 @@ - -*/ - -/** - * La classe Log permet de logger des erreurs - */ -class Minz_Log { - /** - * Les différents niveau de log - * ERROR erreurs bloquantes de l'application - * WARNING erreurs pouvant géner le bon fonctionnement, mais non bloquantes - * NOTICE erreurs mineures ou messages d'informations - * DEBUG Informations affichées pour le déboggage - */ - const ERROR = 2; - const WARNING = 4; - const NOTICE = 8; - const DEBUG = 16; - - /** - * Enregistre un message dans un fichier de log spécifique - * Message non loggué si - * - environment = SILENT - * - level = WARNING et environment = PRODUCTION - * - level = NOTICE et environment = PRODUCTION - * @param $information message d'erreur / information à enregistrer - * @param $level niveau d'erreur - * @param $file_name fichier de log, par défaut LOG_PATH/application.log - */ - public static function record ($information, $level, $file_name = null) { - $env = Configuration::environment (); - - if (! ($env === Configuration::SILENT - || ($env === Configuration::PRODUCTION - && ($level >= Minz_Log::NOTICE)))) { - if (is_null ($file_name)) { - $file_name = LOG_PATH . '/application.log'; - } - - switch ($level) { - case Minz_Log::ERROR : - $level_label = 'error'; - break; - case Minz_Log::WARNING : - $level_label = 'warning'; - break; - case Minz_Log::NOTICE : - $level_label = 'notice'; - break; - case Minz_Log::DEBUG : - $level_label = 'debug'; - break; - default : - $level_label = 'unknown'; - } - - if ($env == Configuration::PRODUCTION) { - $file = @fopen ($file_name, 'a'); - } else { - $file = fopen ($file_name, 'a'); - } - - if ($file !== false) { - $log = '[' . date('r') . ']'; - $log .= ' [' . $level_label . ']'; - $log .= ' --- ' . $information . "\n"; - fwrite ($file, $log); - fclose ($file); - } else { - throw new PermissionDeniedException ( - $file_name, - MinzException::ERROR - ); - } - } - } - - /** - * Automatise le log des variables globales $_GET et $_POST - * Fait appel à la fonction record(...) - * Ne fonctionne qu'en environnement "development" - * @param $file_name fichier de log, par défaut LOG_PATH/application.log - */ - public static function recordRequest($file_name = null) { - $msg_get = str_replace("\n", '', '$_GET content : ' . print_r($_GET, true)); - $msg_post = str_replace("\n", '', '$_POST content : ' . print_r($_POST, true)); - - self::record($msg_get, Minz_Log::DEBUG, $file_name); - self::record($msg_post, Minz_Log::DEBUG, $file_name); - } -} diff --git a/lib/minz/Model.php b/lib/minz/Model.php index 37fc19ed1..adbaba942 100755 --- a/lib/minz/Model.php +++ b/lib/minz/Model.php @@ -7,6 +7,6 @@ /** * La classe Model représente un modèle de l'application (représentation MVC) */ -class Model { +class Minz_Model { } diff --git a/lib/minz/Paginator.php b/lib/minz/Paginator.php index 1a8376e75..5858e76a5 100755 --- a/lib/minz/Paginator.php +++ b/lib/minz/Paginator.php @@ -7,7 +7,7 @@ /** * La classe Paginator permet de gérer la pagination de l'application facilement */ -class Paginator { +class Minz_Paginator { /** * $items tableau des éléments à afficher/gérer */ diff --git a/lib/minz/Request.php b/lib/minz/Request.php index 3e508d8f1..c8ffa4a42 100644 --- a/lib/minz/Request.php +++ b/lib/minz/Request.php @@ -7,7 +7,7 @@ /** * Request représente la requête http */ -class Request { +class Minz_Request { private static $controller_name = ''; private static $action_name = ''; private static $params = array (); @@ -96,7 +96,7 @@ class Request { * @return la base de l'url */ public static function getBaseUrl () { - return Configuration::baseUrl (); + return Minz_Configuration::baseUrl (); } /** @@ -124,10 +124,10 @@ class Request { * > sinon, le dispatcher recharge en interne */ public static function forward ($url = array (), $redirect = false) { - $url = Url::checkUrl ($url); + $url = Minz_Url::checkUrl ($url); if ($redirect) { - header ('Location: ' . Url::display ($url, 'php')); + header ('Location: ' . Minz_Url::display ($url, 'php')); exit (); } else { self::$reseted = true; @@ -185,9 +185,9 @@ class Request { */ private static function magicQuotesOff () { if (get_magic_quotes_gpc ()) { - $_GET = Helper::stripslashes_r ($_GET); - $_POST = Helper::stripslashes_r ($_POST); - $_COOKIE = Helper::stripslashes_r ($_COOKIE); + $_GET = Minz_Helper::stripslashes_r ($_GET); + $_POST = Minz_Helper::stripslashes_r ($_POST); + $_COOKIE = Minz_Helper::stripslashes_r ($_COOKIE); } } @@ -195,5 +195,3 @@ class Request { return !empty ($_POST) || !empty ($_FILES); } } - - diff --git a/lib/minz/Response.php b/lib/minz/Response.php index fcf53c5b1..f8ea3d946 100644 --- a/lib/minz/Response.php +++ b/lib/minz/Response.php @@ -7,7 +7,7 @@ /** * Response représente la requête http renvoyée à l'utilisateur */ -class Response { +class Minz_Response { private static $header = 'HTTP/1.0 200 OK'; private static $body = ''; diff --git a/lib/minz/Router.php b/lib/minz/Router.php index c5d6f5baa..1ccd72597 100755 --- a/lib/minz/Router.php +++ b/lib/minz/Router.php @@ -8,7 +8,7 @@ * La classe Router gère le routage de l'application * Les routes sont définies dans APP_PATH.'/configuration/routes.php' */ -class Router { +class Minz_Router { const ROUTES_PATH_NAME = '/configuration/routes.php'; private $routes = array (); @@ -19,7 +19,7 @@ class Router { * et que l'on utilise l'url rewriting */ public function __construct () { - if (Configuration::useUrlRewriting ()) { + if (Minz_Configuration::useUrlRewriting ()) { if (file_exists (APP_PATH . self::ROUTES_PATH_NAME)) { $routes = include ( APP_PATH . self::ROUTES_PATH_NAME @@ -34,9 +34,9 @@ class Router { $routes ); } else { - throw new FileNotExistException ( + throw new Minz_FileNotExistException ( self::ROUTES_PATH_NAME, - MinzException::ERROR + Minz_Exception::ERROR ); } } @@ -51,10 +51,10 @@ class Router { public function init () { $url = array (); - if (Configuration::useUrlRewriting ()) { + if (Minz_Configuration::useUrlRewriting ()) { try { $url = $this->buildWithRewriting (); - } catch (RouteNotFoundException $e) { + } catch (Minz_RouteNotFoundException $e) { throw $e; } } else { @@ -63,10 +63,10 @@ class Router { $url['params'] = array_merge ( $url['params'], - Request::fetchPOST () + Minz_Request::fetchPOST () ); - Request::forward ($url); + Minz_Request::forward ($url); } /** @@ -77,15 +77,15 @@ class Router { public function buildWithoutRewriting () { $url = array (); - $url['c'] = Request::fetchGET ( + $url['c'] = Minz_Request::fetchGET ( 'c', - Request::defaultControllerName () + Minz_Request::defaultControllerName () ); - $url['a'] = Request::fetchGET ( + $url['a'] = Minz_Request::fetchGET ( 'a', - Request::defaultActionName () + Minz_Request::defaultActionName () ); - $url['params'] = Request::fetchGET (); + $url['params'] = Minz_Request::fetchGET (); // post-traitement unset ($url['params']['c']); @@ -103,7 +103,7 @@ class Router { */ public function buildWithRewriting () { $url = array (); - $uri = Request::getURI (); + $uri = Minz_Request::getURI (); $find = false; foreach ($this->routes as $route) { @@ -121,14 +121,14 @@ class Router { } if (!$find && $uri != '/') { - throw new RouteNotFoundException ( + throw new Minz_RouteNotFoundException ( $uri, - MinzException::ERROR + Minz_Exception::ERROR ); } // post-traitement - $url = Url::checkUrl ($url); + $url = Minz_Url::checkUrl ($url); return $url; } diff --git a/lib/minz/Session.php b/lib/minz/Session.php index f9c9c6754..878caa556 100755 --- a/lib/minz/Session.php +++ b/lib/minz/Session.php @@ -4,7 +4,7 @@ * La classe Session gère la session utilisateur * C'est un singleton */ -class Session { +class Minz_Session { /** * $session stocke les variables de session */ @@ -15,7 +15,7 @@ class Session { */ public static function init () { // démarre la session - session_name (md5 (Configuration::selApplication ())); + session_name (md5 (Minz_Configuration::selApplication ())); session_start (); if (isset ($_SESSION)) { @@ -55,7 +55,7 @@ class Session { if($p == 'language') { // reset pour remettre à jour le fichier de langue à utiliser - Translate::reset (); + Minz_Translate::reset (); } } } diff --git a/lib/minz/Translate.php b/lib/minz/Translate.php index e8cbe4852..e14f783f7 100644 --- a/lib/minz/Translate.php +++ b/lib/minz/Translate.php @@ -8,7 +8,7 @@ * La classe Translate se charge de la traduction * Utilise les fichiers du répertoire /app/i18n/ */ -class Translate { +class Minz_Translate { /** * $language est la langue à afficher */ @@ -25,8 +25,8 @@ class Translate { * l'enregistre dans $translates */ public static function init () { - $l = Configuration::language (); - self::$language = Session::param ('language', $l); + $l = Minz_Configuration::language (); + self::$language = Minz_Session::param ('language', $l); $l_path = APP_PATH . '/i18n/' . self::$language . '.php'; diff --git a/lib/minz/Url.php b/lib/minz/Url.php index ce051ebd9..30f7f6231 100755 --- a/lib/minz/Url.php +++ b/lib/minz/Url.php @@ -3,7 +3,7 @@ /** * La classe Url permet de gérer les URL à travers MINZ */ -class Url { +class Minz_Url { /** * Affiche une Url formatée selon que l'on utilise l'url_rewriting ou non * si oui, on cherche dans la table de routage la correspondance pour formater @@ -29,16 +29,16 @@ class Url { } else { $protocol = 'http:'; } - $url_string = $protocol . '//' . Request::getDomainName () . Request::getBaseUrl (); + $url_string = $protocol . '//' . Minz_Request::getDomainName () . Minz_Request::getBaseUrl (); } else { $url_string = '.'; } if (is_array ($url)) { - $router = new Router (); + $router = new Minz_Router (); - if (Configuration::useUrlRewriting ()) { + if (Minz_Configuration::useUrlRewriting ()) { $url_string .= $router->printUriRewrited ($url); } else { $url_string .= self::printUri ($url, $encodage); @@ -67,13 +67,13 @@ class Url { } if (isset ($url['c']) - && $url['c'] != Request::defaultControllerName ()) { + && $url['c'] != Minz_Request::defaultControllerName ()) { $uri .= $separator . 'c=' . $url['c']; $separator = $and; } if (isset ($url['a']) - && $url['a'] != Request::defaultActionName ()) { + && $url['a'] != Minz_Request::defaultActionName ()) { $uri .= $separator . 'a=' . $url['a']; $separator = $and; } @@ -98,10 +98,10 @@ class Url { if (is_array ($url)) { if (!isset ($url['c'])) { - $url_checked['c'] = Request::defaultControllerName (); + $url_checked['c'] = Minz_Request::defaultControllerName (); } if (!isset ($url['a'])) { - $url_checked['a'] = Request::defaultActionName (); + $url_checked['a'] = Minz_Request::defaultActionName (); } if (!isset ($url['params'])) { $url_checked['params'] = array (); @@ -125,5 +125,5 @@ function _url ($controller, $action) { $params[$args[$i]] = $args[$i + 1]; } - return Url::display (array ('c' => $controller, 'a' => $action, 'params' => $params)); + return Minz_Url::display (array ('c' => $controller, 'a' => $action, 'params' => $params)); } diff --git a/lib/minz/View.php b/lib/minz/View.php index 12202542f..c8d0aefed 100755 --- a/lib/minz/View.php +++ b/lib/minz/View.php @@ -7,7 +7,7 @@ /** * La classe View représente la vue de l'application */ -class View { +class Minz_View { const VIEWS_PATH_NAME = '/views'; const LAYOUT_PATH_NAME = '/layout'; const LAYOUT_FILENAME = '/layout.phtml'; @@ -28,8 +28,8 @@ class View { public function __construct () { $this->view_filename = APP_PATH . self::VIEWS_PATH_NAME . '/' - . Request::controllerName () . '/' - . Request::actionName () . '.phtml'; + . Minz_Request::controllerName () . '/' + . Minz_Request::actionName () . '.phtml'; if (file_exists (APP_PATH . self::LAYOUT_PATH_NAME @@ -37,7 +37,7 @@ class View { $this->use_layout = true; } - self::$title = Configuration::title (); + self::$title = Minz_Configuration::title (); } /** @@ -232,7 +232,7 @@ class View { self::$params[$key] = $value; } public function attributeParams () { - foreach (View::$params as $key => $value) { + foreach (Minz_View::$params as $key => $value) { $this->$key = $value; } } diff --git a/lib/minz/dao/Model_array.php b/lib/minz/dao/Model_array.php deleted file mode 100755 index 0b9ccf071..000000000 --- a/lib/minz/dao/Model_array.php +++ /dev/null @@ -1,122 +0,0 @@ - -*/ - -/** - * La classe Model_array représente le modèle interragissant avec les fichiers de type texte gérant des tableaux php - */ -class Model_array extends Model_txt { - /** - * $array Le tableau php contenu dans le fichier $nameFile - */ - protected $array = array (); - - /** - * Ouvre le fichier indiqué, charge le tableau dans $array et le $nameFile - * @param $nameFile le nom du fichier à ouvrir contenant un tableau - * Remarque : $array sera obligatoirement un tableau - */ - public function __construct ($nameFile) { - parent::__construct ($nameFile); - - if (!$this->getLock ('read')) { - throw new PermissionDeniedException ($this->filename); - } else { - $this->array = include ($this->filename); - $this->releaseLock (); - - if (!is_array ($this->array)) { - $this->array = array (); - } - - $this->array = $this->decodeArray ($this->array); - } - } - - /** - * Écrit un tableau dans le fichier $nameFile - * @param $array le tableau php à enregistrer - **/ - public function writeFile ($array) { - if (!$this->getLock ('write')) { - throw new PermissionDeniedException ($this->namefile); - } else { - $this->erase (); - - $this->writeLine ('writeLine ('return ', false); - $this->writeArray ($array); - $this->writeLine (';'); - - $this->releaseLock (); - } - } - - private function writeArray ($array, $profondeur = 0) { - $tab = ''; - for ($i = 0; $i < $profondeur; $i++) { - $tab .= "\t"; - } - $this->writeLine ('array ('); - - foreach ($array as $key => $value) { - if (is_int ($key)) { - $this->writeLine ($tab . "\t" . $key . ' => ', false); - } else { - $this->writeLine ($tab . "\t" . '\'' . $key . '\'' . ' => ', false); - } - - if (is_array ($value)) { - $this->writeArray ($value, $profondeur + 1); - $this->writeLine (','); - } else { - if (is_numeric ($value)) { - $this->writeLine ($value . ','); - } else { - $this->writeLine ('\'' . addslashes ($value) . '\','); - } - } - } - - $this->writeLine ($tab . ')', false); - } - - private function decodeArray ($array) { - $new_array = array (); - - foreach ($array as $key => $value) { - if (is_array ($value)) { - $new_array[$key] = $this->decodeArray ($value); - } else { - $new_array[$key] = stripslashes ($value); - } - } - - return $new_array; - } - - private function getLock ($type) { - if ($type == 'write') { - $lock = LOCK_EX; - } else { - $lock = LOCK_SH; - } - - $count = 1; - while (!flock ($this->file, $lock) && $count <= 50) { - $count++; - } - - if ($count >= 50) { - return false; - } else { - return true; - } - } - - private function releaseLock () { - flock ($this->file, LOCK_UN); - } -} diff --git a/lib/minz/dao/Model_pdo.php b/lib/minz/dao/Model_pdo.php deleted file mode 100755 index a93291fc8..000000000 --- a/lib/minz/dao/Model_pdo.php +++ /dev/null @@ -1,111 +0,0 @@ - -*/ - -/** - * La classe Model_sql représente le modèle interragissant avec les bases de données - * Seul la connexion MySQL est prise en charge pour le moment - */ -class Model_pdo { - - /** - * Partage la connexion à la base de données entre toutes les instances. - */ - public static $useSharedBd = true; - private static $sharedBd = null; - private static $sharedPrefix; - - /** - * $bd variable représentant la base de données - */ - protected $bd; - - protected $prefix; - - /** - * Créé la connexion à la base de données à l'aide des variables - * HOST, BASE, USER et PASS définies dans le fichier de configuration - */ - public function __construct () { - if (self::$useSharedBd && self::$sharedBd != null) { - $this->bd = self::$sharedBd; - $this->prefix = self::$sharedPrefix; - return; - } - - $db = Configuration::dataBase (); - $driver_options = null; - - try { - $type = $db['type']; - if($type == 'mysql') { - $string = $type - . ':host=' . $db['host'] - . ';dbname=' . $db['base'] - . ';charset=utf8'; - $driver_options = array( - PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8' - ); - } elseif($type == 'sqlite') { - $string = $type . ':/' . DATA_PATH . $db['base'] . '.sqlite'; //TODO: DEBUG UTF-8 http://www.siteduzero.com/forum/sujet/sqlite-connexion-utf-8-18797 - } - - $this->bd = new FreshPDO ( - $string, - $db['user'], - $db['password'], - $driver_options - ); - self::$sharedBd = $this->bd; - - $userPrefix = Configuration::currentUser (); - $this->prefix = $db['prefix'] . (empty($userPrefix) ? '' : ($userPrefix . '_')); - self::$sharedPrefix = $this->prefix; - } catch (Exception $e) { - throw new PDOConnectionException ( - $string, - $db['user'], MinzException::ERROR - ); - } - } - - public function beginTransaction() { - $this->bd->beginTransaction(); - } - public function commit() { - $this->bd->commit(); - } - public function rollBack() { - $this->bd->rollBack(); - } - - public function size() { - $db = Configuration::dataBase (); - $sql = 'SELECT SUM(data_length + index_length) FROM information_schema.TABLES WHERE table_schema = ?'; - $stm = $this->bd->prepare ($sql); - $values = array ($db['base']); - $stm->execute ($values); - $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); - return $res[0]; - } -} - -class FreshPDO extends PDO { - private static function check($statement) { - if (preg_match('/^(?:UPDATE|INSERT|DELETE)/i', $statement)) { - invalidateHttpCache(); - } - } - - public function prepare ($statement, $driver_options = array()) { - FreshPDO::check($statement); - return parent::prepare($statement, $driver_options); - } - - public function exec ($statement) { - FreshPDO::check($statement); - return parent::exec($statement); - } -} diff --git a/lib/minz/dao/Model_txt.php b/lib/minz/dao/Model_txt.php deleted file mode 100755 index aed653068..000000000 --- a/lib/minz/dao/Model_txt.php +++ /dev/null @@ -1,84 +0,0 @@ - -*/ - -/** - * La classe Model_txt représente le modèle interragissant avec les fichiers de type texte - */ -class Model_txt { - /** - * $file représente le fichier à ouvrir - */ - protected $file; - - /** - * $filename est le nom du fichier - */ - protected $filename; - - /** - * Ouvre un fichier dans $file - * @param $nameFile nom du fichier à ouvrir - * @param $mode mode d'ouverture du fichier ('a+' par défaut) - * @exception FileNotExistException si le fichier n'existe pas - * > ou ne peux pas être ouvert - */ - public function __construct ($nameFile, $mode = 'a+') { - $this->filename = $nameFile; - if (!file_exists($this->filename)) { - throw new FileNotExistException ( - $this->filename, - MinzException::WARNING - ); - } - - $this->file = @fopen ($this->filename, $mode); - - if (!$this->file) { - throw new PermissionDeniedException ( - $this->filename, - MinzException::WARNING - ); - } - } - - /** - * Lit une ligne de $file - * @return une ligne du fichier - */ - public function readLine () { - return fgets ($this->file); - } - - /** - * Écrit une ligne dans $file - * @param $line la ligne à écrire - */ - public function writeLine ($line, $newLine = true) { - $char = ''; - if ($newLine) { - $char = "\n"; - } - - fwrite ($this->file, $line . $char); - } - - /** - * Efface le fichier $file - * @return true en cas de succès, false sinon - */ - public function erase () { - return ftruncate ($this->file, 0); - } - - /** - * Ferme $file - */ - public function __destruct () { - if (isset ($this->file)) { - fclose ($this->file); - } - } -} diff --git a/lib/minz/exceptions/MinzException.php b/lib/minz/exceptions/MinzException.php deleted file mode 100644 index 4568c4da8..000000000 --- a/lib/minz/exceptions/MinzException.php +++ /dev/null @@ -1,94 +0,0 @@ -route = $route; - - $message = 'Route `' . $route . '` not found'; - - parent::__construct ($message, $code); - } - - public function route () { - return $this->route; - } -} -class PDOConnectionException extends MinzException { - public function __construct ($string_connection, $user, $code = self::ERROR) { - $message = 'Access to database is denied for `' . $user . '`' - . ' (`' . $string_connection . '`)'; - - parent::__construct ($message, $code); - } -} -class CurrentPagePaginationException extends MinzException { - public function __construct ($page) { - $message = 'Page number `' . $page . '` doesn\'t exist'; - - parent::__construct ($message, self::ERROR); - } -} diff --git a/public/index.php b/public/index.php index 3a2bcd3ae..829e418f9 100755 --- a/public/index.php +++ b/public/index.php @@ -37,18 +37,10 @@ if (file_exists ('install.php')) { } } - set_include_path (get_include_path () - . PATH_SEPARATOR - . LIB_PATH - . PATH_SEPARATOR - . LIB_PATH . '/minz' - . PATH_SEPARATOR - . APP_PATH); - - require (APP_PATH . '/App_FrontController.php'); + require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader try { - $front_controller = new App_FrontController (); + $front_controller = new FreshRSS(); $front_controller->init (); $front_controller->run (); } catch (Exception $e) { -- cgit v1.2.3 From b48b7939d78ffbd35a7efca792e2cb9897e8f160 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 2 Jan 2014 19:08:21 +0100 Subject: JavaScript : Bug actualize quand il n'y a aucun flux + un peu de JSLint. --- app/views/javascript/actualize.phtml | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'app/views/javascript') diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index 69689133c..1f6072c29 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -1,37 +1,41 @@ -var feeds = new Array (); +"use strict"; +var feeds = []; feeds as $feed) { ?> -feeds.push (" 'feed', 'a' => 'actualize', 'params' => array ('id' => $feed->id (), 'ajax' => '1')), 'php'); ?>"); +feeds.push(" 'feed', 'a' => 'actualize', 'params' => array ('id' => $feed->id (), 'ajax' => '1')), 'php'); ?>"); -function initProgressBar (init) { +function initProgressBar(init) { if (init) { - $("body").after ("\
      \ + $("body").after("\
      \ 0 / " + feeds.length + "
      \ \
      "); } else { - window.location.reload (); + window.location.reload(); } } -function updateProgressBar (i) { +function updateProgressBar(i) { $("#actualizeProgressBar").val(i); - $("#actualizeProgress .progress").html (i + " / " + feeds.length); + $("#actualizeProgress .progress").html(i + " / " + feeds.length); } -function updateFeeds () { - initProgressBar (true); +function updateFeeds() { + if (feeds.length === 0) { + return; + } + initProgressBar(true); var i = 0; for (var f in feeds) { - $.ajax ({ + $.ajax({ type: 'POST', url: feeds[f], - }).done (function (data) { + }).done(function (data) { i++; - updateProgressBar (i); + updateProgressBar(i); - if (i == feeds.length) { - initProgressBar (false); + if (i === feeds.length) { + initProgressBar(false); } }); } -- cgit v1.2.3 From 3d876091e1268e3ccd5036449a4deb5134936206 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 9 Jan 2014 23:17:35 +0100 Subject: Nouveau rafraîchissement automatique du nombre d'articles non lus + session Persona MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Devrait aussi résoudre https://github.com/marienfressinaud/FreshRSS/issues/358 À tester --- CHANGELOG | 2 + app/Controllers/javascriptController.php | 8 ++- app/views/javascript/nbUnreadsPerFeed.phtml | 8 +++ p/i/index.php | 1 + p/scripts/main.js | 96 +++++++++++++++++------------ 5 files changed, 74 insertions(+), 41 deletions(-) create mode 100644 app/views/javascript/nbUnreadsPerFeed.phtml (limited to 'app/views/javascript') diff --git a/CHANGELOG b/CHANGELOG index 45936ac03..fe856fe4a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,8 @@ (voir réorganisation ci-dessous) * Pour les versions suivantes, juste garder “./data/config.php” et “./data/*_user.php”, éventuellement “./data/persona/*” +* Rafraîchissement automatique du nombre d’articles non lus toutes les minutes (utilise le cache HTTP à bon escient) + * Permet aussi de conserver la session valide, surtout dans le cas de Persona * Importation OPML instantanée et plus tolérante * Nouvelle gestion des favicons avec téléchargement en parallèle * Nouvelles options diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index e7e25f656..2d0ff4984 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -3,11 +3,17 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { public function firstAction () { $this->view->_useLayout (false); - header('Content-type: text/javascript'); } public function actualizeAction () { + header('Content-Type: text/javascript; charset=UTF-8'); $feedDAO = new FreshRSS_FeedDAO (); $this->view->feeds = $feedDAO->listFeeds (); } + + public function nbUnreadsPerFeedAction() { + header('Content-Type: application/json; charset=UTF-8'); + $catDAO = new FreshRSS_CategoryDAO(); + $this->view->categories = $catDAO->listCategories(true, false); + } } diff --git a/app/views/javascript/nbUnreadsPerFeed.phtml b/app/views/javascript/nbUnreadsPerFeed.phtml new file mode 100644 index 000000000..68f98ce9e --- /dev/null +++ b/app/views/javascript/nbUnreadsPerFeed.phtml @@ -0,0 +1,8 @@ +categories as $cat) { + foreach ($cat->feeds() as $feed) { + $result[$feed->id()] = $feed->nbNotRead(); + } +} +echo json_encode($result); diff --git a/p/i/index.php b/p/i/index.php index 3dcf659c9..187bbabe8 100755 --- a/p/i/index.php +++ b/p/i/index.php @@ -26,6 +26,7 @@ if (file_exists ('install.php')) { session_cache_limiter(''); Minz_Session::init('FreshRSS'); + Minz_Session::_param('keepAlive', 1); //For Persona if (!file_exists(DATA_PATH . '/no-cache.txt')) { require(LIB_PATH . '/http-conditional.php'); diff --git a/p/scripts/main.js b/p/scripts/main.js index 8646d9b72..24fdfd3f3 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -25,6 +25,46 @@ function incLabel(p, inc) { return i > 0 ? ' (' + i + ')' : ''; } +function incUnreadsFeed(article, feed_id, nb) { + //Update unread: feed + var elem = $('#' + feed_id + '>.feed').get(0), + feed_unreads = elem ? (parseInt(elem.getAttribute('data-unread'), 10) || 0) : 0, + feed_priority = elem ? (parseInt(elem.getAttribute('data-priority'), 10) || 0) : 0; + if (elem) { + elem.setAttribute('data-unread', Math.max(0, feed_unreads + nb)); + } + + //Update unread: category + elem = $('#' + feed_id).parent().prevAll('.category').children(':first').get(0); + feed_unreads = elem ? (parseInt(elem.getAttribute('data-unread'), 10) || 0) : 0; + if (elem) { + elem.setAttribute('data-unread', Math.max(0, feed_unreads + nb)); + } + + //Update unread: all + if (feed_priority > 0) { + elem = $('#aside_flux .all').children(':first').get(0); + if (elem) { + feed_unreads = elem ? (parseInt(elem.getAttribute('data-unread'), 10) || 0) : 0; + elem.setAttribute('data-unread', Math.max(0, feed_unreads + nb)); + } + } + + //Update unread: favourites + if (article && article.closest('div').hasClass('favorite')) { + elem = $('#aside_flux .favorites').children(':first').get(0); + if (elem) { + feed_unreads = elem ? (parseInt(elem.getAttribute('data-unread'), 10) || 0) : 0; + elem.setAttribute('data-unread', Math.max(0, feed_unreads + nb)); + } + } + + //Update unread: title + document.title = document.title.replace(/((?: \(\d+\))?)( · .*?)((?: \(\d+\))?)$/, function (m, p1, p2, p3) { + return incLabel(p1, nb) + p2 + incLabel(p3, feed_priority > 0 ? nb : 0); + }); +} + function mark_read(active, only_not_read) { if (active[0] === undefined || (only_not_read === true && !active.hasClass("not_read"))) { return false; @@ -51,45 +91,9 @@ function mark_read(active, only_not_read) { } $r.find('.icon').replaceWith(data.icon); - //Update unread: feed var feed_url = active.find(".website>a").attr("href"), - feed_id = feed_url.substr(feed_url.lastIndexOf('f_')), - elem = $('#' + feed_id + ' .feed').get(0), - feed_unread = elem ? (parseInt(elem.getAttribute('data-unread'), 10) || 0) : 0, - feed_priority = elem ? (parseInt(elem.getAttribute('data-priority'), 10) || 0) : 0; - if (elem) { - elem.setAttribute('data-unread', Math.max(0, feed_unread + inc)); - } - - //Update unread: category - elem = $('#' + feed_id).parent().prevAll('.category').children(':first').get(0); - feed_unread = elem ? (parseInt(elem.getAttribute('data-unread'), 10) || 0) : 0; - if (elem) { - elem.setAttribute('data-unread', Math.max(0, feed_unread + inc)); - } - - //Update unread: all - if (feed_priority > 0) { - elem = $('#aside_flux .all').children(':first').get(0); - if (elem) { - feed_unread = elem ? (parseInt(elem.getAttribute('data-unread'), 10) || 0) : 0; - elem.setAttribute('data-unread', Math.max(0, feed_unread + inc)); - } - } - - //Update unread: favourites - if (active.closest('div').hasClass('favorite')) { - elem = $('#aside_flux .favorites').children(':first').get(0); - if (elem) { - feed_unread = elem ? (parseInt(elem.getAttribute('data-unread'), 10) || 0) : 0; - elem.setAttribute('data-unread', Math.max(0, feed_unread + inc)); - } - } - - //Update unread: title - document.title = document.title.replace(/((?: \(\d+\))?)( · .*?)((?: \(\d+\))?)$/, function (m, p1, p2, p3) { - return incLabel(p1, inc) + p2 + incLabel(p3, feed_priority > 0 ? inc : 0); - }); + feed_id = feed_url.substr(feed_url.lastIndexOf('f_')); + incUnreadsFeed(active, feed_id, inc); }); } @@ -128,8 +132,8 @@ function mark_favorite(active) { if (active.closest('div').hasClass('not_read')) { var elem = $('#aside_flux .favorites').children(':first').get(0), - feed_unread = elem ? (parseInt(elem.getAttribute('data-unread'), 10) || 0) : 0; - elem.setAttribute('data-unread', Math.max(0, feed_unread + inc)); + feed_unreads = elem ? (parseInt(elem.getAttribute('data-unread'), 10) || 0) : 0; + elem.setAttribute('data-unread', Math.max(0, feed_unreads + inc)); } }); } @@ -514,6 +518,17 @@ function init_notifications() { } } +function refreshUnreads() { + $.getJSON('./?c=javascript&a=nbUnreadsPerFeed').done(function (data) { + $.each(data, function(feed_id, nbUnreads) { + feed_id = 'f_' + feed_id; + var elem = $('#' + feed_id + '>.feed').get(0), + feed_unreads = elem ? (parseInt(elem.getAttribute('data-unread'), 10) || 0) : 0; + incUnreadsFeed(null, feed_id, nbUnreads - feed_unreads); + }); + }); +} + // var url_load_more = "", load_more = false, @@ -685,6 +700,7 @@ function init_all() { } init_confirm_action(); init_print_action(); + window.setInterval(refreshUnreads, 60000); if (window.console) { console.log('FreshRSS init done.'); } -- cgit v1.2.3 From eb50ab3b61ee2280dac2696598a58803e246fe22 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 11 Jan 2014 16:48:10 +0100 Subject: Mot de passe + nonce serveur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Début de https://github.com/marienfressinaud/FreshRSS/issues/104 --- README.md | 7 ++----- app/Controllers/javascriptController.php | 27 +++++++++++++++++++++++++++ app/Models/Configuration.php | 4 ++++ app/views/javascript/nonce.phtml | 2 ++ 4 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 app/views/javascript/nonce.phtml (limited to 'app/views/javascript') diff --git a/README.md b/README.md index 96e25f4df..4100a8638 100644 --- a/README.md +++ b/README.md @@ -74,17 +74,14 @@ mysqldump -u utilisateur -p --databases freshrss > freshrss.sql ``` - ---- - # Bibliothèques incluses -* [SimplePie](https://github.com/simplepie/simplepie) +* [SimplePie](http://simplepie.org/) * [MINZ](https://github.com/marienfressinaud/MINZ) * [php-http-304](http://alexandre.alapetite.fr/doc-alex/php-http-304/) * [jQuery](http://jquery.com/) * [keyboard_shortcuts](http://www.openjs.com/scripts/events/keyboard_shortcuts/) -## Uniquement dans certaines configurations +## Uniquement pour certaines options * [bcrypt.js](https://github.com/dcodeIO/bcrypt.js) * [phpQuery](http://code.google.com/p/phpquery/) * [Lazy Load](http://www.appelsiini.net/projects/lazyload) diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index 2d0ff4984..e29f439d8 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -16,4 +16,31 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { $catDAO = new FreshRSS_CategoryDAO(); $this->view->categories = $catDAO->listCategories(true, false); } + + // For Web-form login + public function nonceAction() { + header('Content-Type: application/json; charset=UTF-8'); + header('Last-Modified: ' . gmdate('D, d M Y H:i:s \G\M\T')); + header('Expires: 0'); + header('Cache-Control: private, no-cache, no-store, must-revalidate'); + header('Pragma: no-cache'); + + $user = isset($_GET['user']) ? $_GET['user'] : ''; + if (ctype_alnum($user)) { + try { + $conf = new FreshRSS_Configuration($user); + $hash = $conf->passwordHash; //CRYPT_BLOWFISH - Blowfish hashing with a salt as follows: "$2a$", "$2x$" or "$2y$", a two digit cost parameter, "$", and 22 characters from the alphabet "./0-9A-Za-z". + if (strlen($hash) >= 60) { + $this->view->salt1 = substr($hash, 0, 29); + $this->view->nonce = sha1(Minz_Configuration::salt() . uniqid(mt_rand(), true)); + Minz_Session::_param ('nonce', $this->view->nonce); + return; //Success + } + } catch (Minz_Exception $me) { + Minz_Log::record ('Login failure: ' . $me->getMessage(), Minz_Log::WARNING); + } + } + $this->view->nonce = ''; //Failure + $this->view->salt1 = ''; + } } diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index c29e74603..8f394737a 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -9,6 +9,7 @@ class FreshRSS_Configuration { 'keep_history_default' => 0, 'mail_login' => '', 'token' => '', + 'passwordHash' => '', //CRYPT_BLOWFISH 'posts_per_page' => 20, 'view_mode' => 'normal', 'default_view' => 'not_read', @@ -162,6 +163,9 @@ class FreshRSS_Configuration { } } } + public function _passwordHash ($value) { + $this->data['passwordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; + } public function _mail_login ($value) { $value = filter_var($value, FILTER_VALIDATE_EMAIL); if ($value) { diff --git a/app/views/javascript/nonce.phtml b/app/views/javascript/nonce.phtml new file mode 100644 index 000000000..4ac46c8fc --- /dev/null +++ b/app/views/javascript/nonce.phtml @@ -0,0 +1,2 @@ + $this->salt1, 'nonce' => $this->nonce)); -- cgit v1.2.3 From ed61f9346f4946e27a894d6901a5c64c9f6677cc Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Wed, 5 Feb 2014 00:18:39 -0500 Subject: Changement du rafraichissement manuel des flux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Au lieu de lancer un rafraichissement sur l'ensemble des flux, le rafraichissement se fait sur 10 flux simultanément. Quand un flux est rafraichit, il lance le rafraichissement d'un autre flux jusqu'à épuisement des flux disponibles. --- app/views/javascript/actualize.phtml | 45 ++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 17 deletions(-) (limited to 'app/views/javascript') diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index 1f6072c29..272d1b419 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -3,12 +3,14 @@ var feeds = []; feeds as $feed) { ?> feeds.push(" 'feed', 'a' => 'actualize', 'params' => array ('id' => $feed->id (), 'ajax' => '1')), 'php'); ?>"); +var feed_count = feeds.length; +var feed_processed = 0; function initProgressBar(init) { if (init) { $("body").after("\
      \ - 0 / " + feeds.length + "
      \ - \ + 0 / " + feed_count + "
      \ + \
      "); } else { window.location.reload(); @@ -16,27 +18,36 @@ function initProgressBar(init) { } function updateProgressBar(i) { $("#actualizeProgressBar").val(i); - $("#actualizeProgress .progress").html(i + " / " + feeds.length); + $("#actualizeProgress .progress").html(i + " / " + feed_count); } function updateFeeds() { - if (feeds.length === 0) { + if (feed_count === 0) { return; } initProgressBar(true); - var i = 0; - for (var f in feeds) { - $.ajax({ - type: 'POST', - url: feeds[f], - }).done(function (data) { - i++; - updateProgressBar(i); - - if (i === feeds.length) { - initProgressBar(false); - } - }); + for (var i = 0; i < 10; i++) { + updateFeed(); } } + +function updateFeed() { + if (feeds.length === 0) { + return; + } + var feed = feeds.pop(); + $.ajax({ + type: 'POST', + url: feed, + }).done(function (data) { + feed_processed++; + updateProgressBar(feed_processed); + + if (feed_processed === feed_count) { + initProgressBar(false); + } else { + updateFeed(); + } + }); +} \ No newline at end of file -- cgit v1.2.3 From 7d9a813ed3465ef7175a05355e1ccaef878ab667 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 6 Feb 2014 18:48:49 +0100 Subject: Petite simplification mise à jour JavaScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/marienfressinaud/FreshRSS/pull/414 --- app/views/javascript/actualize.phtml | 19 ++++++++++--------- p/scripts/main.js | 6 ++---- 2 files changed, 12 insertions(+), 13 deletions(-) (limited to 'app/views/javascript') diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index 272d1b419..58c3b7c8f 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -1,10 +1,11 @@ "use strict"; -var feeds = []; -feeds as $feed) { ?> -feeds.push(" 'feed', 'a' => 'actualize', 'params' => array ('id' => $feed->id (), 'ajax' => '1')), 'php'); ?>"); - -var feed_count = feeds.length; -var feed_processed = 0; +var feeds = [feeds as $feed) { + echo "'", Minz_Url::display(array('c' => 'feed', 'a' => 'actualize', 'params' => array('id' => $feed->id(), 'ajax' => '1')), 'php'), "',\n"; + } + ?>], + feed_processed = 0, + feed_count = feeds.length; function initProgressBar(init) { if (init) { @@ -33,10 +34,10 @@ function updateFeeds() { } function updateFeed() { - if (feeds.length === 0) { + var feed = feeds.pop(); + if (feed == undefined) { return; } - var feed = feeds.pop(); $.ajax({ type: 'POST', url: feed, @@ -50,4 +51,4 @@ function updateFeed() { updateFeed(); } }); -} \ No newline at end of file +} diff --git a/p/scripts/main.js b/p/scripts/main.js index 53a365076..8cda62d26 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -648,10 +648,8 @@ function init_actualize() { return false; }); - if(auto_actualize_feeds) { - $.getScript('./?c=javascript&a=actualize').done(function () { - updateFeeds(); - }); + if (auto_actualize_feeds) { + $("#actualize").click(); } } -- cgit v1.2.3 From 178af19fb0e7c13015e991593feea6a5f4aafcc0 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 13 Feb 2014 21:01:12 +0100 Subject: Add possibility to open notification in JavaScript + new message Notifications can be opened directly in JavaScript Class .notification is now id #notification New message when there is no feed to refresh See 06abbd02c2d10934155b2464f73d8ecdb2a68de1 (comments) --- app/Controllers/feedController.php | 4 ++-- app/i18n/en.php | 1 + app/i18n/fr.php | 1 + app/layout/layout.phtml | 11 ++++++--- app/views/javascript/actualize.phtml | 1 + p/scripts/main.js | 46 +++++++++++++++++++++++++++++------- p/themes/Dark/freshrss.css | 15 +++++++----- p/themes/Flat/freshrss.css | 15 +++++++----- p/themes/Origine/freshrss.css | 11 +++++---- 9 files changed, 75 insertions(+), 30 deletions(-) (limited to 'app/views/javascript') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index d98c77558..264607216 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -283,8 +283,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } else { // aucun flux n'a été mis à jour, oups $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('no_feed_actualized') + 'type' => 'good', + 'content' => Minz_Translate::t ('no_feed_to_refresh') ); } diff --git a/app/i18n/en.php b/app/i18n/en.php index af051673d..369853610 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -248,6 +248,7 @@ return array ( 'rss_feeds_of' => 'RSS feed of %s', 'refresh' => 'Refresh', + 'no_feed_to_refresh' => 'There is no feed to refresh…', 'today' => 'Today', 'yesterday' => 'Yesterday', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 5dc184aa3..275c3b1d8 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -248,6 +248,7 @@ return array ( 'rss_feeds_of' => 'Flux RSS de %s', 'refresh' => 'Actualisation', + 'no_feed_to_refresh' => 'Il n’y a aucun flux à actualiser…', 'today' => 'Aujourd’hui', 'yesterday' => 'Hier', diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index d6a1737ee..1501df3c3 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -36,13 +36,18 @@
      notification)) { + $msg = $this->notification['content']; + $status = $this->notification['type']; + invalidateHttpCache(); + } ?> -
      - notification['content']; ?> +
      +
      - diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index 58c3b7c8f..a2b076ea8 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -24,6 +24,7 @@ function updateProgressBar(i) { function updateFeeds() { if (feed_count === 0) { + openNotification("", "good"); return; } initProgressBar(true); diff --git a/p/scripts/main.js b/p/scripts/main.js index e94df2a39..88ef670cd 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -665,23 +665,51 @@ function init_actualize() { } } + +// +var notification = null, + notification_interval = null, + notification_working = false; + +function openNotification(msg, status) { + if (notification_working === true) { + return false; + } + + notification_working = true; + + notification.removeClass(); + notification.addClass(status); + notification.find(".msg").html(msg); + notification.fadeIn(300); + + notification_interval = window.setInterval(closeNotification, 4000); +} + function closeNotification() { - $(".notification").fadeOut(600, function () { - $(".notification").remove(); + notification.fadeOut(600, function() { + notification.removeClass(); + notification.addClass('closed'); + + window.clearInterval(notification_interval); + notification_working = false; }); } function init_notifications() { - var notif = $(".notification"); - if (notif.length > 0) { - window.setInterval(closeNotification, 4000); + notification = $("#notification"); - notif.find("a.close").click(function () { - closeNotification(); - return false; - }); + notification.find("a.close").click(function () { + closeNotification(); + return false; + }); + + if (notification.find(".msg").html().length > 0) { + notification_working = true; + notification_interval = window.setInterval(closeNotification, 4000); } } +// function refreshUnreads() { $.getJSON('./?c=javascript&a=nbUnreadsPerFeed').done(function (data) { diff --git a/p/themes/Dark/freshrss.css b/p/themes/Dark/freshrss.css index e54a0eadd..380dee877 100644 --- a/p/themes/Dark/freshrss.css +++ b/p/themes/Dark/freshrss.css @@ -558,7 +558,7 @@ } /*** NOTIFICATION ***/ -.notification { +#notification { position: absolute; top: 10px; left: 25%; right: 25%; @@ -573,13 +573,16 @@ font-weight: bold; z-index: 10; } - .notification.good { + #notification.closed { + display: none; + } + #notification.good { border:1px solid #f4f899; } - .notification.bad { + #notification.bad { border:1px solid #f4a899; } - .notification a.close { + #notification a.close { display: inline-block; width: 16px; height: 16px; @@ -590,10 +593,10 @@ border-radius: 50px; line-height: 16px; } - .notification.good a.close{ + #notification.good a.close{ border:1px solid #f4f899; } - .notification.bad a.close{ + #notification.bad a.close{ border:1px solid #f4a899; } diff --git a/p/themes/Flat/freshrss.css b/p/themes/Flat/freshrss.css index 19f5967ea..edd67e17c 100644 --- a/p/themes/Flat/freshrss.css +++ b/p/themes/Flat/freshrss.css @@ -561,7 +561,7 @@ body { } /*** NOTIFICATION ***/ -.notification { +#notification { position: absolute; top: 10px; left: 25%; right: 25%; @@ -575,15 +575,18 @@ body { font-weight: bold; z-index: 10; } - .notification.good { + #notification.closed { + display: none; + } + #notification.good { background: #1abc9c; color: #fff; } - .notification.bad { + #notification.bad { background: #e74c3c; color: #fff; } - .notification a.close { + #notification a.close { display: inline-block; width: 16px; height: 16px; @@ -593,10 +596,10 @@ body { border-radius: 3px; line-height: 16px; } - .notification.good a.close { + #notification.good a.close { background: #1abc9c; } - .notification.bad a.close { + #notification.bad a.close { background: #e74c3c; } diff --git a/p/themes/Origine/freshrss.css b/p/themes/Origine/freshrss.css index 85a23140c..80fac05cd 100644 --- a/p/themes/Origine/freshrss.css +++ b/p/themes/Origine/freshrss.css @@ -569,7 +569,7 @@ } /*** NOTIFICATION ***/ -.notification { +#notification { position: absolute; top: 10px; left: 25%; right: 25%; @@ -584,13 +584,16 @@ font-weight: bold; z-index: 10; } - .notification.good { + #notification.closed { + display: none; + } + #notification.good { background: #f4f899; } - .notification.bad { + #notification.bad { background: #f4a899; } - .notification a.close { + #notification a.close { display: inline-block; width: 16px; height: 16px; -- cgit v1.2.3 From b77d9c60ac0cc6614ccc2711ab647d5e0a5037ed Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 13 Feb 2014 21:15:50 +0100 Subject: Use complete instead of done during feed refresh A request can fail: in this case, the progress bar is not updated by using "done". See #421 --- app/views/javascript/actualize.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/views/javascript') diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index a2b076ea8..3b12ad774 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -42,7 +42,7 @@ function updateFeed() { $.ajax({ type: 'POST', url: feed, - }).done(function (data) { + }).complete(function (data) { feed_processed++; updateProgressBar(feed_processed); -- cgit v1.2.3 From 4bdabbd39fd111c6c12d5953bd4bd6de2ae3903d Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 3 Jun 2014 23:41:19 +0200 Subject: Fix theme Origine2 It should be equivalent to Origine (modulo some improvements) See https://github.com/marienfressinaud/FreshRSS/issues/320 --- app/layout/layout.phtml | 2 +- app/views/javascript/actualize.phtml | 2 +- p/themes/Origine2/origine.css | 188 ++++++++++++++++++++++++++++++++--- p/themes/Origine2/template.css | 76 +++++++++----- p/themes/template/template.css | 76 +++++++++----- 5 files changed, 274 insertions(+), 70 deletions(-) (limited to 'app/views/javascript') diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index c22288adb..d2e1e4b3b 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -53,7 +53,7 @@ invalidateHttpCache(); } ?> -
      +
      diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index 3b12ad774..6a92e5642 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -9,7 +9,7 @@ var feeds = [\ + $("body").after("\
      \ 0 / " + feed_count + "
      \ \
      "); diff --git a/p/themes/Origine2/origine.css b/p/themes/Origine2/origine.css index ad97e11cf..31d1d4233 100644 --- a/p/themes/Origine2/origine.css +++ b/p/themes/Origine2/origine.css @@ -41,7 +41,7 @@ input, select, textarea { border: 1px solid #bbb; border-radius: 3px; color: #666; - vertical-align: top; + vertical-align: middle; box-shadow: 0 2px 2px #eee inset; } option { @@ -59,8 +59,7 @@ input:invalid, select:invalid { input:disabled, select:disabled { background: #eee; } -input:focus.extend { - width: 300px; +input.extend { transition: width 200ms linear; -moz-transition: width 200ms linear; -webkit-transition: width 200ms linear; @@ -68,6 +67,18 @@ input:focus.extend { -ms-transition: width 200ms linear; } +/*=== Tables */ +table { + border-collapse: collapse; + text-align: center; +} + +tr, th, td { + padding: 0.5em; + border: 1px solid #ddd; + font-weight: normal; +} + /*=== COMPONENTS */ /*===============*/ /*=== Forms */ @@ -87,6 +98,9 @@ input:focus.extend { min-height: 25px; padding: 5px 0; } +.form-group table { + margin: 10px 0 0 220px; +} /*=== Buttons */ .stick { @@ -249,13 +263,6 @@ a.btn { .nav-list a:hover { text-decoration: none; } -.nav-list .item.error a { - color: #BD362F; -} -.nav-list .item.active.error a { - color: #fff; - background: #BD362F; -} .nav-list .item.empty a { color: #f39c12; } @@ -263,6 +270,13 @@ a.btn { color: #fff; background: #f39c12; } +.nav-list .item.error a { + color: #BD362F; +} +.nav-list .item.active.error a { + color: #fff; + background: #BD362F; +} .nav-list .nav-header { padding: 0 10px; @@ -515,6 +529,7 @@ a.btn { line-height: 3em; font-size: 0.8em; text-align: left; + text-decoration: none; } .categories .feeds .feed:not([data-unread="0"]) { font-weight: bold; @@ -635,21 +650,38 @@ a.btn { background: #fff; } + .flux_header { border-top: 1px solid #ddd; + font-size: 0.8rem; cursor: pointer; } +.flux .website .favicon { + padding: 5px; +} +.flux .date { + color: #666; + font-size: 0.7rem; +} .flux:not(.current):hover .item.title { top: 1px; } +.flux .bottom { + font-size: 0.8rem; + text-align: center; +} + /*=== Content of feed articles */ .content { padding: 20px 10px; } +.content > h1.title > a { + color: #000; +} /*=== Notification and actualize notification */ -#notification { +.notification { padding: 0 0 0 5px; text-align: center; border: 1px solid #eeb; @@ -659,27 +691,33 @@ a.btn { font-size: 0.9em; line-height: 3em; z-index: 10; + vertical-align: middle; } -#notification.good { +.notification.good { background: #ffe; border: 1px solid #eeb; color: #c95; } -#notification.bad { +.notification.bad { background: #fdd; border: 1px solid #ecc; color: #844; } -#notification a.close { +.notification a.close { padding: 0 15px; + line-height: 3em; } -#notification.good a.close:hover { +.notification.good a.close:hover { background: #eeb; } -#notification.bad a.close:hover { +.notification.bad a.close:hover { background: #ecc; } +.notification#actualizeProgress { + line-height: 2em; +} + /*=== "Load more" part */ #bigMarkAsRead { text-align: center; @@ -701,6 +739,66 @@ a.btn { table-layout: fixed; } +/*=== 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 .box-category { + background: #fff; + border-radius: 5px; + text-align: left; + box-shadow: 0 0 3px #bbb; +} +#stream.global .category { + margin: 0; +} +#stream.global .btn { + width: auto; + height: 2em; + margin: 0; + padding: 0 10px; + background: #f6f6f6; + border: none; + border-bottom: 1px solid #ddd; + border-radius: 5px 5px 0 0; + line-height: 2em; + font-size: 1.2rem; +} +#stream.global .btn:not([data-unread="0"]) { + background: #0084CC; + color: #fff; + font-weight: bold; + text-shadow: none; +} +#stream.global .btn:first-child:not([data-unread="0"]):after { + top: 0; right: 5px; + border: 0; + background: none; + color: #fff; + font-weight: bold; + box-shadow: none; + text-shadow: none; +} +#stream.global .box-category .feeds { + max-height: 250px; +} +#stream.global .box-category .feeds .item { + padding: 2px 10px; + font-size: 0.9rem; +} + /*=== DIVERS */ /*===========*/ @@ -714,3 +812,61 @@ a.btn { .aside.aside_feed .nav-form .dropdown .dropdown-menu:after { right: 33px; } + + +/*=== MOBILE */ +/*===========*/ +@media(max-width: 840px) { + .aside { + box-shadow: 3px 0 3px #aaa; + 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 .toggle_aside, + #panel .close { + position: absolute; + display: block; + top: 0; right: 0; + width: 30px; + height: 30px; + line-height: 30px; + text-align: center; + background: #f6f6f6; + border-left: 1px solid #ddd; + border-bottom: 1px solid #ddd; + border-radius: 0 0 0 5px; + } + + .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 { + font-size: 1.1rem; + text-shadow: none; + } + + .flux_header .item.website .favicon { + padding: 12px; + } +} diff --git a/p/themes/Origine2/template.css b/p/themes/Origine2/template.css index c546a824d..d57f2cde3 100644 --- a/p/themes/Origine2/template.css +++ b/p/themes/Origine2/template.css @@ -169,8 +169,7 @@ a.btn { position: absolute; right: 0; background: #fff; - border: 1px solid #aaa; - overflow: auto; + border: 1px solid #aaa; } .dropdown-header { display: block; @@ -294,6 +293,10 @@ a.btn { } /*=== Aside main page (categories) */ +.categories { + list-style: none; + margin: 0; +} .category { display: block; overflow: hidden; @@ -359,10 +362,10 @@ a.btn { position: relative; } .flux .item { - font-size: 0.9em; line-height: 40px; white-space: nowrap; text-overflow: ellipsis; + overflow: hidden; } .flux .item.manage, .flux .item.link { @@ -391,14 +394,16 @@ a.btn { } .flux .item.date { width: 145px; - font-size: 0.7em; text-align: right; } -.flux .item:not(.title) > a { +.flux .item > a { display: block; } -.flux .flux_header .item, -.flux .bottom .item.date { +.flux .item:not(.title) > a { + display: block; + text-decoration: none; + white-space: nowrap; + text-overflow: ellipsis; overflow: hidden; } .flux .item.share > a { @@ -417,6 +422,15 @@ a.btn { 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 { @@ -428,7 +442,7 @@ a.btn { } /*=== Notification and actualize notification */ -#notification { +.notification { position: absolute; top: 1em; left: 25%; right: 25%; @@ -436,24 +450,21 @@ a.btn { background: #fff; border: 1px solid #aaa; } -#notification.closed { +.notification.closed { display: none; } -#notification a.close { +.notification a.close { position: absolute; right: 0; display: inline-block; } -.actualizeProgress { - position: fixed; - top: 1em; - left: 25%; right: 25%; - background: #fff; - border: 1px solid #aaa; -} -.actualizeProgress progress { +#actualizeProgress progress { max-width: 100%; + vertical-align: middle; +} +#actualizeProgress .progress { + vertical-align: middle; } /*=== Navigation menu (for articles) */ @@ -501,9 +512,10 @@ a.btn { /*=== Category boxes */ #stream.global .box-category { display: inline-block; - width: 20em; + width: 19em; max-width: 95%; - border: 1px solid #aaa; + margin: 20px 10px; + border: 1px solid #ccc; vertical-align: top; } #stream.global .category { @@ -516,6 +528,10 @@ a.btn { display: block; overflow: auto; } +#stream.global .box-category .feed { + width: 19em; + max-width: 90%; +} /*=== Panel */ #overlay { @@ -571,27 +587,31 @@ a.btn { .item.date, .day .date { display: none; } - .nav-login, - #panel .close img { + .nav-login { display: block; } .nav_menu .toggle_aside, .aside .toggle_aside, - .nav_menu .search { + .nav_menu .search, + #panel .close img { display: inline-block; } .aside { position: fixed; - top: 0; left: 0; + top: 0; bottom: 0; + left: 0; width: 0; overflow: hidden; - z-index: 10; + z-index: 100; } .aside:target { - width: 80%; + width: 90%; overflow: auto; } + .aside .categories { + margin: 10px 0 75px; + } .flux_header .item.website { width: 40px; @@ -614,6 +634,10 @@ a.btn { width: 100%; } + #stream.global .box-category { + margin: 10px 0; + } + #panel { top: 0; bottom: 0; left: 0; right: 0; diff --git a/p/themes/template/template.css b/p/themes/template/template.css index c546a824d..d57f2cde3 100644 --- a/p/themes/template/template.css +++ b/p/themes/template/template.css @@ -169,8 +169,7 @@ a.btn { position: absolute; right: 0; background: #fff; - border: 1px solid #aaa; - overflow: auto; + border: 1px solid #aaa; } .dropdown-header { display: block; @@ -294,6 +293,10 @@ a.btn { } /*=== Aside main page (categories) */ +.categories { + list-style: none; + margin: 0; +} .category { display: block; overflow: hidden; @@ -359,10 +362,10 @@ a.btn { position: relative; } .flux .item { - font-size: 0.9em; line-height: 40px; white-space: nowrap; text-overflow: ellipsis; + overflow: hidden; } .flux .item.manage, .flux .item.link { @@ -391,14 +394,16 @@ a.btn { } .flux .item.date { width: 145px; - font-size: 0.7em; text-align: right; } -.flux .item:not(.title) > a { +.flux .item > a { display: block; } -.flux .flux_header .item, -.flux .bottom .item.date { +.flux .item:not(.title) > a { + display: block; + text-decoration: none; + white-space: nowrap; + text-overflow: ellipsis; overflow: hidden; } .flux .item.share > a { @@ -417,6 +422,15 @@ a.btn { 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 { @@ -428,7 +442,7 @@ a.btn { } /*=== Notification and actualize notification */ -#notification { +.notification { position: absolute; top: 1em; left: 25%; right: 25%; @@ -436,24 +450,21 @@ a.btn { background: #fff; border: 1px solid #aaa; } -#notification.closed { +.notification.closed { display: none; } -#notification a.close { +.notification a.close { position: absolute; right: 0; display: inline-block; } -.actualizeProgress { - position: fixed; - top: 1em; - left: 25%; right: 25%; - background: #fff; - border: 1px solid #aaa; -} -.actualizeProgress progress { +#actualizeProgress progress { max-width: 100%; + vertical-align: middle; +} +#actualizeProgress .progress { + vertical-align: middle; } /*=== Navigation menu (for articles) */ @@ -501,9 +512,10 @@ a.btn { /*=== Category boxes */ #stream.global .box-category { display: inline-block; - width: 20em; + width: 19em; max-width: 95%; - border: 1px solid #aaa; + margin: 20px 10px; + border: 1px solid #ccc; vertical-align: top; } #stream.global .category { @@ -516,6 +528,10 @@ a.btn { display: block; overflow: auto; } +#stream.global .box-category .feed { + width: 19em; + max-width: 90%; +} /*=== Panel */ #overlay { @@ -571,27 +587,31 @@ a.btn { .item.date, .day .date { display: none; } - .nav-login, - #panel .close img { + .nav-login { display: block; } .nav_menu .toggle_aside, .aside .toggle_aside, - .nav_menu .search { + .nav_menu .search, + #panel .close img { display: inline-block; } .aside { position: fixed; - top: 0; left: 0; + top: 0; bottom: 0; + left: 0; width: 0; overflow: hidden; - z-index: 10; + z-index: 100; } .aside:target { - width: 80%; + width: 90%; overflow: auto; } + .aside .categories { + margin: 10px 0 75px; + } .flux_header .item.website { width: 40px; @@ -614,6 +634,10 @@ a.btn { width: 100%; } + #stream.global .box-category { + margin: 10px 0; + } + #panel { top: 0; bottom: 0; left: 0; right: 0; -- cgit v1.2.3 From ab9d656135e5afcafb824e73a49ff2e9fd2a2dbd Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 9 Jul 2014 20:20:17 +0200 Subject: Block user to click many times on the refresh button See https://github.com/marienfressinaud/FreshRSS/issues/513 --- app/views/javascript/actualize.phtml | 6 ++++-- p/scripts/main.js | 13 +++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'app/views/javascript') diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index 6a92e5642..d08dc47d1 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -10,7 +10,7 @@ var feeds = [\ - 0 / " + feed_count + "
      \ + 0 / " + feed_count + "
      \ \
      "); } else { @@ -24,7 +24,8 @@ function updateProgressBar(i) { function updateFeeds() { if (feed_count === 0) { - openNotification("", "good"); + openNotification("", "good"); + ajax_loading = false; return; } initProgressBar(true); @@ -39,6 +40,7 @@ function updateFeed() { if (feed == undefined) { return; } + $.ajax({ type: 'POST', url: feed, diff --git a/p/scripts/main.js b/p/scripts/main.js index 54ee7f0fd..243159ca5 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1,7 +1,8 @@ "use strict"; var $stream = null, isCollapsed = true, - shares = 0; + shares = 0, + ajax_loading = false; function is_normal_mode() { return $stream.hasClass('normal'); @@ -684,14 +685,22 @@ function init_actualize() { var auto = false; $("#actualize").click(function () { + if (ajax_loading) { + return false; + } + + ajax_loading = true; + $.getScript('./?c=javascript&a=actualize').done(function () { if (auto && feed_count < 1) { auto = false; - return; + ajax_loading = false; + return false; } updateFeeds(); }); + return false; }); -- cgit v1.2.3 From 6655c1b4299897944dea06309261137a7fa91ad7 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 10 Aug 2014 15:28:54 +0200 Subject: Improve design of actualize notification - Remove progress bar - Show title of updated feed --- app/views/javascript/actualize.phtml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'app/views/javascript') diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index d08dc47d1..74cef4998 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -1,25 +1,24 @@ "use strict"; -var feeds = [feeds as $feed) { - echo "'", Minz_Url::display(array('c' => 'feed', 'a' => 'actualize', 'params' => array('id' => $feed->id(), 'ajax' => '1')), 'php'), "',\n"; - } - ?>], +var feeds = [feeds as $feed) { ?>{url: " 'feed', 'a' => 'actualize', 'params' => array('id' => $feed->id(), 'ajax' => '1')), 'php'); ?>",title: "name(); ?>"},], feed_processed = 0, feed_count = feeds.length; function initProgressBar(init) { if (init) { $("body").after("\
      \ - 0 / " + feed_count + "
      \ - \ +
      /
      \ + 0 / " + feed_count + "\
      "); } else { window.location.reload(); } } -function updateProgressBar(i) { - $("#actualizeProgressBar").val(i); +function updateProgressBar(i, title_feed) { $("#actualizeProgress .progress").html(i + " / " + feed_count); + $("#actualizeProgress .title").html(title_feed); } function updateFeeds() { @@ -43,10 +42,10 @@ function updateFeed() { $.ajax({ type: 'POST', - url: feed, + url: feed['url'], }).complete(function (data) { feed_processed++; - updateProgressBar(feed_processed); + updateProgressBar(feed_processed, feed['title']); if (feed_processed === feed_count) { initProgressBar(false); -- cgit v1.2.3