Creating section for the Golf Courses
authorSteve Sutton <steve@gaslightmedia.com>
Wed, 25 Feb 2015 13:38:34 +0000 (08:38 -0500)
committerSteve Sutton <steve@gaslightmedia.com>
Wed, 25 Feb 2015 13:38:34 +0000 (08:38 -0500)
This is based on the Member Packages and uses the same type of approach
file wise as the member packages did.
I used the member_golf table and added the new fields from the packages
into it.

23 files changed:
Toolkit/Members.php
Toolkit/Members/Admin/EditCourses.php [new file with mode: 0644]
Toolkit/Members/Courses.php [new file with mode: 0644]
Toolkit/Members/Database/tables/member_golf.sql
Toolkit/Members/EditCourses.php [new file with mode: 0644]
Toolkit/Members/EditMemberCourseProfile.php [new file with mode: 0644]
Toolkit/Members/EditMemberInfo.php
Toolkit/Members/EditMemberOnlyInfo.php
Toolkit/Members/RecordNavigation.php
Toolkit/Members/config.ini
Toolkit/Members/css/member-admin.css
Toolkit/Members/libjs/edit-member-course.js [new file with mode: 0755]
Toolkit/Members/templates/addCourse.tpl [new file with mode: 0644]
Toolkit/Members/templates/addYourBusinessAdminEmail.tpl [changed mode: 0755->0644]
Toolkit/Members/templates/editCouponEmail.tpl [changed mode: 0755->0644]
Toolkit/Members/templates/editCourse.tpl [new file with mode: 0644]
Toolkit/Members/templates/editCourseProfile.tpl [new file with mode: 0644]
Toolkit/Members/templates/editCourses.tpl [new file with mode: 0644]
Toolkit/Members/templates/exposureDetail.tpl [changed mode: 0755->0644]
Toolkit/Members/templates/exposureList.tpl [changed mode: 0755->0644]
Toolkit/Members/templates/memberNewsletter.tpl [changed mode: 0755->0644]
Toolkit/Members/templates/newMemberApproval.tpl [changed mode: 0755->0644]
Toolkit/Members/templates/newMemberDenial.tpl [changed mode: 0755->0644]

index 066ef01..ea5bdb3 100644 (file)
@@ -247,6 +247,17 @@ class Toolkit_Members
             $out = $mp->getPage($nav);
             break;
 
+        case 'courses' :
+            $GLOBALS['bottomScripts'][]
+                = CKEDITOR_JS . '';
+            $GLOBALS['bottomScripts'][]
+                = MEDIA_BASE_URL . 'Toolkit/Members/libjs/edit-member-course.js';
+
+            $mp = new Toolkit_Members_Admin_EditCourses($pdo, $tEngine);
+            $mp->setupPage();
+            $out = $mp->getPage($nav);
+            break;
+
         case 'photos' :
             $GLOBALS['bottomScripts'][]
                 = MEDIA_APP_BASE_URL . 'libjs/jqueryui/1.8.13/js/jquery-ui-1.8.13.custom.min.js';
diff --git a/Toolkit/Members/Admin/EditCourses.php b/Toolkit/Members/Admin/EditCourses.php
new file mode 100644 (file)
index 0000000..c5e1eff
--- /dev/null
@@ -0,0 +1,1606 @@
+<?php
+//    vim:set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker syntax=php:
+
+/**
+ * Handles the courses tab in the member record
+ *
+ * Controls setting up the add course form if applicable, and rendering
+ * each uploaded course edit form to edit/delete the course.
+ *
+ * PHP version 5
+ *
+ * @category  Toolkit
+ * @package   Members_Admin
+ * @author    Jamie Kahgee <steve@gaslightmedia.com>
+ * @copyright 2009 Jamie Kahgee
+ * @license   http://www.gaslightmedia.com Gaslightmedia
+ * @version   CVS: $Id: EditCourses.php,v 1.20 2010/07/16 20:53:24 jamie Exp $
+ * @link      http://demo.gaslightmedia.com
+ * @see       Toolkit/Image/Server.php
+ */
+
+
+/**
+ * The image server processing class
+ */
+require_once BASE . 'Toolkit/Image/Server.php';
+
+/**
+ * Constructor class to setup the page layout
+ *
+ * this class determines if the user can upload any more courses to their
+ * account and if so renders the add course form.  It also controls
+ * rending the individual forms for each previously uploaded course.
+ *
+ * @category  Toolkit
+ * @package   Members_Admin
+ * @author    Jamie Kahgee <steve@gaslightmedia.com>
+ * @copyright 2009 Jamie Kahgee
+ * @license   http://www.gaslightmedia.com Gaslightmedia
+ * @link      http://demo.gaslightmedia.com
+ */
+class Toolkit_Members_Admin_EditCourses
+{
+    //    {{{ properties
+
+    /**
+     * The table name in the database used to store the data
+     * @var string
+     * @access public
+     */
+    public $tableName = 'member_golf';
+
+    /**
+     * Template used to layout form when editing a course
+     * @var    string
+     * @access protected
+     */
+    protected $pageTemplate = 'editCourses.tpl';
+
+    /**
+     * What is the maximum caption length for courses
+     *
+     * @var    array
+     * @access public
+     * @static
+     */
+    static public $maxTitleLength = 60;
+
+    /**
+     * Objects that will go into the page (add form, edit course forms)
+     * @var    object
+     * @access protected
+     */
+    protected $page;
+
+    /**
+     * Description for protected
+     * @var    PDO
+     * @access protected
+     */
+    protected $dbh;
+
+    //    }}}
+
+    //  {{{ __construct()
+
+    /**
+     * Constructor
+     *
+     * @param PDO                 $pdo     PHP Data Object to use for DB calls
+     * @param HTML_Template_Flexy $tEngine Templating Engine
+     *
+     * @return void
+     * @access public
+     */
+    public function __construct(PDO $pdo, HTML_Template_Flexy $tEngine)
+    {
+        $this->dbh = $pdo;
+        $this->tEngine = $tEngine;
+    }
+
+    //  }}}
+
+    //    {{{    canAddCourses()
+
+    /**
+     * Determine if this member can have more courses added to their profile
+     *
+     * Load the entire course gallery into member via a linked list.
+     * Then return if the # of linked list nodes is smaller than
+     * the maximum limit of courses.
+     *
+     * @access protected
+     * @return boolean If the linked list is smaller than max courses allowed
+     */
+    protected function canAddCourses()
+    {
+        $membersConf = new Config;
+        $membersRoot =& $membersConf->parseConfig(
+            BASE . 'Toolkit/Members/config.ini',
+            'IniFile'
+        );
+        $memberCourseLimit = $membersRoot->getItem('section', 'conf')
+            ->getItem('directive', 'memberCourseLimit')
+            ->getContent();
+        if (   !$memberCourseLimit
+            || !filter_var($memberCourseLimit, FILTER_VALIDATE_INT)
+        ) {
+            return true;
+        }
+        $ll = new Toolkit_Members_Courses(null, $_GET['id']);
+        $ll->setDbh($this->dbh);
+        $ll->createMemberList();
+        return ($ll->getListSize() < $memberCourseLimit);
+    }
+
+    //    }}}
+
+    //    {{{    displayPage()
+
+    /**
+     * Displays the page to the screen
+     *
+     * @param Toolkit_Members_RecordNavigation $nav Record subnav object
+     *
+     * @return void
+     * @access public
+     */
+    public function displayPage(Toolkit_Members_RecordNavigation $nav)
+    {
+        echo $this->getPage($nav);
+    }
+
+    //    }}}
+
+    //    {{{    getPage()
+
+    /**
+     * Sets up the flexy template and returns the rendered page
+     *
+     * @param Toolkit_Members_RecordNavigation $nav record subnav object
+     *
+     * @return object rendered page
+     * @access public
+     */
+    public function getPage(Toolkit_Members_RecordNavigation $nav)
+    {
+        $this->page->nav = $nav->getPageNav();
+        $this->tEngine->compile($this->pageTemplate);
+        return $this->tEngine->bufferedOutputObject($this->page);
+    }
+
+    //    }}}
+
+    //    {{{    getUploadedCourses()
+
+    /**
+     * Get an array of course ids from the DB that have been uploaded for this member
+     *
+     * - Create a linked list of all the members courses
+     * - Walk through the linked list extracting the id from each node into an array
+     *
+     * @access protected
+     * @return array Ids of all uploaded courses for this member
+     */
+    protected function getUploadedCourses()
+    {
+        $courses = new Toolkit_Members_Courses(null, $_GET['id']);
+        $courses->setDbh($this->dbh);
+        $courses->createMemberList();
+        $courses->rewind();
+
+        $ids = array();
+        foreach ($courses as $i) {
+            //    Don't show the pending courses here.
+            if (!$i->getPending()) {
+                $ids[] = $i->getId();
+            }
+        }
+
+        return $ids;
+    }
+
+    //    }}}
+
+    //    {{{    setUpPage()
+
+    /**
+     * Sets up the page to manipulate courses for a member
+     *
+     * Checks if all the courses uploaded for a member (pending & non-pending)
+     * exceed or match the maximum # of courses allowed for each member to
+     * upload to their account.
+     *
+     * For every course that is already uploaded, create an edit-course form that
+     * will allow the user to update the caption or delete the course.
+     *
+     * @return void
+     * @access public
+     */
+    public function setUpPage()
+    {
+        $this->page = new StdClass;
+
+        //    Find out if we can still add courses to the record.
+        //    If we can, then add the upload form to the page for the member to see.
+        if ($this->canAddCourses()) {
+            $addForm = new AddAdminCourse(
+                $this->dbh,
+                'new_member_course',
+                'post',
+                '',
+                '',
+                null,
+                true
+            );
+
+            $addForm->configureForm();
+            $this->page->uploadForm = $addForm->toHtml($this->tEngine);
+        }
+
+        //    Find out if we have any courses already uploaded.
+        //    If we do, then add the edit course form to the page for each course
+        //    so the member can edit/delete their courses.
+        if ($courses = $this->getUploadedCourses()) {
+            $this->page->editForm = array();
+            while (list($i, $j) = each($courses)) {
+                $editForm = new EditAdminCourse(
+                    $this->dbh,
+                    "edit_member_course_$j",
+                    'post',
+                    '',
+                    '',
+                    array('id' => $j),
+                    true
+                );
+
+                $editForm->configureForm();
+                $this->page->editForm[] = $editForm->toHtml($this->tEngine);
+            }
+        }
+    }
+
+    //    }}}
+}
+
+/**
+ * Form to handle creating a new course in the members only area
+ *
+ * Handles inserting new course into db as a pending course and creating a
+ * tuple in the member_updates table which will allow the admin to
+ * approve/deny the new course request.
+ *
+ * @category  MembersDB
+ * @package   Toolkit_Members
+ * @author    Jamie Kahgee <jamie.kahgee@gmail.com>
+ * @copyright 2009 Jamie Kahgee
+ * @license   http://www.gaslightmedia.com Gaslightmedia
+ * @link      http://demo.gaslightmedia.com
+ */
+class AddAdminCourse extends Toolkit_FormBuilder
+{
+    //    {{{ properties
+
+    /**
+     * The table name in the database used to store the data
+     *
+     * @var string
+     * @access public
+     */
+    public $tableName = 'member_golf';
+
+    /**
+     * Some special forms dont utlize this stylesheet
+     * Allow classes to override this setting so it doesn't
+     * get included
+     *
+     * @var boolean
+     * @access protected
+     */
+    protected $includeContactStyleSheet = false;
+
+    /**
+     * The template used to render the form
+     *
+     * @var string
+     * @access protected
+     */
+    protected $formTemplate = 'addCourse.tpl';
+
+    /**
+     * Description for protected
+     * @var    array
+     * @access protected
+     */
+    protected $registeredRules = array();
+
+    /**
+     * Description for protected
+     * @var    string
+     * @access protected
+     */
+    protected $successMsg
+        = '<div id="form-success-top">
+            You successfully uploaded your course.
+           </div>';
+
+    /**
+     * Description for protected
+     * @var    array
+     * @access protected
+     */
+    protected $mimeTypes = array(
+        'image/jpe',
+        'image/jpeg',
+        'image/jpg',
+        'image/jfif',
+        'image/pjpeg',
+        'image/pjp',
+        'image/gif',
+        'image/png',
+    );
+
+    //    }}}
+    //    {{{ __construct()
+
+    /**
+     * Class constructor
+     *
+     * @param PDO    $pdo         PHP Data Object to use for DB calls
+     * @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
+     * @see    Toolkit_Members_Admin_EditCourses
+     */
+    public function __construct(
+        PDO $pdo,
+        $formName,
+        $method = 'post',
+        $action = '',
+        $target = '',
+        $attributes = null,
+        $trackSubmit = false
+    ) {
+        parent::__construct(
+            $formName,
+            $method,
+            $action,
+            $target,
+            $attributes,
+            $trackSubmit
+        );
+        $this->dbh = $pdo;
+    }
+
+    //    }}}
+
+    //  {{{ configureForm()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @return void
+     * @access public
+     */
+    public function configureForm()
+    {
+        $this->configureElements();
+        $this->configureFilters();
+        $this->configureRules();
+    }
+
+    //  }}}
+    //    {{{ configureElements()
+
+    /**
+     * Setup the elements to use on the form.
+     *
+     * @return void
+     * @access public
+     */
+    public function configureElements()
+    {
+        $e = array();
+        //    All Grouped Elements are created here.
+
+        //    All Elements are created here.  This includes group element definitions.
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'title',
+            'display' => 'Course Title',
+        );
+        $e[] = array(
+            'type'        => 'textarea',
+            'req'         => false,
+            'name'        => 'description',
+            'display'     => 'Course Description',
+            'opts'        => array('id' => 'descrAdd', 'class' => 'ckeditor'),
+            'noCharLimit' => true
+        );
+
+        $e[] = array(
+            'type'    => 'checkbox',
+            'req'     => false,
+            'name'    => 'remove_img_rmv',
+            'display' => 'Remove Image',
+        );
+        $e[] = array(
+            'type'    => 'static',
+            'req'     => false,
+            'name'    => 'curr_image',
+            'display' => 'Current Image',
+        );
+        $e[] = array(
+            'type'    => 'hidden',
+            'req'     => false,
+            'name'    => 'curr_image_rmv',
+        );
+        $e[] = array(
+            'type'    => 'file',
+            'req'     => false,
+            'name'    => 'image',
+            'display' => 'Upload a Course Photo / Image',
+        );
+        $e[] = array(
+            'type' => 'header',
+            'req' => false,
+            'name' => 'GolfingHdr',
+            'display' => 'Golf Course Information',
+            //'col2' => true
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'res_url',
+            'display' => 'TeeTime URL',
+            'opts'    => array('class' => 'text'),
+            'noCharLimit' => true
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'par',
+            'display' => 'Par',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'yardage',
+            'display' => 'Yardage',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'course_rating',
+            'display' => 'Course Rating',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'slope_rating',
+            'display' => 'Slope Rating',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'advcheckbox',
+            'req'     => false,
+            'name'    => 'walking_course',
+            'display' => 'Walking Course',
+            'val'     => array(0, 1)
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'holes18',
+            'display' => '18 Holes',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'holes9',
+            'display' => '9 Holes',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'submit',
+            'req'     => false,
+            'name'    => 'add_rmv',
+            'display' => 'Upload new course',
+            'opts'    => array('class' => 'submit')
+        );
+
+        $this->setupElements($e);
+    }
+
+    //    }}}
+    //    {{{ configureRules()
+
+    /**
+     * Configure rules for form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureRules()
+    {
+        $r = array();
+
+        $checkDate = create_function('$d', '$d = implode("-", $d); return Validate::date($d, array("format" => "%n-%j-%Y"));');
+        $r[] = array(
+            'element'    => 'image',
+            'message'    => 'ERROR: Incorrect File Type (.gif, .png, .jpg) only!',
+            'type'       => 'mimetype',
+            'format'     => $this->mimeTypes,
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+
+        $this->setupRules($r);
+    }
+
+    //    }}}
+    //    {{{ configureConstants()
+
+    /**
+     * Configure constants for form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureConstants()
+    {
+        $c = array(
+            'remove_img_rmv' => false
+        );
+
+        $this->setupConstants($c);
+    }
+
+    //    }}}
+    //    {{{ configureFilters()
+
+    /**
+     * Configure filters for form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureFilters()
+    {
+        $f = array();
+
+        $f[] = array(
+            'element' => '__ALL__',
+            'filter' => 'trim'
+        );
+
+        $this->setupFilters($f);
+    }
+
+    //    }}}
+
+    //  {{{ deleteImage()
+
+    /**
+     * Remove an image record
+     *
+     * @param Toolkit_Image_Server $is  Image Server Object
+     * @param string               $img image name
+     *
+     * @return object    Return description (if any) ...
+     * @access protected
+     */
+    protected function deleteImage(Toolkit_Image_Server $is, $img)
+    {
+        return $is->imageDelete($img);
+    }
+
+    //  }}}
+
+    //    {{{ insertData()
+
+    /**
+     * Create a new course in the db
+     *
+     * @param array &$values Form submitted values
+     *
+     * @return object    db result of adding course
+     * @access protected
+     */
+    protected function insertData(&$values)
+    {
+        try {
+            $sql = Toolkit_Common::createSQLInsert(
+                $this->tableName,
+                array_keys($values)
+            );
+
+            return Toolkit_Common::processQuery(
+                $this->dbh,
+                $this->tableName,
+                $sql,
+                $values
+            );
+        } catch (PDOException $e) {
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+     //    }}}
+
+    //    {{{ processData()
+
+    /**
+     * Handles setting up the from processing and which function to get it done
+     *
+     * @param array $values Submitted values from the form.
+     *
+     * @return void
+     * @access protected
+     */
+    protected function processData($values)
+    {
+        $cache = new Cache_Lite(Toolkit_Members::getCacheOptions());
+        $cache->remove("Member-{$_GET['id']}", 'Profile');
+
+        $e =& $this->getElement('curr_image_rmv');
+
+        //echo '<pre>'.print_r($values, true).'</pre>';
+
+        $courses = new Toolkit_Members_Courses(null, $_GET['id']);
+        $courses->setDbh($this->dbh);
+        $courses->createMemberList();
+
+
+        $values['pos']       = $courses->getListSize() + 1;
+        $values['image'] = $e->getValue('curr_image_rmv');
+        $values['member_id'] = $_GET['id'];
+        $values['pending']   = 0;
+        unset($values['MAX_FILE_SIZE'],
+              $values['curr_image_rmv'],
+              $values['remove_img_rmv'],
+              $values['add_rmv']);
+
+        $this->tableMetaData = Toolkit_Common::getTableMetaData(
+            $this->dbh,
+            $this->tableName
+        );
+        $this->insertData($values);
+        //exit;
+
+        $listPage = MEDIA_BASE_URL .
+            "admin/members.php?rt=Members&ac=editMember&tab=courses&id={$_GET['id']}";
+        header("Location: $listPage");
+    }
+
+    //    }}}
+
+    //    {{{ setupRenderers()
+
+    /**
+     * Set up the rendering engine we are going to use to display this form
+     *
+     * @param HTML_Template_Flexy &$tEngine Templating Engine
+     *
+     * @return void
+     * @access protected
+     */
+    protected function setupRenderers(HTML_Template_Flexy &$tEngine)
+    {
+        $renderer = new HTML_QuickForm_Renderer_ObjectFlexy($tEngine);
+
+        $this->accept($renderer);
+        $this->view              = new stdClass();
+        $this->view->showCurrImg = $this->showCurrImg;
+        $this->view->form        = $renderer->toObject();
+        $tEngine->compile($this->formTemplate);
+    }
+
+    //    }}}
+
+    //  {{{ validNewImg()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param array $newImg Parameter description (if any) ...
+     *
+     * @return mixed  Return description (if any) ...
+     * @access public
+     */
+    function validNewImg(array $newImg)
+    {
+        return (   is_numeric($newImg['size'])
+                && $newImg['size'] > 0
+                && in_array($newImg['type'], $this->mimeTypes));
+    }
+
+    //  }}}
+    //  {{{ removeOldImage()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server $is     Parameter description (if any) ...
+     * @param string               $oldImg Parameter description (if any) ...
+     *
+     * @return void
+     * @access public
+     */
+    function removeOldImage(Toolkit_Image_Server $is, $oldImg)
+    {
+        $this->deleteImage($is, $oldImg);
+        if ($this->elementExists('curr_image_rmv')) {
+            $e =& $this->getElement('curr_image_rmv');
+            $e->setValue(null);
+            $this->_submitValues['curr_image_rmv'] = null;
+        }
+    }
+
+    //  }}}
+    //  {{{ syncCurrImage()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @return void
+     * @access protected
+     */
+    protected function syncCurrImage()
+    {
+        $is = new Toolkit_Image_Server();
+
+        $delImg = $this->getSubmitValue('remove_img_rmv');
+        $oldImg = $this->getSubmitValue('curr_image_rmv');
+        $newImg = $this->getSubmitValue('image');
+
+        if ($delImg && $oldImg) {
+            $this->removeOldImage($is, $oldImg);
+            unset($oldImg);
+        } elseif ($oldImg && $this->validNewImg($newImg)) {
+            $this->removeOldImage($is, $oldImg);
+            unset($oldImg);
+        }
+
+        if ($this->validNewImg($newImg)) {
+            $image = $this->uploadImage($is, 'image');
+        } else {
+            $image = $oldImg;
+        }
+
+        if ($image) {
+            $this->updatePhotoElements($is, $image);
+            $this->showCurrImg = true;
+        }
+    }
+
+    //  }}}
+    //    {{{ toHtml()
+
+    /**
+     * Renders the form
+     *
+     * sets the page the form should be redirected to instead of coming back
+     * around to itself.
+     *
+     * @param HTML_Template_Flexy $tEngine Templating Engine
+     *
+     * @return string The rendered form
+     * @access public
+     */
+    public function toHtml(HTML_Template_Flexy $tEngine)
+    {
+        //    We need to validate (and freeze if needed)
+        //    before we render the form. That way the
+        //    template knows about any errors on the form.
+        $this->validated = $this->validate();
+
+        //  If they have submitted the form and uploaded a proper image
+        //  but some other element had an error, then we need to show
+        //  their uploaded image in the form
+        if ($this->isSubmitted()) {
+            $this->syncCurrImage();
+        }
+
+        $this->setupRenderers($tEngine);
+
+        if ($this->validated) {
+            $processed = $this->process(
+                array(&$this, 'processData'),
+                $this->mergeFiles
+            );
+        }
+
+        return $tEngine->bufferedOutputObject($this->view);
+    }
+
+    //    }}}
+
+    //  {{{ updatePhotoElements()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server $is    Parameter description (if any) ...
+     * @param string               $image Parameter description (if any) ...
+     *
+     * @return void
+     * @access public
+     */
+    public function updatePhotoElements(Toolkit_Image_Server $is, $image)
+    {
+        //  Get the dimensions of the image
+        $dimensions = $is->getImageSize(MEMBER_PHOTOS . $image);
+        if (PEAR::isError($dimensions)) {
+            Toolkit_Common::handleError($dimensions);
+        }
+        list($w, $h) = $dimensions;
+        $s = MEMBER_PHOTOS . $image;
+
+        //  Set the image to show in the element
+        $e =& $this->getElement('curr_image');
+        $e->setText('<img width="'.$w.'" height="'.$h.'" src="'.$s.'">');
+
+        //  updated the hidden elements value to make sure it
+        //  holds the most up-to-date image name
+        $e =& $this->getElement('curr_image_rmv');
+        $e->setValue($image);
+    }
+
+    //  }}}
+    //  {{{ uploadImage()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server $is    Parameter description (if any) ...
+     * @param string               $field Parameter description (if any) ...
+     *
+     * @return object    Return description (if any) ...
+     * @access protected
+     */
+    protected function uploadImage(Toolkit_Image_Server $is, $field)
+    {
+        return $is->imageUpload($field);
+    }
+
+    //  }}}
+}
+
+/**
+ * Form to handle editing/deleting existing courses in members only area
+ *
+ * Handles updating caption requests for a member or to remove a
+ * course from thier profile
+ *
+ * @category  MembersDB
+ * @package   Toolkit_Members
+ * @author    Jamie Kahgee <jamie.kahgee@gmail.com>
+ * @copyright 2009 Jamie Kahgee
+ * @license   http://www.gaslightmedia.com Gaslightmedia
+ * @link      http://demo.gaslightmedia.com
+ */
+class EditAdminCourse extends Toolkit_FormBuilder
+{
+    //    {{{ properties
+
+    /**
+     * The table name in the database used to store the data
+     *
+     * @var string
+     * @access public
+     */
+    public $tableName = 'member_golf';
+
+    /**
+     * Some special forms dont utlize this stylesheet
+     * Allow classes to override this setting so it doesn't
+     * get included
+     *
+     * @var boolean
+     * @access protected
+     */
+    protected $includeContactStyleSheet = false;
+
+    /**
+     * The template used to render the form
+     *
+     * @var string
+     * @access protected
+     */
+    protected $formTemplate = 'editCourse.tpl';
+
+    /**
+     * Id of course in db
+     * @var    integer
+     * @access protected
+     */
+    protected $courseId;
+
+    /**
+     * Description for protected
+     * @var    string
+     * @access protected
+     */
+    protected $successMsg
+        = '<div id="form-success-top">
+            You successfully updated your course.
+           </div>';
+
+    /**
+     * Any rules we want to register for this form
+     * @var    array
+     * @access protected
+     */
+    protected $registeredRules = array();
+
+    /**
+     * Description for protected
+     * @var    array
+     * @access protected
+     */
+    protected $mimeTypes = array(
+        'image/jpe',
+        'image/jpeg',
+        'image/jpg',
+        'image/jfif',
+        'image/pjpeg',
+        'image/pjp',
+        'image/gif',
+        'image/png',
+    );
+
+    //    }}}
+    //    {{{ __construct()
+
+    /**
+     * Class constructor
+     *
+     * @param PDO    $pdo         PHP Data Object to use for DB calls
+     * @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
+     * @see    Toolkit_Members_Admin_EditCourses
+     */
+    public function __construct(
+        PDO $pdo,
+        $formName,
+        $method = 'post',
+        $action = '',
+        $target = '',
+        $attributes = null,
+        $trackSubmit = false
+    ) {
+        parent::__construct(
+            $formName,
+            $method,
+            $action,
+            $target,
+            $attributes,
+            $trackSubmit
+        );
+
+        $this->courseId = $attributes['id'];
+        $this->courses  = new Toolkit_Members_Courses(null, $_GET['id']);
+        $this->courses->setDbh($pdo);
+        $this->courses->createMemberList();
+        $this->dbh = $pdo;
+    }
+
+    //    }}}
+
+    //  {{{ configureForm()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @return void
+     * @access public
+     */
+    public function configureForm()
+    {
+        $this->configureElements();
+        $this->configureDefaults();
+        $this->configureFilters();
+        $this->configureRules();
+    }
+
+    //  }}}
+    //    {{{ configureDefaults()
+
+    /**
+     * Setup the element default values for form
+     *
+     * @access public
+     * @see    Toolkit_FormBuilder::setupDefaults()
+     * @return void
+     */
+    public function configureDefaults()
+    {
+        $sql = "
+            SELECT *
+              FROM {$this->tableName}
+             WHERE id = {$this->courseId}";
+
+        $defaults = $this->dbh->query($sql)->fetch(PDO::FETCH_ASSOC);
+        $defaults['curr_image_rmv'] = $defaults['image'];
+        $img = '<img src="%s">';
+        $defaults['curr_image'] = sprintf($img, MEMBER_PHOTOS . $defaults['image']);
+        $this->showCurrImg = $defaults['image'];
+        $this->setupDefaults($defaults);
+    }
+
+    //    }}}
+    //    {{{ configureElements()
+
+    /**
+     * Setup the elements to use on the form.
+     *
+     * @access public
+     * @see    Toolkit_FormBuilder::setupElements()
+     * @return void
+     */
+    public function configureElements()
+    {
+        $e = array();
+        //    All Grouped Elements are created here.
+
+        //    All Elements are created here.  This includes group element definitions.
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'title',
+            'display' => 'Course Title',
+        );
+        $e[] = array(
+            'type'        => 'textarea',
+            'req'         => false,
+            'name'        => 'description',
+            'display'     => 'Course Description',
+            'opts'        => array('id' => 'descr' . $this->courseId, 'class' => 'ckeditor'),
+            'noCharLimit' => true
+        );
+        $e[] = array(
+            'type'    => 'checkbox',
+            'req'     => false,
+            'name'    => 'remove_img_rmv',
+            'display' => 'Remove Image',
+        );
+        $e[] = array(
+            'type'    => 'static',
+            'req'     => false,
+            'name'    => 'curr_image',
+            'display' => 'Current Image',
+        );
+        $e[] = array(
+            'type'    => 'hidden',
+            'req'     => false,
+            'name'    => 'curr_image_rmv',
+        );
+        $e[] = array(
+            'type'    => 'file',
+            'req'     => false,
+            'name'    => 'image',
+            'display' => 'Upload a Course Photo / Image',
+        );
+        $e[] = array(
+            'type'    => 'submit',
+            'req'     => false,
+            'name'    => 'add_rmv',
+            'display' => 'Update Course',
+            'opts'    => array('class' => 'submit')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'res_url',
+            'display' => 'TeeTime URL',
+            'opts'    => array('class' => 'text'),
+            'noCharLimit' => true
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'par',
+            'display' => 'Par',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'yardage',
+            'display' => 'Yardage',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'course_rating',
+            'display' => 'Course Rating',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'slope_rating',
+            'display' => 'Slope Rating',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'advcheckbox',
+            'req'     => false,
+            'name'    => 'walking_course',
+            'display' => 'Walking Course',
+            'val'     => array(0, 1)
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'holes18',
+            'display' => '18 Holes',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'holes9',
+            'display' => '9 Holes',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'submit',
+            'req'     => false,
+            'name'    => 'remove_rmv',
+            'display' => 'Remove Course',
+            'opts'    => array('class' => 'submit')
+        );
+
+        $this->setupElements($e);
+    }
+
+    //    }}}
+    //    {{{ configureRules()
+
+    /**
+     * Configure rules for form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureRules()
+    {
+        $r = array();
+
+        $checkDate = create_function('$d', '$d = implode("-", $d); return Validate::date($d, array("format" => "%n-%j-%Y"));');
+        $r[] = array(
+            'element'    => 'sdate',
+            'message'    => 'ERROR: Invalid Date!',
+            'type'       => 'callback',
+            'format'     => $checkDate,
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+        $r[] = array(
+            'element'    => 'edate',
+            'message'    => 'ERROR: Invalid Date!',
+            'type'       => 'callback',
+            'format'     => $checkDate,
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+        $r[] = array(
+            'element'    => 'image',
+            'message'    => 'ERROR: Incorrect File Type (.gif, .png, .jpg) only!',
+            'type'       => 'mimetype',
+            'format'     => $this->mimeTypes,
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+
+        $this->setupRules($r);
+    }
+
+    //    }}}
+    //    {{{ configureConstants()
+
+    /**
+     * Configure constants for form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureConstants()
+    {
+        $c = array(
+            'remove_img_rmv' => false
+        );
+
+        $this->setupConstants($c);
+    }
+
+    //    }}}
+    //    {{{ configureFilters()
+
+    /**
+     * Configure filters for form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureFilters()
+    {
+        $f = array();
+
+        $f[] = array(
+            'element' => '__ALL__',
+            'filter' => 'trim'
+        );
+
+        $this->setupFilters($f);
+    }
+
+    //    }}}
+
+    //  {{{ deleteImage()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server $is  Parameter description (if any) ...
+     * @param string               $img Parameter description (if any) ...
+     *
+     * @return object    Return description (if any) ...
+     * @access protected
+     */
+    protected function deleteImage(Toolkit_Image_Server $is, $img)
+    {
+        return $is->imageDelete($img);
+    }
+
+    //  }}}
+
+    //    {{{ processData()
+
+    /**
+     * Handles setting up the from processing and which function to get it done
+     *
+     * @param array $values Submitted values from the form.
+     *
+     * @return void
+     * @access protected
+     */
+    protected function processData($values)
+    {
+        $cache = new Cache_Lite(Toolkit_Members::getCacheOptions());
+        $cache->remove("Member-{$_GET['id']}", 'Profile');
+
+        $e =& $this->getElement('curr_image_rmv');
+
+        $values['image'] = $e->getValue('curr_image_rmv');
+        unset($values['MAX_FILE_SIZE'],
+              $values['curr_image_rmv'],
+              $values['remove_img_rmv'],
+              $values['add_rmv']);
+
+        $this->tableMetaData = Toolkit_Common::getTableMetaData(
+            $this->dbh,
+            $this->tableName
+        );
+        $this->updateData($values);
+
+        $listPage = MEDIA_BASE_URL .
+            "admin/members.php?rt=Members&ac=editMember&tab=courses&id={$_GET['id']}";
+        header("Location: $listPage");
+    }
+
+    //    }}}
+
+    //    {{{ setupRenderers()
+
+    /**
+     * Set up the rendering engine we are going to use to display this form
+     *
+     * @param HTML_Template_Flexy &$tEngine Templating Engine
+     *
+     * @return void
+     * @access protected
+     */
+    protected function setupRenderers(HTML_Template_Flexy &$tEngine)
+    {
+        $renderer = new HTML_QuickForm_Renderer_ObjectFlexy($tEngine);
+
+        $this->accept($renderer);
+        $this->view              = new stdClass();
+        $this->view->showCurrImg = $this->showCurrImg;
+        $this->view->form        = $renderer->toObject();
+        $tEngine->compile($this->formTemplate);
+    }
+
+    //    }}}
+
+    //  {{{ validNewImg()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param array $newImg Parameter description (if any) ...
+     *
+     * @return mixed  Return description (if any) ...
+     * @access public
+     */
+    function validNewImg(array $newImg)
+    {
+        return (   is_numeric($newImg['size'])
+                && $newImg['size'] > 0
+                && in_array($newImg['type'], $this->mimeTypes));
+    }
+
+    //  }}}
+    //  {{{ removeOldImage()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server $is     Parameter description (if any) ...
+     * @param string               $oldImg Parameter description (if any) ...
+     *
+     * @return void
+     * @access public
+     */
+    function removeOldImage(Toolkit_Image_Server $is, $oldImg)
+    {
+        $this->deleteImage($is, $oldImg);
+        if ($this->elementExists('curr_image_rmv')) {
+            $e =& $this->getElement('curr_image_rmv');
+            $e->setValue(null);
+            $this->_submitValues['curr_image_rmv'] = null;
+        }
+    }
+
+    //  }}}
+    //  {{{ syncCurrImage()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @return void
+     * @access protected
+     */
+    protected function syncCurrImage()
+    {
+        $is = new Toolkit_Image_Server();
+
+        $delImg = $this->getSubmitValue('remove_img_rmv');
+        $oldImg = $this->getSubmitValue('curr_image_rmv');
+        $newImg = $this->getSubmitValue('image');
+
+        if ($delImg && $oldImg) {
+            $this->removeOldImage($is, $oldImg);
+            unset($oldImg);
+        } elseif ($oldImg && $this->validNewImg($newImg)) {
+            $this->removeOldImage($is, $oldImg);
+            unset($oldImg);
+        }
+
+        if ($this->validNewImg($newImg)) {
+            $image = $this->uploadImage($is, 'image');
+        } else {
+            $image = $oldImg;
+        }
+
+        if ($image) {
+            $this->updatePhotoElements($is, $image);
+            $this->showCurrImg = true;
+        }
+    }
+
+    //  }}}
+
+    //    {{{ toHtml()
+
+    /**
+     * Renders the form
+     *
+     * sets the page the form should be redirected to instead of coming back
+     * around to itself.
+     *
+     * @param HTML_Template_Flexy $tEngine Templating Engine
+     *
+     * @return string The rendered form
+     * @access public
+     */
+    public function toHtml(HTML_Template_Flexy $tEngine)
+    {
+        //    We need to validate (and freeze if needed)
+        //    before we render the form. That way the
+        //    template knows about any errors on the form.
+        $this->validated = $this->validate();
+
+        //  If they have submitted the form and uploaded a proper image
+        //  but some other element had an error, then we need to show
+        //  their uploaded image in the form
+        if ($this->isSubmitted()) {
+            $this->syncCurrImage();
+        }
+
+        $this->setupRenderers($tEngine);
+
+        if ($this->validated) {
+            $processed = $this->process(
+                array(&$this, 'processData'),
+                $this->mergeFiles
+            );
+        }
+
+        return $tEngine->bufferedOutputObject($this->view);
+    }
+
+    //    }}}
+
+    //    {{{    removeCourse()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param int $id Parameter description (if any) ...
+     *
+     * @return object    Return description (if any) ...
+     * @access protected
+     */
+    protected function removeCourse($id)
+    {
+        try {
+            //  need to delete the image associated w/ this course here.
+            $sql = "
+                DELETE FROM {$this->tableName}
+                 WHERE id = :id";
+
+            $stmt = $this->dbh->prepare($sql);
+            $stmt->bindParam(':id', $id, PDO::PARAM_INT);
+            return $stmt->execute();
+        } catch (PDOException $e) {
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+    //    }}}
+
+    //    {{{ updateData()
+
+    /**
+     * Update the course caption
+     *
+     * @param array $values Submitted form values
+     *
+     * @return boolean Result of updating the caption in the db
+     * @access public
+     */
+    protected function updateData($values)
+    {
+        try {
+            if (array_key_exists('remove_rmv', $values)) {
+                return $this->removeCourse($this->courseId);
+            }
+            $sql = Toolkit_Common::createSQLUpdate(
+                $this->tableName,
+                array_keys($values),
+                array('id = :id')
+            );
+
+            $values['id'] = $this->courseId;
+            return Toolkit_Common::processQuery(
+                $this->dbh,
+                $this->tableName,
+                $sql,
+                $values
+            );
+        } catch (PDOException $e) {
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+    //    }}}
+    //  {{{ updatePhotoElements()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server $is    Parameter description (if any) ...
+     * @param string               $image Parameter description (if any) ...
+     *
+     * @return void
+     * @access public
+     */
+    public function updatePhotoElements(Toolkit_Image_Server $is, $image)
+    {
+        //  Get the dimensions of the image
+        $dimensions = $is->getImageSize(MEMBER_PHOTOS . $image);
+        if (PEAR::isError($dimensions)) {
+            Toolkit_Common::handleError($dimensions);
+        }
+        list($w, $h) = $dimensions;
+        $s = MEMBER_PHOTOS . $image;
+
+        //  Set the image to show in the element
+        $e =& $this->getElement('curr_image');
+        $e->setText('<img width="'.$w.'" height="'.$h.'" src="'.$s.'">');
+
+        //  updated the hidden elements value to make sure it
+        //  holds the most up-to-date image name
+        $e =& $this->getElement('curr_image_rmv');
+        $e->setValue($image);
+    }
+
+    //  }}}
+    //  {{{ uploadImage()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server $is    Parameter description (if any) ...
+     * @param string               $field Parameter description (if any) ...
+     *
+     * @return object    Return description (if any) ...
+     * @access protected
+     */
+    protected function uploadImage(Toolkit_Image_Server $is, $field)
+    {
+        return $is->imageUpload($field);
+    }
+
+    //  }}}
+}
+?>
diff --git a/Toolkit/Members/Courses.php b/Toolkit/Members/Courses.php
new file mode 100644 (file)
index 0000000..b300dde
--- /dev/null
@@ -0,0 +1,359 @@
+<?php
+//  vim:set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker syntax=php:
+
+/**
+ * Linked list (LL) implementation of member packages
+ *
+ * File contains the class that gives the ability to create a linked list
+ * of member packages.  You can iterate through manipulate and control every
+ * aspect of the LL.  The best part is, by keeping the LL in order it
+ * automatically maintains the DB for you.
+ *
+ * PHP version 5
+ *
+ * @category  MembersDB
+ * @package   Toolkit_Members
+ * @author    Jamie Kahgee <steve@gaslightmedia.com>
+ * @copyright 2009 Jamie Kahgee
+ * @license   http://www.gaslightmedia.com Gaslightmedia
+ * @version   CVS: $Id: Packages.php,v 1.9 2010/05/25 14:01:16 jamie Exp $
+ * @link      http://demo.gaslightmedia.com
+ * @see       Structures/LinkedList/Double.php
+ *            Toolkit/Members/Packages/Package.php
+ */
+
+/**
+ * Class implementation of a linked list
+ *
+ * @category  MembersDB
+ * @package   Toolkit_Members
+ * @author    Jamie Kahgee <steve@gaslightmedia.com>
+ * @copyright 2009 Jamie Kahgee
+ * @license   http://www.gaslightmedia.com Gaslightmedia
+ * @link      http://demo.gaslightmedia.com
+ * @see       Structures/LinkedList/Double.php
+ */
+class Toolkit_Members_Courses extends Structures_LinkedList_Double
+{
+    //  {{{ properties
+
+    /**
+     * Database handler object
+     * @var    pdo
+     * @access public
+     */
+    public $dbh;
+
+    /**
+     * DB id of member whos packages we are manipulating with this linked list
+     * @var    integer
+     * @access protected
+     */
+    protected $mid;
+
+    //  }}}
+    //  {{{ __construct()
+
+    /**
+     * Constructor
+     *
+     * @param Structures_LinkedList_DoubleNode $root Linked List node object
+     * @param int                              $mid  DB id of member we want to prepare the list for
+     *
+     * @access public
+     */
+    function __construct(
+        Structures_LinkedList_DoubleNode $root = null,
+        $mid = null
+    ) {
+        parent::__construct($root);
+        $this->setMember($mid);
+    }
+
+    //  }}}
+
+    //  {{{ createMemberList()
+
+    /**
+     * Creates a linked list from all the packages a member has in the db.
+     *
+     * @param string $order The order to make the linked list in
+     *
+     * @return boolean false on error
+     * @access public
+     */
+    public function createMemberList($order = 'pos')
+    {
+        if (!is_numeric($this->mid)) {
+            return;
+        }
+
+        $safeOrder = array('pos', 'id');
+        if (!in_array($order, $safeOrder)) {
+            $order = 'pos';
+        }
+        try {
+            //  Get each package tuple from the member_packages table.
+            $sql = "
+                SELECT *
+                  FROM member_golf
+                 WHERE member_id = :member_id
+                 ORDER BY $order";
+
+            $stmt = $this->dbh->prepare($sql);
+            $stmt->bindParam(':member_id', $this->mid, PDO::PARAM_INT);
+            $stmt->execute();
+
+            while ($row = $stmt->fetch()) {
+                //  Create a new node w/ all the data we just extracted.
+                $node = $this->createNode($row);
+                $node->setDbh($this->dbh);
+                //  Sets up any pending data the package might currently have.
+                $node->setPendingData();
+                //  Add the package node to the end of the linked list.
+                $res = $this->appendNode($node);
+            }
+
+        } catch (PDOException $e) {
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+    //  }}}
+    //  {{{ createNode()
+
+    /**
+     * Creates a new linked list node object
+     *
+     * @param array $data Data to populate the new node with
+     *
+     * @access public
+     * @return object newly created linked list node
+     */
+    public function &createNode(array $data)
+    {
+        $node = new Toolkit_Members_Packages_Package($data);
+        $node->setDbh($this->dbh);
+
+        return $node;
+    }
+
+    //  }}}
+
+    //  {{{ getListSize()
+
+    /**
+     * Get how many nodes are currently in the linked list
+     *
+     * @param boolean $filterPending Include pending packages in the count
+     *
+     * @return integer number of nodes in the linked list
+     * @access public
+     */
+    public function getListSize($filterPending = false)
+    {
+        $size = 0;
+        $cur  = $this->rewind();
+
+        //  If the current node is null, then we have no nodes
+        //  in the linked list.  return the empty size.
+        //  Else we have at least one node in the linked list.
+        if (is_null($cur)) {
+            return $size;
+        }
+
+        //  Add one to the size of the list for every
+        //  node we encounter.
+        do {
+            if ($filterPending) {
+                if (!$cur->getPending()) {
+                    ++$size;
+                }
+            } else {
+                ++$size;
+            }
+        } while ($cur = $this->next());
+
+        return $size;
+    }
+
+    //  }}}
+    //  {{{ getMemberId()
+
+    /**
+     * Get which member this linked list is for
+     *
+     * @return integer id of member we are dealing with
+     * @access public
+     */
+    public function getMemberId()
+    {
+        return $this->mid;
+    }
+
+    //  }}}
+
+    //  {{{ findNode()
+
+    /**
+     * find a node from the linked list
+     *
+     * @param integer $target Id of package you are searching for
+     *
+     * @return mixed Toolkit_Members_Packages_Package if present, else false
+     * @access public
+     */
+    public function &findNode($target)
+    {
+        $this->end();
+        $startingId = $this->current->getId();
+
+        if ($target == $startingId) {
+            return $this->current;
+        }
+
+        while ($curr = $this->previous()) {
+            if ($target == $curr->getId()) {
+                return $curr;
+            }
+        }
+
+        return false;
+    }
+
+    //  }}}
+
+    //  {{{ moveNode()
+
+    /**
+     * Adjust nodes position in the linked list
+     *
+     * @param integer $pid id of package you want to move
+     * @param integer $pos new position you want to move to
+     *
+     * @access public
+     * @return void
+     */
+    public function moveNode($pid, $pos)
+    {
+        $node   = $this->findNode($pid);
+        $oldPos = $node->getPosition();
+
+        if ($this->getListSize()) {
+            $cur = $this->rewind();
+            do {
+                if ($cur->getId() == $pid) {
+                    $cur->setPosition($pos);
+                } else {
+                    $curPos = $cur->getPosition();
+                    if ($pos > $oldPos) {
+                        if ($curPos <= $pos && $curPos > $oldPos) {
+                            $cur->setPosition($curPos - 1);
+                        }
+                    } elseif ($pos < $oldPos) {
+                        if ($curPos >= $pos && $curPos < $oldPos) {
+                            $cur->setPosition($curPos + 1);
+                        }
+                    }
+                }
+            } while ($cur = $this->next());
+        }
+    }
+
+    //  }}}
+
+    //  {{{ removeNode()
+
+    /**
+     * Removes a node from the linked list
+     *
+     * @param Toolkit_Image_Server $is     Image Server Object
+     * @param integer              $target Id of package you want to remove
+     *
+     * @return boolean false on error
+     * @access public
+     */
+    public function removeNode(Toolkit_Image_Server $is, $target)
+    {
+        $node = $this->findNode($target);
+        if (!$node) {
+            return false;
+        }
+
+        $node->remove($is);
+        $remNodePos = $node->getPosition();
+
+        //  only try and update positions in the linked list if there are nodes that
+        //  will still exists after this node is removed ie.  size is greater than 1
+        if ($this->getListSize() > 1) {
+            $cur = $this->rewind();
+            do {
+                if ($cur->getPosition() > $remNodePos) {
+                    $cur->setPosition($cur->getPosition() - 1);
+                }
+            } while ($cur = $this->next());
+        }
+
+        $this->deleteNode($node);
+    }
+
+    //  }}}
+
+    //  {{{ setDbh()
+
+    /**
+     * Set the Database Handler
+     *
+     * @param PDO $pdo PHP Data Object to use
+     *
+     * @return void
+     * @access public
+     */
+    public function setDbh(PDO $pdo)
+    {
+        $this->dbh = $pdo;
+    }
+
+    //  }}}
+    //  {{{ setMember()
+
+    /**
+     * Sets which member we are working with
+     *
+     * @param integer $mid id of member
+     *
+     * @access public
+     * @return PEAR error on invalid member id
+     */
+    public function setMember($mid)
+    {
+        if (is_integer($mid)) {
+            $this->mid = $mid;
+        } elseif (is_numeric($mid) && ctype_digit($mid)) {
+            $this->mid = $mid;
+        } else {
+            return PEAR::raiseError('invalid member id');
+        }
+    }
+
+    //  }}}
+
+    //  {{{ emptyList()
+
+    /**
+     * Deletes all nodes from a list
+     *
+     * @access public
+     * @return void
+     */
+    public function emptyList()
+    {
+        $this->end();
+        while ($cur = $this->current()) {
+            $this->deleteNode($cur);
+        }
+    }
+
+    //  }}}
+}
+?>
index a6591ee..cfc0318 100644 (file)
@@ -14,6 +14,13 @@ CREATE TABLE members.member_golf
     REFERENCES members.member(member_id)
     ON UPDATE CASCADE
     ON DELETE CASCADE,
+ pos INTEGER,
+ title TEXT,
+ description TEXT,
+ image TEXT,
+ file TEXT,
+ filename TEXT,
+ pending BOOLEAN,
  PRIMARY KEY (id));
 
 GRANT ALL ON members.member_golf_id_seq TO nobody;
diff --git a/Toolkit/Members/EditCourses.php b/Toolkit/Members/EditCourses.php
new file mode 100644 (file)
index 0000000..83e9d21
--- /dev/null
@@ -0,0 +1,1935 @@
+<?php
+//    vim:set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker syntax=php:
+
+/**
+ * Handles the packages tab in the member record
+ *
+ * Controls setting up the add package form if applicable, and rendering
+ * each uploaded package edit form to edit/delete the package.
+ *
+ * PHP version 5
+ *
+ * @category  MembersDB
+ * @package   Toolkit_Members
+ * @author    Jamie Kahgee <steve@gaslightmedia.com>
+ * @copyright 2009 Jamie Kahgee
+ * @license   http://www.gaslightmedia.com Gaslightmedia
+ * @version   CVS: $Id: EditCourses.php,v 1.16 2010/07/18 16:45:33 jamie Exp $
+ * @link      http://demo.gaslightmedia.com
+ * @see       Toolkit/Image/Server.php
+ */
+
+
+/**
+ * The image server processing class
+ */
+require_once BASE . 'Toolkit/Image/Server.php';
+
+/**
+ * Constructor class to setup the page layout
+ *
+ * this class determines if the user can upload any more packages to their
+ * account and if so renders the add package form.  It also controls
+ * rending the individual forms for each previously uploaded package.
+ *
+ * @category  MembersDB
+ * @package   Toolkit_Members
+ * @author    Jamie Kahgee <steve@gaslightmedia.com>
+ * @copyright 2009 Jamie Kahgee
+ * @license   http://www.gaslightmedia.com Gaslightmedia
+ * @link      http://demo.gaslightmedia.com
+ */
+class Toolkit_Members_EditCourses
+    extends Toolkit_Members_Admin_EditCourses
+{
+    //    {{{ properties
+
+    /**
+     * The table name in the database used to store the data
+     * @var string
+     * @access public
+     */
+    public $tableName = 'member_packages';
+
+    /**
+     * Template used to layout form when editing a package
+     * @var    string
+     * @access protected
+     */
+    protected $pageTemplate = 'editCourses.tpl';
+
+    /**
+     * What is the maximum caption length for packages
+     *
+     * @var    array
+     * @access public
+     * @static
+     */
+    static public $maxTitleLength = 60;
+
+    /**
+     * Objects that will go into the page (add form, edit package forms)
+     * @var    object
+     * @access protected
+     */
+    protected $page;
+
+    /**
+     * Description for protected
+     * @var    PDO
+     * @access protected
+     */
+    protected $dbh;
+
+    //    }}}
+    //    {{{    canAddCourses()
+
+    /**
+     * Determine if this member can have more packages added to their profile
+     *
+     * Load the entire package gallery into member via a linked list.
+     * Then return if the # of linked list nodes is smaller than
+     * the maximum limit of packages.
+     *
+     * @access protected
+     * @return boolean If the linked list is smaller than max packages allowed
+     */
+    protected function canAddCourses()
+    {
+        $membersConf = new Config;
+        $membersRoot =& $membersConf->parseConfig(
+            BASE . 'Toolkit/Members/config.ini',
+            'IniFile'
+        );
+        $memberCourseLimit = $membersRoot->getItem('section', 'conf')
+            ->getItem('directive', 'memberCourseLimit')
+            ->getContent();
+        if (   !$memberCourseLimit
+            || !filter_var($memberCourseLimit, FILTER_VALIDATE_INT)
+        ) {
+            return true;
+        }
+        $id = $GLOBALS['memberAuth']->getAuthData('member_id');
+        $ll = new Toolkit_Members_Courses(null, $id);
+        $ll->setDbh($this->dbh);
+        $ll->createMemberList();
+        return ($ll->getListSize() < $memberCourseLimit);
+    }
+
+    //    }}}
+
+    //    {{{    displayPage()
+
+    /**
+     * Displays the page to the screen
+     *
+     * @return void
+     * @access public
+     */
+    public function displayPage()
+    {
+        echo $this->getPage();
+    }
+
+    //    }}}
+
+    //    {{{    getUploadedCourses()
+
+    /**
+     * Get an array of package ids from the DB that have been uploaded for this member
+     *
+     * - Create a linked list of all the members packages
+     * - Walk through the linked list extracting the id from each node into an array
+     *
+     * @access protected
+     * @return array Ids of all uploaded packages for this member
+     */
+    protected function getUploadedCourses()
+    {
+        $id = $GLOBALS['memberAuth']->getAuthData('member_id');
+        $packages = new Toolkit_Members_Courses(null, $id);
+        $packages->setDbh($this->dbh);
+        $packages->createMemberList();
+        $packages->rewind();
+
+        $ids = array();
+        foreach ($packages as $i) {
+            $ids[] = $i->getId();
+        }
+
+        return $ids;
+    }
+
+    //    }}}
+
+    //    {{{    setUpPage()
+
+    /**
+     * Sets up the page to manipulate packages for a member
+     *
+     * Checks if all the packages uploaded for a member (pending & non-pending)
+     * exceed or match the maximum # of packages allowed for each member to
+     * upload to their account.
+     *
+     * For every package that is already uploaded, create an edit-package form that
+     * will allow the user to update the caption or delete the package.
+     *
+     * @param Config_Container $c Application configuration
+     *
+     * @return void
+     * @access public
+     */
+    public function setUpPage(Config_Container $c)
+    {
+        $this->page = new StdClass;
+
+        //    Find out if we can still add packages to the record.
+        //    If we can, then add the upload form to the page for the member to see.
+        if ($this->canAddCourses()) {
+            $addForm = new AddCourse(
+                $this->dbh,
+                'new_member_package',
+                'post',
+                '',
+                '',
+                null,
+                true
+            );
+
+            $addForm->configureForm($c);
+            $this->page->uploadForm = $addForm->toHtml($this->tEngine);
+        }
+
+        //    Find out if we have any packages already uploaded.
+        //    If we do, then add the edit package form to the page for each package
+        //    so the member can edit/delete their packages.
+        if ($packages = $this->getUploadedCourses()) {
+            $this->page->editForm = array();
+            while (list($i, $j) = each($packages)) {
+                $editForm = new EditCourse(
+                    $this->dbh,
+                    "edit_member_package_$j",
+                    'post',
+                    '',
+                    '',
+                    array('id' => $j),
+                    true
+                );
+
+                $editForm->configureForm();
+                $this->page->editForm[] = $editForm->toHtml($this->tEngine);
+            }
+        }
+    }
+
+    //    }}}
+}
+
+/**
+ * Form to handle creating a new package in the members only area
+ *
+ * Handles inserting new package into db as a pending package and creating a
+ * tuple in the member_updates table which will allow the admin to
+ * approve/deny the new package request.
+ *
+ * @category  MembersDB
+ * @package   Toolkit_Members
+ * @author    Jamie Kahgee <jamie.kahgee@gmail.com>
+ * @copyright 2009 Jamie Kahgee
+ * @license   http://www.gaslightmedia.com Gaslightmedia
+ * @link      <>
+ */
+class AddCourse extends Toolkit_FormBuilder
+{
+    //    {{{ properties
+
+    /**
+     * The table name in the database used to store the data
+     *
+     * @var string
+     * @access public
+     */
+    public $tableName = 'member_packages';
+
+    /**
+     * The template used to render the form
+     *
+     * @var string
+     * @access protected
+     */
+    protected $formTemplate = 'addCourse.tpl';
+
+    /**
+     * The name of the template used to email the owner for any updates
+     *
+     * When a member makes an update to thier record, this is the template
+     * we will use to send out the email notification to the site owner.
+     *
+     * @var string
+     * @access protected
+     */
+    protected $emailTemplate = 'emailOwner.tpl';
+
+    /**
+     * Description for protected
+     * @var    array
+     * @access protected
+     */
+    protected $registeredRules = array();
+
+    /**
+     * Description for protected
+     * @var    string
+     * @access protected
+     */
+    protected $successMsg
+        = '<div id="form-success-top">
+            You successfully uploaded your package.
+           </div>';
+
+    /**
+     * Description for protected
+     * @var    array
+     * @access protected
+     */
+    protected $mimeTypes = array(
+        'image/jpe',
+        'image/jpeg',
+        'image/jpg',
+        'image/jfif',
+        'image/pjpeg',
+        'image/pjp',
+        'image/gif',
+        'image/png',
+    );
+
+    //    }}}
+    //    {{{ __construct()
+
+    /**
+     * Class constructor
+     *
+     * @param PDO    $pdo         PHP Data Object to use for DB calls
+     * @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
+     * @see    Toolkit_Members_Admin_EditCourses
+     */
+    public function __construct(
+        PDO $pdo,
+        $formName,
+        $method = 'post',
+        $action = '',
+        $target = '',
+        $attributes = null,
+        $trackSubmit = false
+    ) {
+        parent::__construct(
+            $formName,
+            $method,
+            $action,
+            $target,
+            $attributes,
+            $trackSubmit
+        );
+        $this->dbh = $pdo;
+    }
+
+    //    }}}
+
+    //  {{{ configureForm()
+
+    /**
+     * Quick form configuration
+     *
+     * @param Config_Container $c Config container
+     *
+     * @return void
+     * @access public
+     */
+    public function configureForm(Config_Container $c)
+    {
+        $this->configureElements();
+        $this->configureFilters();
+        $this->configureRules();
+        $this->configureConstants($c);
+    }
+
+    //  }}}
+    //    {{{ configureElements()
+
+    /**
+     * Setup the elements to use on the form.
+     *
+     * @access public
+     * @see    Toolkit_FormBuilder::setupElements()
+     * @return void
+     */
+    public function configureElements()
+    {
+        $e = array();
+        //    All Grouped Elements are created here.
+
+        //    All Elements are created here.  This includes group element definitions.
+        $e[] = array(
+            'type'    => 'hidden',
+            'req'     => false,
+            'name'    => 'pending',
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'title',
+            'display' => 'Course Title',
+        );
+        $e[] = array(
+            'type'        => 'textarea',
+            'req'         => false,
+            'name'        => 'description',
+            'display'     => 'Course Description',
+            'opts'        => array('id' => 'descrAdd', 'class' => 'ckeditor'),
+            'noCharLimit' => true
+        );
+        $e[] = array(
+            'type'    => 'date',
+            'req'     => true,
+            'name'    => 'sdate',
+            'display' => 'Start Date',
+            'opts'    => array(
+                'format'           => 'm / d / Y',
+                'minYear'          => date('Y'),
+                'maxYear'          => date('Y') + 10,
+                'addEmptyOption'   => true,
+                'emptyOptionValue' => '',
+                'emptyOptionText'  => array(
+                    'm' => 'mm',
+                    'd' => 'dd',
+                    'Y' => 'yyyy',
+                ),
+            )
+        );
+        $e[] = array(
+            'type'    => 'date',
+            'req'     => true,
+            'name'    => 'edate',
+            'display' => 'End Date',
+            'opts'    => array(
+                'format'           => 'm / d / Y',
+                'minYear'          => date('Y'),
+                'maxYear'          => date('Y') + 10,
+                'addEmptyOption'   => true,
+                'emptyOptionValue' => '',
+                'emptyOptionText'  => array(
+                    'm' => 'mm',
+                    'd' => 'dd',
+                    'Y' => 'yyyy',
+                ),
+            )
+        );
+        $e[] = array(
+            'type'    => 'checkbox',
+            'req'     => false,
+            'name'    => 'remove_img_rmv',
+            'display' => 'Remove Image',
+        );
+        $e[] = array(
+            'type'    => 'static',
+            'req'     => false,
+            'name'    => 'curr_image',
+            'display' => 'Current Image',
+        );
+        $e[] = array(
+            'type'    => 'hidden',
+            'req'     => false,
+            'name'    => 'curr_image_rmv',
+        );
+        $e[] = array(
+            'type'    => 'file',
+            'req'     => false,
+            'name'    => 'image',
+            'display' => 'Upload a Course Photo / Image',
+        );
+        $e[] = array(
+            'type'    => 'submit',
+            'req'     => false,
+            'name'    => 'add_rmv',
+            'display' => 'Upload new package',
+            'opts'    => array('class' => 'submit')
+        );
+
+        $this->setupElements($e);
+    }
+
+    //    }}}
+    //    {{{ configureRules()
+
+    /**
+     * Configure rules for form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureRules()
+    {
+        $r = array();
+
+        $checkDate = create_function('$d', '$d = implode("-", $d); return Validate::date($d, array("format" => "%n-%j-%Y"));');
+        $r[] = array(
+            'element'    => 'sdate',
+            'message'    => 'ERROR: Invalid Date!',
+            'type'       => 'callback',
+            'format'     => $checkDate,
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+        $r[] = array(
+            'element'    => 'edate',
+            'message'    => 'ERROR: Invalid Date!',
+            'type'       => 'callback',
+            'format'     => $checkDate,
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+        $r[] = array(
+            'element'    => 'image',
+            'message'    => 'ERROR: Incorrect File Type (.gif, .png, .jpg) only!',
+            'type'       => 'mimetype',
+            'format'     => $this->mimeTypes,
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+
+        $this->setupRules($r);
+    }
+
+    //    }}}
+    //    {{{ configureConstants()
+
+    /**
+     * Configure constants for form
+     *
+     * @param Config_Container $conf Application configuration
+     *
+     * @return void
+     * @access public
+     */
+    public function configureConstants(Config_Container $conf)
+    {
+        $pending = $conf->getItem('section', 'conf')
+            ->getItem('directive', 'strictPending')
+            ->getContent();
+
+        $c = array(
+            'pending' => $pending
+        );
+
+        $this->setupConstants($c);
+    }
+
+    //    }}}
+    //    {{{ configureFilters()
+
+    /**
+     * Configure filters for form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureFilters()
+    {
+        $f = array();
+
+        $f[] = array(
+            'element' => '__ALL__',
+            'filter' => 'trim'
+        );
+
+        $this->setupFilters($f);
+    }
+
+    //    }}}
+
+    //  {{{ deleteImage()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server  $is  Parameter description (if any) ...
+     * @param string                $img Parameter description (if any) ...
+     *
+     * @return object    Return description (if any) ...
+     * @access protected
+     */
+    protected function deleteImage(Toolkit_Image_Server $is, $img)
+    {
+        return $is->imageDelete($img);
+    }
+
+    //  }}}
+
+    //  {{{ emailOwner()
+
+    /**
+     * Emails the owner and anyone else who wants to be advised of updates
+     *
+     * A false value in the primaryAdvisee will cause no email to be sent.
+     * all secondary advisees listed in the constructor are carbon copied
+     * in the email.
+     *
+     * Emails are sent out in both HTML and TXT forms.
+     *
+     * @return boolean result of email
+     * @access protected
+     */
+    protected function emailOwner()
+    {
+        if (MEMBER_RECORD_UPDATES_ADVISOR === false) {
+            return;
+        } else {
+            $this->flexyOptions = Toolkit_Members::getFlexyOptions();
+            $id = $GLOBALS['memberAuth']->getAuthData('member_id');
+            try {
+                $sql = "
+                    SELECT member_name
+                      FROM member
+                     WHERE member_id = :member_id";
+                $stmt = $this->dbh->prepare($sql);
+                $stmt->bindParam(':member_id', $id, PDO::PARAM_INT);
+                $stmt->execute();
+                $row = $stmt->fetch(PDO::FETCH_ASSOC);
+                $memberName = $row['member_name'];
+            } catch (PDOException $e) {
+                return Toolkit_Common::handleError($e);
+            }
+            $template = new HTML_Template_Flexy($this->flexyOptions);
+            $page = new stdClass();
+            $page->member = $memberName;
+            $page->url = ($_SERVER['HTTPS'] == 'on') ? BASE_SECURE_URL : MEDIA_BASE_URL;
+            $page->email = OWNER_EMAIL;
+            $page->siteName = SITENAME;
+            $page->link = '<a target="_blank"  href="'.MEDIA_BASE_URL.'pending-member/'.$id.'/">link</a>';
+
+            $template->compile($this->emailTemplate);
+            //  Merge the compiled template with the $page object.
+            $htmlMsg = $template->bufferedOutputObject($page);
+
+            $msg = "
+                <h3>$memberName</h3>
+                <p>
+                    Has updated thier business record and is now in a pending
+                    state. To approve / reject thier changes you can either log
+                    into your {$page->siteName} admin area or follow this
+                    {$page->link}
+                </p>";
+            $crlf = "\n";
+            $mimeMail = new Mail_mime($crlf);
+            $from = preg_replace("/[^A-Za-z ]/", "", SITENAME) . ' <' . OWNER_EMAIL . '>';
+            $mimeMail->setFrom($from);
+            $mimeMail->setSubject('Member Record Update');
+            $mimeMail->setHTMLBody($htmlMsg);
+            $mimeMail->setTXTBody($msg);
+
+            $mail =& Mail::factory('mail');
+            $body = $mimeMail->get();
+            $headers = $mimeMail->headers($hdrs);
+
+            $res = $mail->send(MEMBER_RECORD_UPDATES_ADVISOR, $headers, $body);
+            if (PEAR::isError($res)) {
+                return Toolkit_Common::handleError($res);
+            } else {
+                return $res;
+            }
+        }
+    }
+
+    //  }}}
+    //    {{{ insertData()
+
+    /**
+     * Create a new package in the db
+     *
+     * @param array &$values Form submitted values
+     *
+     * @return object    db result of adding package
+     * @access protected
+     */
+    protected function insertData(&$values)
+    {
+        try {
+            $this->dbh->beginTransaction();
+            $sql = Toolkit_Common::createSQLInsert(
+                $this->tableName,
+                array_keys($values)
+            );
+
+            $res = Toolkit_Common::processQuery(
+                $this->dbh,
+                $this->tableName,
+                $sql,
+                $values
+            );
+
+            if ($values['pending']) {
+                $this->_createPendingData($values);
+            }
+
+            $this->dbh->commit();
+            return $res;
+        } catch (PDOException $e) {
+            $this->dbh->rollback();
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+    //    }}}
+
+    //    {{{    _createPendingData()
+
+    /**
+     * Description of _createPendingData()
+     *
+     * @param array $values Value array
+     *
+     * @return void|mixed
+     * @access private
+     */
+    private function _createPendingData($values)
+    {
+        try {
+            $sql = "
+                SELECT *
+                  FROM member_packages
+                 WHERE member_id = :member_id
+                 ORDER BY id DESC LIMIT 1";
+
+            $stmt = $this->dbh->prepare($sql);
+            $stmt->bindParam(':member_id', $values['member_id'], PDO::PARAM_INT);
+            $stmt->execute();
+            $row = $stmt->fetch();
+
+            $sql = "
+                INSERT INTO member_updates
+                    (field, update, db_table, data_type, label,
+                     foreign_key, member_id, field_type)
+                VALUES (:field, :update, :db_table, :data_type, :label,
+                        :foreign_key, :member_id, :field_type)";
+
+            $dataToInsert = array();
+            if (!empty($values['title'])) {
+                $dataToInsert[] = array(
+                     'field' => 'title',
+                     'update' => $values['title'],
+                     'label' => 'Title'
+                );
+            }
+
+            if (!empty($values['description'])) {
+                $dataToInsert[] = array(
+                        'field' => 'description',
+                        'update' => $values['description'],
+                        'label' => 'Description'
+                );
+            }
+            /*if (!empty($values['image'])) {
+                $dataToInsert[] = array(
+                        'field' => 'image',
+                        'update' => $values['image'],
+                        'label' => 'Image'
+                );
+            }*/
+            $stmt = $this->dbh->prepare($sql);
+            $stmt->bindValue(':db_table', 'member_packages', PDO::PARAM_STR);
+            $stmt->bindValue(':data_type', 'text', PDO::PARAM_STR);
+            $stmt->bindValue(':field_type', 'text', PDO::PARAM_STR);
+            $stmt->bindParam(':foreign_key', $row['id'], PDO::PARAM_INT);
+            $stmt->bindParam(':member_id', $values['member_id'], PDO::PARAM_INT);
+
+            foreach ($dataToInsert as $i) {
+                $stmt->bindParam(':field', $i['field'], PDO::PARAM_STR);
+                $stmt->bindParam(':update', $i['update'], PDO::PARAM_STR);
+                $stmt->bindParam(':label', $i['label'], PDO::PARAM_STR);
+                $stmt->execute();
+            }
+        } catch (PDOException $e) {
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+    //    }}}
+
+    //    {{{ processData()
+
+    /**
+     * Handles setting up the from processing and which function to get it done
+     *
+     * @param array $values Submitted values from the form.
+     *
+     * @return void
+     * @access protected
+     */
+    protected function processData($values)
+    {
+        $id = $GLOBALS['memberAuth']->getAuthData('member_id');
+        $cache = new Cache_Lite(Toolkit_Members::getCacheOptions());
+        $cache->remove("Member-$id", 'Profile');
+
+        $e =& $this->getElement('curr_image_rmv');
+
+        $packages = new Toolkit_Members_Courses(null, $id);
+        $packages->setDbh($this->dbh);
+        $packages->createMemberList();
+        $values['pos']       = $packages->getListSize() + 1;
+        $values['image'] = $e->getValue('curr_image_rmv');
+        $values['member_id'] = $GLOBALS['memberAuth']->getAuthData('member_id');
+        $values['sdate'] = implode('-', $values['sdate']);
+        $values['edate'] = implode('-', $values['edate']);
+        unset($values['MAX_FILE_SIZE'],
+              $values['curr_image_rmv'],
+              $values['remove_img_rmv'],
+              $values['add_rmv']);
+
+        $this->tableMetaData = Toolkit_Common::getTableMetaData(
+            $this->dbh,
+            $this->tableName
+        );
+        $this->insertData($values);
+        $this->emailOwner();
+
+        $listPage = MEDIA_BASE_URL .
+            "members-only-area/?rt=EditProfile&tab=packages";
+        header("Location: $listPage");
+    }
+
+    //    }}}
+
+    //    {{{ setupRenderers()
+
+    /**
+     * Set up the rendering engine we are going to use to display this form
+     *
+     * @return void
+     * @access protected
+     */
+    protected function setupRenderers()
+    {
+        $fo = Toolkit_Members::getFlexyOptions();
+
+        $this->template = new HTML_Template_Flexy($fo);
+
+        $renderer = new HTML_QuickForm_Renderer_ObjectFlexy($this->template);
+
+        $this->accept($renderer);
+        $this->view              = new StdClass;
+        $this->view->showCurrImg = $this->showCurrImg;
+        $this->view->form        = $renderer->toObject();
+        $this->template->compile($this->formTemplate);
+    }
+
+    //    }}}
+
+    //  {{{ validNewImg()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param array $newImg Parameter description (if any) ...
+     *
+     * @return mixed  Return description (if any) ...
+     * @access public
+     */
+    function validNewImg(array $newImg)
+    {
+        return (is_numeric($newImg['size']) &&
+                $newImg['size'] > 0 &&
+                in_array($newImg['type'], $this->mimeTypes));
+    }
+
+    //  }}}
+    //  {{{ removeOldImage()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server $is     Parameter description (if any) ...
+     * @param string               $oldImg Parameter description (if any) ...
+     *
+     * @return void
+     * @access public
+     */
+    function removeOldImage(Toolkit_Image_Server $is, $oldImg)
+    {
+        $this->deleteImage($is, $oldImg);
+        if ($this->elementExists('curr_image_rmv')) {
+            $e =& $this->getElement('curr_image_rmv');
+            $e->setValue(null);
+            $this->_submitValues['curr_image_rmv'] = null;
+        }
+    }
+
+    //  }}}
+    //  {{{ syncCurrImage()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @return void
+     * @access protected
+     */
+    protected function syncCurrImage()
+    {
+        $is = new Toolkit_Image_Server();
+
+        $delImg = $this->getSubmitValue('remove_img_rmv');
+        $oldImg = $this->getSubmitValue('curr_image_rmv');
+        $newImg = $this->getSubmitValue('image');
+
+        if ($delImg && $oldImg) {
+            $this->removeOldImage($is, $oldImg);
+            unset($oldImg);
+        } elseif ($oldImg && $this->validNewImg($newImg)) {
+            $this->removeOldImage($is, $oldImg);
+            unset($oldImg);
+        }
+
+        if ($this->validNewImg($newImg)) {
+            $image = $this->uploadImage($is, 'image');
+        } else {
+            $image = $oldImg;
+        }
+
+        if ($image) {
+            $this->updatePhotoElements($is, $image);
+            $this->showCurrImg = true;
+        }
+    }
+
+    //  }}}
+    //    {{{ toHtml()
+
+    /**
+     * Renders the form
+     *
+     * sets the page the form should be redirected to instead of coming back
+     * around to itself.
+     *
+     * @return string The rendered form
+     * @access public
+     */
+    public function toHtml()
+    {
+        //    We need to validate (and freeze if needed)
+        //    before we render the form. That way the
+        //    template knows about any errors on the form.
+        $this->validated = $this->validate();
+
+        //  If they have submitted the form and uploaded a proper image
+        //  but some other element had an error, then we need to show
+        //  their uploaded image in the form
+        if ($this->isSubmitted()) {
+            $this->syncCurrImage();
+        }
+
+        $this->setupRenderers();
+
+        if ($this->validated) {
+            $processed = $this->process(
+                array(&$this, 'processData'),
+                $this->mergeFiles
+            );
+        }
+
+        return $this->template->bufferedOutputObject($this->view);
+    }
+
+    //    }}}
+
+    //  {{{ updatePhotoElements()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server $is    Parameter description (if any) ...
+     * @param string               $image Parameter description (if any) ...
+     *
+     * @return void
+     * @access public
+     */
+    public function updatePhotoElements(Toolkit_Image_Server $is, $image)
+    {
+        //  Get the dimensions of the image
+        $dimensions = $is->getImageSize(MEMBER_PHOTOS . $image);
+        if (PEAR::isError($dimensions)) {
+            Toolkit_Common::handleError($dimensions);
+        }
+        list($w, $h) = $dimensions;
+        $s = MEMBER_PHOTOS . $image;
+
+        //  Set the image to show in the element
+        $e =& $this->getElement('curr_image');
+        $e->setText('<img width="'.$w.'" height="'.$h.'" src="'.$s.'">');
+
+        //  updated the hidden elements value to make sure it
+        //  holds the most up-to-date image name
+        $e =& $this->getElement('curr_image_rmv');
+        $e->setValue($image);
+    }
+
+    //  }}}
+    //  {{{ uploadImage()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server  $is    Parameter description (if any) ...
+     * @param string                $field Form field name of image
+     *
+     * @return string image name
+     * @access protected
+     */
+    protected function uploadImage(Toolkit_Image_Server $is, $field)
+    {
+        return $is->imageUpload($field);
+    }
+
+    //  }}}
+}
+
+/**
+ * Form to handle editing/deleting existing packages in members only area
+ *
+ * Handles updating caption requests for a member or to remove a
+ * package from thier profile
+ *
+ * @category  MembersDB
+ * @package   Toolkit_Members
+ * @author    Jamie Kahgee <steve@gaslightmedia.com>
+ * @copyright 2009 Jamie Kahgee
+ * @license   http://www.gaslightmedia.com Gaslightmedia
+ * @link      <>
+ * @see       Toolkit_FormBuilder
+ */
+class EditCourse extends Toolkit_FormBuilder
+{
+    //    {{{ properties
+
+    /**
+     * The table name in the database used to store the data
+     *
+     * @var string
+     * @access public
+     */
+    public $tableName = 'member_packages';
+
+    /**
+     * The template used to render the form
+     *
+     * @var string
+     * @access protected
+     */
+    protected $formTemplate = 'editCourse.tpl';
+
+    /**
+     * The name of the template used to email the owner for any updates
+     *
+     * When a member makes an update to thier record, this is the template
+     * we will use to send out the email notification to the site owner.
+     *
+     * @var string
+     * @access protected
+     */
+    protected $emailTemplate = 'emailOwner.tpl';
+
+    /**
+     * Id of package in db
+     * @var    integer
+     * @access protected
+     */
+    protected $packageId;
+
+    /**
+     * Description for protected
+     * @var    string
+     * @access protected
+     */
+    protected $successMsg
+        = '<div id="form-success-top">
+            You successfully updated your package.
+          </div>';
+
+    /**
+     * Any rules we want to register for this form
+     * @var    array
+     * @access protected
+     */
+    protected $registeredRules = array();
+
+    /**
+     * Description for protected
+     * @var    array
+     * @access protected
+     */
+    protected $mimeTypes = array(
+        'image/jpe',
+        'image/jpeg',
+        'image/jpg',
+        'image/jfif',
+        'image/pjpeg',
+        'image/pjp',
+        'image/gif',
+        'image/png',
+    );
+
+    //    }}}
+    //    {{{ __construct()
+
+    /**
+     * Class constructor
+     *
+     * @param PDO    $pdo         PHP Data Object to use for DB calls
+     * @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
+     * @see    Toolkit_Members_Admin_EditCourses
+     */
+    public function __construct(
+        PDO $pdo,
+        $formName,
+        $method = 'post',
+        $action = '',
+        $target = '',
+        $attributes = null,
+        $trackSubmit = false
+    ) {
+        parent::__construct(
+            $formName,
+            $method,
+            $action,
+            $target,
+            $attributes,
+            $trackSubmit
+        );
+
+        $this->packageId = $attributes['id'];
+        $id = $GLOBALS['memberAuth']->getAuthData('member_id');
+        $this->packages  = new Toolkit_Members_Courses(null, $id);
+        $this->packages->setDbh($pdo);
+        $this->packages->createMemberList();
+        $this->dbh = $pdo;
+    }
+
+    //    }}}
+
+    //  {{{ configureForm()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @return void
+     * @access public
+     */
+    public function configureForm()
+    {
+        $this->configureElements();
+        $this->configureDefaults();
+        $this->configureFilters();
+        $this->configureRules();
+    }
+
+    //  }}}
+    //    {{{ configureDefaults()
+
+    /**
+     * Setup the element default values for form
+     *
+     * @access public
+     * @see    Toolkit_FormBuilder::setupDefaults()
+     * @return void
+     */
+    public function configureDefaults()
+    {
+        $sql = "
+            SELECT *
+              FROM {$this->tableName}
+             WHERE id = {$this->packageId}";
+
+        $defaults = $this->dbh->query($sql)->fetch(PDO::FETCH_ASSOC);
+        $defaults['curr_image_rmv'] = $defaults['image'];
+        $img = '<img src="%s">';
+        $defaults['curr_image'] = sprintf($img, MEMBER_PHOTOS . $defaults['image']);
+
+            //    Get any updates for that photo that are still in
+            //    a pending status.
+            $sql = "
+                SELECT *
+                  FROM member_updates
+                 WHERE id in (
+                    SELECT max(id)
+                      FROM member_updates
+                     WHERE foreign_key = :foreign_key
+                       AND db_table = 'member_packages'
+                     GROUP BY field)";
+
+            $stmt = $this->dbh->prepare($sql);
+            $stmt->execute(array($this->packageId));
+        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
+            if ($row['field'] == 'title') {
+                $defaults['title'] = $row['update'];
+            } elseif ($row['field'] == 'description') {
+                $defaults['description'] = $row['update'];
+            }
+        }
+
+        $this->showCurrImg = $defaults['image'];
+        $this->setupDefaults($defaults);
+    }
+
+    //    }}}
+    //    {{{ configureElements()
+
+    /**
+     * Setup the elements to use on the form.
+     *
+     * @access public
+     * @see    Toolkit_FormBuilder::setupElements()
+     * @return void
+     */
+    public function configureElements()
+    {
+        $e = array();
+        //    All Grouped Elements are created here.
+
+        //    All Elements are created here.  This includes group element definitions.
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'title',
+            'display' => 'Course Title',
+        );
+        $e[] = array(
+            'type'        => 'textarea',
+            'req'         => false,
+            'name'        => 'description',
+            'display'     => 'Course Description',
+            'opts'        => array('id' => 'descr' . $this->packageId, 'class' => 'ckeditor'),
+            'noCharLimit' => true
+        );
+        $e[] = array(
+            'type'    => 'date',
+            'req'     => true,
+            'name'    => 'sdate',
+            'display' => 'Start Date',
+            'opts'    => array(
+                'format'           => 'm / d / Y',
+                'minYear'          => date('Y'),
+                'maxYear'          => date('Y') + 10,
+                'addEmptyOption'   => true,
+                'emptyOptionValue' => '',
+                'emptyOptionText'  => array(
+                    'm' => 'mm',
+                    'd' => 'dd',
+                    'Y' => 'yyyy',
+                ),
+            )
+        );
+        $e[] = array(
+            'type'    => 'date',
+            'req'     => true,
+            'name'    => 'edate',
+            'display' => 'End Date',
+            'opts'    => array(
+                'format'           => 'm / d / Y',
+                'minYear'          => date('Y'),
+                'maxYear'          => date('Y') + 10,
+                'addEmptyOption'   => true,
+                'emptyOptionValue' => '',
+                'emptyOptionText'  => array(
+                    'm' => 'mm',
+                    'd' => 'dd',
+                    'Y' => 'yyyy',
+                ),
+            )
+        );
+        $e[] = array(
+            'type'    => 'checkbox',
+            'req'     => false,
+            'name'    => 'remove_img_rmv',
+            'display' => 'Remove Image',
+        );
+        $e[] = array(
+            'type'    => 'static',
+            'req'     => false,
+            'name'    => 'curr_image',
+            'display' => 'Current Image',
+        );
+        $e[] = array(
+            'type'    => 'hidden',
+            'req'     => false,
+            'name'    => 'curr_image_rmv',
+        );
+        $e[] = array(
+            'type'    => 'file',
+            'req'     => false,
+            'name'    => 'image',
+            'display' => 'Upload a Course Photo / Image',
+        );
+        $e[] = array(
+            'type'    => 'submit',
+            'req'     => false,
+            'name'    => 'add_rmv',
+            'display' => 'Update Course',
+            'opts'    => array('class' => 'submit')
+        );
+        $e[] = array(
+            'type'    => 'submit',
+            'req'     => false,
+            'name'    => 'remove_rmv',
+            'display' => 'Remove Course',
+            'opts'    => array('class' => 'submit')
+        );
+
+        $this->setupElements($e);
+    }
+
+    //    }}}
+    //    {{{ configureRules()
+
+    /**
+     * Configure rules for form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureRules()
+    {
+        $r = array();
+
+        $checkDate = create_function('$d', '$d = implode("-", $d); return Validate::date($d, array("format" => "%n-%j-%Y"));');
+        $r[] = array(
+            'element'    => 'sdate',
+            'message'    => 'ERROR: Invalid Date!',
+            'type'       => 'callback',
+            'format'     => $checkDate,
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+        $r[] = array(
+            'element'    => 'edate',
+            'message'    => 'ERROR: Invalid Date!',
+            'type'       => 'callback',
+            'format'     => $checkDate,
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+        $r[] = array(
+            'element'    => 'image',
+            'message'    => 'ERROR: Incorrect File Type (.gif, .png, .jpg) only!',
+            'type'       => 'mimetype',
+            'format'     => $this->mimeTypes,
+            'validation' => $this->validationType,
+            'reset'      => false,
+            'force'      => false
+        );
+
+        $this->setupRules($r);
+    }
+
+    //    }}}
+    //    {{{ configureConstants()
+
+    /**
+     * Configure constants for form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureConstants()
+    {
+        $c = array(
+            'remove_img_rmv' => false
+        );
+
+        $this->setupConstants($c);
+    }
+
+    //    }}}
+    //    {{{ configureFilters()
+
+    /**
+     * Configure filters for form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureFilters()
+    {
+        $f = array();
+
+        $f[] = array(
+            'element' => '__ALL__',
+            'filter' => 'trim'
+        );
+
+        $this->setupFilters($f);
+    }
+
+    //    }}}
+
+    //  {{{ deleteImage()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server $is  Parameter description (if any) ...
+     * @param string               $img Parameter description (if any) ...
+     *
+     * @return unknown Return description (if any) ...
+     * @access protected
+     */
+    protected function deleteImage(Toolkit_Image_Server $is, $img)
+    {
+        return $is->imageDelete($img);
+    }
+
+    //  }}}
+
+    //    {{{    _createPendingData()
+
+    /**
+     * Description for _createPendingData()
+     *
+     * @param array $values Value array
+     *
+     * @return void|mixed only on error
+     * @access private
+     */
+    private function _createPendingData($values)
+    {
+        try {
+            $sql = "
+                INSERT INTO member_updates
+                    (field, update, db_table, data_type, label,
+                     foreign_key, member_id, field_type)
+                VALUES (:field, :update, :db_table, :data_type, :label,
+                        :foreign_key, :member_id, :field_type)";
+
+            $dataToInsert = array();
+            if ($values['title'] != $this->_defaultValues['title']) {
+                $dataToInsert[] = array(
+                     'field' => 'title',
+                     'update' => $values['title'],
+                     'label' => 'Title'
+                );
+            }
+
+            if ($values['description'] != $this->_defaultValues['description']) {
+                $dataToInsert[] = array(
+                        'field' => 'description',
+                        'update' => $values['description'],
+                        'label' => 'Description'
+                );
+            }
+            /*if ($values['image'] != $this->_defaultValues['image']) {
+                $dataToInsert[] = array(
+                        'field' => 'image',
+                        'update' => $values['image'],
+                        'label' => 'Image'
+                );
+            }*/
+            $stmt = $this->dbh->prepare($sql);
+            $stmt->bindValue(':db_table', 'member_packages', PDO::PARAM_STR);
+            $stmt->bindValue(':data_type', 'text', PDO::PARAM_STR);
+            $stmt->bindValue(':field_type', 'text', PDO::PARAM_STR);
+            $stmt->bindParam(':foreign_key', $values['id'], PDO::PARAM_INT);
+            $stmt->bindParam(':member_id', $values['member_id'], PDO::PARAM_INT);
+
+            foreach ($dataToInsert as $i) {
+                if (!empty($i['update'])) {
+                    $stmt->bindParam(':field', $i['field'], PDO::PARAM_STR);
+                    $stmt->bindParam(':update', $i['update'], PDO::PARAM_STR);
+                    $stmt->bindParam(':label', $i['label'], PDO::PARAM_STR);
+                    $stmt->execute();
+                }
+            }
+        } catch (PDOException $e) {
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+    //    }}}
+
+
+    //  {{{ emailOwner()
+
+    /**
+     * Emails the owner and anyone else who wants to be advised of updates
+     *
+     * A false value in the primaryAdvisee will cause no email to be sent.
+     * all secondary advisees listed in the constructor are carbon copied
+     * in the email.
+     *
+     * Emails are sent out in both HTML and TXT forms.
+     *
+     * @return boolean result of email
+     * @access protected
+     */
+    protected function emailOwner()
+    {
+        if (MEMBER_RECORD_UPDATES_ADVISOR === false) {
+            return;
+        } else {
+            $this->flexyOptions = Toolkit_Members::getFlexyOptions();
+            $id = $GLOBALS['memberAuth']->getAuthData('member_id');
+            try {
+                $sql = "
+                    SELECT member_name
+                      FROM member
+                     WHERE member_id = :member_id";
+                $stmt = $this->dbh->prepare($sql);
+                $stmt->bindParam(':member_id', $id, PDO::PARAM_INT);
+                $stmt->execute();
+                $row = $stmt->fetch(PDO::FETCH_ASSOC);
+                $memberName = $row['member_name'];
+            } catch (PDOException $e) {
+                return Toolkit_Common::handleError($e);
+            }
+            $template = new HTML_Template_Flexy($this->flexyOptions);
+            $page = new stdClass();
+            $page->member = $memberName;
+            $page->url = ($_SERVER['HTTPS'] == 'on') ? BASE_SECURE_URL : MEDIA_BASE_URL;
+            $page->email = OWNER_EMAIL;
+            $page->siteName = SITENAME;
+            $page->link = '<a target="_blank"  href="'.MEDIA_BASE_URL.'pending-member/'.$id.'/">link</a>';
+
+            $template->compile($this->emailTemplate);
+            //  Merge the compiled template with the $page object.
+            $htmlMsg = $template->bufferedOutputObject($page);
+
+            $msg = "
+                <h3>$memberName</h3>
+                <p>
+                    Has updated thier business record and is now in a pending
+                    state. To approve / reject thier changes you can either log
+                    into your {$page->siteName} admin area or follow this
+                    {$page->link}
+                </p>";
+            $crlf = "\n";
+            $mimeMail = new Mail_mime($crlf);
+            $from = preg_replace("/[^A-Za-z ]/", "", SITENAME) . ' <' . OWNER_EMAIL . '>';
+            $mimeMail->setFrom($from);
+            $mimeMail->setSubject('Member Record Update');
+            $mimeMail->setHTMLBody($htmlMsg);
+            $mimeMail->setTXTBody($msg);
+
+            $mail =& Mail::factory('mail');
+            $body = $mimeMail->get();
+            $headers = $mimeMail->headers($hdrs);
+
+            $res = $mail->send(MEMBER_RECORD_UPDATES_ADVISOR, $headers, $body);
+            if (PEAR::isError($res)) {
+                return Toolkit_Common::handleError($res);
+            } else {
+                return $res;
+            }
+        }
+    }
+
+    //  }}}
+    //    {{{ processData()
+
+    /**
+     * Handles setting up the from processing and which function to get it done
+     *
+     * @param array $values Submitted values from the form.
+     *
+     * @return void
+     * @access protected
+     */
+    protected function processData($values)
+    {
+        $id = $GLOBALS['memberAuth']->getAuthData('member_id');
+        $cache = new Cache_Lite(Toolkit_Members::getCacheOptions());
+        $cache->remove("Member-$id", 'Profile');
+
+        $e =& $this->getElement('curr_image_rmv');
+
+        $values['image'] = $e->getValue('curr_image_rmv');
+        $values['sdate'] = implode('-', $values['sdate']);
+        $values['edate'] = implode('-', $values['edate']);
+        unset($values['MAX_FILE_SIZE'],
+              $values['curr_image_rmv'],
+              $values['remove_img_rmv'],
+              $values['add_rmv']);
+
+        $this->tableMetaData = Toolkit_Common::getTableMetaData(
+            $this->dbh,
+            $this->tableName
+        );
+        $this->updateData($values);
+        if (   $values['title'] != $this->_defaultValues['title']
+            || $values['description'] != $this->_defaultValues['description']
+        ) {
+            $this->emailOwner();
+        }
+
+        $listPage = MEDIA_BASE_URL .
+            "members-only-area/?rt=EditProfile&tab=packages";
+        header("Location: $listPage");
+    }
+
+    //    }}}
+
+    //    {{{ setupRenderers()
+
+    /**
+     * Set up the rendering engine we are going to use to display this form
+     *
+     * @return void
+     * @access protected
+     */
+    protected function setupRenderers()
+    {
+        $fo = Toolkit_Members::getFlexyOptions();
+
+        $this->template = new HTML_Template_Flexy($fo);
+
+        $renderer = new HTML_QuickForm_Renderer_ObjectFlexy($this->template);
+
+        $this->accept($renderer);
+        $this->view              = new StdClass;
+        $this->view->showCurrImg = $this->showCurrImg;
+        $this->view->form        = $renderer->toObject();
+        $this->template->compile($this->formTemplate);
+    }
+
+    //    }}}
+
+    //  {{{ validNewImg()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param array $newImg Parameter description (if any) ...
+     *
+     * @return mixed  Return description (if any) ...
+     * @access public
+     */
+    function validNewImg(array $newImg)
+    {
+        return (is_numeric($newImg['size']) &&
+                $newImg['size'] > 0 &&
+                in_array($newImg['type'], $this->mimeTypes));
+    }
+
+    //  }}}
+    //  {{{ removeOldImage()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server $is     Parameter description (if any) ...
+     * @param string               $oldImg Parameter description (if any) ...
+     *
+     * @return void
+     * @access public
+     */
+    function removeOldImage(Toolkit_Image_Server $is, $oldImg)
+    {
+        $this->deleteImage($is, $oldImg);
+        if ($this->elementExists('curr_image_rmv')) {
+            $e =& $this->getElement('curr_image_rmv');
+            $e->setValue(null);
+            $this->_submitValues['curr_image_rmv'] = null;
+        }
+    }
+
+    //  }}}
+    //  {{{ syncCurrImage()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @return void
+     * @access protected
+     */
+    protected function syncCurrImage()
+    {
+        $is = new Toolkit_Image_Server();
+
+        $delImg = $this->getSubmitValue('remove_img_rmv');
+        $oldImg = $this->getSubmitValue('curr_image_rmv');
+        $newImg = $this->getSubmitValue('image');
+
+        if ($delImg && $oldImg) {
+            $this->removeOldImage($is, $oldImg);
+            unset($oldImg);
+        } elseif ($oldImg && $this->validNewImg($newImg)) {
+            $this->removeOldImage($is, $oldImg);
+            unset($oldImg);
+        }
+
+        if ($this->validNewImg($newImg)) {
+            $image = $this->uploadImage($is, 'image');
+        } else {
+            $image = $oldImg;
+        }
+
+        if ($image) {
+            $this->updatePhotoElements($is, $image);
+            $this->showCurrImg = true;
+        }
+    }
+
+    //  }}}
+
+    //    {{{ toHtml()
+
+    /**
+     * Renders the form
+     *
+     * sets the page the form should be redirected to instead of coming back
+     * around to itself.
+     *
+     * @return string The rendered form
+     * @access public
+     */
+    public function toHtml()
+    {
+        //    We need to validate (and freeze if needed)
+        //    before we render the form. That way the
+        //    template knows about any errors on the form.
+        $this->validated = $this->validate();
+
+        //  If they have submitted the form and uploaded a proper image
+        //  but some other element had an error, then we need to show
+        //  their uploaded image in the form
+        if ($this->isSubmitted()) {
+            $this->syncCurrImage();
+        }
+
+        $this->setupRenderers();
+
+        if ($this->validated) {
+            $processed = $this->process(
+                array(&$this, 'processData'),
+                $this->mergeFiles
+            );
+        }
+
+        return $this->template->bufferedOutputObject($this->view);
+    }
+
+    //    }}}
+
+    //    {{{    removeCourse()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param integer $id Member ID
+     *
+     * @return object    Return description (if any) ...
+     * @access protected
+     */
+    protected function removeCourse($id)
+    {
+        try {
+            $this->dbh->beginTransaction();
+            //  need to delete the image associated w/ this package here.
+            $sql = "
+                DELETE FROM {$this->tableName}
+                 WHERE id           = :id
+                   AND member_id    = :mid";
+
+            $stmt = $this->dbh->prepare($sql);
+            $stmt->bindParam(':id', $id, PDO::PARAM_INT);
+            $stmt->bindparam(
+                ':mid',
+                $GLOBALS['memberAuth']->getAuthData('member_id'),
+                PDO::PARAM_INT
+            );
+
+            $stmt->execute();
+
+            $sql = "
+                DELETE FROM member_updates
+                 WHERE db_table = '{$this->tableName}'
+                   AND member_id = :mid
+                   AND foreign_key = :id";
+
+            $stmt = $this->dbh->prepare($sql);
+            $stmt->bindParam(':id', $id, PDO::PARAM_INT);
+            $stmt->bindparam(
+                ':mid',
+                $GLOBALS['memberAuth']->getAuthData('member_id'),
+                PDO::PARAM_INT
+            );
+            $stmt->execute();
+            return $this->dbh->commit();
+        } catch (PDOException $e) {
+            $this->dbh->rollback();
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+    //    }}}
+
+    //    {{{ updateData()
+
+    /**
+     * Update the package caption
+     *
+     * @param array $values Submitted form values
+     *
+     * @return boolean Result of updating the caption in the db
+     * @access public
+     */
+    protected function updateData($values)
+    {
+        try {
+            if (array_key_exists('remove_rmv', $values)) {
+                return $this->removeCourse($this->packageId);
+            }
+            $this->dbh->beginTransaction();
+
+            $pending = $values;
+            $pending['member_id'] = $GLOBALS['memberAuth']->getAuthData('member_id');
+            unset($pending['sdate'], $pending['edate']);
+            unset($values['title'], $values['description']);
+            $sql = Toolkit_Common::createSQLUpdate(
+                $this->tableName,
+                array_keys($values),
+                array('id = :id')
+            );
+
+            //$values['id'] = $this->packageId;
+            $pending['id'] = $values['id'] = $this->packageId;
+            $res = Toolkit_Common::processQuery(
+                $this->dbh,
+                $this->tableName,
+                $sql,
+                $values
+            );
+
+            $this->_createPendingData($pending);
+
+            $this->dbh->commit();
+            return $res;
+        } catch (PDOException $e) {
+            $this->dbh->rollback();
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+    //    }}}
+    //  {{{ updatePhotoElements()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server $is    Parameter description (if any) ...
+     * @param string               $image Parameter description (if any) ...
+     *
+     * @return void
+     * @access public
+     */
+    public function updatePhotoElements(Toolkit_Image_Server $is, $image)
+    {
+        //  Get the dimensions of the image
+        $dimensions = $is->getImageSize(MEMBER_PHOTOS . $image);
+        if (PEAR::isError($dimensions)) {
+            Toolkit_Common::handleError($dimensions);
+        }
+        list($w, $h) = $dimensions;
+        $s = MEMBER_PHOTOS . $image;
+
+        //  Set the image to show in the element
+        $e =& $this->getElement('curr_image');
+        $e->setText('<img width="'.$w.'" height="'.$h.'" src="'.$s.'">');
+
+        //  updated the hidden elements value to make sure it
+        //  holds the most up-to-date image name
+        $e =& $this->getElement('curr_image_rmv');
+        $e->setValue($image);
+    }
+
+    //  }}}
+    //  {{{ uploadImage()
+
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param Toolkit_Image_Server  $is    Parameter description (if any) ...
+     * @param string                $field Parameter description (if any) ...
+     *
+     * @return string    Return description (if any) ...
+     * @access protected
+     */
+    protected function uploadImage(Toolkit_Image_Server $is, $field)
+    {
+        return $is->imageUpload($field);
+    }
+
+    //  }}}
+}
+?>
diff --git a/Toolkit/Members/EditMemberCourseProfile.php b/Toolkit/Members/EditMemberCourseProfile.php
new file mode 100644 (file)
index 0000000..78d693a
--- /dev/null
@@ -0,0 +1,343 @@
+<?php
+//  vim:set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker syntax=php:
+
+/**
+ * File Doc Comment
+ *
+ * PHP version 5
+ *
+ * @category MembersDB
+ * @package  Toolkit_Members
+ * @author   Jamie Kahgee <jamie.kahgee@gmail.com>
+ * @license  http://www.gaslightmedia.com Gaslightmedia
+ * @version  CVS: $Id: EditMemberAmenities.php,v 1.11 2009/11/16 12:11:39 jamie Exp $
+ * @link     http://demo.gaslightmedia.com
+ */
+
+/**
+ * Short description for class
+ *
+ * Long description (if any) ...
+ *
+ * @category  MembersDB
+ * @package   Toolkit_Members
+ * @author    Jamie Kahgee <jamie.kahgee@gmail.com>
+ * @copyright 2009 Jamie Kahgee
+ * @license   http://www.gaslightmedia.com Gaslightmedia
+ * @link      http://demo.gaslightmedia.com
+ */
+class Toolkit_Members_EditMemberCourseProfile
+    extends Toolkit_Members_EditMemberInfo
+    implements Toolkit_Form
+{
+    //  {{{ properties
+
+    /**
+     * The Table name used to store the data of the member record in the database.
+     *
+     * @var string
+     * @access public
+     */
+    public $tableName = 'member_amenity';
+
+    /**
+     * The name of the template used to render the business info form.
+     *
+     * @var string
+     * @access protected
+     */
+    protected $formTemplate = 'editCourseProfile.tpl';
+
+    //  }}}
+    //  {{{ __construct()
+
+    /**
+     * Class constructor
+     *
+     * @param PDO    $pdo         PHP Data Object to use for DB calls
+     * @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
+     * @see    Toolkit_Members_EditMemberInfo
+     */
+    public function __construct(
+        PDO $pdo,
+        $formName,
+        $method = 'post',
+        $action = '',
+        $target = '',
+        $attributes = null,
+        $trackSubmit = false
+    ) {
+        parent::__construct(
+            $pdo,
+            $formName,
+            $method,
+            $action,
+            $target,
+            $attributes,
+            $trackSubmit
+        );
+    }
+
+    //  }}}
+
+    //  {{{ configureDefaults()
+
+    /**
+     * Sets the defaults for elements in the form.
+     *
+     * @return array form element default values
+     * @access public
+     */
+    public function configureDefaults()
+    {
+        try {
+            $sql = "
+              SELECT *
+                FROM {$this->tableName}
+               WHERE member_id = :id ";
+            $stmt = $this->dbh->prepare($sql);
+            $stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT);
+            $stmt->execute();
+
+            while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
+                $defaults[$row['amenity_id']] = true;
+            }
+            $this->setupDefaults($defaults);
+            return $defaults;
+        } catch (PDOException $e) {
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+    //  }}}
+    //  {{{ configureElements()
+
+    /**
+     * Setup the element definitions to use on the form.
+     *
+     * @return void
+     * @access public
+     */
+    public function configureElements()
+    {
+        //  Element definitions
+        $e = array();
+        $amenities = $this->getAmenities();
+        $half = floor(count($amenities) / 2);
+        $i = 0;
+        //  All Grouped Elements are created here.
+
+        //  All Elements are created here.  This includes group element definitions.
+        $e[] = array(
+            'type' => 'header',
+            'req' => false,
+            'name' => 'GolfingHdr',
+            'display' => 'Golf Course Information',
+            'col2' => true
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'res_url',
+            'display' => 'TeeTime URL',
+            'opts'    => array('class' => 'text'),
+            'noCharLimit' => true
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'par',
+            'display' => 'Par',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'yardage',
+            'display' => 'Yardage',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'course_rating',
+            'display' => 'Course Rating',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'slope_rating',
+            'display' => 'Slope Rating',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'advcheckbox',
+            'req'     => false,
+            'name'    => 'walking_course',
+            'display' => 'Walking Course',
+            'val'     => array(0, 1)
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'holes18',
+            'display' => '18 Holes',
+            'opts'    => array('class' => 'text')
+        );
+        $e[] = array(
+            'type'    => 'text',
+            'req'     => false,
+            'name'    => 'holes9',
+            'display' => '9 Holes',
+            'opts'    => array('class' => 'text')
+        );
+
+        $this->setupElements($e);
+    }
+
+    //  }}}
+    //  {{{ configureForm()
+
+    /**
+     * Wrapper function to handle setting up the form
+     *
+     * @return void
+     * @access public
+     */
+    public function configureForm()
+    {
+        $this->configureElements();
+        $this->configureRules();
+        $this->configureDefaults();
+    }
+
+    //  }}}
+    //  {{{ configureRules()
+
+    /**
+     * Sets up all the rules to be used when the form is validated.
+     *
+     * @return void
+     * @access public
+     */
+    public function configureRules()
+    {
+        $this->setupRules();
+    }
+
+    //  }}}
+
+    //  {{{ getAmenities()
+
+    /**
+     * Gets all the amentities
+     *
+     * @return $a array The array of amenities from the DB.
+     * @access protected
+     */
+    protected function getAmenities()
+    {
+        $a = array();
+        try {
+            $sql = "
+                SELECT *
+                  FROM amenity
+                 ORDER BY amenity_name";
+            foreach ($this->dbh->query($sql) as $row) {
+                $a[] = $row;
+            }
+        } catch (PDOException $e) {
+            $this->handleError($e);
+        }
+        return $a;
+    }
+
+    //  }}}
+
+    //  {{{ insertData()
+
+    /**
+     * Create a new record in the database from the data on the form
+     *
+     * @param array $values Form values
+     *
+     * @return boolean False on error, True otherwise.
+     * @access public
+     */
+    public function insertData($values)
+    {
+        try {
+            $sql = "
+                DELETE FROM {$this->tableName}
+                 WHERE member_id = :id";
+            $stmt = $this->dbh->prepare($sql);
+            $stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT);
+            $stmt->execute();
+
+            $params = implode(', ', array_keys($values));
+            $bindParams = ':' . implode(', :', array_keys($values));
+            $sql = "
+                INSERT INTO {$this->tableName} (member_id, amenity_id)
+                VALUES (:member_id, :aid)";
+            $stmt = $this->dbh->prepare($sql);
+            $stmt->bindParam(':member_id', $_GET['id'], PDO::PARAM_INT);
+            foreach ($values as $k => $v) {
+                $stmt->bindParam(':aid', $k, PDO::PARAM_INT);
+                $stmt->execute();
+            }
+
+            $cache = new Cache_Lite(Toolkit_Members::getCacheOptions());
+            $cache->remove("Member-{$_GET['id']}", 'Profile');
+
+            return true;
+        } catch (PDOException $e) {
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+    //  }}}
+
+    //  {{{ processData()
+
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param array $values Parameter description (if any) ...
+     *
+     * @return array     Return description (if any) ...
+     * @access public
+     */
+    public function processData($values)
+    {
+        $this->tableMetaData = Toolkit_Common::getTableMetaData(
+            $this->dbh,
+            $this->tableName
+        );
+
+        foreach ($values as $k => $v) {
+            switch ($k) {
+            default :
+                if (preg_match('/^.+_rmv$/', $k)) {
+                    unset($values[$k]);
+                }
+                break;
+            }
+        }
+
+        return $this->insertData($values);
+    }
+
+    //  }}}
+}
+?>
index 83d9af3..defce70 100644 (file)
@@ -651,6 +651,7 @@ class Toolkit_Members_EditMemberInfo
         $c = array(
             'member_cats[]' => '',
             'remove_logo_rmv' => 0,
+            'remove_logo2_rmv' => 0,
         );
 
         $this->setupConstants($c);
@@ -691,6 +692,12 @@ class Toolkit_Members_EditMemberInfo
                             $v = '<img src="'.MEMBER_PHOTOS.$v.'"
                                         alt="'.$v.'">';
                         }
+                        if ($k == 'logo2') {
+                            $defaults['old_logo2_rmv'] = $v;
+                            $k = 'image2_rmv';
+                            $v = '<img src="'.MEMBER_PHOTOS.$v.'"
+                                        alt="'.$v.'">';
+                        }
                         $defaults[$k] = $v;
                     }
                 }
@@ -1139,6 +1146,44 @@ class Toolkit_Members_EditMemberInfo
             'opts'    => array('class' => 'file')
         );
 
+        //  }}}
+//  //  {{{ Member Logo2
+
+        $e[] = array(
+            'type'    => 'header',
+            'req'     => false,
+            'name'    => 'logo2Hdr',
+            'display' => "$singularType Logo",
+            'col2'    => true
+        );
+        if ($this->hasLogo2()) {
+            $e[] = array(
+                'type'    => 'checkbox',
+                'req'     => false,
+                'name'    => 'remove_logo2_rmv',
+                'display' => 'Remove Logo'
+            );
+            $e[] = array(
+                'type'    => 'static',
+                'req'     => false,
+                'name'    => 'image2_rmv',
+                'display' => 'Current Logo'
+            );
+            $e[] = array(
+                'type' => 'hidden',
+                'req'  => false,
+                'name' => 'old_logo2_rmv'
+            );
+        }
+
+        $e[] = array(
+            'type'    => 'file',
+            'req'     => false,
+            'name'    => 'new_logo2_rmv',
+            'display' => 'New Logo',
+            'opts'    => array('class' => 'file')
+        );
+
         //  }}}
         //    {{{ Payment Type Accepted
 
@@ -2185,6 +2230,52 @@ class Toolkit_Members_EditMemberInfo
     }
 
     //    }}}
+    //  {{{ hasLogo()
+
+    /**
+     * Determine if the member record has a logo
+     *
+     * @return boolean if the record has a logo or not
+     * @access protected
+     */
+    protected function hasLogo2()
+    {
+        try {
+            $member_id = $_GET['id'];
+
+            $sql = "
+                SELECT logo2
+                  FROM {$this->tableName}
+                 WHERE member_id = :member_id";
+
+            $stmt = $this->dbh->prepare($sql);
+            $stmt->bindParam(':member_id', $member_id, PDO::PARAM_INT);
+            $stmt->execute();
+            $row = $stmt->fetch(PDO::FETCH_ASSOC);
+
+            if (get_class($this) === 'Toolkit_Members_EditMemberOnlyInfo') {
+                $sql = "
+                    SELECT count(*) AS total
+                      FROM {$this->pendingTable}
+                     WHERE member_id = :member_id
+                       AND field     = 'logo2'";
+
+                $stmt = $this->dbh->prepare($sql);
+                $stmt->bindParam(':member_id', $member_id, PDO::PARAM_INT);
+                $stmt->execute();
+                $pendingLogos = $stmt->fetch(PDO::FETCH_ASSOC);
+            }
+
+            $hasPending = !empty($pendingLogos['total']);
+            $hasLogo    = !is_null($row['logo2']);
+
+            return ($hasLogo || $hasPending);
+        } catch (PDOException $e) {
+            return Toolkit_Common::handleError($e);
+        }
+    }
+
+    //  }}}
 
     //    {{{ inColumn2()
 
@@ -2501,6 +2592,7 @@ class Toolkit_Members_EditMemberInfo
             }
         }
         $this->processLogo($values);
+        $this->processLogo2($values);
         $this->tableMetaData = Toolkit_Common::getTableMetaData(
             $this->dbh,
             $this->tableName
@@ -2653,6 +2745,127 @@ class Toolkit_Members_EditMemberInfo
     }
 
     //    }}}
+    /**
+     * Short description for function
+     *
+     * Long description (if any) ...
+     *
+     * @param array $values Parameter description (if any) ...
+     *
+     * @return object    Return description (if any) ...
+     * @access protected
+     */
+    protected function processLogo2(&$values)
+    {
+        //  Keep a tidy house.
+        //  There are 2 scenarios to deal w/ logos:
+        //  1.  Removing logo:
+        //      Delete the image from the image server
+        //      and set the values['logo'] to null.
+        //  2.  New logo:
+        //      Check to see if old_logo_rmv holds a value,
+        //      if it does then remove that logo
+        //      Upload the image and put new filename
+        //      into values['logo'] variable.
+        $imgServer  = new Toolkit_Image_Server();
+
+        if ($values['remove_logo2_rmv'] == 1) {
+            $imgServer->imageDelete($values['old_logo2_rmv']);
+            $values['logo2'] = null;
+
+            if (get_class($this) == 'Toolkit_Members_EditMemberOnlyInfo') {
+                try {
+                    //  Make sure any logos that were pending are removed as well.
+                    $sql = "
+                        DELETE FROM {$this->pendingTable}
+                         WHERE field        = 'logo2'
+                           AND member_id    = :member_id";
+                    $stmt = $this->dbh->prepare($sql);
+                    $stmt->bindParam(':member_id', $_GET['id'], PDO::PARAM_INT);
+                    $stmt->execute();
+
+                    $sql = "
+                        UPDATE {$this->tableName}
+                           SET logo2 = :logo2
+                         WHERE member_id = :member_id";
+                    $stmt = $this->dbh->prepare($sql);
+                    $stmt->bindParam(':logo2', $values['logo2'], PDO::PARAM_NULL);
+                    $stmt->bindParam(':member_id', $_GET['id'], PDO::PARAM_INT);
+                    $stmt->execute();
+                } catch (PDOException $e) {
+                    return Toolkit_Common::handleError($e);
+                }
+            }
+        }
+
+        //  If a new logo is uploaded, have the image server
+        //  process that logo and give us back the file name on
+        //  the server.
+        if ($values['new_logo2_rmv']['size'] > 0) {
+            $imgName = $imgServer->imageUpload('new_logo2_rmv');
+            $values['logo2'] = $imgName;
+            $img = '<img alt="'. $imgName . '" src="'.MEMBER_PHOTOS . $imgName.'">';
+
+            //  If the old_logo_rmv key is set and not empty
+            //  then we are replacing an existing logo and did not
+            //  check the remove logo checkbox.
+            //  remove this old logo just for good house keeping.
+            if (isset($values['old_logo2_rmv']) && !empty($values['old_logo2_rmv'])) {
+                $imgServer->imageDelete($values['old_logo2_rmv']);
+                //  update the elements on the form if we are replacing an existing logo.
+                if ($this->elementExists('old_logo2_rmv')) {
+                    $e =& $this->getElement('old_logo2_rmv');
+                    $e->setValue($imgName);
+                }
+                if ($this->elementExists('image2_rmv')) {
+                    $e =& $this->getElement('image2_rmv');
+                    $e->setValue($img);
+                }
+            } else {
+                $source =& $this->createElement(
+                    'checkbox',
+                    'remove_logo2_rmv',
+                    'Remove Logo'
+                );
+                $this->insertElementBefore($source, 'new_logo2_rmv');
+
+                $source =& $this->addElement('hidden', 'old_logo2_rmv');
+                $source->setValue($imgName);
+
+                $source =& $this->createElement(
+                    'static',
+                    'image_rmv',
+                    'Current Logo'
+                );
+                $source->setValue($img);
+                $element = $this->insertElementBefore($source, 'new_logo2_rmv');
+
+                if (PEAR::isError($element)) {
+                    die ('there was an error uploading your file!');
+                } else {
+                    //  I don't know why, but the insertElementBefore
+                    //  function was erasing the value we set earlier.
+                    //  so just reset it to make double sure its there.
+                    $element->setValue($img);
+                }
+            }
+        }
+
+        //  We clicked to remove the logo and did not upload a new one.
+        if ($values['remove_logo2_rmv'] == 1 && $values['new_logo2_rmv']['size'] == 0) {
+            if ($this->elementExists('remove_logo2_rmv')) {
+                $this->removeElement('remove_logo2_rmv', false);
+            }
+            if ($this->elementExists('image2_rmv')) {
+                $this->removeElement('image2_rmv', false);
+            }
+            if ($this->elementExists('old_logo2_rmv')) {
+                $this->removeElement('old_logo2_rmv', false);
+            }
+        }
+    }
+
+    //  }}}
 
     //    {{{ removeCategories()
 
index eca64a9..a6c0d8f 100644 (file)
@@ -152,6 +152,12 @@ class Toolkit_Members_EditMemberOnlyInfo
                                                src="'.MEMBER_PHOTOS.$row['update'].'">';
                                        $row['field'] = 'image_rmv';
                                }
+                if ($row['field'] == 'logo2') {
+                                       $this->oldData['old_logo2_rmv'] = $row['update'];
+                                       $row['update'] = '<img alt="'.$row['update'].'"
+                                               src="'.MEMBER_PHOTOS.$row['update'].'">';
+                                       $row['field'] = 'image2_rmv';
+                               }
                                $this->oldData[$row['field']] = $row['update'];
                        }
                        return $this->setupDefaults($this->oldData);
@@ -477,6 +483,44 @@ class Toolkit_Members_EditMemberOnlyInfo
                        'opts'    => array('class' => 'file')
                );
 
+        //  }}}
+        //  // {{{ Member Logo2
+
+               $e[] = array(
+                       'type'    => 'header',
+                       'req'     => false,
+                       'name'    => 'logo2Hdr',
+                       'display' => "$singularType Logo",
+                       'col2'    => true
+               );
+               if ($this->hasLogo2()) {
+                       $e[] = array(
+                               'type'    => 'checkbox',
+                               'req'     => false,
+                               'name'    => 'remove_logo2_rmv',
+                               'display' => 'Remove Logo'
+                       );
+                       $e[] = array(
+                               'type'    => 'static',
+                               'req'     => false,
+                               'name'    => 'image2_rmv',
+                               'display' => 'Current Logo'
+                       );
+            $e[] = array(
+                               'type' => 'hidden',
+                               'req'  => false,
+                               'name' => 'old_logo2_rmv'
+                       );
+               }
+
+               $e[] = array(
+                       'type'    => 'file',
+                       'req'     => false,
+                       'name'    => 'new_logo2_rmv',
+                       'display' => 'New Logo',
+                       'opts'    => array('class' => 'file')
+               );
+
         //  }}}
                //      {{{ Payment Type Accepted
 
@@ -887,6 +931,7 @@ class Toolkit_Members_EditMemberOnlyInfo
                        WHEN 'lat' THEN 'latitude'
                        WHEN 'lon' THEN 'longitude'
                        WHEN 'logo' THEN 'image_rmv'
+                       WHEN 'logo2' THEN 'image2_rmv'
                        ELSE field
                        END AS field
                   FROM {$this->pendingTable}
@@ -1156,6 +1201,17 @@ class Toolkit_Members_EditMemberOnlyInfo
                                        }
                                }
                        }
+            if ($k == 'logo2') {
+                               if (!empty($v)) {
+                                       if (array_key_exists('old_logo2_rmv', $this->oldData)) {
+                                               if ($v != $this->oldData['old_logo2_rmv']) {
+                                                       $recordUpdates[$k]['data_type'] = 'boolean';
+                                                       $recordUpdates[$k]['field_type'] = 'file';
+                                                       $recordUpdates[$k]['value'] = $v;
+                                               }
+                                       }
+                               }
+                       }
                }
 
                //      Combine the update arrays for the modules and the member record
index 102b9c3..2ce7c2b 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-//     vim:set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker syntax=php:
+//  vim:set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker syntax=php:
 
 /**
  * Navigation class for editing member records
@@ -9,7 +9,7 @@
  * @category MembersDB
  * @package  Toolkit_Members
  * @author   Jamie Kahgee <jamie.kahgee@gmail.com>
- * @license     http://www.gaslightmedia.com Gaslightmedia
+ * @license  http://www.gaslightmedia.com Gaslightmedia
  * @version  CVS: $Id: RecordNavigation.php,v 1.7 2010/07/14 23:31:14 jamie Exp $
  * @link     http://demo.gaslightmedia.com
  */
@@ -21,7 +21,7 @@
  * @package   Toolkit_Members
  * @author    Jamie Kahgee <jamie.kahgee@gmail.com>
  * @copyright 2008 Gaslight Media
- * @license      http://www.gaslightmedia.com Gaslightmedia
+ * @license   http://www.gaslightmedia.com Gaslightmedia
  * @link      http://demo.gaslightmedia.com
  */
 class Toolkit_Members_RecordNavigation
@@ -42,7 +42,7 @@ class Toolkit_Members_RecordNavigation
     }
 
     //  }}}
-       //      {{{     getPageNav()
+    //  {{{ getPageNav()
 
     /**
      * Render the page navigation that is defined in the navStructure
@@ -50,34 +50,34 @@ class Toolkit_Members_RecordNavigation
      * @return string Page navigation structure
      * @access public
      */
-       public function getPageNav()
-       {
-               $menu = new HTML_Menu($this->navStructure, 'rows');
+    public function getPageNav()
+    {
+        $menu = new HTML_Menu($this->navStructure, 'rows');
         $menu->forceCurrentIndex($_GET['tab']);
 
-               $renderer = new HTML_Menu_DirectRenderer($tpl);
-               $renderer->setEntryTemplate(
-                       HTML_MENU_ENTRY_INACTIVE,
-                       '<li><a href="{url}" title="{desc}">{title}</a></li>'
-               );
-               $renderer->setEntryTemplate(
-                       HTML_MENU_ENTRY_ACTIVE,
-                       '<li><a class="current" href="{url}" title="{desc}">{title}</a></li>'
-               );
-               $renderer->setEntryTemplate(
-                       HTML_MENU_ENTRY_ACTIVEPATH,
-                       '<li><a class="current" href="{url}" title="{desc}">{title}</a></li>'
-               );
-               $renderer->setMenuTemplate('', '');
-               $renderer->setRowTemplate('<ul>', '</ul>');
-
-               $menu->render($renderer);
-               return $renderer->toHtml();
-       }
-
-       //      }}}
-
-       //      {{{     setupAdminNavStructure()
+        $renderer = new HTML_Menu_DirectRenderer($tpl);
+        $renderer->setEntryTemplate(
+            HTML_MENU_ENTRY_INACTIVE,
+            '<li><a href="{url}" title="{desc}">{title}</a></li>'
+        );
+        $renderer->setEntryTemplate(
+            HTML_MENU_ENTRY_ACTIVE,
+            '<li><a class="current" href="{url}" title="{desc}">{title}</a></li>'
+        );
+        $renderer->setEntryTemplate(
+            HTML_MENU_ENTRY_ACTIVEPATH,
+            '<li><a class="current" href="{url}" title="{desc}">{title}</a></li>'
+        );
+        $renderer->setMenuTemplate('', '');
+        $renderer->setRowTemplate('<ul>', '</ul>');
+
+        $menu->render($renderer);
+        return $renderer->toHtml();
+    }
+
+    //  }}}
+
+    //  {{{ setupAdminNavStructure()
 
     /**
      * Sets up a multi dimensional array used for the subnav structure
@@ -85,20 +85,20 @@ class Toolkit_Members_RecordNavigation
      * @return mixed false on sql error. otherwise void
      * @access public
      */
-       public function setupAdminNavStructure()
-       {
+    public function setupAdminNavStructure()
+    {
         $singularType = $this->config
-                       ->getItem('section', 'listing type')
-                       ->getItem('directive', 'singular')
-                       ->getContent();
-               $pluralType = $this->config
-                       ->getItem('section', 'listing type')
-                       ->getItem('directive', 'plural')
-                       ->getContent();
+            ->getItem('section', 'listing type')
+            ->getItem('directive', 'singular')
+            ->getContent();
+        $pluralType = $this->config
+            ->getItem('section', 'listing type')
+            ->getItem('directive', 'plural')
+            ->getContent();
 
         //  Default URI parameters that will get us back to the
         //  page were we can edit member data.
-               $params = "rt=Members&amp;ac=editMember";
+        $params = "rt=Members&amp;ac=editMember";
 
         //  If we are editing an existing member, then we need to
         //  add their id into the URI so we know who we are editing
@@ -108,39 +108,44 @@ class Toolkit_Members_RecordNavigation
 
         //  We always show the member info tab.
         //  whether we are adding a member or editing a member
-               $nav = array(
-                       'info' => array(
-                               'title' => "$singularType Info",
-                               'url' => "/members.php?$params",
-                               'desc' => "View and edit $singularType in the database",
-                       )
+        $nav = array(
+            'info' => array(
+                'title' => "$singularType Info",
+                'url' => "/members.php?$params",
+                'desc' => "View and edit $singularType in the database",
+            )
         );
         if (is_numeric($_GET['id'])) {
             $nav['photos'] = array(
-                               'title' => 'Photos',
-                               'url' => "/members.php?$params",
-                               'desc' => "View and edit $pluralType in the database",
-                       );
+                'title' => 'Photos',
+                'url' => "/members.php?$params",
+                'desc' => "View and edit $pluralType in the database",
+            );
             $nav['packages'] = array(
-                               'title' => 'Packages',
-                               'url' => "/members.php?$params",
-                               'desc' => "View and edit $singularType categories",
-                       );
-                       $nav['amenities'] = array(
-                               'title' => 'Amenities',
-                               'url' => "/members.php?$params",
-                               'desc' => "View and edit $singularType amenities",
-                       );
-                       $nav['files'] = array(
-                               'title' => 'Files',
-                               'url' => "/members.php?$params",
-                               'desc' => "View and edit $singularType regions",
-                       );
-                       $nav['contacts'] = array(
-                               'title' => 'Contacts',
-                               'url' => "/members.php?$params",
-                               'desc' => "View and edit $singularType cities",
-                       );
+                'title' => 'Packages',
+                'url' => "/members.php?$params",
+                'desc' => "View and edit $singularType categories",
+            );
+            $nav['courses'] = array(
+                'title' => 'Course Profile',
+                'url'   => "/members.php?$params",
+                'desc'  => "View and edit $singularType Course Profile",
+            );
+            $nav['amenities'] = array(
+                'title' => 'Amenities',
+                'url' => "/members.php?$params",
+                'desc' => "View and edit $singularType amenities",
+            );
+            $nav['files'] = array(
+                'title' => 'Files',
+                'url' => "/members.php?$params",
+                'desc' => "View and edit $singularType regions",
+            );
+            $nav['contacts'] = array(
+                'title' => 'Contacts',
+                'url' => "/members.php?$params",
+                'desc' => "View and edit $singularType cities",
+            );
             $billingModule = $this->config->getItem('section', 'admin')
                 ->getItem('directive', 'billing')
                 ->getContent();
@@ -152,61 +157,61 @@ class Toolkit_Members_RecordNavigation
             }
         }
 
-               $hasPhotos = $this->config
-                       ->getItem('section', 'admin')
-                       ->getItem('directive', 'photos')
-                       ->getContent();
+        $hasPhotos = $this->config
+            ->getItem('section', 'admin')
+            ->getItem('directive', 'photos')
+            ->getContent();
 
-               if (!$hasPhotos) {
-                       unset($nav['photos']);
-               }
+        if (!$hasPhotos) {
+            unset($nav['photos']);
+        }
 
-               $hasPackages = $this->config
-                       ->getItem('section', 'admin')
-                       ->getItem('directive', 'packages')
-                       ->getContent();
+        $hasPackages = $this->config
+            ->getItem('section', 'admin')
+            ->getItem('directive', 'packages')
+            ->getContent();
 
-               if (!$hasPackages) {
-                       unset($nav['packages']);
-               }
+        if (!$hasPackages) {
+            unset($nav['packages']);
+        }
 
-               $hasAmenities = $this->config
-                       ->getItem('section', 'admin')
-                       ->getItem('directive', 'amenities')
-                       ->getContent();
+        $hasAmenities = $this->config
+            ->getItem('section', 'admin')
+            ->getItem('directive', 'amenities')
+            ->getContent();
 
-               if (!$hasAmenities) {
-                       unset($nav['amenities']);
-               }
+        if (!$hasAmenities) {
+            unset($nav['amenities']);
+        }
 
-               $hasFiles = $this->config
-                       ->getItem('section', 'admin')
-                       ->getItem('directive', 'files')
-                       ->getContent();
+        $hasFiles = $this->config
+            ->getItem('section', 'admin')
+            ->getItem('directive', 'files')
+            ->getContent();
 
-               if (!$hasFiles) {
-                       unset($nav['files']);
-               }
+        if (!$hasFiles) {
+            unset($nav['files']);
+        }
 
-               $hasContacts = $this->config
-                       ->getItem('section', 'admin')
-                       ->getItem('directive', 'contacts')
-                       ->getContent();
+        $hasContacts = $this->config
+            ->getItem('section', 'admin')
+            ->getItem('directive', 'contacts')
+            ->getContent();
 
-               if (!$hasContacts) {
-                       unset($nav['contacts']);
-               }
+        if (!$hasContacts) {
+            unset($nav['contacts']);
+        }
 
         //  make full URI's and attach which tab we are working with
         foreach ($nav as $i => &$j) {
             $j['url'] =  MEDIA_BASE_URL . 'admin' . $j['url'] . "&amp;tab=$i";
         }
 
-               $this->navStructure = $nav;
-       }
+        $this->navStructure = $nav;
+    }
 
-       //      }}}
-       //      {{{     setupUserNavSructure()
+    //  }}}
+    //  {{{ setupUserNavSructure()
 
     /**
      * Sets up a multi dimensional array used for the subnav structure
@@ -214,104 +219,104 @@ class Toolkit_Members_RecordNavigation
      * @return mixed  false on sql error. otherwise void
      * @access public
      */
-       public function setupUserNavStructure()
-       {
+    public function setupUserNavStructure()
+    {
         $singularType = $this->config
-                       ->getItem('section', 'listing type')
-                       ->getItem('directive', 'singular')
-                       ->getContent();
-               $pluralType = $this->config
-                       ->getItem('section', 'listing type')
-                       ->getItem('directive', 'plural')
-                       ->getContent();
-
-               $params = "rt=EditProfile";
-               $nav = array(
-                       'info' => array(
-                               'title' => "$singularType Info",
-                               'url' => "/?$params",
-                               'desc' => "View and edit $singularType in the database",
-                       ),
-                       'photos' => array(
-                               'title' => 'Photos',
-                               'url' => "/?$params",
-                               'desc' => "View and edit $pluralType in the database",
-                       ),
-                       'packages' => array(
-                               'title' => 'Packages',
-                               'url' => "/?$params",
-                               'desc' => "View and edit $singularType categories",
-                       ),
-                       'amenities' => array(
-                               'title' => 'Amenities',
-                               'url' => "/?$params",
-                               'desc' => "View and edit $singularType amenities",
-                       ),
-                       'files' => array(
-                               'title' => 'Files',
-                               'url' => "/?$params",
-                               'desc' => "View and edit $singularType regions",
-                       ),
-                       'contacts' => array(
-                               'title' => 'Contacts',
-                               'url' => "/?$params",
-                               'desc' => "View and edit $singularType cities",
-                       ),
-               );
-
-               $hasPhotos = $this->config
-                       ->getItem('section', 'members only')
-                       ->getItem('directive', 'photos')
-                       ->getContent();
-
-               if (!$hasPhotos) {
-                       unset($nav['photos']);
-               }
-
-               $hasPackages = $this->config
-                       ->getItem('section', 'members only')
-                       ->getItem('directive', 'packages')
-                       ->getContent();
-
-               if (!$hasPackages) {
-                       unset($nav['packages']);
-               }
-
-               $hasAmenities = $this->config
-                       ->getItem('section', 'members only')
-                       ->getItem('directive', 'amenities')
-                       ->getContent();
-
-               if (!$hasAmenities) {
-                       unset($nav['amenities']);
-               }
-
-               $hasFiles = $this->config
-                       ->getItem('section', 'members only')
-                       ->getItem('directive', 'files')
-                       ->getContent();
-
-               if (!$hasFiles) {
-                       unset($nav['files']);
-               }
-
-               $hasContacts = $this->config
-                       ->getItem('section', 'members only')
-                       ->getItem('directive', 'contacts')
-                       ->getContent();
-
-               if (!$hasContacts) {
-                       unset($nav['contacts']);
-               }
+            ->getItem('section', 'listing type')
+            ->getItem('directive', 'singular')
+            ->getContent();
+        $pluralType = $this->config
+            ->getItem('section', 'listing type')
+            ->getItem('directive', 'plural')
+            ->getContent();
+
+        $params = "rt=EditProfile";
+        $nav = array(
+            'info' => array(
+                'title' => "$singularType Info",
+                'url' => "/?$params",
+                'desc' => "View and edit $singularType in the database",
+            ),
+            'photos' => array(
+                'title' => 'Photos',
+                'url' => "/?$params",
+                'desc' => "View and edit $pluralType in the database",
+            ),
+            'packages' => array(
+                'title' => 'Packages',
+                'url' => "/?$params",
+                'desc' => "View and edit $singularType categories",
+            ),
+            'amenities' => array(
+                'title' => 'Amenities',
+                'url' => "/?$params",
+                'desc' => "View and edit $singularType amenities",
+            ),
+            'files' => array(
+                'title' => 'Files',
+                'url' => "/?$params",
+                'desc' => "View and edit $singularType regions",
+            ),
+            'contacts' => array(
+                'title' => 'Contacts',
+                'url' => "/?$params",
+                'desc' => "View and edit $singularType cities",
+            ),
+        );
+
+        $hasPhotos = $this->config
+            ->getItem('section', 'members only')
+            ->getItem('directive', 'photos')
+            ->getContent();
+
+        if (!$hasPhotos) {
+            unset($nav['photos']);
+        }
+
+        $hasPackages = $this->config
+            ->getItem('section', 'members only')
+            ->getItem('directive', 'packages')
+            ->getContent();
+
+        if (!$hasPackages) {
+            unset($nav['packages']);
+        }
+
+        $hasAmenities = $this->config
+            ->getItem('section', 'members only')
+            ->getItem('directive', 'amenities')
+            ->getContent();
+
+        if (!$hasAmenities) {
+            unset($nav['amenities']);
+        }
+
+        $hasFiles = $this->config
+            ->getItem('section', 'members only')
+            ->getItem('directive', 'files')
+            ->getContent();
+
+        if (!$hasFiles) {
+            unset($nav['files']);
+        }
+
+        $hasContacts = $this->config
+            ->getItem('section', 'members only')
+            ->getItem('directive', 'contacts')
+            ->getContent();
+
+        if (!$hasContacts) {
+            unset($nav['contacts']);
+        }
 
         //  make full URI's and attach which tab we are working with
         foreach ($nav as $i => &$j) {
             $j['url'] =  MEDIA_BASE_URL . 'members-only-area' . $j['url'] . "&amp;tab=$i";
         }
 
-               $this->navStructure = $nav;
-       }
+        $this->navStructure = $nav;
+    }
 
-       //      }}}
+    //  }}}
 }
 ?>
index e535ae9..8525498 100644 (file)
@@ -32,6 +32,7 @@ searchResultNumbered = On
 searchMapIconActive = On
 ; member packages limit if set to Off then no limit
 memberPackageLimit = Off
+memberCourseLimit = Off
 ; non members On or Off
 nonMembers = Off
 
index 47f65d8..c797f7b 100755 (executable)
@@ -4,60 +4,60 @@ body#memberdb {
   text-align: center;
   font-family: arial, sans-serif;
   font-size: 12px;
-       background-color: #ddd;
-       }
+    background-color: #ddd;
+    }
 a {outline: 0}
 
 #memberdb #cal {
-       display: inline;
-       margin-left: 5px;
+    display: inline;
+    margin-left: 5px;
 }
 #memberdb #wrapper {
-       width: 760px;
-       margin: 0 auto;
-       background:#fff url("../../../images/shadowr.gif") top right repeat-y;
-       text-align: left;
-       margin-top: 15px;
-       height: 1%;
-       overflow: hidden;
-       padding-bottom: 20px;
-       }
+    width: 760px;
+    margin: 0 auto;
+    background:#fff url("../../../images/shadowr.gif") top right repeat-y;
+    text-align: left;
+    margin-top: 15px;
+    height: 1%;
+    overflow: hidden;
+    padding-bottom: 20px;
+    }
 #memberdb #bottom {
   width: 760px;
   margin: 0 auto;
-       background:#fff url("../../../images/shadowb.gif") top right no-repeat;
-       height:7px;
-       font-size: 1px;
-       }
+    background:#fff url("../../../images/shadowb.gif") top right no-repeat;
+    height:7px;
+    font-size: 1px;
+    }
 #memberdb #copyright {
-       width: 760px;
-       font-size: 0.9em;
-       margin: 10px auto;
-       }
+    width: 760px;
+    font-size: 0.9em;
+    margin: 10px auto;
+    }
 
 #memberdb #top {
-       background: url("../../../images/top2.jpg") no-repeat;
-       height: 150px;
-       margin-right: 6px;
-       position: relative;
-       }
+    background: url("../../../images/top2.jpg") no-repeat;
+    height: 150px;
+    margin-right: 6px;
+    position: relative;
+    }
 #memberdb #top h1 {
-       position: absolute;
-       top: 10px;
-       left: 20px;
-       color: #000;
-       color: #CC6C06;
-       font-size: 26px;
-       margin: 0;
-       display: none;}
+    position: absolute;
+    top: 10px;
+    left: 20px;
+    color: #000;
+    color: #CC6C06;
+    font-size: 26px;
+    margin: 0;
+    display: none;}
 #memberdb #top img {
-       position: absolute;
-       top: 30px;
-       left: 20px;
-       border: 0px solid #244b8d;
-       background: white;
-       padding: 5px 5px;
-       }
+    position: absolute;
+    top: 30px;
+    left: 20px;
+    border: 0px solid #244b8d;
+    background: white;
+    padding: 5px 5px;
+    }
 h2 {font-size: 20px;}
 /*
 fieldset {float: left; width:600px;}
@@ -67,10 +67,10 @@ input {font-size: 1.1em;}
 */
 /* Navigation */
 #navcontainer {
-       margin-right: 6px;
-       height: 1%;
-       overflow: hidden;
-       }
+    margin-right: 6px;
+    height: 1%;
+    overflow: hidden;
+    }
 #navcontainer ul {
   padding: 0;
   margin: 0;
@@ -87,9 +87,9 @@ input {font-size: 1.1em;}
   text-decoration: none;
   float: left;
   border-right: 1px solid #fff;
-       font-weight: bold;
-       border-bottom: 1px solid #fff;
-       }
+    font-weight: bold;
+    border-bottom: 1px solid #fff;
+    }
 #navcontainer ul li a:hover {
   background-color: #2C788F;
   color: #fff;
@@ -99,29 +99,29 @@ input {font-size: 1.1em;}
 
 /*sub*/
 #navcontainer div + div ul {
-       background-color: #2C788F;
+    background-color: #2C788F;
 }
 #navcontainer div + div ul li a {
-       padding: 0.5em 1em;
-       background-color: #2C788F;
-       border-right: 1px solid #ccc;
-       font-weight: normal;
-       border-bottom: none;
+    padding: 0.5em 1em;
+    background-color: #2C788F;
+    border-right: 1px solid #ccc;
+    font-weight: normal;
+    border-bottom: none;
 }
 #navcontainer div + div ul li a:hover {
-       color: #000;
+    color: #000;
 }
 #navcontainer div + div ul li a.active  {
-       background-color: #fff;
-       color: black;
-       font-weight: bold;
+    background-color: #fff;
+    color: black;
+    font-weight: bold;
 }
 #navcontainer div + div ul li a.hasPending {
-       background: url("../../../images/flag_green.png") center right no-repeat;
-       padding-right: 21px;
+    background: url("../../../images/flag_green.png") center right no-repeat;
+    padding-right: 21px;
 }
 #navcontainer div + div ul li a.active.hasPending {
-       background: white url("../../../images/flag_green.png") center right no-repeat;
+    background: white url("../../../images/flag_green.png") center right no-repeat;
 }
 /*
 #subnavcontainer {margin-right: 6px;}
@@ -141,8 +141,8 @@ input {font-size: 1.1em;}
   text-decoration: none;
   float: left;
   border-right: 1px solid #ccc;
-       font-weight: normal;
-       }
+    font-weight: normal;
+    }
 #subnavcontainer ul li a:hover {
   background-color: #2C788F;
   color: #000;
@@ -151,9 +151,9 @@ input {font-size: 1.1em;}
 */
  /* Content area */
 #content {
-       margin: 20px 10px;
-       clear: left;
-       }
+    margin: 20px 10px;
+    clear: left;
+    }
 /* BUTTONS what the hell? */
 
 .buttons a, .buttons button {
@@ -247,96 +247,96 @@ ul#toolbox li.toolboxArrow {list-style-type:none;padding-left:0;margin-left:-7px
 .highlight4 tr,.highlight4 td { margin:1px 0; border:#c2d8ae solid 1px; background-color:#c2d8ae;color:#000; }
 .highlight5 tr,.highlight5 td { margin:1px 0; border:#8fae74 solid 1px; background-color:#8fae74;color:#000; }
 .highlight6 tr,.highlight6 td { margin:1px 0; border:#c2d8ae solid 1px; background-color:#c2d8ae;color:#000; }
-/*     -----------------       */
-/*       NEW MEMBER DB         */
-/*     -----------------       */
+/*  -----------------   */
+/*    NEW MEMBER DB     */
+/*  -----------------   */
 
-/*     DATAGRID PAGER  */
+/*  DATAGRID PAGER  */
 .paging {
-       text-align: center;
-       margin: 1.0em 0;
-       padding: 8px 0;
-       width: 100%;
+    text-align: center;
+    margin: 1.0em 0;
+    padding: 8px 0;
+    width: 100%;
 }
 .paging b,
 .paging a {
-       margin-right: 15px;
+    margin-right: 15px;
 }
 .paging b {
-       color: red;
-       padding: 5px 7px;
-       border: 1px solid #585F47;
+    color: red;
+    padding: 5px 7px;
+    border: 1px solid #585F47;
 }
 .paging a:link,
 .paging a:visited {
-       border: solid 1px #DDDDDD;
-       color: #585F47;
-       padding: 5px 7px;
-       text-decoration: none;
+    border: solid 1px #DDDDDD;
+    color: #585F47;
+    padding: 5px 7px;
+    text-decoration: none;
 }
 .paging a:hover {
-       border: 1px solid #585F47;
+    border: 1px solid #585F47;
 }
 
-/*     DATAGRID SORTER  */
+/*  DATAGRID SORTER  */
 #gridSorter {
-       margin: 10px auto;
-       padding: 10px;
-       text-align: center;
-       border: 1px solid #96A379;
+    margin: 10px auto;
+    padding: 10px;
+    text-align: center;
+    border: 1px solid #96A379;
 }
 #gridSorter table,
 #gridSorter td {
-       border: none;
+    border: none;
 }
 #gridSorter .fieldcell {
-       width: auto;
+    width: auto;
 }
 #advanced-search {
-       text-align: right;
-       cursor: pointer;
-       color: blue;
+    text-align: right;
+    cursor: pointer;
+    color: blue;
 }
 .req {
-       color: red;
+    color: red;
 }
 #form-warning-top {
-       color: black;
-       font-size: 110%;
-       font-weight: bold;
-       margin: 10px;
-       padding: 7px;
-       border: 1px solid red;
-       background-color: #FFCCCC;
+    color: black;
+    font-size: 110%;
+    font-weight: bold;
+    margin: 10px;
+    padding: 7px;
+    border: 1px solid red;
+    background-color: #FFCCCC;
 }
 #form-success-top {
-       color: black;
-       font-size: 110%;
-       font-weight: bold;
-       margin: 10px;
-       padding: 7px;
-       border: 1px solid green;
-       background-color: #CCFFCC;
+    color: black;
+    font-size: 110%;
+    font-weight: bold;
+    margin: 10px;
+    padding: 7px;
+    border: 1px solid green;
+    background-color: #CCFFCC;
 }
 
 img {
-       border: 0;
-       display: block;
-       }
+    border: 0;
+    display: block;
+    }
 /*   ---------------   */
 /*     NAVIGATION      */
 /*   ---------------   */
 #nav-detail {
-       margin-top: 12px;
-       height: 1%;
-       overflow: hidden;
-       clear: left;
-       }
+    margin-top: 12px;
+    height: 1%;
+    overflow: hidden;
+    clear: left;
+    }
 #nav-detail ul {
   padding: 0px 0;
-       padding-bottom: 3px;
+    padding-bottom: 3px;
   margin: 0;
-       margin-top: 10px;
+    margin-top: 10px;
   border-bottom: 1px solid #666;
   font-weight: bold;
 }
@@ -358,169 +358,169 @@ img {
 #nav-detail ul li a:hover {
   color: #666;
   background: #ccc;
-       background: #FFFBDF;
+    background: #FFFBDF;
   border-color: #666;
 }
 #nav-detail ul li a.current {
   background: white;
   border-bottom: 1px solid white;
-       color: #000;
+    color: #000;
 }
 
 /* Member Box */
-#member-info   {
-       margin: 0;
-       border: 1px solid #666;
-       border-top: 0;
-       padding: 6px;
-       position: relative;
-       height: 1%;
-       overflow: hidden;
-       clear: left;
-       }
+#member-info    {
+    margin: 0;
+    border: 1px solid #666;
+    border-top: 0;
+    padding: 6px;
+    position: relative;
+    height: 1%;
+    overflow: hidden;
+    clear: left;
+    }
 #member-info h1 {
-       font-size: 16px;
-       }
+    font-size: 16px;
+    }
 #mRow1 {
-       margin: 10px;
-       }
+    margin: 10px;
+    }
 #memberdb #mRow1 {
-       float: left;
-       position: relative;
-       width: 400px;
-       }
+    float: left;
+    position: relative;
+    width: 400px;
+    }
 #mRow1 table {width: 100%;}
 
 #mRow2 {
-       margin: 10px;
-       }
+    margin: 10px;
+    }
 #memberdb #mRow2 {
-       float: right;
-       position: relative;
-       width: 285px;
-       }
+    float: right;
+    position: relative;
+    width: 285px;
+    }
 #mRow2 table {width: 100%;}
 
 #mRow1 .text {
-       width: 180px;
-       }
+    width: 180px;
+    }
 #mRow2 .text {
-       width: 150px;
-       }
+    width: 150px;
+    }
 .form {
-       clear: left;
-       display: block;
-       position: relative;
-       margin: 2em 0 1em 0;
-       padding: 0;
-       border: 0;
-       }
+    clear: left;
+    display: block;
+    position: relative;
+    margin: 2em 0 1em 0;
+    padding: 0;
+    border: 0;
+    }
 #memberdb .form {
-       margin-top: 0;
-       }
+    margin-top: 0;
+    }
 /* narrower column */
 .formNarrow {
-       clear: right;
-       margin: 0 0 1em 0;
-       }
+    clear: right;
+    margin: 0 0 1em 0;
+    }
 .form legend {
-       font-size: 1.2em;
-       font-weight: bold;
-       margin: 0;
-       padding: 0 0 0.3em 0;
-       color: #000;
-       }
+    font-size: 1.2em;
+    font-weight: bold;
+    margin: 0;
+    padding: 0 0 0.3em 0;
+    color: #000;
+    }
 .form table,
 .form td {
-       border-collapse: collapse;
-       border: 1px solid #fff;
-       padding: 0;
-       background: #D6DFC3;
-       }
+    border-collapse: collapse;
+    border: 1px solid #fff;
+    padding: 0;
+    background: #D6DFC3;
+    }
 .form td {
-       padding: 4px 6px;
-       }
+    padding: 4px 6px;
+    }
 .form tr.fieldPending td {
-       background: #FFFF99;
-       border: 1px solid orange;
-       }
+    background: #FFFF99;
+    border: 1px solid orange;
+    }
 .form label {
-       display: block;
-       }
+    display: block;
+    }
 .labelcell {
-       text-align: right;
-       /* width: 120px; */
-       }
+    text-align: right;
+    /* width: 120px; */
+    }
 .formNarrow .labelcell {
-       /* width: 110px; */
-       }
+    /* width: 110px; */
+    }
 .fieldcell {
-       text-align: left;
-       /* width: 220px; */
-       }
+    text-align: left;
+    /* width: 220px; */
+    }
 .fieldcell img {float: left;}
 .formNarrow .fieldcell {
-       /* width: 150px; */
-       }
+    /* width: 150px; */
+    }
 
-/* Multiple rows in one cell    */
+/* Multiple rows in one cell     */
 .fieldcell i {
-       display: block;
-       font-style: normal;
-       padding: 5px;
-       text-align: left;
-       background-color: #eee;
-       margin-bottom: 1px;
-       }
+    display: block;
+    font-style: normal;
+    padding: 5px;
+    text-align: left;
+    background-color: #eee;
+    margin-bottom: 1px;
+    }
 .fieldcell i img {
  margin-right: 6px; }
 /* Category Dropdown */
 .fieldcell i optgroup {
-       font-style: normal;
-       font-size: 11px;
-       }
+    font-style: normal;
+    font-size: 11px;
+    }
 .fieldcell i optgroup option {
-       padding: 0;
-       padding-left: 4px;
-       }
+    padding: 0;
+    padding-left: 4px;
+    }
 
 
 /* Small graphics */
 .remove {
-       float: right;
-       clear: right;}
+    float: right;
+    clear: right;}
 .add {
-       display: block;
-       /* float: right; */
-       display: block;
-       font-style: normal;
-       padding: 5px;
-       text-align: left;
-       background-color: #eee;
-       margin-bottom: 1px;
-       }
+    display: block;
+    /* float: right; */
+    display: block;
+    font-style: normal;
+    padding: 5px;
+    text-align: left;
+    background-color: #eee;
+    margin-bottom: 1px;
+    }
 .add img {float: left; margin-right: 10px;}
 .fieldcell .info {
-       float: right;
-       }
+    float: right;
+    }
 
 .priceFrom,
 .priceTo {
-       width: 4em;
-       }
+    width: 4em;
+    }
 .submit {display: block;}
 
 /* Submit */
 .submitArea {
-       background: #D6DFC3;
-       text-align: center;
-       padding: 10px;
-       clear: both;
-       }
+    background: #D6DFC3;
+    text-align: center;
+    padding: 10px;
+    clear: both;
+    }
 .submitArea input {
-       margin: 0 auto;
-       display: block;
-       }
+    margin: 0 auto;
+    display: block;
+    }
 
 
 /*   ---------------   */
@@ -528,140 +528,140 @@ img {
 /*   ---------------   */
 
 .movable {
-       background-image: url("../../../assets/buttons/arrow_out.png");
-       background-repeat: no-repeat;
-       background-position: 8px 8px;
-       }
+    background-image: url("../../../assets/buttons/arrow_out.png");
+    background-repeat: no-repeat;
+    background-position: 8px 8px;
+    }
 .photoItem {
-       margin-top: 1em;
-       padding: 28px 18px 18px 28px;
-       border: 1px solid #ccc;
-       height: 1%;
-       overflow: hidden;
-       position: relative;
-       background-color: #eee;
-       }
+    margin-top: 1em;
+    padding: 28px 18px 18px 28px;
+    border: 1px solid #ccc;
+    height: 1%;
+    overflow: hidden;
+    position: relative;
+    background-color: #eee;
+    }
 .photoItem form {
-       height: 1%;
-       overflow: hidden;
-       border: 0px solid red;
-       }
+    height: 1%;
+    overflow: hidden;
+    border: 0px solid red;
+    }
 .photoItem .thumb {
-       float: left;
-       position: relative;
-       margin-right: 20px;
-       cursor: move;
-       }
+    float: left;
+    position: relative;
+    margin-right: 20px;
+    cursor: move;
+    }
 .photoItem i {
-       font-style: normal;
-       font-weight: bold;
-       display: block;
-       }
+    font-style: normal;
+    font-weight: bold;
+    display: block;
+    }
 .photoItem input {margin-top: 0.5em;}
 .photoItem input.text {
-       width: 400px;
-       }
+    width: 400px;
+    }
 .photoItem .photoDelete {
-/*     display: block;
-       margin-top: 1em;
-       border: 1px solid #ccc;
-       background: #FFEFEF;
-       width: 130px;
-       padding: 3px;
-       color: #000;
+/*  display: block;
+    margin-top: 1em;
+    border: 1px solid #ccc;
+    background: #FFEFEF;
+    width: 130px;
+    padding: 3px;
+    color: #000;
 */
-       position: absolute;
-       bottom: 20px;
-       right: 20px;
+    position: absolute;
+    bottom: 20px;
+    right: 20px;
 
-       }
+    }
 .photoDelete:hover {background: #EFD1D1;}
 .photoItem .photoDelete img {
-       float: left;
-       margin-right: 6px;
-       }
+    float: left;
+    margin-right: 6px;
+    }
 .photoOptions {}
 #pos-info {
-       font-size: 110%;
-       font-weight: bolder;
-       padding: 5px;
-       margin: 5px 0;
-       text-align: center;
+    font-size: 110%;
+    font-weight: bolder;
+    padding: 5px;
+    margin: 5px 0;
+    text-align: center;
 }
 
 
 /*   ---------------   */
-/*      CONTACTS          */
+/*      CONTACTS       */
 /*   ---------------   */
 .contact {
-       margin-top: 1em;
-       padding: 20px;
-       border: 1px solid #96A379;
-       overflow: hidden;
-       position: relative;
-       background: #D6DFC3;
+    margin-top: 1em;
+    padding: 20px;
+    border: 1px solid #96A379;
+    overflow: hidden;
+    position: relative;
+    background: #D6DFC3;
 }
 
 .contact input.text {
-       width: 200px;
-       display: block;
+    width: 200px;
+    display: block;
 }
 /* SPECIFIC TO Contacts RESULT HERE */
 .contactList {
-       border: 1px solid #96A379;
-       padding: 10px 10px;
-       margin: 5px 0;
-       background-color: #D6DFC3;
-       height: 1%;
-       overflow: hidden;
-       position: relative;
+    border: 1px solid #96A379;
+    padding: 10px 10px;
+    margin: 5px 0;
+    background-color: #D6DFC3;
+    height: 1%;
+    overflow: hidden;
+    position: relative;
 }
 .contactListOn {
-       background-color: #E6EFD1;
-       cursor: hand;
-       cursor: pointer;
+    background-color: #E6EFD1;
+    cursor: hand;
+    cursor: pointer;
 }
 .contactList h3 {
-       font-size: 15px;
-       color: #333;
-       margin: 0 0 0 24px;
-       float: left;
-       width: 175px;
+    font-size: 15px;
+    color: #333;
+    margin: 0 0 0 24px;
+    float: left;
+    width: 175px;
 }
 .contactListOn h3 {
-       color: #000;
+    color: #000;
 }
 .contactList .title {
-       position: absolute;
-       bottom: 10px;
-       right: 300px;
-       width: 170px;
+    position: absolute;
+    bottom: 10px;
+    right: 300px;
+    width: 170px;
 }
 .contactList a.remove {
-       position: absolute;
-       left: 10px;
+    position: absolute;
+    left: 10px;
 }
 .contactList .phone {
-       position: absolute;
-       bottom: 10px;
-       right: 240px;
+    position: absolute;
+    bottom: 10px;
+    right: 240px;
 }
 .contactList .mail{
-       position: absolute;
-       bottom: 6px;
-       right: 8px;
+    position: absolute;
+    bottom: 6px;
+    right: 8px;
 }
 .contactList a.email {
-       position: absolute;
-       bottom: 10px;
-       right: 40px;
+    position: absolute;
+    bottom: 10px;
+    right: 40px;
 }
 .contactList a {
-       color: #96A379;
+    color: #96A379;
    text-decoration: none;
 }
 .contactList a.email {
-       text-decoration: underline;
+    text-decoration: underline;
 }
 .contactList a:link {color: #585F47;}
 .contactList a:visited {color: #585F47;}
@@ -673,150 +673,158 @@ img {
 /*   ---------------   */
 
 .packageItem {
-       margin-top: 1em;
-       padding: 20px;
-       border: 1px solid #96A379;
-       height: 1%;
-       overflow: hidden;
-       position: relative;
-       background: #D6DFC3;
-       }
+    margin-top: 1em;
+    padding: 20px;
+    border: 1px solid #96A379;
+    height: 1%;
+    overflow: hidden;
+    position: relative;
+    background: #D6DFC3;
+    }
 
 .packageItem .thumb {
-       position: relative;
-       margin-bottom: 1em;
-       }
+    position: relative;
+    margin-bottom: 1em;
+    }
 .packageText {
-       float: left;
-       width: 400px;
-       padding-bottom: 1em;
+    float: left;
+    width: 400px;
+    padding-bottom: 1em;
 }
 .packageItem i {
-       font-style: normal;
-       font-weight: bold;
-       display: block;
-       padding-top: 1em;
+    font-style: normal;
+    font-weight: bold;
+    display: block;
+    padding-top: 1em;
 
-       }
+    }
 .packageItem input {margin-top: 0.5em;}
 .packageItem input.text {
-       width: 200px;
-       display: block;
-       }
+    width: 200px;
+    display: block;
+    }
 .packageItem textarea {
-       width: 300px;
-       height: 150px;
-       }
+    width: 300px;
+    height: 150px;
+    }
 .packageItem .packageDelete {
-       display: block;
-       margin-top: 1em;
-       border: 1px solid #ccc;
-       background: #FFEFEF;
-       width: 140px;
-       padding: 3px;
-       position: absolute;
-       bottom: 20px;
-       right: 20px;
-       color: #000;
-       }
+    display: block;
+    margin-top: 1em;
+    border: 1px solid #ccc;
+    background: #FFEFEF;
+    width: 140px;
+    padding: 3px;
+    position: absolute;
+    bottom: 20px;
+    right: 20px;
+    color: #000;
+    }
 .packageDelete:hover {background: #EFD1D1;}
 .packageItem .packageDelete img {
-       float: left;
-       margin-right: 6px;
-       }
+    float: left;
+    margin-right: 6px;
+    }
 .packageOptions {float: left;}
 
+/*   ---------------   */
+/*       COURSES       */
+/*   ---------------   */
+.courseText {
+    float: right;
+    width: 400px;
+    padding-bottom: 1em;
+}
 
 
 /*   ---------------   */
 /*      AMENITIES      */
 /*   ---------------   */
 .amenityList {
-       list-style-type: none;
-       float: left;
-       position: relative;
-       zoom: 1;
-       width: 200px;
-       margin-right: 20px;
-       }
+    list-style-type: none;
+    float: left;
+    position: relative;
+    zoom: 1;
+    width: 200px;
+    margin-right: 20px;
+    }
 #memberdb .amenityList {
-       margin-right: 50px;
-       }
+    margin-right: 50px;
+    }
 .amenityList input {
-       /* No Luck, see http://meyerweb.com/eric/thoughts/2007/05/15/formal-weirdness/ */
+    /* No Luck, see http://meyerweb.com/eric/thoughts/2007/05/15/formal-weirdness/ */
 }
 .amenityList li {
-       vertical-align: middle;
-       height: 1%;
-       overflow: hidden;
-       font-size: 1.1em;
-       }
+    vertical-align: middle;
+    height: 1%;
+    overflow: hidden;
+    font-size: 1.1em;
+    }
 .amenityList label {
   padding: 4px;
   display: block;
-       background: #D6DFC3;
-       margin-bottom: 1px;
+    background: #D6DFC3;
+    margin-bottom: 1px;
 }
 .amenityList label.amenityOn {
-       background-color: #E6EFD1;
-       cursor: hand;
-       cursor: pointer;
-       }
+    background-color: #E6EFD1;
+    cursor: hand;
+    cursor: pointer;
+    }
 .amenityList li.fieldPending label {
-       background: #FFFF99;
-       border: 1px solid orange;
-       }
+    background: #FFFF99;
+    border: 1px solid orange;
+    }
 .amenityList li.fieldPending label.amenityOn {
-       background: #FFFFb2;
-       cursor: hand;
-       cursor: pointer;
-       }
+    background: #FFFFb2;
+    cursor: hand;
+    cursor: pointer;
+    }
 
 /* SPECIFIC TO SEARCH RESULT HERE */
 .searchResult {
-       border: 1px solid #96A379;
-       padding: 10px 20px;
-       margin: 5px 0;
-       background-color: #D6DFC3;
-       height: 1%;
-       overflow: hidden;
-       position: relative;
+    border: 1px solid #96A379;
+    padding: 10px 20px;
+    margin: 5px 0;
+    background-color: #D6DFC3;
+    height: 1%;
+    overflow: hidden;
+    position: relative;
 }
 .searchResultOn {
-       background: url("../../../assets/searchResultOn.gif") no-repeat 98% center #E6EFD1;
-       cursor: hand;
-       cursor: pointer;
+    background: url("../../../assets/searchResultOn.gif") no-repeat 98% center #E6EFD1;
+    cursor: hand;
+    cursor: pointer;
 }
 .searchResult a.remove {
-       position: absolute;
-       left: 10px;
+    position: absolute;
+    left: 10px;
 }
 .searchResult h3 {
-       font-size: 15px;
-       color: #333;
-       margin: 0 0 0 20px;
-       float: left;
-       width: 280px;
-       }
+    font-size: 15px;
+    color: #333;
+    margin: 0 0 0 20px;
+    float: left;
+    width: 280px;
+    }
 .searchResultOn h3 {
-       color: #000;
+    color: #000;
 }
 .searchResult .phone {
-       position: absolute;
-       bottom: 10px;
-       right: 300px;
+    position: absolute;
+    bottom: 10px;
+    right: 300px;
 }
 .searchResult a.email {
-       position: absolute;
-       bottom: 10px;
-       right: 90px;
+    position: absolute;
+    bottom: 10px;
+    right: 90px;
 }
 .searchResult a {
-       color: #96A379;
+    color: #96A379;
    text-decoration: none;
 }
 .searchResult a.email {
-       text-decoration: underline;
+    text-decoration: underline;
 }
 .searchResult a:link {color: #585F47;}
 .searchResult a:visited {color: #585F47;}
@@ -824,121 +832,121 @@ img {
 .searchResult a:active {color: #585F47;}
 
 .pending {
-       background-color: #FFFF99;
-       border: 1px solid orange;
+    background-color: #FFFF99;
+    border: 1px solid orange;
 }
 .pendingMsg {
-       padding: 5px;
-       text-align: center;
+    padding: 5px;
+    text-align: center;
 }
 .pendingPhotoCaption, .pendingLogo,
 .pendingFileName {
-       text-align: center;
+    text-align: center;
 }
 .pendingFileName a {
-       text-decoration: none;
-       margin-bottom: 5px;
-       display: block;
+    text-decoration: none;
+    margin-bottom: 5px;
+    display: block;
 }
 /*
 #pendingUpdates {
-       width: 100%;
+    width: 100%;
 }
 #pendingUpdates .labelcell {
-       width: 100px;
+    width: 100px;
 }
 #pendingUpdates .fieldcell {
-       width: 100%;
+    width: 100%;
 }
 #pendingUpdates .fieldcell div {
-       float: left;
-       color: green;
+    float: left;
+    color: green;
 }
 #pendingUpdates .fieldcell div + div {
-       color: red;
+    color: red;
 }
 label.pendingUpdate {
-       display: block;
+    display: block;
 }
 */
 #subnavcontainer a.hasPending {
-       background: url("../../../images/flag_green.png") center right no-repeat;
-       padding-right: 21px;
+    background: url("../../../images/flag_green.png") center right no-repeat;
+    padding-right: 21px;
 }
 .fieldcell .form_calendar {
-       display: inline;
-       float: none;
-       vertical-align: bottom;
+    display: inline;
+    float: none;
+    vertical-align: bottom;
 }
 
 /* Pending Member Stuff */
 
 .pendingUpdates {
-       width: 100%;
+    width: 100%;
 }
 .pendingPhotoCaption img,
 .pendingUpdates img  {
-       float: left;
+    float: left;
 }
 .updates .field {
-       float: left;
-       clear: left;
-       margin-top: 3px;
-       position: relative;
+    float: left;
+    clear: left;
+    margin-top: 3px;
+    position: relative;
 }
 .authorization {
-        float: right;
-       position: relative;
-       width: 100px;
-       padding: 10px;
-       background: #EAEFE0;
-       border: 1px solid #C3CFA8;
+     float: right;
+    position: relative;
+    width: 100px;
+    padding: 10px;
+    background: #EAEFE0;
+    border: 1px solid #C3CFA8;
 }
 .authorization label {
-       margin: 5px;
-       font-weight: bold;
-       font-size: 13px;
+    margin: 5px;
+    font-weight: bold;
+    font-size: 13px;
 }
 
 /* search result pagination */
 .pages {
-       padding: 1em 0;
-       clear: left;
+    padding: 1em 0;
+    clear: left;
 }
 .pages a, .pages b {
-       color: #003366;
-       display: block;
-       float: left;
-       padding: 0.2em 0.5em;
-       margin-right: 0.1em;
-       border: 1px solid #fff;
-       background: #fff;
+    color: #003366;
+    display: block;
+    float: left;
+    padding: 0.2em 0.5em;
+    margin-right: 0.1em;
+    border: 1px solid #fff;
+    background: #fff;
 }
 .pages b, .business-first-letter a.curr {
-       border: 1px solid #2E6AB1;
-       font-weight: bold;
-       background: #2E6AB1;
-       color: #fff;
+    border: 1px solid #2E6AB1;
+    font-weight: bold;
+    background: #2E6AB1;
+    color: #fff;
 }
 .pages a {
-       border: 1px solid #9AAFE5;
-       text-decoration: none;
+    border: 1px solid #9AAFE5;
+    text-decoration: none;
 }
 .pages a:hover, .business-first-letter a:hover {
-       border-color: #2E6AB1;
+    border-color: #2E6AB1;
 }
 .business-first-letter {
-       margin: 1em 0;
+    margin: 1em 0;
 }
 .business-first-letter > div {
-       margin-bottom: 1em;
+    margin-bottom: 1em;
 }
 .business-first-letter a {
-       margin-right: 0.1em;
-       color: #003366;
-       padding: 0.1em 0.4em;
-       border: 1px solid #9AAFE5;
-       text-decoration: none;
+    margin-right: 0.1em;
+    color: #003366;
+    padding: 0.1em 0.4em;
+    border: 1px solid #9AAFE5;
+    text-decoration: none;
 }
 .level-0 {
         font-weight: bold;
@@ -956,11 +964,11 @@ label.pendingUpdate {
 .level-6 {padding-left: 120px;}
 
 #advanced-record-search img.ui-datepicker-trigger {
-       display: inline;
-       float: none;
+    display: inline;
+    float: none;
 }
 .treeOperators {margin: 1em 0;}
 .treeOperators button {
-       margin-right: 10px;
+    margin-right: 10px;
 }
 .tree li a {background-image: url("../../../images/note_edit.png");}
diff --git a/Toolkit/Members/libjs/edit-member-course.js b/Toolkit/Members/libjs/edit-member-course.js
new file mode 100755 (executable)
index 0000000..79ac5bd
--- /dev/null
@@ -0,0 +1,20 @@
+var MemberPackages =
+{
+    init: function()
+    {
+        if (CKEDITOR.env.isCompatible) {
+            $("textarea.ckeditor").each(function() {
+                CKEDITOR.replace(
+                    $(this).attr('id'),
+                    {
+                        toolbar : 'LimitedToolset',
+                        width : 300,
+                        height : 200
+                    }
+                );
+            });
+        }
+    }
+}
+
+$(document).ready(MemberPackages.init);
diff --git a/Toolkit/Members/templates/addCourse.tpl b/Toolkit/Members/templates/addCourse.tpl
new file mode 100644 (file)
index 0000000..dbb7df1
--- /dev/null
@@ -0,0 +1,75 @@
+<div class="packageItem packageUploadForm">
+    {form.javascript:h}
+    {form.outputHeader():h}
+    {form.hidden:h}
+        <div class="courseText">
+            <i>{form.title.label:h}</i>
+            <div flexy:if="form.title.error" class="req">{form.title.error:h}</div>
+            {form.title.html:h}
+            <i>{form.description.label:h}</i>
+            <div flexy:if="form.description.error" class="req">{form.description.error:h}</div>
+            {form.description.html:h}
+            <i>
+                <span class="req" flexy:if="form.sdate.required">*</span>
+                {form.sdate.label:h}
+            </i>
+            <div flexy:if="form.sdate.error" class="req">{form.sdate.error:h}</div>
+            {form.sdate.html:h}
+            <i>
+                <span class="req" flexy:if="form.edate.required">*</span>
+                {form.edate.label:h}
+            </i>
+            <div flexy:if="form.edate.error" class="req">{form.edate.error:h}</div>
+            {form.edate.html:h}
+        </div>
+        <div class="coursePhoto">
+            <div flexy:if="showCurrImg">
+                <label>
+                    {form.remove_img_rmv.html:h}
+                    {form.remove_img_rmv.label:h}
+                </label>
+                <i>{form.curr_image.label:h}</i>
+                {form.curr_image.html:h}
+            </div>
+            <i>{form.image.label:h}</i>
+            <div flexy:if="form.image.error" class="req">{form.image.error:h}</div>
+            {form.image.html:h}
+        </div>
+        <div class="courseSection">
+            <i>{form.res_url.label:h}</i>
+            <div flexy:if="form.res_url.error" class="req">{form.res_url.error:h}</div>
+            {form.res_url.html:h}
+
+
+            <i>{form.par.label:h}</i>
+            <div flexy:if="form.par.error" class="req">{form.par.error:h}</div>
+            {form.par.html:h}
+
+            <i>{form.yardage.label:h}</i>
+            <div flexy:if="form.yardage.error" class="req">{form.yardage.error:h}</div>
+            {form.yardage.html:h}
+
+            <i>{form.course_rating.label:h}</i>
+            <div flexy:if="form.course_rating.error" class="req">{form.course_rating.error:h}</div>
+            {form.course_rating.html:h}
+
+            <i>{form.slope_rating.label:h}</i>
+            <div flexy:if="form.slope_rating.error" class="req">{form.slope_rating.error:h}</div>
+            {form.slope_rating.html:h}
+
+            <i>{form.walking_course.label:h}</i>
+            <div flexy:if="form.walking_course.error" class="req">{form.walking_course.error:h}</div>
+            {form.walking_course.html:h}
+
+            <i>{form.holes18.label:h}</i>
+            <div flexy:if="form.holes18.error" class="req">{form.holes18.error:h}</div>
+            {form.holes18.html:h}
+
+            <i>{form.holes9.label:h}</i>
+            <div flexy:if="form.holes9.error" class="req">{form.holes9.error:h}</div>
+            {form.holes9.html:h}
+
+        </div>
+        <div class="submitArea"> {form.add_rmv.html:h} </div>
+    </form>
+</div>
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/Toolkit/Members/templates/editCourse.tpl b/Toolkit/Members/templates/editCourse.tpl
new file mode 100644 (file)
index 0000000..15bb6be
--- /dev/null
@@ -0,0 +1,89 @@
+<div class="packageItem packageUploadForm">
+    {form.javascript:h}
+    {form.outputHeader():h}
+    {form.hidden:h}
+        <div class="courseText">
+            <i>{form.title.label:h}</i>
+            <div flexy:if="form.title.error" class="req">
+                {form.title.error:h}
+            </div>
+            {form.title.html:h}
+            <i>{form.description.label:h}</i>
+            <div flexy:if="form.description.error" class="req">
+                {form.description.error:h}
+            </div>
+            {form.description.html:h}
+            <i>
+                <span class="req" flexy:if="form.sdate.required">*</span>
+                {form.sdate.label:h}
+            </i>
+            <div flexy:if="form.sdate.error" class="req">
+                {form.sdate.error:h}
+            </div>
+            {form.sdate.html:h}
+            <i>
+                <span class="req" flexy:if="form.edate.required">*</span>
+                {form.edate.label:h}
+            </i>
+            <div flexy:if="form.edate.error" class="req">
+                {form.edate.error:h}
+            </div>
+            {form.edate.html:h}
+        </div>
+        <div class="coursePhoto">
+            <div flexy:if="showCurrImg">
+                <label>
+                    {form.remove_img_rmv.html:h}
+                    {form.remove_img_rmv.label:h}
+                </label>
+
+                <i>{form.curr_image.label:h}</i>
+                {form.curr_image.html:h}
+            </div>
+            <i>{form.image.label:h}</i>
+            <div flexy:if="form.image.error" class="req">
+                {form.image.error:h}
+            </div>
+            {form.image.html:h}
+        </div>
+        <div class="courseSection">
+            <i>{form.res_url.label:h}</i>
+            <div flexy:if="form.res_url.error" class="req">{form.res_url.error:h}</div>
+            {form.res_url.html:h}
+
+
+            <i>{form.par.label:h}</i>
+            <div flexy:if="form.par.error" class="req">{form.par.error:h}</div>
+            {form.par.html:h}
+
+            <i>{form.yardage.label:h}</i>
+            <div flexy:if="form.yardage.error" class="req">{form.yardage.error:h}</div>
+            {form.yardage.html:h}
+
+            <i>{form.course_rating.label:h}</i>
+            <div flexy:if="form.course_rating.error" class="req">{form.course_rating.error:h}</div>
+            {form.course_rating.html:h}
+
+            <i>{form.slope_rating.label:h}</i>
+            <div flexy:if="form.slope_rating.error" class="req">{form.slope_rating.error:h}</div>
+            {form.slope_rating.html:h}
+
+            <i>{form.walking_course.label:h}</i>
+            <div flexy:if="form.walking_course.error" class="req">{form.walking_course.error:h}</div>
+            {form.walking_course.html:h}
+
+            <i>{form.holes18.label:h}</i>
+            <div flexy:if="form.holes18.error" class="req">{form.holes18.error:h}</div>
+            {form.holes18.html:h}
+
+            <i>{form.holes9.label:h}</i>
+            <div flexy:if="form.holes9.error" class="req">{form.holes9.error:h}</div>
+            {form.holes9.html:h}
+
+        </div>
+        <div class="submitArea">
+            {form.add_rmv.html:h}
+            {form.remove_rmv.html:h}
+        </div>
+    </form>
+</div>
diff --git a/Toolkit/Members/templates/editCourseProfile.tpl b/Toolkit/Members/templates/editCourseProfile.tpl
new file mode 100644 (file)
index 0000000..51ad494
--- /dev/null
@@ -0,0 +1,39 @@
+<div id="nav-detail"> {nav:h} </div>
+<div id="member-info">
+    {if:pending}
+        <div class="pending pendingMsg">
+            The yellow colored items are pending approval from the website
+            administrator.<br>Upon approval, your changes will be visible on
+            the website.
+        </div>
+    {end:}
+    {form.javascript:h}
+    {form.outputHeader():h}
+    {form.hidden:h}
+
+    <!-- Error or Success Message -->
+    {validated():h}
+    <h1>Edit Course Profiles</h1>
+    <p>
+    </p>
+    {foreach:form.sections,sec}
+        <ul>
+            {foreach:sec.elements,elem}
+                {if:fieldPending(elem)}
+                    <li class="fieldPending">
+                {else:}
+                    <li>
+                {end:}
+                    <label>
+                        {elem.html:h}
+                        {elem.label:h}
+                    </label>
+                </li>
+            {end:}
+        </ul>
+    {end:}
+    <div class="submitArea">
+        <input type="submit" class="submit" value="Submit Changes">
+    </div>
+    </form>
+</div>
diff --git a/Toolkit/Members/templates/editCourses.tpl b/Toolkit/Members/templates/editCourses.tpl
new file mode 100644 (file)
index 0000000..65a7a4c
--- /dev/null
@@ -0,0 +1,27 @@
+<style type="text/css">
+.ui-state-highlight {
+    border: 3px dashed #666666;
+    height: 1%;
+    margin-top: 1em;
+    overflow: hidden;
+    padding: 28px 18px 18px 28px;
+    position: relative;
+}
+</style>
+<div id="nav-detail"> {nav:h} </div>
+<div id="member-info">
+    {if:hasPendingPackages}
+        <div class="pending pendingMsg">
+            The yellow colored items are pending approval from the website
+            administrator.<br>Upon approval, your changes will be visible on
+            the website.
+        </div>
+    {end:}
+    <h1>Courses</h1>
+    {uploadForm:h}
+    <div id="packageList" class="container">
+    {foreach:editForm,i}
+        {i:h}
+    {end:}
+    </div>
+</div><!-- /#member-info -->
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)