From 7033efd699231ef4a64f2b392add699b9b5eb2b5 Mon Sep 17 00:00:00 2001 From: Francis Ganya Date: Sun, 20 Nov 2016 17:51:41 +0200 Subject: [PATCH] Working voting system - bug - removes the player from the stats box --- Game.php | 8 +- Game/Assets/css/custom.css | 3 + Game/Assets/css/custom.less | 4 +- Game/Assets/js/Components/AdminWidgets.js | 171 ++++++++--- Game/Assets/js/Components/contributions.js | 8 +- Game/Assets/js/Components/help.js | 2 +- Game/Assets/js/components/PlayComponents.js | 299 ++++++++++++++++++-- Game/Assets/js/core.js | 198 ++++++++++++- Game/Assets/js/dev/AdminWidgets.js | 173 ++++++++--- Game/Assets/js/dev/PlayComponents.js | 297 +++++++++++++++++-- Game/Assets/js/dev/contributions.js | 8 +- Game/Assets/js/dev/help.js | 2 +- Game/Assets/js/play.js | 38 ++- Game/Config/Environment.php | 2 +- Game/Config/Routes.php | 3 +- Game/Controllers/Questions.php | 33 +++ Game/Data/Gameinfo.db | Bin 16384 -> 68608 bytes Game/Models/M_Questions.php | 69 ++++- Game/Screens/Play.php | 14 +- index.php | 1 - 20 files changed, 1166 insertions(+), 167 deletions(-) diff --git a/Game.php b/Game.php index 657aee7..6961a11 100644 --- a/Game.php +++ b/Game.php @@ -23,12 +23,14 @@ $Asset->file(APIPATH."Helpers.php"); $Asset->file(APIPATH."Screen.php"); - +/** +* Extract URI parts +*/ /*----------------------------------------------------------------------------- | Get Controller and action -----------------------------------------------------------------------------*/ -$controller=(isset($_GET['controller'])) ? ucfirst($_GET['controller']) : 'Setup'; -$method=(isset($_GET['method'])) ? $_GET['method'] : 'index'; +$controller=(isset($_GET['controller']) && !empty($_GET['controller'])) ? ucfirst($_GET['controller']) : 'Setup'; +$method=(isset($_GET['method']) && !empty($_GET['method'])) ? $_GET['method'] : 'index'; /*----------------------------------------------------------------------------- | Validate the route diff --git a/Game/Assets/css/custom.css b/Game/Assets/css/custom.css index 6d3553a..a947075 100644 --- a/Game/Assets/css/custom.css +++ b/Game/Assets/css/custom.css @@ -196,6 +196,9 @@ ul.contestant-bar li.active { .validation-error { border-color: red; } +.focused { + border-color: orange; +} .loader { border: 16px solid #E3F2FD; border-radius: 50%; diff --git a/Game/Assets/css/custom.less b/Game/Assets/css/custom.less index edb0c86..8fcf16e 100644 --- a/Game/Assets/css/custom.less +++ b/Game/Assets/css/custom.less @@ -243,7 +243,9 @@ ul.contestant-bar li.active border-color:red; } - +.focused{ + border-color:orange; +} .loader { border: 16px solid @base-bg; border-radius: 50%; diff --git a/Game/Assets/js/Components/AdminWidgets.js b/Game/Assets/js/Components/AdminWidgets.js index 3062a54..7f8f1f9 100644 --- a/Game/Assets/js/Components/AdminWidgets.js +++ b/Game/Assets/js/Components/AdminWidgets.js @@ -3,6 +3,25 @@ * Adminstartion page script * @author Francis Ganya */ + + +function validate(inputTag){ + var arr=$(inputTag); + var errors=0; + arr.map(function(index,input){ + if(input.value.trim().length==0){ + $(this).addClass('animated shake validation-error'); + errors++; + } + }); + + setTimeout(function() { + $(inputTag).removeClass('animated shake validation-error'); + }.bind(this), 1500); + + if(errors!=0) return false; + return true; +} /** * returns a formated svg tag * @param svgTag - the tag to use in the svg class @@ -54,7 +73,8 @@ var FilterForm=React.createClass({displayName: "FilterForm", return{ saveURL:"./?controller=questions&method=add", getURL:"./?controller=contributions&method=question", - removeLink:"./?controller=contributions&method=removeQuestion" + removeLink:"./?controller=contributions&method=removeQuestion", + btnText:"+ DB",mainHeader:"Inspect Contribution" } }, reset:function() @@ -72,15 +92,16 @@ var FilterForm=React.createClass({displayName: "FilterForm", return ( React.createElement("div", {className: this.props.dimensions}, React.createElement("div", {className: "panel panel-primary"}, - React.createElement("div", {className: "panel-heading dark-overlay", dangerouslySetInnerHTML: useSvg("monitor","monitor","Inspect Contribution")}), + React.createElement("div", {className: "panel-heading dark-overlay", dangerouslySetInnerHTML: useSvg("monitor","monitor",this.props.mainHeader)}), React.createElement("div", {className: "panel-body"}, React.createElement("p", null, "Enter ID") ), React.createElement("div", {className: "panel-footer"}, React.createElement("div", {className: "input-group"}, - React.createElement("input", {id: "filter-box", type: "text", value: this.state.id, onChange: this.handleChange, className: "form-control input-md", placeholder: "Inspect Contribution"}), + React.createElement("input", {id: "filter-box", type: "text", value: this.state.id, onChange: this.handleChange, className: "form-control input-md", placeholder: "Inspect"}), React.createElement("span", {className: "input-group-btn"}, - React.createElement("button", {type: "button", className: "btn btn-primary btn-md", onClick: this.getData}, "Inspect") + React.createElement("button", {type: "button", className: "btn btn-primary btn-md", onClick: this.getData}, "inspect"), + React.createElement("button", {type: "button", className: "btn btn-danger btn-md", onClick: this.deleteQ}, "delete") ) ) ) @@ -89,14 +110,52 @@ var FilterForm=React.createClass({displayName: "FilterForm", ) }, + fix:function() + { + var qBoxContent=this.refs.qBox.value; + var aBoxContent=this.refs.ansBox.value; + + while(qBoxContent.lastIndexOf("\"")!=-1){ + qBoxContent=qBoxContent.replace("\"","'"); + } + + while(aBoxContent.lastIndexOf("\"")!=-1){ + aBoxContent=aBoxContent.replace("\"","'"); + } + + this.refs.qBox.value=qBoxContent; + this.refs.ansBox.value=aBoxContent; + }, + deleteQ:function(){ + if(!validate("#filter-box")) return; + var removeQ=new Promise(function(done){ + $.post(this.props.removeLink,{id:this.state.id},function(data,status){ + if(data=='true'){ + done(); + } + else{ + console.error("Error"+data) + $("#filter-box").addClass("validation-error"); + } + }) + }.bind(this)); + + removeQ.then(function(){ + $("#filter-box").val(''); + this.setState({step:"init",id:''}); + }.bind(this)); + }, add:function() { + + if(!validate(".q-inspect-input")) return var sendData=new Promise(function(done){ - $.post(this.props.saveURL,{ + $.post(this.props.saveURL,{ question:this.refs.qBox.value, answer:this.refs.ansBox.value, tag:this.refs.tagBox.value, - category:this.refs.catBox.value + category:this.refs.catBox.value, + id:(this.props.formCat=="main-DB") ? this.state.id :'' },function(data,status){ if(data==='true'){ done(); @@ -110,11 +169,18 @@ var FilterForm=React.createClass({displayName: "FilterForm", sendData.then(function(){ return new Promise(function(done){ - $.post(this.props.removeLink,{id:this.state.id},function(data,status){ + if(this.props.formCat!="main-DB"){ + $.post(this.props.removeLink,{id:this.state.id},function(data,status){ if(data=='true'){ done(); } - }); + }); + } + else{ + done(); + } + + }.bind(this)) }.bind(this)).then(function(){ this.setState({step:"init",id:''}); @@ -123,17 +189,13 @@ var FilterForm=React.createClass({displayName: "FilterForm", // gets the data from the server using the supplied Question ID getData:function() { - if($("#filter-box").val().trim().length==0){ - $("#filter-box").addClass('animated shake validation-error'); - return ; - } - $("#filter-box").removeClass('animated shake validation-error'); + if(!validate("#filter-box")) return ; var getData=new Promise(function(done){ $.post(this.props.getURL,{id:this.state.id},function(data,status){ - if(data!='false'){ + if(data!='false' && data.trim().length!=0){ try{ var data=JSON.parse(data); - $("#filter-box").removeClass("validation-error"); + $("#filter-box").removeClass("validation-error"); done(data); } catch(e){ @@ -144,14 +206,23 @@ var FilterForm=React.createClass({displayName: "FilterForm", } else{ console.error("Error"+data) + $("#filter-box").addClass("validation-error"); } }) }.bind(this)); getData.then(function(data){ this.setState({step:"gotten-data"}); - this.refs.qBox.value=data.question; - this.refs.ansBox.value=data.answer; + if(this.props.formCat!="main-DB"){ + this.refs.qBox.value=data.question; + this.refs.ansBox.value=data.answer; + } + if(this.props.formCat=="main-DB"){ + this.refs.qBox.value=data[0].question; + this.refs.ansBox.value=data[0].answer; + this.refs.tagBox.value=data[0].tag; + this.refs.catBox.value=data[0].cat + } }.bind(this)); }, // render a new form for modifying the data @@ -167,35 +238,47 @@ var FilterForm=React.createClass({displayName: "FilterForm", React.createElement("div", {className: "form-group"}, React.createElement("label", {className: "col-md-3 control-label", htmlFor: "question"}, "Question"), React.createElement("div", {className: "col-md-9"}, - React.createElement("input", {ref: "qBox", placeholder: "Question", className: "form-control"}) + React.createElement("textarea", {ref: "qBox", placeholder: "Question", className: "form-control q-inspect-input", rows: "5"}) ) ), React.createElement("div", {className: "form-group"}, React.createElement("label", {className: "col-md-3 control-label", htmlFor: "answer"}, "Answer"), React.createElement("div", {className: "col-md-9"}, - React.createElement("textarea", {ref: "ansBox", className: "form-control", id: "message", name: "message", placeholder: "Answer", rows: "5"}) + React.createElement("input", {ref: "ansBox", className: "form-control q-inspect-input", id: "message", name: "message", placeholder: "Answer"}) ) ), React.createElement("div", {className: "form-group"}, React.createElement("label", {className: "col-md-3 control-label", htmlFor: "tag"}, "Tag"), React.createElement("div", {className: "col-md-9"}, - React.createElement("input", {ref: "tagBox", type: "text", placeholder: "tag", className: "form-control"}) + React.createElement("select", {ref: "tagBox", type: "text", placeholder: "tag", className: "form-control q-inspect-input"}, + React.createElement("option", {value: "easy"}, "Easy"), + React.createElement("option", {value: "medium"}, "Medium"), + React.createElement("option", {value: "brainy"}, "Brainy") + ) ) ), React.createElement("div", {className: "form-group"}, React.createElement("label", {className: "col-md-3 control-label", htmlFor: "tag"}, "Category"), React.createElement("div", {className: "col-md-9"}, - React.createElement("input", {ref: "catBox", type: "text", placeholder: "category", className: "form-control"}) + React.createElement("input", {ref: "catBox", type: "text", list: "cats", placeholder: "category", className: "form-control q-inspect-input"}), + React.createElement("datalist", {id: "cats"}, + React.createElement("option", {value: "computers"}), + React.createElement("option", {value: "sports"}), + React.createElement("option", {value: "food"}), + React.createElement("option", {value: "animals"}), + React.createElement("option", {value: "General Knowledge"}) + ) ) ), React.createElement("div", {className: "form-group"}, React.createElement("div", {className: "col-md-12 widget-right"}, - React.createElement("button", {type: "button", className: "btn btn-primary btn-md pull-right", onClick: this.add}, "Add To Main DB "), - React.createElement("button", {type: "button", className: "btn btn-primary btn-md pull-right", style: {marginRight:3+'px'}, onClick: this.reset}, "Cancel ") + React.createElement("button", {type: "button", className: "btn btn-success btn-md pull-right", onClick: this.add}, this.props.btnText), + React.createElement("button", {type: "button", className: "btn btn-primary btn-md pull-right", style: {marginRight:3+'px'}, onClick: this.reset}, "Cancel "), + React.createElement("button", {type: "button", className: "btn btn-danger btn-md pull-right", style: {marginRight:3+'px'}, onClick: this.fix}, "fix ") ) ) ) @@ -445,7 +528,7 @@ var Dashboard=React.createClass({displayName: "Dashboard", { return { widgets:[ - {name:"gameCount",count:0,description:"Games played",color:"blue",icon:"chain",xLink:"chain"}, + {name:"gameCount",count:0,description:"Game(s) played",color:"blue",icon:"chain",xLink:"chain"}, {name:"questionCount",count:0,description:"Question(s)",color:"red",icon:"internal hard drive",xLink:"internal-hard-drive"}, {name:"contribCount",count:0,description:"Contributions(+)",color:"teal",icon:"basket",xLink:"basket"}, {name:"topScore",count:0,description:"is the top score",color:"teal",icon:"flag",xLink:"flag"} @@ -603,6 +686,9 @@ var QuestionSection=React.createClass({displayName: "QuestionSection", q_link:"./?controller=Questions&method=all", qc_link:"./?controller=Questions&method=count", dc_link:"./?controller=Questions&method=brainy_count", + getURL:"./?controller=questions&method=question", + saveLink:"./?controller=Questions&method=update", + removeLink:"./?controller=questions&method=remove", max:10000 } @@ -660,26 +746,45 @@ var QuestionSection=React.createClass({displayName: "QuestionSection", }, getInitialState:function() { - return {panels:[]} + return {panels:[],edit:false} + }, + toggleEdit:function() + { + this.setState({edit:!this.state.edit}); }, render:function() { + var aproRender=null; + if(this.state.edit==false){ + aproRender=function(){ + return this.state.panels.map(function(panel,index){ + return( + React.createElement(CustomPanel, {key: index, id: panel.id, percent: panel.count, tag: panel.text, color: panel.color}) + ) + }); + }.bind(this); + } + else{ + aproRender=function(){ + return( + React.createElement(FilterForm, {formCat: "main-DB", getURL: this.props.getURL, saveURL: this.props.saveLink, + removeLink: this.props.removeLink, mainHeader: "update", btnText: "update"}) + ) + }.bind(this); + } return( React.createElement("div", null, React.createElement(Header, {name: "Questions"}), /** main question components */ React.createElement("div", {className: "row"}, React.createElement(CustomTable, {title: "Questions in DB", link: this.props.q_link, - headers: ['id','question','answer',"last_accessed"], - dimensions: "col-lg-9 col-md-9 col-sm-9 col-xs-12"}), + headers: ['id','question','answer',"cat","last_accessed"], + dimensions: "col-lg-8 col-md-7 col-sm-8 col-xs-12"}), React.createElement("div", {className: "col-sm-3 col-lg-3 col-md-3"}, + aproRender(), - this.state.panels.map(function(panel,index){ - return( - React.createElement(CustomPanel, {key: index, id: panel.id, percent: panel.count, tag: panel.text, color: panel.color}) - ) - }) - + React.createElement("button", {type: "button", className: "btn btn-primary", style: {marginRight:3+'px',marginLeft:20+'px'}, onClick: this.toggleEdit}, "Toggle Edit") + ) ) ) diff --git a/Game/Assets/js/Components/contributions.js b/Game/Assets/js/Components/contributions.js index 8628166..0724ef4 100644 --- a/Game/Assets/js/Components/contributions.js +++ b/Game/Assets/js/Components/contributions.js @@ -8,7 +8,7 @@ var SuggestBox=React.createClass({displayName: "SuggestBox", getInitialState:function() { return {status:'not-suggesting',statusMsg:"Hi! How would you like to contribute ?", - formErr:false,err:"Sorry something went wrong.Try again"}; + formErr:false,err:"Sorry something went wrong.Try again",done:false}; }, validateInputs:function(tag){ var qInputs=$(tag); @@ -92,7 +92,9 @@ var SuggestBox=React.createClass({displayName: "SuggestBox", promiseToAddQ.then(function(fromResolve){ if(fromResolve){ - this.setState({status:'not-suggesting'}); + this.refs.qBox.value=""; + this.refs.aBox.value=""; + this.setState({done:true}); } }.bind(this)) @@ -137,7 +139,7 @@ var SuggestBox=React.createClass({displayName: "SuggestBox", ), React.createElement("button", {type: "button", className: "btn wk-btn", onClick: this.sendQuestionSuggestion}, "Suggest"), - React.createElement("button", {type: "button", className: "btn wk-btn marg-1", onClick: this.abort}, "Cancel") + React.createElement("button", {type: "button", id: "doneBtn", className: "btn wk-btn marg-1", onClick: this.abort}, (this.state.done)?"done":"cancel") ) ); }, diff --git a/Game/Assets/js/Components/help.js b/Game/Assets/js/Components/help.js index 219e909..a8b014c 100644 --- a/Game/Assets/js/Components/help.js +++ b/Game/Assets/js/Components/help.js @@ -206,7 +206,7 @@ var AcknowledgementList=React.createClass({displayName: "AcknowledgementList", return( React.createElement("div", null, this.state.projects.map(function(library,index){ - return React.createElement("a", {target: "_blank", href: 'http:://'+library.website, key: index, className: "list-group-item"}, library.project) + return React.createElement("a", {target: "_blank", href: 'http://'+library.website, key: index, className: "list-group-item"}, library.project) }) ) ) diff --git a/Game/Assets/js/components/PlayComponents.js b/Game/Assets/js/components/PlayComponents.js index 5ea459f..bd5efde 100644 --- a/Game/Assets/js/components/PlayComponents.js +++ b/Game/Assets/js/components/PlayComponents.js @@ -86,6 +86,7 @@ var MoneyBar=React.createClass({displayName: "MoneyBar", * Handles responses from the user */ var QuestionPanel=React.createClass({displayName: "QuestionPanel", + getInitialState:function(){return {q_time:20}}, /** * the player answered -evaluate the answer */ @@ -96,6 +97,8 @@ var QuestionPanel=React.createClass({displayName: "QuestionPanel", if(status){ this.props.aHwnd(true); } + this.clearQTimer(); + this.askQuestion(); }, /** * player did not answer - the player failed the question @@ -103,14 +106,45 @@ var QuestionPanel=React.createClass({displayName: "QuestionPanel", handlePass:function(){ // call game-controllers handle pass method this.props.pHwnd(); - }, + }, + /** + * startQTimer starts the question timers + */ + startQTimer:function(){ + var timer=setInterval(function(){ + var q_time=this.state.q_time; + if(q_time==0) + { + this.timeOut(); + } + else{ + this.setState({q_time:q_time-1}); + } + }.bind(this),1000); + this.setState({q_timer:timer}) + }, + /** + * ends question timer + */ + clearQTimer:function(){ + this.setState({q_time:20}); + window.clearInterval(this.state.q_timer); + }, + askQuestion:function(){ + this.startQTimer(); + }, + timeOut:function() + { + this.clearQTimer(); + this.handlePass(); + }, render:function() { return ( React.createElement("div", null, React.createElement("div", {className: "panel panel-default"}, React.createElement("div", {className: "panel-heading"}, - React.createElement("h3", {className: "panel-title"}, "Question") + React.createElement("h3", {className: "panel-title"}, "Question", React.createElement("span", {className: "pull-right"}, this.state.q_time)) ), React.createElement("div", {className: "panel-body"}, "Sample question here" @@ -215,7 +249,7 @@ var PlayWindow=React.createClass({displayName: "PlayWindow", /* Main game play container section */ React.createElement("div", {className: "col-sm-8"}, React.createElement(ContestantBar, {players: this.props.players}), - React.createElement(QuestionPanel, {banker: this.handleBank, aHwnd: this.props.master.handleAnswer, pHwnd: this.props.master.handlePass}) + React.createElement(QuestionPanel, {banker: this.handleBank, aHwnd: this.props.master.handleAnswer, tHwnd: this.props.master.handleTimeOut, pHwnd: this.props.master.handlePass}) ), /* end of main game play container section */ /* timer section */ React.createElement("div", {className: "col-sm-2"}, @@ -368,6 +402,178 @@ var StatisticsWindow=React.createClass({displayName: "StatisticsWindow", } }); +var VotingWindow=React.createClass({displayName: "VotingWindow", + getInitialState:function(){ + return{isDone:false,voter:'',votables:[],count:0,cIndex:0,votes:[]} + }, + componentWillReceiveProps:function(){ + + var votables=this.state.votables; + if(votables.length==0){ + var master=this.props.master; + var players=master.state.contestants; + var votes=this.state.votes; + + players.map(function(player,index){ + votes.push({name:player.fname,cVotes:0}); + }); + + for(var i=1;imostVoted.cVotes){ + mostVoted=votes[index]; + } + } + + //check if there are ties + for(var index=0;index */ + React.createElement("button", {className: "btn wk-btn"}, "Done") + ) + ) + } + } + return( + React.createElement("div", {className: "modal fade", id: "vote-window", "data-backdrop": "static"}, + React.createElement("div", {className: "modal-dialog modal-sm"}, + React.createElement("div", {className: "modal-content"}, + React.createElement("div", {className: "modal-header"}, + React.createElement("button", {type: "button", className: "close", "data-dismiss": "modal", "aria-hidden": "true"}, "×"), + React.createElement("h3", {className: "modal-title"}, "Vote") + ), + React.createElement("div", {className: "modal-body"}, + (!this.state.isDone) ? this.getVote():'this.FinalResponse()' + ), + aproFooter() + ) + ) + ) + ) + } +}) /** * The game controller class * Controls core game components - statistics, playwindow and history @@ -427,10 +633,48 @@ var GameController=React.createClass({displayName: "GameController", this.addEvent('start',function(){ this.startRound(); }.bind(this)); + + //register the voting event + this.addEvent('vote',function(stackInfo){ + //prep ejection msg + var weakPlayer=this.state.game.rounds[this.state.game.currentRound].weakestLink; + var msg=[]; + if(weakPlayer==="N/A"){ + msg.push("Statistically there is no weak player."); + msg.push("But the group thinks your services are no longer required :)"); + } + else{ + msg.push("Statistically "+weakPlayer+" is the weakest link."); + msg.push(this.state.game.rounds[this.state.game.currentRound].weakReason); + if(weakPlayer!=stackInfo.ejected.name){ + msg.push("But the group does not think so."); + } + } + msg.push(stackInfo.ejected.name+" you are the weakest link"); + msg.push("GoodBye!!"); + host.notifyPlayers(msg,function(){ + //remove the player + var players=this.state.contestants; + for(var i=0;i1){ + // get strongest link by amount of money banked + c_arr.map(function(player,index){ + scores.push(player.roundInfo.banked); + }); + + // get the highest banked amount + scores.sort(function(a,b){return (b-a)}) + c_arr.map(function(player,index){ + if(player.roundInfo.banked==scores[0]) { + high_=index; + return; + } + }); + strongest=c_arr[high_].fname; + thisRound.strongReason="Reason : Banked the most money/system select."; + + } + else{ + strongest=c_arr[high_].fname; + thisRound.strongReason="Reason : Answered the most correct questions."; + } + + return strongest; } @@ -155,8 +195,49 @@ function getStrongestPlayer(c_arr){ * calculate and get the weakest Link */ -function getWeakestPlayer(c_arr) +function getWeakestPlayer(c_arr,thisRound) { + var scores=[],matches=0,low_,weakest; + c_arr.map(function(player,index){ + scores.push(player.roundInfo.failed); + }); + + //get the lowest score + scores.sort(function(a,b){return (b-a)}) + c_arr.map(function(player,index){ + if(player.roundInfo.failed==scores[0]) { + matches++; + low_=index; + } + }); + + //there was a tie + if(matches>1){ + // many contestants failed + // get weakest link by amount of money banked + c_arr.map(function(player,index){ + scores.push(player.roundInfo.banked); + }); + + //get the least banked amount + scores.sort(function(a,b){return (a-b)}) + c_arr.map(function(player,index){ + if(player.roundInfo.banked==scores[0]) { + low_=index; + matches++ + thisRound.weakReason="Banked the least amount of money"; + return; + } + }); + weakest=(matches>1) ? "N/A" :c_arr[low_].fname; + + } + else{ + weakest=c_arr[low_].fname; + thisRound.weakReason="Got the most incorrect answers"; + } + + return weakest; } @@ -169,8 +250,12 @@ function handleCore(controller){ var action=$("#int-btn-1").text(); if(action==='start game'){ $('#game-play').modal('show'); - setTimeout(controller.dispatchEvent({type:'start'}),50000); - } + setTimeout(controller.dispatchEvent({type:'start'}),50000); + setInteraction("Interaction 1","Game in progress",function(){ + $("#int-btn-1").removeClass('animated flash focused'); + }); + + } } /** @@ -179,5 +264,104 @@ function handleCore(controller){ * evaluates the value of the second interactivity button and perfoms an accord action */ function handleSub(controller){ + +} + +function validate(inputTag){ + var arr=$(inputTag); + var errors=0; + arr.map(function(index,input){ + if(input.value.trim().length==0){ + $(this).addClass('animated shake validation-error'); + errors++; + } + }); + + setTimeout(function() { + $(inputTag).removeClass('animated shake validation-error'); + }.bind(this), 1500); + + if(errors!=0) return false; + return true; +} + +function Host(){ + this.speak_plain=function(msgs,target,callback){ + var timer=setInterval(function(){ + if(msgs.length==0){ + clearInterval(timer); + if(callback) callback(); + return; + } + $(target).text(msgs[0]); + this.speak_voice(msgs[0]); + msgs.shift(); + }.bind(this),5000); + } + + this.speak_voice=function(){ + var thisMsg = new SpeechSynthesisUtterance(); + var voices = window.speechSynthesis.getVoices(); + thisMsg.voiceURI = 'native'; + thisMsg.volume = 1; // 0 to 1 + thisMsg.rate = 1; // 0.1 to 10 + thisMsg.pitch = 2; //0 to 2 + thisMsg.lang = 'en-UK'; + + thisMsg.onend = function(e,callback) { + if(callback){ + calback(); + } + }; -} \ No newline at end of file + this.speak=function(text,callback){ + thisMsg.text = text; + speechSynthesis.speak(thisMsg); + } + } + + this.notifyPlayers=function(msgs,callback){ + this.speak_plain(msgs,"#off-play-msg-box",callback); + } +} + +function setInteraction(btnText,msgBoxText,callback) +{ + $("#int-btn-1").text(btnText); + $("#off-play-msg-box").text(msgBoxText); + callback(); +} + +function getRoundRemarks(container,earnings) +{ + var remark_index=null; + if(earnings<10000){ + remark_index=0; + } + else if(earnings<20000){ + remark_index=1; + } + else if(earnings<30000){ + remark_index=2; + } + else if(earnings<40000){ + remark_index=3; + } + else if(earnings<50000){ + remark_index=4; + } + else if(earnings<60000){ + remark_index=5; + } + else if(earnings>60000 && earnings<64000){ + remark_index=6; + } + else{ + remark_index=7; + } + container.push("You managed to get "+remarks[remark_index]+" "+earnings); + container.push("That money will go to the next round but one of you will "+(['certainly','definately','surely'])[Math.floor(Math.random()*3)] +" not") + container.push(puns[Math.floor(Math.random()*5)]); + container.push("it's time to vote off the weakest link!"); +} +var host=new Host(); diff --git a/Game/Assets/js/dev/AdminWidgets.js b/Game/Assets/js/dev/AdminWidgets.js index 6dd9333..7a6bc34 100644 --- a/Game/Assets/js/dev/AdminWidgets.js +++ b/Game/Assets/js/dev/AdminWidgets.js @@ -3,6 +3,25 @@ * Adminstartion page script * @author Francis Ganya */ + + +function validate(inputTag){ + var arr=$(inputTag); + var errors=0; + arr.map(function(index,input){ + if(input.value.trim().length==0){ + $(this).addClass('animated shake validation-error'); + errors++; + } + }); + + setTimeout(function() { + $(inputTag).removeClass('animated shake validation-error'); + }.bind(this), 1500); + + if(errors!=0) return false; + return true; +} /** * returns a formated svg tag * @param svgTag - the tag to use in the svg class @@ -54,7 +73,8 @@ var FilterForm=React.createClass({ return{ saveURL:"./?controller=questions&method=add", getURL:"./?controller=contributions&method=question", - removeLink:"./?controller=contributions&method=removeQuestion" + removeLink:"./?controller=contributions&method=removeQuestion", + btnText:"+ DB",mainHeader:"Inspect Contribution" } }, reset:function() @@ -72,15 +92,16 @@ var FilterForm=React.createClass({ return (
-
+

Enter ID

- + - + +
@@ -89,14 +110,52 @@ var FilterForm=React.createClass({ ) }, + fix:function() + { + var qBoxContent=this.refs.qBox.value; + var aBoxContent=this.refs.ansBox.value; + + while(qBoxContent.lastIndexOf("\"")!=-1){ + qBoxContent=qBoxContent.replace("\"","'"); + } + + while(aBoxContent.lastIndexOf("\"")!=-1){ + aBoxContent=aBoxContent.replace("\"","'"); + } + + this.refs.qBox.value=qBoxContent; + this.refs.ansBox.value=aBoxContent; + }, + deleteQ:function(){ + if(!validate("#filter-box")) return; + var removeQ=new Promise(function(done){ + $.post(this.props.removeLink,{id:this.state.id},function(data,status){ + if(data=='true'){ + done(); + } + else{ + console.error("Error"+data) + $("#filter-box").addClass("validation-error"); + } + }) + }.bind(this)); + + removeQ.then(function(){ + $("#filter-box").val(''); + this.setState({step:"init",id:''}); + }.bind(this)); + }, add:function() { + + if(!validate(".q-inspect-input")) return var sendData=new Promise(function(done){ - $.post(this.props.saveURL,{ + $.post(this.props.saveURL,{ question:this.refs.qBox.value, answer:this.refs.ansBox.value, tag:this.refs.tagBox.value, - category:this.refs.catBox.value + category:this.refs.catBox.value, + id:(this.props.formCat=="main-DB") ? this.state.id :'' },function(data,status){ if(data==='true'){ done(); @@ -110,11 +169,18 @@ var FilterForm=React.createClass({ sendData.then(function(){ return new Promise(function(done){ - $.post(this.props.removeLink,{id:this.state.id},function(data,status){ + if(this.props.formCat!="main-DB"){ + $.post(this.props.removeLink,{id:this.state.id},function(data,status){ if(data=='true'){ done(); } - }); + }); + } + else{ + done(); + } + + }.bind(this)) }.bind(this)).then(function(){ this.setState({step:"init",id:''}); @@ -123,17 +189,13 @@ var FilterForm=React.createClass({ // gets the data from the server using the supplied Question ID getData:function() { - if($("#filter-box").val().trim().length==0){ - $("#filter-box").addClass('animated shake validation-error'); - return ; - } - $("#filter-box").removeClass('animated shake validation-error'); + if(!validate("#filter-box")) return ; var getData=new Promise(function(done){ $.post(this.props.getURL,{id:this.state.id},function(data,status){ - if(data!='false'){ + if(data!='false' && data.trim().length!=0){ try{ var data=JSON.parse(data); - $("#filter-box").removeClass("validation-error"); + $("#filter-box").removeClass("validation-error"); done(data); } catch(e){ @@ -144,14 +206,23 @@ var FilterForm=React.createClass({ } else{ console.error("Error"+data) + $("#filter-box").addClass("validation-error"); } }) }.bind(this)); getData.then(function(data){ this.setState({step:"gotten-data"}); - this.refs.qBox.value=data.question; - this.refs.ansBox.value=data.answer; + if(this.props.formCat!="main-DB"){ + this.refs.qBox.value=data.question; + this.refs.ansBox.value=data.answer; + } + if(this.props.formCat=="main-DB"){ + this.refs.qBox.value=data[0].question; + this.refs.ansBox.value=data[0].answer; + this.refs.tagBox.value=data[0].tag; + this.refs.catBox.value=data[0].cat + } }.bind(this)); }, // render a new form for modifying the data @@ -167,35 +238,47 @@ var FilterForm=React.createClass({
- + +
- +
- + + +
- - + + +
@@ -445,7 +528,7 @@ var Dashboard=React.createClass({ { return { widgets:[ - {name:"gameCount",count:0,description:"Games played",color:"blue",icon:"chain",xLink:"chain"}, + {name:"gameCount",count:0,description:"Game(s) played",color:"blue",icon:"chain",xLink:"chain"}, {name:"questionCount",count:0,description:"Question(s)",color:"red",icon:"internal hard drive",xLink:"internal-hard-drive"}, {name:"contribCount",count:0,description:"Contributions(+)",color:"teal",icon:"basket",xLink:"basket"}, {name:"topScore",count:0,description:"is the top score",color:"teal",icon:"flag",xLink:"flag"} @@ -603,6 +686,9 @@ var QuestionSection=React.createClass({ q_link:"./?controller=Questions&method=all", qc_link:"./?controller=Questions&method=count", dc_link:"./?controller=Questions&method=brainy_count", + getURL:"./?controller=questions&method=question", + saveLink:"./?controller=Questions&method=update", + removeLink:"./?controller=questions&method=remove", max:10000 } @@ -660,26 +746,45 @@ var QuestionSection=React.createClass({ }, getInitialState:function() { - return {panels:[]} + return {panels:[],edit:false} + }, + toggleEdit:function() + { + this.setState({edit:!this.state.edit}); }, render:function() { + var aproRender=null; + if(this.state.edit==false){ + aproRender=function(){ + return this.state.panels.map(function(panel,index){ + return( + + ) + }); + }.bind(this); + } + else{ + aproRender=function(){ + return( + + ) + }.bind(this); + } return(
{/** main question components */}
+ headers={['id','question','answer',"cat","last_accessed"]} + dimensions="col-lg-8 col-md-7 col-sm-8 col-xs-12" />
- { - this.state.panels.map(function(panel,index){ - return( - - ) - }) - } + { aproRender() } + + +
diff --git a/Game/Assets/js/dev/PlayComponents.js b/Game/Assets/js/dev/PlayComponents.js index 9de214a..2dd7677 100644 --- a/Game/Assets/js/dev/PlayComponents.js +++ b/Game/Assets/js/dev/PlayComponents.js @@ -86,6 +86,7 @@ var MoneyBar=React.createClass({ * Handles responses from the user */ var QuestionPanel=React.createClass({ + getInitialState:function(){return {q_time:20}}, /** * the player answered -evaluate the answer */ @@ -96,6 +97,8 @@ var QuestionPanel=React.createClass({ if(status){ this.props.aHwnd(true); } + this.clearQTimer(); + this.askQuestion(); }, /** * player did not answer - the player failed the question @@ -103,14 +106,45 @@ var QuestionPanel=React.createClass({ handlePass:function(){ // call game-controllers handle pass method this.props.pHwnd(); - }, + }, + /** + * startQTimer starts the question timers + */ + startQTimer:function(){ + var timer=setInterval(function(){ + var q_time=this.state.q_time; + if(q_time==0) + { + this.timeOut(); + } + else{ + this.setState({q_time:q_time-1}); + } + }.bind(this),1000); + this.setState({q_timer:timer}) + }, + /** + * ends question timer + */ + clearQTimer:function(){ + this.setState({q_time:20}); + window.clearInterval(this.state.q_timer); + }, + askQuestion:function(){ + this.startQTimer(); + }, + timeOut:function() + { + this.clearQTimer(); + this.handlePass(); + }, render:function() { return (
-

Question

+

Question{this.state.q_time}

Sample question here @@ -215,7 +249,7 @@ var PlayWindow=React.createClass({ {/* Main game play container section */}
- +
{/* end of main game play container section */} {/* timer section */}
@@ -368,6 +402,178 @@ var StatisticsWindow=React.createClass({ } }); +var VotingWindow=React.createClass({ + getInitialState:function(){ + return{isDone:false,voter:'',votables:[],count:0,cIndex:0,votes:[]} + }, + componentWillReceiveProps:function(){ + + var votables=this.state.votables; + if(votables.length==0){ + var master=this.props.master; + var players=master.state.contestants; + var votes=this.state.votes; + + players.map(function(player,index){ + votes.push({name:player.fname,cVotes:0}); + }); + + for(var i=1;imostVoted.cVotes){ + mostVoted=votes[index]; + } + } + + //check if there are ties + for(var index=0;index + We have a tie! +
+ {this.state.voter}, + You are the Strongest Link and your decision is final! +

+ )}.bind(this); + } + return( +
+

{this.state.voter}

+
+ {tieMsg()} +

Who Do you think is the weakest link that's slowing you down

+
+ + +
+ ); + }, + render:function(){ + var aproFooter=function(){}; + if(this.state.isDone){ + aproFooter=function(){ + return( +
{/** */} + +
+ ) + } + } + return( +
+
+
+
+ +

Vote

+
+
+ {(!this.state.isDone) ? this.getVote():'this.FinalResponse()'} +
+ {aproFooter()} +
+
+
+ ) + } +}) /** * The game controller class * Controls core game components - statistics, playwindow and history @@ -427,10 +633,48 @@ var GameController=React.createClass({ this.addEvent('start',function(){ this.startRound(); }.bind(this)); + + //register the voting event + this.addEvent('vote',function(stackInfo){ + //prep ejection msg + var weakPlayer=this.state.game.rounds[this.state.game.currentRound].weakestLink; + var msg=[]; + if(weakPlayer==="N/A"){ + msg.push("Statistically there is no weak player."); + msg.push("But the group thinks your services are no longer required :)"); + } + else{ + msg.push("Statistically "+weakPlayer+" is the weakest link."); + msg.push(this.state.game.rounds[this.state.game.currentRound].weakReason); + if(weakPlayer!=stackInfo.ejected.name){ + msg.push("But the group does not think so."); + } + } + msg.push(stackInfo.ejected.name+" you are the weakest link"); + msg.push("GoodBye!!"); + host.notifyPlayers(msg,function(){ + //remove the player + var players=this.state.contestants; + for(var i=0;i +
); @@ -629,5 +883,4 @@ ReactDOM.render(GameCtrl,document.getElementById('game-controller')); /** * Game Interaction buttons */ - - +document.getElementById('int-btn-1').addEventListener('click',handleCore(GameCtrl)); \ No newline at end of file diff --git a/Game/Assets/js/dev/contributions.js b/Game/Assets/js/dev/contributions.js index ba692ab..018b511 100644 --- a/Game/Assets/js/dev/contributions.js +++ b/Game/Assets/js/dev/contributions.js @@ -8,7 +8,7 @@ var SuggestBox=React.createClass({ getInitialState:function() { return {status:'not-suggesting',statusMsg:"Hi! How would you like to contribute ?", - formErr:false,err:"Sorry something went wrong.Try again"}; + formErr:false,err:"Sorry something went wrong.Try again",done:false}; }, validateInputs:function(tag){ var qInputs=$(tag); @@ -92,7 +92,9 @@ var SuggestBox=React.createClass({ promiseToAddQ.then(function(fromResolve){ if(fromResolve){ - this.setState({status:'not-suggesting'}); + this.refs.qBox.value=""; + this.refs.aBox.value=""; + this.setState({done:true}); } }.bind(this)) @@ -137,7 +139,7 @@ var SuggestBox=React.createClass({
- + ); }, diff --git a/Game/Assets/js/dev/help.js b/Game/Assets/js/dev/help.js index cc38d5b..f95ae91 100644 --- a/Game/Assets/js/dev/help.js +++ b/Game/Assets/js/dev/help.js @@ -206,7 +206,7 @@ var AcknowledgementList=React.createClass({ return(
{this.state.projects.map(function(library,index){ - return {library.project} + return {library.project} })}
) diff --git a/Game/Assets/js/play.js b/Game/Assets/js/play.js index f3ba2c8..8ff6647 100644 --- a/Game/Assets/js/play.js +++ b/Game/Assets/js/play.js @@ -5,26 +5,36 @@ $(document).ready(function() * for perfomance these are opt in and have to be manually initialised */ $("[data-toggle=popover]").popover(); +}) + var welcomeMsgs=[ + "You will have to work together as a team to earn the highest amount of money as possible.", + "But only one of you will make it to the end as round by round we eliminate the player voted the weakest link", + "Lets play the weakest link!" + ] /** * puns for eliminating players */ - var puns=[ - "Who should go back to waiting tables", - "Who was'nt worth the cost of our AJAX calls", - "Who should revisit their books", - "who isnt worth your time, eject the idiot", - "One of you has reached the end of their journey", - "Who did a lot to graduate on top of their class" - ]; +var puns=[ + "Who should go back to waiting tables", + "Who was'nt worth the cost of our AJAX calls", + "Who should revisit their books", + "who isnt worth your time, eject the idiot", + "One of you has reached the end of their journey", + "Who did a lot to graduate on top of their class" + ]; /** * remarks on the money bancked + * arranged According to peromance */ var remarks=[ - "distressing", - "terrible", - "deeply distressing", - "sad" - ] -}) \ No newline at end of file + "a deeply distressing", + "a distressing", + "a terrible", + "a sad", + "a reasonable", + "an encouraging", + "a motivating", + "a wonderful" + ]; \ No newline at end of file diff --git a/Game/Config/Environment.php b/Game/Config/Environment.php index 70c5280..beb80a7 100644 --- a/Game/Config/Environment.php +++ b/Game/Config/Environment.php @@ -4,7 +4,7 @@ $host='localhost'; $username='root'; -$key=''; +$key='root'; $db='wkl'; ?> \ No newline at end of file diff --git a/Game/Config/Routes.php b/Game/Config/Routes.php index 03605c4..d08f566 100644 --- a/Game/Config/Routes.php +++ b/Game/Config/Routes.php @@ -11,7 +11,8 @@ $routes['Admin']=array("index"); $routes['Setup']=array("index","installation","bug"); $routes['Game']=array("index","register","play","getPlayData","topGames","get_all","scores","topScore","lowScore","count"); -$routes['Questions']=array("all","add","count","getBrainy","brainy_count","getEasy","getMedium"); +$routes['Questions']=array("all","add","count","question","update","remove","getBrainy", + "brainy_count","getEasy","getMedium","addQMarker"); $routes['Contributions']=array( "index","contributors","top_contributors","count", "questions","question","removeQuestion","suggestions", diff --git a/Game/Controllers/Questions.php b/Game/Controllers/Questions.php index 3df372c..7c1ea40 100644 --- a/Game/Controllers/Questions.php +++ b/Game/Controllers/Questions.php @@ -93,6 +93,39 @@ public function brainy_count() $data=$this->questionMgr->getByDifficulty("brainy"); Response::respondWithJSON(array('count'=>count($data)),"questions"); } + + public function question() + { + if(valid('id',$_POST)){ + return Response::respondWithJSON($this->questionMgr->getQuestions(TRUE,$_POST['id']),"Question"); + } + Response::passive(false); + } + + public function update() + { + if(valid(array('question','answer','tag','category','id'),$_POST)) + { + extract($_POST,EXTR_PREFIX_ALL,'Ex'); + // set the fifth param to true in order to update + return Response::passive($this->questionMgr->add($Ex_question,$Ex_answer,$Ex_tag,$Ex_category,TRUE,$Ex_id)); + } + return Response::passive(false); + } + + public function remove() + { + if(valid('id',$_POST)) + { + return Response::passive($this->questionMgr->removeQuestion($_POST['id'])); + } + return Response::passive(false); + } + + public function addQMarker() + { + $this->questionMgr->sanitize(); + } } ?> \ No newline at end of file diff --git a/Game/Data/Gameinfo.db b/Game/Data/Gameinfo.db index 0ca61695cf66295dd62d6ca62959aecc990b21c3..5f15ebce538fa6c69eddf562aaa0c7b2d9ec7618 100644 GIT binary patch literal 68608 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 J{Cf0D`2fH~GL`@U delta 866 zcmaKrzi-n(6vxkbM}CtgfnZ7y9Fz*wCX^;sg=i5Il%WGsgpe2jw>~%5Cg)r1T zZ{eb-_adE!CW9bazdbBHC@U73XWU*Rj&4*`!c1b;xz6iV-8PA(6RS**ER!0mY>^Vh zB(_OaLKyG4jH|k161_$Z#bSI(OfW54RTWy*d061hW=4?8(jhYgetQuestions(); + $query=''; + foreach($questions as $question) + { + $str=$question['question']; + if($str[strlen($str)-1]!='?') + { + $question['question'].="?"; + $query.="update wkl_questions set question=\"{$question['question']}\" where question_id={$question['id']};"; + } + } + $this->_setSql($query); + $this->_contactDB(TRUE); + + echo "done"; + } + public function add($question,$answer,$tag,$cat,$UPDATE=FALSE,$id=null) { - $query=sprintf('INSERT INTO wkl_questions(question,category,difficulty,last_access) VALUES("%s","%s","%s",CURTIME())', + if($UPDATE){ + $query=sprintf('UPDATE wkl_questions SET question="%s" ,category="%s",difficulty="%s" where question_id=%d', $question,$cat,$tag,$id); + } + else{ + $query=sprintf('INSERT INTO wkl_questions(question,category,difficulty,last_access) VALUES("%s","%s","%s",CURTIME())', $question,$cat,$tag); + } + $this->_setSql($query); $this->_contactDB(); - // get the id of the just added Questions - $this->_setSql("select question_id from wkl_questions order by question_id desc limit 1"); - $this->_contactDB(); - - $id=$this->contactMgr->fetch_array(MYSQLI_ASSOC)['question_id']; + if(!$UPDATE) + { + // get the id of the just added Questions + $this->_setSql("select question_id from wkl_questions order by question_id desc limit 1"); + $this->_contactDB(); - $this->_setSql("insert into wkl_answers(to_qid,answer) values('{$id}','{$answer}')"); + $id=$this->contactMgr->fetch_array(MYSQLI_ASSOC)['question_id']; + $this->_setSql("insert into wkl_answers(to_qid,answer) values('{$id}','{$answer}')"); + } + else{ + $this->_setSql("update wkl_answers set answer='{$answer}' where to_qid={$id}"); + } + $this->_contactDB(); return true; @@ -58,9 +89,15 @@ public function getQuestionCount() * gets question data from the main production DB * @return array */ - public function getQuestions() + public function getQuestions($SINGLE=FALSE,$id=NULL) { - $this->_setSql("SELECT * FROM wkl_questions INNER JOIN wkl_answers ON wkl_questions.question_id=wkl_answers.to_qid"); + if($SINGLE==TRUE && $id!=NULL){ + $this->_setSql("SELECT * FROM wkl_questions INNER JOIN wkl_answers ON wkl_questions.question_id=wkl_answers.to_qid + where question_id={$id}"); + } + else{ + $this->_setSql("SELECT * FROM wkl_questions INNER JOIN wkl_answers ON wkl_questions.question_id=wkl_answers.to_qid"); + } $this->_contactDB(); //encode the questions into an array @@ -76,7 +113,7 @@ public function getQuestions() ); } - + if(empty($this->tempArray)) $this->tempArray=null; return $this->tempArray; } @@ -109,6 +146,14 @@ public function getByDifficulty($difficulty="easy") if(empty($this->tempArray)) $this->tempArray=array(); return $this->tempArray; } - + + public function removeQuestion($id) + { + $this->_setSql("delete from wkl_questions where question_id={$id};delete from wkl_answers where to_qid={$id};"); + $this->_contactDB(TRUE); + + + return true; + } } ?> \ No newline at end of file diff --git a/Game/Screens/Play.php b/Game/Screens/Play.php index 3a12d07..7aa3127 100644 --- a/Game/Screens/Play.php +++ b/Game/Screens/Play.php @@ -14,7 +14,7 @@ ------------------------------------------------------------------------------*/ $load->file(SCREENSPATH.'Common/Styles.php',array('load'=>$load)); echo $load->css("custom"); - echo $load->icon('favicon'); +echo $load->icon('favicon'); ?> <?php echo $title; ?> @@ -58,11 +58,11 @@
Game Messages
-

Welcome contenstants

+

Welcome to the Weakest Link

- - + +
@@ -83,7 +83,7 @@ - +
@@ -118,11 +118,11 @@ ------------------------------------------------------------------------------*/ $load->file(SCREENSPATH.'Common/Scripts.php',array('load'=>$load)); $load->file(SCREENSPATH.'Common/ReactDependency.php',array('load'=>$load)); - echo $load->js("play"); echo $load->js("core"); + echo $load->js("play"); echo $load->js("Components/PlayComponents"); echo $load->js("Components/History"); ?> - + \ No newline at end of file diff --git a/index.php b/index.php index f7045b1..9a193e2 100644 --- a/index.php +++ b/index.php @@ -15,7 +15,6 @@ /*----------------------------------------------------------------------------- | Game Paths -----------------------------------------------------------------------------*/ - //path to the weakest-link $game_path='Weakest-link';