//10409 11126 let post="none" // used to tell which post is to be used for the question set let events=[] let data = null let master = null let eventBuffer=null async function dataInit(){ if(window.location.pathname==="/"){ //no post is specified. Either load full set from this blog or from the specified blog let blog=window.location.host.split(".")[0] if(location.search.length>0){ // search string is given. use it to get the information from the desired blog let blog=window.location.host.split(".")[0]// default to current blog let urlParams = window.location.search.slice(1).split("&") for(let x=urlParams.length-1;x>-1;x--){ if(urlParams[x]==="m=1" || urlParams[x]==="m=0"){ urlParams.splice(x,1) } } urlParams=urlParams.join("&") if(urlParams.includes("=")){ //first param has an "=" sign, post is what is before blog=urlParams.split("=")[0] post=urlParams.split("=")[1].split("&")[0].split("+").join(" ") }else{ post=urlParams.split("&")[0].split("+").join(" ") } const andPos = urlParams.indexOf("&") if(andPos){ urlParams = urlParams.substring(andPos+1) } urlParams = new URLSearchParams(window.location.search.slice(1)); } console.log("blog",blog) console.log("post",post) // get the feed of the blog specified. contines in "gotFeed" after data has arrived const script = document.createElement("script"); script.setAttribute("type", "text/javascript"); const feedURL=`https://${blog}.blogspot.com/feeds/posts/default?alt=json-in-script${String.fromCharCode(38)}callback=gotFeed` console.log("feedURL",feedURL) script.setAttribute("src", feedURL); document.getElementsByTagName("head")[0].appendChild(script); }else{ document.getElementById("loading").style.display="none" document.getElementById("post-content").style.display="" } } function gotFeed(rss){ // we have the feed from a blog. read to process it const blogEntries=[] for(const entry of rss.feed.entry){ const setHtml = entry.content.$t console.log(entry.title) if(setHtml.includes(`class=`+`"event-set"`)&&entry.title.$t.toLowerCase!=="template"){ // question set blogEntries.push(getSetObject(setHtml)) blogEntries[blogEntries.length-1].postTitle = entry.title.$t blogEntries[blogEntries.length-1].postType = "eventSet" }else if(setHtml.includes(`class=`+`"game-title"`)&&entry.title.$t.toLowerCase()!=="game template"){ // game config blogEntries.push(getGameObject(setHtml)) blogEntries[blogEntries.length-1].postTitle = entry.title.$t blogEntries[blogEntries.length-1].postType = "gameConfig" } } // find the post that matches the specified post for(const blogEntry of blogEntries){ if(blogEntry.postTitle===post){ master=blogEntry break } } if(master === null){ // no controlling post was identified. redirect to index window.location.replace("/2025/02/index.html") return } if(master.postType==="gameConfig"){ //buld list of question sets const setList = [] for(const qset of master.sets){ setList.push(qset.name) } master.sets=[] // read in the question sets from for(const blogEntry of blogEntries){ if(setList.includes(blogEntry.name)){ master.sets.push(blogEntry) } } console.log("master",master) //configure data for use in game if(master.instructions){ console.log("master", master) master.message=master.instructions master.award={ eventCount:master.awardCount, percent:master.awardPercent, message:master.awardMessage } } master.categories=[] master.events=[] for(const set of master.sets){ master.categories.push({ name:set.name, description:set.description, image:set.image }) for(evt of set.events){ const newEvent = { name: evt.name, category:set.name, image:evt.image, text:evt.text, date:evt.date } if(evt.endDate){newEvent.endDate=evt.endDate} if(evt.dateText){newEvent.dateText=evt.dateText} master.events.push(newEvent) } } console.log("master2",JSON.parse(JSON.stringify(master))) delete master.sets delete master.awardCount delete master.awardPercent delete master.awardMessage delete master.instructions }else if(master.postType==="eventSet"){ console.log("master",master) master.categories=[{ name:master.name, description:master.description, image:master.image }] for(let x=0;x0){ object[property]=value }else{ object[property]=value } } } } //======================================================================= // Game Code Below this divider //======================================================================= const pos=['Excellent!','Good show!','Well done.','Nice job.','Oh, you are good.', "Well, that's pretty good.",'Top job!','Brilliant!',"You're a genius!",'Right on!', "Look at you!", "Nice work, smarty pants.","You get bragging rights for that one.","You are marvelous."] const neg=["Oh, so close.","Missed it by \"that\" much.","You'll get it next time.","Perfection is a process.","Take this as a learning opportunity.","Never give up.","Try, try again.","You only fail if you quit.","That was a hard one.", "Hmmm. I don't think anyone knows that one.",'Sorry.','So sad.','Not quite.','Ouch.',"This just isn't your day."] const correctColor = "darkgreen" const incorrectColor = "darkred" const monthnames=["January","February","March","April","May","June","July","August","September","October","November","December"] function chooseCategory(evt){ console.log(evt) } function newGame(){ //restart game showGame(true) tag("progress").replaceChildren() tag("timebox").replaceChildren() init() } function beginGame(){ events=[] const startIndexes=[] const eventIndex={} const chosenCategories = [] eventBuffer = null let x=0 tag("timebox").innerHTML=` ` for(const elem of document.querySelectorAll(".category-name")){ //console.log("-------",elem.checked, elem) if(elem.checked){ chosenCategories.push(elem.dataset.categoryName) } } //console.log("chosenCategories",chosenCategories) let qNum = tag("event-count").value.trim() if(isNaN(qNum)){ qNum=data.events.length tag("event-count").value=qNum } const localData=data.events //get rid of any categories not checked for(let e=localData.length-1;e>=0;e--){ let catFound=false for(const cat of fixArray(localData[e].category)){ if(chosenCategories.includes(cat)){ catFound=true break } } if(!catFound){ console.log(localData.splice(e,1)) } } //now local data should have only events from the categories specified //print("local-data----->",localData) placeDebugToggle() for(let x=0;x+=event.startIndex){ conflict=true break } } if(!conflict){break} console.log(x,theEvent) } if(done){break} startIndexes.push(theEvent.startIndex) eventIndex[theEvent.startIndex]=events.length events.push(theEvent) placeScoreBox(x) } startIndexes.sort(compareFn) //print("startIndexes",startIndexes) for(let x=0;x b) { return 1; } // a must be equal to b return 0; } function showGame(intro=false){ if(intro){ tag("intro").style.display="" tag("progress").style.display="none" tag("event").style.display="none" tag("timebox").style.display="none" }else{ tag("intro").style.display="none" tag("progress").style.display="" tag("event").style.display="" tag("timebox").style.display="" } } function fixArray(data){ if(Array.isArray(data)){ return data } return [data] } async function init(){ const params = getParams(location.search) data=JSON.parse(JSON.stringify(master)) console.log ("data",data) const qNum=data.events.length tag("event-count").value=qNum let mainMessage=data.message data.index={} for(let c=0;c "] for(const category of data.categories){ html.push(` `) html.push(` ${category.name} `) html.push(` ${category.description}
`) html.push(` Questions: ${category.count} `) } html.push("") tag("category").innerHTML=html.join("") console.log(data) if(data.categories.length===1){ //if there's only one category, hide the checkbox const category=data.categories[0] document.getElementById(category.name.toLowerCase().split(" ").join("-")).style.visibility="hidden" } else{ if(!mainMessage){mainMessage=" Choose one or more categories below to begin.
"} } if(mainMessage){ tag("main-message").innerHTML=mainMessage }else{ tag("main-message").replaceChildren() } } function monthName(monthNumber){ const moNum=parseInt(monthNumber) return(monthnames[moNum-1]) } function dateString(theEvent){ const fmtDate = formatDate(theEvent.date) if(theEvent.endDate){ //has a start and an end date return fmtDate + " - " + formatDate(theEvent.endDate) }else if(theEvent.dateText){ return theEvent.dateText } // only a start Date return fmtDate } function formatDate(theDate){ const dateTimeArray = theDate.split(" ") const dateArray = dateTimeArray[0].split("-") if(dateTimeArray.length===1){ // there is only a date if(dateArray.length===1){ // only a year return dateArray[0] }else if(dateArray.length===2){ //year and month return monthName(dateArray[1]) + ", " + dateArray[0] } return monthName(dateArray[1]) + " " + parseInt(dateArray[2]) + ", " + dateArray[0] } //there is a date and a time We assume teh date is fully specified const timeArray = theDate.split(":") let ampm="AM" if(parseInt(timeArray[0])>11){ ampm="PM" } if(parseInt(timeArray[0])>12){ timeArray[0]=parseInt(timeArray[0])-12 } return timeArray[0] + ":" + timeArray[0].padStart(2,"0") + " " + ampm + " " + monthName(dataArray[1]) + " " + parseInt(dateArray[2]) + ", " + dateArray[0] } function calcDateIndex(theDate){ const dateTimeArray = theDate.split(" ") if(dateTimeArray.length < 2){ dateTimeArray.push("00:00") } const timeArray = dateTimeArray[1].split(":") const dateArray = dateTimeArray[0].split("-") if(dateArray.length===1){ //YEAR ONLY dateArray.push(7) } if(dateArray.length===2){ //no day dateArray.push(1) } //print("new Date Base:",`${dateArray[0]}-${dateArray[1]}-${dateArray[2]}T${timeArray[0]}:${timeArray[1]}`) //const d = new Date(`${dateArray[0]}-${dateArray[1]}-${dateArray[2]} ${timeArray[0]}:${timeArray[1]}`) const d = new Date(dateArray[0],dateArray[1],dateArray[2],timeArray[0],timeArray[1]) //print("d:",d) return d.getTime() } function placeScoreBox(num){ const div = document.createElement("div") div.className="score" div.id="score-"+num div.style.backgroundColor="#555" div.style.color="#777" div.innerHTML=num+1 tag("progress").appendChild(div) } function print(){ //writes to the debug div. for debugging only console.log("printing",tag("debug").childNodes.length) let backgroundColor="white" const printNodes = tag("debug").childNodes.length if(printNodes && tag("debug").childNodes[printNodes-1].style.backgroundColor==="white"){ backgroundColor="whitesmoke" } for(const arg of arguments){ const div = document.createElement("div") div.className="debug-line" div.style.backgroundColor = backgroundColor if(typeof arg ==="string"){ div.innerHTML=arg }else{ div.innerHTML=JSON.stringify(arg) } tag("debug").appendChild(div) } } function placeDebugToggle(){ return// disabled, only use for debuggig on mac const btn = document.createElement("button") btn.innerText = "T" btn.id="tog-debug" btn.addEventListener("click",function(){ console.log("eee--") if(tag("debug").style.display==="none"){ tag("debug").style.display="block" }else{ tag("debug").style.display="none" } }) tag("progress").appendChild(btn) } function toggleDebug(){ console.log("i'm togglin'") } function recordScore(num, correct=true){ //print(num, correct) tag("score-"+num).style.color="white" if(correct){ tag("score-"+num).style.backgroundColor=correctColor }else{ tag("score-"+num).style.backgroundColor=incorrectColor } } function showPluses(show=true){ for(const elem of document.querySelectorAll(".add")){ if(show){ elem.style.display="" }else{ elem.style.display="none" } } } function askEvent(){ const elem=tag("event") elem.style.maxHeight="" elem.style.overflowY="" tag("progress").scrollIntoView() elem.style.display="" if(events.length<1){ //we are done, show the score tag("event").style.backgroundColor="#ccc" tag("event").style.color="black" let correct = 0 let incorrect = 0 for(const elem of document.querySelectorAll(".score")){ if(elem.style.backgroundColor===correctColor){ correct++ }else{ incorrect++ } } const percent=Math.round((correct/(correct+incorrect))*1000)/10 const html=[] if(data.award){ if(correct+incorrect >=data.award.eventCount ){ if(percent >= data.award.percent){ html.push(`${data.award.message}`) }else{ html.push(`Sorry, you did not earn the award. But don't worry; you can try again.`) } } } html.push(``) console.log("html",html) elem.innerHTML=html.join("") showPluses(false) }else{ tag("event").style.backgroundColor="darkgreen" tag("event").style.color="white" elem.innerHTML=eventHtml(events[0]) //show prompt on first time if(tag("score-1").style.backgroundColor===correctColor || tag("score-1").style.backgroundColor===incorrectColor){ tag("prompt").style.display="none" }else{ tag("prompt").style.display="block" } showPluses(true) } } function tag(id){ return document.getElementById(id) } function scorePalcement(theEvent){ const timeBox=tag("timebox") const tags=timeBox.querySelectorAll(".event-container") let correct=true for(let x=0;x
Score Events: ${correct+incorrect} Correct: ${correct} Incorrect: ${incorrect} Percent: ${percent}% 0 && x ",tags[x-1].dataset.sequence,tags[x].dataset.sequence)} if((x>0 && parseInt(tags[x-1].dataset.sequence) > parseInt(tags[x].dataset.sequence))||(x parseInt(tags[x+1].dataset.sequence))){ //misplaced //elem.querySelector(".header").style.backgroundColor="darkred" correct=false //print("placed",tags[x]) break } } } recordScore(theEvent.number,correct) const elem=tag("message") if(tags.length===1){ elem.innerHTML=`We've placed the first one for you. Now you choose if the next one goes before or after. Tap to continue.` }else if(correct){ elem.innerHTML=pos[randBetween(0,pos.length-1)] + ` Tap to continue.` elem.style.backgroundColor= correctColor elem.style.color= "white" }else{ elem.innerHTML=neg[randBetween(0,neg.length-1)] + ` We'll put it in the right place when you tap to continue.` elem.style.backgroundColor= incorrectColor elem.style.color= "white" } } function proceed(evt){ console.log(evt) let m=evt.target while(m.id!=="message"){ m=m.parentElement } const elem=m.previousElementSibling elem.style.zoom=1 let needToMove=false if(m.style.backgroundColor===incorrectColor){ needToMove=true } m.remove() if(needToMove){ if(elem.previousElementSibling.className==="bar"){ elem.previousElementSibling.remove() }else{ elem.nextElementSibling.remove() } elem.remove() placeEvent() } askEvent() } function placeEvent(evt){ let moving=false if(evt){ // the user is telling us were to put the event or it's the first event eventBuffer=events.shift() }else{ // user did not specify where to place the event, we need to figure it out, also, we'll use the existing eventbuffer to get the event const tags=tag("timebox").querySelectorAll(".event-container") let foundIndex=0 for(let x=0;xtags[x].dataset.sequence){ foundIndex=x+1 } } let plus = tags[tags.length-1].nextElementSibling if(foundIndex < tags.length){ //place where found plus = tags[foundIndex].previousElementSibling } evt={target:plus} moving=true } const theEvent=eventBuffer const elem = evt.target const div = document.createElement("div") const bar = document.createElement("div") const msg = document.createElement("div") msg.id="message" // console.log("-------",tag("score-0").style.color,tag("score-0").style.color!=="white") // if(tag("score-0").style.color!=="white"){msg.className="blinking"} msg.addEventListener('click', proceed) bar.appendChild(div) bar.className="bar" div.className="add" div.innerHTML="+" bar.appendChild(div) div.addEventListener('click', placeEvent) placeDiv(elem,true,bar) const eContainer=document.createElement("div") eContainer.className="event-container" const eDiv=document.createElement("div") eDiv.className="event" const header = document.createElement("div") header.className="header" header.addEventListener("click",toggleEventHeight) eContainer.dataset.sequence=theEvent.sequence eContainer.id="event-"+theEvent.number //var html=[` `] //header.innerHTML=html.join("") header.innerHTML=dateString(theEvent) eContainer.appendChild(header) eContainer.appendChild(eDiv) eDiv.innerHTML=eventHtml(theEvent) placeDiv(elem,true,eContainer) if(moving){ eContainer.querySelector(".header").style.backgroundColor=incorrectColor }else{ eContainer.style.zoom = .5 placeDiv(elem,true,msg) scorePalcement(theEvent) tag("event").style.display="none" showPluses(false) } const theImage = eContainer.querySelector("img") console.log("theImage",theImage) console.log("h",theImage.height) eDiv.style.minHeight="100px" print('Height',theImage.height) } function toggleEventHeight(evt){ let e=evt.target while(e.className!=="event-container"){ e=e.parentElement } e=e.querySelector(".event") if(e.style.maxHeight==="100px"){ e.style.maxHeight="" }else{ e.style.maxHeight="100px" } console.log(e) } function eventHtml(theEvent){ const html=[`
${dateString(theEvent)} `] html.push(`${theEvent.name}`) html.push(`
${theEvent.text}`) return html.join("") } function toggleHeight(elem){ let e = elem while(e.className!=="event-container"){ e=e.parentElement } if(" -" === elem.innerHTML){ elem.innerHTML = " +" e.style.maxHeight="100px" }else{ elem.innerHTML = " -" e.style.maxHeight="" e.style.overflowY="" } } function placeDiv(elem, before=true, div){ let e=elem console.log(e.classList) while(e.className!=="bar"){ console.log(e) e=e.parentElement } console.log(e,e.parentElement) if(before){ e.insertAdjacentElement("beforeBegin",div) }else{ e.insertAdjacentElement("afterEnd",div) } } function randBetween(x,y){ return Math.floor(Math.random() * (y+1-x))+x } function getParams(query_string) { if (!query_string) { query_string = "" } const url_params_array = query_string.split("?").join("").split("&") const url_params = {} for (let x = 0; x < url_params_array.length; x++) { // returns the params from the url as an object const temp = url_params_array[x].split("=") url_params[decodeURI(temp[0])] = decodeURI(temp[1]) } return url_params } function unstick(elem){ if(elem.style.overflowY==="clip"){ elem.style.maxHeight="" elem.style.overflowY="" }else{ elem.style.maxHeight="100px" elem.style.overflowY="clip" } }
Are you a Historic Whiz? Take this HistoriQuiz to find out!
I'd like to organize historic events.
Tap a green plus sign to place this event chronologically.