availability_calendars.module in Availability Calendars 5
Same filename and directory in other branches
Availability Calendars Module
Allows for availability information to be displayed using calendars on specified content types. Originally based on the Availability Module. @author Dan Karran (geodaniel) <dan at karran dot net>
File
availability_calendars.moduleView source
<?php
/**
* Availability Calendars Module
*
* @file
* Allows for availability information to be displayed using calendars on specified content types. Originally based on the Availability Module.
* @author Dan Karran (geodaniel) <dan at karran dot net>
*/
/**
* Implementation of hook_menu()
*/
function availability_calendars_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/settings/availability-calendars',
'title' => t('Availability Calendars'),
'description' => t('Configure global settings for availability calendars module.'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'availability_calendars_admin_settings',
),
);
}
else {
$items[] = array(
'path' => 'availability-calendars',
'title' => t('Availability calendar'),
'callback' => 'availability_calendars_page',
'access' => user_access('edit availability calendars') || user_access('edit own availability calendars'),
'type' => MENU_CALLBACK,
);
}
return $items;
}
/**
* Implementation of hook_perm()
*/
function availability_calendars_perm() {
return array(
'edit own availability calendars',
'edit availability calendars',
);
}
/**
* Settings page callback.
*/
function availability_calendars_admin_settings() {
$form = array();
$form['display'] = array(
'#type' => 'fieldset',
'#title' => t('View settings'),
'#description' => t('Check where you want availability calendars to be displayed. If you choose none of the suggested places below you will need to output it manually using %func function.', array(
'%func' => 'theme_availability_calendars_node()',
)),
);
$form['display']['availability_calendars_display_nodeview'] = array(
'#type' => 'checkbox',
'#title' => t('Node view page'),
'#default_value' => variable_get('availability_calendars_display_nodeview', TRUE),
);
$form['display']['availability_calendars_display_monthcount'] = array(
'#type' => 'textfield',
'#title' => t('Number of months to display'),
'#default_value' => variable_get('availability_calendars_display_monthcount', 12),
'#description' => t("Your calendars will show this number of months to all users except those with the 'edit own availability calendars' or 'edit availability calendars' who will always see 3 extra months on the calendars they can edit. This is to allow them to enter information into future calendars before it is made publicly available."),
);
//TODO: add status codes and css classes in here
return system_settings_form($form);
}
/**
* Create tab to show node availability
*/
function availability_calendars_menu_callback() {
$node = node_load(arg(1));
if (availability_calendars_enabled($node->type)) {
return theme('availability_calendars_node', $node);
}
else {
return FALSE;
}
}
/**
* Availability calendars page
*/
function availability_calendars_page($nid = NULL, $year = NULL, $month = NULL, $edit = FALSE) {
if (is_numeric($nid)) {
$node = node_load($nid);
drupal_set_title(t('Availability for %name', array(
'%name' => $node->title,
)));
if (is_numeric($year) && is_numeric($month)) {
drupal_set_title(t('Availability for %name in %date', array(
'%name' => $node->title,
'%date' => format_date(strtotime("{$year}-{$month}-01 12:00"), 'custom', 'M Y'),
)));
if ($edit == 'edit') {
// Display the edit form for the availability calendar on the node
return availability_calendars_node_edit($node, $year, $month);
}
else {
// Display availability calendar for single month
$monthstodisplay = 1;
return theme('availability_calendars_node', $node, $year, $month, $monthstodisplay);
}
}
elseif (is_numeric($year)) {
// Display availability calendar for a whole year
$month = 1;
$monthstodisplay = 12;
return theme('availability_calendars_node', $node, $year, $month, $monthstodisplay);
}
else {
// Display rolling availability calendar from this point onwards
$year = date('Y');
$month = date('m');
$monthstodisplay = variable_get('availability_display_monthcount', 12);
return theme('availability_calendars_node', $node, $year, $month, $monthstodisplay);
}
}
else {
print drupal_not_found();
}
}
function availability_calendars_node_edit() {
return drupal_get_form('availability_calendars_node_edit_form');
}
function availability_calendars_node_edit_form() {
$nid = check_plain(arg(1));
$year = check_plain(arg(2));
$month = check_plain(arg(3));
$form['nid'] = array(
'#type' => 'hidden',
'#default_value' => $nid,
);
$form['year'] = array(
'#type' => 'hidden',
'#default_value' => $year,
);
$form['month'] = array(
'#type' => 'hidden',
'#default_value' => $month,
);
$startofweek = variable_get('availability_calendars_' . $nid . '_startofweek', 1);
$month_meta = availability_calendars_month_meta($year, $month, $startofweek);
// find all entries in database for this month ($availability, $notes) and pre-populate
$notes_result = db_query('SELECT week, note FROM {availability_calendars_week} WHERE nid = %d AND year = %d and month = %d', $nid, $year, $month);
while ($note = db_fetch_array($notes_result)) {
$notes[$note['week']] = $note['note'];
}
$status_result = db_query('SELECT day, status FROM {availability_calendars_day} WHERE nid = %d AND year = %d AND month = %d', $nid, $year, $month);
while ($status = db_fetch_array($status_result)) {
$day_status[$status['day']] = $status['status'];
}
$day = 1;
for ($week = 1; $week <= $month_meta['weeksinmonth']; $week++) {
$form['week-' . $week] = array(
'#type' => 'fieldset',
'#title' => t('Week @week', array(
'@week' => $week,
)),
);
$form['week-' . $week]['note-' . $week] = array(
'#type' => 'textfield',
'#title' => t('Note'),
'#default_value' => $notes[$week],
'#description' => t('This will be displayed beside the week in the calendar. It could include, for example, a weekly price.'),
);
if ($week == 1) {
$daysinweekremaining = 7 - $month_meta['firstday'];
}
else {
$daysinweekremaining = 7;
}
while ($daysinweekremaining > 0 && $day <= $month_meta['daysinmonth']) {
$form['week-' . $week]['day-' . $day] = array(
'#type' => 'select',
'#title' => t("@date", array(
'@date' => format_date(strtotime("{$year}-{$month}-{$day} 12:00"), 'custom', 'l d F'),
)),
'#options' => availability_calendars_options(),
'#default_value' => $day_status[$day],
);
$day++;
$daysinweekremaining--;
}
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
function availability_calendars_node_edit_form_submit($form_id, $form_values) {
$nid = check_plain($form_values['nid']);
$year = check_plain($form_values['year']);
$month = check_plain($form_values['month']);
// save weekly notes
$week = 1;
$nomoreweeks = FALSE;
while (!$nomoreweeks) {
if (isset($form_values['note-' . $week])) {
$notes[$week] = check_plain($form_values['note-' . $week]);
$week++;
}
else {
$nomoreweeks = TRUE;
}
}
// save $days
$day = 1;
$nomoredays = FALSE;
while (!$nomoredays) {
if (isset($form_values['day-' . $day])) {
$days[$day] = $form_values['day-' . $day];
$day++;
}
else {
$nomoredays = TRUE;
}
}
db_query('DELETE FROM {availability_calendars_week} WHERE nid = %d AND year = %d AND month = %d', $nid, $year, $month);
foreach ($notes as $week => $note) {
db_query('INSERT INTO {availability_calendars_week} (nid, year, month, week, note) VALUES (%d, %d, %d, %d, "%s")', $nid, $year, $month, $week, $note);
}
db_query('DELETE FROM {availability_calendars_day} WHERE nid = %d AND year = %d AND month = %d', $nid, $year, $month);
foreach ($days as $day => $status) {
db_query('INSERT INTO {availability_calendars_day} (nid, year, month, day, status) VALUES (%d, %d, %d, %d, %d)', $nid, $year, $month, $day, $status);
}
drupal_set_message('Availability information saved.');
}
/**
* Themed output to display a lits of node dates.
*
* @param $node
* @return HTML output.
*/
function theme_availability_calendars_node($node, $year = 2008, $month = 01, $monthstodisplay = 12) {
drupal_add_css(drupal_get_path('module', 'availability_calendars') . '/availability_calendars.css');
$rows = array();
// Fill availability array
/* foreach ($node->availability_dates as $k => $v) {
foreach ($v as $i) {
$booked[date("Y", $i['date'])][date("m", $i['date'])][date("d", $i['date'])] = 1;
}
} */
// Calendar code based on example at http://evolt.org/node/60673 :
$day = 1;
$startofweek = variable_get('availability_calendars_' . $node->nid . '_startofweek', 1);
$monthsremaining = $monthstodisplay;
while ($monthsremaining > 0) {
$output .= theme('availability_calendars_month', $node, $year, $month, $startofweek, $booked);
$monthsremaining--;
$month++;
if ($month > 12) {
$month = 1;
$year++;
}
}
// add an extra three months for editors only
if (user_access('edit availability calendars')) {
$monthsremaining = 3;
while ($monthsremaining > 0) {
$output .= theme('availability_calendars_month', $node, $year, $month, $startofweek, $booked);
$monthsremaining--;
$month++;
if ($month > 12) {
$month = 1;
$year++;
}
}
}
return $output;
}
function availability_calendars_month_meta($year, $month, $startofweek) {
$month_meta['daysinmonth'] = date("t", mktime(0, 0, 0, $month, 1, $year));
$month_meta['firstday'] = date("w", mktime(0, 0, 0, $month, 1, $year)) + $startofweek;
$tempDays = $month_meta['firstday'] + $month_meta['daysinmonth'];
// padding
$month_meta['weeksinmonth'] = ceil($tempDays / 7);
// Stop empty weeks occuring at start of month
if ($month_meta['firstday'] > 6) {
$month_meta['firstday'] = $month_meta['firstday'] - 7;
$month_meta['weeksinmonth']--;
}
return $month_meta;
}
function theme_availability_calendars_month($node, $year, $month, $startofweek, $booked) {
$month_meta = availability_calendars_month_meta($year, $month, $startofweek);
for ($j = 0; $j < $month_meta['weeksinmonth']; $j++) {
for ($i = 0; $i < 7; $i++) {
$counter++;
$week[$j][$i] = $counter;
// offset the days
$week[$j][$i] -= $month_meta['firstday'];
if ($week[$j][$i] < 1 || $week[$j][$i] > $month_meta['daysinmonth']) {
$week[$j][$i] = "";
}
}
}
$output = "<table class='cal'>\n";
$output .= "<tr class='calmonth'>\n";
$output .= "<th colspan='8'>" . t("@date", array(
'@date' => format_date(mktime(12, 0, 0, $month, 1, $year), 'custom', 'F Y'),
));
if (user_access('edit availability calendars')) {
$output .= ' ' . l('edit', 'availability-calendars/' . $node->nid . '/' . date('Y/m', mktime(0, 0, 0, $month, 1, $year)) . '/edit', NULL, 'destination=node/' . $node->nid);
}
$output .= "</th>\n";
$output .= "</tr>\n";
/* $days = array(
6 => array("M", "Mon", "Monday"),
5 => array("T", "Tue", "Tuesday"),
4 => array("W", "Wed", "Wednesday"),
3 => array("T", "Thu", "Thursday"),
2 => array("F", "Fri", "Friday"),
1 => array("S", "Sat", "Saturday"),
0 => array("S", "Sun", "Sunday"),
);
// Figure out how to generate the header - see archive.module in 4.7
$output .= "<tr class='caldays'>\n";
$output .= "<th></th>\n";
$output .= "<th>S</th>\n";
$output .= "<th>S</th>\n";
$output .= "<th>M</th>\n";
$output .= "<th>T</th>\n";
$output .= "<th>W</th>\n";
$output .= "<th>T</th>\n";
$output .= "<th>F</th>\n";
$output .= "</tr>\n";
*/
// find all entries in database for this month ($availability, $notes) and pre-populate
$notes_result = db_query('SELECT week, note FROM {availability_calendars_week} WHERE nid = %d AND year = %d AND month = %d', $node->nid, $year, $month);
while ($note = db_fetch_array($notes_result)) {
$notes[$note['week']] = $note['note'];
}
$status_result = db_query('SELECT day, status FROM {availability_calendars_day} WHERE nid = %d AND year = %d AND month = %d', $node->nid, $year, $month);
while ($status = db_fetch_array($status_result)) {
$day_status[$status['day']] = $status['status'];
}
$availability_calendars_options = availability_calendars_options();
foreach ($week as $key => $val) {
$weeknumber = $key + 1;
$output .= "<tr class='calweek'>\n";
$output .= "<td class='calnote'>" . $notes[$weeknumber] . "</td>\n";
for ($i = 0; $i < 7; $i++) {
// if there's a date, it's part of this month
if ($week[$key][$i]) {
if ($day_status[$week[$key][$i]] == 1) {
// booked
$output .= " <td class='calnotavailable'>" . $week[$key][$i] . "</td>\n";
}
elseif ($day_status[$week[$key][$i]] == 2) {
// provisionally booked
$output .= " <td class='calnotavailableprov'>" . $week[$key][$i] . "</td>\n";
}
else {
// available
$output .= " <td class='calavailable'>" . $week[$key][$i] . "</td>\n";
}
}
else {
$output .= " <td class='calothermonth'>" . $number . "</td>\n";
}
}
$output .= "</tr>\n";
}
if ($weeknumber == 5) {
$output .= "<tr>\n";
$output .= "<td colspan='8'> </td>\n";
$output .= "</tr>\n";
}
$output .= "</table>";
return $output;
}
function availability_calendars_options() {
// TODO: make these configurable
return array(
0 => t('Available'),
1 => t('Fully booked'),
2 => t('Provisionally booked'),
);
}
/**
* Implementation of hook_form_alter();
*/
function availability_calendars_form_alter($form_id, &$form) {
global $user;
// Alter node type form to allow availability support to be enabled/disabled
if ($form_id == 'node_type_form') {
$form['workflow']['availability_calendars'] = array(
'#type' => 'radios',
'#title' => t('Availability calendar support'),
'#default_value' => variable_get('availability_calendars_' . $form['#node_type']->type, 0),
'#options' => array(
0 => t('Disabled'),
1 => t('Enabled'),
),
'#description' => t('Enable or disable availability support for this content type. If enabled, node owner will be able to specify node availability.'),
);
}
elseif (isset($form['type']) && $form['type']['#value'] . '_node_form' == $form_id && availability_calendars_enabled($form['type']['#value'])) {
$form['availability'] = array(
'#type' => 'fieldset',
'#title' => t('Availability calendar settings'),
);
$form['availability']['startofweek'] = array(
'#type' => 'select',
'#title' => t('First day of week'),
'#default_value' => variable_get('availability_calendars_' . $form['nid']['#value'] . '_startofweek', 1),
'#options' => array(
6 => t('Monday'),
5 => t('Tuesday'),
4 => t('Wednesday'),
3 => t('Thursday'),
2 => t('Friday'),
1 => t('Saturday'),
0 => t('Sunday'),
),
);
}
}
/**
* Implementation hook node_nodeapi();
*/
function availability_calendars_nodeapi(&$node, $op, $a3 = null, $a4 = null) {
global $user;
if (!availability_calendars_enabled($node->type)) {
return;
}
switch ($op) {
case 'view':
if (variable_get('availability_calendars_display_nodeview', TRUE)) {
$year = date('Y');
$month = date('m');
$monthstodisplay = variable_get('availability_calendars_display_monthcount', 12);
$node->content['availability_calendars'] = array(
'#value' => theme('availability_calendars_node', $node, $year, $month, $monthstodisplay),
'#weight' => 10,
);
}
break;
case 'insert':
case 'update':
availability_calendars_save($node);
break;
case 'delete':
break;
}
}
/**
* Saves a set of dates associated with the node after editing it.
*
* @param object $node Node information to save into the database.
*/
function availability_calendars_save(&$node) {
variable_set('availability_calendars_' . $node->nid . '_startofweek', $node->startofweek);
}
/**
* Checks if availability is enabled for specified content type.
*
* @param string $node_type
*/
function availability_calendars_enabled($node_type) {
return variable_get('availability_calendars_' . $node_type, 0);
}
Functions
Name | Description |
---|---|
availability_calendars_admin_settings | Settings page callback. |
availability_calendars_enabled | Checks if availability is enabled for specified content type. |
availability_calendars_form_alter | Implementation of hook_form_alter(); |
availability_calendars_menu | Implementation of hook_menu() |
availability_calendars_menu_callback | Create tab to show node availability |
availability_calendars_month_meta | |
availability_calendars_nodeapi | Implementation hook node_nodeapi(); |
availability_calendars_node_edit | |
availability_calendars_node_edit_form | |
availability_calendars_node_edit_form_submit | |
availability_calendars_options | |
availability_calendars_page | Availability calendars page |
availability_calendars_perm | Implementation of hook_perm() |
availability_calendars_save | Saves a set of dates associated with the node after editing it. |
theme_availability_calendars_month | |
theme_availability_calendars_node | Themed output to display a lits of node dates. |