1// Used on Home, Contact, About Us 2const customProgramOrder = [ 3 "Regular", 4 "Chinese (Mandarin) Bilingual", 5 "German Bilingual", 6 "Spanish Bilingual", 7 "Early French Immersion", 8 "Late French Immersion", 9 "Arts-Centred", 10 "Science", 11 "All Girls", 12 "Indigenous Focus", 13 "Montessori", 14 "Traditional Learning Centre (TLC)", 15 "Advanced Placement (AP)", 16 "International Baccalaureate (IB)", 17 "International Baccalaureate (French Immersion)", 18 "International Baccalaureate (Career)", 19 "Alternative High School", 20 "Home Education", 21 "Online Learning", 22 "Outreach", 23 "Pregnant & Parenting Teens" 24]; 25 26const alernativePrograms = [ 27 'Spanish Bilingual', 'All Boys', 'Alternative High School', 'Traditional Learning Centre (TLC)', 28 'Early French Immersion', 'Late French Immersion', 'German Bilingual', 'Montessori', 'Online Learning', 29 'Chinese (Mandarin) Bilingual', 'Outreach', 'International Baccalaureate (IB)', 30 'Home Education', 'Science', 'International Baccalaureate (Career)', 31 'Pregnant & Parenting Teens', 'Indigenous Focus', 'Arts-Centred', 32 'All Girls', 'International Baccalaureate (French Immersion)' 33] 34 35/* 36 * Program visibility 37 * 38 * The program fragment's `hidden` field controls where a program appears: 39 * "hidden-everywhere" â not listed anywhere, including the program 40 * listings on Home / Contact / About Us 41 * "hidden-in-search-only" â only hidden from search/filter drop-downs 42 * (Find a School, School Directory); still listed 43 * here 44 * "no" / "" / anything else â shown 45 */ 46const PROGRAM_HIDDEN_EVERYWHERE = 'hidden-everywhere'; 47 48function isProgramHiddenEverywhere(hidden) { 49 return String(hidden == null ? '' : hidden).trim().toLowerCase() === PROGRAM_HIDDEN_EVERYWHERE; 50} 51 52function mergeGradeRanges(ranges) { 53 // Sort by start grade as number 54 ranges.sort((a, b) => Number(a.StartGrade) - Number(b.StartGrade)); 55 56 const merged = []; 57 for (const range of ranges) { 58 const start = Number(range.StartGrade); 59 const end = Number(range.EndGrade); 60 61 if (!merged.length) { 62 merged.push({ start, end }); 63 } else { 64 const last = merged[merged.length - 1]; 65 if (last.end + 1 === start) { 66 last.end = end; 67 } else { 68 merged.push({ start, end }); 69 } 70 } 71 } 72 73 return merged.map(r => `${formatGrade(String(r.start))} - ${formatGrade(String(r.end))}`); 74} 75 76// strip the "fragment://" prefix off a fragment reference to get the bare uuid 77function stripFragment(ref) { 78 return typeof ref === 'string' ? ref.replace('fragment://', '') : ''; 79} 80 81// All data now comes from window.schoolProfileData (fragment-based). 82(window.schoolProfileData?.ready || Promise.resolve()).then(() => { 83 const schools = window.schoolProfileData?.schools || []; 84 const wards = window.schoolProfileData?.wards || []; 85 const areas = window.schoolProfileData?.areas || []; 86 const programs = window.schoolProfileData?.programs || []; 87 88 // fragment lookup maps, keyed by bare uuid 89 const wardMap = new Map(wards.map(w => [w.id, w])); 90 const areaMap = new Map(areas.map(a => [a.id, a])); 91 const programMap = new Map(programs.map(p => [p.id, p])); 92 93 const currentSchoolProfile = 94 schools.find(x => padSchoolCode(x?.profile?.schoolcode) === schoolCode) || 95 schools.find(x => x?.profile?.schoolname === schoolName) || 96 schools.find(x => x?.profile?.schooldisplayname === schoolName); 97 98 const profile = currentSchoolProfile?.profile || {}; 99 100 // resolve ward + area fragments 101 const matchedWard = wardMap.get(stripFragment(profile.wardFragment)) || null; 102 const matchedArea = areaMap.get(stripFragment(profile.areaFragment)) || null; 103 104 const trustee = matchedWard?.data?.trustees?.[0]?.trustee || ''; 105 // area fragment: directors live at data.eduDirectors[].name 106 const eduDirectors = (matchedArea?.data?.eduDirectors || []) 107 .map(d => d?.name) 108 .filter(Boolean); 109 110 // ward/area names sourced from the resolved fragments (not profile.wardname/areaname) 111 const wardName = matchedWard?.data?.trustees?.[0]?.wardname || matchedWard?.title || ''; 112 const areaName = matchedArea?.data?.area?.areaname || matchedArea?.title || ''; 113 114 // assistant principals (top-level assistants[] on the school fragment) 115 const currentAssistants = (currentSchoolProfile?.assistants || []) 116 .map(a => a?.name) 117 .filter(Boolean); 118 119 // enrollment rows { grades, number }, sorted ascending by grade 120 const enrollmentRows = (Array.isArray(currentSchoolProfile?.enrollment) ? currentSchoolProfile.enrollment : []) 121 .slice() 122 .sort((a, b) => Number(a?.grades) - Number(b?.grades)); 123 124 // resolve each program fragment to its name + grade range 125 // Programs marked "hidden-everywhere" are dropped here, so they appear in
126 // neither the program listings nor the Regular/Alternative section checks. 127 const resolvedPrograms = (currentSchoolProfile?.programs || []) 128 .map(pg => { 129 const prog = programMap.get(stripFragment(pg.programFragment)); 130 return { 131 // program name = data.programs.name (matches customProgramOrder); title is fallback 132 name: prog?.data?.programs?.name || prog?.title || '', 133 hidden: prog?.data?.programs?.hidden ?? pg.hidden ?? '', 134 lowGrade: pg.programLowGrade ?? profile.lowgrade, 135 highGrade: pg.programHighGrade ?? profile.highgrade 136 }; 137 }) 138 .filter(p => p.name && !isProgramHiddenEverywhere(p.hidden)); 139 140 //console.log({ currentSchoolProfile, matchedWard, matchedArea, resolvedPrograms }) 141 142 143 $(document).ready(function () { 144 // principal 145 const principal = profile.principal?.trim(); 146 if (principal) { 147 $('.js-principal').html(` 148 <div class="leadership-label">Principal</div> 149 <div class="leadership-name">${principal}</div> 150 `) 151 $('.contact-principal').html(` 152 <p class="team-label">Principal</p> 153 <p class="team-name">${principal}</p> 154 `) 155 } else { 156 $('.js-principal').remove() 157 $('.contact-principal').remove() 158 } 159 160 // assistant principal 161 if (currentAssistants.length > 0) { 162 // home page 163 currentAssistants.forEach(x => { 164 const $leadershipItem = $('<div>').addClass('leadership-item') 165 $leadershipItem.html(` 166 <div class="leadership-label">Assistant Principal</div> 167 <div class="leadership-name">${x}</div> 168 `) 169 $('.js-leadership').append($leadershipItem) 170 }) 171 172 currentAssistants.length > 2 ? $('.js-leadership').addClass('two-by-two') : $('.js-leadership').removeClass('two-by-two') 173 174 // contact page 175 currentAssistants.forEach(x => { 176 const $leadershipContactItem = $('<div>'); 177 $leadershipContactItem.html(` 178 <p class="team-label">Assistant Principal</p> 179 <p class="team-name">${x}</p> 180 `) 181 182 $('.js-contact-leadership').append($leadershipContactItem) 183 }) 184 } 185 186 // education director 187 eduDirectors.forEach(name => { 188 $('.js-edudirector').append($('<div>').text(name)) 189 }) 190 191 // trustee 192 if (trustee) { 193 $('.js-trustee').append($('<div>').text(trustee)) 194 } 195 196 // ward (contact page) 197 wardName ? $('.js-ward').text(wardName.replace('Ward ', '')) : ''; 198 199 // area 200 areaName ? $('.js-area').text(areaName.replace('Area ', '')) : ''; 201 202 // school map image â prefer profile.schoolmap.src, otherwise fall back to the school-code image 203 if (currentSchoolProfile) { 204 if (profile.schoolmap?.src) { 205 $('.js-school-map').attr('src', profile.schoolmap.src).attr('alt', profile.schoolmap.alt || ''); 206 } else { 207 setImageWithPriority('.js-school-map', `/images/${padSchoolCode(profile.schoolcode)}-map`); 208 } 209 } 210 211 // grades and enrollment 212 let enrollment = 0; 213 enrollmentRows.forEach(x => { 214 const grade = formatGrade(String(x?.grades)); 215 const count = Number(x?.number) || 0; 216 enrollment += count; 217 218 const $gradeEnrollment = $("<div>").addClass("grade-enrollment-item").html(` 219 <span>Grade ${grade}: </span>${x?.number} 220 `) 221 222 $('.js-grade-enrolment').append($gradeEnrollment) 223 }) 224 225 if (profile.lowgrade && profile.highgrade) { 226 $('.js-grades').text(`${formatGrade(profile.lowgrade)} - ${profile.highgrade}`) 227 } 228 229 $('.js-enrollment').text(enrollment) 230 231 if (!enrollmentRows.length) { 232 $(".grade-enrollment, .about-school-info.enrolment").remove() 233 } 234 235 // Programs 236 if (resolvedPrograms.length > 0) { 237 let html = ''; 238 let programNames = []; 239 240 // group grade ranges by program name 241 const grouped = resolvedPrograms.reduce((acc, item) => { 242 const key = item.name; 243 if (!acc[key]) acc[key] = []; 244 acc[key].push({ StartGrade: item.lowGrade, EndGrade: item.highGrade }); 245 return acc; 246 }, {}); 247 248 let formattedPrograms = Object.entries(grouped).map(([programName, ranges]) => { 249 const mergedRanges = mergeGradeRanges(ranges); 250 return { 251 programName, 252 output: `${programName} (${mergedRanges.join(', ')})` 253 }; 254 }); 255 256 formattedPrograms.sort((a, b) => { 257 const rawA = customProgramOrder.indexOf(a.programName); 258 const rawB = customProgramOrder.indexOf(b.programName); 259 const indexA = rawA === -1 ? Infinity : rawA; 260 const indexB = rawB === -1 ? Infinity : rawB; 261 return indexA - indexB; 262 }); 263 264 html = formattedPrograms.map(x => `<div class="program-item">${x?.output}</div>`).join(' ') 265 266 // render programs
267 $('.js-programs, .js-home-programs').html(html) 268 269 resolvedPrograms.forEach(x => { programNames.push(x.name) }) 270 271 // render regular program section on how to register page if regular program exists 272 programNames.includes('Regular') ? $('.regular-program.program-wrapper').show() : $('.regular-program.program-wrapper').hide(); 273 274 // render alternative program section on how to register page if one of the alternative programs exists 275 const alernativeProgramExists = alernativePrograms.some(value => programNames.includes(value)); 276 alernativeProgramExists ? $('.alternative-program.program-wrapper').show() : $('.alternative-program.program-wrapper').hide() 277 278 } else { 279 $('.js-programs, .js-home-programs').remove(); 280 } 281 282 }) 283 284});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.