Work on template
authorSteve Sutton <steve@gaslightmedia.com>
Tue, 12 Aug 2014 18:49:17 +0000 (14:49 -0400)
committerSteve Sutton <steve@gaslightmedia.com>
Tue, 12 Aug 2014 18:55:08 +0000 (14:55 -0400)
Output blocks
Output main nav
Output mobile nav

15 files changed:
.gitignore
Toolkit/Events/AddCommonEventForm.php [new file with mode: 0644]
Toolkit/Events/css/event.css [new file with mode: 0755]
Toolkit/Events/views/eventDetail.html [new file with mode: 0755]
Toolkit/Events/views/eventHomePage.html [new file with mode: 0755]
Toolkit/Events/views/eventList.html [new file with mode: 0755]
Toolkit/Events/views/eventSearchForm.html [new file with mode: 0755]
Toolkit/Events/views/mainEventWrapper.html [new file with mode: 0755]
Toolkit/Page.php
Toolkit/Template/BreadCrumbs.php
Toolkit/Toolbox/Forms/EditPage.php
assets/go.png [new file with mode: 0755]
assets/navBg.png [new file with mode: 0755]
robots.txt [new file with mode: 0644]
templates/template.html

index a86e0ec..4c853cb 100644 (file)
@@ -38,3 +38,5 @@ editimagespng/
 nbproject
 Toolkit/Members/MemberImport/upload
 Toolkit/Members/MemberImport/fileHeaders.txt
+Phing
+smarty/
diff --git a/Toolkit/Events/AddCommonEventForm.php b/Toolkit/Events/AddCommonEventForm.php
new file mode 100644 (file)
index 0000000..18e4a6e
--- /dev/null
@@ -0,0 +1,1045 @@
+<?php
+
+//     vim:set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker syntax=php:
+
+/**
+ * New Event Form
+ *
+ * PHP version 5
+ *
+ * @category Toolkit
+ * @package  Events
+ * @author   Steve Sutton <steve@gaslightmedia.com>
+ * @license  http://www.gaslightmedia.com Gaslightmedia
+ * @version  CVS: $Id: AddEventForm.php,v 1.20 2010/07/04 23:58:22 jamie Exp $
+ * @link     http://demo.gaslightmedia.com
+ */
+
+/**
+ * New Event Form
+ *
+ * @category  Toolkit
+ * @package   Events
+ * @author    Steve Sutton <steve@gaslightmedia.com>
+ * @copyright 2012 Gaslight Media
+ * @license   http://www.gaslightmedia.com Gaslightmedia
+ * @link      http://demo.gaslightmedia.com
+ */
+class Toolkit_Events_AddCommonEventForm
+    extends Toolkit_FormBuilder
+    implements Toolkit_Form
+{
+    // {{{     properties
+
+    /**
+     * Table in Database which holds the contact data
+     *
+     * @var    string
+     * @access public
+     */
+    public $tableName = 'events.events';
+
+    /**
+     * Table meta data
+     *
+     * This is used when inserting/updating data for the records
+     * so the PDO's can use explicit data types for the parameters.
+     *
+     * @var    array
+     * @access public
+     */
+    public $tableMetaData;
+
+    /**
+     * Who to send the email to when the contact form is submitted
+     *
+     * If you leave this blank, its value will get set to the OWNER_EMAIL
+     * in the constructor.
+     *
+     * If you ***DO NOT*** want any emails to go out when the form is submitted
+     * then set the value to false. Do not set it to 0 for false, because the
+     * check uses a strict type check to determine if the value is actually
+     * false. This is what allows for the empty value as an option, which sets
+     * the value to OWNER_EMAIL and won't override the $email property if
+     * this class gets subclassed and the value for this property gets set in
+     * the properties of the subclass and not in the constructor after this
+     * constructor function is called.
+     *
+     * tongue twister...I know.
+     * <code>
+     * protected $email = false;
+     * </code>
+     *
+     * @var    unknown
+     * @access protected
+     */
+    protected $email;
+
+    /**
+     * From header in the owner email
+     *
+     * This just sets the From header in the owner email
+     * SITENAME <from@email.com>
+     *
+     * It gets set to the constant SITENAME in the constructor if you leave
+     * empty here, but you can set it to something different here to override
+     * that if you desire.
+     *
+     * @var    unknown
+     * @access protected
+     */
+    protected $siteName;
+
+    /**
+     * Email subject and <h1> header in email
+     *
+     * It gets set in the constructor if you leave empty here, but you
+     * can set it to something different here to override that if you desire.
+     *
+     * @var    string
+     * @access protected
+     */
+    protected $subject = 'New Event Submission';
+
+    /**
+     * Message to display if the form is successfully submitted
+     *
+     * @var    string
+     * @access protected
+     */
+    protected $successMsg = '
+    <style type="text/css">
+        #category {display:none};
+        .listings {display:none};
+    </style>
+               <div id="form-sucess-top">
+            Your event has been successfully added to the events calendar,
+            however will not be visible until it has been approved by
+            the Web site administrator. Thank You.
+               </div>';
+
+    /**
+     * Extra rules for processesing
+     *
+     * This registers the Zip validation rules (and any others listed) for
+     * QuickForm.
+     *
+     * Zip validation checks both US and Canadian Zip codes
+     *
+     * @var    array
+     * @access protected
+     */
+    protected $registeredRules = array(
+        'phone',
+        array(
+            'checkEmail',
+            'callback',
+            'email',
+            'Validate'
+        ),
+        array(
+            'checkURI',
+            'callback',
+            'uri',
+            'Validate'
+        )
+    );
+
+    /**
+     * Options for flexy templating engine
+     *
+     * Pulls the preset options from the setup.phtml file
+     * overwrites the templateDir and compileDir to match this classes needs
+     *
+     * @var    array
+     * @access protected
+     */
+    protected $flexyOptions;
+
+    protected $eventMapper;
+
+    // }}}
+    // {{{     __construct()
+
+    /**
+     * Class constructor
+     *
+     * @param PDO    $pdo         PHP Data Object
+     * @param string $formName    Form's name.
+     * @param string $method      (optional)Form's method defaults to 'POST'
+     * @param string $action      (optional)Form's action
+     * @param string $target      (optional)Form's target defaults to '_self'
+     * @param mixed  $attributes  (optional)Extra attributes for <form> tag
+     * @param bool   $trackSubmit (optional)Whether to track if the form was
+     *                                                           submitted by adding a special hidden field
+     *
+     * @access public
+     */
+    public function __construct(
+        PDO $pdo,
+        $formName,
+        $method = 'post',
+        $action = '',
+        $target = '',
+        $attributes = null,
+        $trackSubmit = false,
+        EventMapper $eventMapper
+    ) {
+        parent::__construct(
+            $formName, $method, $action, $target, $attributes, $trackSubmit
+        );
+
+        $this->dbh = $pdo;
+        $this->eventMapper = $eventMapper;
+
+        if ($this->email !== false && empty($this->email)) {
+            // Set to false to turn off email function.
+            $this->email = ADD_EVENT_EMAIL;
+        }
+        if (empty($this->siteName)) {
+            $this->siteName = SITENAME;
+        }
+        if (empty($this->subject)) {
+            $this->subject = 'Contact Request from website ' . SITENAME;
+        }
+
+        $this->flexyOptions = $GLOBALS['flexyOptions'];
+        $this->flexyOptions['templateDir'] = dirname(__FILE__) . "/templates/";
+        $this->flexyOptions['compileDir'] = dirname(__FILE__) . "/templates/compiled/";
+
+        $var = basename(__FILE__, '.php');
+
+        $callbackUrl = MEDIA_BASE_URL;
+
+        $this->captchaOptions = array(
+            'width'        => 100,
+            'height'       => 50,
+            'callback'     => "{$callbackUrl}Toolkit/qfcaptcha.php?var=$var",
+            'sessionVar'   => $var,
+            'imageOptions' => array(
+                'font_size'        => 16,
+                'font_path'        => GLM_APP_BASE . 'glmPEAR/Image/Canvas/Fonts/',
+                'font_file'        => 'times.ttf',
+                'background_color' => '#cccccc',
+                'obfuscation'      => false,
+                'angle'            => true,
+            ),
+        );
+    }
+
+    // }}}
+    //  {{{ checkDate()
+
+    /**
+     * Validate date input
+     *
+     * allows for empty dates to be valid
+     *
+     * @param array $date date group from form
+     *
+     * @return boolean true if valid, false if not
+     * @access public
+     */
+    public function checkDate($date)
+    {
+        if (!$date) {
+            return true;
+        } else {
+            return Validate::date($date, array('format' => '%m/%d/%Y'));
+        }
+    }
+
+    //  }}}
+    //  {{{ checkDateRange()
+
+    /**
+     * Validate date input
+     *
+     * allows for empty end date to be valid
+     *
+     * @param array $d date group from form
+     *
+     * @return boolean true if valid, false if not
+     * @access public
+     */
+    public function checkDateRange(array $d)
+    {
+        if (!$this->hasEndDate($d[1])) {
+            //  no end date is a valid date range
+            return true;
+        }
+        $pattern = '/([0-9]{2})\/([0-9]{2})\/([0-9]{4})/';
+        if (preg_match($pattern, $d[0], $m)) {
+            $t1 = mktime(0, 0, 0, (int) $m[1], (int) $m[2], (int) $m[3]);
+            $bdate = new Date($t1);
+        }
+        if (preg_match($pattern, $d[1], $m)) {
+            $t2    = mktime(0, 0, 0, (int) $m[1], (int) $m[2], (int) $m[3]);
+            $edate = new Date($t2);
+        }
+        if ($bdate && $edate) {
+            //  0 if the dates are equal - valid
+            // -1 if $bdate is before $edate - valid
+            //  1 if $bdate is after $edate - invalid
+            $res = Date::compare($bdate, $edate);
+            return ($res !== 1);
+        }
+        return true;
+    }
+
+    //  }}}
+    // {{{     configureElements()
+
+    /**
+     * Form element definitions
+     *
+     * @return void
+     * @access public
+     */
+    public function configureElements()
+    {
+        $e = array();
+
+        //     All Elements are created here.  This includes group element definitions.
+        $e[] = array(
+            'type'    => 'header',
+            'name'    => 'eventInfoHdr',
+            'display' => 'Event Information'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => true,
+            'name'    => 'header',
+            'display' => 'Event Name'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => true,
+            'name'    => 'starting',
+            'display' => 'Start Date',
+            'opts'    => array('id' => 'sdate')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => true,
+            'name'    => 'ending',
+            'display' => 'End Date',
+            'opts'    => array('id' => 'edate')
+        );
+        $e[] = array(
+            'type'    => 'date',
+            'req'     => false,
+            'name'    => 'btime',
+            'display' => 'Start Time',
+            'opts'    => array(
+                'format'           => 'h : i A',
+                'addEmptyOption'   => true,
+                'emptyOptionValue' => '',
+                'emptyOptionText'  => array(
+                    'h' => 'hh',
+                    'i' => 'mm',
+                    'A' => 'am/pm'
+                ),
+                'optionIncrement' => array(
+                    'i' => 15,
+                ),
+            ),
+            'error' => 'ERROR: You must select a start time!',
+        );
+        $e[] = array(
+            'type'    => 'date',
+            'req'     => false,
+            'name'    => 'etime',
+            'display' => 'End Time',
+            'opts'    => array(
+                'format'           => 'h : i A',
+                'addEmptyOption'   => true,
+                'emptyOptionValue' => '',
+                'emptyOptionText'  => array(
+                    'h' => 'hh',
+                    'i' => 'mm',
+                    'A' => 'am/pm'
+                ),
+                'optionIncrement' => array(
+                    'i'  => 15,
+                ),
+            ),
+        );
+        $e[] = array(
+            'type'    => 'select',
+            'req'     => true,
+            'name'    => 'category',
+            'display' => 'Category',
+            'opts'    => $this->getTopicFields(),
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'website',
+            'display' => 'Event Website'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'facebook',
+            'display' => 'Facebook',
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'twitter',
+            'display' => 'Twitter',
+        );
+
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'cost',
+            'display' => 'Cost',
+        );
+
+        $e[] = array(
+            'type'    => 'textarea',
+            'req'     => false,
+            'name'    => 'description',
+            'display' => 'Event Description',
+            'opts'    => array('id' => 'description')
+        );
+        $e[] = array(
+            'type'    => 'header',
+            'name'    => 'eventLocationInfoHeader_rmv',
+            'display' => 'Event Location Information
+                <div id="map-dialog">
+                    <div id="map_canvas" style="width:500px; height:400px"></div>
+                </div>
+                <a id="map-it" href="#">Map It</a>'
+        );
+        $e[] = array(
+            'type' => 'hidden',
+            'req'  => false,
+            'name' => 'lat',
+            'opts' => array('id' => 'lat')
+        );
+        $e[] = array(
+            'type' => 'hidden',
+            'req'  => false,
+            'name' => 'lon',
+            'opts' => array('id' => 'lon')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => true,
+            'name'    => 'place',
+            'display' => 'Place'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'address',
+            'display' => 'Address'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => true,
+            'name'    => 'city',
+            'display' => 'City'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'state',
+            'display' => 'State'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'zip',
+            'display' => 'ZIP'
+        );
+        $e[] = array(
+            'type'    => 'header',
+            'name'    => 'eventContactHeader_rmv',
+            'display' => 'Event Contact Information'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'contact_name',
+            'display' => 'Event Contact Person<br>(published on Web site)'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'contact_email',
+            'display' => 'Contact Email<br>(published on Web site)'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => true,
+            'name'    => 'contact_phone',
+            'display' => 'Contact Phone<br>(published on Web site)'
+        );
+
+        $e[] = array(
+            'type'    => 'header',
+            'name'    => 'adminInfoHdr',
+            'display' => 'Event Admin Information'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => true,
+            'name'    => 'admin_contact',
+            'display' => 'Contact Name Submitting Event'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => true,
+            'name'    => 'admin_org',
+            'display' => 'Organization Name Submitting Event'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => true,
+            'name'    => 'admin_phone',
+            'display' => 'Phone'
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => true,
+            'name'    => 'admin_email',
+            'display' => 'Email Address'
+        );
+
+        if ($this->useCaptcha) {
+            $e[] = array(
+                'type'    => 'CAPTCHA_Image',
+                'req'     => false,
+                'name'    => 'captcha_question',
+                'display' => 'Verification code',
+                'opts'    => $this->captchaOptions
+            );
+            $e[] = array(
+                'type'    => 'text',
+                'req'     => true,
+                'name'    => 'captcha_rmv',
+                'display' => 'Enter verification code',
+            );
+        }
+        $e[] = array(
+            'type'    => 'submit',
+            'req'     => false,
+            'name'    => 'submit_rmv',
+            'display' => 'Submit'
+        );
+
+        $this->setupElements($e);
+    }
+
+    // }}}
+    // {{{     configureFilters()
+
+    /**
+     * Form filter definitions
+     *
+     * Applies a data filter for the given fields when the form is submitted
+     *
+     * @return void
+     * @access public
+     */
+    public function configureFilters()
+    {
+        $f = array();
+
+        $f[] = array(
+            'element' => '__ALL__',
+            'filter'  => 'trim'
+        );
+        $f[] = array(
+            'element' => 'website',
+            'filter'  => array('Toolkit_Common', 'filterURI')
+        );
+
+        $this->setupFilters($f);
+    }
+
+    // }}}
+    //  {{{ configureForm()
+
+    /**
+     * Helper function to handle setting up the form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureForm()
+    {
+        $this->configureElements();
+        $this->configureFilters();
+        $this->configureRules();
+    }
+
+    //  }}}
+    // {{{     configureRules()
+
+    /**
+     * Form rule definitions
+     *
+     * Adds validation rules for the given fields
+     *
+     * @return void
+     * @access public
+     */
+    public function configureRules()
+    {
+        //     Form Rules
+        $r[] = array(
+            'element'    => 'topicid',
+            'message'    => 'ERROR: Invalid Category!',
+            'type'       => 'numeric',
+            'format'     => null,
+            'validation' => $this->validationType,
+            'reset'      => true,
+            'force'      => false
+        );
+        $r[]         = array(
+            'element' => 'email',
+            'message' => 'ERROR: Invalid Email Format!',
+            'type'    => 'checkEmail',
+            'format'  => array('use_rfc822' => true),
+            'validation' => $this->validationType,
+            'reset'      => true,
+            'force'      => false
+        );
+        $r[]         = array(
+            'element' => array('starting', 'ending'),
+            'message' => 'ERROR: Starting Date must be before Ending Date',
+            'type'    => 'callback',
+            'format'  => array(&$this, 'checkDateRange'),
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+        $r[]         = array(
+            'element' => 'starting',
+            'message' => 'ERROR: Invalid date!',
+            'type'    => 'callback',
+            'format'  => array(&$this, 'checkDate'),
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+        $r[]         = array(
+            'element' => 'ending',
+            'message' => 'ERROR: Invalid date!',
+            'type'    => 'callback',
+            'format'  => array(&$this, 'checkDate'),
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+        $r[]         = array(
+            'element' => 'website',
+            'message' => 'ERROR: Invalid URL format',
+            'type'    => 'checkURI',
+            'format'  => array(
+                'allowed_schemes' => array('http', 'https'),
+                'strict'     => false
+            ),
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+        $r[]         = array(
+            'element'    => 'contact_phone',
+            'message'    => 'ERROR: Invalid Phone Format (xxx) xxx - xxxx!',
+            'type'       => 'phone',
+            'format'     => null,
+            'validation' => $this->validationType,
+            'reset'      => true,
+            'force'      => false
+        );
+        if ($this->useCaptcha) {
+            $r[] = array(
+                'element'    => 'captcha_rmv',
+                'message'    => 'ERROR: What you entered didn\'t match!',
+                'type'       => 'CAPTCHA',
+                'format'     => $this->captchaQuestion,
+                'validation' => $this->validationType,
+                'reset'      => true,
+                'force'      => false
+            );
+        }
+
+        $this->setupRules($r);
+    }
+
+    // }}}
+    // {{{     getTopicFields()
+
+    /**
+     * get event topics
+     *
+     * @return array topics
+     * @access protected
+     */
+    protected function getTopicFields()
+    {
+        $categories = array('' => '- select -');
+        $catData = $this->eventMapper->fetchAllCategories();
+        foreach ($catData as $category) {
+            $categories[$category->getId()] = $category->getName();
+        }
+        return $categories;
+    }
+
+    // }}}
+    //  {{{ hasEndDate()
+
+    /**
+     * verifies if we have a valid end date to work with
+     *
+     * @param array $d end date
+     *
+     * @return boolean if the end date is
+     */
+    protected function hasEndDate($d)
+    {
+        $pattern = '/([0-9]{2})\/([0-9]{2})\/([0-9]{4})/';
+        if (preg_match($pattern, $d, $m)) {
+            return checkdate((int) $m[1], (int) $m[2], (int) $m[3]);
+        } else {
+            return false;
+        }
+    }
+
+    //  }}}
+    // {{{     emailOwner()
+
+    /**
+     * Emails the owner the submitted data from the submitted form
+     *
+     * Uses a flexy template to render a nice looking html email.
+     * Fills in the supplied data from the form and doesn't add the
+     * empty fields the user didn't fill in.
+     *
+     * @return boolean   result of the mailing
+     * @access protected
+     */
+    protected function emailOwner()
+    {
+        if (!$this->email) {
+            return;
+        }
+
+        $template = new HTML_Template_Flexy($this->flexyOptions);
+        $page     = new stdClass();
+        // for comments textarea need to replace newlines with br
+        $this->formData['comments']['element'] = nl2br($this->getSubmitValue('comments'));
+        unset($this->formData['lat'], $this->formData['lon']);
+
+        //  these values are required, therefor will always be part of
+        //  the formData array
+        $bdate = explode('/', $this->formData['bdate']['element']);
+        $foo   = array_map('trim', $bdate);
+        $this->formatValue($foo, '%02d/%02d/%d');
+        $this->formData['bdate']['element'] = $foo;
+
+        $btime = explode('/', $this->formData['btime']['element']);
+        $foo   = array_map('trim', $btime);
+        $this->formatValue($foo, '%02d:%02d %s');
+        $this->formData['btime']['element'] = $foo;
+
+        //  not required, so check to make sure it exists before trying
+        //  to format the value
+        if (isset($this->formData['edate'])) {
+            $edate = explode('/', $this->formData['edate']['element']);
+            $foo   = array_map('trim', $edate);
+            $this->formatValue($foo, '%02d/%02d/%d');
+            $this->formData['edate']['element'] = $foo;
+        }
+        if (isset($this->formData['etime'])) {
+            $etime = explode('/', $this->formData['etime']['element']);
+            $foo   = array_map('trim', $etime);
+            $this->formatValue($foo, '%02d:%02d %s');
+            $this->formData['etime']['element'] = $foo;
+        }
+
+        $category = $this->eventMapper->fetchCategory(
+            $this->formData['category']['element']
+        );
+        if ($category) {
+            $this->formData['category']['element'] = $category->getName();
+        }
+
+        $page->email_from = FROM_NEWS_EMAIL;
+        $page->subject = $this->subject;
+        $page->formData = $this->formData;
+        $page->eventAdminURL = MEDIA_BASE_URL . 'admin/CommonEvents/index.php?pending=1';
+
+        $template->compile('emailOwner.tpl');
+        $htmlMsg = $template->bufferedOutputObject($page);
+
+        //     Text version can't have HTML in it
+        $msg = "{$page->subject}\n\n";
+        $msg .= "From {$page->fname} {$page->lname}\n\n";
+        $msg .= "Information\n\n";
+        foreach ($page->formData as $i) {
+            $msg .= "{$i['label']}: {$i['element']}\n";
+        }
+
+        $crlf     = "\n";
+        $mimeMail = new Mail_mime($crlf);
+        $mimeMail->setFrom("{$this->siteName} <{$page->email_from}>");
+        $mimeMail->setSubject($this->subject);
+        $mimeMail->setHTMLBody($htmlMsg);
+        $mimeMail->setTXTBody($msg);
+
+        $mail    = Mail::factory('mail');
+        $body    = $mimeMail->get();
+        $headers = $mimeMail->headers();
+
+        $res = $mail->send($this->email, $headers, $body);
+        if (PEAR::isError($res)) {
+            return Toolkit_Common::handleError($res);
+        } else {
+            return $res;
+        }
+    }
+
+    // }}}
+    //  {{{ formatValue()
+
+    /**
+     * Format an array into an acceptable string
+     *
+     * @param mixed  &$i     array values to format or null value for
+     *                       element that was not filled in
+     * @param string $format string to format values into
+     *
+     * @return string formatted string
+     * @access public
+     */
+    public function formatValue(&$i, $format)
+    {
+        //  Allow for 0 to be not empty.  This allows for minutes in the
+        //  time arrays to be valid if they are on the hour ie. (1:00 pm)
+        $notEmpty = create_function('$v', 'return strlen($v) > 0;');
+        if (is_array($i) && count(array_filter($i, $notEmpty)) == 3) {
+            list($x, $y, $z) = array_values($i);
+            eval("\$i = sprintf('$format', $x, $y, $z);");
+        } else {
+            $i = null;
+        }
+    }
+
+    //  }}}
+    // {{{     insertData()
+
+    /**
+     * Inserts contact data into the contact db
+     *
+     * @param array $values submitted values
+     *
+     * @return object result of db insert query
+     * @access protected
+     */
+    protected function insertData($values)
+    {
+        $values = $this->_geocode($values);
+
+        try {
+            // need to set the dates up first
+            $this->formatValue($values['btime'], '%d:%02d %s');
+            $this->formatValue($values['etime'], '%d:%02d %s');
+            $values['description'] = nl2br($values['description']);
+            $values['website']   = preg_replace("/^(http:\/\/)/", "", $values['website']);
+            if ($values['btime']) {
+                $values['starthour'] = $values['btime'];
+                unset($values['btime']);
+            }
+            if ($values['etime']) {
+                $values['endhour'] = $values['etime'];
+                unset($values['etime']);
+            }
+            if ($values['category']) {
+                $values['category'] = $this->eventMapper->fetchCategory(
+                    $values['category']
+                );
+            }
+            if (defined('MEMBERS_DB') && MEMBERS_DB) {
+                $event = MemberEvent::createByValues($values);
+            } else {
+                $event = Event::createByValues($values);
+            }
+            return $this->eventMapper->saveEvent($event);
+
+            return false;
+        } catch (PDOException $e) {
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+    // }}}
+    private function _geocode(array $values)
+    {
+        $geocoder = new GeocodeYahoo();
+        if (!$values['address'] && !$values['city'] && !$values['state']) {
+            return $values;
+        }
+        $address = array(
+                       'city'  => $values['city'],
+                       'state' => $values['state'],
+                       'zip'   => $values['zip'],
+               );
+               if (!empty($values['address'])) {
+                       $address['street'] = $values['address'];
+               }
+        try {
+            $response = $geocoder->geocodeAddress($address);
+            $responseArray = unserialize($response);
+            if ($responseArray['ResultSet']['Result'][0]['Latitude']) {
+                $values['lat'] = $responseArray['ResultSet']['Result'][0]['Latitude'];
+                $values['lon'] = $responseArray['ResultSet']['Result'][0]['Longitude'];
+            } else {
+                $values['lat'] = $responseArray['ResultSet']['Result']['Latitude'];
+                $values['lon'] = $responseArray['ResultSet']['Result']['Longitude'];
+            }
+
+            return $values;
+        } catch (BadMethodCallException $e) {
+            Toolkit_Logger::logException('Invalid Arg', $e);
+        } catch (Exception $e) {
+            Toolkit_Logger::logException('Yahoo GeoCode', $e);
+        }
+
+    }
+    // {{{     processData()
+
+    /**
+     * Handles how to process the form when submitted
+     *
+     * @param array $values Form submitted values
+     *
+     * @return array Result of Insert / Update function
+     * @access protected
+     */
+    public function processData($values)
+    {
+        //     Form data used for the insert/update sql queries and
+        //     the form email.
+        $e = array();
+        $this->setFormData($e);
+
+        //     Get rid of any defined un-needed elements.
+        //     un-needed elements after the form is submitted are defined
+        //     by the ending _rmv name.
+        foreach ($values as $k => &$v) {
+            if (!is_array($v)) {
+                $values[$k] = preg_replace("/\r/", "\n", $v);
+            }
+            if (preg_match('/^.+_rmv$/', $k)) {
+                unset($values[$k]);
+            }
+        }
+        $values['create_date'] = date('m/d/Y');
+
+        return $this->insertData($values);
+    }
+
+    // }}}
+    // {{{     setupRenderers()
+
+    /**
+     * Custom rendering templates for special fields on the form
+     *
+     * @return void
+     * @access protected
+     */
+    protected function setupRenderers()
+    {
+        parent::setupRenderers();
+        $renderer = $this->defaultRenderer();
+        $required = '<!-- BEGIN required --><span class="req">*</span><!-- END required -->';
+        $error    = '<!-- BEGIN error --><div class="req">{error}</div><!-- END error -->';
+
+        $renderer->setElementTemplate('<tr><td colspan="2">' . $required . '{label}' . $error . '{element}</td></tr>', 'descr');
+        $renderer->setElementTemplate('<tr align="center"><td colspan="2">' . $required . '{label}' . $error . '{element}</td></tr>', 'submit_rmv');
+
+        if ($this->useCaptcha) {
+            $renderer->setElementTemplate('<tr><td class="labelcell"><label>{label}</label></td><td class="fieldcell captcha">{element}</td></tr>', 'captcha_question');
+            $renderer->setElementTemplate('<tr><td class="labelcell">' . $required . '<label>{label}</label></td><td class="fieldcell">' . $error . '{element}<span class="tooltip" title="Verification Code|To help us distinguish between information submitted by individuals and those automatically entered by software robots, please type the letters shown.">What is this?</span></td></tr>', 'captcha_rmv');
+        }
+    }
+
+    // }}}
+    // {{{     toHtml()
+
+    /**
+     * Handles how to display the current step the user is at in the form
+     *
+     * destroying and resetting the captcha value dis-allows someone from
+     * re-sending a form on a previous captcha.
+     *
+     * @return string form HTML state
+     * @access public
+     */
+    public function toHtml()
+    {
+        $this->setupRenderers();
+        if ($this->validate()) {
+            $this->captchaQuestion->destroy();
+            $this->cleanForm();
+
+            if ($this->process(array(&$this, 'processData'), $this->mergeFiles)) {
+                $this->freeze();
+                $this->emailOwner();
+                $output = $this->successMsg;
+            }
+            $this->sent = true;
+        } elseif ($this->isSubmitted()) {
+            if ($this->useCaptcha) {
+                $this->captchaQuestion->destroy();
+                $this->captchaAnswer->setValue('');
+            }
+            $output                     = $this->errorMsg;
+            $GLOBALS['topScripts'][]
+                = MEDIA_APP_BASE_URL
+                . 'libjs/jqueryui/1.8.13/js/jquery-ui-1.8.13.custom.min.js';
+            $GLOBALS['styleSheets'][]
+                = MEDIA_APP_BASE_URL
+                . 'libjs/jqueryui/1.8.13/development-bundle/themes/base/jquery.ui.all.css';
+            $GLOBALS['bottomScripts'][] = MEDIA_APP_BASE_URL . 'libjs/textlimit.js';
+            $GLOBALS['topScripts'][]
+                = 'http://maps.googleapis.com/maps/api/js?sensor=true';
+            $GLOBALS['bottomScripts'][]
+                = MEDIA_BASE_URL . 'Toolkit/Maps/geoCoder.js';
+            $GLOBALS['bottomScripts'][]
+                = MEDIA_BASE_URL . 'Toolkit/Events/libjs/addEvent.js';
+            $output .= parent::toHtml();
+        } else {
+            if ($this->useCaptcha) {
+                $this->captchaQuestion->destroy();
+                $this->captchaAnswer->setValue('');
+            }
+            $GLOBALS['topScripts'][]
+                = MEDIA_APP_BASE_URL
+                . 'libjs/jqueryui/1.8.13/js/jquery-ui-1.8.13.custom.min.js';
+            $GLOBALS['styleSheets'][]
+                = MEDIA_APP_BASE_URL
+                . 'libjs/jqueryui/1.8.13/development-bundle/themes/base/jquery.ui.all.css';
+            $GLOBALS['bottomScripts'][] = MEDIA_APP_BASE_URL . 'libjs/textlimit.js';
+            $GLOBALS['topScripts'][]
+                = 'http://maps.googleapis.com/maps/api/js?sensor=true';
+            $GLOBALS['bottomScripts'][]
+                = MEDIA_BASE_URL . 'Toolkit/Maps/geoCoder.js';
+            $GLOBALS['bottomScripts'][]
+                = MEDIA_BASE_URL . 'Toolkit/Events/libjs/addEvent.js';
+            $output                     = parent::toHtml();
+        }
+        return $output;
+    }
+
+    // }}}
+}
+
+?>
diff --git a/Toolkit/Events/css/event.css b/Toolkit/Events/css/event.css
new file mode 100755 (executable)
index 0000000..d6e4289
--- /dev/null
@@ -0,0 +1,479 @@
+/* Events */
+#event-main-column,
+#event-second-column {
+    position: relative;
+    }
+#event-main-column #slider-wrapper {
+    position: relative;
+    }
+#event-main-column #slider-wrapper .nivo-controlNav {
+    position: absolute;
+    bottom: 10px;
+    width: 100%;
+    z-index: 100;
+    }
+.eventrow {
+    font-size: 13px;
+    }
+/* Main Columns on all even pages  */
+#event-main-column {
+       float: left;
+       margin: 0 0 20px 0;
+       }
+#event-second-column {
+       float: right;
+       /*border: 1px solid #c4d2da;*/
+       margin: 0 0 20px 0;
+       }
+
+/* Search Column */
+#event-second-column h3 {
+       margin: 0;
+       /*padding: 15px 5px 5px;*/
+       padding: 0 5px 5px 5px;
+       color: #0578B2;
+       /*border-top: 1px solid #999;*/
+       font-size: 18px;
+    }
+/* Event Shortcuts */
+#event-shortcuts ul {
+       /*background: #c4d2da;*/
+       padding-bottom: 20px;
+       /*background: #114C75;
+       -webkit-border-radius: 6px;
+       -moz-border-radius: 6px;
+       border-radius: 6px;
+       -webkit-box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.4);
+       -moz-box-shadow:    1px 1px 4px rgba(0, 0, 0, 0.4);
+       box-shadow:         1px 1px 4px rgba(0, 0, 0, 0.4);
+    */
+       background: no-repeat url(../../../assets/navBg.png);
+    background-size: cover;
+       }
+#event-shortcuts li {
+       padding: 5px 5px 0;
+       }
+#event-shortcuts a {
+       display: block;
+       padding: 5px;
+       text-align: center;
+       border: 1px solid;
+       border-top-color: #ccc;
+       border-right-color: #aaa;
+       border-bottom-color: #aaa;
+       border-left-color: #ccc;
+       background: #fff;
+       text-decoration: none;
+       color: black;
+       font-size: 14px;
+    }
+#event-shortcuts a:hover {
+       border-top-color: #aaa;
+       border-right-color: #ccc;
+       border-bottom-color: #ccc;
+       border-left-color: #aaa;
+       background: #eee;
+       }
+#event-shortcuts h3 {
+       margin-top: 20px;
+       }
+/* Event Search Form Side */
+#event-search form {
+       background: #c4d2da;
+       background: #eee;
+    background: #0578B2;
+       background: no-repeat url(../../../assets/navBg.png);
+    background-size: cover;
+        padding: 5px 5px 15px 5px;
+       /* background: #114C75;
+       -webkit-border-radius: 6px;
+       -moz-border-radius: 6px;
+       border-radius: 6px;
+       -webkit-box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.4);
+       -moz-box-shadow:    1px 1px 4px rgba(0, 0, 0, 0.4);
+       box-shadow:         1px 1px 4px rgba(0, 0, 0, 0.4);
+       */
+    }
+#event-search form span {
+    color: white;
+    font-size: 14px;
+    display: block;
+    padding: 5px 0;
+    }
+#eventNameSearchWrapper form span  {
+    text-align: center;
+    }
+
+#event-search #startMonth,
+#event-search #endMonth {
+       border: 1px solid #aaa;
+       padding: 2px 4px;
+       display: block;
+       /*background: #fff url(http://app.gaslightmedia.com/assets/icons/calendar.png) no-repeat 156px center;*/
+       background: #fff;
+       margin: 6px 0;
+       width: 100%;
+    }
+#startMonthWrapper, #endMonthWrapper {
+       position: relative;
+       z-index: 5;
+       }
+.ui-datepicker-trigger {
+       position: absolute;
+       z-index: 6;
+       right: 5px;
+       top: 3px;
+       cursor: pointer;
+       }
+#event-search select {
+       border: 1px solid #aaa;
+       padding: 2px 4px;
+       width: 100%;
+       display: block;
+       }
+#submitWrapper, #submitNameWrapper, #event-search input[type="image"] {
+       text-align: center;
+       }
+#event-search span {
+       font-weight: bold;
+       }
+/* Featured Events Side */
+#event-featured div {
+       background-repeat: no-repeat; 
+       padding-bottom: 20px;
+       height: 100px;
+       position: relative;
+       /* border: 1px solid #c4d2da;
+       border-bottom: 1px solid #c4d2da; */
+       margin: 0 0 10px 0px;
+       }
+#event-featured h3 {
+       margin-top: 20px;
+       }
+#event-featured p {
+       position: absolute;
+       right: 0;
+       bottom: 5px;
+       display: inline-block;
+       /*background: #ddd;*/
+       background: rgba(255, 255, 255, .8);
+       margin: 0;
+       padding: 3px 6px;
+       font-size: 11px;
+       /* font-size: 1rem; */
+       }
+#event-featured a {
+       position: absolute;
+       left: 0;
+       top: 0;
+       width: 100%;
+       background: #ddd;
+       background: rgba(255, 255, 255, .9);
+       padding: 3px 5px;
+       font-size: 12px;
+       /* font-size: 1rem; */
+       }
+/* MAIN EVENT PAGE */
+.eventrow {
+       overflow: hidden;
+       height: 1%;
+       clear: left;
+       }
+.event-category-block {
+       background: #eee;
+       border: 1px solid #ccc;
+    
+       margin: 20px 20px 0 0;
+       float: left;
+       width: 240px;
+/*     -webkit-border-radius: 6px;
+       -moz-border-radius: 6px;
+       border-radius: 6px;
+       -webkit-box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.4);
+       -moz-box-shadow:    1px 1px 4px rgba(0, 0, 0, 0.4);
+       box-shadow:         1px 1px 4px rgba(0, 0, 0, 0.4);
+*/     }
+.event-category-2 {
+       margin-right: 0;
+       }
+#event-main-column .event-category-block h2 {
+       /* font-size: 1.3rem; */
+       border-bottom: 1px solid #999;
+       margin: 0;
+       padding: 5px 10px;
+       background: #ddd;
+       -webkit-border-top-left-radius: 6px;
+       -webkit-border-top-right-radius: 6px;
+       -moz-border-radius-topleft: 6px;
+       -moz-border-radius-topright: 6px;
+       border-top-left-radius: 6px;
+       border-top-right-radius: 6px;
+       }
+.event-category-block div {
+       /*border-bottom: 1px solid #ccc;*/
+       padding: 5px 10px;
+       font-weight: bold;
+       }
+.event-category-block b {
+       margin-right: 10px;
+       font-weight: bold;
+       display: block;
+       }
+.event-category-block a, .event-list a, .eventDetail a, #eventDetailContact a {
+       color: #114C75;
+       }
+.event-more {
+       display: block;
+       text-align: right;
+       padding: 5px;
+       font-size: 12px;
+       /* font-size: 1.2rem; */
+       display: none;
+       }
+.event-more:hover {
+       background: #fefefe;
+       }
+/* Event Detail page */
+.gmnoprint { /* removes map ui */
+       display: none !important;
+       }
+#eventDetail {
+       margin-top: 1em;
+       font-size: 12px;
+    }
+#eventDetail h2 {
+       position: relative;
+       margin: 0;
+       padding: 10px;
+       border: 1px solid #ccc;
+       }
+#eventDetail h2 p {
+       display: inline-block;
+       background: white;
+       background: rgba(255, 255, 255, .9);
+       padding: 10px;
+       margin: 0;
+       position: absolute;
+       bottom: 20px;
+       left: 20px;
+       font-size: 18px;
+       /* font-size: 1.8rem; */
+       }
+#eventDetailTop {
+       background: #eee;
+       height: 1%;
+       overflow: hidden;
+       border: 1px solid #ccc;
+       border-top: 1px solid #eee;
+       }
+#eventDetailMap {
+
+       border: 1px solid;
+       border-top-color: #ccc;
+       border-right-color: #aaa;
+       border-bottom-color: #aaa;
+       border-left-color: #ccc;
+    margin-top: 10px;
+    }
+#eventDetailMap:hover {
+       border-top-color: #aaa;
+       border-right-color: #ccc;
+       border-bottom-color: #ccc;
+       border-left-color: #aaa;
+       }
+#eventDetail-map {
+       cursor: pointer;
+       height:160px; 
+       }
+#EventDrivingDirectionsContainer {
+       margin: 10px 0 0 0;
+       }
+#EventDrivingDirectionsForm {
+    margin: 0;
+    }
+#EventDrivingDirectionSubmit {
+    display: block;
+    width: 100%;
+    line-height: 28px;
+    height: 28px;
+       border: 1px solid;
+       border-top-color: #ccc;
+       border-right-color: #aaa;
+       border-bottom-color: #aaa;
+       border-left-color: #ccc;
+       background: white;
+       font-size: 12px;
+       /* font-size: 1.0rem; */
+       color: #000;
+       cursor: pointer;
+       }
+#EventDrivingDirectionSubmit:hover {
+       border-top-color: #aaa;
+       border-right-color: #ccc;
+       border-bottom-color: #ccc;
+       border-left-color: #aaa;
+       background: #eee;
+       }
+#EventDrivingDirectionSubmit:hover {
+       background-position: 0px -28px;
+       }
+#eventDetailInfo {
+       padding: 10px;
+       font-size: 12px;
+       /* font-size: .8rem; */
+       height: 1%;
+       overflow: hidden;
+       line-height: 1.5;
+    }
+#eventDetailInfo > div {
+       height: 1%;
+       overflow: hidden;
+       padding: 5px 5px 5px 30px;
+       margin: 0 5px 5px 0;
+       border-top: 1px solid #ededed;
+       border-left: 1px solid #ededed;
+       border-right: 1px solid #ddd;
+       border-bottom: 1px solid #ddd;
+       background-color: #fefefe;
+       background-repeat: no-repeat;
+       background-position: 6px 6px;
+       }
+#eventDetailTime {
+       background-image: url(http://app.gaslightmedia.com/assets/icons/clock.png);
+       }
+#eventDetailDate {
+       font-weight: bold;
+       float: left;
+       margin-right: 20px;
+       }
+#eventDetailHour {
+       float: left;
+       }
+#eventDetailPlace {
+       background-image: url(http://app.gaslightmedia.com/assets/icons/map.png);
+       background-position: 7px 7px;
+       }
+#eventDetailLocation {
+       font-weight: bold;
+       }
+#eventCost {
+       background-image: url(http://app.gaslightmedia.com/assets/icons/coins.png);
+       }
+#eventDetailContact {
+       background-image: url(http://app.gaslightmedia.com/assets/icons/vcard.png);
+       }
+#eventDetailContact h3 {
+       margin: 0;
+       font-size: 12px;
+       /* font-size: 1.0rem; */
+       }
+#eventDetailContact p {
+       margin: 0;
+       }
+#eventDetailAddress,
+#eventDetailCity {
+       display: block;
+       }
+#eventDetailDesc {
+       margin: 0;
+       padding: 20px;
+       border: 1px solid #ccc;
+       border-top: 0;
+       }
+#eventDetailDesc p {
+       margin-top: 0;
+       }
+/*  Event Search Result */
+.event-search {
+       font-size: 12px;
+       /* font-size: 1.2rem; */
+       background: #eee;
+       border: 1px dashed #ccc;
+       padding: 3px 6px;
+       }
+.event-list {
+       border-bottom: 1px solid #ccc;
+       height: 1%;
+       overflow: hidden;
+       padding: 6px 0;
+       }
+.event-list-date {
+       width: 130px;
+       float: left;
+       padding: 3px 6px;
+       display: block;
+       margin: 0;
+       font-size: 12px;
+       /* font-size: 1.2rem; */
+       font-weight: bold;
+       }
+.event-list h3 {
+       font-size: 12px;
+       /* font-size: 1.2rem; */
+       float: left;
+       padding: 3px;
+       width: 280px;
+       background-image: none !important;
+       margin: 0;
+       line-height: 1.5em;
+       }
+.event-list h3 a {
+       font-size: 13px;
+       /* font-size: 1.3rem; */
+       }
+.event-list-Frequency {
+       float: right;
+       text-align: right;
+       width: 80px;
+       font-size: 11px;
+       /* font-size: 1.1rem; */
+       margin: 0;
+       }
+.ulCr, .ulCr li, .ulCr ul {
+       list-style-type: none;
+       margin: 0;
+       padding: 0;
+       display: block;
+       }
+#EventSocialLinks {
+       clear: right;
+       /*width: 162px;*/
+       /*background: #0F0;*/
+       margin: 0 2% 10px 0;
+       }
+#EventSocialLinks ul {
+       display: block;
+       margin: 0;
+       padding: 0;
+       list-style-type: none;
+       }
+#EventSocialLinks ul li {
+       display: block;
+       float: right;
+       height: 28px;
+       /*width: 81px;*/
+       width: 100%;
+       margin: 8px 0 0 0;
+       padding: 0;
+       }
+#EventSocialLinks ul li a {
+       display: block;
+       text-indent: -9999px;
+       width: 100%;
+       height: 28px;
+       margin: 0;
+       border-top: 1px solid #CCC;
+       border-right: 1px solid #CCC;
+       border-left: 1px solid #AAA;
+       border-bottom: 1px solid #AAA;
+       box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       }
+#EventSocialLinks ul li a#fb {
+       float: right;
+       background: #39588F url(http://app.gaslightmedia.com/Common/EventCalendar_V0/assets/fb.jpg) center center no-repeat;
+       }
+#EventSocialLinks ul li a#tw {
+       float: right;
+       background: #FFF url(http://app.gaslightmedia.com/Common/EventCalendar_V0/assets/tw.jpg) center center no-repeat;
+       }
\ No newline at end of file
diff --git a/Toolkit/Events/views/eventDetail.html b/Toolkit/Events/views/eventDetail.html
new file mode 100755 (executable)
index 0000000..e7c94a1
--- /dev/null
@@ -0,0 +1,75 @@
+<flexy:toJavascript
+       flexy:prefix=""
+    eventTitle="event.header"
+       >
+</flexy:toJavascript>
+<div id="eventDetail">
+       <div>
+      {if:event.image}
+      <img src="{imgPathDetail:h}{event.image}">
+      {end:}
+               <h2 id="eventHeaderTitle">{event.header:h}</h2>
+               <div id="eventDetailTop">
+                       <div id="eventDetailInfo" class="medium-8 columns">
+                               <div id="eventDetailTime">
+                                       <div id="eventDetailDate">{event.dates}</div>
+                                       <div id="eventDetailHour" flexy:if="event.getEventTimes">{event.getEventTimes()} </div>
+                               </div><!-- /#eventDetailTime -->
+                               <div id="eventDetailPlace" flexy:if="event.hasLocation">
+                                       <div id="eventDetailLocation" flexy:if="event.place">{event.place}</div>
+                    {if:!event.hideAddress}
+                                       <span id="eventDetailAddress" flexy:if="event.address">{event.address}</span>
+                                       <span id="eventDetailCity" flexy:if="event.city">{event.city}, {event.state} {event.zip}</span>
+                    {end:}
+                                       <div id="event-lat" rel="{event.lat}" flexy:if="event.lat"></div>
+                                       <div id="event-lon" rel="{event.lon}" flexy:if="event.lon"></div>
+                               </div><!-- /#eventDetailPlace -->
+                               <div id="eventCost" flexy:if="event.cost">{event.cost}</div>
+                <div class="eventurl" flexy:if="event.website">
+                    <a class="external" href="{event.website}">{event.website}</a>
+                </div>
+                <div class="eventurl" flexy:if="event.file">
+                    Files: <a href="{filePathDetail:h}{event.file.filename}">
+                      {if:event.file.urltext}
+                        {event.file.urltext:h}
+                      {else:}
+                        {event.file.filename:h}
+                      {end:}
+                    </a>
+                </div>
+                               <div id="eventDetailContact" flexy:if="event.hasContactInfo">
+                                       <h3>Contact &amp; More Info</h3>
+                                       <div class="eventcontact" flexy:if="event.contactName">Contact: {event.contactName}</div>
+                                       <div class="eventemail" flexy:if="event.contactEmail">Email: <a href="mailto:{event.contact_email}">{event.contactEmail}</a></div>
+                                       <div class="eventphone" flexy:if="event.contactPhone">Phone: {event.contactPhone}</div>
+                               </div><!-- /#eventDetailContact -->
+                       </div><!-- /#eventDetailInfo -->
+            <div class="medium-4 columns">
+                <div id="eventDetailMap" flexy:if="event.hasLatLon">
+                    <div id="eventDetail-map" flexy:if="event.lat" title="Click to enlarge">map...</div>
+                    <div id="map-dialog" flexy:if="event.lat"><div id="map_canvas" style="width:500px; height:400px">Loading...</div></div>
+                </div><!-- /#eventDetailMap -->
+                <div id="EventDrivingDirectionsContainer" flexy:if="event.lat">
+                    <form id="EventDrivingDirectionsForm" name="EventDrivingDirectionsForm" flexy:ignore="yes" method="post" action="">
+                        <input type="hidden" id="EventLocation" name="EventLocation" value="{event.place:h}">
+                        <input type="hidden" id="EventLat" name="EventLat" value="{event.lat}">
+                        <input type="hidden" id="EventLon" name="EventLon" value="{event.lon}">
+                        <input type="submit" id="EventDrivingDirectionSubmit" name="EventDrivingDirectionSubmit" value="Get Directions">
+                    </form>
+                </div>
+                <div id="EventSocialLinks" flexy:if="event.hasSocialMedia">
+                  <!--<h2 >Social Media Links</h2>-->
+                  <ul>
+                    <li flexy:if="event.facebook" class="mFacebook">
+                        <a id="fb" class="external" href="{event.facebook:h}">Facebook</a>
+                    </li>
+                    <li flexy:if="event.twitter" class="mTwitter">
+                        <a id="tw" class="external" href="{event.twitter:h}">Twitter</a>
+                    </li>
+                  </ul>
+                </div>
+            </div>
+               </div><!-- /#eventDetailTop -->
+               <div id="eventDetailDesc" flexy:if="event.description">{event.description:h}</div>
+       </div>
+</div>
diff --git a/Toolkit/Events/views/eventHomePage.html b/Toolkit/Events/views/eventHomePage.html
new file mode 100755 (executable)
index 0000000..aa3fec0
--- /dev/null
@@ -0,0 +1,75 @@
+{if:hasSlideshowEvents}
+<div id="slider-wrapper" class="slider-wrapper theme-default">
+       <div class="ribbon"></div>
+       <div id="slider" class="nivoSlider">
+    {foreach:slideShow,e}
+        {if:e.href}
+        <a href="{e.href:h}">
+        {end:}
+            <img src="{eventSliderUrl:h}{e.image:h}" alt="{e.header}" title="#event-{e.id:h}">
+        {if:e.href}
+        </a>
+        {end:}
+    {end:}
+       </div>
+</div>
+<div flexy:foreach="slideShow,e" id="event-{e.id:h}" class="nivo-html-caption">
+       <strong>{e.header}</strong>
+       <span>{e.dates}</span>
+</div>
+<script type="text/javascript">
+$(window).load(function() {
+       $('#slider').nivoSlider({
+               effect: 'fade',
+               animSpeed: 1000,
+               pauseTime: 5000
+       });
+       if ($('#slider').children('a').size() <= 1 ) {
+               $('.nivo-prevNav').css('display', 'none');
+               $('.nivo-nextNav').css('display', 'none');
+       }
+});
+</script>
+{end:}
+<div id="blocks_container">
+<?php
+       $index = 0;
+       if ($this->options['strict']
+    || (is_array($t->blocks)
+    || is_object($t->blocks))) {
+               foreach($t->blocks as $category => $events) {
+                       if ($index % 2 == 0) { echo '<div class="eventrow">'; } ?>
+                       <div class="event-category-block<?php
+                 if ($index % 2 != 0) {
+                     echo ' event-category-2';
+                 } echo ' topic' . $events['id']; ?>">
+                               <h2><a href="<?php echo $t->topicSearchUrl.$events['id'];?>">
+                  <?php echo $category;?></a>
+                </h2>
+                               <?php
+              if ($this->options['strict']
+              || (is_array($events['data'])
+              || is_object($events['data']))) {
+                foreach($events['data'] as $event) {
+                ?>
+                                       <div>
+                                       <b><?php echo $event->getDates();?></b>
+                    <a href="<?php echo $event->getHref();?>">
+                    <?php echo $event->getHeader();?></a>
+                                       </div>
+                               <?php }
+                }?>
+                <a href="<?php echo $t->topicSearchUrl.$events['id'];?>"
+                   class="event-more">All <?php echo $category;?></a>
+                       </div>
+               <?php
+        if ($index % 2 != 0) {
+            echo '</div><!-- /.eventrow -->';
+        } ?>
+                       <?php
+            if ($index == count($t->blocks)-1 && ($index + 1) % 2 != 0) {
+                echo '</div><!-- /.eventrow -->';
+            } ?>
+               <?php $index++; }?>
+       <?php }?>
+</div>
\ No newline at end of file
diff --git a/Toolkit/Events/views/eventList.html b/Toolkit/Events/views/eventList.html
new file mode 100755 (executable)
index 0000000..7d3fc10
--- /dev/null
@@ -0,0 +1,152 @@
+<style type="text/css">
+<!--
+/* Steve's Styles */
+#category, .listing {display: none;}
+.event-list-thumb {float:left;}
+/* Leif's Styles */
+.event-date-hdr {
+    width: 98%;
+    padding: 5px 2% 5px 0;
+    margin: 0;
+}
+#toolbox .event-date-hdr p {
+    display: block;
+    padding: 0;
+    margin: 1em 0 0 0;
+    font-size: 22px;
+    /* font-sizw: 1.9rem; */
+    font-weight: bold;
+    font-family: Constantia, "Lucida Bright", Lucidabright, "Lucida Serif", Lucida, "DejaVu Serif", "Bitstream Vera Serif", "Liberation Serif", Georgia, serif;
+    color: #477645;
+    }
+.event-category-hdr {
+    width: 98%;
+    padding: 5px 2% 5px 0;
+    margin: 0;
+    color: #E4E4E4;
+    text-align: left;
+    border-bottom: 1px solid #E4E4E4;
+}
+.event-category-hdr h3 {
+    display: block;
+    padding: 0;
+    margin: 0;
+    font-weight: bold;
+    color: #666;
+    font-size: 14px;
+    }
+.event-cat {
+    margin: 10px 0 10px 0;
+    overflow: hidden;
+}
+.event-list {
+    margin: 0;
+    padding: 14px 0;
+    border-bottom: 1px solid #E4E4E4;
+}
+.event-list-Intro {
+    display: block;
+    padding: 28px 0 0 0;
+       clear: left;
+}
+.event-list h3 {
+    display: block;
+    float: left;
+    margin: 0;
+    padding: 0;
+    width: 70%;
+}
+.event-list h3 a {
+    display: block;
+    font-size: 16px;
+    /* font-size: 1.6rem; */
+    font-weight: bold;
+    color: black;
+    }
+.event-list h3 a:hover {
+}
+.event-list-thumb  {
+    display: block;
+    float: left;
+    border: 1px solid rgb(51,102,153);
+    border-radius: 8px;
+    margin: 8px 4% 8px 0;
+    width: 26%;
+}
+.event-right {
+    float: right;
+    width: 30%;
+    min-height: 54px;
+}
+.event-list-Times {
+    display: block;
+    float: right;
+    clear: right;
+    color: #00456C;
+    width: 100%;
+    text-align: right;
+    margin: 0;
+    padding: 0 0 2px 0;
+    min-height: 20px;
+}
+.event-list-Frequency {
+    display: block;
+    float: right;
+    clear: right;
+    color: #00456C;
+    width: 100%;
+    text-align: right;
+    padding: 0 0 6px 0;
+}
+-->
+</style>
+<div id="eventsList">
+{if:search}
+<flexy:toJavascript
+    flexy:prefix=""
+    eventTitle="search"
+    >
+</flexy:toJavascript>
+{end:}
+<p class="event-search" flexy:if="search">
+    {front.searchFor.showing} {search}
+    {if:events}
+    <a href="{searchUrl:h}&print=1" flexy:if="printable">{front.searchFor.pdfLink}</a>
+    {end:}
+</p>
+{if:events}
+  {foreach:events,dateTime,date}
+  <div class="event-date-hdr"><p>{dateTime}</p></div>
+    {foreach:date,categoryName,category}
+      <div class="event-cat">
+
+        <div class="event-category-hdr"><h3>{categoryName}</h3></div>
+        {foreach:category,event}
+          {if:event.spans}<div class="event-list ongoing">{end:}
+          {if:event.recurr}<div class="event-list reacur">{end:}
+          {if:event.normal}<div class="event-list">{end:}
+          <h3>
+            <a href="{event.href}">{event.header}</a>
+          </h3>
+          <div class="event-right">
+          <span class="event-list-Times">{event.getEventTimes()}</span>
+          {if:event.spans}<span class="event-list-Frequency">Ongoing Event</span>{end:}
+          {if:event.recurr}<span class="event-list-Frequency">Repeating Event</span>{end:}
+          </div><!-- /.event-right -->
+          {if:event.image}
+            <a href="{event.href}"><img class="event-list-thumb"
+                src="{imgBaseUrl:h}eventListThumb/{event.image}"
+                width="100"></a>
+          {end:}
+          <div class="event-list-Intro">
+              {event.intro:h}
+          </div>
+        </div><!-- /.event-list -->
+      {end:}
+    </div><!-- /.event-cat -->
+    {end:}
+  {end:}
+{else:}
+    <p>No events were found for your search. </p>
+{end:}
+</div><!-- /#eventsList -->
diff --git a/Toolkit/Events/views/eventSearchForm.html b/Toolkit/Events/views/eventSearchForm.html
new file mode 100755 (executable)
index 0000000..466c47d
--- /dev/null
@@ -0,0 +1,122 @@
+<div id="event-search">
+    <h3>{front.search.title}</h3>
+    {if:options.hasNameSearch}
+    <div id="eventNameSearchWrapper">
+        <form class="eventSearrchForm" name="event-search-form" action="{eventPageUrl:h}">
+            <input type="hidden" name="catid" value="{_REQUEST[catid]}">
+            <input type="hidden" name="search" value="1">
+            <span>{front.search.eventName}</span>
+            <input
+                type="search"
+                id="eventNameSearch"
+                name="eventName"
+                placeholder="Search for events"
+                value="{_REQUEST[eventName]}">
+            <div id="submitNameWrapper">
+                <input
+                    type="image"
+                    src="<?php echo MEDIA_BASE_URL;?>assets/go.png">
+            </div>
+        </form>
+    </div>
+    {end:}
+    <form class="eventSearrchForm" name="event-search-form" action="{eventPageUrl:h}">
+        <input type="hidden" name="catid" value="{_REQUEST[catid]}">
+        <input type="hidden" name="search" value="1">
+        <span>{front.search.from}</span>
+        <div id="startMonthWrapper">
+          <input
+              name="startMonth"
+              id="startMonth"
+              size="10"
+              value="{_REQUEST[startMonth]}">
+        </div>
+        <span>{front.search.to}</span>
+        <div id="endMonthWrapper">
+          <input
+              name="endMonth"
+              id="endMonth"
+              size="10"
+              value="{_REQUEST[endMonth]}">
+        </div>
+        <span>{front.search.type}</span>
+        <select name="category" id="eventCategorySearch">
+          <option value="">-Select-</option>
+        <?php
+        if (!empty($t->categories)) {
+            foreach ($t->categories as $category) {
+                echo '<option value="'
+                    . $category->id . '"'
+                    . (($category->id == $_REQUEST['category'])
+                        ?' selected'
+                        :'')
+                    . '>'.$category->name.'</option>';
+            }
+        }
+        ?>
+        </select>
+        {if:hasRegions}
+            <span>{front.search.region}</span>
+            <select name="region" id="eventRegionSearch">
+              <option value="">-Select-</option>
+            <?php
+            if (!empty($t->regions)) {
+                foreach ($t->regions as $region) {
+                    echo '<option value="'
+                        . $region['id'] . '"'
+                        . (($region['id'] == $_REQUEST['region'])
+                            ?' selected'
+                            :'')
+                        . '>'.$region['name'].'</option>';
+                }
+            }
+            ?>
+            </select>
+        {end:}
+        <div id="submitWrapper">
+          <input
+            type="image"
+            src="<?php echo MEDIA_BASE_URL;?>assets/go.png">
+        </div>
+    </form>
+</div>
+{if:options.hasNameSearch}
+<script>
+    $(function() {
+        var cache = {};
+        $("#eventNameSearch").autocomplete({
+            minLength: 2,
+            source: function(request, response) {
+                var term = request.term;
+                if (term in cache) {
+                    response(cache[ term ]);
+                    return;
+                }
+                var startDate = $('#startMonth').val();
+                var endDate = $('#endMonth').val();
+                var category = $('#eventCategorySearch').val();
+                var region = $('#eventRegionSearch').val();
+                var url = '<?php echo BASE_URL?>index.php?catid=<?php echo $t->eventPageId;?>';
+                url += '&ac=eventSearch';
+                if (startDate) {
+                    url += '&startMonth=' + startDate;
+                }
+                if (endDate) {
+                    url += '&endMonth=' + endDate;
+                }
+                if (category) {
+                    url += '&category=' + category;
+                }
+                if (region) {
+                    url += '&region=' + region;
+                }
+
+                $.getJSON(url, request, function(data, status, xhr) {
+                    //cache[ term ] = data;
+                    response(data);
+                });
+            }
+        });
+    });
+</script>
+{end:}
diff --git a/Toolkit/Events/views/mainEventWrapper.html b/Toolkit/Events/views/mainEventWrapper.html
new file mode 100755 (executable)
index 0000000..b43bfbc
--- /dev/null
@@ -0,0 +1,62 @@
+{if:styleSheets}
+  {foreach:styleSheets,style}
+    <link rel="stylesheet" type="text/css" href="{style}">
+  {end:}
+{end:}
+{if:topScripts}
+  {foreach:topScripts,script}
+    <script type="text/javascript" src="{script}"></script>
+  {end:}
+{end:}
+<flexy:toJavascript
+    flexy:prefix=""
+    eventPageUrl="eventPageUrl"
+    search="searchOn"
+    >
+</flexy:toJavascript>
+<div class="container full">
+    <div class="row inner">
+        <div id="event-main-column" class="small-12 medium-8 large-9 columns">
+          {if:eventHomePage}<flexy:include src="eventHomePage.html">{end:}
+          {if:eventListResults}<flexy:include src="eventList.html">{end:}
+          {if:eventDetailPage}<flexy:include src="eventDetail.html">{end:}
+        </div>
+        <div id="event-second-column" class="small-12 medium-4 large-3 columns">
+            <flexy:include src="eventSearchForm.html">
+            <div id="event-shortcuts">
+              <h3>{front.shortCuts.title}</h3>
+              <ul class="ulCr">
+                <li flexy:if="hasMajorEvents">
+                  <a href="{majorEventsUrl:h}">{front.shortCuts.major}</a>
+                </li>
+                <li>
+                  <a href="{todayUrl:h}">{front.shortCuts.today}</a>
+                </li>
+                <li>
+                  <a href="{tomorrowUrl:h}">{front.shortCuts.tomorrow}</a>
+                </li>
+                <li flexy:foreach="dayRanges,days,dayRange">
+                  <a href="{nextUrl:h}{days}">{dayRange}</a>
+                </li>
+              </ul>
+            </div><!-- /#event-shortcuts -->
+            <div id="event-featured" flexy:if="hasFeaturedEvents">
+              <h3>{front.featured.title}</h3>
+              <div
+                flexy:foreach="featured,event"
+                style="background-image: url({eventFeaturedUrl:h}{event.image:h})">
+                <p>{event.dates}</p>
+                <a href="{event.href:h}">{event.header}</a>
+              </div>
+            </div><!-- /#event-featured -->
+        </div><!-- /#event-second-column -->
+    </div><!-- /.row -->
+</div><!-- /.container -->
+{if:bottomScripts}
+  {foreach:bottomScripts,script}
+    <script type="text/javascript" src="{script}"></script>
+  {end:}
+{end:}
+{startScriptTag:h}
+<flexy:include src="js/events.js">
+</script>
index 11e8e02..73c918b 100755 (executable)
@@ -456,7 +456,8 @@ class Toolkit_Page
         $this->mainNav = $this->_getMainNav($this->_catid);
         $this->sideNav = $this->_getSideNav($this->_catid);
         // main Navigation output
-        $this->mainNavigationUl = $this->_getMainNavigation();
+        $this->mainNavigationUl   = $this->_getMainNavigation();
+        $this->mobileNavigationUl = $this->_getMobileNavigation();
 
         $this->newsletterAction = Toolkit_Template_Page::getSeoUrl(
             $this->_pageGateway, 10
@@ -598,7 +599,36 @@ class Toolkit_Page
         return ($html) ? $html : '';
     }
 
-    private function _arrayToListHTML($array, $level = 0, $className = null)
+    private function _getMobileNavigation()
+    {
+        if (defined('MAIN_LEVEL_NAV_ARRAY') && MAIN_LEVEL_NAV_ARRAY) {
+            $mainNavArray = unserialize(MAIN_LEVEL_NAV_ARRAY);
+        }
+        $sideNav = new Toolkit_Template_Navigation_AllInOneSideNav(
+            $this->_pageGateway
+        );
+        $nav  = $sideNav->getNavigation();
+        $newNav = array();
+        foreach ($nav as $key => $item) {
+            if ($item['id'] == HOME_ID) {
+                $item['class'] = 'home';
+            }
+            if (in_array($item['id'], $mainNavArray)
+                || $item['id'] == HOME_ID
+            ) {
+                $key = array_search($item['id'], $mainNavArray);
+                if ($key !== false) {
+                    $item['class'] = $key;
+                }
+                $newNav[] = $item;
+            }
+        }
+//        echo '<pre>'.print_r($newNav, true).'</pre>';exit;
+        $html = $this->_arrayToListHTML($newNav, 0, 'off-canvas-list', true);
+        return ($html) ? $html : '';
+    }
+
+    private function _arrayToListHTML($array, $level = 0, $className = null, $mobile = false)
     {
         static $tab = "\t", $format = '<a href="%s"%s>%s</a>';
 
@@ -606,37 +636,49 @@ class Toolkit_Page
             return;
         }
         $tabs = str_repeat($tab, $level * 2);
-        $mainClass = ($level == 0 && $className)
-            ? ' class="'.$className.'"'
-            : ' class="dropdown"';
+        if ($mobile) {
+            $mainClass = ' class="'.$className.'"';
+        } else {
+            $mainClass = ($level == 0 && $className)
+                ? ' class="'.$className.'"'
+                : ' class="dropdown"';
+        }
+
         $result = "{$tabs}<ul{$mainClass}>\n";
         foreach ($array as $i => $node) {
             $classes = array();
-//            $class
-//                = ($node['class'] == 'current')
-//                ? ' class="'.$node['class'].'"'
-//                : '';
-            if ($node['class']) {
-                $classes[] = $node['class'];
+            if ($mobile && $node['class']) {
+                $class = ' class="'.$node['class'].'"';
+            } else {
+                if ($node['class']) {
+                    $classes[] = $node['class'];
+                }
             }
+
+
             if (!empty($node['pages'])) {
                 $classes[] = 'has-dropdown';
             }
             $parent = ' class="'.implode(' ', $classes).'"';
-//            $parent
-//                = ($node['class'] == 'parent')
-//                ? ' class="'.$node['class'].'"'
-//                : ' class="not-click"';
             $link = sprintf(
                 $format,
                 $node['uri'],
                 $class,
                 $node['label']
             );
-            $result .= "{$tabs}{$tab}<li{$parent}>\n{$tabs}{$tab}{$tab}"
-                . "{$link}\n"
-                . $this->_arrayToListHTML($node['pages'], $level + 1)
-                . "{$tabs}{$tab}</li>\n";
+            $result .= "{$tabs}{$tab}<li{$parent}>\n{$tabs}{$tab}{$tab}{$link}\n";
+            if ($mobile) {
+                if (!empty($node['pages'])) {
+                    $result .= '<a class="toggle"></a>';
+                }
+
+                $result .=  $this->_arrayToListHTML($node['pages'], $level + 1, '', true);
+            } else {
+                $result .=  $this->_arrayToListHTML($node['pages'], $level + 1);
+            }
+
+
+            $result .= "{$tabs}{$tab}</li>\n";
         }
         $result .= "{$tabs}</ul>\n";
         return $result;
index 3a2a20e..fc37b45 100644 (file)
@@ -131,10 +131,13 @@ class Toolkit_Template_BreadCrumbs
        public function toHtml($id)
        {
                $breadCrumbsArray = $this->getBreadCrumbsArray($id);
-               $breadCrumbs      = implode(' > ', $breadCrumbsArray);
+//        echo '<pre>'.print_r($breadCrumbsArray, true).'</pre>';
+//        exit;
+               $breadCrumbs = '<li>'.implode(' </li><li> ', $breadCrumbsArray).'</li>';
 
                return !empty($breadCrumbsArray)
-                       ? '<div id="breadcrumbs" class="opensearchserver.ignore">' . $breadCrumbs . '</div>'
+                       ? '<ul class="breadcrumbs opensearchserver.ignore">'
+                . $breadCrumbs . '</ul>'
                        : '';
        }
 
index 10a9cc1..6d89cbd 100644 (file)
@@ -42,7 +42,7 @@ class Toolkit_Toolbox_Forms_EditPage
      * @var    integer
      * @access protected
      */
-    protected $maxDepth = 0;
+    protected $maxDepth = 2;
 
     /**
      * Don't need to register any rules for this form.
diff --git a/assets/go.png b/assets/go.png
new file mode 100755 (executable)
index 0000000..2b307a9
Binary files /dev/null and b/assets/go.png differ
diff --git a/assets/navBg.png b/assets/navBg.png
new file mode 100755 (executable)
index 0000000..51e3030
Binary files /dev/null and b/assets/navBg.png differ
diff --git a/robots.txt b/robots.txt
new file mode 100644 (file)
index 0000000..084cd33
--- /dev/null
@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /admin/
index 8f2e941..ca8ced5 100644 (file)
               </ul>
               <section class="top-bar-section">
                   {mainNavigationUl:h}
-<!--                <ul class="left">
-                  <li class="not-click activities">
-                    <a href="/activities">Activities</a>
-                  </li>
-                  <li class="not-click attractions">
-                    <a href="/attractions">Attractions</a>
-                  </li>
-                  <li class="has-dropdown not-click lodging">
-                    <a href="/lodging">Lodging</a>
-                    <ul class="dropdown">
-                      <li><a href="#">Bed &amp; Breakfasts</a></li>
-                      <li><a href="#">Cabins/Cottages</a></li>
-                      <li><a href="#" id="active">Campgrounds</a></li>
-                      <li><a href="#">Hotels/Motels</a></li>
-                      <li><a href="#">Vacation Homes</a></li>
-                    </ul>
-                  </li>
-                  <li class="not-click restaurants">
-                    <a href="/restaurants">Restaurants</a>
-                  </li>
-                  <li class="not-click shopping">
-                    <a href="/shopping">Shopping</a>
-                  </li>
-                  <li class="not-click calendar">
-                    <a href="/calendar">Calendar</a>
-                  </li>
-                </ul>-->
               </section>
             </nav>
             <!-- Off-canvas menu -->
             <aside class="right-off-canvas-menu">
-              <ul class="off-canvas-list">
+                {mobileNavigationUl:h}
+<!--              <ul class="off-canvas-list">
                 <li>
                   <a class="home" href="/">Home</a>
                 </li>
                 <li>
                   <a class="calendar" href="/calendar">Calendar</a>
                 </li>
-              </ul>
+              </ul>-->
             </aside>
             <!-- /Nav Menus -->