//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(`${category.name} `)
html.push(`
${category.description} `)
html.push(`Questions: ${category.count} `)
html.push(` `)
}
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(`Score
Events: ${correct+incorrect}
Correct: ${correct}
Incorrect: ${incorrect}
Percent: ${percent}%
`)
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;x0 && 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=[` ${dateString(theEvent)}
`]
//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=[`
`]
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.
