The Wrecking Crew Peering Disco Tutorial

The Wrecking Crew Peering Disco Tutorial

The Wrecking Crew Peering Disco Tutorial

Javascript makes the online wooooorrrrllllddd go around. External Javascript, we find, can help twin this wooooorrrrllllddd with another wooooorrrrllllddd in a “peer to peer” manner. After all, with …

The Wrecking Crew Disco
the changed HTML the changed HTML
the_wrecking_crew.html disco_version.html
The Wrecking Crew Disco

… the latter was based on the former, in any case, so why not apply those onerror changes (you can read about at User Controlled Dynamic Javascript YouTube Embedded API Onerror Tutorial) to “The Wrecking Crew” web application (we talked about with The Wrecking Crew Dynamic Javascript YouTube Embedded API Search Tutorial below) and then twin it with the “Disco” web application via “the glue” that is our new youtube_brady_bunch.js


// youtube_brady_bunch.js
// RJM Programming
// June, 2023
// Help out (eg. peer to peer twinning) ...
var ptplisturls=['./the_wrecking_crew.html','./disco_version.html'];
var newoptideas=[];

function capitfl(intl) {
var intwords=intl.split(' ');
var outwords=intl;
for (var mn=0; mn<intwords.length; mn++) {
outwords=outwords.replace(intwords[mn], intwords[mn].replace(intwords[mn].substring(0,1),intwords[mn].substring(0,1).toUpperCase()));
}
return outwords.replace(/\ Version$/g, '');
}

function checksytitle() {
var ols='';
var vsbn=document.URL.split('.htm')[0].split('/')[eval(-1 + document.URL.split('.htm')[0].split('/').length)].replace(/\_/g,' ');
if (document.getElementById('sytitle')) {
var hc=document.getElementById('sytitle').innerHTML.replace(/\ \;/g,' ');
ols='<option value="' + document.URL + '">' + hc + '</option>';
//alert(45);
if (hc.toLowerCase().indexOf('<select') == -1) {
//alert(145);
for (var inb=0; inb<ptplisturls.length; inb++) {
if (ptplisturls[inb].toLowerCase().indexOf(hc.toLowerCase()) != -1) {
//alert(ptplisturls[inb] + ' vs ' + hc);
if (ols.indexOf('>' + hc + '<') == -1) {
newoptideas.unshift('<option value="' + ptplisturls[inb] + '">' + hc + '</option>');
}
} else {
//alert(ptplisturls[inb] + ' Vs ' + hc);
if (ols.indexOf('>' + capitfl(ptplisturls[inb].split('.htm')[0].split('/')[eval(-1 + ptplisturls[inb].split('.htm')[0].split('/').length)].replace(/\_/g,' ')) + '<') == -1) {
newoptideas.push('<option value="' + ptplisturls[inb] + '">' + capitfl(ptplisturls[inb].split('.htm')[0].split('/')[eval(-1 + ptplisturls[inb].split('.htm')[0].split('/').length)].replace(/\_/g,' ')) + '</option>');
}
}
}
}
if (eval('' + newoptideas.length) != 0) {
for (var jnb=0; jnb<newoptideas.length; jnb++) {
ols+=newoptideas[jnb];
}
document.getElementById('sytitle').innerHTML='<select id=selsytitle onchange="location.href=this.value;">' + ols + '</select>';
newoptideas=[];
}
}
}

setInterval(checksytitle, 8000);

… called via (near bottom of body element (but the defer should mean you do not have to do that)) …


<script type='text/javascript' src='./youtube_brady_bunch.js' defer></script>

… external Javascript (called by the parent “twins” (the mind boggles?!)), with the added advantage that this application of external Javascript into the equation opens up ways for us to just change this external Javascript into the future for either …

… huh? And you thought we’d forgotten?! Shame on you!

Stop Press

We created a Yacht Rock web application, today, too, thanks to inspiration from ABC Radio Sydney’s Sonic Journey: Yacht Rock
and Wikipedia and Summer breeze yacht rock classics – Gary Martin … thank you, all. External Javascript wise, just an array needed one new member in the changed youtube_brady_bunch.js helping out the first Yacht Rock draft web application with full integration into the “peer to peer” arrangements.


Previous relevant The Wrecking Crew Dynamic Javascript YouTube Embedded API Search Tutorial is shown below.

The Wrecking Crew Dynamic Javascript YouTube Embedded API Search Tutorial

The Wrecking Crew Dynamic Javascript YouTube Embedded API Search Tutorial

Today’s work enhancing yesterday’s The Wrecking Crew Dynamic Javascript YouTube Embedded API Peer Genericity Tutorial progress for the recently “made over” “The Wrecking Crew” and “Disco” web applications is not only to do with YouTube video …

  • shoring up the search functionality (in that top textbox), now “subcontracting that out” to …
  • the integration functionality with …

… the last talked about Karaoke YouTube Video Search Update Tutorial HTML and Javascript changed karaoke_youtube_api.htm web application with the cosy YouTube search relationship it has. In turn, integration goes the other way around as well via a multiple dropdown select mode via a new “Grid?” button mode of use, including the cute …


if multiple dropdown choice number correspond to number of clicks used, that order of clicking becomes the video order within that (potentially) 3x3 grid

… as we sometimes are very interested in “order” and “context” and “sequencing” with video content …

The Wrecking Crew Disco
the changed HTML the changed HTML
the_wrecking_crew.html disco_version.html
The Wrecking Crew Disco


Previous relevant The Wrecking Crew Dynamic Javascript YouTube Embedded API Peer Genericity Tutorial is shown below.

The Wrecking Crew Dynamic Javascript YouTube Embedded API Peer Genericity Tutorial

The Wrecking Crew Dynamic Javascript YouTube Embedded API Peer Genericity Tutorial

Today we are genericizing (and thereby personalising) on top of the work of The Wrecking Crew Dynamic Javascript YouTube Embedded API Web Inspector Tutorial the recently “made over” “The Wrecking Crew” and “Disco” YouTube IFrame Player API web applications, which now have a “peer” relationship, by allowing for …

  • comma separated YouTube video ID list (that can be entered into the topmost textbox)
  • vertical bar delimited user defined video list Title

But what are we getting at by saying we are developing a peer relationship? It means via new select (dropdown) elements up the top of each, have URL values that when selected, can navigate you to, and the form of these URLs can be …

  • the “home” default web application
  • the “other” web application (ie. for “The Wrecking Crew” the “other” web application is “Disco”, and vice versa)
  • user defined comma separated YouTube video ID list URLs …

… saved away for optional recall via window.localStorage logic, that is reflected by a hard coded web application title within a span element mapped to a select (dropdown) element within that same span element when the user has stored such a user defined list in localStorage …


var ourtwc=location.search.split('aprefix=')[1] ? decodeURIComponent(location.search.split('aprefix=')[1].split('&')[0]) : 'disco';
var yourtwc="Disco";
if (ourtwc != 'disco') { yourtwc=location.search.split('atitle=')[1] ? decodeURIComponent(location.search.split('atitle=')[1].split('&')[0]) : "Your List"; }
if (document.URL.indexOf('clear=') != -1) {
if (window.localStorage) {
localStorage.removeItem('list' + ourtwc);
localStorage.removeItem(ourtwc + 'list');
if (ourtwc != 'disco') { location.href=document.URL.split('?')[0].split('#')[0]; }
}
}

function ddit(yts) {
var outsug=yts, thisttl='', outyts=yts, yoursug='', sofarc='', altttl='';
var ione=1;
var lastlslook=' ';
if (window.localStorage) {
while (lastlslook != '') {
outsug=('000' + ione).slice(-3);
lastlslook=decodeURIComponent(('' + localStorage.getItem('list' + outsug))).replace(/\+/g,' ').replace(/^null$/g,'').trim();
console.log('yts=' + yts + ' and ione=' + ione + ' and lastlslook=' + lastlslook);
if (lastlslook.toLowerCase().indexOf('http') == 0) {
sofarc+=lastlslook;
//alert(lastlslook + ' ... ' + outyts);
if (lastlslook.indexOf('&atitle=') != -1) {
thisttl=decodeURIComponent(lastlslook.split('&atitle=')[1].split('&')[0].split('#')[0]);
} else {
thisttl=outsug;
}
if (outyts.indexOf('<SELECT') == -1) {
if (yts == 'Disco') {
console.log('a');
outyts="<SELECT id=syztitle onchange='location.href=this.value;'><option value='" + document.URL.split('?')[0].split('#')[0] + "'>Disco</option><option value='" + lastlslook.split('#')[0] + "'>" + thisttl + "</option><option value='" + lastlslook.split('#')[0].replace('?','?clear=y&') + "'>-" + thisttl + "</option><option value='" + document.URL.split('?')[0].split('#')[0].replace('/disco_version.','/the_wrecking_crew.') + "'>The Wrecking Crew</option></SELECT>";
} else if (document.URL.indexOf('atitle=') != -1) {
altttl=decodeURIComponent(document.URL.split('atitle=')[1].split('&')[0].split('#')[0]);
console.log('ta:' + thisttl);
outyts="<SELECT id=syztitle onchange='location.href=this.value;'><option value='" + document.URL.split('#')[0] + "'>" + altttl + "</option><option value='" + document.URL.split('#')[0].replace('?','?clear=y&') + "'>-" + altttl + "</option><option value='" + document.URL.split('?')[0].split('#')[0] + "'>Disco</option><option value='" + lastlslook.split('#')[0] + "'>" + thisttl + "</option><option value='" + lastlslook.split('#')[0].replace('?','?clear=y&') + "'>-" + thisttl + "</option><option value='" + document.URL.split('?')[0].split('#')[0].replace('/disco_version.','/the_wrecking_crew.') + "'>The Wrecking Crew</option></SELECT>";
} else if (document.URL.indexOf('aprefix=') != -1) {
altttl=decodeURIComponent(document.URL.split('aprefix=')[1].split('&')[0].split('#')[0]);
console.log('tb:' + thisttl);
outyts="<SELECT id=syztitle onchange='location.href=this.value;'><option value='" + document.URL.split('#')[0] + "'>" + altttl + "</option><option value='" + document.URL.split('#')[0].replace('?','?clear=y&') + "'>-" + altttl + "</option><option value='" + document.URL.split('?')[0].split('#')[0] + "'>Disco</option><option value='" + lastlslook.split('#')[0] + "'>" + thisttl + "</option><option value='" + lastlslook.split('#')[0].replace('?','?clear=y&') + "'>-" + thisttl + "</option><option value='" + document.URL.split('?')[0].split('#')[0].replace('/disco_version.','/the_wrecking_crew.') + "'>The Wrecking Crew</option></SELECT>";
} else {
console.log('b');
outyts="<SELECT id=syztitle onchange='location.href=this.value;'><option value='" + lastlslook.split('#')[0] + "'>" + thisttl + "</option><option value='" + lastlslook.split('#')[0].replace('?','?clear=y&') + "'>-" + thisttl + "</option><option value='" + document.URL.split('?')[0].split('#')[0] + "'>Disco</option><option value='" + document.URL.split('?')[0].split('#')[0].replace('/disco_version.','/the_wrecking_crew.') + "'>The Wrecking Crew</option></SELECT>";
}
} else if (lastlslook.toLowerCase().indexOf('http') == 0 && outyts.indexOf("<option value='" + lastlslook.split('#')[0] + "'>" + thisttl + "</option>") == -1) {
outyts=outyts.replace("</SELECT>","<option value='" + lastlslook.split('#')[0] + "'>" + thisttl + "</option><option value='" + lastlslook.split('#')[0].replace('?','?clear=y&') + "'>-" + thisttl + "</option></SELECT>");
}
} else if (outyts.indexOf('<SELECT') == -1) {
if (yts != 'Disco' && document.URL.indexOf('clear=') == -1) {
console.log('Yts=' + yts + ' and ione=' + ione + ' and lastlslook=' + lastlslook);
if (yourtwc.replace("Disco","") != '') {
thisttl=yourtwc;
} else {
thisttl=outsug;
}
console.log('c');
outyts="<SELECT id=syztitle onchange=location.href=this.value;><option value='" + document.URL.split('#')[0] + "'>" + thisttl + "</option><option value='" + document.URL.split('#')[0].replace('?','?clear=y&') + "'>-" + thisttl + "</option><option value='" + document.URL.split('?')[0].split('#')[0] + "'>Disco</option><option value='" + document.URL.split('?')[0].split('#')[0].replace('/disco_version.','/the_wrecking_crew.') + "'>The Wrecking Crew</option></SELECT>";
console.log('Yts=' + yts + ' and outsug=' + outsug + ' and thisttl=' + thisttl);
localStorage.setItem('list' + outsug, encodeURIComponent(document.URL.split('#')[0]));
lastlslook=decodeURIComponent(('' + window.localStorage.getItem('list' + outsug))).replace(/\+/g,' ').replace(/^null$/g,'').trim();
console.log('YTs=' + yts + ' and outsug=' + outsug + ' and lastlslook=' + lastlslook);
sofarc+=document.URL.split('#')[0];
yoursug=outsug;
}
} else {
}
ione++;
}
}
if (yoursug != '') {
if (sofarc.indexOf(document.URL.split('#')[0]) == -1 && document.URL.indexOf('clear=') == -1) {
console.log('5');
window.localStorage.setItem('list' + yoursug, encodeURIComponent(document.URL.split('#')[0]));
}
} else if (yts != 'Disco' && sofarc.indexOf(document.URL.split('#')[0]) == -1 && document.URL.indexOf('clear=') == -1) {
console.log('15');
window.localStorage.setItem('list' + outsug, encodeURIComponent(document.URL.split('#')[0]));
}
if (outyts.toLowerCase().indexOf('<select') == 0) {
tselih=outyts;
setTimeout(muchlater, 2000);
}
return outyts;
}

function undostop() {
document.getElementById('sytitle').innerHTML=ddit(yourtwc);
// rest of function code
}

setTimeout(undostop, 9000);

… as per … table above.


Previous relevant The Wrecking Crew Dynamic Javascript YouTube Embedded API Web Inspector Tutorial is shown below.

The Wrecking Crew Dynamic Javascript YouTube Embedded API Web Inspector Tutorial

The Wrecking Crew Dynamic Javascript YouTube Embedded API Web Inspector Tutorial

With the last couple of days of blog posting, including yesterday’s The Wrecking Crew Dynamic Javascript YouTube Embedded API Onerror Tutorial we risked the ire of many an internet reader by including in the blog posting itself HTML iframes of those twin “The Wrecking Crew” and “Disco” YouTube IFrame Player API web applications. Por que? Well, it is a bit of a sin to not give fair warning of future sound coming from a computer source of the internet. And, unless we were dreaming, earlier on this morning Australian Eastern Standard Time, that faux pas was possible. Sorry, if you were caught out.

We noticed the problem on an iPad, but never, so far, on our MacBook Pro. And this is quite possible. The stringency with which Apple tries to stop this happening with iOS is very noticeable to this programmer. It is understandable, though, that Apple would want to precede the creation of sound after an action (like a button press), so that a real human is part of the decision making.

We weren’t there ready with the tools to “scoop up” the information necessary to debug our “one off” iPad disappointment, alas. What is the next best? We have a lot of time for the web inspectors of the web browsers back at macOS (for the MacBook Pro). Team their use with Javascript …


console.log([Informational messaging]);

… (not alert([Informational messaging]); as we often settle for, but not today with the emphasis on trying to understand …

  • the order
  • the relationship

… among the YouTube IFrame Player API events, without the interference alert([Informational messaging]); (Javascript popup windows) could cause) … and you have a powerful debugging tool at your disposal. Even better if you can test on the iPad itself with the macOS Safari web browser Web Inspector (and the Apple white lead) as outlined with HTML5 Web Audio Piano Mobile Safari Web Inspector Debug Tutorial.


function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.BUFFERING) { // && !done) {
curplay=curplay;
} else if (event.data == YT.PlayerState.CUED) { // && !done) {
curplay=curplay;
} else if (event.data == YT.PlayerState.PAUSED) { // && !done) {
//curv=eval(eval(1 + curv) % eval('' + 9));
//alert('' + curv);
if (curplay != '') { precv=curv; precp=curplay; }
curplay='';
//vplayer[curv].playVideo();
} else if (event.data == YT.PlayerState.PLAYING) { // && !done) {
if (dostop) {
console.log('onPlayerStateChange: dostop');
stopthese.push(event.target);
setTimeout(stopVideo, 6000);
} else if (curplay == '') {

if (precp == event.target.getVideoUrl().split('=')[1].split('&')[0]) {
//alert(1);
console.log('onPlayerStateChange: 2;' +precp);
curplay=precp;
curv=precv;
} else if (1 == 6) {
//alert(11);
mid=precv;
if (1 == 2) { vplayer[curv].mute(); }
}

curplay=event.target.getVideoUrl().split('=')[1].split('&')[0];
curdur=eval('' + event.target.getDuration());
console.log('onPlayerStateChange: 3;precp=' + precp + ';' + event.target.getVideoUrl() + ';' + curplay + ';' + curdur);
for (var ijj=0; ijj<yid.length; ijj++) {
if (yid[ijj].indexOf(curplay + '|') == 0) { curv=ijj; }
}


if (mid >= 0) { setTimeout(midit, 2000); }


//}
//alert(curplay + ' ... ' + curv);
} else {
//console.log('' + eval('' + event.target.getCurrentTime()) + ' >= ' + curdur);
if (eval(2 + eval('' + event.target.getCurrentTime())) >= curdur) {
// alert('ready');
vplayer[curv].mute();
console.log('onPlayerStateChange: 4;' + vplayer[curv].getVideoData().title + ';mute;seekTo;unMute;play');
curv=eval(eval(1 + curv) % eval('' + 9));
//alert('' + curv);
//vplayer[curv]=eval("new YT.Player('vplayer" + eval(1 + curv) + "', { height: '260', width: '33%', videoId: '" + yid[curv] + "', events: { 'onReady': onPlayerReady, 'onStateChange': onPlayerStateChange }})");
curplay='';
vplayer[curv].seekTo(0,true);
vplayer[curv].unMute();
vplayer[curv].playVideo();
//alert('2:' + curv);
}
}
//done = true;
} else if (curplay != '') {
//console.log('' + eval('' + event.target.getCurrentTime()) + ' >= ' + curdur);
if (eval(2 + eval('' + event.target.getCurrentTime())) >= curdur) {
// alert('Ready');
vplayer[curv].mute();
console.log('onPlayerStateChange: 5;' + vplayer[curv].getVideoData().title + ';mute;seekTo;unMute;play');
curv=eval(eval(1 + curv) % eval('' + 9));
//alert('' + curv);
curplay='';
vplayer[curv].seekTo(0,true);
vplayer[curv].unMute();
vplayer[curv].playVideo();
//alert('3:' + curv);
}
}
}

… leading to the eventual three codeline solution you see below …


// 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='';
if (!lsdone) {
lsdone=true;
scont=scont.replace('</option>', '</option>' + tryls());
//alert(('' + scont.split('</option>').length));
}
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;
console.log('onPlayerReady:' + uri + ';' + dis + '|' + cti + '|' + gvd);
yid[jis]+='|' + dis + '|' + cti + '|' + gvd;
//alert(yid[jis]);
splaycnt++;
if (splaycnt > 9) {
if (scont.indexOf(yid[jis]) == -1) {
prv=scont;
if (scont.indexOf('>' + gvd + '<') == -1) { scont=prv.split('</option>')[0] + '</option><option id="' + yid[jis].split('|')[0] + '" onclick="oclick(this);" value="' + yid[jis] + '">' + gvd + '</option>' + prv.replace(prv.split('</option>')[0] + '</option>',''); }
}
} else {
if (scont.indexOf('>' + gvd + '<') == -1) { scont+='<option id="' + yid[jis].split('|')[0] + '" onclick="oclick(this);" value="' + yid[jis] + '">' + gvd + '</option>'; }
if (splaycnt == 9 && yid.length > 9) {
for (iyi=0; iyi<yid.length; iyi++) {
if (scont.indexOf(yid[iyi]) == -1) {
try {
huht=vplayer[splaycnt].getVideoData().title;
prv=scont;
if (scont.indexOf('>' + gvd + '<') == -1) { scont=prv.split('</option>')[0] + '</option><option id="' + yid[iyi].split('|')[0] + '" value="' + yid[iyi] + '" onclick="oclick(this);">' + gvd + '</option>' + prv.replace(prv.split('</option>')[0] + '</option>',''); }
} catch(rtde) {
}
}
}
}
}
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
event.target.mute();
}

event.target.playVideo();
event.target.mute();
}

… and in action with today’s tutorial picture … and … see table up the webpage.


Previous relevant The Wrecking Crew Dynamic Javascript YouTube Embedded API Onerror Tutorial is shown below.

The Wrecking Crew Dynamic Javascript YouTube Embedded API Onerror Tutorial

The Wrecking Crew Dynamic Javascript YouTube Embedded API Onerror Tutorial

Again, both yesterday’s The Wrecking Crew Dynamic Javascript YouTube Embedded API Ajax Tutorial and User Controlled Dynamic Javascript YouTube Embedded API Ajax Tutorial before it can benefit from today’s improvement idea regarding videos whose creators have stopped their YouTube videos from being able to be launched from non-YouTube websites, as we are asking of YouTube content we link to with our YouTube IFrame Player API driven twin web applications. What’s needed to avoid the …

Video unavailable
Watch this video on YouTube.
Playback on other websites has been disabled by the
video owner.

…. issue we are talking about here? That issue is annoying in two parts …

  1. cannot play video in that embedded iframe element … and …
  2. if playing on a non-mobile platform, encountering an iframe with this error halts any thoughts of “continuous play” (like a playlist that repeats and keeps playing, like on the radio) that the user may like (on in the background, while they do something else, for instance)

Well, it’s an event we have to “kick into play”, that you ordinarily might be able to ignore, as per


vplayer.push(eval("new YT.Player('vplayer" + ii + "', { height: '260', width: '33%', videoId: '" + yid[-1 + ii] + "', playerVars: { autoplay: 0, controls: 1, disablekb: 1, loop: 0, modestbranding: 0, showinfo: 0, autohide: 1, color: 'white', iv_load_policy: 3, theme: 'light', rel: 0 }, events: { 'onError': onProblem, 'onReady': onPlayerReady, 'onStateChange': onPlayerStateChange }})"));

… calling on a new Javascript event function …


function onProblem(event) {
console.log(event.target.f);
console.log(event.target.l);
var pvidid='', embedurl='', vtitle='';
if (event.target.f.outerHTML.indexOf('embed/') != -1) {
pvidid=event.target.f.outerHTML.split('embed/')[1].split('?')[0];
}
if (pvidid != '') {
if (lastscont.indexOf(pvidid) != -1) {
// D-TC8CRCIKM|194|0|The Grass Roots - Sooner Or Later - [original STEREO]
//alert(lastscont.split(pvidid)[1]);
var vbs=lastscont.split(pvidid)[1].split('|');
if (eval('' + vbs.length) >= 4) {
vtitle='' + vbs[3];
}
}
if (event.target.f.outerHTML.indexOf(' class="player-unavailable"') != -1 || pvidid != '') {
embedurl='http' + event.target.f.outerHTML.split('http')[1].split('"')[0];
if (document.URL.toLowerCase().indexOf('rjmprogramming.com.au/') != -1) {
var zzhr = new XMLHttpRequest();
var zzform=new FormData();
zzform.append('inline', '');
zzform.append('to', 'rmetcalfe@rjmprogramming.com.au');
zzform.append('subj', 'Please find alternative to YouTube ' + pvidid + ' in relevant code ... ' + vtitle);
zzform.append('body', encodeURIComponent('Problem video is first iframe of ... ' + String.fromCharCode(10) + String.fromCharCode(10) + document.URL.split('#')[0].split('?')[0] + '?hastoinclude=' + pvidid + String.fromCharCode(10) + String.fromCharCode(10) + 'Problem YouTube video is ... ' + String.fromCharCode(10) + String.fromCharCode(10) + "https://www.youtube.com/watch?v=" + pvidid));
zzhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
zzhr.send(zzform);
//var remurl='mailto:rmetcalfe@rjmprogramming.com.au?subject=' + encodeURIComponent('Please find alternative to YouTube ' + pvidid + ' in relevant code ... ' + vtitle) + '&body=' + encodeURIComponent('Problem video is first iframe of ... ' + String.fromCharCode(10) + String.fromCharCode(10) + document.URL.split('#')[0].split('?')[0] + '?hastoinclude=' + pvidid + String.fromCharCode(10) + String.fromCharCode(10) + 'Problem YouTube video is ... ' + String.fromCharCode(10) + String.fromCharCode(10) + "https://www.youtube.com/watch?v=" + pvidid);
//if (('' + document.getElementById('badvideo').href).indexOf('mailto') != 0) { document.getElementById('badvideo').href=remurl; document.getElementById('badvideo').click(); }
} else {
var emurl='mailto:rmetcalfe@rjmprogramming.com.au?subject=' + encodeURIComponent('Please find alternative to YouTube ' + pvidid + ' in relevant code ... ' + vtitle) + '&body=' + encodeURIComponent('Problem video is first iframe of ... ' + String.fromCharCode(10) + String.fromCharCode(10) + document.URL.split('#')[0].split('?')[0] + '?hastoinclude=' + pvidid + String.fromCharCode(10) + String.fromCharCode(10) + 'Problem YouTube video is ... ' + String.fromCharCode(10) + String.fromCharCode(10) + "https://www.youtube.com/watch?v=" + pvidid);
if (('' + document.getElementById('badvideo').href).indexOf('mailto') != 0) { document.getElementById('badvideo').href=emurl; document.getElementById('badvideo').click(); }
}
}
}
}

… which, as you may have gleaned, provides us an email mechanism by which we, here at RJM Programming, can be informed about when a YouTube video ID we reference, perhaps into the future, becomes restrictive, this way (and hopefully we can find an alternative YouTube video ID to use)see table up the webpage.


Previous relevant The Wrecking Crew Dynamic Javascript YouTube Embedded API LocalStorage Tutorial is shown below.

The Wrecking Crew Dynamic Javascript YouTube Embedded API LocalStorage Tutorial

The Wrecking Crew Dynamic Javascript YouTube Embedded API LocalStorage Tutorial

Both yesterday’s The Wrecking Crew Dynamic Javascript YouTube Embedded API Ajax Tutorial and User Controlled Dynamic Javascript YouTube Embedded API Ajax Tutorial before it can benefit from today’s improvement idea. That idea involves data storage that stays on the “client” side of the “client/server” web application architecture. Yes, as you may have noticed, these web applications were not offering all the options they could for those user controlled entry list dropdowns at the bottom.

We use the window.localStorage now to gradually store all the content those dropdowns could hold. So it is as if the web application “learns its lines” over time with these improvements


var lsdone=false;
if (document.URL.indexOf('clear=') != -1) {
if (window.localStorage) {
window.localStorage.removeItem('twclist');
}
}

function lessopt(selih) {
var outih=selih, opttoadd='';
var opta=selih.split('</option>');
if (opta.length > 1) {
outih='';
for (var iop=0; iop<opta.length; iop++) {
if (opta[iop] != '') {
opttoadd='<option' + opta[iop].split('<option')[1] + '</option>';
if (outih.indexOf(opttoadd) == -1) {
outih+=opttoadd;
}
}
}
}
return outih;
}

function tryls() {
var lastscont='';
if (window.localStorage) {
lastscont=decodeURIComponent(('' + window.localStorage.getItem('twclist'))).replace(/\+/g,' ').replace(/^null$/g,'');
}
return lastscont;
}

function setls(towhat) {
var lastscont='';
if (window.localStorage) {
window.localStorage.setItem('twclist', encodeURIComponent(towhat));
}
return lastscont;
}


// 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='';
if (!lsdone) {
lsdone=true;
scont=scont.replace('</option>', '</option>' + tryls());
}

// Rest of code
}


function undostop() {
document.getElementById('xshuffle').style.visibility='visible';
bprefix=topics.replace(/\|/g, ', ');
if (bprefix != '') {
var huhb=document.getElementById('wshuffle').innerHTML;
document.getElementById('wshuffle').innerHTML=bprefix + ', ' + huhb;
}
document.getElementById('wshuffle').style.visibility='visible';
document.getElementById('pshuffle').style.visibility='visible';
document.getElementById('qshuffle').style.visibility='visible';
document.getElementById('rshuffle').style.visibility='visible';
if (yid.length > 9 || 1 == 1) {
var tdsl=document.getElementsByTagName('td');
document.getElementById('oone').innerHTML=document.getElementById('oone').innerHTML.replace(' 9 slots available)', ' 9 slots available, ' + tdsl.length + ' total)');
document.getElementById('ashuffle').style.visibility='visible';
document.getElementById('zshuffle').style.visibility='visible';
scont=lessopt(scont);
document.getElementById('sshuffle').size=eval(-1 + eval('' + scont.split('</option>').length));
document.getElementById('sshuffle').innerHTML=scont;
setls(document.getElementById('sshuffle').innerHTML.replace(document.getElementById('sshuffle').innerHTML.split('</option>')[0] + '</option>', ''));
document.getElementById('dshuffle').style.visibility='visible';
}
document.getElementById('rshuffle').focus();
dostop=false;
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
//alert(1);
//const huhss=document.querySelectorAll('video');
//alert(11);
for (var hdiv=0; hdiv<vplayer.length; hdiv++) {
//alert(111);
vplayer[hdiv].unMute();
//alert(hdiv.id);
}
//.webkitEnterFullScreen();
}
}

… gleaning information about the videos as they load them (especially the video titles and durations) via the YouTube Embedded Iframe API code for … see table up the webpage.


Previous relevant User Controlled Dynamic Javascript YouTube Embedded API Ajax Tutorial is shown below.

User Controlled Dynamic Javascript YouTube Embedded API Ajax Tutorial

User Controlled Dynamic Javascript YouTube Embedded API Ajax Tutorial

Around here we have our favourite Javascript and PHP function names. And in that list, the Javascript “ajaxit([argument1])” features strongly and commonly. After reaching below the sink After talking excitedly to the kitchen taps about my plans … oddly, receiving no reply … probably because it’s a Monday here … we expect … we use that Javascript client Ajax approach that can do for you what you would often call on a serverside language, like PHP, to do?! Anyone, anyone? No, Barbara Woodhouse, we do not wrelease the tap dancing dogs on Mondays … ever … any more serious suggestions please? Yes, Jesse James Garrett it’s interesting your blurtings include …

the asynchronous technology behind emerging services like Google Maps and Google Suggest, as well as the resulting user experience which made it possible to browse without interruption by eliminating the reloading of the whole page

… though I’d like you to run a plagorism checker on all “blurtings” and “lerts” for the next lesson please.

Yes, under certain conditions, Ajax (methodologies) can retrieve information and not have to leave what you are interacting with on the current webpage, to do this.

Can you imagine how we might apply this with our current project? Yes, patently not everyone is in the mood for “Disco”, especially on the first draft way back when, when we allowed sound to happen before a decently “flagged” button press to forewarn … a fairly big “Internet sin”, since fixed. And so, we now add HTML input textbox (ie.type=text) element, with onblur event “ajaxit([argument1])” logic (passing across the textbox’s value) as per …


var zhr=null;
var url='';
var zok=0;

function ajaxit(qsel) {
if (qsel != '') {
url="//www.rjmprogramming.com.au/HTMLCSS/legend_via_map.php?url=" + encodeURIComponent("http://www.youtube.com/results?search_query=" + encodeURIComponent(qsel));
if (!zhr) {
zhr = getXMLHttpRequest();
}

if (zhr != null) {
zhr = zhr;
} else {
try {
zhr = new ActiveXObject("Msxml2.XMLHTTP");
} catch (othermicrosoft) {
try {
zhr = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
zhr = false;
}
}
}


if (zhr) {
if (url != '') {
zok=0;
zhr.open("GET", url, true);
zhr.onreadystatechange = showStuff;
zhr.send(null);
url='';
}
} else {
zok = 1; //alert("Sorry ... no XMLHttpRequest possible");
}
}
}

… to add new concepts into the mix of option (sub)elements offered off that aforesaid mentioned (multiple selection mode) dropdown (of YouTube videos). As an optional “off default workflow” piece of functionality we show it prominently (above the fold) now, as well as “below the fold” where the dropdown is positioned on the webpage of the Ajax changed disco_version.html‘s live run.

Adding to yesterday’s User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial


Previous relevant User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial is shown below.

User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial

User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial

We think that whenever you …

  • deprive many people of “order” in their lives … they’ll crave for (and maybe seek out) “order” … and when you …
  • deprive many people of “randomosity” in their lives … they’ll crave for (and maybe seek out) “randomosity”

… and so we see a mix of both in a web application as an advantage. Today, for the first time we can remember, extending onto yesterday’s User Controlled Dynamic Javascript YouTube Embedded API Tutorial functionality, definitely lacking some “order” we feel, we’ve allowed a …

  • select “dropdown” element …
  • multiple mode … have its …
  • button press “finish of selections” event logic …

    function process(bsin) {
    var jj=0, mbo='', mlist='', mdelim='', vscnt=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 != '') {
    jj++;
    vscnt++;
    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) {
    if (oclickcnt == vscnt) { mlist=olist; }
    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('/&','/?');
    }
    oclickcnt=0;
    occ=[];
    olist='';
    odelim='';
    }
  • take into account the order the user clicked select element option elements …

    var oclickcnt=0;
    var occ=[];
    var olist='';
    var odelim='';

    function oclick(opto) {
    oclickcnt++;
    olist+=odelim + opto.id.split('|')[0];
    odelim=',';
    }

    … option element onclick event Javascript event logic… so long as …
  • these two or more clicks/touches on option elements (via their onclick event logics) (total in) number (to) the same (total) as the final number of options selected (ie. most “shift” key arrangement selections cannot be catered for in this logic, but totally “ctrl” (Windows) / “command” (macOS) key may work)

… allowing for the user to control the video list, and its order.

And on non-mobile platforms, we allow for a natural “sequencing” of play, once the first video is played and unmuted. That way, on non-mobile, your changed disco_version.html live run web application can act like a continuous (radio like) “stream” of music. Even so, on non-mobile, a user can “pause” a video, and start another via their own user actions, and the “stream” sequencing will change to fit in with the changed arrangements.


Previous relevant User Controlled Dynamic Javascript YouTube Embedded API Tutorial is shown below.

User Controlled Dynamic Javascript YouTube Embedded API Tutorial

User Controlled Dynamic Javascript YouTube Embedded API Tutorial

The recent Dynamic Javascript and the YouTube Embedded API Tutorial showed the great YouTube IFrame Player API in action, including … and this dovetails well into today’s work … no advertisements.

A lot of us will know how great YouTube playlists are. Today, we offer a(n example of) …

  • an up to 9 “Disco Version” random array of YouTube videos that can be played ina session …
  • from a possible array of 24 table cell slots (10-24 not shown, but “duration”able behind the scenes) …
  • the 15 not randomly picked available to the user in a dropdown selection they can, optionally …
    1. pick one from,click a “Shuffle” button, and a randomized list of 8 others is headedby your selected video … or …
    2. pick more than one and the first (up to 9) forms your ordered selection of playable videos

… and the progress today leaves you controlling when to play the videos, yourself, clicking YouTube play buttons to make that happen.

Enjoy the “how we got there” disco_version.html upbeat disco selection live run link.


Previous relevant Dynamic Javascript and the YouTube Embedded API Tutorial is shown below.

Dynamic Javascript and the YouTube Embedded API Tutorial

Dynamic Javascript and the YouTube Embedded API Tutorial

Webpages without Javascript are generally pretty static and boring. Javascript is that dynamic client addition to webpage functionality, but perhaps you only think of it as that statically written part of the webpage unable to be reloaded into effect after that initial webpage load. Well, that is not taking into account Javascript such as …


<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
</script>

… taken from the excellent YouTube IFrame Player API we really like to use around here to embed and control YouTube videos embedded into an HTML iframe element.

In today’s small extension of that we load nine such HTML iframe embedded YouTube videos into a 3×3 grid. We resisted the previous Brady Bunch usage of such an arrangement (perhaps you’ll be sad to hear?!) in favour of showing you a “collage” of video snippets from one of my favourite films ever, Mr Smith Goes to Washington.

We hope the HTML and Javascript dynamic_js.html‘s code will be food for thought, that you can test for yourself at this live run link.

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.


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.

Posted in eLearning, Event-Driven Programming, OOP, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

User Controlled Dynamic Javascript YouTube Embedded API Onerror Tutorial

User Controlled Dynamic Javascript YouTube Embedded API Onerror Tutorial

User Controlled Dynamic Javascript YouTube Embedded API Onerror Tutorial

We happened to be retrying our YouTube IFrame Player API based web application of User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial, brushing up on the moves?! 🕺 We’ll fix the light fitting later.

It’s been a while, and we think YT Player Onerror event arrangements …


vplayer.push(eval("new YT.Player('vplayer" + ii + "', { height: '260', width: '33%', videoId: '" + yid[-1 + ii] + "', playerVars: { autoplay: 0, controls: 1, disablekb: 1, loop: 0, modestbranding: 0, showinfo: 0, autohide: 1, color: 'white', iv_load_policy: 3, theme: 'light', rel: 0 }, events: { 'onError': onProblem, 'onReady': onPlayerReady, 'onStateChange': onPlayerStateChange }})"));

… might have changed, or we didn’t test on Windows or some web browser platforms, because some YouTube video IDs pointed to videos whose content was blocked, and we were not informed via email, as we’d coded for. So, we …

  • remedied the YT Player onerror event logic (using more event.data member and event.target.getVideoUrl() method rather than event.target.fanything) …

    function onProblem(event) {
    problemcount++;
    //if (problemvid.replace(',','') != '' && !problemthere) { problemthere=true; setTimeout(postonp, 8000); }
    console.log(event.target.f);
    console.log(event.target.l);
    var pvidid='', embedurl='', vtitle='';
    //if (event.target.f) {
    // alert('preHuh:' + event.target.f.outerHTML);
    //}
    console.log('event.data: ' + event.data + ' ' + event.target.getVideoUrl());
    pvidid=event.target.getVideoUrl().split('=')[1];
    if (pvidid == '') {
    if (event.target.f.outerHTML.indexOf('embed/') != -1) {
    pvidid=event.target.f.outerHTML.split('embed/')[1].split('?')[0];
    }
    }
    if (pvidid != '') {
    if (lastscont.indexOf(pvidid) != -1) {
    // D-TC8CRCIKM|194|0|The Grass Roots - Sooner Or Later - [original STEREO]
    //alert(lastscont.split(pvidid)[1]);
    var vbs=lastscont.split(pvidid)[1].split('|');
    if (eval('' + vbs.length) >= 4) {
    vtitle='' + vbs[3];
    }
    }
    if ((('' + event.data + ' ').substring(0,1) == '1' || ('' + event.target.f.outerHTML).indexOf(' class="player-unavailable"') != -1) || pvidid != '') {
    if (1 == 1) {
    embedurl=event.target.getVideoUrl()
    } else {
    embedurl='http' + event.target.f.outerHTML.split('http')[1].split('"')[0];
    }
    if (document.URL.toLowerCase().indexOf('rjmprogramming.com.au/') != -1) {
    var zzhr = new XMLHttpRequest();
    var zzform=new FormData();
    zzform.append('inline', '');
    zzform.append('to', 'rmetcalfe@rjmprogramming.com.au');
    zzform.append('subj', 'Please find alternative to YouTube ' + pvidid + ' in relevant code ... ' + vtitle);
    zzform.append('body', encodeURIComponent('Problem video is first iframe of ... ' + String.fromCharCode(10) + String.fromCharCode(10) + document.URL.split('#')[0].split('?')[0] + '?hastoinclude=' + pvidid + String.fromCharCode(10) + String.fromCharCode(10) + 'Problem YouTube video is ... ' + String.fromCharCode(10) + String.fromCharCode(10) + "https://www.youtube.com/watch?v=" + pvidid));
    zzhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
    zzhr.send(zzform);
    //var remurl='mailto:rmetcalfe@rjmprogramming.com.au?subject=' + encodeURIComponent('Please find alternative to YouTube ' + pvidid + ' in relevant code ... ' + vtitle) + '&body=' + encodeURIComponent('Problem video is first iframe of ... ' + String.fromCharCode(10) + String.fromCharCode(10) + document.URL.split('#')[0].split('?')[0] + '?hastoinclude=' + pvidid + String.fromCharCode(10) + String.fromCharCode(10) + 'Problem YouTube video is ... ' + String.fromCharCode(10) + String.fromCharCode(10) + "https://www.youtube.com/watch?v=" + pvidid);
    //if (('' + document.getElementById('badvideo').href).indexOf('mailto') != 0) { document.getElementById('badvideo').href=remurl; document.getElementById('badvideo').click(); }
    } else {
    var emurl='mailto:rmetcalfe@rjmprogramming.com.au?subject=' + encodeURIComponent('Please find alternative to YouTube ' + pvidid + ' in relevant code ... ' + vtitle) + '&body=' + encodeURIComponent('Problem video is first iframe of ... ' + String.fromCharCode(10) + String.fromCharCode(10) + document.URL.split('#')[0].split('?')[0] + '?hastoinclude=' + pvidid + String.fromCharCode(10) + String.fromCharCode(10) + 'Problem YouTube video called ' + event.target.getVideoData().title + ' is ... ' + String.fromCharCode(10) + String.fromCharCode(10) + "https://www.youtube.com/watch?v=" + pvidid);
    if (document.URL.indexOf('rjmprogramming.com.au') == -1 || ('' + document.getElementById('badvideo').href).indexOf('mailto') != 0) { document.getElementById('badvideo').href=emurl; document.getElementById('badvideo').click(); }
    }
    //} else {
    //alert('huh:' + ('' + event.target.f));
    }
    //} else {
    //alert('Huh:' + ('' + event.target.f));
    }
    //alert('http' + ('' + event.target.f).split('http')[1].split('"')[0]);
    }

    … now allowing local web server testing hook into a mailto: “a” link email methodology, so that …
  • changing our Disco YouTube video list …

    yid=location.search.split('videolist=')[1] ? eval("['" + decodeURIComponent(location.search.split('videolist=')[1].split('&')[0]).replace(/\,/g,"','") + "']") : shuffle((location.search.split('alist=')[1] ? ourdecodeURIComponent(location.search.split('alist=')[1].split('&')[0]) : [('h2r59-Xmge4').replace('h2r59-Xmge4','iKr9wZpjBqE'),'yT1iDKkZNYU','S-u6qdeaPoE','Nm-ISatLDG0','Gs069dndIYk','dwxjpIJm9JM','8iwBM_YB1sE','CS9OO0S5w2k','I_izvAbhExY','xFrGuyw1V8s',('T6fVDAjs9f0').replace('T6fVDAjs9f0','5OpuZzsPBhQ'),'gQ8O9SidZbs','_QNEf9oGw8o','1ff29VSvP_s','4-Vz6tNfV1Y','Zi_XLOBDo_Y','xfmZRiePkEM','iPUmE-tne5U','m5y2GaW0MZA',('ZqaeaoGloGg').replace('ZqaeaoGloGg','rUdw7V-FC_Q'),'XKuJUxGntRI','vsBak0oCgdY','eBpYgpF1bqQ','DVDCNmdi7QI']));

    could bring us more joy

… in the changed disco_version.html live run web application can act like a continuous (radio like) “stream” of music on non-mobile platforms. Even so, on non-mobile, a user can “pause” a video, and start another via their own user actions, and the “stream” sequencing will change to fit in with the changed arrangements.


Previous relevant User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial is shown below.

User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial

User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial

We think that whenever you …

  • deprive many people of “order” in their lives … they’ll crave for (and maybe seek out) “order” … and when you …
  • deprive many people of “randomosity” in their lives … they’ll crave for (and maybe seek out) “randomosity”

… and so we see a mix of both in a web application as an advantage. Today, for the first time we can remember, extending onto yesterday’s User Controlled Dynamic Javascript YouTube Embedded API Tutorial functionality, definitely lacking some “order” we feel, we’ve allowed a …

  • select “dropdown” element …
  • multiple mode … have its …
  • button press “finish of selections” event logic …

    function process(bsin) {
    var jj=0, mbo='', mlist='', mdelim='', vscnt=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 != '') {
    jj++;
    vscnt++;
    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) {
    if (oclickcnt == vscnt) { mlist=olist; }
    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('/&','/?');
    }
    oclickcnt=0;
    occ=[];
    olist='';
    odelim='';
    }
  • take into account the order the user clicked select element option elements …

    var oclickcnt=0;
    var occ=[];
    var olist='';
    var odelim='';

    function oclick(opto) {
    oclickcnt++;
    olist+=odelim + opto.id.split('|')[0];
    odelim=',';
    }

    … option element onclick event Javascript event logic… so long as …
  • these two or more clicks/touches on option elements (via their onclick event logics) (total in) number (to) the same (total) as the final number of options selected (ie. most “shift” key arrangement selections cannot be catered for in this logic, but totally “ctrl” (Windows) / “command” (macOS) key may work)

… allowing for the user to control the video list, and its order.

And on non-mobile platforms, we allow for a natural “sequencing” of play, once the first video is played and unmuted. That way, on non-mobile, your changed disco_version.html live run web application can act like a continuous (radio like) “stream” of music. Even so, on non-mobile, a user can “pause” a video, and start another via their own user actions, and the “stream” sequencing will change to fit in with the changed arrangements.


Previous relevant User Controlled Dynamic Javascript YouTube Embedded API Tutorial is shown below.

User Controlled Dynamic Javascript YouTube Embedded API Tutorial

User Controlled Dynamic Javascript YouTube Embedded API Tutorial

The recent Dynamic Javascript and the YouTube Embedded API Tutorial showed the great YouTube IFrame Player API in action, including … and this dovetails well into today’s work … no advertisements.

A lot of us will know how great YouTube playlists are. Today, we offer a(n example of) …

  • an up to 9 “Disco Version” random array of YouTube videos that can be played ina session …
  • from a possible array of 24 table cell slots (10-24 not shown, but “duration”able behind the scenes) …
  • the 15 not randomly picked available to the user in a dropdown selection they can, optionally …
    1. pick one from,click a “Shuffle” button, and a randomized list of 8 others is headedby your selected video … or …
    2. pick more than one and the first (up to 9) forms your ordered selection of playable videos

… and the progress today leaves you controlling when to play the videos, yourself, clicking YouTube play buttons to make that happen.

Enjoy the “how we got there” disco_version.html upbeat disco selection live run link.


Previous relevant Dynamic Javascript and the YouTube Embedded API Tutorial is shown below.

Dynamic Javascript and the YouTube Embedded API Tutorial

Dynamic Javascript and the YouTube Embedded API Tutorial

Webpages without Javascript are generally pretty static and boring. Javascript is that dynamic client addition to webpage functionality, but perhaps you only think of it as that statically written part of the webpage unable to be reloaded into effect after that initial webpage load. Well, that is not taking into account Javascript such as …


<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
</script>

… taken from the excellent YouTube IFrame Player API we really like to use around here to embed and control YouTube videos embedded into an HTML iframe element.

In today’s small extension of that we load nine such HTML iframe embedded YouTube videos into a 3×3 grid. We resisted the previous Brady Bunch usage of such an arrangement (perhaps you’ll be sad to hear?!) in favour of showing you a “collage” of video snippets from one of my favourite films ever, Mr Smith Goes to Washington.

We hope the HTML and Javascript dynamic_js.html‘s code will be food for thought, that you can test for yourself at this live run link.

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.

Posted in eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

PHP Wikipedia List Scrolling Tutorial

PHP Wikipedia List Scrolling Tutorial

PHP Wikipedia List Scrolling Tutorial

We had occasion to revisit the “peer to peer” web application arrangements of the PHP Wikipedia List Genericization Tutorial thread of blog postings, and wondered whether its …

… button click event Javascript logic window.scrollBy(100,0) repercussions could be improved upon. Why? Well, within the “broad brush” design view of these web application webpages of …


<html>
<body>
<div align=center><h1> ... menu type contents ... </h1></div>
<table><tr><td> ... scrollable individual cell place information pods ... </td></tr></table>
<div align=center><iframe> ... Google Chart Map Chart Iframe ... </iframe></div>
</body>
</html>

… too many clicks of that “More … That a Way ->” button could result in menu type contents and Google Chart Map Chart Iframe disappearing from the user’s view, off to the left of screen.

Thinking about solutions to this, our first thought was the use of CSS position:absolute but as we coded, we started to realize that would …

  • shift the remaining position:relative scrollable individual cell place information pods up to clash with menu type contents (re-)positioning
  • the div align=center initial thinking above would mean the menu type contents and Google Chart Map Chart Iframe still disappear, albeit slower to disappear

… but that …

  • keeping the position:relative default … combined with …
  • adjusted CSS style margin-left settings could match the amount of horizontal scrolling … and …
  • make the div align=center be div align=left for first div and be div align=right for last div … and …
  • also increase the width of <div align=centerright><iframe> … Google Chart Map Chart Iframe … </iframe></div> by the horizontal scrolling amount

… was a better approach …


var lastscp=0;
var lasthonex=0, lastiframex=0, lastdivw=0;

function scrollchange() {
//document.title=('' + document.body.scrollLeft);
var huhsc=eval('' + ('' + document.body.scrollLeft).replace('px',''));
if (huhsc != 0) {
if (lastscp != huhsc) {
lastscp=huhsc;
//document.title='leftScrollPos=' + huhsc;
if (1 == 1) {
document.getElementsByTagName('div')[0].align='left';
document.getElementsByTagName('div')[eval(-1 + document.getElementsByTagName('div').length)].align='right';
document.getElementsByTagName('div')[eval(-1 + document.getElementsByTagName('div').length)].style.width='' + eval(huhsc + eval(('' + lastdivw).split('.')[0])) + 'px';
document.getElementsByTagName('h1')[0].style.marginLeft='' + huhsc + 'px';
document.getElementsByTagName('iframe')[0].style.marginLeft='' + huhsc + 'px';
} else {
document.getElementsByTagName('h1')[0].style.position='absolute';
document.getElementsByTagName('h1')[0].style.left='' + eval(huhsc + eval(('' + lasthonex).split('.')[0])) + 'px';
document.getElementsByTagName('h1')[0].style.top=('' + lasthonex).split('.')[1] + 'px';
document.getElementsByTagName('iframe')[0].style.position='absolute';
document.getElementsByTagName('iframe')[0].style.left='' + eval(huhsc + eval(('' + lastiframex).split('.')[0])) + 'px';
document.getElementsByTagName('iframe')[0].style.top=('' + lastiframex).split('.')[1] + 'px';
}
}
} else if (lastscp != huhsc) {
//document.title='leftScrollPos=' + huhsc;
if (1 == 1) {
document.getElementsByTagName('div')[0].align='left';
document.getElementsByTagName('div')[eval(-1 + document.getElementsByTagName('div').length)].align='right';
document.getElementsByTagName('div')[eval(-1 + document.getElementsByTagName('div').length)].style.width='' + eval(huhsc + eval(('' + lastdivw).split('.')[0])) + 'px';
document.getElementsByTagName('h1')[0].style.marginLeft='' + huhsc + 'px';
document.getElementsByTagName('iframe')[0].style.marginLeft='' + huhsc + 'px';
} else {
document.getElementsByTagName('h1')[0].style.position='absolute';
document.getElementsByTagName('h1')[0].style.left='' + eval(huhsc + eval(('' + lasthonex).split('.')[0])) + 'px';
document.getElementsByTagName('h1')[0].style.top=('' + lasthonex).split('.')[1] + 'px';
document.getElementsByTagName('iframe')[0].style.position='absolute';
document.getElementsByTagName('iframe')[0].style.left='' + eval(huhsc + eval(('' + lastiframex).split('.')[0])) + 'px';
document.getElementsByTagName('iframe')[0].style.top=('' + lastiframex).split('.')[1] + 'px';
}j
} else if (lasthonex == 0 && lastiframex == 0) {
var rectlis=document.getElementsByTagName('h1')[0].getBoundingClientRect();
lasthonex=eval(('' + rectlis.left).split('.')[0] + '.' + ('' + ('' + rectlis.top).split('.')[0] + '.').replace('0.','1.').replace('.',''));
rectlis=document.getElementsByTagName('iframe')[0].getBoundingClientRect();
lastiframex=eval(('' + rectlis.left).split('.')[0] + '.' + ('' + ('' + rectlis.top).split('.')[0] + '.').replace('0.','1.').replace('.',''));
rectlis=document.getElementsByTagName('div')[eval(-1 + document.getElementsByTagName('div').length)].getBoundingClientRect();
lastdivw=eval('' + rectlis.width);
}
}

setInterval(scrollchange, 1000);

… which could be applied to three external Javascript files …

.. to fulfill our wish to leave more relevant webpage visible to the user at all times with these web applications.


Previous relevant PHP Wikipedia List Genericization Tutorial is shown below.

PHP Wikipedia List Genericization Tutorial

PHP Wikipedia List Genericization Tutorial

We had to do it! It’s not perfect, but what software is perfect. We feel it could benefit those more intrepid users out there. So what is it?

A few days ago we presented PHP Wikipedia Australian List Integration Tutorial showing some Wikipedia “list of” webpages related to some Australian “concepts” for latitude and longitude (our where of life conduit) based tabular data.

Today we’ve started genericizing those “business rules” to add a new option to …

  • not have to relate the job to Australia, necessarily … but …
  • ask for a Wikipedia URL that starts with “List_of_” as a lot of such webpages have as the start of their URLs …
  • then have concept word(s) follow in the URL …
  • then follow that by _of_ or _in_ or _on_ … followed by …
  • a placename (eg. country name) … then …
  • look for some latitude and longitude data within that data

… and as you can imagine with that last one we can’t cater for everything, but we try hard to cater for quite of few combinations of what the latitude and longitude data could look like.

This is a PHP writes PHP job building webpages like those of the tutorial below, dynamically (and ephemerally), with the new bit of PHP running the show and in these early days we have not catered for it being used a lot, so if you start using it and get somebody else’s “run” data, that’s how the cookie crumbles for now.

We’ll leave you with some that worked for us during the quiet times of our development cycle …

To run what we refer to as a “makeover”, click this live run link and the PHP is downloadable via this template_wiki.php link, as the chance to learn some geography you never knew.


Previous relevant PHP Wikipedia Australian List Integration Tutorial is shown below.

PHP Wikipedia Australian List Integration Tutorial

PHP Wikipedia Australian List Integration Tutorial

Yesterday’s PHP Wikipedia Australian List Makeover Tutorial got us thinking more about “where of life” functionality integration possibilities.

For us, with many “where of life” web applications, the Google Charts Map Chart is a core part of the functionality, as the receptacle, and more and more often as time goes on, also a launching pad out to other concepts, such as …

  • TimeZone … and …
  • Weather

… two of the concepts hovering about our “Other Side of the World” web application we last talked about with Other Side of the World Google Chart Tutorial, whose supervisory HTML other_side_of_the_world.htm‘s live run, changed in this way to tweak the the linking of …

  • latitude and longitude and (anywhere) placename … to …
  • TimeZone place(s) … and then (with great help from Weather Underground (thanks)) onto …
  • direct or nearby weather predictions

… coming off a new Map Chart Google Chart and its select event menu option

  • Nearest TimeZone=Z (and onto Other Side of the World and Weather)
  • YouTube=Y (looking for placename)

… the latter integrating us with YouTube API for Iframe embedded videos interface HTML/Javascript “parent” web application called karaoke_youtube_api.htm HTML iframe elements in another direction additional to yesterday’s usage. Along the way, we tweak the Google Map=G menu option, adding more map type options and zooming in a little less by default, and with the Nearby Airports=A option making the default be a search for 3 (rather than 4) nearby airports. A lot of this all happens because of the changes to

… which all got changed to allow for an “Animate” feature, allowing for an automated right to left “animation” (via hashtagging) of the Wikipedia based slides near the top of this suite of web application’s webpages. We hope you get to try all this out for yourself.


Previous relevant PHP Wikipedia Australian List Makeover Tutorial is shown below.

PHP Wikipedia Australian List Makeover Tutorial

PHP Wikipedia Australian List Makeover Tutorial

Some time back we linked a Wikipedia “list” webpage to the Google Charts Map Chart functionality with PHP Modularization for Lighthouses in Australia Tutorial.

We’re revisiting, and finding some “peer” web applications, linked by a dropdown, that all …

  • access a relevant Wikipedia “list” webpage for Australian “things” and mentioning latitude and longitude … which link to …
  • Google Charts Map Chart

… for all of …

We were inspired to take on this “makeover” of “where of life” functionalities because earlier on today we discovered a stupendous online resource for Australian geography enthusiasts, the Bonzle Digital Atlas of Australia, with incredibly detailed and flexible search mechanisms, thanks heaps!

We’ve decided to include extra buttons (to those already linking to Google Maps links and to the relevant Wikipedia webpage) for that suite of web applications above for …

Great for research and “surfing the Australian world”! Lose yourself!

What happened Javascript (australian_lighthouses.js changed this way) and PHP wise?


Previous relevant PHP Modularization for Lighthouses in Australia Tutorial is shown below.

PHP Modularization for Lighthouses in Australia Tutorial

PHP Modularization for Lighthouses in Australia Tutorial

Today we want to try two more things …

  1. continuing on with our PHP code (you could call australian_lighthouses.php) for our Australian Lighthouses project
  2. talk about PHP glob and its modularization sensibilities

… so let’s talk about the second one first … it’s south of north … chortle, chortle.

What does PHP’s glob do? It is doing functionality like the “underworkings” of any browse button you would see would do when you have a hard disk (in your life) … unfortunately, this is no longer a given (with mobile technology and the “cloud” challenging this thinking, sometimes). Give glob a file specification and a directory to start with, and it will happily (if you were both “globular” and “modular” you would be, too) provide you with a list of filenames, so that we use it to construct this PHP function for use with our lighthouses web application …


function selcreate($def) {
$ret=$def;
$selstr='<select onchange=" window.location=this.value; "><option value="' . str_replace(" ", "_", strtolower($def)) . '_lighthouses.php">' . $def . '</option>';
$cnt=0;
foreach (glob("*_lighthouses.php") as $filename) {
if (strpos(($filename . "*"), (str_replace(" ", "_", strtolower($def)) . '_lighthouses.php*')) === false) {
$cnt++;
$newidea=str_replace("_", " ", str_replace("_lighthouses.php", "", strtolower($filename)));
$newideas=explode(" ", $newidea);
$ideas=strtoupper(substr($newideas[0],0,1)) . strtolower(substr($newideas[0],1));
for ($ii=1; $ii<sizeof($newideas); $ii++) {
$ideas.=(" " . strtoupper(substr($newideas[$ii],0,1)) . strtolower(substr($newideas[$ii],1)));
}
$selstr.='<option value="' . $filename . '">' . $ideas . '</option>';
}
}
if ($cnt > 0) return $selstr . "</select>";
return $ret;
}

… and hope you can see that glob could be used for PHP code to self-detect sibling variation programs, so that, for instance, if we “plonked” (ie. eg. (s)ftp it) an egypt_lighthouses.php (probably with an egypt_lighthouses.js accompanying Javascript file) into the same directory as our …

… it would automatically be added into the functionality of its siblings without you having to change any code of those siblings … and that egypt_lighthouses.php is free to be a web application with a totally different method of functionality … cute, huh?!

As a matter of fact ireland_lighthouses.php is quite different, and if you examine the code, you will see that the Javascript putElement(s)By via PHP Relative URLs Tutorial is more apt to a discussion of its workings.

You see, there are so many many different ways to “skin a cat” in Information Technology, quite often … not always … but “quite often” … and why be cornered into thinking there is only one way to do things?

The other thing you’ll find is that even though ireland_lighthouses.php differs a lot to its nearest matching sibling (in terms of methodology), new_zealand_lighthouses.php the Javascript corresponding codesets called ireland_lighthouses.js and new_zealand_lighthouses.js are only superficially different … in other words our PHP coalesces concepts into a similar “client” look … a “modularization” of sorts … not everybody’s sort, but a sort none the less … and this begs a question?

Why is “modularization” a good thing? Well, to me, you don’t have to have any “modularization” going on at all, and this is fine by me, but you must deal with issues that allow you to modify many many codesets efficiently and accurately in vastly different ways to be efficient, or be “modular” and be able to, perhaps, even, automate your changes, because of these “modular” patterns you’ve created … many people find “modularization” blissful … and often it suits the work patterns for teams of programmers. Perhaps you want to read about MVC (and its like) as a coding modularization idea for PHP (or many other programming languages, for that matter).


Previous releveant PHP/Javascript Asynchronous Lighthouses in Australia Tutorial is shown below.

PHP/Javascript Asynchronous Lighthouses in Australia Tutorial

PHP/Javascript Asynchronous Lighthouses in Australia Tutorial

Today we want to try two things …

  1. continuing on with our PHP code (you could call australian_lighthouses.php) for our Australian Lighthouses project
  2. talk about Javascript asynchronous script tag option

… so let’s talk about the second one first … it’s south … chortle, chortle.

Why should you be interested in the HTML’s script tag attributes …

  • asynch=”asynch”
  • defer=”defer”

? Well, we want our web pages to load as fast as possible. Yaaaaaa?! So if there was the mechanism to do more than one bit of ((client) Javascript) thinking at a time would you avail yourself of the opportunity … or would you pick what’s behind door 3?

Do you want to hear more on this theory wise? It seems to me, there are web application mission critical parts, and there are embellishments, quite often … “nice to haves” but not “mission critical” … well, if those “nice to haves” could be arranged not to hog all the web application designated CPU that would be good, wouldn’t it?! Yaaaaaaaaaaa?!

So, that, in theory, is y why.

Now back to the project at hand … Australian Lighthouses … don’t you think some geographical sorting options and place name sorting options might be useful? Yaaaaaaaaaaaaaaaaa?! But for us it doesn’t feel mission critical … so we …

  • place the logic in some external Javascript called australian_lighthouses.js
  • we load it from the PHP via
    <script type=”text/javascript” src=”australian_lighthouses.js” async=”async”></script>

    … and this amounts to the only change to today’s PHP code from yesterday as per this link

… and this becomes a way to modularize your thinking regarding a project … please don’t think there are not a myriad of other ways … this is just one idea here.

With regard to how we approached our external Javascript we did not demand anything (much) of our parent PHP and this may not be the fastest way to approach this. What we mean by that is that, perhaps, as a general rule, external Javascript can perform faster with the parent PHP or HTML leaving it with a lot more HTML element id=”[elementId]” to hang its hats on, so to speak … instead, here, we acted innocently with our Javascript and used lots of calls to the Javascript DOM method getElementsByTagName() (which results in an array return value). Perhaps calls to getElementById() via (parent) arranged id=”[elementId]” would be faster?! Today, as with the previous Static HTML Javascript Primer Tutorial we concentrated on the “modular” feel to additional external Javascript code ideas.

So try a live run to see what we mean.


Previous relevant PHP Lighthouses in Australia Primer Tutorial is shown below.

PHP Lighthouses in Australia Primer Tutorial

PHP Lighthouses in Australia Primer Tutorial

Today we examine some of the methodology behind a project idea.

Projects need …

  • an idea … ours came from listening to the radio and hearing about Lighthouses, and how the technologies had changed what they look like and how they function these days … to quote Wikipedia with respect to Australian Lighthouses (thanks) …

    The first lighthouse was Macquarie Lighthouse, which was lit in 1793 as a tripod mounted wood and coal fired beacon. The last manned lighthouse was Maatsuyker Island Lighthouse, off the south coast of Tasmania, which was automated in 1996.

  • a means to access information … much easier these days with the search engines … we went with a Google Search as per list of lighthouse positions … which led to …
  • the information source(s) … we settled, and were not surprised about the source, for Wikipedia’s List of lighthouses and lightvessels in Australia – Wikipedia … then, once happy about the quality of the source information, analyzed …
  • the source data format … initially, at least, via View->Page Source, relative to the webpage … to get ideas for how to parse the data … so that we can determine a …
  • programming language of choice … which is PHP … no surprise here … will need a server-side language … and a method like PHP’s file_get_contents() … from there …
  • PHP coding to parse the data and put it into another format that value adds … otherwise why do it, as the Wikipedia information is fine as is … that is where we determine that we should …
  • include an iframe that uses the Google Chart Map Chart to add that extra overall positional view of Lighthouses … a definite asset to the reader’s understanding of the subject … definitely a “where” web application … and in doing this we notice that …
  • Google Chart Map Chart map.php web application needed to be able to handle much larger input data streams than it could in its previous incarnation of only allowing PHP $_GET[] parameters … so we change it to allow $_POST[] parameters … maybe you noticed this with yesterday’s PHP/Javascript/HTML Google Chart Map Onclick Tutorial as shown below … as this meant that …
  • we need an HTML form that POSTs to the iframe with the Google Chart Map Chart map.php web application allowable because we are on the same domain with this thinking … and using an HTML textarea element to store the huge string of Lighthouse data that will be passed across via urldecode($_POST[‘data’]) at map.php … using PHP’s urldecode() and urlencode() methods and Javascript’s decodeURIComponent() method … as well as utilizing …
  • Google Chart Map Chart map.php web application onclick and tooltip functionality we’ve been working on lately … hence the talk about this below … working out what (component) tools could do with a “makeover” is an extremely important part of any project and can be a useful compartmentalizing of the project

… and so we end up with our live run behind which is the PHP programming source code you could call australian_lighthouses.php for your perusal.


Previous relevant PHP/Javascript/HTML Google Chart Map Onclick Tutorial is shown below.

PHP/Javascript/HTML Google Chart Map Onclick Tutorial

PHP/Javascript/HTML Google Chart Map Onclick Tutorial

They say “the knee bone’s connected to the thigh bone” then they say “the thigh bone’s connected to the … hip bone” then they say “let’s call the whole thing off” … sometimes.

Today we say “the onmouseover event is connected to the onclick event” then we say “the onclick event is connected to the online woooooorld” … “do … the hokey pokey” x3 … “that’s what the onclick event preceeded by the onmouseover event within the environs you are encountering … is all about”.

That news is pretty good actually, because it means mobile users are not missing out on much not having easy access to any onmouseover (ie. hover) functionality … they’ll still reach any onclick logic you present them, in the default case of events where onclick is a valid “touch” event as well.

So the data structure of arrangements to allow for this onclick functionality is intrinsically the same as allowed for yesterday with the PHP/Javascript/HTML Google Chart Map Tooltips Tutorial as shown below, but we just check for some more delimitation issue matters, and our updated prompting window logic gets quite “blurby” as per the Javascript (via PHP) …



echo " datalinesuffix = prompt('Enter decimal Latitude,Longitude ' + thisline + extra + ' (for no more hit Cancel button and append with ' + '\\n\\n' + ',\"A tooltip and clicking link for Google Map of <a target=_blank href=https://www.google.com.au/maps/place/' + encodeURIComponent(dlp2) + '>' + dlp2 + '</a>\" ' + '\\n\\n' + ' or maybe perhaps ' + '\\n\\n' + ',\"A tooltip and clicking link for Google Map based on latitude and longitude of <a target=_blank href=https://maps.google.com.au/maps?' + encodeURIComponent('z=15&t=m&q=loc:') + '{latitude}{longitude}>' + dlp2 + '</a>\"' + '\\n\\n' + ' optionally (as (just) two examples of what is possible with HTML included (activates with onclick bit not onmouseover))', thisdef); " . "\n";
echo ' if (datalinesuffix != null) { if (datalinesuffix.indexOf("{latitude}") != -1) { dlsa=datalinesuffix.split(","); if (dlsa[0].indexOf("-") == -1) { datalinesuffix=datalinesuffix.replace("{latitude}",encodeURIComponent("+" + dlsa[0])); } else { datalinesuffix=datalinesuffix.replace("{latitude}",encodeURIComponent(dlsa[0])); } } if (datalinesuffix.indexOf("{longitude}") != -1) { dlsa=datalinesuffix.split(","); if (dlsa.length > 1) { if (dlsa[1].indexOf("-") == -1) { datalinesuffix=datalinesuffix.replace("{longitude}",encodeURIComponent("+" + dlsa[1])); } else { datalinesuffix=datalinesuffix.replace("{longitude}",encodeURIComponent(dlsa[1])); } } } } ' . "\n";

… as again we are making use of $_GET[] parameters coming into the PHP at the server side.

The bigger picture plan for how this helps something else we are trying will become apparent over time … in the fullness of time … at the appropriate juncture of juxtapositions.

Let’s see some PHP code in live action for this tutorial where you define your map characteristics and data.

Link to Google Chart Tools “spiritual home” … via Google.
Link to Google Chart Tools Map information … via Google.
Link to Google Chart tooltips information … via Google.

Link to some downloadable PHP programming code … rename to map.php which changed from yesterday as per this link.


Previous relevant PHP/Javascript/HTML Google Chart Map Tooltips Tutorial is shown below.

PHP/Javascript/HTML Google Chart Map Tooltips Tutorial

PHP/Javascript/HTML Google Chart Map Tooltips Tutorial

Here is a tutorial that is revisiting Google Graphs API, or Google Chart Tools, and its Map functionality, which we first talked about with PHP/Javascript/HTML Google Chart Map Tutorial as shown below. Please read

Google Chart Tools provide a perfect way to visualize data on your website. From simple line charts to complex hierarchical tree maps, the chart galley provides a large number of well-designed chart types. Populating your data is easy using the provided client- and server-side tools.

Why are we revisiting? Well, we are interested in the interactive side to this wonderful product. We are going to start with a look into “tooltips”. Tooltips are those optional informational features of some webpages that happen when hovering over an HTML element, principally through the filling out of an HTML element’s title global attribute.. Google Charts functionality amounts to the use of Javascript, and, these days, SVG HTML elements, so “tooltips” are very relevant to the “user experience” when using Google Charts. With the Map Chart, the latitude, laongitude set is combined with a title, which can be the default “tooltip” shown, as this is all fine for many usages, but we want to extend it so that that title doesn’t have to be the tooltip.

The integration of this added functionality into the Google Chart Map Chart involves adding an extra “string” column to the data table as per the bold bits of the new Javascript (via PHP) snippet …



if (isset($_GET['value']) && (isset($_GET['tooltip']) || strpos($GETdata, "'") !== false)) {
echo " var data = new google.visualization.DataTable(); /" . "/" . $GETlabel . $GETvalue . " \n";
echo " data.addColumn('number', '" . str_replace("'","",str_replace(",","",str_replace("['","",$GETlabel))) . "'); \n";
echo " data.addColumn('number', " . str_replace(",", "); data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}}); data.addColumn('string', ", str_replace("]","",$GETvalue)) . "); \n";
echo " data.addRows([ \n";
echo str_replace("''" . "''", "''", str_replace("~", "'", substr($GETdata,1)));
echo " ]); \n";
} else {

echo ' var data = google.visualization.arrayToDataTable([ ' . "\n";
echo " " . $GETlabel . $GETvalue . " \n";
echo str_replace("''" . "''", "''", str_replace("~", "'", $GETdata));
echo " ]);\n";
}

… making use of $_GET[] parameters coming into the PHP at the server side … you’ll find that Javascript loves to work with PHP as one of those Fred and Ginger relationships of the programming world … you’ll be happier writing Javascript from your PHP too … try it and you’ll see the advantages time and again and again and again … did we leave out one? … and again.

The bigger picture plan for how this helps something else we are trying will hopefully become apparent over time.

Let’s see some PHP code in live action for this tutorial where you define your map characteristics and data.

Link to Google Chart Tools “spiritual home” … via Google.
Link to Google Chart Tools Map information … via Google.
Link to Google Chart tooltips information … via Google.

Link to some downloadable PHP programming code … rename to map.php which changed from the days of Google Charts Emailing Primer Tutorial as per this link.


Previous relevant PHP/Javascript/HTML Google Chart Map Tutorial is shown below.

PHP/Javascript/HTML Google Chart Map Tutorial

PHP/Javascript/HTML Google Chart Map Tutorial

Here is a tutorial that introduces you to Google Graphs API, or Google Chart Tools, and its Map functionality.

Google Chart Tools provide a perfect way to visualize data on your website. From simple line charts to complex hierarchical tree maps, the chart galley provides a large number of well-designed chart types. Populating your data is easy using the provided client- and server-side tools.

Let’s see some PHP code in live action for this tutorial where you define your map characteristics and data.

Link to Google Chart Tools “spiritual home” … via Google.
Link to Google Chart Tools Map information … via Google.

Link to some downloadable PHP programming code … rename to map.php.

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.


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.

Posted in eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , | Leave a comment

Dropdown Image Dog and Cat Ideas Tutorial

Dropdown Image Dog and Cat Ideas Tutorial

Dropdown Image Dog and Cat Ideas Tutorial

Onto the recent Dropdown Image More No Map Ideas Tutorial

  • we let it rain cats and dogs with new animal options to our biology quiz, requiring Wikipedia URL interpretation to do with answers, and leading to leniency in the answer interpretation Javascript code …

    function process(tv, tvo) {
    if (answer == ' ' && tv == '') {
    answer='';
    } else {
    if (answer == '') {
    while (answer == '') {
    answer=prompt('What is your <?php echo strtolower($suffix); ?> type guess?', '');
    if (answer == null) { answer=''; } else { answer=answer.replace('Galápagos', 'Galapagos').replace('galápagos', 'galapagos'); }
    }
    } else {
    answer=answer.replace('Galápagos', 'Galapagos').replace('galápagos', 'galapagos');
    }
    goes++;
    if (tvo.outerHTML.indexOf('<img') == 0) {
    rans=('' + tvo.getAttribute('data-answer'));
    } else {
    var val=document.getElementById('schoices');
    var ival=val.selectedIndex;
    rans=('' + val.options[val.selectedIndex].getAttribute('data-answer'));
    document.getElementById('schoices').selectedIndex = '-1';
    }
    if (answer.trim().toLowerCase() == rans.trim().toLowerCase() || (anywhere && eval('' + answer.trim().toLowerCase().length) >= 3 && (' ' + rans.trim().toLowerCase() + ' ').indexOf(' ' + answer.trim().toLowerCase() + ' ') != -1)) {
    score++;
    } else if ((rans.trim() + '~').toLowerCase().indexOf(' ' + answer.trim().toLowerCase() + '~') != -1) {
    score+=0.5;
    setTimeout(zexplain, 200);
    } else {
    setTimeout(explain, 200);
    }
    document.getElementById('score').innerHTML='Score: ' + score + '/' + goes;
    answer=' ';
    document.getElementById('ians').value='';
    setTimeout(noans, 400);
    }
    }
  • we add some CSS styling …

    <style>
    option::before {
    content: '\00200d'; /* '\0026aa'; */
    font-size: px;
    }

    #snoun {
    background-color: yellow;
    }

    body {
    background: linear-gradient(to right, #ffffff, #fcfafc, #f9f6f8, #f8f1f3, #f6ecec);
    }

    select { /* Thanks to https://stackoverflow.com/questions/4531269/hide-vertical-scrollbar-in-select-element */
    scrollbar-width: none; /*For Firefox*/;
    -ms-overflow-style: none; /*For Internet Explorer 10+*/;
    }

    select:-webkit-scrollbar { /*For WebKit Browsers*/
    width: 0;
    height: 0;
    }
    </style>
  • we cater for answer concern regarding non-ascii characters as per …

    optsare[ii].setAttribute('data-answer', blurbs[iii].replace('Galápagos tortoise', 'Galapagos tortoise'));
  • we keep width and height dimension user settings as user changes Biology Quiz animal option …

    location.href=(document.URL.split('#')[0].replace('noun=', 'noun' + Math.floor(Math.random() * 198675453) + '=') + '&noun=' + encodeURIComponent(this.value.trim())).replace('.php&', '.php?');

… in the changed dropdown_thumbnail_image_choices.php biology Quiz.


Previous relevant Dropdown Image More No Map Ideas Tutorial is shown below.

Dropdown Image More No Map Ideas Tutorial

Dropdown Image More No Map Ideas Tutorial

Generally speaking, regarding yesterday’s Dropdown Image No Map Ideas Tutorial Biology Quiz work with Wikipedia (thanks) our data categories …

  • dropdown image backgrounder uses image map data from Wikipedia … and today we extend that data scope to …
  • dropdown image backgrounder uses image data not involving image maps from Wikipedia … in two scenarios, so far, that we have identified …
    1. one image with one caption within a specific table class (eg. Amphibian)
    2. one image for clockwise captions within a specific table class (eg. Marsupial)

… today, we nuance …

  • more biology class combinations
  • table cell isolation for scan of images with biology table

… in getting to a dropdown Biology Quiz option list of …

… in the changed dropdown_thumbnail_image_choices.php biology Quiz.


Previous relevant Dropdown Image No Map Ideas Tutorial is shown below.

Dropdown Image No Map Ideas Tutorial

Dropdown Image No Map Ideas Tutorial

Yesterday’s Dropdown Image Dimensions Idea Tutorial continued the trend of our …

  • dropdown image backgrounder uses image map data from Wikipedia … and today we extend that data scope to …
  • dropdown image backgrounder uses image data not involving image maps from Wikipedia … in two scenarios, so far, that we have identified …
    1. one image with one caption within a specific table class (eg. Amphibian)
    2. one image for clockwise captions within a specific table class (eg. Marsupial)

… in the changed dropdown_thumbnail_image_choices.php biology Quiz.


Previous relevant Dropdown Image Dimensions Idea Tutorial is shown below.

Dropdown Image Idea Map Genericization Tutorial

Dropdown Image Dimensions Idea Tutorial

Thumbnail images are all well and good, but for web applications, such as our quiz one, that might benefit from scrutiny of images, in the recent Dropdown Image Idea Map Genericization Tutorial, it would be good to offer the user some control over the size of the images in their biology themed Quiz.

We want to funnel this ask through a Javascript window.prompt scenario, given it is optional functionality, and we think it is over the top to dedicate one or two textboxes to the asking of …

  • image display width … and …
  • image display height

… dimensions. And then, as far as the arrangements go to make use of these collected user settings go, we just start using GET URL arguments for width= and height= respectively …

<?php

$three="3"; // number of image map columns
$six="6"; // number of image map rows
$restl="calc(50% - 600px)";
$onehundred="100";
$seventy="70";
if (isset($_GET['width'])) {
$onehundred=str_replace('+','_',urldecode($_GET['width']));
$restl="" . (20 + $onehundred) . "px";
} else if (isset($_POST['width'])) {
$onehundred=str_replace('+','_',urldecode($_POST['width']));
$restl="" . (20 + $onehundred) . "px";
}

?>

… in the pure PHP initializations. Then up the top of the PHP written Javascript we now have …


<script type=text/javascript>
var tw=<?php echo ($onehundred * $three); ?>, lw=<?php echo $onehundred; ?>;
var th=<?php echo ($seventy * $six); ?>, lh=<?php echo $seventy; ?>;
//

… and then establishing the size of the HTML canvas element …


<canvas id=mycanvas width=<?php echo $onehundred; ?> height=<?php echo $seventy; ?> style=display:none;></canvas>

… and referenced a lot in the document.body onload event “postoverlay” Javascript function below …


function postoverlay() {
var lgbegin='linear-gradient(0deg, #ffffff 10%, rgba(255,255,0,0.6) 20%, rgba(192,192,192,0.6) 31%, rgba(255,215,0,0.6) 42%, rgba(211,211,211,0.6) 53%, rgba(255,165,0,0.6) 63%, rgba(224,255,255,0.6) 74%, rgba(254,254,254,0.6) 85%, #CC7722 100%),linear-gradient(to right,yellow,pink),';
var delim='', topp=0, hinc=0;;
var proposeds='<style> #tf { background-image: ; background-position: ; background-size: ; background-repeat: ; } </style>';
var rect=document.getElementById('schoices').getBoundingClientRect();
var optsare=document.getElementsByTagName('option');
//var rectrtd=document.getElementById('rtd').getBoundingClientRect();


if (eval('' + rect.height) > 100 || 1 == 1) {


document.getElementById('schoices').style.backgroundColor='transparent';
document.getElementById('tf').style.position='absolute';
document.getElementById('tf').style.left='' + rect.left + 'px';
document.getElementById('tf').style.top='' + rect.top + 'px';

document.getElementById('tf').style.width='' + rect.width + 'px';
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
//document.getElementById('tf').style.width='' + tw + 'px';
document.getElementById('tf').style.height='' + th + 'px';
} else {
document.getElementById('tf').style.height='' + rect.height + 'px';
}

document.getElementById('schoices').style.position='absolute';
document.getElementById('schoices').style.left='' + rect.left + 'px';
document.getElementById('schoices').style.top='' + rect.top + 'px';
document.getElementById('schoices').style.width='' + rect.width + 'px';
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('schoices').style.height='' + th + 'px';
document.getElementById('schoices').style.display='none';
} else {
document.getElementById('schoices').style.height='' + rect.height + 'px';
}


//document.getElementById('rtd').style.position='absolute';
//document.getElementById('rtd').style.left='' + rectrtd.left + 'px';
//document.getElementById('rtd').style.top='' + rectrtd.top + 'px';
//document.getElementById('rtd').style.width='' + rectrtd.width + 'px';
//document.getElementById('rtd').style.height='' + rectrtd.height + 'px';

// Thanks to https://stackoverflow.com/questions/49660659/css-gradients-inside-gradients
//document.getElementById('tf').style.background='linear-gradient(0deg, #ffffff 10%, rgba(255,255,0,0.6) 20%, rgba(192,192,192,0.6) 31%, rgba(255,215,0,0.6) 42%, rgba(211,211,211,0.6) 53%, rgba(255,165,0,0.6) 63%, rgba(224,255,255,0.6) 74%, rgba(254,254,254,0.6) 85%, #CC7722 100%), linear-gradient( to right, yellow, pink )'; // #fcfafc #f9f6f8 #f8f1f3
document.getElementById('tf').style.zIndex='-1';
topp=rect.top;
//alert('rect.height=' + rect.height);
lgbegin='';

for (var ii=0; ii<eval('' + document.getElementById('schoices').size); ii++) {
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('tf').style.zIndex='88';
document.getElementById('tf').setAttribute('contenteditable',false);
hinc=Math.round(eval(rect.height / eval('' + document.getElementById('schoices').size)));
document.getElementById('tf').innerHTML+='<img style="position:absolute;z-index:89;left:' + rect.left + 'px;top:' + topp + 'px;width:' + rect.width + 'px;height:' + Math.round(eval(rect.height / eval('' + document.getElementById('schoices').size))) + 'px;" src="' + imguris[randlist[ii]] + '" data-answer="' + "" + blurbs[randlist[ii]] + "" + '" onclick=" process(' + "'" + blurbs[randlist[ii]] + "',this)" + '; "></img>';
if (1 == 11) {
topp+=hinc;
} else {
topp+=eval(rect.height / eval('' + document.getElementById('schoices').size));
}
} else {
hinc=eval('' + optsare[ii].style.height);
proposeds=proposeds.replace(' ;', delim + lgbegin + "url('" + imguris[randlist[ii]] + "')" + ' ;');
proposeds=proposeds.replace(' ;', delim + rect.left + 'px ' + topp + 'px' + ' ;');
if (1 == 11) {
proposeds=proposeds.replace(' ;', delim + rect.width + 'px ' + hinc + 'px' + ' ;');
} else if (1 == 1) {
proposeds=proposeds.replace(' ;', delim + '<?php echo $onehundred; ?>' + 'px ;'); // contain
} else {
proposeds=proposeds.replace(' ;', delim + rect.width + 'px ' + Math.round(eval(rect.height / eval('' + document.getElementById('schoices').size))) + 'px' + ' ;');
}
proposeds=proposeds.replace(' ;', delim + 'no-repeat' + ' ;');
delim=',';
if (1 == 11) {
topp+=hinc;
} else {
topp+=eval(rect.height / eval('' + document.getElementById('schoices').size));
}
}
}

document.getElementById('dstyle').innerHTML=proposeds.replace("</stXyle>", " option::before { content: '' !important; } </style>");

}


}

… in the changed dropdown_thumbnail_image_choices.php biology Quiz.


Previous relevant Dropdown Image Idea Map Genericization Tutorial is shown below.

Dropdown Image Idea Map Genericization Tutorial

Dropdown Image Idea Map Genericization Tutorial

There is a certain level of genericization we can apply to yesterday’s Dropdown Image Idea Primer Tutorial‘s Bird Quiz “proof of concept” start, to begin to extend its functionality, today.

We say “certain level” because Wikipedia content is written by a myriad of expert Wiki Page Writers out there, thanks one and all. There are not hard and fast rules about how that content is formed, any more than the content here, in this WordPress blog, is presented, and appears as a webpage before your very (yes, very) eyes! But, there can be patterns, and in this biology field of content, we’ve noticed, our biology images can often be presented in the form …

  • HTML image map element contains the answer data we need for our current (biology) quiz project … and …
  • HTML img element accompanying that image map element can contain the base graphics we need

… to derive data URI image thumbnails via an inhouse canvas element’s talents regarding …


function canvasize() {
document.getElementById('schoices').title='Quiz';
if (document.getElementById('snoun').outerHTML.indexOf('>' + '<?php echo $suffix; ?>' + '<') == -1) {
document.getElementById('snoun').innerHTML+='<option value="<?php echo $suffix; ?> "><?php echo $suffix; ?></option>';
}
document.getElementById('snoun').value='<?php echo $suffix; ?> ';
elem=document.getElementById('mycanvas');
context = elem.getContext('2d');
var cs=wikiblurbthanks.split(' coords="');
var bs=wikiblurbthanks.split(' alt="');
for (var kk=1; kk<bs.length; kk++) {
blurbs.push(bs[kk].split('"')[0]);
if (kk == 1) {
if (cs[1].indexOf('0,') == 0 && cs[2].indexOf('0,') == 0) {
yfirst=true;
}
}
}
console.log(blurbs);
//alert('blurbs length=' + blurbs.length);
var cimg=new Image();
cimg.onload = function(){
var ourlw=eval(cimg.width / <?php echo $three; ?>);
var ourlh=eval(cimg.height / <?php echo $six; ?>);
if (yfirst) {
for (var ii=0; ii<<?php echo $three; ?>; ii++) {
for (var jj=0; jj<<?php echo $six; ?>; jj++) {
context.clearRect(0,0,elem.width,elem.height);
context.drawImage(cimg,eval(ii * ourlw),eval(jj * ourlh),ourlw,ourlh,0,0,elem.width,elem.height);
imguris.push(elem.toDataURL('image/png'));
console.log('here');
}
}
} else {
for (var jj=0; jj<<?php echo $six; ?>; jj++) {
for (var ii=0; ii<<?php echo $three; ?>; ii++) {
context.clearRect(0,0,elem.width,elem.height);
context.drawImage(cimg,eval(ii * ourlw),eval(jj * ourlh),ourlw,ourlh,0,0,elem.width,elem.height);
imguris.push(elem.toDataURL('image/png'));
console.log('here');
}
}
}
overlay();
};
cimg.src='<?php echo 'data:image/' . str_replace('jpg','jpeg',strtolower(explode('.', explode('#', explode('?', $wurl)[0])[0])[-1 + sizeof(explode('.', explode('#', explode('?', $wurl)[0])[0]))])) . ';base64,' . base64_encode(file_get_contents($wurl)) ?>';
}

… slicing and dicing of imagery. If you’d have looked yesterday at this Javascript function you’d have seen much less PHP interventional code, and this increased “intervention” forms the basis for our “genericization drive” today, where we identify tasks that PHP can help with in that initial phase …

<?php

$three="3";
$six="6";
$wurl='http://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Bird_Diversity_2013.png/300px-Bird_Diversity_2013.png';
$suffix="Bird";
$mapdata='<map name="ImageMap_fbc6cc846e0ab4e8"><area href="/wiki/Red-crested_turaco" shape="rect" coords="0,0,100,70" alt="Red-crested turaco" title="Red-crested turaco" /><area href="/wiki/Steller%27s_sea_eagle" shape="rect" coords="0,70,100,141" alt="Steller' . "'" . 's sea eagle" title="Steller' . "'" . 's sea eagle" /><area href="/wiki/Rock_dove" shape="rect" coords="0,209,100,141" alt="Rock dove" title="Rock dove" /><area href="/wiki/Southern_cassowary" shape="rect" coords="0,279,100,210" alt="Southern cassowary" title="Southern cassowary" /><area href="/wiki/Gentoo_penguin" shape="rect" coords="0,348,100,279" alt="Gentoo penguin" title="Gentoo penguin" /><area href="/wiki/Bar-throated_minla" shape="rect" coords="0,418,100,348" alt="Bar-throated minla" title="Bar-throated minla" /><area href="/wiki/Shoebill" shape="rect" coords="200,0,100,70" alt="Shoebill" title="Shoebill" /><area href="/wiki/Grey_crowned_crane" shape="rect" coords="200,70,100,141" alt="Grey crowned crane" title="Grey crowned crane" /><area href="/wiki/Anna%27s_hummingbird" shape="rect" coords="200,209,100,141" alt="Anna' . "'" . 's hummingbird" title="Anna' . "'" . 's hummingbird" /><area href="/wiki/Rainbow_lorikeet" shape="rect" coords="200,279,100,210" alt="Rainbow lorikeet" title="Rainbow lorikeet" /><area href="/wiki/Grey_heron" shape="rect" coords="200,348,100,279" alt="Grey heron" title="Grey heron" /><area href="/wiki/Eurasian_eagle-owl" shape="rect" coords="200,418,100,348" alt="Eurasian eagle-owl" title="Eurasian eagle-owl" /><area href="/wiki/White-tailed_tropicbird" shape="rect" coords="300,0,200,70" alt="White-tailed tropicbird" title="White-tailed tropicbird" /><area href="/wiki/Indian_peafowl" shape="rect" coords="300,70,200,141" alt="Indian peafowl" title="Indian peafowl" /><area href="/wiki/Atlantic_puffin" shape="rect" coords="300,209,200,141" alt="Atlantic puffin" title="Atlantic puffin" /><area href="/wiki/American_flamingo" shape="rect" coords="300,279,200,210" alt="American flamingo" title="American flamingo" /><area href="/wiki/Blue-footed_booby" shape="rect" coords="300,348,200,279" alt="Blue-footed booby" title="Blue-footed booby" /><area href="/wiki/Keel-billed_toucan" shape="rect" coords="300,418,200,348" alt="Keel-billed toucan" title="Keel-billed toucan" /></map>';
if (isset($_GET['noun'])) {
$suffix=str_replace('+','_',urldecode($_GET['noun']));
} else if (isset($_POST['noun'])) {
$suffix=str_replace('+','_',urldecode($_POST['noun']));
}
$content=file_get_contents('https://en.wikipedia.org/wiki/' . urlencode($suffix));
$mapbits=explode('</map>', $content);
if (sizeof($mapbits) > 1) {
$imgbits=explode('<img ', $mapbits[1]);
$mapdata=str_replace("'", "' + \"'\" + '", '<map ' . explode('<map ', $mapbits[0])[1] . '</map>');
$optcount=(-1 + sizeof(explode('<area', $mapdata)));
$six=floor($optcount / 3);
if (sizeof($imgbits) > 1) {
if (strpos($imgbits[1], ' src="') !== false) {
$wurl='http://' . explode('//', explode('"', explode(' src="', $imgbits[1])[1])[0])[1];
}
}
} else {
$suffix="Bird";
$mapdata='<map name="ImageMap_fbc6cc846e0ab4e8"><area href="/wiki/Red-crested_turaco" shape="rect" coords="0,0,100,70" alt="Red-crested turaco" title="Red-crested turaco" /><area href="/wiki/Steller%27s_sea_eagle" shape="rect" coords="0,70,100,141" alt="Steller' . "'" . 's sea eagle" title="Steller' . "'" . 's sea eagle" /><area href="/wiki/Rock_dove" shape="rect" coords="0,209,100,141" alt="Rock dove" title="Rock dove" /><area href="/wiki/Southern_cassowary" shape="rect" coords="0,279,100,210" alt="Southern cassowary" title="Southern cassowary" /><area href="/wiki/Gentoo_penguin" shape="rect" coords="0,348,100,279" alt="Gentoo penguin" title="Gentoo penguin" /><area href="/wiki/Bar-throated_minla" shape="rect" coords="0,418,100,348" alt="Bar-throated minla" title="Bar-throated minla" /><area href="/wiki/Shoebill" shape="rect" coords="200,0,100,70" alt="Shoebill" title="Shoebill" /><area href="/wiki/Grey_crowned_crane" shape="rect" coords="200,70,100,141" alt="Grey crowned crane" title="Grey crowned crane" /><area href="/wiki/Anna%27s_hummingbird" shape="rect" coords="200,209,100,141" alt="Anna' . "'" . 's hummingbird" title="Anna' . "'" . 's hummingbird" /><area href="/wiki/Rainbow_lorikeet" shape="rect" coords="200,279,100,210" alt="Rainbow lorikeet" title="Rainbow lorikeet" /><area href="/wiki/Grey_heron" shape="rect" coords="200,348,100,279" alt="Grey heron" title="Grey heron" /><area href="/wiki/Eurasian_eagle-owl" shape="rect" coords="200,418,100,348" alt="Eurasian eagle-owl" title="Eurasian eagle-owl" /><area href="/wiki/White-tailed_tropicbird" shape="rect" coords="300,0,200,70" alt="White-tailed tropicbird" title="White-tailed tropicbird" /><area href="/wiki/Indian_peafowl" shape="rect" coords="300,70,200,141" alt="Indian peafowl" title="Indian peafowl" /><area href="/wiki/Atlantic_puffin" shape="rect" coords="300,209,200,141" alt="Atlantic puffin" title="Atlantic puffin" /><area href="/wiki/American_flamingo" shape="rect" coords="300,279,200,210" alt="American flamingo" title="American flamingo" /><area href="/wiki/Blue-footed_booby" shape="rect" coords="300,348,200,279" alt="Blue-footed booby" title="Blue-footed booby" /><area href="/wiki/Keel-billed_toucan" shape="rect" coords="300,418,200,348" alt="Keel-billed toucan" title="Keel-billed toucan" /></map>';
$content=file_get_contents('https://en.wikipedia.org/wiki/' . urlencode($suffix));
$mapbits=explode('</map>', $content);
if (sizeof($mapbits) > 1) {
$imgbits=explode('<img ', $mapbits[1]);
$mapdata=str_replace("'", "' + \"'\" + '", '<map ' . explode('<map ', $mapbits[0])[1] . '</map>');
$optcount=(-1 + sizeof(explode('<area', $mapdata)));
$six=floor($optcount / 3);
if (sizeof($imgbits) > 1) {
if (strpos($imgbits[1], ' src="') !== false) {
$wurl='http://' . explode('//', explode('"', explode(' src="', $imgbits[1])[1])[0])[1];
}
}
}
}

?>

… and use them, rather than hardcodings, where we see those hardcodings that used to just involve our guinea pig project topic, “Birds”, in the context of a quiz, so we now offer dropdown selectable …

  • Bird
  • Mammal
  • Insect

… (biology) quiz options with our new incarnation of dropdown_thumbnail_image_choices.php you can still try for yourself.


Previous relevant Dropdown Image Idea Primer Tutorial is shown below.

Dropdown Image Idea Primer Tutorial

Dropdown Image Idea Primer Tutorial

We’ve long mused about the idea that an HTML select (ie. dropdown) element can have images as a background. Well, we’re here to tell you that a dropdown element on its own is not capable of this, it being an element associated with operating system functionality. But we can …

… and the recent Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Linear Gradient Tutorial got us interested in …

  • dropdown background transparency … combined with …
  • underlaid, precisely, div z-index smaller

… and what’s to stop us setting a multiple background image arrangement for the div element above? Anyone? Anyone? Yes, Aristotle, it is clearly self-evident that an earthquake might stop us, yes, or an anti-clockwise hurricane, perhaps, yes … but you do realize our class is taking place in the Blue Mountains, near Sydney, Australia?!

Anyway, we decided to turn this idea, similar to one we explored a lot with the Just Javascript Card Game iPhone Debugging Tutorial thread of blog postings of reasonably recent times, into a Bird Quiz, the imagery inspiration thanks to … Aristotle? Aristotle? … clearly and self evidently, Wikipedia, thanks.

The Wikipedia imagery being an image map you might be interested to see the setting up of all this …


<html>
<head>
<title>Dropdown Thumbnail Image Choices - RJM Programming - June, 2023</title>
<style>
option::before {
content: '\00200d'; /* '\0026aa'; */
font-size: 70px;
}
</style>
<script type=text/javascript>
var tw=300, lw=100;
var th=420, lh=70;
var sofar=',';
var elem=null, context=null;
var wikiblurbthanks='<div class="center"><div class="noresize" style="height: 418px; width: 300px; "><map name="ImageMap_fbc6cc846e0ab4e8"><area href="/wiki/Red-crested_turaco" shape="rect" coords="0,0,100,70" alt="Red-crested turaco" title="Red-crested turaco" /><area href="/wiki/Steller%27s_sea_eagle" shape="rect" coords="0,70,100,141" alt="Steller' + "'" + 's sea eagle" title="Steller' + "'" + 's sea eagle" /><area href="/wiki/Rock_dove" shape="rect" coords="0,209,100,141" alt="Rock dove" title="Rock dove" /><area href="/wiki/Southern_cassowary" shape="rect" coords="0,279,100,210" alt="Southern cassowary" title="Southern cassowary" /><area href="/wiki/Gentoo_penguin" shape="rect" coords="0,348,100,279" alt="Gentoo penguin" title="Gentoo penguin" /><area href="/wiki/Bar-throated_minla" shape="rect" coords="0,418,100,348" alt="Bar-throated minla" title="Bar-throated minla" /><area href="/wiki/Shoebill" shape="rect" coords="200,0,100,70" alt="Shoebill" title="Shoebill" /><area href="/wiki/Grey_crowned_crane" shape="rect" coords="200,70,100,141" alt="Grey crowned crane" title="Grey crowned crane" /><area href="/wiki/Anna%27s_hummingbird" shape="rect" coords="200,209,100,141" alt="Anna' + "'" + 's hummingbird" title="Anna' + "'" + 's hummingbird" /><area href="/wiki/Rainbow_lorikeet" shape="rect" coords="200,279,100,210" alt="Rainbow lorikeet" title="Rainbow lorikeet" /><area href="/wiki/Grey_heron" shape="rect" coords="200,348,100,279" alt="Grey heron" title="Grey heron" /><area href="/wiki/Eurasian_eagle-owl" shape="rect" coords="200,418,100,348" alt="Eurasian eagle-owl" title="Eurasian eagle-owl" /><area href="/wiki/White-tailed_tropicbird" shape="rect" coords="300,0,200,70" alt="White-tailed tropicbird" title="White-tailed tropicbird" /><area href="/wiki/Indian_peafowl" shape="rect" coords="300,70,200,141" alt="Indian peafowl" title="Indian peafowl" /><area href="/wiki/Atlantic_puffin" shape="rect" coords="300,209,200,141" alt="Atlantic puffin" title="Atlantic puffin" /><area href="/wiki/American_flamingo" shape="rect" coords="300,279,200,210" alt="American flamingo" title="American flamingo" /><area href="/wiki/Blue-footed_booby" shape="rect" coords="300,348,200,279" alt="Blue-footed booby" title="Blue-footed booby" /><area href="/wiki/Keel-billed_toucan" shape="rect" coords="300,418,200,348" alt="Keel-billed toucan" title="Keel-billed toucan" /></map>';
var imguris=[];
var blurbs=[];
var randlist=[];
var answer='', score=0, goes='', rans='';
var yfirst=false;

function overlay() {
var iii=0;
var optsare=document.getElementsByTagName('option');
for (var ii=0; ii<eval('' + optsare.length); ii++) {
iii=Math.floor(Math.random() * blurbs.length);
while (sofar.indexOf(',' + iii + ',') != -1) {
iii=Math.floor(Math.random() * blurbs.length);
}
sofar+='' + iii + ',';
console.log('iii=' + iii);
optsare[ii].value='' + blurbs[iii];
optsare[ii].innerText='';
optsare[ii].setAttribute('data-answer', blurbs[iii]);
randlist.push(iii);
}
if (eval('' + optsare.length) > 0) {
document.getElementById('schoices').size=eval('' + optsare.length);
document.getElementById('schoices').selectedIndex = '-1';
}
setTimeout(postoverlay, 2000);
}

function postoverlay() {
var lgbegin='linear-gradient(0deg, #ffffff 10%, rgba(255,255,0,0.6) 20%, rgba(192,192,192,0.6) 31%, rgba(255,215,0,0.6) 42%, rgba(211,211,211,0.6) 53%, rgba(255,165,0,0.6) 63%, rgba(224,255,255,0.6) 74%, rgba(254,254,254,0.6) 85%, #CC7722 100%),linear-gradient(to right,yellow,pink),';
var delim='', topp=0, hinc=0;;
var proposeds='<style> #tf { background-image: ; background-position: ; background-size: ; background-repeat: ; } </style>';
var rect=document.getElementById('schoices').getBoundingClientRect();
var optsare=document.getElementsByTagName('option');
//var rectrtd=document.getElementById('rtd').getBoundingClientRect();


if (eval('' + rect.height) > 100 || 1 == 1) {

document.getElementById('schoices').style.backgroundColor='transparent';
document.getElementById('tf').style.position='absolute';
document.getElementById('tf').style.left='' + rect.left + 'px';
document.getElementById('tf').style.top='' + rect.top + 'px';
document.getElementById('tf').style.width='' + rect.width + 'px';
document.getElementById('tf').style.height='' + rect.height + 'px';

document.getElementById('schoices').style.position='absolute';
document.getElementById('schoices').style.left='' + rect.left + 'px';
document.getElementById('schoices').style.top='' + rect.top + 'px';
document.getElementById('schoices').style.width='' + rect.width + 'px';
document.getElementById('schoices').style.height='' + rect.height + 'px';


//document.getElementById('rtd').style.position='absolute';
//document.getElementById('rtd').style.left='' + rectrtd.left + 'px';
//document.getElementById('rtd').style.top='' + rectrtd.top + 'px';
//document.getElementById('rtd').style.width='' + rectrtd.width + 'px';
//document.getElementById('rtd').style.height='' + rectrtd.height + 'px';

// Thanks to https://stackoverflow.com/questions/49660659/css-gradients-inside-gradients
//document.getElementById('tf').style.background='linear-gradient(0deg, #ffffff 10%, rgba(255,255,0,0.6) 20%, rgba(192,192,192,0.6) 31%, rgba(255,215,0,0.6) 42%, rgba(211,211,211,0.6) 53%, rgba(255,165,0,0.6) 63%, rgba(224,255,255,0.6) 74%, rgba(254,254,254,0.6) 85%, #CC7722 100%), linear-gradient( to right, yellow, pink )'; // #fcfafc #f9f6f8 #f8f1f3
document.getElementById('tf').style.zIndex='-1';
topp=rect.top;
//alert('rect.height=' + rect.height);
lgbegin='';
// <img alt="Bird Diversity 2013.png" src="//upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Bird_Diversity_2013.png/300px-Bird_Diversity_2013.png" decoding="async" width="300" height="418" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Bird_Diversity_2013.png/450px-Bird_Diversity_2013.png 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Bird_Diversity_2013.png/600px-Bird_Diversity_2013.png 2x" data-file-width="999" data-file-height="1392" usemap="#ImageMap_fbc6cc846e0ab4e8">


for (var ii=0; ii<eval('' + document.getElementById('schoices').size); ii++) {
hinc=eval('' + optsare[ii].style.height);
proposeds=proposeds.replace(' ;', delim + lgbegin + "url('" + imguris[randlist[ii]] + "')" + ' ;');
proposeds=proposeds.replace(' ;', delim + rect.left + 'px ' + topp + 'px' + ' ;');
if (1 == 11) {
proposeds=proposeds.replace(' ;', delim + rect.width + 'px ' + hinc + 'px' + ' ;');
} else if (1 == 1) {
proposeds=proposeds.replace(' ;', delim + 'contain' + ' ;');
} else {
proposeds=proposeds.replace(' ;', delim + rect.width + 'px ' + Math.round(eval(rect.height / eval('' + document.getElementById('schoices').size))) + 'px' + ' ;');
}
proposeds=proposeds.replace(' ;', delim + 'no-repeat' + ' ;');
delim=',';
if (1 == 11) {
topp+=hinc;
} else {
topp+=eval(rect.height / eval('' + document.getElementById('schoices').size));
}
}

document.getElementById('dstyle').innerHTML=proposeds.replace("</stXyle>", " option::before { content: '' !important; } </style>");

}

}

function process(tv, tvo) {
if (answer == ' ' && tv == '') {
answer='';
} else {
if (answer == '') {
while (answer == '') {
answer=prompt('What is your bird type guess?', '');
if (answer == null) { answer=''; }
}
}
goes++;
var val=document.getElementById('schoices');
var ival=val.selectedIndex;
rans=('' + val.options[val.selectedIndex].getAttribute('data-answer'));
document.getElementById('schoices').selectedIndex = '-1';
if (answer.trim().toLowerCase() == rans.trim().toLowerCase()) {
score++;
} else {
setTimeout(explain, 200);
}
document.getElementById('score').innerHTML='Score: ' + score + '/' + goes;
answer=' ';
document.getElementById('ians').value='';
setTimeout(noans, 400);
}
}

function noans() {
answer='';
}

function explain() {
if (confirm('Sorry, not the answer. Do you want to know what that bird is called?')) {
alert(rans);
}
}

function canvasize() {
document.getElementById('schoices').title='Quiz';
elem=document.getElementById('mycanvas');
context = elem.getContext('2d');
var cs=wikiblurbthanks.split(' coords="');
var bs=wikiblurbthanks.split(' alt="');
for (var kk=1; kk<bs.length; kk++) {
blurbs.push(bs[kk].split('"')[0]);
if (kk == 1) {
if (cs[1].indexOf('0,') == 0 && cs[2].indexOf('0,') == 0) {
yfirst=true;
}
}
}
console.log(blurbs);
//alert('blurbs length=' + blurbs.length);
var cimg=new Image();
cimg.onload = function(){
var ourlw=eval(cimg.width / 3);
var ourlh=eval(cimg.height / 6);
if (yfirst) {
for (var ii=0; ii<3; ii++) { for (var jj=0; jj<6; jj++) { context.clearRect(0,0,elem.width,elem.height); context.drawImage(cimg,eval(ii * ourlw),eval(jj * ourlh),ourlw,ourlh,0,0,elem.width,elem.height); imguris.push(elem.toDataURL('image/png')); console.log('here'); } } } else { for (var jj=0; jj<6; jj++) { for (var ii=0; ii<3; ii++) { context.clearRect(0,0,elem.width,elem.height); context.drawImage(cimg,eval(ii * ourlw),eval(jj * ourlh),ourlw,ourlh,0,0,elem.width,elem.height); imguris.push(elem.toDataURL('image/png')); console.log('here'); } } } overlay(); }; cimg.src='<?php echo 'data:image/png;base64,' . base64_encode(file_get_contents('http://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Bird_Diversity_2013.png/300px-Bird_Diversity_2013.png')) ?>'; }
</script>
</head>
<body onload='canvasize();'>
<!--table><tr><td style=width:25%;-->
<select data-size=9 onchange=process(this.value,this); style='display:block;background-color:#fefefe;overflow-y:auto;width:104px;border:2px dotted green;' title='Media and document action items ... please note you can hover swipe right or left, accurately, and with panache, regarding animated options to speed up transitions between option values' id=schoices><option class=nonwhite style=text-align:center; id=mydefopt title='Add Voiceover Audio to Video' value=''></option><option value='Add Voiceover Audio to Video'> Add Voiceover Audio to Video </option><option id=oimagemagick style='text-align:center;' value='Images to PDF'> Images to PDF</option><option id=opdfimages style='text-align:right;' value='PDF to Images'> PDF to Images</option><option value='Burn subtitles'> Burn subtitles</option><option value='Concat demuxer'> Concat demuxer</option><option value='Rotate a video'> Rotate a video</option><option id=opandoc style=text-align:center; value='Text to HTML'> Text to HTML</option><option class='nonwhite' style=text-align:center; id=mydefopttwo title='pandoc' value=''></option></select>
<!--/td><td style=width:75%; id=rtd>
<h1 style=float:right;>  Dropdown Thumbnail Image Choices</h1><br>
<h3 style=float:right;>  RJM Programming - June, 2023</h3>
</td></tr></table-->
<div id=tf contenteditable=true></div>
<div id=dstyle style=display:none;></div>
<h1 style='position:absolute;left:calc(50% - 600px);top:0px;'>Dropdown Thumbnail Image Choices</h1><br>
<h3 style='position:absolute;left:calc(50% - 600px);top:100px;'>RJM Programming - June, 2023</h3>
<h4 style='position:absolute;left:calc(50% - 600px);top:200px;'>Bird Quiz ... thanks to <a target=_blank title='Bird' href='https://en.wikipedia.org/wiki/Bird'>Wikipedia</a></h3>
<p id=score style='position:absolute;left:calc(50% - 600px);top:300px;'>Score: 0/0</p>
<div style='position:absolute;left:calc(50% - 600px);top:400px;'>
<input id=ians onblur='answer=this.value;' placeholder='Your guess, then click the relevant bird image' value='' style='width:300px;'></input>
</div>
<canvas id=mycanvas width=100 height=70 style=display:none;></canvas>
</body>
</html>

… in our “proof of concept” dropdown_thumbnail_image_choices.php Bird Quiz web application you should feel free to try for yourself.

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.

Posted in eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Code Difference Privacy Tutorial

Code Difference Privacy Tutorial

Code Difference Privacy Tutorial

Yesterday’s Code Difference Colour Coding Tutorial Difference Report modifications (still) had the inherent weakness …

  • it was possible, but unlikely, for users to see other user generated reports, if they happened to be asking for reports at exactly the same time … because …
  • we had not catered for busy traffic here … but, today …
  • we cater, better, for busy online traffic … and at the same time …
  • improve the privacy of the reporting on an IP address basis

The downside, at least for us managing this, is that we do not want a build up of files belonging to difference reports long gone. We arrange it, then, that as soon as the report is created, a window.open scenario is coded for …

<?php

$legend=' <span id=lspan><span><font size=2 color=purple>New additional</font></span> <span><font size=2 color=magenta>Changed single </font><font size=2 color=indigo> line</font></span> <span><font size=2 color=blue>New block of lines</font></span> <span><font size=2 color=orange>Deleted lines</font></span> <span><font size=2 color=darkgreen>Changed multiple </font><font size=2 color=olive>lines</font> <a id=myaa onclick="var wod=window.open(' . "'','_blank','left=100,top=100,width=600,height=600'" . '); wod.document.write(' . "'<textarea title=' + document.URL + ' cols=120 rows=40 style=background-color:pink;>' + " . 'window.atob(' . "'" . trim(base64_encode(file_get_contents("huh" . server_remote_addr() . ".huh"))) . "'" . ') + ' . "'</textarea>'" . '); wod.document.title=document.URL; " style=text-decoration:underline;cursor:pointer;>Original ...</a></span></span>';

$onecommand=" function muchl() { if (document.getElementById('lspan').innerHTML.indexOf(\".atob('')\") != -1) { document.getElementById('lspan').innerHTML=document.getElementById('lspan').innerHTML.replace(\".atob('')\", \".atob('" . trim(base64_encode(file_get_contents("huh" . server_remote_addr() . ".huh"))) . "')\"); } } setTimeout(muchl,8000); ";

?>

… leaving the door open for us to tidy up straight away in our changed diff.php‘s more colourful Code Differences helper.


Previous relevant Code Difference Colour Coding Tutorial is shown below.

Code Difference Colour Coding Tutorial

Code Difference Colour Coding Tutorial

It’s coming up to a few years now, since we looked at the code differences reporting we offer the reader, as a way to scrutinize code changes, around here, when we presented Code Download Table Difference Functional Hover Tutorial. Well, we thought we might try some colour coding to perhaps lift the fog on the cryptic nature of Linux diff (difference) command based reports. They can be cryptic because they can feed into the automation feeding of the report into other Linux commands to facilitate ongoing editing endeavours, but we do not want to go into that here, at least today.

But on examining the reports we came up with the following difference report “categories” if you will …

  • New additional
  • Changed single line
  • New block of lines
  • Deleted lines
  • Changed multiple lines

… the header (of a block of interest) the dead give away, depending on the existence of “a” or “c” or “d” and/or “,” for a common sense reinterpretation by us not visiting “man diff” ourselves, yet, regarding this work.

Feel free to take a look at our changed diff.php‘s more colourful Code Differences helper.


Previous relevant Code Download Table Difference Functional Hover Tutorial is shown below.

Code Download Table Multiple Row Email Hover Tutorial

Code Download Table Difference Functional Hover Tutorial

Is it worth adding “onmouseover” event logic onto yesterday’s Code Download Table Difference Functional Linking Tutorial? You bet it is! Just because “onmouseover” has no relevance to mobile platforms, so, obversely, developing software with version control systems is irrelevant to mobile platforms.

a place for everything and everything in its place

… we figure. But this is of relevance to the programmer. Sometimes, rather than cater for all the platforms, settling on a subset (of those platforms) can be apt because …

  • one of mobile or non-mobile subsets of platforms is irrelevant to the scenario … as for today … or …
  • you try to reinvent the wheel on the pretext that you are waiting for a particular web browser or platform to allow the functionality in, into the future … you could be waiting a while, with the complexity of app arrangements going on around the net these days

Anyway, back to the “onmouseover” event on non-mobile platforms … it was the case that this event was a favourite for the conduit towards Ajax (client) functionality. And thinking on what we do today to nuance our Code Differences PHP web application, we were thinking …

What would Ajax (like to) do?

… and we decided Ajax would really like to …

  • populate a “div” style=display:inline-block; element adjacent to the functional detail to inform about … but this was not possible … so, instead, we …
  • populate a popup window near to the functional detail to inform about

… for a non-mobile “hover” (ie. “onmouseover”) event.

Along the way we add some more hashtag navigations and set up more colour coding to the output of (the optional) “functional links” Code Difference reporting.

So take a look at our changed diff.php Code Differences helper applied to itself below …


Previous relevant Code Download Table Multiple Row Email Report Tutorial is shown below.

Code Download Table Multiple Row Email Report Tutorial

Code Download Table Multiple Row Email Report Tutorial

Before leaving yesterday’s Download and Copy or Move Code Download Table Tutorial extensions to our Code Download Table functionality …

  • add copy onto a download functionality to the Code Download Table … today, we …
  • add a Multiple Row selection basis for a personalized Email Report for the user

… as we saw that there was scope for this as a sharing mechanism for project discussions and ideas, we hope.

Today’s tutorial picture tries to show the steps to emailing off a report of interest to a user …

  1. User clicks the “Allow Multiple Row Clicks” checkbox …

    prefixask=prefixask.replace('</div>', '<div id=divawrc style=display:inline-block;>  Allow Multiple Row Clicks <input onchange="domrows();" id=awrc style=inline-block; type=checkbox></input> <div id=dawrc style=display:inline-block;></div></div></div>');

    … which causes …
  2. “Report” button shows to its right …

    function domrows() {
    document.getElementById('dawrc').innerHTML='<input style=inline-block; type=button onclick=treportdo(); value=Report></input>';
    var trsis=document.getElementsByTagName('tr');
    for (var itrsis=0; itrsis<trsis.length; itrsis++) {
    trsis[itrsis].onclick = function(e) { if (e.target.innerHTML != '') { var trs=document.getElementsByTagName('tr'); for (var itrs=0; itrs<trs.length; itrs++) { if (trs[itrs].outerHTML.indexOf(e.target.innerHTML) != -1) { trs[itrs].style.border='2px dotted red'; } } } };
    }
    }

    … and table row onclick logic is dynamically applied to those “tr” elements
  3. User clicks somewhere within rows they are interested in seeing be included in a report (which is a snippet of the whole Code Download Table, perhaps to do with a project of interest, or a learning topic of interest)
  4. User optionally clicks the “Report” button …

    function treportdo() {
    var trsis=document.getElementsByTagName('tr');
    webc='<html><head><script type="text/javascript"> function emailto(eto) { window.opener.parentemailto(eto); } function xemailto(eto) { if (eto.indexOf("@") != -1) { var zhr=new XMLHttpRequest(); var zform=new FormData(); zform.append("inline",""); zform.append("to",eto); zform.append("subj","Code Download Table part"); zform.append("body",document.getElementById("mytable").outerHTML); zhr.open("post", "//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php", true); zhr.send(zform); alert("Email sent to " + eto); } } </script></head><body><table id=mytable></table><br><br><br><input onblur=emailto(this.value); placeholder="Email to" type=email></input></body></html>';
    for (var itrsis=0; itrsis<trsis.length; itrsis++) {
    if (itrsis == 0) {
    webc=webc.replace('</table>', trsis[itrsis].outerHTML + '</table>');
    }
    if (trsis[itrsis].outerHTML.indexOf('>') > trsis[itrsis].outerHTML.indexOf('border:')) {
    if (trsis[itrsis].outerHTML.indexOf('dotted') > trsis[itrsis].outerHTML.indexOf('border:')) {
    webc=webc.replace('</table>', trsis[itrsis].outerHTML + '</table>');
    }
    }
    }
    var woois=window.open('','_blank','top=20,left=20,width=600,height=600');
    woois.document.write(webc);
    }

    … which causes a …
  5. New popup window opens showing the relevant snippet of Code Download Table of interest to the user … including …
  6. Textbox for an optional emailee entry that can be filled in … to …
  7. Set off Ajax/FormData methodology means …

    function parentemailto(eto) {
    if (eto.indexOf("@") != -1) {
    var zhr=new XMLHttpRequest();
    var zform=new FormData();
    zform.append("inline","");
    zform.append("to",eto);
    zform.append("subj","RJM Programming Code Download Table part");
    zform.append("body", reltoabs('<table' + webc.split('</table>')[0].split('<table')[1] + '</table>'));
    zhr.open("post", "//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php", true);
    zhr.send(zform);
    alert("Email sent to " + eto);
    }
    }

    … to send off an Inline HTML Email report to the emailee … including …
  8. Links of email can be clicked to get back to source code and other links back at the RJM Programming domain web server

… in our changed getmelist.js external Javascript code file (that you can try out for yourself at this live run link).


Previous relevant Download and Copy or Move Code Download Table Tutorial is shown below.

Download and Copy or Move Code Download Table Tutorial

Download and Copy or Move Code Download Table Tutorial

After the “goings on” with the relatively recent PHP Blog Summary Fixed Title Events Tutorial we thought we were finished with “Code Download Table” functionality … but then …

along came Jones yesterday’s Download and Copy or Move Server Tutorial

… and … lo and behold … we saw a good use for the idea of …

  1. download from “the net” to a Downloads folder on your computer or device … and more often than not …
  2. you, the user, copies or renames this data to another location on your computer or device with command line or with operating system GUI

… and allowing for that second step above be programmatical with the most apt functionality that had ever passed our cotton pickin’ mind … our Code Download Table … wi’ all tho’ GETME’s!

But we don’t want to interfere too much with the Code Download Table “flow” here, so create up the top left 20 seconds worth of time (extendable by their actions) available to the user to create “download” attributes on all …

  • “a” links … with …
  • “href” attribute containing “GETME” …
  • but not “diff.php” … and …
  • “download” attribute (the attribute necessary to “download” rather than our default displaying of source code in a new webpage)

… plus no href attribute containing “?s=” either, for today’s purposes with a changed getmelist.js external Javascript code file (that you can try out for yourself at this live run link) … via its new …


var dnprefix=decodeURIComponent(('' + localStorage.getItem('download_copy_to_folder')).replace(/^null$/g,'')); //.replace(/\+/g,' ').replace(/\\\\/g, '_').replace(/\//g, '_').replace(/\:/g, '_');
var delaymore=0;
var prefixask='<div id=firstask style="position:absolute;top:0px;left:0px;"> Download GETME? <input id=dpccb style=inline-block; type=checkbox onchange="dogetmes(document.getElementById(' + "'" + 'dpcis' + "'" + ').value);"></input> <input style=inline-block;width:300px; onclick="delaymore+=20000;" onblur="if (document.getElementById(' + "'" + 'dpccb' + "'" + ').checked) { dogetmes(document.getElementById(this.value); }" type=text id=dpcis placeholder="Optional Download Folder Later Copy to Place via Listener" value="' + dnprefix + '"></input></div>';

function dogetmes(dpprefix) {
delaymore+=20000;
var asis=document.getElementsByTagName('a');
if (dpprefix != dnprefix && 1 == 7) {
localStorage.setItem('download_copy_to_folder', dpprefix);
}
for (var iasis=0; iasis<asis.length; iasis++) {
if (asis[iasis].href.indexOf('diff.php') == -1 && asis[iasis].href.indexOf('?s=') == -1 && asis[iasis].href.indexOf('GETME') != -1) {
asis[iasis].download=dpprefix.replace(/\//g,'_').replace(/\\\\/g,'_').replace(/\:/g,'_') + asis[iasis].href.split('/')[eval(-1 + asis[iasis].href.split('/').length)];
}
}
}

function nomorepa() {
if (eval('' + delaymore) == 0) {
if (document.getElementById('firstask')) {
document.getElementById('firstask').innerHTML='';
}
} else {
setTimeout(nomorepa, eval('' + delaymore));
delaymore=0;
}
}

function lastdivpop() {
var wasih='';
if (document.getElementById('lastdiv')) {
if (document.getElementById('lastdiv').innerHTML == '') {
wasih=wasih;
setTimeout(lastdivpop, 3000);
} else if (document.getElementById('lastdiv').innerHTML.indexOf('firstask') == -1) {
wasih=document.getElementById('lastdiv').innerHTML;
document.getElementById('lastdiv').innerHTML=prefixask + wasih;
prefixask='';
setTimeout(nomorepa, 20000);
} else {
setTimeout(lastdivpop, 3000);
}
}
}

setTimeout(lastdivpop, 8000);


Previous relevant Download and Copy or Move Server Tutorial is shown below.

Download and Copy or Move Server Tutorial

Download and Copy or Move Server Tutorial

Yesterday’s Download and Copy or Move Primer Tutorial was all about the “client side” of …

… and we’ve just “tweaked” (albeit, very importantly, in our books (… but the pamphlettes are still not playing ball)) to ensure no “file clobbering” takes place so that the Korn Shell now does …


suf=""
isuf=-1
while [ -f "${dpath}/${brest}${suf}" ]; do
((isuf=isuf+1))
suf="_${isuf}"
done
if [ ! -z "$suf" ]; then
echo "mv ${dpath}/${brest} ${dpath}/${brest}${suf} # `date`" >> download_to_place.out
mv ${dpath}/${brest} ${dpath}/${brest}${suf} >> download_to_place.out 2>> download_to_place.err
fi

… in download_copier.ksh download_copier.ksh Korn Shell scripting on our macOS operating system “client”.

But today is mainly about filling in the missing bits on the “server” side. This (need for a) “conduit” we referred to yesterday is because we accept no folder paths can be mentioned at the “server” end. Suppose, though, that the “non-pathed” filename we supply to an “a” link’s “download” attribute can be prefixed by a mildly mashed up version of that path we copy to from the Downloads folder of your “client” computer or device, as you perform a “download” via the clicking of an “a” link.

Well, at this blog we’d already started functionality to toggle the use or not of …

  • “a” links … with …
  • “href” attribute containing “GETME” …
  • but not “diff.php” … and …
  • “download” attribute (the attribute necessary to “download” rather than our default displaying of source code in a new webpage)

Were you here, then, when we published WordPress Blog Download Mode Toggler Primer Tutorial (or were you indisposed again?!) There we established an “All Posts” menu “Toggle Download Mode from GETME” option piece of functionality to toggle between …

  • displaying of source code in a new webpage for GETME “a” links … versus …
  • use the changed PHP toggle_download.php in conjunction with a changed good ‘ol TwentyTen Theme header.php as below …
    <?php

    if (outs == null) {
    var dnprefix=decodeURIComponent(('' + localStorage.getItem('download_copy_to_folder')).replace(/^null$/g,'')).replace(/\+/g,' ').replace(/\\\\/g, '_').replace(/\//g, '_').replace(/\:/g, '_');
    for (idmjk=0; idmjk<admjk.length; idmjk++) {
    if (admjk[idmjk].href.indexOf('GETME') != -1 && admjk[idmjk].href.indexOf('diff.php') == -1) {

    if (origcafd < 0) { //!cafd) {
    xp=admjk[idmjk].href.split("GETME");
    prexp=xp[0].split("/");
    postprexp=prexp[-1 + prexp.length].split(".");
    extis = postprexp[-1 + postprexp.length].replace(/_/g,"").replace(/-/g,"").replace(/GETME/g,"");
    outs="//www.rjmprogramming.com.au/getmelist.htm?topoff=150&tsp=" + (Math.floor(Math.random() * 1999900) + 100) + "#" + postprexp[0] + "." + postprexp[-1 + postprexp.length].replace(extis,"").replace(extis,"").replace(extis,"") + "GETME" + extis;
    aorig=admjk[idmjk].innerHTML;
    admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(".","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Code Download Table\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=500,height=500'); } return false; \">⚫</span>");
    if (aorig == admjk[idmjk].innerHTML && admjk[idmjk].innerHTML.indexOf('er posts') == -1) admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(" ","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Code Download Table\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=500,height=500'); } return false; \">⚪</span>");
    cafd++;
    } else {
    prestuffs = admjk[idmjk].href.split('/');
    newaspare = admjk[idmjk].href.replace('_-GETME', '').replace('__GETME', '').replace('_GETME', '').replace(big, '');

    while (big.indexOf('-') != -1) {

    big = big.replace('-', '');

    newaspare = newaspare.replace(big, '');

    }

    big = '----------------------GETME';
    stuffs = newaspare.split('/');
    if (dnprefix != '') {
    admjk[idmjk].download = dnprefix + prestuffs[stuffs.length - 1];
    } else {

    admjk[idmjk].download = dnprefix + stuffs[stuffs.length - 1];
    }
    admjk[idmjk].title = "(Really download) " + admjk[idmjk].title + ' ... welcome to the long hover functionality that shows allows for a Download Mode for the blog that can be toggled';
    admjk[idmjk].onmouseover = " getDownloadMode(); ";
    admjk[idmjk].onmouseout = " yehBut(); ";
    admjk[idmjk].ontouchstart = " getDownloadMode(); ";
    admjk[idmjk].ontouchend = " yehBut(); ";
    }
    } else if (admjk[idmjk].href.indexOf('GETME') != -1 && origcafd < 0) { //!cafd) {
    xp=admjk[idmjk].href.split("GETME");
    prexp=xp[0].split("/");
    postprexp=prexp[-1 + prexp.length].split(".");
    extis = postprexp[-1 + postprexp.length].replace(/_/g,"").replace(/-/g,"").replace(/GETME/g,"");
    outs="//www.rjmprogramming.com.au/getmelist.htm?topoff=150&tsp=" + (Math.floor(Math.random() * 1999900) + 100) + "#" + postprexp[0] + "." + postprexp[-1 + postprexp.length].replace(extis,"").replace(extis,"").replace(extis,"") + "GETME" + extis;
    aorig=admjk[idmjk].innerHTML;
    selbitis=allthecombos((admjk[idmjk].href + '=').split('=')[1].split('&')[0]);
    admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(".","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Code Download Table\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=500,height=500'); } return false; \"><select onchange=\" if (this.value.length > 0) { window.open(this.value,'_blank'); } return false; \" style='margin-bottom:0px;width:40px;' id='sel" + cafd + "'><option value=>⚫</option>" + selbitis + "</select></span>");
    if (aorig == admjk[idmjk].innerHTML && admjk[idmjk].innerHTML.indexOf('er posts') == -1) admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(" ","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Code Download Table\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=500,height=500'); } return false; \"><select onchange=\" if (this.value.length > 0) { window.open(this.value,'_blank'); } return false; \" style='margin-bottom:0px;width:40px;' id='sel" + cafd + "'><option value=>⚪</option>" + selbitis + "</select></span>");
    cafd++;
    } else if ((admjk[idmjk].innerHTML.indexOf('live run') != -1 || admjk[idmjk].title.toLowerCase().indexOf('click picture') != -1) && origcafd < 0) { //!cafd) {
    outs="//www.rjmprogramming.com.au/slideshow.html#tuts";
    admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(" ","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Cut to the Chase ... see the blog post list related to live runs and slideshows ... ie. the main point of the blog posting\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=650,height=100'); } return false; \">✂</span>");
    cafd++;
    }
    }
    }

    ?>
    … to, depending on whether the user specifies in the “All Posts” toggling’s Javascript prompt window presented, specifies a new comma separated “client folder of interest to copy to” place (stored in window.localStorage), will …

    1. download with the GETME to the Downloads folder and copy off to the specified folder of interest (backing up as necessary) … versus …
    2. the default download mode downloads to the Downloads folder without the GETME parts

See these changes in action below, contextualizing “server” and “client” codes in the full picture of assisted Downloads (copied on to a folder of the user’s interest) …


Previous relevant Download and Copy or Move Primer Tutorial is shown below.

Download and Copy or Move Primer Tutorial

Download and Copy or Move Primer Tutorial

Downloading from “the net” (“server land”) to your computer or device (“client land”) is a big part of the online experience and the sharing of data over the world wide web. But have you ever wondered about the two step design of …

  1. download from “the net” to a Downloads folder on your computer or device … and more often than not …
  2. you, the user, copies or renames this data to another location on your computer or device with command line or with operating system GUI

… ? Why not allow the “server” side define where it can download to on the “client”? Well, that would be a security nightmare, allowing a highjacking of mission critical files on your computer or device. So, I get it, that is a “no no”. But could we have a controlled “arrangement” between …

… ? We think that sounds reasonable and so, today, we start our (two parts or more) mini-project (making step 2 above be considered to be programmatically handled, sometimes) designing a Korn Shell (“client” side) listener to suit our macOS “client” computer, executed as a background process via …


ksh download_copier.ksh &

But what is the conduit, if the “server” web applications/pages cannot define a destination folder other than the macOS Downloads folder for the user involved? Well, that is where we need either …

… to define a “client land” folder to copy to (from the user’s Download folder (receiving the downloaded data).

That first Korn Shell read command interactive input was interesting to us for a command backgrounded via the “&” command suffix. But if stdin and stdout are not mentioned in the command you can answer this interactive input and then the processing the Korn Shell performs proceeds in the background. Exactly what we were hoping for, but weren’t sure that this was the case!

The picture is filled in better tomorrow as we discuss the conduit in more detail tomorrow.

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.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Event-Driven Programming, Operating System, Software, Tutorials | Tagged , , , , , , , , , , , , , | Leave a comment

Code Difference Colour Coding Tutorial

Code Difference Colour Coding Tutorial

Code Difference Colour Coding Tutorial

It’s coming up to a few years now, since we looked at the code differences reporting we offer the reader, as a way to scrutinize code changes, around here, when we presented Code Download Table Difference Functional Hover Tutorial. Well, we thought we might try some colour coding to perhaps lift the fog on the cryptic nature of Linux diff (difference) command based reports. They can be cryptic because they can feed into the automation feeding of the report into other Linux commands to facilitate ongoing editing endeavours, but we do not want to go into that here, at least today.

But on examining the reports we came up with the following difference report “categories” if you will …

  • New additional
  • Changed single line
  • New block of lines
  • Deleted lines
  • Changed multiple lines

… the header (of a block of interest) the dead give away, depending on the existence of “a” or “c” or “d” and/or “,” for a common sense reinterpretation by us not visiting “man diff” ourselves, yet, regarding this work.

Feel free to take a look at our changed diff.php‘s more colourful Code Differences helper.


Previous relevant Code Download Table Difference Functional Hover Tutorial is shown below.

Code Download Table Multiple Row Email Hover Tutorial

Code Download Table Difference Functional Hover Tutorial

Is it worth adding “onmouseover” event logic onto yesterday’s Code Download Table Difference Functional Linking Tutorial? You bet it is! Just because “onmouseover” has no relevance to mobile platforms, so, obversely, developing software with version control systems is irrelevant to mobile platforms.

a place for everything and everything in its place

… we figure. But this is of relevance to the programmer. Sometimes, rather than cater for all the platforms, settling on a subset (of those platforms) can be apt because …

  • one of mobile or non-mobile subsets of platforms is irrelevant to the scenario … as for today … or …
  • you try to reinvent the wheel on the pretext that you are waiting for a particular web browser or platform to allow the functionality in, into the future … you could be waiting a while, with the complexity of app arrangements going on around the net these days

Anyway, back to the “onmouseover” event on non-mobile platforms … it was the case that this event was a favourite for the conduit towards Ajax (client) functionality. And thinking on what we do today to nuance our Code Differences PHP web application, we were thinking …

What would Ajax (like to) do?

… and we decided Ajax would really like to …

  • populate a “div” style=display:inline-block; element adjacent to the functional detail to inform about … but this was not possible … so, instead, we …
  • populate a popup window near to the functional detail to inform about

… for a non-mobile “hover” (ie. “onmouseover”) event.

Along the way we add some more hashtag navigations and set up more colour coding to the output of (the optional) “functional links” Code Difference reporting.

So take a look at our changed diff.php Code Differences helper applied to itself below …


Previous relevant Code Download Table Multiple Row Email Report Tutorial is shown below.

Code Download Table Multiple Row Email Report Tutorial

Code Download Table Multiple Row Email Report Tutorial

Before leaving yesterday’s Download and Copy or Move Code Download Table Tutorial extensions to our Code Download Table functionality …

  • add copy onto a download functionality to the Code Download Table … today, we …
  • add a Multiple Row selection basis for a personalized Email Report for the user

… as we saw that there was scope for this as a sharing mechanism for project discussions and ideas, we hope.

Today’s tutorial picture tries to show the steps to emailing off a report of interest to a user …

  1. User clicks the “Allow Multiple Row Clicks” checkbox …

    prefixask=prefixask.replace('</div>', '<div id=divawrc style=display:inline-block;>  Allow Multiple Row Clicks <input onchange="domrows();" id=awrc style=inline-block; type=checkbox></input> <div id=dawrc style=display:inline-block;></div></div></div>');

    … which causes …
  2. “Report” button shows to its right …

    function domrows() {
    document.getElementById('dawrc').innerHTML='<input style=inline-block; type=button onclick=treportdo(); value=Report></input>';
    var trsis=document.getElementsByTagName('tr');
    for (var itrsis=0; itrsis<trsis.length; itrsis++) {
    trsis[itrsis].onclick = function(e) { if (e.target.innerHTML != '') { var trs=document.getElementsByTagName('tr'); for (var itrs=0; itrs<trs.length; itrs++) { if (trs[itrs].outerHTML.indexOf(e.target.innerHTML) != -1) { trs[itrs].style.border='2px dotted red'; } } } };
    }
    }

    … and table row onclick logic is dynamically applied to those “tr” elements
  3. User clicks somewhere within rows they are interested in seeing be included in a report (which is a snippet of the whole Code Download Table, perhaps to do with a project of interest, or a learning topic of interest)
  4. User optionally clicks the “Report” button …

    function treportdo() {
    var trsis=document.getElementsByTagName('tr');
    webc='<html><head><script type="text/javascript"> function emailto(eto) { window.opener.parentemailto(eto); } function xemailto(eto) { if (eto.indexOf("@") != -1) { var zhr=new XMLHttpRequest(); var zform=new FormData(); zform.append("inline",""); zform.append("to",eto); zform.append("subj","Code Download Table part"); zform.append("body",document.getElementById("mytable").outerHTML); zhr.open("post", "//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php", true); zhr.send(zform); alert("Email sent to " + eto); } } </script></head><body><table id=mytable></table><br><br><br><input onblur=emailto(this.value); placeholder="Email to" type=email></input></body></html>';
    for (var itrsis=0; itrsis<trsis.length; itrsis++) {
    if (itrsis == 0) {
    webc=webc.replace('</table>', trsis[itrsis].outerHTML + '</table>');
    }
    if (trsis[itrsis].outerHTML.indexOf('>') > trsis[itrsis].outerHTML.indexOf('border:')) {
    if (trsis[itrsis].outerHTML.indexOf('dotted') > trsis[itrsis].outerHTML.indexOf('border:')) {
    webc=webc.replace('</table>', trsis[itrsis].outerHTML + '</table>');
    }
    }
    }
    var woois=window.open('','_blank','top=20,left=20,width=600,height=600');
    woois.document.write(webc);
    }

    … which causes a …
  5. New popup window opens showing the relevant snippet of Code Download Table of interest to the user … including …
  6. Textbox for an optional emailee entry that can be filled in … to …
  7. Set off Ajax/FormData methodology means …

    function parentemailto(eto) {
    if (eto.indexOf("@") != -1) {
    var zhr=new XMLHttpRequest();
    var zform=new FormData();
    zform.append("inline","");
    zform.append("to",eto);
    zform.append("subj","RJM Programming Code Download Table part");
    zform.append("body", reltoabs('<table' + webc.split('</table>')[0].split('<table')[1] + '</table>'));
    zhr.open("post", "//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php", true);
    zhr.send(zform);
    alert("Email sent to " + eto);
    }
    }

    … to send off an Inline HTML Email report to the emailee … including …
  8. Links of email can be clicked to get back to source code and other links back at the RJM Programming domain web server

… in our changed getmelist.js external Javascript code file (that you can try out for yourself at this live run link).


Previous relevant Download and Copy or Move Code Download Table Tutorial is shown below.

Download and Copy or Move Code Download Table Tutorial

Download and Copy or Move Code Download Table Tutorial

After the “goings on” with the relatively recent PHP Blog Summary Fixed Title Events Tutorial we thought we were finished with “Code Download Table” functionality … but then …

along came Jones yesterday’s Download and Copy or Move Server Tutorial

… and … lo and behold … we saw a good use for the idea of …

  1. download from “the net” to a Downloads folder on your computer or device … and more often than not …
  2. you, the user, copies or renames this data to another location on your computer or device with command line or with operating system GUI

… and allowing for that second step above be programmatical with the most apt functionality that had ever passed our cotton pickin’ mind … our Code Download Table … wi’ all tho’ GETME’s!

But we don’t want to interfere too much with the Code Download Table “flow” here, so create up the top left 20 seconds worth of time (extendable by their actions) available to the user to create “download” attributes on all …

  • “a” links … with …
  • “href” attribute containing “GETME” …
  • but not “diff.php” … and …
  • “download” attribute (the attribute necessary to “download” rather than our default displaying of source code in a new webpage)

… plus no href attribute containing “?s=” either, for today’s purposes with a changed getmelist.js external Javascript code file (that you can try out for yourself at this live run link) … via its new …


var dnprefix=decodeURIComponent(('' + localStorage.getItem('download_copy_to_folder')).replace(/^null$/g,'')); //.replace(/\+/g,' ').replace(/\\\\/g, '_').replace(/\//g, '_').replace(/\:/g, '_');
var delaymore=0;
var prefixask='<div id=firstask style="position:absolute;top:0px;left:0px;"> Download GETME? <input id=dpccb style=inline-block; type=checkbox onchange="dogetmes(document.getElementById(' + "'" + 'dpcis' + "'" + ').value);"></input> <input style=inline-block;width:300px; onclick="delaymore+=20000;" onblur="if (document.getElementById(' + "'" + 'dpccb' + "'" + ').checked) { dogetmes(document.getElementById(this.value); }" type=text id=dpcis placeholder="Optional Download Folder Later Copy to Place via Listener" value="' + dnprefix + '"></input></div>';

function dogetmes(dpprefix) {
delaymore+=20000;
var asis=document.getElementsByTagName('a');
if (dpprefix != dnprefix && 1 == 7) {
localStorage.setItem('download_copy_to_folder', dpprefix);
}
for (var iasis=0; iasis<asis.length; iasis++) {
if (asis[iasis].href.indexOf('diff.php') == -1 && asis[iasis].href.indexOf('?s=') == -1 && asis[iasis].href.indexOf('GETME') != -1) {
asis[iasis].download=dpprefix.replace(/\//g,'_').replace(/\\\\/g,'_').replace(/\:/g,'_') + asis[iasis].href.split('/')[eval(-1 + asis[iasis].href.split('/').length)];
}
}
}

function nomorepa() {
if (eval('' + delaymore) == 0) {
if (document.getElementById('firstask')) {
document.getElementById('firstask').innerHTML='';
}
} else {
setTimeout(nomorepa, eval('' + delaymore));
delaymore=0;
}
}

function lastdivpop() {
var wasih='';
if (document.getElementById('lastdiv')) {
if (document.getElementById('lastdiv').innerHTML == '') {
wasih=wasih;
setTimeout(lastdivpop, 3000);
} else if (document.getElementById('lastdiv').innerHTML.indexOf('firstask') == -1) {
wasih=document.getElementById('lastdiv').innerHTML;
document.getElementById('lastdiv').innerHTML=prefixask + wasih;
prefixask='';
setTimeout(nomorepa, 20000);
} else {
setTimeout(lastdivpop, 3000);
}
}
}

setTimeout(lastdivpop, 8000);


Previous relevant Download and Copy or Move Server Tutorial is shown below.

Download and Copy or Move Server Tutorial

Download and Copy or Move Server Tutorial

Yesterday’s Download and Copy or Move Primer Tutorial was all about the “client side” of …

… and we’ve just “tweaked” (albeit, very importantly, in our books (… but the pamphlettes are still not playing ball)) to ensure no “file clobbering” takes place so that the Korn Shell now does …


suf=""
isuf=-1
while [ -f "${dpath}/${brest}${suf}" ]; do
((isuf=isuf+1))
suf="_${isuf}"
done
if [ ! -z "$suf" ]; then
echo "mv ${dpath}/${brest} ${dpath}/${brest}${suf} # `date`" >> download_to_place.out
mv ${dpath}/${brest} ${dpath}/${brest}${suf} >> download_to_place.out 2>> download_to_place.err
fi

… in download_copier.ksh download_copier.ksh Korn Shell scripting on our macOS operating system “client”.

But today is mainly about filling in the missing bits on the “server” side. This (need for a) “conduit” we referred to yesterday is because we accept no folder paths can be mentioned at the “server” end. Suppose, though, that the “non-pathed” filename we supply to an “a” link’s “download” attribute can be prefixed by a mildly mashed up version of that path we copy to from the Downloads folder of your “client” computer or device, as you perform a “download” via the clicking of an “a” link.

Well, at this blog we’d already started functionality to toggle the use or not of …

  • “a” links … with …
  • “href” attribute containing “GETME” …
  • but not “diff.php” … and …
  • “download” attribute (the attribute necessary to “download” rather than our default displaying of source code in a new webpage)

Were you here, then, when we published WordPress Blog Download Mode Toggler Primer Tutorial (or were you indisposed again?!) There we established an “All Posts” menu “Toggle Download Mode from GETME” option piece of functionality to toggle between …

  • displaying of source code in a new webpage for GETME “a” links … versus …
  • use the changed PHP toggle_download.php in conjunction with a changed good ‘ol TwentyTen Theme header.php as below …
    <?php

    if (outs == null) {
    var dnprefix=decodeURIComponent(('' + localStorage.getItem('download_copy_to_folder')).replace(/^null$/g,'')).replace(/\+/g,' ').replace(/\\\\/g, '_').replace(/\//g, '_').replace(/\:/g, '_');
    for (idmjk=0; idmjk<admjk.length; idmjk++) {
    if (admjk[idmjk].href.indexOf('GETME') != -1 && admjk[idmjk].href.indexOf('diff.php') == -1) {

    if (origcafd < 0) { //!cafd) {
    xp=admjk[idmjk].href.split("GETME");
    prexp=xp[0].split("/");
    postprexp=prexp[-1 + prexp.length].split(".");
    extis = postprexp[-1 + postprexp.length].replace(/_/g,"").replace(/-/g,"").replace(/GETME/g,"");
    outs="//www.rjmprogramming.com.au/getmelist.htm?topoff=150&tsp=" + (Math.floor(Math.random() * 1999900) + 100) + "#" + postprexp[0] + "." + postprexp[-1 + postprexp.length].replace(extis,"").replace(extis,"").replace(extis,"") + "GETME" + extis;
    aorig=admjk[idmjk].innerHTML;
    admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(".","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Code Download Table\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=500,height=500'); } return false; \">⚫</span>");
    if (aorig == admjk[idmjk].innerHTML && admjk[idmjk].innerHTML.indexOf('er posts') == -1) admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(" ","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Code Download Table\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=500,height=500'); } return false; \">⚪</span>");
    cafd++;
    } else {
    prestuffs = admjk[idmjk].href.split('/');
    newaspare = admjk[idmjk].href.replace('_-GETME', '').replace('__GETME', '').replace('_GETME', '').replace(big, '');

    while (big.indexOf('-') != -1) {

    big = big.replace('-', '');

    newaspare = newaspare.replace(big, '');

    }

    big = '----------------------GETME';
    stuffs = newaspare.split('/');
    if (dnprefix != '') {
    admjk[idmjk].download = dnprefix + prestuffs[stuffs.length - 1];
    } else {

    admjk[idmjk].download = dnprefix + stuffs[stuffs.length - 1];
    }
    admjk[idmjk].title = "(Really download) " + admjk[idmjk].title + ' ... welcome to the long hover functionality that shows allows for a Download Mode for the blog that can be toggled';
    admjk[idmjk].onmouseover = " getDownloadMode(); ";
    admjk[idmjk].onmouseout = " yehBut(); ";
    admjk[idmjk].ontouchstart = " getDownloadMode(); ";
    admjk[idmjk].ontouchend = " yehBut(); ";
    }
    } else if (admjk[idmjk].href.indexOf('GETME') != -1 && origcafd < 0) { //!cafd) {
    xp=admjk[idmjk].href.split("GETME");
    prexp=xp[0].split("/");
    postprexp=prexp[-1 + prexp.length].split(".");
    extis = postprexp[-1 + postprexp.length].replace(/_/g,"").replace(/-/g,"").replace(/GETME/g,"");
    outs="//www.rjmprogramming.com.au/getmelist.htm?topoff=150&tsp=" + (Math.floor(Math.random() * 1999900) + 100) + "#" + postprexp[0] + "." + postprexp[-1 + postprexp.length].replace(extis,"").replace(extis,"").replace(extis,"") + "GETME" + extis;
    aorig=admjk[idmjk].innerHTML;
    selbitis=allthecombos((admjk[idmjk].href + '=').split('=')[1].split('&')[0]);
    admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(".","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Code Download Table\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=500,height=500'); } return false; \"><select onchange=\" if (this.value.length > 0) { window.open(this.value,'_blank'); } return false; \" style='margin-bottom:0px;width:40px;' id='sel" + cafd + "'><option value=>⚫</option>" + selbitis + "</select></span>");
    if (aorig == admjk[idmjk].innerHTML && admjk[idmjk].innerHTML.indexOf('er posts') == -1) admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(" ","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Code Download Table\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=500,height=500'); } return false; \"><select onchange=\" if (this.value.length > 0) { window.open(this.value,'_blank'); } return false; \" style='margin-bottom:0px;width:40px;' id='sel" + cafd + "'><option value=>⚪</option>" + selbitis + "</select></span>");
    cafd++;
    } else if ((admjk[idmjk].innerHTML.indexOf('live run') != -1 || admjk[idmjk].title.toLowerCase().indexOf('click picture') != -1) && origcafd < 0) { //!cafd) {
    outs="//www.rjmprogramming.com.au/slideshow.html#tuts";
    admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(" ","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Cut to the Chase ... see the blog post list related to live runs and slideshows ... ie. the main point of the blog posting\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=650,height=100'); } return false; \">✂</span>");
    cafd++;
    }
    }
    }

    ?>
    … to, depending on whether the user specifies in the “All Posts” toggling’s Javascript prompt window presented, specifies a new comma separated “client folder of interest to copy to” place (stored in window.localStorage), will …

    1. download with the GETME to the Downloads folder and copy off to the specified folder of interest (backing up as necessary) … versus …
    2. the default download mode downloads to the Downloads folder without the GETME parts

See these changes in action below, contextualizing “server” and “client” codes in the full picture of assisted Downloads (copied on to a folder of the user’s interest) …


Previous relevant Download and Copy or Move Primer Tutorial is shown below.

Download and Copy or Move Primer Tutorial

Download and Copy or Move Primer Tutorial

Downloading from “the net” (“server land”) to your computer or device (“client land”) is a big part of the online experience and the sharing of data over the world wide web. But have you ever wondered about the two step design of …

  1. download from “the net” to a Downloads folder on your computer or device … and more often than not …
  2. you, the user, copies or renames this data to another location on your computer or device with command line or with operating system GUI

… ? Why not allow the “server” side define where it can download to on the “client”? Well, that would be a security nightmare, allowing a highjacking of mission critical files on your computer or device. So, I get it, that is a “no no”. But could we have a controlled “arrangement” between …

… ? We think that sounds reasonable and so, today, we start our (two parts or more) mini-project (making step 2 above be considered to be programmatically handled, sometimes) designing a Korn Shell (“client” side) listener to suit our macOS “client” computer, executed as a background process via …


ksh download_copier.ksh &

But what is the conduit, if the “server” web applications/pages cannot define a destination folder other than the macOS Downloads folder for the user involved? Well, that is where we need either …

… to define a “client land” folder to copy to (from the user’s Download folder (receiving the downloaded data).

That first Korn Shell read command interactive input was interesting to us for a command backgrounded via the “&” command suffix. But if stdin and stdout are not mentioned in the command you can answer this interactive input and then the processing the Korn Shell performs proceeds in the background. Exactly what we were hoping for, but weren’t sure that this was the case!

The picture is filled in better tomorrow as we discuss the conduit in more detail tomorrow.

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.


If this was interesting you may be interested in this too.

Posted in eLearning, Operating System, Software, Tutorials | Tagged , , , , , , , , , , | Leave a comment