crosswords.min.js 10 KB

1234567891011121314151617181920212223
  1. var R={id:{scoreboard:"scoreboard",grid:"grid"},klass:{line:"crossword-line",cell:{item:"cell",black:"cell-disabled",definition:"cell-definition",letter:"cell-letter",definitions:{item:"definition",rightVertical:"definition-right-vt",rightHorizontal:"definition-right-hz",bottomVertical:"definition-bottom-vt",bottomHorizontal:"definition-bottom-hz"},found:"cell-letter-correct",pending:"cell-letter-pending",wrong:"cell-letter-wrong",selected:"cell-selected",currentInput:"cell-input"}}};var UI_CELLS=[],UI_PLAYERS={},playerDomList;function dCreate(domName){return document.createElement(domName)}function dGet(id){return document.getElementById(id)}
  2. function uiCreateCell(cellData,x,y){var cell=dCreate("div");cell.className=R.klass.cell.item;if(cellData.isBlack)cell.classList.add(R.klass.cell.black);else if(cellData.definitions!==null){cell.classList.add(R.klass.cell.definition);var cellContent=dCreate("span");for(var i=0,nbDefinitions=cellData.definitions.length;i<nbDefinitions;i++){var definition=cellData.definitions[i],domDefinition=dCreate("span");domDefinition.dataset.x=x;domDefinition.dataset.y=y;domDefinition.dataset.definition=i;domDefinition.className=
  3. R.klass.cell.definitions.item;domDefinition.innerHTML=definition.text.join("<br/>");cellContent.appendChild(domDefinition)}cell.appendChild(cellContent)}else cell.classList.add(R.klass.cell.letter);return cell}function uiCreatePlayer(player){var dom=dCreate("li"),playerName=dCreate("span");playerName.textContent=player.name;dom.appendChild(playerName);dom.score=dCreate("span");dom.appendChild(dom.score);dom.style.color=player.color;return dom}
  4. function uiCreateGrid(){var frag=document.createDocumentFragment();for(var i=0;i<GRID.height;i++){var line=dCreate("div");line.className=R.klass.line;frag.appendChild(line);for(var j=0;j<GRID.width;j++){var cell=uiCreateCell(GRID.grid[j][i],j,i);cell.dataset.x=j;cell.dataset.y=i;line.appendChild(cell);UI_CELLS.push({x:j,y:i,dom:cell,data:GRID.grid[j][i]})}}for(var i=0;i<GRID.height;i++)for(var j=0;j<GRID.width;j++){var cell=UI_CELLS[i*GRID.width+j];if(cell.data.definitions)cell.data.definitions.forEach(function(d){switch(d.direction){case Definition.RIGHT_VERTICAL:UI_CELLS[i*
  5. GRID.width+j+1].dom.classList.add(R.klass.cell.definitions.rightVertical);break;case Definition.RIGHT_HORIZONTAL:UI_CELLS[i*GRID.width+j+1].dom.classList.add(R.klass.cell.definitions.rightHorizontal);break;case Definition.BOTTOM_VERTICAL:UI_CELLS[(i+1)*GRID.width+j].dom.classList.add(R.klass.cell.definitions.bottomVertical);break;case Definition.BOTTOM_HORIZONTAL:UI_CELLS[(i+1)*GRID.width+j].dom.classList.add(R.klass.cell.definitions.bottomHorizontal);break}})}onGridUpdated();var gridContainer=dGet(R.id.grid);
  6. gridContainer.textContent="";gridContainer.appendChild(frag)}function onGridUpdated(){UI_CELLS.forEach(function(i){if(!i.data.definitions&&!i.data.isBlack)if(i.data.letter){i.dom.textContent=i.data.letter;if(i.data.found){i.dom.classList.add(R.klass.cell.found);i.dom.classList.remove(R.klass.cell.wrong);i.dom.style.color=i.data.found.color}}else i.dom.textContent=""})}
  7. function onPlayersUpdated(){var container;for(var i in GRID.players){var uiPlayer=UI_PLAYERS[i];if(!uiPlayer){uiPlayer=UI_PLAYERS[i]=uiCreatePlayer(GRID.players[i]);if(!container)container=dGet(R.id.scoreboard);container.appendChild(uiPlayer)}uiPlayer.score.textContent=GRID.players[i].score}}
  8. function gridClickDelegate(e){var target=e.target;while(target&&(target.dataset&&!target.dataset.x))target=target.parentElement;if(target&&target.dataset&&target.dataset.x&&target.dataset.y){var clickedCell=UI_CELLS[parseInt(target.dataset.x,10)+parseInt(target.dataset.y,10)*GRID.width];if(clickedCell.data.isBlack)unselect();else if(clickedCell.data.definitions){var first=true;unselect();if(clickedCell.data.definitions[target.dataset.definition])clickedCell.data.definitions[target.dataset.definition].word.forEach(function(coordinates){select(coordinates[0],
  9. coordinates[1]);if(first&&!UI_CELLS[coordinates[0]+coordinates[1]*GRID.width].data.found){CURRENTINPUT=UI_CELLS[coordinates[0]+coordinates[1]*GRID.width];CURRENTINPUT.dom.classList.add(R.klass.cell.currentInput)}first=false})}else{var words=GRID.getWord(clickedCell.x,clickedCell.y);unselect();words.forEach(function(word){word.forEach(function(coordinates){select(coordinates[0],coordinates[1])})});target.classList.add(R.klass.cell.currentInput);CURRENTINPUT=clickedCell}}};function Definition(data){this.text=data["text"];this.direction=data["pos"];this.word=null}Definition.RIGHT_HORIZONTAL=1;Definition.RIGHT_VERTICAL=2;Definition.BOTTOM_HORIZONTAL=3;Definition.BOTTOM_VERTICAL=4;function Cell(){this.isBlack=false;this.definitions=null;this.found=null;this.letter=null}
  10. Cell.prototype.update=function(data,players){if(data["type"]===null)this.isBlack=true;else if(data["definitions"]!==undefined){this.definitions=[];data["definitions"].forEach(function(definition){this.definitions.push(new Definition(definition))}.bind(this))}else if(data["letter"]){this.letter=data["letter"];this.found=players[data["found"]];return data["v"]}return 0};
  11. function Player(data){this.id=data["name"];this.idEncoded=encodeURIComponent(data["name"]);this.score=data["score"];var pos=data["name"].indexOf("|");this.name=data["name"].substr(0,pos);this.color="#"+data["name"].substr(pos+1);console.log(this)}Player.prototype.update=function(data){this.score=data["score"];return data["v"]};
  12. function Grid(data){this.title=data["title"]||"";this.difficulty=data["difficulty"];this.width=data["w"];this.height=data["h"];this.players={};this.playerSelf=null;this.words=[];this.grid=[];for(var i=0;i<this.width;i++){this.grid[i]=[];for(var j=0;j<this.height;j++)this.grid[i][j]=new Cell}}
  13. Grid.prototype.computeWord=function(x,y,dx,dy){if(!this.grid[x+dx]||!this.grid[x+dx][y+dy]||this.grid[x+dx][y+dy].definitions||this.grid[x+dx][y+dy].isBlack)return[[x,y]];var word=this.computeWord(x+dx,y+dy,dx,dy);word.unshift([x,y]);return word};Grid.prototype.getWord=function(x,y){var words=[];this.words.forEach(function(word){for(var i=0,nbLetters=word.length;i<nbLetters;i++)if(word[i][0]==x&&word[i][1]==y){words.push(word);break}});return words};
  14. Grid.prototype.updatePlayers=function(playerData){var maxVersion=0;playerData.forEach(function(player){var localPlayer=this.players[player["name"]];if(!localPlayer)localPlayer=this.players[player["name"]]=new Player(player);maxVersion=Math.max(maxVersion,localPlayer.update(player))}.bind(this));return maxVersion};
  15. Grid.prototype.update=function(data){var maxVersion=null,topologyUpdated=false;data.forEach(function(cellData){var updateResult=this.grid[cellData["x"]][cellData["y"]].update(cellData,this.players);maxVersion=Math.max(maxVersion||0,updateResult);if(updateResult===0)topologyUpdated=true}.bind(this));if(topologyUpdated){var words=[];for(var i=0;i<this.width;i++)for(var j=0;j<this.height;j++)if(this.grid[i][j].definitions)this.grid[i][j].definitions.forEach(function(definition){var word;switch(definition.direction){case Definition.RIGHT_VERTICAL:word=
  16. this.computeWord(i+1,j,0,1);break;case Definition.RIGHT_HORIZONTAL:word=this.computeWord(i+1,j,1,0);break;case Definition.BOTTOM_VERTICAL:word=this.computeWord(i,j+1,0,1);break;case Definition.BOTTOM_HORIZONTAL:word=this.computeWord(i,j+1,1,0);break}words.push(word);definition.word=word}.bind(this));this.words=words}return maxVersion};var POLL_INTERVAL=5E3;function doGet(url,callback){var xhr=new XMLHttpRequest;xhr.onreadystatechange=function(e){if(xhr.readyState===4){var resp=null;if(xhr.status===200){resp=xhr.response;try{resp=JSON.parse((resp))}catch(e){resp=null}}callback(xhr.status,resp)}};xhr.open("GET",url,true);xhr.send(null)}
  17. function initPolling(){lazyGetPseudonyme(function(pseudo){if(pseudo)doGet("/api/poll?grid="+GRID_PUBLIC_ID+"&v="+KNOWN_VERSION,function(status,resp){if(resp){GRID=new Grid(resp);updateOnPollResult(resp);GRID.playerSelf=GRID.players[pseudo];scheduleNextPoll()}})})}
  18. function pollNow(){if(pollNow.polling!==true){if(pollNow.pollSchedule){clearTimeout(pollNow.pollSchedule);pollNow.pollSchedule=0}pollNow.polling=true;doGet("/api/poll?grid="+GRID_PUBLIC_ID+"&v="+KNOWN_VERSION,function(status,resp){pollNow.polling=false;if(resp)updateOnPollResult(resp);scheduleNextPoll()})}}function scheduleNextPoll(){if(!pollNow.pollSchedule)pollNow.pollSchedule=setInterval(pollNow,POLL_INTERVAL)};var GRID_PUBLIC_ID,KNOWN_VERSION=0,GRID,SELECTED=[],CURRENTINPUT=null;function lazyGetPseudonyme(cb){var pseudo=window["sessionStorage"].getItem("pseudonyme_"+GRID_PUBLIC_ID);if(pseudo)cb(pseudo);else doGet("/api/register?grid="+GRID_PUBLIC_ID,function(status,pseudo){if(status&&pseudo){window["sessionStorage"].setItem("pseudonyme_"+GRID_PUBLIC_ID,pseudo);cb(pseudo)}else cb(null)})}
  19. function keyPressHandler(cell,key){cell.dom.classList.add(R.klass.cell.pending);doGet("/api/put?grid="+GRID_PUBLIC_ID+"&key="+key+"&x="+cell.x+"&y="+cell.y+"&me="+GRID.playerSelf.idEncoded,function(status,resp){cell.dom.classList.remove(R.klass.cell.pending);if(status===403&&!cell.data.found)cell.dom.classList.add(R.klass.cell.wrong);else if(status===204)pollNow();else pollNow()})}
  20. function updateOnPollResult(resp){if(resp["players"]){GRID.updatePlayers(resp["players"]);onPlayersUpdated();console.log("players updated")}if(resp["grid"]){GRID.update(resp["grid"]);uiCreateGrid()}KNOWN_VERSION=Math.max(KNOWN_VERSION,resp["v"]||0)}function unselect(){SELECTED.forEach(function(cell){cell.dom.classList.remove(R.klass.cell.selected)});if(CURRENTINPUT){CURRENTINPUT.dom.classList.remove(R.klass.cell.currentInput);CURRENTINPUT=null}SELECTED=[]}
  21. function select(x,y){var cell=UI_CELLS[x+y*GRID.width];SELECTED.push(cell);cell.dom.classList.add(R.klass.cell.selected)}
  22. document.addEventListener("DOMContentLoaded",function(){GRID_PUBLIC_ID=document.location.hash.substr(1);if(GRID_PUBLIC_ID==""){document.location.href="/";return}document.addEventListener("click",gridClickDelegate);document.addEventListener("keypress",function(e){if(CURRENTINPUT&&!CURRENTINPUT.data.found)if(e.key.length===1){var key=e.key.charAt(0).toUpperCase();if(key.match(/[A-Z]/)){CURRENTINPUT.data.letter=key;keyPressHandler(CURRENTINPUT,key);onGridUpdated()}}else if(e.key.toUpperCase()=="DELETE"){CURRENTINPUT.data.letter=
  23. null;onGridUpdated()}else if(e.key.toUpperCase()=="BACKSPACE"){CURRENTINPUT.data.letter=null;onGridUpdated()}console.log(e)});initPolling()});