summaryrefslogtreecommitdiff
path: root/blog/data/poll.js
diff options
context:
space:
mode:
Diffstat (limited to 'blog/data/poll.js')
-rw-r--r--blog/data/poll.js171
1 files changed, 171 insertions, 0 deletions
diff --git a/blog/data/poll.js b/blog/data/poll.js
new file mode 100644
index 0000000..55b4e22
--- /dev/null
+++ b/blog/data/poll.js
@@ -0,0 +1,171 @@
+//By Chris Xiong, 2018
+//License: Expat
+let p=null;
+let Caption;
+let Choices;
+let Score;
+let Next;
+let values=[];
+let curq;
+function evalexpr(e)
+{
+ let ret=0;
+ let op=function(a,o,b){
+ switch(o){
+ case '+':return a+b;
+ case '-':return a-b;
+ case '*':return a*b;
+ case '/':return a/b;
+ }
+ };
+ for(let p=e.match(/[+\-*\/]/);p;p=e.match(/[+\-*\/]/))
+ {
+ let vp=e.match(/[A-Za-z]\w*/);
+ if(vp)
+ {
+ const v=vp[0];
+ if(values[v]===undefined)throw 'shit';
+ ret=op(ret,p[0],values[v]);
+ e=e.substr(vp.index+vp[0].length);
+ }
+ else
+ {
+ let np=e.match(/\d+(.\d*)?/);
+ if(np)
+ {
+ const n=Number(np[0]);
+ ret=op(ret,p[0],n);
+ e=e.substr(np.index+np[0].length);
+ }else throw 'shit';
+ }
+ }
+ return ret;
+}
+function evalsetexpr(e)
+{
+ const s=e.split('=');
+ if(s.length<2)throw 'shit';
+ values[s[0].trim()]=evalexpr(s[1]);
+}
+function evaltestexpr(e)
+{
+ const m=e.match(/([A-Za-z]\w*)\s*(leq|geq|lt|gt)\s*([A-Za-z0-9.]*)/);
+ if(!m)throw 'shit';
+ const v=m[1],op=m[2],vr=m[3];
+ const vv=values[v];
+ const vvr=isNaN(Number(vr))?values[vr]:Number(vr);
+ if(vv===undefined||vvr===undefined)throw 'shit';
+ switch(op.trim())
+ {
+ case 'leq':return vv<=vvr;
+ case 'geq':return vv>=vvr;
+ case 'lt':return vv<vvr;
+ case 'gt':return vv>vvr;
+ }
+ throw 'shit';
+}
+function evalcondexpr(e)
+{
+ if(!e.trim().length)return true;
+ let ret=false;
+ let op=function(a,o,b){
+ switch(o){
+ case '|':return a||b;
+ case '&':return a&&b;
+ }
+ };
+ for(let p=e.search(/[|&]/);p!=-1;p=e.search(/[|&]/))
+ {
+ let np=e.substr(p+1).search(/[|&]/);
+ let n=e.substr(p+1,np!=-1?np-1:undefined);
+ ret=op(ret,e[p],evaltestexpr(n.trim()));
+ e=np?e.substr(np):"";
+ }
+ return ret;
+}
+function initq()
+{
+ const q=p.question[curq];
+ for(let i=0;i<q.initialization.length;++i)
+ {
+ if(evalcondexpr(q.initialization[i].c))
+ evalsetexpr(q.initialization[i].s);
+ }
+ if(!evalcondexpr(q.precond)){++curq;if(curq<p.question.length)initq();else finalize();}
+}
+function evalq()
+{
+ if(curq>=p.question.length)return;
+ const q=p.question[curq];
+ let seln=0;
+ for(let i=0;i<q.choice.length;++i)
+ {
+ const e=document.getElementById(`choice${i}`);
+ if(e.checked)++seln;
+ if(e.checked)
+ {
+ for(let j=0;j<q.choice[i].setp.length;++j)
+ if(evalcondexpr(q.choice[i].setp[j].c))
+ evalsetexpr(q.choice[i].setp[j].s);
+ }
+ else
+ {
+ for(let j=0;j<q.choice[i].setn.length;++j)
+ if(evalcondexpr(q.choice[i].setn[j].c))
+ evalsetexpr(q.choice[i].setn[j].s);
+ }
+ }
+ if(!seln&&q.type=='single'){alert('Wanna cheat?...');return;}
+ ++curq;
+ if(curq==p.question.length)finalize();else{showq();initq();}
+}
+function showq()
+{
+ const q=p.question[curq];
+ Caption.innerHTML=q.caption;
+ while(Choices.firstChild)Choices.removeChild(Choices.firstChild);
+ for(let i=0;i<q.choice.length;++i)
+ {
+ const d=document.createElement('div');
+ const e=document.createElement('input');
+ e.type=q.type=='multi'?'checkbox':'radio';
+ e.innerHTML=q.choice[i].caption;
+ e.qid=i;e.id=`choice${i}`;
+ e.setAttribute('name','choice');
+ e.classList.add('check');
+ const l=document.createElement('label');
+ l.innerHTML=q.choice[i].caption;
+ l.setAttribute('for',e.id);
+ d.appendChild(e);
+ d.appendChild(l);
+ Choices.appendChild(d);
+ }
+ Score.innerHTML=`${values['score']}, Question ${curq+1}/${p.question.length}`;
+}
+function _init()
+{
+ Caption=document.getElementById('qcaption');
+ Choices=document.getElementById('qchoices');
+ Score=document.getElementById('score');
+ Next=document.getElementById('nextbtn');
+ curq=0;values['score']=0;
+ initq();showq();
+}
+async function init()
+{
+ const resp=await fetch(new Request('/blog/data/applefan.json'));
+ r=await resp.text();
+ p=JSON.parse(r);
+ _init();
+}
+function finalize()
+{
+ Next.style.color='#888';
+ Score.innerHTML=`${values['score']}, Question ${p.question.length}/${p.question.length}`;
+ Caption.innerHTML='';
+ Choices.innerHTML='';
+ for(let i=0;i<p.verdict.length;++i)
+ if(evalcondexpr(p.verdict[i].precond))
+ Caption.innerHTML+=p.verdict[i].caption;
+}
+init();