Changeset - e01a189f2233
[Not reviewed]
default
0 2 0
Nathan Brink (binki) - 15 years ago 2011-03-21 00:08:44
ohnobinki@ohnopublishing.net
Ensure that there is always at least and only one empty course entry line. Readd the ``Add section'' button for a few moments.
2 files changed with 140 insertions and 12 deletions:
0 comments (0 inline, 0 general)
input.php
Show inline comments
 
@@ -51,30 +51,29 @@ if ($sch)
 
{
 
  $nclasses = $sch->nclasses_get();
 
  for ($class_key = 0; $class_key < $nclasses; $class_key ++)
 
    {
 
      $my_hc .= input_class_js($sch->class_get($class_key), '    ');
 
    }
 
}
 
else
 
  {
 
    $default_courses = school_default_courses($school);
 
    foreach ($default_courses as $default_class)
 
      $my_hc .= input_class_js($default_class, '    ');
 
    $my_hc .= '    class_last = add_class();
 
';
 
  }
 
$my_hc .= '    class_last = add_class();' . PHP_EOL;
 
if ($qtips_always || !isset($_SESSION['saw_qtips']))
 
  {
 
    $my_hc .= '        addTips();' . PHP_EOL;
 
    $my_hc .= '    addTips();' . PHP_EOL;
 
    $_SESSION['saw_qtips'] = TRUE;
 
  }
 
$my_hc .= '  });
 
';
 

	
 
$inputPage->headcode_add('scheduleInput', $inputPage->script_wrap($my_hc), TRUE);
 

	
 
$inputPage->head();
 

	
 
/*
 
 * Force a student to choose a school or declare he's a generic
 
 * student before displaying the input form. To do this, we need
scripts/scheduleInput.js
Show inline comments
 
@@ -13,26 +13,56 @@
 
 * 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
 
    //--------------------------------------------------
 

	
 
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
 
 *   Help to generate a unique section identifier for each section
 
 *   added to a given course.
 
 *
 
 * Necessary to support PHP-style post array thingies, like
 
 * classes[0][1][$x] would be all of the data for course_i=0,
 
 * section_i=1, variable $x (ex. day of week, start time, end time,
 
 * teacher). We can't have two sections for a given course using the
 
 * same section_i because those values would override eachother.
 
 */
 
var last_section_i = 0;
 

	
 
/*
 
 * \brief
 
 *   The course number which contains nothing.
 
 *
 
 * To avoid having a user need to click the ``Add course'' button, we
 
 * keep a course added at the end of the list of courses. If this
 
 * variable is -1, it indicates that no such free course exists. If it
 
 * is zero or greater, that number is the class which is the free one.
 
 */
 
var slate_permutate_course_free = -1;
 

	
 
    //--------------------------------------------------
 
    // Validation Functions
 
    //--------------------------------------------------      
 

	
 
	//--------------------------------------------------
 
	// Default Error Message
 
	//--------------------------------------------------
 
	jQuery.each(jQuery.validator.messages, function(i) {
 
		jQuery.validator.messages[i] = "<p class=\"error\">Please fill the field</p>";
 
	});
 

	
 
@@ -85,25 +115,25 @@ jQuery.validator.addMethod('classRequire
 
			       if (cnum < 0 || cnum > classNum)
 
				   alert('JS error: ' + cnum + ' is an invalid class number.');
 

	
 
			       /*
 
				* ignore the class with no
 
				* sections. This only works when the
 
				* class was added and the user _never_
 
				* clicked the Add Section button. Once
 
				* the user clicks that button, he has
 
				* to delete the class because of how
 
				* our numbering works.
 
				*/
 
			       if (!sectionsOfClass[cnum])
 
			       if (!course_has_sections(cnum))
 
				   return true;
 

	
 
			       return false;
 
			   },
 
			   '<p class="error">Enter Class Name.</p>');
 

	
 
	//--------------------------------------------------
 
	// Add validation rules
 
	//--------------------------------------------------
 
	jQuery.validator.addClassRules("selectRequired", {
 
		selectNone: true
 
	});
 
@@ -120,25 +150,25 @@ jQuery.validator.addClassRules('classReq
 
/**
 
 * \brief
 
 * Returns the common inputs for each new section.
 
 */
 
function genSectionHtml(cnum)
 
{
 
    genSectionHtml_n(cnum, '', '', '', '', '', '', '');
 
}
 

	
 
/* @TODO: This should select & set items based on args, if the args != '' */
 
function genSectionHtml_n(cnum, name, synonym, stime, etime, days, prof, location, type)
 
{
 
		var snum = sectionsOfClass[cnum];
 
    var snum = last_section_i ++;
 
		
 
		var cssclasses = 'section class' + cnum;
 
		if(type == 'lab') {
 
		    cssclasses += ' lab';
 
		}
 
		
 
		var result = '<tr class="' + cssclasses + '"><td class="none"></td>';
 
	        result = result + '<td class="sectionIdentifier center"><input type="text" size="1" class="required" name="postData[' + cnum + '][' + snum + '][letter]" value="' + name + '" /><input type="hidden" name="postData[' + cnum + '][' + snum + '][synonym]" value="' + synonym + '" /></td>';
 
		result = result + '<td class="professor center"><input type="text" size="10" class="profName" name="postData[' + cnum + ']['+ snum + '][professor]" value="' + prof + '" /></td>';
 
		result = result + '<td><select class="selectRequired" name="postData[' + cnum + '][' + snum + '][start]"><option value="none"></option>' +
 
		    genOptionHtml("0700", "7:00 am", stime) + genOptionHtml("0730", "7:30 am", stime) +
 
		    genOptionHtml("0800", "8:00 am", stime) + genOptionHtml("0830", "8:30 am", stime) +
 
@@ -240,24 +270,27 @@ function addTips()
 
  });
 
}
 

	
 
/**
 
 * \brief
 
 *   Add a section to a class.
 
 */
 
function add_section_n(cnum, name, synonym, stime, etime, days, prof, location, type)
 
{
 
    jQuery('.pclass'+cnum).after(genSectionHtml_n(cnum, name, synonym, stime, etime, days, prof, location, type));
 
    sectionsOfClass[cnum] ++;
 

	
 
    /* store course_i in a place the newly added section will look for it */
 
    jQuery('.pclass' + cnum).next().data({course_i: cnum});
 

	
 
    /* unhide the saturday columns if it's used by autocomplete data */
 
    if (days.s)
 
	jQuery('#jsrows col.saturday').removeClass('collapsed');
 
}
 
function add_section(cnum)
 
{
 
    return add_section_n(cnum, '', '', '', '', {m: false, t: false, w: false, h: false, f: false, s: false}, '', '', '');
 
}
 

	
 
/**
 
 * Add a list of sections gotten via an AJAX call.
 
 */
 
@@ -284,26 +317,33 @@ function add_sections(cnum, data)
 
	jQuery.each(data.dependencies, function(i, dep)
 
		    {
 
			var new_course_num = add_class_n(dep['class']);
 
			add_sections(new_course_num, dep);
 
		    });
 
}
 

	
 
	//--------------------------------------------------
 
	// Adds a new class to the input.
 
	//--------------------------------------------------
 
	function add_class_n(name)
 
	{
 
	    /*
 
	     * If we're adding a course entry form with preadded
 
	     * content, first remove the empty course.
 
	     */
 
	    if (name.length && slate_permutate_course_free != -1)
 
		course_remove(slate_permutate_course_free);
 

	
 
		sectionsOfClass[classNum] = 0; // Initialize at 0
 
		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]" value="' + name + '" /></td><td colspan="10"></td><td class="tdInput"><div class="deleteClass"><input type="button" value="Remove" class="gray" /></div></td><td class="none"></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]" value="' + name + '" /></td><td colspan="10"></td><td class="tdInput"><div class="deleteClass"><input type="button" value="Remove" class="gray" /></div></td><td class="none"><button class="addSection gray">+</button></td></tr>');
 

	
 
		/* store classNum as course_i into the <tr />: */
 
		jQuery('#tr-course-' + classNum).data({course_i: classNum});
 

	
 
		var class_elem = jQuery('.className' + classNum);
 
		class_elem.autocomplete({ source: 'auto.php' });
 
		class_elem.bind('autocompleteselect', {class_num: classNum, class_elem: class_elem},
 
			function(event, ui)
 
			    {
 
				if (!ui.item)
 
				    return;
 

	
 
@@ -341,29 +381,115 @@ function add_sections(cnum, data)
 
					    val(newval).
 
					    autocomplete("search", newval);
 

	
 
					/* void out the default event since we are setting the value ourselves, with a '-' */
 
					event.preventDefault();
 
				    }
 
			    });
 

	
 
		classNum++;
 

	
 
		return (classNum - 1);
 
	}
 

	
 
/**
 
 * \brief
 
 *   Ensure that there is an empty course entry and return its
 
 *   identifier.
 
 */
 
function add_class()
 
{
 
    return add_class_n('');
 
    /*
 
     * 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('');
 
    return slate_permutate_course_free;
 
}
 

	
 
/**
 
 * \brief
 
 *   Remove a course entry.
 
 *
 
 * Ensures that slate_permutate_course_free is kept consistent.
 
 *
 
 * \param course_i
 
 *   The internal JS identifer for the course (not the course_id which
 
 *   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;
 
}
 

	
 
/**
 
 * \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)
 
{
 
    return sectionsOfClass[course_i] > 0;
 
}
 

	
 
/**
 
 * \brief
 
 *   Figure out whether or not an empty course entry has become filled
 
 *   or whether a full course has become emptied and react.
 
 *
 
 * This mainly ensures that there is always exactly one course entry
 
 * spot, eliminating the need of an ``Add class'' button.
 
 *
 
 * \param that
 
 *   If this is not being called as a 'change' or 'keyup' event
 
 *   handler for a <input class="className"/>, then that may refer to
 
 *   a jQuery object representing the <input class="className"/> to
 
 *   inspect.
 
 */
 
function course_free_check(that)
 
{
 
    var me;
 
    if (jQuery.type(that) == 'undefined')
 
	me = that;
 
    else
 
	me = jQuery(this);
 

	
 
    var course_i = me.parent().parent().data('course_i');
 
    if (course_i == slate_permutate_course_free && (me.val().length || course_has_sections(course_i)))
 
	{
 
	    /* I am no longer the empty course entry */
 
	    slate_permutate_course_free = -1;
 
	    add_class();
 
	}
 
    if (course_i != slate_permutate_course_free && !(me.val().length || course_has_sections(course_i)))
 
	{
 
	    /* I am now an empty course entry */
 
	    /* kill an other empty course entry if it exists... */
 
	    if (slate_permutate_course_free != -1)
 
		course_remove(slate_permutate_course_free);
 
	    slate_permutate_course_free = course_i;
 
	}
 
}
 

	
 
/**
 
 * \brief
 
 *   Render a slate_permutate-encoded time-of-day.
 
 *
 
 * \param time_str
 
 *   A four-character representation of a time of day based on a
 
 *   time's 24-hour representation.
 
 * \return
 
 *   A string representing the specified time.
 
 */
 
function prettyTime(time_str)
 
@@ -406,60 +532,63 @@ jQuery(document).ready(function() {
 
	// Bind the class-adding method
 
	//--------------------------------------------------
 
	jQuery('#addclass').click(function() {
 
		var classNum = add_class();
 
		// add_section(classNum); // enable eventually
 
	});
 

	
 
	//--------------------------------------------------
 
	// Deletes the selected class from input
 
	//--------------------------------------------------
 
	jQuery('.deleteClass').live('click', function() {
 
		if(confirm('Delete class and all sections of this class?')) {
 
		    jQuery('.class' + jQuery(this).parent().parent().data('course_i')).remove();
 
		    course_remove(jQuery(this).parent().parent().data('course_i'));
 
		}
 
	});
 

	
 
	//--------------------------------------------------
 
	// Deletes the selected section from the input
 
	//--------------------------------------------------
 
	jQuery('.deleteSection').live('click', function() {
 
	  // Decreases the total number of classes
 
		sectionsOfClass[jQuery(this).parent().parent().data('course_i')]--;
 
	  
 
		var course_i = jQuery(this).parent().parent().data('course_i');
 
		sectionsOfClass[course_i]--;
 
		course_free_check(jQuery('.pclass' + course_i + ' .className'));
 

	
 
	  // 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();
 
	    }
 
	  });
 
	});
 

	
 
	});
 
	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');
 
		add_section(course_i, sectionsOfClass[course_i]);
 
		add_section(course_i);
 
	});
 

	
 
	//--------------------------------------------------
 
	// Default text
 
	//--------------------------------------------------
 
	jQuery(".defText").focus(function(srcc)
 
	{
 
	    if (jQuery(this).val() == jQuery(this)[0].title)
 
	    {
 
		jQuery(this).removeClass("defaultTextActive");
 
		jQuery(this).val("");
 
	    }
0 comments (0 inline, 0 general)