The progress on top of yesterday’s YouTube Embedded Iframe API Summary Emoji Buttons Tutorial‘s progress today can be summarised by …
- select “multiple” (ie. dropdown element) size=[fullListShownNumber] mode with (option subelement “onclick=gmlistit(this);”) logic (✔ based) to consider the order of singular clicks (in order to give the user added control resembling that of a playlist) …
function gmlistit(invlo) {
var invl=invlo.value;
if (invl == '') { return ''; }
var isvalid=false;
var morethanone=0;
if (('' + invl).indexOf('|') != -1) {
if (gmlist.indexOf(invl.split('|')[0]) == -1) {
isvalid=true;
if (gmlist == '') {
gmlist=invl.split('|')[0];
} else {
gmlist+=',' + invl.split('|')[0];
}
}
// alert('gmlist=' + gmlist);
}
var sin=document.getElementById('sshuffle');
for (var ii=1; ii<sin.options.length; ii++) {
if (sin.options[ii].selected) {
morethanone++;
}
}
if (morethanone > 1) {
gmlist='';
isvalid=false;
}
for (var i=1; i<sin.options.length; i++) {
if (sin.options[i].selected) {
if (sin.options[i].innerText.indexOf(String.fromCodePoint(10004)) == -1) {
sin.options[i].innerText+=' ' + String.fromCodePoint(10004);
} else if (morethanone > 1) {
sin.options[i].innerText=sin.options[i].innerText.split(String.fromCodePoint(10004))[0] + String.fromCodePoint(10004);
}
if (sin.options[i].value.indexOf('|') != -1) {
if (gmlist.indexOf(sin.options[i].value.split('|')[0]) == -1) {
if (gmlist == '') {
gmlist=sin.options[i].value.split('|')[0];
} else {
gmlist+=',' + sin.options[i].value.split('|')[0];
}
sin.options[i].innerText+=' ' + gmlist.split(',').length;
}
}
} else if (morethanone > 1) {
if (sin.options[i].innerText.indexOf(String.fromCodePoint(10004)) != -1) {
sin.options[i].innerText=sin.options[i].innerText.split(String.fromCodePoint(10004))[0];
sin.options[i].style.backgroundColor='white';
}
}
}
if (isvalid) {
invlo.style.backgroundColor='rgb(230,230,230)';
invlo.innerText+=' ' + gmlist.split(',').length;
}
}
- cookie means (via 🍪 “emoji buttons”) by which to save a video list for recall (in an intersessional sense) …
// Initializations
var scoo='disco_yt_list';
var sbut='<span id="sd"><a href="#dshuffle" title="Shuffle">🔀</a> <a onclick="askvs();" title=Videos>❓</a></span> ';
if (cookieAVal(scoo) != '') { sbut=sbut.replace('</span>', ' <a onclick="recall();" title="Recall ' + cookieAVal(scoo) + '">🍪</a></span>'); }
var xsbut=sbut;
// ... then later ...
function cookieAVal(cName) {
if (document.cookie != '') {
var tCookie=document.cookie.split("; ");
for (var j=0; j<tCookie.length; j++) {
if (cName == tCookie[j].split("=")[0]) {
return decodeURIComponent(tCookie[j].split("=")[1]);
}
}
}
return '';
}
function recall() {
var uvbit=cookieAVal(scoo);
if (uvbit != '') {
location.href=document.URL.split('#')[0].split('?')[0] + '?mustbeone=' + encodeURIComponent(uvbit.split(',')[0]) + '&videolist=' + encodeURIComponent(uvbit);
}
}
function deleteACookie(goodname) {
var expireDate = new Date();
expireDate.setDate(expireDate.getDate()-1);
document.cookie = goodname + "=; expires=" + expireDate.toGMTString();
}
function setACookie(gname, qyst) {
if (cookieAVal(gname) != '') { deleteACookie(gname); }
var expireDate = new Date();
expireDate.setMonth(expireDate.getMonth()+6);
document.cookie = gname + "=" + encodeURIComponent(qyst) + "; expires=" + expireDate.toGMTString();
}
- detail element order with most recent at the top and the current relevant entry flagged by an 🕺 emoji …
// Example code applied to the new HTML paradigm part <detail id=dprex><summary id=prex><div id=dd></div></detail> div nested element ...
document.getElementById('prex').innerHTML='Enjoy watching and listening to ' + event.target.getVideoData().title + ' ... ' + sbut + d;
if (document.getElementById('markp' + event.target.id)) {
markith(d, event.target.id, 'p', 0);
} else {
mh=markith(d, event.target.id, 'p', 1);
if (wasdc != '') {
document.getElementById('dd').innerHTML='Enjoy watching and listening to ' + event.target.getVideoData().title + ' ... ' + mh + '<br>' + wasdc;
} else {
document.getElementById('dd').innerHTML+='Enjoy watching and listening to ' + event.target.getVideoData().title + ' ... ' + mh + '<br>';
}
}
// ... uses ...
function markith(thed, theid, themid, addmode) {
var sofar='';
var ouremoji=String.fromCodePoint(128378);
var dprexc=document.getElementById('dprex').innerHTML.split('<div id="dd">')[0].split('</div>')[0];
dprexc=document.getElementById('dd').innerHTML; //.split('<div id="dd">')[0].split('</div>')[0];
var idp=false;
wasdc='';
while (dprexc.indexOf(ouremoji) != -1) {
dprexc=dprexc.replace(ouremoji,'');
idp=true;
}
if (idp) {
var blines=dprexc.split('<br>');
var newdc=blines[0] + '<br>';
sofar+=blines[0].split(' ... ')[0];
for (var inew=1; inew<blines.length; inew++) {
if (blines[inew].split(' ... ')[0] != blines[eval(-1 + inew)].split(' ... ')[0] && sofar.indexOf(blines[inew].split(' ... ')[0]) == -1) {
newdc+=blines[inew] + '<br>';
sofar+=blines[inew].split(' ... ')[0];
}
}
if (newdc != dprexc) {
dprexc=newdc;
}
wasdc=dprexc;
document.getElementById('dd').innerHTML=dprexc;
}
var mks=document.getElementsByTagName('span');
for (var imks=0; imks<mks.length; imks++) {
if (('' + mks[imks].id) == ('mark' + themid + theid)) {
mks[imks].className="curmark";
if (mks[imks].innerHTML.length != ('' + thed).length) { mks[imks].innerHTML=mks[imks].innerHTML.slice(eval('-' + ('' + thed).length)); }
} else if (('' + mks[imks].id).indexOf('mark') == 0) {
mks[imks].className="oldmark";
if (mks[imks].innerHTML.length != ('' + thed).length) { mks[imks].innerHTML=mks[imks].innerHTML.slice(eval('-' + ('' + thed).length)); }
}
}
if (document.getElementById('mark' + themid + theid) && addmode == 0) {
document.getElementById('mark' + themid + theid).innerHTML=ouremoji + thed;
return '';
}
if (addmode == 2) {
document.getElementById('dd').innerHTML=prexc + '<span class=curmask id=mark' + themid + theid + '>' + ouremoji + thed + '</span>';
return '';
} else if (addmode == 1) {
return ouremoji + thed;
} else if (addmode == 0) {
return '<span class=curmask id=mark' + themid + theid + '>' + ouremoji + thed + '</span>';
}
}
And so, yet again, please try the YouTube disco web application (via dynamic_js.html changed this way).
Previous relevant YouTube Embedded Iframe API Summary Emoji Buttons Tutorial is shown below.
We weren’t sure if today’s idea, on top of the progress of yesterday’s YouTube Embedded Iframe API Video Unavailable Moderation Tutorial of adding intelligence to …
- detail’s summary (sub)element …
- style=position:fixed;
- big z-index value (for overlaying purposes) … by …
- embedding into its innerHTL content “a” link emojis (what we like to think of as “emoji buttons”)
… would work, because we hadn’t tried this before, and we knew you couldn’t do anything like this for “select’s option (sub)element”. But it does! Yayyyyy!
And we think it could be really useful, in order to display action items “within the fold” at all times (which is what “style=position:fixed;” is helping with …
var sbut='<a href=#dshuffle title=Shuffle>🔀</a> <a onclick=askvs(); title=Videos>❓</a> ';
// used later on ...
document.getElementById('prex').innerHTML='Enjoy watching and listening to ' + event.target.getVideoData().title + ' ... ' + sbut + d;
document.getElementById('dprex').innerHTML+='Enjoy watching and listening to ' + event.target.getVideoData().title + ' ... ' + d + '<br>';
// ... and ...
function askvs() {
var newlist=prompt('Please enter comma separated YouTube video ID list.', 'h2r59-Xmge4,yT1iDKkZNYU,S-u6qdeaPoE,Nm-ISatLDG0,Gs069dndIYk,dwxjpIJm9JM,8iwBM_YB1sE,CS9OO0S5w2k,I_izvAbhExY,xFrGuyw1V8s,piIJk0CFjUo,gQ8O9SidZbs,_QNEf9oGw8o,1ff29VSvP_s,4-Vz6tNfV1Y,Zi_XLOBDo_Y,xfmZRiePkEM,iPUmE-tne5U,m5y2GaW0MZA,yioNn7XS-bw,XKuJUxGntRI,vsBak0oCgdY,eBpYgpF1bqQ,DVDCNmdi7QI');
if (newlist != null) {
location.href=document.URL.split('#')[0].split('?')[0] + '?videolist=' + encodeURIComponent(newlist.replace(/\'/g,'').replace(/\"/g,'').replace(/\;/g,','));
}
}
And so, again, please try the YouTube disco web application (via dynamic_js.html changed this way).
Previous relevant YouTube Embedded Iframe API Video Unavailable Moderation Tutorial is shown below.
When doing the work for yesterday’s YouTube Embedded Iframe API and the Promise Object Tutorial we found some …
Video unavailable
… videos (that happen regarding some broken privilege on those videos). In trying to skip over these, we were unsuccessful using any YouTube Embedded Iframe API “onError” event scenario to identify this. What did work was …
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
var dis, cti, gvd, uri, jis, prv='', iyi=0, huht='';
uri=event.target.getVideoUrl();
jis=yid.indexOf(uri.split('=')[1].split('&')[0]);
dis=event.target.getDuration();
cti=event.target.getCurrentTime();
gvd=event.target.getVideoData().title;
yid[jis]+='|' + dis + '|' + cti + '|' + gvd;
// etcetera etcetera etcetera
if (('' + dis) != '0') { isoks[eval(-1 + eval('' + event.target.id))]=true; } else if (1 == 1) { if (document.getElementById('bshuffle').value == 'Shuffle') { document.getElementById('bshuffle').value='Help Moderate Unavailable Videos or Shuffle'; } ajaxits.push("ajaxit('" + uri + "', '" + gvd + "', '');"); } else if (1 == 3) { alert('video ' + eval(-1 + eval('' + event.target.id)) + ' isunavailable'); }
// etcetera etcetera etcetera
… dis returns zero.
So, today, we wanted to set up an email driven Self Moderation regime for these “Video unavailable” category of YouTube videos. Here is some Javascript code …
var lastallok='';
var noclick=false;
var cfrom=location.search.split('from=')[1] ? decodeURIComponent(location.search.split('from=')[1].split('&')[0]) : ' ';
var cto=location.search.split('to=')[1] ? decodeURIComponent(location.search.split('to=')[1].split('&')[0]).replace(cfrom,'') : ' ';
var ctitle=location.search.split('title=')[1] ? decodeURIComponent(location.search.split('title=')[1].split('&')[0]) : '';
var ajaxits=[];
function ajaxit(badurl, badtitle, ccit) {
var zhr = new XMLHttpRequest();
var zform=new FormData();
var pbl='';
zform.append('inline', '');
zform.append('to', 'rmetcalfe@rjmprogramming.com.au');
if (('' + ccit).indexOf('@') != -1) {
zform.append('cc', ccit);
pbl='public ';
}
zform.append('bcc', 'rmetcalfe15@gmail.com');
zform.append('subj', ('Video ' + badurl + ' unavailable ... ').replace(' ','') + pbl + ' disco moderation ... ' + badtitle);
var bigstr='';
var aform='';
if (cfrom.trim() != '' && cto.trim() != cfrom.trim() && ctitle != '') {
aform='<br><br><p>YouTube Video unavailable URL: <a target=_blank href=' + badurl + '>' + badurl + '</a></p><br><p>Video title (as known): ' + ctitle + '</p><br><p>Proposed Better YouTube URL: <a target=_blank href=' + cto + '>' + cto + '</a></p>';
bigstr='<bo' + 'dy><h1>Video ' + badurl + ' unavailable ... ' + pbl + ' disco moderation ... ' + badtitle + '</h1><a target=_blank title="?" href="//www.youtube.com/results?search_query=' + encodeURIComponent(badtitle) + '">Try this YouTube search</a>' + aform + '</body>';
} else if (cfrom.trim() != '' && cto.trim() != cfrom.trim()) {
aform='<br><br><p>YouTube Video unavailable URL: <a target=_blank href=' + badurl + '>' + badurl + '</a></p><br><p>Video title (as known): ' + badtitle + '</p><br><p>Proposed Better YouTube URL: <a target=_blank href=' + cto + '>' + cto + '</a></p>';
bigstr='<bo' + 'dy><h1>Video ' + badurl + ' unavailable ... ' + pbl + ' disco moderation ... ' + badtitle + '</h1><a target=_blank title="?" href="//www.youtube.com/results?search_query=' + encodeURIComponent(badtitle) + '">Try this YouTube search</a>' + aform + '</body>';
} else {
aform='<br><br><form target=_blank action=http://www.rjmprogramming.com.au/HTMLCSS/dynamic_js.htm method=GET><input type=hidden name=from value="' + badurl + '"></input><input type=hidden name=title value="' + badtitle + '"></input><br><br>New YouTube URL: <input style=width:350px; name=to type=text value="' + badurl + '"></input><br><br><input type=submit value=Moderate></input></form>';
bigstr='<bo' + 'dy><h1>Video ' + badurl + ' unavailable ... ' + pbl + ' disco moderation ... ' + badtitle + '</h1><a target=_blank title="?" href="//www.youtube.com/results?search_query=' + encodeURIComponent(badtitle) + '">Try this YouTube search</a>' + aform + '</body>';
}
zform.append('tdhuhta', bigstr);
zhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
console.log('badtitle=' + badtitle + ' and badurl='+ badurl);
zhr.send(zform);
}
function ajaxitcheck() {
if (ajaxits.length > 0) {
for (var iep=0; iep<ajaxits.length; iep++) {
eval(ajaxits[iep]);
}
ajaxits=[];
}
}
function process(bsin) {
var jj=0, mbo='', mlist='', mdelim='';
var ajx=0;
var sin=document.getElementById(bsin.id.replace('b','s'));
for (var i=0; i<sin.options.length; i++) {
if (sin.options[i].selected) {
if (sin.options[i].value != '') {
ajx=1;
jj++;
mbo=sin.options[i].value.split('|')[0];
mlist+=mdelim + sin.options[i].value.split('|')[0];
mdelim=',';
}
}
}
if (jj == 1) {
location.href=(document.URL.split('#')[0].replace('mustbeone=','mustxxxbeone=') + '&mustbeone=' + encodeURIComponent(mbo)).replace('.html&','.html?').replace('.htm&','.htm?').replace('.php&','.php?').replace('/&','/?');
} else if (jj > 1) {
location.href=(document.URL.split('#')[0].replace('mustbeone=','mustxxxbeone=').replace('videolist=','videoxxxlist=') + '&videolist=' + encodeURIComponent(mlist)).replace('.html&','.html?').replace('.htm&','.htm?').replace('.php&','.php?').replace('/&','/?');
}
if (jj == 0 && ajx == 0) {
if (ajaxits.length > 0) {
var ep=prompt('Email moderation form to?', '');
if (ep != null) { //ep=''; }
for (var iep=0; iep<ajaxits.length; iep++) {
//alert(ajaxits[iep].replace("'')", "'" + ep + "')"));
eval(ajaxits[iep].replace("'')", "'" + ep + "')"));
}
ajaxits=[];
}
} else {
ajaxit(cfrom, cto, prompt('Email moderation form to?', ''));
}
}
}
// ... and then down at the bottom of the Javascript ...
if (cfrom.trim() != '' && cto.trim() != cfrom.trim()) {
ajaxit(cfrom, ctitle, '');
}
setTimeout(ajaxitcheck, 120000);
So, again, please try the YouTube disco web application (via dynamic_js.html changed this way).
Previous relevant YouTube Embedded Iframe API and the Promise Object Tutorial is shown below.
There’s another environment in which we want to involve use of the promise object following on from yesterday’s Promise Object Sleeping and Doing Primer Tutorial, and that is with an inhouse web application using the YouTube Embedded Iframe API.
Today’s web application progress does not have to use the promise object, but we wanted to see if a layer of multitasking can work in the very event driven YouTube Vide Iframe Embedded API environment, and the verdict is …
Yes
Today, though, the main extra functionality feature onto the Disco themed 3×3 set of “active” YouTube video based table cells is …
- details/summary element (set) …
- initially at top/left but becoming …
document.getElementById('dprex').style.position='fixed';
document.getElementById('dprex').style.backgroundColor='yellow';
document.getElementById('dprex').style.border='1px dotted red';
document.getElementById('dprex').style.opacity='0.8';
document.getElementById('dprex').style.fontColor='blue';
document.getElementById('dprex').style.fontSize='18px';
document.getElementById('dprex').style.top='41%';
document.getElementById('dprex').style.left='0px';
document.getElementById('dprex').style.zIndex='20';
- containing content as per …
- summary element contains latest timestamped play/pause event information
- details element (user revealed) contains accumulated information (minus timestamp) above …
<details style="display: inline-block; position: fixed; background-color: yellow; border: 1px dotted red; opacity: 0.8; font-size: 18px; top: 41%; left: 0px; z-index: 20;" id="dprex"><summary id="prex">So long Michael Jackson - Billie Jean (Official Video) ... Mon Jul 26 2021 20:28:14 GMT+1000 (Australian Eastern Standard Time)..</summary>Enjoy watching and listening to Boney M. - Sunny (Official Video) [HD 1080p]<br>So long Boney M. - Sunny (Official Video) [HD 1080p]<br>Enjoy watching and listening to Boney M. - Sunny (Official Video) [HD 1080p]<br>So long Boney M. - Sunny (Official Video) [HD 1080p]<br>Enjoy watching and listening to Boney M. - Sunny (Official Video) [HD 1080p]<br>So long sweet Boney M. - Sunny (Official Video) [HD 1080p]<br>Enjoy watching and listening to Hot Chocolate - It Started With A Kiss (HD Live)<br>So long Hot Chocolate - It Started With A Kiss (HD Live)<br>Enjoy watching and listening to Hot Chocolate - It Started With A Kiss (HD Live)<br>So long sweet Hot Chocolate - It Started With A Kiss (HD Live)<br>Enjoy watching and listening to Bee Gees - Stayin' Alive (Official Video)<br>So long sweet Bee Gees - Stayin' Alive (Official Video)<br>Enjoy watching and listening to Earth, Wind & Fire - September (Official Video)<br>So long sweet Earth, Wind & Fire - September (Official Video)<br>Enjoy watching and listening to Michael Jackson - Billie Jean (Official Video)<br>So long sweet Michael Jackson - Billie Jean (Official Video)<br>Enjoy watching and listening to Yvonne Elliman If I can't have you 1977 16:9<br>So long sweet Yvonne Elliman If I can't have you 1977 16:9<br>Enjoy watching and listening to Anita Ward - "Ring My Bell" 1979<br>So long sweet Anita Ward - "Ring My Bell" 1979<br>Enjoy watching and listening to Boney M. - Sunny (Official Video) [HD 1080p]<br>Enjoy watching and listening to Boney M. - Sunny (Official Video) [HD 1080p]<br>So long sweet Boney M. - Sunny (Official Video) [HD 1080p]<br>So long Michael Jackson - Billie Jean (Official Video)<br></details>
Also, after a first “play” click by the user, on non-mobile platforms, if the user keeps up a “one video playing at a time” paradigm, and the web application is in focus, the disco music videos can follow each other programmatically (as if you were listening to a playlist, or radio).
So please try the YouTube disco web application (via dynamic_js.html changed this way).
Previous relevant Promise Object Sleeping and Doing Primer Tutorial is shown below.
We’re here today to fulfil yesterday’s Web Application Controlled Progress Cursor Primer Tutorial‘s pledge …
… which reminded me that we need to learn some more about the promise object
… and were happy to discover the Promise object talents of …
- sleeping … allowing for …
- multitasking
- doing … all using clientside Javascript
… very interesting. The serverside languages such as PHP make it a doddle to multitask (via sleep) but Javascript sleep has not always been a straightforward proposition, until we could promise, that is!
Today’s await.html‘s use of it to sleep and in between show …
- analogue clock … and …
- Dams of the USA (via dams_usa.html changed this way)
… asynchronously both doing their own thing while the await.html works away in the background too, feeding off “child 2” clicks of “child 1” above to know when to say how long the dams took to load. Yes, the “child 2” “onload” event, alone, cannot help determine this, but more “drilling into” the inner workings of the code behind “child 2″‘s progress element, via …
<html>
<head>
<script type='text/javascript'>
var numsleeps=700000;
var ix=0;
var d=new Date();
var marks=[new Date(), new Date()];
var imark=0;
function sleep(ms) { // thanks to https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep
return new Promise(resolve => setTimeout(resolve, ms));
}
async function demo() {
console.log(numsleeps + ' Taking a break...' + d);
await sleep(2000);
d=new Date();
console.log(numsleeps + ' Two seconds later, showing sleep in a loop...' + d);
// Sleep in loop
for (let i = 0; i < 5; i++) {
if (i === 3) {
await sleep(2000);
d=new Date();
console.log(numsleeps + ' ' + d);
}
}
numsleeps--;
if (('' + numsleeps) != '0' && ('' + numsleeps).indexOf('-') == -1) { setTimeout(demo, 1); }
}
function betw() {
var seconds = (marks[1].getTime() - marks[0].getTime()) / 1000;
document.getElementById('sh1').innerHTML='It took ' + seconds + ' seconds (from ' + marks[0] + ' to ' + marks[1] + ') to load the dams.';
numsleeps=0;
}
function markit() {
marks[imark]=d;
imark++;
console.log('mark ' + imark + ': ' + d);
if (imark == 2) { setTimeout(betw, 800); imark=0; }
}
demo();
</script>
</head>
<body>
<h1>Sleeping and Doing via Promise Object - RJM Programming - July, 2021 <span id=sh1></span></h1>
<table style=width:100%;height:90%;><tr><td><iframe onclick="markit();" id=lif src=./analogue_clock.htm style=width:100%;height:100%;></iframe></td><td><iframe id=rif src=./dams_usa.html?rand=7564675 style=width:100%;height:100%;></iframe></td></tr>
</body>
</html>
Previous relevant Web Application Controlled Progress Cursor Primer Tutorial is shown below.
We had occasion to revisit the card game (and more) recent web application exploits highlighted in the recent Just Javascript Card Game Cursor Tutorial thread of blog postings and shaped to play Bridge via …
https://www.rjmprogramming.com.au/HTMLCSS/cards_usefocus.html?card_memories=04.1:ara
… and was “personally relatively” happy up to the first Javascript prompt popup window. Huh?! What’s with “personally relatively”? Can I be serious? Well, I’m insulted!
The thing is, I don’t mind, when I’m writing the code (funny about that?!) very complex and convoluted prompt window instructions and options. But …
- not everybody is willing to read such long diatribes
- actions can speak louder than words, so we figure between those first two prompt windows in a Bridge or 500 card game, it would be beneficial to show a “progress cursor” (ie. usually associated with the user waiting for a process to finish) between the first and second prompt windows to help show the players there could be waiting and irrelevant players turning away should all four players want to play fairly in their game
It was an interesting Javascript coding exercise …
- (sort of) overload the “prompt” function with our inhouse “superprompt” function via …
- globally replace ” prompt(” with ” superprompt(“
- globally replace “=prompt(” with “=superprompt(“
- add the following Javascript code …
var aheadoffirst=(('' + document.URL.replace('?', '&').indexOf('&card_') != -1) ? trueize() : 0);
function dbcpp() {
if (aheadoffirst == 2) {
document.body.style.cursor='progress'; // between first and second prompt windows
setTimeout(dbcpp, 1000);
} else if (aheadoffirst == 0) {
document.body.style.cursor='pointer';
} else {
document.body.style.cursor='pointer';
setTimeout(dbcpp, 1000);
}
}
function trueize() { // bit like a promise
setTimeout(dbcpp, 1000);
return 1;
}
function superprompt(opone, optwo) {
if (aheadoffirst == 3) {
document.body.style.cursor='pointer';
aheadoffirst=0;
} else if (aheadoffirst != 0) {
aheadoffirst++;
if (aheadoffirst == 3) {
document.body.style.cursor='progress'; // between first and second prompt windows
}
}
return prompt(opone, optwo);
}
… which reminded me that we need to learn some more about the promise object.
See this in action with the changed cards_usefocus.html code behind the “Just Javascript” Memories Card Game or live run with single window (good for mobile) or default live run (for your platform, and if non-mobile it will try child popup windows).
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.