<commit_before>/**
 * Schedules view. Displays periods of selected courses in a week grid.
 * @param {HTMLElement} target- The element in which this view should be rendered
 * @param {Object} params - API params for this view
 * @return {undefined}
 * @memberOf Yacs.views
 */
Yacs.views.schedules = function (target, params) {
  // before doing anything, determine how to use the route
  // parameters to choose the section ids to be passed to the
  // API
  var schedule_ids = [];

  // check for query parameters
  if('section_ids' in params) {
    // if there are query parameters,
    // use them and ignore current selections
    var section_ids = params['section_ids'].split(',');
    // eliminate all non-integer section ids
    var sidlen = section_ids.length;
    for(var i=0; i<sidlen; ++i) {
      var sid = parseInt(section_ids[i]);
      if(!isNaN(sid)) {
        schedule_ids.push(sid);
      }
    }

    // If the cookie doesn't have any selections,
    // write them into it, and reroute to a route without section_ids in the query.
    if(Yacs.user.getSelections().length < 1) {
      Yacs.user.addSelections(schedule_ids);
      Yacs.router.visit('/schedules');
    }
    // TODO: look for a param that defines which schedule to go to
    // initially
  }
  else {
    // if section_ids is not specified in params, use the cookie
    // to populate the schedule_ids list
    schedule_ids = Yacs.user.getSelections();
  }

  Yacs.render(target, 'schedules');

  var scheduleElement = target.querySelector('#schedule-container');
  var selectionElement = target.querySelector('#selection-container');
  var leftSwitchElement = target.querySelector('#left-switch');
  var rightSwitchElement = target.querySelector('#right-switch');
  var clearButtonElement = target.querySelector('#clear-btn');
  var scheduleNumElement = target.querySelector('#schedule-num');
  var scheduleCountElement = target.querySelector('#schedule-count');
  var scheduleStatusElement = target.querySelector('#schedule-status');
  var crnListElement = target.querySelector('#crn-list');
  var schedule = new Schedule(scheduleElement);
  var scheduleData = [];
  var scheduleIndex = 0;

  /**
   * Convert military time string to minutes-since-midnight integer form.
   * This function should be deprecated in issue #102
   */
  var toMinutes = function (timeString) {
    var int = parseInt(timeString);
    return Math.floor(int / 100) * 60 + int % 100;
  };

  /**
   * Translate schedules returned by the API into a displayable form.
   * For each schedule, convert period times ro minutes-since-midnight form,
   * and collect the CRNs from each section.
   * Additionally, determine the min star time and the max end time
   * of all of the schedules.
   */
  var processSchedules = function (schedules) {
    var start = 480;
    var end = 1200;
    var processedSchedules = schedules.map(function (schedule) {
      var courseIds = [];
      var events = [];
      var crns = [];
      schedule.sections.forEach(function (section) {
        var color = courseIds.indexOf(section.course_id);
        if (color == -1) {
          courseIds.push(section.course_id);
          color = courseIds.length - 1;
        }
        crns.push(section.crn);
        section.periods.forEach(function (period) {
          start = Math.min(start, toMinutes(period.start));
          end = Math.max(end, toMinutes(period.end));
          events.push({
            start: toMinutes(period.start),
            end: toMinutes(period.end),
            day: period.day,
            colorNum: color,
            title: [
              section.department_code + ' ' + section.course_number + ' - ' + section.name,
              section.crn,
              section.instructors[0] || ''
            ],
            tooltip: section.course_name,
          });
        });
      });
      return { events: events, crns: crns };
    });
    return { schedules: processedSchedules, start: start, end: end };
  };

  /**
   * Process schedules returned by the API, and update view accordingly,
   * setting the time range of the schedule view to accomodate all schedules.
   * If no schedules are available, show the appropriate status text.
   */
  var setSchedules = function (schedules) {
    var data = processSchedules(schedules);
    scheduleData = data.schedules;
    schedule.destroy();
    schedule = new Schedule(scheduleElement,
      { timeBegin: Math.ceil((data.start) / 60) * 60,
        timeSpan: Math.ceil((data.end - data.start) / 60) * 60 });
    scheduleCountElement.textContent = scheduleData.length;
    if (scheduleData.length > 0) {
      showSchedule(0);
    } else {
      showSchedule(-1);
      if (Yacs.user.getSelections().length > 0) {
        scheduleStatusElement.textContent = "No schedules found :( Try removing some courses";
      } else {
        scheduleStatusElement.textContent = "Nothing to see here :) Try adding some courses";
      }
    }
  };

  /**
   * Query the server for schedules based on the stored selections,
   * and update the view to show the new schedules.
   * If no sections are selected, skip the call and show nil schedules.
   */
  var updateSchedules = function (selections) {
    if(typeof selections == 'undefined') {
      selections = Yacs.user.getSelectionsRaw();
    }
    if (selections.length > 0) {
      Yacs.models.schedules.query({ section_ids: selections,
                                    show_periods: true },
        function(data, success) {
          if (success) {
            setSchedules(data.schedules);
          } else {
            Yacs.user.clearSelections();
            setSchedules([]);
          }
      });
      clearButtonElement.disabled = false;
    } else {
      setSchedules([]);
      clearButtonElement.disabled = true;
    }
  };

  /**
   * Show schedule at given index, and display corresponding CRNs.
   * If index is -1, show nil schedule.
   */
  var showSchedule = function (index) {
    if (index == -1) {
      scheduleStatusElement.textContent = "";
      scheduleNumElement.textContent = 0;
    } else {
      schedule.setEvents(scheduleData[index].events);
      scheduleNumElement.textContent = index + 1;
      scheduleStatusStr = 'CRNs: ' + scheduleData[index].crns.join(', ');
      scheduleStatusElement.textContent = scheduleStatusStr;
    }
  };

  /**
   * Switch to schedule [[n + 1] % n] in the sequence
   */
  var nextSchedule = function () {
    if (scheduleData.length > 0) {
      scheduleIndex = (++scheduleIndex < scheduleData.length ? scheduleIndex : 0);
      showSchedule(scheduleIndex);
    }
  };

  /**
   * Switch to schedule [[n - 1] % n] in the sequence
   */
  var prevSchedule = function () {
    if (scheduleData.length > 0) {
      scheduleIndex = (--scheduleIndex < 0 ? scheduleData.length - 1 : scheduleIndex);
      showSchedule(scheduleIndex);
    }
  };

  /**
   * Show next schedule if right is clicked or pressed,
   * show previous schedule if left is clicked or pressed
   */
  Yacs.on('click', leftSwitchElement, prevSchedule);
  Yacs.on('click', rightSwitchElement, nextSchedule);
  Yacs.on('keydown', document, function (elem, event) { if (event.keyCode == 37) prevSchedule(); });
  Yacs.on('keydown', document, function (elem, event) { if (event.keyCode == 39) nextSchedule(); });

  /**
   * Clear selections in cookie when clear button is pressed, and update
   * schedule and selctions views accordingly.
   */
  Yacs.on('click', clearButtonElement, function () {
    Yacs.user.clearSelections();
  });

  /**
   * Show selected courses / sections on the schedule page. The courses shown
   * are explicitly the courses that had one or more sections selected at the
   * time the view was rendered.
   */
  var selections = Yacs.user.getSelections();
  if (selections.length > 0) {
    Yacs.views.courses(selectionElement, { section_id: selections })
  }

  Yacs.observe('selection', scheduleElement, updateSchedules);
  // use section ids extracted from URL parameters at top
  updateSchedules(schedule_ids);
};
<commit_msg>Removed frontend check that schedule IDs in URL are valid ints<commit_after>/**
 * Schedules view. Displays periods of selected courses in a week grid.
 * @param {HTMLElement} target- The element in which this view should be rendered
 * @param {Object} params - API params for this view
 * @return {undefined}
 * @memberOf Yacs.views
 */
Yacs.views.schedules = function (target, params) {
  // before doing anything, determine how to use the route
  // parameters to choose the section ids to be passed to the
  // API
  var schedule_ids = [];

  // check for query parameters
  if('section_ids' in params) {
    // if there are query parameters,
    // use them and ignore current selections
    schedule_ids = params['section_ids'].split(',');

    // If the cookie doesn't have any selections,
    // write them into it, and reroute to a route without section_ids in the query.
    if(Yacs.user.getSelections().length < 1) {
      Yacs.user.addSelections(schedule_ids);
      Yacs.router.visit('/schedules');
    }
    // TODO: look for a param that defines which schedule to go to
    // initially
  }
  else {
    // if section_ids is not specified in params, use the cookie
    // to populate the schedule_ids list
    schedule_ids = Yacs.user.getSelections();
  }

  Yacs.render(target, 'schedules');

  var scheduleElement = target.querySelector('#schedule-container');
  var selectionElement = target.querySelector('#selection-container');
  var leftSwitchElement = target.querySelector('#left-switch');
  var rightSwitchElement = target.querySelector('#right-switch');
  var clearButtonElement = target.querySelector('#clear-btn');
  var scheduleNumElement = target.querySelector('#schedule-num');
  var scheduleCountElement = target.querySelector('#schedule-count');
  var scheduleStatusElement = target.querySelector('#schedule-status');
  var crnListElement = target.querySelector('#crn-list');
  var schedule = new Schedule(scheduleElement);
  var scheduleData = [];
  var scheduleIndex = 0;

  /**
   * Convert military time string to minutes-since-midnight integer form.
   * This function should be deprecated in issue #102
   */
  var toMinutes = function (timeString) {
    var int = parseInt(timeString);
    return Math.floor(int / 100) * 60 + int % 100;
  };

  /**
   * Translate schedules returned by the API into a displayable form.
   * For each schedule, convert period times ro minutes-since-midnight form,
   * and collect the CRNs from each section.
   * Additionally, determine the min star time and the max end time
   * of all of the schedules.
   */
  var processSchedules = function (schedules) {
    var start = 480;
    var end = 1200;
    var processedSchedules = schedules.map(function (schedule) {
      var courseIds = [];
      var events = [];
      var crns = [];
      schedule.sections.forEach(function (section) {
        var color = courseIds.indexOf(section.course_id);
        if (color == -1) {
          courseIds.push(section.course_id);
          color = courseIds.length - 1;
        }
        crns.push(section.crn);
        section.periods.forEach(function (period) {
          start = Math.min(start, toMinutes(period.start));
          end = Math.max(end, toMinutes(period.end));
          events.push({
            start: toMinutes(period.start),
            end: toMinutes(period.end),
            day: period.day,
            colorNum: color,
            title: [
              section.department_code + ' ' + section.course_number + ' - ' + section.name,
              section.crn,
              section.instructors[0] || ''
            ],
            tooltip: section.course_name,
          });
        });
      });
      return { events: events, crns: crns };
    });
    return { schedules: processedSchedules, start: start, end: end };
  };

  /**
   * Process schedules returned by the API, and update view accordingly,
   * setting the time range of the schedule view to accomodate all schedules.
   * If no schedules are available, show the appropriate status text.
   */
  var setSchedules = function (schedules) {
    var data = processSchedules(schedules);
    scheduleData = data.schedules;
    schedule.destroy();
    schedule = new Schedule(scheduleElement,
      { timeBegin: Math.ceil((data.start) / 60) * 60,
        timeSpan: Math.ceil((data.end - data.start) / 60) * 60 });
    scheduleCountElement.textContent = scheduleData.length;
    if (scheduleData.length > 0) {
      showSchedule(0);
    } else {
      showSchedule(-1);
      if (Yacs.user.getSelections().length > 0) {
        scheduleStatusElement.textContent = "No schedules found :( Try removing some courses";
      } else {
        scheduleStatusElement.textContent = "Nothing to see here :) Try adding some courses";
      }
    }
  };

  /**
   * Query the server for schedules based on the stored selections,
   * and update the view to show the new schedules.
   * If no sections are selected, skip the call and show nil schedules.
   */
  var updateSchedules = function (selections) {
    if(typeof selections == 'undefined') {
      selections = Yacs.user.getSelectionsRaw();
    }
    if (selections.length > 0) {
      Yacs.models.schedules.query({ section_ids: selections,
                                    show_periods: true },
        function(data, success) {
          if (success) {
            setSchedules(data.schedules);
          } else {
            Yacs.user.clearSelections();
            setSchedules([]);
          }
      });
      clearButtonElement.disabled = false;
    } else {
      setSchedules([]);
      clearButtonElement.disabled = true;
    }
  };

  /**
   * Show schedule at given index, and display corresponding CRNs.
   * If index is -1, show nil schedule.
   */
  var showSchedule = function (index) {
    if (index == -1) {
      scheduleStatusElement.textContent = "";
      scheduleNumElement.textContent = 0;
    } else {
      schedule.setEvents(scheduleData[index].events);
      scheduleNumElement.textContent = index + 1;
      scheduleStatusStr = 'CRNs: ' + scheduleData[index].crns.join(', ');
      scheduleStatusElement.textContent = scheduleStatusStr;
    }
  };

  /**
   * Switch to schedule [[n + 1] % n] in the sequence
   */
  var nextSchedule = function () {
    if (scheduleData.length > 0) {
      scheduleIndex = (++scheduleIndex < scheduleData.length ? scheduleIndex : 0);
      showSchedule(scheduleIndex);
    }
  };

  /**
   * Switch to schedule [[n - 1] % n] in the sequence
   */
  var prevSchedule = function () {
    if (scheduleData.length > 0) {
      scheduleIndex = (--scheduleIndex < 0 ? scheduleData.length - 1 : scheduleIndex);
      showSchedule(scheduleIndex);
    }
  };

  /**
   * Show next schedule if right is clicked or pressed,
   * show previous schedule if left is clicked or pressed
   */
  Yacs.on('click', leftSwitchElement, prevSchedule);
  Yacs.on('click', rightSwitchElement, nextSchedule);
  Yacs.on('keydown', document, function (elem, event) { if (event.keyCode == 37) prevSchedule(); });
  Yacs.on('keydown', document, function (elem, event) { if (event.keyCode == 39) nextSchedule(); });

  /**
   * Clear selections in cookie when clear button is pressed, and update
   * schedule and selctions views accordingly.
   */
  Yacs.on('click', clearButtonElement, function () {
    Yacs.user.clearSelections();
  });

  /**
   * Show selected courses / sections on the schedule page. The courses shown
   * are explicitly the courses that had one or more sections selected at the
   * time the view was rendered.
   */
  var selections = Yacs.user.getSelections();
  if (selections.length > 0) {
    Yacs.views.courses(selectionElement, { section_id: selections })
  }

  Yacs.observe('selection', scheduleElement, updateSchedules);
  // use section ids extracted from URL parameters at top
  updateSchedules(schedule_ids);
};

{'fraction_non_alphanumeric': 0.11393596986817325, 'fraction_numerical': 0.006591337099811676, 'mean_word_length': 2.7958065284727187, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '934223', 'n_tokens_mistral': 4593, 'n_tokens_neox': 4398, 'n_words': 1338}