Changeset - bc140e90c361
[Not reviewed]
default
0 12 0
Nathan Brink (binki) - 14 years ago 2011-10-26 23:44:20
ohnobinki@ohnopublishing.net
Crawl and store credit-hours per section. Display credit-hours, but provide no UI for updating them. Fixes bug #114.

Credit-hour crawling support for calvin and cedarville.
12 files changed with 295 insertions and 40 deletions:
0 comments (0 inline, 0 general)
inc/class.schedule.php
Show inline comments
 
<?php /* -*- mode: php; -*- */
 
<?php /* -*- mode: php; indent-tabs-mode: nil; -*- */
 
/*
 
 * Copyright 2010 Nathan Gelderloos, Ethan Zonca, Nathan Phillip Brink
 
 *
 
 * This file is part of SlatePermutate.
 
 *
 
 * SlatePermutate is free software: you can redistribute it and/or modify
 
@@ -20,12 +20,13 @@
 

	
 
$incdir = dirname(__FILE__) . DIRECTORY_SEPARATOR;
 
include_once $incdir . 'class.course.inc';
 
include_once $incdir . 'class.section.php';
 
include_once $incdir . 'class.page.php';
 
require_once $incdir . 'school.inc';
 
require_once $incdir . 'math.inc';
 

	
 
/*
 
 * Load a Classes -> Course converter class for the sake of the
 
 * Schedule::__wakeup() magic function.
 
 */
 
require_once $incdir . 'class.classes_convert.inc';
 
@@ -185,13 +186,13 @@ class Schedule
 
   *   The instructor of this section/section_meeting.
 
   *
 
   * \return
 
   *   NULL on success, a string on error which is a message for the
 
   *   user and a valid XHTML fragment.
 
   */
 
  function addSection($course_name, $letter, $time_start, $time_end, $days, $synonym = NULL, $instructor = NULL, $location = NULL, $type = 'lecture', $slot = 'default')
 
  function addSection($course_name, $letter, $time_start, $time_end, $days, $synonym = NULL, $instructor = NULL, $location = NULL, $type = 'lecture', $slot = 'default', $credit_hours = -1.0)
 
  {
 
    if (empty($letter) && (empty($time_start) || !strcmp($time_start, 'none')) && (empty($time_end) || !strcmp($time_end, 'none')) && empty($days)
 
	&& empty($synonym) && empty($instructor) && empty($location) && (empty($type) || !strcmp($type, 'lecture'))
 
	&& (empty($slot) || !strcmp($slot, 'default')))
 
      return;
 

	
 
@@ -200,19 +201,24 @@ class Schedule
 
	|| $time_start > $time_end)
 
      {
 
	return 'Invalid time specifications for ' . htmlentities($course_name) . '-' . htmlentities($letter)
 
	  . '. Start time: <tt>' . htmlentities($time_start) . '</tt>. End time: <tt>' . htmlentities($time_end) . '</tt>.';
 
      }
 

	
 
    if (!empty($credit_hours) && !is_numeric($credit_hours))
 
      {
 
        return 'Invalid credit-hour specification of <tt>' . htmlentities($credit_hours) . '</tt> for ' . htmlentities($course_name) . '-' . htmlentities($letter) . '. Please use a floating point number or do not enter anything if the number of credit hours is not known.';
 
      }
 

	
 
    foreach ($this->courses as $course)
 
      if (!strcmp($course_name, $course->getName()))
 
	{
 
	  $section = $course->section_get($letter);
 
	  if (!$section)
 
	    {
 
	      $section = new Section($letter, array(), $synonym);
 
              $section = new Section($letter, array(), $synonym, $credit_hours);
 
	      $course->section_add($section, $slot);
 
	    }
 
	  $section->meeting_add(new SectionMeeting($days, $time_start, $time_end, $location, $type, $instructor));
 

	
 
	  return;
 
	}
 
@@ -526,13 +532,13 @@ class Schedule
 
	$min_time = (int)min($time);
 
	$sort_time = FALSE;
 
	foreach ($this->courses as $course)
 
	  foreach ($course as $course_slot)
 
	  {
 
	    for ($si = 0; $si < $course_slot->sections_count(); $si ++)
 
	      foreach ($course_slot->section_get_i($si)->getMeetings() as $meeting)
 
              foreach ($course_slot->section_get_i($si)->getMeetings() as $meeting)
 
		{
 
		  /* Saturdayness */
 
		  if ($meeting->getDay(5))
 
		    {
 
		      $max_day_plusone = 6;
 
		      $have_saturday = TRUE;
 
@@ -584,12 +590,13 @@ class Schedule
 
                  <form action="#"><p class="nospace">
 
                    <label><strong>Display:</strong></label>
 
                    <input id="show-course-title" name="show-course-title" type="checkbox" /><label for="show-course-title">Course Title</label>
 
                    <input id="show-prof" name="show-prof" type="checkbox" checked="checked" /><label for="show-prof">Professor</label>
 
                    <input id="show-location" name="show-location" type="checkbox" /><label for="show-location">Room</label>
 
                    <input id="show-synonym" name="show-synonym" type="checkbox" /><label for="show-synonym">Synonym</label>
 
                    <input id="show-credit-hours" name="show-credit-hours" type="checkbox" /><label for="show-credit-hours">Credits</label>
 
                    <span id="regCodes"><label><a href="#"><strong>Register for Classes</strong></a></label></span></p>
 
                  </form>
 
                </div> <!-- id="show-box" -->'
 
	     . '<div id="the-tabs"><ul>' . "\n";
 

	
 
	$suppressed_permutations = array();
 
@@ -642,12 +649,19 @@ class Schedule
 
	     * section rendered in this permutation. This is used for
 
	     * the ``Registration Numbers'' dialog which noramlly
 
	     * shows users course synonyms.
 
	     */
 
	    $permutation_courses = array();
 

	
 
            /*
 
             * Count the number of credit hours in this particular
 
             * schedule.
 
             */
 
            $credit_hours = array();
 
            $have_credit_hours = FALSE;
 

	
 
	     echo  '      <div class="section" id="tabs-' . ($i+1) . "\">\n";
 
  
 
	    // Beginning of table
 
	    echo "        <table style=\"empty-cells:show;\" border=\"1\" cellspacing=\"0\">\n";
 
				
 
	    // Header row
 
@@ -721,19 +735,30 @@ class Schedule
 
				      $carret = '&#013;' . htmlentities("<br />");
 
				      echo '            <td rowspan="' . $rowspan[$dayLoop]
 
					. '" class="qTipCell ' . $single_multi . ' class' . $j
 
					. '" title="' . htmlentities($title, ENT_QUOTES) . $carret
 
					. 'Prof: ' . htmlentities($current_meeting->instructor_get(), ENT_QUOTES) . $carret
 
					. 'Room: ' . htmlentities($current_meeting->getLocation(), ENT_QUOTES) . $carret
 
					. 'Type: ' . htmlentities($current_meeting->type_get(), ENT_QUOTES) . $carret . '">'
 
                                        . 'Type: ' . htmlentities($current_meeting->type_get(), ENT_QUOTES) . $carret;
 

	
 
                                      $section_credit_hours = $section->credit_hours_get();
 
                                      if ($section_credit_hours >= 0)
 
                                        {
 
                                          $credit_hours[$section->getSynonym()] = $section_credit_hours;
 
                                          $have_credit_hours = TRUE;
 

	
 
                                          echo 'Credits: ' . htmlentities($section_credit_hours, ENT_QUOTES) . $carret;
 
                                        }
 
                                      echo '">'
 
					. '<span class="course-title block">' . htmlentities($title) . '</span>' . PHP_EOL
 
					. htmlentities($course->getName(), ENT_QUOTES) . '-'
 
					. htmlentities($section->getLetter(), ENT_QUOTES) . "\n"
 
					. '<span class="prof block">' . htmlentities($current_meeting->instructor_get(), ENT_QUOTES) . "</span>\n"
 
					. '<span class="location block">' . htmlentities($current_meeting->getLocation(), ENT_QUOTES) . "</span>\n"
 
					. '<span class="synonym block">' . htmlentities($section->getSynonym(), ENT_QUOTES) . "</span>\n"
 
                                        . '<span class="credit-hours block">' . htmlentities($section_credit_hours, ENT_QUOTES) . ' Credits</span>' . PHP_EOL
 
					. "</td>\n";
 

	
 
				      /* for the ``Registration Codes'' dialogue: */
 
				      if (empty($permutations_courses[$j]))
 
					{
 
					  $singleton_course = new Course($course->getName(), $course->title_get());
 
@@ -763,14 +788,19 @@ class Schedule
 
		
 
		// End of row
 
		echo "          </tr>\n";
 
	      }
 

	
 
	    // End of table
 
	    echo "        </table>\n"
 
              . '         <span class="course-data">'.  htmlentities(json_encode($permutation_courses)) . "</span>\n"
 
	    echo "        </table>\n";
 

	
 
            if ($have_credit_hours)
 
              echo '        <p>Credit Hours: ' . sum($credit_hours) . '</p>' . PHP_EOL;
 

	
 
            echo ''
 
              . '        <span class="course-data">'.  htmlentities(json_encode($permutation_courses)) . "</span>\n"
 
	      . '      </div> <!-- id="section' . ($i + 1) . "\" -->\n";
 
	  }
 

	
 
          echo "    </div> <!-- class=\"scontent\" -->\n"
 
	     . "  </div> <!-- class=\"scroller\" -->\n"
 
	     . "</div> <!-- id=\"my-glider\" -->\n"
inc/class.section.php
Show inline comments
 
@@ -32,12 +32,17 @@ class Section
 

	
 
  /* meeting times, array of SectionMeeting */
 
  private $meetings;
 

	
 
  /* the section synonym which uniquely identifies this section/course combination */
 
  private $synonym;
 
  /**
 
   * \brief
 
   *   The number of credit hours this course has.
 
   */
 
  private $credit_hours;
 

	
 
  /**
 
   * \brief
 
   *   Construct a Section.
 
   *
 
   * \param $letter
 
@@ -51,20 +56,21 @@ class Section
 
   *   this. Another example, Cedarville lists different meeting times
 
   *   inside of a single section. Cedarville also lists all lectures
 
   *   and lab meeting times directly in a section's listing.
 
   * \param $synonym
 
   *   Some schools have a unique number for each section. This field
 
   *   is for that number.
 
   * \param $credit_hours
 
   *   The number of credit hours this course is worth.
 
   */
 
  function __construct ($letter, array $section_meetings = array(), $synonym = NULL)
 
  function __construct ($letter, array $section_meetings = array(), $synonym = NULL, $credit_hours = -1.0)
 
  {
 
    $this->letter = $letter;
 

	
 
    $this->meetings = $section_meetings;
 

	
 
    $this->synonym = $synonym;
 
    $this->credit_hours = (float)$credit_hours;
 
  }
 

	
 
  public function getLetter()
 
  {
 
    return $this->letter;
 
  }
 
@@ -90,12 +96,24 @@ class Section
 
  {
 
    return $this->meetings;
 
  }
 

	
 
  /**
 
   * \brief
 
   *   Retrieve the number of credit hours this course has.
 
   * \return
 
   *   The number of credit hours this course has, or a negative
 
   *   number if not specified.
 
   */
 
  public function credit_hours_get()
 
  {
 
    return $this->credit_hours;
 
  }
 

	
 
  /**
 
   * \brief
 
   *   Check if this section conflicts with the given section.
 
   *
 
   * \param $that
 
   *   The other section for which I should check for conflicts.
 
   * \return
 
   *   TRUE if there is a conflict, FALSE otherwise.
 
@@ -199,13 +217,15 @@ class Section
 
  public function to_json_arrays()
 
  {
 
    $json_arrays = array();
 

	
 
    foreach ($this->meetings as $meeting)
 
      {
 
	$json_array = array('section' => $this->letter,
 
	$json_array = array(
 
			    'credit_hours' => $this->credit_hours_get(),
 
			    'section' => $this->letter,
 
			    'synonym' => $this->synonym,
 
			    );
 

	
 
	$json_array += $meeting->to_json_array();
 
	$json_arrays[] = $json_array;
 
      }
 
@@ -238,15 +258,18 @@ class Section
 
    $letter = '';
 
    $synonym = NULL;
 
    foreach ($json_arrays as $meeting)
 
      {
 
	$letter = $meeting['section'];
 
	$synonym = $meeting['synonym'];
 
	if (!isset($json['credit_hours']) || $json['credit_hours'] < 0)
 
	  $json['credit_hours'] = -1.0;
 
	$credit_hours = $json['credit_hours'];
 
	$section_meetings[] = SectionMeeting::from_json_array($meeting);
 
      }
 
    $section = new Section($letter, $section_meetings, $synonym);
 
    $section = new Section($letter, $section_meetings, $synonym, $credit_hours);
 

	
 
    return $section;
 
  }
 

	
 
  /* for legacy unserialization */
 
  private $start;
 
@@ -284,8 +307,11 @@ class Section
 
      {
 
	/* Move the instructor (old $this->prof) property to our SectionMeeting children */
 
	foreach ($this->meetings as $meeting)
 
	  $meeting->instructor_set($this->prof);
 
	unset($this->prof);
 
      }
 

	
 
    if (!isset($this->credit_hours))
 
      $this->credit_hours = -1.0;
 
  }
 
}
inc/class.semester.inc
Show inline comments
 
@@ -207,27 +207,30 @@ class Semester
 
   * \param $section_meeting
 
   *   The SectionMeeting to be added to a section which may or may
 
   *   not already be in this Semester.
 
   * \param $course_slot_id
 
   *   The name of the new CourseSlot to create if the given section
 
   *   does not yet exist.
 
   * \param $credit_hours
 
   *   The number of credit hours of the associated course or a
 
   *   negative value if unknown.
 
   */
 
  public function section_meeting_add($dept, $course, $title, $section, $synonym, $section_meeting, $course_slot_id = 'default')
 
  public function section_meeting_add($dept, $course, $title, $section, $synonym, $section_meeting, $course_slot_id = 'default', $credit_hours = -1.0)
 
  {
 
    $dept = strtoupper($dept);
 
    $course = strtoupper($course);
 

	
 
    if (empty($this->departments[$dept][$course]))
 
      $course_obj = NULL;
 
    else
 
      {
 
	$course_obj = $this->departments[$dept][$course];
 
	$section_obj = $course_obj->section_get($section);
 
      }
 
    if (empty($course_obj) || empty($section_obj))
 
      return $this->section_add($dept, $course, new Section($section, array($section_meeting), $synonym), $title, $course_slot_id);
 
      return $this->section_add($dept, $course, new Section($section, array($section_meeting), $synonym, $credit_hours), $title, $course_slot_id);
 

	
 
    $section_obj->meeting_add($section_meeting);
 
    return;
 
  }
 

	
 
  /**
inc/math.inc
Show inline comments
 
@@ -44,12 +44,32 @@ if (!function_exists('mean'))
 
        }
 

	
 
      return $val;
 
    }
 
  }
 

	
 
if (!function_exists('sum'))
 
  {
 
    /**
 
     * \brief
 
     *   Add all elements in a set together.
 
     *
 
     * \parram $S
 
     *   The set to sum up.
 
     * \return
 
     *   The sum of all elements in the set.
 
     */
 
    function sum($S)
 
    {
 
      $ret = 0;
 
      foreach ($S as $S_i)
 
        $ret += $S_i;
 
      return $ret;
 
    }
 
  }
 

	
 
if (!function_exists('stddev'))
 
  {
 
    function stddev(array $values)
 
    {
 
      $mean = mean($values);
 

	
input.php
Show inline comments
 
@@ -150,13 +150,14 @@ elseif ($errors_fix)
 
		. json_encode(array('m' => !empty($section['days'][0]), 't' => !empty($section['days'][1]), 'w' => !empty($section['days'][2]),
 
				    'h' => !empty($section['days'][3]), 'f' => !empty($section['days'][4]),
 
				    's' => !empty($section['days'][5])))
 
		. ', ' . json_encode($section['professor']) . ', '
 
		. json_encode($section['location']) . ', '
 
		. json_encode($section['type']) . ', '
 
		. json_encode($section['slot']) . ');' . PHP_EOL;
 
		. json_encode($section['slot']) . ', '
 
		. json_encode(isset($section['credit_hours']) ? $section['credit_hours'] : -1) . ');' . PHP_EOL;
 
	  $my_hc .= PHP_EOL;
 
	}
 
  }
 
else
 
  {
 
    $default_courses = school_default_courses($school);
 
@@ -311,12 +312,16 @@ if (!empty($_REQUEST['selectsemester']))
 
        </tr>
 
      </table>
 
    </td>
 
  </tr>
 
</table>
 

	
 
<div class="credit-hours-total">
 
  <p>Credit Hours: <span class="credit-hours-total-value">0</span></p>
 
</div>
 

	
 
<div class="paddingtop">
 
  <input class="button olive" type="submit" value="Find a schedule" />
 
</div>
 

	
 
</form>
 

	
 
@@ -350,12 +355,13 @@ function input_course_js(Course $course,
 
	    . json_encode($meeting->getEndTime()) . ', '
 
	    . json_encode(array('m' => $meeting->getDay(0), 't' => $meeting->getDay(1), 'w' => $meeting->getDay(2), 'h' => $meeting->getDay(3), 'f' => $meeting->getDay(4),
 
				's' => $meeting->getDay(5))) . ', '
 
	    . json_encode($meeting->instructor_get()) . ', '
 
	    . json_encode($meeting->getLocation()) . ', '
 
	    . json_encode($meeting->type_get()) . ', '
 
	    . json_encode($course_slot->id_get()) . ');' . PHP_EOL;
 
	    . json_encode($course_slot->id_get()) . ', '
 
	    . json_encode($section->credit_hours_get()) . ');' . PHP_EOL;
 
	}
 
    }
 

	
 
  return $js;
 
}
process.php
Show inline comments
 
@@ -199,22 +199,24 @@ if(!$DEBUG)
 
	     */
 
	    if(is_array($course) && count($course) > 1)
 
	      {
 
		if (empty($course['title']))
 
		  $course['title'] = '';
 

	
 
		if (empty($course['credit_hours']))
 
		  $course['credit_hours'] = -1;
 
		$allClasses->addCourse($course['name'], $course['title']);
 

	
 
				foreach($course as $section)
 
				  /* Skip the section name, which isn't a section */
 
					if(is_array($section))
 
					  {
 
					    if (empty($section['slot']))
 
					      $section['slot'] = 'default';
 

	
 
					    $error_string = $allClasses->addSection($course['name'], $section['letter'], $section['start'], $section['end'], arrayToDays(empty($section['days']) ? array() : $section['days'], 'alpha'), $section['synonym'], $section['professor'], $section['location'], $section['type'], $section['slot']);
 
					    $error_string = $allClasses->addSection($course['name'], $section['letter'], $section['start'], $section['end'], arrayToDays(empty($section['days']) ? array() : $section['days'], 'alpha'), $section['synonym'], $section['professor'], $section['location'], $section['type'], $section['slot'], $section['credit_hours']);
 
					    if ($error_string !== NULL)
 
					      $errors[] = $error_string;
 
					  }
 
			}
 
		}
 

	
school.d/calvin.crawl.inc
Show inline comments
 
@@ -373,13 +373,13 @@ function calvin_crawl_semester(array $sc
 
	  $meeting_place = $meeting_info_matches[8];
 

	
 
	  foreach (array('date_start', 'date_end', 'meeting_type', 'days', 'time_start', 'time_end', 'meeting_place', 'meeting_type') as $var)
 
	    school_crawl_logf($school_crawl_log, 10, "%s:%s", $var, ${$var});
 

	
 
	  $semester->section_meeting_add($section_id['department'], $section_id['course'], $title, $section_id['section'], $synonym,
 
					 new SectionMeeting($days, $time_start, $time_end, $meeting_place, $meeting_type, $faculty_name));
 
					 new SectionMeeting($days, $time_start, $time_end, $meeting_place, $meeting_type, $faculty_name), 'default', $credits);
 

	
 
	  /*
 
	   * Try to update semester's longetivity stats to help the
 
	   * school_semester_guess() function:
 
	   */
 
	  $date_start_time = strptime($date_start, '%m/%d/%Y');
school.d/cedarville.crawl.inc
Show inline comments
 
@@ -209,12 +209,13 @@ function cedarville_crawl_semester(array
 
	      school_crawl_logf($school_crawl_log, 6, "Error parsing section_id. Given `%s'; interpreted as `%s'. Skipping.",
 
				$course_table[1]->nodeValue, implode('-', $section_parts));
 
	      continue;
 
	    }
 

	
 
          $title = $course_table[2]->nodeValue;
 
	  $credit_hours = $course_table[4]->nodeValue;
 

	
 
	  /*
 
	   * For courses with multiple section meetings, each
 
	   * instructor for each section meeting is separated by <br/>.
 
	   */
 
	  $instructors = array('');
 
@@ -315,13 +316,13 @@ function cedarville_crawl_semester(array
 

	
 
	      $meeting_i ++;
 
	    }
 

	
 
	  $semester->section_add($section_parts['department'], $section_parts['course'],
 
				 new Section($section_parts['section'], $meetings,
 
					     $synonym), $title);
 
					     $synonym, $credit_hours), $title);
 
	}
 
    }
 

	
 
  return 0;
 
}
 

	
school.d/cedarville.inc
Show inline comments
 
@@ -57,14 +57,13 @@ EOF;
 
 *   An array of Course objects.
 
 */
 

	
 
function cedarville_default_courses()
 
{
 
  $chapel = new Course('Chapel','Chapel');
 
  $chapel->section_add(new Section('_', array(new SectionMeeting('mtwhf', '1000', '1045', '', 'chapel','n/a')),
 
				   '', '_'));
 
  $chapel->section_add(new Section('_', array(new SectionMeeting('mtwhf', '1000', '1045', '', 'chapel','n/a'))));
 

	
 
  return array($chapel);
 
}
 

	
 
/**
 
 * \brief
scripts/scheduleInput.js
Show inline comments
 
@@ -18,12 +18,20 @@
 
 */
 

	
 
    //--------------------------------------------------
 
    // General Notes
 
    //--------------------------------------------------
 

	
 
/**
 
 * \brief
 
 *   The next course_i value that will be produced when add_class() is
 
 *   called.
 
 *
 
 * If iterating through all of the possible courses, use (classNum -
 
 * 1) as the upper bound.
 
 */
 
var classNum = 0;
 

	
 
/**
 
 * \brief
 
 *   The number of section entries for a given course.
 
 *
 
@@ -116,13 +124,13 @@ function addTips()
 
}
 

	
 
/**
 
 * \brief
 
 *   Add a section to a class.
 
 */
 
function add_section_n(cnum, name, synonym, stime, etime, days, instructor, location, type, slot)
 
function add_section_n(cnum, name, synonym, stime, etime, days, instructor, location, type, slot, credit_hours)
 
{
 
    var snum = last_section_i ++;
 
    var cssclasses = 'section class' + cnum + ' ' + safe_css_class('slot-' + slot);
 
    var last_tr;
 

	
 
	/*
 
@@ -199,12 +207,13 @@ function add_section_n(cnum, name, synon
 
<td class="cbrow"><input type="checkbox" class="daysRequired" name="postData[' + cnum + '][' + snum + '][days][3]" value="1" ' + (days.h ? 'checked="checked"' : '') + ' /></td>\
 
<td class="cbrow"><input type="checkbox" class="daysRequired" name="postData[' + cnum + '][' + snum + '][days][4]" value="1" ' + (days.f ? 'checked="checked"' : '') + ' /></td>\
 
<td class="cbrow"><input type="checkbox" class="daysRequired" name="postData[' + cnum + '][' + snum + '][days][5]" value="1" ' + (days.s ? 'checked="checked"' : '') + ' /></td>' +
 
	'<td class="removeCell"><div class="deleteSection"><input type="button" value="x" class="gray" /></div></td><td class="emptyCell">' +
 
	'<input class="section-location-entry" type="hidden" name="postData[' + cnum + '][' + snum + '][location]" />' +
 
	'<input class="section-type-entry" type="hidden" name="postData[' + cnum + '][' + snum + '][type]" />' +
 
		'<input class="section-credit-hours-entry" type="hidden" name="postData[' + cnum + '][' + snum + '][credit_hours]" />' +
 
	'</td></tr>';
 

	
 
    /*
 
     * Try to append this section to the last section in its
 
     * associated CourseSlot...
 
     */
 
@@ -230,22 +239,25 @@ function add_section_n(cnum, name, synon
 
    section_tr.find('.section-letter-entry').val(name);
 
    section_tr.find('.section-synonym-entry').val(synonym);
 
    section_tr.find('.section-slot-entry').val(slot);
 
    section_tr.find('.profName').val(instructor);
 
    section_tr.find('.section-location-entry').val(location);
 
    section_tr.find('.section-type-entry').val(type);
 
	section_tr.find('.section-credit-hours-entry').val(credit_hours);
 

	
 
    /* unhide the saturday columns if it's used by autocomplete data */
 
    if (days.s)
 
	jQuery('#jsrows col.saturday').removeClass('collapsed');
 

	
 
	credit_hours_change(cnum);
 

	
 
    return last_section_i - 1;
 
}
 
function add_section(cnum)
 
{
 
    var section_i = add_section_n(cnum, '', '', '', '', {m: false, t: false, w: false, h: false, f: false, s: false}, '', '', '', 'default');
 
    var section_i = add_section_n(cnum, '', '', '', '', {m: false, t: false, w: false, h: false, f: false, s: false}, '', '', '', 'default', -1);
 
    if (cnum == slate_permutate_course_free)
 
	course_free_check(cnum);
 
    return section_i;
 
}
 

	
 
/**
 
@@ -272,27 +284,28 @@ function add_sections(cnum, data)
 
	return;
 

	
 
    jQuery.each(data.sections, function(i, section)
 
		{
 
		    if (!section.slot)
 
			section.slot = 'default';
 
			if (section.credit_hours === undefined)
 
				section.credit_hours = -1;
 

	
 
		    add_section_n(cnum, section.section, section.synonym, section.time_start, section.time_end, section.days, section.instructor, section.location, section.type, section.slot);
 
		    add_section_n(cnum, section.section, section.synonym, section.time_start, section.time_end, section.days, section.instructor, section.location, section.type, section.slot, section.credit_hours);
 
		});
 

	
 
    /*
 
     * Handle course-level interdependencies.
 
     */
 
    if (data.dependencies)
 
	jQuery.each(data.dependencies, function(i, dep)
 
		    {
 
	jQuery.each(data.dependencies, function(i, dep) {
 
			/* Gracefully deprecate the old crawler's JSON format. */
 
			if (dep['class'])
 
			    dep.course = dep['class'];
 

	
 
			var new_course_num = add_class_n(dep.course, dep['title'] ? dep['title'] : '');
 
		var new_course_num = add_class_n(dep.course, dep['title'] ? dep['title'] : '');
 
			add_sections(new_course_num, dep);
 
		    });
 
}
 

	
 
/**
 
 * \brief
 
@@ -364,19 +377,20 @@ function add_class_n(course_id, title)
 
     */
 
    if (course_id.length && slate_permutate_course_free != -1)
 
	course_remove(slate_permutate_course_free);
 

	
 
    sectionsOfClass[classNum] = 0; // Initialize at 0
 
    course_ajax_requests[classNum] = false;
 
    jQuery('#jsrows').append('<tr id="tr-course-' + classNum + '" class="class class' + classNum + ' pclass' + classNum + '"><td class="nameTip"><input type="text" id="input-course-' + classNum + '" class="classRequired defText className'+classNum+' className" title="Class Name" name="postData[' + classNum + '][name]" /></td><td colspan="10"><input type="text" name="postData[' + classNum + '][title]" class="inPlace course-title-entry input-submit-disable" /></td><td class="tdInput"><div class="deleteClass"><input type="button" value="Remove" class="gray" /></div></td><td class="none"><button type="button" class="addSection gray">+</button></td></tr>');
 
    jQuery('#jsrows').append('<tr id="tr-course-' + classNum + '" class="class class' + classNum + ' pclass' + classNum + '"><td class="nameTip"><input type="text" id="input-course-' + classNum + '" class="classRequired defText className'+classNum+' className" title="Class Name" name="postData[' + classNum + '][name]" /></td><td colspan="10"><input type="text" name="postData[' + classNum + '][title]" class="inPlace inPlace-enable course-title-entry input-submit-disable" /><span class="course-credit-hours course-credit-hours-' + classNum + '"></span></td><td class="tdInput"><div class="deleteClass"><input type="button" value="Remove" class="gray" /></div></td><td class="none"><button type="button" class="addSection gray">+</button></td></tr>');
 

	
 
		/* store classNum as course_i into the <tr />: */
 
    var tr_course = jQuery('#tr-course-' + classNum);
 
    tr_course.data({course_i: classNum});
 
    tr_course.find('.course-title-entry').val(title);
 
    tr_course.find('.className').val(course_id);
 
	tr_course.find('.course-credit-hours-label').attr('for', 'course-credit-hours-entry-' + classNum);
 

	
 
		var class_elem = jQuery('.className' + classNum);
 

	
 
		class_elem.autocomplete({ source: 'auto.php?school=' + slate_permutate_school + '&semester=' + slate_permutate_semester });
 
		class_elem.bind('autocompleteselect', {class_num: classNum, class_elem: class_elem},
 
			function(event, ui)
 
@@ -418,13 +432,13 @@ function add_class()
 
{
 
    /*
 
     * Don't add an empty new course entry if there already is
 
     * one. Otherwise, set this new class to be the ``hot'' one.
 
     */
 
    if (slate_permutate_course_free == -1)
 
	slate_permutate_course_free = add_class_n('', '');
 
		slate_permutate_course_free = add_class_n('', '');
 
    return slate_permutate_course_free;
 
}
 

	
 
/**
 
 * \brief
 
 *   Try to fetch a section once the user has chosen an autocomplete
 
@@ -523,12 +537,14 @@ function course_remove(course_i)
 
    /*
 
     * Check if the class intended for the user to
 
     * enter information into has been removed.
 
     */
 
    if (slate_permutate_course_free == course_i)
 
	slate_permutate_course_free = -1;
 

	
 
	credit_hours_change(course_i);
 
}
 

	
 
/**
 
 * \brief
 
 *   Figure whether or not a given course entry has sections.
 
 *
 
@@ -648,12 +664,134 @@ function prettyTime(time_str)
 
 */
 
function safe_css_class(classname)
 
{
 
    return classname;
 
}
 

	
 
/**
 
 * \internal
 
 * \brief
 
 *   Whether or not to display the credit_hours column is currently
 
 *   being displayed to the user.
 
 *
 
 * An internal state variable for show_credit_hours().
 
 */
 
var credit_hours_shown = false;
 

	
 
/**
 
 * \brief
 
 *   Display the Credit Hours column to the user.
 
 */
 
function show_credit_hours()
 
{
 
	if (credit_hours_shown)
 
		return;
 

	
 
	jQuery('#content').addClass('credit-hours-shown');
 

	
 
	credit_hours_shown = true;
 
}
 

	
 
/**
 
 * \brief
 
 *   Hide the Credit Hours column from the user.
 
 */
 
function hide_credit_hours()
 
{
 
	if (!credit_hours_shown)
 
		return;
 

	
 
	jQuery('#content').removeClass('credit-hours-shown');
 

	
 
	credit_hours_shown = false;
 
}
 

	
 
/**
 
 * \brief
 
 *   State for the displification of the total number of credit hours.
 
 */
 
var credit_hours = [];
 

	
 
/**
 
 * \brief
 
 *   Update the running credit hours total.
 
 */
 
function credit_hours_change(course_i)
 
{
 
	var objs = jQuery('.section.class' + course_i + ' .section-credit-hours-entry');
 

	
 
	if (objs.length)
 
	{
 
		var course_credit_hours = {min: -1, max: -1};
 

	
 
		objs.each(function(i, e) {
 
			var obj = jQuery(e);
 
			var section = obj.closest('.section').find('.section-letter-entry').val();
 

	
 
			var val = obj.val();
 
			if (!val.length)
 
				return true;
 
			var hours = parseFloat(val);
 
			if (!isNaN(hours) && hours >= 0)
 
			{
 
				if (hours > course_credit_hours.max)
 
					course_credit_hours.max = hours;
 
				if (course_credit_hours.min < 0 || hours < course_credit_hours.min)
 
					course_credit_hours.min = hours;
 
			}
 
		});
 
		credit_hours[course_i] = course_credit_hours;
 

	
 
		if (course_credit_hours.min >= 0)
 
		{
 
			var text = course_credit_hours.min;
 
			if (course_credit_hours.max != course_credit_hours.min)
 
				text += '-' + course_credit_hours.max;
 
			text += ' Credits';
 
			jQuery('#tr-course-' + course_i + ' .course-credit-hours').text(text);
 
		}
 
	}
 
	else
 
		/* course_i was deleted or is void */
 
		credit_hours[course_i] = {min: -1, max: -1};
 

	
 
	var credit_hours_total = {min: 0, max: 0};
 
	var saw_credit_hours = false;
 
	var course_j;
 
	for (course_j = 0; course_j < classNum; course_j ++)
 
	{
 
		if (credit_hours[course_j] === undefined)
 
			continue;
 

	
 
		/* Ignore deleted courses */
 
		if (credit_hours[course_j] && !jQuery('tr.class' + course_j).length)
 
		{
 
			credit_hours[course_j] = undefined;
 
			continue;
 
		}
 

	
 
		/* Ignore courses which have no credit_hours set. */
 
		if (credit_hours[course_j].min < 0)
 
			continue;
 
		saw_credit_hours = true;
 

	
 
		credit_hours_total.min += credit_hours[course_j].min;
 
		credit_hours_total.max += credit_hours[course_j].max;
 
	}
 

	
 
	if (saw_credit_hours)
 
		show_credit_hours();
 
	else
 
		hide_credit_hours();
 

	
 
	var text = credit_hours_total.min;
 
	if (credit_hours_total.max != credit_hours_total.min)
 
		text += '-' + credit_hours_total.max;
 
	jQuery('.credit-hours-total-value').text(text);
 
}
 

	
 
//--------------------------------------------------
 
// Items bound to pageload/events
 
//--------------------------------------------------
 
jQuery(document).ready(function() {
 

	
 
	//--------------------------------------------------
 
@@ -677,13 +815,12 @@ jQuery(document).ready(function() {
 
	//--------------------------------------------------
 
	// Deletes the selected section from the input
 
	//--------------------------------------------------
 
	jQuery('.deleteSection').live('click', function() {
 
	  // Decreases the total number of classes
 
		var course_i = jQuery(this).parent().parent().data('course_i');
 
		sectionsOfClass[course_i]--;
 

	
 
	  // Find the ID cell of the row we're in
 
	  var row = jQuery(this).parent().parent().find(".sectionIdentifier");
 

	
 
	  // The first input is the one containing the section ID
 
	  var toMatch = jQuery(row).find("input").val();
 
@@ -691,15 +828,16 @@ jQuery(document).ready(function() {
 
	  // This gets the second class of the row, "class#"
 
	  var classClass = "." + jQuery(row).parent().attr("class").split(" ")[1];
 

	
 
	  // Iterate over each section of this class
 
	  jQuery(classClass).each( function() {
 
	    // If this section has the same course ID as the item clicked, remove it.
 
	    if(jQuery(this).find("input").val() == toMatch){
 
		jQuery(this).remove();
 
	    }
 
		  if(jQuery(this).find("input").val() == toMatch) {
 
			  jQuery(this).remove();
 
			  sectionsOfClass[course_i]--;
 
	      }
 
	  });
 
	  course_free_check(course_i);
 
	});
 

	
 
	jQuery('.className').live('change', course_free_check).live('keyup', course_free_check);
 

	
 
@@ -767,14 +905,14 @@ jQuery(document).ready(function() {
 
	});
 

	
 

	
 
        //-------------------------------------------------
 
        // Style course titles as inputs when clicked
 
        //-------------------------------------------------
 
        jQuery('.course-title-entry').live('click', function() {
 
          jQuery(this).toggleClass('inPlace');
 
        jQuery('.inPlace-enable').live('click', function() {
 
          jQuery(this).removeClass('inPlace');
 
        });
 
    /*
 
     * Prevent accidental form submission for className and course
 
     * title entry text fields.
 
     */
 
    jQuery('.input-submit-disable').live('keyup keydown', slate_permutate_nullify_enter);
 
@@ -785,10 +923,15 @@ jQuery(document).ready(function() {
 
				      course_autocomplete(jQuery(this).parent().parent().data('course_i'));
 

	
 
				      /* Prevent form submission like slate_permutate_nullify_enter() does. */
 
				      return false;
 
				  }
 
			      });
 
        jQuery('.course-title-entry').live('blur', function() {
 
        jQuery('.inPlace-enable').live('blur', function() {
 
          jQuery(this).addClass('inPlace');
 
        });
 

	
 
	credit_hours_shown = jQuery('#content').is('.credit-hours-shown');
 
	jQuery('.section-credit-hours-entry').live('change', function() {
 
		credit_hours_change(jQuery(this).closest('.section').data('course_i'));
 
	});
 
});
styles/general.css
Show inline comments
 
/*
 
 * Copyright 2010 Nathan Gelderloos, Ethan Zonca, Nathan Phillip Brink
 
 * Copyright 2011 Nathan Gelderloos, Ethan Zonca, Nathan Phillip Brink
 
 *
 
 * This file is part of SlatePermutate.
 
 *
 
 * SlatePermutate is free software: you can redistribute it and/or modify
 
 * it under the terms of the GNU Affero General Public License as published by
 
 * the Free Software Foundation, either version 3 of the License, or
 
@@ -123,12 +123,21 @@ a:hover {
 
#container td {
 
  padding: .17em;
 
}
 
#container .class td {
 
  background: #70a97c; 
 
}
 
#container .class input
 
{
 
    display: inline-block;
 
}
 
#container .class .course-credit-hours
 
{
 
    width: 20%;
 
    text-align: right;
 
}
 
#container .tdInput {
 
  background: none!important; 
 
}
 
#container td.center {
 
  text-align:center;
 
}
 
@@ -384,25 +393,40 @@ a:hover {
 

	
 
  font: normal bold 1.2em sans-serif;
 
}
 

	
 
.course-title-entry
 
{
 
    width: 80%;
 
    width: 70%;
 
}
 

	
 
.tr-slot-id-hidden
 
{
 
  display: none;
 
}
 

	
 
.inPlace {
 
  color: #000;
 
  border: none;
 
  border-color: transparent;
 
  background: transparent;
 
}
 

	
 
.warning
 
{
 
  background: #ffffdd;
 
  border: 1pt solid yellow;
 
}
 

	
 
#content .course-credit-hours,
 
#content .credit-hours-total
 
{
 
    display: none;
 
}
 

	
 
#content.credit-hours-shown .course-credit-hours
 
{
 
    display: inline-block;
 
}
 
#content.credit-hours-shown .credit-hours-total
 
{
 
    display: block;
 
}
styles/output.css
Show inline comments
 
@@ -77,13 +77,14 @@ td{
 
  border-style:none none solid solid;
 
  background: #F0F0F0;
 
}
 

	
 
.prof,
 
.location,
 
.synonym
 
.synonym,
 
.credit-hours
 
{
 
    color: #444444;
 
    font-size: small;
 
}
 

	
 
/* Class Coloring */
0 comments (0 inline, 0 general)