(function () { "use strict"; // as of 2018, LW does not use CDM, but leave it in just in case const FACS = new Set(["AP", "ED", "ES", "FA", "GL", "GS", "HH", "LE", "LW", "SB", "SC"]); const SUBJS = { "ACTG": ["SB"], "ADMB": ["AP"], "ADMS": ["AP"], "ANTH": ["AP", "GS"], "ARB": ["AP"], "ARTH": ["FA", "GS"], "ARTM": ["SB"], "ASL": ["AP"], "AUCO": ["ED"], "BBED": ["ED"], "BC": ["SC"], "BCHM": ["SC"], "BIOL": ["SC", "GL", "GS", "ED"], "BLIS": ["GS"], "BPHS": ["SC"], "BSUS": ["SB"], "BUEC": ["GL"], "CAT": ["GL"], "CCY": ["AP"], "CDIS": ["GS"], "CDNS": ["AP", "GL"], "CGTA": ["GS"], "CH": ["AP"], "CHEM": ["SC", "GS", "ED"], "CIVL": ["LE", "GS"], "CLST": ["AP"], "CLTR": ["AP"], "CMCT": ["GS"], "COGS": ["AP"], "COMN": ["AP"], "COMS": ["GL"], "COOP": ["LE", "SC"], "CRIM": ["AP"], "CSLA": ["GL"], "DANC": ["FA", "GS", "ED"], "DATT": ["FA"], "DCAD": ["SB"], "DEMS": ["AP", "GS"], "DESN": ["FA"], "DEST": ["ED"], "DIGM": ["GS"], "DLLL": ["AP"], "DRAA": ["ED"], "DRST": ["GL"], "DVST": ["GS"], "ECON": ["AP", "GL", "SB", "GS", "ED"], "EDFE": ["ED"], "EDFR": ["ED"], "EDIN": ["ED"], "EDIS": ["ED"], "EDJI": ["ED"], "EDPJ": ["ED"], "EDPR": ["ED"], "EDST": ["ED"], "EDUC": ["ED", "GS"], "EECS": ["LE", "GS"], "EIL": ["GS"], "EMBA": ["SB"], "EN": ["AP", "GL", "GS", "ED"], "ENG": ["LE", "GS"], "ENSL": ["GL"], "ENTR": ["SB"], "ENVB": ["SC"], "ENVS": ["GS", "ED"], "ESL": ["AP"], "ESS": ["GS"], "ESSE": ["LE"], "EXCH": ["SB"], "FACC": ["GS"], "FACS": ["FA"], "FAST": ["ED"], "FILM": ["FA", "GS"], "FINE": ["SB"], "FND": ["AP"], "FNEN": ["SB"], "FNSV": ["SB"], "FR": ["AP"], "FRAN": ["GL"], "FREN": ["ED", "GS"], "FSL": ["GL"], "GCIN": ["AP"], "GEOG": ["AP", "SC", "GS", "ED"], "GER": ["AP"], "GFWS": ["GS"], "GK": ["AP"], "GKM": ["AP"], "GWST": ["AP", "GL"], "HEB": ["AP", "ED"], "HIMP": ["SB"], "HIST": ["AP", "GL", "GS", "ED"], "HLST": ["HH"], "HLTH": ["GS"], "HREQ": ["AP"], "HRM": ["AP", "GS"], "HUMA": ["AP", "GL", "GS"], "IBUS": ["SB"], "IHST": ["HH"], "ILST": ["GL"], "INDG": ["AP"], "INDS": ["ED"], "INDV": ["AP", "FA"], "INST": ["GS"], "INTE": ["GS"], "INTL": ["SB"], "ISCI": ["SC"], "IT": ["AP"], "ITEC": ["AP", "GL", "GS"], "JC": ["AP"], "JP": ["AP"], "KAHS": ["GS"], "KINE": ["HH"], "KOR": ["AP"], "LA": ["AP"], "LAL": ["GS"], "LASO": ["AP"], "LAW": ["ED", "GS", "LW"], "LIN": ["GL"], "LING": ["AP"], "LLDV": ["ED"], "LLS": ["AP"], "LREL": ["GS"], "LYON": ["GL"], "MACC": ["SB"], "MATH": ["SC", "GL", "ED", "GS"], "MBA": ["SB"], "MBAN": ["SB"], "MDES": ["GS"], "MECH": ["GS"], "MFIN": ["SB"], "MGMT": ["SB"], "MINE": ["SB"], "MIST": ["AP"], "MKTG": ["SB"], "MODR": ["AP", "GL"], "MSTM": ["SB"], "MUSI": ["FA", "GS", "ED"], "NATS": ["SC", "GL"], "NURS": ["HH", "GS"], "OMIS": ["SB"], "ORCO": ["ED"], "ORGS": ["SB"], "OVGS": ["SB", "GS"], "PACC": ["GS"], "PANF": ["FA"], "PERS": ["AP"], "PHED": ["ED"], "PHIL": ["AP", "GL", "GS", "ED"], "PHYS": ["SC", "GL", "GS", "ED"], "PIA": ["GS"], "PKIN": ["HH"], "PLCY": ["SB"], "POLS": ["AP", "GL", "GS", "ED"], "POR": ["AP"], "PPAL": ["GS"], "PPAS": ["AP"], "PRAC": ["ED"], "PROP": ["SB"], "PRWR": ["AP"], "PSYC": ["GS", "GL"], "PUBL": ["SB"], "RU": ["AP"], "SCIE": ["ED"], "SENE": ["SC"], "SGMT": ["SB"], "SLGS": ["ED"], "SLST": ["GS"], "SOCI": ["AP", "GL", "GS"], "SOSC": ["AP", "GL", "ED"], "SOWK": ["AP", "GS"], "SP": ["AP", "GL"], "SPTH": ["GS"], "STS": ["GS"], "SWAH": ["AP"], "SXST": ["AP", "GL"], "TECH": ["ED"], "TESL": ["AP"], "THEA": ["FA", "GS"], "THST": ["GS"], "TLSE": ["ED"], "TRAN": ["GL", "GS"], "TRAS": ["GS"], "TXLW": ["GS"], "TYP": ["AP"], "VISA": ["FA", "GS"], "WKLS": ["AP"] } const TOKEN_DELIM_RE = /[^A-Za-z0-9.=]/; const CRSN_RE = /^[0-9]{4}$/; const DEPTCRSN_RE = /^([A-Z]{2,4})([0-9]{4})$/; const CRED_RE = /^(?:Cr=([0-9]{1,2}(?:\.[0-9]{0,2})?)|([0-9]{1,2}\.[0-9]{0,2}))$/; const MAYBE_CRED_RE = /^[0-9]{1,2}$/; const MAYBE_DEPT_RE = /^[A-Z]{2,4}$/; const IGNORE_RE = /^[A-Z]$/; function parse_ycq_s(str) { let ycq_s = JSON.parse(str || "{}"); ycq_s.course_creds = ycq_s.course_creds || {}; ycq_s.course_subjs = ycq_s.course_subjs || {}; ycq_s.course_facs = ycq_s.course_facs || {}; ycq_s.subj_facs = ycq_s.subj_facs || {}; ycq_s.default_facs = ycq_s.default_facs || []; return ycq_s; } var cached_ycq_s = parse_ycq_s(localStorage.ycq); let now = new Date(); let month = now.getMonth(); // change to next summer on new year // begin next FW on July 1 let fw_year, s_year; if (month >= 6) { fw_year = now.getFullYear(); } else { fw_year = now.getFullYear() - 1; } s_year = now.getFullYear(); let fw_sess = document.createElement("option"); let fw_sess_val = "FW " + fw_year; fw_sess.value = fw_sess_val; fw_sess.textContent = `Fall/Winter ${fw_year}-${fw_year+1}`; let s_sess = document.createElement("option"); let s_sess_val = "SU " + (s_year - 1); s_sess.value = s_sess_val; s_sess.textContent = `Summer ${s_year}`; switch (cached_ycq_s.sess) { case fw_sess_val: fw_sess.selected = true; break; case s_sess_val: s_sess.selected = true; break; default: /* assume enrolling for summer courses between March and May inclusive */ if (month >= 2 && month <= 4) s_sess.selected = true; else fw_sess.selected = true; } let ENGLISH_TYPES = {"fac": "faculty", "subj": "subject/subject", "crsn": "course number", "cred": "credit number", "sess": "session (pick on the right)"}; function ready() { let ywhAd = document.getElementById("ywh-ad"); if (location.protocol != "http:" && location.protocol != "https:" && location.protocol != "file:") { ywhAd.style.display = "none"; } let sessions = document.querySelector("#sessions"); sessions.appendChild(fw_sess); sessions.appendChild(s_sess); let input = document.getElementById("input"); let link = document.getElementById("link"); let linkContainer = document.getElementById("link-container"); let state; let apply = function () { state = {subj: "", fac: "", crsn: "", cred: ""}; let multiple = new Set(); let warn = [], error = []; let got = function (type, token) { if (state[type]) multiple.add(ENGLISH_TYPES[type]); state[type] = token; }; let tryParse = function (token) { let subjcrsn, cred; if (SUBJS.hasOwnProperty(token)) { got("subj", token); } else if (FACS.has(token)) { got("fac", token); } else if ((subjcrsn = DEPTCRSN_RE.exec(token))) { got("subj", subjcrsn[1]); got("crsn", subjcrsn[2]); } else if ((cred = CRED_RE.exec(token))) { got("cred", parseFloat(cred[1] || cred[2]).toFixed(2)); } else if (CRSN_RE.test(token)) { got("crsn", token); } else if (MAYBE_CRED_RE.test(token)) { got("cred", parseFloat(token).toFixed(2)); warn.push(`assuming ${token} is the number of credits`); } else if (MAYBE_DEPT_RE.test(token)) { state.maybeSubj = token; } else if (!IGNORE_RE.test(token)) { return false; } return true; }; input.value.split(TOKEN_DELIM_RE).forEach(function (token) { if (!token || tryParse(token) || tryParse(token.toUpperCase())) return; warn.push(`don't understand search term: ${token}`); }); if (!state.subj && state.maybeSubj) { state.subj = state.maybeSubj; warn.push("guessing subject is " + state.maybeSubj); } if (!state.subj && state.crsn && cached_ycq_s.course_subjs[state.crsn]) { state.subj = cached_ycq_s.course_subjs[state.crsn]; warn.push(`using saved subject for ${state.crsn}: ${state.subj}`); } if (!state.subj && cached_ycq_s.default_subj) { state.subj = cached_ycq_s.default_subj; warn.push(`using saved default subject: ${state.subj}`); } if (!state.fac && state.subj) { // if no faculty, try: // 1. most recent faculty for this course // 2. most recent faculty for this subject // 3. most recent compatible faculty // 4. first compatible faculty // 1. most recent faculty for this course if (state.crsn && cached_ycq_s.course_facs[state.subj + state.crsn]) { state.fac = cached_ycq_s.course_facs[state.subj + state.crsn]; warn.push(`using saved faculty for ${state.subj} ${state.crsn}: ${state.fac}, other options maybe: ${other_facs}`); } else if (cached_ycq_s.subj_facs[state.subj]) { // 2. most recent faculty for this subject state.fac = cached_ycq_s.subj_facs[state.subj]; warn.push(`using saved faculty for ${state.subj}: ${state.fac}, other options: ${other_facs}`); } else if (SUBJS.hasOwnProperty(state.subj)) { let compat_facs = SUBJS[state.subj]; // 3. most recent compatible faculty if (cached_ycq_s.default_facs) for (let i = cached_ycq_s.default_facs.length - 1; i >= 0; i--) if (compat_facs.indexOf(cached_ycq_s.default_facs[i]) > -1) state.fac = cached_ycq_s.default_facs[i]; let using_faculty = "saved"; // 4. first compatible faculty if (!state.fac) { state.fac = compat_facs[0]; using_faculty = "default"; } let other_facs = compat_facs .filter(f => f != state.fac) .map(f => `${f}`) .join(", "); if (other_facs) warn.push(`using ${using_faculty} faculty for ${state.subj}: ${state.fac}, other options: ${other_facs}`); } else { error.push("no faculty provided and unknown subject"); } } if (state.subj && state.crsn && !state.cred) { if (cached_ycq_s.course_creds[state.subj + state.crsn]) { state.cred = cached_ycq_s.course_creds[state.subj + state.crsn]; warn.push(`using saved credit number for ${state.subj} ${state.crsn}: ${state.cred}`); } else { state.cred = "3.00"; warn.push("assuming the number of credits is 3.00"); } } let sess = document.getElementById("sessions").value.split(" "); state.sess = sess[0]; state.year = parseInt(sess[1], 10); if (state.fac && state.subj && state.crsn && state.cred && state.year && state.sess) { link.href = `https://w2prod.sis.yorku.ca/Apps/WebObjects/cdm.woa/wa/crsq?fa=${state.fac}&sj=${state.subj}&cn=${state.crsn}&cr=${state.cred}&ay=${state.year}&ss=${state.sess}`; link.textContent = `${state.fac}/${state.subj} ${state.crsn} ${state.cred} (${sessions.selectedOptions[0].textContent}) | York University`; linkContainer.style.display = "block"; } else if (state.fac && state.subj && state.sess) { link.href = `https://w2prod.sis.yorku.ca/Apps/WebObjects/cdm.woa/wa/crsq1?faculty=${state.fac}&subject=${state.subj}&academicyear=${state.year}&studysession=${state.sess}`; link.textContent = `${state.fac}/${state.subj} Courses (${sessions.selectedOptions[0].textContent}) | York University`; linkContainer.style.display = "block"; } else { linkContainer.style.display = "none"; error.push("need at least subject. see examples above"); } if (multiple.size) warn.push("multiple terms for " + Array.from(multiple.values()).join(", ") + ", using last occurrence for each"); document.getElementById("warning").innerHTML = warn.map(w => 'warning: ' + w).join("
"); document.getElementById("error").innerHTML = error.map(e => 'error: ' + e).join("
"); }; input.addEventListener("input", apply); sessions.addEventListener("change", apply); document.body.addEventListener("click", function (e) { if (e.target.closest(".sample-query")) { e.preventDefault(); input.select(); // doesn't work in Firefox, oh well if (!document.execCommand || !document.execCommand("insertText", false, e.target.textContent)) input.value = e.target.textContent; apply(); input.focus(); } else if (e.target.closest(".prepend-query")) { e.preventDefault(); let r = false; if (document.execCommand) { input.setSelectionRange(0, 0); r = document.execCommand("insertText", false, e.target.textContent + " "); } if (!r) input.value = e.target.textContent + " " + input.value; apply(); } }); let save_defaults = function () { let old_ycq_s_s = localStorage.ycq; let new_ycq_s = parse_ycq_s(old_ycq_s_s); if (state.fac) { let default_facs = new Set(new_ycq_s.default_facs); default_facs.delete(state.fac); default_facs.add(state.fac); let new_facs = Array.from(default_facs); if (new_facs.length != new_ycq_s.default_facs.length || new_facs.some((v, i) => v !== new_ycq_s.default_facs[i])) { new_ycq_s.default_facs = new_facs; } } if (state.subj) { if (state.crsn) { if (state.fac) new_ycq_s.course_facs[state.subj + state.crsn] = state.fac; if (state.cred) new_ycq_s.course_creds[state.subj + state.crsn] = state.cred; new_ycq_s.course_subjs[state.crsn] = state.subj; } new_ycq_s.default_subj = state.subj; } new_ycq_s.sess = document.getElementById("sessions").value; let new_ycq_s_s = JSON.stringify(new_ycq_s); if (new_ycq_s_s != old_ycq_s_s) { cached_ycq_s = new_ycq_s; localStorage.ycq = new_ycq_s_s; } }; link.addEventListener("click", save_defaults); document.forms[0].addEventListener("submit", function (e) { e.preventDefault(); if (linkContainer.style.display == "block") link.click(); }); input.addEventListener("keydown", function (e) { if (e.key == "Enter") { e.preventDefault(); if (linkContainer.style.display == "block") { // firefox silently ignores simulated link events with modifiers // use [\/] to fix syntax highlighting if (/(?:Firefox|Gecko)[\/]/.test(navigator.userAgent) && (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey)) { if (e.ctrlKey) { link.target = "_blank"; link.click(); link.target = ""; } else if (e.shiftKey) { // only need save here because other methods already trigger the link click event // for efficiency, don't save twice save_defaults(); window.open(link.href, "_blank", "noopener,width=625,resizable,menubar,toolbar,location,personalbar,status,scrollbars"); } else { link.click(); } } else { link.dispatchEvent(new MouseEvent("click", e)); } } } }); apply(); } if (document.readyState === "interactive" || document.readyState === "complete") { ready(); } else { document.addEventListener("DOMContentLoaded", ready); } }());