Action: Scheduler

Compatible with: R6.x
Current version: 0.4
Credits: AhA, WikiAdmin

{{scheduler}}

1. Description

Scheduler is an action which allows a person to keep a day calendar (or diary for that matter). Although the entry formatting is simple, at the same time it provides flexibility. A user can enter a day schedule.....


8:00 am - meeting with joe
9:00 am - coffee with angie
10:00 am - clients from budapest

or use it to keep a to-do list, or even a diary for the day. The schedule for a day can be viewed with the entry tool, in the monthly view, or in the day view. The day viewer is formatted for printing out usable schedules, & you can designate a specific user with it and see somebody else's schedule (I intend on modifying this so that there will be an easy-to-use text entry box for entering user names).

2. Installation

To install the scheduler system, the existing database must be extended by 1 table and the following PHP file must be copied to the /action folder.

2.1. Action

This script must be saved under the name scheduler.php and copied to the /action folder.


/action/scheduler.php


<?php

// {{scheduler mode="[day|month|default]"]}}

$prefix            $this->db->table_prefix;

$create_table = function() use ($prefix)
{
    
$this->db->sql_query(
        
"CREATE TABLE wacko_scheduler (
            scheduler_id INT(10) NOT NULL AUTO_INCREMENT,
            user_id INT(10) UNSIGNED NOT NULL DEFAULT '0',
            day TINYINT(2) NOT NULL DEFAULT '0',
            month TINYINT(2) NOT NULL DEFAULT '0',
            year MEDIUMINT(4) NOT NULL DEFAULT '0',
            schedule TEXT,
        PRIMARY KEY (scheduler_id),
        KEY idx_user_id (user_id)
    );"
);
};

$weekdays = function($pattern 'EEEE'): array
{
    
$formatter = new IntlDateFormatter(
        
$this->get_user()['user_lang'] ?? $this->language['locale'],
        
IntlDateFormatter::NONE,
        
IntlDateFormatter::NONE,
        
'UTC',
        
IntlDateFormatter::GREGORIAN,
        
$pattern
    
);

    
$days array_map(
        function(
$dow) use ($formatter) {
            return 
$formatter->format(strtotime('next Sunday +' $dow ' days'));
        },
        [
2345671#range(1, 7)
    
);

    return 
$days;
};

$months = function($pattern 'MMMM')
{
    
$formatter \IntlDateFormatter::create(
        
$this->get_user()['user_lang'] ?? $this->language['locale'],
        
\IntlDateFormatter::LONG,
        
\IntlDateFormatter::NONE,
        
'UTC',
        
\IntlDateFormatter::GREGORIAN,
        
$pattern
    
);

    
$months array_map(
        function(
$m) use ($formatter){
            return 
$formatter->format(mktime(000$m21970));
        },
        
range(112)
    );

    return 
$months;
};

// get the last day of the month
$get_last_day_of_month    = function ($mon$year)
{
    for (
$tday 28$tday <= 31$tday++)
    {
        
$tdate getdate(mktime(000$mon$tday$year));

        if (
$tdate['mon'] != $mon) break;
    }

    
$tday--;
    return 
$tday;
};

$mode_month        'month';
$mode_day        'day';
$mode_default    'default';
$mod_selector    'mode';

$mode            $_GET[$mod_selector]    ?? $mode_default;
$year            $_GET['year']            ?? date('Y'time());
$month            $_GET['month']        ?? date('m'time());
$today            $_GET['day']            ?? date('d'time());


// navigation
$tabs    = [
            
'default'    => 'SchedMonthlyView',
            
'day'        => 'SchedDailyView',
            
'month'        => 'SchedMonthlyCalendar',
        ];

if (!
array_key_exists($mode$tabs))
{
    
$mode '';
}

// print navigation
$tpl->tabs        $this->tab_menu($tabs$mode'', ['month' => $month'day' => $today'year' => $year], $mod_selector);
$tpl->mode        $mode;

// $monthname = $month;
$lastday        $get_last_day_of_month($month$year);
$tmpd            getdate(mktime(000$month1$year));
#$monthname        = $tmpd['month'];
$firstwday        $tmpd['wday'];

    
$month_loc        $months();
    
$monthname        $month_loc[(int) $month 1];

    
$display_date    $today '. ' $monthname ' ' $year ':';

$username        $this->get_user_name();
$user_id        $this->get_user_id();

$schedule        $_POST['schedule'] ?? '';

if (isset(
$_POST['save']))
{
    
$update            0;

    
$result $this->db->load_single(
        
"SELECT scheduler_id
        FROM 
{$prefix}scheduler
        WHERE user_id    = '" 
. (int) $user_id "'
            AND day        = '" 
. (int) $today "'
            AND month    = '" 
. (int) $month "'
            AND year    = '" 
. (int) $year "'");

    
// added to delete the empty schedule
    
$this->db->sql_query(
        
"DELETE
        FROM 
{$prefix}scheduler
        WHERE schedule = ''"
);

    if (!empty(
$result['scheduler_id']))
    {
        
$update            1;
        
$scheduler_id    $result['scheduler_id'];
    }

    if (
$update)
    {
        
$this->db->sql_query(
            
"UPDATE {$prefix}scheduler SET
                schedule = " 
$this->db->q($schedule) . "
            WHERE user_id = '" 
. (int) $user_id "'
                AND scheduler_id = '" 
. (int) $scheduler_id "'");
    }
    else
    {
        
$this->db->sql_query(
            
"INSERT INTO {$prefix}scheduler (
                user_id,
                schedule,
                month,
                day,
                year
            )
            VALUES (" 
.
                (int) 
$user_id ", " .
                
$this->db->q($schedule) . ", " .
                (int) 
$month ", " .
                (int) 
$today ", " .
                (int) 
$year "
            )"
);
    }
}
// end

// OUTPUT
$result $this->db->load_single(
    
"SELECT schedule
    FROM 
{$prefix}scheduler
    WHERE user_id    = '" 
. (int) $user_id "'
        AND day        = '" 
. (int) $today "'
        AND month    = '" 
. (int) $month "'
        AND year    = '" 
. (int) $year "'");

$schedule    $result['schedule'] ?? '';

$href_prev_day        $this->href('''', ['mode' => $mode'day' => (($today 1) < 1) ? $lastday $today 1'year' => $year'month' => $month]);
$href_next_day        $this->href('''', ['mode' => $mode'day' => (($today 1) > $lastday) ? $today 1'year' => $year'month' => $month]);
$href_prev_month    $this->href('''', ['mode' => $mode'month' => (($month 1) < 1) ? 12 $month 1'year' => (($month 1) < 1) ? $year $year]);
$href_next_month    $this->href('''', ['mode' => $mode'month' => (($month 1) > 12) ? $month 1'year' => (($month 1) > 12) ? $year $year]);

if (
$mode == 'day')
{
    
$tpl->enter('day_');
    
$printout        str_replace("\n"'<hr></td></tr><tr align="left"><td>'$schedule);
    
$printowner        $username ' ' $this->_t('SchedLabel');

    
$tpl->prevday    $href_prev_day;
    
$tpl->nextday    $href_next_day;
    
$tpl->label        $printowner ' ' $display_date;

    if (
$user $this->get_user())
    {
        
$tpl->tasks $printout ?: $this->_t('SchedNoEntries');
    }

    
$tpl->leave(); // day_
}
else if (
$mode == 'month')
{
    
$tpl->enter('month_');

    
// get what weekday the first is on

    
$tpl->prevmonth    $href_prev_month;
    
$tpl->nextmonth    $href_next_month;
    
$tpl->label        $username ' ' $this->_t('SchedCalendarLabel') . ' ' $monthname ' ' $year;

    foreach (
$weekdays() as $weekday)
    {
        
$tpl->n_weekday    $weekday;
    }

    
//shift one left circular, now we calculate with 1..7
    
if ($firstwday == 0)
    {
        
$firstwday 7;
    }

    
//$firstwday = (($firstwday + 7) % 7);
    
$wday            $firstwday;
    
$firstweek        true;
    
$day            1;

    
$tpl->enter('d_');

    
// loop through all the days of the month
    
while ($day <= $lastday)
    {
        
// set up blank days for first week
        
if ($firstweek)
        {
            
$tpl->first true;

            
// firstwday contains the starting day of the current month
            
for ($i 1$i $firstwday$i++)
            {
                
$tpl->first_b_n true;
            }

            
$firstweek false;
        }

        
// check for event
        
$tag        $year ':' $month ':' $day;
        
$todaydate    date('Y:m:d'time());

        if (
$tag == $todaydate)
        {
            
$style1 '<span style="color: #FF0000"><b>';
            
$style2 '</b></span>';
            
$token 'yes';
        }
        else
        {
            
$style1 '';
            
$style2 '';
            
$token 'no';
        }

        
// code to determine what data should be entered into each cell
        
$result $this->db->load_single(
            
"SELECT schedule
            FROM 
{$prefix}scheduler
            WHERE user_id    = '" 
. (int) $user_id "'
                AND day        = '" 
. (int) $day "'
                AND month    = '" 
. (int) $month "'
                AND year    = '" 
. (int) $year "'");

        
$dayoutput    $result['schedule'] ?? '';
        
// replace <some text>@...\n with <some text> \n
        
$dayoutput    preg_replace("/(.*?\w+?.*?)@(.*?)\n+?/""$1\n"$dayoutput);
        
// replace @...\n with nothing
        
$dayoutput    preg_replace("/(.*?)@(.*?)\n/"""$dayoutput);
        
$dayoutput    preg_replace("/(.*?)@(.*)/""$1"$dayoutput);
        
// replace <newline> with <br>
        
$dayoutput    str_replace("\n""<br>"$dayoutput);

        if (
$token == 'yes')
        {
            
# $printme = '<a href="' . $this->href('', '', ['mode' => $mode_day, 'day' => $day, 'month' => $month, 'year' => $year, '#' => 'entry-box']) . '"><small>[Print Day]</small></a>';
        
}
        else
        {
            
$printme '';
        }

        
$tpl->href            $this->href('''', ['day' => $day'month' => $month'year' => $year'#' => 'entry-box']);
        
$tpl->day            $style1 $day $style2 ;
        
$tpl->print            $printme;
        
$tpl->schedule    $dayoutput;

        
// nn Monday (0) start a new row
        
if ($wday == 1)
        {
            
$tpl->tr2 true;
        }

        
// Sunday -> next row
        
if ($wday == 7)
        {
            
$tpl->etr true;
        }

        
$wday = ($wday 7) + 1;
        
$day++;
    }

    
$tpl->leave(); // d_

    
$tpl->prevday        $href_prev_day;
    
$tpl->nextday        $href_next_day;
    
$tpl->dlabel        $username ' ' $this->_t('SchedDayLabel') . ' ' $display_date;

    
$tpl->hrefform        $this->href('''', ['mode' => $mode_month'month' => $month'day' => $today'year' => $year]);
    
$tpl->schedule    $schedule;

    
$tpl->leave(); // month_
}
else if (
$mode == 'default')
{
    
$tpl->enter('default_');

    
$tpl->month        $monthname ' ' $year;
    
$tpl->prevmonth    $href_prev_month;
    
$tpl->nextmonth    $href_next_month;

    foreach (
$weekdays('EEEEEE') as $weekday)
    {
        
$tpl->n_weekday    $weekday;
    }


    
//shift one left circular, now we calculate with 1..7
    
if ($firstwday == 0)
    {
        
$firstwday 7;
    }

    
$wday            $firstwday;
    
$firstweek        true;
    
$day            1;

    
$tpl->enter('d_');

    
// loop through all the days of the month
    
while ($day <= $lastday)
    {
        
// set up blank days for first week
        
if ($firstweek)
        {
            
$tpl->first true;

            for (
$i 1$i $firstwday$i++)
            {
                
$tpl->first_b_n true;
            }

            
$firstweek false;
        }

        
// check for event
        
$tag        $year ':' $month ':' $day;
        
$todaydate    date('Y:m:d'time());

        if (
$tag == $todaydate)
        {
            
$style1 '<span style="color: #FF0000"><b>';
            
$style2 '</b></span>';
        }
        else
        {
            
$style1 '';
            
$style2 '';
        }

        
$tpl->href        $this->href('''', ['day' => $day'month' => $month'year' => $year]);
        
$tpl->day        $style1 $day $style2;

        
// Sunday start week with <tr>
        
if ($wday == 1)
        {
            
$tpl->tr2    true;
        }

        
// Sunday week with </tr>
        
if ($wday == 7)
        {
            
$tpl->etr    true;
        }

        
$wday = ($wday 7) + 1;
        
$day++;
    }

    
$tpl->leave(); // d_

    
$tpl->enter('f_');

    
// title over textarea box
    
$printowner            $username ' ' $this->_t('SchedLabel');

    
$tpl->label            $printowner ' ' $display_date;
    
$tpl->prevday        $href_prev_day;
    
$tpl->nextday        $href_next_day;

    
$tpl->hrefform        $this->href('''', ['mode' => $mode_default'month' => $month'day' => $today'year' => $year]);
    
$tpl->schedule    $schedule;

    
$tpl->leave(); // f_
    
$tpl->leave(); // default_
}
else
{
    
$tpl->mustlogin true;
}


2.2. Template

This script must be saved under the name scheduler.tpl and copied to the /action/template folder.


/action/template/scheduler.tpl

[ === main === ]
 
<h2>[ ' mode ' ]</h2>
[ ' tabs ' ]
<br><br>
[= mustlogin _ =
    <em>[ ' _t: SchedMustLogin ' ]</em>
=]
<div align="center">
    <table border=0 width=100%>
    <tr>
        <td>
            <div align="center">
 
        [= day _ =
            <div align="center">
                <a href="[ ' prevday ' ]"><<</a>
                <b>[ ' label ' ]</b>
                <a href="[ ' nextday ' ]">>></a>
 
                <table class='box' width='600' border='1' cellspacing='1' cellpadding='7' bgcolor='#ddccbb'>
                    <tr>
                        <td>
                            <p></p>
                            <table class='box' width='100%' border='0' cellspacing='0' cellpadding='2' bgcolor='#ffffff'>
                                <tr align='left'>
                                    <td>
                                        <p>[ ' tasks ' ]</p>
                                    </td>
                                </tr>
                            </table>
                        </td>
                    </tr>
                </table>
            </div>
            </div>
        =]
        [= month _ =
            <table>
                <tr>
                    <td valign="top">
                        <table cellpadding="2" cellspacing="0" border="1">
                            <tr>
                                <td colspan="7">
                                    <table cellpadding="0" cellspacing="0" border="0" width="100%">
                                        <tr>
                                            <td width="20"><a href="[ ' prevmonth ' ]"><<<</a></td>
                                            <td align="center"><strong>[ ' label ' ]</strong></td>
                                            <td width="20"><a href="[ ' nextmonth ' ]">>>></a></td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                            <tr bgcolor="#ddccbb">
                            [= n _ =
                                <td>[ ' weekday ' ]</td>
                            =]
                            </tr>
                            [= d _ =
                                [= first _ =
                                <tr class="tr1">
                                    [= b _ =
                                    <td>[ ' n | void ' ]</td>
                                    =]
                                =]
                                [= tr2 _ =
                                    <tr class="tr2">
                                    [ ' nonstatic ' ]
                                =]
                                    <td valign=top align=left width=150 height=70>
                                        <table width="100%">
                                            <tr bgcolor="#E4DFDA">
                                                <td><a href="[ ' href ' ]">[ ' day ' ]</a>[ ' print ' ]</td>
                                            </tr>
                                            <tr>
                                                <td><small>[ ' schedule ' ]</small></td>
                                            </tr>
                                        </table>
                                    </td>
                                [= etr _ =
                                    </tr>
                                    [ ' nonstatic ' ]
                                =]
                            =]
                        </tr>
                    </table>
                </td>
            </tr>
        </table>
            </div>
        </td>
    </tr>
    <tr>
        <td widht=500>
            <p></p>
 
            <div align="center">
                <a name="entry-box"></a>
                <a href="[ ' prevday ' ]"><<</a>
                <b>[ ' dlabel ' ]</b>
                <a href="[ ' nextday ' ]">>></a>
                <br><em><small>[ ' _t: SchedCommentsNote ' ]</small></em>
                <form action="[ ' hrefform ' ]" method="post" name="day_schedule">
                    [ ' csrf: day_schedule ' ]
                    <input type="hidden" name="save" value="true" />
                    <textarea cols="90" rows="10" name="schedule">[ ' schedule ' ]</textarea><br>
                    <button type="submit">[ ' _t: SubmitButton ' ]</button>
                </form>
            </div>
        =]
        [= default _ =
            <table bgcolor="#ddccbb">
                <tr>
                    <td valign="top">
 
                        <table cellpadding="2" cellspacing="0" border="1">
                            <tr bgcolor="#ffffff">
                                <td colspan="7">
                                    <table cellpadding="0" cellspacing="0" border="0" width="100%">
                                        <tr bgcolor="#ffffff">
                                            <td width="20"><a href="[ ' prevmonth ' ]"><<<</a></td>
                                            <td align="center">[ ' month ' ]</td>
                                            <td width="20"><a href="[ ' nextmonth ' ]">>>></a></td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                            <tr bgcolor="#ddccbb">
                            [= n _ =
                                <td width="22">[ ' weekday ' ]</td>
                            =]
                            </tr>
                        [= d _ =
                            [= first _ =
                            <tr bgcolor="#ffffff">
                                [= b _ =
                                <td>[ ' n | void ' ]</td>
                                =]
                            =]
                            [= tr2 _ =
                            <tr bgcolor="#ffffff">
                            [ ' nonstatic ' ]
                            =]
                                <td>
                                    <a href="[ ' href ' ]">[ ' day ' ]</a>
                                </td>
                            [= etr _ =
                                </tr>
                                [ ' nonstatic ' ]
                            =]
                        =]
                            </tr>
                        </table>
 
                    </td>
                </tr>
            </table>
            </div>
        </td>
        <td width=500>
        [= f _ =
            <br>
            <a href="[ ' prevday ' ]"><<</a>
            <b>[ ' label ' ]</b>
            <a href="[ ' nextday ' ]">>></a>
 
            <form action="[ ' hrefform ' ]" method="post" name="day_schedule">
                [ ' csrf: day_schedule ' ]
                <input type="hidden" name="save" value="true">
                <textarea cols="65" rows="12" name="schedule">[ ' schedule ' ]</textarea>
                <button type="submit">[ ' _t: SubmitButton ' ]</button>
            </form>
        =]
    =]
 
        </td>
    </tr>
</table>
</div>

2.3. Database

The existing Wacko MySQL database must be extended with the following table. Change the prefix for the tables accordingly if necessary.


create extra table:


CREATE TABLE wacko_scheduler (
  scheduler_id INT(10) NOT NULL AUTO_INCREMENT,
  user_id INT(10) UNSIGNED NOT NULL DEFAULT '0',
  day TINYINT(2) NOT NULL DEFAULT '0',
  month TINYINT(2) NOT NULL DEFAULT '0',
  year MEDIUMINT(4) NOT NULL DEFAULT '0',
  schedule TEXT,
  PRIMARY KEY (scheduler_id),
  KEY idx_user_id (user_id)
);

2.4. Message sets

en

	'SchedMustLogin'					=> 'The calendar works only for logged in users.',
	'SchedNoEntries'						=> 'There are no entries on this day.',
	'SchedLabel'							=> 'Appointments and tasks for ',
	'SchedCommentsNote'				=> 'Preface comments with @.',

	'SchedMonthlyView'					=> 'Monthly view',
	'SchedDailyView'						=> 'Daily view',
	'SchedMonthlyCalendar'				=> 'Monthly Calendar',
	'SchedCalendarLabel'					=> 'Calendar for',
	'SchedDayLabel'						=> 'Entry for the',

de

	'SchedMustLogin'					=> 'Der Kalender funktioniert nur bei angemeldeten Nutzern.',
	'SchedNoEntries'						=> 'Es gibt keine Einträge an diesem Tag.',
	'SchedLabel'							=> 'Termine und Aufgaben für ',
	'SchedCommentsNote'				=> 'Kommentare mit @ einleiten.',

	'SchedMonthlyView'					=> 'Monatsübersicht',
	'SchedDailyView'						=> 'Tagesansicht',
	'SchedMonthlyCalendar'				=> 'Monatskalender',
	'SchedCalendarLabel'					=> 'Kalender für',
	'SchedDayLabel'						=> 'Eintrag für den',

3. Documentation

How can I use this Calendar for group events?


Note:
By default only events of the (one) logged in person respectivly his actual account will be shown.


work around:
Share an account. Eg. "GroupXYAccount" which will be used for event accord only.


Login: GroupXYAccount
Password: onepasswordforallgroupmembers

4. Changelog

0.1 Intitial version
0.2 Ported to WackoWiki
0.3 Ported to R6.0
0.4 Added template

5. To Do

  • localization
  • how to [doc]
  • month, week, day 
  • refactor
  • add template
    • further cleanup: styles, tags and time format

Read comments (0 comments)