{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./Usc.Web/scripts/modules/_timetableModule/resources/_resources.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/resources/alerts.service.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/resources/planner.factory.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/resources/recentsearches.factory.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/resources/storage.service.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/resources/timetable.factory.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/filters/_filters.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/filters/uniquebycoursecode.filter.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/filters/datetime.filter.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/filters/program.filter.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/filters/pattern.filter.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/filters/paging.filter.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/filters/sentencecase.filter.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/filters/day.filter.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/filters/location.filter.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/filters/type.filter.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/filters/time.filter.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/controllers/_controllers.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/controllers/addedtoplanner.controller.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/controllers/classdetail.modal.controller.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/controllers/confirmics.modal.controller.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/controllers/firstrun.modal.controller.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/controllers/planner.controller.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/controllers/recentsearches.controller.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/controllers/removefromplanner.modal.controller.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/controllers/timetable.controller.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/controllers/updatecourseselection.modal.controller.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/_timetable.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/directives/_directives.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/directives/classblock.directive.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/directives/plannercoursecard.directive.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/directives/recentsearchcard.directive.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/directives/searchresult.directive.js","webpack:///./Usc.Web/scripts/modules/_timetableModule/directives/searchresultrow.directive.js"],"names":["installedModules","__webpack_require__","moduleId","module","i","l","exports","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","moduleName","angular","factory","alerts","add","type","prefix","msg","push","close","splice","service","$rootScope","$filter","timetableService","storageService","alertsService","$uibModal","timetableConfig","data","onlineCourseCount","onlineClassCount","addedToPlanner","planner","notify","$emit","addClassToPlanner","courseCode","description","courseId","termId","checkUnique","checkClashes","exists","where","existingElement","id","classNo","toString","classMeetingNo","length","day","class","clash","red","meetingEndTime","meetingStartTime","duration","parseInt","replace","meetingDay","x","room","hours","Math","round","classes","checkDayForClashes","meetingDayNo","hasClasses","classSection","classDesc","forEach","isAdd","q","j","finishHour","kClassEndDate","kClassStartDate","newEndDate","newStartDate","kClass","kClasses","checkFollowingClasses","toLowerCase","Date","meetingStartDate","meetingEndDate","addCourseToPlanner","el","course","clearPlannerUi","DAYS","addToPlanner","fromModal","getClasses","then","uniqueInPlanner","indexOf","SIDEBAR_MAX","classesToAdd","foundOnlineOffering","undefined","currentClass","currentClassB","v","classInstance","hasClash","exactClash","courseFound","classFound","startDate","getDay","plannerItem","plannerItemStart","plannerItemEnd","newItemStart","newItemEnd","newItemStartDate","newItemEndDate","plannerItemStartDate","plannerItemEndDate","parseFloat","addAlert","storePlanner","removeFromPlanner","isCourse","open","template","controller","result","resp","doRemoveFromPlanner","k","hour","filter","size","keys","getFromLocalStorage","indexes","getPlanner","item","courseIds","term","getClassBySearchTerm","cls","updateUi","addedItem","scopeItem","found","serverDs","serverData","serverItem","enrolmentStatus","godMode","getSelectedClassIds","map","scaffold","temp","recent","getRecent","fullDescription","index","findIndex","storeRecent","remove","selectedTerm","subscribe","$new","e","arg","HAS_LOCALSTORAGE","localStorage","LOCAL_STORE_KEY","JSON","stringify","parse","getItem","$http","$q","URL_BASE","currentTerms","courses","getCourses","promise","when","response","sort","a","b","getCourseDetails","setSelectedTerm","scope","event","callback","handler","$on","search","query","getTerms","getEmployee","emplId","getValidatedCourseTerms","method","url","courseList","CourseList","getCampus","getSelectedTerm","checkParams","terms","keyValue","params","location","substr","split","checkForVisibleChildren","filters","f","hasVisibleChildren","hiddenByFilter","jClass","showAll","input","hourSection","hoursMinutes","minSection","career","hiddenByProgramFilter","clsNo","hiddenTitle","currentPage","perPage","start","end","hiddenByLocationFilter","allClassesClosed","slice","toUpperCase","charCodeAt","validDays","days","dayFilter","filterVal","locations","isOnline","val","startsWith","classType","timeFilter","$scope","vm","args","$uibModalInstance","all","courseDetailHref","dismiss","$timeout","getIcs","icsMsg","blob","downloadLink","icsBody","dtStamp","dtStartTime","dtFinishTime","dtEnd","icsEvent","startTime","finishTime","finishDate","title","getFullYear","getMonth","getDate","getHours","getMinutes","navigator","userAgent","match","Blob","window","msSaveOrOpenBlob","document","createElement","href","escape","download","body","appendChild","click","removeChild","ok","plannerFactory","this","online","let","concat","$watch","newVal","oldVal","fromSearch","validationData","removalList","y","status","cancel","recentSearchesFactory","showFirstRunModal","GODMODE","root","querySelector","overlayInterval","dataset","now","prevSearchTerm","allClassesClosedMessage","allClosedMessage","init","loadingCourses","results","noResults","locationFilters","showFilters","showError","DBErrorMsg","noActiveFilters","lastModalDate","getTime","godsOnly","tempLocations","camp","unshift","resetFilters","refresh","filterResults","activeFilters","time","badgeHour","timeFilters","h","countVisibleResults","countTotalPages","showHideActiveFilters","submitSearch","updateFilter","weekend","program","programFilters","typeFilters","selectedfilters","paging","searching","setTerm","ids","offeredLocations","vv","self","join","filterNewResults","getElementById","childElementCount","visibleResultsCount","allHidden","allClassesHidden","totalPages","ceil","clearSearch","arr","seed","searchTerm","errorMsg","showAllFrom","submitSearchOnBlur","typeaheadSelect","force","templateUrl","backdrop","courseName","current","validClasses","classTypes","currentClassNos","toRemove","buildUniqueList","initial","parsed","uniqueArray","isCurrentClasses","isMultiday","hasMultiday","toAdd","SetSelectedClass","showCurrent","markForRemoval","checked","getNgOption","timetableControllers","timetableDirectives","timetableFilters","timetableResources","constant","checkLocalStorage","isGodMode","queryString","uscApp","requires","directive","classData","restrict","link","cssClass","trim","showClassDetail","resolve","inPlanner","fromPlanner","updateSelectionModal","selectedClassIds","classToAdd","$sce","currentSort","reverseSort","sortByColumn","col","sortBy","hasHiddenTitles","some","trustAsHtml","noteText","noteSeq","element","classList","hideDayTime"],"mappings":"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","file":"timetable-bundle-c213d1a4d065a31b33c9.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/dist/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 85);\n","import alertsService from './alerts.service';\r\nimport plannerFactory from './planner.factory';\r\nimport recentSearchesFactory from './recentsearches.factory';\r\nimport storageService from './storage.service';\r\nimport timetableFactory from './timetable.factory';\r\n\r\nconst moduleName = 'usc.timetable.resources';\r\n\r\nangular.module(moduleName, [])\r\n    .factory('alertsService', alertsService)\r\n    .service('plannerFactory', ['$rootScope', '$filter', 'timetableService', 'storageService', 'alertsService', '$uibModal', 'timetableConfig', plannerFactory])\r\n    .service('recentSearchesFactory', ['$rootScope', 'storageService', 'timetableConfig', recentSearchesFactory])\r\n    .service('storageService', ['$rootScope', 'timetableConfig', 'timetableService', storageService])\r\n    .factory('timetableService', ['$rootScope', '$http', '$q', timetableFactory]);\r\n\r\n\r\n\r\nexport default moduleName;","\r\n/**\r\n * The service for displaying alerts\r\n * @param {} constants \r\n * @returns {} \r\n */\r\nexport default function () {\r\n\r\n    var alerts = [];\r\n\r\n    /**\r\n     * Push an alert object into the current alert stack\r\n     * @param {} type \r\n     * @param {} prefix \r\n     * @param {} text \r\n     * @returns {} \r\n     */\r\n    function add(type, prefix, msg) {\r\n        alerts.push({\r\n            type: type,\r\n            prefix: prefix,\r\n            msg: msg,\r\n            close: () => alerts.splice(0, 1)\r\n        });\r\n    }\r\n\r\n    return {\r\n        add: add,\r\n        get: () => alerts\r\n    }\r\n};","export default function ($rootScope, $filter, timetableService, storageService, alertsService, $uibModal, timetableConfig) {\r\n\r\n    var data = {\r\n        onlineCourseCount: 0,\r\n        onlineClassCount: 0,\r\n        addedToPlanner: [],\r\n        planner: []\r\n    };\r\n\r\n    /* the modal, keep these templates out of the main html view */\r\n    var removeModalTemplate =\r\n        '<div class=\"modal-header\">' +\r\n        '   <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\" ng-click=\"cancel()\"><span aria-hidden=\"true\" class=\"fa fa-xmark\"></span></button>' +\r\n        '   <h4 class=\"modal-title\" id=\"update-modal-label\">Are you sure?</h4>' +\r\n        '</div>' +\r\n        '<div class=\"modal-body\">' +\r\n        '   <p>Removing a course will remove all associated classes from the planner.</p>' +\r\n        '</div>' +\r\n        '<div class=\"modal-footer\">' +\r\n        '   <button class=\"btn btn-success\" ng-click=\"ok()\">OK</button>' +\r\n        '   <button class=\"btn btn-default\" ng-click=\"cancel()\">Cancel</button>' +\r\n        '</div>';\r\n\r\n    /**\r\n     * Build the empty planner view\r\n     * @returns {} \r\n     */\r\n    function scaffold() {\r\n        var i, j, l = timetableConfig.DAYS.length, o, temp = [];\r\n\r\n        for (i = 0; i < l; i++) {\r\n\r\n            o = {};\r\n            o.name = timetableConfig.DAYS[i];\r\n            o.hours = [];\r\n\r\n            // 15-> 16 to add extra spot for online\r\n            for (j = 0; j < 16; j++) {\r\n                o.hours.push({ 'classes': [] });\r\n            }\r\n            temp.push(o);\r\n            data.planner.push(o);\r\n        }\r\n\r\n        return temp;\r\n    }\r\n\r\n    /**\r\n     * Emit the change event, this is available for subscription via subscribe()\r\n     * @returns {} \r\n     */\r\n    function notify() {\r\n        $rootScope.$emit('plannerChanged', data);\r\n    }\r\n\r\n    /**\r\n     * Add the course/class to the planner object\r\n     * @param {} c \r\n     * @param {} courseCode \r\n     * @param {} description \r\n     * @param {} courseId \r\n     * @param {} termId \r\n     * @param {} fromModal \r\n     * @param {} courses \r\n     * @returns {} \r\n     */\r\n    function addToPlanner(c, courseCode, description, courseId, termId, fromModal) {\r\n\r\n        var classes;\r\n        // need to fetch the courses from the service, which returns a promise, hence the closure\r\n        timetableService.getClasses(c.courseId, termId)\r\n            .then(function (r) {\r\n                classes = r.data ? r.data.data : r;\r\n                add();\r\n            });\r\n\r\n        function add() {\r\n\r\n            var uniqueInPlanner = [];\r\n            data.addedToPlanner.forEach(function (course) {\r\n                if (uniqueInPlanner.indexOf(course.courseCode) === -1) {\r\n                    uniqueInPlanner.push(course.courseCode);\r\n                }\r\n            });\r\n\r\n            // show alert if:\r\n            // there are six courses in the planner and the object to add is a course\r\n            // there are six courses in the planner and the object to add is a class but the coursecode has not already been added\r\n            if (uniqueInPlanner.length === timetableConfig.SIDEBAR_MAX &&\r\n                (c === null || uniqueInPlanner.indexOf(courseCode) === -1 && c !== null)) {\r\n                alertsService.add('danger', 'ERROR', 'Unable to add <i>' + courseCode + '</i>. Remove at least one selection and try again. Maximum selections is ' + timetableConfig.SIDEBAR_MAX);\r\n            } else {\r\n\r\n                // need to check for multiple instance of the same class id                \r\n                // $scope.results[0].classes holds the class list for the current object if the search came from a typeahead selection\r\n                // if it was character search, results needs to be iterated\r\n                // multiDay.length will be >= 1 - either the class sent to addToPlanner, or a set of classes with matching classNo\r\n                // results.length will be 0 if it's modal selection, so multiday just holds the class object, if one exists\r\n                var i,\r\n                    classesToAdd = [];\r\n\r\n                if ((fromModal === undefined || fromModal !== true) && c !== null) {\r\n\r\n                    if (classes) {\r\n                        classes.forEach(function (currentClass) {\r\n                            if (classesToAdd[0] === undefined && currentClass.classNo === c.classNo) {\r\n                                classesToAdd.push(currentClass);\r\n                            } else if (currentClass.classNo === c.classNo &&\r\n                                currentClass.meetingDayNo !== c.meetingDayNo &&\r\n                                (currentClass.meetingStartTime !== c.meetingStartTime &&\r\n                                    currentClass.meetingEndTime !== c.meetingEndTime ||\r\n                                    currentClass.classMeetingNo !== c.classMeetingNo)) {\r\n\r\n                                classesToAdd.push(currentClass);\r\n                            }\r\n                        });\r\n                    }\r\n\r\n                } else if (c !== null && fromModal === true) {\r\n\r\n                    angular.forEach(c,\r\n                        function (currentClass) {\r\n                            if (classesToAdd[0] === undefined) {\r\n                                classesToAdd.push(currentClass);\r\n                            }\r\n                            if (classesToAdd.length > 1) {\r\n                                angular.forEach(classesToAdd,\r\n                                    function (currentClassB) {\r\n                                        if (currentClass.meetingDayNo !== currentClassB.meetingDayNo &&\r\n                                            (currentClass.meetingStartTime !== currentClassB.meetingStartTime &&\r\n                                                currentClass.meetingEndTime !== currentClassB.meetingEndTime)) {\r\n                                            classesToAdd.push(currentClass);\r\n                                        }\r\n                                    });\r\n                            }\r\n                        });\r\n                }\r\n\r\n                // online classes are often listed more than once, but should only be added once\r\n                // remove all but a single instance of the online class\r\n                var foundOnlineOffering = false;\r\n                classesToAdd.forEach(function (v, i) {\r\n                    if (foundOnlineOffering && v.room === 'ONLINE') {\r\n                        classesToAdd.splice(1, i);\r\n                    } else if (v.room === 'ONLINE') {\r\n                        foundOnlineOffering = true;\r\n                    }\r\n                });\r\n\r\n                for (i = 0; i < classesToAdd.length; i += 1) {\r\n\r\n                    var classInstance = classesToAdd[i],\r\n                        hasClash = false,\r\n                        exactClash = false,\r\n                        courseFound = false,\r\n                        clash = null;\r\n\r\n                    if (!classInstance.meetingDayNo) {\r\n                        var startDate = new Date(classInstance.meetingStartDate);\r\n                        classInstance.meetingDayNo = startDate.getDay() + 1; // our week starts on sunday, 1 index\r\n                        classInstance.meetingDay = timetableConfig.DAYS[startDate.getDay()];\r\n                    }\r\n\r\n                    var classFound = data.addedToPlanner.where(function (plannerItem) {\r\n\r\n                        if (plannerItem.courseCode === courseCode) {\r\n                            courseFound = true;\r\n                        }\r\n\r\n                        if (classInstance && classInstance.room !== 'ONLINE') {\r\n                            if (plannerItem &&\r\n                                plannerItem.hasOwnProperty('class') &&\r\n                                plannerItem.class.meetingDay === classInstance.meetingDay) {\r\n\r\n                                // start times are the same = exact clash\r\n                                var newItemStartDate = new Date(classInstance.meetingStartDate),\r\n                                    newItemEndDate = new Date(classInstance.meetingEndDate),\r\n                                    plannerItemStartDate = new Date(plannerItem.class.meetingStartDate),\r\n                                    plannerItemEndDate = new Date(plannerItem.class.meetingEndDate);\r\n\r\n                                // check both directions - existing may fall in new, new may fall in existing\r\n                                // particularly relevant for single-date classes\r\n                                if ((newItemStartDate < plannerItemEndDate && newItemStartDate >= plannerItemStartDate) ||\r\n                                    (newItemEndDate <= plannerItemEndDate && newItemEndDate > plannerItemStartDate) ||\r\n                                    (plannerItemStartDate < newItemEndDate && plannerItemStartDate >= newItemStartDate) ||\r\n                                    (plannerItemEndDate <= newItemEndDate && plannerItemEndDate > newItemStartDate)) {\r\n\r\n                                    var plannerItemStart = parseFloat($filter('date')(plannerItem.class.meetingStartTime, 'H.MM')),\r\n                                        plannerItemEnd = parseFloat($filter('date')(plannerItem.class.meetingEndTime, 'H.MM')),\r\n                                        newItemStart = parseFloat($filter('date')(classInstance.meetingStartTime, 'H.MM')),\r\n                                        newItemEnd = parseFloat($filter('date')(classInstance.meetingEndTime, 'H.MM'));\r\n\r\n                                    if (plannerItemStart === newItemStart) {\r\n                                        hasClash = true;\r\n                                        exactClash = true;\r\n                                        clash = plannerItem;\r\n                                    } else if (\r\n                                        newItemStart > plannerItemStart && newItemStart < plannerItemEnd || // start of new overlaps\r\n                                        newItemEnd > plannerItemStart && newItemEnd < plannerItemEnd || // end of new overlaps \r\n                                        plannerItemStart > newItemStart && plannerItemStart < newItemEnd || // start of existing overlaps\r\n                                        plannerItemEnd > newItemStart && plannerItemEnd < newItemEnd) { // end of existing overlaps\r\n                                        hasClash = true;\r\n                                        clash = plannerItem;\r\n                                    }\r\n                                }\r\n                            }\r\n\r\n                            if (plannerItem && plannerItem.hasOwnProperty('id')) {\r\n                                return plannerItem.id ===\r\n                                    classInstance.classNo.toString() + classInstance.classMeetingNo.toString();\r\n                            } else if (plannerItem && plannerItem.hasOwnProperty('class')) {\r\n                                return plannerItem.class.classNo === classInstance.classNo;\r\n                            }\r\n                        }\r\n                        return false;\r\n                    }).length;\r\n\r\n                    // allow multiday classes to clash start times\r\n                    if (exactClash && classesToAdd.length === 1 && classInstance.classNo === clash.class.classNo) {\r\n                        alertsService.add('danger',\r\n                            'ERROR',\r\n                            'Unable to add <i>' +\r\n                            classInstance.classSection +\r\n                            ' ' +\r\n                            classInstance.classDesc +\r\n                            '</i> - class is already in planner.');\r\n                    } else {\r\n                        // this will be classes where start/finish times overlap existing\r\n                        if (hasClash) {\r\n                            alertsService.add('danger', 'WARNING', classInstance.classSection + ' ' + classInstance.classDesc + ' clashes with ' + clash.class.classSection + ' ' + clash.class.classDesc);\r\n                        }\r\n                        if (classFound === 0 && classInstance !== null) {\r\n                            // checkClashes flag prevents checking clashes when adding multiple classes at once\r\n                            addClassToPlanner(classInstance,\r\n                                courseCode,\r\n                                description,\r\n                                courseId,\r\n                                termId,\r\n                                false,\r\n                                (classesToAdd.length === 1));\r\n                        } else if (!courseFound) {\r\n                            addCourseToPlanner(courseCode, description, courseId, termId, false);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                // if adding multiple classes, warn the user of possible clashes and check planner for these\r\n                if (classesToAdd.length > 1) {\r\n\r\n                    alertsService.addAlert('danger', 'WARNING', classInstance.classSection + ' ' + classInstance.classDesc + ' is offered on different days each week and may conflict with existing classes.');\r\n\r\n                    var day;\r\n                    if (classesToAdd.length > 1) {\r\n                        for (i = 0; i < classesToAdd.length; i++) {\r\n                            day = data.planner.where(function (o) {\r\n                                return o.name === classesToAdd[i].meetingDay;\r\n                            })[0];\r\n\r\n                            checkDayForClashes(day, true);\r\n                        }\r\n                    } else {\r\n                        day = data.planner.where(function (o) {\r\n                            return o.name === classInstance.meetingDay;\r\n                        })[0];\r\n\r\n                        checkDayForClashes(day, true);\r\n                    }\r\n                }\r\n            }\r\n\r\n            storageService.storePlanner(data.addedToPlanner);\r\n            notify();\r\n        }\r\n    }\r\n\r\n    function addClassToPlanner(c, courseCode, description, courseId, termId, checkUnique, checkClashes) {\r\n        // the class object is nested within an object identifying the parent course by code and name\r\n\r\n        var exists = false;\r\n        if (checkUnique) {\r\n            exists = data.addedToPlanner.where(function (existingElement) {\r\n                if (c !== null) {\r\n                    return existingElement.hasOwnProperty('id')\r\n                        ? existingElement.id === c.classNo.toString() + c.classMeetingNo.toString()\r\n                        : existingElement.classNo === c.classNo;\r\n                }\r\n                return true;\r\n            }).length > 0 ? true : false;\r\n        }\r\n\r\n        var o = {\r\n            'class': c,\r\n            courseCode: courseCode,\r\n            description: description,\r\n            courseId: courseId,\r\n            termId: termId,\r\n            id: c.classNo.toString() + c.classMeetingNo.toString()\r\n        };\r\n\r\n        o.class.clash = '';\r\n        o.class.red = '';\r\n        o.class.meetingEndTime = $filter('date')(c.meetingEndTime, 'HH:MM');\r\n        o.class.meetingStartTime = $filter('date')(c.meetingStartTime, 'HH:MM');\r\n        o.class.duration = o.class.meetingEndTime ? (parseInt(o.class.meetingEndTime.replace(':', '')) - parseInt(o.class.meetingStartTime.replace(':', ''))) / 2 : 0;\r\n\r\n        var day = data.planner.where(function (d) {\r\n            return d.name === c.meetingDay;\r\n        })[0];\r\n\r\n        if (o.class.room === 'ONLINE') {\r\n            day.hours[0].classes.push(o);\r\n        } else {\r\n            day.hours[Math.round((parseInt($filter('date')(o.class.meetingStartTime, 'HH:MM').replace(':', '')) - 600) / 100)].classes.push(o); // eg (1900 - 600) / 100 = 13, or 7pm -> 6am + 12hours, where the 6am cell is labelled 'online'\r\n        }\r\n\r\n        if (checkClashes !== false) {\r\n            checkDayForClashes(day, true);\r\n        }\r\n\r\n        data.planner[o.class.meetingDayNo - 1].hasClasses = true;\r\n\r\n        if (!exists) {\r\n            data.addedToPlanner.push(o);\r\n            alertsService.add('success', 'SUCCESS', 'Class <i>' + c.classSection + ' ' + c.classDesc + '</i> successfully added to planner.');\r\n        }\r\n\r\n        // find the day with the most online options added, set that count as the onlineClassCount value, which controls the height of the top row of the planner\r\n        // online classes can't clash, so must stack instead.\r\n        var x = 0;\r\n        data.planner.forEach(function (day) {\r\n            if (day.hours[0].classes.length > x) {\r\n                x = day.hours[0].classes.length;\r\n            }\r\n        });\r\n        data.onlineClassCount = x;\r\n    }\r\n\r\n    function checkDayForClashes(day, isAdd) {\r\n\r\n        // if course removed, reset clash value for all existing\r\n        var i, q, classes, j, r;\r\n        if (!isAdd) {\r\n            for (i = 0, q = day.hours.length; i < q; i++) {\r\n                if (day.hours[i].classes.length > 0) {\r\n                    classes = day.hours[i].classes;\r\n                    for (j = 0, r = classes.length; j < r; j++) {\r\n                        classes[j].class.clash = '';\r\n                        classes[j].class.red = '';\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        // check each hour of the current day\r\n        for (i = 0, q = day.hours.length; i < q; i++) {\r\n\r\n            // if the hour has classes\r\n            if (day.hours[i].classes.length > 0) {\r\n\r\n                classes = day.hours[i].classes;\r\n\r\n                // check each class in the current hour\r\n                for (j = 0, r = classes.length; j < r; j++) {\r\n\r\n                    var c = classes[j].class,\r\n                        finishHour = c.meetingEndTime ? Math.round((parseInt(c.meetingEndTime.replace(':', '')) - 600) / 100) : i + c.duration;\r\n\r\n                    if (c.room !== 'ONLINE') {\r\n                        checkFollowingClasses(i, finishHour, c, day);\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    function checkFollowingClasses(i, finishHour, c, day) {\r\n        // given the start and finish time for the current class, check for others starting in the same period.\r\n        var kClasses,\r\n            kClass;\r\n\r\n        for (i; i < finishHour; i++) {\r\n\r\n            kClasses = day.hours[i].classes;\r\n\r\n            if (kClasses.length > 0) {\r\n\r\n                for (var l = 0, t = kClasses.length; l < t; l++) {\r\n\r\n                    kClass = kClasses[l].class;\r\n\r\n                    if ((c.classNo.toString() + c.classMeetingNo.toString()).toLowerCase() !==\r\n                        (kClass.classNo.toString() + kClass.classMeetingNo.toString()).toLowerCase()) {\r\n\r\n                        if (c.clash !== '') {\r\n                            kClass.clash = c.clash === 'left' ? 'right' : 'left';\r\n                        } else {\r\n                            c.clash = 'left';\r\n                            kClass.clash = 'right';\r\n                        }\r\n\r\n                        var newStartDate = new Date(c.meetingStartDate),\r\n                            newEndDate = new Date(c.meetingEndDate),\r\n                            kClassStartDate = new Date(kClass.meetingStartDate),\r\n                            kClassEndDate = new Date(kClass.meetingEndDate);\r\n\r\n                        if ((newStartDate < kClassEndDate && newStartDate >= kClassStartDate) ||\r\n                            (newEndDate <= kClassEndDate && newEndDate > kClassStartDate)) {\r\n\r\n                            c.red = true;\r\n                            kClass.red = true;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * manage removal of class/course from the planner, and related storage etc\r\n     * @param {Object} c - will be removed from the planner array\r\n     * @param {book} isCourse -indicates the object type, being course or class\r\n     * @returns {} \r\n     */\r\n    function removeFromPlanner(c, isCourse) {\r\n        if (isCourse) {\r\n\r\n            var modalInstance = $uibModal.open({\r\n                template: removeModalTemplate,\r\n                controller: 'RemoveCourseFromPlannerModalCtrl'\r\n            });\r\n\r\n            modalInstance.result.then(function (resp) {\r\n                if (resp === true) {\r\n                    doRemoveFromPlanner(c);\r\n                }\r\n            });\r\n        } else {\r\n\r\n            var classNo = null,\r\n                courseId = null,\r\n                hasClasses,\r\n                day,\r\n                hour,\r\n                i,\r\n                j,\r\n                k,\r\n                l,\r\n                m,\r\n                o;\r\n\r\n            for (i = 0, j = data.planner.length; i < j; i++) {\r\n                day = data.planner[i];\r\n                hasClasses = false;\r\n\r\n                for (k = 0, l = Object.size(day.hours); k < l; k++) {\r\n                    hour = day.hours[Object.keys(day.hours)[k]];\r\n                    m = Object.size(hour.classes);\r\n\r\n                    if (m > 0) {\r\n                        while (m--) {\r\n                            o = hour.classes[m];\r\n                            //two different methods of removing class from planner \r\n                            //one using class selection modal template by checking classNo and one using x button for class in planner by checking id\r\n                            if (c.class !== undefined && o.class.classNo === c.class.classNo ||\r\n                                c.hasOwnProperty('classNo') &&\r\n                                o.id.indexOf(c.classNo.toString()) === 0) {\r\n                                classNo = o.class.classNo;\r\n                                courseId = o.courseId;\r\n                                hour.classes.splice(hour.classes.indexOf(o), 1);\r\n\r\n                                checkDayForClashes(day, false);\r\n                            }\r\n                        }\r\n                        if (Object.size(hour.classes) > 0) {\r\n                            hasClasses = true;\r\n                        }\r\n                    }\r\n                }\r\n                if (!hasClasses) {\r\n                    data.planner[i].hasClasses = false;\r\n                }\r\n            }\r\n\r\n            data.addedToPlanner = data.addedToPlanner.where(function (p) {\r\n                return p.class !== undefined ? p.class.classNo !== classNo : p.courseId !== courseId;\r\n            });\r\n\r\n            storageService.storePlanner(data.addedToPlanner);\r\n\r\n            notify();\r\n        }\r\n    }\r\n\r\n\r\n    /**\r\n     * execute the actual removal from the planner, once the previous function has completed its modifications\r\n     * @param {} c \r\n     * @returns {} \r\n     */\r\n    function doRemoveFromPlanner(c) {\r\n\r\n        data.addedToPlanner = data.addedToPlanner.filter(function (p) {\r\n            return p.courseCode !== c && p.courseCode !== c.courseCode; // c could be a code or course object\r\n        });\r\n\r\n        var i, j, k, l, m, o, day, hasClasses, hour;\r\n\r\n        for (i = 0, j = data.planner.length; i < j; i++) {\r\n\r\n            day = data.planner[i];\r\n            hasClasses = false;\r\n\r\n            for (k = 0, l = Object.size(day.hours); k < l; k++) {\r\n\r\n                hour = day.hours[Object.keys(day.hours)[k]];\r\n                m = Object.size(hour.classes);\r\n\r\n                if (m > 0) {\r\n                    while (m--) {\r\n                        o = hour.classes[m];\r\n                        if (o.courseCode === c || o.courseCode === c.courseCode) {\r\n                            hour.classes.splice(hour.classes.indexOf(o), 1);\r\n                            checkDayForClashes(day, false);\r\n                        }\r\n                    }\r\n                }\r\n                if (Object.size(hour.classes) > 0) {\r\n                    hasClasses = true;\r\n                }\r\n            }\r\n            if (!hasClasses) {\r\n                data.planner[i].hasClasses = false;\r\n            }\r\n        }\r\n\r\n        storageService.storePlanner(data.addedToPlanner);\r\n        notify();\r\n    }\r\n\r\n    /**\r\n     * \r\n     * @param {} courseCode \r\n     * @param {} description \r\n     * @param {} courseId \r\n     * @param {} termId \r\n     * @param {} checkUnique \r\n     * @returns {} \r\n     */\r\n    function addCourseToPlanner(courseCode, description, courseId, termId, checkUnique) {\r\n\r\n        var exists = false;\r\n        if (checkUnique) {\r\n            exists = data.addedToPlanner.where(function (el) {\r\n                return el.courseCode === courseCode;\r\n            }).length;\r\n        }\r\n        /*if it's not currently added then add this from current courses or if it's not existed in the current courses send */\r\n        if (!exists) {\r\n\r\n            var course = {\r\n                courseCode: courseCode,\r\n                description: description,\r\n                termId: termId,\r\n                courseId: courseId\r\n            };\r\n\r\n            data.addedToPlanner.push(course);\r\n\r\n            alertsService.add('success', 'SUCCESS', 'Course <i>' + course.description + '</i> successfully added to planner.');\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Removes all classes from the planner by emptying the containing array\r\n     * @returns {} \r\n     */\r\n    function clearPlannerUi() {\r\n        var i, j;\r\n        for (i = 0; i < timetableConfig.DAYS.length; i++) {\r\n            for (j = 0; j < 15; j++) {\r\n                if (data.planner[i] && data.planner[i].hours[j]) {\r\n                    data.planner[i].hours[j].classes = [];\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Fetch the planner from localstorage, then validated included classes against the current offering for the selected term\r\n     */\r\n    function getFromLocalStorage() {\r\n\r\n        data.addedToPlanner = storageService.getPlanner();\r\n\r\n        // Matt Crawford            \r\n        // Create an array for verification at the server side of the existance of a course\r\n        if (data.addedToPlanner && data.addedToPlanner.length > 0) {\r\n            var indexes = [];\r\n\r\n            angular.forEach(data.addedToPlanner,\r\n                function (item) {\r\n\r\n                    if (!indexes[item.termId]) {\r\n                        indexes[item.termId] = [];\r\n                    }\r\n\r\n                    if (indexes[item.termId.toString()].indexOf(item.courseId.toString()) === -1) {\r\n                        indexes[item.termId.toString()].push(item.courseId.toString());\r\n                    }\r\n                });\r\n\r\n            // Load the matching items from the server\r\n            if (indexes.length > 0) {\r\n                angular.forEach(indexes, function (courseIds, term) {\r\n                    timetableService.getClassBySearchTerm(courseIds, term).then(function (cls) {\r\n                        if (cls.data.data && cls.data.data.length > 0) {\r\n\r\n                            var updateUi = false;\r\n\r\n                            // Iterate through each item that has been added to the planner\r\n                            for (var addedItem = 0; addedItem < data.addedToPlanner.length; addedItem++) {\r\n                                var scopeItem = data.addedToPlanner[addedItem];\r\n\r\n                                // Iterate through the multi dimental array of data return from the server\r\n                                var found = false;\r\n                                for (var serverDs = 0; serverDs < cls.data.data.length; serverDs++) {\r\n\r\n                                    var serverData = cls.data.data[serverDs].value;\r\n                                    for (var item = 0; item < serverData.length; item++) {\r\n                                        var serverItem = serverData[item];\r\n                                        if (serverItem.enrolmentStatus === 'C' && !$rootScope.godMode)\r\n                                            continue;\r\n\r\n                                        if (scopeItem.courseCode === serverItem.courseCode &&\r\n                                            scopeItem.courseId === serverItem.courseId &&\r\n                                            scopeItem.class.classSection ===\r\n                                            serverItem.classSection) {\r\n                                            // We have found the item\r\n                                            found = true;\r\n                                            break;\r\n                                        }\r\n                                    }\r\n\r\n                                    if (found)\r\n                                        break;\r\n                                }\r\n\r\n                                if (!found) {\r\n                                    data.addedToPlanner.splice(addedItem, 1);\r\n                                    updateUi = true;\r\n                                }\r\n                            }\r\n\r\n                            // Store the results if we have removed anything and refresh the UI\r\n                            // This needs to be called due to the asyncronis nature of this call,\r\n                            // The add items code below will be called before we get here\r\n                            if (updateUi) {\r\n\r\n                                storageService.storePlanner(data.addedToPlanner);\r\n                                clearPlannerUi();\r\n\r\n                                for (var j = 0, l = data.addedToPlanner.length; j < l; j++) {\r\n                                    var c = data.addedToPlanner[j];\r\n                                    if (c.hasOwnProperty('class')) {\r\n                                        addClassToPlanner(c.class,\r\n                                            c.courseCode,\r\n                                            c.description,\r\n                                            c.courseId,\r\n                                            c.termId,\r\n                                            true);\r\n                                    } else {\r\n                                        addCourseToPlanner(c.courseCode,\r\n                                            c.description,\r\n                                            c.courseId,\r\n                                            c.termId,\r\n                                            true);\r\n                                    }\r\n                                }\r\n                            }\r\n                        }\r\n                    });\r\n                });\r\n            }\r\n        }\r\n        // Add items to the planner now\r\n        if (data.addedToPlanner !== null) {\r\n            for (var j = 0, l = data.addedToPlanner.length; j < l; j++) {\r\n                var c = data.addedToPlanner[j];\r\n                if (c.hasOwnProperty('class')) {\r\n                    addClassToPlanner(c.class, c.courseCode, c.description, c.courseId, c.termId, true);\r\n                } else {\r\n                    addCourseToPlanner(c.courseCode, c.description, c.courseId, c.termId, true);\r\n                }\r\n            }\r\n        } else {\r\n            data.addedToPlanner = [];\r\n        }\r\n\r\n        notify();\r\n    }\r\n\r\n    /**\r\n     * Generic function to return the current state\r\n     */\r\n    function get() {\r\n        return data;\r\n    }\r\n\r\n    /**\r\n     * Return an array of class ids, for the classes added to the current planner view\r\n     * @returns {} \r\n     */\r\n    function getSelectedClassIds() {\r\n        return data.addedToPlanner.map(function (v) {\r\n            return v.id;\r\n        });\r\n    }\r\n\r\n    return {\r\n        addToPlanner: addToPlanner,\r\n        get: get,\r\n        removeFromPlanner: removeFromPlanner,\r\n        clearPlannerUi: clearPlannerUi,\r\n        getFromLocalStorage: getFromLocalStorage,\r\n        getSelectedClassIds: getSelectedClassIds,\r\n        scaffold: scaffold,\r\n        notify: notify\r\n    }\r\n};","\r\n/**\r\n * Interface for adding and removing search results to the recent searches set\r\n * @param {} $rootScope \r\n * @param {} storageService \r\n * @param {} $constants \r\n * @returns {} \r\n */\r\nexport default function ($rootScope, storageService, timetableConfig) {\r\n\r\n    var recent = storageService.getRecent();\r\n\r\n    /**\r\n     * Emit the change event, this is available for subscription via timetableservice.subscribe()\r\n     * @returns {} \r\n     */\r\n    function notify() {\r\n        $rootScope.$emit('recentChanged', recent);\r\n    }\r\n\r\n    /**\r\n     * Add a course, class or search term to the recently viewed array\r\n     * @param {} c \r\n     * @returns {} \r\n     */\r\n    function add(c) {\r\n\r\n        var found = recent.where(function (el) {\r\n            return el.courseCode === c.courseCode || c.courseCode === el.fullDescription;\r\n        }).length;\r\n\r\n        if (!found && recent.length) {\r\n            if (recent.length + 1 > timetableConfig.SIDEBAR_MAX) {\r\n                recent.splice(recent.length - 1, 1);\r\n            }\r\n\r\n            recent.splice(0, 0, c);\r\n        } else if (!recent.length) {\r\n            recent[0] = c;\r\n        } else if (found) {\r\n\r\n            var index = recent.findIndex(function (el) {\r\n                return el.courseCode === c.courseCode || c.courseCode === el.fullDescription;\r\n            });\r\n\r\n            recent.splice(0, 0, recent.splice(index, 1)[0]);\r\n        }\r\n\r\n        // store it, then tell the world\r\n        storageService.storeRecent(recent);\r\n        notify();\r\n    }\r\n\r\n    /**\r\n     * Remove the selected item from the recent searches object, then update stored version\r\n     * @param {} $event \r\n     * @param {} index \r\n     * @returns {} \r\n     */\r\n    function remove(c) {\r\n\r\n        var index = recent.findIndex(function (el) {\r\n            return el.courseCode === c.courseCode || c.courseCode === el.fullDescription;\r\n        });\r\n\r\n        recent.splice(index, 1);\r\n\r\n        storageService.storeRecent(recent);\r\n        notify();\r\n    };\r\n\r\n    return {\r\n        add: add,\r\n        remove: remove\r\n    }\r\n};","/**\r\n * The service for interacting with local storage\r\n * Includes pub-sub functions for syncing data across the app\r\n * @param {} constants \r\n * @returns {} \r\n */\r\nexport default function ($rootScope, timetableConfig, timetableService) {\r\n\r\n    var selectedTerm = {},\r\n        recent = [],\r\n        planner = [];\r\n\r\n    /**\r\n     * Update the added to planner list when selected term updates\r\n     */\r\n    timetableService.subscribe($rootScope.$new(), 'selectedTermChanged',\r\n        function selectedTermChanged(e, arg) {\r\n            selectedTerm = arg;\r\n        });\r\n\r\n    /**\r\n     * Push the planner courses into local storage, if available, using the selected term id as an identifier for later retrieval\r\n     * @param {} data \r\n     * @param {} term \r\n     * @returns {} \r\n     */\r\n    function storePlanner(data) {\r\n        if (timetableConfig.HAS_LOCALSTORAGE && data !== null && selectedTerm && selectedTerm.id) {\r\n            localStorage[timetableConfig.LOCAL_STORE_KEY + 'planner_' + selectedTerm.id] = JSON.stringify(data);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Push recently viewed courses object into local storage, if it is available\r\n     * @param {} data \r\n     * @returns {} \r\n     */\r\n    function storeRecent(data) {\r\n        if (timetableConfig.HAS_LOCALSTORAGE && data !== null) {\r\n            localStorage[timetableConfig.LOCAL_STORE_KEY + 'recent'] = JSON.stringify(data);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Retrieves recent course search information from localstorage. If none exists, or localstorage is not available, returns an empty array\r\n     * @returns {} \r\n     */\r\n    function getRecent() {\r\n        if (timetableConfig.HAS_LOCALSTORAGE) {\r\n            recent = JSON.parse(localStorage.getItem(timetableConfig.LOCAL_STORE_KEY + 'recent')) || [];\r\n            $rootScope.$emit('getRecent', recent);\r\n            return recent;\r\n        }\r\n        return [];\r\n    }\r\n\r\n    /**\r\n     * Retrieves planner information from localstorage, provided a term has been selected. If none exists, or localstorage is not available, returns an empty array \r\n     * @returns {} \r\n     */\r\n    function getPlanner() {\r\n        if (timetableConfig.HAS_LOCALSTORAGE && selectedTerm && selectedTerm.id) {\r\n            planner = JSON.parse(localStorage.getItem(timetableConfig.LOCAL_STORE_KEY + 'planner_' + selectedTerm.id)) || [];\r\n            $rootScope.$emit('getPlanner', planner);\r\n            return planner;\r\n        }\r\n        return [];\r\n    }\r\n\r\n    return {\r\n        storePlanner: storePlanner,\r\n        storeRecent: storeRecent,\r\n        getPlanner: getPlanner,\r\n        getRecent: getRecent\r\n    }\r\n};","export default function ($rootScope, $http, $q) {\r\n\r\n    var URL_BASE = '/webapi/classsearch/',\r\n        selectedTerm = {},\r\n        currentTerms = [],\r\n        courses = {},\r\n        classes = {};\r\n\r\n    /**\r\n     * Generic subscription function for pubsub syncing\r\n     * @param {} scope \r\n     * @param {} event \r\n     * @param {} callback \r\n     * @returns {} \r\n     */\r\n    function subscribe(scope, event, callback) {\r\n        var handler = $rootScope.$on(event, callback);\r\n        scope.$on('$destroy', handler);\r\n    }\r\n\r\n    /**\r\n     * Get all currently timetabled terms and cache the result \r\n     * @returns {} \r\n     */\r\n    function getTerms() {\r\n        return $http.get(URL_BASE + 'GetCurrentTerms').then(function (result) {\r\n            currentTerms = result.data.data;\r\n            return result.data;\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Get all courses for the currently selected term and cache the result to a local object using the termId as the key        \r\n     * @returns {} \r\n     */\r\n    function getCourses() {\r\n        var promise;\r\n\r\n        var termId = selectedTerm.id;\r\n\r\n        if (!courses[termId]) {\r\n            var url = URL_BASE + 'GetCourses?term=' + termId;\r\n            promise = $http.get(url);\r\n            promise.then(function (response) {\r\n\r\n                response.data.data = response.data.data.sort(function (a, b) {\r\n                    if (a.courseCode < b.courseCode) {\r\n                        return -1;\r\n                    }\r\n                    if (a.courseCode > b.courseCode) {\r\n                        return 1;\r\n                    }\r\n                    return 0;\r\n                });\r\n                courses[termId] = response.data;\r\n                $rootScope.$emit('coursesChanged', response.data);\r\n            });\r\n        } else {\r\n            promise = $q.when(courses[termId]);\r\n            $rootScope.$emit('coursesChanged', courses[termId]);\r\n        }\r\n        return promise;\r\n    }\r\n\r\n    /**\r\n     * Get the employee by id\r\n     * @param {} emplId \r\n     * @returns {} \r\n     */\r\n    function getEmployee(emplId) {\r\n        return $http.get(URL_BASE + 'GetCoord?empl=' + emplId).then(function (result) {\r\n            return result.data;\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Get classes for the given term and course id, cache the result\r\n     * Cached result will be returned if it exists.\r\n     * @param {} termId \r\n     * @param {} courseId \r\n     * @returns {} \r\n     */\r\n    function getClasses(courseId, termId) {\r\n\r\n        var promise,\r\n            term = termId || selectedTerm.id,\r\n            key = term + '_' + courseId;\r\n\r\n        if (!classes[key]) {\r\n            var url = URL_BASE + 'GetClassMeetings?term=' + term + '&course=' + courseId;\r\n            promise = $http.get(url);\r\n            promise.then(function (response) {\r\n                classes[key] = response.data.data;\r\n\r\n            });\r\n        } else {\r\n            promise = $q.when(classes[key]);\r\n        }\r\n        return promise;\r\n    }\r\n\r\n    /**\r\n     * \r\n     * @param {} data \r\n     * @returns {} \r\n     */\r\n    function getValidatedCourseTerms(data) {\r\n        return $http({\r\n            method: 'POST',\r\n            url: URL_BASE + 'VerifyCourseTerm',\r\n            data: JSON.stringify(data)\r\n        }).then(function (result) {\r\n            return result.data;\r\n        });\r\n    }\r\n\r\n    function getClassBySearchTerm(courseList, term) {\r\n        var data = {\r\n            termId: term || selectedTerm.id,\r\n            CourseList: courseList\r\n        };\r\n        return $http({\r\n            method: 'POST',\r\n            url: URL_BASE + 'GetClassbySearchTerm',\r\n            data: JSON.stringify(data)\r\n        }).then(function (result) {\r\n            return result.data;\r\n        });\r\n    }\r\n\r\n    function getCourseDetails(courseId) {\r\n        return $http.get(URL_BASE + 'GetCourseDetails?&course=' + courseId).then(function (result) {\r\n            return result.data;\r\n        });\r\n    }\r\n\r\n    function getCampus() {\r\n        return $http.get(URL_BASE + 'GetCampus').then(function (result) {\r\n            return result.data;\r\n        });\r\n    }\r\n\r\n    function setSelectedTerm(term) {\r\n        selectedTerm = currentTerms.filter(function (v) {\r\n            return v.id === term.id || v.id === term; // term may be object or int\r\n        })[0];\r\n\r\n        getCourses();\r\n        $rootScope.$emit('selectedTermChanged', selectedTerm);\r\n    }\r\n\r\n    /**\r\n     * Get the selected term - this is not a promise and will return immediately\r\n     * @returns {} \r\n     */\r\n    function getSelectedTerm() {\r\n        return selectedTerm;\r\n    }\r\n\r\n    /**\r\n     * Return a \r\n     * @param {} query \r\n     * @param {} termId \r\n     * @returns {} \r\n     */\r\n    function search(query, termId) {\r\n\r\n        setSelectedTerm(termId);\r\n\r\n        getCourses(termId)\r\n            .then(function (r) {\r\n                var c = r.data.data ? r.data.data : r.data,\r\n                    resp = c.filter(function (v) {\r\n                        return v.courseCode === query || v.fullDescription.toLowerCase().indexOf(query.toLowerCase()) !== -1;\r\n                    });\r\n                $rootScope.$emit('resultsChanged', resp);\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Check for an inbound course in the query string, and submit a search if it exists\r\n     */\r\n    function checkParams(terms) {\r\n\r\n        var course,\r\n            i,\r\n            keyValue,\r\n            queryString = location.search.substr(1),\r\n            params = queryString.split('&');\r\n\r\n        for (i = 0; i < params.length; i++) {\r\n            keyValue = params[i].split('=');\r\n\r\n            if (keyValue.length && keyValue[0] === 'course') {\r\n                course = keyValue[1];\r\n            }\r\n        }\r\n        if (course) {\r\n\r\n            // needs a term, but still returns everything, not sure why.\r\n            setSelectedTerm(terms[0]);\r\n\r\n            getCourseDetails(course).then(function (resp) {\r\n                $rootScope.$emit('resultsChanged', !resp.data ? [] : resp.data.filter(function (v) {\r\n                    return terms.indexOf(v.termId) !== -1;\r\n                }));\r\n            });\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Check the provided item for any class instances which are not hidden by filters\r\n     * @param {any} item\r\n     * @param {any} filters\r\n     */\r\n    function checkForVisibleChildren(item, filters) {\r\n        var keys = [];\r\n        for (var f in filters) {\r\n            if (!keys.hasOwnProperty(f)) {\r\n                keys.push(f);\r\n            }\r\n        }\r\n\r\n        item.hasVisibleChildren = false;\r\n\r\n        for (var j = 0, m = item.classes.length; j < m; j++) {\r\n            var hiddenByFilter = false,\r\n                jClass = item.classes[j];\r\n\r\n            for (var k = 0, n = keys.length; k < n; k++) {\r\n                if (jClass.hasOwnProperty(keys[k] + 'Filter') && jClass[keys[k] + 'Filter'] === false ||\r\n                    (jClass.enrolmentStatus !== 'O' && !$rootScope.showAll)) {\r\n                    hiddenByFilter = true;\r\n                }\r\n            }\r\n            jClass.hiddenByFilter = hiddenByFilter;\r\n        }\r\n\r\n        var visibleChildrenCount = item.classes.where(function (el) {\r\n            return el.hiddenByFilter === false;\r\n        }).length;\r\n\r\n        if (visibleChildrenCount > 0) {\r\n            item.hasVisibleChildren = true;\r\n        }\r\n        return item;\r\n    }\r\n\r\n    /* Expose a public API */\r\n    return {\r\n        subscribe: subscribe,\r\n        getCourses: getCourses,\r\n        search: search,\r\n        getTerms: getTerms,\r\n        getEmployee: getEmployee,\r\n        getClasses: getClasses,\r\n        getValidatedCourseTerms: getValidatedCourseTerms,\r\n        getClassBySearchTerm: getClassBySearchTerm,\r\n        getCourseDetails: getCourseDetails,\r\n        getCampus: getCampus,\r\n        getSelectedTerm: getSelectedTerm,\r\n        setSelectedTerm: setSelectedTerm,\r\n        checkParams: checkParams,\r\n        checkForVisibleChildren: checkForVisibleChildren\r\n    };\r\n};","import uniqueByCourseCode from './uniquebycoursecode.filter';\r\nimport dateTime from './datetime.filter';\r\nimport program from './program.filter';\r\nimport pattern from './pattern.filter';\r\nimport paging from './paging.filter';\r\nimport sentenceCase from './sentencecase.filter';\r\nimport day from './day.filter';\r\nimport location from './location.filter';\r\nimport type from './type.filter';\r\nimport time from './time.filter';\r\n\r\nconst moduleName = 'usc.timetable.filters';\r\n\r\nangular.module(moduleName, [])\r\n    .filter('uniqueByCourseCode', uniqueByCourseCode)\r\n    .filter('dateTime', dateTime)\r\n    .filter('program', program)\r\n    .filter('pattern', pattern)\r\n    .filter('paging', paging)\r\n    .filter('sentenceCase', sentenceCase)\r\n    .filter('day', ['timetableService', day])\r\n    .filter('location', ['timetableService', location])\r\n    .filter('type', ['timetableService', type])\r\n    .filter('time', ['timetableService', time]);\r\n\r\nexport default moduleName;","export default function () {\r\n    return function (input) {\r\n        if (input) {\r\n            var result = [], found = false;\r\n\r\n            if (input.length) {\r\n                result.push(input[0]);\r\n            }\r\n\r\n            for (var i = 0, l = input.length; i < l; i++) {\r\n\r\n                for (var j = 0; j < result.length; j++) {\r\n\r\n                    if (result[j].courseCode === input[i].courseCode) {\r\n                        found = true;\r\n                        break;\r\n                    } else {\r\n                        found = false;\r\n                    }\r\n                }\r\n\r\n                if (!found) {\r\n                    result.push(input[i]);\r\n                }\r\n            }\r\n            return result;\r\n        }\r\n\r\n        return null;\r\n    };\r\n};","export default function () {\r\n    return function (input, type) {\r\n        if (input) {\r\n            if (type === 'time') {\r\n                var hoursMinutes = input.split(/[.:]/);\r\n                var hourSection = parseInt(hoursMinutes[0], 10);\r\n                var minSection = parseInt(hoursMinutes[1], 10) > 0\r\n                    ? ':' + parseInt(hoursMinutes[1], 10)\r\n                    : '';\r\n\r\n                if (hourSection > 12) {\r\n                    input = (hourSection - 12) + minSection + 'pm';\r\n                } else if (hourSection === 12 && minSection === '') {\r\n                    input = hourSection + 'noon';\r\n                } else if (hourSection === 12 && minSection !== '') {\r\n                    input = hourSection + minSection + 'pm';\r\n                } else {\r\n                    input = hourSection + minSection + 'am';\r\n                }\r\n                return input;\r\n            } else {\r\n                var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\r\n                return days[input - 1];\r\n            }\r\n        }\r\n        return null;\r\n    };\r\n};","export default function () {\r\n    return function (input, key, filters) {\r\n\r\n        for (var i = 0, l = input.length; i < l; i++) {\r\n            if (input[i].career === filters[key] || filters[key] === 'Show all') {\r\n                input[i].hiddenByProgramFilter = false;\r\n            } else {\r\n                input[i].hiddenByProgramFilter = true;\r\n            }\r\n        }\r\n        return input;\r\n    }\r\n};","export default function () {\r\n    return function (input) {\r\n        for (var i = 0, l = input.length; i < l; i++) {\r\n            for (var j = 1, clsNo = input[i].classes.length; j < clsNo; j++)\r\n                if (input[i].classes[j].classNo === input[i].classes[j - 1].classNo) {\r\n                    input[i].classes[j].hiddenTitle = true;\r\n                } else {\r\n                    input[i].classes[j].hiddenTitle = false;\r\n                }\r\n        }\r\n    }\r\n};","export default function () {\r\n    return function (input, currentPage, perPage) {\r\n\r\n        var start = (currentPage - 1) * perPage,\r\n            end = start + perPage;\r\n\r\n        var output = input.where(function (el) {\r\n            return !el.hiddenByProgramFilter && !el.hiddenByLocationFilter && !el.allClassesClosed;\r\n        });\r\n\r\n        return (output || []).slice(start, end);\r\n    }\r\n};","export default function () {\r\n    return function (input) {\r\n        input = input[0].toUpperCase() + input.substr(1).toLowerCase();\r\n        if (input.charCodeAt(input.length - 1) === 0) {\r\n            input = input.substr(0, input.length - 1) + '.';\r\n        }\r\n        return input;\r\n    }\r\n};","export default timetableService => {\r\n    return function (input, key, filters) {\r\n\r\n        var validDays = [],\r\n            days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\r\n            dayFilter = filters[key],\r\n            i;\r\n\r\n        for (i = 0; i < dayFilter.length; i++) {\r\n            if (dayFilter[i] === true) {\r\n                validDays.push(days[i]);\r\n            }\r\n        }\r\n\r\n        for (i = 0; i < input.length; i++) {\r\n            if (!input[i].classes)\r\n                continue;\r\n\r\n            for (var j = 0, m = input[i].classes.length; j < m; j++) {\r\n                var c = input[i].classes[j];\r\n                if (c.meetingDay && validDays.indexOf(c.meetingDay) === -1) {\r\n                    c[key + 'Filter'] = false;\r\n                } else {\r\n                    c[key + 'Filter'] = true;\r\n                }\r\n            }\r\n\r\n            input[i] = timetableService.checkForVisibleChildren(input[i], filters);\r\n        }\r\n        return input;\r\n    }\r\n};","export default timetableService => {\r\n    return function (input, key, filters) {\r\n\r\n        var filterVal = filters[key];\r\n\r\n        for (var i = 0, l = input.length; i < l; i++) {\r\n            for (var j = 0, m = input[i].classes.length; j < m; j++) {\r\n                var c = input[i].classes[j];\r\n                if (filterVal === 'Show all' || filterVal === c[key]) {\r\n                    c[key + 'Filter'] = true;\r\n                } else {\r\n                    c[key + 'Filter'] = false;\r\n                }\r\n            }\r\n\r\n            input[i] = timetableService.checkForVisibleChildren(input[i], filters);\r\n            input[i].hiddenByLocationFilter = input[i].locations.indexOf(filterVal) === -1 &&\r\n                filterVal !== 'Show all';\r\n        }\r\n\r\n        return input;\r\n    }\r\n};","export default timetableService => {\r\n    return function (input, key, filters) {\r\n        var val = filters[key],\r\n            isOnline,\r\n            c, // the class item for the inner loop\r\n            item; // the course item for the outer loop\r\n\r\n        for (var i = 0, l = input.length; i < l; i++) {\r\n            item = input[i];\r\n\r\n            for (var j = 0, m = item.classes.length; j < m; j++) {\r\n                c = item.classes[j];\r\n                isOnline = c.room.startsWith('ONL') || c.classType.startsWith('ONL');\r\n                if (val === 'Show all' ||\r\n                    val.startsWith('On-campus') && !isOnline ||\r\n                    val.startsWith('Online') && isOnline) {\r\n                    c[key + 'Filter'] = true;\r\n                } else {\r\n                    c[key + 'Filter'] = false;\r\n                }\r\n            }\r\n\r\n            input[i] = timetableService.checkForVisibleChildren(item, filters);\r\n        }\r\n\r\n        return input;\r\n    }\r\n};","export default timetableService => {\r\n    return function (input, key, filters) {\r\n\r\n        var hour = filters[key].hour,\r\n            type = filters[key].type,\r\n            c,\r\n            i,\r\n            j,\r\n            m,\r\n            l = input.length;\r\n\r\n        if (hour === null || type === null || type === 'Show all') {\r\n            for (i = 0; i < l; i++) {\r\n                m = input[i].classes;\r\n                for (j = 0; j < m.length; j++) {\r\n                    m[j].timeFilter = true;\r\n                }\r\n\r\n                input[i] = timetableService.checkForVisibleChildren(input[i], filters);\r\n            }\r\n        } else {\r\n            for (i = 0; i < l; i++) {\r\n                m = input[i].classes;\r\n                for (j = 0; j < m.length; j++) {\r\n                    c = m[j];\r\n                    c.timeFilter = false;\r\n\r\n                    if (c.meetingStartTime !== undefined && c.meetingStartTime !== null) {\r\n\r\n                        if (type === 'Starting after') {\r\n                            if (hour &&\r\n                                parseInt(c.meetingStartTime.replace(':', '')) >=\r\n                                parseInt(hour.replace(':', ''))) {\r\n                                c.timeFilter = true;\r\n                            }\r\n                        } else if (type === 'Finishing before') {\r\n                            if (hour &&\r\n                                parseInt(c.meetingEndTime.replace(':', '')) <=\r\n                                parseInt(hour.replace(':', ''))) {\r\n                                c.timeFilter = true;\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n\r\n                input[i] = timetableService.checkForVisibleChildren(input[i], filters);\r\n            }\r\n        }\r\n        return input;\r\n    }\r\n};","import addedToPlannerController from './addedtoplanner.controller';\r\nimport classDetailModalController from './classdetail.modal.controller';\r\nimport confirmIcsModalController from './confirmics.modal.controller';\r\nimport firstRunModalController from './firstrun.modal.controller';\r\nimport plannerController from './planner.controller';\r\nimport recentSearchesController from './recentsearches.controller';\r\nimport removeFromPlannerModalController from './removefromplanner.modal.controller';\r\nimport timetableController from './timetable.controller';\r\nimport updateCourseSelectionModalController from './updatecourseselection.modal.controller';\r\n\r\nconst moduleName = 'usc.timetable.controllers';\r\n\r\nangular.module(moduleName, [])\r\n    .controller('addedToPlannerCtrl', ['$scope', 'timetableService', 'storageService', addedToPlannerController])\r\n    .controller('ClassDetailModalCtrl', ['$scope', '$uibModalInstance', 'c', 'all', classDetailModalController])\r\n    .controller('ConfirmIcsModalCtrl', ['$scope', '$uibModalInstance', '$timeout', 'addedToPlanner', '$filter', confirmIcsModalController])\r\n    .controller('FirstRunModalCtrl', ['$scope', '$uibModalInstance', firstRunModalController])\r\n    .controller('uscTimetablePlannerController', ['$scope', '$rootScope', 'timetableService', 'plannerFactory', plannerController])\r\n    .controller('recentSearchesCtrl', ['$scope', 'timetableService', 'storageService', recentSearchesController])\r\n    .controller('RemoveCourseFromPlannerModalCtrl', ['$scope', '$uibModalInstance', removeFromPlannerModalController])\r\n    .controller('UscTimetableController', ['$scope', '$rootScope', 'timetableService', 'plannerFactory', 'recentSearchesFactory', 'alertsService', '$uibModal', '$filter', '$timeout', '$q', 'timetableConfig', timetableController])\r\n    .controller('UpdateClassSelectionModalCtrl', ['$scope', '$uibModalInstance', '$filter', 'courseCode', 'courseName', 'current', 'classes', updateCourseSelectionModalController]);\r\n\r\nexport default moduleName;","/**\r\n * Display a list of course cards in the added to planner UI container\r\n * @param {} $scope \r\n * @param {} timetableService \r\n * @param {} storageService \r\n * @returns {} \r\n */\r\nexport default function ($scope, timetableService, storageService) {\r\n\r\n    /**\r\n     * Update the added to planner list when selected term updates\r\n     */\r\n    timetableService.subscribe($scope, 'selectedTermChanged', () => {\r\n        $scope.vm.addedToPlanner = storageService.getPlanner();\r\n    });\r\n\r\n    /**\r\n     * Receive model updates when the recent courses object is updated in the service\r\n     */\r\n    timetableService.subscribe($scope, 'plannerChanged', (e, args) => {\r\n        $scope.vm.addedToPlanner = args.addedToPlanner;\r\n    });\r\n};","export default function ($scope, $uibModalInstance, c, all) {\r\n\r\n    $scope.class = c.class;\r\n    $scope.course = c;\r\n    $scope.all = all;\r\n\r\n    $scope.courseDetailHref = '/learn/courses-and-programs/courses/' +\r\n        $scope.course.courseCode.toLowerCase();\r\n\r\n    $scope.close = function() {\r\n        $uibModalInstance.dismiss();\r\n    };\r\n\r\n};","export default function ($scope, $uibModalInstance, $timeout, addedToPlanner, $filter) {\r\n\r\n    $scope.getIcs = function () {\r\n\r\n        var icsHeader = 'BEGIN:VCALENDAR\\r\\nVERSION:2.0\\r\\nPRODID:-//UniSC//NONSGML v1.0//EN\\r\\nX-WR-CALNAME:USC timetable planner\\r\\n',\r\n            email = 'timetable@usc.edu.au',\r\n            icsBody = '',\r\n            icsMsg;\r\n\r\n        angular.forEach(addedToPlanner, function (el) {\r\n\r\n            if (el.hasOwnProperty('class')) {\r\n\r\n                var icsEvent,\r\n                    dtStamp = new Date(),\r\n                    day = el.class.meetingDay,\r\n                    startTime = $filter('date')(el.class.meetingStartTime, \"HH:MM\").replace(\":\", \"\"),\r\n                    finishTime = $filter('date')(el.class.meetingEndTime, \"HH:MM\").replace(\":\", \"\"),\r\n                    startDate = el.class.meetingStartDate,\r\n                    finishDate = el.class.meetingEndDate,\r\n                    location = el.class.room + ' ' + el.class.location,\r\n                    title = el.courseCode + ' ' + el.class.classDesc,\r\n                    dtStartTime = $filter('date')(startDate, 'yyyyMMdd') + 'T' + startTime + '00',\r\n                    dtFinishTime = $filter('date')(startDate, 'yyyyMMdd') + 'T' + finishTime + '00',\r\n                    dtEnd = $filter('date')(finishDate, 'yyyyMMdd') + 'T' + finishTime + '00';\r\n\r\n                icsEvent = 'BEGIN:VEVENT\\r\\nUID:' + email + '\\r\\nDTSTAMP:' + dtStamp.getFullYear() + (dtStamp.getMonth() + 1) + (dtStamp.getDate() + 1) + 'T' + dtStamp.getHours() + dtStamp.getMinutes() + '\\r\\n';\r\n                icsEvent += 'DTSTART:' + dtStartTime + '\\r\\nDTEND:' + dtFinishTime + '\\r\\nLOCATION:' + location + '\\r\\nSUMMARY:' + title + '\\r\\nRRULE:FREQ=WEEKLY;UNTIL=' + dtEnd + ';BYDAY=' + day.substr(0, 2).toUpperCase() + '\\r\\nEND:VEVENT\\r\\n';\r\n\r\n                icsBody += icsEvent;\r\n            }\r\n        });\r\n\r\n        icsMsg = icsHeader + icsBody + 'END:VCALENDAR';\r\n\r\n        if (!navigator.userAgent.match(/msie|trident/i)) {\r\n\r\n            var downloadLink = document.createElement(\"a\");\r\n            downloadLink.href = 'data:text/calendar;charset=utf-8,\\r\\n' + escape(icsMsg);\r\n            downloadLink.download = \"Timetable planner.ics\";\r\n            //when an event is triggered programmatically which already exists in the client side, it calls $apply within $digest for the second time\r\n            // which causing Action Already In Progress error. \r\n            //To avoid this we need to move the call to event outside of the digest, by using $timeout(fn, 0, false)\r\n            //refer to https://docs.angularjs.org/error/$rootScope/inprog?p0=$apply\r\n            $timeout(function () {\r\n                document.body.appendChild(downloadLink);\r\n                downloadLink.click();\r\n                document.body.removeChild(downloadLink);\r\n            }, 0, false);\r\n\r\n        }\r\n        else {\r\n            var blob = new Blob([icsMsg]);\r\n            window.navigator.msSaveOrOpenBlob(blob, 'Timetable planner.ics');\r\n        }\r\n    };\r\n\r\n    $scope.close = function () {\r\n        $uibModalInstance.dismiss('cancel');\r\n    };\r\n\r\n};","export default function ($scope, $uibModalInstance) {\r\n\r\n    $scope.ok = function () {\r\n        $uibModalInstance.close(true);\r\n    };\r\n\r\n};","export default function ($scope, $rootScope, timetableService, plannerFactory) {\r\n    var vm = this;\r\n\r\n    vm.planner = plannerFactory.scaffold();\r\n\r\n    function getOnline() {\r\n        let online = [];\r\n\r\n        vm.planner.forEach(day => {\r\n            if (day.hours[0].classes.length) {\r\n                online = online.concat(day.hours[0].classes);\r\n            }\r\n        });\r\n\r\n        return online.length ? online : undefined;\r\n    }\r\n\r\n    timetableService.subscribe($scope, 'plannerChanged',\r\n        function plannerUpdated(e, args) {\r\n            vm.addedToPlanner = args.addedToPlanner;\r\n            vm.onlineClassCount = args.onlineClassCount;\r\n            vm.onlineCourseCount = args.onlineCourseCount;\r\n            vm.planner = args.planner;\r\n            vm.online = getOnline();\r\n        });\r\n\r\n    $rootScope.$watch('selectedTerm', function (newVal, oldVal) {\r\n        if (newVal && newVal !== oldVal) {\r\n            plannerFactory.getFromLocalStorage();\r\n        }\r\n    }, true);\r\n};","export default function ($scope, timetableService, storageService) {\r\n\r\n    this.recent = storageService.getRecent();\r\n\r\n    /**\r\n     * Receive model updates when the recent courses object is updated in the service\r\n     */\r\n    timetableService.subscribe($scope, 'recentChanged', (e, arg) => this.recent = arg);\r\n\r\n    if (this.recent.length) {\r\n\r\n        // Get a list of history objects to be validated against the server side\r\n        // exclude recent objects representing saved searches - only valid course items\r\n        var validationData = this.recent.filter((v, i) => {\r\n            v.index = i;\r\n            return v.description;\r\n        }).map(v => {\r\n            return { courseCode: v.courseCode, termId: v.termId, index: v.index };\r\n        });\r\n\r\n        var fromSearch = this.recent.filter((v, i) => {\r\n            v.index = i;\r\n            return !v.description;\r\n        });\r\n\r\n        // possible we have no courses to check\r\n        if (validationData.length) {\r\n            // Call the server to get the course and term changes in the recently viewed\r\n            timetableService.getValidatedCourseTerms(validationData).then(removalList => {\r\n                var item,\r\n                    i,\r\n                    y;\r\n\r\n                if (removalList.status.toLowerCase() === 'success' &&\r\n                    removalList.data &&\r\n                    removalList.data.length > 0) {\r\n                    // We have recieved some items to remove from the recently viewed list as they are no longer available.\r\n                    for (i = 0; i < removalList.data.length; i++) {\r\n                        item = removalList.data[i];\r\n                        for (y = 0; y < this.recent.length; y++) {\r\n                            if (this.recent[y].courseCode === item.courseCode &&\r\n                                this.recent[y].termId === item.termId) {\r\n                                this.recent.splice(y, 1);\r\n                            }\r\n                        }\r\n                    }\r\n\r\n                    if (fromSearch.length) {\r\n                        fromSearch.forEach(v => this.recent.splice(v.index, 0, v));\r\n                    }\r\n\r\n                    storageService.storeRecent(this.recent);\r\n                }\r\n            });\r\n        }\r\n    }\r\n};","export default function ($scope, $uibModalInstance) {\r\n    $scope.ok = function () {\r\n        $uibModalInstance.close(true);\r\n    };\r\n\r\n    $scope.cancel = function () {\r\n        $uibModalInstance.dismiss('cancel');\r\n    };\r\n};","export default function ($scope, $rootScope, timetableService, plannerFactory, recentSearchesFactory, alertsService, $uibModal, $filter, $timeout, $q, timetableConfig) {\r\n\r\n    var showFirstRunModal = !timetableConfig.GODMODE,\r\n        root = document.querySelector('[ng-controller=\"UscTimetableController\"]'),\r\n        overlayInterval = root.dataset.overlayInterval || 28,\r\n        now = new Date();\r\n\r\n    // punting this into rootscope rather than creating another service - constant value, so happy to cause a little pollution...\r\n    $rootScope.allClassesClosedMessage = root.dataset.allClosedMessage;\r\n\r\n    // When the term changes, update the UI via init(), which essentially resets the view\r\n    timetableService.subscribe($scope, 'selectedTermChanged', function (e, arg) {\r\n        init(arg);\r\n    });\r\n\r\n    // Raised when all courses for the selected teaching period are available\r\n    timetableService.subscribe($scope, 'coursesChanged', function (e, arg) {\r\n        $scope.courses = arg.data;\r\n        $scope.loadingCourses = false;\r\n    });\r\n\r\n    timetableService.subscribe($scope, 'resultsChanged', function (e, arg) {\r\n        $scope.results = arg;\r\n        $scope.noResults = $scope.results.length === 0;\r\n        getClasses();\r\n    });\r\n\r\n    // declare a bunch of scoped variables\r\n    // arrays\r\n    $scope.courses = [];\r\n    $scope.results = [];\r\n    $scope.alerts = alertsService.get();\r\n    $scope.locationFilters = [];\r\n    $scope.days = timetableConfig.DAYS;\r\n    //bools\r\n    $scope.showFilters = false;\r\n    $scope.showError = false;\r\n    $scope.DBErrorMsg = false;\r\n    $scope.noActiveFilters = true;\r\n\r\n    //numeric\r\n    $scope.perPage = 3;\r\n    $scope.currentPage = 1;\r\n\r\n    // should we show the first-run modal -> godmode will supress the modal, regardless of elapsed days since last displayed\r\n    if (!timetableConfig.GODMODE && timetableConfig.HAS_LOCALSTORAGE) {\r\n        // check first run modal date\r\n        if (localStorage[timetableConfig.LOCAL_STORE_KEY + 'acceptedConditions']) {\r\n            var lastModalDate = new Date(localStorage[timetableConfig.LOCAL_STORE_KEY + 'acceptedConditions']);\r\n            if (Object.prototype.toString.call(lastModalDate) === '[object Date]') {\r\n                var then = lastModalDate.getTime(),\r\n                    diff = (now.getTime() - then) / 864e5; // millseconds -> seconds -> minutes -> hours -> days\r\n\r\n                showFirstRunModal = diff > overlayInterval;\r\n            }\r\n        }\r\n    }\r\n\r\n    $q.all([timetableService.getTerms(), timetableService.getCampus()])\r\n        .then(function (resp) {\r\n\r\n            if (resp[0]) {\r\n\r\n                if (resp[0].status === 'Error' || resp[0].data.length === 0) {\r\n                    $scope.DBErrorMsg = true;\r\n                } else {\r\n                    $scope.terms = $filter('orderBy')(resp[0].data, 'fullDescription');\r\n\r\n                    if (!timetableConfig.GODMODE) {\r\n                        $scope.terms = $scope.terms.filter(term => !term.godsOnly);\r\n                    }\r\n                }\r\n            }\r\n            if (resp[1]) {\r\n                if (resp[1].status === 'Error' || resp[1].data.length === 0) {\r\n                    $scope.DBErrorMsg = true;\r\n                } else {\r\n                    var tempLocations = [];\r\n                    for (var camp = 0; camp < resp[1].data.length; camp++) {\r\n                        tempLocations.push(resp[1].data[camp]);\r\n                    }\r\n\r\n                    $scope.locationFilters = tempLocations.sort(function (a, b) {\r\n                        if (a < b) {\r\n                            return -1;\r\n                        }\r\n                        if (a > b) {\r\n                            return 1;\r\n                        }\r\n                        return 0;\r\n                    });\r\n                    $scope.locationFilters.unshift('Show all');\r\n                }\r\n            }\r\n\r\n            $scope.loadingCourses = false;\r\n\r\n            timetableService.checkParams($scope.terms.map(function (v) {\r\n                return v.id;\r\n            }));\r\n        });\r\n\r\n    //////////////////////////////////////////////////////\r\n    // SCOPED FUNCTIONS\r\n    /////////////////////////////////////////////////////\r\n\r\n    //reseting filters\r\n    $scope.resetFilters = function () {\r\n        resetFilters(false);\r\n    };\r\n\r\n    $scope.refresh = function () {\r\n        init();\r\n    };\r\n\r\n    /**\r\n     * Filter the results set in response to a UI change\r\n     * If no results exist, and the location filter triggers this function, force a search for all courses\r\n     * @param {} key \r\n     * @returns {} \r\n     */\r\n    $scope.filterResults = function (key) {\r\n        $scope.loadingCourses = true;\r\n        if ($scope.results.length) {\r\n            if (key === 'time' && $scope.activeFilters.time.hour !== null) {\r\n                $scope.badgeHour = $scope.timeFilters.hour.where(function (h) {\r\n                    return h.value === $scope.activeFilters.time.hour;\r\n                })[0].key;\r\n            }\r\n\r\n            $scope.results = $filter(key)($scope.results, key, $scope.activeFilters);\r\n            $scope.currentPage = 1;\r\n\r\n            countVisibleResults(); \r\n            countTotalPages();\r\n            showHideActiveFilters();\r\n        } else if (key === 'location') {\r\n            $scope.submitSearch(null, null, true);\r\n        }\r\n        $scope.loadingCourses = false;\r\n    };\r\n\r\n    $scope.updateFilter = function (key, index, weekend) {\r\n        if (key === 'day') {\r\n            $scope.activeFilters.day[index] = weekend !== true;\r\n        }\r\n        if (key === 'program') {\r\n            $scope.activeFilters.program = $scope.programFilters[0];\r\n        }\r\n        if (key === 'location') {\r\n            $scope.activeFilters.location = $scope.locationFilters[0];\r\n        }\r\n        if (key === 'type') {\r\n            $scope.activeFilters.type = $scope.typeFilters[0];\r\n        }\r\n\r\n        if (key === 'time') {\r\n            $scope.activeFilters.time = {\r\n                type: $scope.timeFilters.type[0],\r\n                hour: null\r\n            };\r\n        }\r\n\r\n        $scope.selectedfilters--;\r\n        $scope.results = $filter(key)($scope.results, key, $scope.activeFilters);\r\n        $scope.currentPage = 1;\r\n\r\n        countVisibleResults();\r\n        countTotalPages();\r\n        showHideActiveFilters();\r\n    };\r\n\r\n    $scope.paging = function (i) {\r\n        $scope.currentPage = $scope.currentPage + i;\r\n    };\r\n\r\n    /**\r\n     * Set the selected term in the factory, triggering a request for all courses for the term\r\n     * @returns {} \r\n     */\r\n    $scope.setTerm = function () {\r\n        $scope.loadingCourses = true;\r\n        $scope.showFilters = false;\r\n        timetableService.setSelectedTerm($scope.selectedTerm);\r\n    };\r\n\r\n    /**\r\n     * Find the course detail when a selection is made in the search typeahead\r\n     * @param {} $item \r\n     * @returns {} \r\n     */\r\n    var prevSearchTerm = '', searching = false;\r\n\r\n    $scope.submitSearchOnBlur = function () {\r\n        searching = false;\r\n        $timeout(function () {\r\n            if (!searching) {\r\n                $scope.submitSearch();\r\n            }\r\n        }, 100);\r\n    }\r\n\r\n    //submit button - find all courses matching search params\r\n    $scope.submitSearch = function (typeaheadSelect, item, force) {\r\n\r\n        searching = true;\r\n\r\n        $scope.searchTerm = item ? item.fullDescription : $scope.searchTerm;\r\n\r\n        if ($scope.searchTerm !== prevSearchTerm || force) {\r\n            $scope.results = [];\r\n            for (var i = 0, l = $scope.courses.length; i < l; i++) {\r\n                var c = $scope.courses[i];\r\n\r\n                if (c.fullDescription.toLowerCase().indexOf($scope.searchTerm.toLowerCase()) > -1) {\r\n                    c.hasVisibleChildren = true;\r\n                    c.hiddenByProgramFilter = false;\r\n\r\n                    $scope.results.push(c);\r\n                }\r\n            }\r\n            $scope.noResults = $scope.results.length === 0;\r\n\r\n            if ($scope.searchTerm.length) {\r\n                recentSearchesFactory.add({\r\n                    courseCode: typeaheadSelect ? item.courseCode : $scope.searchTerm,\r\n                    description: typeaheadSelect ? item.description : '',\r\n                    termId: $scope.selectedTerm.id\r\n                });\r\n            }\r\n\r\n            prevSearchTerm = $scope.searchTerm;\r\n\r\n            getClasses();\r\n        }\r\n    }\r\n\r\n    //////////////////////////////////////////////////////\r\n    // PRIVATE FUNCTIONS\r\n    /////////////////////////////////////////////////////\r\n\r\n    /**\r\n     * For the current set of search results, request the classes\r\n     * @returns {} \r\n     */\r\n    function getClasses() {\r\n        $scope.loadingCourses = true;\r\n        var ids = $scope.results.map(function (v) {\r\n            return v.courseId;\r\n        });\r\n\r\n        timetableService.getClassBySearchTerm(ids)\r\n            .then(function (resp) {\r\n                mapClassesToCourses(resp.data);\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Relate classes object to the relevant course object in the search results\r\n     * Also store a location string on the search result to ease filtering\r\n     * @param {} classes \r\n     * @returns {} \r\n     */\r\n    function mapClassesToCourses(classes) {\r\n        $scope.results.forEach(function (result) {\r\n            var c = classes.filter(function (vv) {\r\n                return vv.key === result.courseId;\r\n            })[0];\r\n\r\n            if (c) {\r\n                var offeredLocations = c.value.map(function (v) {\r\n                    return v.location;\r\n                }).filter(function (value, index, self) {\r\n                    return self.indexOf(value) === index;\r\n                }).join('|');\r\n\r\n                result.classes = c.value;\r\n                result.locations = offeredLocations;\r\n            }\r\n        });\r\n\r\n        // need to trigger the location filter, as a location may exist prior to the results\r\n        filterNewResults();\r\n        $scope.loadingCourses = false;\r\n    }\r\n\r\n\r\n    // Generate the hour values for the time filer\r\n    function populateTimeFilter() {\r\n        var arr = [], seed = 7, i = 0;\r\n        for (; i < 15; i++) {\r\n\r\n            var time = seed <= 12 ? seed : seed - 12;\r\n\r\n            arr.push({\r\n                'key': time + (seed < 12 ? 'am' : seed === 12 ? 'nn' : 'pm'),\r\n                'value': seed + ':00'\r\n            });\r\n\r\n            seed = seed + 1;\r\n        }\r\n        return arr;\r\n    }\r\n\r\n    function showHideActiveFilters() {\r\n        $timeout(function () {\r\n            $scope.noActiveFilters = document.getElementById('filteringBy').childElementCount === 0;\r\n        }, 10);\r\n    }\r\n\r\n    /**\r\n     * \r\n     * @returns {} \r\n     */\r\n    function countVisibleResults() {\r\n        $scope.visibleResultsCount = $scope.results.filter(function (el) {\r\n            var allHidden = true;\r\n            el.allClassesClosed = el.classes.filter(function (v) {\r\n                allHidden = v.hiddenByFilter ? allHidden : false;\r\n                return v.enrolmentStatus !== 'O' || (v.enrolmentStatus === 'O' && v.location !== $scope.activeFilters.location && $scope.activeFilters.location !== 'Show all');\r\n            }).length === el.classes.length;\r\n\r\n            el.allClassesHidden = allHidden;\r\n            return el.hiddenByProgramFilter === false && el.hiddenByLocationFilter === false && allHidden === false;\r\n        }).length;\r\n    }\r\n\r\n    function countTotalPages() {\r\n        $scope.totalPages = Math.ceil($scope.visibleResultsCount / $scope.perPage);\r\n    }\r\n\r\n    //review the current set filters for new results\r\n    function filterNewResults() {\r\n\r\n        $scope.loadingCourses = true;\r\n\r\n        var filters = ['day', 'location', 'time', 'program'];\r\n        for (var i = 0; i < filters.length; i++) {\r\n            $scope.results = $filter(filters[i])($scope.results, filters[i], $scope.activeFilters);\r\n        }\r\n        $filter('pattern')($scope.results);\r\n\r\n        countVisibleResults();\r\n        countTotalPages();\r\n        $scope.loadingCourses = false;\r\n    }\r\n\r\n    function resetFilters(clearSearch) {\r\n        // reset filter values to sensible defaults\r\n        $scope.programFilters = ['Show all', 'Undergraduate', 'Postgraduate', 'Enabling'];\r\n        $scope.typeFilters = ['Show all', 'On-campus only', 'Online only'];\r\n        $scope.timeFilters = {\r\n            type: ['Show all', 'Starting after', 'Finishing before'],\r\n            hour: populateTimeFilter()\r\n        };\r\n\r\n        $scope.activeFilters = {\r\n            program: $scope.programFilters[0],\r\n            type: $scope.typeFilters[0],\r\n            day: [false, true, true, true, true, true, true],\r\n            time: {\r\n                type: $scope.timeFilters.type[0],\r\n                hour: null\r\n            },\r\n            location: $scope.locationFilters[0]\r\n        };\r\n\r\n        if (clearSearch === undefined) {\r\n            //reset course search term \r\n            $scope.searchTerm = '';\r\n            $scope.totalPages = 0;\r\n            $scope.errorMsg = '';\r\n            //Reseting course details search \r\n        } else {\r\n            filterNewResults();\r\n        }\r\n    }\r\n\r\n    if (showFirstRunModal && !timetableConfig.GODMODE) {\r\n        var firstRunModalInstance = $uibModal.open({\r\n            templateUrl: 'firstRunModal.html',\r\n            controller: 'FirstRunModalCtrl',\r\n            backdrop: 'static'\r\n        });\r\n\r\n        firstRunModalInstance.result.then(function (resp) {\r\n            if (resp) {\r\n                resetFilters();\r\n                if (timetableConfig.HAS_LOCALSTORAGE) {\r\n                    localStorage[timetableConfig.LOCAL_STORE_KEY + 'acceptedConditions'] = new Date();\r\n                }\r\n            }\r\n        });\r\n    } else {\r\n        resetFilters();\r\n    }\r\n\r\n    /**\r\n     * Reset button or semester change calls init, clears all semester-specific variables\r\n     * @param {} arg \r\n     * @returns {} \r\n     */\r\n    function init(arg) {\r\n        $scope.selectedTerm = arg || undefined;\r\n        $scope.loadingCourses = true;\r\n        $scope.showFilters = true;\r\n        $scope.results = [];\r\n        $scope.visibleResultsCount = 0;\r\n        $rootScope.showAll = arg ? timetableService.getSelectedTerm().showAllFrom < now.getTime() || timetableConfig.GODMODE : false;\r\n\r\n        if (timetableConfig.HAS_LOCALSTORAGE) {\r\n            plannerFactory.clearPlannerUi();\r\n            plannerFactory.getFromLocalStorage();\r\n        }\r\n\r\n        resetFilters();\r\n\r\n        // this is a bit lazy, but fixes the infinite loading when reverting back to a previously selected teaching period\r\n        $scope.loadingCourses = false;\r\n    }\r\n};","export default function ($scope, $uibModalInstance, $filter, courseCode, courseName, current, classes) {\r\n\r\n    $scope.courseName = courseName;\r\n    $scope.courseCode = courseCode;\r\n\r\n    $scope.validClasses = [];\r\n    $scope.current = [];\r\n    $scope.classTypes = [];\r\n\r\n    var uniqueClassNos = [],\r\n        currentClassNos = [],\r\n        toRemove = [];\r\n\r\n    function buildUniqueList(initial, parsed, uniqueArray, isCurrentClasses) {\r\n        initial.forEach(c => {\r\n            if (c && (c.enrolmentStatus === 'O' || isCurrentClasses)) {\r\n\r\n                var classNo = c.classNo,\r\n                    i = uniqueArray.indexOf(classNo);\r\n\r\n                if (i === -1) {\r\n                    c.isMultiday = false;\r\n                    parsed.push(c);\r\n                    uniqueArray.push(classNo);\r\n                } else {\r\n                    parsed[i].isMultiday = true;\r\n                    $scope.hasMultiday = true;\r\n                }\r\n\r\n                if ($scope.classTypes.indexOf(c) === -1) {\r\n                    $scope.classTypes.push(c);\r\n                }\r\n            }\r\n        });\r\n    };\r\n\r\n    buildUniqueList(current, $scope.current, currentClassNos, true);\r\n    buildUniqueList(classes, $scope.validClasses, uniqueClassNos);\r\n\r\n    // make sure no classes exist in valid that are already selected - multidays will still be appearing    \r\n    $scope.validClasses = $scope.validClasses.filter(c => currentClassNos.indexOf(c.classNo) === -1);\r\n\r\n    $scope.toAdd = null;\r\n    $scope.SetSelectedClass = t => {\r\n        $scope.toAdd = t;\r\n    }\r\n\r\n    $scope.showCurrent = current.length !== 0;\r\n\r\n    $scope.markForRemoval = () => {\r\n        toRemove = $scope.current.filter(el =>el.checked);\r\n    }\r\n\r\n    $scope.getNgOption = c => \r\n        !c.isMultiday\r\n            ? `${c.classDesc} (${c.meetingDay}, ${$filter('dateTime')(c.meetingStartTime, 'time')}-${$filter('dateTime')(c.meetingEndTime, 'time')}, ${c.location})`\r\n            : `${c.classDesc} (${c.classSection}) *`;    \r\n\r\n    $scope.ok = () => {\r\n        var toAdd = $scope.validClasses.filter(o => (o.classNo.toString() + o.classMeetingNo.toString()) === $scope.toAdd);     \r\n        $uibModalInstance.close([toAdd, toRemove]);\r\n    };\r\n\r\n    $scope.cancel = function () {\r\n        resetRemoval();\r\n        $uibModalInstance.dismiss('cancel');\r\n    };\r\n\r\n    function resetRemoval() {\r\n        $scope.current.forEach(o => o.checked = false);            \r\n    }\r\n};","import timetableControllers from './controllers/_controllers';\r\nimport timetableDirectives from './directives/_directives';\r\nimport timetableFilters from './filters/_filters';\r\nimport timetableResources from './resources/_resources';\r\n\r\nimport 'Sass/views/timetable.scss';\r\n\r\nconst moduleName = 'usc.timetable';\r\n\r\n/**\r\n * Check for querystring value where godmode=true\r\n * @returns {} \r\n */\r\nconst isGodMode = () => {\r\n    var queryString = location.href.indexOf('?') !== -1 ? location.href.substr(location.href.indexOf('?')) : '',\r\n        params = queryString.substr(1, queryString.length - 1).split('&'),\r\n        i,\r\n        keyValue,\r\n        resp = false;\r\n\r\n    for (i = 0; i < params.length; i++) {\r\n        keyValue = params[i].split('=');\r\n        if (keyValue.length &&\r\n            keyValue[0].toLowerCase() === 'godmode' &&\r\n            keyValue[1].toLowerCase().startsWith('true')) {\r\n            resp = true;\r\n        }\r\n    }\r\n\r\n    return resp;\r\n};\r\n\r\n/**\r\n * Is localstorage API available?\r\n * @returns {} \r\n */\r\nconst checkLocalStorage = () => {\r\n    try {\r\n        return 'localStorage' in window && window['localStorage'] !== null;\r\n    } catch (e) {\r\n        return false;\r\n    }\r\n};\r\n\r\nangular.module(moduleName,\r\n    [\r\n        timetableControllers,\r\n        timetableDirectives,\r\n        timetableFilters,\r\n        timetableResources\r\n    ]).constant('timetableConfig',\r\n    {\r\n        'LOCAL_STORE_KEY': '__usc__timetable__',\r\n        'DAYS': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\r\n        'SIDEBAR_MAX': 6,\r\n        'HAS_LOCALSTORAGE': checkLocalStorage(),\r\n        'GODMODE': isGodMode()\r\n    });\r\n\r\nconst app = angular.module(window.uscApp);\r\napp.requires.push(moduleName);","import classBlock from './classblock.directive';\r\nimport plannerCourseCard from './plannercoursecard.directive';\r\nimport recentSearchCard from './recentsearchcard.directive';\r\nimport searchResult from './searchresult.directive';\r\nimport searchResultRow from './searchresultrow.directive';\r\n\r\nconst moduleName = 'usc.timetable.directives';\r\n\r\nangular.module(moduleName, [])\r\n    .directive('classBlock', ['timetableService', 'plannerFactory', '$uibModal', classBlock])\r\n    .directive('plannerCourseCard', ['$filter', 'timetableService', 'plannerFactory', '$uibModal', plannerCourseCard])\r\n    .directive('recentSearchCard', ['timetableService', 'recentSearchesFactory', recentSearchCard])\r\n    .directive('searchResult', ['$filter', '$sce', '$rootScope', searchResult])\r\n    .directive('searchResultRow', ['plannerFactory', searchResultRow]);\r\n\r\nexport default moduleName;","\r\n\r\n/**\r\n * Display the class item in the planner grid UI\r\n * @param {} timetableService \r\n * @param {} plannerFactory \r\n * @param {} $uibModal \r\n * @returns {} \r\n */\r\nexport default function (timetableService, plannerFactory, $uibModal) {\r\n\r\n    const classDetailModalTemplate = `\r\n        <div class=\"modal-header\">\r\n           <h3 class=\"mb-0 h4\" id=\"update-modal-label\">{{ ::course.courseCode }} {{ ::course.description }} - {{ ::class.classDesc }}</h3>\r\n        </div>\r\n        <div class=\"modal-body\">\r\n           <div class=\"alert\" ng-if=\"class.noteText !== null\">\r\n                <i class=\"fal fa-comment-alt-exclamation\"></i>\r\n                <div>\r\n                    <p>{{ class.noteText }}</p>    \r\n                </div>\r\n            </div>\r\n           <dl class=\"dl-columns\">\r\n               <dt>Location</dt>\r\n               <dd>{{ class.room }} <span ng-if=\"class.room !== \\'ONLINE\\'\">({{ class.location }})</span></dd>\r\n               <dt>Day</dt>\r\n               <dd>{{ class.meetingDayNo|dateTime:\\'day\\' }}</dd>\r\n               <dt ng-if=\"class.meetingStartTime !== null && class.meetingEndTime !== null && class.room !== \\'ONLINE\\'\">Time</dt>\r\n               <dd ng-if=\"class.meetingStartTime !== null && class.meetingEndTime !== null && class.room !== \\'ONLINE\\'\">\r\n                    {{ class.meetingStartTime|dateTime:\\'time\\' }}&ndash;{{ class.meetingEndTime|dateTime:\\'time\\' }}\r\n                </dd>\r\n               <dt ng-if=\"all[0].meetingStartDate !== null && all[0].meetingEndDate !== null\">Dates</dt>\r\n               <dd ng-if=\"all[0].meetingStartDate !== null && all[0].meetingEndDate !== null\">\r\n                   <span ng-repeat=\"a in all track by $index\">\r\n                       <span>{{ a.meetingStartDate | date:\\'d MMMM\\' }}&ndash;{{ a.meetingEndDate | date:\\'d MMMM\\' }}</span><br ng-if=\"$index < all.length\" />\r\n                   </span>\r\n               </dd>\r\n           </dl>\r\n           <p class=\"footnote\">For course requisites and fee information, refer to the <a href=\"{{ courseDetailHref }}\">course detail</a>.</p>\r\n        </div>\r\n        <div class=\"modal-footer\">\r\n           <a class=\"btn btn-secondary mr-auto\" href=\"{{ courseDetailHref }}\">Course detail</a>\r\n           <button class=\"btn btn-outline-primary\" ng-click=\"close()\">Close</button>\r\n        </div>`;\r\n\r\n    return {\r\n        scope: {\r\n            classData: '='\r\n        },\r\n        restrict: 'E',\r\n        replace: true,\r\n        template: `\r\n            <div class=\"class-block height{{ class.duration }} {{ cssClass }}\"\r\n                ng-click=\"showClassDetail()\"\r\n                aria-label=\"Class detail\"\r\n                title=\"Class detail\">\r\n                <h6>{{ classData.courseCode }} <span ng-bind=\"!isOnline ? \\' - \\' + class.classDesc : \\'\\'\"></span></h6>\r\n                <button class=\"btn btn-link course-card-btn\" stop-event ng-click=\"removeFromPlanner()\" aria-label=\"Remove from planner\" title=\"Remove from planner\">\r\n                    <i class=\"fal fa-xmark\"></i>\r\n                </button>               \r\n                <div ng-if=\"class.noteText !== null\" class=\"notes-icon\" aria-label=\"Refer to class notes\" title=\"Refer to class notes\">\r\n                    <i class=\"fal fa-info-circle\"></i>\r\n                </div>\r\n            </div>`,\r\n        link: function (scope) {\r\n\r\n            scope.class = scope.classData.class;\r\n\r\n            /**\r\n             * Set the class on the block element, as determined by the properities of the class\r\n             */\r\n            function cssClass() {\r\n                scope.cssClass = [\r\n                    scope.class.room === 'ONLINE' ? 'online' : '',\r\n                    scope.class.clash === 'left' ? 'clash-left' : '',\r\n                    scope.class.clash === 'right' ? 'clash-right' : '',\r\n                    scope.class.red ? 'clash-red' : ''\r\n                ].join(' ').trim();\r\n\r\n                scope.isOnline = scope.class.classDesc.toLowerCase().replace(' ', '') === 'online';\r\n            }\r\n\r\n            cssClass();\r\n\r\n            /**\r\n             * display the modal for the selected class, triggered by clicking the card.\r\n             * fetches all classes for the given course to display in dropdown for adding new class selections\r\n             * @returns {} \r\n             */\r\n            scope.showClassDetail = function () {\r\n\r\n                timetableService.getClasses(scope.class.courseId).then(function (response) {\r\n\r\n                    var classes = response.data ? response.data.data : response;\r\n\r\n                    const modal = $uibModal.open({\r\n                        template: classDetailModalTemplate,\r\n                        controller: 'ClassDetailModalCtrl',\r\n                        resolve: {\r\n                            c: function () {\r\n                                return scope.classData;\r\n                            },\r\n                            all: function () {\r\n                                return classes.where(function (r) {\r\n                                    return r.classNo === scope.class.classNo && r.meetingDayNo === scope.class.meetingDayNo && r.meetingStartTime === scope.class.meetingStartTime;\r\n                                });\r\n                            }\r\n                        }\r\n                    });\r\n\r\n                    // doesn't return anything, but need to manage the closure\r\n                    modal.result.then(() => { }, () => { });\r\n                });\r\n            };\r\n\r\n            /**\r\n             * Remove the class from the planner view\r\n             * @returns {} \r\n             */\r\n            scope.removeFromPlanner = function () {\r\n                plannerFactory.removeFromPlanner(scope.classData, false);\r\n            }\r\n\r\n            /**\r\n             * When the planner is updated, the classes on the current class block may need to change\r\n             * Easiest way to do this is subscribe to changes, then fetch the corresponding class from the planner\r\n             * and replace the current with the new, and regenerate the CSS string\r\n             */\r\n            timetableService.subscribe(scope, 'plannerChanged',\r\n                function (e, args) {\r\n                    var inPlanner = args.addedToPlanner;\r\n                    if (inPlanner.length) {\r\n                        var fromPlanner = inPlanner.filter(function (v) {\r\n                            return v.class.classNo === scope.class.classNo;\r\n                        })[0];\r\n\r\n                        if (fromPlanner) {\r\n                            scope.classData.class = fromPlanner.class;\r\n                            cssClass();\r\n                        }\r\n                    }\r\n                });\r\n        }\r\n    };\r\n};","export default function ($filter, timetableService, plannerFactory, $uibModal) {\r\n\r\n    var selectionModalTemplate = `\r\n        <div class=\"modal-header\">\r\n           <h3 class=\"mb-0 h4\" id=\"update-modal-label\">Update selection:<br />\r\n           {{ ::courseCode }} {{ ::courseName }}</h3>\r\n        </div>\r\n        <div class=\"modal-body\">\r\n           <study-load classes=\"classTypes\" ng-if=\"validClasses\"></study-load>\r\n            <div class=\"alert mb-3\" ng-if=\"hasMultiday === true\">\r\n                <i class=\"fal fa-comment-alt-exclamation\"></i>\r\n                <div>\r\n                   <p >This class has multiple offerings each week, or an irregular schedule. Modifying it will update multiple class times in the planner.</p>\r\n                </div>    \r\n            </div>\r\n           <form role=\"form\" class=\"update-selection-form\">\r\n               <div class=\"form-row\" ng-class=\"{\\'no-active-classes\\': validClasses.length === 0}\">\r\n                   <label for=\"add-class\" class=\"col-form-label col-sm-4\">Add class</label>\r\n                   <div class=\"col\">\r\n                       <select name=\"add-class\" ng-if=\"validClasses\" ng-model=\"toAdd\" class=\"form-control\"\r\n                           ng-options=\"(c.classNo.toString()+c.classMeetingNo.toString()) as getNgOption(c) for c in validClasses\" ng-change=\"SetSelectedClass(toAdd)\">\r\n                           <option value=\"\">Select a class</option>\r\n                       </select>\r\n                       <p ng-if=\"!validClasses\">No classes available</p>\r\n                   </div>\r\n               </div>\r\n               <span class=\"or d-flex justify-content-center align-items-center\" ng-show=\"showCurrent\"> OR </span>\r\n               <div class=\"form-row\" ng-show=\"showCurrent\">\r\n                   <label for=\"remove-class\" class=\"col-form-label col-sm-4\">Remove class</label>\r\n                   <div class=\"col\">\r\n                        <div class=\"custom-control custom-checkbox\" ng-repeat=\"c in current track by $index\">\r\n                            <input type=\"checkbox\" id=\"option_{{$index}}\" \r\n                                value=\"\" ng-model=\"c.checked\" ng-change=\"markForRemoval()\"\r\n                                class=\"custom-control-input\" name=\"remove-class\" />\r\n                            <label class=\"custom-control-label\" for=\"option_{{$index}}\" ng-bind=\"getNgOption(c)\"></label>\r\n                        </div>                    \r\n                   </div>\r\n               </div>\r\n           </form>\r\n        </div>\r\n        <div class=\"modal-footer\">\r\n           <button class=\"btn btn-outline-primary\" ng-click=\"cancel()\">Cancel</button>\r\n           <button class=\"btn btn-primary\" ng-click=\"ok()\">OK</button>\r\n        </div>`;\r\n\r\n    return {\r\n        scope: {\r\n            course: '='\r\n        },\r\n        restrict: 'EA',\r\n        replace: true,\r\n        template: `\r\n            <li class=\"course-card\">\r\n              <a ng-click=\"updateSelectionModal()\" class=\"course-card-link\" title=\"Update selections for {{ course.courseCode }}\" stop-event>\r\n                <h5 class=\"course-card-title\" ng-bind=\"course.courseCode\"></h5>\r\n                <span class=\"course-card-name\" ng-bind=\"course.description\"></span>\r\n                <button class=\"btn btn-link course-card-btn\">\r\n                    <i class=\"fal fa-xmark\" title=\"Remove from planner\" ng-click=\"removeFromPlanner()\" stop-event></i>\r\n                </button>                \r\n              </a>\r\n            </li>`,\r\n        link: function (scope) {\r\n\r\n            scope.removeFromPlanner = function () {\r\n                plannerFactory.removeFromPlanner(scope.course, true);\r\n            }\r\n\r\n            scope.updateSelectionModal = function () {\r\n                var classes = [],\r\n                    current = [],\r\n                    selectedClassIds = plannerFactory.getSelectedClassIds(),\r\n                    i, k, l;\r\n\r\n                timetableService.getClasses(scope.course.courseId).then(function (resp) {\r\n\r\n                    var r = resp.data ? resp.data.data : resp;\r\n\r\n                    for (i = 0, l = r.length; i < l; i++) {\r\n                        k = r[i];\r\n\r\n                        if (k.meetingStartTime !== null) {\r\n                            k.meetingStartTime = $filter('date')(k.meetingStartTime, 'HH:MM');\r\n                            k.meetingEndTime = $filter('date')(k.meetingEndTime, 'HH:MM');\r\n                            k.courseCode = scope.course.courseCode;\r\n                            k.description = scope.course.courseName;\r\n                            k.termId = scope.course.termId;\r\n                            k.courseId = scope.course.courseId;\r\n                            k.checked = false;\r\n\r\n                            if (k.classMeetingNo && selectedClassIds.indexOf(k.classNo.toString() + k.classMeetingNo.toString()) === -1) {\r\n                                classes.push(k);\r\n                            } else if (k.hasOwnProperty('classNo')) {\r\n                                current.push(k);\r\n                            }\r\n                        }\r\n                    }\r\n\r\n                    var modalInstance = $uibModal.open({\r\n                        template: selectionModalTemplate,\r\n                        controller: 'UpdateClassSelectionModalCtrl',\r\n                        resolve: {\r\n                            courseCode: () => scope.course.courseCode,\r\n                            courseName: () => scope.course.description,\r\n                            current: () => current,\r\n                            classes: () => classes\r\n                        }\r\n                    });\r\n\r\n                    modalInstance.result.then(function (resp) {\r\n\r\n                        // class to be added to planner\r\n                        if (resp[0].length > 0) {\r\n                            var classToAdd = resp[0][0],\r\n                                classesToAdd = classes.where(function (c) {\r\n                                    // need to return any classes with the same id, to allow for multi-day classes\r\n                                    return c.classNo === classToAdd.classNo;\r\n                                });\r\n\r\n                            plannerFactory.addToPlanner(classesToAdd,\r\n                                classToAdd.courseCode,\r\n                                classToAdd.description,\r\n                                classToAdd.courseId,\r\n                                classToAdd.termId,\r\n                                true);\r\n                        }\r\n\r\n                        // classes to be removed from planner\r\n                        if (resp[1].length > 0) {\r\n                            for (i = 0, l = resp[1].length; i < l; i++) {\r\n                                plannerFactory.removeFromPlanner(resp[1][i], false);\r\n                            }\r\n                        }\r\n                    }, () => {});\r\n                });\r\n            };\r\n        }\r\n    };\r\n};","/**\r\n * Build the card for display in the recent searches column\r\n * @param {} $rootScope \r\n * @param {} recentSearchesFactory \r\n * @returns {} \r\n */\r\nexport default function (timetableService, recentSearchesFactory) {\r\n\r\n    var recentSearchCardTemplate = `\r\n        <li class=\"course-card\">\r\n          <a ng-click=\"get()\" stop-event class=\"course-card-link\">\r\n            <h5 class=\"course-card-title\" ng-bind=\"course.courseCode\"></h5>\r\n            <span class=\"course-card-name\" ng-bind=\"course.description\"></span>\r\n            <button class=\"btn btn-link course-card-btn\" title=\"Remove from recent searches\" ng-click=\"remove()\" stop-event>\r\n                <i class=\"fal fa-xmark\"></i>\r\n            </button>\r\n          </a>\r\n        </li>`;\r\n\r\n    return {\r\n        scope: {\r\n            course: '=',\r\n            submitSearch: '&'\r\n        },\r\n        restrict: 'E',\r\n        replace: true,\r\n        template: recentSearchCardTemplate,\r\n        link: function (scope) {\r\n\r\n            scope.get = function () {\r\n                timetableService.search(scope.course.courseCode, scope.course.termId);\r\n            };\r\n\r\n            scope.remove = function () {\r\n                recentSearchesFactory.remove(scope.course);\r\n            };\r\n        }\r\n    };\r\n};","/**\r\n * Display the search result item\r\n * @param {} $filter \r\n * @returns {} \r\n */\r\nexport default function ($filter, $sce, $rootScope) {\r\n\r\n\r\n    var searchResultTemplate = `\r\n           <h5> {{ ::result.fullDescription }} <span class=\"badge\" title=\"{{ ::result.career }}\" ng-bind=\"::result.career.charAt(0)\"></span></h5>\r\n           <p ng-if=\"result.termFullDescription\" ng-bind=\"::result.termFullDescription\"></p>\r\n           <p ng-if=\"result.formalName && result.coordUrl.length > 0\">Coordinated by <a ng-href=\"{{ ::result.coordUrl }}\" href=\"\" target=\"_blank\" ng-bind=\"::result.formalName\"></a></p>\r\n           <p ng-if=\"result.formalName && result.coordUrl === 0\">Coordinated by {{ ::result.formalName }}</p>\r\n           <div class=\"notice\">\r\n               <p ng-if=\"result.offering === 5\">This course is only available online.</p>\r\n               <p ng-if=\"result.offering !== 5\">Remember that your courses may have various components such as lectures, tutorials or workshops which you will need to select/enrol into.</p>\r\n               <p ng-if=\"noteText\" ng-bind=\"::noteText\"></p>\r\n               <p  ng-if=\"result.messageLong\" ng-bind=\"::result.messageLong | sentenceCase\"</p>\r\n           </div>\r\n           <table ng-hide=\"result.offering === 5\" ng-class=\"{\\'show-all\\' : godMode || showAll }\">\r\n               <thead>\r\n                   <tr>\r\n                       <th ng-click=\"sortByColumn(\\'classSection\\')\" title=\"Order by: Class\">Class <i class=\"fal fa-sort\"></i></th>\r\n                       <th ng-click=\"sortByColumn(\\'meetingDayNo\\')\" title=\"Order by: Day\">Day <i class=\"fal fa-sort\"></i></th>\r\n                       <th ng-click=\"sortByColumn(\\'location\\')\" title=\"Order by: Campus\">Campus <i class=\"fal fa-sort\"></i></th>\r\n                       <th>Room</th>\r\n                       <th ng-click=\"sortByColumn(\\'meetingStartTime\\')\" title=\"Order by: Time\">Time <i class=\"fal fa-sort\"></i></th>\r\n                       <th>Dates</th>\r\n                       <th></th>\r\n                   </tr>\r\n               </thead>\r\n               <tbody>\r\n                  <tr search-result-row result=\"x\" course=\"result\" ng-repeat=\"x in result.classes | filter:{hiddenByFilter:false} track by $index\"></tr>\r\n                  <tr class=\"no-results-row\" ng-if=\"!showAll && result.allClassesClosed\">\r\n                       <td colspan=\"7\">\r\n                          <div class=\"alert alert-warning footnote\" ng-bind-html=\"allClassesClosedMessage\"></div>\r\n                      </td>\r\n                   </tr>\r\n                   <tr class=\"all-hidden-row\" ng-if=\"result.allClassesHidden && !result.allClassesClosed\">\r\n                      <td colspan=\"7\">\r\n                           <div class=\"alert alert-warning footnote\">\r\n                               <p>All classes for this course are hidden by filters.</p>\r\n                           </div>\r\n                      </td>\r\n                   </tr>\r\n              </tbody>\r\n           </table>`;\r\n\r\n\r\n    return {\r\n        scope: {\r\n            result: '='\r\n        },\r\n        restrict: 'E',\r\n        replace: false,\r\n        template: searchResultTemplate,\r\n        link: function (scope) {\r\n\r\n            scope.reverseSort = false;\r\n            var currentSort;            \r\n\r\n            scope.sortByColumn = function (col) {\r\n                scope.reverseSort = col !== currentSort ? false : !scope.reverseSort;\r\n\r\n                var sortBy = ['classSection', scope.reverseSort ? '-hiddenTitle' : '+hiddenTitle', scope.reverseSort ? '-meetingStartDate' : '+meetingStartDate'];\r\n                var hasHiddenTitles = scope.result.classes.some(x => !x.hiddenByFilter && x.hiddenTitle);\r\n\r\n                scope.result.classes = $filter('orderBy')\r\n                    (scope.result.classes, hasHiddenTitles ? sortBy : [col, 'classSection'], scope.reverseSort);\r\n\r\n                currentSort = col;\r\n            }\r\n\r\n            scope.allClassesClosedMessage = $sce.trustAsHtml($rootScope.allClassesClosedMessage);\r\n            scope.showAll = $rootScope.showAll;\r\n\r\n            if (scope.result.classes) {\r\n                scope.noteText =\r\n                    scope.result.classes[0].noteSeq > 0 && scope.result.classes[0].noteText.indexOf(' ') !== -1\r\n                        ? scope.result.classes[0].noteText\r\n                        : undefined;\r\n            }\r\n        }\r\n    };\r\n};","\r\n/**\r\n * Build a search result table row\r\n * @param {} $rootScope \r\n * @param {} recentSearchesFactory \r\n * @returns {} \r\n */\r\nexport default function (plannerFactory) {\r\n\r\n    var searchResultRowTemplate = `\r\n        <td ng-if=\"!result.hiddenTitle\">\r\n           <span>{{ result.classSection }} {{ result.classDesc }}</span>\r\n           <div class=\"class-note\" ng-if=\"::result.noteText\" uib-tooltip=\"{{ result.noteText }}\">\r\n                <i class=\"fal fa-info-circle\"></i>\r\n            </div>\r\n        </td>\r\n        <td ng-if=\"result.hiddenTitle\"></td>\r\n        <td>{{ hideDayTime ? '-' : result.meetingDay }}</td>\r\n        <td ng-bind=\"result.location\"></td>\r\n        <td ng-bind=\"result.room\"></td>\r\n        <td>{{ hideDayTime ? '-' : (result.meetingStartTime|dateTime:\\'time\\') + \\'-\\' + (result.meetingEndTime|dateTime:\\'time\\') }}</td>\r\n        <td>{{result.meetingStartDate|date:\"d MMM\"}}-{{result.meetingEndDate|date:\"d MMM\"}}</td>\r\n        <td>\r\n           <button class=\"btn btn-outline-primary\" title=\"Add {{result.classDesc}} {{result.classNo}} to planner\"\r\n               ng-click=\"addToPlanner()\"\r\n               ng-if=\"!hideDayTime && result.meetingStartTime !== null && !result.hiddenTitle && result.room!==\\'PLACEMENT\\'\" stop-event>\r\n                    <i class=\"fal fa-plus \"></i>\r\n            </button>\r\n           <span class=\"row-closed\" title=\"{{result.classDesc}} {{result.classNo}} is closed\">CLOSED</span>\r\n        </td>`;\r\n\r\n    return {\r\n        scope: {\r\n            course: '=',\r\n            result: '='\r\n        },\r\n        restrict: 'A',\r\n        replace: false,\r\n        template: searchResultRowTemplate,\r\n        link: (scope, element) => {\r\n\r\n            if (scope.result.enrolmentStatus !== 'O') {\r\n                element[0].classList.add('closed');\r\n            }\r\n\r\n            // hide day and time for any item where day, start and end are not defined\r\n            scope.hideDayTime = true;\r\n            if (scope.result.meetingDay && scope.result.meetingStartTime && scope.result.meetingEndTime) {\r\n                scope.hideDayTime = false;\r\n            }\r\n\r\n            scope.addToPlanner = () =>\r\n                plannerFactory.addToPlanner(scope.result, scope.course.courseCode, scope.course.description, scope.course.courseId, scope.course.termId);            \r\n\r\n        }\r\n    };\r\n};"],"sourceRoot":""}