source view: calendar.php


<?php



  // error handling for event editing
  // conference display






  function JSSafe ( $s )
  {
    return str_replace( array( "\\", "'" ), array( "\\\\", "\\'" ), $s );
  }



  function defaultValue ( $values, $key, $error_array )
  {
    if ( count( $error_array ) )
    {
      if ( strlen( $values[$key] ) )
      {
        printf( ' value="%s"', htmlspecialchars( $values[$key] ) );
      }
    
      print '';
    }
  }



  require './classes/DB.php';
  require './classes/Admin.php';



  function nullOut ( &$s )
  {
    $s = strlen( $s ) ? $s : null;
  }



  $reload_form_entry = false;
  $submission_errors = array();
  $form              = array();
  if ( Admin::isLoggedIn() && $_GET['action'] == 'deleteitem' )
  {
    $id = intval( $_GET['id'] );

    $delete_query = DB::getDB()->prepare( 'DELETE FROM tblCalendarItems WHERE calendarItemID = ?' );
    $delete_query->bind_param( 'i', $id );
    $delete_query->execute();
    $delete_query->close();

    header( 'Location: /calendar' );
    exit;
  }

  if ( Admin::isLoggedIn() && ( $_GET['action'] == 'newitem' || $_GET['action'] == 'edititem' ) )
  {
    $reload_form_entry = true;

    $error_strings = array(
      'enddate'    => 'At least one of date/time must be nonempty.',
      'endtime'    => 'At least one of date/time must be nonempty.',
      'location'   => 'Location must be nonempty.',
      'papertitle' => 'Paper title must be nonempty.',
      'startdate'  => 'At least one of date/time must be nonempty.',
      'starttime'  => 'At least one of date/time must be nonempty.'
    );

    $paper_title           = trim( $_POST['papertitle'] );
    $event_start_time      = trim( $_POST['starttime'] );
    $event_end_time        = trim( $_POST['endtime'] );
    $conference_start_date = trim( $_POST['startdate'] );
    $conference_end_date   = trim( $_POST['enddate'] );
    $conference_name       = trim( $_POST['conferencename'] );
    $conference_url        = trim( $_POST['conferenceurl'] );
    $location              = trim( $_POST['location'] );
    $location_address      = trim( $_POST['locationaddress'] );
    $location_url          = trim( $_POST['locationurl'] );
    $location_lat_lng      = trim( $_POST['locationlatlng'] );
    $details               = trim( $_POST['details'] );
    $paper_url             = trim( $_POST['paperurl'] );

    // clean input
    if ( !preg_match( '/^\d{4}?\-\d\d?\-\d\d?\s*[Tt\s]\s*\d\d?:\d\d\s*(?:[AaPp][Mm]?)?$/', $event_start_time ) )
    {
      $event_start_time = '';
    }
    if ( !preg_match( '/^\d{4}\-\d\d?\-\d\d\s*[Tt\s]\s*\d\d?:\d\d\s*(?:[AaPp][Mm]?)?$/', $event_end_time ) )
    {
      $event_end_time = '';
    }

    if ( !preg_match( '/^\d{4}\-\d\d?\-\d\d?$/', $conference_start_date ) )
    {
      $conference_start_date = '';
    }
    if ( !preg_match( '/^\d{4}\-\d\d?\-\d\d?$/', $conference_end_date ) )
    {
      $conference_end_date = '';
    }

    if ( !preg_match( '/^https?:\/\//', $conference_url ) )
    {
      $conference_url = '';
    }
    if ( !preg_match( '/^https?:\/\//', $location_url ) )
    {
      $location_url = '';
    }
    if ( !preg_match( '/^https?:\/\//', $paper_url ) )
    {
      $paper_url = '';
    }

    if ( !preg_match( '/^\-?\d+\.?\d*,\s*\-?\d+\.?\d*$/', $location_lat_lng ) )
    {
      $location_lat_lng = '';
    }

    $form = array(
      'conferencename'  => $conference_name,
      'conferenceurl'   => $conference_url,
      'details'         => $details,
      'enddate'         => $conference_end_date,
      'endtime'         => $event_end_time,
      'location'        => $location,
      'locationaddress' => $location_address,
      'locationlatlng'  => $location_lat_lng,
      'locationurl'     => $location_url,
      'papertitle'      => $paper_title,
      'paperurl'        => $paper_url,
      'startdate'       => $conference_start_date,
      'starttime'       => $event_start_time
    );

    // set errors
    if ( strlen( $paper_title ) < 1 )
    {
      $submission_errors['papertitle'] = $error_strings['papertitle'];
    }
    if ( strlen( $location ) < 1 )
    {
      $submission_errors['location'] = $error_strings['location'];
    }
    if ( ( strlen( $event_start_time ) < 1 || strlen( $event_end_time ) < 1 ) && ( strlen( $conference_start_date ) < 1 || strlen( $conference_end_date ) < 1 ) )
    {
      if ( strlen( $event_start_time ) )
      {
        $submission_errors['endtime'] = $error_strings['endtime'];
      }
      else if ( strlen( $event_end_time ) )
      {
        $submission_errors['starttime'] = $error_strings['starttime'];
      }

      if ( strlen( $conference_start_date ) )
      {
        $submission_errors['enddate'] = $error_strings['enddate'];
      }
      else if ( strlen( $conference_end_date ) )
      {
        $submission_errors['startdate'] = $error_strings['startdate'];
      }

      if ( strlen( $event_start_time ) < 1 && strlen( $event_end_time ) < 1 && strlen( $conference_start_date ) < 1 && strlen( $conference_end_date ) < 1 )
      {
        $submission_errors['starttime'] = $error_strings['starttime'];
      }
    }
    
    if ( count( $submission_errors ) < 1 )
    {
      $event_id = -1;
      if ( $_GET['action'] == 'newitem' )
      {
        DB::getDB()->query( 'INSERT INTO tblCalendarItems ( paperTitle ) VALUES ( "" )' );
        $event_id = DB::getDB()->insert_id;
      }
      else if ( isset( $_POST['eventid'] ) && preg_match( '/^\d+$/', $_POST['eventid'] ) )
      {
        $event_id = $_POST['eventid'];
      }

      nullOut( $event_start_time );
      nullOut( $event_end_time );
      nullOut( $conference_start_date );
      nullOut( $conference_end_date );
      nullOut( $conference_name );
      nullOut( $conference_url );
      nullOut( $location );
      nullOut( $location_address );
      nullOut( $location_url );
      nullOut( $location_lat_lng );
      nullOut( $details );
      nullOut( $paper_title );
      nullOut( $paper_url );

      $update_query_string = <<<EOQ
UPDATE tblCalendarItems
SET
  eventStartTime      = ?,
  eventEndTime        = ?,
  conferenceStartDate = ?,
  conferenceEndDate   = ?,
  conferenceName      = ?,
  conferenceURL       = ?,
  location            = ?,
  locationAddress     = ?,
  locationURL         = ?,
  locationLatLng      = ?,
  details             = ?,
  paperTitle          = ?,
  paperURL            = ?
WHERE calendarItemID = ?
EOQ;
      $update_query = DB::getDB()->prepare( $update_query_string );
      $update_query->bind_param( 'sssssssssssssi',
        $event_start_time,
        $event_end_time,
        $conference_start_date,
        $conference_end_date,
        $conference_name,
        $conference_url,
        $location,
        $location_address,
        $location_url,
        $location_lat_lng,
        $details,
        $paper_title,
        $paper_url,
        $event_id
      );
      $update_query->execute();
      $update_query->close();

      header( 'Location: calendar.php' );
      exit;
    }
  }






  require './classes/Page.php';
  $page = new Page();
  $page->setTitle( 'calendar' );
  $page->setParentURL( 'research.php' );



  $page->addHeader( <<<EOS
<style type="text/css">
  .schemadata
  {
    display: none;
  }

  .schema-data
  {
    display: none;
  }

  ul
  {
    list-style-type: none;
  }

  li
  {
    margin-bottom: 3ex;
  }

  td > input:not([type="submit"]):not([type="button"])
  {
    width: 100%;
  }

  .event-details
  {
  }

  .event-location
  {
  }

  .event-time
  {
    display:     block;
    font-weight: 500;
  }

  .event-title
  {
    display: block;
  }

  .hidden-details
  {
    display: none;
  }
</style>
EOS
);

  if ( Admin::isLoggedIn() )
  {
    $page->addHeader( <<<EOJ
<script language="javascript">
  function deleteItem ( e, id )
  {
    if ( confirm( 'Delete item ' + id + '?' ) )
    {
      parent.location = '?action=deleteitem&id=' + id;
    }
  }



  function editItem ( e, id )
  {
    // load form structure, relabel with unique id
    var h = document.getElementById( 'eventform' ).innerHTML.replace( /for="/gi, 'for="edit-' + id + '-' ).replace( /id="/gi, 'id="edit-' + id + '-' ).replace( /Create/, 'Edit' );
    var f = document.createElement( 'form' );
    f.setAttribute( 'action', '?action=edititem' );
    f.setAttribute( 'method', 'post' );
    f.innerHTML = h;

    while ( e.tagName.toUpperCase() != 'LI' && e.parentNode )
    {
      e = e.parentNode;
    }

    // hide existing display data
    for ( var i = 0; i < e.childNodes.length; ++i )
    {
      if ( e.childNodes[i].style )
      {
        e.childNodes[i].style.display = 'none';
      }
    }

    // add form controls
    e.appendChild( f );
    var b = document.createElement( 'input' );
    b.setAttribute( 'type', 'button' );
    b.setAttribute( 'value', 'Cancel' );
    var close_form = function () {
      var e = f.parentNode;
      e.removeChild( f );

      for ( var i = 0; i < e.childNodes.length; ++i )
      {
        if ( e.childNodes[i].style )
        {
          e.childNodes[i].style.display = '';
        }
      }
    };
    b.addEventListener( 'click', close_form );
    document.getElementById( 'edit-' + id + '-newitemsubmit' ).parentNode.appendChild( b );

    // update values from json
    var d = eval( '[' + document.getElementById( 'event-' + id + '-json' ).innerHTML + ']' );
    for ( var k in d[0] )
    {
      document.getElementById( 'edit-' + id + '-' + k ).value = d[0][k];
    }

    // add event id to form
    var i = document.createElement( 'input' );
    i.setAttribute( 'name', 'eventid' );
    i.setAttribute( 'type', 'hidden' );
    i.setAttribute( 'value', id );
    f.appendChild( i );

    // focus
    document.getElementById( 'edit-' + id + '-papertitle' ).focus();
    var inputs = f.getElementsByTagName( 'input' );
    for ( var i = 0; i < inputs.length; ++i )
    {
      inputs[i].addEventListener( 'keyup', function ( e ) {
        if ( e.which == 27 || e.keyCode == 27 )
        {
          close_form();
        }
      } );
    }

    return false;
  }
</script>
EOJ
    );
  }



  $page->printPageHeader();



  class CalendarItem implements JSONSerializable
  {
    private $conference_end_date;
    private $conference_name;
    private $conference_start_date;
    private $conference_url;
    private $details;
    private $event_end_time;
    private $event_start_time;
    private $id;
    private $location;
    private $location_address;
    private $location_lat_lng;
    private $location_url;
    private $paper_title;
    private $paper_url;



    public function __construct ( $id, $event_start_time, $event_end_time, $conference_start_date, $conference_end_date, $conference_name, $conference_url, $location, $location_address, $location_url, $location_lat_lng, $details, $paper_title, $paper_url )
    {
      $this->conference_end_date   = $conference_end_date;
      $this->conference_name       = $conference_name;
      $this->conference_start_date = $conference_start_date;
      $this->conference_url        = $conference_url;
      $this->details               = $details;
      $this->event_end_time        = $event_end_time;
      $this->event_start_time      = $event_start_time;
      $this->id                    = $id;
      $this->location              = $location;
      $this->location_address      = $location_address;
      $this->location_lat_lng      = $location_lat_lng;
      $this->location_url          = $location_url;
      $this->paper_title           = $paper_title;
      $this->paper_url             = $paper_url;
    }



    public static function fetchFutureCalendarItems ()
    {
      $items = array();

      $query_string = <<<EOQ
SELECT
  calendarItemID,
  UNIX_TIMESTAMP( eventStartTime ),
  UNIX_TIMESTAMP( eventEndTime ),
  UNIX_TIMESTAMP( conferenceStartDate ),
  UNIX_TIMESTAMP( conferenceEndDate ),
  conferenceName,
  conferenceURL,
  location,
  locationAddress,
  locationURL,
  locationLatLng,
  details,
  paperTitle,
  paperURL
FROM tblCalendarItems
WHERE
  (
    (
      eventEndTime > NOW()
      OR
      (
        MONTH( eventEndTime ) = MONTH( NOW() )
        AND YEAR( eventEndTime ) = YEAR( NOW() )
      )
    )
    OR
    (
      conferenceEndDate > NOW()
      OR
      (
        MONTH( conferenceEndDate ) = MONTH( NOW() )
        AND YEAR( conferenceEndDate ) = YEAR( NOW() )
      )
    )
  )
ORDER BY IFNULL( eventStartTime, conferenceStartDate ) ASC
EOQ;
      $event_query = DB::getDB()->query( $query_string );
      while ( $query_row = $event_query->fetch_row() )
      {
        array_push( $items, new CalendarItem( $query_row[0], $query_row[1], $query_row[2], $query_row[3], $query_row[4], $query_row[5], $query_row[6], $query_row[7], $query_row[8], $query_row[9], $query_row[10], $query_row[11], $query_row[12], $query_row[13] ) );
      }

      $event_query->close();
      return $items;
    }



    public function getMonth ()
    {
      if ( $this->event_start_time )
      {
        return date( 'F Y', $this->event_start_time );
      }
      else
      {
        return date( 'F Y', $this->conference_start_date );
      }
    }



    public function isConference ()
    {
      return $this->conference_start_date > 0;
    }



    public function isConferencePresentation ()
    {
      return $this->isConference() && $this->isPresentation();
    }



    public function isPresentation ()
    {
      return $this->event_start_time > 0;
    }



    public function jsonSerialize ()
    {
      return array(
        'papertitle'      => $this->paper_title,
        'starttime'       => strlen( $this->event_start_time ) ? date( 'Y-m-d\TH:i', $this->event_start_time ) : '',
        'endtime'         => strlen( $this->event_end_time ) ? date( 'Y-m-d\TH:i', $this->event_end_time ) : '',
        'startdate'       => strlen( $this->conference_start_date ) ? date( 'Y-m-d', $this->conference_start_date ) : '',
        'enddate'         => strlen( $this->conference_end_date ) ? date( 'Y-m-d', $this->conference_end_date ) : '',
        'conferencename'  => $this->conference_name,
        'conferenceurl'   => $this->conference_url,
        'location'        => $this->location,
        'locationaddress' => $this->location_address,
        'locationurl'     => $this->location_url,
        'locationlatlng'  => $this->location_lat_lng,
        'details'         => $this->details,
        'paperurl'        => $this->paper_url
      );
    }



    public function render ( $is_admin = false, $do_print = true )
    {
      $event_string = <<<EOE
<li itemscope itemtype="http://schema.org/Event">
  <span class="schemadata" itemprop="performer" itemscope itemtype="http://schema.org/Person">
    <span itemprop="name">Kyle Woodward</span>
    <span itemprop="sameas">http://kylewoodward.com</span>
  </span>
  <link itemtype="eventstatus" href="http://schema.org/EventScheduled" />
  <span itemprop="offers"></span>

EOE;

      if ( Admin::isLoggedIn() )
      {
        $event_string .= <<<EOH
  <div style="float:right;width:48px;text-align:center;cursor:pointer;background-color:#ffe6e6;line-height:48px;margin-left:5px;" onclick="return deleteItem( this, {$this->id} );">delete</div>
  <div style="float:right;width:48px;text-align:center;cursor:pointer;background-color:#eee;line-height:48px;" onclick="return editItem( this, {$this->id} );">edit</div>
EOH;
        $event_string .= sprintf( '<span id="event-%d-json" class="schemadata">%s</span>', $this->id, json_encode( $this ) );
      }
  
      //
      // CreativeWork
      //   * Name
      //   * URL
      // (Event title)
      // StartDate - EndDate ====== DONE TO HERE
      // Location
      //   * Name
      //   * Address
      //   * URL
      // (SuperEvent ============== DONE FROM HERE
      //   * Name
      //   * StartDate - EndDate
      //   * Location
      //     - Name
      //     - Address
      //     - URL
      // )
      // Details
      //
      
      $creative_work = <<<EOCW
<span itemprop="workfeatured" itemscope itemtype="http://schema.org/CreativeWork">
  %s<span class="event-title" itemprop="name">%s</span>%s
</span><a class="schema-data" href="/calendar.php" itemprop="url"><span itemprop="name">%s</span></a>

EOCW;
      $creative_work = sprintf( $creative_work,
        strlen( $this->paper_url ) ? sprintf( '<a href="%s" itemprop="url">', htmlspecialchars( $this->paper_url ) ) : '',
        htmlspecialchars( $this->paper_title ),
        strlen( $this->paper_url ) ? '</a>' : '',
        htmlspecialchars( $this->paper_title )
      );

      $time_template          = '<time datetime="%s" itemprop="%sdate">%s</time>';
      $event_time_string      = sprintf( "{$time_template}&ndash;{$time_template}", date( 'c', $this->event_start_time ), 'start', date( 'F d, g:ia', $this->event_start_time ), date( 'c', $this->event_end_time ), 'end', date( 'g:ia', $this->event_end_time ) );
      $conference_date_string = sprintf( $time_template, date( 'Y-m-d', $this->conference_start_date ), 'start', date( 'F d', $this->conference_start_date ) ) . (
          $this->conference_start_date != $this->conference_end_date ? sprintf( "&ndash;{$time_template}", date( 'Y-m-d', $this->conference_end_date ), 'end', date( 'F d', $this->conference_end_date ) ) :
          ''
        );

      // need to add lat/lng
      // need to add differential places (?)
      $location = <<<EOL
<span itemprop="location" itemscope itemtype="http://schema.org/Place">
  %s<span itemprop="name">%s</span>%s
  <span class="%s">(<span itemprop="address">%s</span>)</span>
</span>

EOL;
      $location = sprintf( $location,
        strlen( $this->location_url ) ? sprintf( '<a href="%s" itemprop="url">', htmlspecialchars( $this->location_url ) ) : '',
        htmlspecialchars( $this->location ),
        strlen( $this->location_url ) ? '</a>' : '',
        $this->isConference() ? 'event-location' : 'schema-data',
        $this->location_address
      );

      $super_event = <<<EOSE
<span class="schema-data" itemprop="superevent" itemscope itemtype="http://schema.org/Event">
  <link itemprop="eventstatus" itemtype="http://schema.org/EventScheduled" />
  %s<span itemprop="name">%s</span>%s
  %s
  %s
</span>

EOSE;
      $super_event = sprintf( $super_event,
        strlen( $this->conference_url ) ? sprintf( '<a href="%s" itemprop="url">', htmlspecialchars( $this->conference_url ) ) : '',
        htmlspecialchars( $this->conference_name ),
        strlen( $this->conference_url ) ? '</a>' : '',
        $conference_date_string,
        $location
      );

      $event_string .= $creative_work;
      $event_string .= sprintf( '<span class="event-time">%s</span>', $this->isPresentation() ? $event_time_string : $conference_date_string );
      $event_string .= $this->isConference() ? $super_event : '';
      $event_string .= $location;
      $event_string .= sprintf( '<span class="event-details" itemprop="description">%s</span>', htmlspecialchars( $this->details ) );
      $event_string .= '</li>';

      //
      // Display string
      //
      if ( $do_print )
      {
        print $event_string;
      }
      else
      {
        return $event_string;
      }
    }
  }







?>
<!-- h3>calendar</h3 -->
<?



  $calendar = CalendarItem::fetchFutureCalendarItems();
  $month    = '';
  for ( $i = 0; $i < count( $calendar ); ++$i )
  {
    $item = $calendar[$i];
    if ( $item->getMonth() != $month )
    {
      if ( strlen( $month ) > 0 )
      {
        print '</ul>';
      }

      $month = $item->getMonth();
      printf( '<h3>%s</h3><ul>', strtolower( $month ) );
    }

    $item->render( Admin::isLoggedIn() );
  }

  if ( strlen( $month ) > 0 )
  {
    print '</ul>';
  }
  else
  {
?>
<h3>calendar</h3>
<p>
No upcoming events.
</p>
<?php
  }



?>
<?php



  if ( Admin::isLoggedIn() )
  {
    if ( $_GET['action'] == 'edititem' )
    {
// why are these in here?
//      $form              = array();
//      $submission_errors = array();
    }
?>
<h3>create new event</h3>
<?php

    if ( count( $submission_errors ) )
    {
?>
<div style="background-color:rgba(153,0,0,0.2);margin:1ex;padding:1ex;">
<p>Please fix the following errors:</p>
<ul style="margin:0ex 0ex 0ex 2ex;">
<?php
      foreach ( $submission_errors as $error )
      {
        ?><li><?php print $error; ?></li><?
      }
?>
</ul></div>
<?php
    }
?>
<form action="?action=newitem" method="post" id="eventform" style="margin-top:2ex;">
  <table>
    <tbody>
      <tr><td><label for="papertitle">Title</label></td><td><input id="papertitle" name="papertitle" type="text"<?php defaultValue( $form, 'papertitle', $submission_errors ); ?> /></td></tr>
      <tr><td><label for="starttime">Start time</label></td><td><input id="starttime" name="starttime" placeholder="yyyy-mm-dd hh:mm[AP]" type="datetime-local"<?php defaultValue( $form, 'starttime', $submission_errors ); ?> /></td></tr>
      <tr><td><label for="endtime">End time</label></td><td><input id="endtime" name="endtime" placeholder="yyyy-mm-dd hh:mm[AP]" type="datetime-local"<?php defaultValue( $form ,'endtime', $submission_errors );?> /></td></tr>
      <tr><td><label for="startdate">Event start</label></td><td><input id="startdate" name="startdate" placeholder="yyyy-mm-dd" type="date"<?php defaultValue( $form, 'startdate', $submission_errors ); ?> /></td></tr>
      <tr><td><label for="enddate">Event end</label></td><td><input id="enddate" name="enddate" placeholder="yyyy-mm-dd" type="date"<?php defaultValue( $form, 'enddate', $submission_errors ); ?> /></td></tr>
      <tr><td><label for="conferencename">Conference name</label></td><td><input id="conferencename" name="conferencename" type="text"<?php defaultValue( $form, 'conferencename', $submission_errors ); ?> /></td></tr>
      <tr><td><label for="conferenceurl">Conference URL</label></td><td><input id="conferenceurl" name="conferenceurl" type="url"<?php defaultValue( $form, 'conferenceurl', $submission_errors ); ?> /></td></tr>
      <tr><td><label for="location">Location name</label></td><td><input id="location" name="location" type="text"<?php defaultValue( $form, 'location', $submission_errors ); ?> /></td></tr>
      <tr><td><label for="locationaddress">Location address</label></td><td><input id="locationaddress" name="locationaddress" type="text"<?php defaultValue( $form, 'locationaddress', $submission_errors ); ?> /></td></tr>
      <tr><td><label for="locationurl">Location URL</label></td><td><input id="locationurl" name="locationurl" type="url"<?php defaultValue( $form, 'locationurl', $submission_errors ); ?> /></td></tr>
      <tr><td><label for="locationlatlng">Location</label></td><td><input id="locationlatlng" name="locationlatlng" placeholder="latitude, longitude" type="text"<?php defaultValue( $form, 'locationlatlng', $submission_errors ); ?> /></td></tr>
      <tr><td><label for="details">Details</label></td><td><textarea id="details" name="details" style="font-family:inherit;"><?php
        if ( strlen( $form['details'] ) )
        {
          print htmlspecialchars( $form['details'] );
        }
      ?></textarea></td></tr>
      <tr><td><label for="paperurl">URL</label></td><td><input id="paperurl" name="paperurl" type="url"<?php defaultValue( $form, 'paperurl', $submission_errors ); ?> /></td></tr>
      <tr><td></td><td><input id="newitemsubmit" type="submit" value="Create" /></td></tr>
    </tbody>
  </table>
</form>
<?
  }



  $page->printPageFooter();



?>