Walking Trip …

Walking Trip

Walking Trip

Offenbach's Suite ... Warts 'n All

Offenbach's Suite ... Warts 'n All

 📅  

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

Posted in Photography, Trips | Tagged , , | 34 Comments

Select Multiple Webpage Palette Speech Bubble Legitimised YouTube Tutorial

Select Multiple Webpage Palette Speech Bubble Legitimised YouTube Tutorial

Select Multiple Webpage Palette Speech Bubble Legitimised YouTube Tutorial

If we gave you the probability of …

1 / ( 73,786,976,294,838,206,464 / 4 )

… of guessing a code, do you know what that code is? If not, do you know what …

73,786,976,294,838,206,464

… represents? Well, how about we leave a snail trail hint …
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
… it’s the same as 64^11 … and the first thing that springs to mind regarding 64 might be …
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
base64?! And the next thing that might spring to mind regarding 11 might be …
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
… number of characters in a YouTube video ID?! Leaving us with …

So what’s the go with “/ 4“?

Well, there you need a lesson in YouTubeonetrics and we’re recommending …

… for mathematics enthusiasts and IT historians alike here. The odds of you guessing any one YouTube video ID of interest just got 4 times easier!

On viewing this totally useful video, thanks, we decided to have a first pass not using Ajax to determine whether a user’s 11 character string is a legitimate YouTube video, and plumping in our …

Day 5 Nuance 3

… pass today, with the “can sometimes not get it right, but that is not really that bad” means by which we can rule out some 11 character strings from consideration as YouTube video references, via …


function maybelegit(ineleven, iflegit) {
if (eval('' + ineleven.length) != 11) {
return iflegit.replace('tube','tuJUNKbe');
} else if (ineleven.slice(-1).replace('A','').replace('E','').replace('I','').replace('M','').replace('Q','').replace('U','').replace('Y','').replace('c','').replace('g','').replace('k','').replace('o','').replace('s','').replace('w','').replace('0','').replace('4','').replace('8','') != '') {
return iflegit.replace('tube','tuJUNKbe');
}
for (var ijk=0; ijk<ineleven.length; ijk++) {
if (ineleven.substring(ijk).substring(0,1) >= 'a' && ineleven.substring(ijk).substring(0,1) <= 'z') {
ijk=ijk;
} else if (ineleven.substring(ijk).substring(0,1) >= 'A' && ineleven.substring(ijk).substring(0,1) <= 'Z') {
ijk=ijk;
} else if (ineleven.substring(ijk).substring(0,1) >= '0' && ineleven.substring(ijk).substring(0,1) <= '9') {
ijk=ijk;
} else if (ineleven.substring(ijk).substring(0,1) == '/' || ineleven.substring(ijk).substring(0,1) == '+') {
ijk=ijk;
} else if (ineleven.substring(ijk).substring(0,1) == '-' || ineleven.substring(ijk).substring(0,1) == '_') {
ijk=ijk;
} else {
return iflegit.replace('tube','tuJUNKbe');
}
}
return iflegit;
}

… called this way


function elevenize(whatwords) {
var outwords=whatwords;
if (!butnotif) {
var klines=0, kwords=0
var otherlines=whatwords.split(String.fromCharCode(10));
var otherwords=[];
for (klines=0; klines<otherlines.length; klines++) {
otherwords=otherlines[klines].split(' ');
for (kwords=0; kwords<otherwords.length; kwords++) {
otherwords[kwords]=otherwords[kwords].split('</')[0];
if (eval('' + otherwords[kwords].length) == 11) {
outwords=outwords.replace(otherwords[kwords], '<tspan class="' + maybelegit(otherwords[kwords],'tubeaudioyou') + '">' + otherwords[kwords] + '</tspan> ');
}
}
}
}
return outwords;
}

But, alas, strings like programming will still get through even though, at the time of writing, is not a valid YouTube video ID yet?!, though the shouted out PROGRAMMING has no truck, now …

… because of the Javascript above in the SVG tspan 11 more legitimate letter word YouTube reference Speech Bubble changed select_palette.html web application, further to yesterday’s Select Multiple Webpage Palette Speech Bubble YouTube One Click Tutorial.


Previous relevant Select Multiple Webpage Palette Speech Bubble YouTube One Click Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble YouTube One Click Tutorial

Select Multiple Webpage Palette Speech Bubble YouTube One Click Tutorial

Improving on yesterday’s Select Multiple Webpage Palette Speech Bubble YouTube Placement Tutorial, today we have …

Day 4 Nuance 2

… bringing the happy news that for a legitimate 11 character YouTube reference within the Speech Bubbles it is a one click scenario for …

  • non-mobile … and …
  • mobile

… alike.

Yet again, what changed? Well …


Previous relevant Select Multiple Webpage Palette Speech Bubble YouTube Placement Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble YouTube Placement Tutorial

Select Multiple Webpage Palette Speech Bubble YouTube Placement Tutorial

It’s …

Day 3 Nuance 1

… today, and you’d expect that scoreline given home ground advantage … onto yesterday’s Select Multiple Webpage Palette Speech Bubble YouTube Tutorial where the progress is …

  • for mobile platforms, where our 11 character links led us to a new window scenario … so yesterday … today …
  • we keep the YouTube video to the same webpage, over to the right

… but still, alas, several tap/clicks needed to get to the video playing.

A lot of the time of “Nuance 1” occurred using a lot of …


event.stopPropagation();

… calling for onclick and onmousedown and ontouchdown event calls in amongst the new tabularly organized inline HTML


function maybeemoji(insvg) {
// blah blah blah
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
if (document.getElementById('dcont').innerHTML.indexOf('<table') != -1) {
return insvg.replace('></text>', '>' + newoutthing + '</text>').replace(" data-emoji=''", " data-emoji='" + newoutthing + "'").replace(' data-emoji=""', ' data-emoji="' + newoutthing + '"');
}
thehoster='tdleft';
return '<table><tr><td id=tdleft style=vertical-align:top;>' + insvg.replace('></text>', '>' + newoutthing + '</text>').replace(" data-emoji=''", " data-emoji='" + newoutthing + "'").replace(' data-emoji=""', ' data-emoji="' + newoutthing + '"') + '</td><td id=tdnothing style=vertical-align:top; onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="event.stopPropagation();"><a onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="notallowed(); event.stopPropagation();" href=#tdleft title="Speech Bubble">💬</a><br><a onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="notallowed(); event.stopPropagation();" href=#tdnothing title="YouTube">📹</a></td><td id=tdright style=vertical-align:top; onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="event.stopPropagation();"><iframe style=display:none;width:900px;height:800px; id=rightif name=rightif src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=&theaNOid=&theifrNOameid=&thebuttoNOnwording=&justaJUNKudio=&youtube_duration=22223.000&email=&emoji=on&c0=on&i0=0&j0=22223&i1=&j1=&i2=&j2=&i3=&j3=&i4=&j4=&i5=&j5=&i6=&j6=&i7=&j7=&i8=&j8=&i9=&j9=&i10=&j10=&i11=&j11=&i12=&j12=&i13=&j13=&i14=&j14=&i15=&j15=&i16=&j16=&i17=&j17=&i18=&j18=&i19=&j19=&i20=&j20=&i21=&j21=&i22=&j22=&i23=&j23=&i24=&j24=&i25=&j25=&i26=&j26=&i27=&j27=&i28=&j28=&i29=&j29="></iframe></td><td id=tdmiddle style=vertical-align:top; onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="notallowed(); event.stopPropagation();"><a onclick="event.stopPropagation();" href=#tdleft title="Speech Bubble">💬</a><br><a onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="notallowed(); event.stopPropagation();" href=#tdnothing title="YouTube">📹</a></td></tr></table>';
}
// blah blah blah non-mobile returns
}

… describing the HTML elements added for mobile usage, here. Even then, annoyingly, if you tapped on one of these, the Javascript would too often call function addcontents in a way we thought was aggravating, and so we resorted to a global variable usage and started doing as below …


var allowed=true;

function addcontents(inboc) {
if (!allowed) {
allowed=true;
return false;
}

var nboc='', seventeen="17", zero=0, numlines=1, one=1, grest='', ghuh='', wasfound=false, jnew=0;
// blah blah blah open textarea popup window blah blah blah
}

function notallowed() {
allowed=false;
setTimeout(function(){ allowed=true; }, 1000);
}

Again, what changed? Well …


Previous relevant Select Multiple Webpage Palette Speech Bubble YouTube Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble YouTube Tutorial

Select Multiple Webpage Palette Speech Bubble YouTube Tutorial

Well, onto yesterday’s SVG Tspan Element Primer Tutorial our “two day” job is “two days” of sorts. Definitely for non-mobile, deploying the “inline audio stream of YouTube video play” concept we wanted, but for mobile, let me “count the ways” …

  1. to get any functionality down to “one tap/click to play” … well …
  2. we tried for mobile, and haven’t given up, but the complexity of “overlay” related z-index and “where to place iframe element” issues exploded my tiny little brain … and so …
  3. for mobile we’ve “parked” the ideal solution … in favour of, for now …
  4. the mobile “two day solution” that, like for non-mobile, underlines those 11 character YouTube references as links that can navigate interested users to a new tab/window YouTube window to play the “whole shebang” (and … sigh … needing that extra tap/click) … leaving …
  5. Days 3 (and on) to nuance

Another project where the last 10% nuances is probably going to take more time than the rest! Anyway, we’ll see how this “mini project” develops.

What changed? Well …

  • the SVG tspan 11 letter word YouTube reference Speech Bubble changed select_palette.html web application … now helped out by …
  • now SVG tspan savvy external Javascript ytaudioonly.js assisting YouTube Audio Stream of Video Playsspecifically

    // blah blah blah
    var thespansare=[];

    function ihun(ao) {
    var aih=ao.innerText;
    if (aih.trim() != '') {
    var newihis='';
    for (var iaih=0; iaih<aih.length; iaih++) {
    newihis+='_';
    }
    ao.innerHTML=newihis;
    }
    }


    function audioytlook() { // first happens around document.body onload event
    // blah blah blah
    var taop='', ttdom='', ttid=' id=newspan8', ziif='', yiif='';
    // blah blah blah
    thespansare=document.getElementsByTagName('tspan');
    if (eval('' + thespansare.length) > 0) {
    for (jits=0; jits<thespansare.length; jits++) {
    //alert(thespansare[jits].outerHTML);
    if ( ('' + thespansare[jits].outerHTML).indexOf('tubeaudioyou') != -1 && ('' + thespansare[jits].outerHTML).indexOf(' data-mentioned=') == -1) {
    //alert('HERE');
    jitrect=thespansare[jits].getBoundingClientRect();
    if (document.getElementById('doverlay')) {
    if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && document.URL.indexOf('.9JUNK5.247/') == -1) {
    //alert('why');
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    ttid+='8';
    } else {
    ziif=' style="z-index:50;" ';
    yiif=' event.stopPropagation(); ';
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); "; // document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    //document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.4;z-index:176;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a></span>';
    //document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    //alert('<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">___________</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>');
    document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">___________</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    ttid+='8';
    }
    } else {
    if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && document.URL.indexOf('.9JUNK5.247/') == -1) {
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    document.body.innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    ttid+='8';
    } else {
    ziif=' style="z-index:150;" ';
    yiif=' event.stopPropagation(); ';
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    document.body.innerHTML+='<span' + ttid + ' style="opacity:0.4;z-index:176;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">___________</a></span>';
    ttid+='8';
    }
    }
    thespansare[jits].setAttribute('data-mentioned', 'y');
    }
    }
    thespansare=[];
    }

    var audioonlyas=document.getElementsByTagName('a');
    // blah blah blah
    }

    // blah blah blah

    … slotting in tspan logic ahead of the a link analysis


Previous relevant SVG Tspan Element Primer Tutorial is shown below.

SVG Tspan Element Primer Tutorial

SVG Tspan Element Primer Tutorial

We’re starting a planned “mini project” to improve Select Multiple Webpage Palette Speech Bubble Swipe Tutorial and what we find important …

  1. regarding improvements to existant functionality it is most important to not interfere with any current functionality … and then …
  2. implement new functionalities off this platform

… and with our “mini project” of embellishing 11 letter words in the Speech Bubbles of our Select Multiple Webpage Palette Speech Bubble web application of recent times, we have a natural compartmentalization playing out mimicking those ideas above, that goes …

  1. Day 1 – work with the data that is the HTML (and SVG) of Speech Bubbles where they look and behave as ever, but 11 letter words get nested into SVG tspan elements
  2. Day 2 – embellish the web application via those SVG tspan elements

It’s our first go using SVG tspan elements as a “forward thinking” tool, and it helped us thinking on this regarding the corrollaries to HTML span element. What initially concerned us using SVG tspan was whether we’d have to specify x and y attributes, but, as it panned out, no, the SVG text element nesting the tspan takes care of that, so, “top supportive” we’d say, and a lot like how we think of the HTML span element working, and helping out, enormously!

Into “Day 2” though, and we’ll be wanting to do Javascript DOM things in the “overlay” line of thinking. So part of a “Day 1” paradigm, you will better leave that “Day 1” proving the work of “Day 2” is possible, and this was achieved via


function detecttspan() {
var tsrect=null;
var tss=document.getElementsByTagName('tspan');
for (var itss=0; itss<tss.length; itss++) {
tsrect=tss[itss].getBoundingClientRect();
alert('' + tss[itss].outerHTML + ' left:' + tsrect.left + ' top:' + tsrect.top);
}
}

… with the good news we started “Day 1” not being sure of “passed the test”, as you can see from today’s tutorial picture, and …

… this one illustrating work in the SVG tspan 11 letter word Speech Bubble changed select_palette.html web application.

Why 11? Tune in tomorrow.


Previous relevant Select Multiple Webpage Palette Speech Bubble Swipe Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Swipe Tutorial

Select Multiple Webpage Palette Speech Bubble Swipe Tutorial

Today’s tutorial is an amalgam of …

  1. concepts off Apple iOS Control Centre Tutorial … and …
  2. continuing on with the functionality of the recent Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial‘s External Javascript YouTube Audio Stream of Video web application ideas

… which, to us, is in the category of …

  • optional
  • experimental
  • quirky … and yet …
  • something we may well turn to for future endeavours … and so, worth it

… so, though there is opposition you can’t say I didn’t do it my way … which means, correct me if I’m wrong here, that means “I did it my way”that right … team?!.

We’re adding …

  • web application “swipe down and left from top right” … email after entering data … and …
  • web application “swipe up from bottom” … SMS after entering data

… user interaction “shortcuts” into the mix, via …


var firstx=null, firsty=null, pos3=-3, pos4=-3, nextx=null, nexty=null, slowitdown=false, isok=true, oktoemail=false, oktosms=false;
var wow=-1, woh=-1, wiw=-1, wih=-1;
var firstone=true;


function controlisok() {
isok=true;
}

function swipecheck(ev) {
if (!window.opener && isok) {
if (ev.touches) {
if (ev.touches[0].pageX) {
pos3 = ev.touches[0].pageX;
pos4 = ev.touches[0].pageY;
} else {
pos3 = ev.touches[0].clientX;
pos4 = ev.touches[0].clientY;
}
console.log('pos3 = ' + pos3 + ',pos4 = ' + pos4);
} else if (ev.clientX || ev.clientY) {
pos3 = ev.clientX;
pos4 = ev.clientY;
console.log('pos3 = ' + pos3 + ' ,pos4 = ' + pos4);
} else {
pos3 = ev.pageX;
pos4 = ev.pageY;
console.log('pos3 = ' + pos3 + ', pos4 = ' + pos4);
}


if (pos3 >= 0 && pos4 >= 0) {
if (firstx == null) {
firstx=pos3;
firsty=pos4;
slowitdown=true;
isok=false;
setTimeout(controlisok, 400);
} else if (pos3 != firstx || pos4 != firsty) {
nextx=pos3;
nexty=pos4;
// Swipe down left from top right
if (nextx < firstx && nexty > firsty && pos3 > eval(document.documentElement.clientWidth / 2) && pos4 < eval(document.documentElement.clientHeight / 2)) {
if (firstone) {
if (eval(firstx - nextx) > 5 && eval(nexty - firsty) && eval(window.innerWidth - firstx) < 90 && eval(firsty) < 90) {
firstone=false;
//alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
shapetodoemail(); // alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
}
}
// ... else swipe up from bottom
} else if (nexty < firsty && firsty > eval(document.documentElement.clientHeight / 2) && pos4 > eval(document.documentElement.clientHeight / 2)) {
if (firstone) {
if (eval(firstx - nextx) < 5 && eval(nexty - firsty) < 5 && eval(firsty) > eval(document.documentElement.clientHeight / 2)) {
firstone=false;
//alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
shapetodosms(); // alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
}
}
} else if (pos3 <= eval(document.documentElement.clientWidth / 2) || pos4 >= eval(document.documentElement.clientHeight / 2)) {
firstx=null;
firsty=null;
nextx=null;
nexty=null;
}
}
}
}
}

function gettodoemail() {
return oktoemail;
}

function settodoemail(towhat) {
oktoemail=towhat;
}

function shapetodoemail() {
oktoemail=true;
setTimeout(trytodoemail, 5000);
}

function trytodoemail() {
if (oktoemail) {
doemail();
}
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function gettodosms() {
return oktosms;
}

function settodosms(towhat) {
oktosms=towhat;
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function trytodosms() {
if (oktosms) {
dosms();
}
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function gwow() {
return wow;
}

function gwiw() {
return wiw;
}

function gwoh() {
return woh;
}

function gwih() {
return wih;
}

function getwow() {
if (window.opener) {
return window.opener.gwow();
} else {
return wow;
}
}

function getwoh() {
if (window.opener) {
return window.opener.gwoh();
} else {
return woh;
}
}

function getwiw() {
if (window.opener) {
return window.opener.gwiw();
} else {
return wiw;
}
}

function getwih() {
if (window.opener) {
return window.opener.gwih();
} else {
return wih;
}
}

function atstart() {
document.body.style.zoom = 1.0

var scale = 'scale(1)';
document.body.style.webkitTransform = scale; // Chrome, Opera, Safari
document.body.style.msTransform = scale; // IE 9
document.body.style.transform = scale; // General
wow=eval(window.outerWidth);
woh=eval(window.outerHeight);
wiw=eval(window.innerWidth);
wih=eval(window.innerHeight);
//alert('' + wih + ' vs ' + woh);
if (window.opener) {
firstone=false;
setTimeout(function(){
oktoemail=window.opener.gettodoemail();
oktosms=window.opener.gettodosms();
window.opener.settodoemail(false);
window.opener.settodosms(false);
}, 2000);
}
}

if (!window.screenLeft) {
window.screenLeft = window.screenX;
window.screenTop = window.screenY;
}

called into play via …


<body onload="atstart(); startsi(); dotdotdotten();" ontouchmove="swipecheck(event);" onmousemove="swipecheck(event);">

… in the changed select_palette.html web application.


Previous relevant Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial

The recent Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial‘s …

  • privacy for Group Talk “public” Bulletin Board functionalities …
  • involved logic for the two scenarios …
    1. data-applyprivacy=Y … via two prefixing spaces entered by originator of Group … completely hides relevant Group Talk Bulletin Board data from viewers outside that Group Talk
    2. data-applyprivacy=y … via one prefixing space entered by originator of Group … hides contact parts of Group Talk Bulletin Board data from viewers outside that Group Talk

    … but we had not “nuanced” the functionality for that second suboption on that first subpass

… and that is the work discussed today, a nuance that amounts to …

Allow non-group Bulletin Board readers see what we say but given cryptic username choices will not know how to contact that Group

That work took place in the PHP component of our Select Multiple Webpage Palette Speech Bubble web application as per

<?php

if (!isset($_GET['owner']) && isset($_GET['me']) && !isset($_GET['contact'])) {
$findings=explode(',', str_replace(';',',',str_replace('+',' ',urldecode($_GET['me']))));
} else if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
$aprivone=' data-applyprivacy="Y"';
$aprivtwo=' data-applyprivacy="y"';
}


if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
$prevcont="";
for ($i=(0 + 0); $i<sizeof($lines); $i++) {
$thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
if (strpos($thisline, $curgmt) !== false && strpos(str_replace("'",'"',$thisline), $aprivone) === false) { // && strpos(str_replace("'",'"',$thisline), $aprivtwo) === false) {
if (strpos(str_replace("'",'"',$thisline), $aprivtwo) !== false) {
$thatline=$thisline;
if (strpos($thatline, 'contact="') !== false && strpos(str_replace('contact=""',"contact=''",$thatline), 'contact="') !== false) {
while (strpos(str_replace('contact=""',"contact=''",$thatline), 'contact="') !== false) {
$thingtochange=explode('"', explode('contact="', str_replace('contact=""',"contact=''",$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
if (strpos($thatline, "contact='") !== false && strpos(str_replace("contact=''",'contact=""',$thatline), "contact='") !== false) {
while (strpos(str_replace("contact=''",'contact=""',$thatline), "contact='") !== false) {
$thingtochange=explode("'", explode("contact='", str_replace("contact=''",'contact=""',$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
if (strpos(str_replace("[]","",$thatline), "[") !== false && strpos(str_replace("[]","",$thatline), "]") !== false) {
while (strpos(str_replace("[]","",$thatline), "[") !== false && strpos(str_replace("[]","",$thatline), "]") !== false) {
$thingtochange=explode("]", explode("[", str_replace("[]","",$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
$prevcont.=$thatline;
} else {

$prevcont.=$thisline;
}
}
}
$vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
exit;
}

?>

… in the changed select_palette.php “eighth draft” PHP.


Previous relevant Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial

Meanwhile, back at some other ranch … somewhere … we’re some of the way down the line, with our recent …

  • Select Multiple Webpage Palette web application …
  • Bulletin Board subset of functionality, towards with it’s …
  • Group Talk (comma separated list of username/contacts) abilities … now offer …
  • Bulletin Board privacy

… as people in a Group Talk may appreciate. In other words, your generic Bulletin Board viewers would not see your Group Talk setup communications should the originator of any Group Talk now, either at …

  • best, as a To: + spaces appendage to a textarea line record (delimited by line feed) … ahead of a way with …
  • spaces prefixing to the prompt widow off right click or gesture events … starting the ball rolling …
  • populating a new data-applyprivacy global data attribute into the SVG

… allowing this new privacy functionality to work.

Again, we’ll need more than the work today to bed this in, but we now do not think there are any impassable concepts to its implementation.

And so, onto the recent Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial‘s work we have the changed select_palette.html web application helped out by the changed select_palette.php “seventh draft” PHP we have made a start making this “privacy dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial

Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial

Yesterday’s Select Multiple Webpage Palette Speech Bubble Emoji Tutorial warned you today …

we may have nuances yet to come

… and allowing for emojis within a Group Talk user’s username (via control-command-space for macOS or Mac OS X, logo key + . (period) for Windows, control+space for iOS, top left + for Android keyboard) be an identifier on their Speech Bubbles … well, it leaves us speechless with nuance!

Yesterday we were attempting to do this but had more success, today, with


/**
* Convert a string to HTML entities ... Thanks to https://zditect.com/code/javascript/easy-solution-to-encode-html-entities-in-javascript.html
*/
String.prototype.toHtmlEntities = function() {
return this.replace(/./gm, function(s) {
return (s.match(/[a-z0-9" . "\\" . "s]+/i)) ? s : '&#' + s.charCodeAt(0) + ';';
});
};


function maybeemoji(insvg) {
var outthing='', newoutthing='', jb=0;
var outsvg=insvg;
//alert('0:' + outsvg);
if (outsvg.indexOf(' data-otherc') != -1 && outsvg.indexOf(' data-ip') != -1) {
outsvg=outsvg.replace(outsvg.split(' data-otherc')[1].split(' data-ip')[0],'').split('97%')[0];
}

//alert(outsvg);

outhtmlentities='';
nonouthtmlentities='';

var nonencodeds=outsvg.split('&#');
for (jb=1; jb<nonencodeds.length; jb++) {
if (eval('' + nonencodeds[jb].split(';')[0]) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
newoutthing+=String.fromCodePoint(eval('' + nonencodeds[jb].split(';')[0]));
if (nonencodeds[jb] != (nonencodeds[jb].split(';')[0] + ';')) {
nonouthtmlentities=' ';
}
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
}
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

if (outhtmlentities == '') {
if (outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' ').indexOf('&#') >= 0) {
//alert('2987:' + outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' '));
nonencodeds=outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' ').split('&#')
for (jb=1; jb<nonencodeds.length; jb++) {
if (eval('' + nonencodeds[jb].split(';')[0]) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
newoutthing+=String.fromCodePoint(eval('' + nonencodeds[jb].split(';')[0]));
if (nonencodeds[jb] != (nonencodeds[jb].split(';')[0] + ';')) {
nonouthtmlentities=' ';
}
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
}
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

}
}


if (outhtmlentities == '') {
//alert(987);
var encodedStr=outsvg.replace(/[\u00A0-\u9999<>\&]/g, function(i) {
if (eval('' + i.charCodeAt(0)) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+i.charCodeAt(0)+';';
newoutthing+=String.fromCodePoint(eval('' + i.charCodeAt(0)));
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+i.charCodeAt(0)+';';
}
return '&#'+i.charCodeAt(0)+';';
});
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

if (outhtmlentities == '') {
if (document.getElementById('myip').value != '' && insvg.replace(/\'/g,'"').indexOf(' data-owner="') != -1 && insvg.replace(/\'/g,'"').indexOf(' data-contact="') != -1) {
var basisstr=insvg.replace(/\'/g,'"').split(' data-owner="')[1].split('"')[0] + insvg.replace(/\'/g,'"').split(' data-contact="')[1].split('"')[0] + document.getElementById('myip').value;
var bcnt=999, koffset=0;
for (var ib=0; ib<basisstr.length; ib++) {
//if (bcnt == 999) { bcnt=129293; }
//bcnt+=eval('' + basisstr.substring(ib).charCodeAt(0));
koffset+=eval('' + basisstr.substring(ib).charCodeAt(0));
}
if (koffset > 0) {
bcnt+=Math.round(eval(eval('' + koffset) / 10));
var itries=0;
if (4 == 5) { bcnt=129293; }
while (supports_emoji(String.fromCodePoint(eval('' + bcnt)))) {
bcnt++;
itries++;
if (itries >= 230) { bcnt=129293; }
}
//alert(bcnt);
outthing='&#' + bcnt + ';';
newoutthing+=String.fromCodePoint(eval('' + bcnt));
}
}
}
return insvg.replace('></text>', '>' + newoutthing + '</text>').replace(" data-emoji=''", " data-emoji='" + newoutthing + "'").replace(' data-emoji=""', ' data-emoji="' + newoutthing + '"');
}

… in the changed select_palette.html web application helped out by the changed select_palette.php “sixth draft” PHP we have made a start making this “emoji dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble Emoji Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Emoji Tutorial

Select Multiple Webpage Palette Speech Bubble Emoji Tutorial

The reason for today’s efforts with our latest web application have a similar theme to yesterday’s Select Multiple Webpage Palette Speech Bubble IP Address Tutorial‘s efforts, namely …

help differentiate Speech Bubbles of different users in a Group Talk arrangement with our public Bulletin Board functionality

Today’s research into displaying emoji text at the pointy corner of the Speech Bubble hopes to help out here, and though we may have nuances yet to come, we can say with the changed select_palette.html web application helped out by the changed select_palette.php “fifth draft” PHP we have made a start making this “emoji dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble IP Address Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble IP Address Tutorial

Select Multiple Webpage Palette Speech Bubble IP Address Tutorial

To further differentiate Group Talk users accessing the public Bulletin Board of our web application talked about in Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

  • we need to consider user IP addresses, as Wikipedia describes …

    An Internet Protocol address (IP address) is a numerical label such as 192.0.2.1 that is assigned to a device connected to a computer network that uses the Internet Protocol for communication.[1][2] IP addresses serve two main functions: network interface identification, and location addressing.

    Some readers may have noted for a couple of days now, our newly introduced PHP has been assisting the calling HTML, and itself, by remembering the user’s IP address. Yesterday, it was to help colour code Speech Bubbles, and today, it helps in amongst …

    • username … and …
    • contact … set lists … with …
    • IP address

    … to differentiate email and SMS invitation origin calls of our web application, as to who that user has been described as by the originator of the Group Talk settings with the changed select_palette.html web application helped out by the changed select_palette.php “fourth draft” PHP.


    Previous relevant Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial is shown below.

    Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

    Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

    The concept of Group Talk started with yesterday’s Select Multiple Webpage Palette Speech Bubble Invitations Tutorial. It made us think that we should start thinking about the differentiation of voices amongst the Speech Bubbles of the public Bulletin Board we’re supporting with the associated web application and its user mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic talents.

    We decided that one way could be to …

    • Colour Code the background colour of the Speech Bubbles via the user IP address …
      <?php

      $gbcol="0,0,255";

      function server_remote_addr() {
      global $gbcol;
      $rma = $_SERVER['REMOTE_ADDR'];
      $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
      $uas=explode('.', str_replace('::1','65.254.95.247',$rma)); // 65.254.93.32

      if (sizeof($uas) >= 3) {
      $gbcol='' . ($uas[0] % 256);
      $gbcol.=',' . ($uas[1] % 256);
      $gbcol.=',' . (($uas[2] + $uas[(-1 + sizeof($uas))]) % 256);
      }

      // you can add different browsers with the same way ..
      if(preg_match('/(chromium)[ \/]([\w.]+)/', $ua))
      $rma = '000000'.$rma;
      elseif(preg_match('/(chrome)[ \/]([\w.]+)/', $ua))
      $rma = '00000'.$rma;
      elseif(preg_match('/(safari)[ \/]([\w.]+)/', $ua))
      $rma = '0000'.$rma;
      elseif(preg_match('/(opera)[ \/]([\w.]+)/', $ua))
      $rma = '000'.$rma;
      elseif(preg_match('/(msie)[ \/]([\w.]+)/', $ua))
      $rma = '00'.$rma;
      elseif(preg_match('/(mozilla)[ \/]([\w.]+)/', $ua))
      $rma = '0'.$rma;
      return str_replace(":", "_", $rma);
      }

      server_remote_addr();

      ?>
    • when a Group Talk invitation is sent out do not have the sender username and/or contact as the recipient username and/or contact

    … moving further along with the changed select_palette.html web application helped out by the changed select_palette.php “third draft” PHP.


    Previous relevant Select Multiple Webpage Palette Speech Bubble Invitations Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Invitations Tutorial

    Select Multiple Webpage Palette Speech Bubble Invitations Tutorial

    Yesterday’s Select Multiple Webpage Palette Speech Bubble PHP Tutorial‘s …

    • PHP embellishment of …
    • the day before’s SVG data enhancemants … today improves yesterday’s …
    • public Bulletin Board via user mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logics … today, adding …
    • optional invitation communication email and/or SMS logics via Group Talk set comma separated optional user username/contact entered data set lists helping with Group Talk filtering means of filtering the Speech Bubble data

    … with the changed select_palette.html web application helped out by the changed select_palette.php “second draft” PHP.


    Previous relevant Select Multiple Webpage Palette Speech Bubble PHP Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble PHP Tutorial

    Select Multiple Webpage Palette Speech Bubble PHP Tutorial

    Yesterday’s Select Multiple Webpage Palette Speech Bubble Data Tutorial‘s …

    • data … begets …
    • PHP
    … around here a lot, as PHP is our domain’s “first call” serverside language.

    Add to that that “yesterday’s tomorrow is today” we’re supposed to be finished with our “short two day mini project sojourn”, and in a crude way we have, but we want a third day to add nuance to the arrangements with data filtering and more sophistication regarding collection, within the approach of our new …

    Bulletin Board of Speech Bubbles

    … that becomes a …

    • shareable
    • public (on this second day, a bit too public)
    • reverse chronological
    • speech bubble

    … resource, if the user avails themselves of the mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic smarts with the changed select_palette.html web application, now helped out by select_palette.php “first draft” PHP …


    <?php
    // select_palette.php
    // RJM Programming
    // May, 2025

    $prevcont="";
    $curcont="";
    $curgmt=gmdate("Ymd");
    $newlines=[];

    if (isset($_POST['indata'])) {
    $ind=str_replace('+',' ',urldecode($_POST['indata']));
    $lines=explode('<svg name="', $ind);
    if (!file_exists('/tmp/select_palette.htm')) {
    file_put_contents('/tmp/select_palette.htm', '');
    } else {
    $prevcont=file_get_contents('/tmp/select_palette.htm');
    if (strpos($prevcont, '<svg name="' . $curgmt) === false) {
    file_put_contents('/tmp/select_palette.htm', '');
    } else {
    $curcont=$prevcont;
    }
    }


    for ($i=1; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false && strpos($thisline, ' data-public="n"') === false && (strpos($thisline, ' data-owner="') !== false && strpos($thisline, ' data-owner=""') === false) || (strpos($thisline, ' data-contact="') !== false && strpos($thisline, ' data-contact=""') === false)) {
    if (strpos($curcont, $thisline) === false) {
    $curcont.=$thisline;
    }
    }
    }
    file_put_contents('/tmp/select_palette.htm', $curcont);
    echo '<html><body></body></html>';
    exit;

    } else if (isset($_GET['extract'])) {
    if (file_exists('/tmp/select_palette.htm')) {
    $prevcont=file_get_contents('/tmp/select_palette.htm');
    if (strpos($prevcont, '<svg name="' . $curgmt) === false) {
    file_put_contents('/tmp/select_palette.htm', '');
    }
    $lines=explode('<svg name="', $prevcont);
    rsort($lines);

    if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
    $prevcont="";
    for ($i=0; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false) {
    $prevcont.=$thisline;
    }
    }
    $vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
    echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
    exit;
    } else {
    $prevcont="";
    for ($i=0; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false) {
    $isok=true;
    if (isset($_GET['owner']) && strpos(strtolower($thisline), ' data-owner="' . strtolower(str_replace('+',' ',urldecode($_GET['owner'])) . '"')) === false) {
    $isok=false;
    }
    if (isset($_GET['contact']) && strpos(strtolower($thisline), ' data-contact="' . strtolower(str_replace('+',' ',urldecode($_GET['contact'])) . '"')) === false) {
    $isok=false;
    }
    if (isset($_GET['me']) && strpos(strtolower($thisline), strtolower('="' . str_replace('+',' ',urldecode($_GET['me'])) . '"')) === false) {
    $isok=false;
    } else if (isset($_GET['me'])) {
    $isok=true;
    }
    if ($isok) { $prevcont.=$thisline; }
    }
    }
    $vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
    echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
    exit;
    }

    }

    }

    ?>

    … meaning …

    Data … is enhanced … … by … PHP


    Previous relevant Select Multiple Webpage Palette Speech Bubble Data Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Data Tutorial

    Select Multiple Webpage Palette Speech Bubble Data Tutorial

    Onto yesterday’s Select Multiple Webpage Palette Speech Bubble Tutorial, today, we’re preparing for tomorrow.

    You heard it here first.

    Admittedly, nothing startling there, but it was the first time we remember …

    • embellishing SVG data … with so much …
    • what we normally associate with HTML element work …
      1. global data attributes
      2. id and name attribution …
      3. event logic

    Yes, all possible with SVG, though not the first thing we think of using SVG data within our HTML. We normally think, just display thoughts, but today, we’re paving the way for tomorrow, and our “short two day mini project sojourn” will become clearer regarding motives, then, or get hints trying with strategically changed select_palette.html web application‘s mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic …


    var taar=[];
    var preadd=0;
    var windowuser='', windowcontact='', windowask=true, suffix='';


    function defwuwc(inwindowuser,inwindowcontact) {
    if ((inwindowuser + inwindowcontact) == '') { return ''; }
    if (inwindowuser != '' && inwindowcontact != '') { return inwindowuser + '[' + inwindowcontact + ']'; }
    if (inwindowuser != '' && inwindowcontact == '') { return inwindowuser; }
    return inwindowcontact;
    }


    function treg(ttis) {
    var dotherest=false;
    var ctown=defwuwc(windowuser,windowcontact);
    var ourwindowask=windowask;
    preadd=1;
    if (ttis.outerHTML.indexOf(' data-public=') != -1) {
    if (windowuser == '' && windowcontact == '' && windowask) {
    ctown=prompt("To share on today's board enter a username and/or contact string (append space to remember, append another space to apply to all other Speech Bubbles) ... eg. " + String.fromCharCode(10) + "Robert Metcalfe[rmetcalfe15@gmail.com]", defwuwc(windowuser,windowcontact));
    }
    if (ctown == null) { ctown=''; }
    if (ctown != ctown.replace(/\ \ $/g,'')) {
    windowask=false;
    dotherest=true;
    ctown=ctown.trim();
    } else if (ctown != ctown.replace(/\ $/g,'')) {
    windowask=false;
    ctown=ctown.trim();
    }
    if (ctown.indexOf('[') > 0 && ctown.indexOf(']') != -1) {
    windowuser=ctown.split('[')[0];
    windowcontact=ctown.split('[')[1].split(']')[0];
    } else if (ctown.indexOf('[') == 0 && ctown.indexOf(']') != -1) {
    windowcontact=ctown.split('[')[1].split(']')[0];
    windowuser=windowcontact;
    } else {
    windowuser=ctown;
    windowcontact='';
    }
    if (windowuser != '') {
    ttis.setAttribute('data-owner', windowuser);
    }
    if (windowcontact != '') {
    ttis.setAttribute('data-contact', windowcontact);
    }
    if (windowuser != '' || windowcontact != '') {
    ttis.setAttribute('data-public', 'y');
    ttis.innerHTML=ttis.innerHTML.replace(/\<text\ /g,'<text stroke="blue" ');
    if (dotherest) {
    var svgs=document.getElementsByTagName('svg');
    for (var isvgs=0; isvgs<svgs.length; isvgs++) {
    if (svgs[isvgs].outerHTML.indexOf(' stroke=') == -1) {
    if (('' + svgs[isvgs].id) != ('' + ttis.id)) {
    if (windowuser != '') {
    svgs[isvgs].setAttribute('data-owner', windowuser);
    }
    if (windowcontact != '') {
    svgs[isvgs].setAttribute('data-contact', windowcontact);
    }
    if (windowuser != '' || windowcontact != '') {
    svgs[isvgs].setAttribute('data-public', 'y');
    }
    svgs[isvgs].innerHTML=svgs[isvgs].innerHTML.replace(/\<text\ /g,'<text stroke="blue" ');
    }
    }
    }
    }
    } else {
    windowask=ourwindowask;
    }
    }
    //alert(ttis.outerHTML);
    setTimeout(function(){ preadd=0; }, 5000);
    }


    Previous relevant Select Multiple Webpage Palette Speech Bubble Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Tutorial

    Select Multiple Webpage Palette Speech Bubble Tutorial

    Yesterday’s Select Multiple Webpage Palette Popup Tutorial modus operandi revolved around …

    delimitation rules

    … as so many matters do with written down text.

    We rethought yesterday’s HTML textarea start regarding line feed Speech Bubble creation possibilities, and thought …

    It’s too unwieldy for a user to add to their textual data when what they really want to do is Speech Bubbles.

    Yesterday’s thinking really hoped the user entered a Speech Bubble data one at a time, but what if the user wants to enter several Speech Bubbles in the one textarea incarnation?

    Good question. (Calling all ducks with a slow paddle going?!)

    Yes, but there is that ~~ existing delimitation rule, as of yesterday equating to a line feed. Supposing ~~ was given the delimitation roles …

    1. the character sets …
      lineFeed~~lineFeed
      … separate Speech Bubbles … ie. in the textarea a ~~ record is all there is on a line of textarea text
    2. the character set …
      ~~lineFeed
      … at the start wipes out any previously remembered text data and starts again
    3. else retain the ~~ mapping to lineFeed

    … in combination with the textarea always first presented blank and the previous Speech Bubble or Lines of Text remembered and retained unless the middle condition above happens?

    Well, we think it’s a plan, and led us to be able to share a Speech Bubble presentation of Shakepeare’s Act 1 Scene 1 of Macbeth. And so, today with the changed select_palette.html web application, onto yesterday’s …

    one textarea element

    … paradigm, we present …

    • previous text data in a details/summary “reveal” mode of use above the textarea element, as relevant
    • and below the textarea element we now have buttons to Email or SMS your text creations off to a recipient

    … harnessing hashtag navigational data methodologies in “a” “mailto:” (email) or “sms:” (SMS) prefixing href attributes, as per …


    function doemail() {
    var anchor=null;
    if (woois) {
    if (!woois.closed) {
    if (woois.document.getElementById('myta').outerHTML.indexOf(' data-done="y"') == -1) {
    if (woois.document.getElementById('myta').value.trim() != '') {
    woois.document.getElementById('myta').setAttribute('data-done', 'y');
    setTimeout(doemail, 6000);
    return '';
    }
    } else if (woois.document.getElementById('myta').value.trim() != '') {
    setTimeout(doemail, 6000);
    return '';
    }
    woois.close();
    woois=null;
    setTimeout(doemail, 6000);
    return '';
    }
    }
    var emis=prompt('Please enter email address to send to.', '');
    if (emis == null) { emis=''; }
    if (emis.indexOf('@') != -1) {
    anchor = document.createElement('a');
    anchor.href = 'mailto:' + emis.trim() + '?subject=My%20Speech%20Bubble%20data&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    document.body.appendChild(anchor);
    anchor.innerHTML='Email';
    anchor.target='_top';
    anchor.click();
    } else if (emis.trim() != '' && emis.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
    anchor = document.createElement('a');
    anchor.href = 'sms:' + emis.trim() + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    anchor.innerHTML='SMS';
    anchor.target='_top';
    anchor.click();
    }
    }

    function dosms(){
    var anchor=null;
    if (woois) {
    if (!woois.closed) {
    if (woois.document.getElementById('myta').outerHTML.indexOf(' data-done="y"') == -1) {
    if (woois.document.getElementById('myta').value.trim() != '') {
    woois.document.getElementById('myta').setAttribute('data-done', 'y');
    setTimeout(dosms, 6000);
    return '';
    }
    } else if (woois.document.getElementById('myta').value.trim() != '') {
    setTimeout(dosms, 6000);
    return '';
    }
    woois.close();
    woois=null;
    setTimeout(dosms, 6000);
    return '';
    }
    }
    var emis=prompt('Please enter SMS number to send to.', '');
    if (emis == null) { emis=''; }
    if (emis.indexOf('@') != -1) {
    anchor = document.createElement('a');
    anchor.href = 'mailto:' + emis.trim() + '?subject=My%20Speech%20Bubble%20data&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    document.body.appendChild(anchor);
    anchor.innerHTML='Email';
    anchor.target='_top';
    anchor.click();
    } else if (emis.trim() != '' && emis.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
    anchor = document.createElement('a');
    anchor.href = 'sms:' + emis.trim() + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    anchor.innerHTML='SMS';
    anchor.target='_top';
    anchor.click();
    }
    }


    Previous relevant Select Multiple Webpage Palette Popup Tutorial is shown below.

    Select Multiple Webpage Palette Popup Tutorial

    Select Multiple Webpage Palette Popup Tutorial

    Regarding yesterday’s Select Multiple Webpage Palette Primer Tutorial

    • you start with an outlandish premise …
    • it stays “outlandish” select (dropdown) element wise on non-mobile … but …
    • catering for mobile …
    • you are forced to encase it in a hosting div element (with the onmousedown and ontouchdown precursor events to onclick)

    … all contributing to getting us to a point, today, we can say we’ve added a layer of (useful, extra) functionality, by …

    • no longer asking for user interactive input via a Javascript prompt window … but, instead, like with Background Image Foreground Content Tutorial … we …
    • ask for user interactive input via a window.open (ie. popup) “here’s looking at you, kid” window.opener incarnation guise of our changed select_palette.html web application … just consisting of …
    • one textarea element …
      1. still capable of ~~ delimitation as with the Javascript prompt window thinking … but also now …
      2. harnessing the talents of a textarea line feed delimitation within it’s value attribute

      … able to extend functionality towards decent …

    • speech bubble feeling thoughts (so far, just) … because …
    • it opens up the idea that the div element innerHTML attribute can be the SVG we had previously been supplying as background HTML/CSS (via Javascript DOM) data

    Cute, huh?! (ahead of the “Speech Bubble styling” niceties making it really cute, yet, for us … but who knows what you can achieve on the “cute styling front”?!).


    Previous relevant Select Multiple Webpage Palette Primer Tutorial is shown below.

    Select Multiple Webpage Palette Primer Tutorial

    Select Multiple Webpage Palette Primer Tutorial

    In the world of web applications, there are often many ways to approach any given requirement. Like with yesterday’s Select Multiple Mobile Background Image Tutorial, today’s “albeit a bit out there idea” is to …

    • offer a select (multiple attribute) “dropdown” HTML element …
    • as a webpage covering …
    • template or palette … where the user …
    • writes user defined lines of words created

    … onto. Pretty simple idea for a “first then second draft“! But maybe not the first idea to spring to mind regarding making such an idea happen?!


    Previous relevant Select Multiple Mobile Background Image Tutorial is shown below.

    Select Multiple Mobile Background Image Tutorial

    Select Multiple Mobile Background Image Tutorial

    We had occasion to revisit Window LocalStorage Client Versus Server Map Tutorial‘s web application today changed this way to end up with wls_vs_php.htm, on an iPad, and saw how initially lacking was the advice on how to work the Capital City to Country quiz. The reason, primarily, in our view, is that on mobile platforms an element such as …


    <select class=dglow onclick=" console.log('67234'); noif(); " title='Please select Capital(s) below to get Countries Report ...' onfocusout=" document.getElementById('myrepsb').className='dglow'; tablemode = ''; nothere=true; updatecountries(null);" style='width:300px;margin-top:0px;margin-left:0px;vertical-align:top;height:100vh;background-color:lightblue;' id=scapitals multiple>
    // innard options //
    </select>

    … you just see words to the effect …

    0 items …

    … but we’d see more use for this select element “opened up” on initialization. As we read, and believed, via this useful link, thanks, this “programmatical click on mobile platforms” to open up such a select element is not easy. So we decided to go down the route of …

    • to a select multiple element …
    • on mobile …
    • background image …
    • at top right …
    • that is wording advice “Click/tap me”
    • when first encountered

    … and we came up with the document.body onload event call “new Javascript code snippet” …


    if (document.URL.indexOf('?') == -1) {
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    document.getElementById('scapitals').click(); // this is just wishful thinking, but no error is caused, and you never know?
    document.getElementById('scapitals').style.background="url(\"data:image/svg+xml;base64," + window.btoa("<svg xmlns='http://www.w3.org/2000/svg' width='126' height='48' viewport='0 0 100 100' style='border-radius:15px;background-color:rgba(0,0,255,0.3);fill:black;font-family:Verdana;font-size:17px;'><text x='5%' y='60%'>Click/tap me</text></svg>") + "\") no-repeat top right";
    }
    }

    Next best approach, we’d say?!


    Previous relevant Window LocalStorage Client Versus Server Map Tutorial is shown below.

    Window LocalStorage Client Versus Server Map Tutorial

    Window LocalStorage Client Versus Server Map Tutorial

    Get a good map, and a goodly number of times you’ll want a map of smaller or larger scale than the one you have. Murphy’s Law? This is probably why in the wonderful woooooooorrrrrrrrlllllld of Google Charts they have included …

    • Geo Chart topographic map of the world or of regions
    • Map Chart terrestrial/satellite map of your group of markers at a zoom level of your choosing

    … and hope you can see that the latter can save the day for a Short Distance Trip (corner shop, anyone?!).

    So we’ve added onto yesterday’s Window LocalStorage Client Versus Server Timeline Tutorial progress a new toggling button to view a scenario in either Google Chart scenario above.

    You can see this integration work with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link supervising a tweaked geo_chart.php Geo Chart interfacer.


    Previous relevant Window LocalStorage Client Versus Server Timeline Tutorial is shown below.

    Window LocalStorage Client Versus Server Timeline Tutorial

    Window LocalStorage Client Versus Server Timeline Tutorial

    Up to yesterday’s Window LocalStorage Client Versus Server User Tutorial‘s progress, our Capital City Find Matching Country Report web application project was all about …

    • where (and capital of “what”) … but we often seek out a way to add into the mix that 4th dimension …
    • when (ie. time)

    … and regarding the current project, a …

    • where “map” … can interface with a …
    • when “Trip Plan Itinerary”

    … and for this purpose, we’re going to interface to the excellent Google Charts Annotated Timeline Chart, thanks, because it combines links of “time” to “user annotations” in a timeline way, that similar way you might describe the qualities of a Trip, even before you’ve gone on that trip. We’ve also added it so that an unordered places list can be turned into a Trip Plan Itinerary at the click/touch of a new map 🗺 &#128506; emoji button.

    Again, see how these timeline amendments were achieved with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link and annotatedtimeline_chart.php which changed quite a lot.


    Previous relevant Window LocalStorage Client Versus Server User Tutorial is shown below.

    Window LocalStorage Client Versus Server User Tutorial

    Window LocalStorage Client Versus Server User Tutorial

    The inherent weakness with our current Capital City Find Matching Country Report web application project, to our minds, was that places of interest are not restricted to the Capital Cities of Countries, especially when “Trip Planning”. On the other hand, it would be impossible to cater for every “place” in the world. That is far too subjective for good web application applicability. What would be good though, is to allow in user defined …


    Place name, Country name

    … terms, the definitions of interest to a user. We can ask this …

    • flagged by the click/touch of an emoji button … and …
    • the interactive entry presented via a Javascript prompt window

    . When thinking of data applicable to an individual, then that can be catered for by recording it in localStorage where it will be recalled on the next execution of that web application in the same web browser.

    This, along with a Colour Wheel of the “nearest TimeZone place” onto the existing logic of yesterday’s Window SessionStorage Client Versus Server Order Tutorial progress could make for a more useful and practical tool for those Trip Planners out there!

    See how this was achieved with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.

    Did you know?

    To click/touch one of those Google Chart Geo Chart lines between Emoji Flag Markers will show a new Google Maps directions web page with transport times and detail, as well as an inhouse crow fly distance of that trip leg, as shown up the top right of today’s tutorial picture.


    Previous relevant Window SessionStorage Client Versus Server Order Tutorial is shown below.

    Window SessionStorage Client Versus Server Order Tutorial

    Window SessionStorage Client Versus Server Order Tutorial

    If we are to honour our thoughts of being able to use our current Capital City Find Matching Country Report web application as a Trip Planner …

    Our primary integration today is to (software) integrate the great Weather Underground and its great API service for autocomplete name searches for weather (and hurricane) information. Why bother? Well, can you not envisage a user using that Ajax functionality of yesterday’s Window SessionStorage Client Versus Server Ajax Tutorial as a trip planner, perhaps, or as a “checking up on relatives overseas” tool, perhaps? And not all the capital cities are timezone places, and so for some of those we can use Weather integration to still show apt online information when click/touching a Countries Report row. Speaking of this “row”, we make an improvement whereby on a first click of a right hand (Country) row cell, that cell is not initially a contenteditable=”true” one (that may frustrate showing the keyboard on mobile, when most likely it was the row touch intended), but then becomes a contenteditable=”true” cell henceforth.

    … then yesterday’s Window SessionStorage Client Versus Server Flags Tutorial “progress to now” needs to take notice of a user’s order of multiple select (dropdown) element click/touching of Capital City option (sub)elements, just as we did with the recent User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial‘s web application project to allow for a user ordered YouTube video playlist.

    Because what is a Trip Planner without an ordered trip? Well, that is debatable, but what isn’t (debatable), is that there will be people in the world who appreciate the “mapping out” of a proposed Trip Planning Itinerary. What could we call on here? We can think of the Google Chart Geo Chart work around about the time of Google Geo Chart Co-ordinate Emojis Tutorial, when we started using …

    • a world map … with …
    • emoji markers … and optionally …
    • joined up by straight lines

    … an idea for a Trip Plan itinerary synopsis, perhaps?!

    If you examined closely yesterday’s code changes you will have noticed our collecting of TimeZone Place geographical latitude and longitude information. Today, we start making use of that preparatory work with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.

    Stop Press

    The “emoji markers” above (as of 2 January 2020) will be “country flags” (as per Window SessionStorage Client Versus Server Flags Tutorial ideas), as defined.


    Previous relevant Window SessionStorage Client Versus Server Flags Tutorial is shown below.

    Window SessionStorage Client Versus Server Flags Tutorial

    Window SessionStorage Client Versus Server Flags Tutorial

    Yes, there’s more to do onto yesterday’s Window SessionStorage Client Versus Server CSS Tutorial‘s Capital City Find Matching Country Report web application project, in our eyes. We have not even mentioned “Internationalization” as a concept up to now. In this line of thinking …

    Did you know?

    Emoji flags via ISO 2 character country codes are dead easy via Regional Indicator Symbol characters …


    var lri="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    var dri=["127462","127463","127464","127465","127466","127467","127468","127469","127470","127471","127472","127473","127474","127475","127476","127477","127478","127479","127480","127481","127482","127483","127484","127485","127486","127487"];

    var thiscc='AU'; // ISO 2 character countrycode for Australia
    var ccsuff='', ccchar=' ';
    for (var iccsuff=0; iccsuff<thiscc.length; iccsuff++) {
    ccchar=thiscc.substring(iccsuff, eval(1 + eval('' + iccsuff))).toUpperCase();
    ccsuff+='&#' + dri[eval('' + lri.indexOf(ccchar))] + ';';
    }
    document.getElementById('lastflag').innerHTML=ccsuff;

    … to result in (via <span style=font-size:64px;>&#127462;&#127482;</span>) …


    🇦🇺

    … providing interest and general translatability to the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.


    Previous relevant Window SessionStorage Client Versus Server CSS Tutorial is shown below.

    Window SessionStorage Client Versus Server CSS Tutorial

    Window SessionStorage Client Versus Server CSS Tutorial

    Further to yesterday’s Window SessionStorage Client Versus Server Integration Tutorial we have a two pronged improvements set for you today with our current Capital City Find Matching Country Report web application project …

    • CSS styling changes … and …
    • additional functionality for Email and SMS links back to our current Capital City Find Matching Country Report web application project (to complete the cycle)

    We use several modes of CSS application (the first and last of particular relevance to today’s “highlighting of workflow” improvements) …

    … the “static” measures often helping to highlight the web application’s main workflow of user interaction and the “dynamic” measures helping to alert the user as to where to proceed with their “workflow”.

    In terms of CSS styling work …

    1. for non-mobile platforms we allow for more columns to be applied to our Capitals select (dropdown) element (in order to reduce some user scrolling, as does our new additional A-Z letter basis sorting functionality) as per … the “dynamic” Javascript DOM “class” modifications

      if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
      document.getElementById('lefttd').className='lefttd';
      }

      … dovetailing with the “static” internal CSS coding

      <style>
      .lefttd {
      column-count: 4;
      max-height: 35%;
      vertical-align: top;
      max-width: 70%;
      font-size: 8px;
      background-color: rgba(205,205,205,0.5);
      background-image: -webkit-gradient(
      linear,
      right bottom,
      left top,
      color-stop(0, rgba(205, 205, 205, 0.8)),
      color-stop(0.50, rgba(255, 255, 0, 0.2))
      );
      background-image: -o-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -moz-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -webkit-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -ms-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: linear-gradient(to left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);

      }
      </style>

      … and please note that around here at RJM Programming we have a “far from hard and fast rule” (but a rule regardless) regarding HTML element ID and class attributes that they concern (and (usually) be compartmentalised into) Javascript (DOM) manipulations and CSS styling issues respectively … and add a linear-gradient background to the table cell when expecting the initial user interaction on non-mobile platforms
    2. a “dynamic” Javascript DOM “class” modification … document.getElementById(‘myrepsb’).className=’dglow’; … is made to the “Report…” button at the Capitals select (dropdown) onfocusout event so as to highlight (with “glow” inspired styling) where user interaction may flow to

    As far as links go, you may expect to need serverside means to construct these in online Email and SMS message interfacing, but email (client program) products like Gmail parse your ascii text and convert http: or https: protocol URLs in your Email body to hyperlinks, as does the Messages SMS application here on this MacBook Pro using macOS Mojave. Cute, huh?! So to close the circle back from remote thar’ parts back to our web application is a simple matter of, in broad brush terms …

    • adding two new buttons called “Email Columns and Links …” and “SMS Columns and Links …” that …
    • set a global variable andlinkto = true; … setting in play, within the report writing code (that likes monospaced fonts) …
    • add a new links column to the right with URLs like …
      https://www.rjmprogramming.com.au/HTMLCSS/wls_vs_php.htm?andgo=y&countries=Belize&capitals=Belmopan
      … to tell your client programs to form the hyperlinks for us (if they are “of the mood”, that is!)

    To improve user experience we use “dynamic” Javascript DOM HTML “style” attribute change means to easier close the “Colour Wheel” helper web application “above the fold” by changing the CSS z-index (Javascript DOM [element].style.zIndex) of elements accordingly, when the user clicks other elements. You can see all this with the first “the changed” link above, where all “glow” CSS styling will also feature prominently.


    Previous relevant Window SessionStorage Client Versus Server Integration Tutorial is shown below.

    Window SessionStorage Client Versus Server Integration Tutorial

    Window SessionStorage Client Versus Server Integration Tutorial

    We hope, when performing a “software integration” task, that the two or more components of that integration work with each other’s talents, rather than a big tussle like reinventing the wheel. This ideal makes the work …

    • sometimes difficult but rewarding because …
    • the differences between two independent software components can be quite large and daunting … and the programmer has to see that …
    • care is applied so as not to wreck previous functionality and integrations in making the current integration work

    … and that is why we’ve made corollaries to “building from scratch” (when planning and design is a huge component) can be a lot simpler than a software integration “renovation”, in the past, here at this blog.

    Our primary integration today is to (software) integrate the great Weather Underground and its great API service for autocomplete name searches for weather (and hurricane) information. Why bother? Well, can you not envisage a user using that Ajax functionality of yesterday’s Window SessionStorage Client Versus Server Ajax Tutorial as a trip planner, perhaps, or as a “checking up on relatives overseas” tool, perhaps? And not all the capital cities are timezone places, and so for some of those we can use Weather integration to still show apt online information when click/touching a Countries Report row. Speaking of this “row”, we make an improvement whereby on a first click of a right hand (Country) row cell, that cell is not initially a contenteditable=”true” one (that may frustrate showing the keyboard on mobile, when most likely it was the row touch intended), but then becomes a contenteditable=”true” cell henceforth.

    As a user experience improvement for “trip planners” perhaps, we allow the user to alphabetically sort the presented select (dropdown) element entries …


    var firstopt='';
    var wasopts='';
    var restopts='';

    function readyitforsort(iselid) {
    var optsare=[];
    var huhisel=document.getElementById(iselid).innerHTML;
    var huhsopts=huhisel.split('</option>');
    for (var ihuh=0; ihuh<huhsopts.length; ihuh++) {
    if (huhsopts[ihuh].trim() != '') {
    if (firstopt == '') {
    firstopt=huhsopts[ihuh] + '</option>';
    } else {
    wasopts+=huhsopts[ihuh].replace('option ','option data-ih="' + (huhsopts[ihuh].split('>')[eval(-1 + huhsopts[ihuh].split('>').length)] + '" ')) + '</option>';
    optsare.push(huhsopts[ihuh].replace('option ','option data-ih="' + (huhsopts[ihuh].split('>')[eval(-1 + huhsopts[ihuh].split('>').length)] + '" ')) + '</option>');
    }
    }
    }
    optsare.sort();
    for (var jhuh=0; jhuh<optsare.length; jhuh++) {
    restopts+=optsare[jhuh];
    }
    }

    … controlled by a new dropdown in the left hand column header cell.

    We also allow the user to move the iframe element with some positioning emoji buttons near the “Close” button one (of yesterday’s work).

    Into the future, too, we’ll have more to say regarding the germination of an idea “to allow a mobile onmouseover simulator (of sorts)” be to allow the user to perform a swipe across an individual HTML element of interest on mobile platforms (ie. harness ontouchmove event) as per (so far) … kicked off by “<body onload=” setTimeout(athn, 5000); “>” …


    var last24='';
    var rectdc;

    function nodivalert() {
    document.getElementById('divalert').style.display='none';
    document.getElementById('divalert').style.zIndex='-456';
    document.getElementById('divalert').style.left=('-' + rectdc.left).replace('px','') + 'px';
    document.getElementById('divalert').style.top=('-' + rectdc.top).replace('px','') + 'px';
    }

    function ourdivalert(inmsg) {
    document.getElementById('divalert').style.position='absolute';
    document.getElementById('divalert').style.left=('' + rectdc.left).replace('px','') + 'px';
    document.getElementById('divalert').style.top='' + eval(-80 + eval(('' + rectdc.top).replace('px',''))) + 'px';
    document.getElementById('divalert').style.backgroundColor='#e0e0e0';
    document.getElementById('divalert').style.display='block';
    document.getElementById('divalert').style.zIndex='456';
    document.getElementById('divalert').style.opacity='0.8';
    document.getElementById('divalert').style.padding='5px 5px 5px 5px';
    document.getElementById('divalert').innerHTML=inmsg + '<br><br><input type=button value=Close onclick=nodivalert();></input>';
    setTimeout(nodivalert,9000);
    }

    function athn() {
    rectdc=document.getElementById('dc').getBoundingClientRect();
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    document.getElementById('dc').ontouchmove=function(event) { if (last24.substring(0,eval(-1 + last24.length)) == event.target.title.substring(0,eval(-1 + event.target.title.length))) { last24=last24; } else { last24=event.target.title; ourdivalert(event.target.title); } }
    } else {
    document.getElementById('dc').onmousemove=function(event) { if (last24.substring(0,eval(-1 + last24.length)) == event.target.title.substring(0,eval(-1 + event.target.title.length))) { last24=last24; } else { last24=event.target.title; ourdivalert(event.target.title); } }
    }
    }

    … working with the new HTML …


    <div id=divalert></div>
    </body>
    </html>

    … to try to allow the “explainer of an element” advantages non-mobile platforms have for hovering over an HTML element with a title attribute filled in.

    And so, yet again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new Weather integration functionality. It caused the changed colour_wheel.html‘s colour wheel (at this live run link) to be affected (by integrations “up”).


    Previous relevant Window SessionStorage Client Versus Server Ajax Tutorial is shown below.

    Window SessionStorage Client Versus Server Ajax Tutorial

    Window SessionStorage Client Versus Server Ajax Tutorial

    We have a few “clientside chestnuts” to use with our current Capital City Find Matching Country Report web application project today, those being …

    • Ajax functionality, kicked off by an “onclick” event set of logic, allowing mobile platforms to also have a look in (the look in that they miss when the event logic is off the “onmouseover” event)
    • iframe and its …
      1. srcdoc attribute (“content” alternative to src “url” attribute) … along with, and crucially needing (because srcdoc ignores its own document.body onload goings on, that we need the “Iframe Client Pre-Emptive” methods below to circumvent) the …
      2. onload event opportunity of an iframe element (we group into “Iframe Client Pre-Emptive” methods, here)

    … adding onto yesterday’s Window SessionStorage Client Versus Server Canvas Tutorial.

    It’s not that involved with the Ajax work today, given that there are no cross-domain issues, though there are cross-protocol (SSL https: versus non-SSL http:) issues to be careful about. Those can be addressed because the web application is recalled to present its “Country Report” and that is the opportunity to check on protocol navigation requirements.

    Along the way, we also make this happen for the user on …

    • click/touching a table row … it sets off new “tr” (table row) element logic calling our (inhouse) Timezone and Wikipedia Place Information helper (HTML) via Ajax (so not leaving the webpage) … and because of place name oddities we allow for …
    • “td” (table cell) element user amendments by setting their contenteditable attributes to “true” (since fixed, but we found the Timezone Europe/Tirane pointing at Tirane in Albania used to be spelt “Tirana”)

    … that latter methodology normally a technique we apply to “div” elements (so, there you are!)

    Also used are “overlay” techniques, two of the “usual suspects” here coming into play, to present to the “Ajax content to srcdoc iframe arrangements” …

    Yet again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new “Ajax” functionality.


    Previous relevant Window SessionStorage Client Versus Server Canvas Tutorial is shown below.

    Window SessionStorage Client Versus Server Canvas Tutorial

    Window SessionStorage Client Versus Server Canvas Tutorial

    Yesterday’s Window SessionStorage Client Versus Server Share Tutorial dealt with ascii text clipboard copy assisted sharing options with our current Capital City Find Matching Country Report web application project. This suited both Email and SMS share options we coded for, but today’s extension of functionality from “ascii text” data to “graphical data” only suits Email sharing. The other caveat with our work is that no serverside (for us, PHP) help is allowed, so no PHP mail here.

    What comes into play with a “graphical data” clientside (only) sharing approach? It will not surprise many readers that, for us, it involves …

    • canvas element … converting HTML table outerHTML “ascii text” data … via …
    • canvas drawing methods “[canvasContext].strokeRect()” and “[canvasContext].strokeText()” via “[cellElement].getBoundingClientRect()” … to convert that canvas element content via …
    • [canvasElement].toDataURL() … to an …
    • img element nested in a div contenteditable=true element … so as to hook in with today’s very useful helper link, thanks … use …

    • function tabletoclipboard(canvas) { // thanks to https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard
      var img = document.createElement('img');
      img.src = canvas.toDataURL();

      var div = document.createElement('div');
      div.contentEditable = true;
      div.appendChild(img);
      document.body.appendChild(div);

      // do copy
      SelectText(div);
      document.execCommand('Copy');
      document.body.removeChild(div);
      }

      function SelectText(element) { // thanks to https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard
      var doc = document;
      if (doc.body.createTextRange) {
      var range = document.body.createTextRange();
      range.moveToElementText(element);
      range.select();
      } else if (window.getSelection) {
      var selection = window.getSelection();
      var range = document.createRange();
      range.selectNodeContents(element);
      selection.removeAllRanges();
      selection.addRange(range);
      }
      }
    • to leave the user’s device’s clipboard containing a useful table (with linework) … ready to …
    • paste into an email body section

    … sharing off to an emailee collaborator.

    Again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new “Email Table” button functionality.


    Previous relevant Window SessionStorage Client Versus Server Share Tutorial is shown below.

    Window SessionStorage Client Versus Server Share Tutorial

    Window SessionStorage Client Versus Server Share Tutorial

    Yesterday’s Window SessionStorage Client Versus Server Tutorial has been amended today for two new sharing and collaboration options, those being …

    • email
    • SMS

    … but you may well be familiar with the restrictions on email and SMS client (program) approaches to this, coming from HTML “a” link “mailto:” and “sms:” href property prefixes respectively. We’re going to need help with the 800 odd character (length) restrictions with the (resultant) web address (bar) URL, but what? How about working off the great advice of this wonderful link, thanks, to copy what we’d have assembled into an ascii text Report into the characters contained by the user’s device’s clipboard?


    function copytoclipboard(str) { // thanks to https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f
    var el = document.createElement('textarea');
    el.value = str;
    el.setAttribute('readonly', '');
    el.style.position = 'absolute';
    el.style.left = '-9999px';
    document.body.appendChild(el);
    el.select();
    document.execCommand('copy');
    document.body.removeChild(el);
    }

    An issue that springs up here using such clipboard ascii text content, whenever you get the Font choice given to you, pick a monospaced Font like Courier New or “Fixed Width”.

    See the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new sharing functionality.


    Previous relevant Window SessionStorage Client Versus Server Tutorial is shown below.

    Window SessionStorage Client Versus Server Tutorial

    Window SessionStorage Client Versus Server Tutorial

    Sometimes it’s the case at this blog that we’d like to introduce a new topic, but do not do so, because we cannot show any real world (or real application) use of that concept. So it has been, up until now, with the concept of (web browser) window (object) sessionStorage property. But yesterday’s Window LocalStorage Client Versus Server Primer Tutorial represented an opportunity akin to when Haley’s Comet gets at its closest to the Earth … while you see a chance, take it … chance because of that nuance whereby we were not trying to store data for any other purpose than passing data onto …

    1. a known entity … ie. same web application … at …
    2. a known time … ie. immediately

    … two conditions that make the code design “marginally” more ideal for the window object property concept of sessionStorage rather than localStorage, in that any …


    localStorage.removeItem([knownLocalStorageName]);

    … becomes superfluous as with sessionStorage data will disappear between web browser sessions, anyway.

    We offer this new concept as a non-default option of a select (dropdown) element replacement to the h1 element hardcoding “localStorage” with the changed wls_vs_php.htm Capital City Find Matching Country Report live run. The other nuance of difference with sessionStorage usage is that in the document.body onload event logic, we may as well (as part of other changes) pre-emptively look for, and if there, respond to, any found sessionStorage data points, even without the user having flagged it specifically


    var datamode='localStorage';

    function checkforreport() {
    var divcont='';
    var dcaps, dctys, idis;
    if (getcapitals == 'localStorage') {
    if (window.localStorage) {
    getcapitals=decodeURIComponent(localStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
    localStorage.removeItem('wls_vs_php_capitals');
    } else {
    getcapitals='';
    }
    } else if (getcapitals == 'sessionStorage') {
    document.getElementById('smode').value=getcapitals;
    datamode=getcapitals;
    if (window.sessionStorage) {
    getcapitals=decodeURIComponent(sessionStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
    } else {
    getcapitals='';
    }
    }
    else if (getcapitals == '' && window.sessionStorage) {
    getcapitals=decodeURIComponent(('' + sessionStorage.getItem('wls_vs_php_capitals')).replace(/^null$/g,'')).replace(/\+/g,' ');
    if (getcapitals != '') {
    document.getElementById('smode').value='sessionStorage';
    datamode='sessionStorage';
    }
    }

    if (getcountries == 'localStorage') {
    if (window.localStorage) {
    getcountries=decodeURIComponent(localStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
    if (getcapitals.replace('localStorage','') != '' && getcountries.replace('localStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
    localStorage.removeItem('wls_vs_php_countries');
    } else {
    getcountries='';
    }
    } else if (getcountries == 'sessionStorage') {
    if (window.sessionStorage) {
    getcountries=decodeURIComponent(sessionStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
    if (getcapitals.replace('sessionStorage','') != '' && getcountries.replace('sessionStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
    } else {
    getcountries='';
    }
    }
    else if (getcountries == '' && document.getElementById('smode').value == 'sessionStorage' && window.sessionStorage) {
    getcountries=decodeURIComponent(('' + sessionStorage.getItem('wls_vs_php_countries')).replace(/^null$/g,'')).replace(/\+/g,' ');
    if (getcountries != '') {
    document.getElementById('smode').value='sessionStorage';
    datamode='sessionStorage';
    }
    }

    if (getcapitals != '' && getcountries != '') {
    divcont='<table border=5 style="width:95%;vertical-align:top;background-color:white;"><tr style=background-color:#f0f0f0;"><th>Capital</th><th>Country</th></tr></table>';
    dcaps=getcapitals.split('|');
    dctys=getcountries.split('|');
    for (idis=0; idis<dcaps.length; idis++) {
    divcont=divcont.replace('</table>', '<tr><td>' + dcaps[idis] + '</td><td>' + dctys[idis] + '</td></tr></table>');
    }
    document.getElementById('dreport').innerHTML=divcont;
    }
    document.getElementById('smode').value=datamode;
    }

    Which beggars the question “What are the differences between sessionStorage and localStorage?” A quick reading might surmise that “the latter has an expiration date”. We leave you with an open ended Google search so that you may extend your readings on this.


    Previous relevant Window LocalStorage Client Versus Server Primer Tutorial is shown below.

    Window LocalStorage Client Versus Server Primer Tutorial

    Window LocalStorage Client Versus Server Primer Tutorial

    Even though we rave on a lot about serverside PHP and its $_POST method=POST (versus HTML/Javascript recipient via ? and & argument $_GET method=GET scenario) data length advantages as the recipient of an HTML form method=POST set of data that could be sizeable, we’ve just realized that there is a client Javascript and window.localStorage methodology that may help alleviate the need to involve PHP (and any other serverside intervention) on occasions.

    Hint: Yes, we’ve raved on about this too?! Does the blog posting title give it away? Okay, yes, it should read “localStorage”, but thought we’d gone past such juvenile finickiness since the Whac-A-Mole controversy of 1st December 2019 (or even The Great Tea Trolley Disaster of ’67, we daresay).

    It can even use a “self-destruct” approach to the use of this “localStorage” on having used it because …

    • the web application knows who is using it (localStorage) … and on having accessed and read it …
    • the web application knows it (localStorage) is of no use to any other user (in this web application’s case, at least)

    … which is very pleasing for a Land Surveyor who likes to leave cow paddocks as they’ve seen them so to speak. Except it’s like having a ten tonne truck worth of data access in amongst the cow pats when having access to “localStorage” (or PHP), rather than a little piddle of calf wee (wee Metcalfes know a thing or two about these things!) data access of ? and & HTML/Javascript URL arguments (or even if we were to use HTTP Cookies).

    It’s not as if we all have access to serverside language usage, though we do, because we really like PHP and MAMP and Apache/PHP/MySql web servers (and have arranged our development environment accordingly), but what if you are starting out in web development, and still want to allow for sizeable chunks of data with your web applications? Huh? Huh?! See the possibilities? Try our proof of concept wls_vs_php.html Capital City Find Matching Country Report live run, and highlight a whole swathe of (multiple mode) dropdown option Capital Cities holding down the shift key before pressing the yellow “Report” button. If the URL ends up as …

    https://rjmprogramming.com.au/HTMLCSS/wls_vs_php.html?capitals=localStorage&countries=localStorage

    that’s because the web application’s …


    function analyze() {
    var purl=document.URL.split('#')[0].split('?')[0] + '?capitals=' + encodeURIComponent(document.getElementById('capitals').value) + '&countries=' + encodeURIComponent(document.getElementById('countries').value);
    if (purl.length > 800) {
    if (phpexists) {
    document.getElementById('myform').method='POST';
    document.getElementById('myform').action='./wls_vs_php.php';
    } else if (window.localStorage) {
    localStorage.setItem('wls_vs_php_countries', encodeURIComponent(document.getElementById('countries').value));
    localStorage.setItem('wls_vs_php_capitals', encodeURIComponent(document.getElementById('capitals').value));
    document.getElementById('capitals').value='localStorage';
    document.getElementById('countries').value='localStorage';
    location.href=document.URL.split('#')[0].split('?')[0] + '?capitals=' + encodeURIComponent(document.getElementById('capitals').value) + '&countries=' + encodeURIComponent(document.getElementById('countries').value);

    return false;
    }
    }
    return true;
    }

    … HTML form onsubmit event logic …

    1. discovered no PHP web application existant (via Client Pre-emptive Iframe techniques) … and …
    2. discovered (in a sanity check feeling way) that to go down the proposed HTML form method=GET approach was risking a …

      HTTP 414 "Request URI too long"

      … web browser error … and that …
    3. localStorage was a known web browser piece of functionality
    4. … and so as per our localStorage logic we …

    5. back out of the default HTML form method=GET navigation setup of the web application in favour of …
      • storing that data into localStorage
      • substituting into the URL ? and & arguments the hardcoding “localStorage” (and in so doing, getting back under the HTTP 414 “Request URI too long” limitation, piecing together (what amounts to) …
        location.href=document.URL.split(‘#’)[0].split(‘?’)[0] + ‘?capitals=localStorage&countries=localStorage’;)
        … that on a recall to this same web application a …
      • document.body onload event piece of Javascript logic checks the localStorage for its incoming Capital City Country Report data, as per …

        var phpexists=false;
        var getcapitals=location.search.split('capitals=')[1] ? decodeURIComponent(location.search.split('capitals=')[1].split('&')[0]).replace(/\+/g,' ') : '';
        var getcountries=location.search.split('countries=')[1] ? decodeURIComponent(location.search.split('countries=')[1].split('&')[0]).replace(/\+/g,' ') : '';

        function checkforreport() {
        var divcont='';
        var dcaps, dctys, idis;
        if (getcapitals == 'localStorage') {
        if (window.localStorage) {
        getcapitals=decodeURIComponent(localStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
        localStorage.removeItem('wls_vs_php_capitals');
        } else {
        getcapitals='';
        }
        }
        if (getcountries == 'localStorage') {
        if (window.localStorage) {
        getcountries=decodeURIComponent(localStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
        if (getcapitals.replace('localStorage','') != '' && getcountries.replace('localStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
        localStorage.removeItem('wls_vs_php_countries');
        } else {
        getcountries='';
        }
        }

        if (getcapitals != '' && getcountries != '') {
        divcont='<table border=5 style="width:95%;vertical-align:top;background-color:white;"><tr style=background-color:#f0f0f0;"><th>Capital</th><th>Country</th></tr></table>';
        dcaps=getcapitals.split('|');
        dctys=getcountries.split('|');
        for (idis=0; idis<dcaps.length; idis++) {
        divcont=divcont.replace('</table>', '<tr><td>' + dcaps[idis] + '</td><td>' + dctys[idis] + '</td></tr></table>');
        }
        document.getElementById('dreport').innerHTML=divcont;
        }
        }

        … the localStorage.removeItem() representing that “self-destruct” nuance we were talking about before

    We may well use this methodology in future projects, and hope it has been of some little interest to you as well?!

    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.


    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.


    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 Ajax, eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Select Multiple Webpage Palette Speech Bubble YouTube One Click Tutorial

Select Multiple Webpage Palette Speech Bubble YouTube One Click Tutorial

Select Multiple Webpage Palette Speech Bubble YouTube One Click Tutorial

Improving on yesterday’s Select Multiple Webpage Palette Speech Bubble YouTube Placement Tutorial, today we have …

Day 4 Nuance 2

… bringing the happy news that for a legitimate 11 character YouTube reference within the Speech Bubbles it is a one click scenario for …

  • non-mobile … and …
  • mobile

… alike.

Yet again, what changed? Well …


Previous relevant Select Multiple Webpage Palette Speech Bubble YouTube Placement Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble YouTube Placement Tutorial

Select Multiple Webpage Palette Speech Bubble YouTube Placement Tutorial

It’s …

Day 3 Nuance 1

… today, and you’d expect that scoreline given home ground advantage … onto yesterday’s Select Multiple Webpage Palette Speech Bubble YouTube Tutorial where the progress is …

  • for mobile platforms, where our 11 character links led us to a new window scenario … so yesterday … today …
  • we keep the YouTube video to the same webpage, over to the right

… but still, alas, several tap/clicks needed to get to the video playing.

A lot of the time of “Nuance 1” occurred using a lot of …


event.stopPropagation();

… calling for onclick and onmousedown and ontouchdown event calls in amongst the new tabularly organized inline HTML


function maybeemoji(insvg) {
// blah blah blah
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
if (document.getElementById('dcont').innerHTML.indexOf('<table') != -1) {
return insvg.replace('></text>', '>' + newoutthing + '</text>').replace(" data-emoji=''", " data-emoji='" + newoutthing + "'").replace(' data-emoji=""', ' data-emoji="' + newoutthing + '"');
}
thehoster='tdleft';
return '<table><tr><td id=tdleft style=vertical-align:top;>' + insvg.replace('></text>', '>' + newoutthing + '</text>').replace(" data-emoji=''", " data-emoji='" + newoutthing + "'").replace(' data-emoji=""', ' data-emoji="' + newoutthing + '"') + '</td><td id=tdnothing style=vertical-align:top; onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="event.stopPropagation();"><a onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="notallowed(); event.stopPropagation();" href=#tdleft title="Speech Bubble">💬</a><br><a onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="notallowed(); event.stopPropagation();" href=#tdnothing title="YouTube">📹</a></td><td id=tdright style=vertical-align:top; onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="event.stopPropagation();"><iframe style=display:none;width:900px;height:800px; id=rightif name=rightif src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=&theaNOid=&theifrNOameid=&thebuttoNOnwording=&justaJUNKudio=&youtube_duration=22223.000&email=&emoji=on&c0=on&i0=0&j0=22223&i1=&j1=&i2=&j2=&i3=&j3=&i4=&j4=&i5=&j5=&i6=&j6=&i7=&j7=&i8=&j8=&i9=&j9=&i10=&j10=&i11=&j11=&i12=&j12=&i13=&j13=&i14=&j14=&i15=&j15=&i16=&j16=&i17=&j17=&i18=&j18=&i19=&j19=&i20=&j20=&i21=&j21=&i22=&j22=&i23=&j23=&i24=&j24=&i25=&j25=&i26=&j26=&i27=&j27=&i28=&j28=&i29=&j29="></iframe></td><td id=tdmiddle style=vertical-align:top; onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="notallowed(); event.stopPropagation();"><a onclick="event.stopPropagation();" href=#tdleft title="Speech Bubble">💬</a><br><a onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="notallowed(); event.stopPropagation();" href=#tdnothing title="YouTube">📹</a></td></tr></table>';
}
// blah blah blah non-mobile returns
}

… describing the HTML elements added for mobile usage, here. Even then, annoyingly, if you tapped on one of these, the Javascript would too often call function addcontents in a way we thought was aggravating, and so we resorted to a global variable usage and started doing as below …


var allowed=true;

function addcontents(inboc) {
if (!allowed) {
allowed=true;
return false;
}

var nboc='', seventeen="17", zero=0, numlines=1, one=1, grest='', ghuh='', wasfound=false, jnew=0;
// blah blah blah open textarea popup window blah blah blah
}

function notallowed() {
allowed=false;
setTimeout(function(){ allowed=true; }, 1000);
}

Again, what changed? Well …


Previous relevant Select Multiple Webpage Palette Speech Bubble YouTube Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble YouTube Tutorial

Select Multiple Webpage Palette Speech Bubble YouTube Tutorial

Well, onto yesterday’s SVG Tspan Element Primer Tutorial our “two day” job is “two days” of sorts. Definitely for non-mobile, deploying the “inline audio stream of YouTube video play” concept we wanted, but for mobile, let me “count the ways” …

  1. to get any functionality down to “one tap/click to play” … well …
  2. we tried for mobile, and haven’t given up, but the complexity of “overlay” related z-index and “where to place iframe element” issues exploded my tiny little brain … and so …
  3. for mobile we’ve “parked” the ideal solution … in favour of, for now …
  4. the mobile “two day solution” that, like for non-mobile, underlines those 11 character YouTube references as links that can navigate interested users to a new tab/window YouTube window to play the “whole shebang” (and … sigh … needing that extra tap/click) … leaving …
  5. Days 3 (and on) to nuance

Another project where the last 10% nuances is probably going to take more time than the rest! Anyway, we’ll see how this “mini project” develops.

What changed? Well …

  • the SVG tspan 11 letter word YouTube reference Speech Bubble changed select_palette.html web application … now helped out by …
  • now SVG tspan savvy external Javascript ytaudioonly.js assisting YouTube Audio Stream of Video Playsspecifically

    // blah blah blah
    var thespansare=[];

    function ihun(ao) {
    var aih=ao.innerText;
    if (aih.trim() != '') {
    var newihis='';
    for (var iaih=0; iaih<aih.length; iaih++) {
    newihis+='_';
    }
    ao.innerHTML=newihis;
    }
    }


    function audioytlook() { // first happens around document.body onload event
    // blah blah blah
    var taop='', ttdom='', ttid=' id=newspan8', ziif='', yiif='';
    // blah blah blah
    thespansare=document.getElementsByTagName('tspan');
    if (eval('' + thespansare.length) > 0) {
    for (jits=0; jits<thespansare.length; jits++) {
    //alert(thespansare[jits].outerHTML);
    if ( ('' + thespansare[jits].outerHTML).indexOf('tubeaudioyou') != -1 && ('' + thespansare[jits].outerHTML).indexOf(' data-mentioned=') == -1) {
    //alert('HERE');
    jitrect=thespansare[jits].getBoundingClientRect();
    if (document.getElementById('doverlay')) {
    if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && document.URL.indexOf('.9JUNK5.247/') == -1) {
    //alert('why');
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    ttid+='8';
    } else {
    ziif=' style="z-index:50;" ';
    yiif=' event.stopPropagation(); ';
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); "; // document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    //document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.4;z-index:176;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a></span>';
    //document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    //alert('<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">___________</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>');
    document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">___________</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    ttid+='8';
    }
    } else {
    if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && document.URL.indexOf('.9JUNK5.247/') == -1) {
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    document.body.innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    ttid+='8';
    } else {
    ziif=' style="z-index:150;" ';
    yiif=' event.stopPropagation(); ';
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    document.body.innerHTML+='<span' + ttid + ' style="opacity:0.4;z-index:176;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">___________</a></span>';
    ttid+='8';
    }
    }
    thespansare[jits].setAttribute('data-mentioned', 'y');
    }
    }
    thespansare=[];
    }

    var audioonlyas=document.getElementsByTagName('a');
    // blah blah blah
    }

    // blah blah blah

    … slotting in tspan logic ahead of the a link analysis


Previous relevant SVG Tspan Element Primer Tutorial is shown below.

SVG Tspan Element Primer Tutorial

SVG Tspan Element Primer Tutorial

We’re starting a planned “mini project” to improve Select Multiple Webpage Palette Speech Bubble Swipe Tutorial and what we find important …

  1. regarding improvements to existant functionality it is most important to not interfere with any current functionality … and then …
  2. implement new functionalities off this platform

… and with our “mini project” of embellishing 11 letter words in the Speech Bubbles of our Select Multiple Webpage Palette Speech Bubble web application of recent times, we have a natural compartmentalization playing out mimicking those ideas above, that goes …

  1. Day 1 – work with the data that is the HTML (and SVG) of Speech Bubbles where they look and behave as ever, but 11 letter words get nested into SVG tspan elements
  2. Day 2 – embellish the web application via those SVG tspan elements

It’s our first go using SVG tspan elements as a “forward thinking” tool, and it helped us thinking on this regarding the corrollaries to HTML span element. What initially concerned us using SVG tspan was whether we’d have to specify x and y attributes, but, as it panned out, no, the SVG text element nesting the tspan takes care of that, so, “top supportive” we’d say, and a lot like how we think of the HTML span element working, and helping out, enormously!

Into “Day 2” though, and we’ll be wanting to do Javascript DOM things in the “overlay” line of thinking. So part of a “Day 1” paradigm, you will better leave that “Day 1” proving the work of “Day 2” is possible, and this was achieved via


function detecttspan() {
var tsrect=null;
var tss=document.getElementsByTagName('tspan');
for (var itss=0; itss<tss.length; itss++) {
tsrect=tss[itss].getBoundingClientRect();
alert('' + tss[itss].outerHTML + ' left:' + tsrect.left + ' top:' + tsrect.top);
}
}

… with the good news we started “Day 1” not being sure of “passed the test”, as you can see from today’s tutorial picture, and …

… this one illustrating work in the SVG tspan 11 letter word Speech Bubble changed select_palette.html web application.

Why 11? Tune in tomorrow.


Previous relevant Select Multiple Webpage Palette Speech Bubble Swipe Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Swipe Tutorial

Select Multiple Webpage Palette Speech Bubble Swipe Tutorial

Today’s tutorial is an amalgam of …

  1. concepts off Apple iOS Control Centre Tutorial … and …
  2. continuing on with the functionality of the recent Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial‘s External Javascript YouTube Audio Stream of Video web application ideas

… which, to us, is in the category of …

  • optional
  • experimental
  • quirky … and yet …
  • something we may well turn to for future endeavours … and so, worth it

… so, though there is opposition you can’t say I didn’t do it my way … which means, correct me if I’m wrong here, that means “I did it my way”that right … team?!.

We’re adding …

  • web application “swipe down and left from top right” … email after entering data … and …
  • web application “swipe up from bottom” … SMS after entering data

… user interaction “shortcuts” into the mix, via …


var firstx=null, firsty=null, pos3=-3, pos4=-3, nextx=null, nexty=null, slowitdown=false, isok=true, oktoemail=false, oktosms=false;
var wow=-1, woh=-1, wiw=-1, wih=-1;
var firstone=true;


function controlisok() {
isok=true;
}

function swipecheck(ev) {
if (!window.opener && isok) {
if (ev.touches) {
if (ev.touches[0].pageX) {
pos3 = ev.touches[0].pageX;
pos4 = ev.touches[0].pageY;
} else {
pos3 = ev.touches[0].clientX;
pos4 = ev.touches[0].clientY;
}
console.log('pos3 = ' + pos3 + ',pos4 = ' + pos4);
} else if (ev.clientX || ev.clientY) {
pos3 = ev.clientX;
pos4 = ev.clientY;
console.log('pos3 = ' + pos3 + ' ,pos4 = ' + pos4);
} else {
pos3 = ev.pageX;
pos4 = ev.pageY;
console.log('pos3 = ' + pos3 + ', pos4 = ' + pos4);
}


if (pos3 >= 0 && pos4 >= 0) {
if (firstx == null) {
firstx=pos3;
firsty=pos4;
slowitdown=true;
isok=false;
setTimeout(controlisok, 400);
} else if (pos3 != firstx || pos4 != firsty) {
nextx=pos3;
nexty=pos4;
// Swipe down left from top right
if (nextx < firstx && nexty > firsty && pos3 > eval(document.documentElement.clientWidth / 2) && pos4 < eval(document.documentElement.clientHeight / 2)) {
if (firstone) {
if (eval(firstx - nextx) > 5 && eval(nexty - firsty) && eval(window.innerWidth - firstx) < 90 && eval(firsty) < 90) {
firstone=false;
//alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
shapetodoemail(); // alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
}
}
// ... else swipe up from bottom
} else if (nexty < firsty && firsty > eval(document.documentElement.clientHeight / 2) && pos4 > eval(document.documentElement.clientHeight / 2)) {
if (firstone) {
if (eval(firstx - nextx) < 5 && eval(nexty - firsty) < 5 && eval(firsty) > eval(document.documentElement.clientHeight / 2)) {
firstone=false;
//alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
shapetodosms(); // alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
}
}
} else if (pos3 <= eval(document.documentElement.clientWidth / 2) || pos4 >= eval(document.documentElement.clientHeight / 2)) {
firstx=null;
firsty=null;
nextx=null;
nexty=null;
}
}
}
}
}

function gettodoemail() {
return oktoemail;
}

function settodoemail(towhat) {
oktoemail=towhat;
}

function shapetodoemail() {
oktoemail=true;
setTimeout(trytodoemail, 5000);
}

function trytodoemail() {
if (oktoemail) {
doemail();
}
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function gettodosms() {
return oktosms;
}

function settodosms(towhat) {
oktosms=towhat;
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function trytodosms() {
if (oktosms) {
dosms();
}
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function gwow() {
return wow;
}

function gwiw() {
return wiw;
}

function gwoh() {
return woh;
}

function gwih() {
return wih;
}

function getwow() {
if (window.opener) {
return window.opener.gwow();
} else {
return wow;
}
}

function getwoh() {
if (window.opener) {
return window.opener.gwoh();
} else {
return woh;
}
}

function getwiw() {
if (window.opener) {
return window.opener.gwiw();
} else {
return wiw;
}
}

function getwih() {
if (window.opener) {
return window.opener.gwih();
} else {
return wih;
}
}

function atstart() {
document.body.style.zoom = 1.0

var scale = 'scale(1)';
document.body.style.webkitTransform = scale; // Chrome, Opera, Safari
document.body.style.msTransform = scale; // IE 9
document.body.style.transform = scale; // General
wow=eval(window.outerWidth);
woh=eval(window.outerHeight);
wiw=eval(window.innerWidth);
wih=eval(window.innerHeight);
//alert('' + wih + ' vs ' + woh);
if (window.opener) {
firstone=false;
setTimeout(function(){
oktoemail=window.opener.gettodoemail();
oktosms=window.opener.gettodosms();
window.opener.settodoemail(false);
window.opener.settodosms(false);
}, 2000);
}
}

if (!window.screenLeft) {
window.screenLeft = window.screenX;
window.screenTop = window.screenY;
}

called into play via …


<body onload="atstart(); startsi(); dotdotdotten();" ontouchmove="swipecheck(event);" onmousemove="swipecheck(event);">

… in the changed select_palette.html web application.


Previous relevant Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial

The recent Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial‘s …

  • privacy for Group Talk “public” Bulletin Board functionalities …
  • involved logic for the two scenarios …
    1. data-applyprivacy=Y … via two prefixing spaces entered by originator of Group … completely hides relevant Group Talk Bulletin Board data from viewers outside that Group Talk
    2. data-applyprivacy=y … via one prefixing space entered by originator of Group … hides contact parts of Group Talk Bulletin Board data from viewers outside that Group Talk

    … but we had not “nuanced” the functionality for that second suboption on that first subpass

… and that is the work discussed today, a nuance that amounts to …

Allow non-group Bulletin Board readers see what we say but given cryptic username choices will not know how to contact that Group

That work took place in the PHP component of our Select Multiple Webpage Palette Speech Bubble web application as per

<?php

if (!isset($_GET['owner']) && isset($_GET['me']) && !isset($_GET['contact'])) {
$findings=explode(',', str_replace(';',',',str_replace('+',' ',urldecode($_GET['me']))));
} else if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
$aprivone=' data-applyprivacy="Y"';
$aprivtwo=' data-applyprivacy="y"';
}


if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
$prevcont="";
for ($i=(0 + 0); $i<sizeof($lines); $i++) {
$thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
if (strpos($thisline, $curgmt) !== false && strpos(str_replace("'",'"',$thisline), $aprivone) === false) { // && strpos(str_replace("'",'"',$thisline), $aprivtwo) === false) {
if (strpos(str_replace("'",'"',$thisline), $aprivtwo) !== false) {
$thatline=$thisline;
if (strpos($thatline, 'contact="') !== false && strpos(str_replace('contact=""',"contact=''",$thatline), 'contact="') !== false) {
while (strpos(str_replace('contact=""',"contact=''",$thatline), 'contact="') !== false) {
$thingtochange=explode('"', explode('contact="', str_replace('contact=""',"contact=''",$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
if (strpos($thatline, "contact='") !== false && strpos(str_replace("contact=''",'contact=""',$thatline), "contact='") !== false) {
while (strpos(str_replace("contact=''",'contact=""',$thatline), "contact='") !== false) {
$thingtochange=explode("'", explode("contact='", str_replace("contact=''",'contact=""',$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
if (strpos(str_replace("[]","",$thatline), "[") !== false && strpos(str_replace("[]","",$thatline), "]") !== false) {
while (strpos(str_replace("[]","",$thatline), "[") !== false && strpos(str_replace("[]","",$thatline), "]") !== false) {
$thingtochange=explode("]", explode("[", str_replace("[]","",$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
$prevcont.=$thatline;
} else {

$prevcont.=$thisline;
}
}
}
$vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
exit;
}

?>

… in the changed select_palette.php “eighth draft” PHP.


Previous relevant Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial

Meanwhile, back at some other ranch … somewhere … we’re some of the way down the line, with our recent …

  • Select Multiple Webpage Palette web application …
  • Bulletin Board subset of functionality, towards with it’s …
  • Group Talk (comma separated list of username/contacts) abilities … now offer …
  • Bulletin Board privacy

… as people in a Group Talk may appreciate. In other words, your generic Bulletin Board viewers would not see your Group Talk setup communications should the originator of any Group Talk now, either at …

  • best, as a To: + spaces appendage to a textarea line record (delimited by line feed) … ahead of a way with …
  • spaces prefixing to the prompt widow off right click or gesture events … starting the ball rolling …
  • populating a new data-applyprivacy global data attribute into the SVG

… allowing this new privacy functionality to work.

Again, we’ll need more than the work today to bed this in, but we now do not think there are any impassable concepts to its implementation.

And so, onto the recent Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial‘s work we have the changed select_palette.html web application helped out by the changed select_palette.php “seventh draft” PHP we have made a start making this “privacy dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial

Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial

Yesterday’s Select Multiple Webpage Palette Speech Bubble Emoji Tutorial warned you today …

we may have nuances yet to come

… and allowing for emojis within a Group Talk user’s username (via control-command-space for macOS or Mac OS X, logo key + . (period) for Windows, control+space for iOS, top left + for Android keyboard) be an identifier on their Speech Bubbles … well, it leaves us speechless with nuance!

Yesterday we were attempting to do this but had more success, today, with


/**
* Convert a string to HTML entities ... Thanks to https://zditect.com/code/javascript/easy-solution-to-encode-html-entities-in-javascript.html
*/
String.prototype.toHtmlEntities = function() {
return this.replace(/./gm, function(s) {
return (s.match(/[a-z0-9" . "\\" . "s]+/i)) ? s : '&#' + s.charCodeAt(0) + ';';
});
};


function maybeemoji(insvg) {
var outthing='', newoutthing='', jb=0;
var outsvg=insvg;
//alert('0:' + outsvg);
if (outsvg.indexOf(' data-otherc') != -1 && outsvg.indexOf(' data-ip') != -1) {
outsvg=outsvg.replace(outsvg.split(' data-otherc')[1].split(' data-ip')[0],'').split('97%')[0];
}

//alert(outsvg);

outhtmlentities='';
nonouthtmlentities='';

var nonencodeds=outsvg.split('&#');
for (jb=1; jb<nonencodeds.length; jb++) {
if (eval('' + nonencodeds[jb].split(';')[0]) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
newoutthing+=String.fromCodePoint(eval('' + nonencodeds[jb].split(';')[0]));
if (nonencodeds[jb] != (nonencodeds[jb].split(';')[0] + ';')) {
nonouthtmlentities=' ';
}
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
}
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

if (outhtmlentities == '') {
if (outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' ').indexOf('&#') >= 0) {
//alert('2987:' + outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' '));
nonencodeds=outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' ').split('&#')
for (jb=1; jb<nonencodeds.length; jb++) {
if (eval('' + nonencodeds[jb].split(';')[0]) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
newoutthing+=String.fromCodePoint(eval('' + nonencodeds[jb].split(';')[0]));
if (nonencodeds[jb] != (nonencodeds[jb].split(';')[0] + ';')) {
nonouthtmlentities=' ';
}
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
}
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

}
}


if (outhtmlentities == '') {
//alert(987);
var encodedStr=outsvg.replace(/[\u00A0-\u9999<>\&]/g, function(i) {
if (eval('' + i.charCodeAt(0)) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+i.charCodeAt(0)+';';
newoutthing+=String.fromCodePoint(eval('' + i.charCodeAt(0)));
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+i.charCodeAt(0)+';';
}
return '&#'+i.charCodeAt(0)+';';
});
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

if (outhtmlentities == '') {
if (document.getElementById('myip').value != '' && insvg.replace(/\'/g,'"').indexOf(' data-owner="') != -1 && insvg.replace(/\'/g,'"').indexOf(' data-contact="') != -1) {
var basisstr=insvg.replace(/\'/g,'"').split(' data-owner="')[1].split('"')[0] + insvg.replace(/\'/g,'"').split(' data-contact="')[1].split('"')[0] + document.getElementById('myip').value;
var bcnt=999, koffset=0;
for (var ib=0; ib<basisstr.length; ib++) {
//if (bcnt == 999) { bcnt=129293; }
//bcnt+=eval('' + basisstr.substring(ib).charCodeAt(0));
koffset+=eval('' + basisstr.substring(ib).charCodeAt(0));
}
if (koffset > 0) {
bcnt+=Math.round(eval(eval('' + koffset) / 10));
var itries=0;
if (4 == 5) { bcnt=129293; }
while (supports_emoji(String.fromCodePoint(eval('' + bcnt)))) {
bcnt++;
itries++;
if (itries >= 230) { bcnt=129293; }
}
//alert(bcnt);
outthing='&#' + bcnt + ';';
newoutthing+=String.fromCodePoint(eval('' + bcnt));
}
}
}
return insvg.replace('></text>', '>' + newoutthing + '</text>').replace(" data-emoji=''", " data-emoji='" + newoutthing + "'").replace(' data-emoji=""', ' data-emoji="' + newoutthing + '"');
}

… in the changed select_palette.html web application helped out by the changed select_palette.php “sixth draft” PHP we have made a start making this “emoji dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble Emoji Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Emoji Tutorial

Select Multiple Webpage Palette Speech Bubble Emoji Tutorial

The reason for today’s efforts with our latest web application have a similar theme to yesterday’s Select Multiple Webpage Palette Speech Bubble IP Address Tutorial‘s efforts, namely …

help differentiate Speech Bubbles of different users in a Group Talk arrangement with our public Bulletin Board functionality

Today’s research into displaying emoji text at the pointy corner of the Speech Bubble hopes to help out here, and though we may have nuances yet to come, we can say with the changed select_palette.html web application helped out by the changed select_palette.php “fifth draft” PHP we have made a start making this “emoji dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble IP Address Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble IP Address Tutorial

Select Multiple Webpage Palette Speech Bubble IP Address Tutorial

To further differentiate Group Talk users accessing the public Bulletin Board of our web application talked about in Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

  • we need to consider user IP addresses, as Wikipedia describes …

    An Internet Protocol address (IP address) is a numerical label such as 192.0.2.1 that is assigned to a device connected to a computer network that uses the Internet Protocol for communication.[1][2] IP addresses serve two main functions: network interface identification, and location addressing.

    Some readers may have noted for a couple of days now, our newly introduced PHP has been assisting the calling HTML, and itself, by remembering the user’s IP address. Yesterday, it was to help colour code Speech Bubbles, and today, it helps in amongst …

    • username … and …
    • contact … set lists … with …
    • IP address

    … to differentiate email and SMS invitation origin calls of our web application, as to who that user has been described as by the originator of the Group Talk settings with the changed select_palette.html web application helped out by the changed select_palette.php “fourth draft” PHP.


    Previous relevant Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial is shown below.

    Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

    Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

    The concept of Group Talk started with yesterday’s Select Multiple Webpage Palette Speech Bubble Invitations Tutorial. It made us think that we should start thinking about the differentiation of voices amongst the Speech Bubbles of the public Bulletin Board we’re supporting with the associated web application and its user mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic talents.

    We decided that one way could be to …

    • Colour Code the background colour of the Speech Bubbles via the user IP address …
      <?php

      $gbcol="0,0,255";

      function server_remote_addr() {
      global $gbcol;
      $rma = $_SERVER['REMOTE_ADDR'];
      $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
      $uas=explode('.', str_replace('::1','65.254.95.247',$rma)); // 65.254.93.32

      if (sizeof($uas) >= 3) {
      $gbcol='' . ($uas[0] % 256);
      $gbcol.=',' . ($uas[1] % 256);
      $gbcol.=',' . (($uas[2] + $uas[(-1 + sizeof($uas))]) % 256);
      }

      // you can add different browsers with the same way ..
      if(preg_match('/(chromium)[ \/]([\w.]+)/', $ua))
      $rma = '000000'.$rma;
      elseif(preg_match('/(chrome)[ \/]([\w.]+)/', $ua))
      $rma = '00000'.$rma;
      elseif(preg_match('/(safari)[ \/]([\w.]+)/', $ua))
      $rma = '0000'.$rma;
      elseif(preg_match('/(opera)[ \/]([\w.]+)/', $ua))
      $rma = '000'.$rma;
      elseif(preg_match('/(msie)[ \/]([\w.]+)/', $ua))
      $rma = '00'.$rma;
      elseif(preg_match('/(mozilla)[ \/]([\w.]+)/', $ua))
      $rma = '0'.$rma;
      return str_replace(":", "_", $rma);
      }

      server_remote_addr();

      ?>
    • when a Group Talk invitation is sent out do not have the sender username and/or contact as the recipient username and/or contact

    … moving further along with the changed select_palette.html web application helped out by the changed select_palette.php “third draft” PHP.


    Previous relevant Select Multiple Webpage Palette Speech Bubble Invitations Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Invitations Tutorial

    Select Multiple Webpage Palette Speech Bubble Invitations Tutorial

    Yesterday’s Select Multiple Webpage Palette Speech Bubble PHP Tutorial‘s …

    • PHP embellishment of …
    • the day before’s SVG data enhancemants … today improves yesterday’s …
    • public Bulletin Board via user mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logics … today, adding …
    • optional invitation communication email and/or SMS logics via Group Talk set comma separated optional user username/contact entered data set lists helping with Group Talk filtering means of filtering the Speech Bubble data

    … with the changed select_palette.html web application helped out by the changed select_palette.php “second draft” PHP.


    Previous relevant Select Multiple Webpage Palette Speech Bubble PHP Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble PHP Tutorial

    Select Multiple Webpage Palette Speech Bubble PHP Tutorial

    Yesterday’s Select Multiple Webpage Palette Speech Bubble Data Tutorial‘s …

    • data … begets …
    • PHP
    … around here a lot, as PHP is our domain’s “first call” serverside language.

    Add to that that “yesterday’s tomorrow is today” we’re supposed to be finished with our “short two day mini project sojourn”, and in a crude way we have, but we want a third day to add nuance to the arrangements with data filtering and more sophistication regarding collection, within the approach of our new …

    Bulletin Board of Speech Bubbles

    … that becomes a …

    • shareable
    • public (on this second day, a bit too public)
    • reverse chronological
    • speech bubble

    … resource, if the user avails themselves of the mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic smarts with the changed select_palette.html web application, now helped out by select_palette.php “first draft” PHP …


    <?php
    // select_palette.php
    // RJM Programming
    // May, 2025

    $prevcont="";
    $curcont="";
    $curgmt=gmdate("Ymd");
    $newlines=[];

    if (isset($_POST['indata'])) {
    $ind=str_replace('+',' ',urldecode($_POST['indata']));
    $lines=explode('<svg name="', $ind);
    if (!file_exists('/tmp/select_palette.htm')) {
    file_put_contents('/tmp/select_palette.htm', '');
    } else {
    $prevcont=file_get_contents('/tmp/select_palette.htm');
    if (strpos($prevcont, '<svg name="' . $curgmt) === false) {
    file_put_contents('/tmp/select_palette.htm', '');
    } else {
    $curcont=$prevcont;
    }
    }


    for ($i=1; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false && strpos($thisline, ' data-public="n"') === false && (strpos($thisline, ' data-owner="') !== false && strpos($thisline, ' data-owner=""') === false) || (strpos($thisline, ' data-contact="') !== false && strpos($thisline, ' data-contact=""') === false)) {
    if (strpos($curcont, $thisline) === false) {
    $curcont.=$thisline;
    }
    }
    }
    file_put_contents('/tmp/select_palette.htm', $curcont);
    echo '<html><body></body></html>';
    exit;

    } else if (isset($_GET['extract'])) {
    if (file_exists('/tmp/select_palette.htm')) {
    $prevcont=file_get_contents('/tmp/select_palette.htm');
    if (strpos($prevcont, '<svg name="' . $curgmt) === false) {
    file_put_contents('/tmp/select_palette.htm', '');
    }
    $lines=explode('<svg name="', $prevcont);
    rsort($lines);

    if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
    $prevcont="";
    for ($i=0; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false) {
    $prevcont.=$thisline;
    }
    }
    $vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
    echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
    exit;
    } else {
    $prevcont="";
    for ($i=0; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false) {
    $isok=true;
    if (isset($_GET['owner']) && strpos(strtolower($thisline), ' data-owner="' . strtolower(str_replace('+',' ',urldecode($_GET['owner'])) . '"')) === false) {
    $isok=false;
    }
    if (isset($_GET['contact']) && strpos(strtolower($thisline), ' data-contact="' . strtolower(str_replace('+',' ',urldecode($_GET['contact'])) . '"')) === false) {
    $isok=false;
    }
    if (isset($_GET['me']) && strpos(strtolower($thisline), strtolower('="' . str_replace('+',' ',urldecode($_GET['me'])) . '"')) === false) {
    $isok=false;
    } else if (isset($_GET['me'])) {
    $isok=true;
    }
    if ($isok) { $prevcont.=$thisline; }
    }
    }
    $vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
    echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
    exit;
    }

    }

    }

    ?>

    … meaning …

    Data … is enhanced … … by … PHP


    Previous relevant Select Multiple Webpage Palette Speech Bubble Data Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Data Tutorial

    Select Multiple Webpage Palette Speech Bubble Data Tutorial

    Onto yesterday’s Select Multiple Webpage Palette Speech Bubble Tutorial, today, we’re preparing for tomorrow.

    You heard it here first.

    Admittedly, nothing startling there, but it was the first time we remember …

    • embellishing SVG data … with so much …
    • what we normally associate with HTML element work …
      1. global data attributes
      2. id and name attribution …
      3. event logic

    Yes, all possible with SVG, though not the first thing we think of using SVG data within our HTML. We normally think, just display thoughts, but today, we’re paving the way for tomorrow, and our “short two day mini project sojourn” will become clearer regarding motives, then, or get hints trying with strategically changed select_palette.html web application‘s mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic …


    var taar=[];
    var preadd=0;
    var windowuser='', windowcontact='', windowask=true, suffix='';


    function defwuwc(inwindowuser,inwindowcontact) {
    if ((inwindowuser + inwindowcontact) == '') { return ''; }
    if (inwindowuser != '' && inwindowcontact != '') { return inwindowuser + '[' + inwindowcontact + ']'; }
    if (inwindowuser != '' && inwindowcontact == '') { return inwindowuser; }
    return inwindowcontact;
    }


    function treg(ttis) {
    var dotherest=false;
    var ctown=defwuwc(windowuser,windowcontact);
    var ourwindowask=windowask;
    preadd=1;
    if (ttis.outerHTML.indexOf(' data-public=') != -1) {
    if (windowuser == '' && windowcontact == '' && windowask) {
    ctown=prompt("To share on today's board enter a username and/or contact string (append space to remember, append another space to apply to all other Speech Bubbles) ... eg. " + String.fromCharCode(10) + "Robert Metcalfe[rmetcalfe15@gmail.com]", defwuwc(windowuser,windowcontact));
    }
    if (ctown == null) { ctown=''; }
    if (ctown != ctown.replace(/\ \ $/g,'')) {
    windowask=false;
    dotherest=true;
    ctown=ctown.trim();
    } else if (ctown != ctown.replace(/\ $/g,'')) {
    windowask=false;
    ctown=ctown.trim();
    }
    if (ctown.indexOf('[') > 0 && ctown.indexOf(']') != -1) {
    windowuser=ctown.split('[')[0];
    windowcontact=ctown.split('[')[1].split(']')[0];
    } else if (ctown.indexOf('[') == 0 && ctown.indexOf(']') != -1) {
    windowcontact=ctown.split('[')[1].split(']')[0];
    windowuser=windowcontact;
    } else {
    windowuser=ctown;
    windowcontact='';
    }
    if (windowuser != '') {
    ttis.setAttribute('data-owner', windowuser);
    }
    if (windowcontact != '') {
    ttis.setAttribute('data-contact', windowcontact);
    }
    if (windowuser != '' || windowcontact != '') {
    ttis.setAttribute('data-public', 'y');
    ttis.innerHTML=ttis.innerHTML.replace(/\<text\ /g,'<text stroke="blue" ');
    if (dotherest) {
    var svgs=document.getElementsByTagName('svg');
    for (var isvgs=0; isvgs<svgs.length; isvgs++) {
    if (svgs[isvgs].outerHTML.indexOf(' stroke=') == -1) {
    if (('' + svgs[isvgs].id) != ('' + ttis.id)) {
    if (windowuser != '') {
    svgs[isvgs].setAttribute('data-owner', windowuser);
    }
    if (windowcontact != '') {
    svgs[isvgs].setAttribute('data-contact', windowcontact);
    }
    if (windowuser != '' || windowcontact != '') {
    svgs[isvgs].setAttribute('data-public', 'y');
    }
    svgs[isvgs].innerHTML=svgs[isvgs].innerHTML.replace(/\<text\ /g,'<text stroke="blue" ');
    }
    }
    }
    }
    } else {
    windowask=ourwindowask;
    }
    }
    //alert(ttis.outerHTML);
    setTimeout(function(){ preadd=0; }, 5000);
    }


    Previous relevant Select Multiple Webpage Palette Speech Bubble Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Tutorial

    Select Multiple Webpage Palette Speech Bubble Tutorial

    Yesterday’s Select Multiple Webpage Palette Popup Tutorial modus operandi revolved around …

    delimitation rules

    … as so many matters do with written down text.

    We rethought yesterday’s HTML textarea start regarding line feed Speech Bubble creation possibilities, and thought …

    It’s too unwieldy for a user to add to their textual data when what they really want to do is Speech Bubbles.

    Yesterday’s thinking really hoped the user entered a Speech Bubble data one at a time, but what if the user wants to enter several Speech Bubbles in the one textarea incarnation?

    Good question. (Calling all ducks with a slow paddle going?!)

    Yes, but there is that ~~ existing delimitation rule, as of yesterday equating to a line feed. Supposing ~~ was given the delimitation roles …

    1. the character sets …
      lineFeed~~lineFeed
      … separate Speech Bubbles … ie. in the textarea a ~~ record is all there is on a line of textarea text
    2. the character set …
      ~~lineFeed
      … at the start wipes out any previously remembered text data and starts again
    3. else retain the ~~ mapping to lineFeed

    … in combination with the textarea always first presented blank and the previous Speech Bubble or Lines of Text remembered and retained unless the middle condition above happens?

    Well, we think it’s a plan, and led us to be able to share a Speech Bubble presentation of Shakepeare’s Act 1 Scene 1 of Macbeth. And so, today with the changed select_palette.html web application, onto yesterday’s …

    one textarea element

    … paradigm, we present …

    • previous text data in a details/summary “reveal” mode of use above the textarea element, as relevant
    • and below the textarea element we now have buttons to Email or SMS your text creations off to a recipient

    … harnessing hashtag navigational data methodologies in “a” “mailto:” (email) or “sms:” (SMS) prefixing href attributes, as per …


    function doemail() {
    var anchor=null;
    if (woois) {
    if (!woois.closed) {
    if (woois.document.getElementById('myta').outerHTML.indexOf(' data-done="y"') == -1) {
    if (woois.document.getElementById('myta').value.trim() != '') {
    woois.document.getElementById('myta').setAttribute('data-done', 'y');
    setTimeout(doemail, 6000);
    return '';
    }
    } else if (woois.document.getElementById('myta').value.trim() != '') {
    setTimeout(doemail, 6000);
    return '';
    }
    woois.close();
    woois=null;
    setTimeout(doemail, 6000);
    return '';
    }
    }
    var emis=prompt('Please enter email address to send to.', '');
    if (emis == null) { emis=''; }
    if (emis.indexOf('@') != -1) {
    anchor = document.createElement('a');
    anchor.href = 'mailto:' + emis.trim() + '?subject=My%20Speech%20Bubble%20data&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    document.body.appendChild(anchor);
    anchor.innerHTML='Email';
    anchor.target='_top';
    anchor.click();
    } else if (emis.trim() != '' && emis.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
    anchor = document.createElement('a');
    anchor.href = 'sms:' + emis.trim() + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    anchor.innerHTML='SMS';
    anchor.target='_top';
    anchor.click();
    }
    }

    function dosms(){
    var anchor=null;
    if (woois) {
    if (!woois.closed) {
    if (woois.document.getElementById('myta').outerHTML.indexOf(' data-done="y"') == -1) {
    if (woois.document.getElementById('myta').value.trim() != '') {
    woois.document.getElementById('myta').setAttribute('data-done', 'y');
    setTimeout(dosms, 6000);
    return '';
    }
    } else if (woois.document.getElementById('myta').value.trim() != '') {
    setTimeout(dosms, 6000);
    return '';
    }
    woois.close();
    woois=null;
    setTimeout(dosms, 6000);
    return '';
    }
    }
    var emis=prompt('Please enter SMS number to send to.', '');
    if (emis == null) { emis=''; }
    if (emis.indexOf('@') != -1) {
    anchor = document.createElement('a');
    anchor.href = 'mailto:' + emis.trim() + '?subject=My%20Speech%20Bubble%20data&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    document.body.appendChild(anchor);
    anchor.innerHTML='Email';
    anchor.target='_top';
    anchor.click();
    } else if (emis.trim() != '' && emis.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
    anchor = document.createElement('a');
    anchor.href = 'sms:' + emis.trim() + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    anchor.innerHTML='SMS';
    anchor.target='_top';
    anchor.click();
    }
    }


    Previous relevant Select Multiple Webpage Palette Popup Tutorial is shown below.

    Select Multiple Webpage Palette Popup Tutorial

    Select Multiple Webpage Palette Popup Tutorial

    Regarding yesterday’s Select Multiple Webpage Palette Primer Tutorial

    • you start with an outlandish premise …
    • it stays “outlandish” select (dropdown) element wise on non-mobile … but …
    • catering for mobile …
    • you are forced to encase it in a hosting div element (with the onmousedown and ontouchdown precursor events to onclick)

    … all contributing to getting us to a point, today, we can say we’ve added a layer of (useful, extra) functionality, by …

    • no longer asking for user interactive input via a Javascript prompt window … but, instead, like with Background Image Foreground Content Tutorial … we …
    • ask for user interactive input via a window.open (ie. popup) “here’s looking at you, kid” window.opener incarnation guise of our changed select_palette.html web application … just consisting of …
    • one textarea element …
      1. still capable of ~~ delimitation as with the Javascript prompt window thinking … but also now …
      2. harnessing the talents of a textarea line feed delimitation within it’s value attribute

      … able to extend functionality towards decent …

    • speech bubble feeling thoughts (so far, just) … because …
    • it opens up the idea that the div element innerHTML attribute can be the SVG we had previously been supplying as background HTML/CSS (via Javascript DOM) data

    Cute, huh?! (ahead of the “Speech Bubble styling” niceties making it really cute, yet, for us … but who knows what you can achieve on the “cute styling front”?!).


    Previous relevant Select Multiple Webpage Palette Primer Tutorial is shown below.

    Select Multiple Webpage Palette Primer Tutorial

    Select Multiple Webpage Palette Primer Tutorial

    In the world of web applications, there are often many ways to approach any given requirement. Like with yesterday’s Select Multiple Mobile Background Image Tutorial, today’s “albeit a bit out there idea” is to …

    • offer a select (multiple attribute) “dropdown” HTML element …
    • as a webpage covering …
    • template or palette … where the user …
    • writes user defined lines of words created

    … onto. Pretty simple idea for a “first then second draft“! But maybe not the first idea to spring to mind regarding making such an idea happen?!


    Previous relevant Select Multiple Mobile Background Image Tutorial is shown below.

    Select Multiple Mobile Background Image Tutorial

    Select Multiple Mobile Background Image Tutorial

    We had occasion to revisit Window LocalStorage Client Versus Server Map Tutorial‘s web application today changed this way to end up with wls_vs_php.htm, on an iPad, and saw how initially lacking was the advice on how to work the Capital City to Country quiz. The reason, primarily, in our view, is that on mobile platforms an element such as …


    <select class=dglow onclick=" console.log('67234'); noif(); " title='Please select Capital(s) below to get Countries Report ...' onfocusout=" document.getElementById('myrepsb').className='dglow'; tablemode = ''; nothere=true; updatecountries(null);" style='width:300px;margin-top:0px;margin-left:0px;vertical-align:top;height:100vh;background-color:lightblue;' id=scapitals multiple>
    // innard options //
    </select>

    … you just see words to the effect …

    0 items …

    … but we’d see more use for this select element “opened up” on initialization. As we read, and believed, via this useful link, thanks, this “programmatical click on mobile platforms” to open up such a select element is not easy. So we decided to go down the route of …

    • to a select multiple element …
    • on mobile …
    • background image …
    • at top right …
    • that is wording advice “Click/tap me”
    • when first encountered

    … and we came up with the document.body onload event call “new Javascript code snippet” …


    if (document.URL.indexOf('?') == -1) {
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    document.getElementById('scapitals').click(); // this is just wishful thinking, but no error is caused, and you never know?
    document.getElementById('scapitals').style.background="url(\"data:image/svg+xml;base64," + window.btoa("<svg xmlns='http://www.w3.org/2000/svg' width='126' height='48' viewport='0 0 100 100' style='border-radius:15px;background-color:rgba(0,0,255,0.3);fill:black;font-family:Verdana;font-size:17px;'><text x='5%' y='60%'>Click/tap me</text></svg>") + "\") no-repeat top right";
    }
    }

    Next best approach, we’d say?!


    Previous relevant Window LocalStorage Client Versus Server Map Tutorial is shown below.

    Window LocalStorage Client Versus Server Map Tutorial

    Window LocalStorage Client Versus Server Map Tutorial

    Get a good map, and a goodly number of times you’ll want a map of smaller or larger scale than the one you have. Murphy’s Law? This is probably why in the wonderful woooooooorrrrrrrrlllllld of Google Charts they have included …

    • Geo Chart topographic map of the world or of regions
    • Map Chart terrestrial/satellite map of your group of markers at a zoom level of your choosing

    … and hope you can see that the latter can save the day for a Short Distance Trip (corner shop, anyone?!).

    So we’ve added onto yesterday’s Window LocalStorage Client Versus Server Timeline Tutorial progress a new toggling button to view a scenario in either Google Chart scenario above.

    You can see this integration work with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link supervising a tweaked geo_chart.php Geo Chart interfacer.


    Previous relevant Window LocalStorage Client Versus Server Timeline Tutorial is shown below.

    Window LocalStorage Client Versus Server Timeline Tutorial

    Window LocalStorage Client Versus Server Timeline Tutorial

    Up to yesterday’s Window LocalStorage Client Versus Server User Tutorial‘s progress, our Capital City Find Matching Country Report web application project was all about …

    • where (and capital of “what”) … but we often seek out a way to add into the mix that 4th dimension …
    • when (ie. time)

    … and regarding the current project, a …

    • where “map” … can interface with a …
    • when “Trip Plan Itinerary”

    … and for this purpose, we’re going to interface to the excellent Google Charts Annotated Timeline Chart, thanks, because it combines links of “time” to “user annotations” in a timeline way, that similar way you might describe the qualities of a Trip, even before you’ve gone on that trip. We’ve also added it so that an unordered places list can be turned into a Trip Plan Itinerary at the click/touch of a new map 🗺 &#128506; emoji button.

    Again, see how these timeline amendments were achieved with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link and annotatedtimeline_chart.php which changed quite a lot.


    Previous relevant Window LocalStorage Client Versus Server User Tutorial is shown below.

    Window LocalStorage Client Versus Server User Tutorial

    Window LocalStorage Client Versus Server User Tutorial

    The inherent weakness with our current Capital City Find Matching Country Report web application project, to our minds, was that places of interest are not restricted to the Capital Cities of Countries, especially when “Trip Planning”. On the other hand, it would be impossible to cater for every “place” in the world. That is far too subjective for good web application applicability. What would be good though, is to allow in user defined …


    Place name, Country name

    … terms, the definitions of interest to a user. We can ask this …

    • flagged by the click/touch of an emoji button … and …
    • the interactive entry presented via a Javascript prompt window

    . When thinking of data applicable to an individual, then that can be catered for by recording it in localStorage where it will be recalled on the next execution of that web application in the same web browser.

    This, along with a Colour Wheel of the “nearest TimeZone place” onto the existing logic of yesterday’s Window SessionStorage Client Versus Server Order Tutorial progress could make for a more useful and practical tool for those Trip Planners out there!

    See how this was achieved with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.

    Did you know?

    To click/touch one of those Google Chart Geo Chart lines between Emoji Flag Markers will show a new Google Maps directions web page with transport times and detail, as well as an inhouse crow fly distance of that trip leg, as shown up the top right of today’s tutorial picture.


    Previous relevant Window SessionStorage Client Versus Server Order Tutorial is shown below.

    Window SessionStorage Client Versus Server Order Tutorial

    Window SessionStorage Client Versus Server Order Tutorial

    If we are to honour our thoughts of being able to use our current Capital City Find Matching Country Report web application as a Trip Planner …

    Our primary integration today is to (software) integrate the great Weather Underground and its great API service for autocomplete name searches for weather (and hurricane) information. Why bother? Well, can you not envisage a user using that Ajax functionality of yesterday’s Window SessionStorage Client Versus Server Ajax Tutorial as a trip planner, perhaps, or as a “checking up on relatives overseas” tool, perhaps? And not all the capital cities are timezone places, and so for some of those we can use Weather integration to still show apt online information when click/touching a Countries Report row. Speaking of this “row”, we make an improvement whereby on a first click of a right hand (Country) row cell, that cell is not initially a contenteditable=”true” one (that may frustrate showing the keyboard on mobile, when most likely it was the row touch intended), but then becomes a contenteditable=”true” cell henceforth.

    … then yesterday’s Window SessionStorage Client Versus Server Flags Tutorial “progress to now” needs to take notice of a user’s order of multiple select (dropdown) element click/touching of Capital City option (sub)elements, just as we did with the recent User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial‘s web application project to allow for a user ordered YouTube video playlist.

    Because what is a Trip Planner without an ordered trip? Well, that is debatable, but what isn’t (debatable), is that there will be people in the world who appreciate the “mapping out” of a proposed Trip Planning Itinerary. What could we call on here? We can think of the Google Chart Geo Chart work around about the time of Google Geo Chart Co-ordinate Emojis Tutorial, when we started using …

    • a world map … with …
    • emoji markers … and optionally …
    • joined up by straight lines

    … an idea for a Trip Plan itinerary synopsis, perhaps?!

    If you examined closely yesterday’s code changes you will have noticed our collecting of TimeZone Place geographical latitude and longitude information. Today, we start making use of that preparatory work with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.

    Stop Press

    The “emoji markers” above (as of 2 January 2020) will be “country flags” (as per Window SessionStorage Client Versus Server Flags Tutorial ideas), as defined.


    Previous relevant Window SessionStorage Client Versus Server Flags Tutorial is shown below.

    Window SessionStorage Client Versus Server Flags Tutorial

    Window SessionStorage Client Versus Server Flags Tutorial

    Yes, there’s more to do onto yesterday’s Window SessionStorage Client Versus Server CSS Tutorial‘s Capital City Find Matching Country Report web application project, in our eyes. We have not even mentioned “Internationalization” as a concept up to now. In this line of thinking …

    Did you know?

    Emoji flags via ISO 2 character country codes are dead easy via Regional Indicator Symbol characters …


    var lri="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    var dri=["127462","127463","127464","127465","127466","127467","127468","127469","127470","127471","127472","127473","127474","127475","127476","127477","127478","127479","127480","127481","127482","127483","127484","127485","127486","127487"];

    var thiscc='AU'; // ISO 2 character countrycode for Australia
    var ccsuff='', ccchar=' ';
    for (var iccsuff=0; iccsuff<thiscc.length; iccsuff++) {
    ccchar=thiscc.substring(iccsuff, eval(1 + eval('' + iccsuff))).toUpperCase();
    ccsuff+='&#' + dri[eval('' + lri.indexOf(ccchar))] + ';';
    }
    document.getElementById('lastflag').innerHTML=ccsuff;

    … to result in (via <span style=font-size:64px;>&#127462;&#127482;</span>) …


    🇦🇺

    … providing interest and general translatability to the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.


    Previous relevant Window SessionStorage Client Versus Server CSS Tutorial is shown below.

    Window SessionStorage Client Versus Server CSS Tutorial

    Window SessionStorage Client Versus Server CSS Tutorial

    Further to yesterday’s Window SessionStorage Client Versus Server Integration Tutorial we have a two pronged improvements set for you today with our current Capital City Find Matching Country Report web application project …

    • CSS styling changes … and …
    • additional functionality for Email and SMS links back to our current Capital City Find Matching Country Report web application project (to complete the cycle)

    We use several modes of CSS application (the first and last of particular relevance to today’s “highlighting of workflow” improvements) …

    … the “static” measures often helping to highlight the web application’s main workflow of user interaction and the “dynamic” measures helping to alert the user as to where to proceed with their “workflow”.

    In terms of CSS styling work …

    1. for non-mobile platforms we allow for more columns to be applied to our Capitals select (dropdown) element (in order to reduce some user scrolling, as does our new additional A-Z letter basis sorting functionality) as per … the “dynamic” Javascript DOM “class” modifications

      if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
      document.getElementById('lefttd').className='lefttd';
      }

      … dovetailing with the “static” internal CSS coding

      <style>
      .lefttd {
      column-count: 4;
      max-height: 35%;
      vertical-align: top;
      max-width: 70%;
      font-size: 8px;
      background-color: rgba(205,205,205,0.5);
      background-image: -webkit-gradient(
      linear,
      right bottom,
      left top,
      color-stop(0, rgba(205, 205, 205, 0.8)),
      color-stop(0.50, rgba(255, 255, 0, 0.2))
      );
      background-image: -o-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -moz-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -webkit-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -ms-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: linear-gradient(to left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);

      }
      </style>

      … and please note that around here at RJM Programming we have a “far from hard and fast rule” (but a rule regardless) regarding HTML element ID and class attributes that they concern (and (usually) be compartmentalised into) Javascript (DOM) manipulations and CSS styling issues respectively … and add a linear-gradient background to the table cell when expecting the initial user interaction on non-mobile platforms
    2. a “dynamic” Javascript DOM “class” modification … document.getElementById(‘myrepsb’).className=’dglow’; … is made to the “Report…” button at the Capitals select (dropdown) onfocusout event so as to highlight (with “glow” inspired styling) where user interaction may flow to

    As far as links go, you may expect to need serverside means to construct these in online Email and SMS message interfacing, but email (client program) products like Gmail parse your ascii text and convert http: or https: protocol URLs in your Email body to hyperlinks, as does the Messages SMS application here on this MacBook Pro using macOS Mojave. Cute, huh?! So to close the circle back from remote thar’ parts back to our web application is a simple matter of, in broad brush terms …

    • adding two new buttons called “Email Columns and Links …” and “SMS Columns and Links …” that …
    • set a global variable andlinkto = true; … setting in play, within the report writing code (that likes monospaced fonts) …
    • add a new links column to the right with URLs like …
      https://www.rjmprogramming.com.au/HTMLCSS/wls_vs_php.htm?andgo=y&countries=Belize&capitals=Belmopan
      … to tell your client programs to form the hyperlinks for us (if they are “of the mood”, that is!)

    To improve user experience we use “dynamic” Javascript DOM HTML “style” attribute change means to easier close the “Colour Wheel” helper web application “above the fold” by changing the CSS z-index (Javascript DOM [element].style.zIndex) of elements accordingly, when the user clicks other elements. You can see all this with the first “the changed” link above, where all “glow” CSS styling will also feature prominently.


    Previous relevant Window SessionStorage Client Versus Server Integration Tutorial is shown below.

    Window SessionStorage Client Versus Server Integration Tutorial

    Window SessionStorage Client Versus Server Integration Tutorial

    We hope, when performing a “software integration” task, that the two or more components of that integration work with each other’s talents, rather than a big tussle like reinventing the wheel. This ideal makes the work …

    • sometimes difficult but rewarding because …
    • the differences between two independent software components can be quite large and daunting … and the programmer has to see that …
    • care is applied so as not to wreck previous functionality and integrations in making the current integration work

    … and that is why we’ve made corollaries to “building from scratch” (when planning and design is a huge component) can be a lot simpler than a software integration “renovation”, in the past, here at this blog.

    Our primary integration today is to (software) integrate the great Weather Underground and its great API service for autocomplete name searches for weather (and hurricane) information. Why bother? Well, can you not envisage a user using that Ajax functionality of yesterday’s Window SessionStorage Client Versus Server Ajax Tutorial as a trip planner, perhaps, or as a “checking up on relatives overseas” tool, perhaps? And not all the capital cities are timezone places, and so for some of those we can use Weather integration to still show apt online information when click/touching a Countries Report row. Speaking of this “row”, we make an improvement whereby on a first click of a right hand (Country) row cell, that cell is not initially a contenteditable=”true” one (that may frustrate showing the keyboard on mobile, when most likely it was the row touch intended), but then becomes a contenteditable=”true” cell henceforth.

    As a user experience improvement for “trip planners” perhaps, we allow the user to alphabetically sort the presented select (dropdown) element entries …


    var firstopt='';
    var wasopts='';
    var restopts='';

    function readyitforsort(iselid) {
    var optsare=[];
    var huhisel=document.getElementById(iselid).innerHTML;
    var huhsopts=huhisel.split('</option>');
    for (var ihuh=0; ihuh<huhsopts.length; ihuh++) {
    if (huhsopts[ihuh].trim() != '') {
    if (firstopt == '') {
    firstopt=huhsopts[ihuh] + '</option>';
    } else {
    wasopts+=huhsopts[ihuh].replace('option ','option data-ih="' + (huhsopts[ihuh].split('>')[eval(-1 + huhsopts[ihuh].split('>').length)] + '" ')) + '</option>';
    optsare.push(huhsopts[ihuh].replace('option ','option data-ih="' + (huhsopts[ihuh].split('>')[eval(-1 + huhsopts[ihuh].split('>').length)] + '" ')) + '</option>');
    }
    }
    }
    optsare.sort();
    for (var jhuh=0; jhuh<optsare.length; jhuh++) {
    restopts+=optsare[jhuh];
    }
    }

    … controlled by a new dropdown in the left hand column header cell.

    We also allow the user to move the iframe element with some positioning emoji buttons near the “Close” button one (of yesterday’s work).

    Into the future, too, we’ll have more to say regarding the germination of an idea “to allow a mobile onmouseover simulator (of sorts)” be to allow the user to perform a swipe across an individual HTML element of interest on mobile platforms (ie. harness ontouchmove event) as per (so far) … kicked off by “<body onload=” setTimeout(athn, 5000); “>” …


    var last24='';
    var rectdc;

    function nodivalert() {
    document.getElementById('divalert').style.display='none';
    document.getElementById('divalert').style.zIndex='-456';
    document.getElementById('divalert').style.left=('-' + rectdc.left).replace('px','') + 'px';
    document.getElementById('divalert').style.top=('-' + rectdc.top).replace('px','') + 'px';
    }

    function ourdivalert(inmsg) {
    document.getElementById('divalert').style.position='absolute';
    document.getElementById('divalert').style.left=('' + rectdc.left).replace('px','') + 'px';
    document.getElementById('divalert').style.top='' + eval(-80 + eval(('' + rectdc.top).replace('px',''))) + 'px';
    document.getElementById('divalert').style.backgroundColor='#e0e0e0';
    document.getElementById('divalert').style.display='block';
    document.getElementById('divalert').style.zIndex='456';
    document.getElementById('divalert').style.opacity='0.8';
    document.getElementById('divalert').style.padding='5px 5px 5px 5px';
    document.getElementById('divalert').innerHTML=inmsg + '<br><br><input type=button value=Close onclick=nodivalert();></input>';
    setTimeout(nodivalert,9000);
    }

    function athn() {
    rectdc=document.getElementById('dc').getBoundingClientRect();
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    document.getElementById('dc').ontouchmove=function(event) { if (last24.substring(0,eval(-1 + last24.length)) == event.target.title.substring(0,eval(-1 + event.target.title.length))) { last24=last24; } else { last24=event.target.title; ourdivalert(event.target.title); } }
    } else {
    document.getElementById('dc').onmousemove=function(event) { if (last24.substring(0,eval(-1 + last24.length)) == event.target.title.substring(0,eval(-1 + event.target.title.length))) { last24=last24; } else { last24=event.target.title; ourdivalert(event.target.title); } }
    }
    }

    … working with the new HTML …


    <div id=divalert></div>
    </body>
    </html>

    … to try to allow the “explainer of an element” advantages non-mobile platforms have for hovering over an HTML element with a title attribute filled in.

    And so, yet again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new Weather integration functionality. It caused the changed colour_wheel.html‘s colour wheel (at this live run link) to be affected (by integrations “up”).


    Previous relevant Window SessionStorage Client Versus Server Ajax Tutorial is shown below.

    Window SessionStorage Client Versus Server Ajax Tutorial

    Window SessionStorage Client Versus Server Ajax Tutorial

    We have a few “clientside chestnuts” to use with our current Capital City Find Matching Country Report web application project today, those being …

    • Ajax functionality, kicked off by an “onclick” event set of logic, allowing mobile platforms to also have a look in (the look in that they miss when the event logic is off the “onmouseover” event)
    • iframe and its …
      1. srcdoc attribute (“content” alternative to src “url” attribute) … along with, and crucially needing (because srcdoc ignores its own document.body onload goings on, that we need the “Iframe Client Pre-Emptive” methods below to circumvent) the …
      2. onload event opportunity of an iframe element (we group into “Iframe Client Pre-Emptive” methods, here)

    … adding onto yesterday’s Window SessionStorage Client Versus Server Canvas Tutorial.

    It’s not that involved with the Ajax work today, given that there are no cross-domain issues, though there are cross-protocol (SSL https: versus non-SSL http:) issues to be careful about. Those can be addressed because the web application is recalled to present its “Country Report” and that is the opportunity to check on protocol navigation requirements.

    Along the way, we also make this happen for the user on …

    • click/touching a table row … it sets off new “tr” (table row) element logic calling our (inhouse) Timezone and Wikipedia Place Information helper (HTML) via Ajax (so not leaving the webpage) … and because of place name oddities we allow for …
    • “td” (table cell) element user amendments by setting their contenteditable attributes to “true” (since fixed, but we found the Timezone Europe/Tirane pointing at Tirane in Albania used to be spelt “Tirana”)

    … that latter methodology normally a technique we apply to “div” elements (so, there you are!)

    Also used are “overlay” techniques, two of the “usual suspects” here coming into play, to present to the “Ajax content to srcdoc iframe arrangements” …

    Yet again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new “Ajax” functionality.


    Previous relevant Window SessionStorage Client Versus Server Canvas Tutorial is shown below.

    Window SessionStorage Client Versus Server Canvas Tutorial

    Window SessionStorage Client Versus Server Canvas Tutorial

    Yesterday’s Window SessionStorage Client Versus Server Share Tutorial dealt with ascii text clipboard copy assisted sharing options with our current Capital City Find Matching Country Report web application project. This suited both Email and SMS share options we coded for, but today’s extension of functionality from “ascii text” data to “graphical data” only suits Email sharing. The other caveat with our work is that no serverside (for us, PHP) help is allowed, so no PHP mail here.

    What comes into play with a “graphical data” clientside (only) sharing approach? It will not surprise many readers that, for us, it involves …

    • canvas element … converting HTML table outerHTML “ascii text” data … via …
    • canvas drawing methods “[canvasContext].strokeRect()” and “[canvasContext].strokeText()” via “[cellElement].getBoundingClientRect()” … to convert that canvas element content via …
    • [canvasElement].toDataURL() … to an …
    • img element nested in a div contenteditable=true element … so as to hook in with today’s very useful helper link, thanks … use …

    • function tabletoclipboard(canvas) { // thanks to https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard
      var img = document.createElement('img');
      img.src = canvas.toDataURL();

      var div = document.createElement('div');
      div.contentEditable = true;
      div.appendChild(img);
      document.body.appendChild(div);

      // do copy
      SelectText(div);
      document.execCommand('Copy');
      document.body.removeChild(div);
      }

      function SelectText(element) { // thanks to https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard
      var doc = document;
      if (doc.body.createTextRange) {
      var range = document.body.createTextRange();
      range.moveToElementText(element);
      range.select();
      } else if (window.getSelection) {
      var selection = window.getSelection();
      var range = document.createRange();
      range.selectNodeContents(element);
      selection.removeAllRanges();
      selection.addRange(range);
      }
      }
    • to leave the user’s device’s clipboard containing a useful table (with linework) … ready to …
    • paste into an email body section

    … sharing off to an emailee collaborator.

    Again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new “Email Table” button functionality.


    Previous relevant Window SessionStorage Client Versus Server Share Tutorial is shown below.

    Window SessionStorage Client Versus Server Share Tutorial

    Window SessionStorage Client Versus Server Share Tutorial

    Yesterday’s Window SessionStorage Client Versus Server Tutorial has been amended today for two new sharing and collaboration options, those being …

    • email
    • SMS

    … but you may well be familiar with the restrictions on email and SMS client (program) approaches to this, coming from HTML “a” link “mailto:” and “sms:” href property prefixes respectively. We’re going to need help with the 800 odd character (length) restrictions with the (resultant) web address (bar) URL, but what? How about working off the great advice of this wonderful link, thanks, to copy what we’d have assembled into an ascii text Report into the characters contained by the user’s device’s clipboard?


    function copytoclipboard(str) { // thanks to https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f
    var el = document.createElement('textarea');
    el.value = str;
    el.setAttribute('readonly', '');
    el.style.position = 'absolute';
    el.style.left = '-9999px';
    document.body.appendChild(el);
    el.select();
    document.execCommand('copy');
    document.body.removeChild(el);
    }

    An issue that springs up here using such clipboard ascii text content, whenever you get the Font choice given to you, pick a monospaced Font like Courier New or “Fixed Width”.

    See the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new sharing functionality.


    Previous relevant Window SessionStorage Client Versus Server Tutorial is shown below.

    Window SessionStorage Client Versus Server Tutorial

    Window SessionStorage Client Versus Server Tutorial

    Sometimes it’s the case at this blog that we’d like to introduce a new topic, but do not do so, because we cannot show any real world (or real application) use of that concept. So it has been, up until now, with the concept of (web browser) window (object) sessionStorage property. But yesterday’s Window LocalStorage Client Versus Server Primer Tutorial represented an opportunity akin to when Haley’s Comet gets at its closest to the Earth … while you see a chance, take it … chance because of that nuance whereby we were not trying to store data for any other purpose than passing data onto …

    1. a known entity … ie. same web application … at …
    2. a known time … ie. immediately

    … two conditions that make the code design “marginally” more ideal for the window object property concept of sessionStorage rather than localStorage, in that any …


    localStorage.removeItem([knownLocalStorageName]);

    … becomes superfluous as with sessionStorage data will disappear between web browser sessions, anyway.

    We offer this new concept as a non-default option of a select (dropdown) element replacement to the h1 element hardcoding “localStorage” with the changed wls_vs_php.htm Capital City Find Matching Country Report live run. The other nuance of difference with sessionStorage usage is that in the document.body onload event logic, we may as well (as part of other changes) pre-emptively look for, and if there, respond to, any found sessionStorage data points, even without the user having flagged it specifically


    var datamode='localStorage';

    function checkforreport() {
    var divcont='';
    var dcaps, dctys, idis;
    if (getcapitals == 'localStorage') {
    if (window.localStorage) {
    getcapitals=decodeURIComponent(localStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
    localStorage.removeItem('wls_vs_php_capitals');
    } else {
    getcapitals='';
    }
    } else if (getcapitals == 'sessionStorage') {
    document.getElementById('smode').value=getcapitals;
    datamode=getcapitals;
    if (window.sessionStorage) {
    getcapitals=decodeURIComponent(sessionStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
    } else {
    getcapitals='';
    }
    }
    else if (getcapitals == '' && window.sessionStorage) {
    getcapitals=decodeURIComponent(('' + sessionStorage.getItem('wls_vs_php_capitals')).replace(/^null$/g,'')).replace(/\+/g,' ');
    if (getcapitals != '') {
    document.getElementById('smode').value='sessionStorage';
    datamode='sessionStorage';
    }
    }

    if (getcountries == 'localStorage') {
    if (window.localStorage) {
    getcountries=decodeURIComponent(localStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
    if (getcapitals.replace('localStorage','') != '' && getcountries.replace('localStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
    localStorage.removeItem('wls_vs_php_countries');
    } else {
    getcountries='';
    }
    } else if (getcountries == 'sessionStorage') {
    if (window.sessionStorage) {
    getcountries=decodeURIComponent(sessionStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
    if (getcapitals.replace('sessionStorage','') != '' && getcountries.replace('sessionStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
    } else {
    getcountries='';
    }
    }
    else if (getcountries == '' && document.getElementById('smode').value == 'sessionStorage' && window.sessionStorage) {
    getcountries=decodeURIComponent(('' + sessionStorage.getItem('wls_vs_php_countries')).replace(/^null$/g,'')).replace(/\+/g,' ');
    if (getcountries != '') {
    document.getElementById('smode').value='sessionStorage';
    datamode='sessionStorage';
    }
    }

    if (getcapitals != '' && getcountries != '') {
    divcont='<table border=5 style="width:95%;vertical-align:top;background-color:white;"><tr style=background-color:#f0f0f0;"><th>Capital</th><th>Country</th></tr></table>';
    dcaps=getcapitals.split('|');
    dctys=getcountries.split('|');
    for (idis=0; idis<dcaps.length; idis++) {
    divcont=divcont.replace('</table>', '<tr><td>' + dcaps[idis] + '</td><td>' + dctys[idis] + '</td></tr></table>');
    }
    document.getElementById('dreport').innerHTML=divcont;
    }
    document.getElementById('smode').value=datamode;
    }

    Which beggars the question “What are the differences between sessionStorage and localStorage?” A quick reading might surmise that “the latter has an expiration date”. We leave you with an open ended Google search so that you may extend your readings on this.


    Previous relevant Window LocalStorage Client Versus Server Primer Tutorial is shown below.

    Window LocalStorage Client Versus Server Primer Tutorial

    Window LocalStorage Client Versus Server Primer Tutorial

    Even though we rave on a lot about serverside PHP and its $_POST method=POST (versus HTML/Javascript recipient via ? and & argument $_GET method=GET scenario) data length advantages as the recipient of an HTML form method=POST set of data that could be sizeable, we’ve just realized that there is a client Javascript and window.localStorage methodology that may help alleviate the need to involve PHP (and any other serverside intervention) on occasions.

    Hint: Yes, we’ve raved on about this too?! Does the blog posting title give it away? Okay, yes, it should read “localStorage”, but thought we’d gone past such juvenile finickiness since the Whac-A-Mole controversy of 1st December 2019 (or even The Great Tea Trolley Disaster of ’67, we daresay).

    It can even use a “self-destruct” approach to the use of this “localStorage” on having used it because …

    • the web application knows who is using it (localStorage) … and on having accessed and read it …
    • the web application knows it (localStorage) is of no use to any other user (in this web application’s case, at least)

    … which is very pleasing for a Land Surveyor who likes to leave cow paddocks as they’ve seen them so to speak. Except it’s like having a ten tonne truck worth of data access in amongst the cow pats when having access to “localStorage” (or PHP), rather than a little piddle of calf wee (wee Metcalfes know a thing or two about these things!) data access of ? and & HTML/Javascript URL arguments (or even if we were to use HTTP Cookies).

    It’s not as if we all have access to serverside language usage, though we do, because we really like PHP and MAMP and Apache/PHP/MySql web servers (and have arranged our development environment accordingly), but what if you are starting out in web development, and still want to allow for sizeable chunks of data with your web applications? Huh? Huh?! See the possibilities? Try our proof of concept wls_vs_php.html Capital City Find Matching Country Report live run, and highlight a whole swathe of (multiple mode) dropdown option Capital Cities holding down the shift key before pressing the yellow “Report” button. If the URL ends up as …

    https://rjmprogramming.com.au/HTMLCSS/wls_vs_php.html?capitals=localStorage&countries=localStorage

    that’s because the web application’s …


    function analyze() {
    var purl=document.URL.split('#')[0].split('?')[0] + '?capitals=' + encodeURIComponent(document.getElementById('capitals').value) + '&countries=' + encodeURIComponent(document.getElementById('countries').value);
    if (purl.length > 800) {
    if (phpexists) {
    document.getElementById('myform').method='POST';
    document.getElementById('myform').action='./wls_vs_php.php';
    } else if (window.localStorage) {
    localStorage.setItem('wls_vs_php_countries', encodeURIComponent(document.getElementById('countries').value));
    localStorage.setItem('wls_vs_php_capitals', encodeURIComponent(document.getElementById('capitals').value));
    document.getElementById('capitals').value='localStorage';
    document.getElementById('countries').value='localStorage';
    location.href=document.URL.split('#')[0].split('?')[0] + '?capitals=' + encodeURIComponent(document.getElementById('capitals').value) + '&countries=' + encodeURIComponent(document.getElementById('countries').value);

    return false;
    }
    }
    return true;
    }

    … HTML form onsubmit event logic …

    1. discovered no PHP web application existant (via Client Pre-emptive Iframe techniques) … and …
    2. discovered (in a sanity check feeling way) that to go down the proposed HTML form method=GET approach was risking a …

      HTTP 414 "Request URI too long"

      … web browser error … and that …
    3. localStorage was a known web browser piece of functionality
    4. … and so as per our localStorage logic we …

    5. back out of the default HTML form method=GET navigation setup of the web application in favour of …
      • storing that data into localStorage
      • substituting into the URL ? and & arguments the hardcoding “localStorage” (and in so doing, getting back under the HTTP 414 “Request URI too long” limitation, piecing together (what amounts to) …
        location.href=document.URL.split(‘#’)[0].split(‘?’)[0] + ‘?capitals=localStorage&countries=localStorage’;)
        … that on a recall to this same web application a …
      • document.body onload event piece of Javascript logic checks the localStorage for its incoming Capital City Country Report data, as per …

        var phpexists=false;
        var getcapitals=location.search.split('capitals=')[1] ? decodeURIComponent(location.search.split('capitals=')[1].split('&')[0]).replace(/\+/g,' ') : '';
        var getcountries=location.search.split('countries=')[1] ? decodeURIComponent(location.search.split('countries=')[1].split('&')[0]).replace(/\+/g,' ') : '';

        function checkforreport() {
        var divcont='';
        var dcaps, dctys, idis;
        if (getcapitals == 'localStorage') {
        if (window.localStorage) {
        getcapitals=decodeURIComponent(localStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
        localStorage.removeItem('wls_vs_php_capitals');
        } else {
        getcapitals='';
        }
        }
        if (getcountries == 'localStorage') {
        if (window.localStorage) {
        getcountries=decodeURIComponent(localStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
        if (getcapitals.replace('localStorage','') != '' && getcountries.replace('localStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
        localStorage.removeItem('wls_vs_php_countries');
        } else {
        getcountries='';
        }
        }

        if (getcapitals != '' && getcountries != '') {
        divcont='<table border=5 style="width:95%;vertical-align:top;background-color:white;"><tr style=background-color:#f0f0f0;"><th>Capital</th><th>Country</th></tr></table>';
        dcaps=getcapitals.split('|');
        dctys=getcountries.split('|');
        for (idis=0; idis<dcaps.length; idis++) {
        divcont=divcont.replace('</table>', '<tr><td>' + dcaps[idis] + '</td><td>' + dctys[idis] + '</td></tr></table>');
        }
        document.getElementById('dreport').innerHTML=divcont;
        }
        }

        … the localStorage.removeItem() representing that “self-destruct” nuance we were talking about before

    We may well use this methodology in future projects, and hope it has been of some little interest to you as well?!

    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.


    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.


    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 Ajax, eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Select Multiple Webpage Palette Speech Bubble YouTube Placement Tutorial

Select Multiple Webpage Palette Speech Bubble YouTube Placement Tutorial

Select Multiple Webpage Palette Speech Bubble YouTube Placement Tutorial

It’s …

Day 3 Nuance 1

… today, and you’d expect that scoreline given home ground advantage … onto yesterday’s Select Multiple Webpage Palette Speech Bubble YouTube Tutorial where the progress is …

  • for mobile platforms, where our 11 character links led us to a new window scenario … so yesterday … today …
  • we keep the YouTube video to the same webpage, over to the right

… but still, alas, several tap/clicks needed to get to the video playing.

A lot of the time of “Nuance 1” occurred using a lot of …


event.stopPropagation();

… calling for onclick and onmousedown and ontouchdown event calls in amongst the new tabularly organized inline HTML


function maybeemoji(insvg) {
// blah blah blah
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
if (document.getElementById('dcont').innerHTML.indexOf('<table') != -1) {
return insvg.replace('></text>', '>' + newoutthing + '</text>').replace(" data-emoji=''", " data-emoji='" + newoutthing + "'").replace(' data-emoji=""', ' data-emoji="' + newoutthing + '"');
}
thehoster='tdleft';
return '<table><tr><td id=tdleft style=vertical-align:top;>' + insvg.replace('></text>', '>' + newoutthing + '</text>').replace(" data-emoji=''", " data-emoji='" + newoutthing + "'").replace(' data-emoji=""', ' data-emoji="' + newoutthing + '"') + '</td><td id=tdnothing style=vertical-align:top; onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="event.stopPropagation();"><a onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="notallowed(); event.stopPropagation();" href=#tdleft title="Speech Bubble">💬</a><br><a onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="notallowed(); event.stopPropagation();" href=#tdnothing title="YouTube">📹</a></td><td id=tdright style=vertical-align:top; onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="event.stopPropagation();"><iframe style=display:none;width:900px;height:800px; id=rightif name=rightif src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=&theaNOid=&theifrNOameid=&thebuttoNOnwording=&justaJUNKudio=&youtube_duration=22223.000&email=&emoji=on&c0=on&i0=0&j0=22223&i1=&j1=&i2=&j2=&i3=&j3=&i4=&j4=&i5=&j5=&i6=&j6=&i7=&j7=&i8=&j8=&i9=&j9=&i10=&j10=&i11=&j11=&i12=&j12=&i13=&j13=&i14=&j14=&i15=&j15=&i16=&j16=&i17=&j17=&i18=&j18=&i19=&j19=&i20=&j20=&i21=&j21=&i22=&j22=&i23=&j23=&i24=&j24=&i25=&j25=&i26=&j26=&i27=&j27=&i28=&j28=&i29=&j29="></iframe></td><td id=tdmiddle style=vertical-align:top; onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="notallowed(); event.stopPropagation();"><a onclick="event.stopPropagation();" href=#tdleft title="Speech Bubble">💬</a><br><a onmousedown="notallowed(); event.stopPropagation();" ontouchdown="notallowed(); event.stopPropagation();" onclick="notallowed(); event.stopPropagation();" href=#tdnothing title="YouTube">📹</a></td></tr></table>';
}
// blah blah blah non-mobile returns
}

… describing the HTML elements added for mobile usage, here. Even then, annoyingly, if you tapped on one of these, the Javascript would too often call function addcontents in a way we thought was aggravating, and so we resorted to a global variable usage and started doing as below …


var allowed=true;

function addcontents(inboc) {
if (!allowed) {
allowed=true;
return false;
}

var nboc='', seventeen="17", zero=0, numlines=1, one=1, grest='', ghuh='', wasfound=false, jnew=0;
// blah blah blah open textarea popup window blah blah blah
}

function notallowed() {
allowed=false;
setTimeout(function(){ allowed=true; }, 1000);
}

Again, what changed? Well …


Previous relevant Select Multiple Webpage Palette Speech Bubble YouTube Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble YouTube Tutorial

Select Multiple Webpage Palette Speech Bubble YouTube Tutorial

Well, onto yesterday’s SVG Tspan Element Primer Tutorial our “two day” job is “two days” of sorts. Definitely for non-mobile, deploying the “inline audio stream of YouTube video play” concept we wanted, but for mobile, let me “count the ways” …

  1. to get any functionality down to “one tap/click to play” … well …
  2. we tried for mobile, and haven’t given up, but the complexity of “overlay” related z-index and “where to place iframe element” issues exploded my tiny little brain … and so …
  3. for mobile we’ve “parked” the ideal solution … in favour of, for now …
  4. the mobile “two day solution” that, like for non-mobile, underlines those 11 character YouTube references as links that can navigate interested users to a new tab/window YouTube window to play the “whole shebang” (and … sigh … needing that extra tap/click) … leaving …
  5. Days 3 (and on) to nuance

Another project where the last 10% nuances is probably going to take more time than the rest! Anyway, we’ll see how this “mini project” develops.

What changed? Well …

  • the SVG tspan 11 letter word YouTube reference Speech Bubble changed select_palette.html web application … now helped out by …
  • now SVG tspan savvy external Javascript ytaudioonly.js assisting YouTube Audio Stream of Video Playsspecifically

    // blah blah blah
    var thespansare=[];

    function ihun(ao) {
    var aih=ao.innerText;
    if (aih.trim() != '') {
    var newihis='';
    for (var iaih=0; iaih<aih.length; iaih++) {
    newihis+='_';
    }
    ao.innerHTML=newihis;
    }
    }


    function audioytlook() { // first happens around document.body onload event
    // blah blah blah
    var taop='', ttdom='', ttid=' id=newspan8', ziif='', yiif='';
    // blah blah blah
    thespansare=document.getElementsByTagName('tspan');
    if (eval('' + thespansare.length) > 0) {
    for (jits=0; jits<thespansare.length; jits++) {
    //alert(thespansare[jits].outerHTML);
    if ( ('' + thespansare[jits].outerHTML).indexOf('tubeaudioyou') != -1 && ('' + thespansare[jits].outerHTML).indexOf(' data-mentioned=') == -1) {
    //alert('HERE');
    jitrect=thespansare[jits].getBoundingClientRect();
    if (document.getElementById('doverlay')) {
    if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && document.URL.indexOf('.9JUNK5.247/') == -1) {
    //alert('why');
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    ttid+='8';
    } else {
    ziif=' style="z-index:50;" ';
    yiif=' event.stopPropagation(); ';
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); "; // document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    //document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.4;z-index:176;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a></span>';
    //document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    //alert('<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">___________</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>');
    document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">___________</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    ttid+='8';
    }
    } else {
    if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && document.URL.indexOf('.9JUNK5.247/') == -1) {
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    document.body.innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    ttid+='8';
    } else {
    ziif=' style="z-index:150;" ';
    yiif=' event.stopPropagation(); ';
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    document.body.innerHTML+='<span' + ttid + ' style="opacity:0.4;z-index:176;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">___________</a></span>';
    ttid+='8';
    }
    }
    thespansare[jits].setAttribute('data-mentioned', 'y');
    }
    }
    thespansare=[];
    }

    var audioonlyas=document.getElementsByTagName('a');
    // blah blah blah
    }

    // blah blah blah

    … slotting in tspan logic ahead of the a link analysis


Previous relevant SVG Tspan Element Primer Tutorial is shown below.

SVG Tspan Element Primer Tutorial

SVG Tspan Element Primer Tutorial

We’re starting a planned “mini project” to improve Select Multiple Webpage Palette Speech Bubble Swipe Tutorial and what we find important …

  1. regarding improvements to existant functionality it is most important to not interfere with any current functionality … and then …
  2. implement new functionalities off this platform

… and with our “mini project” of embellishing 11 letter words in the Speech Bubbles of our Select Multiple Webpage Palette Speech Bubble web application of recent times, we have a natural compartmentalization playing out mimicking those ideas above, that goes …

  1. Day 1 – work with the data that is the HTML (and SVG) of Speech Bubbles where they look and behave as ever, but 11 letter words get nested into SVG tspan elements
  2. Day 2 – embellish the web application via those SVG tspan elements

It’s our first go using SVG tspan elements as a “forward thinking” tool, and it helped us thinking on this regarding the corrollaries to HTML span element. What initially concerned us using SVG tspan was whether we’d have to specify x and y attributes, but, as it panned out, no, the SVG text element nesting the tspan takes care of that, so, “top supportive” we’d say, and a lot like how we think of the HTML span element working, and helping out, enormously!

Into “Day 2” though, and we’ll be wanting to do Javascript DOM things in the “overlay” line of thinking. So part of a “Day 1” paradigm, you will better leave that “Day 1” proving the work of “Day 2” is possible, and this was achieved via


function detecttspan() {
var tsrect=null;
var tss=document.getElementsByTagName('tspan');
for (var itss=0; itss<tss.length; itss++) {
tsrect=tss[itss].getBoundingClientRect();
alert('' + tss[itss].outerHTML + ' left:' + tsrect.left + ' top:' + tsrect.top);
}
}

… with the good news we started “Day 1” not being sure of “passed the test”, as you can see from today’s tutorial picture, and …

… this one illustrating work in the SVG tspan 11 letter word Speech Bubble changed select_palette.html web application.

Why 11? Tune in tomorrow.


Previous relevant Select Multiple Webpage Palette Speech Bubble Swipe Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Swipe Tutorial

Select Multiple Webpage Palette Speech Bubble Swipe Tutorial

Today’s tutorial is an amalgam of …

  1. concepts off Apple iOS Control Centre Tutorial … and …
  2. continuing on with the functionality of the recent Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial‘s External Javascript YouTube Audio Stream of Video web application ideas

… which, to us, is in the category of …

  • optional
  • experimental
  • quirky … and yet …
  • something we may well turn to for future endeavours … and so, worth it

… so, though there is opposition you can’t say I didn’t do it my way … which means, correct me if I’m wrong here, that means “I did it my way”that right … team?!.

We’re adding …

  • web application “swipe down and left from top right” … email after entering data … and …
  • web application “swipe up from bottom” … SMS after entering data

… user interaction “shortcuts” into the mix, via …


var firstx=null, firsty=null, pos3=-3, pos4=-3, nextx=null, nexty=null, slowitdown=false, isok=true, oktoemail=false, oktosms=false;
var wow=-1, woh=-1, wiw=-1, wih=-1;
var firstone=true;


function controlisok() {
isok=true;
}

function swipecheck(ev) {
if (!window.opener && isok) {
if (ev.touches) {
if (ev.touches[0].pageX) {
pos3 = ev.touches[0].pageX;
pos4 = ev.touches[0].pageY;
} else {
pos3 = ev.touches[0].clientX;
pos4 = ev.touches[0].clientY;
}
console.log('pos3 = ' + pos3 + ',pos4 = ' + pos4);
} else if (ev.clientX || ev.clientY) {
pos3 = ev.clientX;
pos4 = ev.clientY;
console.log('pos3 = ' + pos3 + ' ,pos4 = ' + pos4);
} else {
pos3 = ev.pageX;
pos4 = ev.pageY;
console.log('pos3 = ' + pos3 + ', pos4 = ' + pos4);
}


if (pos3 >= 0 && pos4 >= 0) {
if (firstx == null) {
firstx=pos3;
firsty=pos4;
slowitdown=true;
isok=false;
setTimeout(controlisok, 400);
} else if (pos3 != firstx || pos4 != firsty) {
nextx=pos3;
nexty=pos4;
// Swipe down left from top right
if (nextx < firstx && nexty > firsty && pos3 > eval(document.documentElement.clientWidth / 2) && pos4 < eval(document.documentElement.clientHeight / 2)) {
if (firstone) {
if (eval(firstx - nextx) > 5 && eval(nexty - firsty) && eval(window.innerWidth - firstx) < 90 && eval(firsty) < 90) {
firstone=false;
//alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
shapetodoemail(); // alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
}
}
// ... else swipe up from bottom
} else if (nexty < firsty && firsty > eval(document.documentElement.clientHeight / 2) && pos4 > eval(document.documentElement.clientHeight / 2)) {
if (firstone) {
if (eval(firstx - nextx) < 5 && eval(nexty - firsty) < 5 && eval(firsty) > eval(document.documentElement.clientHeight / 2)) {
firstone=false;
//alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
shapetodosms(); // alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
}
}
} else if (pos3 <= eval(document.documentElement.clientWidth / 2) || pos4 >= eval(document.documentElement.clientHeight / 2)) {
firstx=null;
firsty=null;
nextx=null;
nexty=null;
}
}
}
}
}

function gettodoemail() {
return oktoemail;
}

function settodoemail(towhat) {
oktoemail=towhat;
}

function shapetodoemail() {
oktoemail=true;
setTimeout(trytodoemail, 5000);
}

function trytodoemail() {
if (oktoemail) {
doemail();
}
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function gettodosms() {
return oktosms;
}

function settodosms(towhat) {
oktosms=towhat;
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function trytodosms() {
if (oktosms) {
dosms();
}
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function gwow() {
return wow;
}

function gwiw() {
return wiw;
}

function gwoh() {
return woh;
}

function gwih() {
return wih;
}

function getwow() {
if (window.opener) {
return window.opener.gwow();
} else {
return wow;
}
}

function getwoh() {
if (window.opener) {
return window.opener.gwoh();
} else {
return woh;
}
}

function getwiw() {
if (window.opener) {
return window.opener.gwiw();
} else {
return wiw;
}
}

function getwih() {
if (window.opener) {
return window.opener.gwih();
} else {
return wih;
}
}

function atstart() {
document.body.style.zoom = 1.0

var scale = 'scale(1)';
document.body.style.webkitTransform = scale; // Chrome, Opera, Safari
document.body.style.msTransform = scale; // IE 9
document.body.style.transform = scale; // General
wow=eval(window.outerWidth);
woh=eval(window.outerHeight);
wiw=eval(window.innerWidth);
wih=eval(window.innerHeight);
//alert('' + wih + ' vs ' + woh);
if (window.opener) {
firstone=false;
setTimeout(function(){
oktoemail=window.opener.gettodoemail();
oktosms=window.opener.gettodosms();
window.opener.settodoemail(false);
window.opener.settodosms(false);
}, 2000);
}
}

if (!window.screenLeft) {
window.screenLeft = window.screenX;
window.screenTop = window.screenY;
}

called into play via …


<body onload="atstart(); startsi(); dotdotdotten();" ontouchmove="swipecheck(event);" onmousemove="swipecheck(event);">

… in the changed select_palette.html web application.


Previous relevant Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial

The recent Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial‘s …

  • privacy for Group Talk “public” Bulletin Board functionalities …
  • involved logic for the two scenarios …
    1. data-applyprivacy=Y … via two prefixing spaces entered by originator of Group … completely hides relevant Group Talk Bulletin Board data from viewers outside that Group Talk
    2. data-applyprivacy=y … via one prefixing space entered by originator of Group … hides contact parts of Group Talk Bulletin Board data from viewers outside that Group Talk

    … but we had not “nuanced” the functionality for that second suboption on that first subpass

… and that is the work discussed today, a nuance that amounts to …

Allow non-group Bulletin Board readers see what we say but given cryptic username choices will not know how to contact that Group

That work took place in the PHP component of our Select Multiple Webpage Palette Speech Bubble web application as per

<?php

if (!isset($_GET['owner']) && isset($_GET['me']) && !isset($_GET['contact'])) {
$findings=explode(',', str_replace(';',',',str_replace('+',' ',urldecode($_GET['me']))));
} else if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
$aprivone=' data-applyprivacy="Y"';
$aprivtwo=' data-applyprivacy="y"';
}


if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
$prevcont="";
for ($i=(0 + 0); $i<sizeof($lines); $i++) {
$thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
if (strpos($thisline, $curgmt) !== false && strpos(str_replace("'",'"',$thisline), $aprivone) === false) { // && strpos(str_replace("'",'"',$thisline), $aprivtwo) === false) {
if (strpos(str_replace("'",'"',$thisline), $aprivtwo) !== false) {
$thatline=$thisline;
if (strpos($thatline, 'contact="') !== false && strpos(str_replace('contact=""',"contact=''",$thatline), 'contact="') !== false) {
while (strpos(str_replace('contact=""',"contact=''",$thatline), 'contact="') !== false) {
$thingtochange=explode('"', explode('contact="', str_replace('contact=""',"contact=''",$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
if (strpos($thatline, "contact='") !== false && strpos(str_replace("contact=''",'contact=""',$thatline), "contact='") !== false) {
while (strpos(str_replace("contact=''",'contact=""',$thatline), "contact='") !== false) {
$thingtochange=explode("'", explode("contact='", str_replace("contact=''",'contact=""',$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
if (strpos(str_replace("[]","",$thatline), "[") !== false && strpos(str_replace("[]","",$thatline), "]") !== false) {
while (strpos(str_replace("[]","",$thatline), "[") !== false && strpos(str_replace("[]","",$thatline), "]") !== false) {
$thingtochange=explode("]", explode("[", str_replace("[]","",$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
$prevcont.=$thatline;
} else {

$prevcont.=$thisline;
}
}
}
$vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
exit;
}

?>

… in the changed select_palette.php “eighth draft” PHP.


Previous relevant Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial

Meanwhile, back at some other ranch … somewhere … we’re some of the way down the line, with our recent …

  • Select Multiple Webpage Palette web application …
  • Bulletin Board subset of functionality, towards with it’s …
  • Group Talk (comma separated list of username/contacts) abilities … now offer …
  • Bulletin Board privacy

… as people in a Group Talk may appreciate. In other words, your generic Bulletin Board viewers would not see your Group Talk setup communications should the originator of any Group Talk now, either at …

  • best, as a To: + spaces appendage to a textarea line record (delimited by line feed) … ahead of a way with …
  • spaces prefixing to the prompt widow off right click or gesture events … starting the ball rolling …
  • populating a new data-applyprivacy global data attribute into the SVG

… allowing this new privacy functionality to work.

Again, we’ll need more than the work today to bed this in, but we now do not think there are any impassable concepts to its implementation.

And so, onto the recent Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial‘s work we have the changed select_palette.html web application helped out by the changed select_palette.php “seventh draft” PHP we have made a start making this “privacy dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial

Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial

Yesterday’s Select Multiple Webpage Palette Speech Bubble Emoji Tutorial warned you today …

we may have nuances yet to come

… and allowing for emojis within a Group Talk user’s username (via control-command-space for macOS or Mac OS X, logo key + . (period) for Windows, control+space for iOS, top left + for Android keyboard) be an identifier on their Speech Bubbles … well, it leaves us speechless with nuance!

Yesterday we were attempting to do this but had more success, today, with


/**
* Convert a string to HTML entities ... Thanks to https://zditect.com/code/javascript/easy-solution-to-encode-html-entities-in-javascript.html
*/
String.prototype.toHtmlEntities = function() {
return this.replace(/./gm, function(s) {
return (s.match(/[a-z0-9" . "\\" . "s]+/i)) ? s : '&#' + s.charCodeAt(0) + ';';
});
};


function maybeemoji(insvg) {
var outthing='', newoutthing='', jb=0;
var outsvg=insvg;
//alert('0:' + outsvg);
if (outsvg.indexOf(' data-otherc') != -1 && outsvg.indexOf(' data-ip') != -1) {
outsvg=outsvg.replace(outsvg.split(' data-otherc')[1].split(' data-ip')[0],'').split('97%')[0];
}

//alert(outsvg);

outhtmlentities='';
nonouthtmlentities='';

var nonencodeds=outsvg.split('&#');
for (jb=1; jb<nonencodeds.length; jb++) {
if (eval('' + nonencodeds[jb].split(';')[0]) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
newoutthing+=String.fromCodePoint(eval('' + nonencodeds[jb].split(';')[0]));
if (nonencodeds[jb] != (nonencodeds[jb].split(';')[0] + ';')) {
nonouthtmlentities=' ';
}
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
}
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

if (outhtmlentities == '') {
if (outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' ').indexOf('&#') >= 0) {
//alert('2987:' + outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' '));
nonencodeds=outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' ').split('&#')
for (jb=1; jb<nonencodeds.length; jb++) {
if (eval('' + nonencodeds[jb].split(';')[0]) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
newoutthing+=String.fromCodePoint(eval('' + nonencodeds[jb].split(';')[0]));
if (nonencodeds[jb] != (nonencodeds[jb].split(';')[0] + ';')) {
nonouthtmlentities=' ';
}
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
}
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

}
}


if (outhtmlentities == '') {
//alert(987);
var encodedStr=outsvg.replace(/[\u00A0-\u9999<>\&]/g, function(i) {
if (eval('' + i.charCodeAt(0)) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+i.charCodeAt(0)+';';
newoutthing+=String.fromCodePoint(eval('' + i.charCodeAt(0)));
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+i.charCodeAt(0)+';';
}
return '&#'+i.charCodeAt(0)+';';
});
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

if (outhtmlentities == '') {
if (document.getElementById('myip').value != '' && insvg.replace(/\'/g,'"').indexOf(' data-owner="') != -1 && insvg.replace(/\'/g,'"').indexOf(' data-contact="') != -1) {
var basisstr=insvg.replace(/\'/g,'"').split(' data-owner="')[1].split('"')[0] + insvg.replace(/\'/g,'"').split(' data-contact="')[1].split('"')[0] + document.getElementById('myip').value;
var bcnt=999, koffset=0;
for (var ib=0; ib<basisstr.length; ib++) {
//if (bcnt == 999) { bcnt=129293; }
//bcnt+=eval('' + basisstr.substring(ib).charCodeAt(0));
koffset+=eval('' + basisstr.substring(ib).charCodeAt(0));
}
if (koffset > 0) {
bcnt+=Math.round(eval(eval('' + koffset) / 10));
var itries=0;
if (4 == 5) { bcnt=129293; }
while (supports_emoji(String.fromCodePoint(eval('' + bcnt)))) {
bcnt++;
itries++;
if (itries >= 230) { bcnt=129293; }
}
//alert(bcnt);
outthing='&#' + bcnt + ';';
newoutthing+=String.fromCodePoint(eval('' + bcnt));
}
}
}
return insvg.replace('></text>', '>' + newoutthing + '</text>').replace(" data-emoji=''", " data-emoji='" + newoutthing + "'").replace(' data-emoji=""', ' data-emoji="' + newoutthing + '"');
}

… in the changed select_palette.html web application helped out by the changed select_palette.php “sixth draft” PHP we have made a start making this “emoji dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble Emoji Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Emoji Tutorial

Select Multiple Webpage Palette Speech Bubble Emoji Tutorial

The reason for today’s efforts with our latest web application have a similar theme to yesterday’s Select Multiple Webpage Palette Speech Bubble IP Address Tutorial‘s efforts, namely …

help differentiate Speech Bubbles of different users in a Group Talk arrangement with our public Bulletin Board functionality

Today’s research into displaying emoji text at the pointy corner of the Speech Bubble hopes to help out here, and though we may have nuances yet to come, we can say with the changed select_palette.html web application helped out by the changed select_palette.php “fifth draft” PHP we have made a start making this “emoji dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble IP Address Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble IP Address Tutorial

Select Multiple Webpage Palette Speech Bubble IP Address Tutorial

To further differentiate Group Talk users accessing the public Bulletin Board of our web application talked about in Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

  • we need to consider user IP addresses, as Wikipedia describes …

    An Internet Protocol address (IP address) is a numerical label such as 192.0.2.1 that is assigned to a device connected to a computer network that uses the Internet Protocol for communication.[1][2] IP addresses serve two main functions: network interface identification, and location addressing.

    Some readers may have noted for a couple of days now, our newly introduced PHP has been assisting the calling HTML, and itself, by remembering the user’s IP address. Yesterday, it was to help colour code Speech Bubbles, and today, it helps in amongst …

    • username … and …
    • contact … set lists … with …
    • IP address

    … to differentiate email and SMS invitation origin calls of our web application, as to who that user has been described as by the originator of the Group Talk settings with the changed select_palette.html web application helped out by the changed select_palette.php “fourth draft” PHP.


    Previous relevant Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial is shown below.

    Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

    Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

    The concept of Group Talk started with yesterday’s Select Multiple Webpage Palette Speech Bubble Invitations Tutorial. It made us think that we should start thinking about the differentiation of voices amongst the Speech Bubbles of the public Bulletin Board we’re supporting with the associated web application and its user mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic talents.

    We decided that one way could be to …

    • Colour Code the background colour of the Speech Bubbles via the user IP address …
      <?php

      $gbcol="0,0,255";

      function server_remote_addr() {
      global $gbcol;
      $rma = $_SERVER['REMOTE_ADDR'];
      $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
      $uas=explode('.', str_replace('::1','65.254.95.247',$rma)); // 65.254.93.32

      if (sizeof($uas) >= 3) {
      $gbcol='' . ($uas[0] % 256);
      $gbcol.=',' . ($uas[1] % 256);
      $gbcol.=',' . (($uas[2] + $uas[(-1 + sizeof($uas))]) % 256);
      }

      // you can add different browsers with the same way ..
      if(preg_match('/(chromium)[ \/]([\w.]+)/', $ua))
      $rma = '000000'.$rma;
      elseif(preg_match('/(chrome)[ \/]([\w.]+)/', $ua))
      $rma = '00000'.$rma;
      elseif(preg_match('/(safari)[ \/]([\w.]+)/', $ua))
      $rma = '0000'.$rma;
      elseif(preg_match('/(opera)[ \/]([\w.]+)/', $ua))
      $rma = '000'.$rma;
      elseif(preg_match('/(msie)[ \/]([\w.]+)/', $ua))
      $rma = '00'.$rma;
      elseif(preg_match('/(mozilla)[ \/]([\w.]+)/', $ua))
      $rma = '0'.$rma;
      return str_replace(":", "_", $rma);
      }

      server_remote_addr();

      ?>
    • when a Group Talk invitation is sent out do not have the sender username and/or contact as the recipient username and/or contact

    … moving further along with the changed select_palette.html web application helped out by the changed select_palette.php “third draft” PHP.


    Previous relevant Select Multiple Webpage Palette Speech Bubble Invitations Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Invitations Tutorial

    Select Multiple Webpage Palette Speech Bubble Invitations Tutorial

    Yesterday’s Select Multiple Webpage Palette Speech Bubble PHP Tutorial‘s …

    • PHP embellishment of …
    • the day before’s SVG data enhancemants … today improves yesterday’s …
    • public Bulletin Board via user mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logics … today, adding …
    • optional invitation communication email and/or SMS logics via Group Talk set comma separated optional user username/contact entered data set lists helping with Group Talk filtering means of filtering the Speech Bubble data

    … with the changed select_palette.html web application helped out by the changed select_palette.php “second draft” PHP.


    Previous relevant Select Multiple Webpage Palette Speech Bubble PHP Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble PHP Tutorial

    Select Multiple Webpage Palette Speech Bubble PHP Tutorial

    Yesterday’s Select Multiple Webpage Palette Speech Bubble Data Tutorial‘s …

    • data … begets …
    • PHP
    … around here a lot, as PHP is our domain’s “first call” serverside language.

    Add to that that “yesterday’s tomorrow is today” we’re supposed to be finished with our “short two day mini project sojourn”, and in a crude way we have, but we want a third day to add nuance to the arrangements with data filtering and more sophistication regarding collection, within the approach of our new …

    Bulletin Board of Speech Bubbles

    … that becomes a …

    • shareable
    • public (on this second day, a bit too public)
    • reverse chronological
    • speech bubble

    … resource, if the user avails themselves of the mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic smarts with the changed select_palette.html web application, now helped out by select_palette.php “first draft” PHP …


    <?php
    // select_palette.php
    // RJM Programming
    // May, 2025

    $prevcont="";
    $curcont="";
    $curgmt=gmdate("Ymd");
    $newlines=[];

    if (isset($_POST['indata'])) {
    $ind=str_replace('+',' ',urldecode($_POST['indata']));
    $lines=explode('<svg name="', $ind);
    if (!file_exists('/tmp/select_palette.htm')) {
    file_put_contents('/tmp/select_palette.htm', '');
    } else {
    $prevcont=file_get_contents('/tmp/select_palette.htm');
    if (strpos($prevcont, '<svg name="' . $curgmt) === false) {
    file_put_contents('/tmp/select_palette.htm', '');
    } else {
    $curcont=$prevcont;
    }
    }


    for ($i=1; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false && strpos($thisline, ' data-public="n"') === false && (strpos($thisline, ' data-owner="') !== false && strpos($thisline, ' data-owner=""') === false) || (strpos($thisline, ' data-contact="') !== false && strpos($thisline, ' data-contact=""') === false)) {
    if (strpos($curcont, $thisline) === false) {
    $curcont.=$thisline;
    }
    }
    }
    file_put_contents('/tmp/select_palette.htm', $curcont);
    echo '<html><body></body></html>';
    exit;

    } else if (isset($_GET['extract'])) {
    if (file_exists('/tmp/select_palette.htm')) {
    $prevcont=file_get_contents('/tmp/select_palette.htm');
    if (strpos($prevcont, '<svg name="' . $curgmt) === false) {
    file_put_contents('/tmp/select_palette.htm', '');
    }
    $lines=explode('<svg name="', $prevcont);
    rsort($lines);

    if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
    $prevcont="";
    for ($i=0; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false) {
    $prevcont.=$thisline;
    }
    }
    $vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
    echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
    exit;
    } else {
    $prevcont="";
    for ($i=0; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false) {
    $isok=true;
    if (isset($_GET['owner']) && strpos(strtolower($thisline), ' data-owner="' . strtolower(str_replace('+',' ',urldecode($_GET['owner'])) . '"')) === false) {
    $isok=false;
    }
    if (isset($_GET['contact']) && strpos(strtolower($thisline), ' data-contact="' . strtolower(str_replace('+',' ',urldecode($_GET['contact'])) . '"')) === false) {
    $isok=false;
    }
    if (isset($_GET['me']) && strpos(strtolower($thisline), strtolower('="' . str_replace('+',' ',urldecode($_GET['me'])) . '"')) === false) {
    $isok=false;
    } else if (isset($_GET['me'])) {
    $isok=true;
    }
    if ($isok) { $prevcont.=$thisline; }
    }
    }
    $vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
    echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
    exit;
    }

    }

    }

    ?>

    … meaning …

    Data … is enhanced … … by … PHP


    Previous relevant Select Multiple Webpage Palette Speech Bubble Data Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Data Tutorial

    Select Multiple Webpage Palette Speech Bubble Data Tutorial

    Onto yesterday’s Select Multiple Webpage Palette Speech Bubble Tutorial, today, we’re preparing for tomorrow.

    You heard it here first.

    Admittedly, nothing startling there, but it was the first time we remember …

    • embellishing SVG data … with so much …
    • what we normally associate with HTML element work …
      1. global data attributes
      2. id and name attribution …
      3. event logic

    Yes, all possible with SVG, though not the first thing we think of using SVG data within our HTML. We normally think, just display thoughts, but today, we’re paving the way for tomorrow, and our “short two day mini project sojourn” will become clearer regarding motives, then, or get hints trying with strategically changed select_palette.html web application‘s mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic …


    var taar=[];
    var preadd=0;
    var windowuser='', windowcontact='', windowask=true, suffix='';


    function defwuwc(inwindowuser,inwindowcontact) {
    if ((inwindowuser + inwindowcontact) == '') { return ''; }
    if (inwindowuser != '' && inwindowcontact != '') { return inwindowuser + '[' + inwindowcontact + ']'; }
    if (inwindowuser != '' && inwindowcontact == '') { return inwindowuser; }
    return inwindowcontact;
    }


    function treg(ttis) {
    var dotherest=false;
    var ctown=defwuwc(windowuser,windowcontact);
    var ourwindowask=windowask;
    preadd=1;
    if (ttis.outerHTML.indexOf(' data-public=') != -1) {
    if (windowuser == '' && windowcontact == '' && windowask) {
    ctown=prompt("To share on today's board enter a username and/or contact string (append space to remember, append another space to apply to all other Speech Bubbles) ... eg. " + String.fromCharCode(10) + "Robert Metcalfe[rmetcalfe15@gmail.com]", defwuwc(windowuser,windowcontact));
    }
    if (ctown == null) { ctown=''; }
    if (ctown != ctown.replace(/\ \ $/g,'')) {
    windowask=false;
    dotherest=true;
    ctown=ctown.trim();
    } else if (ctown != ctown.replace(/\ $/g,'')) {
    windowask=false;
    ctown=ctown.trim();
    }
    if (ctown.indexOf('[') > 0 && ctown.indexOf(']') != -1) {
    windowuser=ctown.split('[')[0];
    windowcontact=ctown.split('[')[1].split(']')[0];
    } else if (ctown.indexOf('[') == 0 && ctown.indexOf(']') != -1) {
    windowcontact=ctown.split('[')[1].split(']')[0];
    windowuser=windowcontact;
    } else {
    windowuser=ctown;
    windowcontact='';
    }
    if (windowuser != '') {
    ttis.setAttribute('data-owner', windowuser);
    }
    if (windowcontact != '') {
    ttis.setAttribute('data-contact', windowcontact);
    }
    if (windowuser != '' || windowcontact != '') {
    ttis.setAttribute('data-public', 'y');
    ttis.innerHTML=ttis.innerHTML.replace(/\<text\ /g,'<text stroke="blue" ');
    if (dotherest) {
    var svgs=document.getElementsByTagName('svg');
    for (var isvgs=0; isvgs<svgs.length; isvgs++) {
    if (svgs[isvgs].outerHTML.indexOf(' stroke=') == -1) {
    if (('' + svgs[isvgs].id) != ('' + ttis.id)) {
    if (windowuser != '') {
    svgs[isvgs].setAttribute('data-owner', windowuser);
    }
    if (windowcontact != '') {
    svgs[isvgs].setAttribute('data-contact', windowcontact);
    }
    if (windowuser != '' || windowcontact != '') {
    svgs[isvgs].setAttribute('data-public', 'y');
    }
    svgs[isvgs].innerHTML=svgs[isvgs].innerHTML.replace(/\<text\ /g,'<text stroke="blue" ');
    }
    }
    }
    }
    } else {
    windowask=ourwindowask;
    }
    }
    //alert(ttis.outerHTML);
    setTimeout(function(){ preadd=0; }, 5000);
    }


    Previous relevant Select Multiple Webpage Palette Speech Bubble Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Tutorial

    Select Multiple Webpage Palette Speech Bubble Tutorial

    Yesterday’s Select Multiple Webpage Palette Popup Tutorial modus operandi revolved around …

    delimitation rules

    … as so many matters do with written down text.

    We rethought yesterday’s HTML textarea start regarding line feed Speech Bubble creation possibilities, and thought …

    It’s too unwieldy for a user to add to their textual data when what they really want to do is Speech Bubbles.

    Yesterday’s thinking really hoped the user entered a Speech Bubble data one at a time, but what if the user wants to enter several Speech Bubbles in the one textarea incarnation?

    Good question. (Calling all ducks with a slow paddle going?!)

    Yes, but there is that ~~ existing delimitation rule, as of yesterday equating to a line feed. Supposing ~~ was given the delimitation roles …

    1. the character sets …
      lineFeed~~lineFeed
      … separate Speech Bubbles … ie. in the textarea a ~~ record is all there is on a line of textarea text
    2. the character set …
      ~~lineFeed
      … at the start wipes out any previously remembered text data and starts again
    3. else retain the ~~ mapping to lineFeed

    … in combination with the textarea always first presented blank and the previous Speech Bubble or Lines of Text remembered and retained unless the middle condition above happens?

    Well, we think it’s a plan, and led us to be able to share a Speech Bubble presentation of Shakepeare’s Act 1 Scene 1 of Macbeth. And so, today with the changed select_palette.html web application, onto yesterday’s …

    one textarea element

    … paradigm, we present …

    • previous text data in a details/summary “reveal” mode of use above the textarea element, as relevant
    • and below the textarea element we now have buttons to Email or SMS your text creations off to a recipient

    … harnessing hashtag navigational data methodologies in “a” “mailto:” (email) or “sms:” (SMS) prefixing href attributes, as per …


    function doemail() {
    var anchor=null;
    if (woois) {
    if (!woois.closed) {
    if (woois.document.getElementById('myta').outerHTML.indexOf(' data-done="y"') == -1) {
    if (woois.document.getElementById('myta').value.trim() != '') {
    woois.document.getElementById('myta').setAttribute('data-done', 'y');
    setTimeout(doemail, 6000);
    return '';
    }
    } else if (woois.document.getElementById('myta').value.trim() != '') {
    setTimeout(doemail, 6000);
    return '';
    }
    woois.close();
    woois=null;
    setTimeout(doemail, 6000);
    return '';
    }
    }
    var emis=prompt('Please enter email address to send to.', '');
    if (emis == null) { emis=''; }
    if (emis.indexOf('@') != -1) {
    anchor = document.createElement('a');
    anchor.href = 'mailto:' + emis.trim() + '?subject=My%20Speech%20Bubble%20data&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    document.body.appendChild(anchor);
    anchor.innerHTML='Email';
    anchor.target='_top';
    anchor.click();
    } else if (emis.trim() != '' && emis.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
    anchor = document.createElement('a');
    anchor.href = 'sms:' + emis.trim() + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    anchor.innerHTML='SMS';
    anchor.target='_top';
    anchor.click();
    }
    }

    function dosms(){
    var anchor=null;
    if (woois) {
    if (!woois.closed) {
    if (woois.document.getElementById('myta').outerHTML.indexOf(' data-done="y"') == -1) {
    if (woois.document.getElementById('myta').value.trim() != '') {
    woois.document.getElementById('myta').setAttribute('data-done', 'y');
    setTimeout(dosms, 6000);
    return '';
    }
    } else if (woois.document.getElementById('myta').value.trim() != '') {
    setTimeout(dosms, 6000);
    return '';
    }
    woois.close();
    woois=null;
    setTimeout(dosms, 6000);
    return '';
    }
    }
    var emis=prompt('Please enter SMS number to send to.', '');
    if (emis == null) { emis=''; }
    if (emis.indexOf('@') != -1) {
    anchor = document.createElement('a');
    anchor.href = 'mailto:' + emis.trim() + '?subject=My%20Speech%20Bubble%20data&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    document.body.appendChild(anchor);
    anchor.innerHTML='Email';
    anchor.target='_top';
    anchor.click();
    } else if (emis.trim() != '' && emis.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
    anchor = document.createElement('a');
    anchor.href = 'sms:' + emis.trim() + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    anchor.innerHTML='SMS';
    anchor.target='_top';
    anchor.click();
    }
    }


    Previous relevant Select Multiple Webpage Palette Popup Tutorial is shown below.

    Select Multiple Webpage Palette Popup Tutorial

    Select Multiple Webpage Palette Popup Tutorial

    Regarding yesterday’s Select Multiple Webpage Palette Primer Tutorial

    • you start with an outlandish premise …
    • it stays “outlandish” select (dropdown) element wise on non-mobile … but …
    • catering for mobile …
    • you are forced to encase it in a hosting div element (with the onmousedown and ontouchdown precursor events to onclick)

    … all contributing to getting us to a point, today, we can say we’ve added a layer of (useful, extra) functionality, by …

    • no longer asking for user interactive input via a Javascript prompt window … but, instead, like with Background Image Foreground Content Tutorial … we …
    • ask for user interactive input via a window.open (ie. popup) “here’s looking at you, kid” window.opener incarnation guise of our changed select_palette.html web application … just consisting of …
    • one textarea element …
      1. still capable of ~~ delimitation as with the Javascript prompt window thinking … but also now …
      2. harnessing the talents of a textarea line feed delimitation within it’s value attribute

      … able to extend functionality towards decent …

    • speech bubble feeling thoughts (so far, just) … because …
    • it opens up the idea that the div element innerHTML attribute can be the SVG we had previously been supplying as background HTML/CSS (via Javascript DOM) data

    Cute, huh?! (ahead of the “Speech Bubble styling” niceties making it really cute, yet, for us … but who knows what you can achieve on the “cute styling front”?!).


    Previous relevant Select Multiple Webpage Palette Primer Tutorial is shown below.

    Select Multiple Webpage Palette Primer Tutorial

    Select Multiple Webpage Palette Primer Tutorial

    In the world of web applications, there are often many ways to approach any given requirement. Like with yesterday’s Select Multiple Mobile Background Image Tutorial, today’s “albeit a bit out there idea” is to …

    • offer a select (multiple attribute) “dropdown” HTML element …
    • as a webpage covering …
    • template or palette … where the user …
    • writes user defined lines of words created

    … onto. Pretty simple idea for a “first then second draft“! But maybe not the first idea to spring to mind regarding making such an idea happen?!


    Previous relevant Select Multiple Mobile Background Image Tutorial is shown below.

    Select Multiple Mobile Background Image Tutorial

    Select Multiple Mobile Background Image Tutorial

    We had occasion to revisit Window LocalStorage Client Versus Server Map Tutorial‘s web application today changed this way to end up with wls_vs_php.htm, on an iPad, and saw how initially lacking was the advice on how to work the Capital City to Country quiz. The reason, primarily, in our view, is that on mobile platforms an element such as …


    <select class=dglow onclick=" console.log('67234'); noif(); " title='Please select Capital(s) below to get Countries Report ...' onfocusout=" document.getElementById('myrepsb').className='dglow'; tablemode = ''; nothere=true; updatecountries(null);" style='width:300px;margin-top:0px;margin-left:0px;vertical-align:top;height:100vh;background-color:lightblue;' id=scapitals multiple>
    // innard options //
    </select>

    … you just see words to the effect …

    0 items …

    … but we’d see more use for this select element “opened up” on initialization. As we read, and believed, via this useful link, thanks, this “programmatical click on mobile platforms” to open up such a select element is not easy. So we decided to go down the route of …

    • to a select multiple element …
    • on mobile …
    • background image …
    • at top right …
    • that is wording advice “Click/tap me”
    • when first encountered

    … and we came up with the document.body onload event call “new Javascript code snippet” …


    if (document.URL.indexOf('?') == -1) {
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    document.getElementById('scapitals').click(); // this is just wishful thinking, but no error is caused, and you never know?
    document.getElementById('scapitals').style.background="url(\"data:image/svg+xml;base64," + window.btoa("<svg xmlns='http://www.w3.org/2000/svg' width='126' height='48' viewport='0 0 100 100' style='border-radius:15px;background-color:rgba(0,0,255,0.3);fill:black;font-family:Verdana;font-size:17px;'><text x='5%' y='60%'>Click/tap me</text></svg>") + "\") no-repeat top right";
    }
    }

    Next best approach, we’d say?!


    Previous relevant Window LocalStorage Client Versus Server Map Tutorial is shown below.

    Window LocalStorage Client Versus Server Map Tutorial

    Window LocalStorage Client Versus Server Map Tutorial

    Get a good map, and a goodly number of times you’ll want a map of smaller or larger scale than the one you have. Murphy’s Law? This is probably why in the wonderful woooooooorrrrrrrrlllllld of Google Charts they have included …

    • Geo Chart topographic map of the world or of regions
    • Map Chart terrestrial/satellite map of your group of markers at a zoom level of your choosing

    … and hope you can see that the latter can save the day for a Short Distance Trip (corner shop, anyone?!).

    So we’ve added onto yesterday’s Window LocalStorage Client Versus Server Timeline Tutorial progress a new toggling button to view a scenario in either Google Chart scenario above.

    You can see this integration work with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link supervising a tweaked geo_chart.php Geo Chart interfacer.


    Previous relevant Window LocalStorage Client Versus Server Timeline Tutorial is shown below.

    Window LocalStorage Client Versus Server Timeline Tutorial

    Window LocalStorage Client Versus Server Timeline Tutorial

    Up to yesterday’s Window LocalStorage Client Versus Server User Tutorial‘s progress, our Capital City Find Matching Country Report web application project was all about …

    • where (and capital of “what”) … but we often seek out a way to add into the mix that 4th dimension …
    • when (ie. time)

    … and regarding the current project, a …

    • where “map” … can interface with a …
    • when “Trip Plan Itinerary”

    … and for this purpose, we’re going to interface to the excellent Google Charts Annotated Timeline Chart, thanks, because it combines links of “time” to “user annotations” in a timeline way, that similar way you might describe the qualities of a Trip, even before you’ve gone on that trip. We’ve also added it so that an unordered places list can be turned into a Trip Plan Itinerary at the click/touch of a new map 🗺 &#128506; emoji button.

    Again, see how these timeline amendments were achieved with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link and annotatedtimeline_chart.php which changed quite a lot.


    Previous relevant Window LocalStorage Client Versus Server User Tutorial is shown below.

    Window LocalStorage Client Versus Server User Tutorial

    Window LocalStorage Client Versus Server User Tutorial

    The inherent weakness with our current Capital City Find Matching Country Report web application project, to our minds, was that places of interest are not restricted to the Capital Cities of Countries, especially when “Trip Planning”. On the other hand, it would be impossible to cater for every “place” in the world. That is far too subjective for good web application applicability. What would be good though, is to allow in user defined …


    Place name, Country name

    … terms, the definitions of interest to a user. We can ask this …

    • flagged by the click/touch of an emoji button … and …
    • the interactive entry presented via a Javascript prompt window

    . When thinking of data applicable to an individual, then that can be catered for by recording it in localStorage where it will be recalled on the next execution of that web application in the same web browser.

    This, along with a Colour Wheel of the “nearest TimeZone place” onto the existing logic of yesterday’s Window SessionStorage Client Versus Server Order Tutorial progress could make for a more useful and practical tool for those Trip Planners out there!

    See how this was achieved with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.

    Did you know?

    To click/touch one of those Google Chart Geo Chart lines between Emoji Flag Markers will show a new Google Maps directions web page with transport times and detail, as well as an inhouse crow fly distance of that trip leg, as shown up the top right of today’s tutorial picture.


    Previous relevant Window SessionStorage Client Versus Server Order Tutorial is shown below.

    Window SessionStorage Client Versus Server Order Tutorial

    Window SessionStorage Client Versus Server Order Tutorial

    If we are to honour our thoughts of being able to use our current Capital City Find Matching Country Report web application as a Trip Planner …

    Our primary integration today is to (software) integrate the great Weather Underground and its great API service for autocomplete name searches for weather (and hurricane) information. Why bother? Well, can you not envisage a user using that Ajax functionality of yesterday’s Window SessionStorage Client Versus Server Ajax Tutorial as a trip planner, perhaps, or as a “checking up on relatives overseas” tool, perhaps? And not all the capital cities are timezone places, and so for some of those we can use Weather integration to still show apt online information when click/touching a Countries Report row. Speaking of this “row”, we make an improvement whereby on a first click of a right hand (Country) row cell, that cell is not initially a contenteditable=”true” one (that may frustrate showing the keyboard on mobile, when most likely it was the row touch intended), but then becomes a contenteditable=”true” cell henceforth.

    … then yesterday’s Window SessionStorage Client Versus Server Flags Tutorial “progress to now” needs to take notice of a user’s order of multiple select (dropdown) element click/touching of Capital City option (sub)elements, just as we did with the recent User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial‘s web application project to allow for a user ordered YouTube video playlist.

    Because what is a Trip Planner without an ordered trip? Well, that is debatable, but what isn’t (debatable), is that there will be people in the world who appreciate the “mapping out” of a proposed Trip Planning Itinerary. What could we call on here? We can think of the Google Chart Geo Chart work around about the time of Google Geo Chart Co-ordinate Emojis Tutorial, when we started using …

    • a world map … with …
    • emoji markers … and optionally …
    • joined up by straight lines

    … an idea for a Trip Plan itinerary synopsis, perhaps?!

    If you examined closely yesterday’s code changes you will have noticed our collecting of TimeZone Place geographical latitude and longitude information. Today, we start making use of that preparatory work with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.

    Stop Press

    The “emoji markers” above (as of 2 January 2020) will be “country flags” (as per Window SessionStorage Client Versus Server Flags Tutorial ideas), as defined.


    Previous relevant Window SessionStorage Client Versus Server Flags Tutorial is shown below.

    Window SessionStorage Client Versus Server Flags Tutorial

    Window SessionStorage Client Versus Server Flags Tutorial

    Yes, there’s more to do onto yesterday’s Window SessionStorage Client Versus Server CSS Tutorial‘s Capital City Find Matching Country Report web application project, in our eyes. We have not even mentioned “Internationalization” as a concept up to now. In this line of thinking …

    Did you know?

    Emoji flags via ISO 2 character country codes are dead easy via Regional Indicator Symbol characters …


    var lri="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    var dri=["127462","127463","127464","127465","127466","127467","127468","127469","127470","127471","127472","127473","127474","127475","127476","127477","127478","127479","127480","127481","127482","127483","127484","127485","127486","127487"];

    var thiscc='AU'; // ISO 2 character countrycode for Australia
    var ccsuff='', ccchar=' ';
    for (var iccsuff=0; iccsuff<thiscc.length; iccsuff++) {
    ccchar=thiscc.substring(iccsuff, eval(1 + eval('' + iccsuff))).toUpperCase();
    ccsuff+='&#' + dri[eval('' + lri.indexOf(ccchar))] + ';';
    }
    document.getElementById('lastflag').innerHTML=ccsuff;

    … to result in (via <span style=font-size:64px;>&#127462;&#127482;</span>) …


    🇦🇺

    … providing interest and general translatability to the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.


    Previous relevant Window SessionStorage Client Versus Server CSS Tutorial is shown below.

    Window SessionStorage Client Versus Server CSS Tutorial

    Window SessionStorage Client Versus Server CSS Tutorial

    Further to yesterday’s Window SessionStorage Client Versus Server Integration Tutorial we have a two pronged improvements set for you today with our current Capital City Find Matching Country Report web application project …

    • CSS styling changes … and …
    • additional functionality for Email and SMS links back to our current Capital City Find Matching Country Report web application project (to complete the cycle)

    We use several modes of CSS application (the first and last of particular relevance to today’s “highlighting of workflow” improvements) …

    … the “static” measures often helping to highlight the web application’s main workflow of user interaction and the “dynamic” measures helping to alert the user as to where to proceed with their “workflow”.

    In terms of CSS styling work …

    1. for non-mobile platforms we allow for more columns to be applied to our Capitals select (dropdown) element (in order to reduce some user scrolling, as does our new additional A-Z letter basis sorting functionality) as per … the “dynamic” Javascript DOM “class” modifications

      if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
      document.getElementById('lefttd').className='lefttd';
      }

      … dovetailing with the “static” internal CSS coding

      <style>
      .lefttd {
      column-count: 4;
      max-height: 35%;
      vertical-align: top;
      max-width: 70%;
      font-size: 8px;
      background-color: rgba(205,205,205,0.5);
      background-image: -webkit-gradient(
      linear,
      right bottom,
      left top,
      color-stop(0, rgba(205, 205, 205, 0.8)),
      color-stop(0.50, rgba(255, 255, 0, 0.2))
      );
      background-image: -o-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -moz-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -webkit-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -ms-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: linear-gradient(to left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);

      }
      </style>

      … and please note that around here at RJM Programming we have a “far from hard and fast rule” (but a rule regardless) regarding HTML element ID and class attributes that they concern (and (usually) be compartmentalised into) Javascript (DOM) manipulations and CSS styling issues respectively … and add a linear-gradient background to the table cell when expecting the initial user interaction on non-mobile platforms
    2. a “dynamic” Javascript DOM “class” modification … document.getElementById(‘myrepsb’).className=’dglow’; … is made to the “Report…” button at the Capitals select (dropdown) onfocusout event so as to highlight (with “glow” inspired styling) where user interaction may flow to

    As far as links go, you may expect to need serverside means to construct these in online Email and SMS message interfacing, but email (client program) products like Gmail parse your ascii text and convert http: or https: protocol URLs in your Email body to hyperlinks, as does the Messages SMS application here on this MacBook Pro using macOS Mojave. Cute, huh?! So to close the circle back from remote thar’ parts back to our web application is a simple matter of, in broad brush terms …

    • adding two new buttons called “Email Columns and Links …” and “SMS Columns and Links …” that …
    • set a global variable andlinkto = true; … setting in play, within the report writing code (that likes monospaced fonts) …
    • add a new links column to the right with URLs like …
      https://www.rjmprogramming.com.au/HTMLCSS/wls_vs_php.htm?andgo=y&countries=Belize&capitals=Belmopan
      … to tell your client programs to form the hyperlinks for us (if they are “of the mood”, that is!)

    To improve user experience we use “dynamic” Javascript DOM HTML “style” attribute change means to easier close the “Colour Wheel” helper web application “above the fold” by changing the CSS z-index (Javascript DOM [element].style.zIndex) of elements accordingly, when the user clicks other elements. You can see all this with the first “the changed” link above, where all “glow” CSS styling will also feature prominently.


    Previous relevant Window SessionStorage Client Versus Server Integration Tutorial is shown below.

    Window SessionStorage Client Versus Server Integration Tutorial

    Window SessionStorage Client Versus Server Integration Tutorial

    We hope, when performing a “software integration” task, that the two or more components of that integration work with each other’s talents, rather than a big tussle like reinventing the wheel. This ideal makes the work …

    • sometimes difficult but rewarding because …
    • the differences between two independent software components can be quite large and daunting … and the programmer has to see that …
    • care is applied so as not to wreck previous functionality and integrations in making the current integration work

    … and that is why we’ve made corollaries to “building from scratch” (when planning and design is a huge component) can be a lot simpler than a software integration “renovation”, in the past, here at this blog.

    Our primary integration today is to (software) integrate the great Weather Underground and its great API service for autocomplete name searches for weather (and hurricane) information. Why bother? Well, can you not envisage a user using that Ajax functionality of yesterday’s Window SessionStorage Client Versus Server Ajax Tutorial as a trip planner, perhaps, or as a “checking up on relatives overseas” tool, perhaps? And not all the capital cities are timezone places, and so for some of those we can use Weather integration to still show apt online information when click/touching a Countries Report row. Speaking of this “row”, we make an improvement whereby on a first click of a right hand (Country) row cell, that cell is not initially a contenteditable=”true” one (that may frustrate showing the keyboard on mobile, when most likely it was the row touch intended), but then becomes a contenteditable=”true” cell henceforth.

    As a user experience improvement for “trip planners” perhaps, we allow the user to alphabetically sort the presented select (dropdown) element entries …


    var firstopt='';
    var wasopts='';
    var restopts='';

    function readyitforsort(iselid) {
    var optsare=[];
    var huhisel=document.getElementById(iselid).innerHTML;
    var huhsopts=huhisel.split('</option>');
    for (var ihuh=0; ihuh<huhsopts.length; ihuh++) {
    if (huhsopts[ihuh].trim() != '') {
    if (firstopt == '') {
    firstopt=huhsopts[ihuh] + '</option>';
    } else {
    wasopts+=huhsopts[ihuh].replace('option ','option data-ih="' + (huhsopts[ihuh].split('>')[eval(-1 + huhsopts[ihuh].split('>').length)] + '" ')) + '</option>';
    optsare.push(huhsopts[ihuh].replace('option ','option data-ih="' + (huhsopts[ihuh].split('>')[eval(-1 + huhsopts[ihuh].split('>').length)] + '" ')) + '</option>');
    }
    }
    }
    optsare.sort();
    for (var jhuh=0; jhuh<optsare.length; jhuh++) {
    restopts+=optsare[jhuh];
    }
    }

    … controlled by a new dropdown in the left hand column header cell.

    We also allow the user to move the iframe element with some positioning emoji buttons near the “Close” button one (of yesterday’s work).

    Into the future, too, we’ll have more to say regarding the germination of an idea “to allow a mobile onmouseover simulator (of sorts)” be to allow the user to perform a swipe across an individual HTML element of interest on mobile platforms (ie. harness ontouchmove event) as per (so far) … kicked off by “<body onload=” setTimeout(athn, 5000); “>” …


    var last24='';
    var rectdc;

    function nodivalert() {
    document.getElementById('divalert').style.display='none';
    document.getElementById('divalert').style.zIndex='-456';
    document.getElementById('divalert').style.left=('-' + rectdc.left).replace('px','') + 'px';
    document.getElementById('divalert').style.top=('-' + rectdc.top).replace('px','') + 'px';
    }

    function ourdivalert(inmsg) {
    document.getElementById('divalert').style.position='absolute';
    document.getElementById('divalert').style.left=('' + rectdc.left).replace('px','') + 'px';
    document.getElementById('divalert').style.top='' + eval(-80 + eval(('' + rectdc.top).replace('px',''))) + 'px';
    document.getElementById('divalert').style.backgroundColor='#e0e0e0';
    document.getElementById('divalert').style.display='block';
    document.getElementById('divalert').style.zIndex='456';
    document.getElementById('divalert').style.opacity='0.8';
    document.getElementById('divalert').style.padding='5px 5px 5px 5px';
    document.getElementById('divalert').innerHTML=inmsg + '<br><br><input type=button value=Close onclick=nodivalert();></input>';
    setTimeout(nodivalert,9000);
    }

    function athn() {
    rectdc=document.getElementById('dc').getBoundingClientRect();
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    document.getElementById('dc').ontouchmove=function(event) { if (last24.substring(0,eval(-1 + last24.length)) == event.target.title.substring(0,eval(-1 + event.target.title.length))) { last24=last24; } else { last24=event.target.title; ourdivalert(event.target.title); } }
    } else {
    document.getElementById('dc').onmousemove=function(event) { if (last24.substring(0,eval(-1 + last24.length)) == event.target.title.substring(0,eval(-1 + event.target.title.length))) { last24=last24; } else { last24=event.target.title; ourdivalert(event.target.title); } }
    }
    }

    … working with the new HTML …


    <div id=divalert></div>
    </body>
    </html>

    … to try to allow the “explainer of an element” advantages non-mobile platforms have for hovering over an HTML element with a title attribute filled in.

    And so, yet again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new Weather integration functionality. It caused the changed colour_wheel.html‘s colour wheel (at this live run link) to be affected (by integrations “up”).


    Previous relevant Window SessionStorage Client Versus Server Ajax Tutorial is shown below.

    Window SessionStorage Client Versus Server Ajax Tutorial

    Window SessionStorage Client Versus Server Ajax Tutorial

    We have a few “clientside chestnuts” to use with our current Capital City Find Matching Country Report web application project today, those being …

    • Ajax functionality, kicked off by an “onclick” event set of logic, allowing mobile platforms to also have a look in (the look in that they miss when the event logic is off the “onmouseover” event)
    • iframe and its …
      1. srcdoc attribute (“content” alternative to src “url” attribute) … along with, and crucially needing (because srcdoc ignores its own document.body onload goings on, that we need the “Iframe Client Pre-Emptive” methods below to circumvent) the …
      2. onload event opportunity of an iframe element (we group into “Iframe Client Pre-Emptive” methods, here)

    … adding onto yesterday’s Window SessionStorage Client Versus Server Canvas Tutorial.

    It’s not that involved with the Ajax work today, given that there are no cross-domain issues, though there are cross-protocol (SSL https: versus non-SSL http:) issues to be careful about. Those can be addressed because the web application is recalled to present its “Country Report” and that is the opportunity to check on protocol navigation requirements.

    Along the way, we also make this happen for the user on …

    • click/touching a table row … it sets off new “tr” (table row) element logic calling our (inhouse) Timezone and Wikipedia Place Information helper (HTML) via Ajax (so not leaving the webpage) … and because of place name oddities we allow for …
    • “td” (table cell) element user amendments by setting their contenteditable attributes to “true” (since fixed, but we found the Timezone Europe/Tirane pointing at Tirane in Albania used to be spelt “Tirana”)

    … that latter methodology normally a technique we apply to “div” elements (so, there you are!)

    Also used are “overlay” techniques, two of the “usual suspects” here coming into play, to present to the “Ajax content to srcdoc iframe arrangements” …

    Yet again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new “Ajax” functionality.


    Previous relevant Window SessionStorage Client Versus Server Canvas Tutorial is shown below.

    Window SessionStorage Client Versus Server Canvas Tutorial

    Window SessionStorage Client Versus Server Canvas Tutorial

    Yesterday’s Window SessionStorage Client Versus Server Share Tutorial dealt with ascii text clipboard copy assisted sharing options with our current Capital City Find Matching Country Report web application project. This suited both Email and SMS share options we coded for, but today’s extension of functionality from “ascii text” data to “graphical data” only suits Email sharing. The other caveat with our work is that no serverside (for us, PHP) help is allowed, so no PHP mail here.

    What comes into play with a “graphical data” clientside (only) sharing approach? It will not surprise many readers that, for us, it involves …

    • canvas element … converting HTML table outerHTML “ascii text” data … via …
    • canvas drawing methods “[canvasContext].strokeRect()” and “[canvasContext].strokeText()” via “[cellElement].getBoundingClientRect()” … to convert that canvas element content via …
    • [canvasElement].toDataURL() … to an …
    • img element nested in a div contenteditable=true element … so as to hook in with today’s very useful helper link, thanks … use …

    • function tabletoclipboard(canvas) { // thanks to https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard
      var img = document.createElement('img');
      img.src = canvas.toDataURL();

      var div = document.createElement('div');
      div.contentEditable = true;
      div.appendChild(img);
      document.body.appendChild(div);

      // do copy
      SelectText(div);
      document.execCommand('Copy');
      document.body.removeChild(div);
      }

      function SelectText(element) { // thanks to https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard
      var doc = document;
      if (doc.body.createTextRange) {
      var range = document.body.createTextRange();
      range.moveToElementText(element);
      range.select();
      } else if (window.getSelection) {
      var selection = window.getSelection();
      var range = document.createRange();
      range.selectNodeContents(element);
      selection.removeAllRanges();
      selection.addRange(range);
      }
      }
    • to leave the user’s device’s clipboard containing a useful table (with linework) … ready to …
    • paste into an email body section

    … sharing off to an emailee collaborator.

    Again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new “Email Table” button functionality.


    Previous relevant Window SessionStorage Client Versus Server Share Tutorial is shown below.

    Window SessionStorage Client Versus Server Share Tutorial

    Window SessionStorage Client Versus Server Share Tutorial

    Yesterday’s Window SessionStorage Client Versus Server Tutorial has been amended today for two new sharing and collaboration options, those being …

    • email
    • SMS

    … but you may well be familiar with the restrictions on email and SMS client (program) approaches to this, coming from HTML “a” link “mailto:” and “sms:” href property prefixes respectively. We’re going to need help with the 800 odd character (length) restrictions with the (resultant) web address (bar) URL, but what? How about working off the great advice of this wonderful link, thanks, to copy what we’d have assembled into an ascii text Report into the characters contained by the user’s device’s clipboard?


    function copytoclipboard(str) { // thanks to https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f
    var el = document.createElement('textarea');
    el.value = str;
    el.setAttribute('readonly', '');
    el.style.position = 'absolute';
    el.style.left = '-9999px';
    document.body.appendChild(el);
    el.select();
    document.execCommand('copy');
    document.body.removeChild(el);
    }

    An issue that springs up here using such clipboard ascii text content, whenever you get the Font choice given to you, pick a monospaced Font like Courier New or “Fixed Width”.

    See the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new sharing functionality.


    Previous relevant Window SessionStorage Client Versus Server Tutorial is shown below.

    Window SessionStorage Client Versus Server Tutorial

    Window SessionStorage Client Versus Server Tutorial

    Sometimes it’s the case at this blog that we’d like to introduce a new topic, but do not do so, because we cannot show any real world (or real application) use of that concept. So it has been, up until now, with the concept of (web browser) window (object) sessionStorage property. But yesterday’s Window LocalStorage Client Versus Server Primer Tutorial represented an opportunity akin to when Haley’s Comet gets at its closest to the Earth … while you see a chance, take it … chance because of that nuance whereby we were not trying to store data for any other purpose than passing data onto …

    1. a known entity … ie. same web application … at …
    2. a known time … ie. immediately

    … two conditions that make the code design “marginally” more ideal for the window object property concept of sessionStorage rather than localStorage, in that any …


    localStorage.removeItem([knownLocalStorageName]);

    … becomes superfluous as with sessionStorage data will disappear between web browser sessions, anyway.

    We offer this new concept as a non-default option of a select (dropdown) element replacement to the h1 element hardcoding “localStorage” with the changed wls_vs_php.htm Capital City Find Matching Country Report live run. The other nuance of difference with sessionStorage usage is that in the document.body onload event logic, we may as well (as part of other changes) pre-emptively look for, and if there, respond to, any found sessionStorage data points, even without the user having flagged it specifically


    var datamode='localStorage';

    function checkforreport() {
    var divcont='';
    var dcaps, dctys, idis;
    if (getcapitals == 'localStorage') {
    if (window.localStorage) {
    getcapitals=decodeURIComponent(localStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
    localStorage.removeItem('wls_vs_php_capitals');
    } else {
    getcapitals='';
    }
    } else if (getcapitals == 'sessionStorage') {
    document.getElementById('smode').value=getcapitals;
    datamode=getcapitals;
    if (window.sessionStorage) {
    getcapitals=decodeURIComponent(sessionStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
    } else {
    getcapitals='';
    }
    }
    else if (getcapitals == '' && window.sessionStorage) {
    getcapitals=decodeURIComponent(('' + sessionStorage.getItem('wls_vs_php_capitals')).replace(/^null$/g,'')).replace(/\+/g,' ');
    if (getcapitals != '') {
    document.getElementById('smode').value='sessionStorage';
    datamode='sessionStorage';
    }
    }

    if (getcountries == 'localStorage') {
    if (window.localStorage) {
    getcountries=decodeURIComponent(localStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
    if (getcapitals.replace('localStorage','') != '' && getcountries.replace('localStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
    localStorage.removeItem('wls_vs_php_countries');
    } else {
    getcountries='';
    }
    } else if (getcountries == 'sessionStorage') {
    if (window.sessionStorage) {
    getcountries=decodeURIComponent(sessionStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
    if (getcapitals.replace('sessionStorage','') != '' && getcountries.replace('sessionStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
    } else {
    getcountries='';
    }
    }
    else if (getcountries == '' && document.getElementById('smode').value == 'sessionStorage' && window.sessionStorage) {
    getcountries=decodeURIComponent(('' + sessionStorage.getItem('wls_vs_php_countries')).replace(/^null$/g,'')).replace(/\+/g,' ');
    if (getcountries != '') {
    document.getElementById('smode').value='sessionStorage';
    datamode='sessionStorage';
    }
    }

    if (getcapitals != '' && getcountries != '') {
    divcont='<table border=5 style="width:95%;vertical-align:top;background-color:white;"><tr style=background-color:#f0f0f0;"><th>Capital</th><th>Country</th></tr></table>';
    dcaps=getcapitals.split('|');
    dctys=getcountries.split('|');
    for (idis=0; idis<dcaps.length; idis++) {
    divcont=divcont.replace('</table>', '<tr><td>' + dcaps[idis] + '</td><td>' + dctys[idis] + '</td></tr></table>');
    }
    document.getElementById('dreport').innerHTML=divcont;
    }
    document.getElementById('smode').value=datamode;
    }

    Which beggars the question “What are the differences between sessionStorage and localStorage?” A quick reading might surmise that “the latter has an expiration date”. We leave you with an open ended Google search so that you may extend your readings on this.


    Previous relevant Window LocalStorage Client Versus Server Primer Tutorial is shown below.

    Window LocalStorage Client Versus Server Primer Tutorial

    Window LocalStorage Client Versus Server Primer Tutorial

    Even though we rave on a lot about serverside PHP and its $_POST method=POST (versus HTML/Javascript recipient via ? and & argument $_GET method=GET scenario) data length advantages as the recipient of an HTML form method=POST set of data that could be sizeable, we’ve just realized that there is a client Javascript and window.localStorage methodology that may help alleviate the need to involve PHP (and any other serverside intervention) on occasions.

    Hint: Yes, we’ve raved on about this too?! Does the blog posting title give it away? Okay, yes, it should read “localStorage”, but thought we’d gone past such juvenile finickiness since the Whac-A-Mole controversy of 1st December 2019 (or even The Great Tea Trolley Disaster of ’67, we daresay).

    It can even use a “self-destruct” approach to the use of this “localStorage” on having used it because …

    • the web application knows who is using it (localStorage) … and on having accessed and read it …
    • the web application knows it (localStorage) is of no use to any other user (in this web application’s case, at least)

    … which is very pleasing for a Land Surveyor who likes to leave cow paddocks as they’ve seen them so to speak. Except it’s like having a ten tonne truck worth of data access in amongst the cow pats when having access to “localStorage” (or PHP), rather than a little piddle of calf wee (wee Metcalfes know a thing or two about these things!) data access of ? and & HTML/Javascript URL arguments (or even if we were to use HTTP Cookies).

    It’s not as if we all have access to serverside language usage, though we do, because we really like PHP and MAMP and Apache/PHP/MySql web servers (and have arranged our development environment accordingly), but what if you are starting out in web development, and still want to allow for sizeable chunks of data with your web applications? Huh? Huh?! See the possibilities? Try our proof of concept wls_vs_php.html Capital City Find Matching Country Report live run, and highlight a whole swathe of (multiple mode) dropdown option Capital Cities holding down the shift key before pressing the yellow “Report” button. If the URL ends up as …

    https://rjmprogramming.com.au/HTMLCSS/wls_vs_php.html?capitals=localStorage&countries=localStorage

    that’s because the web application’s …


    function analyze() {
    var purl=document.URL.split('#')[0].split('?')[0] + '?capitals=' + encodeURIComponent(document.getElementById('capitals').value) + '&countries=' + encodeURIComponent(document.getElementById('countries').value);
    if (purl.length > 800) {
    if (phpexists) {
    document.getElementById('myform').method='POST';
    document.getElementById('myform').action='./wls_vs_php.php';
    } else if (window.localStorage) {
    localStorage.setItem('wls_vs_php_countries', encodeURIComponent(document.getElementById('countries').value));
    localStorage.setItem('wls_vs_php_capitals', encodeURIComponent(document.getElementById('capitals').value));
    document.getElementById('capitals').value='localStorage';
    document.getElementById('countries').value='localStorage';
    location.href=document.URL.split('#')[0].split('?')[0] + '?capitals=' + encodeURIComponent(document.getElementById('capitals').value) + '&countries=' + encodeURIComponent(document.getElementById('countries').value);

    return false;
    }
    }
    return true;
    }

    … HTML form onsubmit event logic …

    1. discovered no PHP web application existant (via Client Pre-emptive Iframe techniques) … and …
    2. discovered (in a sanity check feeling way) that to go down the proposed HTML form method=GET approach was risking a …

      HTTP 414 "Request URI too long"

      … web browser error … and that …
    3. localStorage was a known web browser piece of functionality
    4. … and so as per our localStorage logic we …

    5. back out of the default HTML form method=GET navigation setup of the web application in favour of …
      • storing that data into localStorage
      • substituting into the URL ? and & arguments the hardcoding “localStorage” (and in so doing, getting back under the HTTP 414 “Request URI too long” limitation, piecing together (what amounts to) …
        location.href=document.URL.split(‘#’)[0].split(‘?’)[0] + ‘?capitals=localStorage&countries=localStorage’;)
        … that on a recall to this same web application a …
      • document.body onload event piece of Javascript logic checks the localStorage for its incoming Capital City Country Report data, as per …

        var phpexists=false;
        var getcapitals=location.search.split('capitals=')[1] ? decodeURIComponent(location.search.split('capitals=')[1].split('&')[0]).replace(/\+/g,' ') : '';
        var getcountries=location.search.split('countries=')[1] ? decodeURIComponent(location.search.split('countries=')[1].split('&')[0]).replace(/\+/g,' ') : '';

        function checkforreport() {
        var divcont='';
        var dcaps, dctys, idis;
        if (getcapitals == 'localStorage') {
        if (window.localStorage) {
        getcapitals=decodeURIComponent(localStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
        localStorage.removeItem('wls_vs_php_capitals');
        } else {
        getcapitals='';
        }
        }
        if (getcountries == 'localStorage') {
        if (window.localStorage) {
        getcountries=decodeURIComponent(localStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
        if (getcapitals.replace('localStorage','') != '' && getcountries.replace('localStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
        localStorage.removeItem('wls_vs_php_countries');
        } else {
        getcountries='';
        }
        }

        if (getcapitals != '' && getcountries != '') {
        divcont='<table border=5 style="width:95%;vertical-align:top;background-color:white;"><tr style=background-color:#f0f0f0;"><th>Capital</th><th>Country</th></tr></table>';
        dcaps=getcapitals.split('|');
        dctys=getcountries.split('|');
        for (idis=0; idis<dcaps.length; idis++) {
        divcont=divcont.replace('</table>', '<tr><td>' + dcaps[idis] + '</td><td>' + dctys[idis] + '</td></tr></table>');
        }
        document.getElementById('dreport').innerHTML=divcont;
        }
        }

        … the localStorage.removeItem() representing that “self-destruct” nuance we were talking about before

    We may well use this methodology in future projects, and hope it has been of some little interest to you as well?!

    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.


    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.


    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 Ajax, eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Select Multiple Webpage Palette Speech Bubble YouTube Tutorial

Select Multiple Webpage Palette Speech Bubble YouTube Tutorial

Select Multiple Webpage Palette Speech Bubble YouTube Tutorial

Well, onto yesterday’s SVG Tspan Element Primer Tutorial our “two day” job is “two days” of sorts. Definitely for non-mobile, deploying the “inline audio stream of YouTube video play” concept we wanted, but for mobile, let me “count the ways” …

  1. to get any functionality down to “one tap/click to play” … well …
  2. we tried for mobile, and haven’t given up, but the complexity of “overlay” related z-index and “where to place iframe element” issues exploded my tiny little brain … and so …
  3. for mobile we’ve “parked” the ideal solution … in favour of, for now …
  4. the mobile “two day solution” that, like for non-mobile, underlines those 11 character YouTube references as links that can navigate interested users to a new tab/window YouTube window to play the “whole shebang” (and … sigh … needing that extra tap/click) … leaving …
  5. Days 3 (and on) to nuance

Another project where the last 10% nuances is probably going to take more time than the rest! Anyway, we’ll see how this “mini project” develops.

What changed? Well …

  • the SVG tspan 11 letter word YouTube reference Speech Bubble changed select_palette.html web application … now helped out by …
  • now SVG tspan savvy external Javascript ytaudioonly.js assisting YouTube Audio Stream of Video Playsspecifically

    // blah blah blah
    var thespansare=[];

    function ihun(ao) {
    var aih=ao.innerText;
    if (aih.trim() != '') {
    var newihis='';
    for (var iaih=0; iaih<aih.length; iaih++) {
    newihis+='_';
    }
    ao.innerHTML=newihis;
    }
    }


    function audioytlook() { // first happens around document.body onload event
    // blah blah blah
    var taop='', ttdom='', ttid=' id=newspan8', ziif='', yiif='';
    // blah blah blah
    thespansare=document.getElementsByTagName('tspan');
    if (eval('' + thespansare.length) > 0) {
    for (jits=0; jits<thespansare.length; jits++) {
    //alert(thespansare[jits].outerHTML);
    if ( ('' + thespansare[jits].outerHTML).indexOf('tubeaudioyou') != -1 && ('' + thespansare[jits].outerHTML).indexOf(' data-mentioned=') == -1) {
    //alert('HERE');
    jitrect=thespansare[jits].getBoundingClientRect();
    if (document.getElementById('doverlay')) {
    if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && document.URL.indexOf('.9JUNK5.247/') == -1) {
    //alert('why');
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    ttid+='8';
    } else {
    ziif=' style="z-index:50;" ';
    yiif=' event.stopPropagation(); ';
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); "; // document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    //document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.4;z-index:176;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a></span>';
    //document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    //alert('<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">___________</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>');
    document.getElementById('doverlay').innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:76;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">___________</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    ttid+='8';
    }
    } else {
    if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && document.URL.indexOf('.9JUNK5.247/') == -1) {
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    document.body.innerHTML+='<span' + ttid + ' style="opacity:0.1;visibility:visible;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">' + thespansare[jits].innerHTML + '</a><span style="visibility:visible;opacity:0.8;">' + String.fromCodePoint(128251) + String.fromCodePoint(127926) + '</span></span>';
    ttid+='8';
    } else {
    ziif=' style="z-index:150;" ';
    yiif=' event.stopPropagation(); ';
    taop='opacity:0.9;';
    ttdom=" ihun(document.getElementById('aja')); document.getElementById('" + ttid.replace(' id=','') + "').style.opacity='0.6'; ";
    document.body.innerHTML+='<span' + ttid + ' style="opacity:0.4;z-index:176;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;"><a class="audioNOTQUITEytplay" href="//www.youtube.com/watch?v=' + thespansare[jits].innerHTML + '" data-style="opacity:0.4;z-index:876;position:absolute;top:' + jitrect.top + 'px;left:' + jitrect.left + 'px;">___________</a></span>';
    ttid+='8';
    }
    }
    thespansare[jits].setAttribute('data-mentioned', 'y');
    }
    }
    thespansare=[];
    }

    var audioonlyas=document.getElementsByTagName('a');
    // blah blah blah
    }

    // blah blah blah

    … slotting in tspan logic ahead of the a link analysis


Previous relevant SVG Tspan Element Primer Tutorial is shown below.

SVG Tspan Element Primer Tutorial

SVG Tspan Element Primer Tutorial

We’re starting a planned “mini project” to improve Select Multiple Webpage Palette Speech Bubble Swipe Tutorial and what we find important …

  1. regarding improvements to existant functionality it is most important to not interfere with any current functionality … and then …
  2. implement new functionalities off this platform

… and with our “mini project” of embellishing 11 letter words in the Speech Bubbles of our Select Multiple Webpage Palette Speech Bubble web application of recent times, we have a natural compartmentalization playing out mimicking those ideas above, that goes …

  1. Day 1 – work with the data that is the HTML (and SVG) of Speech Bubbles where they look and behave as ever, but 11 letter words get nested into SVG tspan elements
  2. Day 2 – embellish the web application via those SVG tspan elements

It’s our first go using SVG tspan elements as a “forward thinking” tool, and it helped us thinking on this regarding the corrollaries to HTML span element. What initially concerned us using SVG tspan was whether we’d have to specify x and y attributes, but, as it panned out, no, the SVG text element nesting the tspan takes care of that, so, “top supportive” we’d say, and a lot like how we think of the HTML span element working, and helping out, enormously!

Into “Day 2” though, and we’ll be wanting to do Javascript DOM things in the “overlay” line of thinking. So part of a “Day 1” paradigm, you will better leave that “Day 1” proving the work of “Day 2” is possible, and this was achieved via


function detecttspan() {
var tsrect=null;
var tss=document.getElementsByTagName('tspan');
for (var itss=0; itss<tss.length; itss++) {
tsrect=tss[itss].getBoundingClientRect();
alert('' + tss[itss].outerHTML + ' left:' + tsrect.left + ' top:' + tsrect.top);
}
}

… with the good news we started “Day 1” not being sure of “passed the test”, as you can see from today’s tutorial picture, and …

… this one illustrating work in the SVG tspan 11 letter word Speech Bubble changed select_palette.html web application.

Why 11? Tune in tomorrow.


Previous relevant Select Multiple Webpage Palette Speech Bubble Swipe Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Swipe Tutorial

Select Multiple Webpage Palette Speech Bubble Swipe Tutorial

Today’s tutorial is an amalgam of …

  1. concepts off Apple iOS Control Centre Tutorial … and …
  2. continuing on with the functionality of the recent Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial‘s External Javascript YouTube Audio Stream of Video web application ideas

… which, to us, is in the category of …

  • optional
  • experimental
  • quirky … and yet …
  • something we may well turn to for future endeavours … and so, worth it

… so, though there is opposition you can’t say I didn’t do it my way … which means, correct me if I’m wrong here, that means “I did it my way”that right … team?!.

We’re adding …

  • web application “swipe down and left from top right” … email after entering data … and …
  • web application “swipe up from bottom” … SMS after entering data

… user interaction “shortcuts” into the mix, via …


var firstx=null, firsty=null, pos3=-3, pos4=-3, nextx=null, nexty=null, slowitdown=false, isok=true, oktoemail=false, oktosms=false;
var wow=-1, woh=-1, wiw=-1, wih=-1;
var firstone=true;


function controlisok() {
isok=true;
}

function swipecheck(ev) {
if (!window.opener && isok) {
if (ev.touches) {
if (ev.touches[0].pageX) {
pos3 = ev.touches[0].pageX;
pos4 = ev.touches[0].pageY;
} else {
pos3 = ev.touches[0].clientX;
pos4 = ev.touches[0].clientY;
}
console.log('pos3 = ' + pos3 + ',pos4 = ' + pos4);
} else if (ev.clientX || ev.clientY) {
pos3 = ev.clientX;
pos4 = ev.clientY;
console.log('pos3 = ' + pos3 + ' ,pos4 = ' + pos4);
} else {
pos3 = ev.pageX;
pos4 = ev.pageY;
console.log('pos3 = ' + pos3 + ', pos4 = ' + pos4);
}


if (pos3 >= 0 && pos4 >= 0) {
if (firstx == null) {
firstx=pos3;
firsty=pos4;
slowitdown=true;
isok=false;
setTimeout(controlisok, 400);
} else if (pos3 != firstx || pos4 != firsty) {
nextx=pos3;
nexty=pos4;
// Swipe down left from top right
if (nextx < firstx && nexty > firsty && pos3 > eval(document.documentElement.clientWidth / 2) && pos4 < eval(document.documentElement.clientHeight / 2)) {
if (firstone) {
if (eval(firstx - nextx) > 5 && eval(nexty - firsty) && eval(window.innerWidth - firstx) < 90 && eval(firsty) < 90) {
firstone=false;
//alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
shapetodoemail(); // alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
}
}
// ... else swipe up from bottom
} else if (nexty < firsty && firsty > eval(document.documentElement.clientHeight / 2) && pos4 > eval(document.documentElement.clientHeight / 2)) {
if (firstone) {
if (eval(firstx - nextx) < 5 && eval(nexty - firsty) < 5 && eval(firsty) > eval(document.documentElement.clientHeight / 2)) {
firstone=false;
//alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
shapetodosms(); // alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
}
}
} else if (pos3 <= eval(document.documentElement.clientWidth / 2) || pos4 >= eval(document.documentElement.clientHeight / 2)) {
firstx=null;
firsty=null;
nextx=null;
nexty=null;
}
}
}
}
}

function gettodoemail() {
return oktoemail;
}

function settodoemail(towhat) {
oktoemail=towhat;
}

function shapetodoemail() {
oktoemail=true;
setTimeout(trytodoemail, 5000);
}

function trytodoemail() {
if (oktoemail) {
doemail();
}
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function gettodosms() {
return oktosms;
}

function settodosms(towhat) {
oktosms=towhat;
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function trytodosms() {
if (oktosms) {
dosms();
}
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function gwow() {
return wow;
}

function gwiw() {
return wiw;
}

function gwoh() {
return woh;
}

function gwih() {
return wih;
}

function getwow() {
if (window.opener) {
return window.opener.gwow();
} else {
return wow;
}
}

function getwoh() {
if (window.opener) {
return window.opener.gwoh();
} else {
return woh;
}
}

function getwiw() {
if (window.opener) {
return window.opener.gwiw();
} else {
return wiw;
}
}

function getwih() {
if (window.opener) {
return window.opener.gwih();
} else {
return wih;
}
}

function atstart() {
document.body.style.zoom = 1.0

var scale = 'scale(1)';
document.body.style.webkitTransform = scale; // Chrome, Opera, Safari
document.body.style.msTransform = scale; // IE 9
document.body.style.transform = scale; // General
wow=eval(window.outerWidth);
woh=eval(window.outerHeight);
wiw=eval(window.innerWidth);
wih=eval(window.innerHeight);
//alert('' + wih + ' vs ' + woh);
if (window.opener) {
firstone=false;
setTimeout(function(){
oktoemail=window.opener.gettodoemail();
oktosms=window.opener.gettodosms();
window.opener.settodoemail(false);
window.opener.settodosms(false);
}, 2000);
}
}

if (!window.screenLeft) {
window.screenLeft = window.screenX;
window.screenTop = window.screenY;
}

called into play via …


<body onload="atstart(); startsi(); dotdotdotten();" ontouchmove="swipecheck(event);" onmousemove="swipecheck(event);">

… in the changed select_palette.html web application.


Previous relevant Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial

The recent Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial‘s …

  • privacy for Group Talk “public” Bulletin Board functionalities …
  • involved logic for the two scenarios …
    1. data-applyprivacy=Y … via two prefixing spaces entered by originator of Group … completely hides relevant Group Talk Bulletin Board data from viewers outside that Group Talk
    2. data-applyprivacy=y … via one prefixing space entered by originator of Group … hides contact parts of Group Talk Bulletin Board data from viewers outside that Group Talk

    … but we had not “nuanced” the functionality for that second suboption on that first subpass

… and that is the work discussed today, a nuance that amounts to …

Allow non-group Bulletin Board readers see what we say but given cryptic username choices will not know how to contact that Group

That work took place in the PHP component of our Select Multiple Webpage Palette Speech Bubble web application as per

<?php

if (!isset($_GET['owner']) && isset($_GET['me']) && !isset($_GET['contact'])) {
$findings=explode(',', str_replace(';',',',str_replace('+',' ',urldecode($_GET['me']))));
} else if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
$aprivone=' data-applyprivacy="Y"';
$aprivtwo=' data-applyprivacy="y"';
}


if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
$prevcont="";
for ($i=(0 + 0); $i<sizeof($lines); $i++) {
$thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
if (strpos($thisline, $curgmt) !== false && strpos(str_replace("'",'"',$thisline), $aprivone) === false) { // && strpos(str_replace("'",'"',$thisline), $aprivtwo) === false) {
if (strpos(str_replace("'",'"',$thisline), $aprivtwo) !== false) {
$thatline=$thisline;
if (strpos($thatline, 'contact="') !== false && strpos(str_replace('contact=""',"contact=''",$thatline), 'contact="') !== false) {
while (strpos(str_replace('contact=""',"contact=''",$thatline), 'contact="') !== false) {
$thingtochange=explode('"', explode('contact="', str_replace('contact=""',"contact=''",$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
if (strpos($thatline, "contact='") !== false && strpos(str_replace("contact=''",'contact=""',$thatline), "contact='") !== false) {
while (strpos(str_replace("contact=''",'contact=""',$thatline), "contact='") !== false) {
$thingtochange=explode("'", explode("contact='", str_replace("contact=''",'contact=""',$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
if (strpos(str_replace("[]","",$thatline), "[") !== false && strpos(str_replace("[]","",$thatline), "]") !== false) {
while (strpos(str_replace("[]","",$thatline), "[") !== false && strpos(str_replace("[]","",$thatline), "]") !== false) {
$thingtochange=explode("]", explode("[", str_replace("[]","",$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
$prevcont.=$thatline;
} else {

$prevcont.=$thisline;
}
}
}
$vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
exit;
}

?>

… in the changed select_palette.php “eighth draft” PHP.


Previous relevant Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial

Meanwhile, back at some other ranch … somewhere … we’re some of the way down the line, with our recent …

  • Select Multiple Webpage Palette web application …
  • Bulletin Board subset of functionality, towards with it’s …
  • Group Talk (comma separated list of username/contacts) abilities … now offer …
  • Bulletin Board privacy

… as people in a Group Talk may appreciate. In other words, your generic Bulletin Board viewers would not see your Group Talk setup communications should the originator of any Group Talk now, either at …

  • best, as a To: + spaces appendage to a textarea line record (delimited by line feed) … ahead of a way with …
  • spaces prefixing to the prompt widow off right click or gesture events … starting the ball rolling …
  • populating a new data-applyprivacy global data attribute into the SVG

… allowing this new privacy functionality to work.

Again, we’ll need more than the work today to bed this in, but we now do not think there are any impassable concepts to its implementation.

And so, onto the recent Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial‘s work we have the changed select_palette.html web application helped out by the changed select_palette.php “seventh draft” PHP we have made a start making this “privacy dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial

Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial

Yesterday’s Select Multiple Webpage Palette Speech Bubble Emoji Tutorial warned you today …

we may have nuances yet to come

… and allowing for emojis within a Group Talk user’s username (via control-command-space for macOS or Mac OS X, logo key + . (period) for Windows, control+space for iOS, top left + for Android keyboard) be an identifier on their Speech Bubbles … well, it leaves us speechless with nuance!

Yesterday we were attempting to do this but had more success, today, with


/**
* Convert a string to HTML entities ... Thanks to https://zditect.com/code/javascript/easy-solution-to-encode-html-entities-in-javascript.html
*/
String.prototype.toHtmlEntities = function() {
return this.replace(/./gm, function(s) {
return (s.match(/[a-z0-9" . "\\" . "s]+/i)) ? s : '&#' + s.charCodeAt(0) + ';';
});
};


function maybeemoji(insvg) {
var outthing='', newoutthing='', jb=0;
var outsvg=insvg;
//alert('0:' + outsvg);
if (outsvg.indexOf(' data-otherc') != -1 && outsvg.indexOf(' data-ip') != -1) {
outsvg=outsvg.replace(outsvg.split(' data-otherc')[1].split(' data-ip')[0],'').split('97%')[0];
}

//alert(outsvg);

outhtmlentities='';
nonouthtmlentities='';

var nonencodeds=outsvg.split('&#');
for (jb=1; jb<nonencodeds.length; jb++) {
if (eval('' + nonencodeds[jb].split(';')[0]) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
newoutthing+=String.fromCodePoint(eval('' + nonencodeds[jb].split(';')[0]));
if (nonencodeds[jb] != (nonencodeds[jb].split(';')[0] + ';')) {
nonouthtmlentities=' ';
}
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
}
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

if (outhtmlentities == '') {
if (outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' ').indexOf('&#') >= 0) {
//alert('2987:' + outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' '));
nonencodeds=outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' ').split('&#')
for (jb=1; jb<nonencodeds.length; jb++) {
if (eval('' + nonencodeds[jb].split(';')[0]) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
newoutthing+=String.fromCodePoint(eval('' + nonencodeds[jb].split(';')[0]));
if (nonencodeds[jb] != (nonencodeds[jb].split(';')[0] + ';')) {
nonouthtmlentities=' ';
}
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
}
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

}
}


if (outhtmlentities == '') {
//alert(987);
var encodedStr=outsvg.replace(/[\u00A0-\u9999<>\&]/g, function(i) {
if (eval('' + i.charCodeAt(0)) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+i.charCodeAt(0)+';';
newoutthing+=String.fromCodePoint(eval('' + i.charCodeAt(0)));
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+i.charCodeAt(0)+';';
}
return '&#'+i.charCodeAt(0)+';';
});
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

if (outhtmlentities == '') {
if (document.getElementById('myip').value != '' && insvg.replace(/\'/g,'"').indexOf(' data-owner="') != -1 && insvg.replace(/\'/g,'"').indexOf(' data-contact="') != -1) {
var basisstr=insvg.replace(/\'/g,'"').split(' data-owner="')[1].split('"')[0] + insvg.replace(/\'/g,'"').split(' data-contact="')[1].split('"')[0] + document.getElementById('myip').value;
var bcnt=999, koffset=0;
for (var ib=0; ib<basisstr.length; ib++) {
//if (bcnt == 999) { bcnt=129293; }
//bcnt+=eval('' + basisstr.substring(ib).charCodeAt(0));
koffset+=eval('' + basisstr.substring(ib).charCodeAt(0));
}
if (koffset > 0) {
bcnt+=Math.round(eval(eval('' + koffset) / 10));
var itries=0;
if (4 == 5) { bcnt=129293; }
while (supports_emoji(String.fromCodePoint(eval('' + bcnt)))) {
bcnt++;
itries++;
if (itries >= 230) { bcnt=129293; }
}
//alert(bcnt);
outthing='&#' + bcnt + ';';
newoutthing+=String.fromCodePoint(eval('' + bcnt));
}
}
}
return insvg.replace('></text>', '>' + newoutthing + '</text>').replace(" data-emoji=''", " data-emoji='" + newoutthing + "'").replace(' data-emoji=""', ' data-emoji="' + newoutthing + '"');
}

… in the changed select_palette.html web application helped out by the changed select_palette.php “sixth draft” PHP we have made a start making this “emoji dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble Emoji Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Emoji Tutorial

Select Multiple Webpage Palette Speech Bubble Emoji Tutorial

The reason for today’s efforts with our latest web application have a similar theme to yesterday’s Select Multiple Webpage Palette Speech Bubble IP Address Tutorial‘s efforts, namely …

help differentiate Speech Bubbles of different users in a Group Talk arrangement with our public Bulletin Board functionality

Today’s research into displaying emoji text at the pointy corner of the Speech Bubble hopes to help out here, and though we may have nuances yet to come, we can say with the changed select_palette.html web application helped out by the changed select_palette.php “fifth draft” PHP we have made a start making this “emoji dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble IP Address Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble IP Address Tutorial

Select Multiple Webpage Palette Speech Bubble IP Address Tutorial

To further differentiate Group Talk users accessing the public Bulletin Board of our web application talked about in Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

  • we need to consider user IP addresses, as Wikipedia describes …

    An Internet Protocol address (IP address) is a numerical label such as 192.0.2.1 that is assigned to a device connected to a computer network that uses the Internet Protocol for communication.[1][2] IP addresses serve two main functions: network interface identification, and location addressing.

    Some readers may have noted for a couple of days now, our newly introduced PHP has been assisting the calling HTML, and itself, by remembering the user’s IP address. Yesterday, it was to help colour code Speech Bubbles, and today, it helps in amongst …

    • username … and …
    • contact … set lists … with …
    • IP address

    … to differentiate email and SMS invitation origin calls of our web application, as to who that user has been described as by the originator of the Group Talk settings with the changed select_palette.html web application helped out by the changed select_palette.php “fourth draft” PHP.


    Previous relevant Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial is shown below.

    Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

    Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

    The concept of Group Talk started with yesterday’s Select Multiple Webpage Palette Speech Bubble Invitations Tutorial. It made us think that we should start thinking about the differentiation of voices amongst the Speech Bubbles of the public Bulletin Board we’re supporting with the associated web application and its user mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic talents.

    We decided that one way could be to …

    • Colour Code the background colour of the Speech Bubbles via the user IP address …
      <?php

      $gbcol="0,0,255";

      function server_remote_addr() {
      global $gbcol;
      $rma = $_SERVER['REMOTE_ADDR'];
      $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
      $uas=explode('.', str_replace('::1','65.254.95.247',$rma)); // 65.254.93.32

      if (sizeof($uas) >= 3) {
      $gbcol='' . ($uas[0] % 256);
      $gbcol.=',' . ($uas[1] % 256);
      $gbcol.=',' . (($uas[2] + $uas[(-1 + sizeof($uas))]) % 256);
      }

      // you can add different browsers with the same way ..
      if(preg_match('/(chromium)[ \/]([\w.]+)/', $ua))
      $rma = '000000'.$rma;
      elseif(preg_match('/(chrome)[ \/]([\w.]+)/', $ua))
      $rma = '00000'.$rma;
      elseif(preg_match('/(safari)[ \/]([\w.]+)/', $ua))
      $rma = '0000'.$rma;
      elseif(preg_match('/(opera)[ \/]([\w.]+)/', $ua))
      $rma = '000'.$rma;
      elseif(preg_match('/(msie)[ \/]([\w.]+)/', $ua))
      $rma = '00'.$rma;
      elseif(preg_match('/(mozilla)[ \/]([\w.]+)/', $ua))
      $rma = '0'.$rma;
      return str_replace(":", "_", $rma);
      }

      server_remote_addr();

      ?>
    • when a Group Talk invitation is sent out do not have the sender username and/or contact as the recipient username and/or contact

    … moving further along with the changed select_palette.html web application helped out by the changed select_palette.php “third draft” PHP.


    Previous relevant Select Multiple Webpage Palette Speech Bubble Invitations Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Invitations Tutorial

    Select Multiple Webpage Palette Speech Bubble Invitations Tutorial

    Yesterday’s Select Multiple Webpage Palette Speech Bubble PHP Tutorial‘s …

    • PHP embellishment of …
    • the day before’s SVG data enhancemants … today improves yesterday’s …
    • public Bulletin Board via user mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logics … today, adding …
    • optional invitation communication email and/or SMS logics via Group Talk set comma separated optional user username/contact entered data set lists helping with Group Talk filtering means of filtering the Speech Bubble data

    … with the changed select_palette.html web application helped out by the changed select_palette.php “second draft” PHP.


    Previous relevant Select Multiple Webpage Palette Speech Bubble PHP Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble PHP Tutorial

    Select Multiple Webpage Palette Speech Bubble PHP Tutorial

    Yesterday’s Select Multiple Webpage Palette Speech Bubble Data Tutorial‘s …

    • data … begets …
    • PHP
    … around here a lot, as PHP is our domain’s “first call” serverside language.

    Add to that that “yesterday’s tomorrow is today” we’re supposed to be finished with our “short two day mini project sojourn”, and in a crude way we have, but we want a third day to add nuance to the arrangements with data filtering and more sophistication regarding collection, within the approach of our new …

    Bulletin Board of Speech Bubbles

    … that becomes a …

    • shareable
    • public (on this second day, a bit too public)
    • reverse chronological
    • speech bubble

    … resource, if the user avails themselves of the mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic smarts with the changed select_palette.html web application, now helped out by select_palette.php “first draft” PHP …


    <?php
    // select_palette.php
    // RJM Programming
    // May, 2025

    $prevcont="";
    $curcont="";
    $curgmt=gmdate("Ymd");
    $newlines=[];

    if (isset($_POST['indata'])) {
    $ind=str_replace('+',' ',urldecode($_POST['indata']));
    $lines=explode('<svg name="', $ind);
    if (!file_exists('/tmp/select_palette.htm')) {
    file_put_contents('/tmp/select_palette.htm', '');
    } else {
    $prevcont=file_get_contents('/tmp/select_palette.htm');
    if (strpos($prevcont, '<svg name="' . $curgmt) === false) {
    file_put_contents('/tmp/select_palette.htm', '');
    } else {
    $curcont=$prevcont;
    }
    }


    for ($i=1; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false && strpos($thisline, ' data-public="n"') === false && (strpos($thisline, ' data-owner="') !== false && strpos($thisline, ' data-owner=""') === false) || (strpos($thisline, ' data-contact="') !== false && strpos($thisline, ' data-contact=""') === false)) {
    if (strpos($curcont, $thisline) === false) {
    $curcont.=$thisline;
    }
    }
    }
    file_put_contents('/tmp/select_palette.htm', $curcont);
    echo '<html><body></body></html>';
    exit;

    } else if (isset($_GET['extract'])) {
    if (file_exists('/tmp/select_palette.htm')) {
    $prevcont=file_get_contents('/tmp/select_palette.htm');
    if (strpos($prevcont, '<svg name="' . $curgmt) === false) {
    file_put_contents('/tmp/select_palette.htm', '');
    }
    $lines=explode('<svg name="', $prevcont);
    rsort($lines);

    if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
    $prevcont="";
    for ($i=0; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false) {
    $prevcont.=$thisline;
    }
    }
    $vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
    echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
    exit;
    } else {
    $prevcont="";
    for ($i=0; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false) {
    $isok=true;
    if (isset($_GET['owner']) && strpos(strtolower($thisline), ' data-owner="' . strtolower(str_replace('+',' ',urldecode($_GET['owner'])) . '"')) === false) {
    $isok=false;
    }
    if (isset($_GET['contact']) && strpos(strtolower($thisline), ' data-contact="' . strtolower(str_replace('+',' ',urldecode($_GET['contact'])) . '"')) === false) {
    $isok=false;
    }
    if (isset($_GET['me']) && strpos(strtolower($thisline), strtolower('="' . str_replace('+',' ',urldecode($_GET['me'])) . '"')) === false) {
    $isok=false;
    } else if (isset($_GET['me'])) {
    $isok=true;
    }
    if ($isok) { $prevcont.=$thisline; }
    }
    }
    $vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
    echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
    exit;
    }

    }

    }

    ?>

    … meaning …

    Data … is enhanced … … by … PHP


    Previous relevant Select Multiple Webpage Palette Speech Bubble Data Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Data Tutorial

    Select Multiple Webpage Palette Speech Bubble Data Tutorial

    Onto yesterday’s Select Multiple Webpage Palette Speech Bubble Tutorial, today, we’re preparing for tomorrow.

    You heard it here first.

    Admittedly, nothing startling there, but it was the first time we remember …

    • embellishing SVG data … with so much …
    • what we normally associate with HTML element work …
      1. global data attributes
      2. id and name attribution …
      3. event logic

    Yes, all possible with SVG, though not the first thing we think of using SVG data within our HTML. We normally think, just display thoughts, but today, we’re paving the way for tomorrow, and our “short two day mini project sojourn” will become clearer regarding motives, then, or get hints trying with strategically changed select_palette.html web application‘s mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic …


    var taar=[];
    var preadd=0;
    var windowuser='', windowcontact='', windowask=true, suffix='';


    function defwuwc(inwindowuser,inwindowcontact) {
    if ((inwindowuser + inwindowcontact) == '') { return ''; }
    if (inwindowuser != '' && inwindowcontact != '') { return inwindowuser + '[' + inwindowcontact + ']'; }
    if (inwindowuser != '' && inwindowcontact == '') { return inwindowuser; }
    return inwindowcontact;
    }


    function treg(ttis) {
    var dotherest=false;
    var ctown=defwuwc(windowuser,windowcontact);
    var ourwindowask=windowask;
    preadd=1;
    if (ttis.outerHTML.indexOf(' data-public=') != -1) {
    if (windowuser == '' && windowcontact == '' && windowask) {
    ctown=prompt("To share on today's board enter a username and/or contact string (append space to remember, append another space to apply to all other Speech Bubbles) ... eg. " + String.fromCharCode(10) + "Robert Metcalfe[rmetcalfe15@gmail.com]", defwuwc(windowuser,windowcontact));
    }
    if (ctown == null) { ctown=''; }
    if (ctown != ctown.replace(/\ \ $/g,'')) {
    windowask=false;
    dotherest=true;
    ctown=ctown.trim();
    } else if (ctown != ctown.replace(/\ $/g,'')) {
    windowask=false;
    ctown=ctown.trim();
    }
    if (ctown.indexOf('[') > 0 && ctown.indexOf(']') != -1) {
    windowuser=ctown.split('[')[0];
    windowcontact=ctown.split('[')[1].split(']')[0];
    } else if (ctown.indexOf('[') == 0 && ctown.indexOf(']') != -1) {
    windowcontact=ctown.split('[')[1].split(']')[0];
    windowuser=windowcontact;
    } else {
    windowuser=ctown;
    windowcontact='';
    }
    if (windowuser != '') {
    ttis.setAttribute('data-owner', windowuser);
    }
    if (windowcontact != '') {
    ttis.setAttribute('data-contact', windowcontact);
    }
    if (windowuser != '' || windowcontact != '') {
    ttis.setAttribute('data-public', 'y');
    ttis.innerHTML=ttis.innerHTML.replace(/\<text\ /g,'<text stroke="blue" ');
    if (dotherest) {
    var svgs=document.getElementsByTagName('svg');
    for (var isvgs=0; isvgs<svgs.length; isvgs++) {
    if (svgs[isvgs].outerHTML.indexOf(' stroke=') == -1) {
    if (('' + svgs[isvgs].id) != ('' + ttis.id)) {
    if (windowuser != '') {
    svgs[isvgs].setAttribute('data-owner', windowuser);
    }
    if (windowcontact != '') {
    svgs[isvgs].setAttribute('data-contact', windowcontact);
    }
    if (windowuser != '' || windowcontact != '') {
    svgs[isvgs].setAttribute('data-public', 'y');
    }
    svgs[isvgs].innerHTML=svgs[isvgs].innerHTML.replace(/\<text\ /g,'<text stroke="blue" ');
    }
    }
    }
    }
    } else {
    windowask=ourwindowask;
    }
    }
    //alert(ttis.outerHTML);
    setTimeout(function(){ preadd=0; }, 5000);
    }


    Previous relevant Select Multiple Webpage Palette Speech Bubble Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Tutorial

    Select Multiple Webpage Palette Speech Bubble Tutorial

    Yesterday’s Select Multiple Webpage Palette Popup Tutorial modus operandi revolved around …

    delimitation rules

    … as so many matters do with written down text.

    We rethought yesterday’s HTML textarea start regarding line feed Speech Bubble creation possibilities, and thought …

    It’s too unwieldy for a user to add to their textual data when what they really want to do is Speech Bubbles.

    Yesterday’s thinking really hoped the user entered a Speech Bubble data one at a time, but what if the user wants to enter several Speech Bubbles in the one textarea incarnation?

    Good question. (Calling all ducks with a slow paddle going?!)

    Yes, but there is that ~~ existing delimitation rule, as of yesterday equating to a line feed. Supposing ~~ was given the delimitation roles …

    1. the character sets …
      lineFeed~~lineFeed
      … separate Speech Bubbles … ie. in the textarea a ~~ record is all there is on a line of textarea text
    2. the character set …
      ~~lineFeed
      … at the start wipes out any previously remembered text data and starts again
    3. else retain the ~~ mapping to lineFeed

    … in combination with the textarea always first presented blank and the previous Speech Bubble or Lines of Text remembered and retained unless the middle condition above happens?

    Well, we think it’s a plan, and led us to be able to share a Speech Bubble presentation of Shakepeare’s Act 1 Scene 1 of Macbeth. And so, today with the changed select_palette.html web application, onto yesterday’s …

    one textarea element

    … paradigm, we present …

    • previous text data in a details/summary “reveal” mode of use above the textarea element, as relevant
    • and below the textarea element we now have buttons to Email or SMS your text creations off to a recipient

    … harnessing hashtag navigational data methodologies in “a” “mailto:” (email) or “sms:” (SMS) prefixing href attributes, as per …


    function doemail() {
    var anchor=null;
    if (woois) {
    if (!woois.closed) {
    if (woois.document.getElementById('myta').outerHTML.indexOf(' data-done="y"') == -1) {
    if (woois.document.getElementById('myta').value.trim() != '') {
    woois.document.getElementById('myta').setAttribute('data-done', 'y');
    setTimeout(doemail, 6000);
    return '';
    }
    } else if (woois.document.getElementById('myta').value.trim() != '') {
    setTimeout(doemail, 6000);
    return '';
    }
    woois.close();
    woois=null;
    setTimeout(doemail, 6000);
    return '';
    }
    }
    var emis=prompt('Please enter email address to send to.', '');
    if (emis == null) { emis=''; }
    if (emis.indexOf('@') != -1) {
    anchor = document.createElement('a');
    anchor.href = 'mailto:' + emis.trim() + '?subject=My%20Speech%20Bubble%20data&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    document.body.appendChild(anchor);
    anchor.innerHTML='Email';
    anchor.target='_top';
    anchor.click();
    } else if (emis.trim() != '' && emis.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
    anchor = document.createElement('a');
    anchor.href = 'sms:' + emis.trim() + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    anchor.innerHTML='SMS';
    anchor.target='_top';
    anchor.click();
    }
    }

    function dosms(){
    var anchor=null;
    if (woois) {
    if (!woois.closed) {
    if (woois.document.getElementById('myta').outerHTML.indexOf(' data-done="y"') == -1) {
    if (woois.document.getElementById('myta').value.trim() != '') {
    woois.document.getElementById('myta').setAttribute('data-done', 'y');
    setTimeout(dosms, 6000);
    return '';
    }
    } else if (woois.document.getElementById('myta').value.trim() != '') {
    setTimeout(dosms, 6000);
    return '';
    }
    woois.close();
    woois=null;
    setTimeout(dosms, 6000);
    return '';
    }
    }
    var emis=prompt('Please enter SMS number to send to.', '');
    if (emis == null) { emis=''; }
    if (emis.indexOf('@') != -1) {
    anchor = document.createElement('a');
    anchor.href = 'mailto:' + emis.trim() + '?subject=My%20Speech%20Bubble%20data&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    document.body.appendChild(anchor);
    anchor.innerHTML='Email';
    anchor.target='_top';
    anchor.click();
    } else if (emis.trim() != '' && emis.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
    anchor = document.createElement('a');
    anchor.href = 'sms:' + emis.trim() + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    anchor.innerHTML='SMS';
    anchor.target='_top';
    anchor.click();
    }
    }


    Previous relevant Select Multiple Webpage Palette Popup Tutorial is shown below.

    Select Multiple Webpage Palette Popup Tutorial

    Select Multiple Webpage Palette Popup Tutorial

    Regarding yesterday’s Select Multiple Webpage Palette Primer Tutorial

    • you start with an outlandish premise …
    • it stays “outlandish” select (dropdown) element wise on non-mobile … but …
    • catering for mobile …
    • you are forced to encase it in a hosting div element (with the onmousedown and ontouchdown precursor events to onclick)

    … all contributing to getting us to a point, today, we can say we’ve added a layer of (useful, extra) functionality, by …

    • no longer asking for user interactive input via a Javascript prompt window … but, instead, like with Background Image Foreground Content Tutorial … we …
    • ask for user interactive input via a window.open (ie. popup) “here’s looking at you, kid” window.opener incarnation guise of our changed select_palette.html web application … just consisting of …
    • one textarea element …
      1. still capable of ~~ delimitation as with the Javascript prompt window thinking … but also now …
      2. harnessing the talents of a textarea line feed delimitation within it’s value attribute

      … able to extend functionality towards decent …

    • speech bubble feeling thoughts (so far, just) … because …
    • it opens up the idea that the div element innerHTML attribute can be the SVG we had previously been supplying as background HTML/CSS (via Javascript DOM) data

    Cute, huh?! (ahead of the “Speech Bubble styling” niceties making it really cute, yet, for us … but who knows what you can achieve on the “cute styling front”?!).


    Previous relevant Select Multiple Webpage Palette Primer Tutorial is shown below.

    Select Multiple Webpage Palette Primer Tutorial

    Select Multiple Webpage Palette Primer Tutorial

    In the world of web applications, there are often many ways to approach any given requirement. Like with yesterday’s Select Multiple Mobile Background Image Tutorial, today’s “albeit a bit out there idea” is to …

    • offer a select (multiple attribute) “dropdown” HTML element …
    • as a webpage covering …
    • template or palette … where the user …
    • writes user defined lines of words created

    … onto. Pretty simple idea for a “first then second draft“! But maybe not the first idea to spring to mind regarding making such an idea happen?!


    Previous relevant Select Multiple Mobile Background Image Tutorial is shown below.

    Select Multiple Mobile Background Image Tutorial

    Select Multiple Mobile Background Image Tutorial

    We had occasion to revisit Window LocalStorage Client Versus Server Map Tutorial‘s web application today changed this way to end up with wls_vs_php.htm, on an iPad, and saw how initially lacking was the advice on how to work the Capital City to Country quiz. The reason, primarily, in our view, is that on mobile platforms an element such as …


    <select class=dglow onclick=" console.log('67234'); noif(); " title='Please select Capital(s) below to get Countries Report ...' onfocusout=" document.getElementById('myrepsb').className='dglow'; tablemode = ''; nothere=true; updatecountries(null);" style='width:300px;margin-top:0px;margin-left:0px;vertical-align:top;height:100vh;background-color:lightblue;' id=scapitals multiple>
    // innard options //
    </select>

    … you just see words to the effect …

    0 items …

    … but we’d see more use for this select element “opened up” on initialization. As we read, and believed, via this useful link, thanks, this “programmatical click on mobile platforms” to open up such a select element is not easy. So we decided to go down the route of …

    • to a select multiple element …
    • on mobile …
    • background image …
    • at top right …
    • that is wording advice “Click/tap me”
    • when first encountered

    … and we came up with the document.body onload event call “new Javascript code snippet” …


    if (document.URL.indexOf('?') == -1) {
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    document.getElementById('scapitals').click(); // this is just wishful thinking, but no error is caused, and you never know?
    document.getElementById('scapitals').style.background="url(\"data:image/svg+xml;base64," + window.btoa("<svg xmlns='http://www.w3.org/2000/svg' width='126' height='48' viewport='0 0 100 100' style='border-radius:15px;background-color:rgba(0,0,255,0.3);fill:black;font-family:Verdana;font-size:17px;'><text x='5%' y='60%'>Click/tap me</text></svg>") + "\") no-repeat top right";
    }
    }

    Next best approach, we’d say?!


    Previous relevant Window LocalStorage Client Versus Server Map Tutorial is shown below.

    Window LocalStorage Client Versus Server Map Tutorial

    Window LocalStorage Client Versus Server Map Tutorial

    Get a good map, and a goodly number of times you’ll want a map of smaller or larger scale than the one you have. Murphy’s Law? This is probably why in the wonderful woooooooorrrrrrrrlllllld of Google Charts they have included …

    • Geo Chart topographic map of the world or of regions
    • Map Chart terrestrial/satellite map of your group of markers at a zoom level of your choosing

    … and hope you can see that the latter can save the day for a Short Distance Trip (corner shop, anyone?!).

    So we’ve added onto yesterday’s Window LocalStorage Client Versus Server Timeline Tutorial progress a new toggling button to view a scenario in either Google Chart scenario above.

    You can see this integration work with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link supervising a tweaked geo_chart.php Geo Chart interfacer.


    Previous relevant Window LocalStorage Client Versus Server Timeline Tutorial is shown below.

    Window LocalStorage Client Versus Server Timeline Tutorial

    Window LocalStorage Client Versus Server Timeline Tutorial

    Up to yesterday’s Window LocalStorage Client Versus Server User Tutorial‘s progress, our Capital City Find Matching Country Report web application project was all about …

    • where (and capital of “what”) … but we often seek out a way to add into the mix that 4th dimension …
    • when (ie. time)

    … and regarding the current project, a …

    • where “map” … can interface with a …
    • when “Trip Plan Itinerary”

    … and for this purpose, we’re going to interface to the excellent Google Charts Annotated Timeline Chart, thanks, because it combines links of “time” to “user annotations” in a timeline way, that similar way you might describe the qualities of a Trip, even before you’ve gone on that trip. We’ve also added it so that an unordered places list can be turned into a Trip Plan Itinerary at the click/touch of a new map 🗺 &#128506; emoji button.

    Again, see how these timeline amendments were achieved with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link and annotatedtimeline_chart.php which changed quite a lot.


    Previous relevant Window LocalStorage Client Versus Server User Tutorial is shown below.

    Window LocalStorage Client Versus Server User Tutorial

    Window LocalStorage Client Versus Server User Tutorial

    The inherent weakness with our current Capital City Find Matching Country Report web application project, to our minds, was that places of interest are not restricted to the Capital Cities of Countries, especially when “Trip Planning”. On the other hand, it would be impossible to cater for every “place” in the world. That is far too subjective for good web application applicability. What would be good though, is to allow in user defined …


    Place name, Country name

    … terms, the definitions of interest to a user. We can ask this …

    • flagged by the click/touch of an emoji button … and …
    • the interactive entry presented via a Javascript prompt window

    . When thinking of data applicable to an individual, then that can be catered for by recording it in localStorage where it will be recalled on the next execution of that web application in the same web browser.

    This, along with a Colour Wheel of the “nearest TimeZone place” onto the existing logic of yesterday’s Window SessionStorage Client Versus Server Order Tutorial progress could make for a more useful and practical tool for those Trip Planners out there!

    See how this was achieved with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.

    Did you know?

    To click/touch one of those Google Chart Geo Chart lines between Emoji Flag Markers will show a new Google Maps directions web page with transport times and detail, as well as an inhouse crow fly distance of that trip leg, as shown up the top right of today’s tutorial picture.


    Previous relevant Window SessionStorage Client Versus Server Order Tutorial is shown below.

    Window SessionStorage Client Versus Server Order Tutorial

    Window SessionStorage Client Versus Server Order Tutorial

    If we are to honour our thoughts of being able to use our current Capital City Find Matching Country Report web application as a Trip Planner …

    Our primary integration today is to (software) integrate the great Weather Underground and its great API service for autocomplete name searches for weather (and hurricane) information. Why bother? Well, can you not envisage a user using that Ajax functionality of yesterday’s Window SessionStorage Client Versus Server Ajax Tutorial as a trip planner, perhaps, or as a “checking up on relatives overseas” tool, perhaps? And not all the capital cities are timezone places, and so for some of those we can use Weather integration to still show apt online information when click/touching a Countries Report row. Speaking of this “row”, we make an improvement whereby on a first click of a right hand (Country) row cell, that cell is not initially a contenteditable=”true” one (that may frustrate showing the keyboard on mobile, when most likely it was the row touch intended), but then becomes a contenteditable=”true” cell henceforth.

    … then yesterday’s Window SessionStorage Client Versus Server Flags Tutorial “progress to now” needs to take notice of a user’s order of multiple select (dropdown) element click/touching of Capital City option (sub)elements, just as we did with the recent User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial‘s web application project to allow for a user ordered YouTube video playlist.

    Because what is a Trip Planner without an ordered trip? Well, that is debatable, but what isn’t (debatable), is that there will be people in the world who appreciate the “mapping out” of a proposed Trip Planning Itinerary. What could we call on here? We can think of the Google Chart Geo Chart work around about the time of Google Geo Chart Co-ordinate Emojis Tutorial, when we started using …

    • a world map … with …
    • emoji markers … and optionally …
    • joined up by straight lines

    … an idea for a Trip Plan itinerary synopsis, perhaps?!

    If you examined closely yesterday’s code changes you will have noticed our collecting of TimeZone Place geographical latitude and longitude information. Today, we start making use of that preparatory work with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.

    Stop Press

    The “emoji markers” above (as of 2 January 2020) will be “country flags” (as per Window SessionStorage Client Versus Server Flags Tutorial ideas), as defined.


    Previous relevant Window SessionStorage Client Versus Server Flags Tutorial is shown below.

    Window SessionStorage Client Versus Server Flags Tutorial

    Window SessionStorage Client Versus Server Flags Tutorial

    Yes, there’s more to do onto yesterday’s Window SessionStorage Client Versus Server CSS Tutorial‘s Capital City Find Matching Country Report web application project, in our eyes. We have not even mentioned “Internationalization” as a concept up to now. In this line of thinking …

    Did you know?

    Emoji flags via ISO 2 character country codes are dead easy via Regional Indicator Symbol characters …


    var lri="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    var dri=["127462","127463","127464","127465","127466","127467","127468","127469","127470","127471","127472","127473","127474","127475","127476","127477","127478","127479","127480","127481","127482","127483","127484","127485","127486","127487"];

    var thiscc='AU'; // ISO 2 character countrycode for Australia
    var ccsuff='', ccchar=' ';
    for (var iccsuff=0; iccsuff<thiscc.length; iccsuff++) {
    ccchar=thiscc.substring(iccsuff, eval(1 + eval('' + iccsuff))).toUpperCase();
    ccsuff+='&#' + dri[eval('' + lri.indexOf(ccchar))] + ';';
    }
    document.getElementById('lastflag').innerHTML=ccsuff;

    … to result in (via <span style=font-size:64px;>&#127462;&#127482;</span>) …


    🇦🇺

    … providing interest and general translatability to the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.


    Previous relevant Window SessionStorage Client Versus Server CSS Tutorial is shown below.

    Window SessionStorage Client Versus Server CSS Tutorial

    Window SessionStorage Client Versus Server CSS Tutorial

    Further to yesterday’s Window SessionStorage Client Versus Server Integration Tutorial we have a two pronged improvements set for you today with our current Capital City Find Matching Country Report web application project …

    • CSS styling changes … and …
    • additional functionality for Email and SMS links back to our current Capital City Find Matching Country Report web application project (to complete the cycle)

    We use several modes of CSS application (the first and last of particular relevance to today’s “highlighting of workflow” improvements) …

    … the “static” measures often helping to highlight the web application’s main workflow of user interaction and the “dynamic” measures helping to alert the user as to where to proceed with their “workflow”.

    In terms of CSS styling work …

    1. for non-mobile platforms we allow for more columns to be applied to our Capitals select (dropdown) element (in order to reduce some user scrolling, as does our new additional A-Z letter basis sorting functionality) as per … the “dynamic” Javascript DOM “class” modifications

      if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
      document.getElementById('lefttd').className='lefttd';
      }

      … dovetailing with the “static” internal CSS coding

      <style>
      .lefttd {
      column-count: 4;
      max-height: 35%;
      vertical-align: top;
      max-width: 70%;
      font-size: 8px;
      background-color: rgba(205,205,205,0.5);
      background-image: -webkit-gradient(
      linear,
      right bottom,
      left top,
      color-stop(0, rgba(205, 205, 205, 0.8)),
      color-stop(0.50, rgba(255, 255, 0, 0.2))
      );
      background-image: -o-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -moz-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -webkit-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -ms-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: linear-gradient(to left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);

      }
      </style>

      … and please note that around here at RJM Programming we have a “far from hard and fast rule” (but a rule regardless) regarding HTML element ID and class attributes that they concern (and (usually) be compartmentalised into) Javascript (DOM) manipulations and CSS styling issues respectively … and add a linear-gradient background to the table cell when expecting the initial user interaction on non-mobile platforms
    2. a “dynamic” Javascript DOM “class” modification … document.getElementById(‘myrepsb’).className=’dglow’; … is made to the “Report…” button at the Capitals select (dropdown) onfocusout event so as to highlight (with “glow” inspired styling) where user interaction may flow to

    As far as links go, you may expect to need serverside means to construct these in online Email and SMS message interfacing, but email (client program) products like Gmail parse your ascii text and convert http: or https: protocol URLs in your Email body to hyperlinks, as does the Messages SMS application here on this MacBook Pro using macOS Mojave. Cute, huh?! So to close the circle back from remote thar’ parts back to our web application is a simple matter of, in broad brush terms …

    • adding two new buttons called “Email Columns and Links …” and “SMS Columns and Links …” that …
    • set a global variable andlinkto = true; … setting in play, within the report writing code (that likes monospaced fonts) …
    • add a new links column to the right with URLs like …
      https://www.rjmprogramming.com.au/HTMLCSS/wls_vs_php.htm?andgo=y&countries=Belize&capitals=Belmopan
      … to tell your client programs to form the hyperlinks for us (if they are “of the mood”, that is!)

    To improve user experience we use “dynamic” Javascript DOM HTML “style” attribute change means to easier close the “Colour Wheel” helper web application “above the fold” by changing the CSS z-index (Javascript DOM [element].style.zIndex) of elements accordingly, when the user clicks other elements. You can see all this with the first “the changed” link above, where all “glow” CSS styling will also feature prominently.


    Previous relevant Window SessionStorage Client Versus Server Integration Tutorial is shown below.

    Window SessionStorage Client Versus Server Integration Tutorial

    Window SessionStorage Client Versus Server Integration Tutorial

    We hope, when performing a “software integration” task, that the two or more components of that integration work with each other’s talents, rather than a big tussle like reinventing the wheel. This ideal makes the work …

    • sometimes difficult but rewarding because …
    • the differences between two independent software components can be quite large and daunting … and the programmer has to see that …
    • care is applied so as not to wreck previous functionality and integrations in making the current integration work

    … and that is why we’ve made corollaries to “building from scratch” (when planning and design is a huge component) can be a lot simpler than a software integration “renovation”, in the past, here at this blog.

    Our primary integration today is to (software) integrate the great Weather Underground and its great API service for autocomplete name searches for weather (and hurricane) information. Why bother? Well, can you not envisage a user using that Ajax functionality of yesterday’s Window SessionStorage Client Versus Server Ajax Tutorial as a trip planner, perhaps, or as a “checking up on relatives overseas” tool, perhaps? And not all the capital cities are timezone places, and so for some of those we can use Weather integration to still show apt online information when click/touching a Countries Report row. Speaking of this “row”, we make an improvement whereby on a first click of a right hand (Country) row cell, that cell is not initially a contenteditable=”true” one (that may frustrate showing the keyboard on mobile, when most likely it was the row touch intended), but then becomes a contenteditable=”true” cell henceforth.

    As a user experience improvement for “trip planners” perhaps, we allow the user to alphabetically sort the presented select (dropdown) element entries …


    var firstopt='';
    var wasopts='';
    var restopts='';

    function readyitforsort(iselid) {
    var optsare=[];
    var huhisel=document.getElementById(iselid).innerHTML;
    var huhsopts=huhisel.split('</option>');
    for (var ihuh=0; ihuh<huhsopts.length; ihuh++) {
    if (huhsopts[ihuh].trim() != '') {
    if (firstopt == '') {
    firstopt=huhsopts[ihuh] + '</option>';
    } else {
    wasopts+=huhsopts[ihuh].replace('option ','option data-ih="' + (huhsopts[ihuh].split('>')[eval(-1 + huhsopts[ihuh].split('>').length)] + '" ')) + '</option>';
    optsare.push(huhsopts[ihuh].replace('option ','option data-ih="' + (huhsopts[ihuh].split('>')[eval(-1 + huhsopts[ihuh].split('>').length)] + '" ')) + '</option>');
    }
    }
    }
    optsare.sort();
    for (var jhuh=0; jhuh<optsare.length; jhuh++) {
    restopts+=optsare[jhuh];
    }
    }

    … controlled by a new dropdown in the left hand column header cell.

    We also allow the user to move the iframe element with some positioning emoji buttons near the “Close” button one (of yesterday’s work).

    Into the future, too, we’ll have more to say regarding the germination of an idea “to allow a mobile onmouseover simulator (of sorts)” be to allow the user to perform a swipe across an individual HTML element of interest on mobile platforms (ie. harness ontouchmove event) as per (so far) … kicked off by “<body onload=” setTimeout(athn, 5000); “>” …


    var last24='';
    var rectdc;

    function nodivalert() {
    document.getElementById('divalert').style.display='none';
    document.getElementById('divalert').style.zIndex='-456';
    document.getElementById('divalert').style.left=('-' + rectdc.left).replace('px','') + 'px';
    document.getElementById('divalert').style.top=('-' + rectdc.top).replace('px','') + 'px';
    }

    function ourdivalert(inmsg) {
    document.getElementById('divalert').style.position='absolute';
    document.getElementById('divalert').style.left=('' + rectdc.left).replace('px','') + 'px';
    document.getElementById('divalert').style.top='' + eval(-80 + eval(('' + rectdc.top).replace('px',''))) + 'px';
    document.getElementById('divalert').style.backgroundColor='#e0e0e0';
    document.getElementById('divalert').style.display='block';
    document.getElementById('divalert').style.zIndex='456';
    document.getElementById('divalert').style.opacity='0.8';
    document.getElementById('divalert').style.padding='5px 5px 5px 5px';
    document.getElementById('divalert').innerHTML=inmsg + '<br><br><input type=button value=Close onclick=nodivalert();></input>';
    setTimeout(nodivalert,9000);
    }

    function athn() {
    rectdc=document.getElementById('dc').getBoundingClientRect();
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    document.getElementById('dc').ontouchmove=function(event) { if (last24.substring(0,eval(-1 + last24.length)) == event.target.title.substring(0,eval(-1 + event.target.title.length))) { last24=last24; } else { last24=event.target.title; ourdivalert(event.target.title); } }
    } else {
    document.getElementById('dc').onmousemove=function(event) { if (last24.substring(0,eval(-1 + last24.length)) == event.target.title.substring(0,eval(-1 + event.target.title.length))) { last24=last24; } else { last24=event.target.title; ourdivalert(event.target.title); } }
    }
    }

    … working with the new HTML …


    <div id=divalert></div>
    </body>
    </html>

    … to try to allow the “explainer of an element” advantages non-mobile platforms have for hovering over an HTML element with a title attribute filled in.

    And so, yet again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new Weather integration functionality. It caused the changed colour_wheel.html‘s colour wheel (at this live run link) to be affected (by integrations “up”).


    Previous relevant Window SessionStorage Client Versus Server Ajax Tutorial is shown below.

    Window SessionStorage Client Versus Server Ajax Tutorial

    Window SessionStorage Client Versus Server Ajax Tutorial

    We have a few “clientside chestnuts” to use with our current Capital City Find Matching Country Report web application project today, those being …

    • Ajax functionality, kicked off by an “onclick” event set of logic, allowing mobile platforms to also have a look in (the look in that they miss when the event logic is off the “onmouseover” event)
    • iframe and its …
      1. srcdoc attribute (“content” alternative to src “url” attribute) … along with, and crucially needing (because srcdoc ignores its own document.body onload goings on, that we need the “Iframe Client Pre-Emptive” methods below to circumvent) the …
      2. onload event opportunity of an iframe element (we group into “Iframe Client Pre-Emptive” methods, here)

    … adding onto yesterday’s Window SessionStorage Client Versus Server Canvas Tutorial.

    It’s not that involved with the Ajax work today, given that there are no cross-domain issues, though there are cross-protocol (SSL https: versus non-SSL http:) issues to be careful about. Those can be addressed because the web application is recalled to present its “Country Report” and that is the opportunity to check on protocol navigation requirements.

    Along the way, we also make this happen for the user on …

    • click/touching a table row … it sets off new “tr” (table row) element logic calling our (inhouse) Timezone and Wikipedia Place Information helper (HTML) via Ajax (so not leaving the webpage) … and because of place name oddities we allow for …
    • “td” (table cell) element user amendments by setting their contenteditable attributes to “true” (since fixed, but we found the Timezone Europe/Tirane pointing at Tirane in Albania used to be spelt “Tirana”)

    … that latter methodology normally a technique we apply to “div” elements (so, there you are!)

    Also used are “overlay” techniques, two of the “usual suspects” here coming into play, to present to the “Ajax content to srcdoc iframe arrangements” …

    Yet again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new “Ajax” functionality.


    Previous relevant Window SessionStorage Client Versus Server Canvas Tutorial is shown below.

    Window SessionStorage Client Versus Server Canvas Tutorial

    Window SessionStorage Client Versus Server Canvas Tutorial

    Yesterday’s Window SessionStorage Client Versus Server Share Tutorial dealt with ascii text clipboard copy assisted sharing options with our current Capital City Find Matching Country Report web application project. This suited both Email and SMS share options we coded for, but today’s extension of functionality from “ascii text” data to “graphical data” only suits Email sharing. The other caveat with our work is that no serverside (for us, PHP) help is allowed, so no PHP mail here.

    What comes into play with a “graphical data” clientside (only) sharing approach? It will not surprise many readers that, for us, it involves …

    • canvas element … converting HTML table outerHTML “ascii text” data … via …
    • canvas drawing methods “[canvasContext].strokeRect()” and “[canvasContext].strokeText()” via “[cellElement].getBoundingClientRect()” … to convert that canvas element content via …
    • [canvasElement].toDataURL() … to an …
    • img element nested in a div contenteditable=true element … so as to hook in with today’s very useful helper link, thanks … use …

    • function tabletoclipboard(canvas) { // thanks to https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard
      var img = document.createElement('img');
      img.src = canvas.toDataURL();

      var div = document.createElement('div');
      div.contentEditable = true;
      div.appendChild(img);
      document.body.appendChild(div);

      // do copy
      SelectText(div);
      document.execCommand('Copy');
      document.body.removeChild(div);
      }

      function SelectText(element) { // thanks to https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard
      var doc = document;
      if (doc.body.createTextRange) {
      var range = document.body.createTextRange();
      range.moveToElementText(element);
      range.select();
      } else if (window.getSelection) {
      var selection = window.getSelection();
      var range = document.createRange();
      range.selectNodeContents(element);
      selection.removeAllRanges();
      selection.addRange(range);
      }
      }
    • to leave the user’s device’s clipboard containing a useful table (with linework) … ready to …
    • paste into an email body section

    … sharing off to an emailee collaborator.

    Again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new “Email Table” button functionality.


    Previous relevant Window SessionStorage Client Versus Server Share Tutorial is shown below.

    Window SessionStorage Client Versus Server Share Tutorial

    Window SessionStorage Client Versus Server Share Tutorial

    Yesterday’s Window SessionStorage Client Versus Server Tutorial has been amended today for two new sharing and collaboration options, those being …

    • email
    • SMS

    … but you may well be familiar with the restrictions on email and SMS client (program) approaches to this, coming from HTML “a” link “mailto:” and “sms:” href property prefixes respectively. We’re going to need help with the 800 odd character (length) restrictions with the (resultant) web address (bar) URL, but what? How about working off the great advice of this wonderful link, thanks, to copy what we’d have assembled into an ascii text Report into the characters contained by the user’s device’s clipboard?


    function copytoclipboard(str) { // thanks to https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f
    var el = document.createElement('textarea');
    el.value = str;
    el.setAttribute('readonly', '');
    el.style.position = 'absolute';
    el.style.left = '-9999px';
    document.body.appendChild(el);
    el.select();
    document.execCommand('copy');
    document.body.removeChild(el);
    }

    An issue that springs up here using such clipboard ascii text content, whenever you get the Font choice given to you, pick a monospaced Font like Courier New or “Fixed Width”.

    See the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new sharing functionality.


    Previous relevant Window SessionStorage Client Versus Server Tutorial is shown below.

    Window SessionStorage Client Versus Server Tutorial

    Window SessionStorage Client Versus Server Tutorial

    Sometimes it’s the case at this blog that we’d like to introduce a new topic, but do not do so, because we cannot show any real world (or real application) use of that concept. So it has been, up until now, with the concept of (web browser) window (object) sessionStorage property. But yesterday’s Window LocalStorage Client Versus Server Primer Tutorial represented an opportunity akin to when Haley’s Comet gets at its closest to the Earth … while you see a chance, take it … chance because of that nuance whereby we were not trying to store data for any other purpose than passing data onto …

    1. a known entity … ie. same web application … at …
    2. a known time … ie. immediately

    … two conditions that make the code design “marginally” more ideal for the window object property concept of sessionStorage rather than localStorage, in that any …


    localStorage.removeItem([knownLocalStorageName]);

    … becomes superfluous as with sessionStorage data will disappear between web browser sessions, anyway.

    We offer this new concept as a non-default option of a select (dropdown) element replacement to the h1 element hardcoding “localStorage” with the changed wls_vs_php.htm Capital City Find Matching Country Report live run. The other nuance of difference with sessionStorage usage is that in the document.body onload event logic, we may as well (as part of other changes) pre-emptively look for, and if there, respond to, any found sessionStorage data points, even without the user having flagged it specifically


    var datamode='localStorage';

    function checkforreport() {
    var divcont='';
    var dcaps, dctys, idis;
    if (getcapitals == 'localStorage') {
    if (window.localStorage) {
    getcapitals=decodeURIComponent(localStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
    localStorage.removeItem('wls_vs_php_capitals');
    } else {
    getcapitals='';
    }
    } else if (getcapitals == 'sessionStorage') {
    document.getElementById('smode').value=getcapitals;
    datamode=getcapitals;
    if (window.sessionStorage) {
    getcapitals=decodeURIComponent(sessionStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
    } else {
    getcapitals='';
    }
    }
    else if (getcapitals == '' && window.sessionStorage) {
    getcapitals=decodeURIComponent(('' + sessionStorage.getItem('wls_vs_php_capitals')).replace(/^null$/g,'')).replace(/\+/g,' ');
    if (getcapitals != '') {
    document.getElementById('smode').value='sessionStorage';
    datamode='sessionStorage';
    }
    }

    if (getcountries == 'localStorage') {
    if (window.localStorage) {
    getcountries=decodeURIComponent(localStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
    if (getcapitals.replace('localStorage','') != '' && getcountries.replace('localStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
    localStorage.removeItem('wls_vs_php_countries');
    } else {
    getcountries='';
    }
    } else if (getcountries == 'sessionStorage') {
    if (window.sessionStorage) {
    getcountries=decodeURIComponent(sessionStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
    if (getcapitals.replace('sessionStorage','') != '' && getcountries.replace('sessionStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
    } else {
    getcountries='';
    }
    }
    else if (getcountries == '' && document.getElementById('smode').value == 'sessionStorage' && window.sessionStorage) {
    getcountries=decodeURIComponent(('' + sessionStorage.getItem('wls_vs_php_countries')).replace(/^null$/g,'')).replace(/\+/g,' ');
    if (getcountries != '') {
    document.getElementById('smode').value='sessionStorage';
    datamode='sessionStorage';
    }
    }

    if (getcapitals != '' && getcountries != '') {
    divcont='<table border=5 style="width:95%;vertical-align:top;background-color:white;"><tr style=background-color:#f0f0f0;"><th>Capital</th><th>Country</th></tr></table>';
    dcaps=getcapitals.split('|');
    dctys=getcountries.split('|');
    for (idis=0; idis<dcaps.length; idis++) {
    divcont=divcont.replace('</table>', '<tr><td>' + dcaps[idis] + '</td><td>' + dctys[idis] + '</td></tr></table>');
    }
    document.getElementById('dreport').innerHTML=divcont;
    }
    document.getElementById('smode').value=datamode;
    }

    Which beggars the question “What are the differences between sessionStorage and localStorage?” A quick reading might surmise that “the latter has an expiration date”. We leave you with an open ended Google search so that you may extend your readings on this.


    Previous relevant Window LocalStorage Client Versus Server Primer Tutorial is shown below.

    Window LocalStorage Client Versus Server Primer Tutorial

    Window LocalStorage Client Versus Server Primer Tutorial

    Even though we rave on a lot about serverside PHP and its $_POST method=POST (versus HTML/Javascript recipient via ? and & argument $_GET method=GET scenario) data length advantages as the recipient of an HTML form method=POST set of data that could be sizeable, we’ve just realized that there is a client Javascript and window.localStorage methodology that may help alleviate the need to involve PHP (and any other serverside intervention) on occasions.

    Hint: Yes, we’ve raved on about this too?! Does the blog posting title give it away? Okay, yes, it should read “localStorage”, but thought we’d gone past such juvenile finickiness since the Whac-A-Mole controversy of 1st December 2019 (or even The Great Tea Trolley Disaster of ’67, we daresay).

    It can even use a “self-destruct” approach to the use of this “localStorage” on having used it because …

    • the web application knows who is using it (localStorage) … and on having accessed and read it …
    • the web application knows it (localStorage) is of no use to any other user (in this web application’s case, at least)

    … which is very pleasing for a Land Surveyor who likes to leave cow paddocks as they’ve seen them so to speak. Except it’s like having a ten tonne truck worth of data access in amongst the cow pats when having access to “localStorage” (or PHP), rather than a little piddle of calf wee (wee Metcalfes know a thing or two about these things!) data access of ? and & HTML/Javascript URL arguments (or even if we were to use HTTP Cookies).

    It’s not as if we all have access to serverside language usage, though we do, because we really like PHP and MAMP and Apache/PHP/MySql web servers (and have arranged our development environment accordingly), but what if you are starting out in web development, and still want to allow for sizeable chunks of data with your web applications? Huh? Huh?! See the possibilities? Try our proof of concept wls_vs_php.html Capital City Find Matching Country Report live run, and highlight a whole swathe of (multiple mode) dropdown option Capital Cities holding down the shift key before pressing the yellow “Report” button. If the URL ends up as …

    https://rjmprogramming.com.au/HTMLCSS/wls_vs_php.html?capitals=localStorage&countries=localStorage

    that’s because the web application’s …


    function analyze() {
    var purl=document.URL.split('#')[0].split('?')[0] + '?capitals=' + encodeURIComponent(document.getElementById('capitals').value) + '&countries=' + encodeURIComponent(document.getElementById('countries').value);
    if (purl.length > 800) {
    if (phpexists) {
    document.getElementById('myform').method='POST';
    document.getElementById('myform').action='./wls_vs_php.php';
    } else if (window.localStorage) {
    localStorage.setItem('wls_vs_php_countries', encodeURIComponent(document.getElementById('countries').value));
    localStorage.setItem('wls_vs_php_capitals', encodeURIComponent(document.getElementById('capitals').value));
    document.getElementById('capitals').value='localStorage';
    document.getElementById('countries').value='localStorage';
    location.href=document.URL.split('#')[0].split('?')[0] + '?capitals=' + encodeURIComponent(document.getElementById('capitals').value) + '&countries=' + encodeURIComponent(document.getElementById('countries').value);

    return false;
    }
    }
    return true;
    }

    … HTML form onsubmit event logic …

    1. discovered no PHP web application existant (via Client Pre-emptive Iframe techniques) … and …
    2. discovered (in a sanity check feeling way) that to go down the proposed HTML form method=GET approach was risking a …

      HTTP 414 "Request URI too long"

      … web browser error … and that …
    3. localStorage was a known web browser piece of functionality
    4. … and so as per our localStorage logic we …

    5. back out of the default HTML form method=GET navigation setup of the web application in favour of …
      • storing that data into localStorage
      • substituting into the URL ? and & arguments the hardcoding “localStorage” (and in so doing, getting back under the HTTP 414 “Request URI too long” limitation, piecing together (what amounts to) …
        location.href=document.URL.split(‘#’)[0].split(‘?’)[0] + ‘?capitals=localStorage&countries=localStorage’;)
        … that on a recall to this same web application a …
      • document.body onload event piece of Javascript logic checks the localStorage for its incoming Capital City Country Report data, as per …

        var phpexists=false;
        var getcapitals=location.search.split('capitals=')[1] ? decodeURIComponent(location.search.split('capitals=')[1].split('&')[0]).replace(/\+/g,' ') : '';
        var getcountries=location.search.split('countries=')[1] ? decodeURIComponent(location.search.split('countries=')[1].split('&')[0]).replace(/\+/g,' ') : '';

        function checkforreport() {
        var divcont='';
        var dcaps, dctys, idis;
        if (getcapitals == 'localStorage') {
        if (window.localStorage) {
        getcapitals=decodeURIComponent(localStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
        localStorage.removeItem('wls_vs_php_capitals');
        } else {
        getcapitals='';
        }
        }
        if (getcountries == 'localStorage') {
        if (window.localStorage) {
        getcountries=decodeURIComponent(localStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
        if (getcapitals.replace('localStorage','') != '' && getcountries.replace('localStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
        localStorage.removeItem('wls_vs_php_countries');
        } else {
        getcountries='';
        }
        }

        if (getcapitals != '' && getcountries != '') {
        divcont='<table border=5 style="width:95%;vertical-align:top;background-color:white;"><tr style=background-color:#f0f0f0;"><th>Capital</th><th>Country</th></tr></table>';
        dcaps=getcapitals.split('|');
        dctys=getcountries.split('|');
        for (idis=0; idis<dcaps.length; idis++) {
        divcont=divcont.replace('</table>', '<tr><td>' + dcaps[idis] + '</td><td>' + dctys[idis] + '</td></tr></table>');
        }
        document.getElementById('dreport').innerHTML=divcont;
        }
        }

        … the localStorage.removeItem() representing that “self-destruct” nuance we were talking about before

    We may well use this methodology in future projects, and hope it has been of some little interest to you as well?!

    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.


    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.


    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 Ajax, eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | 1 Comment

SVG Tspan Element Primer Tutorial

SVG Tspan Element Primer Tutorial

SVG Tspan Element Primer Tutorial

We’re starting a planned “mini project” to improve Select Multiple Webpage Palette Speech Bubble Swipe Tutorial and what we find important …

  1. regarding improvements to existant functionality it is most important to not interfere with any current functionality … and then …
  2. implement new functionalities off this platform

… and with our “mini project” of embellishing 11 letter words in the Speech Bubbles of our Select Multiple Webpage Palette Speech Bubble web application of recent times, we have a natural compartmentalization playing out mimicking those ideas above, that goes …

  1. Day 1 – work with the data that is the HTML (and SVG) of Speech Bubbles where they look and behave as ever, but 11 letter words get nested into SVG tspan elements
  2. Day 2 – embellish the web application via those SVG tspan elements

It’s our first go using SVG tspan elements as a “forward thinking” tool, and it helped us thinking on this regarding the corrollaries to HTML span element. What initially concerned us using SVG tspan was whether we’d have to specify x and y attributes, but, as it panned out, no, the SVG text element nesting the tspan takes care of that, so, “top supportive” we’d say, and a lot like how we think of the HTML span element working, and helping out, enormously!

Into “Day 2” though, and we’ll be wanting to do Javascript DOM things in the “overlay” line of thinking. So part of a “Day 1” paradigm, you will better leave that “Day 1” proving the work of “Day 2” is possible, and this was achieved via


function detecttspan() {
var tsrect=null;
var tss=document.getElementsByTagName('tspan');
for (var itss=0; itss<tss.length; itss++) {
tsrect=tss[itss].getBoundingClientRect();
alert('' + tss[itss].outerHTML + ' left:' + tsrect.left + ' top:' + tsrect.top);
}
}

… with the good news we started “Day 1” not being sure of “passed the test”, as you can see from today’s tutorial picture, and …

… this one illustrating work in the SVG tspan 11 letter word Speech Bubble changed select_palette.html web application.

Why 11? Tune in tomorrow.


Previous relevant Select Multiple Webpage Palette Speech Bubble Swipe Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Swipe Tutorial

Select Multiple Webpage Palette Speech Bubble Swipe Tutorial

Today’s tutorial is an amalgam of …

  1. concepts off Apple iOS Control Centre Tutorial … and …
  2. continuing on with the functionality of the recent Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial‘s External Javascript YouTube Audio Stream of Video web application ideas

… which, to us, is in the category of …

  • optional
  • experimental
  • quirky … and yet …
  • something we may well turn to for future endeavours … and so, worth it

… so, though there is opposition you can’t say I didn’t do it my way … which means, correct me if I’m wrong here, that means “I did it my way”that right … team?!.

We’re adding …

  • web application “swipe down and left from top right” … email after entering data … and …
  • web application “swipe up from bottom” … SMS after entering data

… user interaction “shortcuts” into the mix, via …


var firstx=null, firsty=null, pos3=-3, pos4=-3, nextx=null, nexty=null, slowitdown=false, isok=true, oktoemail=false, oktosms=false;
var wow=-1, woh=-1, wiw=-1, wih=-1;
var firstone=true;


function controlisok() {
isok=true;
}

function swipecheck(ev) {
if (!window.opener && isok) {
if (ev.touches) {
if (ev.touches[0].pageX) {
pos3 = ev.touches[0].pageX;
pos4 = ev.touches[0].pageY;
} else {
pos3 = ev.touches[0].clientX;
pos4 = ev.touches[0].clientY;
}
console.log('pos3 = ' + pos3 + ',pos4 = ' + pos4);
} else if (ev.clientX || ev.clientY) {
pos3 = ev.clientX;
pos4 = ev.clientY;
console.log('pos3 = ' + pos3 + ' ,pos4 = ' + pos4);
} else {
pos3 = ev.pageX;
pos4 = ev.pageY;
console.log('pos3 = ' + pos3 + ', pos4 = ' + pos4);
}


if (pos3 >= 0 && pos4 >= 0) {
if (firstx == null) {
firstx=pos3;
firsty=pos4;
slowitdown=true;
isok=false;
setTimeout(controlisok, 400);
} else if (pos3 != firstx || pos4 != firsty) {
nextx=pos3;
nexty=pos4;
// Swipe down left from top right
if (nextx < firstx && nexty > firsty && pos3 > eval(document.documentElement.clientWidth / 2) && pos4 < eval(document.documentElement.clientHeight / 2)) {
if (firstone) {
if (eval(firstx - nextx) > 5 && eval(nexty - firsty) && eval(window.innerWidth - firstx) < 90 && eval(firsty) < 90) {
firstone=false;
//alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
shapetodoemail(); // alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
}
}
// ... else swipe up from bottom
} else if (nexty < firsty && firsty > eval(document.documentElement.clientHeight / 2) && pos4 > eval(document.documentElement.clientHeight / 2)) {
if (firstone) {
if (eval(firstx - nextx) < 5 && eval(nexty - firsty) < 5 && eval(firsty) > eval(document.documentElement.clientHeight / 2)) {
firstone=false;
//alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
shapetodosms(); // alert('firstx=' + firstx + ' and firsty=' + firsty + ' and left irrelevant diff=' + eval(firstx - nextx) + ' and top irrelevant diff=' + eval(nexty - firsty) + ' and diff left=' + eval(window.innerWidth - firstx) + ' and diff top=' + eval(firsty) + ' and window height diff=' + eval(getwoh() - getwih()) + ' and window.outerHeight,window.innerHeight,document.documentElement.clientHeight=' + getwoh() + ',' + getwih() + ',' + document.documentElement.clientHeight + ' and window.opener=' + window.opener);
}
}
} else if (pos3 <= eval(document.documentElement.clientWidth / 2) || pos4 >= eval(document.documentElement.clientHeight / 2)) {
firstx=null;
firsty=null;
nextx=null;
nexty=null;
}
}
}
}
}

function gettodoemail() {
return oktoemail;
}

function settodoemail(towhat) {
oktoemail=towhat;
}

function shapetodoemail() {
oktoemail=true;
setTimeout(trytodoemail, 5000);
}

function trytodoemail() {
if (oktoemail) {
doemail();
}
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function gettodosms() {
return oktosms;
}

function settodosms(towhat) {
oktosms=towhat;
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function trytodosms() {
if (oktosms) {
dosms();
}
}

function shapetodosms() {
oktosms=true;
setTimeout(trytodosms, 5000);
}

function gwow() {
return wow;
}

function gwiw() {
return wiw;
}

function gwoh() {
return woh;
}

function gwih() {
return wih;
}

function getwow() {
if (window.opener) {
return window.opener.gwow();
} else {
return wow;
}
}

function getwoh() {
if (window.opener) {
return window.opener.gwoh();
} else {
return woh;
}
}

function getwiw() {
if (window.opener) {
return window.opener.gwiw();
} else {
return wiw;
}
}

function getwih() {
if (window.opener) {
return window.opener.gwih();
} else {
return wih;
}
}

function atstart() {
document.body.style.zoom = 1.0

var scale = 'scale(1)';
document.body.style.webkitTransform = scale; // Chrome, Opera, Safari
document.body.style.msTransform = scale; // IE 9
document.body.style.transform = scale; // General
wow=eval(window.outerWidth);
woh=eval(window.outerHeight);
wiw=eval(window.innerWidth);
wih=eval(window.innerHeight);
//alert('' + wih + ' vs ' + woh);
if (window.opener) {
firstone=false;
setTimeout(function(){
oktoemail=window.opener.gettodoemail();
oktosms=window.opener.gettodosms();
window.opener.settodoemail(false);
window.opener.settodosms(false);
}, 2000);
}
}

if (!window.screenLeft) {
window.screenLeft = window.screenX;
window.screenTop = window.screenY;
}

called into play via …


<body onload="atstart(); startsi(); dotdotdotten();" ontouchmove="swipecheck(event);" onmousemove="swipecheck(event);">

… in the changed select_palette.html web application.


Previous relevant Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Nuance Tutorial

The recent Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial‘s …

  • privacy for Group Talk “public” Bulletin Board functionalities …
  • involved logic for the two scenarios …
    1. data-applyprivacy=Y … via two prefixing spaces entered by originator of Group … completely hides relevant Group Talk Bulletin Board data from viewers outside that Group Talk
    2. data-applyprivacy=y … via one prefixing space entered by originator of Group … hides contact parts of Group Talk Bulletin Board data from viewers outside that Group Talk

    … but we had not “nuanced” the functionality for that second suboption on that first subpass

… and that is the work discussed today, a nuance that amounts to …

Allow non-group Bulletin Board readers see what we say but given cryptic username choices will not know how to contact that Group

That work took place in the PHP component of our Select Multiple Webpage Palette Speech Bubble web application as per

<?php

if (!isset($_GET['owner']) && isset($_GET['me']) && !isset($_GET['contact'])) {
$findings=explode(',', str_replace(';',',',str_replace('+',' ',urldecode($_GET['me']))));
} else if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
$aprivone=' data-applyprivacy="Y"';
$aprivtwo=' data-applyprivacy="y"';
}


if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
$prevcont="";
for ($i=(0 + 0); $i<sizeof($lines); $i++) {
$thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
if (strpos($thisline, $curgmt) !== false && strpos(str_replace("'",'"',$thisline), $aprivone) === false) { // && strpos(str_replace("'",'"',$thisline), $aprivtwo) === false) {
if (strpos(str_replace("'",'"',$thisline), $aprivtwo) !== false) {
$thatline=$thisline;
if (strpos($thatline, 'contact="') !== false && strpos(str_replace('contact=""',"contact=''",$thatline), 'contact="') !== false) {
while (strpos(str_replace('contact=""',"contact=''",$thatline), 'contact="') !== false) {
$thingtochange=explode('"', explode('contact="', str_replace('contact=""',"contact=''",$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
if (strpos($thatline, "contact='") !== false && strpos(str_replace("contact=''",'contact=""',$thatline), "contact='") !== false) {
while (strpos(str_replace("contact=''",'contact=""',$thatline), "contact='") !== false) {
$thingtochange=explode("'", explode("contact='", str_replace("contact=''",'contact=""',$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
if (strpos(str_replace("[]","",$thatline), "[") !== false && strpos(str_replace("[]","",$thatline), "]") !== false) {
while (strpos(str_replace("[]","",$thatline), "[") !== false && strpos(str_replace("[]","",$thatline), "]") !== false) {
$thingtochange=explode("]", explode("[", str_replace("[]","",$thatline))[1])[0];
$thatline=str_replace($thingtochange, '', $thatline);
}
}
$prevcont.=$thatline;
} else {

$prevcont.=$thisline;
}
}
}
$vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
exit;
}

?>

… in the changed select_palette.php “eighth draft” PHP.


Previous relevant Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial

Select Multiple Webpage Palette Speech Bubble Group Talk Privacy Tutorial

Meanwhile, back at some other ranch … somewhere … we’re some of the way down the line, with our recent …

  • Select Multiple Webpage Palette web application …
  • Bulletin Board subset of functionality, towards with it’s …
  • Group Talk (comma separated list of username/contacts) abilities … now offer …
  • Bulletin Board privacy

… as people in a Group Talk may appreciate. In other words, your generic Bulletin Board viewers would not see your Group Talk setup communications should the originator of any Group Talk now, either at …

  • best, as a To: + spaces appendage to a textarea line record (delimited by line feed) … ahead of a way with …
  • spaces prefixing to the prompt widow off right click or gesture events … starting the ball rolling …
  • populating a new data-applyprivacy global data attribute into the SVG

… allowing this new privacy functionality to work.

Again, we’ll need more than the work today to bed this in, but we now do not think there are any impassable concepts to its implementation.

And so, onto the recent Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial‘s work we have the changed select_palette.html web application helped out by the changed select_palette.php “seventh draft” PHP we have made a start making this “privacy dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial

Select Multiple Webpage Palette Speech Bubble Username Emoji Tutorial

Yesterday’s Select Multiple Webpage Palette Speech Bubble Emoji Tutorial warned you today …

we may have nuances yet to come

… and allowing for emojis within a Group Talk user’s username (via control-command-space for macOS or Mac OS X, logo key + . (period) for Windows, control+space for iOS, top left + for Android keyboard) be an identifier on their Speech Bubbles … well, it leaves us speechless with nuance!

Yesterday we were attempting to do this but had more success, today, with


/**
* Convert a string to HTML entities ... Thanks to https://zditect.com/code/javascript/easy-solution-to-encode-html-entities-in-javascript.html
*/
String.prototype.toHtmlEntities = function() {
return this.replace(/./gm, function(s) {
return (s.match(/[a-z0-9" . "\\" . "s]+/i)) ? s : '&#' + s.charCodeAt(0) + ';';
});
};


function maybeemoji(insvg) {
var outthing='', newoutthing='', jb=0;
var outsvg=insvg;
//alert('0:' + outsvg);
if (outsvg.indexOf(' data-otherc') != -1 && outsvg.indexOf(' data-ip') != -1) {
outsvg=outsvg.replace(outsvg.split(' data-otherc')[1].split(' data-ip')[0],'').split('97%')[0];
}

//alert(outsvg);

outhtmlentities='';
nonouthtmlentities='';

var nonencodeds=outsvg.split('&#');
for (jb=1; jb<nonencodeds.length; jb++) {
if (eval('' + nonencodeds[jb].split(';')[0]) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
newoutthing+=String.fromCodePoint(eval('' + nonencodeds[jb].split(';')[0]));
if (nonencodeds[jb] != (nonencodeds[jb].split(';')[0] + ';')) {
nonouthtmlentities=' ';
}
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
}
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

if (outhtmlentities == '') {
if (outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' ').indexOf('&#') >= 0) {
//alert('2987:' + outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' '));
nonencodeds=outsvg.toHtmlEntities().replace(/\&\#[0-9][0-9][0-9]\;/g,' ').replace(/\&\#[0-9][0-9]\;/g,' ').replace(/\&\#[0-9]\;/g,' ').split('&#')
for (jb=1; jb<nonencodeds.length; jb++) {
if (eval('' + nonencodeds[jb].split(';')[0]) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
newoutthing+=String.fromCodePoint(eval('' + nonencodeds[jb].split(';')[0]));
if (nonencodeds[jb] != (nonencodeds[jb].split(';')[0] + ';')) {
nonouthtmlentities=' ';
}
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+nonencodeds[jb].split(';')[0]+';';
}
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

}
}


if (outhtmlentities == '') {
//alert(987);
var encodedStr=outsvg.replace(/[\u00A0-\u9999<>\&]/g, function(i) {
if (eval('' + i.charCodeAt(0)) >= 1000 && nonouthtmlentities == '') {
outhtmlentities+='&#'+i.charCodeAt(0)+';';
newoutthing+=String.fromCodePoint(eval('' + i.charCodeAt(0)));
} else if (outhtmlentities != '') {
nonouthtmlentities+='&#'+i.charCodeAt(0)+';';
}
return '&#'+i.charCodeAt(0)+';';
});
}

if (outhtmlentities != '') { outthing=outhtmlentities; }

if (outhtmlentities == '') {
if (document.getElementById('myip').value != '' && insvg.replace(/\'/g,'"').indexOf(' data-owner="') != -1 && insvg.replace(/\'/g,'"').indexOf(' data-contact="') != -1) {
var basisstr=insvg.replace(/\'/g,'"').split(' data-owner="')[1].split('"')[0] + insvg.replace(/\'/g,'"').split(' data-contact="')[1].split('"')[0] + document.getElementById('myip').value;
var bcnt=999, koffset=0;
for (var ib=0; ib<basisstr.length; ib++) {
//if (bcnt == 999) { bcnt=129293; }
//bcnt+=eval('' + basisstr.substring(ib).charCodeAt(0));
koffset+=eval('' + basisstr.substring(ib).charCodeAt(0));
}
if (koffset > 0) {
bcnt+=Math.round(eval(eval('' + koffset) / 10));
var itries=0;
if (4 == 5) { bcnt=129293; }
while (supports_emoji(String.fromCodePoint(eval('' + bcnt)))) {
bcnt++;
itries++;
if (itries >= 230) { bcnt=129293; }
}
//alert(bcnt);
outthing='&#' + bcnt + ';';
newoutthing+=String.fromCodePoint(eval('' + bcnt));
}
}
}
return insvg.replace('></text>', '>' + newoutthing + '</text>').replace(" data-emoji=''", " data-emoji='" + newoutthing + "'").replace(' data-emoji=""', ' data-emoji="' + newoutthing + '"');
}

… in the changed select_palette.html web application helped out by the changed select_palette.php “sixth draft” PHP we have made a start making this “emoji dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble Emoji Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble Emoji Tutorial

Select Multiple Webpage Palette Speech Bubble Emoji Tutorial

The reason for today’s efforts with our latest web application have a similar theme to yesterday’s Select Multiple Webpage Palette Speech Bubble IP Address Tutorial‘s efforts, namely …

help differentiate Speech Bubbles of different users in a Group Talk arrangement with our public Bulletin Board functionality

Today’s research into displaying emoji text at the pointy corner of the Speech Bubble hopes to help out here, and though we may have nuances yet to come, we can say with the changed select_palette.html web application helped out by the changed select_palette.php “fifth draft” PHP we have made a start making this “emoji dream” happen.


Previous relevant Select Multiple Webpage Palette Speech Bubble IP Address Tutorial is shown below.

Select Multiple Webpage Palette Speech Bubble IP Address Tutorial

Select Multiple Webpage Palette Speech Bubble IP Address Tutorial

To further differentiate Group Talk users accessing the public Bulletin Board of our web application talked about in Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

  • we need to consider user IP addresses, as Wikipedia describes …

    An Internet Protocol address (IP address) is a numerical label such as 192.0.2.1 that is assigned to a device connected to a computer network that uses the Internet Protocol for communication.[1][2] IP addresses serve two main functions: network interface identification, and location addressing.

    Some readers may have noted for a couple of days now, our newly introduced PHP has been assisting the calling HTML, and itself, by remembering the user’s IP address. Yesterday, it was to help colour code Speech Bubbles, and today, it helps in amongst …

    • username … and …
    • contact … set lists … with …
    • IP address

    … to differentiate email and SMS invitation origin calls of our web application, as to who that user has been described as by the originator of the Group Talk settings with the changed select_palette.html web application helped out by the changed select_palette.php “fourth draft” PHP.


    Previous relevant Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial is shown below.

    Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

    Select Multiple Webpage Palette Colour Coded Speech Bubble Tutorial

    The concept of Group Talk started with yesterday’s Select Multiple Webpage Palette Speech Bubble Invitations Tutorial. It made us think that we should start thinking about the differentiation of voices amongst the Speech Bubbles of the public Bulletin Board we’re supporting with the associated web application and its user mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic talents.

    We decided that one way could be to …

    • Colour Code the background colour of the Speech Bubbles via the user IP address …
      <?php

      $gbcol="0,0,255";

      function server_remote_addr() {
      global $gbcol;
      $rma = $_SERVER['REMOTE_ADDR'];
      $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
      $uas=explode('.', str_replace('::1','65.254.95.247',$rma)); // 65.254.93.32

      if (sizeof($uas) >= 3) {
      $gbcol='' . ($uas[0] % 256);
      $gbcol.=',' . ($uas[1] % 256);
      $gbcol.=',' . (($uas[2] + $uas[(-1 + sizeof($uas))]) % 256);
      }

      // you can add different browsers with the same way ..
      if(preg_match('/(chromium)[ \/]([\w.]+)/', $ua))
      $rma = '000000'.$rma;
      elseif(preg_match('/(chrome)[ \/]([\w.]+)/', $ua))
      $rma = '00000'.$rma;
      elseif(preg_match('/(safari)[ \/]([\w.]+)/', $ua))
      $rma = '0000'.$rma;
      elseif(preg_match('/(opera)[ \/]([\w.]+)/', $ua))
      $rma = '000'.$rma;
      elseif(preg_match('/(msie)[ \/]([\w.]+)/', $ua))
      $rma = '00'.$rma;
      elseif(preg_match('/(mozilla)[ \/]([\w.]+)/', $ua))
      $rma = '0'.$rma;
      return str_replace(":", "_", $rma);
      }

      server_remote_addr();

      ?>
    • when a Group Talk invitation is sent out do not have the sender username and/or contact as the recipient username and/or contact

    … moving further along with the changed select_palette.html web application helped out by the changed select_palette.php “third draft” PHP.


    Previous relevant Select Multiple Webpage Palette Speech Bubble Invitations Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Invitations Tutorial

    Select Multiple Webpage Palette Speech Bubble Invitations Tutorial

    Yesterday’s Select Multiple Webpage Palette Speech Bubble PHP Tutorial‘s …

    • PHP embellishment of …
    • the day before’s SVG data enhancemants … today improves yesterday’s …
    • public Bulletin Board via user mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logics … today, adding …
    • optional invitation communication email and/or SMS logics via Group Talk set comma separated optional user username/contact entered data set lists helping with Group Talk filtering means of filtering the Speech Bubble data

    … with the changed select_palette.html web application helped out by the changed select_palette.php “second draft” PHP.


    Previous relevant Select Multiple Webpage Palette Speech Bubble PHP Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble PHP Tutorial

    Select Multiple Webpage Palette Speech Bubble PHP Tutorial

    Yesterday’s Select Multiple Webpage Palette Speech Bubble Data Tutorial‘s …

    • data … begets …
    • PHP
    … around here a lot, as PHP is our domain’s “first call” serverside language.

    Add to that that “yesterday’s tomorrow is today” we’re supposed to be finished with our “short two day mini project sojourn”, and in a crude way we have, but we want a third day to add nuance to the arrangements with data filtering and more sophistication regarding collection, within the approach of our new …

    Bulletin Board of Speech Bubbles

    … that becomes a …

    • shareable
    • public (on this second day, a bit too public)
    • reverse chronological
    • speech bubble

    … resource, if the user avails themselves of the mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic smarts with the changed select_palette.html web application, now helped out by select_palette.php “first draft” PHP …


    <?php
    // select_palette.php
    // RJM Programming
    // May, 2025

    $prevcont="";
    $curcont="";
    $curgmt=gmdate("Ymd");
    $newlines=[];

    if (isset($_POST['indata'])) {
    $ind=str_replace('+',' ',urldecode($_POST['indata']));
    $lines=explode('<svg name="', $ind);
    if (!file_exists('/tmp/select_palette.htm')) {
    file_put_contents('/tmp/select_palette.htm', '');
    } else {
    $prevcont=file_get_contents('/tmp/select_palette.htm');
    if (strpos($prevcont, '<svg name="' . $curgmt) === false) {
    file_put_contents('/tmp/select_palette.htm', '');
    } else {
    $curcont=$prevcont;
    }
    }


    for ($i=1; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false && strpos($thisline, ' data-public="n"') === false && (strpos($thisline, ' data-owner="') !== false && strpos($thisline, ' data-owner=""') === false) || (strpos($thisline, ' data-contact="') !== false && strpos($thisline, ' data-contact=""') === false)) {
    if (strpos($curcont, $thisline) === false) {
    $curcont.=$thisline;
    }
    }
    }
    file_put_contents('/tmp/select_palette.htm', $curcont);
    echo '<html><body></body></html>';
    exit;

    } else if (isset($_GET['extract'])) {
    if (file_exists('/tmp/select_palette.htm')) {
    $prevcont=file_get_contents('/tmp/select_palette.htm');
    if (strpos($prevcont, '<svg name="' . $curgmt) === false) {
    file_put_contents('/tmp/select_palette.htm', '');
    }
    $lines=explode('<svg name="', $prevcont);
    rsort($lines);

    if (!isset($_GET['owner']) && !isset($_GET['me']) && !isset($_GET['contact'])) {
    $prevcont="";
    for ($i=0; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false) {
    $prevcont.=$thisline;
    }
    }
    $vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
    echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
    exit;
    } else {
    $prevcont="";
    for ($i=0; $i<sizeof($lines); $i++) {
    $thisline='<svg name="' . explode('</svg>', $lines[$i])[0] . '</svg><br><br><br>';
    if (strpos($thisline, $curgmt) !== false) {
    $isok=true;
    if (isset($_GET['owner']) && strpos(strtolower($thisline), ' data-owner="' . strtolower(str_replace('+',' ',urldecode($_GET['owner'])) . '"')) === false) {
    $isok=false;
    }
    if (isset($_GET['contact']) && strpos(strtolower($thisline), ' data-contact="' . strtolower(str_replace('+',' ',urldecode($_GET['contact'])) . '"')) === false) {
    $isok=false;
    }
    if (isset($_GET['me']) && strpos(strtolower($thisline), strtolower('="' . str_replace('+',' ',urldecode($_GET['me'])) . '"')) === false) {
    $isok=false;
    } else if (isset($_GET['me'])) {
    $isok=true;
    }
    if ($isok) { $prevcont.=$thisline; }
    }
    }
    $vslen=strlen(str_replace('+','%20',urlencode($prevcont)));
    echo '<html><body onload=" if (encodeURIComponent(parent.document.getElementById(' . "'publicreport'" . ').innerHTML).length != ' . $vslen . ') { parent.document.getElementById(' . "'publicreport'" . ').innerHTML=decodeURIComponent(' . "'" . str_replace('+','%20',urlencode($prevcont)) . "'" . '); } "></body></html>';
    exit;
    }

    }

    }

    ?>

    … meaning …

    Data … is enhanced … … by … PHP


    Previous relevant Select Multiple Webpage Palette Speech Bubble Data Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Data Tutorial

    Select Multiple Webpage Palette Speech Bubble Data Tutorial

    Onto yesterday’s Select Multiple Webpage Palette Speech Bubble Tutorial, today, we’re preparing for tomorrow.

    You heard it here first.

    Admittedly, nothing startling there, but it was the first time we remember …

    • embellishing SVG data … with so much …
    • what we normally associate with HTML element work …
      1. global data attributes
      2. id and name attribution …
      3. event logic

    Yes, all possible with SVG, though not the first thing we think of using SVG data within our HTML. We normally think, just display thoughts, but today, we’re paving the way for tomorrow, and our “short two day mini project sojourn” will become clearer regarding motives, then, or get hints trying with strategically changed select_palette.html web application‘s mobile ontouchend and non-mobile oncontextmenu event interfacing Javascript logic …


    var taar=[];
    var preadd=0;
    var windowuser='', windowcontact='', windowask=true, suffix='';


    function defwuwc(inwindowuser,inwindowcontact) {
    if ((inwindowuser + inwindowcontact) == '') { return ''; }
    if (inwindowuser != '' && inwindowcontact != '') { return inwindowuser + '[' + inwindowcontact + ']'; }
    if (inwindowuser != '' && inwindowcontact == '') { return inwindowuser; }
    return inwindowcontact;
    }


    function treg(ttis) {
    var dotherest=false;
    var ctown=defwuwc(windowuser,windowcontact);
    var ourwindowask=windowask;
    preadd=1;
    if (ttis.outerHTML.indexOf(' data-public=') != -1) {
    if (windowuser == '' && windowcontact == '' && windowask) {
    ctown=prompt("To share on today's board enter a username and/or contact string (append space to remember, append another space to apply to all other Speech Bubbles) ... eg. " + String.fromCharCode(10) + "Robert Metcalfe[rmetcalfe15@gmail.com]", defwuwc(windowuser,windowcontact));
    }
    if (ctown == null) { ctown=''; }
    if (ctown != ctown.replace(/\ \ $/g,'')) {
    windowask=false;
    dotherest=true;
    ctown=ctown.trim();
    } else if (ctown != ctown.replace(/\ $/g,'')) {
    windowask=false;
    ctown=ctown.trim();
    }
    if (ctown.indexOf('[') > 0 && ctown.indexOf(']') != -1) {
    windowuser=ctown.split('[')[0];
    windowcontact=ctown.split('[')[1].split(']')[0];
    } else if (ctown.indexOf('[') == 0 && ctown.indexOf(']') != -1) {
    windowcontact=ctown.split('[')[1].split(']')[0];
    windowuser=windowcontact;
    } else {
    windowuser=ctown;
    windowcontact='';
    }
    if (windowuser != '') {
    ttis.setAttribute('data-owner', windowuser);
    }
    if (windowcontact != '') {
    ttis.setAttribute('data-contact', windowcontact);
    }
    if (windowuser != '' || windowcontact != '') {
    ttis.setAttribute('data-public', 'y');
    ttis.innerHTML=ttis.innerHTML.replace(/\<text\ /g,'<text stroke="blue" ');
    if (dotherest) {
    var svgs=document.getElementsByTagName('svg');
    for (var isvgs=0; isvgs<svgs.length; isvgs++) {
    if (svgs[isvgs].outerHTML.indexOf(' stroke=') == -1) {
    if (('' + svgs[isvgs].id) != ('' + ttis.id)) {
    if (windowuser != '') {
    svgs[isvgs].setAttribute('data-owner', windowuser);
    }
    if (windowcontact != '') {
    svgs[isvgs].setAttribute('data-contact', windowcontact);
    }
    if (windowuser != '' || windowcontact != '') {
    svgs[isvgs].setAttribute('data-public', 'y');
    }
    svgs[isvgs].innerHTML=svgs[isvgs].innerHTML.replace(/\<text\ /g,'<text stroke="blue" ');
    }
    }
    }
    }
    } else {
    windowask=ourwindowask;
    }
    }
    //alert(ttis.outerHTML);
    setTimeout(function(){ preadd=0; }, 5000);
    }


    Previous relevant Select Multiple Webpage Palette Speech Bubble Tutorial is shown below.

    Select Multiple Webpage Palette Speech Bubble Tutorial

    Select Multiple Webpage Palette Speech Bubble Tutorial

    Yesterday’s Select Multiple Webpage Palette Popup Tutorial modus operandi revolved around …

    delimitation rules

    … as so many matters do with written down text.

    We rethought yesterday’s HTML textarea start regarding line feed Speech Bubble creation possibilities, and thought …

    It’s too unwieldy for a user to add to their textual data when what they really want to do is Speech Bubbles.

    Yesterday’s thinking really hoped the user entered a Speech Bubble data one at a time, but what if the user wants to enter several Speech Bubbles in the one textarea incarnation?

    Good question. (Calling all ducks with a slow paddle going?!)

    Yes, but there is that ~~ existing delimitation rule, as of yesterday equating to a line feed. Supposing ~~ was given the delimitation roles …

    1. the character sets …
      lineFeed~~lineFeed
      … separate Speech Bubbles … ie. in the textarea a ~~ record is all there is on a line of textarea text
    2. the character set …
      ~~lineFeed
      … at the start wipes out any previously remembered text data and starts again
    3. else retain the ~~ mapping to lineFeed

    … in combination with the textarea always first presented blank and the previous Speech Bubble or Lines of Text remembered and retained unless the middle condition above happens?

    Well, we think it’s a plan, and led us to be able to share a Speech Bubble presentation of Shakepeare’s Act 1 Scene 1 of Macbeth. And so, today with the changed select_palette.html web application, onto yesterday’s …

    one textarea element

    … paradigm, we present …

    • previous text data in a details/summary “reveal” mode of use above the textarea element, as relevant
    • and below the textarea element we now have buttons to Email or SMS your text creations off to a recipient

    … harnessing hashtag navigational data methodologies in “a” “mailto:” (email) or “sms:” (SMS) prefixing href attributes, as per …


    function doemail() {
    var anchor=null;
    if (woois) {
    if (!woois.closed) {
    if (woois.document.getElementById('myta').outerHTML.indexOf(' data-done="y"') == -1) {
    if (woois.document.getElementById('myta').value.trim() != '') {
    woois.document.getElementById('myta').setAttribute('data-done', 'y');
    setTimeout(doemail, 6000);
    return '';
    }
    } else if (woois.document.getElementById('myta').value.trim() != '') {
    setTimeout(doemail, 6000);
    return '';
    }
    woois.close();
    woois=null;
    setTimeout(doemail, 6000);
    return '';
    }
    }
    var emis=prompt('Please enter email address to send to.', '');
    if (emis == null) { emis=''; }
    if (emis.indexOf('@') != -1) {
    anchor = document.createElement('a');
    anchor.href = 'mailto:' + emis.trim() + '?subject=My%20Speech%20Bubble%20data&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    document.body.appendChild(anchor);
    anchor.innerHTML='Email';
    anchor.target='_top';
    anchor.click();
    } else if (emis.trim() != '' && emis.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
    anchor = document.createElement('a');
    anchor.href = 'sms:' + emis.trim() + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    anchor.innerHTML='SMS';
    anchor.target='_top';
    anchor.click();
    }
    }

    function dosms(){
    var anchor=null;
    if (woois) {
    if (!woois.closed) {
    if (woois.document.getElementById('myta').outerHTML.indexOf(' data-done="y"') == -1) {
    if (woois.document.getElementById('myta').value.trim() != '') {
    woois.document.getElementById('myta').setAttribute('data-done', 'y');
    setTimeout(dosms, 6000);
    return '';
    }
    } else if (woois.document.getElementById('myta').value.trim() != '') {
    setTimeout(dosms, 6000);
    return '';
    }
    woois.close();
    woois=null;
    setTimeout(dosms, 6000);
    return '';
    }
    }
    var emis=prompt('Please enter SMS number to send to.', '');
    if (emis == null) { emis=''; }
    if (emis.indexOf('@') != -1) {
    anchor = document.createElement('a');
    anchor.href = 'mailto:' + emis.trim() + '?subject=My%20Speech%20Bubble%20data&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    document.body.appendChild(anchor);
    anchor.innerHTML='Email';
    anchor.target='_top';
    anchor.click();
    } else if (emis.trim() != '' && emis.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
    anchor = document.createElement('a');
    anchor.href = 'sms:' + emis.trim() + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#bodyih=' + encodeURIComponent(document.body.innerHTML));
    anchor.style.display='none';
    anchor.innerHTML='SMS';
    anchor.target='_top';
    anchor.click();
    }
    }


    Previous relevant Select Multiple Webpage Palette Popup Tutorial is shown below.

    Select Multiple Webpage Palette Popup Tutorial

    Select Multiple Webpage Palette Popup Tutorial

    Regarding yesterday’s Select Multiple Webpage Palette Primer Tutorial

    • you start with an outlandish premise …
    • it stays “outlandish” select (dropdown) element wise on non-mobile … but …
    • catering for mobile …
    • you are forced to encase it in a hosting div element (with the onmousedown and ontouchdown precursor events to onclick)

    … all contributing to getting us to a point, today, we can say we’ve added a layer of (useful, extra) functionality, by …

    • no longer asking for user interactive input via a Javascript prompt window … but, instead, like with Background Image Foreground Content Tutorial … we …
    • ask for user interactive input via a window.open (ie. popup) “here’s looking at you, kid” window.opener incarnation guise of our changed select_palette.html web application … just consisting of …
    • one textarea element …
      1. still capable of ~~ delimitation as with the Javascript prompt window thinking … but also now …
      2. harnessing the talents of a textarea line feed delimitation within it’s value attribute

      … able to extend functionality towards decent …

    • speech bubble feeling thoughts (so far, just) … because …
    • it opens up the idea that the div element innerHTML attribute can be the SVG we had previously been supplying as background HTML/CSS (via Javascript DOM) data

    Cute, huh?! (ahead of the “Speech Bubble styling” niceties making it really cute, yet, for us … but who knows what you can achieve on the “cute styling front”?!).


    Previous relevant Select Multiple Webpage Palette Primer Tutorial is shown below.

    Select Multiple Webpage Palette Primer Tutorial

    Select Multiple Webpage Palette Primer Tutorial

    In the world of web applications, there are often many ways to approach any given requirement. Like with yesterday’s Select Multiple Mobile Background Image Tutorial, today’s “albeit a bit out there idea” is to …

    • offer a select (multiple attribute) “dropdown” HTML element …
    • as a webpage covering …
    • template or palette … where the user …
    • writes user defined lines of words created

    … onto. Pretty simple idea for a “first then second draft“! But maybe not the first idea to spring to mind regarding making such an idea happen?!


    Previous relevant Select Multiple Mobile Background Image Tutorial is shown below.

    Select Multiple Mobile Background Image Tutorial

    Select Multiple Mobile Background Image Tutorial

    We had occasion to revisit Window LocalStorage Client Versus Server Map Tutorial‘s web application today changed this way to end up with wls_vs_php.htm, on an iPad, and saw how initially lacking was the advice on how to work the Capital City to Country quiz. The reason, primarily, in our view, is that on mobile platforms an element such as …


    <select class=dglow onclick=" console.log('67234'); noif(); " title='Please select Capital(s) below to get Countries Report ...' onfocusout=" document.getElementById('myrepsb').className='dglow'; tablemode = ''; nothere=true; updatecountries(null);" style='width:300px;margin-top:0px;margin-left:0px;vertical-align:top;height:100vh;background-color:lightblue;' id=scapitals multiple>
    // innard options //
    </select>

    … you just see words to the effect …

    0 items …

    … but we’d see more use for this select element “opened up” on initialization. As we read, and believed, via this useful link, thanks, this “programmatical click on mobile platforms” to open up such a select element is not easy. So we decided to go down the route of …

    • to a select multiple element …
    • on mobile …
    • background image …
    • at top right …
    • that is wording advice “Click/tap me”
    • when first encountered

    … and we came up with the document.body onload event call “new Javascript code snippet” …


    if (document.URL.indexOf('?') == -1) {
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    document.getElementById('scapitals').click(); // this is just wishful thinking, but no error is caused, and you never know?
    document.getElementById('scapitals').style.background="url(\"data:image/svg+xml;base64," + window.btoa("<svg xmlns='http://www.w3.org/2000/svg' width='126' height='48' viewport='0 0 100 100' style='border-radius:15px;background-color:rgba(0,0,255,0.3);fill:black;font-family:Verdana;font-size:17px;'><text x='5%' y='60%'>Click/tap me</text></svg>") + "\") no-repeat top right";
    }
    }

    Next best approach, we’d say?!


    Previous relevant Window LocalStorage Client Versus Server Map Tutorial is shown below.

    Window LocalStorage Client Versus Server Map Tutorial

    Window LocalStorage Client Versus Server Map Tutorial

    Get a good map, and a goodly number of times you’ll want a map of smaller or larger scale than the one you have. Murphy’s Law? This is probably why in the wonderful woooooooorrrrrrrrlllllld of Google Charts they have included …

    • Geo Chart topographic map of the world or of regions
    • Map Chart terrestrial/satellite map of your group of markers at a zoom level of your choosing

    … and hope you can see that the latter can save the day for a Short Distance Trip (corner shop, anyone?!).

    So we’ve added onto yesterday’s Window LocalStorage Client Versus Server Timeline Tutorial progress a new toggling button to view a scenario in either Google Chart scenario above.

    You can see this integration work with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link supervising a tweaked geo_chart.php Geo Chart interfacer.


    Previous relevant Window LocalStorage Client Versus Server Timeline Tutorial is shown below.

    Window LocalStorage Client Versus Server Timeline Tutorial

    Window LocalStorage Client Versus Server Timeline Tutorial

    Up to yesterday’s Window LocalStorage Client Versus Server User Tutorial‘s progress, our Capital City Find Matching Country Report web application project was all about …

    • where (and capital of “what”) … but we often seek out a way to add into the mix that 4th dimension …
    • when (ie. time)

    … and regarding the current project, a …

    • where “map” … can interface with a …
    • when “Trip Plan Itinerary”

    … and for this purpose, we’re going to interface to the excellent Google Charts Annotated Timeline Chart, thanks, because it combines links of “time” to “user annotations” in a timeline way, that similar way you might describe the qualities of a Trip, even before you’ve gone on that trip. We’ve also added it so that an unordered places list can be turned into a Trip Plan Itinerary at the click/touch of a new map 🗺 &#128506; emoji button.

    Again, see how these timeline amendments were achieved with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link and annotatedtimeline_chart.php which changed quite a lot.


    Previous relevant Window LocalStorage Client Versus Server User Tutorial is shown below.

    Window LocalStorage Client Versus Server User Tutorial

    Window LocalStorage Client Versus Server User Tutorial

    The inherent weakness with our current Capital City Find Matching Country Report web application project, to our minds, was that places of interest are not restricted to the Capital Cities of Countries, especially when “Trip Planning”. On the other hand, it would be impossible to cater for every “place” in the world. That is far too subjective for good web application applicability. What would be good though, is to allow in user defined …


    Place name, Country name

    … terms, the definitions of interest to a user. We can ask this …

    • flagged by the click/touch of an emoji button … and …
    • the interactive entry presented via a Javascript prompt window

    . When thinking of data applicable to an individual, then that can be catered for by recording it in localStorage where it will be recalled on the next execution of that web application in the same web browser.

    This, along with a Colour Wheel of the “nearest TimeZone place” onto the existing logic of yesterday’s Window SessionStorage Client Versus Server Order Tutorial progress could make for a more useful and practical tool for those Trip Planners out there!

    See how this was achieved with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.

    Did you know?

    To click/touch one of those Google Chart Geo Chart lines between Emoji Flag Markers will show a new Google Maps directions web page with transport times and detail, as well as an inhouse crow fly distance of that trip leg, as shown up the top right of today’s tutorial picture.


    Previous relevant Window SessionStorage Client Versus Server Order Tutorial is shown below.

    Window SessionStorage Client Versus Server Order Tutorial

    Window SessionStorage Client Versus Server Order Tutorial

    If we are to honour our thoughts of being able to use our current Capital City Find Matching Country Report web application as a Trip Planner …

    Our primary integration today is to (software) integrate the great Weather Underground and its great API service for autocomplete name searches for weather (and hurricane) information. Why bother? Well, can you not envisage a user using that Ajax functionality of yesterday’s Window SessionStorage Client Versus Server Ajax Tutorial as a trip planner, perhaps, or as a “checking up on relatives overseas” tool, perhaps? And not all the capital cities are timezone places, and so for some of those we can use Weather integration to still show apt online information when click/touching a Countries Report row. Speaking of this “row”, we make an improvement whereby on a first click of a right hand (Country) row cell, that cell is not initially a contenteditable=”true” one (that may frustrate showing the keyboard on mobile, when most likely it was the row touch intended), but then becomes a contenteditable=”true” cell henceforth.

    … then yesterday’s Window SessionStorage Client Versus Server Flags Tutorial “progress to now” needs to take notice of a user’s order of multiple select (dropdown) element click/touching of Capital City option (sub)elements, just as we did with the recent User Controlled Dynamic Javascript YouTube Embedded API Ordered Tutorial‘s web application project to allow for a user ordered YouTube video playlist.

    Because what is a Trip Planner without an ordered trip? Well, that is debatable, but what isn’t (debatable), is that there will be people in the world who appreciate the “mapping out” of a proposed Trip Planning Itinerary. What could we call on here? We can think of the Google Chart Geo Chart work around about the time of Google Geo Chart Co-ordinate Emojis Tutorial, when we started using …

    • a world map … with …
    • emoji markers … and optionally …
    • joined up by straight lines

    … an idea for a Trip Plan itinerary synopsis, perhaps?!

    If you examined closely yesterday’s code changes you will have noticed our collecting of TimeZone Place geographical latitude and longitude information. Today, we start making use of that preparatory work with our changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.

    Stop Press

    The “emoji markers” above (as of 2 January 2020) will be “country flags” (as per Window SessionStorage Client Versus Server Flags Tutorial ideas), as defined.


    Previous relevant Window SessionStorage Client Versus Server Flags Tutorial is shown below.

    Window SessionStorage Client Versus Server Flags Tutorial

    Window SessionStorage Client Versus Server Flags Tutorial

    Yes, there’s more to do onto yesterday’s Window SessionStorage Client Versus Server CSS Tutorial‘s Capital City Find Matching Country Report web application project, in our eyes. We have not even mentioned “Internationalization” as a concept up to now. In this line of thinking …

    Did you know?

    Emoji flags via ISO 2 character country codes are dead easy via Regional Indicator Symbol characters …


    var lri="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    var dri=["127462","127463","127464","127465","127466","127467","127468","127469","127470","127471","127472","127473","127474","127475","127476","127477","127478","127479","127480","127481","127482","127483","127484","127485","127486","127487"];

    var thiscc='AU'; // ISO 2 character countrycode for Australia
    var ccsuff='', ccchar=' ';
    for (var iccsuff=0; iccsuff<thiscc.length; iccsuff++) {
    ccchar=thiscc.substring(iccsuff, eval(1 + eval('' + iccsuff))).toUpperCase();
    ccsuff+='&#' + dri[eval('' + lri.indexOf(ccchar))] + ';';
    }
    document.getElementById('lastflag').innerHTML=ccsuff;

    … to result in (via <span style=font-size:64px;>&#127462;&#127482;</span>) …


    🇦🇺

    … providing interest and general translatability to the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link.


    Previous relevant Window SessionStorage Client Versus Server CSS Tutorial is shown below.

    Window SessionStorage Client Versus Server CSS Tutorial

    Window SessionStorage Client Versus Server CSS Tutorial

    Further to yesterday’s Window SessionStorage Client Versus Server Integration Tutorial we have a two pronged improvements set for you today with our current Capital City Find Matching Country Report web application project …

    • CSS styling changes … and …
    • additional functionality for Email and SMS links back to our current Capital City Find Matching Country Report web application project (to complete the cycle)

    We use several modes of CSS application (the first and last of particular relevance to today’s “highlighting of workflow” improvements) …

    … the “static” measures often helping to highlight the web application’s main workflow of user interaction and the “dynamic” measures helping to alert the user as to where to proceed with their “workflow”.

    In terms of CSS styling work …

    1. for non-mobile platforms we allow for more columns to be applied to our Capitals select (dropdown) element (in order to reduce some user scrolling, as does our new additional A-Z letter basis sorting functionality) as per … the “dynamic” Javascript DOM “class” modifications

      if (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
      document.getElementById('lefttd').className='lefttd';
      }

      … dovetailing with the “static” internal CSS coding

      <style>
      .lefttd {
      column-count: 4;
      max-height: 35%;
      vertical-align: top;
      max-width: 70%;
      font-size: 8px;
      background-color: rgba(205,205,205,0.5);
      background-image: -webkit-gradient(
      linear,
      right bottom,
      left top,
      color-stop(0, rgba(205, 205, 205, 0.8)),
      color-stop(0.50, rgba(255, 255, 0, 0.2))
      );
      background-image: -o-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -moz-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -webkit-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: -ms-linear-gradient(left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);
      background-image: linear-gradient(to left top, rgba(205, 205, 205, 1) 0%, rgba(255, 255, 0, 0.2) 50%);

      }
      </style>

      … and please note that around here at RJM Programming we have a “far from hard and fast rule” (but a rule regardless) regarding HTML element ID and class attributes that they concern (and (usually) be compartmentalised into) Javascript (DOM) manipulations and CSS styling issues respectively … and add a linear-gradient background to the table cell when expecting the initial user interaction on non-mobile platforms
    2. a “dynamic” Javascript DOM “class” modification … document.getElementById(‘myrepsb’).className=’dglow’; … is made to the “Report…” button at the Capitals select (dropdown) onfocusout event so as to highlight (with “glow” inspired styling) where user interaction may flow to

    As far as links go, you may expect to need serverside means to construct these in online Email and SMS message interfacing, but email (client program) products like Gmail parse your ascii text and convert http: or https: protocol URLs in your Email body to hyperlinks, as does the Messages SMS application here on this MacBook Pro using macOS Mojave. Cute, huh?! So to close the circle back from remote thar’ parts back to our web application is a simple matter of, in broad brush terms …

    • adding two new buttons called “Email Columns and Links …” and “SMS Columns and Links …” that …
    • set a global variable andlinkto = true; … setting in play, within the report writing code (that likes monospaced fonts) …
    • add a new links column to the right with URLs like …
      https://www.rjmprogramming.com.au/HTMLCSS/wls_vs_php.htm?andgo=y&countries=Belize&capitals=Belmopan
      … to tell your client programs to form the hyperlinks for us (if they are “of the mood”, that is!)

    To improve user experience we use “dynamic” Javascript DOM HTML “style” attribute change means to easier close the “Colour Wheel” helper web application “above the fold” by changing the CSS z-index (Javascript DOM [element].style.zIndex) of elements accordingly, when the user clicks other elements. You can see all this with the first “the changed” link above, where all “glow” CSS styling will also feature prominently.


    Previous relevant Window SessionStorage Client Versus Server Integration Tutorial is shown below.

    Window SessionStorage Client Versus Server Integration Tutorial

    Window SessionStorage Client Versus Server Integration Tutorial

    We hope, when performing a “software integration” task, that the two or more components of that integration work with each other’s talents, rather than a big tussle like reinventing the wheel. This ideal makes the work …

    • sometimes difficult but rewarding because …
    • the differences between two independent software components can be quite large and daunting … and the programmer has to see that …
    • care is applied so as not to wreck previous functionality and integrations in making the current integration work

    … and that is why we’ve made corollaries to “building from scratch” (when planning and design is a huge component) can be a lot simpler than a software integration “renovation”, in the past, here at this blog.

    Our primary integration today is to (software) integrate the great Weather Underground and its great API service for autocomplete name searches for weather (and hurricane) information. Why bother? Well, can you not envisage a user using that Ajax functionality of yesterday’s Window SessionStorage Client Versus Server Ajax Tutorial as a trip planner, perhaps, or as a “checking up on relatives overseas” tool, perhaps? And not all the capital cities are timezone places, and so for some of those we can use Weather integration to still show apt online information when click/touching a Countries Report row. Speaking of this “row”, we make an improvement whereby on a first click of a right hand (Country) row cell, that cell is not initially a contenteditable=”true” one (that may frustrate showing the keyboard on mobile, when most likely it was the row touch intended), but then becomes a contenteditable=”true” cell henceforth.

    As a user experience improvement for “trip planners” perhaps, we allow the user to alphabetically sort the presented select (dropdown) element entries …


    var firstopt='';
    var wasopts='';
    var restopts='';

    function readyitforsort(iselid) {
    var optsare=[];
    var huhisel=document.getElementById(iselid).innerHTML;
    var huhsopts=huhisel.split('</option>');
    for (var ihuh=0; ihuh<huhsopts.length; ihuh++) {
    if (huhsopts[ihuh].trim() != '') {
    if (firstopt == '') {
    firstopt=huhsopts[ihuh] + '</option>';
    } else {
    wasopts+=huhsopts[ihuh].replace('option ','option data-ih="' + (huhsopts[ihuh].split('>')[eval(-1 + huhsopts[ihuh].split('>').length)] + '" ')) + '</option>';
    optsare.push(huhsopts[ihuh].replace('option ','option data-ih="' + (huhsopts[ihuh].split('>')[eval(-1 + huhsopts[ihuh].split('>').length)] + '" ')) + '</option>');
    }
    }
    }
    optsare.sort();
    for (var jhuh=0; jhuh<optsare.length; jhuh++) {
    restopts+=optsare[jhuh];
    }
    }

    … controlled by a new dropdown in the left hand column header cell.

    We also allow the user to move the iframe element with some positioning emoji buttons near the “Close” button one (of yesterday’s work).

    Into the future, too, we’ll have more to say regarding the germination of an idea “to allow a mobile onmouseover simulator (of sorts)” be to allow the user to perform a swipe across an individual HTML element of interest on mobile platforms (ie. harness ontouchmove event) as per (so far) … kicked off by “<body onload=” setTimeout(athn, 5000); “>” …


    var last24='';
    var rectdc;

    function nodivalert() {
    document.getElementById('divalert').style.display='none';
    document.getElementById('divalert').style.zIndex='-456';
    document.getElementById('divalert').style.left=('-' + rectdc.left).replace('px','') + 'px';
    document.getElementById('divalert').style.top=('-' + rectdc.top).replace('px','') + 'px';
    }

    function ourdivalert(inmsg) {
    document.getElementById('divalert').style.position='absolute';
    document.getElementById('divalert').style.left=('' + rectdc.left).replace('px','') + 'px';
    document.getElementById('divalert').style.top='' + eval(-80 + eval(('' + rectdc.top).replace('px',''))) + 'px';
    document.getElementById('divalert').style.backgroundColor='#e0e0e0';
    document.getElementById('divalert').style.display='block';
    document.getElementById('divalert').style.zIndex='456';
    document.getElementById('divalert').style.opacity='0.8';
    document.getElementById('divalert').style.padding='5px 5px 5px 5px';
    document.getElementById('divalert').innerHTML=inmsg + '<br><br><input type=button value=Close onclick=nodivalert();></input>';
    setTimeout(nodivalert,9000);
    }

    function athn() {
    rectdc=document.getElementById('dc').getBoundingClientRect();
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    document.getElementById('dc').ontouchmove=function(event) { if (last24.substring(0,eval(-1 + last24.length)) == event.target.title.substring(0,eval(-1 + event.target.title.length))) { last24=last24; } else { last24=event.target.title; ourdivalert(event.target.title); } }
    } else {
    document.getElementById('dc').onmousemove=function(event) { if (last24.substring(0,eval(-1 + last24.length)) == event.target.title.substring(0,eval(-1 + event.target.title.length))) { last24=last24; } else { last24=event.target.title; ourdivalert(event.target.title); } }
    }
    }

    … working with the new HTML …


    <div id=divalert></div>
    </body>
    </html>

    … to try to allow the “explainer of an element” advantages non-mobile platforms have for hovering over an HTML element with a title attribute filled in.

    And so, yet again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new Weather integration functionality. It caused the changed colour_wheel.html‘s colour wheel (at this live run link) to be affected (by integrations “up”).


    Previous relevant Window SessionStorage Client Versus Server Ajax Tutorial is shown below.

    Window SessionStorage Client Versus Server Ajax Tutorial

    Window SessionStorage Client Versus Server Ajax Tutorial

    We have a few “clientside chestnuts” to use with our current Capital City Find Matching Country Report web application project today, those being …

    • Ajax functionality, kicked off by an “onclick” event set of logic, allowing mobile platforms to also have a look in (the look in that they miss when the event logic is off the “onmouseover” event)
    • iframe and its …
      1. srcdoc attribute (“content” alternative to src “url” attribute) … along with, and crucially needing (because srcdoc ignores its own document.body onload goings on, that we need the “Iframe Client Pre-Emptive” methods below to circumvent) the …
      2. onload event opportunity of an iframe element (we group into “Iframe Client Pre-Emptive” methods, here)

    … adding onto yesterday’s Window SessionStorage Client Versus Server Canvas Tutorial.

    It’s not that involved with the Ajax work today, given that there are no cross-domain issues, though there are cross-protocol (SSL https: versus non-SSL http:) issues to be careful about. Those can be addressed because the web application is recalled to present its “Country Report” and that is the opportunity to check on protocol navigation requirements.

    Along the way, we also make this happen for the user on …

    • click/touching a table row … it sets off new “tr” (table row) element logic calling our (inhouse) Timezone and Wikipedia Place Information helper (HTML) via Ajax (so not leaving the webpage) … and because of place name oddities we allow for …
    • “td” (table cell) element user amendments by setting their contenteditable attributes to “true” (since fixed, but we found the Timezone Europe/Tirane pointing at Tirane in Albania used to be spelt “Tirana”)

    … that latter methodology normally a technique we apply to “div” elements (so, there you are!)

    Also used are “overlay” techniques, two of the “usual suspects” here coming into play, to present to the “Ajax content to srcdoc iframe arrangements” …

    Yet again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new “Ajax” functionality.


    Previous relevant Window SessionStorage Client Versus Server Canvas Tutorial is shown below.

    Window SessionStorage Client Versus Server Canvas Tutorial

    Window SessionStorage Client Versus Server Canvas Tutorial

    Yesterday’s Window SessionStorage Client Versus Server Share Tutorial dealt with ascii text clipboard copy assisted sharing options with our current Capital City Find Matching Country Report web application project. This suited both Email and SMS share options we coded for, but today’s extension of functionality from “ascii text” data to “graphical data” only suits Email sharing. The other caveat with our work is that no serverside (for us, PHP) help is allowed, so no PHP mail here.

    What comes into play with a “graphical data” clientside (only) sharing approach? It will not surprise many readers that, for us, it involves …

    • canvas element … converting HTML table outerHTML “ascii text” data … via …
    • canvas drawing methods “[canvasContext].strokeRect()” and “[canvasContext].strokeText()” via “[cellElement].getBoundingClientRect()” … to convert that canvas element content via …
    • [canvasElement].toDataURL() … to an …
    • img element nested in a div contenteditable=true element … so as to hook in with today’s very useful helper link, thanks … use …

    • function tabletoclipboard(canvas) { // thanks to https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard
      var img = document.createElement('img');
      img.src = canvas.toDataURL();

      var div = document.createElement('div');
      div.contentEditable = true;
      div.appendChild(img);
      document.body.appendChild(div);

      // do copy
      SelectText(div);
      document.execCommand('Copy');
      document.body.removeChild(div);
      }

      function SelectText(element) { // thanks to https://stackoverflow.com/questions/27863617/is-it-possible-to-copy-a-canvas-image-to-the-clipboard
      var doc = document;
      if (doc.body.createTextRange) {
      var range = document.body.createTextRange();
      range.moveToElementText(element);
      range.select();
      } else if (window.getSelection) {
      var selection = window.getSelection();
      var range = document.createRange();
      range.selectNodeContents(element);
      selection.removeAllRanges();
      selection.addRange(range);
      }
      }
    • to leave the user’s device’s clipboard containing a useful table (with linework) … ready to …
    • paste into an email body section

    … sharing off to an emailee collaborator.

    Again, see the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new “Email Table” button functionality.


    Previous relevant Window SessionStorage Client Versus Server Share Tutorial is shown below.

    Window SessionStorage Client Versus Server Share Tutorial

    Window SessionStorage Client Versus Server Share Tutorial

    Yesterday’s Window SessionStorage Client Versus Server Tutorial has been amended today for two new sharing and collaboration options, those being …

    • email
    • SMS

    … but you may well be familiar with the restrictions on email and SMS client (program) approaches to this, coming from HTML “a” link “mailto:” and “sms:” href property prefixes respectively. We’re going to need help with the 800 odd character (length) restrictions with the (resultant) web address (bar) URL, but what? How about working off the great advice of this wonderful link, thanks, to copy what we’d have assembled into an ascii text Report into the characters contained by the user’s device’s clipboard?


    function copytoclipboard(str) { // thanks to https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f
    var el = document.createElement('textarea');
    el.value = str;
    el.setAttribute('readonly', '');
    el.style.position = 'absolute';
    el.style.left = '-9999px';
    document.body.appendChild(el);
    el.select();
    document.execCommand('copy');
    document.body.removeChild(el);
    }

    An issue that springs up here using such clipboard ascii text content, whenever you get the Font choice given to you, pick a monospaced Font like Courier New or “Fixed Width”.

    See the changed wls_vs_php.htm‘s Capital City Find Matching Country Report live run link’s new sharing functionality.


    Previous relevant Window SessionStorage Client Versus Server Tutorial is shown below.

    Window SessionStorage Client Versus Server Tutorial

    Window SessionStorage Client Versus Server Tutorial

    Sometimes it’s the case at this blog that we’d like to introduce a new topic, but do not do so, because we cannot show any real world (or real application) use of that concept. So it has been, up until now, with the concept of (web browser) window (object) sessionStorage property. But yesterday’s Window LocalStorage Client Versus Server Primer Tutorial represented an opportunity akin to when Haley’s Comet gets at its closest to the Earth … while you see a chance, take it … chance because of that nuance whereby we were not trying to store data for any other purpose than passing data onto …

    1. a known entity … ie. same web application … at …
    2. a known time … ie. immediately

    … two conditions that make the code design “marginally” more ideal for the window object property concept of sessionStorage rather than localStorage, in that any …


    localStorage.removeItem([knownLocalStorageName]);

    … becomes superfluous as with sessionStorage data will disappear between web browser sessions, anyway.

    We offer this new concept as a non-default option of a select (dropdown) element replacement to the h1 element hardcoding “localStorage” with the changed wls_vs_php.htm Capital City Find Matching Country Report live run. The other nuance of difference with sessionStorage usage is that in the document.body onload event logic, we may as well (as part of other changes) pre-emptively look for, and if there, respond to, any found sessionStorage data points, even without the user having flagged it specifically


    var datamode='localStorage';

    function checkforreport() {
    var divcont='';
    var dcaps, dctys, idis;
    if (getcapitals == 'localStorage') {
    if (window.localStorage) {
    getcapitals=decodeURIComponent(localStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
    localStorage.removeItem('wls_vs_php_capitals');
    } else {
    getcapitals='';
    }
    } else if (getcapitals == 'sessionStorage') {
    document.getElementById('smode').value=getcapitals;
    datamode=getcapitals;
    if (window.sessionStorage) {
    getcapitals=decodeURIComponent(sessionStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
    } else {
    getcapitals='';
    }
    }
    else if (getcapitals == '' && window.sessionStorage) {
    getcapitals=decodeURIComponent(('' + sessionStorage.getItem('wls_vs_php_capitals')).replace(/^null$/g,'')).replace(/\+/g,' ');
    if (getcapitals != '') {
    document.getElementById('smode').value='sessionStorage';
    datamode='sessionStorage';
    }
    }

    if (getcountries == 'localStorage') {
    if (window.localStorage) {
    getcountries=decodeURIComponent(localStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
    if (getcapitals.replace('localStorage','') != '' && getcountries.replace('localStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
    localStorage.removeItem('wls_vs_php_countries');
    } else {
    getcountries='';
    }
    } else if (getcountries == 'sessionStorage') {
    if (window.sessionStorage) {
    getcountries=decodeURIComponent(sessionStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
    if (getcapitals.replace('sessionStorage','') != '' && getcountries.replace('sessionStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
    } else {
    getcountries='';
    }
    }
    else if (getcountries == '' && document.getElementById('smode').value == 'sessionStorage' && window.sessionStorage) {
    getcountries=decodeURIComponent(('' + sessionStorage.getItem('wls_vs_php_countries')).replace(/^null$/g,'')).replace(/\+/g,' ');
    if (getcountries != '') {
    document.getElementById('smode').value='sessionStorage';
    datamode='sessionStorage';
    }
    }

    if (getcapitals != '' && getcountries != '') {
    divcont='<table border=5 style="width:95%;vertical-align:top;background-color:white;"><tr style=background-color:#f0f0f0;"><th>Capital</th><th>Country</th></tr></table>';
    dcaps=getcapitals.split('|');
    dctys=getcountries.split('|');
    for (idis=0; idis<dcaps.length; idis++) {
    divcont=divcont.replace('</table>', '<tr><td>' + dcaps[idis] + '</td><td>' + dctys[idis] + '</td></tr></table>');
    }
    document.getElementById('dreport').innerHTML=divcont;
    }
    document.getElementById('smode').value=datamode;
    }

    Which beggars the question “What are the differences between sessionStorage and localStorage?” A quick reading might surmise that “the latter has an expiration date”. We leave you with an open ended Google search so that you may extend your readings on this.


    Previous relevant Window LocalStorage Client Versus Server Primer Tutorial is shown below.

    Window LocalStorage Client Versus Server Primer Tutorial

    Window LocalStorage Client Versus Server Primer Tutorial

    Even though we rave on a lot about serverside PHP and its $_POST method=POST (versus HTML/Javascript recipient via ? and & argument $_GET method=GET scenario) data length advantages as the recipient of an HTML form method=POST set of data that could be sizeable, we’ve just realized that there is a client Javascript and window.localStorage methodology that may help alleviate the need to involve PHP (and any other serverside intervention) on occasions.

    Hint: Yes, we’ve raved on about this too?! Does the blog posting title give it away? Okay, yes, it should read “localStorage”, but thought we’d gone past such juvenile finickiness since the Whac-A-Mole controversy of 1st December 2019 (or even The Great Tea Trolley Disaster of ’67, we daresay).

    It can even use a “self-destruct” approach to the use of this “localStorage” on having used it because …

    • the web application knows who is using it (localStorage) … and on having accessed and read it …
    • the web application knows it (localStorage) is of no use to any other user (in this web application’s case, at least)

    … which is very pleasing for a Land Surveyor who likes to leave cow paddocks as they’ve seen them so to speak. Except it’s like having a ten tonne truck worth of data access in amongst the cow pats when having access to “localStorage” (or PHP), rather than a little piddle of calf wee (wee Metcalfes know a thing or two about these things!) data access of ? and & HTML/Javascript URL arguments (or even if we were to use HTTP Cookies).

    It’s not as if we all have access to serverside language usage, though we do, because we really like PHP and MAMP and Apache/PHP/MySql web servers (and have arranged our development environment accordingly), but what if you are starting out in web development, and still want to allow for sizeable chunks of data with your web applications? Huh? Huh?! See the possibilities? Try our proof of concept wls_vs_php.html Capital City Find Matching Country Report live run, and highlight a whole swathe of (multiple mode) dropdown option Capital Cities holding down the shift key before pressing the yellow “Report” button. If the URL ends up as …

    https://rjmprogramming.com.au/HTMLCSS/wls_vs_php.html?capitals=localStorage&countries=localStorage

    that’s because the web application’s …


    function analyze() {
    var purl=document.URL.split('#')[0].split('?')[0] + '?capitals=' + encodeURIComponent(document.getElementById('capitals').value) + '&countries=' + encodeURIComponent(document.getElementById('countries').value);
    if (purl.length > 800) {
    if (phpexists) {
    document.getElementById('myform').method='POST';
    document.getElementById('myform').action='./wls_vs_php.php';
    } else if (window.localStorage) {
    localStorage.setItem('wls_vs_php_countries', encodeURIComponent(document.getElementById('countries').value));
    localStorage.setItem('wls_vs_php_capitals', encodeURIComponent(document.getElementById('capitals').value));
    document.getElementById('capitals').value='localStorage';
    document.getElementById('countries').value='localStorage';
    location.href=document.URL.split('#')[0].split('?')[0] + '?capitals=' + encodeURIComponent(document.getElementById('capitals').value) + '&countries=' + encodeURIComponent(document.getElementById('countries').value);

    return false;
    }
    }
    return true;
    }

    … HTML form onsubmit event logic …

    1. discovered no PHP web application existant (via Client Pre-emptive Iframe techniques) … and …
    2. discovered (in a sanity check feeling way) that to go down the proposed HTML form method=GET approach was risking a …

      HTTP 414 "Request URI too long"

      … web browser error … and that …
    3. localStorage was a known web browser piece of functionality
    4. … and so as per our localStorage logic we …

    5. back out of the default HTML form method=GET navigation setup of the web application in favour of …
      • storing that data into localStorage
      • substituting into the URL ? and & arguments the hardcoding “localStorage” (and in so doing, getting back under the HTTP 414 “Request URI too long” limitation, piecing together (what amounts to) …
        location.href=document.URL.split(‘#’)[0].split(‘?’)[0] + ‘?capitals=localStorage&countries=localStorage’;)
        … that on a recall to this same web application a …
      • document.body onload event piece of Javascript logic checks the localStorage for its incoming Capital City Country Report data, as per …

        var phpexists=false;
        var getcapitals=location.search.split('capitals=')[1] ? decodeURIComponent(location.search.split('capitals=')[1].split('&')[0]).replace(/\+/g,' ') : '';
        var getcountries=location.search.split('countries=')[1] ? decodeURIComponent(location.search.split('countries=')[1].split('&')[0]).replace(/\+/g,' ') : '';

        function checkforreport() {
        var divcont='';
        var dcaps, dctys, idis;
        if (getcapitals == 'localStorage') {
        if (window.localStorage) {
        getcapitals=decodeURIComponent(localStorage.getItem('wls_vs_php_capitals')).replace(/\+/g,' ');
        localStorage.removeItem('wls_vs_php_capitals');
        } else {
        getcapitals='';
        }
        }
        if (getcountries == 'localStorage') {
        if (window.localStorage) {
        getcountries=decodeURIComponent(localStorage.getItem('wls_vs_php_countries')).replace(/\+/g,' ');
        if (getcapitals.replace('localStorage','') != '' && getcountries.replace('localStorage','') != '') { document.getElementById('myh1').innerHTML+=' <font size=1>... yes, it was needed</font>'; }
        localStorage.removeItem('wls_vs_php_countries');
        } else {
        getcountries='';
        }
        }

        if (getcapitals != '' && getcountries != '') {
        divcont='<table border=5 style="width:95%;vertical-align:top;background-color:white;"><tr style=background-color:#f0f0f0;"><th>Capital</th><th>Country</th></tr></table>';
        dcaps=getcapitals.split('|');
        dctys=getcountries.split('|');
        for (idis=0; idis<dcaps.length; idis++) {
        divcont=divcont.replace('</table>', '<tr><td>' + dcaps[idis] + '</td><td>' + dctys[idis] + '</td></tr></table>');
        }
        document.getElementById('dreport').innerHTML=divcont;
        }
        }

        … the localStorage.removeItem() representing that “self-destruct” nuance we were talking about before

    We may well use this methodology in future projects, and hope it has been of some little interest to you as well?!

    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.


    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.


    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 Ajax, eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

WordPress Recent Posts Image Relative URL Issue Tutorial

WordPress Recent Posts Image Relative URL Issue Tutorial

WordPress Recent Posts Image Relative URL Issue Tutorial

Further to the daily crontab/curl (and PHP based) WordPress “Recent Posts” daily functionality that happens here at RJM Programming, as talked about with the recent WordPress Recent Posts Korn Shell Tutorial, the last couple of days we had a problem with non-rendering WordPress Blog tutorial thumbnails, to which our reaction involved …

  • one day of denial … where we did the necessary copy of image file on the web server so that the zero length crontab/curl image version could be sidestepped …
  • second day …

    It happened again! Ugh!!

    … let’s investigate …

  • PHP folder error_logtail -2 error_log

    [09-Jun-2025 05:05:34 Australia/Perth] PHP Warning: file_get_contents(/image_flipping_or_flopping_at_speed_more.gif): Failed to open stream: No such file or directory in /home/rjmprogr/public_html/PHP/recent-posts-2.php on line 131
    [09-Jun-2025 05:05:39 Australia/Perth] PHP Warning: file_get_contents(/image_flipping_or_flopping_at_speed_share.gif): Failed to open stream: No such file or directory in /home/rjmprogr/public_html/PHP/recent-posts-2.php on line 131

… got us, luckily, stumbling upon a “controllable environment”. In thinking on this, it is an advantage of PHP that it leaves clues in Apache error_log log files, so, thanks.

What did we see on arriving at erroneous line 131 of recent-posts-2.php editing in macOS TextWrangler?


126 if (substr($thisimg,0,2) == '//') $thisimg='http:' . $thisimg; // new SSL specific line 4/5/2017
127 //echo "\n" . $thisimg . "\n";
128 if (strpos($thisimg, 'rjmprogramming.com.au/') !== false) {
129 copy('/home/rjmprogr/public_html/' . explode('rjmprogramming.com.au/', $thisimg)[1], dirname(__FILE__) . "/" . $narray[$thisij] . ".jpg");
130 } else {
131 $icont = file_get_contents(str_replace('https:','http:',$thisimg));
132 file_put_contents(dirname(__FILE__) . "/" . $narray[$thisij] . ".jpg", $icont);
133 }
134 if (file_exists(dirname(__FILE__) . "/" . $narray[$thisij] . ".jpeg")) {
135 unlink(dirname(__FILE__) . "/" . $narray[$thisij] . ".jpeg");
136 }

And it was really line 126 that reminded us what we’d done a couple of days ago. We were getting no peace on our primary IP address to RJM Programming domain web server, but found peace back at the old one. What about we write the blog postings on the old web server WordPress blog “admin” section place, and then transfer what we end up with over to the newer IP address when conditions are better, and we don’t have to pfaff around quite so much that way? Good idea, except that the tutorial image may not show if it contains an absolute image URL back to the “hounded upon” IP address version, so being that said images exist in both IP address places, let’s make the blog posting tutorial image a “relative one” starting with / (but just one, not two, getting back to line 126) so that we can see it render properly.

So what?! (we hear you wonder) Indeed! But, our crontab/curl code above needed to end up with

<?php

if (substr($thisimg,0,2) == '//') {
$thisimg='http:' . $thisimg; // new SSL specific line 4/5/2017
} else if (substr($thisimg,0,1) == '/') { // ... and what about a relative image URL
$thisimg='http://www.rjmprogramming.com.au' . $thisimg;
} else if (substr($thisimg,0,3) == '../') { // ... and what about a relative image URL
$thisimg='http://www.rjmprogramming.com.au' . substr($thisimg,2);
} else if (substr($thisimg,0,2) == './') { // ... and what about a relative image URL
$thisimg='http://www.rjmprogramming.com.au/ITblog' . substr($thisimg,1);
}

//echo "\n" . str_replace('https:','http:',$thisimg) . "\n";
if (strpos($thisimg, 'rjmprogramming.com.au/') !== false) {
copy('/home/rjmprogr/public_html/' . explode('rjmprogramming.com.au/', $thisimg)[1], dirname(__FILE__) . "/" . $narray[$thisij] . ".jpg");
} else {
$icont = file_get_contents(str_replace('https:','http:',$thisimg));
file_put_contents(dirname(__FILE__) . "/" . $narray[$thisij] . ".jpg", $icont);
}
if (file_exists(dirname(__FILE__) . "/" . $narray[$thisij] . ".jpeg")) {
unlink(dirname(__FILE__) . "/" . $narray[$thisij] . ".jpeg");
}

?>

… to cater for this very mild and reasonable change of WordPress blog posting creation “habit” affecting the changed recent-posts-2.php WordPress “Recent Posts” PHP processing codeset.

Did you know?

Are you aware, on Linux or macOS of the wonders of, for example …


tail -f error_log

… as a means of dynamically tracking new records being added to error_log in real time?! Can be incredibly useful for debugging PHP!


Previous relevant WordPress Recent Posts Korn Shell Tutorial is shown below.

WordPress Recent Posts Korn Shell Tutorial

WordPress Recent Posts Korn Shell Tutorial

Today we’re rearranging how our WordPress.org blog Recent Posts widget images are created via crontab and curl in a scheduled way on this newer Apache/PHP/MySql Linux web server, as we talked about with WordPress Recent Posts Navigation Issue Tutorial too.

For a reason still unclear to us the recent-posts-2.php exec call of ImageMagick convert creation of thumbnails failed, after a failure creating zero length non-thumbnail images (fixed now using PHP copy rather than file_put_contents), though it works on the command line in a Linux environment with that same priviledged username.

Especially given that thumbnail usage is optional in the WordPress Recent Posts functionality, rather than spend more time unhappy, we’re happy if a beginning to Korn Shell (which the PHP now writes in a way so that the execution of the Korn Shell causes it’s self destruction) involvement …

… within the crontab purview.

Hopefully we’ll have good news tomorrow that it worked as a new approach.


Previous relevant WordPress Recent Posts Navigation Issue Tutorial is shown below.

WordPress Recent Posts Navigation Issue Tutorial

WordPress Recent Posts Navigation Issue Tutorial

Back to the topic of “WordPress Blog Recent Posts” (and its relationship to the RJM Programming Landing Page) last referenced at WordPress Recent Posts Widget Caching Issues Tutorial, is today’s fix to an iPhone usage hashtag navigational annoyance that would leave the Blog Title lose a bit of its visibility up the top when navigated to via the RJM Programming Landing Page top left “Recent Posts” thumbnail images.

The fix saw us add to the existant “#post-” prefixed hashtag navigation with our “#andabit=-70” “double hashtagging” as mentioned in WordPress Blog Hashtag Navigation Return Onmouseover Tutorial. It took us a while to track down where to intervene to achieve this, and we eventually cottoned onto the way that if that RJM Programming Landing Page top left “Recent Posts” iframe container (ie. zero.html) of those thumbnail images could involve URLs suffixed by “#andabit=-70” we would rid the hashtag navigation of that annoyance

<?php

file_put_contents(dirname(__FILE__) . "/zero.html",
str_replace(" href='", ' href="',
str_replace("#andabit=-7x' title='","#andabit=-70' title='",
str_replace("0' title='","0#andabit=-7x' title='",
str_replace("1' title='","1#andabit=-7x' title='",
str_replace("2' title='","2#andabit=-7x' title='",
str_replace("3' title='","3#andabit=-7x' title='",
str_replace("4' title='","4#andabit=-7x' title='",
str_replace("5' title='","5#andabit=-7x' title='",
str_replace("6' title='","6#andabit=-7x' title='",
str_replace("7' title='","7#andabit=-7x' title='",
str_replace("8' title='","8#andabit=-7x' title='",
str_replace("9' title='","9#andabit=-7x' title='",
str_replace("/wordpress/", "/ITblog/", $htmlis))
))))))))))));

?>

… reflected by a changed recent-posts-2.php WordPress “Recent Posts” PHP processing codeset.

Then that “#andabit=-70” propagates through to a “double hashtagging” scenario you can see with today’s tutorial picture.


Previous relevant WordPress Recent Posts Widget Caching Issues Tutorial is shown below.

WordPress Recent Posts Widget Caching Issues Tutorial

WordPress Recent Posts Widget Caching Issues Tutorial

The WordPress blog you are reading, with the TwentyTen theme, has a useful “widget” (contained unit of functionality on the webpage that WordPress knows about) called “Recent Posts”, which we’ve had a lot of fun over the years, working with, but “working against”, a tad (because the issue is not exactly mission critical, and) if you are not careful, are the combination of …

  • the content needed to be up to date at all times would need to counter the once a day crontab/curl arrangements (that WordPress does not know about) for the new posting each day … versus …
  • the caching of the web browser used can circumvent the up to date correspondence of …
    1. “a” link nesting … of …
    2. “img” blog posting thumbnail

… in two scenarios that we have discovered …

  1. you arrive back at a blog posting webpage after a crontab/curl sequence has happened … the caching causes the “img” and “a” not to correspond, at least on that first such occasion, sometimes …
  2. you arrive off the Landing Page (after a crontab/curl sequence has happened) and up the top left you click on a blog posting that isn’t the latest, and you visited the day before, the caching from that day before causes the “img” and “a” not to correspond, at least on that first such occasion, sometimes

Today’s animated GIF presentation represents a warts and all (occasionally mistaking a Javascript issue for a CSS one) showing of the troubleshooting and investigation of such caching WordPress Recent Posts issues.

Central to the solutions are the idea that the crontab/curl work leaves behind a zero.html “report webpage” we can effectively test the caching against as like a “sanity test” … like. As “caching” is a “client” thaing whereas the PHP of the TwentyTen theme code “header.php” happens is taking place at the “server” end of thaings, what can be the “conduit” between these two woooooorrrrrrllllllldddds …

<?php echo ”

<iframe onload='rptds(this);' style='display:none;' src='//www.rjmprogramming.com.au/PHP/zero.html<?php echo "?rand=" . rand(0,198765432); ?>'></iframe>

“; ?>

… placed immediately after the “body” element definition. That Javascript “onload” event logic sets up some global arrays we’ll use later …

<?php echo ”

var nothanks=false, findthing="", rptdlist=[], rptdhref=[], rptdtitle=[];

function rptds(iois) {
var thistdis='';
if (iois != null) {
var xaaconto = (iois.contentWindow || iois.contentDocument);
if (xaaconto != null) {
if (xaaconto.document) { xaaconto = xaaconto.document; }
if (xaaconto.body != null) {
var ltds=xaaconto.body.innerHTML.split('<td');
for (var iltds=1; iltds<ltds.length; iltds++) {
thistdis='<td' + ltds[iltds].split('</td>')[0] + '</td>';
rptdlist.push(thistdis);
if (thistdis.indexOf(' href="') != -1) {
rptdhref.push(thistdis.split(' href="')[1].split('"')[0]);
}
if (thistdis.indexOf(' title="') != -1) {
rptdtitle.push(thistdis.split(' title="')[1].split('"')[0]);
}
}
}
}
}
}

“; ?>

… so that changed code in Javascript “function rptwo” as below …

<?php echo ”

function rptwo() {
var tworp=document.getElementById('recent-posts-2');
if (tworp != null) {
if (tworp.innerHTML.indexOf('<u' + 'l>') != -1) {
var ihs=tworp.innerHTML.split("</a>");
tworp.innerHTML = tworp.innerHTML.replace('<u' + 'l>', '<u' + 'l class="iconlist">').replace(/a href/g,'a style="border:1px solid rgba(0,127,0,0.6);background: rgba(0,255,0,0.6); background: -webkit-linear-gradient(left top, rgba(0,255,0,0.6), rgba(255,255,0,0.6)); background: -o-linear-gradient(bottom right, rgba(0,255,0,0.5), rgba(255,255,0,0.6)); background: -moz-linear-gradient(bottom right, rgba(0,255,0,0.6), rgba(255,255,0,0.6)); background: linear-gradient(to bottom right, rgba(0,255,0,0.6), rgba(255,255,0,0.6));" title="Go to tutorial" onclick="if (1 == 2) { findthing=' + "''" + '; } nothanks=true;" href');
var eight=new Array("one", "two", "three", "four", "five", "six", "seven", "eight");
var ieight;
tworp.innerHTML = tworp.innerHTML.replace(/<\/a>/g, "</a><img class='iiconlist' src='//www.rjmprogramming.com.au/wordpress/transparent.png' style='z-index:3;margin-left:0px;margin-top:0px;opacity:0.2;width:140px;height:100px;box-shadow:rgba(0,0,255,0.2) 2px 2px 2px 2px inset;' onmouseover='getRpnow();' onmouseout='yehBut();' ontouchstart='getRpnow();' ontouchend='yehBut();' title=' ... welcome to the long hover functionality that shows Blog Post regarding Recent Post images'>");
for (ieight=0; ieight<eight.length; ieight++) {
if (ihs.length > eval(0 + ieight)) {
if (rptdtitle.length > ieight) {
if (ihs[eval(0 + ieight)].split(">")[eval(-1 + ihs[eval(0 + ieight)].split(">").length)] != rptdtitle[ieight]) {
tworp.innerHTML = tworp.innerHTML.replace(ihs[eval(0 + ieight)], ihs[eval(0 + ieight)].replace(' href=', ' href="' + rptdhref[ieight].replace('?p=', '?rx=' + Math.floor(Math.random() * 198765434) + '&p=') + '" data-href=').replace('>' + ihs[eval(0 + ieight)].split(">")[eval(-1 + ihs[eval(0 + ieight)].split(">").length)] + '<', '>' + rptdtitle[ieight] + '<'));
tworp.innerHTML = tworp.innerHTML.replace("<li>", "<li title='Cut to the Chase' onclick=' findthing=\"" + rptdtitle[ieight] + "\"; setTimeout(rplater,1000); nothanks=false; ' class='" + eight[ieight] + "'>");
} else {
tworp.innerHTML = tworp.innerHTML.replace("<li>", "<li title='Cut to the Chase' onclick=' findthing=\"" + ihs[eval(0 + ieight)].split(">")[eval(-1 + ihs[eval(0 + ieight)].split(">").length)] + "\"; setTimeout(rplater,1000); nothanks=false; ' class='" + eight[ieight] + "'>");
}
} else {

tworp.innerHTML = tworp.innerHTML.replace("<li>", "<li title='Cut to the Chase' onclick=' findthing=\"" + ihs[eval(0 + ieight)].split(">")[eval(-1 + ihs[eval(0 + ieight)].split(">").length)] + "\"; setTimeout(rplater,1000); nothanks=false; ' class='" + eight[ieight] + "'>");
}
} else {
tworp.innerHTML = tworp.innerHTML.replace("<li>", "<li class='" + eight[ieight] + "'>");
}
//tworp.innerHTML = tworp.innerHTML.replace("<img class=", "<img onclick='clickaid(\"a" + eight[ieight] + "\");' class=").replace("<img title=\" ", "<img onclick=\"clickaid('a" + eight[ieight] + "');\" title=\"");
tworp.innerHTML = tworp.innerHTML.replace("<img class=", "<img onclick=\"if (1 == 2) { findthing=''; } nothanks=true; clickaid('a" + eight[ieight] + "');\" class=").replace("<img title=\" ", "<img onclick=\"clickaid('a" + eight[ieight] + "');\" title=\"");
}
}
}
}

“; ?>

… helps resolve the second issue’s mismatched data sources which caching may exacerbate.

What about the first issue? Well, we went down the route of thinking this was bound to be a Javascript scripting issue and went through the code with that in mind, until searching for “one.jp” (I think it was) within “header.php” got us tweaked into realizing some of the CSS styling there was encouraging the cache to not let go of “img” “src” attributes. As we are more and more fond of doing these days, even for image URLs, we add some “get” “?” and/or “&” arguments to cause the web browser to go back to the source (and so, around the “cache”) to get its data, as per “header.php”‘s (changed)


<style>
li.one {
background-image: url('//www.rjmprogramming.com.au/PHP/one.jpg<?php echo "?rnd=" . rand(0,19876545); ?>');
background-position: left;
background-repeat: no-repeat;
background-size: 128px 80px;
height: 150px;
text-indent: 0px;
}

li.two {
background-image: url('//www.rjmprogramming.com.au/PHP/two.jpg<?php echo "?rnd=" . rand(0,19876545); ?>');
background-position: left;
background-repeat: no-repeat;
background-size: 128px 80px;
height: 150px;
text-indent: 0px;
}

li.three {
background-image: url('//www.rjmprogramming.com.au/PHP/three.jpg<?php echo "?rnd=" . rand(0,19876545); ?>');
background-position: left;
background-repeat: no-repeat;
background-size: 128px 80px;
height: 150px;
text-indent: 0px;
}

li.four {
background-image: url('//www.rjmprogramming.com.au/PHP/four.jpg<?php echo "?rnd=" . rand(0,19876545); ?>');
background-position: left;
background-repeat: no-repeat;
background-size: 128px 80px;
height: 150px;
text-indent: 0px;
}

li.five {
background-image: url('//www.rjmprogramming.com.au/PHP/five.jpg<?php echo "?rnd=" . rand(0,19876545); ?>');
background-position: left;
background-repeat: no-repeat;
background-size: 128px 80px;
height: 150px;
text-indent: 0px;
}

li.six {
background-image: url('//www.rjmprogramming.com.au/PHP/six.jpg<?php echo "?rnd=" . rand(0,19876545); ?>');
background-position: left;
background-repeat: no-repeat;
background-size: 128px 80px;
height: 150px;
text-indent: 0px;
}

li.seven {
background-image: url('//www.rjmprogramming.com.au/PHP/seven.jpg<?php echo "?rnd=" . rand(0,19876545); ?>');
background-position: left;
background-repeat: no-repeat;
background-size: 128px 80px;
height: 150px;
text-indent: 0px;
}

li.eight {
background-image: url('//www.rjmprogramming.com.au/PHP/eight.jpg<?php echo "?rnd=" . rand(0,19876545); ?>');
background-position: left;
background-repeat: no-repeat;
background-size: 128px 80px;
height: 150px;
text-indent: 0px;
}
</style>

Continuing in that long line of WordPress Recent Posts work you look over to your right (or down the bottom, for some mobile platforms) of the blog webpage for the relevant widget that has that relationship to the Landing Page as we last talked about with Landing Page WordPress Tags Primer Tutorial. There, you can see, we hope, more reliable correspondence of “a” to “img” data sources, in their rightful order, the catalyst for change being that once a day crontab/curl “inhouse” publishing of one WordPress blog post.


Previous relevant Landing Page WordPress Tags Primer Tutorial is shown below.

Landing Page WordPress Tags Primer Tutorial

Landing Page WordPress Tags Primer Tutorial

We’re hooking into our crontab/curl PHP overnight arrangements regarding Recent Posts to add in …

  • a once a day creation of a web server “tag cloud” HTML file … derived via …
  • WordPress blog widget “Tags” content

… that creates on the RJM Programming “Landing Page” a toggling arrangement between …

  • this new “tag cloud” content in an iframe “onload” event populating of a global variable divtc … within the Landing Page Javascript …

    var divtc='';

    function anticheckd(iois) {
    document.getElementById('divtagcloud').innerHTML='';
    }

    function checkd(iois) {
    if (iois != null) {
    var aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    divtc=aconto.body.innerHTML;
    if (divtc.indexOf(' class="tagcloud"') != -1) {
    setTimeout(divtctoggler, 8000);
    } else {
    document.getElementById('divtagcloud').innerHTML='';
    }
    }
    }
    }
    }

    function divtctoggler() {
    if (divtc != '') {
    if (document.getElementById('divtagcloud').innerHTML == '' || document.getElementById('divtagcloud').innerHTML.indexOf('<iframe ') != -1) {
    document.getElementById('topi').style.display='none';
    document.getElementById('divtagcloud').style.transformOrigin="30% 10%"; //zoom="0.75";
    document.getElementById('divtagcloud').style.transform="scale(0.5)"; //zoom="0.75";
    document.getElementById('divtagcloud').innerHTML=divtc;
    } else {
    document.getElementById('divtagcloud').innerHTML='';
    document.getElementById('topi').style.display='block';
    }
    setTimeout(divtctoggler, 15000);
    }
    }

    … supporting the new HTML …

    <div id=divtagcloud><iframe style='display:none;' onerror='anticheckd(this);' onload='checkd(this);' src='//www.rjmprogramming.com.au/PHP/divtagcloud.html'></iframe></div>

    … with …
  • existing Google Chart Pie Chart example of use

… in its “div widget” within the Landing Page HTML. As far as the crontab/curl PHP goes the changed recent-posts-2.php does its job of populating …

… via …

<?php

$classtagcloud=file_get_contents("https://www.rjmprogramming.com.au/ITblog/?p=14234");
$classtags=explode('<div class="tagcloud"', str_replace("http:","",str_replace("https:","",$classtagcloud)));
if (sizeof($classtags) > 1) {
file_put_contents(dirname(__FILE__) . '/divtagcloud.html', str_replace('<a ','<a target=_blank ','<html><body><div class="tagcloud"' . explode('</div>', $classtags[1])[0] . '</div></body></html>'));
}

?>

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, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , | Leave a comment

PHP Wikipedia Geo Map Google Chart Region Makeover Tutorial

PHP Wikipedia Geo Map Google Chart Region Makeover Tutorial

PHP Wikipedia Geo Map Google Chart Region Makeover Tutorial

You’d hope if you are doing something regularly, you could improve on something you did in 2018, here in 2025?! Well, that’s the story of today, revisiting that Wikipedia basis of Google Chart Geo Chart and Map Chart web application talked about with PHP Wikipedia Geo Map Google Chart Region Tutorial.

Back in 2018, it seems, we were keen on hashtag navigation like …

<?php

location.href='#tdmiddle';

?>

… whereas these days, unless a deliberate hashtag analysis is planned for in the code, we’re more likely to plump for …

<?php

document.getElementById('tdmiddle').scrollIntoView();

?>

… and so it came to pass, as one example of today’s web application rework. This second idea can have the advantage that if element “tdmiddle” is already “above the fold”, probably no programmatical scrolling will happen, and often that is good news, whereas the first approach tries to make sure element “tdmiddle” finishes up the top of the device’s webpage’s screen, often “a sledgehammer to crack a nut” approach.

And here’s why revisits are good practice? Would you believe we spent ten minutes on the “revisit” thinking the webpage started with the Google Maps Geo Chart and Map Chart table element section until …

  1. previous blog posting images … and …
  2. the code modification above

… tweaked us to the importance of the Wikipedia optioned dropdown that was there neglected “above the fold” for those ten minutes! Doh!

Okay, not good, but that embarrassment, at least, got us to wonder about how to better “decorate” that dropdown for the user, and then were thankful that this project was a PHP one, because we could reference a “very generous, thank you” image from Wikipedia as a background image “decoration” idea, as per (first simplistic go)

<?php

$cont=str_replace('<a href="#', '<a HREF="#', file_get_contents("http:" . str_replace("https:","",str_replace("http:","",$url))));

$bckidea='';
if (strpos($cont, '<img src="') !== false) {
$bckidea="background-image:linear-gradient(rgba(255,255,255,0.6),rgba(255,255,255,0.6)),url(" . explode('"', explode('<img src="', $cont)[1])[0] . ");background-repeat:repeat;background-size:contain;";
}


?>

… and then to …

<?php

$cont=str_replace('<a href="#', '<a HREF="#', file_get_contents("http:" . str_replace("https:","",str_replace("http:","",$url))));

$swrd=' src';
$selt='';
$bckidea='';
$aone=1;
$imgsare=explode('<img src="', $cont);
if (sizeof($imgsare) < 5 && sizeof(explode('<img alt="', $cont)) >= 5) { $swrd=' alt'; $imgsare=explode('<img alt="', $cont); }
$atestis='start?type=';
$tries=1;
if (sizeof($imgsare) >= 5) { while (strpos($atestis, 'start?type=') !== false && $tries < 50) { $tries++; $aone=rand(1, (-3 + sizeof($imgsare))); if (strpos(explode('>', $imgsare[$aone])[0], 'start?type=') === false) { $atestis=' '; } else if ($tries >= 50) { $aone=1; $atestis=' '; } } }
if (strpos($cont, '<img' . $swrd . '="') !== false) {
if ($swrd == ' alt' && strpos($imgsare[$aone], ' src="') !== false) {
$imgsare[$aone]=explode(' src="', $imgsare[$aone])[1];
}
$bckidea="background-image:linear-gradient(rgba(255,255,255,0.6),rgba(255,255,255,0.6)),url(" . explode('"', $imgsare[$aone])[0] . ");background-repeat:repeat;background-size:contain;";
$selt=' title="' . explode('"', $imgsare[$aone])[0] . '" ';
if (strpos($selt, '/') !== false) {
$selt=' title="' . explode('"', explode('/', $selt)[-1 + sizeof(explode('/', $selt))])[0] . '" ';
}
if (strpos(explode('>', $imgsare[$aone])[0], ' title="') !== false) {
$selt=' title="' . explode('"', explode(' title="', $imgsare[$aone])[1])[0] . '" ';
}
}


?>

… effectively, those CSS linear-gradients helping make the background image “further off into the background” and the use of background-repeat property being “repeat” a rare venture for us, and even rarer combined with a background-size property being “contain”, to better suit “backgrounding” a thing that is a lot wider than it is high.

We also tracked down some sort of data anomaly with Submarine Volcanoes on Earth Wikipedia data that we have skirted over for now, and that was stopping the webpage displaying for this Wikipedia choice.

All making for an interesting “revisit session” regarding the mildly made over craters.php live run.


Previous relevant PHP Wikipedia Geo Map Google Chart Region Tutorial is shown below.

PHP Wikipedia Geo Map Google Chart Region Tutorial

PHP Wikipedia Geo Map Google Chart Region Tutorial

Of course, it would be great if the people of the world could think more in terms of the Earth as a whole … social justice for all, freedom for all, lessening of poverty, end of slavery, end of war, care for the animals we share the Earth with, care for the environment … the list goes on. But alas, as far as organization of life goes, it is hard to think past the regional. You may have noticed with yesterday’s PHP Wikipedia Geo Map Google Chart Genericization Tutorial how the Google Chart Geo Charts were based on a map of the world, even for topics that were to do with a region (mode format), such as the “Mountains in Turkey” shown.

That awkwardness of presentation was the fault of the inadequacies, back then, of our interface to the Google Chart Geo Chart, rather than a paucity of functionality up at the Google end … doh. But now, and before actually, we have a better way for the user to define Google Chart Geo Chart regional displays, and we improve our interface to do that with a changed PHP code geo_chart.php (that you can try in isolation for yourself, if you like, at this live run link). With those changes there you may notice that we also now cater for text mode format whereby the Geo Chart is further annotated via the placename text, rather than any markers or shading alternative annotations. This mode of use is faster in that we don’t look for any image URLs for any markers, and so we now offer dropdown options using this faster presentation mode for those users in a real hurry. What about cluttered text? Well, Google Charts code (natively) handles that very well with an inbuilt “inset view” when the going gets tight. Cute, huh?!

Also, we offer the user the chance to try and define their own Wikipedia geodata URL of interest, via a Javascript prompt window ask, but, as you can imagine, we cannot guarantee success with this user defined mode of use. Here we might describe another “noun” concept, the (?isocode=) ISO Two Letter Code Country Code where the user can say that they want to zoom in on that region of interest with their Geo Chart display.

Yet again, feel free to try this changed PHP code craters.php live run to go exploring other “where of life” ideas in more apt regional settings, perhaps.


Previous relevant PHP Wikipedia Geo Map Google Chart Genericization Tutorial is shown below.

PHP Wikipedia Geo Map Google Chart Genericization Tutorial

PHP Wikipedia Geo Map Google Chart Genericization Tutorial

As we wrote the “where of life” “Meteorite Craters on Earth” PHP web application code behind yesterday’s PHP Wikipedia Geo Map Google Chart Tutorial, as with many other codes we write, we were on the lookout, just quietly, for how parameterizable its “inputs” were. In a fairly simple web application concept, the parameters are often “parameterizable” … doh … so that you might reach a point where you question …


Does this web application have the potential to be more than what it has initially been modelled to cater for?

How do you know what a “candidate” for this feels like? To us, that goes, “look for the nouns associated with the hardcodings” you made, and probably repeated in code, in that first incarnation. For us, with yesterday’s work that led us to consider, as parameters, two major “parameters”, namely …

  • $url
  • $title

Simple, huh?! So now, think of the mechanism to offer those two concepts as “parameterizable” ideas where the user is given choice, and, as is so often the case for us, that involves turning a hardcoded HTML (h1, in this case) textual element into an HTML select (dropdown) element. Within that HTML select element we use all of …

  • its value, for storing a $url of relevance
  • its HTML option subelement innerHTML properties … for display purposes
  • its HTML option subelement title properties … for “particularization” purposes (eg. mechanism to enable a suffix to the eventual Wikipedia search that will happen in the Geo Chart HTML iframe)

What else would we say is part of a “genericization drive”, quite often? Glad you didn’t ask! The delimitation rules of “plucking out” relevant geodata from Wikipedia data involves various PHP “explode” (first argument) delimiters of interest, depending on the data of interest. You can’t cater for everything, but cater for formats of some commonality on the net. Later, we may extend further, offering the option that the user directs towards the $url of interest themselves, rather than it being “trapped” in a programmer defined HTML select (dropdown) element makeup. Take a look at PHP code here …


$dataarray=explode("&amp;title=", $cont); // where $cont is webpage content


if (sizeof($dataarray) == 1) {
$dataarray=explode("&title=", $cont);
}
if (sizeof($dataarray) == 1) {
if (sizeof(explode('&amp;params=', $cont)) > 1) {
$altf='&amp;params=';
$dataarray=explode($altf, $cont);
} else if (sizeof(explode('_W_"><span', $cont)) > 1) {
$altf='_W_"><span';
$dataarray=explode($altf, $cont);
} else if (sizeof(explode('&amp;params=', $cont)) > 1) {
$altf='&amp;params=';
$dataarray=explode($altf, $cont);
} else if (sizeof(explode('_W_"><span', $cont)) > 1) {
$altf='_W_"><span';
$dataarray=explode($altf, $cont);
} else if (sizeof(explode('_E_"><span', $cont)) > 1) {
$altf='_E_"><span';
$dataarray=explode($altf, $cont);
} else if (sizeof(explode('_W_', $cont)) > 1) {
$altf='_W_';
$dataarray=explode($altf, $cont);
} else if (sizeof(explode('_E_', $cont)) > 1) {
$altf='_E_';
$dataarray=explode($altf, $cont);
}
}

… to get a delimitation basis, on which you “plant” yourself looking to the right only sometimes but more to the left to then glean $url and $title data item (concepts).

Again, feel free to try this changed PHP code craters.php live run to go exploring other “where of life” ideas, thanks again to Google Charts and Wikipedia. We hope this is of some interest to you.


Previous relevant PHP Wikipedia Geo Map Google Chart Tutorial is shown below.

PHP Wikipedia Geo Map Google Chart Tutorial

PHP Wikipedia Geo Map Google Chart Tutorial

The “where of life” talents of Google Chart are pretty irresistible to us, for web application ideas. More and more we see both the combination of the talents of …

… complementary, more than doubling up, ever since we could, with the Geo Chart, plot geographical places and tailor the markers of those to links and image hotlinks to Wikipedia webpages, thanks, with Google Geo Chart Co-ordinate Emojis Tutorial. We’ve also integrated back with Google Geo and Map Chart Integration Tutorial.

And so, in the tradition of blog postings like PHP Wikipedia Australian List Integration Tutorial, today, we have written a web application exploring the “where of life” subject, “Meteorite Craters on Earth”.

Want to do some Meteorite Crater exploration? Try this craters.php live run to go exploring. Hope this is of interest to you.


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.


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

Image Flipping or Flopping at Speed Sharing Tutorial

Image Flipping or Flopping at Speed Sharing Tutorial

Image Flipping or Flopping at Speed Sharing Tutorial

To value add with a web application, further to yesterday’s Image Flipping or Flopping at Speed Browsing Tutorial, we see it as important to get to a point where you can broach that big philosophical question …

Do you see what I see?

… and the most approachable way we know to attempt this is to allow an …

  • email … or …
  • SMS

… recipient be able to click a link within an email or SMS, and recreate a lot of what the originator is trying to convey, information wise.

To do this, we use …

  • “a” href=”mailto:[EmailAddress]?subject=Image%20Flip%20or%20Flop&body=encodeURIComponent(originatorURLsimulatingCurrentLook)”
  • “a” href=”sms:[SMSnumber]&body=encodeURIComponent(originatorURLsimulatingCurrentLook)” … or …

… elements constructed on the fly via the user press of two new buttons presented (within the Javascript script element’s document.write clause) …

<script type=text/javascript>

document.write(' blah blah blah <br><br>Show Axis <input id=axchk type=checkbox onchange=changeax(this); ' + (showax == true ? 'checked' : '') + '></input>  <button onclick=" doemail(); " id="butemail">Email &#128231;</button>  <button onclick=" dosms(); " id="butsms">SMS &#128223;</button><br><br> blah blah blah ');

</script>

… via …


function constructahref() {
var phrefis=document.URL.split('?')[0].split('#')[0];
phrefis+='?radius=' + encodeURIComponent('' + brad) + '&rpm=' + encodeURIComponent('' + rpm) + '&transform=' + encodeURIComponent(document.getElementById('sforf').value) + '&axis=' + (showax == true ? 'y' : 'n') + '&#url=' + (theimgurl == 'http://www.rjmprogramming.com.au/Android/NalaLuna.jpg' ? '' : encodeURIComponent(document.getElementById('myimg').src));
return phrefis;
}


function doemail() {
var anchor=null;
var emis=prompt('Please enter email address to send to.', '');
if (emis == null) { emis=''; }
if (emis.indexOf('@') != -1) {
anchor = document.createElement('a');
anchor.href = 'mailto:' + emis.trim() + '?subject=My%20Flip%20or%20Flop&body=' + encodeURIComponent(constructahref());
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();


} else if (emis.trim() != '' && emis.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
anchor = document.createElement('a');
anchor.href = 'sms:' + emis.trim() + '&body=' + encodeURIComponent(constructahref());
anchor.style.display='none';
anchor.innerHTML='SMS';
anchor.target='_top';
anchor.click();
}
}

function dosms(){
var anchor=null;
var emis=prompt('Please enter SMS number to send to.', '');
if (emis == null) { emis=''; }
if (emis.indexOf('@') != -1) {
anchor = document.createElement('a');
anchor.href = 'mailto:' + emis.trim() + '?subject=My%20Flip%20or%20Flop&body=' + encodeURIComponent(constructahref());
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();


} else if (emis.trim() != '' && emis.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
anchor = document.createElement('a');
anchor.href = 'sms:' + emis.trim() + '&body=' + encodeURIComponent(constructahref());
anchor.style.display='none';
anchor.innerHTML='SMS';
anchor.target='_top';
anchor.click();
}
}

So what is the point of the new checkbox? Well, that involves some aesthetic display work involving a new horizontal rule ( ie. hr <hr id=myhr style=display:none;z-index:-1;transform:rotate(90deg);overflow:visible;></hr> ) element we use to approximate the axis around which the Flip or Flop (of the image) is taking place …


var iw=0, ih=0;
var showax=(location.search + ('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'').replace(/^\#/g,'&')).split('axis=')[1] ? ((decodeURIComponent((location.search + ('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'').replace(/^\#/g,'&')).split('axis=')[1].split('&')[0])).toLowerCase().indexOf('y') == 0 ? true : false) : true;



function changef(tbo) {
if (tbo.value.toLowerCase() == 'flip') {
imgo.style.transform='scaleY(1)';
sxis=1.0,
syis=0.0;
document.getElementById('myhr').style.left='0px';
document.getElementById('myhr').style.width='' + eval(10 + eval('' + Math.max(ih,iw))) + 'px';
//document.getElementById('myhr').style.height='20px';
document.getElementById('myhr').style.top='' + eval(eval('' + iw) / 2) + 'px';
document.getElementById('myhr').style.transformOrigin='' + eval(eval('' + eval(10 + eval('' + Math.max(ih,iw)))) / 2) + 'px 0px';
//document.getElementById('myhr').style.backgroundColor='black';
document.getElementById('myhr').style.transform='rotate(90deg)';

} else if (tbo.value.toLowerCase() == 'flop') {
imgo.style.transform='scaleX(1)';
//alert('here');
sxis=0.0,
syis=1.0;
document.getElementById('myhr').style.left='0px';
document.getElementById('myhr').style.width='' + eval(30 + eval('' + Math.max(ih,iw))) + 'px';
//document.getElementById('myhr').style.height='20px';
document.getElementById('myhr').style.top='' + eval(eval('' + ih) / 2) + 'px';
document.getElementById('myhr').style.transformOrigin='' + eval(eval('' + eval(10 + eval('' + Math.max(ih,iw)))) / 2) + 'px 0px'; // + eval(eval('' + eval(10 + eval('' + iw))) / 2) + 'px';
//document.getElementById('myhr').style.backgroundColor='black';
document.getElementById('myhr').style.transform='rotate(0deg)';

} else if (tbo.value.toLowerCase() == 'flipflop') {
imgo.style.transform='scaleX(1)';
imgo.style.transform='scaleY(1)';
//alert('here');
sxis=0.1,
syis=0.0;
ffnum=0;
document.getElementById('myhr').style.left='0px';
document.getElementById('myhr').style.width='' + eval(10 + eval('' + Math.max(ih,iw))) + 'px';
//document.getElementById('myhr').style.height='20px';
document.getElementById('myhr').style.top='' + eval(eval('' + iw) / 2) + 'px';
document.getElementById('myhr').style.transformOrigin='' + eval(eval('' + eval(10 + eval('' + Math.max(ih,iw)))) / 2) + 'px 0px';
//document.getElementById('myhr').style.backgroundColor='black';
document.getElementById('myhr').style.transform='rotate(90deg)';

} else if (tbo.value.toLowerCase() == 'flopflip') {
imgo.style.transform='scaleX(1)';
imgo.style.transform='scaleY(1)';
//alert('here');
sxis=0.0,
syis=0.1;
ffnum=0;
document.getElementById('myhr').style.left='0px';
document.getElementById('myhr').style.width='' + eval(10 + eval('' + Math.max(ih,iw))) + 'px';
//document.getElementById('myhr').style.height='20px';
document.getElementById('myhr').style.top='' + eval(eval('' + iw) / 2) + 'px';
document.getElementById('myhr').style.transformOrigin='' + eval(eval('' + eval(10 + eval('' + Math.max(ih,iw)))) / 2) + 'px 0px';
//document.getElementById('myhr').style.backgroundColor='black';
document.getElementById('myhr').style.transform='rotate(90deg)';

}
}

function doanim() {
if (Math.abs(sxis) > 0.5) {
sxis=eval(-1.0 * sxis);
imgo.style.transform='scaleX(' + sxis + ')';
} else if (Math.abs(syis) > 0.5) {
syis=eval(-1.0 * syis);
imgo.style.transform='scaleY(' + syis + ')';
} else if (Math.abs(sxis) > 0.0) {
imgo.style.transform=flipflops[ffnum];
if (flipflops[ffnum].indexOf('X(-') != -1) {
document.getElementById('myhr').style.left='0px';
document.getElementById('myhr').style.width='' + eval(10 + eval('' + Math.max(ih,iw))) + 'px';
//document.getElementById('myhr').style.height='20px';
document.getElementById('myhr').style.top='' + eval(eval('' + iw) / 2) + 'px';
document.getElementById('myhr').style.transformOrigin='' + eval(eval('' + eval(10 + eval('' + Math.max(ih,iw)))) / 2) + 'px 0px';
//document.getElementById('myhr').style.backgroundColor='black';
document.getElementById('myhr').style.transform='rotate(90deg)';
} else if (flipflops[ffnum].indexOf('Y(-') != -1) {
document.getElementById('myhr').style.left='0px';
document.getElementById('myhr').style.width='' + eval(30 + eval('' + Math.max(ih,iw))) + 'px';
//document.getElementById('myhr').style.height='20px';
document.getElementById('myhr').style.top='' + eval(eval('' + ih) / 2) + 'px';
document.getElementById('myhr').style.transformOrigin='' + eval(eval('' + eval(10 + eval('' + Math.max(ih,iw)))) / 2) + 'px 0px'; // + eval(eval('' + eval(10 + eval('' + iw))) / 2) + 'px';
//document.getElementById('myhr').style.backgroundColor='black';
document.getElementById('myhr').style.transform='rotate(0deg)';
}

ffnum++;
if (ffnum >= eval('' + flipflops.length)) { ffnum=0; }

} else if (Math.abs(syis) > 0.0) {
imgo.style.transform=flopflips[ffnum];
if (flopflips[ffnum].indexOf('X(-') != -1) {
document.getElementById('myhr').style.left='0px';
document.getElementById('myhr').style.width='' + eval(10 + eval('' + Math.max(ih,iw))) + 'px';
//document.getElementById('myhr').style.height='20px';
document.getElementById('myhr').style.top='' + eval(eval('' + iw) / 2) + 'px';
document.getElementById('myhr').style.transformOrigin='' + eval(eval('' + eval(10 + eval('' + Math.max(ih,iw)))) / 2) + 'px 0px';
//document.getElementById('myhr').style.backgroundColor='black';
document.getElementById('myhr').style.transform='rotate(90deg)';
} else if (flopflips[ffnum].indexOf('Y(-') != -1) {
document.getElementById('myhr').style.left='0px';
document.getElementById('myhr').style.width='' + eval(30 + eval('' + Math.max(ih,iw))) + 'px';
//document.getElementById('myhr').style.height='20px';
document.getElementById('myhr').style.top='' + eval(eval('' + ih) / 2) + 'px';
document.getElementById('myhr').style.transformOrigin='' + eval(eval('' + eval(10 + eval('' + Math.max(ih,iw)))) / 2) + 'px 0px'; // + eval(eval('' + eval(10 + eval('' + iw))) / 2) + 'px';
//document.getElementById('myhr').style.backgroundColor='black';
document.getElementById('myhr').style.transform='rotate(0deg)';
}

ffnum++;
if (ffnum >= eval('' + flopflips.length)) { ffnum=0; }
}
setTimeout(doanim, Math.round(isecs * 1000));
}


function startanim(isio) {
imgo=isio;
iw=imgo.width;
ih=imgo.height;
if (!started) {
setTimeout(doanim, Math.round(isecs * 1000));
}
started=true;
var rectone=document.getElementById('rpm').getBoundingClientRect();
var recttwo=document.getElementById('imgurl').getBoundingClientRect();
var rectthree=document.getElementById('radius').getBoundingClientRect();
document.getElementById('imgurl').style.width='' + eval(eval('' + rectone.right) - eval('' + recttwo.left)) + 'px';
document.getElementById('radius').style.width='' + eval(eval('' + rectone.right) - eval('' + rectthree.left)) + 'px';
if (dcbi == '') { dcbi=document.getElementById('divcbi').innerHTML; }
if (showax) {
document.getElementById('myhr').style.display='block';
} else {
document.getElementById('myhr').style.display='none';
}
document.getElementById('myhr').style.position='absolute';
document.getElementById('myhr').style.left='0px';
document.getElementById('myhr').style.width='' + eval(10 + eval('' + Math.max(ih,iw))) + 'px';
document.getElementById('myhr').style.height='20px';
document.getElementById('myhr').style.top='' + eval(eval('' + iw) / 2) + 'px';
document.getElementById('myhr').style.transformOrigin='' + eval(eval('' + eval(10 + eval('' + Math.max(ih,iw)))) / 2) + 'px 0px';
document.getElementById('myhr').style.backgroundColor='rgba(127,127,127,0.7)';
document.getElementById('myimg').style.zIndex='2';
document.getElementById('myimg').style.marginTop='5px';
document.getElementById('myimg').style.marginLeft='5px';
document.getElementById('tdleft').style.marginRight='5px';

//alert('' + iw + '.' + ih);
if (tis != 'flip') { changef(document.getElementById('sforf')); }
if (brad != '0') { brad='-999'; changeradius(document.getElementById('radius')); }
}

… in the modified third draft Image Flipping or Flopping at Speed web application you can try, for yourself, also, below.


Previous relevant Image Flipping or Flopping at Speed Browsing Tutorial is shown below.

Image Flipping or Flopping at Speed Browsing Tutorial

Image Flipping or Flopping at Speed Browsing Tutorial

We’ve thought of a few ways to improve on the work of yesterday’s Image Flipping or Flopping at Speed Primer Tutorial, they being …

  • onto yesterday’s Image URL means of addressing your image today we allow for local file browsing of your image file (and transferred into the web application’s image contents via Javascript …

    var imgo=null;
    var sxis=1.0, syis=0.0;
    var rpm=eval(300 / 10);
    var isecs=eval(30 / rpm); // 0.1;
    var imagedurl='', theimgurl='http://www.rjmprogramming.com.au/Android/NalaLuna.jpg';
    var theclass=theimgurl.slice(-96).replace(/\:/g,'!').replace(/\./g,'|'); //'http!//www.rjmprogramming.com.au/Android/NalaLuna|jpg';
    var dcbi='', started=false;


    function resultlook() {
    if (document.getElementById('result').innerHTML != '') {
    imagedurl=document.getElementById('result').innerHTML;
    document.getElementById('result').innerHTML='';
    theimgurl=imagedurl;
    theclass=theimgurl.slice(-96).replace(/\:/g,'!').replace(/\./g,'|');
    document.getElementById('myimg').src=imagedurl;
    imgo=document.getElementById('myimg');
    document.getElementById('myimg').className=theclass;
    document.getElementById('imgurl').placeholder=imagedurl;
    document.getElementById('imgurl').title=imagedurl;
    document.getElementById('imgurl').value='';
    imagedurl='';
    document.getElementById('divcbi').innerHTML=dcbi;
    }
    }


    setInterval(resultlook, 5000);

    … teaming up with the HTML access to our inhouse local file browser …

    <div id=divcbi style=display:inline-block;><iframe scrolling=no frameborder=0 id=cbi data-accept="image/*" style="width:163px;height:228px;margin-top:-204px;display:inline-block;background-color:transparent;" src="/HTMLCSS/client_browsing.htm?d=3121605626826&wording=Allimages%20images%2E%20"></iframe></div>

    … allowing for the data URI to be gleaned this way)
  • allow for a CSS border-radius property be applied to your image via …

    var brad="0";

    function changeradius(tbo) {
    if (eval('' + tbo.value) != brad) {
    brad=('' + tbo.value);
    document.getElementById('myimg').style.borderRadius='' + brad.trim().replace(/px$/g,'') + (brad.replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').replace(/px/g,'').trim() == '' ? 'px' : '');
    }
    }
  • onto yesterday’s Flip and Flop transform options today we add FlipFlop and FlopFlip options this way

    var ffnum=0;
    var flipflops=['scaleX(1) scaleY(1)','scaleX(-1) scaleY(1)','scaleX(-1) scaleY(-1)','scaleX(1) scaleY(-1)'];
    var flopflips=['scaleX(1) scaleY(1)','scaleX(1) scaleY(-1)','scaleX(-1) scaleY(-1)','scaleX(-1) scaleY(1)'];


    function doanim() {
    if (Math.abs(sxis) > 0.5) {
    sxis=eval(-1.0 * sxis);
    imgo.style.transform='scaleX(' + sxis + ')';
    } else if (Math.abs(syis) > 0.5) {
    syis=eval(-1.0 * syis);
    imgo.style.transform='scaleY(' + syis + ')';
    } else if (Math.abs(sxis) > 0.0) {
    imgo.style.transform=flipflops[ffnum];
    ffnum++;
    if (ffnum >= eval('' + flipflops.length)) { ffnum=0; }
    } else if (Math.abs(syis) > 0.0) {
    imgo.style.transform=flopflips[ffnum];
    ffnum++;
    if (ffnum >= eval('' + flopflips.length)) { ffnum=0; }
    }

    setTimeout(doanim, Math.round(isecs * 1000));
    }

    function changef(tbo) {
    if (tbo.value.toLowerCase() == 'flip') {
    imgo.style.transform='scaleY(1)';
    sxis=1.0,
    syis=0.0;
    } else if (tbo.value.toLowerCase() == 'flop') {
    imgo.style.transform='scaleX(1)';
    //alert('here');
    sxis=0.0,
    syis=1.0;
    } else if (tbo.value.toLowerCase() == 'flipflop') {
    imgo.style.transform='scaleX(1)';
    imgo.style.transform='scaleY(1)';
    //alert('here');
    sxis=0.1,
    syis=0.0;
    ffnum=0;
    } else if (tbo.value.toLowerCase() == 'flopflip') {
    imgo.style.transform='scaleX(1)';
    imgo.style.transform='scaleY(1)';
    //alert('here');
    sxis=0.0,
    syis=0.1;
    ffnum=0;
    }

    }

    … to add to the variety of display possibilities

… in a modified second draft Image Flipping or Flopping at Speed web application you can try, for yourself, also, below.


Previous relevant Image Flipping or Flopping at Speed Primer Tutorial is shown below.

Image Flipping or Flopping at Speed Primer Tutorial

Image Flipping or Flopping at Speed Primer Tutorial

The “making of” the recent Select Multiple Webpage Palette Speech Bubble Swipe Tutorial inspired us to start down the road of a new …

Image Flipping or Flopping at Speed

… web application. At first, with it, we wondered, regarding our animation, whether we could …

  • create “smoothed out” flipping or flopping scenarios via CSS keyframes and transition animations … or …
  • use Javascript DOM

… and sadly the “CSS keyframes and transition animations” is a “no go” for this project (ie. not every CSS property can be animated this way, as we have alluded to in the past).

Never mind, today we supplied the starting three controls the user has, over to the right of their image …

  1. image URL (in textbox, in first draft) …
  2. toggling between Flip and Flop ability …
  3. revolutions per minute

… settings in this first draft Image Flipping or Flopping at Speed web application you can try, for yourself, also, below …

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 Animation, eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , | Leave a comment