diff options
-rw-r--r-- | script.js | 361 |
1 files changed, 300 insertions, 61 deletions
@@ -1,25 +1,195 @@ (function () { "use strict"; -const FACS = new Set(); -const DEPTS = new Map(); -// maintain: CDM Advanced Search, -// console.log(Array.prototype.map.call(document.getElementsByName("subjectPopup")[0].children,(e)=>'"'+e.textContent.match(/[A-Z]{2,4}/)[0] + '"').join(", ")) -[ - ["AP", "ADMB", "ADMS", "ANTH", "ARB", "ASL", "CCY", "CDNS", "CH", "CLST", "CLTR", "COGS", "COMN", "CRIM", "DEMS", "DLLL", "ECON", "EN", "ESL", "FND", "FR", "GCIN", "GEOG", "GER", "GK", "GKM", "GWST", "HEB", "HIST", "HREQ", "HRM", "HUMA", "INDG", "INDV", "IT", "ITEC", "JC", "JP", "KOR", "LA", "LASO", "LING", "LLS", "MIST", "MODR", "PERS", "PHIL", "POLS", "POR", "PPAS", "PRWR", "RU", "SOCI", "SOSC", "SOWK", "SP", "SWAH", "SXST", "TESL", "TYP", "WKLS", "WRIT"], - ["ED", "AUCO", "BBED", "BIOL", "CHEM", "DANC", "DEST", "DRAA", "ECON", "EDFE", "EDFR", "EDIN", "EDIS", "EDJI", "EDPJ", "EDPR", "EDST", "EDUC", "EN", "ENVS", "FAST", "FREN", "GEOG", "HEB", "HIST", "INDS", "LAW", "LLDV", "MATH", "MUSI", "ORCO", "PHED", "PHIL", "PHYS", "POLS", "PRAC", "SCIE", "SLGS", "SOSC", "TECH", "TLSE", "VISA"], - ["ES", "ENVS"], - ["FA", "ARTH", "DANC", "DATT", "DESN", "FACS", "FILM", "INDV", "MUSI", "PANF", "THEA", "VISA", "YSDN"], - ["GL", "BIOL", "BUEC", "CAT", "CDNS", "COMS", "CSLA", "DRST", "ECON", "EN", "ENSL", "FRAN", "FSL", "GWST", "HIST", "HUMA", "ILST", "ITEC", "LIN", "LYON", "MATH", "MODR", "NATS", "PHIL", "PHYS", "POLS", "PSYC", "SOCI", "SOSC", "SP", "SXST", "TRAN", "WKST", "WMST"], - ["GS", "ANTH", "ARTH", "BIOL", "BLIS", "CDIS", "CGTA", "CHEM", "CIVL", "CMCT", "DANC", "DEMS", "DIGM", "DVST", "ECON", "EDUC", "EECS", "EIL", "EN", "ENG", "ENVS", "ESS", "FACC", "FILM", "FREN", "GEOG", "GFWS", "HIST", "HLTH", "HRM", "HUMA", "INST", "INTE", "ITEC", "KAHS", "LAL", "LAW", "LREL", "MATH", "MDES", "MECH", "MUSI", "NURS", "OVGS", "PACC", "PHIL", "PHYS", "PIA", "POLS", "PPAL", "PSYC", "SLST", "SOCI", "SOWK", "SPTH", "STS", "THEA", "THST", "TRAN", "TRAS", "TXLW", "VISA", "WMST"], - ["HH", "HLST", "IHST", "KINE", "NURS", "PKIN", "PSYC"], - ["LE", "CIVL", "COOP", "EECS", "ENG", "ESSE", "MECH"], - ["SB", "ACTG", "ARTM", "BSUS", "DCAD", "ECON", "EMBA", "ENTR", "EXCH", "FINE", "FNEN", "FNSV", "HIMP", "IBUS", "MBA", "INTL", "MACC", "MBAN", "MFIN", "MGMT", "MINE", "MKTG", "MSTM", "OMIS", "ORGS", "OVGS", "PLCY", "PROP", "PUBL", "SGMT", "SOCM"], - ["SC", "BC", "BCHM", "BIOL", "BPHS", "CHEM", "COOP", "ENVB", "GEOG", "ISCI", "MATH", "NATS", "PHYS", "SENE", "STS"] -].forEach((arr) => { - let faculty = arr.shift(); - FACS.add(faculty); - arr.forEach((subj) => DEPTS.set(subj, faculty)); -}); + +// 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}$/; @@ -29,12 +199,16 @@ const MAYBE_CRED_RE = /^[0-9]{1,2}$/; const MAYBE_DEPT_RE = /^[A-Z]{2,4}$/; const IGNORE_RE = /^[A-Z]$/; -let ycq_storage = JSON.parse(localStorage.ycq || "{}"); -if (!ycq_storage) - ycq_storage = {}; -ycq_storage.course_creds = ycq_storage.course_creds || {}; -ycq_storage.course_subjs = ycq_storage.course_subjs || {}; -ycq_storage.default_subj = ycq_storage.default_subj || ""; +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(); @@ -55,7 +229,7 @@ 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 (ycq_storage.sess) { +switch (cached_ycq_s.sess) { case fw_sess_val: fw_sess.selected = true; break; case s_sess_val: s_sess.selected = true; break; default: @@ -97,7 +271,7 @@ function ready() { let tryParse = function (token) { let subjcrsn, cred; - if (DEPTS.has(token)) { + if (SUBJS.hasOwnProperty(token)) { got("subj", token); } else if (FACS.has(token)) { got("fac", token); @@ -130,25 +304,61 @@ function ready() { warn.push("guessing subject is " + state.maybeSubj); } - if (!state.subj && ycq_storage.course_subjs[state.crsn]) { - state.subj = ycq_storage.course_subjs[state.crsn]; + 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 && ycq_storage.default_subj) { - state.subj = ycq_storage.default_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) { - state.fac = DEPTS.get(state.subj); - if (!state.fac) + // 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 => `<a href="#" class="prepend-query">${f}</a>`) + .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 (ycq_storage.course_creds[state.subj + state.crsn]) { - state.cred = ycq_storage.course_creds[state.subj + state.crsn]; + 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"; @@ -156,18 +366,17 @@ function ready() { } } - let r_sess = document.getElementById("sessions").value; - let sess = r_sess.split(" "); + 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 = `York University: ${state.fac}/${state.subj} ${state.crsn} ${state.cred} (${sessions.selectedOptions[0].textContent})`; + 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 = `York University: ${state.fac}/${state.subj} Courses (${sessions.selectedOptions[0].textContent})`; + link.textContent = `${state.fac}/${state.subj} Courses (${sessions.selectedOptions[0].textContent}) | York University`; linkContainer.style.display = "block"; } else { linkContainer.style.display = "none"; @@ -179,15 +388,12 @@ function ready() { document.getElementById("warning").innerHTML = warn.map(w => 'warning: ' + w).join("<br>"); document.getElementById("error").innerHTML = error.map(e => 'error: ' + e).join("<br>"); - - ycq_storage.sess = r_sess; - localStorage.ycq = JSON.stringify(ycq_storage); }; input.addEventListener("input", apply); sessions.addEventListener("change", apply); - document.getElementById("sample-queries").addEventListener("click", function (e) { - if (e.target.tagName == "A") { + document.body.addEventListener("click", function (e) { + if (e.target.closest(".sample-query")) { e.preventDefault(); input.select(); // doesn't work in Firefox, oh well @@ -195,26 +401,57 @@ function ready() { 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_crsn = function () { - let modified = false; - if (state.crsn) { - if (state.subj && state.cred) { - ycq_storage.course_creds[state.subj + state.crsn] = state.cred; - modified = true; + 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) { - ycq_storage.course_subjs[state.crsn] = state.subj; - ycq_storage.default_subj = state.subj; - modified = true; + } + + 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; } - if (modified) - localStorage.ycq = JSON.stringify(ycq_storage); }; - link.addEventListener("click", save_crsn); + link.addEventListener("click", save_defaults); document.forms[0].addEventListener("submit", function (e) { e.preventDefault(); if (linkContainer.style.display == "block") @@ -225,14 +462,16 @@ function ready() { e.preventDefault(); if (linkContainer.style.display == "block") { // firefox silently ignores simulated link events with modifiers - if (/(?:Firefox|Gecko)\//.test(navigator.userAgent) && (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey)) { + // 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_crsn here because other methods already trigger the link click event - save_crsn(); + // 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 { |