Events Moose Jaw
Your go-to guide for what's happening in Moose Jaw, Saskatchewan
×
Upcoming Events
📅 ${esc(e.dateDisplay)} — ${esc(e.name)}
`; if(e.category) html+=` `; if(e.venue) html+=` `; if(e.desc) html+=`${esc(e.desc)}
`; if(e.link) html+=` `; card.innerHTML=html; const t=timesFrom({dateObj:e.parsedDate,startText:e.startText,endText:e.endText,locTimeText:e.locTimeText}); const data={title:e.name,description:e.desc,location:e.venue,start:t.start,end:t.end,allDay:t.allDay,url:e.link||location.href}; const actions=document.createElement('div'); actions.className='actions'; // Calendar const calWrap=document.createElement('div'); calWrap.className='menu'; const calBtn=document.createElement('button'); calBtn.className='btn'; calBtn.textContent='➕ Add to Calendar'; const calDd=document.createElement('div'); calDd.className='dd'; const aG=document.createElement('a'); aG.href=gcalUrl(data); aG.target='_blank'; aG.rel='noopener'; aG.textContent='Google Calendar'; const aI=document.createElement('a'); aI.href='#'; aI.textContent='Apple / Outlook (ICS)'; aI.addEventListener('click',ev=>{ev.preventDefault(); const blob=new Blob([buildICS(data)],{type:"text/calendar;charset=utf-8"}); const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download=(data.title||"event").toLowerCase().replace(/[^a-z0-9]+/g,'-')+".ics"; document.body.appendChild(a); a.click(); setTimeout(()=>{URL.revokeObjectURL(a.href); a.remove();},0); calDd.style.display='none';}); calDd.appendChild(aG); calDd.appendChild(aI); calWrap.appendChild(calBtn); calWrap.appendChild(calDd); calBtn.addEventListener('click',()=>calDd.style.display=(calDd.style.display==='block'?'none':'block')); document.addEventListener('click',e3=>{ if(!calWrap.contains(e3.target)) calDd.style.display='none'; }); // Share const shareWrap=document.createElement('div'); shareWrap.className='menu'; const shareBtn=document.createElement('button'); shareBtn.className='btn'; shareBtn.textContent='🔗 Share'; const shareDd=document.createElement('div'); shareDd.className='dd'; const S=shareLinks(data); const tryNative=async()=>{ if(navigator.share){ try{ await navigator.share(S.web); return true; }catch(_){ return false; } } return false; }; [{label:"Share (native)",onClick:async(ev)=>{ev.preventDefault();const ok=await tryNative();if(!ok) window.open(S.email,'_blank');}}, {label:"Email",href:S.email},{label:"Facebook",href:S.fb},{label:"X (Twitter)",href:S.x},{label:"WhatsApp",href:S.wa} ].forEach(cfg=>{const a=document.createElement('a');a.textContent=cfg.label; if(cfg.href){a.href=cfg.href;a.target='_blank';a.rel='noopener';} if(cfg.onClick){a.addEventListener('click', cfg.onClick);} shareDd.appendChild(a);}); shareWrap.appendChild(shareBtn); shareWrap.appendChild(shareDd); shareBtn.addEventListener('click',()=>shareDd.style.display=(shareDd.style.display==='block'?'none':'block')); document.addEventListener('click',e3=>{ if(!shareWrap.contains(e3.target)) shareDd.style.display='none'; }); actions.appendChild(calWrap); actions.appendChild(shareWrap); card.appendChild(actions); return card; } function buildChips(categories){ const bar=$('#emj-bar'), chips=$('#emj-chips'); chips.innerHTML=''; const make=(label,val,active=false)=>{ const b=document.createElement('button'); b.className='chip'; if(active) b.classList.add('active'); b.textContent=label; if(val) b.style.background=colorFrom(val); b.addEventListener('click',()=>{ document.querySelectorAll('#emj .chip').forEach(x=>x.classList.remove('active')); b.classList.add('active'); state.cat=(val||'').toLowerCase(); applyFilters(); }); chips.appendChild(b); }; make('All','',true); categories.sort().forEach(c=>make(c,c,false)); bar.style.display=categories.length?'block':'none'; } // ---------- State & Filters ---------- const state={all:[],past:[],up:[],cat:'',archiveOpen:false,archiveLoaded:false}; function applyFilters(){ const q=$('#emj-q').value.trim().toLowerCase(); const cat=state.cat; const match=e=>(!q||e.search.includes(q))&&(!cat||(e.category||'').toLowerCase()===cat); $('#emj-up').querySelectorAll('.card').forEach(c=>c.remove()); state.up.filter(match).forEach(e=>$('#emj-up').appendChild(renderCard(e))); if(state.archiveLoaded){ $('#emj-arch').querySelectorAll('.card').forEach(c=>c.remove()); state.past.filter(match).forEach(e=>$('#emj-arch').appendChild(renderCard(e))); } } // ---------- Load & Render ---------- async function load(){ $('#emj-up').innerHTML=' '; let text; try{ const res=await fetch(CSV_URL,{cache:'no-store'}); if(!res.ok) throw new Error('HTTP '+res.status); text=await res.text(); }catch(e){ $('#emj-up').innerHTML=' '; return; } const rows=parseCSV(text); if(!rows||rows.length<2){ $('#emj-up').innerHTML=' '; return; } const headers=rows[0].map(h=>String(h||'').trim()); const idx={ date: findIdx(headers, ['date']), name: findIdx(headers, ['event name','name','title']), cat: findIdx(headers, ['category','type']), loct: findIdx(headers, ['location & time','location']), start: findIdx(headers, ['start time','start']), end: findI Family
Community Ice Skating
Join the community for open ice skating at the civic center this Saturday.
Read more →Music
Live Jazz at Downtown Café
Enjoy smooth jazz and great food every Friday evening downtown.
Read more →Explore Moose Jaw
Best Coffee Shops in Moose Jaw
Discover Moose Jaw’s coziest spots for your caffeine fix.
Top Parks & Trails for Spring
Perfect spots for walking, biking, and picnics in Moose Jaw.
About
Events Moose Jaw is your simple, ad-free community calendar.
We collect events from Facebook, posters, and community submissions so you don’t miss what’s happening in the Friendly City.