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 288 insertions and 33 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
 
 * 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
 
 * (at your option) any later version.
 
 *
 
 * SlatePermutate is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU Affero General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU Affero General Public License
 
 * along with SlatePermutate.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
$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';
 

	
 
/**
 
 * \brief
 
 *   Finds possible Section combinations for a user's given Courses
 
 *   and stores and displays the results.
 
 *
 
@@ -179,46 +180,51 @@ class Schedule
 

	
 
  /**
 
   * \brief
 
   *   Adds a section to this semester after finding the class.
 
   *
 
   * \param $instructor
 
   *   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;
 

	
 
    /* reject invalid times */
 
    if (!strcmp($time_start, 'none') || !strcmp($time_end, 'none')
 
	|| $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;
 
	}
 

	
 
    error_log('Could not find class when parsing schedule from postData: ' . $course_name);
 
    echo 'Could not find class: ' . $course_name . "<br />\n";
 
  }
 

	
 
  /**
 
@@ -578,24 +584,25 @@ class Schedule
 
	  . '          the information you enter correctly.' . PHP_EOL
 
	  . '        </em>' . PHP_EOL
 
	  . '      </p>' . PHP_EOL
 
	  . '    </div>' . PHP_EOL;
 
	echo '<div id="tabs">' . "\n" .
 
               '<div id="show-box" class="show-buttons">
 
                  <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();
 
	if (!empty($_REQUEST['print']))
 
	  {
 
	    $print = $_REQUEST['print'];
 
	    if ($print !== 'all')
 
	      {
 
		for ($i = $first_permutation; $i <= $last_permutation; $i ++)
 
@@ -636,24 +643,31 @@ class Schedule
 
	     */
 
	    if (!empty($suppressed_permutations[$i]))
 
	      continue;
 

	
 
	    /*
 
	     * Store a JSON list of courses, each with only the one
 
	     * 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
 
	    echo "          <tr>\n"
 
	      . '            <td class="none permuteNum">' . ($i + 1) . "</td>\n"
 
	      . "            <td class=\"day\">Monday</td>\n"
 
	      . "            <td class=\"day\">Tuesday</td>\n"
 
	      . "            <td class=\"day\">Wednesday</td>\n"
 
	      . "            <td class=\"day\">Thursday</td>\n"
 
@@ -715,31 +729,42 @@ class Schedule
 
				      $title = $course->title_get();
 
				      if (empty($title))
 
					$title = '';
 
				      else
 
					$title .= ' ';
 

	
 
				      $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());
 
					  $singleton_course->section_add($section, $course_slot->id_get());
 
					  $permutation_courses[$j] = $singleton_course->to_json_array();
 
					}
 

	
 
				      $filled = TRUE;
 
				    }
 
@@ -757,25 +782,30 @@ class Schedule
 
			if(!$filled)
 
			{
 
				echo "            <td class=\"none\">&nbsp;</td>\n";
 
			}
 
			$filled = FALSE;
 
		}
 
		
 
		// End of row
 
		echo "          </tr>\n";
 
	      }
 

	
 
	    // End of table
 
	    echo "        </table>\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"
 
	     . $footcloser; // Closes off the content div
 
      } else {
 
      echo '<html><body><p>There are no possible schedules. Please <a href="input.php?s='.$this->id.'">try again</a>.</p></body></html>';
 
    }
 

	
inc/class.section.php
Show inline comments
 
@@ -26,51 +26,57 @@ require_once dirname(__FILE__) . DIRECTO
 
 */
 
class Section
 
{
 

	
 
  private $letter;	// Section letter
 
  private $prof;	// Professor, preserved for Section::__wakeup()
 

	
 
  /* 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
 
   *   The identifier (often a letter or numeral) of this section. For
 
   *   CS-262-A, this would be 'a'.
 
   * \param $section_meetings
 
   *   An array of SectionMeeting objects which describe all the
 
   *   different types of meetings this particular section has. It
 
   *   will be very uncommon for a course to have more than one such
 
   *   meeting time for a section. For example, Calvin doesn't have
 
   *   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;
 
  }
 

	
 
  /**
 
   * \return
 
   *   This section's synonym -- a unique numeric identifier for this
 
   *   course. NULL if undefined.
 
   */
 
@@ -84,24 +90,36 @@ class Section
 
   *   Get an array of section meetings for this section.
 
   *
 
   * \return
 
   *   An array of SectionMeeting objects.
 
   */
 
  public function getMeetings()
 
  {
 
    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.
 
   */
 
  public function conflictsWith(Section $that)
 
  {
 
    foreach ($this->meetings as $this_meeting)
 
      foreach ($that->meetings as $that_meeting)
 
      if ($this_meeting->conflictsWith($that_meeting))
 
@@ -193,25 +211,27 @@ class Section
 
   *   Get arrays of information needed by the AJAX stuff.
 
   *
 
   * \return
 
   *   An array of arrays that should be merged with the return value
 
   *   of other Section::to_json_arrays() calls.
 
   */
 
  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;
 
      }
 

	
 
    return $json_arrays;
 
  }
 

	
 
  /**
 
   * \brief
 
@@ -232,27 +252,30 @@ class Section
 
   * \return
 
   *   A Section object.
 
   */
 
  public static function from_json_arrays(array $json_arrays)
 
  {
 
    $section_meetings = array();
 
    $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;
 
  private $tend;
 
  private $bdays;
 

	
 
  /**
 
   * \brief
 
   *   A magic function which tries to upgrade old serialized sections
 
@@ -278,14 +301,17 @@ class Section
 
	/*
 
	 * if we're reserialized in the future, make sure we don't do this same upgrade procedure again ;-).
 
	 */
 
	unset($this->start);
 
      }
 
    elseif (!empty($this->prof))
 
      {
 
	/* 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
 
@@ -201,39 +201,42 @@ class Semester
 
   *   NULL.
 
   *   belongs to.
 
   * \param $section
 
   *   The letter or numbers which make up the section's name.
 
   * \param $synonym
 
   *   The section synonym or NULL.
 
   * \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;
 
  }
 

	
 
  /**
 
   * \brief
 
   *   Update the time_end.
 
   *
 
   * The time_end is a unix timestamp roughly estimating the time at
 
   * which a semester starts. It is used when guessing what semester a
 
   * user is interested in.
inc/math.inc
Show inline comments
 
@@ -38,24 +38,44 @@ if (!function_exists('mean'))
 
      $i = 0;
 
      foreach ($values as $value)
 
        {
 
          $val = $val * $i / ($i + 1)
 
            + $value / ($i + 1);
 
          $i ++;
 
        }
 

	
 
      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);
 

	
 
      $squares = 0;
 
      $i = 0;
 
      foreach ($values as $value)
 
        $squares += pow($mean - $value, 2);
 
      return sqrt($squares / (count($values) - 1));
 
    }
input.php
Show inline comments
 
@@ -144,25 +144,26 @@ elseif ($errors_fix)
 
	    $my_hc .= '    class_last = add_class_n(' . json_encode($course['name']) . ', ' . json_encode($title) . ');' . PHP_EOL;
 
	  foreach ($course as $section)
 
	    if (is_array($section))
 
	      $my_hc .= '    add_section_n(class_last, ' . json_encode($section['letter']) . ', '
 
		. json_encode($section['synonym']) . ', ' . json_encode($section['start']) . ', '
 
		. json_encode($section['end']) . ', '
 
		. 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);
 
    foreach ($default_courses as $default_class)
 
      $my_hc .= input_course_js($default_class, '    ');
 
  }
 
$my_hc .= '    class_last = add_class();' . PHP_EOL;
 
if ($qtips_always || !isset($_SESSION['saw_qtips']))
 
  {
 
@@ -305,24 +306,28 @@ if (!empty($_REQUEST['selectsemester']))
 
          <td class="center">W</td>
 
          <td class="center">Th</td>
 
          <td class="center">F</td>
 
	  <td class="center">S</td>
 
          <td class="center"></td>
 
          <td class="center"></td>
 
        </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>
 

	
 
<?php 
 

	
 
/* Show/hide Advanced Options: <p><span id="showadvanced" style="margin-left: 1em;"><a href="#">Advanced</a></span></p> */ 
 
?>
 
<div id="showInstructions" style="width: 100%; text-align: center;"><a href="#">Detailed Instructions...</a></div>
 

	
 
@@ -344,18 +349,19 @@ function input_course_js(Course $course,
 
	$meetings = $section->getMeetings();
 
      foreach ($meetings as $meeting)
 
	{
 
	  $js .= $whitespace . 'add_section_n(class_last, ' . json_encode($section->getLetter()) . ', '
 
	    . json_encode($section->getSynonym()) . ', '
 
	    . json_encode($meeting->getStartTime()) . ', '
 
	    . 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
 
@@ -193,34 +193,36 @@ if(!$DEBUG)
 
	  {
 
	    /*
 
	     * Only add classes if the user added at least one
 
	     * section to the class. We know that $course['name']
 
	     * is not a section, so count() needs to be > 1 and
 
	     * we need to skip over 'name' in our loop.
 
	     */
 
	    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;
 
					  }
 
			}
 
		}
 

	
 
		/*
 
		 * Tell the user that his input is erroneous and
 
		 * require him to fix it.
 
		 */
 
		if (count($errors))
 
		  {
school.d/calvin.crawl.inc
Show inline comments
 
@@ -367,25 +367,25 @@ function calvin_crawl_semester(array $sc
 
	  /* e.g., 'Lecture', 'Practicum' */
 
	  $meeting_type = school_crawl_meeting_type($meeting_info_matches[3]);
 

	
 
	  $days = school_crawl_days_format($school_crawl_log, explode(', ', $meeting_info_matches[5]));
 
	  $time_start = school_crawl_time_format(strptime($meeting_info_matches[6], '%I:%M%p'));
 
	  $time_end = school_crawl_time_format(strptime($meeting_info_matches[7], '%I:%M%p'));
 
	  $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');
 
	  $date_end_time = strptime($date_end, '%m/%d/%Y');
 

	
 
	  if ($date_start_time !== FALSE)
 
	    {
 
	      $date_start_time = school_crawl_gmmktime($date_start_time, -5 * 60*60);
 
	      $semester->time_start_pool_add($date_start_time);
school.d/cedarville.crawl.inc
Show inline comments
 
@@ -203,24 +203,25 @@ function cedarville_crawl_semester(array
 
	   */
 

	
 
	  $synonym = $course_table[0]->nodeValue;
 
	  $section_parts = Section::parse($course_table[1]->nodeValue);
 
	  if (count($section_parts) < 3)
 
	    {
 
	      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('');
 
	  foreach ($course_table[3]->childNodes as $child)
 
	    switch ($child->nodeType)
 
	      {
 
	      case XML_ELEMENT_NODE:
 
		end($instructors);
 
		if (!strcmp($child->tagName, 'br')
 
@@ -309,25 +310,25 @@ function cedarville_crawl_semester(array
 
	       */
 
	      if ($meeting_i >= count($instructors))
 
		$instructors[$meeting_i] = $instructors[0];
 

	
 
	      $meetings[] = new SectionMeeting($days, $time_start, $time_end,
 
					       $room, $type, $instructors[$meeting_i]);
 

	
 
	      $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;
 
}
 

	
 
/**
 
 * \brief
 
 *   Look up the URI used to access information about a particular
 
 *   Cedarville semester.
 
 *
 
 * \param $semester
school.d/cedarville.inc
Show inline comments
 
@@ -51,26 +51,25 @@ EOF;
 
/**
 
 * \brief
 
 *   Get a list of default classes (with sections (with meeting
 
 *   times)) for Cedarville students.
 
 *
 
 * \return
 
 *   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
 
 *   Implement <school_id>_page_css().
 
 */
 
function cedarville_page_css($school)
 
{
 
  return <<<CSS
 
#container .type-lab .sectionIdentifier,
scripts/scheduleInput.js
Show inline comments
 
@@ -12,24 +12,32 @@
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU Affero General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU Affero General Public License
 
 * along with SlatePermutate.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
    //--------------------------------------------------
 
    // 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.
 
 *
 
 * Key is course_i, value is the current number of sections.
 
 */
 
var sectionsOfClass = new Array();
 

	
 
/**
 
 * \brief
 
@@ -110,25 +118,25 @@ function addTips()
 
        my: 'top left', 
 
        at: 'bottom right'
 
      }
 
    }
 
  );
 

	
 
}
 

	
 
/**
 
 * \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;
 

	
 
	/*
 
	 * Add the type of the course to the CSS if it's a valid (and
 
	 * _clean-looking_ CSS class). Supports things like Cedarville's
 
	 * coloration of labs/ILB.
 
	 */
 
	if (/[a-z-]+/.exec(type) != null)
 
		cssclasses += ' type-' + type;
 
@@ -193,24 +201,25 @@ function add_section_n(cnum, name, synon
 
    }
 

	
 
    section_html = section_html + '</select></td>\
 
<td class="cbrow"><input type="checkbox" class="daysRequired" name="postData[' + cnum + '][' + snum + '][days][0]" value="1" ' + (days.m ? 'checked="checked"' : '') + ' /></td>\
 
<td class="cbrow"><input type="checkbox" class="daysRequired" name="postData[' + cnum + '][' + snum + '][days][1]" value="1" ' + (days.t ? 'checked="checked"' : '') + ' /></td>\
 
<td class="cbrow"><input type="checkbox" class="daysRequired" name="postData[' + cnum + '][' + snum + '][days][2]" value="1" ' + (days.w ? 'checked="checked"' : '') + ' /></td>\
 
<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...
 
     */
 
    last_tr = jQuery('tr.class' + cnum + '.' + safe_css_class('slot-' + slot) + ':last');
 
    if (!last_tr.length)
 
    {
 
	/* Also append a a new ``we are this slot'' row... */
 
	course_add_slot_row(cnum, slot);
 
	last_tr = jQuery('tr.class' + cnum + ':last');
 
@@ -224,34 +233,37 @@ function add_section_n(cnum, name, synon
 

	
 
    /*
 
     * Store data into the newly created HTML. With this method we
 
     * have to _avoid_ escaping entities in the text we're setting as
 
     * values because the DOM stuff will escape it for us.
 
     */
 
    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;
 
}
 

	
 
/**
 
 * Add a list of sections gotten via an AJAX call.
 
 */
 
function add_sections(cnum, data)
 
{
 
    var i;
 

	
 
@@ -266,34 +278,35 @@ function add_sections(cnum, data)
 
    if (data['class'])
 
	data.course = data['class'];
 
    if (data.course)
 
	jQuery('.className' + cnum).val(data.course);
 

	
 
    if (!data.sections)
 
	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'] : '');
 
			add_sections(new_course_num, dep);
 
		    });
 
}
 

	
 
/**
 
 * \brief
 
 *   Adds an identifier for a course slot.
 
@@ -358,31 +371,32 @@ function enable_course_slots()
 
 */
 
function add_class_n(course_id, title)
 
{
 
    /*
 
     * If we're adding a course entry form with preadded
 
     * content, first remove the empty course.
 
     */
 
    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)
 
			    {
 
				if (!ui.item)
 
				    return;
 

	
 
				if (ui.item.value.indexOf('-') != -1)
 
				    {
 
@@ -517,24 +531,26 @@ function course_autocomplete(course_i, t
 
 *   the PHP cares about).
 
 */
 
function course_remove(course_i)
 
{
 
    jQuery('.class' + course_i).remove();
 

	
 
    /*
 
     * 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.
 
 *
 
 * \param course_i
 
 *   The internal javascript representation of a course entry.
 
 * \return
 
 *   true or false.
 
 */
 
function course_has_sections(course_i)
 
@@ -642,24 +658,146 @@ function prettyTime(time_str)
 
/**
 
 * \brief
 
 *   Takes any value classname and tries to smooth it out to a valid
 
 *   CSS class name.
 
 *
 
 * \todo STUB
 
 */
 
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() {
 

	
 
	//--------------------------------------------------
 
	// Deletes the selected class from input
 
	//--------------------------------------------------
 
	jQuery('.deleteClass').live('click', function() {
 
	    /* The user is not allowed to interactively delete the one empty course */
 
	    var course_i = jQuery(this).parent().parent().data('course_i');
 
	    if (slate_permutate_course_free == course_i)
 
@@ -671,40 +809,40 @@ jQuery(document).ready(function() {
 
		course_remove(course_i);
 
		return false;
 
	    }
 
	    return false;
 
	});
 

	
 
	//--------------------------------------------------
 
	// 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();
 
	    
 
	  // 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();
 
			  sectionsOfClass[course_i]--;
 
	    }
 
	  });
 
	  course_free_check(course_i);
 
	});
 

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

	
 
	//--------------------------------------------------
 
	// Bind the section-adding method
 
	//--------------------------------------------------
 
	jQuery('.addSection').live('click', function() {
 
		var course_i = jQuery(this).parent().parent().data('course_i');
 
@@ -761,34 +899,39 @@ jQuery(document).ready(function() {
 
		jQuery('#showLess').show();
 
        });
 
        jQuery('#showLess').click( function() {
 
		jQuery('.hidden').hide();
 
		jQuery('#showMore').show();
 
		jQuery('#showLess').hide();
 
	});
 

	
 

	
 
        //-------------------------------------------------
 
        // 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);
 
    jQuery('.className').live('keyup keydown', function(e)
 
			      {
 
				  if (e.which == 13)
 
				  {
 
				      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
 
 * (at your option) any later version.
 
 *
 
 * SlatePermutate is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU Affero General Public License for more details.
 
@@ -117,24 +117,33 @@ a:hover {
 
  text-decoration: underline;
 
}
 

	
 

	
 
/* Table Styling */
 

	
 
#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;
 
}
 
#container .section:nth-child(even) td {
 
  background: #EEE;
 
}
 
#container .section:nth-child(odd) td {
 
  background: #CCC;
 
}
 
@@ -378,31 +387,46 @@ a:hover {
 
  border-color: #303030;
 
  border-width: 2px;
 
  color: #f3f3f3;
 
  background-color: #505050;
 

	
 
  background: rgba(80,80,80,.9)!important;
 

	
 
  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
 
@@ -71,25 +71,26 @@ td{
 
{
 
  border-style:none none solid none; 
 
  border-bottom: 1px solid #aaa;
 
  white-space: nowrap;
 
}
 
.day{
 
  border-style:none none solid solid;
 
  background: #F0F0F0;
 
}
 

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

	
 
/* Class Coloring */
 
.multi {  }
 
.class0 { background: #69c76f; }
 
.class1 { background: #c5c769; }
 
.class2 { background: #c76b69; }
 
.class3 { background: #696fc7; }
 
.class4 { background: #69a7c7; }
0 comments (0 inline, 0 general)