From 95aa9b7f4e95d3144d36798b350aa0d174db5c5c Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Sat, 20 Apr 2024 17:49:49 -0500 Subject: [PATCH 01/19] changing things. will push to main before requesting pull from gh-pages --- index.html | 69 +++++++++++++++++++++--------------------- script.js | 10 ++++-- styles.css | 2 +- webint.css | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 37 deletions(-) create mode 100644 webint.css diff --git a/index.html b/index.html index 989b9b5..71a97d1 100644 --- a/index.html +++ b/index.html @@ -2,68 +2,69 @@ + AI interview

AI interview

-
-
- Questions the AI should ask you +
+
+ Questions the AI should ask you
-
    -
  • +
      +
      Input text to say after interview: - -
    • -
      + +
      +

      Choose Voice:

      - -

      - + +

      +
      -
      -
      - -
      - - - +
      +
      + +
      + + +
      - +
      -
      -

      - - + +

      + +
      - +
      - +
      Your ResponsesYour Responses
      Questions Answers
      -
      - - +
      + +
      - - - - - + + + + + \ No newline at end of file diff --git a/script.js b/script.js index 6723446..b22a364 100644 --- a/script.js +++ b/script.js @@ -1,8 +1,14 @@ identify() +class Question{ + constructor(question){ + this.question = question; + this.build() + } +} function makeQuestion(question, index) { let questionHolder = make('li'); - [['span', 'questionnumber', index], ['span', 'question', question], - ['button', 'removebutton', 'X'], ['div', 'upanddown']].forEach(e=>{ + [['span', 'question', question], + ['button', 'removebutton', 'X']].forEach(e=>{ questionHolder.appendChild((questionHolder[e[1]]=make(e[0]))).className=e[1]; questionHolder[e[1]].textContent=e[2]; //appendChild would return the element so you can add a className diff --git a/styles.css b/styles.css index e4547a3..8e2a5aa 100644 --- a/styles.css +++ b/styles.css @@ -177,7 +177,7 @@ animation: blink 1s cubic-bezier(0, 0, 1, -0.12) infinite; opacity: 0; z-index: 200; border-radius: 40px; padding: 0; margin: 0; } -@-webkit-keyframes blink{ +@keyframes blink{ 0%{opacity: 1} 50%{opacity: 0} } diff --git a/webint.css b/webint.css new file mode 100644 index 0000000..eacc50e --- /dev/null +++ b/webint.css @@ -0,0 +1,89 @@ +*{ + transition: .2s; +} + +body{ + font: 1.2rem math; + display: flex; + flex-flow: column; + align-items: center; + --color: lightblue; + --b: 1px solid var(--color); + gap: 10px; + margin: 30px; +} + +button{ + color: var(--color); + background: transparent; + font-size: 1rem; + border: thin lightblue; + padding: 5px; + cursor: pointer; + transition: .2s; + display: flex; + align-items: center; + justify-content: center; + /* box-sizing: content-box; */ +} + +[type="text"]{ + padding: 7px; + border: var(--b); + border-radius: .7em; + width: fit-content; + color: gray; +} +[type="text"]:hover{ + border-color: blue +} +[type="text"]:active, [type="text"]:focus{ + border-color: darkblue; + outline: none; +} + + +button:hover, button:active{ + padding: 10px; + border: 1px solid lightblue; + border-radius: 1em; +} + +h2{ + border-bottom: var(--b); + margin: 0; + padding: 5px; +} + + +#questionslist{ + display: flex; + flex-flow: column; + gap: 5px; + list-style-type: armenian; +} + +#questionslist>li{ + /* display: flex; */ + gap: 5px; +} + +#questionslist>li button, #setupdesc button{ + width: 30px; + height: 30px; + float: right; + font-size: 1.2rem; +} + + + +Do a 'share interview' feature. +save all questions to a json, +save voice +save voice settings + +or save in queries that can be read (will be too long) + +or reroute by bitly + + From 67f0c73df89ab18af99dc3d3f9ae10223c68ae98 Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Sat, 20 Apr 2024 19:08:37 -0500 Subject: [PATCH 02/19] HTML okay --- events.js | 232 ++++++++++++++++++++-------------------- index.html | 150 +++++++++++++++----------- script.js => scripts.js | 0 styles.css | 38 +------ web.config | 8 -- webint.css | 119 +++++++++++++++++++-- 6 files changed, 314 insertions(+), 233 deletions(-) rename script.js => scripts.js (100%) delete mode 100644 web.config diff --git a/events.js b/events.js index 4eb2444..8c38375 100644 --- a/events.js +++ b/events.js @@ -1,117 +1,117 @@ -//all functions and variables if (except all event based) here -onbeforeunload=()=>{ - speechSynthesis.cancel(); - localStorage.questions = JSON.stringify([...questionslist.children].map(i=>i.querySelector('.question').innerText)); -} -addquestion.onclick=()=>{ - makeQuestion('Write a question here, write a question here', questionslist.childElementCount+1) -} -startbutton.onclick=()=>{ - if (!(questions=[...questionslist.children].map(i=>i.querySelector('.question').innerText)).length) return errors.innerHTML = 'No question added, Please add at least one questions to proceed'; - if (!confirm('Proceed?')) return - embassy.style.display='flex'; setup.style.display='none'; - shouldusevideo.checked?you.style.display='none':interviewbox.style.display='none'; - questionbox.innerText=(currentQuestion=questions[index])//setup non-video - if (!shouldusevideo.checked) return; - // while (!voice){} - loading.loading = 1; - userMedia = navigator.mediaDevices.getUserMedia({ - audio: true, video: true, - facingMode: {exact: "user"} - }); - userMedia.then(mediaStream=>{ - //setup video recording - stream = mediaStream; - recorder = new MediaRecorder(mediaStream) - recorder.ondataavailable=()=>{ - loading.loading = 1; - finalFile = new Blob([event.data], {type:"video/mp4"}) - response.src=URL.createObjectURL(finalFile); - refresher.style.display='block'; - responseHolder.style.display='flex'; - loading.loading = 0; - } - recorder.start(); - video.srcObject = mediaStream; video.muted=true; - }).catch(error=>{alert('an error occurred, exitting!!'); location.reload()}) - video.onloadstart=()=>{ - loading.loading=0; - video.play(); - let hours = new Date(Date.now()).getHours(), time; - if(hours>16){ - time ='evening' - }else if(hours>11){ - time='afternoon' - }else if(hours>=0){ - time='morning' - } - question = new SpeechSynthesisUtterance(` - Good ${time}}. Welcome to your interview. - Please click the repeat button to repeat any asked question, - and click the forward button to go to the next question.`); - question.voice =voice//= voices[+getAll('[name=voice]').filter(v=>v.checked)[0].value] - voice; question.rate=.8; - speechSynthesis.speak(question); - question.onstart=()=>say.disabled=forward.disabled=true; - question.onend = ()=>{setTimeout(()=>!video.paused&&(say.disabled=forward.disabled=false), randBtw(1000, 2500))}; - // setup q and a - } +// //all functions and variables if (except all event based) here +// onbeforeunload=()=>{ +// speechSynthesis.cancel(); +// localStorage.questions = JSON.stringify([...questionslist.children].map(i=>i.querySelector('.question').innerText)); +// } +// addquestion.onclick=()=>{ +// makeQuestion('Write a question here, write a question here', questionslist.childElementCount+1) +// } +// startbutton.onclick=()=>{ +// if (!(questions=[...questionslist.children].map(i=>i.querySelector('.question').innerText)).length) return errors.innerHTML = 'No question added, Please add at least one questions to proceed'; +// if (!confirm('Proceed?')) return +// embassy.style.display='flex'; setup.style.display='none'; +// shouldusevideo.checked?you.style.display='none':interviewbox.style.display='none'; +// questionbox.innerText=(currentQuestion=questions[index])//setup non-video +// if (!shouldusevideo.checked) return; +// // while (!voice){} +// loading.loading = 1; +// userMedia = navigator.mediaDevices.getUserMedia({ +// audio: true, video: true, +// facingMode: {exact: "user"} +// }); +// userMedia.then(mediaStream=>{ +// //setup video recording +// stream = mediaStream; +// recorder = new MediaRecorder(mediaStream) +// recorder.ondataavailable=()=>{ +// loading.loading = 1; +// finalFile = new Blob([event.data], {type:"video/mp4"}) +// response.src=URL.createObjectURL(finalFile); +// refresher.style.display='block'; +// responseHolder.style.display='flex'; +// loading.loading = 0; +// } +// recorder.start(); +// video.srcObject = mediaStream; video.muted=true; +// }).catch(error=>{alert('an error occurred, exitting!!'); location.reload()}) +// video.onloadstart=()=>{ +// loading.loading=0; +// video.play(); +// let hours = new Date(Date.now()).getHours(), time; +// if(hours>16){ +// time ='evening' +// }else if(hours>11){ +// time='afternoon' +// }else if(hours>=0){ +// time='morning' +// } +// question = new SpeechSynthesisUtterance(` +// Good ${time}}. Welcome to your interview. +// Please click the repeat button to repeat any asked question, +// and click the forward button to go to the next question.`); +// question.voice =voice//= voices[+getAll('[name=voice]').filter(v=>v.checked)[0].value] +// voice; question.rate=.8; +// speechSynthesis.speak(question); +// question.onstart=()=>say.disabled=forward.disabled=true; +// question.onend = ()=>{setTimeout(()=>!video.paused&&(say.disabled=forward.disabled=false), randBtw(1000, 2500))}; +// // setup q and a +// } -} -answerquestion.onclick=()=>{ - event.preventDefault(); - if (!answerbox.reportValidity()) return; - answers.push(answerbox.value); answerbox.value=''; - if(index+1>=questions.length){ - //submit - embassy.style.display='none' - responses.style.display='flex'; - questions.forEach((q, i)=>{ - let r = responses.insertRow(); - (r.insertCell()).innerText = q; - (r.insertCell()).innerText = answers[i] - }) - return refresher.style.display='block' - } - questionbox.innerText=(currentQuestion = questions[++index]) - if(index+2>questions.length) answerquestion.innerText='End interview'; -} -playorpause.onclick=()=>{ - if (video.paused) { - speechSynthesis.resume(); recorder.resume(); video.play(); playorpause.innerText = 'Pause Recording'; - say.disabled=forward.disabled=false; - } else { - speechSynthesis.pause(); recorder.pause(); video.pause();playorpause.innerText = 'Continue Recording'; - question.onstart(); - } -} -forward.onclick=()=>{ - question.onstart(); - if(index>=questions.length){ - //submit - question.text = after.value?after.value:after.placeholder; - speechSynthesis.speak(question) - question.onend=()=>{ - embassy.style.display='none' - stream.getTracks().forEach(i=>i.stop()); - recorder.stop(); - } - return - } - question.text=(currentQuestion=questions[index++]); - speechSynthesis.speak(question) - if(index+1>questions.length) forward.innerText='End interview'; -} -say.onclick=()=>{ - speechSynthesis.cancel(); - speechSynthesis.speak(question); -} -// addquestion.click() -//for downloading -save.onclick=()=>{ - downloader.href=response.src; - downloader.click(); -} -getAll('[name=voice]').forEach(v=>{ - v.onchange=()=>{voice=speechSynthesis.getVoices()[+v.value]} -}) +// } +// answerquestion.onclick=()=>{ +// event.preventDefault(); +// if (!answerbox.reportValidity()) return; +// answers.push(answerbox.value); answerbox.value=''; +// if(index+1>=questions.length){ +// //submit +// embassy.style.display='none' +// responses.style.display='flex'; +// questions.forEach((q, i)=>{ +// let r = responses.insertRow(); +// (r.insertCell()).innerText = q; +// (r.insertCell()).innerText = answers[i] +// }) +// return refresher.style.display='block' +// } +// questionbox.innerText=(currentQuestion = questions[++index]) +// if(index+2>questions.length) answerquestion.innerText='End interview'; +// } +// playorpause.onclick=()=>{ +// if (video.paused) { +// speechSynthesis.resume(); recorder.resume(); video.play(); playorpause.innerText = 'Pause Recording'; +// say.disabled=forward.disabled=false; +// } else { +// speechSynthesis.pause(); recorder.pause(); video.pause();playorpause.innerText = 'Continue Recording'; +// question.onstart(); +// } +// } +// forward.onclick=()=>{ +// question.onstart(); +// if(index>=questions.length){ +// //submit +// question.text = after.value?after.value:after.placeholder; +// speechSynthesis.speak(question) +// question.onend=()=>{ +// embassy.style.display='none' +// stream.getTracks().forEach(i=>i.stop()); +// recorder.stop(); +// } +// return +// } +// question.text=(currentQuestion=questions[index++]); +// speechSynthesis.speak(question) +// if(index+1>questions.length) forward.innerText='End interview'; +// } +// say.onclick=()=>{ +// speechSynthesis.cancel(); +// speechSynthesis.speak(question); +// } +// // addquestion.click() +// //for downloading +// save.onclick=()=>{ +// downloader.href=response.src; +// downloader.click(); +// } +// getAll('[name=voice]').forEach(v=>{ +// v.onchange=()=>{voice=speechSynthesis.getVoices()[+v.value]} +// }) diff --git a/index.html b/index.html index 71a97d1..dff9b7a 100644 --- a/index.html +++ b/index.html @@ -1,70 +1,96 @@ - + + + + + + AI interview + + - - - AI interview - - - - -

      AI interview

      -
      -
      - Questions the AI should ask you - + +
      +
      +
      + + + + + +
      -
        -
        - Input text to say after interview: - +

        Input a question, please!

        + +

        AI interview

        +
        +
        + Questions the AI should ask you + +
        +
          +
          + + + + +
          +
          + + +
          +
          +

          Choose Voice:

          +
          + + +
          +
          +
          -
          -

          Choose Voice:

          - - - +
          + + + +
          - -

          - -
          -
          -
          - -
          - - - -
          - +
          +

          + + +
          +
          + + + + + + + + +
          Your Responses
          QuestionsAnswers
          + +
          +
          + +
          -
          -

          - - -
          -
          - - - - - - - - -
          Your Responses
          QuestionsAnswers
          -
          - - -
          - - - - - - + + + + + \ No newline at end of file diff --git a/script.js b/scripts.js similarity index 100% rename from script.js rename to scripts.js diff --git a/styles.css b/styles.css index 8e2a5aa..13416c1 100644 --- a/styles.css +++ b/styles.css @@ -153,40 +153,4 @@ th{color: darkblue; text-align: -webkit-auto;} button{font-size: 1em; height: fit-content} } - /* loading */ -#loading, #loading:before{ - width: 80px; - height: 80px; - border: none; - position: fixed; -/* display: none; */ - top: calc(50vh - 40px); - left: calc(50vw - 40px); z-index: 199; - margin: 0; -} -#loading:before{ - content: ''; - width: 1000%; height: 1000%; - top: 0; left: 0; border-radius: 0; - background: rgb(0 0 0 / 60%); -} -body #loading>div{ - width: 20px; height: 20px; border: none; background: white; - top: 0; left: calc(50% - 10px);var(--x); position: absolute; -animation: blink 1s cubic-bezier(0, 0, 1, -0.12) infinite; - opacity: 0; z-index: 200; border-radius: 40px; - padding: 0; margin: 0; -} -@keyframes blink{ - 0%{opacity: 1} - 50%{opacity: 0} -} -#c0{transform: translate(0px, 0px);} -#c1{transform: translate(20px, 11px);} -#c2{transform: translate(30px, 30px)} -#c3{transform: translate(20px, 50px)} -#c4{transform: translate(0px, 60px)} -#c5{transform: translate(-20px, 50px)} -#c6{transform: translate(-30px, 30px)} -#c7{transform: translate(-20px, 11px);} -/* end loading */ \ No newline at end of file + \ No newline at end of file diff --git a/web.config b/web.config deleted file mode 100644 index 6c8e9b0..0000000 --- a/web.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/webint.css b/webint.css index eacc50e..c06f116 100644 --- a/webint.css +++ b/webint.css @@ -1,14 +1,19 @@ +/* General */ *{ transition: .2s; + clear: both; + /* VARIABLES */ + --color: lightblue; + --b: 1px solid var(--color); + --usevideo: flex; + /* end VARIABLES */ } body{ - font: 1.2rem math; + font: 1.4rem math; display: flex; flex-flow: column; align-items: center; - --color: lightblue; - --b: 1px solid var(--color); gap: 10px; margin: 30px; } @@ -24,15 +29,27 @@ button{ display: flex; align-items: center; justify-content: center; + box-sizing: border-box; /* box-sizing: content-box; */ } +button:hover, button:active{ + padding: 10px; + border: 1px solid lightblue; + border-radius: 1em; +} +[disabled]{ + filter: blur(1px) grayscale(.5); +} + [type="text"]{ padding: 7px; - border: var(--b); - border-radius: .7em; + border: none; + border-bottom: var(--b); + border-width: 2px; width: fit-content; color: gray; + font-size: 0.7em; } [type="text"]:hover{ border-color: blue @@ -42,11 +59,11 @@ button{ outline: none; } - -button:hover, button:active{ - padding: 10px; - border: 1px solid lightblue; - border-radius: 1em; +/* More specific general */ +#REFRESHER{ + position: absolute; + float: right; + align-self: flex-end; } h2{ @@ -55,7 +72,68 @@ h2{ padding: 5px; } +#ERRORS{ + color: darkred; + font-size: 0.9em; + margin: 0; + padding: 0; + letter-spacing: 0.1em; +} + +/* loading */ +#loading, #loading:before{ + width: 80px; + height: 80px; + border: none; + position: fixed; + top: calc(50vh - 40px); + left: calc(50vw - 40px); z-index: 199; + margin: 0; +} +#loading:before{ + content: ''; + width: 1000%; + height: 1000%; + top: 0; + left: 0; + border-radius: 0; + background: rgb(0 0 0 / 60%); +} +body #loading>div{ + width: 20px; + height: 20px; + border: none; + background: white; + top: 0; + left: calc(50% - 10px); + position: absolute; + opacity: 0; + z-index: 200; + border-radius: 40px; + padding: 0; + margin: 0; + animation: blink 1s cubic-bezier(0, 0, 1, -0.12) infinite; +} +@keyframes blink{ + 0%{opacity: 1} + 50%{opacity: 0} +} +#c0{transform: translate(0px, 0px);} +#c1{transform: translate(20px, 11px);} +#c2{transform: translate(30px, 30px)} +#c3{transform: translate(20px, 50px)} +#c4{transform: translate(0px, 60px)} +#c5{transform: translate(-20px, 50px)} +#c6{transform: translate(-30px, 30px)} +#c7{transform: translate(-20px, 11px);} +/* end loading */ + + +/* end More specific general */ + +/* end General */ +/* SETUP SCREEN */ #questionslist{ display: flex; flex-flow: column; @@ -75,8 +153,28 @@ h2{ font-size: 1.2rem; } +/* end SETUP SCREEN */ + +/* VIDEOINTERVIEW SCREEN */ +/* end VIDEOINTERVIEW SCREEN */ + +/* TEXTINTERVIEW SCREEN */ +/* end TEXTINTERVIEW SCREEN */ + + + +/* VIDEORESPONSE SCREEN */ +/* end VIDEORESPONSE SCREEN */ + + +/* TEXTRESPONSE SCREEN */ +/* end TEXTRESPONSE SCREEN */ + + + +/* Do a 'share interview' feature. save all questions to a json, save voice @@ -87,3 +185,4 @@ or save in queries that can be read (will be too long) or reroute by bitly +*/ \ No newline at end of file From fd2899623f5fa2d31db4a291ec397d7a8c59b9bb Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Sat, 20 Apr 2024 19:30:39 -0500 Subject: [PATCH 03/19] loading OKAY --- classes.js | 46 +++++++++++++++++++++++++++++++ funcs.js | 15 +++-------- index.html | 4 +-- scripts.js | 79 +++++++++++++----------------------------------------- setup.js | 54 ++++++++++++++++++------------------- styles.css | 6 ++--- webint.css | 24 ++++++++--------- 7 files changed, 112 insertions(+), 116 deletions(-) create mode 100644 classes.js diff --git a/classes.js b/classes.js new file mode 100644 index 0000000..9550879 --- /dev/null +++ b/classes.js @@ -0,0 +1,46 @@ +class Question{ + constructor(question){ + this.question = question; + this.build() + } +} + + +function makeQuestion(question, index) { + let questionHolder = make('li'); + [['span', 'question', question], + ['button', 'removebutton', 'X']].forEach(e=>{ + questionHolder.appendChild((questionHolder[e[1]]=make(e[0]))).className=e[1]; + questionHolder[e[1]].textContent=e[2]; + //appendChild would return the element so you can add a className + }); + [['up', '/\\'], ['down', '\\/']].forEach((a)=>{ + questionHolder.upanddown + .appendChild(questionHolder[a[0]]=make('button')).className=a[0]; + questionHolder[a[0]].textContent=a[1] + }); + questionHolder.question.contentEditable=true;//make contentEditable + questionslist.append(questionHolder);//add to DOM + //start filling in + questionHolder.questionnumber.textContent=index; + questionHolder.question.value=question; + //events + questionHolder.removebutton.onclick=()=>questionHolder.remove();//for deleting the question + questionHolder.upanddown.onclick=()=>{ + if (event.target.parentElement!=questionHolder.upanddown)return;//so that I can use ternary ifelse + let dir = event.target.className; + (event.target.className=='up') + ?(questionslist.firstElementChild!=questionHolder) + &&questionslist + .insertBefore(questionHolder, questionHolder.previousElementSibling) + :(questionslist.lastElementChild!=questionHolder) + &&((questionslist.lastElementChild + .previousElementSibling==questionHolder) + ?questionslist.appendChild(questionHolder) + :questionslist.insertBefore(questionHolder + , questionHolder.nextElementSibling.nextElementSibling) + ) + }; + questionHolder.onclick=()=>questionslist.querySelectorAll('.questionnumber').forEach((n, i)=>n.textContent=i+1); + questionHolder.question.focus() +} \ No newline at end of file diff --git a/funcs.js b/funcs.js index 1469a46..ea37924 100644 --- a/funcs.js +++ b/funcs.js @@ -1,16 +1,9 @@ -//make, get, identify, getall, randbtw +// dom functions let make = (name='div')=>document.createElement(name) , get = (id)=>document.getElementById(id) , getE = (selector,value)=>document.querySelector(`[${selector}=${value}]`) , getS = (query)=>document.querySelector(query) - , getAll = (query)=>[...document.querySelectorAll(query)]; -let identify = ()=>getAll('[id]').forEach(i=>window[i.id] = i) + , getAll = (query)=>[...document.querySelectorAll(query)] + , identify = ()=>getAll('[id]').forEach(i=>window[i.id] = i) , add = (what,to=document.body)=>to.appendChild(what) - , bx = (who)=>who.getBoundingClientRect(); - -function randBtw(x=0, y=0, prec=0) { - let n = `${(y - x + 1) * Math.random() + x}`; - let s = n.split('.') - , N = s[0] + s[1].slice(0, prec) - return Number(N) -} + , bx = (who)=>who.getBoundingClientRect(); \ No newline at end of file diff --git a/index.html b/index.html index dff9b7a..29cbc15 100644 --- a/index.html +++ b/index.html @@ -12,7 +12,6 @@
          -
          @@ -88,7 +87,8 @@

          Choose Voice:

          - + + diff --git a/scripts.js b/scripts.js index b22a364..db0a5cd 100644 --- a/scripts.js +++ b/scripts.js @@ -1,63 +1,20 @@ -identify() -class Question{ - constructor(question){ - this.question = question; - this.build() - } -} -function makeQuestion(question, index) { - let questionHolder = make('li'); - [['span', 'question', question], - ['button', 'removebutton', 'X']].forEach(e=>{ - questionHolder.appendChild((questionHolder[e[1]]=make(e[0]))).className=e[1]; - questionHolder[e[1]].textContent=e[2]; - //appendChild would return the element so you can add a className - }); - [['up', '/\\'], ['down', '\\/']].forEach((a)=>{ - questionHolder.upanddown - .appendChild(questionHolder[a[0]]=make('button')).className=a[0]; - questionHolder[a[0]].textContent=a[1] - }); - questionHolder.question.contentEditable=true;//make contentEditable - questionslist.append(questionHolder);//add to DOM - //start filling in - questionHolder.questionnumber.textContent=index; - questionHolder.question.value=question; - //events - questionHolder.removebutton.onclick=()=>questionHolder.remove();//for deleting the question - questionHolder.upanddown.onclick=()=>{ - if (event.target.parentElement!=questionHolder.upanddown)return;//so that I can use ternary ifelse - let dir = event.target.className; - (event.target.className=='up') - ?(questionslist.firstElementChild!=questionHolder) - &&questionslist - .insertBefore(questionHolder, questionHolder.previousElementSibling) - :(questionslist.lastElementChild!=questionHolder) - &&((questionslist.lastElementChild - .previousElementSibling==questionHolder) - ?questionslist.appendChild(questionHolder) - :questionslist.insertBefore(questionHolder - , questionHolder.nextElementSibling.nextElementSibling) - ) - }; - questionHolder.onclick=()=>questionslist.querySelectorAll('.questionnumber').forEach((n, i)=>n.textContent=i+1); - questionHolder.question.focus() -} +// Turn all elements with ID into variables +identify(); + +// initialize the loading element, that blocks the screen and all (function loader(){ - window.loading = make(); loading.id = 'loading'; - for (let n = 0; n<8; n++){ - let c = make(); c.id = 'c'+n; - c.style.animationDelay = n/8+'s'; -// use other numbers appart from .125 to see effects; - loading.appendChild(c); loading.hidden = 1; - } - document.body.appendChild(loading); -})(); -Object.defineProperty(loading, 'loading', { - set: function (b) { - eval(b)?document.body.appendChild(loading):loading.remove(); - }, - get: function () { - return loading.isConnected; + let loading; + (loading = make()).id = "LOADING"; + showLoading = () => void add(loading); + hideLoading = () => loading.remove(); + isPageLoading = () => loading.isConnected; + const N = 10 + for (let n = 0; n < N; n++){ + let c; + (c = make()).id = 'c'+n; + c.style.animationDelay = n/N+'s'; + // use other numbers appart from .1 to see effects; + // will have to change animation-duration and dimensions too + loading.append(c); } -}) \ No newline at end of file +})(); \ No newline at end of file diff --git a/setup.js b/setup.js index 43e3e3f..ccc2a91 100644 --- a/setup.js +++ b/setup.js @@ -1,29 +1,29 @@ -//start from the top -// first get the saved questions if any -let baseli = getS('li'), //the base for adding questions -questions = localStorage.questions && JSON.parse( - localStorage.questions), currentQueston - , index = 0, answers = [], userMedia - , recorder, stream, voices = speechSynthesis.getVoices() - , voice, question, downloader = make('a'); -downloader.download = 'interview.mp4'; -if (questions) { - questions.forEach((q,i)=>{ - makeQuestion(q, 1 + i) - }) -} -function mov() { +// //start from the top +// // first get the saved questions if any +// let baseli = getS('li'), //the base for adding questions +// questions = localStorage.questions && JSON.parse( +// localStorage.questions), currentQueston +// , index = 0, answers = [], userMedia +// , recorder, stream, voices = speechSynthesis.getVoices() +// , voice, question, downloader = make('a'); +// downloader.download = 'interview.mp4'; +// if (questions) { +// questions.forEach((q,i)=>{ +// makeQuestion(q, 1 + i) +// }) +// } +// function mov() { - p.then(mediaStream=>{ - m = MediaRecorder; - video.onloadedmetadata = (x)=>{ - confirm('play?') && video.play(); - a.push(x) - } - MediaRecorder.start(); - }); +// p.then(mediaStream=>{ +// m = MediaRecorder; +// video.onloadedmetadata = (x)=>{ +// confirm('play?') && video.play(); +// a.push(x) +// } +// MediaRecorder.start(); +// }); - p.catch(err=>console.log(err)) -} -// startbutton.onclick = mov -loading.loading = 0; +// p.catch(err=>console.log(err)) +// } +// // startbutton.onclick = mov +// loading.loading = 0; diff --git a/styles.css b/styles.css index 13416c1..11cd669 100644 --- a/styles.css +++ b/styles.css @@ -39,7 +39,7 @@ li, label{ margin-bottom: 10px; display: flex; gap: 10px; padding: 10px 15px; - padding-right: ; + /* padding-right: ; */ background: aliceblue; align-items: center; justify-content: space-evenly; @@ -50,14 +50,14 @@ li, label{ border: 1px solid blue; } #shouldusevideo{scale: 3} -#setup #ondout{margin: ;padding: 10px 5px} +/* #setup #ondout{margin: padding: 10px 5px} */ #voicechoices>label{ align-self: end; } #voicechoices input{ scale: 1.5; border: 1px solid blue; } -#voiceschoices h4{align-self: } +/* #voiceschoices h4{align-self: } */ button{ background: #0078d4; color: white; border-color: aliceblue; diff --git a/webint.css b/webint.css index c06f116..a5b6518 100644 --- a/webint.css +++ b/webint.css @@ -80,8 +80,8 @@ h2{ letter-spacing: 0.1em; } -/* loading */ -#loading, #loading:before{ +/* LOADING */ +#LOADING, #LOADING:before{ width: 80px; height: 80px; border: none; @@ -90,7 +90,7 @@ h2{ left: calc(50vw - 40px); z-index: 199; margin: 0; } -#loading:before{ +#LOADING:before{ content: ''; width: 1000%; height: 1000%; @@ -99,20 +99,20 @@ h2{ border-radius: 0; background: rgb(0 0 0 / 60%); } -body #loading>div{ - width: 20px; - height: 20px; +#LOADING>div{ + width: 16px; + height: 16px; + border-radius: 32px; + padding: 0; + margin: 0; border: none; background: white; + position: absolute; top: 0; left: calc(50% - 10px); - position: absolute; opacity: 0; z-index: 200; - border-radius: 40px; - padding: 0; - margin: 0; - animation: blink 1s cubic-bezier(0, 0, 1, -0.12) infinite; + animation: blink 0.8s cubic-bezier(0, 0, 1, -0.12) infinite; } @keyframes blink{ 0%{opacity: 1} @@ -126,7 +126,7 @@ body #loading>div{ #c5{transform: translate(-20px, 50px)} #c6{transform: translate(-30px, 30px)} #c7{transform: translate(-20px, 11px);} -/* end loading */ +/* end LOADING */ /* end More specific general */ From 539f16c2fed8d575da470efa4fd3b59801c7e6a7 Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Sat, 20 Apr 2024 20:41:49 -0500 Subject: [PATCH 04/19] styling nice (to me anyway) --- funcs.js | 10 +++++- index.html | 20 ++++++------ webint.css | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 108 insertions(+), 16 deletions(-) diff --git a/funcs.js b/funcs.js index ea37924..bf00c92 100644 --- a/funcs.js +++ b/funcs.js @@ -6,4 +6,12 @@ let make = (name='div')=>document.createElement(name) , getAll = (query)=>[...document.querySelectorAll(query)] , identify = ()=>getAll('[id]').forEach(i=>window[i.id] = i) , add = (what,to=document.body)=>to.appendChild(what) - , bx = (who)=>who.getBoundingClientRect(); \ No newline at end of file + , bx = (who)=>who.getBoundingClientRect() + , show = (what) => what.style.display="" + , hide = (what) => what.style.display="none"; + + +// switch screen +function switchScreen(screenID){ + get(screenID).style.display = "" +} \ No newline at end of file diff --git a/index.html b/index.html index 29cbc15..5bae640 100644 --- a/index.html +++ b/index.html @@ -12,17 +12,17 @@
          -
          - +
          + - - +
          @@ -33,7 +33,7 @@

          AI interview

          Questions the AI should ask you - +
            @@ -57,7 +57,7 @@

            Choose Voice:

            - +
            @@ -80,11 +80,11 @@

            Choose Voice:

            Answers - +
            - +
            diff --git a/webint.css b/webint.css index a5b6518..b0684ba 100644 --- a/webint.css +++ b/webint.css @@ -18,10 +18,15 @@ body{ margin: 30px; } -button{ +[disabled]{ + filter: blur(1px) grayscale(.5); +} + +/* buttons */ +button, .say{ color: var(--color); background: transparent; - font-size: 1rem; + font-size: 0.8em; border: thin lightblue; padding: 5px; cursor: pointer; @@ -30,18 +35,51 @@ button{ align-items: center; justify-content: center; box-sizing: border-box; + text-transform: uppercase; /* box-sizing: content-box; */ } button:hover, button:active{ padding: 10px; border: 1px solid lightblue; - border-radius: 1em; + border-radius: 0.8em; } -[disabled]{ - filter: blur(1px) grayscale(.5); +button:active{ + background-color: var(--color); + color: white; +} + +/* icon buttons */ +/* .icon{ + padding: 0 +} */ +.icon:hover, .icon:focus, .icon:active{ + border-radius: 0; +} +/* end icon buttons */ + +/* major buttons */ +.major{ + background: var(--color); + color: white; + font-size: 1em; + border-radius: 0.5em; + padding: 10px 20px; + margin: 5px; } +.major:hover, .major:active{ + padding: 10px 20px; + background-color: blue; + border-radius: 0.5em; +} +.major:active{ + background-color: rgb(0, 0, 127); +} +/* end major buttons */ +/* end buttons */ + +/* input text */ [type="text"]{ padding: 7px; border: none; @@ -58,6 +96,7 @@ button:hover, button:active{ border-color: darkblue; outline: none; } +/* end input text */ /* More specific general */ #REFRESHER{ @@ -128,6 +167,51 @@ h2{ #c7{transform: translate(-20px, 11px);} /* end LOADING */ +/* INTERVIEW CONTROLS */ +#CONTROLS{ + display: flex; + flex-flow: row; + align-items: center; + justify-content: space-between; + gap: 5px; +} +#CONTROLS>button, .say{ + border-right: var(--b); + gap: 0px +} +.say>*{ + gap: 0px; + margin: 0; + font-size: 1em; +} +#CONTROLS select{ + padding: 2px 15px 2px 10px; + background-color: var(--color); + color: white; + border: none; + border-radius: 0.2em; + /* margin-left: 0.5em; */ + width: 1em; + cursor: pointer; + /* transform: scaleX(-1); */ + /* width: 1em; */ + /* display: none; */ +} +#CONTROLS select:active{ + background-color: blue; +} +select:active, select:focus{ + outline: none; +} +#CONTROLS option{ + text-transform: uppercase; + border-radius: 1em; + padding: 51px; +} +#CONTROLS option:hover{ + background-color: red; +} +/* end INTERVIEW CONTROLS */ /* end More specific general */ From 5616b87b0a0c931d859e45189dfa18ccd84f1a8b Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Mon, 22 Apr 2024 22:43:19 -0500 Subject: [PATCH 05/19] made Switch (should turn to Toggle later) class. --- classes.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/classes.js b/classes.js index 9550879..baf18bd 100644 --- a/classes.js +++ b/classes.js @@ -5,6 +5,31 @@ class Question{ } } +class Switch{ + constructor(where){ + this.container = where; + this.build(); + this.event(); + } + build(){ + add((this.switch = make()) + , add((this.holder = make()), this.container) + ).className = "switch"; + this.holder.className = "switchold off"; + this.switch.tabIndex = -1 + } + event(){ + this.switch.onclick = (event)=>{ + event.preventDefault(); + this.holder.classList.contains("off") + ?this.holder.classList.remove("off") + :this.holder.classList.add("off"); + } + } + on(){ + return !this.holder.classList.contains("off") + } +} function makeQuestion(question, index) { let questionHolder = make('li'); From f3934b5cafe0ae65ad26d2470c42eb74370dca47 Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Mon, 22 Apr 2024 22:43:55 -0500 Subject: [PATCH 06/19] more markuping and styling (started styling SETUP screen) --- index.html | 23 +++++++------ scripts.js | 5 ++- webint.css | 97 ++++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 97 insertions(+), 28 deletions(-) diff --git a/index.html b/index.html index 5bae640..9869cd4 100644 --- a/index.html +++ b/index.html @@ -11,7 +11,7 @@ -
            + -

            Input a question, please!

            +

            AI interview

            @@ -35,16 +35,19 @@

            AI interview

            Questions the AI should ask you
            -
              -
              - - - - +
                +
              • + + + +
              • +
              +
              + Toggle Video:
              - +

              Choose Voice:

              @@ -87,8 +90,8 @@

              Choose Voice:

              - + diff --git a/scripts.js b/scripts.js index db0a5cd..6c3846d 100644 --- a/scripts.js +++ b/scripts.js @@ -17,4 +17,7 @@ identify(); // will have to change animation-duration and dimensions too loading.append(c); } -})(); \ No newline at end of file +})(); + +// create switch inside SHOULDVIDEO +const videoSwitch = new Switch(SHOULDVIDEO) \ No newline at end of file diff --git a/webint.css b/webint.css index b0684ba..fbbc191 100644 --- a/webint.css +++ b/webint.css @@ -1,6 +1,6 @@ /* General */ *{ - transition: .2s; + transition: 0.1s; clear: both; /* VARIABLES */ --color: lightblue; @@ -50,11 +50,18 @@ button:active{ } /* icon buttons */ -/* .icon{ - padding: 0 -} */ +.icon{ + width: 2em; + height: 2em; + text-align: center; + display: flex; + align-items: center; + justify-content: center; + +} .icon:hover, .icon:focus, .icon:active{ - border-radius: 0; + padding: 0; + border-radius: 1em; } /* end icon buttons */ @@ -87,7 +94,7 @@ button:active{ border-width: 2px; width: fit-content; color: gray; - font-size: 0.7em; + font-size: 0.9em; } [type="text"]:hover{ border-color: blue @@ -218,25 +225,81 @@ select:active, select:focus{ /* end General */ /* SETUP SCREEN */ -#questionslist{ +#SETUPDESC{ + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: var(--b); +} +/* #SETUPDESC>span{ + border-bottom: var(--b); +} */ +#ADDQUESTION{ + font-size: 1em; +} +#QUESTIONLIST{ display: flex; flex-flow: column; gap: 5px; - list-style-type: armenian; + list-style-type: symbols(1,2,3); + list-style-position: outside; } -#questionslist>li{ +#QUESTIONLIST>li{ /* display: flex; */ - gap: 5px; + flex-flow: row; + /* gap: 5px; */ + align-items: center; + position: relative; + /* border-bottom: var(--b); */ } - -#questionslist>li button, #setupdesc button{ - width: 30px; - height: 30px; - float: right; - font-size: 1.2rem; +#QUESTIONLIST>li [type="text"]{ + /* justify-self: flex-start; */ + display: inline-block; + width: 70%; +} +*{ + --x: #QUESTIONLIST>li span; +} +--x{ + display: none; + color: red; +} +#QUESTIONLIST>li button{ + float: right; clear: none; + /* display: none; */ +} +#SHOULDVIDEO{ + display: flex; + gap: 10px; + align-items: center; +} +.switchold{ + width: 2em; + height: 1em; + display: flex; + flex-flow: row; + justify-content: end; + border-radius: 40px; + border: var(--b); + border-width: 3px; + align-items: center; + padding: 2px; +} +.switchold.off{ + justify-content: start; + background-color: black; +} +.switch{ + background-color: lightblue; + width: 1em; + height: 1em; + border-radius: 1em; + cursor: pointer; +} +.switch:hover{ + filter: drop-shadow(2px 4px 6px black); } - /* end SETUP SCREEN */ /* VIDEOINTERVIEW SCREEN */ From ee9a4d687bd7fcdb7fd142c1875a12474ce505c9 Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Tue, 23 Apr 2024 14:48:12 -0500 Subject: [PATCH 07/19] made the question class --- classes.js | 94 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/classes.js b/classes.js index baf18bd..fb49b1a 100644 --- a/classes.js +++ b/classes.js @@ -1,22 +1,56 @@ class Question{ - constructor(question){ - this.question = question; - this.build() + constructor(question="What do you want to be asked?"){ + this._question = question; + this.build(); + this.event(); + } + get question(){ + return this.text.value; + } + set question(ask){ + this.text.value = ask; + } + build(){ + add( + (this.text = make("input")) + , add(this.box = make("li"), QUESTIONLIST) + ).value = this._question; + this.text.type = "text"; + + ["mover", "deleter"].forEach((type, i)=>{ + add( + (this[type] = make("button")), this.box + ).className = "icon"; + this[type].textContent = Question.iconValues[i]; + }); } + event(){ + this.deleter.onclick=()=>this.delete(); + } + delete(){ + this.box.remove(); + Question.deletedQuestions.push(this); + } + restore(){ + QUESTIONLIST.append(this.box); + } + static iconValues = ['<>', 'X']; + static deletedQuestions = []; } class Switch{ - constructor(where){ - this.container = where; + constructor(where, obj, property, values){ + [this.container, this.obj, this.property, this.values] = arguments this.build(); this.event(); + Switch.swtiches.push(this); } build(){ add((this.switch = make()) , add((this.holder = make()), this.container) ).className = "switch"; this.holder.className = "switchold off"; - this.switch.tabIndex = -1 + this.switch.tabIndex = -1; } event(){ this.switch.onclick = (event)=>{ @@ -24,48 +58,18 @@ class Switch{ this.holder.classList.contains("off") ?this.holder.classList.remove("off") :this.holder.classList.add("off"); + this.action(); } } on(){ return !this.holder.classList.contains("off") } -} - -function makeQuestion(question, index) { - let questionHolder = make('li'); - [['span', 'question', question], - ['button', 'removebutton', 'X']].forEach(e=>{ - questionHolder.appendChild((questionHolder[e[1]]=make(e[0]))).className=e[1]; - questionHolder[e[1]].textContent=e[2]; - //appendChild would return the element so you can add a className - }); - [['up', '/\\'], ['down', '\\/']].forEach((a)=>{ - questionHolder.upanddown - .appendChild(questionHolder[a[0]]=make('button')).className=a[0]; - questionHolder[a[0]].textContent=a[1] - }); - questionHolder.question.contentEditable=true;//make contentEditable - questionslist.append(questionHolder);//add to DOM - //start filling in - questionHolder.questionnumber.textContent=index; - questionHolder.question.value=question; - //events - questionHolder.removebutton.onclick=()=>questionHolder.remove();//for deleting the question - questionHolder.upanddown.onclick=()=>{ - if (event.target.parentElement!=questionHolder.upanddown)return;//so that I can use ternary ifelse - let dir = event.target.className; - (event.target.className=='up') - ?(questionslist.firstElementChild!=questionHolder) - &&questionslist - .insertBefore(questionHolder, questionHolder.previousElementSibling) - :(questionslist.lastElementChild!=questionHolder) - &&((questionslist.lastElementChild - .previousElementSibling==questionHolder) - ?questionslist.appendChild(questionHolder) - :questionslist.insertBefore(questionHolder - , questionHolder.nextElementSibling.nextElementSibling) - ) - }; - questionHolder.onclick=()=>questionslist.querySelectorAll('.questionnumber').forEach((n, i)=>n.textContent=i+1); - questionHolder.question.focus() + action(){ + // all switches will set a property of something + // between to two values (flex/none) (true/false) + // 1/0 + let [obj, property, values] = [this.obj, this.property, this.values] + obj[property] = obj[property] == values[0]?values[1]:values[0] + } + static swtiches = []; } \ No newline at end of file From dab8f36b3b367f3b733bee19a3ef32e3d080bbda Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Tue, 23 Apr 2024 14:48:30 -0500 Subject: [PATCH 08/19] more styling --- index.html | 37 +++++++++++++++++-------------------- webint.css | 17 +++++++++++++++-- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/index.html b/index.html index 9869cd4..1a64ed1 100644 --- a/index.html +++ b/index.html @@ -35,29 +35,26 @@

              AI interview

              Questions the AI should ask you
              -
                -
              • - - - -
              • -
              +
                Toggle Video:
                -
                - - -
                -
                -

                Choose Voice:

                -
                - - +
                +
                + + +
                +
                + Choose Voice: +
                + + + +
                diff --git a/webint.css b/webint.css index fbbc191..2ac059b 100644 --- a/webint.css +++ b/webint.css @@ -73,6 +73,9 @@ button:active{ border-radius: 0.5em; padding: 10px 20px; margin: 5px; + text-align: center; + display: block; + justify-self: center; } .major:hover, .major:active{ padding: 10px 20px; @@ -231,6 +234,13 @@ select:active, select:focus{ align-items: center; border-bottom: var(--b); } +#SETUP{ + display: flex; + flex-flow: column; + justify-content: center; + gap: 10px; + /* border: 1px solid black; */ +} /* #SETUPDESC>span{ border-bottom: var(--b); } */ @@ -241,8 +251,7 @@ select:active, select:focus{ display: flex; flex-flow: column; gap: 5px; - list-style-type: symbols(1,2,3); - list-style-position: outside; + list-style-type: decimal; } #QUESTIONLIST>li{ @@ -300,6 +309,10 @@ select:active, select:focus{ .switch:hover{ filter: drop-shadow(2px 4px 6px black); } + +.withoutVideo{ + display: var(--usevideo); +} /* end SETUP SCREEN */ /* VIDEOINTERVIEW SCREEN */ From 7aae46caecfda7fa602d15ce37047d1b1b359834 Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Tue, 23 Apr 2024 14:48:41 -0500 Subject: [PATCH 09/19] start --- events.js | 20 +++++++++++++------- scripts.js | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/events.js b/events.js index 8c38375..282d43c 100644 --- a/events.js +++ b/events.js @@ -1,11 +1,17 @@ // //all functions and variables if (except all event based) here -// onbeforeunload=()=>{ -// speechSynthesis.cancel(); -// localStorage.questions = JSON.stringify([...questionslist.children].map(i=>i.querySelector('.question').innerText)); -// } -// addquestion.onclick=()=>{ -// makeQuestion('Write a question here, write a question here', questionslist.childElementCount+1) -// } + +ADDQUESTION.onclick=()=>new Question + +for (let index = 0; index < 5; index++) { + new Question + +} + +onbeforeunload=()=>{ + speechSynthesis.cancel(); + localStorage.questions = JSON.stringify([...QUESTIONLIST.children].map(i=>i.querySelector('input').innerText)); +} + // startbutton.onclick=()=>{ // if (!(questions=[...questionslist.children].map(i=>i.querySelector('.question').innerText)).length) return errors.innerHTML = 'No question added, Please add at least one questions to proceed'; // if (!confirm('Proceed?')) return diff --git a/scripts.js b/scripts.js index 6c3846d..55cda6f 100644 --- a/scripts.js +++ b/scripts.js @@ -19,5 +19,48 @@ identify(); } })(); + // create switch inside SHOULDVIDEO -const videoSwitch = new Switch(SHOULDVIDEO) \ No newline at end of file +const videoSwitch = new Switch(SHOULDVIDEO + , VIDEOSETTINGS.style, "display", ["none", ""]) + + +// function makeQuestion(question) { +// } +// let questionHolder = make('li'); +// [['span', 'question', question], +// ['button', 'removebutton', 'X']].forEach(e=>{ +// questionHolder.appendChild((questionHolder[e[1]]=make(e[0]))).className=e[1]; +// questionHolder[e[1]].textContent=e[2]; +// //appendChild would return the element so you can add a className +// }); +// [['up', '/\\'], ['down', '\\/']].forEach((a)=>{ +// questionHolder.upanddown +// .appendChild(questionHolder[a[0]]=make('button')).className=a[0]; +// questionHolder[a[0]].textContent=a[1] +// }); +// questionHolder.question.contentEditable=true;//make contentEditable +// questionslist.append(questionHolder);//add to DOM +// //start filling in +// questionHolder.questionnumber.textContent=index; +// questionHolder.question.value=question; +// //events +// questionHolder.removebutton.onclick=()=>questionHolder.remove();//for deleting the question +// questionHolder.upanddown.onclick=()=>{ +// if (event.target.parentElement!=questionHolder.upanddown)return;//so that I can use ternary ifelse +// let dir = event.target.className; +// (event.target.className=='up') +// ?(questionslist.firstElementChild!=questionHolder) +// &&questionslist +// .insertBefore(questionHolder, questionHolder.previousElementSibling) +// :(questionslist.lastElementChild!=questionHolder) +// &&((questionslist.lastElementChild +// .previousElementSibling==questionHolder) +// ?questionslist.appendChild(questionHolder) +// :questionslist.insertBefore(questionHolder +// , questionHolder.nextElementSibling.nextElementSibling) +// ) +// }; +// questionHolder.onclick=()=>questionslist.querySelectorAll('.questionnumber').forEach((n, i)=>n.textContent=i+1); +// questionHolder.question.focus() +// } From 96073b6241a54013c36badd8c682bd9deccb3b06 Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Wed, 24 Apr 2024 02:47:19 -0500 Subject: [PATCH 10/19] to some point, done with setup --- classes.js | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++- events.js | 36 +++++++++++++++--- funcs.js | 3 +- index.html | 24 +++++------- scripts.js | 49 ++++++++++++------------- webint.css | 70 +++++++++++++++++++++++++++++------ 6 files changed, 228 insertions(+), 60 deletions(-) diff --git a/classes.js b/classes.js index fb49b1a..fcf6b57 100644 --- a/classes.js +++ b/classes.js @@ -3,6 +3,7 @@ class Question{ this._question = question; this.build(); this.event(); + Question.questions.push(this); } get question(){ return this.text.value; @@ -23,19 +24,57 @@ class Question{ ).className = "icon"; this[type].textContent = Question.iconValues[i]; }); + ["box", "text", "mover", "deleter"].forEach(dom=>this[dom].obj=this); + this.mover.draggable = true; } event(){ this.deleter.onclick=()=>this.delete(); + this.text.onkeyup=(event)=>{ + event.key=="Enter" && event.ctrlKey && (new Question).text.focus(); + } + this.mover.onkeydown=(event)=>{ + Question.keys.includes(event.key) && event.preventDefault(); + } + this.mover.onkeyup=(event)=>{ + if (Question.keys.includes(event.key) && + this.box[`${Question.keyMap[event.key]}ElementSibling`]){ + event.preventDefault(); + if (event.key.includes("Up")){ + QUESTIONLIST.insertBefore(this.box, this.box.previousElementSibling); + } else{ + QUESTIONLIST.insertBefore(this.box.nextElementSibling, this.box); + } + this.mover.focus(); + } + } + this.mover.ondragstart=(event)=>{ + this.box.classList.add("highlight"); + } + this.mover.ondragend=(event)=>{ + let at = document.elementFromPoint(event.x, event.y); + if (at.obj && at.obj != this){ + QUESTIONLIST.insertBefore(this.box, at.obj.box) + } + this.box.classList.remove("highlight"); + } + // this.mover.onmouse } delete(){ this.box.remove(); + remove(this, Question.questions); Question.deletedQuestions.push(this); } restore(){ QUESTIONLIST.append(this.box); } + static restoreLast(){ + SETUP.checkVisibility() && Question.deletedQuestions.length && Question.deletedQuestions.pop().restore(); + } + static questions = []; static iconValues = ['<>', 'X']; static deletedQuestions = []; + static keyMap = {"ArrowUp": "previous", "ArrowDown": "next"}; + static keys = Object.keys(Question.keyMap); } class Switch{ @@ -49,8 +88,8 @@ class Switch{ add((this.switch = make()) , add((this.holder = make()), this.container) ).className = "switch"; - this.holder.className = "switchold off"; - this.switch.tabIndex = -1; + this.holder.className = "switchold"; + // this.switch.tabIndex = -1; } event(){ this.switch.onclick = (event)=>{ @@ -72,4 +111,67 @@ class Switch{ obj[property] = obj[property] == values[0]?values[1]:values[0] } static swtiches = []; +} + +class Help{ + constructor(){ + this.messages = [ + "Use ctrl+z to restore last delted question" + , "Hit enter on a question box to add another question" + , "etc" + ] + } +} + +class SearchUI{ + // to specific + constructor(where, values){ + [this.container, this._values] = arguments; + this.build(); + this.event(); + } + get values(){ + if (typeof this._values == "function"){ + return this._values(); + } else{ + return this._values; + } + } + build(){ + add((this.searchBox = make("input")) + , add((this.box = make()) + , this.container)).type = "text"; + this.box.className = "searchui"; + add((this.list = make("ul")), this.box).hidden = true; + this.list.size = 20 + } + event(){ + // change onvoice... to event variable/not + speechSynthesis.onvoiceschanged=(event)=>{ + let voices = this.values; + for (let i in voices){ + add(make("li"), this.list).textContent = voices[i].name; + } + } + this.searchBox.onfocus=()=>this.list.hidden=false; + this.searchBox.onblur=()=>setTimeout(()=>this.list.hidden=true, 500); + this.searchBox.oninput=(event)=>{ + [...this.list.children].forEach(child=>{ + child.hidden = !(child.textContent.toLowerCase().includes(this.searchBox.value.toLowerCase())) + }) + } + this.list.onclick=(event)=>{ + event.stopImmediatePropagation(); + event.stopPropagation(); + if (event.target.parentElement == this.list){ + this.searchBox.value = event.target.textContent; + TESTVOICE.test = this.values[this.values.map(i=>i.name).indexOf(this.searchBox.value)]; + } + } + } + get value(){ + if (this.values.includes(this.searchBox.value)){ + return this.searchBox.value; + } + } } \ No newline at end of file diff --git a/events.js b/events.js index 282d43c..0024a60 100644 --- a/events.js +++ b/events.js @@ -1,15 +1,39 @@ // //all functions and variables if (except all event based) here - +onload=()=>{ + // Turn all elements with ID into variables + identify(); + // restore saved questions + restoreSavedQuestions(); + // create a toggle to switch video options + createVideoToggle(); + // create voice search ui + createVoiceSearchUI() +} +// add event listeners +addEventListener("keyup", (event)=>{ + if (event.key == 'b' && event.ctrlKey){ + Question.restoreLast(); + } +}) +// add question button ADDQUESTION.onclick=()=>new Question -for (let index = 0; index < 5; index++) { - new Question - +// restore question button +RESTOREQUESTION.onclick=()=>Question.restoreLast(); + +// TESTing voices +TESTVOICE.onclick =()=>{ + speechSynthesis.cancel(); + if (!TESTVOICE.test) return; + let talk = new SpeechSynthesisUtterance( + `Hi, this is speech synthesis, using ${TESTVOICE.test.name}`); + talk.voice = TESTVOICE.test; + speechSynthesis.speak(talk); } onbeforeunload=()=>{ speechSynthesis.cancel(); - localStorage.questions = JSON.stringify([...QUESTIONLIST.children].map(i=>i.querySelector('input').innerText)); + localStorage.questions = JSON.stringify([...QUESTIONLIST.children].map(q=>q.obj.question)); } // startbutton.onclick=()=>{ @@ -121,3 +145,5 @@ onbeforeunload=()=>{ // getAll('[name=voice]').forEach(v=>{ // v.onchange=()=>{voice=speechSynthesis.getVoices()[+v.value]} // }) + +// add voice recording to use instead of talking out \ No newline at end of file diff --git a/funcs.js b/funcs.js index bf00c92..13a2e0e 100644 --- a/funcs.js +++ b/funcs.js @@ -8,7 +8,8 @@ let make = (name='div')=>document.createElement(name) , add = (what,to=document.body)=>to.appendChild(what) , bx = (who)=>who.getBoundingClientRect() , show = (what) => what.style.display="" - , hide = (what) => what.style.display="none"; + , hide = (what) => what.style.display="none" + , remove = (what, from) => from.splice(from.indexOf(what), 1); // switch screen diff --git a/index.html b/index.html index 1a64ed1..ccd3657 100644 --- a/index.html +++ b/index.html @@ -33,28 +33,24 @@

                AI interview

                Questions the AI should ask you - +
                + + +
                  - Toggle Video: + Toggle video usage:
                  -
                  - Choose Voice: -
                  - - - -
                  +
                  + + Choose Voice: +
                  @@ -73,7 +69,7 @@

                  AI interview

                  - + diff --git a/scripts.js b/scripts.js index 55cda6f..2b6b365 100644 --- a/scripts.js +++ b/scripts.js @@ -1,8 +1,5 @@ -// Turn all elements with ID into variables -identify(); - // initialize the loading element, that blocks the screen and all -(function loader(){ +function loader(){ let loading; (loading = make()).id = "LOADING"; showLoading = () => void add(loading); @@ -17,34 +14,32 @@ identify(); // will have to change animation-duration and dimensions too loading.append(c); } -})(); +}; // create switch inside SHOULDVIDEO -const videoSwitch = new Switch(SHOULDVIDEO - , VIDEOSETTINGS.style, "display", ["none", ""]) +function createVideoToggle(){ + const videoSwitch = new Switch(SHOULDVIDEO + , VIDEOSETTINGS.style, "display", ["none", ""]) +} + +// create search ui for voices +function createVoiceSearchUI(){ + speechSearch = new SearchUI(VOICETHINGS + , ()=>speechSynthesis.getVoices() + // , ()=>["Daniel", "Ogirimah", "Enesi"] + ) +} + +// well... +function restoreSavedQuestions(){ + const QUESTIONS = localStorage.questions?JSON.parse(localStorage.questions):[]; + QUESTIONS.forEach(q=>(new Question(q))); +} // function makeQuestion(question) { -// } -// let questionHolder = make('li'); -// [['span', 'question', question], -// ['button', 'removebutton', 'X']].forEach(e=>{ -// questionHolder.appendChild((questionHolder[e[1]]=make(e[0]))).className=e[1]; -// questionHolder[e[1]].textContent=e[2]; -// //appendChild would return the element so you can add a className -// }); -// [['up', '/\\'], ['down', '\\/']].forEach((a)=>{ -// questionHolder.upanddown -// .appendChild(questionHolder[a[0]]=make('button')).className=a[0]; -// questionHolder[a[0]].textContent=a[1] -// }); -// questionHolder.question.contentEditable=true;//make contentEditable -// questionslist.append(questionHolder);//add to DOM -// //start filling in -// questionHolder.questionnumber.textContent=index; -// questionHolder.question.value=question; -// //events +// } //events // questionHolder.removebutton.onclick=()=>questionHolder.remove();//for deleting the question // questionHolder.upanddown.onclick=()=>{ // if (event.target.parentElement!=questionHolder.upanddown)return;//so that I can use ternary ifelse @@ -64,3 +59,5 @@ const videoSwitch = new Switch(SHOULDVIDEO // questionHolder.onclick=()=>questionslist.querySelectorAll('.questionnumber').forEach((n, i)=>n.textContent=i+1); // questionHolder.question.focus() // } + +// a = new Question \ No newline at end of file diff --git a/webint.css b/webint.css index 2ac059b..0e1a210 100644 --- a/webint.css +++ b/webint.css @@ -91,7 +91,7 @@ button:active{ /* input text */ [type="text"]{ - padding: 7px; + padding: 7px 0; border: none; border-bottom: var(--b); border-width: 2px; @@ -128,6 +128,9 @@ h2{ padding: 0; letter-spacing: 0.1em; } +#ACCESSORIES{ + display: none; +} /* LOADING */ #LOADING, #LOADING:before{ @@ -228,23 +231,24 @@ select:active, select:focus{ /* end General */ /* SETUP SCREEN */ -#SETUPDESC{ - display: flex; - justify-content: space-between; - align-items: center; - border-bottom: var(--b); -} -#SETUP{ +body>div{ display: flex; flex-flow: column; justify-content: center; gap: 10px; /* border: 1px solid black; */ } +#SETUPDESC{ + display: flex; + flex-flow: row; + justify-content: space-between; + align-items: center; + border-bottom: var(--b); +} /* #SETUPDESC>span{ border-bottom: var(--b); } */ -#ADDQUESTION{ +#SETUPDESC>button{ font-size: 1em; } #QUESTIONLIST{ @@ -260,8 +264,14 @@ select:active, select:focus{ /* gap: 5px; */ align-items: center; position: relative; + flex-wrap: nowrap; + max-width: 100%; /* border-bottom: var(--b); */ } +#QUESTIONLIST>li.highlight{ + border: var(--b); + border-radius: 1em; +} #QUESTIONLIST>li [type="text"]{ /* justify-self: flex-start; */ display: inline-block; @@ -275,7 +285,8 @@ select:active, select:focus{ color: red; } #QUESTIONLIST>li button{ - float: right; clear: none; + float: right; clear: left; + outline-color: red; /* display: none; */ } #SHOULDVIDEO{ @@ -310,8 +321,43 @@ select:active, select:focus{ filter: drop-shadow(2px 4px 6px black); } -.withoutVideo{ - display: var(--usevideo); +#VIDEOSETTINGS{ + display: flex; + flex-flow: column; + gap: 10px; +} +#VOICETHINGS{ + display: flex; + gap: 20px; + flex-flow: row; + align-items: center; +} +.searchui{ + display: flex; + flex-flow: column; + /* justify-content: baseline; */ +} +.searchui>ul{ + width: 50%; + font-size: 0.9em; + position: absolute; + margin-top: 2em; + z-index: 199; + padding: 10px; + border: var(--b); + border-radius: 0.5em; + overflow-y: scroll; + background-color: white; + height: 10em; +} +.searchui li{ + cursor: pointer; + padding: 3px; +} +.searchui li:hover{ + padding: 5px; + border: var(--b); + border-radius: 0.5em; } /* end SETUP SCREEN */ From 62eadbecd1956de88954834b29600b63d4f6d5e6 Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Wed, 24 Apr 2024 20:48:34 -0500 Subject: [PATCH 11/19] started interview.js --- classes.js | 97 +++++++++++++++++++++++++++++++++++++++++++++++----- events.js | 44 ++++++++++++++++++++---- funcs.js | 3 +- index.html | 15 +++++--- interview.js | 52 ++++++++++++++++++++++++++++ scripts.js | 41 +++++++++------------- setup.js | 3 +- webint.css | 92 ++++++++++++++++++++++++++++++++++++++++++++----- 8 files changed, 294 insertions(+), 53 deletions(-) create mode 100644 interview.js diff --git a/classes.js b/classes.js index fcf6b57..9eaba1a 100644 --- a/classes.js +++ b/classes.js @@ -52,7 +52,7 @@ class Question{ } this.mover.ondragend=(event)=>{ let at = document.elementFromPoint(event.x, event.y); - if (at.obj && at.obj != this){ + if (at && at.obj && at.obj != this){ QUESTIONLIST.insertBefore(this.box, at.obj.box) } this.box.classList.remove("highlight"); @@ -100,7 +100,7 @@ class Switch{ this.action(); } } - on(){ + get on(){ return !this.holder.classList.contains("off") } action(){ @@ -150,22 +150,27 @@ class SearchUI{ speechSynthesis.onvoiceschanged=(event)=>{ let voices = this.values; for (let i in voices){ - add(make("li"), this.list).textContent = voices[i].name; + add(make("li"), this.list).textContent = voices[i]; } } this.searchBox.onfocus=()=>this.list.hidden=false; - this.searchBox.onblur=()=>setTimeout(()=>this.list.hidden=true, 500); + this.searchBox.addEventListener("blur" + , ()=>setTimeout(()=>this.list.hidden=true, 500)); + this.searchBox.onblur=(event)=>{ + TESTVOICE.test = getVoice(this.searchBox.value); + } this.searchBox.oninput=(event)=>{ [...this.list.children].forEach(child=>{ - child.hidden = !(child.textContent.toLowerCase().includes(this.searchBox.value.toLowerCase())) - }) + child.hidden = !(child.textContent.toLowerCase().includes(this.searchBox.value.toLowerCase())); + }); + this.searchBox.onblur(); } this.list.onclick=(event)=>{ event.stopImmediatePropagation(); event.stopPropagation(); if (event.target.parentElement == this.list){ this.searchBox.value = event.target.textContent; - TESTVOICE.test = this.values[this.values.map(i=>i.name).indexOf(this.searchBox.value)]; + TESTVOICE.test = getVoice(this.searchBox.value); } } } @@ -174,4 +179,80 @@ class SearchUI{ return this.searchBox.value; } } -} \ No newline at end of file +} + +// modals +class Modal{ + constructor(buttons){ + this.buttons = buttons; + this.message = ""; + this.build(); + this.event(); + Modal.modals.push(this); + } + build(){ + add(this.modal = make()).className = "modal"; + add(this.messageBox = make('p'), this.modal); + this.buttons.forEach((button, pos)=>{ + add(this[button] = make("button"), this.modal).textContent = button; + this[button].pos = pos; + }) + } + event(){ + this.modal.onclick=(event)=>{ + if (event.target.nodeName == "BUTTON"){ + this.method(event.target.pos); + this.close(); + } + } + } + changeButtons(buttons){ + this.buttons.forEach((button, pos)=>{ + this[button].textContent = buttons[pos]; + this[button].pos = pos; + this[buttons[pos]] = this[button]; + }) + this.buttons = buttons; + } + open(message, buttons){ + // do not do anything if a modal is already up + if (Modal.showing) { + this.blink(); + return; + }; + showLoading() + if (buttons) this.changeButtons(buttons); + this.messageBox.textContent = message; + this.modal.classList.add("shown"); + this[this.buttons[this.buttons.length-1]].focus(); + // promise + // will be given to the event onclick + return new Promise((resolve)=>this.method = resolve); + } + close(){ + this.modal.classList.remove("shown", "blink"); + hideLoading(); + } + blink(){ + this.modal.classList.add("blink"); + setTimeout(()=>this.modal.classList.remove("blink"), 500); + } + get shown(){ + return this.modal.classList.contains("shown"); + } + static get showing(){ + return Modal.modals.some(modal=>modal.shown); + } + static modals = []; + static alertBox = new Modal(["CLOSE"]); + static confirmBox = new Modal(["CANCEL", "OK"]); +} +function alert(message, buttons){ + return Modal.alertBox.open(message, buttons); +} +function confirm(message, buttons){ + return Modal.confirmBox.open(message, buttons); +} + +// maise: young girl +// make search better by giving properties \ No newline at end of file diff --git a/events.js b/events.js index 0024a60..87a3173 100644 --- a/events.js +++ b/events.js @@ -2,12 +2,23 @@ onload=()=>{ // Turn all elements with ID into variables identify(); + // make LOADING DIV + loader(); + // show only SETUP + switchScreen("SETUP"); // restore saved questions restoreSavedQuestions(); // create a toggle to switch video options createVideoToggle(); // create voice search ui createVoiceSearchUI() + + // initialize SpeechSynthesisUtterance + TALK = new SpeechSynthesisUtterance(); + + // TESTS + // a = alert("Hi!").then(console.log); + videoSwitch.switch.click() } // add event listeners addEventListener("keyup", (event)=>{ @@ -25,10 +36,8 @@ RESTOREQUESTION.onclick=()=>Question.restoreLast(); TESTVOICE.onclick =()=>{ speechSynthesis.cancel(); if (!TESTVOICE.test) return; - let talk = new SpeechSynthesisUtterance( - `Hi, this is speech synthesis, using ${TESTVOICE.test.name}`); - talk.voice = TESTVOICE.test; - speechSynthesis.speak(talk); + say(`Hi, this is speech synthesis, using ${TESTVOICE.test.name}` + , TESTVOICE.test) } onbeforeunload=()=>{ @@ -36,7 +45,30 @@ onbeforeunload=()=>{ localStorage.questions = JSON.stringify([...QUESTIONLIST.children].map(q=>q.obj.question)); } -// startbutton.onclick=()=>{ +STARTBUTTON.onclick=()=>{ + onbeforeunload(); + questions = JSON.parse(localStorage.questions); + if (!questions.length){ + return alert("You have to add at least one question"); + } else if (videoSwitch.on && !speechSearch.value) { + return alert("Please, choose a voice!"); + } + confirm("Are you sure you want to begin?") + .then(resp=>{ + if (resp){ + ( + interview = new Interview( + JSON.parse(localStorage.questions) + , videoSwitch.on + )).start(); + } else{ + alert("Make changes then click START"); + } + }) + // console.log(interview) + // console.log(confirm("Do you want to start the interview")) + // .then(resp=>resp?interview.start():delete interview); +} // if (!(questions=[...questionslist.children].map(i=>i.querySelector('.question').innerText)).length) return errors.innerHTML = 'No question added, Please add at least one questions to proceed'; // if (!confirm('Proceed?')) return // embassy.style.display='flex'; setup.style.display='none'; @@ -146,4 +178,4 @@ onbeforeunload=()=>{ // v.onchange=()=>{voice=speechSynthesis.getVoices()[+v.value]} // }) -// add voice recording to use instead of talking out \ No newline at end of file +// add voice recording to use instead of TALKing out \ No newline at end of file diff --git a/funcs.js b/funcs.js index 13a2e0e..5b816ba 100644 --- a/funcs.js +++ b/funcs.js @@ -14,5 +14,6 @@ let make = (name='div')=>document.createElement(name) // switch screen function switchScreen(screenID){ - get(screenID).style.display = "" + getAll("body>div").forEach(div=>{if (div.id) div.style.display = "none"}); + get(screenID).style.display = ""; } \ No newline at end of file diff --git a/index.html b/index.html index ccd3657..23bad3c 100644 --- a/index.html +++ b/index.html @@ -13,7 +13,6 @@
                  Your ResponsesYour Responses
                  Questions
                  @@ -78,15 +83,17 @@

                  AI interview

                  +
                  + + - \ No newline at end of file diff --git a/interview.js b/interview.js new file mode 100644 index 0000000..89d8095 --- /dev/null +++ b/interview.js @@ -0,0 +1,52 @@ + +class Interview{ + constructor(questions, useVideo){ + window.x = this; + [this.questions, this.useVideo] = [questions, useVideo]; + this.index = 0; + this.configure(); + } + get question(){ + return this.questions[this.index]; + } + configure(){ + // choose the container video/text + this.container = Interview.containers[this.useVideo+0]; + this.container.append(CONTROLS); + this.layoutButton = new Switch(CONTROLS + , CONTROLS, "layout", [1, 0]); + // build what should be built + // add controls to that place... + // setup controls.event + // maybe move this class to another file (interview.js) + // ... + } + start(){ + // + alert("Not yet implemented") + } + next(){ + // + } + previous(){ + // this and next will use should useVideo + } + static containers = [TEXTINTERVIEW, VIDEOINTERVIEW]; +} + +// set some things for CONTROLS +Object.defineProperty(CONTROLS, "layout", { + get: function(){return false}, + set: function(value){ + if (value){ + CONTROLS.classList.add("side"); + CONTROLS.parentElement.classList.add("side"); + } else{ + CONTROLS.classList.remove("side"); + CONTROLS.parentElement.classList.remove("side"); + } + } +}) +function layout(){ + CONTROLS +} \ No newline at end of file diff --git a/scripts.js b/scripts.js index 2b6b365..1835321 100644 --- a/scripts.js +++ b/scripts.js @@ -19,14 +19,14 @@ function loader(){ // create switch inside SHOULDVIDEO function createVideoToggle(){ - const videoSwitch = new Switch(SHOULDVIDEO + videoSwitch = new Switch(SHOULDVIDEO , VIDEOSETTINGS.style, "display", ["none", ""]) } // create search ui for voices function createVoiceSearchUI(){ speechSearch = new SearchUI(VOICETHINGS - , ()=>speechSynthesis.getVoices() + , ()=>speechSynthesis.getVoices().map(i=>i.name) // , ()=>["Daniel", "Ogirimah", "Enesi"] ) } @@ -38,26 +38,17 @@ function restoreSavedQuestions(){ } -// function makeQuestion(question) { -// } //events -// questionHolder.removebutton.onclick=()=>questionHolder.remove();//for deleting the question -// questionHolder.upanddown.onclick=()=>{ -// if (event.target.parentElement!=questionHolder.upanddown)return;//so that I can use ternary ifelse -// let dir = event.target.className; -// (event.target.className=='up') -// ?(questionslist.firstElementChild!=questionHolder) -// &&questionslist -// .insertBefore(questionHolder, questionHolder.previousElementSibling) -// :(questionslist.lastElementChild!=questionHolder) -// &&((questionslist.lastElementChild -// .previousElementSibling==questionHolder) -// ?questionslist.appendChild(questionHolder) -// :questionslist.insertBefore(questionHolder -// , questionHolder.nextElementSibling.nextElementSibling) -// ) -// }; -// questionHolder.onclick=()=>questionslist.querySelectorAll('.questionnumber').forEach((n, i)=>n.textContent=i+1); -// questionHolder.question.focus() -// } - -// a = new Question \ No newline at end of file +// say function to speak +function say(text, voice){ + // global variable talk + speechSynthesis.cancel(); + [TALK.text, TALK.voice] = arguments; + speechSynthesis.speak(TALK); +} + + +// get voice from voice name +function getVoice(name){ + return speechSynthesis.getVoices().find(i=>i.name == name); +} +// the rest will be at setup.js \ No newline at end of file diff --git a/setup.js b/setup.js index ccc2a91..5114720 100644 --- a/setup.js +++ b/setup.js @@ -1,4 +1,5 @@ -// //start from the top + + // // first get the saved questions if any // let baseli = getS('li'), //the base for adding questions // questions = localStorage.questions && JSON.parse( diff --git a/webint.css b/webint.css index 0e1a210..ee1dbf3 100644 --- a/webint.css +++ b/webint.css @@ -76,6 +76,7 @@ button:active{ text-align: center; display: block; justify-self: center; + margin-top: 20px; } .major:hover, .major:active{ padding: 10px 20px; @@ -90,7 +91,7 @@ button:active{ /* end buttons */ /* input text */ -[type="text"]{ +[type="text"], textarea{ padding: 7px 0; border: none; border-bottom: var(--b); @@ -99,10 +100,10 @@ button:active{ color: gray; font-size: 0.9em; } -[type="text"]:hover{ +[type="text"]:hover, textarea:hover{ border-color: blue } -[type="text"]:active, [type="text"]:focus{ +[type="text"]:active, [type="text"]:focus, textarea:active, textarea:focus{ border-color: darkblue; outline: none; } @@ -139,7 +140,7 @@ h2{ border: none; position: fixed; top: calc(50vh - 40px); - left: calc(50vw - 40px); z-index: 199; + left: calc(50vw - 40px); z-index: 20; margin: 0; } #LOADING:before{ @@ -163,7 +164,7 @@ h2{ top: 0; left: calc(50% - 10px); opacity: 0; - z-index: 200; + z-index: 21; animation: blink 0.8s cubic-bezier(0, 0, 1, -0.12) infinite; } @keyframes blink{ @@ -184,14 +185,23 @@ h2{ #CONTROLS{ display: flex; flex-flow: row; - align-items: center; justify-content: space-between; gap: 5px; + align-items: center; +} +#CONTROLS.side{ + flex-flow: column; + align-items: end; } #CONTROLS>button, .say{ border-right: var(--b); gap: 0px } +#CONTROLS.side>button, #CONTROLS.side>div{ + border: none; + /* border-right: var(--b`); */ + border-bottom: var(--b); +} .say>*{ gap: 0px; margin: 0; @@ -226,8 +236,51 @@ select:active, select:focus{ } /* end INTERVIEW CONTROLS */ +/* Modals */ +.modal{ + border: var(--b); + border-width: 3px; + border-radius: 0.8em; + /* display: none; */ + flex-flow: row; + width: 18em; + position: fixed; + /* top: 0; */ + left: calc(50% - 9em); + flex-wrap: wrap; + z-index: 23; + background-color: white; + padding: 10px; + box-sizing: border-box; + transition: 0.3s; + transform: scale(0); + align-items: center; + justify-content: space-evenly; +} +.modal.shown{ + display: flex; + transform: scale(1); +} +.modal.shown.blink{ + border-color: red; +} +.modal>p{ + width: -webkit-fill-available; + text-align: center; + border: var(--b); + border-radius: 0.3em; + padding: 5px; + margin: 0; + max-height: 5em; + overflow-y: scroll; +} +/* end Modals */ + /* end More specific general */ + + + /* end General */ /* SETUP SCREEN */ @@ -342,7 +395,7 @@ body>div{ font-size: 0.9em; position: absolute; margin-top: 2em; - z-index: 199; + z-index: 10; padding: 10px; border: var(--b); border-radius: 0.5em; @@ -363,8 +416,31 @@ body>div{ /* VIDEOINTERVIEW SCREEN */ /* end VIDEOINTERVIEW SCREEN */ - +#TEXTINTERVIEW{ + font-size: 0.9em; + align-items: center; +} +/* #QUESTIONBOX, #ANSWERBOX{ +} */ +#QUESTIONBOX{ + width: 20em; + overflow-y: scroll; + border-radius: 0.8em; + padding: 20px; + scrollbar-width: none; + border: var(--b); + max-height: 50vh; + +} +#ANSWERBOX{ + background-color: white; + font-size: 0.9em; + resize: none; + margin-top: 5px; + padding: 0 10px +} /* TEXTINTERVIEW SCREEN */ + /* end TEXTINTERVIEW SCREEN */ From 793a837650c0ce970d9897c8250d529bd7ae2ee1 Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Thu, 25 Apr 2024 02:16:45 -0500 Subject: [PATCH 12/19] works for text based interviews --- classes.js | 2 +- index.html | 10 ++-- interview.js | 136 +++++++++++++++++++++++++++++++++++++++++++++------ scripts.js | 1 + webint.css | 66 ++++++++++++++++++++++--- 5 files changed, 186 insertions(+), 29 deletions(-) diff --git a/classes.js b/classes.js index 9eaba1a..a23f262 100644 --- a/classes.js +++ b/classes.js @@ -78,7 +78,7 @@ class Question{ } class Switch{ - constructor(where, obj, property, values){ + constructor(where, obj, property, values=[true, false]){ [this.container, this.obj, this.property, this.values] = arguments this.build(); this.event(); diff --git a/index.html b/index.html index 23bad3c..fcffd98 100644 --- a/index.html +++ b/index.html @@ -15,7 +15,7 @@
                  -
                  +
                  diff --git a/interview.js b/interview.js index cdd80c0..8e63d22 100644 --- a/interview.js +++ b/interview.js @@ -33,6 +33,14 @@ class Interview{ // end video specific PLAYORPAUSE.remove(); + /* this will be refactored to sth else: SAY.textcontent=REWRITE... + there will be up to three pregenerated text for answer + probably in this.suggestions = ...[[], []] + this.get:suggestion(): + choice(this.suggestions[this.index]) + for both text and video interview + */ + SAY.remove(); } event(){ @@ -50,8 +58,8 @@ class Interview{ break; case "PLAYORPAUSE": - target.textContent = target.textContent == "PAUSE"?"RESUME":"PAUSE"; this[target.textContent.toLowerCase()](); + target.textContent = target.textContent == "PAUSE"?"RESUME":"PAUSE"; break; default: @@ -60,16 +68,10 @@ class Interview{ } if (this.useVideo){ // TALK.voice = getVoice(speechSearch.value); - TALK.onstart=()=>{ + TALK.onstart = TALK.onresume = VIDEO.onpause = ()=>{ this.disenable(); // disable repeat, previous, next } - TALK.onpause=()=>{ - - this.disenable(); - // switch between pause and RESUME, pause video - // disable previous, next, repeat (onstart()) - }; TALK.onerror=()=>console.log; // VIDEO event (try onload too, "DOMCONTENTLOADED...") @@ -124,7 +126,11 @@ class Interview{ navigator.mediaDevices.getUserMedia({ audio: true, video: true, facingMode: {exact: "user"} }).then(mediaStream=>{ - this.video(mediaStream); + navigator.mediaDevices.getDisplayMedia({ + audio: true, video: true + }).then(screenStream=>{ + this.video(mediaStream, screenStream); + }) }).catch((error)=>{ console.log(error); this.exit("Permission Denied. Click to restart.") @@ -143,16 +149,44 @@ class Interview{ } this.ask(0); } - video(mediaStream){ - this.mediaStream = mediaStream; - this.videoRecorder = new MediaRecorder(mediaStream, { - mimeType: "video/webm; codecs=vp9" - }); + video(mediaStream, screenStream){ + // for playing around, add the screen's stream + // get the video track + this.videoTrack = mediaStream.getVideoTracks()[0]; + + // merge the two streams into one audio stream + let audioCtx = new AudioContext() + , destination = audioCtx.createMediaStreamDestination(); + [...arguments].forEach(stream=>{ + audioCtx.createMediaStreamSource(stream).connect(destination); + }) + + // get the one audio track from the gotten stream + this.audioTrack= destination.stream.getAudioTracks()[0]; + + // create a new media stream to be used + this.mediaStream = new MediaStream(); + // add video and audio tracks to this one stream + ["audio", "video"].forEach(track=>{ + this.mediaStream.addTrack(this[track+"Track"]); + }) + this.mediaRecorder = new MediaRecorder( + this.mediaStream, {mimeType: "video/webm; codecs=vp9"} + ); + this.screenStream = screenStream; + // this.mediaStream.removeTrack(mediaStream.getAudioTracks()[0]); + // [this.mediaStream, this.screenStream] = arguments; + // ["media", "screen"].forEach(rec=>{ + // this[rec+"Recorder"] = new MediaRecorder( + // this[rec+"Stream"], {mimeType: "video/webm; codecs=vp9"} + // ); + // }) + // event - this.videoRecorder.ondataavailable=(event)=>{ + this.mediaRecorder.ondataavailable=(event)=>{ this.videoResponse(event); } - this.videoRecorder.start(); + this.mediaRecorder.start(); VIDEO.srcObject = this.mediaStream; VIDEO.muted = true; } @@ -164,8 +198,10 @@ class Interview{ REFRESHER.disabled = false; if (this.useVideo){ say(TEXTAFTER.value).then(resp=>{ - this.mediaStream.getTracks().forEach(i=>i.stop()); - this.videoRecorder.stop(); + ["screen", "media"].forEach(type=>{ + this[type+"Stream"].getTracks().forEach(i=>i.stop()); + }) + this.mediaRecorder.stop(); }); return; } @@ -195,9 +231,18 @@ class Interview{ } pause(){ speechSynthesis.pause(); + VIDEO.pause(); + this.mediaRecorder.pause(); + // pause audio recorder (screen recording) } resume(){ + // resume audio recorder (screen recording) + this.mediaRecorder.resume(); + VIDEO.play(); speechSynthesis.resume(); + if (!speechSynthesis.speaking && !speechSynthesis.paused){ + this.disenable(false); + } } blur(){ this.questionBox.setAttribute("disabled", "true"); @@ -219,7 +264,7 @@ class Interview{ videoResponse(event){ showLoading("making video..."); switchScreen("VIDRESP"); - this.videoFile = new Blob([event.data], {type: "video/webm"}); + this.videoFile = event.data; VIDEORESPONSE.src = URL.createObjectURL(this.videoFile); (SAVE.downloader = make('a')).download = "ai-interview.webm"; SAVE.downloader.href = VIDEORESPONSE.src; From 48a9aa7111857ce8c6797a0dbd1cc242f2895bcd Mon Sep 17 00:00:00 2001 From: Daniel Enesi <137162024+DanielOnGitHub17@users.noreply.github.com> Date: Fri, 26 Apr 2024 15:39:54 -0500 Subject: [PATCH 17/19] Update about.txt --- about.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/about.txt b/about.txt index 65cd6f9..dc621d6 100644 --- a/about.txt +++ b/about.txt @@ -1,5 +1,3 @@ -Made By Daniel Enesi, do not copy, do not pirate. +Made By Daniel Enesi. Do not misuse. -enesidaniel.120064@gmail.com, +2347010081471 - -Asks interview questions and records answers, either in text or in voice +Asks interview questions and records answers, either in text or in video. From 287a21a99021c3518de7c22e3d7c2275d0107894 Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Fri, 26 Apr 2024 17:31:25 -0500 Subject: [PATCH 18/19] final changes. checking if permission was given, will deploy to github pages soon --- classes.js | 24 ++++++++++++++++-------- events.js | 21 ++++++--------------- index.html | 18 ++++++++++++------ interview.js | 40 ++++++++++++++++++++-------------------- scripts.js | 50 +++++++++++++++++++++++++++++++++++++++++++++----- webint.css | 3 +++ 6 files changed, 102 insertions(+), 54 deletions(-) diff --git a/classes.js b/classes.js index 58f8a52..5114237 100644 --- a/classes.js +++ b/classes.js @@ -58,6 +58,11 @@ class Question{ this.box.classList.remove("highlight"); } // this.mover.onmouse + this.text.onblur=()=>{ + if (!this.question.trim()){ + this.question = this._question; + } + } } delete(){ this.box.remove(); @@ -156,28 +161,31 @@ class SearchUI{ this.searchBox.onfocus=()=>this.list.hidden=false; this.searchBox.addEventListener("blur" , ()=>setTimeout(()=>this.list.hidden=true, 500)); - this.searchBox.onblur=(event)=>{ - TESTVOICE.test = getVoice(this.searchBox.value); - } this.searchBox.oninput=(event)=>{ [...this.list.children].forEach(child=>{ child.hidden = !(child.textContent.toLowerCase().includes(this.searchBox.value.toLowerCase())); }); - this.searchBox.onblur(); + if (this.value){ + TALK.voice = getVoice(this.value); + } } this.list.onclick=(event)=>{ event.stopImmediatePropagation(); event.stopPropagation(); if (event.target.parentElement == this.list){ - this.searchBox.value = event.target.textContent; - TALK.voice = getVoice(this.searchBox.value); + this.value = event.target.textContent; } } } get value(){ if (this.values.includes(this.searchBox.value)){ return this.searchBox.value; - } + }; + return false; + } + set value(name){ + this.searchBox.value = name; + TALK.voice = getVoice(name); } } @@ -222,7 +230,7 @@ class Modal{ }; showLoading() if (buttons) this.changeButtons(buttons); - this.messageBox.textContent = message; + this.messageBox.innerHTML = message; this.modal.classList.add("shown"); this[this.buttons[this.buttons.length-1]].focus(); // promise diff --git a/events.js b/events.js index 874171d..1b8c571 100644 --- a/events.js +++ b/events.js @@ -7,15 +7,9 @@ onload=()=>{ // show only SETUP switchScreen("SETUP"); // restore saved questions - restoreSavedQuestions(); - // create a toggle to switch video options - createVideoToggle(); - // create voice search ui - createVoiceSearchUI() - - // initialize SpeechSynthesisUtterance - TALK = new SpeechSynthesisUtterance(); - TALK.onend=()=>say.resolve(true); + restoreSavedData(); + // consent to recording + consentToRecording(); // TESTS // a = alert("Hi!").then(console.log); @@ -42,20 +36,17 @@ TESTVOICE.onclick =()=>{ onbeforeunload=()=>{ speechSynthesis.cancel(); - localStorage.questions = JSON.stringify([...QUESTIONLIST.children].map(q=>q.obj.question)); - // TEXTAFTER.value = - // TEXTBEFORE.value = -} + saveData();} STARTBUTTON.onclick=()=>{ - onbeforeunload(); + saveData(); questions = JSON.parse(localStorage.questions); if (!questions.length){ return alert("You have to add at least one question"); } else if (videoSwitch.on && !speechSearch.value) { return alert("Please, choose a voice!"); } - confirm("Are you sure you want to begin?") + confirm("Are you sure you want to begin?", ["No", "Yes"]) .then(resp=>{ if (resp){ ( diff --git a/index.html b/index.html index eee6290..8bba9fa 100644 --- a/index.html +++ b/index.html @@ -41,15 +41,21 @@

                  AI interview

                  Toggle video usage:
                  - -
                  - - -
                  +
                    +
                  • + + +
                  • +
                  • + + +
                  • +
                  Choose Voice: +
                  @@ -59,7 +65,7 @@

                  AI interview

                  -

                  Text from SpeechRecognition will be displayed here

                  +

                  Stay focused. You can do this!

                  diff --git a/interview.js b/interview.js index 8e63d22..2b759b2 100644 --- a/interview.js +++ b/interview.js @@ -26,6 +26,7 @@ class Interview{ // end general // video specific this.questionBox = this.useVideo?CC:QUESTIONBOX; + SAY.remove(); if (this.useVideo){ this.layoutButton.switch.click(); // switch layout return; @@ -41,7 +42,6 @@ class Interview{ for both text and video interview */ - SAY.remove(); } event(){ CONTROLS.onclick=(event)=>{ @@ -86,7 +86,7 @@ class Interview{ } else{ time = hours > 11?"afternoon":"morning"; } - say(`Good ${time}. ${choice(Interview.starters)}`).then(begin=>{ + say(`Good ${time}. ${FIRSTSAY.value}`).then(begin=>{ this.ask(0); }) } @@ -129,11 +129,19 @@ class Interview{ navigator.mediaDevices.getDisplayMedia({ audio: true, video: true }).then(screenStream=>{ + // check if user followed instructions. + let track = screenStream.getAudioTracks()[0]; + if (!track || track.label != "System Audio"){ + throw "Did not follow instructions"; + } this.video(mediaStream, screenStream); + }).catch(error=>{ + console.log(error); + this.exit("You must share entire screen and system audio."); }) }).catch((error)=>{ console.log(error); - this.exit("Permission Denied. Click to restart.") + this.exit("You should allow all permissions!"); }) }) @@ -152,15 +160,19 @@ class Interview{ video(mediaStream, screenStream){ // for playing around, add the screen's stream // get the video track + this.mdStm = mediaStream; this.videoTrack = mediaStream.getVideoTracks()[0]; - + // stop screen's videoTrack + let screenVideo = screenStream.getVideoTracks()[0]; + screenVideo.stop(); + screenStream.removeTrack(screenVideo); // merge the two streams into one audio stream let audioCtx = new AudioContext() , destination = audioCtx.createMediaStreamDestination(); [...arguments].forEach(stream=>{ audioCtx.createMediaStreamSource(stream).connect(destination); }) - + this.dest = destination.stream; // get the one audio track from the gotten stream this.audioTrack= destination.stream.getAudioTracks()[0]; @@ -169,20 +181,11 @@ class Interview{ // add video and audio tracks to this one stream ["audio", "video"].forEach(track=>{ this.mediaStream.addTrack(this[track+"Track"]); - }) + }); this.mediaRecorder = new MediaRecorder( this.mediaStream, {mimeType: "video/webm; codecs=vp9"} ); this.screenStream = screenStream; - // this.mediaStream.removeTrack(mediaStream.getAudioTracks()[0]); - // [this.mediaStream, this.screenStream] = arguments; - // ["media", "screen"].forEach(rec=>{ - // this[rec+"Recorder"] = new MediaRecorder( - // this[rec+"Stream"], {mimeType: "video/webm; codecs=vp9"} - // ); - // }) - - // event this.mediaRecorder.ondataavailable=(event)=>{ this.videoResponse(event); } @@ -197,7 +200,7 @@ class Interview{ if (!bool) return; REFRESHER.disabled = false; if (this.useVideo){ - say(TEXTAFTER.value).then(resp=>{ + say(FINALSAY.value).then(resp=>{ ["screen", "media"].forEach(type=>{ this[type+"Stream"].getTracks().forEach(i=>i.stop()); }) @@ -249,7 +252,7 @@ class Interview{ setTimeout(()=>this.questionBox.removeAttribute("disabled"), 200) } exit(message="Sorry, an error occured. You will have to restart."){ - alert(message).then(()=>location.reload()); + alert(message, ["RESTART"]).then(()=>location.reload()); } textResponse(){ switchScreen("TXTRESP"); @@ -272,9 +275,6 @@ class Interview{ hideLoading(); } static containers = [TEXTINTERVIEW, VIDEOINTERVIEW]; - static starters = ["We will begin now." - , "Welcome to your interview.", "Make sure you are ready." - , "Your interview starts now.", "This interview will test your knowledge"] // in SETUP, do a starter. } diff --git a/scripts.js b/scripts.js index cdf5c40..b32d129 100644 --- a/scripts.js +++ b/scripts.js @@ -31,15 +31,29 @@ function createVoiceSearchUI(){ ) } -// well... -function restoreSavedQuestions(){ +// for "data persistence"... +function saveData(){ + // questions + localStorage.questions = JSON.stringify([...QUESTIONLIST.children].map(q=>q.obj.question)); + // FIRST|FINAL-->SAY + ["FIRSTSAY", "FINALSAY"].forEach(pos=>{ + if (window[pos]){ + localStorage[pos] = window[pos].value; + } + }) +} +function restoreSavedData(){ const QUESTIONS = localStorage.questions?JSON.parse(localStorage.questions):[]; QUESTIONS.forEach(q=>(new Question(q))); - + ["FIRSTSAY", "FINALSAY"].forEach(pos=>{ + if (localStorage[pos]){ + window[pos].value = localStorage[pos]; + } + }) } // say function to speak -function say(text, voice){ +function say(text="", voice){ // global variable talk speechSynthesis.cancel(); TALK.text = text; @@ -55,4 +69,30 @@ function say(text, voice){ function getVoice(name){ return speechSynthesis.getVoices().find(i=>i.name == name); } -// the rest will be at setup.js \ No newline at end of file + +// get user consent for recording screen and making video (remove) +function consentToRecording(){ + confirm(` + To use this app's video feature, you must share your entire screen +
                  and allow the app to record system audio
                  + The app does not store recorded data after usage.
                  + Your privacy is paramount + `, ["decline", "agree"]).then(bool=>{ + // create a toggle to switch video options + createVideoToggle(); + if (bool){ + // create voice search ui + createVoiceSearchUI() + if (localStorage.voice){ + speechSearch.value = localStorage.voice; + } + + // initialize SpeechSynthesisUtterance + TALK = new SpeechSynthesisUtterance(); + TALK.onend=()=>say.resolve(true); + } else{ + videoSwitch.switch.click(); + SHOULDVIDEO.remove(); + } + }) +} \ No newline at end of file diff --git a/webint.css b/webint.css index 747f2ec..4582dce 100644 --- a/webint.css +++ b/webint.css @@ -388,6 +388,9 @@ body>div{ margin-top: 20px; padding-top: 10px; } +#VIDEOSETTINGS>ul{ + list-style-type: none; +} #VOICETHINGS{ display: flex; gap: 20px; From a6bc6f7940da471116d31ad65b4862237dead549 Mon Sep 17 00:00:00 2001 From: Daniel Enesi Date: Fri, 26 Apr 2024 17:37:10 -0500 Subject: [PATCH 19/19] more changes. then I will move to gh-pages to add some more features --- events.js | 112 +----------------------------------------------------- setup.js | 30 --------------- 2 files changed, 1 insertion(+), 141 deletions(-) delete mode 100644 setup.js diff --git a/events.js b/events.js index 1b8c571..29d0af2 100644 --- a/events.js +++ b/events.js @@ -58,114 +58,4 @@ STARTBUTTON.onclick=()=>{ alert("Make changes then click START"); } }) -} -// if (!(questions=[...questionslist.children].map(i=>i.querySelector('.question').innerText)).length) return errors.innerHTML = 'No question added, Please add at least one questions to proceed'; -// if (!confirm('Proceed?')) return -// embassy.style.display='flex'; setup.style.display='none'; -// shouldusevideo.checked?you.style.display='none':interviewbox.style.display='none'; -// questionbox.innerText=(currentQuestion=questions[index])//setup non-video -// if (!shouldusevideo.checked) return; -// // while (!voice){} -// loading.loading = 1; -// userMedia = navigator.mediaDevices.getUserMedia({ -// audio: true, video: true, -// facingMode: {exact: "user"} -// }); -// userMedia.then(mediaStream=>{ -// //setup video recording -// stream = mediaStream; -// recorder = new MediaRecorder(mediaStream) -// recorder.ondataavailable=()=>{ -// loading.loading = 1; -// finalFile = new Blob([event.data], {type:"video/mp4"}) -// response.src=URL.createObjectURL(finalFile); -// refresher.style.display='block'; -// responseHolder.style.display='flex'; -// loading.loading = 0; -// } -// recorder.start(); -// video.srcObject = mediaStream; video.muted=true; -// }).catch(error=>{alert('an error occurred, exitting!!'); location.reload()}) -// video.onloadstart=()=>{ -// loading.loading=0; -// video.play(); -// let hours = new Date(Date.now()).getHours(), time; -// if(hours>16){ -// time ='evening' -// }else if(hours>11){ -// time='afternoon' -// }else if(hours>=0){ -// time='morning' -// } -// question = new SpeechSynthesisUtterance(` -// Good ${time}}. Welcome to your interview. -// Please click the repeat button to repeat any asked question, -// and click the forward button to go to the next question.`); -// question.voice =voice//= voices[+getAll('[name=voice]').filter(v=>v.checked)[0].value] -// voice; question.rate=.8; -// speechSynthesis.speak(question); -// question.onstart=()=>say.disabled=forward.disabled=true; -// question.onend = ()=>{setTimeout(()=>!video.paused&&(say.disabled=forward.disabled=false), randBtw(1000, 2500))}; -// // setup q and a -// } - -// } -// answerquestion.onclick=()=>{ -// event.preventDefault(); -// if (!answerbox.reportValidity()) return; -// answers.push(answerbox.value); answerbox.value=''; -// if(index+1>=questions.length){ -// //submit -// embassy.style.display='none' -// responses.style.display='flex'; -// questions.forEach((q, i)=>{ -// let r = responses.insertRow(); -// (r.insertCell()).innerText = q; -// (r.insertCell()).innerText = answers[i] -// }) -// return refresher.style.display='block' -// } -// questionbox.innerText=(currentQuestion = questions[++index]) -// if(index+2>questions.length) answerquestion.innerText='End interview'; -// } -// playorpause.onclick=()=>{ -// if (video.paused) { -// speechSynthesis.resume(); recorder.resume(); video.play(); playorpause.innerText = 'Pause Recording'; -// say.disabled=forward.disabled=false; -// } else { -// speechSynthesis.pause(); recorder.pause(); video.pause();playorpause.innerText = 'Continue Recording'; -// question.onstart(); -// } -// } -// forward.onclick=()=>{ -// question.onstart(); -// if(index>=questions.length){ -// //submit -// question.text = after.value?after.value:after.placeholder; -// speechSynthesis.speak(question) -// question.onend=()=>{ -// embassy.style.display='none' -// stream.getTracks().forEach(i=>i.stop()); -// recorder.stop(); -// } -// return -// } -// question.text=(currentQuestion=questions[index++]); -// speechSynthesis.speak(question) -// if(index+1>questions.length) forward.innerText='End interview'; -// } -// say.onclick=()=>{ -// speechSynthesis.cancel(); -// speechSynthesis.speak(question); -// } -// // addquestion.click() -// //for downloading -// save.onclick=()=>{ -// downloader.href=response.src; -// downloader.click(); -// } -// getAll('[name=voice]').forEach(v=>{ -// v.onchange=()=>{voice=speechSynthesis.getVoices()[+v.value]} -// }) - -// add voice recording to use instead of TALKing out \ No newline at end of file +} \ No newline at end of file diff --git a/setup.js b/setup.js deleted file mode 100644 index 5114720..0000000 --- a/setup.js +++ /dev/null @@ -1,30 +0,0 @@ - - -// // first get the saved questions if any -// let baseli = getS('li'), //the base for adding questions -// questions = localStorage.questions && JSON.parse( -// localStorage.questions), currentQueston -// , index = 0, answers = [], userMedia -// , recorder, stream, voices = speechSynthesis.getVoices() -// , voice, question, downloader = make('a'); -// downloader.download = 'interview.mp4'; -// if (questions) { -// questions.forEach((q,i)=>{ -// makeQuestion(q, 1 + i) -// }) -// } -// function mov() { - -// p.then(mediaStream=>{ -// m = MediaRecorder; -// video.onloadedmetadata = (x)=>{ -// confirm('play?') && video.play(); -// a.push(x) -// } -// MediaRecorder.start(); -// }); - -// p.catch(err=>console.log(err)) -// } -// // startbutton.onclick = mov -// loading.loading = 0;