コード例 #1
0
ファイル: check.php プロジェクト: rair/yacs
     return;
     // parse the whole list
 } else {
     // fetch one anchor and the linked member
     $errors_count = 0;
     while ($row = SQL::fetch($result)) {
         // animate user screen and take care of time
         $count++;
         if (!($count % 100)) {
             $context['text'] .= sprintf(i18n::s('%d records have been processed'), $count) . BR . "\n";
             // ensure enough execution time
             Safe::set_time_limit(30);
         }
         // check that the anchor exists, if any
         if ($row['anchor'] && !Anchors::get($row['anchor'])) {
             $context['text'] .= sprintf(i18n::s('Orphan: %s'), 'date ' . Skin::build_link(Dates::get_url($row['id']), $row['id'] . ' ' . $row['date_stamp'])) . BR . "\n";
             if (++$errors_count >= 25) {
                 $context['text'] .= i18n::s('Too many successive errors. Aborted') . BR . "\n";
                 break;
             }
         } else {
             $errors_count = 0;
         }
     }
 }
 // ending message
 $context['text'] .= sprintf(i18n::s('%d records have been processed'), $count) . BR . "\n";
 // display the execution time
 $time = round(get_micro_time() - $context['start_time'], 2);
 $context['text'] .= '<p>' . sprintf(i18n::s('Script terminated in %.2f seconds.'), $time) . '</p>';
 // forward to the index page
コード例 #2
0
ファイル: view.php プロジェクト: rair/yacs
        $context['text'] .= Skin::build_block(Skin::finalize_list($menu, 'menu_bar'), 'bottom');
    }
    //
    // populate the extra panel
    //
    // commands for associates and editors
    if (Surfer::is_associate() || is_object($anchor) && $anchor->is_assigned()) {
        $context['page_tools'][] = Skin::build_link(Dates::get_url($id, 'edit'), i18n::s('Edit'));
        $context['page_tools'][] = Skin::build_link(Dates::get_url($id, 'delete'), i18n::s('Delete'));
        // commands for the author
    } elseif (Surfer::is($item['edit_id'])) {
        $context['page_tools'][] = Skin::build_link(Dates::get_url($id, 'edit'), i18n::s('Edit'));
    }
    // the navigation sidebar
    //
    // buttons to display previous and next pages, if any
    if (is_object($anchor)) {
        $neighbours = $anchor->get_neighbours('date', $item);
        $text .= Skin::neighbours($neighbours, 'sidebar');
    }
    // build a nice sidebar box
    if ($text) {
        $text =& Skin::build_box(i18n::s('Navigation'), $text, 'neighbours', 'neighbours');
    }
    $context['components']['neighbours'] = $text;
    // the referrals, if any, in a sidebar
    //
    $context['components']['referrals'] =& Skin::build_referrals(Dates::get_url($item['id']));
}
// render the skin
render_skin();
コード例 #3
0
ファイル: day.php プロジェクト: rair/yacs
        $cache_id = 'dates/day.php#text#' . $target;
        if (!($text = Cache::get($cache_id))) {
            // draw one day
            if ($items = Dates::list_for_day($year, $month, $day, 'decorated')) {
                $text .= Skin::build_list($items, 'decorated');
            } else {
                $text .= '<p>' . i18n::s('Nothing has been recorded for this date.') . '</p>';
            }
            // robots cannot navigate
            if (!Surfer::is_crawler()) {
                // previous day
                $previous = gmstrftime('%Y/%m/%d', gmmktime(0, 0, 0, $month, $day - 1, $year));
                // next day
                $next = gmstrftime('%Y/%m/%d', gmmktime(0, 0, 0, $month, $day + 1, $year));
                // neighbours
                $neighbours = array(Dates::get_url($previous, 'day'), Skin::build_date($previous, 'standalone'), Dates::get_url($next, 'day'), Skin::build_date($next, 'standalone'), Dates::get_url($year . '/' . $month, 'month'), Dates::get_month_label($year . '/' . $month));
                // links to display previous and next days
                $text .= Skin::neighbours($neighbours, 'slideshow');
            }
            // cache, whatever change, for 1 minute
            Cache::put($cache_id, $text, 'stable', 60);
        }
        // in the main panel
        $context['text'] .= $text;
    }
}
// side bar with the list of most recent pages
$cache_id = 'dates/day.php#extra';
if (!($text = Cache::get($cache_id))) {
    if ($items =& Articles::list_by('publication', 0, COMPACT_LIST_SIZE, 'compact')) {
        $text =& Skin::build_box(i18n::s('Recent pages'), Skin::build_list($items, 'compact'), 'boxes');
コード例 #4
0
ファイル: edit.php プロジェクト: rair/yacs
        $follow_up = i18n::s('What do you want to do now?');
        $menu = array();
        $menu = array_merge($menu, array($anchor->get_url() => i18n::s('View the page')));
        $menu = array_merge($menu, array($anchor->get_url('edit') => i18n::s('Edit the page')));
        $follow_up .= Skin::build_list($menu, 'menu_bar');
        $context['text'] .= Skin::build_block($follow_up, 'bottom');
        // update of an existing date
    } else {
        // increment the post counter of the surfer
        Users::increment_posts(Surfer::get_id());
        // touch the related anchor
        $anchor->touch('date:update', $_REQUEST['id'], isset($_REQUEST['silent']) && $_REQUEST['silent'] == 'Y');
        // clear cache
        Dates::clear($_REQUEST);
        // forward to the view page
        Safe::redirect($context['url_to_home'] . $context['url_to_root'] . Dates::get_url($_REQUEST['id']));
    }
    // display the form on GET
} else {
    $with_form = TRUE;
}
// display the form
if ($with_form) {
    // reference the anchor page
    if (is_object($anchor) && $anchor->is_viewable()) {
        $context['text'] .= '<p>' . Skin::build_link($anchor->get_url(), $anchor->get_title()) . "</p>\n";
    }
    // the form to edit an date
    $context['text'] .= '<form method="post" action="' . $context['script_url'] . '" onsubmit="return validateDocumentPost(this)" id="main_form"><div>';
    // form fields
    $fields = array();
コード例 #5
0
ファイル: skin_skeleton.php プロジェクト: rair/yacs
 /**
  * Format a date
  *
  * Accept either a time stamp, or a formatted string as input parameter:
  * - YYYY-MM-DD HH:MM:SS
  * - YYMMDD HH:MM:SS GMT
  *
  * The variant is processed as follows:
  * - 'day' - only day, month and year --no time information
  * - 'with_hour' - adapts to time scale, and mention hours for today and yesterday
  * - 'no_hour' - adapts to time scale, but don't mention hours
  * - 'full' - display the full date
  * - 'month' - only month and year
  * - 'publishing' - allows for smart skinning
  * - 'standalone' - like full, but without the 'on ' prefix
  * - 'iso8601' - special format
  * - 'plain' - example 'Feb 26 2010 22:30:31 GMT'
  * - 'yyyy-mm-dd' - only day, month and year --no time information
  *
  * The date provided is considered to be GMT-based.
  * It is adjusted to the time zone of the surfer, if applicable.
  * This adjustment does not apply to following variants:
  * - 'day'
  * - 'iso8601'
  * - 'standalone'
  *
  *
  * @link http://www.w3.org/TR/NOTE-datetime the w3c profile of ISO 8601
  * @link http://www.cs.tut.fi/~jkorpela/iso8601.html short description of ISO 8601
  * @link http://fr2.php.net/date Code for ISO 8601 formatting
  *
  * @param int or string the date to be displayed
  * @param string the variant
  * @param string the language to express this stamp
  * @param int offset to GMT of the provided date, if any
  * @return the HTML to be used
  */
 public static function &build_date($stamp, $variant = 'with_hour', $language = NULL, $gmt_offset = 0)
 {
     global $context, $local;
     // return by reference
     $output = '';
     // sanity check
     if (!isset($stamp) || !$stamp) {
         return $output;
     }
     // surfer offset, except on 'day' and 'iso8601'
     if ($variant == 'day' || $variant == 'iso8601' || $variant == 'standalone' || $variant == 'local') {
         $surfer_offset = 0;
     } else {
         $surfer_offset = Surfer::get_gmt_offset();
     }
     // YYMMDD-HH:MM:SS GMT -- this one is natively GMT
     if (preg_match('/GMT$/', $stamp) && strlen($stamp) == 19) {
         // YYMMDD-HH:MM:SS GMT -> HH, MM, SS, MM, DD, YY
         $actual_stamp = mktime(substr($stamp, 7, 2), substr($stamp, 10, 2), substr($stamp, 13, 2), substr($stamp, 2, 2), substr($stamp, 4, 2), substr($stamp, 0, 2));
         // adjust to surfer time zone
         $actual_stamp += $surfer_offset * 3600;
         // time()-like stamp
     } elseif (intval($stamp) > 10000000) {
         // adjust to surfer time zone
         $actual_stamp = intval($stamp) + ($surfer_offset - $gmt_offset) * 3600;
         // YYYY-MM-DD HH:MM:SS, or a string that can be readed
     } elseif (($actual_stamp = strtotime($stamp)) != -1) {
         // adjust to surfer time zone
         $actual_stamp += ($surfer_offset - $gmt_offset) * 3600;
     } else {
         $output = '*' . $stamp . '*';
         return $output;
     }
     if (!($items = @getdate($actual_stamp))) {
         $output = '*' . $stamp . '*';
         return $output;
     }
     // if undefined language, use preferred language for absolute formats
     if ($language) {
     } elseif ($variant == 'full' || $variant == 'iso8601' || $variant == 'local') {
         $language = $context['preferred_language'];
     } else {
         $language = $context['language'];
     }
     // in French '1' -> '1er'
     if ($language == 'fr' && $items['mday'] == 1) {
         $items['mday'] = '1er';
     }
     // allow for months localization through i18n
     $months = array('*', i18n::s('Jan.'), i18n::s('Feb.'), i18n::s('Mar.'), i18n::s('Apr.'), i18n::s('May'), i18n::s('June'), i18n::s('Jul.'), i18n::s('Aug.'), i18n::s('Sep.'), i18n::s('Oct.'), i18n::s('Nov.'), i18n::s('Dec.'));
     // load month labels adapted to required language
     $months = array('*', i18n::lookup($context['l10n'][$language], 'Jan.'), i18n::lookup($context['l10n'][$language], 'Feb.'), i18n::lookup($context['l10n'][$language], 'Mar.'), i18n::lookup($context['l10n'][$language], 'Apr.'), i18n::lookup($context['l10n'][$language], 'May'), i18n::lookup($context['l10n'][$language], 'June'), i18n::lookup($context['l10n'][$language], 'Jul.'), i18n::lookup($context['l10n'][$language], 'Aug.'), i18n::lookup($context['l10n'][$language], 'Sep.'), i18n::lookup($context['l10n'][$language], 'Oct.'), i18n::lookup($context['l10n'][$language], 'Nov.'), i18n::lookup($context['l10n'][$language], 'Dec.'));
     // now
     $now = time();
     // server actual offset -- provided as a parameter
     //		$gmt_offset = intval((strtotime(date('M d Y H:i:s')) - strtotime(gmdate('M d Y H:i:s'))) / 3600);
     // server stamp, as seen by surfer
     $today = getdate($now + ($surfer_offset - $gmt_offset) * 3600);
     // time stamp only
     if (preg_match('/00:00/', date('H:i', $actual_stamp))) {
         $time = '';
     } else {
         $trailer = '';
         if (!$surfer_offset && $variant !== 'local') {
             $trailer = ' GMT';
         }
         $time = sprintf(i18n::s(' at %s%s'), date(i18n::s('h:i a'), $actual_stamp), $trailer);
     }
     // format a date as an absolute string
     if ($variant == 'full' || $variant == 'local') {
         if ($language == 'fr') {
             $output .= $items['mday'] . ' ' . $months[$items['mon']] . ' ' . $items['year'] . $time;
         } else {
             $output .= $months[$items['mon']] . ' ' . $items['mday'] . ' ' . $items['year'] . $time;
         }
         return $output;
     }
     // publishing date is in the future
     if ($variant == 'publishing' && strcmp($stamp, $context['now']) > 0) {
         $output .= DRAFT_FLAG;
     }
     // allow for smart skinning -- http://www.wplover.com/1449/easier-date-display-technique-with-css-3/
     if ($variant == 'publishing') {
         $output .= '<span class="day">' . $items['mday'] . '</span>' . '<span class="month">' . $months[$items['mon']] . '</span>' . '<span class="year">' . $items['year'] . '</span>';
         return $output;
     }
     // the same, but without prefix
     if ($variant == 'standalone') {
         if ($language == 'fr') {
             $output .= $items['mday'] . ' ' . $months[$items['mon']] . ' ' . $items['year'] . $time;
         } else {
             $output .= $months[$items['mon']] . ' ' . $items['mday'] . ' ' . $items['year'] . $time;
         }
         return $output;
     }
     // month only
     if ($variant == 'month') {
         if ($language == 'fr') {
             $output .= $months[$items['mon']] . ' ' . $items['year'];
         } else {
             $output .= $months[$items['mon']] . ' ' . $items['year'];
         }
         return $output;
     }
     // day only
     if ($variant == 'day') {
         // same year, don't mention it
         if ($items['year'] == $today['year']) {
             if ($language == 'fr') {
                 $output .= $items['mday'] . ' ' . $months[$items['mon']];
             } else {
                 $output .= $months[$items['mon']] . ' ' . $items['mday'];
             }
             // different year
         } else {
             if ($language == 'fr') {
                 $output .= $items['mday'] . ' ' . $months[$items['mon']] . ' ' . $items['year'];
             } else {
                 $output .= $months[$items['mon']] . ' ' . $items['mday'] . ' ' . $items['year'];
             }
         }
         return $output;
     }
     // in a calendar
     if ($variant == 'calendar') {
         include_once $context['path_to_root'] . 'dates/dates.php';
         $month_link =& Skin::build_link(Dates::get_url($items['year'] . '/' . $items['mon'], 'month'), $months[$items['mon']], 'basic', i18n::s('Calendar of this month'));
         $year_link =& Skin::build_link(Dates::get_url($items['year'], 'year'), $items['year'], 'basic', i18n::s('Calendar of this year'));
         if ($language == 'fr') {
             $output .= $items['mday'] . ' ' . $month_link . ' ' . $year_link;
         } else {
             $output .= $month_link . ' ' . $items['mday'] . ' ' . $year_link;
         }
         return $output;
     }
     // format a date according to ISO 8601 format
     if ($variant == 'iso8601') {
         $tzd = date('O', $actual_stamp);
         $tzd = $tzd[0] . str_pad((int) ($tzd / 100), 2, "0", STR_PAD_LEFT) . ':' . str_pad((int) ($tzd % 100), 2, "0", STR_PAD_LEFT);
         $output = date('Y-m-d\\TH:i:s', $actual_stamp) . $tzd;
         return $output;
     }
     // format a raw date
     if ($variant == 'yyyy-mm-dd') {
         $output = date('Y-m-d', $actual_stamp);
         return $output;
     }
     // plain date
     if ($variant == 'plain') {
         $output = date('M d Y H:i:s', $actual_stamp) . ' GMT';
         return $output;
     }
     // less than 24 hours
     if ($items['yday'] == $today['yday'] && $items['year'] == $today['year']) {
         $time = date('H:i', $actual_stamp);
         if ($variant == 'no_hour' || preg_match('/00:00/', $time)) {
             $local['today_en'] = 'today';
             $local['today_fr'] = 'aujourd\'hui';
         } else {
             $trailer = '';
             if (!$surfer_offset) {
                 $trailer = ' GMT';
             }
             $local['today_en'] = 'today at ' . date('h:i a', $actual_stamp) . $trailer;
             $local['today_fr'] = 'aujourd\'hui &agrave; ' . date('H:i', $actual_stamp) . $trailer;
         }
         $output = i18n::user('today');
         return $output;
         // less than 48 hours
     } elseif ($items['yday'] + 1 == $today['yday'] && $items['year'] == $today['year']) {
         $time = date('H:i', $actual_stamp);
         if ($variant == 'no_hour' || preg_match('/00:00/', $time)) {
             $local['yesterday_en'] = 'yesterday';
             $local['yesterday_fr'] = 'hier';
         } else {
             $trailer = '';
             if (!$surfer_offset) {
                 $trailer = ' GMT';
             }
             $local['yesterday_en'] = 'yesterday at ' . date('h:i a', $actual_stamp) . $trailer;
             $local['yesterday_fr'] = 'hier &agrave; ' . date('H:i', $actual_stamp) . $trailer;
         }
         $output = i18n::user('yesterday');
         return $output;
         // this year
     } elseif ($stamp <= $now && $items['year'] == $today['year']) {
         if ($language == 'fr') {
             $output .= 'le ' . $items['mday'] . ' ' . $months[$items['mon']];
         } else {
             $output .= 'on ' . $months[$items['mon']] . ' ' . $items['mday'];
         }
         return $output;
         // date in fr: le dd mmm yy
     } elseif ($language == 'fr') {
         $output .= 'le ' . $items['mday'] . ' ' . $months[$items['mon']] . ' ' . $items['year'];
         // date in en: on mmm dd yy
     } else {
         $output .= 'on ' . $months[$items['mon']] . ' ' . $items['mday'] . ' ' . $items['year'];
     }
     $output .= $time ? ' ' . $time : '';
     return $output;
 }
コード例 #6
0
ファイル: dates.php プロジェクト: rair/yacs
 /**
  * produce monthly views for provided items
  *
  * @parameter array of $url => ($prefix, $label, $suffix, $type, $icon, $date)
  * @parameter boolean if TRUE, add links to yearly and monthly views
  * @parameter boolean if FALSE, do no display month caption
  * @parameter boolean if FALSE, do not label days in week
  * @parameter boolean if TRUE, display day content below the calendar
  * @parameter int forced year, in case no dates are provided
  * @parameter int forced month, in case no dates are provided
  * @return a string to be put in the web page
  */
 public static function &build_months($dates, $with_zoom = FALSE, $with_caption = TRUE, $with_headers = TRUE, $compact = FALSE, $forced_year = NULL, $forced_month = NULL, $style = "month calendar")
 {
     global $context;
     // we return some text
     $text = '';
     // nothing done yet
     $current_year = $current_month = $current_day = NULL;
     $day_content = array();
     // day details
     static $day_panel_index;
     if (!isset($day_panel_index)) {
         $day_panel_index = 1;
     }
     $day_panel_id = 'day_panel_' . $day_panel_index++;
     // process all dates
     foreach ($dates as $date_link => $date_attributes) {
         // look at this date
         list($prefix, $label, $suffix, $type, $icon, $date) = $date_attributes;
         $year = intval(substr($date, 0, 4));
         $month = intval(substr($date, 5, 2));
         $day = intval(substr($date, 8, 2));
         // flush previous day, if any
         if ($day_content && ($day != $current_day || $month != $current_month || $year != $current_year)) {
             $text .= '<td class="spot">' . Dates::build_day($current_day, $day_content, $day_panel_id, $compact) . '</td>';
             $current_day++;
             if (++$day_in_week >= W_END_DAY) {
                 $day_in_week = W_START_DAY;
                 $text .= '</tr><tr>';
             }
             $day_content = array();
         }
         // use the image as a link to the target page
         if ($icon) {
             // fix relative path
             if (!preg_match('/^(\\/|http:|https:|ftp:)/', $icon)) {
                 $icon = $context['url_to_root'] . $icon;
             }
             // build the complete HTML element
             $icon = Skin::build_link($date_link, '<img src="' . $icon . '" alt="" title="' . encode_field($label) . '" />', 'overlaid') . BR;
         }
         // content for this date
         $day_content[] = $icon . $prefix . Skin::build_link($date_link, $label, 'overlaid') . $suffix;
         // close current month
         if ($current_month && $month != $current_month) {
             $text .= Dates::build_month_suffix($current_year, $current_month, $current_day);
         }
         // move to month for this date
         while (!$current_year && !$current_month && !$current_day || $month != $current_month) {
             if (!$current_month) {
                 $current_year = $year;
                 $current_month = $month;
             } else {
                 if (++$current_month > 12) {
                     $current_year++;
                     $current_month = 1;
                 }
             }
             // add a caption
             $title = '';
             if ($with_caption) {
                 // month title
                 $title = ucfirst(Dates::get_month_label($current_month)) . ' ' . $current_year;
                 // zoom to the monthly view
                 if ($with_zoom) {
                     $title = Skin::build_link(Dates::get_url($current_year . '/' . $current_month, 'month'), $title, 'month');
                 }
             }
             // first day of this month
             $first_of_month = gmmktime(0, 0, 0, $month, 1, $year);
             // day in week for the first day of the month
             //$day_in_week = (int)gmstrftime(STRFTIME_FORMAT, $first_of_month);
             $day_in_week = gmstrftime(STRFTIME_FORMAT, $first_of_month);
             $day_in_week = Dates::day2num($day_in_week);
             // start a new month
             $current_day = 1;
             $text .= Dates::build_month_prefix($current_year, $current_month, $day_in_week, $style, $title, $with_headers);
             // not yet at the target month, close an empty month
             if ($month != $current_month) {
                 $text .= Dates::build_month_suffix($current_year, $current_month, $current_day);
             }
         }
         // fill in gaps
         while ($current_day < $day) {
             $text .= '<td>' . $current_day++ . '</td>';
             // start a new week on next row
             if (++$day_in_week >= W_END_DAY) {
                 $day_in_week = W_START_DAY;
                 $text .= '</tr><tr>';
             }
         }
     }
     // flush previous day
     if ($day_content) {
         $text .= '<td class="spot">' . Dates::build_day($current_day++, $day_content, $day_panel_id, $compact) . '</td>';
     }
     // close last month, if any
     if ($current_month) {
         $text .= Dates::build_month_suffix($current_year, $current_month, $current_day);
     }
     // draw an empty calendar, if required
     if (!$text && $forced_year) {
         // one single month
         if ($forced_month > 0) {
             // add a caption
             $title = '';
             if ($with_caption) {
                 // month title
                 $title = ucfirst(Dates::get_month_label($forced_month)) . ' ' . $forced_year;
                 // zoom to the monthly view
                 if ($with_zoom) {
                     $title = Skin::build_link(Dates::get_url($forced_year . '/' . $forced_month, 'month'), $title, 'month');
                 }
             }
             $text .= Dates::build_month_prefix($forced_year, $forced_month, -1, $style, $title, $with_headers) . Dates::build_month_suffix($forced_year, $forced_month, 1);
         }
     }
     // empty rows are not allowed
     $text = str_replace('<tr></tr>', '', $text);
     // an area to display date details
     $text .= '<div id="' . $day_panel_id . '" class="day_panel" ></div>';
     // done
     return $text;
 }
コード例 #7
0
ファイル: year.php プロジェクト: rair/yacs
// no more than three years difference with now
if (abs(mktime(0, 0, 0, 1, 1, $year) - time()) > 31536000 * 3) {
    Safe::header('Status: 401 Unauthorized', TRUE, 401);
    Logger::error(i18n::s('You are not allowed to perform this operation.'));
} else {
    // page main content
    $cache_id = 'dates/year.php#text#' . $year;
    if (!($text = Cache::get($cache_id))) {
        // robots cannot navigate
        if (!Surfer::is_crawler()) {
            // previous year
            $previous = $year - 1;
            // next year
            $next = $year + 1;
            // neighbours
            $neighbours = array(Dates::get_url($previous, 'year'), $previous, Dates::get_url($next, 'year'), $next, NULL, NULL);
            // links to display previous and next years
            $text .= Skin::neighbours($neighbours, 'slideshow');
        }
        // one calendar per month
        for ($index = 1; $index <= 12; $index++) {
            // items for this month
            $items =& Dates::list_for_month($year, $index, 'links');
            // draw all months - force empty months
            $text .= Dates::build_months($items, TRUE, TRUE, TRUE, FALSE, $year, $index);
        }
        // cache, whatever change, for 5 minutes
        Cache::put($cache_id, $text, 'stable', 300);
    }
    $context['text'] .= $text;
}
コード例 #8
0
ファイル: month.php プロジェクト: rair/yacs
    // no more than two years difference with now
    if (abs(mktime(0, 0, 0, $month, 1, $year) - time()) > 31536000 * 2) {
        Safe::header('Status: 401 Unauthorized', TRUE, 401);
        Logger::error(i18n::s('You are not allowed to perform this operation.'));
    } else {
        // page main content
        $cache_id = 'dates/month.php#text#' . $target;
        if (!($text = Cache::get($cache_id))) {
            // robots cannot navigate
            if (!Surfer::is_crawler()) {
                // previous month
                $previous = gmstrftime('%Y/%m', gmmktime(0, 0, 0, $month - 1, 1, $year));
                // next month
                $next = gmstrftime('%Y/%m', gmmktime(0, 0, 0, $month + 1, 1, $year));
                // neighbours
                $neighbours = array(Dates::get_url($previous, 'month'), Dates::get_month_label($previous), Dates::get_url($next, 'month'), Dates::get_month_label($next), Dates::get_url($year, 'year'), $year);
                // links to display previous and next months
                $text .= Skin::neighbours($neighbours, 'slideshow');
            }
            // get items for this month
            $items =& Dates::list_for_month($year, $month, 'links');
            // draw one month - force an empty month
            $text .= Dates::build_months($items, FALSE, FALSE, TRUE, FALSE, $year, $month);
            // cache, whatever change, for 5 minutes
            Cache::put($cache_id, $text, 'stable', 300);
        }
        $context['text'] .= $text;
    }
}
// page extra content
$cache_id = 'dates/month.php#extra';