b2evolution PHP Cross Reference Blogging Systems

Source: /plugins/_calendar.plugin.php - 1163 lines - 38948 bytes - Summary - Text - Print

Description: This file implements the Calendar plugin. This file is part of the b2evolution project - {@link http://b2evolution.net/}

   1  <?php
   2  /**
   3   * This file implements the Calendar plugin.
   4   *
   5   * This file is part of the b2evolution project - {@link http://b2evolution.net/}
   6   *
   7   * @copyright (c)2003-2014 by Francois Planque - {@link http://fplanque.com/}
   8   * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
   9   *
  10   * {@internal License choice
  11   * - If you have received this file as part of a package, please find the license.txt file in
  12   *   the same folder or the closest folder above for complete license terms.
  13   * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
  14   *   then you must choose one of the following licenses before using the file:
  15   *   - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
  16   *   - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
  17   * }}
  18   *
  19   * {@internal Open Source relicensing agreement:
  20   * Daniel HAHLER grants Francois PLANQUE the right to license
  21   * Daniel HAHLER's contributions to this file and the b2evolution project
  22   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  23   * }}
  24   *
  25   * @package plugins
  26   *
  27   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  28   * @author blueyed: Daniel HAHLER.
  29   * @author fplanque: Francois PLANQUE - {@link http://fplanque.net/}
  30   * @author hansreinders: Hans REINDERS
  31   * @author cafelog (team)
  32   *
  33   * @version $Id: _calendar.plugin.php 6136 2014-03-08 07:59:48Z manuel $
  34   */
  35  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  36  
  37  
  38  /**
  39   * Calendar Plugin
  40   *
  41   * This plugin displays
  42   */
  43  class calendar_plugin extends Plugin
  44  {
  45      /**
  46       * Variables below MUST be overriden by plugin implementations,
  47       * either in the subclass declaration or in the subclass constructor.
  48       */
  49  
  50      var $name;
  51      var $code = 'evo_Calr';
  52      var $priority = 20;
  53      var $version = '5.0.0';
  54      var $author = 'The b2evo Group';
  55      var $group = 'widget';
  56  
  57  
  58    /**
  59       * @var ItemQuery
  60       */
  61      var $ItemQuery;
  62  
  63      /**
  64       * Init
  65       */
  66  	function PluginInit( & $params )
  67      {
  68          $this->name = T_( 'Calendar Widget' );
  69          $this->short_desc = T_('This skin tag displays a navigable calendar.');
  70          $this->long_desc = T_('Days containing posts are highlighted.');
  71  
  72          $this->dbtable = 'T_items__item';
  73          $this->dbprefix = 'post_';
  74          $this->dbIDname = 'post_ID';
  75      }
  76  
  77  
  78    /**
  79     * Get definitions for widget specific editable params
  80     *
  81       * @see Plugin::GetDefaultSettings()
  82       * @param local params like 'for_editing' => true
  83       */
  84  	function get_widget_param_definitions( $params )
  85      {
  86          $r = array(
  87              'displaycaption' => array(
  88                  'label' => T_('Display caption'),
  89                  'note' => T_('Display caption on top of calendar'),
  90                  'type' => 'checkbox',
  91                  'defaultvalue' => true,
  92              ),
  93              'linktomontharchive' => array(
  94                  'label' => T_('Link caption to archives'),
  95                  'note' => T_('The month in the caption can be clicked to see all posts for this month'),
  96                  'type' => 'checkbox',
  97                  'defaultvalue' => true,
  98              ),
  99              'headerdisplay' => array(
 100                  'label' => 'Column headers',
 101                  'note' => T_('How do you want to display the days of the week in the column headers?'),
 102                  'type' => 'select',
 103                  'options' => array( 'e' => 'F', 'D' => 'Fri', 'l' => 'Friday', '' => T_('No header') ),
 104                  'defaultvalue' => 'D',
 105              ),
 106              'navigation' => array(
 107                  'label' => 'Navigation arrows',
 108                  'note' => T_('Where do you want to display the navigation arrows?'),
 109                  'type' => 'select',
 110                  'options' => array( 'caption' => T_('Top'), 'tfoot' => T_('Bottom'), '' => T_('No navigation') ),
 111                  'defaultvalue' => 'tfoot',
 112              ),
 113              'browseyears' => array(
 114                  'label' => T_('Navigate years'),
 115                  'note' => T_('Display double arrows for yearly navigation?'),
 116                  'type' => 'checkbox',
 117                  'defaultvalue' => true,
 118              ),
 119          );
 120          return $r;
 121      }
 122  
 123  
 124      /**
 125       * Event handler: SkinTag (widget)
 126       *
 127       * @param array Associative array of parameters. Valid keys are:
 128       *      - 'block_start' : (Default: '<div class="bSideItem">')
 129       *      - 'block_end' : (Default: '</div>')
 130       *      - 'title' : (Default: T_('Calendar'))
 131       *      - 'displaycaption'
 132       *      - 'monthformat'
 133       *      - 'linktomontharchive'
 134       *      - 'tablestart'
 135       *      - 'tableend'
 136       *      - 'monthstart'
 137       *      - 'monthend'
 138       *      - 'rowstart'
 139       *      - 'rowend'
 140       *      - 'headerdisplay'
 141       *      - 'headerrowstart'
 142       *      - 'headerrowend'
 143       *      - 'headercellstart'
 144       *      - 'headercellend'
 145       *      - 'cellstart'
 146       *      - 'cellend'
 147       *      - 'linkpostcellstart'
 148       *      - 'linkposttodaycellstart'
 149       *      - 'todaycellstart'
 150       *      - 'todaycellstartpost'
 151       *      - 'navigation' : Where do we want to have the navigation arrows? (Default: 'tfoot')
 152       *      - 'browseyears' : boolean  Do we want arrows to move one year at a time?
 153       *      - 'min_timestamp' : Minimum unix timestamp the user can browse too or 'query' (Default: 2000-01-01)
 154       *      - 'max_timestamp' : Maximum unix timestamp the user can browse too or 'query' (Default: now + 1 year )
 155       *      - 'postcount_month_atitle'
 156       *      - 'postcount_month_atitle_one'
 157       *      - 'postcount_year_atitle'
 158       *      - 'postcount_year_atitle_one'
 159       *      - 'link_type' : 'canonic'|'context' (default: canonic)
 160       * @return boolean did we display?
 161       */
 162  	function SkinTag( $params )
 163      {
 164          // Prefix of the ItemList object
 165          $itemlist_prefix = isset( $params['itemlist_prefix'] ) ? $params['itemlist_prefix'] : '';
 166  
 167          global $month;
 168          global $Blog, $cat_array, $cat_modifier;
 169          global $show_statuses;
 170          global $author, $assgn, $status, $types;
 171          global ${$itemlist_prefix.'m'}, $w, $dstart;
 172          global $s, $sentence, $exact;
 173          global $posttypes_specialtypes;
 174  
 175          /**
 176           * Default params:
 177           */
 178          // This is what will enclose the block in the skin:
 179          if(!isset($params['block_start'])) $params['block_start'] = '<div class="bSideItem">';
 180          if(!isset($params['block_end'])) $params['block_end'] = "</div>\n";
 181  
 182          // Title:
 183          if(!isset($params['block_title_start'])) $params['block_title_start'] = '<h3>';
 184          if(!isset($params['block_title_end'])) $params['block_title_end'] = '</h3>';
 185          if(!isset($params['title'])) $params['title'] = '';
 186  
 187  
 188          $Calendar = new Calendar( ${$itemlist_prefix.'m'}, $params );
 189  
 190          // TODO: automate with a table inside of Calendatr object. Table should also contain descriptions and default values to display in help screen.
 191          // Note: minbrowse and maxbrowe already work this way.
 192          if( isset($params['displaycaption']) ) $Calendar->set( 'displaycaption', $params['displaycaption'] );
 193          if( isset($params['monthformat']) ) $Calendar->set( 'monthformat', $params['monthformat'] );
 194          if( isset($params['linktomontharchive']) ) $Calendar->set( 'linktomontharchive', $params['linktomontharchive'] );
 195          if( isset($params['tablestart']) ) $Calendar->set( 'tablestart', $params['tablestart'] );
 196          if( isset($params['tableend']) ) $Calendar->set( 'tableend', $params['tableend'] );
 197          if( isset($params['monthstart']) ) $Calendar->set( 'monthstart', $params['monthstart'] );
 198          if( isset($params['monthend']) ) $Calendar->set( 'monthend', $params['monthend'] );
 199          if( isset($params['rowstart']) ) $Calendar->set( 'rowstart', $params['rowstart'] );
 200          if( isset($params['rowend']) ) $Calendar->set( 'rowend', $params['rowend'] );
 201          if( isset($params['headerdisplay']) ) $Calendar->set( 'headerdisplay', $params['headerdisplay'] );
 202          if( isset($params['headerrowstart']) ) $Calendar->set( 'headerrowstart', $params['headerrowstart'] );
 203          if( isset($params['headerrowend']) ) $Calendar->set( 'headerrowend', $params['headerrowend'] );
 204          if( isset($params['headercellstart']) ) $Calendar->set( 'headercellstart', $params['headercellstart'] );
 205          if( isset($params['headercellend']) ) $Calendar->set( 'headercellend', $params['headercellend'] );
 206          if( isset($params['cellstart']) ) $Calendar->set( 'cellstart', $params['cellstart'] );
 207          if( isset($params['cellend']) ) $Calendar->set( 'cellend', $params['cellend'] );
 208          if( isset($params['emptycellstart']) ) $Calendar->set( 'emptycellstart', $params['emptycellstart'] );
 209          if( isset($params['emptycellend']) ) $Calendar->set( 'emptycellend', $params['emptycellend'] );
 210          if( isset($params['emptycellcontent']) ) $Calendar->set( 'emptycellcontent', $params['emptycellcontent'] );
 211          if( isset($params['linkpostcellstart']) ) $Calendar->set( 'linkpostcellstart', $params['linkpostcellstart'] );
 212          if( isset($params['linkposttodaycellstart']) ) $Calendar->set( 'linkposttodaycellstart', $params['linkposttodaycellstart'] );
 213          if( isset($params['todaycellstart']) ) $Calendar->set( 'todaycellstart', $params['todaycellstart'] );
 214          if( isset($params['todaycellstartpost']) ) $Calendar->set( 'todaycellstartpost', $params['todaycellstartpost'] );
 215          if( isset($params['navigation']) ) $Calendar->set( 'navigation', $params['navigation'] );
 216          if( isset($params['browseyears']) ) $Calendar->set( 'browseyears', $params['browseyears'] );
 217          if( isset($params['postcount_month_atitle']) ) $Calendar->set( 'postcount_month_atitle', $params['postcount_month_atitle'] );
 218          if( isset($params['postcount_month_atitle_one']) ) $Calendar->set( 'postcount_month_atitle_one', $params['postcount_month_atitle_one'] );
 219          if( isset($params['postcount_year_atitle']) ) $Calendar->set( 'postcount_year_atitle', $params['postcount_year_atitle'] );
 220          if( isset($params['postcount_year_atitle_one']) ) $Calendar->set( 'postcount_year_atitle_one', $params['postcount_year_atitle_one'] );
 221          // Link type:
 222          if( isset($params['link_type']) ) $Calendar->set( 'link_type', $params['link_type'] );
 223          if( isset($params['context_isolation']) ) $Calendar->set( 'context_isolation', $params['context_isolation'] );
 224  
 225          echo $params['block_start'];
 226  
 227          if( !empty($params['title']) )
 228          {    // We want to display a title for the widget block:
 229              echo $params['block_title_start'];
 230              echo $params['title'];
 231              echo $params['block_title_end'];
 232          }
 233  
 234          // CONSTRUCT THE WHERE CLAUSE:
 235  
 236          // - - Select a specific Item:
 237          // $this->ItemQuery->where_ID( $p, $title );
 238  
 239          if( $Calendar->link_type == 'context' )
 240          {    // We want to preserve the current context:
 241              // * - - Restrict to selected blog/categories:
 242              $Calendar->ItemQuery->where_chapter2( $Blog, $cat_array, $cat_modifier );
 243  
 244              // * Restrict to the statuses we want to show:
 245              $Calendar->ItemQuery->where_visibility( $show_statuses );
 246  
 247              // Restrict to selected authors:
 248              $Calendar->ItemQuery->where_author( $author );
 249  
 250              // Restrict to selected assignees:
 251              $Calendar->ItemQuery->where_assignees( $assgn );
 252  
 253              // Restrict to selected satuses:
 254              $Calendar->ItemQuery->where_statuses( $status );
 255  
 256              // - - - + * * if a month is specified in the querystring, load that month:
 257              $Calendar->ItemQuery->where_datestart( /* NO m */'', /* NO w */'', $dstart, '', $Blog->get_timestamp_min(), $Blog->get_timestamp_max() );
 258  
 259              // Keyword search stuff:
 260              $Calendar->ItemQuery->where_keywords( $s, $sentence, $exact );
 261  
 262              // Exclude pages and intros:
 263              $Calendar->ItemQuery->where_types( $types );
 264          }
 265          else
 266          {    // We want to preserve only the minimal context:
 267              // * - - Restrict to selected blog/categories:
 268              $Calendar->ItemQuery->where_chapter2( $Blog, array(), '' );
 269  
 270              // * Restrict to the statuses we want to show:
 271              $Calendar->ItemQuery->where_visibility( $show_statuses );
 272  
 273              // - - - + * * if a month is specified in the querystring, load that month:
 274              $Calendar->ItemQuery->where_datestart( /* NO m */'', /* NO w */'', '', '', $Blog->get_timestamp_min(), $Blog->get_timestamp_max() );
 275  
 276              // Exclude pages and intros and sidebar stuff:
 277              $Calendar->ItemQuery->where_types( '-'.implode(',',$posttypes_specialtypes) );
 278          }
 279  
 280          // DISPLAY:
 281          $Calendar->display( );
 282  
 283          echo $params['block_end'];
 284  
 285          return true;
 286      }
 287  }
 288  
 289  
 290  /**
 291   * Calendar
 292   *
 293   * @package evocore
 294   */
 295  class Calendar
 296  {
 297      var $year;
 298  
 299      /**
 300       * The month to display or empty in mode 'year' with no selected month.
 301       * @var string
 302       */
 303      var $month;
 304  
 305      /**
 306       * 'month' or 'year'
 307       * @var string
 308       */
 309      var $mode;
 310  
 311      var $where;
 312      /**
 313       * SQL query string
 314       * @var string
 315       */
 316      var $request;
 317      /**
 318       * Result set
 319       */
 320      var $result;
 321      /**
 322       * Number of rows in result set
 323       * @var integer
 324       */
 325      var $result_num_rows;
 326  
 327      var $displaycaption;
 328      var $monthformat;
 329      var $monthstart;
 330      var $monthend;
 331      var $linktomontharchive;
 332      /**
 333       * Where to do the navigation
 334       *
 335       * 'caption' or 'tfoot';
 336       *
 337       * @var string
 338       */
 339      var $navigation = 'tfoot';
 340  
 341      var $tablestart;
 342      var $tableend;
 343  
 344      var $rowstart;
 345      var $rowend;
 346  
 347      var $headerdisplay;
 348      var $headerrowstart;
 349      var $headerrowend;
 350      var $headercellstart;
 351      var $headercellend;
 352  
 353      var $cellstart;
 354      var $cellend;
 355  
 356      var $emptycellstart;
 357      var $emptycellend;
 358  
 359      var $emptycellcontent;
 360  
 361      /**
 362       * Do we want to browse years in the caption? True by default for mode == year,
 363       * false for mode == month (gets set in constructor).
 364       * @var boolean
 365       */
 366      var $browseyears;
 367  
 368      /**
 369       * Is today in the displayed frame?
 370       * @var boolean
 371       * @access protected
 372       */
 373      var $today_is_visible;
 374  
 375  
 376      var $link_type;
 377      var $context_isolation;
 378  
 379      var $params = array( );
 380      
 381      /**
 382       * Prefix of the ItemList object
 383       * @var string
 384       */
 385      var $itemlist_prefix = '';
 386  
 387      /**
 388       * Calendar::Calendar(-)
 389       *
 390       * Constructor
 391       *
 392       * @param string Month ('YYYYMM'), year ('YYYY'), current ('')
 393       * @param array Associative array of parameters. Valid keys are:
 394       *      - 'min_timestamp' : Minimum unix timestamp the user can browse too or 'query' (Default: 2000-01-01)
 395       *      - 'max_timestamp' : Maximum unix timestamp the user can browse too or 'query' (Default: now + 1 year )
 396       */
 397  	function Calendar( $m = '', $params = array() )
 398      {
 399          global $localtimenow;
 400  
 401          $this->dbtable = 'T_items__item';
 402          $this->dbprefix = 'post_';
 403          $this->dbIDname = 'post_ID';
 404  
 405          if( isset( $params['itemlist_prefix'] ) )
 406          { // Set a prefix of the ItemList object
 407              $this->itemlist_prefix = $params['itemlist_prefix'];
 408          }
 409  
 410          // OBJECT THAT WILL BE USED TO CONSTRUCT THE WHERE CLAUSE:
 411          $this->ItemQuery = new ItemQuery( $this->dbtable, $this->dbprefix, $this->dbIDname );    // COPY!!
 412  
 413          $localyearnow = date( 'Y', $localtimenow );
 414          $localmonthnow = date( 'm', $localtimenow );
 415  
 416          // Find out which month to display:
 417          if( empty($m) )
 418          { // Current month (monthly)
 419              $this->year = $localyearnow;
 420              $this->month = $localmonthnow;
 421              $this->mode = 'month';
 422  
 423              $this->today_is_visible = true;
 424          }
 425          else
 426          {    // We have requested a specific date
 427              $this->year = substr($m, 0, 4);
 428              if (strlen($m) < 6)
 429              { // no month provided
 430                  $this->mode = 'year';
 431  
 432                  if( $this->year == $localyearnow )
 433                  { // we display current year, month gets current
 434                      $this->month = $localmonthnow;
 435                  }
 436                  else
 437                  { // highlight no month, when not current year
 438                      $this->month = '';
 439                  }
 440              }
 441              else
 442              {
 443                  $this->month = substr($m, 4, 2);
 444                  $this->mode = 'month';
 445              }
 446  
 447              $this->today_is_visible = ( $this->year == $localyearnow
 448                  && ( empty($this->month) || $this->month == $localmonthnow ) );
 449          }
 450  
 451  
 452          // Default styling:
 453          $this->displaycaption = 1;    // set this to 0 if you don't want to display the month name
 454          $this->monthformat = 'F Y';
 455          $this->linktomontharchive = true;  // month displayed as link to month' archive
 456  
 457          $this->tablestart = '<table class="bCalendarTable" cellspacing="0" summary="Monthly calendar with links to each day\'s posts">'."\n";
 458          $this->tableend = '</table>';
 459  
 460          $this->monthstart = '<caption>';
 461          $this->monthend = "</caption>\n";
 462  
 463          $this->rowstart = '<tr class="bCalendarRow">' . "\n";
 464          $this->rowend = "</tr>\n";
 465  
 466          $this->headerdisplay = 'D';     // D => 'Fri'; e => 'F', l (lowercase l) => 'Friday'
 467          // These codes are twisted because they're the same as for date formats.
 468          // set this to 0 or '' if you don't want to display the "Mon Tue Wed..." header
 469  
 470          $this->headerrowstart = '<thead><tr class="bCalendarRow">' . "\n";
 471          $this->headerrowend = "</tr></thead>\n";
 472          $this->headercellstart = '<th class="bCalendarHeaderCell" abbr="[abbr]" scope="col" title="[abbr]">';    // please leave [abbr] there !
 473          $this->headercellend = "</th>\n";
 474  
 475          $this->cellstart = '<td class="bCalendarCell">';
 476          $this->cellend = "</td>\n";
 477  
 478          $this->emptycellstart = '<td class="bCalendarEmptyCell">';
 479          $this->emptycellend = "</td>\n";
 480          $this->emptycellcontent = '&nbsp;';
 481  
 482          $this->linkpostcellstart = '<td class="bCalendarLinkPost">';
 483          $this->linkposttodaycellstart = '<td class="bCalendarLinkPostToday">';
 484          $this->todaycellstart = '<td id="bCalendarToday">';
 485          $this->todaycellstartpost = '<td id="bCalendarToday" class="bCalendarLinkPost">';
 486  
 487          // Where do we want to have the navigation arrows? tfoot or caption
 488          $this->navigation = 'tfoot';
 489  
 490          // Do we want arrows to move one year at a time?
 491          $this->browseyears = true;
 492  
 493          /**#@+
 494           * Display number of posts with days/months
 495           *
 496           * - set to '' (empty) to disable
 497           * - %d gets replaced with the number of posts on that day/month
 498           */
 499          $this->postcount_month_atitle = T_('%d posts');                         // in archive links title tag
 500          $this->postcount_month_atitle_one = T_('1 post');                      //  -- " -- [for single post]
 501          $this->postcount_year_atitle = T_('%d posts');                             // in archive links title tag
 502          $this->postcount_year_atitle_one = T_('1 post');                         // in archive links title tag
 503          /**#@-*/
 504  
 505          // Link type:
 506          $this->link_type = 'canonic';
 507          $this->context_isolation = 'm,w,p,title,unit,dstart';
 508  
 509          // New style params:
 510          $this->params = $params;
 511  
 512          // Default values:
 513          if( empty( $this->params['min_timestamp'] ) )
 514          {    // 2000-01-01:
 515              $this->params['min_timestamp'] = mktime( 0, 0, 0, 1, 1, 2000 );
 516          }
 517          if( empty( $this->params['max_timestamp'] ) )
 518          {    // Now + 1 year:
 519              $this->params['max_timestamp'] = mktime( 23, 59, 59, date( 'm', $localtimenow  ),  date( 'd', $localtimenow ),  date( 'Y', $localtimenow )+1 );
 520          }
 521  
 522      }
 523  
 524  
 525      /*
 526       * Calendar->set(-)
 527       *
 528       * set a variable
 529       */
 530  	function set( $var, $value )
 531      {
 532          $this->$var = $value;
 533      }
 534  
 535  
 536      /**
 537       * Display the calendar.
 538       *
 539       * @todo If a specific day (mode == month) or month (mode == year) is selected, apply another class (default to some border)
 540       */
 541  	function display()
 542      {
 543          global $DB;
 544          global $weekday, $weekday_abbrev, $weekday_letter, $month, $month_abbrev;
 545          global $time_difference;
 546  
 547          if( $this->mode == 'month' )
 548          {
 549              $end_of_week = ((locale_startofweek() + 7) % 7);
 550  
 551              // fplanque>> note: I am removing the searchframe thing because 1) I don't think it's of any use
 552              // and 2) it's brutally inefficient! If someone needs this it should be implemented with A SINGLE
 553              // QUERY which gets the last available post (BTW, I think there is already a function for that somwhere)
 554              // walter>> As we are just counting items, the ORDER BY db_prefix . date_start doesn't matter. And a side effect
 555              // of that is make queries standart compatible (compatible with other databases than MySQL)
 556  
 557              $arc_sql = 'SELECT COUNT(DISTINCT '.$this->dbIDname.') AS item_count,
 558                                                      EXTRACT(DAY FROM '.$this->dbprefix.'datestart) AS myday
 559                                      FROM ('.$this->dbtable.' INNER JOIN T_postcats ON '.$this->dbIDname.' = postcat_post_ID)
 560                                          INNER JOIN T_categories ON postcat_cat_ID = cat_ID
 561                                      WHERE EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) = \''.$this->year.'\'
 562                                          AND EXTRACT(MONTH FROM '.$this->dbprefix.'datestart) = \''.$this->month.'\'
 563                                          '.$this->ItemQuery->get_where( ' AND ' ).'
 564                                      GROUP BY myday '.$this->ItemQuery->get_group_by( ', ' );
 565              // echo $this->ItemQuery->where;
 566              $arc_result = $DB->get_results( $arc_sql, ARRAY_A );
 567  
 568              foreach( $arc_result as $arc_row )
 569              {
 570                  if( !isset( $daysinmonthwithposts[ $arc_row['myday'] ] ) )
 571                  {
 572                      $daysinmonthwithposts[ $arc_row['myday'] ] = 0;
 573                  }
 574                  // The '+' situation actually only happens when we have a complex GROUP BY above
 575                  // (multiple categories wcombined with "ALL")
 576                  $daysinmonthwithposts[ $arc_row['myday'] ] += $arc_row['item_count'];
 577              }
 578  
 579              $daysinmonth = intval(date('t', mktime(0, 0, 0, $this->month, 1, $this->year)));
 580              // echo 'days in month=', $daysinmonth;
 581  
 582  
 583              // caution: offset bug inside (??)
 584              $datestartofmonth = mktime(0, 0, 0, $this->month, 1, $this->year );
 585              // echo date( locale_datefmt(), $datestartofmonth );
 586              $calendarblah = get_weekstartend( $datestartofmonth, locale_startofweek() );
 587              $calendarfirst = $calendarblah['start'];
 588  
 589  
 590              $dateendofmonth = mktime(0, 0, 0, $this->month, $daysinmonth, $this->year);
 591              // echo 'end of month: '.date( 'Y-m-d H:i:s', $dateendofmonth );
 592              $calendarblah = get_weekstartend( $dateendofmonth, locale_startofweek() );
 593              $calendarlast = $calendarblah['end'];
 594              // echo date( ' Y-m-d H:i:s', $calendarlast );
 595  
 596  
 597  
 598              // here the offset bug is corrected
 599              if( (intval(date('d', $calendarfirst)) > 1) && (intval(date('m', $calendarfirst)) == intval($this->month)) )
 600              {
 601                  #pre_dump( 'with offset bug', date('Y-m-d', $calendarfirst) );
 602                  $calendarfirst = $calendarfirst - 604800 /* 1 week */;
 603                  #pre_dump( 'without offset bug', date('Y-m-d', $calendarfirst) );
 604              }
 605          }
 606          else
 607          { // mode is 'year'
 608              // Find months with posts
 609              $arc_sql = '
 610                  SELECT COUNT(DISTINCT '.$this->dbIDname.') AS item_count, EXTRACT(MONTH FROM '.$this->dbprefix.'datestart) AS mymonth
 611                    FROM ('.$this->dbtable.' INNER JOIN T_postcats ON '.$this->dbIDname.' = postcat_post_ID)
 612                   INNER JOIN T_categories ON postcat_cat_ID = cat_ID
 613                   WHERE EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) = \''.$this->year.'\' '
 614                         .$this->ItemQuery->get_where( ' AND ' ).'
 615                   GROUP BY mymonth '.$this->ItemQuery->get_group_by( ', ' );
 616              $arc_result = $DB->get_results( $arc_sql, ARRAY_A );
 617  
 618              if( $DB->num_rows > 0 )
 619              { // OK we have a month with posts! // fp>dh why did you removed that?
 620                  foreach( $arc_result as $arc_row )
 621                  {
 622                      $monthswithposts[ $arc_row['mymonth'] ] = $arc_row['item_count'];
 623                  }
 624              }
 625          }
 626  
 627  
 628          // ** display everything **
 629  
 630          echo $this->tablestart;
 631  
 632          // CAPTION :
 633  
 634          if( $this->displaycaption )
 635          { // caption:
 636              echo $this->monthstart;
 637  
 638              if( $this->navigation == 'caption' )
 639              {
 640                  echo implode( '&nbsp;', $this->getNavLinks( 'prev' ) ).'&nbsp;';
 641              }
 642  
 643              if( $this->mode == 'month' )
 644              { // MONTH CAPTION:
 645                  $text = date_i18n($this->monthformat, mktime(0, 0, 0, $this->month, 1, $this->year));
 646  
 647                  if( $this->linktomontharchive )
 648                  { // chosen month with link to archives
 649                      echo $this->archive_link( $text, T_('View monthly archive'), $this->year, $this->month );
 650                  }
 651                  else
 652                  {
 653                      echo $text;
 654                  }
 655              }
 656              else
 657              { // YEAR CAPTION:
 658                  echo date_i18n('Y', mktime(0, 0, 0, 1, 1, $this->year)); // display year
 659              }
 660  
 661              if( $this->navigation == 'caption' )
 662              {
 663                  echo '&nbsp;'.implode( '&nbsp;', $this->getNavLinks( 'next' ) );
 664              }
 665  
 666              echo $this->monthend;
 667          }
 668  
 669          // HEADER :
 670  
 671          if( !empty($this->headerdisplay) && ($this->mode == 'month') )
 672          { // Weekdays:
 673              echo $this->headerrowstart;
 674  
 675              for( $i = locale_startofweek(), $j = $i + 7; $i < $j; $i = $i + 1)
 676              {
 677                  echo str_replace('[abbr]', T_($weekday[($i % 7)]), $this->headercellstart);
 678                  switch( $this->headerdisplay )
 679                  {
 680                      case 'e':
 681                          // e => 'F'
 682                          echo T_($weekday_letter[($i % 7)]);
 683                          break;
 684  
 685                      case 'l':
 686                          // l (lowercase l) => 'Friday'
 687                          echo T_($weekday[($i % 7)]);
 688                          break;
 689  
 690                      default:    // Backward compatibility: any non emty value will display this
 691                          // D => 'Fri'
 692                          echo T_($weekday_abbrev[($i % 7)]);
 693                  }
 694  
 695                  echo $this->headercellend;
 696              }
 697  
 698              echo $this->headerrowend;
 699          }
 700  
 701          // FOOTER :
 702  
 703          if( $this->navigation == 'tfoot' )
 704          { // We want to display navigation in the table footer:
 705              echo "<tfoot>\n";
 706              echo "<tr>\n";
 707              echo '<td colspan="'.( ( $this->mode == 'month' ? 2 : 1 ) + (int)$this->today_is_visible ).'" id="prev">';
 708              echo implode( '&nbsp;', $this->getNavLinks( 'prev' ) );
 709              echo "</td>\n";
 710  
 711              if( $this->today_is_visible )
 712              {
 713                  if( $this->mode == 'month' )
 714                  {
 715                      echo '<td class="pad">&nbsp;</td>'."\n";
 716                  }
 717              }
 718              else
 719              {
 720                  echo '<td colspan="'.( $this->mode == 'month' ? '3' : '2' ).'" class="center">'
 721                              .$this->archive_link( T_('Current'), '', date('Y'), ( $this->mode == 'month' ? date('m') : NULL ) )
 722                              .'</td>';
 723              }
 724              echo '<td colspan="'.( ( $this->mode == 'month' ? 2 : 1 ) + (int)$this->today_is_visible ).'" id="next">';
 725              echo implode( '&nbsp;', $this->getNavLinks( 'next' ) );
 726              echo "</td>\n";
 727              echo "</tr>\n";
 728              echo "</tfoot>\n";
 729          }
 730  
 731          // REAL TABLE DATA :
 732  
 733          echo '<tbody>'.$this->rowstart;
 734  
 735          if( $this->mode == 'year' )
 736          {    // DISPLAY MONTHS:
 737  
 738              for ($i = 1; $i < 13; $i = $i + 1)
 739              {    // For each month:
 740                  if( isset($monthswithposts[ $i ]) )
 741                  {
 742                      if( $this->month == $i )
 743                      {
 744                          echo $this->todaycellstartpost;
 745                      }
 746                      else
 747                      {
 748                          echo $this->linkpostcellstart;
 749                      }
 750                      if( $monthswithposts[ $i ] > 1 && !empty($this->postcount_year_atitle) )
 751                      { // display postcount
 752                          $title = sprintf($this->postcount_year_atitle, $monthswithposts[ $i ]);
 753                      }
 754                      elseif( !empty($this->postcount_year_atitle_one) )
 755                      { // display postcount for one post
 756                          $title = sprintf($this->postcount_year_atitle_one, 1);
 757                      }
 758                      else
 759                      {
 760                          $title = '';
 761                      }
 762                      echo $this->archive_link( T_($month_abbrev[ zeroise($i, 2) ]), $title, $this->year, $i );
 763                  }
 764                  elseif( $this->month == $i )
 765                  { // current month
 766                      echo $this->todaycellstart;
 767                      echo T_($month_abbrev[ zeroise($i, 2) ]);
 768                  }
 769                  else
 770                  {
 771                      echo $this->cellstart;
 772                      echo T_($month_abbrev[ zeroise($i, 2) ]);
 773                  }
 774                  echo $this->cellend;
 775                  if( $i == 4 || $i == 8 )
 776                  { // new row
 777                      echo $this->rowend.$this->rowstart;
 778                  }
 779              }
 780          }
 781          else // mode == 'month'
 782          {    // DISPLAY DAYS of current month:
 783              $dow = 0;
 784              $last_day = -1;
 785              $dom_displayed = 0; // days of month displayed
 786  
 787              for( $i = $calendarfirst; $i <= $calendarlast; $i = $i + 86400 )
 788              { // loop day by day (86400 seconds = 24 hours; but not on days where daylight saving changes!)
 789                  if( $dow == 7 )
 790                  { // We need to start a new row:
 791                      if( $dom_displayed >= $daysinmonth )
 792                      { // Last day already displayed!
 793                          break;
 794                      }
 795                      echo $this->rowend;
 796                      echo $this->rowstart;
 797                      $dow = 0;
 798                  }
 799                  $dow++;
 800  
 801                  // correct daylight saving ("last day"+86400 would lead to "last day at 23:00")
 802                  // fp> TODO: use mkdate()
 803                  while( date('j', $i) == $last_day )
 804                  {
 805                      $i += 3600;
 806                  }
 807                  $last_day = date('j', $i);
 808  
 809  
 810                  if (date('m', $i) != $this->month)
 811                  { // empty cell
 812                      echo $this->emptycellstart;
 813                      echo $this->emptycellcontent;
 814                      echo $this->emptycellend;
 815                  }
 816                  else
 817                  { // This day is in this month
 818                      $dom_displayed++;
 819                      $calendartoday = (date('Ymd',$i) == date('Ymd', (time() + $time_difference)));
 820  
 821                      if( isset($daysinmonthwithposts[ date('j', $i) ]) )
 822                      {
 823                          if( $calendartoday )
 824                          {
 825                              echo $this->todaycellstartpost;
 826                          }
 827                          else
 828                          {
 829                              echo $this->linkpostcellstart;
 830                          }
 831                          if( $daysinmonthwithposts[ date('j', $i) ] > 1 && !empty($this->postcount_month_atitle) )
 832                          { // display postcount
 833                              $title = sprintf($this->postcount_month_atitle, $daysinmonthwithposts[ date('j', $i) ]);
 834                          }
 835                          elseif( !empty($this->postcount_month_atitle_one) )
 836                          { // display postcount for one post
 837                              $title = sprintf($this->postcount_month_atitle_one, 1);
 838                          }
 839                          else
 840                          {
 841                              $title = '';
 842                          }
 843                          echo $this->archive_link( date('j',$i), $title, $this->year, $this->month, date('d',$i) );
 844                      }
 845                      elseif ($calendartoday)
 846                      {
 847                          echo $this->todaycellstart;
 848                          echo date('j',$i);
 849                      }
 850                      else
 851                      {
 852                          echo $this->cellstart;
 853                          echo date('j',$i);
 854                      }
 855                      echo $this->cellend;
 856                  }
 857              } // loop day by day
 858          } // mode == 'month'
 859  
 860          echo $this->rowend."</tbody>\n";
 861  
 862          echo $this->tableend;
 863  
 864      }  // display(-)
 865  
 866  
 867      /**
 868       * Create a link to archive, using either URL params or extra path info.
 869       *
 870       * Can make contextual links.
 871       *
 872       * @param string
 873       * @param string
 874       * @param string year
 875       * @param string month
 876       * @param string day
 877       */
 878  	function archive_link( $text, $title, $year, $month = NULL, $day = NULL )
 879      {
 880          /**
 881           * @var Blog
 882           */
 883          global $Blog;
 884  
 885          if( $this->link_type == 'context' )
 886          {    // We want to preserve context:
 887              $url_params = $this->itemlist_prefix.'m='.$year;
 888              if( !empty( $month ) )
 889              {
 890                  $url_params .= zeroise($month,2);
 891                  if( !empty( $day ) )
 892                  {
 893                      $url_params .= zeroise($day,2);
 894                  }
 895              }
 896              return '<a rel="nofollow" href="'.regenerate_url( $this->context_isolation, $url_params ).'">'.format_to_output($text).'</a>';
 897          }
 898          else
 899          {    // We want a canonic link:
 900              return $Blog->gen_archive_link( $text, $title, $year, $month, $day );
 901          }
 902      }
 903  
 904  
 905      /**
 906       * Get links to navigate between month / year.
 907       *
 908       * Unless min/max_timestamp='query' has been specified, this will not do any (time consuming!) queries to check where the posts are.
 909       *
 910       * @param string 'prev' / 'next'
 911       * @return array
 912       */
 913  	function getNavLinks( $direction )
 914      {
 915          global $DB, $localtimenow;
 916  
 917          //pre_dump( 'get_nav_links', $direction );
 918  
 919          $r = array();
 920  
 921          if( $this->params['min_timestamp'] == 'query' || $this->params['max_timestamp'] == 'query' )
 922          { // Do inits:
 923              // WE NEED SPECIAL QUERY PARAMS WHEN MOVING THOUGH MONTHS ( NO dstart especially! )
 924              $nav_ItemQuery = new ItemQuery( $this->dbtable, $this->dbprefix, $this->dbIDname );    // TEMP object
 925              // Restrict to selected blog/categories:
 926              $nav_ItemQuery->where_chapter2( $this->ItemQuery->Blog, $this->ItemQuery->cat_array, $this->ItemQuery->cat_modifier );
 927              // Restrict to the statuses we want to show:
 928              $nav_ItemQuery->where_visibility( $this->ItemQuery->show_statuses );
 929              // Restrict to selected authors:
 930              $nav_ItemQuery->where_author( $this->ItemQuery->author );
 931              // if a month is specified in the querystring, load that month:
 932              $nav_ItemQuery->where_datestart( /* NO m */'', /* NO w */'', /* NO dstart */'', '', $this->ItemQuery->timestamp_min, $this->ItemQuery->timestamp_max );
 933              // Keyword search stuff:
 934              $nav_ItemQuery->where_keywords( $this->ItemQuery->keywords, $this->ItemQuery->phrase, $this->ItemQuery->exact );
 935              // Exclude pages and intros:
 936              $nav_ItemQuery->where_types( $this->ItemQuery->types );
 937          }
 938  
 939          switch( $direction )
 940          {
 941              case 'prev':
 942                  //pre_dump( $this->params['min_timestamp'] );
 943                  $r[] = '';
 944  
 945                  if( empty($this->month) )
 946                  { // if $this->month is empty, we're in mode "year" with no selected month
 947                      $use_range_month = 12;
 948                      $use_range_day = 31;
 949                  }
 950                  else
 951                  {
 952                      $use_range_month = $this->month;
 953                      $use_range_day = 1;    // Note: cannot use current day since all months do not have same number of days
 954                  }
 955  
 956                  /*
 957                   * << (PREV YEAR)
 958                   */
 959                  if( $this->browseyears )
 960                  {    // We want arrows to move one year at a time
 961                      if( $this->params['min_timestamp'] == 'query' )
 962                      {    // Let's query to find the correct year:
 963                          if( $row = $DB->get_row(
 964                                  'SELECT EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) AS year,
 965                                                  EXTRACT(MONTH FROM '.$this->dbprefix.'datestart) AS month
 966                                      FROM ('.$this->dbtable.' INNER JOIN T_postcats ON '.$this->dbIDname.' = postcat_post_ID)
 967                                                  INNER JOIN T_categories ON postcat_cat_ID = cat_ID
 968                                      WHERE EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) < '.$this->year.'
 969                                                  '.$nav_ItemQuery->get_where( ' AND ' )
 970                                                  .$nav_ItemQuery->get_group_by( ' GROUP BY ' ).'
 971                                      ORDER BY EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) DESC, ABS( '.$use_range_month.' - EXTRACT(MONTH FROM '.$this->dbprefix.'datestart) ) ASC
 972                                      LIMIT 1', OBJECT, 0, 'Calendar: find prev year with posts' )
 973                              )
 974                          {
 975                              $prev_year_year = $row->year;
 976                              $prev_year_month = $row->month;
 977                          }
 978                      }
 979                      else
 980                      { // Let's see if the previous year is in the desired navigation range:
 981                          $prev_year_ts = mktime( 0, 0, 0, $use_range_month, $use_range_day,  $this->year-1 );
 982                          if( $prev_year_ts >= $this->params['min_timestamp'] )
 983                          {
 984                              $prev_year_year = date( 'Y', $prev_year_ts );
 985                              $prev_year_month = date( 'm', $prev_year_ts );
 986                          }
 987                      }
 988                  }
 989  
 990                  if( !empty($prev_year_year) )
 991                  {    // We have a link to display:
 992                      $r[] = $this->archive_link( '&lt;&lt;', sprintf(
 993                                                  ( $this->mode == 'month'
 994                                                          ? /* Calendar link title to a month in a previous year */ T_('Previous year (%04d-%02d)')
 995                                                          : /* Calendar link title to a previous year */ T_('Previous year (%04d)') ),
 996                                                  $prev_year_year, $prev_year_month ), $prev_year_year, ($this->mode == 'month') ? $prev_year_month : NULL ) ;
 997                  }
 998  
 999  
1000                  /*
1001                   * < (PREV MONTH)
1002                   */
1003                  if( $this->mode == 'month' )
1004                  { // We are browsing months, we'll display arrows to move one month at a time:
1005                      if( $this->params['min_timestamp'] == 'query' )
1006                      {    // Let's query to find the correct month:
1007                          if( $row = $DB->get_row(
1008                                  'SELECT EXTRACT(MONTH FROM '.$this->dbprefix.'datestart) AS month,
1009                                                  EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) AS year
1010                                  FROM ('.$this->dbtable.' INNER JOIN T_postcats ON '.$this->dbIDname.' = postcat_post_ID)
1011                                      INNER JOIN T_categories ON postcat_cat_ID = cat_ID
1012                                  WHERE
1013                                  (
1014                                      EXTACT(YEAR FROM '.$this->dbprefix.'datestart) < '.($this->year).'
1015                                      OR ( EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) = '.($this->year).'
1016                                                  AND EXTRACT(MONTH FROM '.$this->dbprefix.'datestart) < '.($this->month).'
1017                                              )
1018                                  )
1019                                  '.$nav_ItemQuery->get_where( ' AND ' )
1020                                   .$nav_ItemQuery->get_group_by( ' GROUP BY ' ).'
1021                                  ORDER BY EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) DESC, EXTRACT(MONTH FROM '.$this->dbprefix.'datestart) DESC
1022                                  LIMIT 1',
1023                                  OBJECT,
1024                                  0,
1025                                  'Calendar: Find prev month with posts' )
1026                              )
1027                          {
1028                              $prev_month_year = $row->year;
1029                              $prev_month_month = $row->month;
1030                          }
1031                      }
1032                      else
1033                      { // Let's see if the previous month is in the desired navigation range:
1034                          $prev_month_ts = mktime( 0, 0, 0, $this->month-1, 1, $this->year ); // Note: cannot use current day since all months do not have same number of days
1035                          if( $prev_month_ts >= $this->params['min_timestamp'] )
1036                          {
1037                              $prev_month_year = date( 'Y', $prev_month_ts );
1038                              $prev_month_month = date( 'm', $prev_month_ts );
1039                          }
1040                      }
1041                  }
1042  
1043                  if( !empty($prev_month_year) )
1044                  {    // We have a link to display:
1045                      $r[] = $this->archive_link( '&lt;', sprintf( T_('Previous month (%04d-%02d)'), $prev_month_year, $prev_month_month ), $prev_month_year, $prev_month_month );
1046                  }
1047                  break;
1048  
1049  
1050              case 'next':
1051                  //pre_dump( $this->params['max_timestamp'] );
1052  
1053                  /*
1054                   * > (NEXT MONTH)
1055                   */
1056                  if( $this->mode == 'month' )
1057                  { // We are browsing months, we'll display arrows to move one month at a time:
1058                      if( $this->params['max_timestamp'] == 'query' )
1059                      {    // Let's query to find the correct month:
1060                          if( $row = $DB->get_row(
1061                                  'SELECT EXTRACT(MONTH FROM '.$this->dbprefix.'datestart) AS month,
1062                                                  EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) AS year
1063                                  FROM ('.$this->dbtable.' INNER JOIN T_postcats ON '.$this->dbIDname.' = postcat_post_ID)
1064                                      INNER JOIN T_categories ON postcat_cat_ID = cat_ID
1065                                  WHERE
1066                                  (
1067                                      EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) > '.($this->year).'
1068                                      OR ( EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) = '.($this->year).'
1069                                                  AND EXTRACT(MONTH FROM '.$this->dbprefix.'datestart) > '.($this->month).'
1070                                              )
1071                                  )
1072                                  '.$nav_ItemQuery->get_where( ' AND ' )
1073                                   .$nav_ItemQuery->get_group_by( ' GROUP BY ' ).'
1074                                  ORDER BY EXTRACT(YEAR FROM '.$this->dbprefix.'datestart), EXTRACT(MONTH FROM '.$this->dbprefix.'datestart) ASC
1075                                  LIMIT 1',
1076                                  OBJECT,
1077                                  0,
1078                                  'Calendar: Find next month with posts' )
1079                              )
1080                          {
1081                              $next_month_year = $row->year;
1082                              $next_month_month = $row->month;
1083                          }
1084                      }
1085                      else
1086                      { // Let's see if the next month is in the desired navigation range:
1087                          $next_month_ts = mktime( 0, 0, 0, $this->month+1, 1,  $this->year ); // Note: cannot use current day since all months do not have same number of days
1088                          if( $next_month_ts <= $this->params['max_timestamp'] )
1089                          {
1090                              $next_month_year = date( 'Y', $next_month_ts );
1091                              $next_month_month = date( 'm', $next_month_ts );
1092                          }
1093                      }
1094                  }
1095  
1096                  if( !empty($next_month_year) )
1097                  {    // We have a link to display:
1098                      $r[] = $this->archive_link( '&gt;', sprintf( T_('Next month (%04d-%02d)'), $next_month_year, $next_month_month ), $next_month_year, $next_month_month );
1099                  }
1100  
1101  
1102                  if( empty($this->month) )
1103                  { // if $this->month is empty, we're in mode "year" with no selected month
1104                      $use_range_month = 12;
1105                      $use_range_day = 31;
1106                  }
1107                  else
1108                  {
1109                      $use_range_month = $this->month;
1110                      $use_range_day = 1;    // Note: cannot use current day since all months do not have same number of days
1111                  }
1112  
1113                  /*
1114                   * >> (NEXT YEAR)
1115                   */
1116                  if( $this->browseyears )
1117                  { // We want arrows to move one year at a time
1118                      if( $this->params['max_timestamp'] == 'query' )
1119                      {    // Let's query to find the correct year:
1120                      if( $row = $DB->get_row(
1121                              'SELECT EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) AS year,
1122                                              EXTRACT(MONTH FROM '.$this->dbprefix.'datestart) AS month
1123                                  FROM ('.$this->dbtable.' INNER JOIN T_postcats ON '.$this->dbIDname.' = postcat_post_ID)
1124                                      INNER JOIN T_categories ON postcat_cat_ID = cat_ID
1125                                  WHERE EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) > '.$this->year.'
1126                                   '.$nav_ItemQuery->get_where( ' AND ' )
1127                                   .$nav_ItemQuery->get_group_by( ' GROUP BY ' ).'
1128                                  ORDER BY EXTRACT(YEAR FROM '.$this->dbprefix.'datestart) ASC, ABS( '.$use_range_month.' - EXTRACT(MONTH FROM '.$this->dbprefix.'datestart) ) ASC
1129                                  LIMIT 1', OBJECT, 0, 'Calendar: find next year with posts' )
1130                          )
1131                          {
1132                              $next_year_year = $row->year;
1133                              $next_year_month = $row->month;
1134                          }
1135                      }
1136                      else
1137                      { // Let's see if the next year is in the desired navigation range:
1138                          $next_year_ts = mktime( 0, 0, 0, $use_range_month, $use_range_day,  $this->year+1 );
1139                          if( $next_year_ts <= $this->params['max_timestamp'] )
1140                          {
1141                              $next_year_year = date( 'Y', $next_year_ts );
1142                              $next_year_month = date( 'm', $next_year_ts );
1143                          }
1144                      }
1145  
1146                  if( !empty($next_year_year) )
1147                  {    // We have a link to display:
1148                          $r[] = $this->archive_link( '&gt;&gt;', sprintf(
1149                                                                      ( $this->mode == 'month'
1150                                                                              ? /* Calendar link title to a month in a following year */ T_('Next year (%04d-%02d)')
1151                                                                              : /* Calendar link title to a following year */ T_('Next year (%04d)') ),
1152                                                                      $next_year_year, $next_year_month ), $next_year_year, ($this->mode == 'month') ? $next_year_month : NULL );
1153                      }
1154                  }
1155                  break;
1156          }
1157  
1158          return $r;
1159      }
1160  
1161  }
1162  
1163  ?>

title

Description

title

Description

title

Description

title

title

Body