I plan on releasing Ditto 2.0.1, the first episode of the Ditto screen cast, and an updated version of DittoCal on Sunday. Please download a dev copy of Ditto from
http://www.modxcms.com/ditto_download.html and put it through its paces. I’ll post a dev copy to the public a little later (its 3am now... I must sleep!). You can get a sneak peek of the screencast at
http://ditto.modxcms.com/screencast/episode_001.mov. I’ve attached a copy of the DittoCal snippet code (for use with Ditto 2.0.1) to the end of this post (the JSON class is the same).
As usual please keep the previews internal. Thanks.
<?php
/* -------------------------------------------------------------
:: Snippet: DittoCal
----------------------------------------------------------------
Short Description:
Calendar to display blog post navigation.
Version:
1.2
Created by:
Kyle Jaebker (kylej - [email protected])
Modified by:
Mark Kaplan (modxcms.com)
Date:
18-Mar-07
Required Usage:
[!DittoCal?calSource=``!]
You must create a new document with the following settings:
template: blank
show in menu: no
published: yes
searchable: no
content type: text/plain
document content:
[!Ditto? &parents=`yourblogfolder` &display=`all` &format=`json`!]
This document is used to output your post data so that it
can be read into the calendar. You should set the startId
to your blog folder and set summarize to the max number
of posts you expect to have. Leave everything else the same
as above.
Changelog:
18-MAR-07 - Made compatible with Ditto 2.0.1. Added &id and &landing for use
with Ditto. If you have a Ditto call on the document with the same id as
&landing and ID as &id with &extenders=`dateFilter`, DittoCal will pass
the required information to filter the results to only show documents on
that day.
17-JUL-06 - Added code to remove next link if next month is past the most
recent post. If day is clicked on calendar the calendar will remain on
that month when new page is loaded. A new class will be assigned to the
day that was selected as well. Added placeholder output support and debug
output.
----------------------------------------------------------------
:: Description
----------------------------------------------------------------
DittoCal creates a small monthly calendar to display links
to your blog posts. The initial display shows the month
of your latest blog post.
----------------------------------------------------------------
:: Parameters
----------------------------------------------------------------
calSource - the path to the document created above
(i.e. http://www.muddydogpaws.com/blog_json)
linkClass - class for date links
dayNameLength - how many characters of the day to display (default: 3)
firstDay - first day of the week (default: 0)
values: 0 - sunday
1 - monday
2 - tuesday
3 - wednesday
4 - thursday
5 - friday
6 - saturday
showPn - show the previous/next links [1 | 0] (default: 1)
debug - set to 1 for debug output [1 | 0] (default: 0)
ph - name of placeholder to output to
activeDay - class for the day clicked in calendar
id - Ditto ID
landing - document id of the document containing a Ditto call with &id=`id` and &extenders=`dateFilter`
----------------------------------------------------------------
:: Example Call
----------------------------------------------------------------
[!DittoCal? &calSource=`http://www.muddydogpaws.com/blog_json` &dayNameLength=`1`!]
----------------------------------------------------------------
:: Credits
----------------------------------------------------------------
The code to generate the calendar was provided by:
PHP Calendar (version 2.3), written by Keith Devens
http://keithdevens.com/software/php_calendar
see example at http://keithdevens.com/weblog
License: http://keithdevens.com/software/license
------------------------------------------------------------- */
$prefix = isset($id) ? $id : "cal";
$landing = isset($landing) ? $landing : 0;
$calSource = isset($calSource) ? $calSource : 0;
$linkClass = isset($linkClass) ? $linkClass : 'cal_link';
$dayNameLength = isset($dayNameLength) ? $dayNameLength : 3;
$firstDay = isset($firstDay) ? $firstDay : 0;
$showPn = isset($showPn) ? $showPn : 1;
$debug = isset($debug) ? $debug : 0;
$ph = isset($ph) ? $ph : 0;
$activeDay = isset($activeDay) ? $activeDay : 'curDay';
$snippetPath = $modx->config['base_path'] . 'assets/snippets/';
require_once($snippetPath.'DittoCal/JSON.php');
//Set this array if you want a link for the month
/*
$monthLinks = array(
'2006' => array(
'03'=>'http://www.muddydogpaws.com/json_test',
'04'=>'http://www.muddydogpaws.com/notebook')
);
*/
if (!$calSource) {
return 'You must specify a source for your calendar.';
}
//Get the json formatted data
$source = file_get_contents($calSource);
if ($debug) {
$debugOutput .= '<h2>DittoCal Debug Output</h2>';
$debugOutput .= '<h3>Initial Data from Json</h3>';
$debugOutput .= '<pre>' . print_r($source,TRUE) . '</pre>';
}
// create a new instance of Services_JSON
if (class_exists(Services_JSON)) {
$json = new Services_JSON();
} else {
return 'The class Services_JSON could not be found. Make sure you have the file JSON.php in the directory assets/snippets/DittoCal';
}
$postData = $json->decode($source);
if ($debug) {
$debugOutput .= '<h3>Data after JSON decoding</h3>';
$debugOutput .= '<pre>' . print_r($postData,TRUE) . '</pre>';
}
//Use the month & year passed-in if set else use first post as month & year
if (isset($_GET['cal_month']) && isset($_GET['cal_year'])) {
$filterMonth = $_GET['cal_month'];
$filterYear = $_GET['cal_year'];
} else {
$timestamp = getDate($postData->entries[0]->date);
$filterMonth = $timestamp["mon"];
$filterYear = $timestamp["year"];
}
if ($debug) {
$debugOutput .= '<h3>Filter Settings</h3>';
$debugOutput .= '<p>Filter Month: ' . $filterMonth . '<br/>Filter Year: ' . $filterYear . '</p>';
}
$cal_days = array();
//Filter out posts that are not in the specified month & year, set the link
if (is_array($postData->entries)) {
foreach($postData->entries as $n => $v) {
$vTimestamp = getDate($v->date);
$checkMonth = $vTimestamp["mon"];
$checkYear = $vTimestamp["year"];
if (($checkMonth != $filterMonth) || ($checkYear != $filterYear)) {
unset($postData->entries[$n]);
} else {
$theDay = $vTimestamp["mday"];
$url = ($landing === 0) ? $v->link : $modx->makeURL($landing);
if($modx->config['friendly_urls']) {
$dayUrl = $url . '?'.$prefix.'_month=' . $checkMonth . '&'.$prefix.'_year=' . $checkYear . '&'.$prefix.'_day=' . $theDay;
} else {
$dayUrl = $url . '&'.$prefix.'_month=' . $checkMonth . '&'.$prefix.'_year=' . $checkYear . '&'.$prefix.'_day=' . $theDay;
}
if(isset($_GET[$prefix.'_day']) && $_GET[$prefix.'_day'] == $theDay) {
$dayClass = $activeDay;
} else {
$dayClass = $linkClass;
}
$cal_days[$theDay] = array($dayUrl,$dayClass,$v->title);
}
}
} else {
if (!isset($debugOutput)) $debugOutput = '';
$debugOutput .= '<h3>Processing Error</h3><p>There was an error processing the json data. Set the debug param equal to 1 for more info.</p>';
return $debugOutput;
}
//Sort the posts by day
ksort($cal_days);
if ($debug) {
$debugOutput .= '<h3>Day Array for output</h3>';
$debugOutput .= '<pre>' . print_r($cal_days,TRUE) . '</pre>';
if (isset($monthLinks)) {
$debugOutput .= '<h3>Month Links Array</h3><pre>' . print_r($monthLinks,TRUE) . '</pre>';
}
}
//Set the prev & next Links
if ($showPn) {
$numMonth = intval($filterMonth);
$numYear = intval($filterYear);
if ($numMonth == 1) {
$prevMonth = 12;
$prevYear = $numYear - 1;
$nextYear = $numYear;
$nextMonth = $numMonth + 1;
} elseif ($numMonth == 12) {
$prevMonth = $numMonth - 1;
$prevYear = $numYear;
$nextYear = $numYear + 1;
$nextMonth = 1;
} else {
$prevMonth = $numMonth - 1;
$prevYear = $numYear;
$nextYear = $numYear;
$nextMonth = $numMonth + 1;
}
$nextMonth = $nextMonth < 10 ? '0' . $nextMonth : $nextMonth;
$prevMonth = $prevMonth < 10 ? '0' . $prevMonth : $prevMonth;
$prevArgs = 'cal_month=' . $prevMonth . '&cal_year=' . $prevYear;
$nextArgs = 'cal_month=' . $nextMonth . '&cal_year=' . $nextYear;
$prevLink = $modx->makeUrl($modx->documentObject['id'],'',$prevArgs);
$nextLink = $modx->makeUrl($modx->documentObject['id'],'',$nextArgs);
$checkCurMonth = date('n',time());
$checkCurYear = date('Y',time());
if ($checkCurMonth == $numMonth && $checkCurYear == $numYear) {
$pn = array('«'=>$prevLink);
} else {
$pn = array('«'=>$prevLink,'»'=>$nextLink);
}
} else {
$pn = array();
}
//Set month link if specified
if (isset($monthLinks[$filterYear][$filterMonth])) {
$monthLink = $monthLinks[$filterYear][$filterMonth];
} else {
$monthLink = NULL;
}
$output = generate_calendar($filterYear,$filterMonth,$cal_days,$dayNameLength,$monthLink,$firstDay,$pn);
//Output the calendar
if ($debug) {
$output = $output . $debugOutput;
}
if ($ph) {
$modx->setPlaceholder($ph,$output);
} else {
return $output;
}
# PHP Calendar (version 2.3), written by Keith Devens
# http://keithdevens.com/software/php_calendar
# see example at http://keithdevens.com/weblog
# License: http://keithdevens.com/software/license
function generate_calendar($year, $month, $days = array(), $day_name_length = 3, $month_href = NULL, $first_day = 0, $pn = array()){
$first_of_month = gmmktime(0,0,0,$month,1,$year);
#remember that mktime will automatically correct if invalid dates are entered
# for instance, mktime(0,0,0,12,32,1997) will be the date for Jan 1, 1998
# this provides a built in "rounding" feature to generate_calendar()
$day_names = array(); #generate all the day names according to the current locale
for($n=0,$t=(3+$first_day)*86400; $n<7; $n++,$t+=86400) #January 4, 1970 was a Sunday
$day_names[$n] = ucfirst(gmstrftime('%A',$t)); #%A means full textual day name
list($month, $year, $month_name, $weekday) = explode(',',gmstrftime('%m,%Y,%B,%w',$first_of_month));
$weekday = ($weekday + 7 - $first_day) % 7; #adjust for $first_day
$title = htmlentities(ucfirst($month_name)).' '.$year; #note that some locales don't capitalize month and day names
#Begin calendar. Uses a real <caption>. See http://diveintomark.org/archives/2002/07/03
@list($p, $pl) = each($pn); @list($n, $nl) = each($pn); #previous and next links, if applicable
if($p) $p = '<span class="calendar-prev">'.($pl ? '<a href="'.htmlspecialchars($pl).'" id="calendar-prev">'.$p.'</a>' : $p).'</span> ';
if($n) $n = ' <span class="calendar-next">'.($nl ? '<a href="'.htmlspecialchars($nl).'" id="calendar-next">'.$n.'</a>' : $n).'</span>';
$calendar = '<table class="calendar" cellspacing="0" cellpadding="0">'."\n".
'<caption class="calendar-month">'.$p.($month_href ? '<a href="'.htmlspecialchars($month_href).'">'.$title.'</a>' : $title).$n."</caption>\n<tr>";
if($day_name_length){ #if the day names should be shown ($day_name_length > 0)
#if day_name_length is >3, the full name of the day will be printed
foreach($day_names as $d)
$calendar .= '<th abbr="'.htmlentities($d).'">'.htmlentities($day_name_length < 4 ? substr($d,0,$day_name_length) : $d).'</th>';
$calendar .= "</tr>\n<tr>";
}
if($weekday > 0) $calendar .= '<td colspan="'.$weekday.'"> </td>'; #initial 'empty' days
for($day=1,$days_in_month=gmdate('t',$first_of_month); $day<=$days_in_month; $day++,$weekday++){
if($weekday == 7){
$weekday = 0; #start a new week
$calendar .= "</tr>\n<tr>";
}
if(isset($days[$day]) and is_array($days[$day])){
@list($link, $classes, $title, $content) = $days[$day];
if(is_null($content)) $content = $day;
$calendar .= '<td'.($classes ? ' class="'.htmlspecialchars($classes).'">' : '>').
($link ? '<a href="'.htmlspecialchars($link).'" title="'.htmlspecialchars($title).'">'.$content.'</a>' : $content).'</td>';
}
else $calendar .= "<td>$day</td>";
}
if($weekday != 7) $calendar .= '<td colspan="'.(7-$weekday).'"> </td>'; #remaining "empty" days
return $calendar."</tr>\n</table>\n";
}
?>