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

CSS Outline Primer Tutorial

CSS Outline Primer Tutorial

CSS Outline Primer Tutorial

The CSS “border” emphasis of the previous Emoji Borders and Backgrounds Canvas Annotation Tutorial has concepts, we see online, confusing people, and myself, regarding what the CSS “outline” feature is capable of (or not capable of). Here is W3school‘s pertinent paragraph on this …

Note: Outline differs from borders! The outline is drawn outside the element’s border, and may overlap other content. Also, the outline is NOT a part of the element’s dimensions; the element’s total width and height is not affected by the width of the outline.

The CSS “outline” concept is not the panacea to as many web design requirements as the “border” concept is. For instance, even seeing within the purview of making our “proof of concept” web application …

  • no linear gradients can be worked in the “outline” realm
  • no such properties as “outline-top” or “outline-left” or “outline-bottom” or “outline-right” exist within the “outline” realm
  • no such property as “outline-radius”
  • no outline images in the “outline” realm

If we were to summarize, the CSS “outline” concept’s talents can lie with …

  • being around an HTML element (and not part of it … perhaps in web design, useful as “a place of rest” (including non-mobile on hover element title displays) for users?!)
  • decorative colour around an HTML element (perhaps to get the user’s attention to hone in on that element, or perhaps a dynamic conduit towards “thickening” an existant HTML element border (especially as Javascript DOM such as [element].style.outline=’2px solid green’; // is available to programmers))
  • can form a replacement nesting HTML element background colour means
  • in it’s simplest CSS syntax ( eg: outline: 2px solid green; ) can be easily remembered next to the simplest syntax of border (probably very familiar to you) CSS syntax ( eg: border: 2px solid green; ) … just differently located on the webpage

We’ve been shy to use “outline” CSS and so it is as much for our learning as well that, today, we present a CSS “outline proof of concept” then “nuanced for greater user interaction” outline_css.html web application


Previous relevant Emoji Borders and Backgrounds Canvas Annotation Tutorial is shown below.

Emoji Borders and Backgrounds Canvas Annotation Tutorial

Emoji Borders and Backgrounds Canvas Annotation Tutorial

Up to now with the SVG -> IMG -> CANVAS parent web application to our newish PHP tool child of Emoji Borders and Backgrounds Curl Tutorial we have tried to keep …

  • SVG
  • IMG
  • CANVAS

… contents in synch as far as looks go. That ignores the reason CANVAS (element) was invented when HTML5 came out. It was invented to not only contain image graphical data, but be able to amend that data. So we also allow it with our web application from today on, integrating with our inhouse “User of Signature” web application last talked about at Local Fonts Revisited Middle Tutorial, to amend (initially image via [canvas].toDataURL(‘image/png’) via SVG streams of data which may include emoji borders and backgrounds) graphical data.

We integrate via a same domain window.open scenario. Before you all start groaning, consider the advantages of a …


uoss=window.open('../HTMLCSS/user_of_signature_signature.htm' + chash,'_blank','top=20,left=20,width=' + eval(0.9 * eval('' + screen.width)) + ',height=' + eval(0.8 * eval('' + screen.height)) + '');

… albeit non-mobile window.open (ie. popup window) call. Not only are you …

  • (on non-mobile) seeing two windows on top of each other … but …
  • the “window.opener” (acting like “parent” does for an “iframe” arrangement) reference can have you, via Javascript DOM, share the data of the popup window canvas element with that of the “window.opener” (window) canvas element

… and then, we arrange for a “reset” (to ignore these annotation changes), via the “middle-element” IMG element, should the “Undo” functionality of our HTML changed user_of_signature_signature.html‘s User of Signature Signature (standalone) live run not be enough flexibility to the functionality, which has a new document.body onload event triggering of Javascript function cancontlook below …


var cancont='';
var cancontw=-1, canconth=-1;

if (('' + window.opener).replace('null','') != '') {
var cans=window.opener.document.getElementsByTagName('canvas');
if (cans.length > 0) { cancont=cans[0].toDataURL('image/png'); cancontw=cans[0].width; canconth=cans[0].height; }
}

function cancontlook() {
if (cancont != '') { // called via SVG - IMG - CANVAS
celem=document.getElementById('topcanvas');
ccontext = celem.getContext("2d");
celem.width=cancontw;
celem.height=canconth;
cimg=new Image;
cimg.onload = function(){
ccontext.drawImage(cimg,0,0);
};
cimg.src=cancont;
if (document.getElementById('toptd')) {
document.getElementById('toptd').style.left='' + cancontw + 'px';
var recttoptd=document.getElementById('toptd').getBoundingClientRect();
document.getElementById('topcbutton').innerHTML='⬅';
document.getElementById('topcbutton').style.position='fixed';
document.getElementById('topcbutton').style.top='' + recttoptd.top + 'px';
//document.getElementById('topcbutton').style.left='' + recttoptd.left + 'px';
document.getElementById('topcbutton').style.left='' + eval(0.98 * eval('' + screen.width)) + 'px';
document.getElementById('topcbutton').style.zIndex='89';
document.getElementById('topcbutton').title='Back to SVG - IMG - CANVAS web application caller';
//document.getElementById('topcbutton').onclick=function() { window.opener.focus(); };
}
if (document.getElementById('toppixellate')) {
document.getElementById('toppixellate').style.top='' + canconth + 'px';
}
if (('' + location.hash).replace(/^\#/g,'') != '') {
document.getElementById('topcstyle').innerHTML=' function iysh() {
if (document.getElementById('topcbutton').innerHTML.indexOf(' ') != -1) {
document.getElementById('topcbutton').innerHTML=document.getElementById('topcbutton').innerHTML.replace(' ','');
alert('Please do this manually');
}
}

function woff() {
document.getElementById('topcbutton').innerHTML+=' ';
setTimeout(iysh, 2000);
window.opener.focus();
}

So, again, try our changed PHP canvas_svg.php SVG -> IMG -> CANVAS live run web application new PHP writes Javascript …

<?php echo ”

var canvases;
var prechash='', chash='';
var passeddu='', origpasseddu='';
var uoss=null;
var wois=null, woiso=false;

// New document.body onload logic below
canvases=document.getElementsByTagName('canvas');
if (document.getElementById('gstyle')) {
if (document.getElementById('gstyle').innerHTML.indexOf('canvas {') != -1) {
prechash=document.getElementById('gstyle').innerHTML.split('canvas {')[1].split('}')[0];
}
}
if (canvases[0].outerHTML.indexOf(' style="') != -1) {
chash='#' + encodeURIComponent(prechash + canvases[0].outerHTML.split(' style="')[1].split('"')[0]);
}
//canvases[0].onclick=function() { if (!uoss) { uoss=window.open('../HTMLCSS/user_of_signature_signature.htm' + chash,'_blank','top=20,left=20,width=' + eval(0.9 * eval('' + screen.width)) + ',height=' + eval(0.8 * eval('' + screen.height)) + ''); } };
canvases[0].onclick=function() { if (!uoss) { setTimeout(monitoru,6000); origpasseddu=canvases[0].toDataURL('image/png'); passeddu=origpasseddu; uoss=window.open('../HTMLCSS/user_of_signature_signature.htm' + chash,'_blank'); } else { uoss.focus(); } };

function monitoru() {
if (uoss) {
if (uoss.document.getElementById('topcbutton').innerHTML.indexOf(' ') != -1) {
uoss.document.getElementById('topcbutton').innerHTML=uoss.document.getElementById('topcbutton').innerHTML.replace(' ','');
window.focus();
}
var thispdu=uoss.document.getElementById('topcanvas').toDataURL('image/png');
if (passeddu != thispdu) {
document.getElementById('antiu').style.display='inline-block';
passeddu=thispdu;
var xnewimg=document.createElement('img');
xnewimg.onload = function() {
// draw the image onto the canvas
canvas.getContext('2d').drawImage(xnewimg, 0, 0);
}
xnewimg.src = passeddu;
}
setTimeout(monitoru, 6000);
}
}

function antiuossc() {
if (uoss) {
var znewimg=document.createElement('img');
znewimg.onload = function() {
// draw the image onto the canvas
canvas.getContext('2d').drawImage(znewimg, 0, 0);
passeddu=uoss.document.getElementById('topcanvas').toDataURL('image/png');
}
znewimg.src = origpasseddu;
}
}

function uossc() {
if (!uoss) {
setTimeout(monitoru,6000);
origpasseddu=canvases[0].toDataURL('image/png');
passeddu=origpasseddu;
uoss=window.open('../HTMLCSS/user_of_signature_signature.htm' + chash,'_blank','top=20,left=20,width=' + eval(0.9 * eval('' + screen.width)) + ',height=' + eval(0.8 * eval('' + screen.height)) + '');
} else {
uoss.focus();
}
}

“; ?>


Previous relevant Emoji Borders and Backgrounds Curl Tutorial is shown below.

Emoji Borders and Backgrounds Curl Tutorial

Emoji Borders and Backgrounds Curl Tutorial

We find curl to be that interesting PHP “mode of use” hybrid of the involvement of …

  • HTTP protocol URLs
  • command line
  • interface to PHP exec

… that might help you “look back at yourself from outside” as we use it to interface to Google PageSpeed Insights webpage screenshot functionality (which can look at a designated URL and effectively screenshot it for you) … thanks.

The URL “GET” argument restriction of “only ?” first arguments, as with yesterday’s Emoji Borders and Backgrounds QR Code Tutorial, comes into play interfacing to Google PageSpeed Insights webpage screenshot functionality.

We used to restrict our curl usage thinking to “only ?” first argument use too, arguing (with ourselves) that the Linux and Unix and macOS and Mac OS X “&” character command line meaning of “process in the background” would be a constraint. Of course it isn’t, because … anyone, anyone? Yes, Henry, you should use a “curl” command line command, using double quotes, of the form …


curl "https://www.rjmprogramming.com.au/PHP/canvas_svg.php?emoji=128248&iurl=two.jpg%23circle&css=opacity%3A0.9%3Bfont-size%3A20px%3B&textcss=text-shadow%3A%20-2px%202px%203px%20%23ff2d95%3B&ultext=Hello%250AThere"

… and the “&”s are understood to be URL “GET” argument delimiters, and not a “process in the background” designator.

And here’s the thing exemplified above. The alternative file_get_contents PHP function cannot do that https: protocol type of URL, yet Google PageSpeed Insights webpage screenshot functionality demands such URLs … hence the “curl” interest.

So try our changed PHP canvas_svg.php SVG -> IMG -> CANVAS live run web application …

<?php

$psbig='curl "https://pagespeedonline.googleapis.com/pagespeedonline/v5/runPagespeed/?url=' . str_replace('localhost:8888','www.rjmprogramming.com.au',$udirname) . 'canvas_svg.php&screenshot=true" > /tmp/pscs.xxx';
if (isset($_GET['justtheone']) && strpos(('' . $_SERVER['QUERY_STRING']), '&') === false) {
header('Location: ' . str_replace('http:','',$udirname . 'canvas_svg.php' . '?' . urldecode(str_replace('justtheone=','',$_GET['justtheone']))));
exit;
} else if (('' . $_SERVER['QUERY_STRING']) != '') {
$qrbig="http://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=" . $udirname . "canvas_svg.php?justtheone=" . urlencode($_SERVER['QUERY_STRING']) . "&choe=UTF-8";
$psbig='curl "https://pagespeedonline.googleapis.com/pagespeedonline/v5/runPagespeed/?url=' . str_replace('localhost:8888','www.rjmprogramming.com.au',$udirname) . 'canvas_svg.php?justtheone=' . urlencode( str_replace('howpagespeedseesme=y&','', str_replace('?howpagespeedseesme=y','', str_replace('&howpagespeedseesme=y','', $_SERVER['QUERY_STRING']))) ) . '&screenshot=true" > /tmp/pscs.xxx';
}


$extis='.xxx';
if (strpos(('' . $_SERVER['QUERY_STRING']), 'howpagespeedseesme=') !== false) {
if (file_exists('/tmp/')) {
if (file_exists('/tmp/pscs.xxx')) {
unlink('/tmp/pscs.xxx');
}
}
exec($psbig);
while (!file_exists('/tmp/pscs' . $extis)) {
sleep(4);
}
while (filesize('/tmp/pscs' . $extis) == 0) {
sleep(4);
}
$scx=file_get_contents('/tmp/pscs' . $extis);
$scxs=explode('"screenshot":', $scx);
if (sizeof($scxs) > 1) {
$postscxs=explode('"data": ', $scxs[1]);
if (sizeof($postscxs) > 1) {
echo '<html><body><h2>How Google <a target=_blank title="Google PageSpeed Insights" href="https://pagespeed.web.dev/">PageSpeed Insights</a> Screenshots This ...</h2><img src=' . substr($postscxs[1],0,1) . explode(substr($postscxs[1],0,1), substr($postscxs[1],1))[0] . substr($postscxs[1],0,1) . '></img></body></html>';
} else {
echo '<html><body><h2>How Google <a target=_blank title="Google PageSpeed Insights" href="https://pagespeed.web.dev/">PageSpeed Insights</a> Screenshots This ...</h2><p>Sorry, resource exhausted. Could try again later.</p></body></html>';
}
} else {
echo '<html><body><h2>How Google <a target=_blank title="Google PageSpeed Insights" href="https://pagespeed.web.dev/">PageSpeed Insights</a> Screenshots This</h2><p>Sorry, resource exhausted. Could try again later.</p></body></html>';
}
exit;
}

?>

… working with the new HTML div <div id=readyforiframe></div> element, along with <span title=’Google PageSpeed Insights webpage screenshot view of this web browser address URL’ onclick=’psit();’> &#128248; </span> 📸 “emoji button” in the HTML static code … with associated Javascript function …

<?php echo ”

function psit() {
document.getElementById('readyforiframe').style.width='100%';
document.getElementById('readyforiframe').style.height='900px';
document.getElementById('readyforiframe').innerHTML='<iframe style="width:100%;height:900px;" src="' + (document.URL.split('#')[0] + '&howpagespeedseesme=y').replace('.php&','.php?') + '"></iframe>';
location.href='#readyforiframe';
}

“; ?>


Previous relevant Emoji Borders and Backgrounds Web Browser Tutorial is shown below.

Emoji Borders and Backgrounds Web Browser Tutorial

Emoji Borders and Backgrounds Web Browser Tutorial

Yesterday’s Emoji Borders and Backgrounds Shape Sharing Tutorial had us sharing via email or SMS our “Emoji Borders and Backgrounds” creations via inhouse organized arrangements. But many people are used to just right-clicking (for Windows) and two finger gesturing (for macOS and Mac OS X) on …

  • SVG
  • IMG
  • CANVAS

… graphical elements, which can be made to “look” the same, and sort of “suck it and see” as far as menu options presented, helping them out sharing graphical information. In many cases, users don’t care what form of element the image comes contained in. But, if you involve “background-image” CSS along the way to achieve a (consistent) “look”, as we had done before today, (some of) the output of those menu options could be lacking (because they look for “foreground data”), and so we do away with the need for a “background-image” …

<?php


function ctoilater() {
img.src=canvas.toDataURL('data/png');
}



if ((iurl != '' && document.URL.indexOf('noimage') == -1) && emoji != '') {
//imgs[0].style.background='URL("' + iurl + '")';
//canvases[0].style.background='URL("' + iurl + '")';
if (emoji != '') {
imgs[0].style.backgroundPosition='20px 20px';
}

imgs[0].style.backgroundRepeat='no-repeat';
canvases[0].style.backgroundRepeat='no-repeat';


var newimg=document.createElement('img');
newimg.onload = function() {
// draw the image onto the canvas
if (document.URL.indexOf('emoji=') != -1) {
canvas.getContext('2d').drawImage(newimg, 20, 20);
} else {
canvas.getContext('2d').drawImage(newimg, 0, 0);
}
setTimeout(ctoilater, 3000);
}
newimg.src = iurl;


}

?>

… look on the IMG and CANVAS element usage (as above) and use the great way a …

  • CANVAS can contain merged image data … and a …
  • CANVAS can convert back to an image data URI

… to mean IMG and CANVAS can end up united in a “real image data” look and content, via SVG that can be made up of …

  • emoji TEXT
  • user TEXT
  • user IMAGE (like IMG)
  • user shapes CIRCLE and/or ELLIPSE and/or RECT and/or LINE and/or POLYLINE and/or POLYGON … and inhouse NOIMAGE

… (SVG) “streams” of graphical data.

We also needed to cater for that inhouse “NOIMAGE” shape lack of IMAGE data in our changed PHP canvas_svg.php SVG -> IMG -> CANVAS live run web application.

Did you know?

An example of how having web browser (right-clicking (for Windows) and two finger gesturing (for macOS and Mac OS X)) menu options be useful, consider an image menu option such as “Copy image” be used by the user. The user can compose their own (email client (or get to email client via all uppercase web application “to” email “address” definition)) email then, and just Edit -> Paste the results, as an image, into the email body, ahead of sending off that email.


Previous relevant Emoji Borders and Backgrounds Shape Sharing Tutorial is shown below.

Emoji Borders and Backgrounds Shape Sharing Tutorial

Emoji Borders and Backgrounds Shape Sharing Tutorial

The code “shape shifting” of recent times morphs into “shape sharing” together in amongst the parent users of our PHP tool “Emoji Borders and Backgrounds” web application featuring in yesterday’s Emoji Borders and Backgrounds Shape Numerics Tutorial.

We found the “SVG+XML” mimetype data not accepted by Gmail for an Inline HTML Email, so we have coded for the Downloadable HTML Attachment “way to go”.

<?php

function emailit() {
var fbit='';
var tois=prompt('Please enter an email address to email to (all uppercase uses email client rather than PHP mail and all numerical sends an SMS).','');
if (tois == null) { tois=''; }
if (tois.trim() != '') {
if (tois.indexOf('@') != -1) {
if (tois.toUpperCase() == tois) {
document.getElementById('divemail').innerHTML='<a id=aemail style=display:none; href=mailto:' + tois + '?subject=My%20Emoji%20Border%20and%20Background%20Creation&body=' + encodeURIComponent(document.URL) + '>Email</a>';
//fbit=('' + document.getElementById('aemail').href).split('?')[1];
//document.getElementById('aemail').href='mailto:' + tois + '?' + fbit;
document.getElementById('aemail').click();
} else {
var zhr = new XMLHttpRequest();
var zform=new FormData();
if (1 == 2) { zform.append('inline', ''); }
zform.append('to', tois);
zform.append('subj', 'My Emoji Borders and Background Creation ... at [date] ...');
//alert(encodeURIComponent('<html><body><img src=\"<?php echo $bemb; ?>\"></img></body></html>'));
zform.append('tdhuhta', encodeURIComponent('<html>' + '<?php echo $headstyle; ?>' + '<body><img src="<?php echo $bemb; ?>"></img></body></html>'));
zhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
zhr.send(zform);
alert('Email sent to ' + tois);
}
} else if (tois.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,'') == '') {
document.getElementById('divsms').innerHTML='<a id=asms style=display:none; href=sms:' + tois + '&body=' + encodeURIComponent(document.URL) + '>SMS</a>';
//document.getElementById('asms').href='sms:' + tois + '&body=' + encodeURIComponent(document.URL);
document.getElementById('asms').click();
}
}
}

?>

The inhouse slideshow PHP clones’ changed associated external Javascript inhouse_slideshow.js live run is available.

The Image Map Grid changed PHP imagegridmap.php‘s live run is available.

And the “shape sharing” goes on in our (third parent (to our PHP tool) “cab off the rank”) SVG -> IMG -> CANVAS changed PHP canvas_svg.php live run is available, being helped out by PHP tool code changes for inline_svg.php‘s live run.


Previous relevant Emoji Borders and Backgrounds Shape Numerics Tutorial is shown below.

Emoji Borders and Backgrounds Shape Numerics Tutorial

Emoji Borders and Backgrounds Shape Numerics Tutorial

If you are familiar with the geometry of shapes, it is full of numbers, with the implications as to how the shape is represented and displayed, that those numbers can affect. And so, onto yesterday’s Emoji Borders and Backgrounds Shapes Tutorial‘s start with …

  • SVG circle element
  • SVG rect element … shapes yesterday, we add …
  • SVG ellipse element functionality today … and for all these, as well as the …
  • SVG text element we start allowing “shape numerics” as being a user definable thaing

These “shape numerics” can help the user control (that SVG element’s) …

  • position
  • size
  • opacity
  • font size … (for text elements) on top of that non-numeric control yesterday’s work gave us, being (that SVG element’s fill) …
  • colour

This is all handled, still, within that “image” argument definition, and we allow a decimal (ie. “.”) delimiter be the way a user separates their integer values (where an opacity value becomes “0.” + [integerValue]).

As an example take a look at the example …

URL
https://www.rjmprogramming.com.au/inline_svg.php?uctext=hello%0Az267.254&mltext=bonjour&image=PHP/one.jpg%23ellipsepurple267.254.156.89.6,noimage
Iframe

The PHP code changes for inline_svg.php‘s live run principally involved two new PHP functions …

Collect information at a suitable juncture …
<?php

$crcolour="pink";
$gcx=-1;
$gcy=-1;
$gwidth=-1;
$gheight=-1;
$gopacity=-1.0;
$gfontsize=-1;
$gradius=-1;
$gradiusone=-1;
$gradiustwo=-1;
$gshape='';

function collectstuff($inthingis, $proshape) {
global $crcolour, $gcx, $gcy, $gwidth, $gheight, $gopacity, $gfontsize, $gradius, $gradiusone, $gradiustwo, $gshape;
$gshape=strtolower($proshape);
if ($gshape == 'text') {
$crcolour="black";
$gcx=-1;
$gcy=-1;
$gwidth=-1;
$gheight=-1;
$gopacity=-1.0;
$gfontsize=-1;
$gradius=-1;
$gradiusone=-1;
$gradiustwo=-1;
}
if ($inthingis == '') { return ''; }
$decthings=explode('.', strtolower($inthingis));
if ($gshape == 'text') {
$crcolour='black';
if (sizeof($decthings) >= 3 && strpos(strtolower($inthingis), 'px') !== false) {
for ($ii=0; $ii<sizeof($decthings); $ii++) {
if (sizeof(explode('p', $decthings[$ii])) > 1) {
$gfontsize=explode('p', $decthings[$ii])[0];
$inthingis=str_replace('' . $decthings[$ii] . '.','', str_replace('.' . $decthings[$ii] . '','', str_replace('.' . $decthings[$ii] . '.','.', strtolower($inthingis) )));
$decthings=explode('.', strtolower($inthingis));
}
}
}
if (sizeof($decthings) < 2 || substr($inthingis,-1,1) < '0' || substr($inthingis,-1,1) > '9') {
return $inthingis;
}
$crcol='';
while (substr($inthingis,-1,1) == '.' || (substr($inthingis,-1,1) >= '0' && substr($inthingis,-1,1) <= '9')) {
$crcol=substr($inthingis,-1,1) . $crcol;
$inthingis=substr($inthingis,0,(-1 + strlen($inthingis)));
}
//file_put_contents('x.x', $crcol . ' ... ' . substr($inthingis,-1,1));
$decthings=explode('.', strtolower($crcol));
if (sizeof($decthings) >= 2) {
$gcx=$decthings[0];
$gcy=$decthings[1];
if (sizeof($decthings) > 2) {
$gopacity='0.' . $decthings[2];
if (sizeof($decthings) > 3) {
$gfontsize=$decthings[3];
}
}
} else {
return $inthingis . $crcol;
}
return $inthingis;
} else {
$crcolour='pink';
if (strpos(strtolower($inthingis), 'px') !== false) {
for ($ii=0; $ii<sizeof($decthings); $ii++) {
if (sizeof(explode('p', $decthings[$ii])) > 1) {
$gfontsize=explode('p', $decthings[$ii])[0];
$inthingis=str_replace('' . $decthings[$ii] . '.','', str_replace('.' . $decthings[$ii] . '','', str_replace('.' . $decthings[$ii] . '.','.', strtolower($inthingis) )));
$decthings=explode('.', strtolower($inthingis));
}
}
}
}
if (substr($inthingis,0,1) < '0' || substr($inthingis,0,1) > '9') {
$crcolour=explode('0',explode('1',explode('2',explode('3',explode('4',explode('5',explode('6',explode('7',explode('8',explode('9',$inthingis)[0])[0])[0])[0])[0])[0])[0])[0])[0])[0];
$inthingis=strtolower(str_replace($crcolour, '', $inthingis));
$decthings=explode('.', strtolower($inthingis));
} else if (substr($inthingis,-1,1) < '0' || substr($inthingis,-1,1) > '9') {
$crcolour='';
while (substr($inthingis,-1,1) < '0' || substr($inthingis,-1,1) > '9') {
$crcolour=substr($inthingis,-1,1) . $crcolour;
$inthingis=substr($inthingis,0,(-1 + strlen($inthingis)));
}
$inthingis=strtolower(str_replace($crcolour, '', $inthingis));
$decthings=explode('.', strtolower($inthingis));
}
if ($gshape == 'text') {
if (sizeof($decthings) >= 2) {
$gcx=$decthings[0];
$gcy=$decthings[1];
if (sizeof($decthings) > 2) {
$gopacity='0.' . $decthings[2];
if (sizeof($decthings) > 3) {
$gfontsize=$decthings[3];
}
}
}
} else if ($gshape == 'circle') {
if (sizeof($decthings) >= 2) {
$gcx=$decthings[0];
$gcy=$decthings[1];
if (sizeof($decthings) > 2) {
$gradius=$decthings[2];
if (sizeof($decthings) > 3) {
$gopacity='0.' . $decthings[3];
}
}
} else if (sizeof($decthings) == 1 && $decthings[0] != '') {
$gradius=$decthings[0];
}
} else if ($gshape == 'ellipse') {
if (sizeof($decthings) >= 4) {
$gcx=$decthings[0];
$gcy=$decthings[1];
$gradiusone=$decthings[2];
$gradiustwo=$decthings[3];
if (sizeof($decthings) > 4) {
$gopacity='0.' . $decthings[4];
}
} else if (sizeof($decthings) == 3) {
$gradiusone=$decthings[0];
$gradiustwo=$decthings[1];
$gopacity='0.' . $decthings[2];
} else if (sizeof($decthings) == 2) {
$gradiusone=$decthings[0];
$gradiustwo=$decthings[1];
} else if (sizeof($decthings) == 1 && $decthings[0] != '') {
$gradius=$decthings[0];
}
} else if ($gshape == 'rect') {
if (sizeof($decthings) >= 4) {
$gcx=$decthings[0];
$gcy=$decthings[1];
$gwidth=$decthings[2];
$gheight=$decthings[3];
if (sizeof($decthings) > 4) {
$gopacity='0.' . $decthings[4];
}
} else if (sizeof($decthings) == 3) {
$gwidth=$decthings[0];
$gheight=$decthings[1];
$gopacity='0.' . $decthings[2];
} else if (sizeof($decthings) == 2) {
$gwidth=$decthings[0];
$gheight=$decthings[1];
} else if (sizeof($decthings) == 1 && $decthings[0] != '') {
$gopacity='0.' . $decthings[0];
}
}
return $crcolour;
}

?>
Reshape a default SVG element definition depending on the information collected
<?php

function retandclear($inthing) {
global $crcolour, $gcx, $gcy, $gwidth, $gheight, $gopacity, $gfontsize, $gradius, $gradiusone, $gradiustwo, $gshape;
$outthing=$inthing;

if (strpos($inthing, '<text ') !== false) {
$gshape='text';
} else if (strpos($inthing, '<circle ') !== false) {
$gshape='circle';
} else if (strpos($inthing, '<ellipse ') !== false) {
$gshape='ellipse';
} else if (strpos($inthing, '<rect ') !== false) {
$gshape='rect';
}

if (strtolower($gshape) == 'ellipse' && $gradiusone >= 0 && strpos($inthing, ' rx="') !== false) {
$outthing=str_replace(' rx="' . explode('"', explode(' rx="', $outthing)[1])[0], ' rx="' . $gradiusone, $outthing);
}

if (strtolower($gshape) == 'ellipse' && $gradiustwo >= 0 && strpos($inthing, ' ry="') !== false) {
$outthing=str_replace(' ry="' . explode('"', explode(' ry="', $outthing)[1])[0], ' ry="' . $gradiustwo, $outthing);
}

if ($gcx >= 0 && strpos(str_replace(' cx="',' x="',$inthing), ' x="') !== false) {
$outthing=str_replace('x="' . explode('"', explode('x="', $outthing)[1])[0], 'x="' . $gcx, $outthing);
}

if ($gcy >= 0 && strpos(str_replace(' cy="',' y="',$inthing), ' y="') !== false) {
$outthing=str_replace('y="' . explode('"', explode('y="', $outthing)[1])[0], 'y="' . $gcy, $outthing);
}

if ($gwidth >= 0 && strpos($inthing, ' width="') !== false) {
$outthing=str_replace('width="' . explode('"', explode('width="', $outthing)[1])[0], 'width="' . $gwidth, $outthing);
}

if ($gheight >= 0 && strpos($inthing, ' height="') !== false) {
$outthing=str_replace('height="' . explode('"', explode('height="', $outthing)[1])[0], 'height="' . $gwidth, $outthing);
}

if (strtolower($gshape) == 'circle' && $gradius >= 0 && strpos($inthing, ' r="') !== false) {
$outthing=str_replace(' r="' . explode('"', explode(' r="', $outthing)[1])[0], ' r="' . $gradius, $outthing);
}

if (strtolower($gshape) == 'text' && $gfontsize >= 0 && strpos($inthing, ' font-size="') !== false) {
$outthing=str_replace(' font-size="' . explode('"', explode(' font-size="', $outthing)[1])[0], ' font-size="' . $gfontsize . 'px', $outthing);
} else if (strtolower($gshape) == 'text' && $gfontsize >= 0 && strpos($inthing, ' font-size="') === false) {
$outthing=str_replace('<text ', '<text font-size="' . $gfontsize . 'px" ', $outthing);
}

if ($gopacity >= 0 && strpos($inthing, ' fill-opacity="') !== false) {
$outthing=str_replace(' fill-opacity="' . explode('"', explode(' fill-opacity="', $outthing)[1])[0], ' fill-opacity="' . $gopacity, $outthing);
}

if ($crcolour != '' && strpos($inthing, ' fill="') !== false && strpos($inthing, ' fill="' . $crcolour) === false) {
$outthing=str_replace(' fill="' . explode('"', explode(' fill="', $outthing)[1])[0], ' fill="' . $crcolour, $outthing);
}

if ($gshape != 'text') {
$crcolour="pink";
$gcx=-1;
$gcy=-1;
$gwidth=-1;
$gheight=-1;
$gopacity=-1.0;
$gfontsize=-1;
$gradius=-1;
$gradiusone=-1;
$gradiustwo=-1;
$gshape='';
}
return $outthing;
}

?>

Integration tasks await!


Previous relevant Emoji Borders and Backgrounds Shapes Tutorial is shown below.

Emoji Borders and Backgrounds Shapes Tutorial

Emoji Borders and Backgrounds Shapes Tutorial

Onto yesterday’s Emoji Borders and Backgrounds Text Justification Tutorial we add some consideration of SVG shape creations into the mix of the Emoji Borders and Backgrounds work, starting just with the PHP tool, at this stage, and just considering …

… to start off with, and feeding off yesterday’s …

  • width=[designatedPxWidth] and height=[designatedPxHeight] … and/or …
  • image=[someImageUrl] (width and height)

… breakdown as to how a user can define a box of interest, as a great “line in the sand” for us to work around with this new “Shapes functionality”. It’s an interfacing job, for tomorrow, getting parents to work with this “image” argument based way a user can define these shapes, including a “noimage” option that uses an image’s width and height (to help out with the shape definition) but does not display that image.

Along the way we also mildly rearrange PHP code for inline_svg.php‘s live run so as to allow for more than one user text to be added via justification prefixing methodologies.


Previous relevant Emoji Borders and Backgrounds Text Justification Tutorial is shown below.

Emoji Borders and Backgrounds Text Justification Tutorial

Emoji Borders and Backgrounds Text Justification Tutorial

Yesterday’s Emoji Borders and Backgrounds CSS Styling Tutorial‘s work involving …

  • SVG CSS styling … could be classified as an “aesthetics” matter, as could today’s …
  • SVG text justification

… work, though there is no CSS involved with today’s solutions that we have decided on. But we did get great help from “How to place and center text in an SVG rectangle – Stack Overflow”, thanks, getting us to use a lot more …


text-anchor="end"

… SVG text element attributing to neaten our emojis up and for the 2nd character “r” text justifications below …

  • ultext=[SomeText] … top left justification
  • uctext=[SomeText] … top center justification
  • urtext=[SomeText] … top right justification
  • mltext=[SomeText] … middle left justification
  • mctext=[SomeText] … middle center justification (our inhouse default … ie. text=[SomeText] is the same)
  • mrtext=[SomeText] … middle right justification
  • bltext=[SomeText] … bottom left justification
  • bctext=[SomeText] … bottom center justification
  • brtext=[SomeText] … bottom right justification

… relative to one or both (modes of user defining a box) of …

  • width=[designatedPxWidth] and height=[designatedPxHeight] … and/or …
  • image=[someImageUrl] (width and height)

Our changed PHP tool inline_svg.php‘s live run needed tweaks in the code parsing arguments …

<?php

$gminus30=-1;
$gtop30=-1;
$eight=8;
$twentyfive=25;
$threedotone=3.1;
$textjust="";
$wtwo=2.0;
$htwo=2.0;
$tn='text';


foreach ($_GET as $name=>$val) {
if (strpos(strtolower('' . $name . '~'), 'css~') !== false) {
if ($svgmiddle == '') {
$svgmiddle="
<style type=\"text/css\" >
<![CDATA[
." . strtolower($name) . " { " . str_replace(';;',';',trim(str_replace('+',' ', urldecode($_GET[$name]))) . ';') . " }
]]>
</style>

";
} else {
$svgmiddle=str_replace("<![CDATA[", "<![CDATA[
." . strtolower($name) . " { " . str_replace(';;',';',trim(str_replace('+',' ', urldecode($_GET[$name]))) . ';') . " } ", $svgmiddle);
}
} else if (strpos(strtolower('' . $name . '~'), 'text~') !== false) {
$tn=$name;
if (strpos(strtolower('~' . $name . '~'), '~text~') !== false) {
$textjust="";
} else if (strtolower(substr($name,0,1)) == 't' || strtolower(substr($name,0,1)) == 'u') {
$htwo=$h;
$eight=0;
$twentyfive=30;
} else if (strtolower(substr($name,0,1)) == 'b' || strtolower(substr($name,0,1)) == 'l') {
$htwo=1;
$gtop30=0;
}
if (strpos(strtolower('' . $name . '~'), 'rtext~') !== false) {
$textjust=' text-anchor="end" ';
$gminus30=(-20 + $w);
}
if (strpos(strtolower('' . $name . '~'), 'ltext~') !== false) {
$wtwo=$w;
$gminus30=20;
$threedotone=0;
}

}

}

foreach ($_POST as $name=>$val) {
if (strpos(strtolower('' . $name . '~'), 'css~') !== false) {
if ($svgmiddle == '') {
$svgmiddle="
<style type=\"text/css\" >
<![CDATA[
." . strtolower($name) . " { " . str_replace(';;',';',trim(str_replace('+',' ', urldecode($_POST[$name]))) . ';') . " }
]]>
</style>

";
} else {
$svgmiddle=str_replace("<![CDATA[", "<![CDATA[
." . strtolower($name) . " { " . str_replace(';;',';',trim(str_replace('+',' ', urldecode($_POST[$name]))) . ';') . " }
", $svgmiddle);
}
} else if (strpos(strtolower('' . $name . '~'), 'text~') !== false) {
$tn=$name;
if (strpos(strtolower('~' . $name . '~'), '~text~') !== false) {
$textjust="";
} else if (strtolower(substr($name,0,1)) == 't' || strtolower(substr($name,0,1)) == 'u') {
$htwo=$h;
$eight=0;
$twentyfive=30;
} else if (strtolower(substr($name,0,1)) == 'b' || strtolower(substr($name,0,1)) == 'l') {
$htwo=1;
$gtop30=0;
}
if (strpos(strtolower('' . $name . '~'), 'rtext~') !== false) {
$textjust=' text-anchor="end" ';
$gminus30=(-20 + $w);
}
if (strpos(strtolower('' . $name . '~'), 'ltext~') !== false) {
$wtwo=$w;
$gminus30=20;
$threedotone=0;
}

}

}

?>

… in order to “flesh out” our SVG text element creations. Déjà vu (all over again) for attentive readers below.

The inhouse slideshow PHP clones’ changed associated external Javascript inhouse_slideshow.js now prompts

Please enter comma separated HTML decimal entity(s) for your Emoji Border to slideshow. Can use an Emoji Menu entry (eg. control-command-space for macOS or Mac OS X, logo key + . (period) for Windows, control+space for iOS, top left + for Android keyboard). Optionally append &[text|image]css=[CSSstyle] to change styling. Optionally justify some text via &[ul|uc|ur|ml|[mc]|mr|bl|bc|br]text=[someText%0AsecondLine] to change styling. Eg. 🏖&css=opacity:0.9;&textcss=font-size:20px;&ultext=Hello%0AThere

The Image Map Grid changed PHP imagegridmap.php‘s live run now prompts

Please enter comma separated HTML decimal entity(s) for your Emoji Border to slideshow. Can use an Emoji Menu entry (eg. control-command-space for macOS or Mac OS X, logo key + . (period) for Windows, control+space for iOS, top left + for Android keyboard). Optionally append &[text|image]css=[CSSstyle] to change styling. Optionally justify some text via &[ul|uc|ur|ml|[mc]|mr|bl|bc|br]text=[someText%0AsecondLine] to change styling. Eg. 🏖&iurl=four.jpg&css=opacity:0.9;font-size:20px;&textcss=text-shadow: -2px 2px 3px #ff2d95;&ultext=Hello%0AThere

Day before yesterday’s (third parent (to our PHP tool) “cab off the rank”) SVG -> IMG -> CANVAS changed PHP canvas_svg.php live run now prompts

Please enter comma separated HTML decimal entity(s) for your Emoji Border to graphics. Can use an Emoji Menu entry (eg. control-command-space for macOS or Mac OS X, logo key + . (period) for Windows, control+space for iOS, top left + for Android keyboard). Optionally append &iurl=[newImageURL] to change base image. Optionally append &[text|image]css=[CSSstyle] to change styling. Optionally justify some text via &[ul|uc|ur|ml|[mc]|mr|bl|bc|br]text=[someText%0AsecondLine] to change styling. Eg. 🏖&iurl=four.jpg&css=opacity:0.9;font-size:20px;&textcss=text-shadow: -2px 2px 3px #ff2d95;&ultext=Hello%0AThere


Previous relevant Emoji Borders and Backgrounds CSS Styling Tutorial is shown below.

Emoji Borders and Backgrounds CSS Styling Tutorial

Emoji Borders and Backgrounds CSS Styling Tutorial

It was some time ago now that we said …

… via a new “text” argument arranged for the PHP and in readiness for some more aesthetic improvements in the display side of things with our emoji borders and backgrounds

Well, what gives? Eh, wot’s up ‘guv? Yes, indeed … all we can say is …

We got sidetracted.

… and applying spell checker to get around an expression that amuses us …

We got sidetracked.

So, “being ‘guv” … eh, wot … today we’re having a posting catch up with all the parents and PHP tool child allowing for some CSS styling to be a possibility with the web applications around the theme of “Emoji Borders and Backgrounds”, onto yesterday’s Emoji Borders and Backgrounds in Canvas Tutorial.

And so wotwhat’s the go with styling in SVG “land”? Is SVG classy? It’s not that much different to HTML and CSS, in that “style” elements are allowed, and SVG allows you to define a “class” attribute for SVG elements, so that’s kind of classy … eh, wot, ‘guv?! Thanks to this great link for the heads up on this.

We decided to allow for our changed inline_svg.php PHP tool’s PHP tool live run to understand all arguments coming in whose name ends in CSS …

<?php

$svgmiddle='';

foreach ($_GET as $name=>$val) {
if (strpos(strtolower('' . $name . '~'), 'css~') !== false) {
if ($svgmiddle == '') {
$svgmiddle="
<style type=\"text/css\" >
<![CDATA[
." . strtolower($name) . " { " . str_replace(';;',';',trim(str_replace('+',' ', urldecode($_GET[$name]))) . ';') . " }
]]>
</style>

";
} else {
$svgmiddle=str_replace("<![CDATA[", "<![CDATA[
." . strtolower($name) . " { " . str_replace(';;',';',trim(str_replace('+',' ', urldecode($_GET[$name]))) . ';') . " } ", $svgmiddle);
}
}
}

foreach ($_POST as $name=>$val) {
if (strpos(strtolower('' . $name . '~'), 'css~') !== false) {
if ($svgmiddle == '') {
$svgmiddle="
<style type=\"text/css\" >
<![CDATA[
." . strtolower($name) . " { " . str_replace(';;',';',trim(str_replace('+',' ', urldecode($_POST[$name]))) . ';') . " }
]]>
</style>

";
} else {
$svgmiddle=str_replace("<![CDATA[", "<![CDATA[
." . strtolower($name) . " { " . str_replace(';;',';',trim(str_replace('+',' ', urldecode($_POST[$name]))) . ';') . " }
", $svgmiddle);
}
}
}

?>

… to add the means by which the SVG’s optional “style” elements be populated, leaving it up to the various parents to inform the users of the possibilities here.

The inhouse slideshow PHP clones’ changed associated external Javascript inhouse_slideshow.js now prompts

Please enter comma separated HTML decimal entity(s) for your Emoji Border to slideshow. Can use an Emoji Menu entry (eg. control-command-space for macOS or Mac OS X, logo key + . (period) for Windows, control+space for iOS, top left + for Android keyboard). Optionally append &[text|image]css=[CSSstyle] to change styling. Eg. 🏖&css=opacity:0.9;&textcss=font-size:20px;

The Image Map Grid changed PHP imagegridmap.php‘s live run now prompts

Please enter comma separated HTML decimal entity(s) for your Emoji Border to slideshow. Can use an Emoji Menu entry (eg. control-command-space for macOS or Mac OS X, logo key + . (period) for Windows, control+space for iOS, top left + for Android keyboard). Optionally append &[text|image]css=[CSSstyle] to change styling. Eg. 🏖&iurl=four.jpg&css=opacity:0.9;font-size:20px;&textcss=text-shadow: -2px 2px 3px #ff2d95;

Yesterday’s (third parent (to our PHP tool) “cab off the rank”) SVG -> IMG -> CANVAS changed PHP canvas_svg.php live run now prompts

Please enter comma separated HTML decimal entity(s) for your Emoji Border to graphics. Can use an Emoji Menu entry (eg. control-command-space for macOS or Mac OS X, logo key + . (period) for Windows, control+space for iOS, top left + for Android keyboard). Optionally append &iurl=[newImageURL] to change base image. Optionally append &[text|image]css=[CSSstyle] to change styling. Eg. 🏖&iurl=four.jpg&css=opacity:0.9;font-size:20px;&textcss=text-shadow: -2px 2px 3px #ff2d95;


Previous relevant Emoji Borders and Backgrounds in Canvas Tutorial is shown below.

Emoji Borders and Backgrounds in Canvas Tutorial

Emoji Borders and Backgrounds in Canvas Tutorial

Extending yesterday’s Emoji Borders and Backgrounds in Image Map Grid Tutorial‘s “Emoji Border and Background” horizons, today, we take an interest in three associated HTML “graphic” elements …

Can we start with SVG+XML data and get to populate CANVAS data via IMG data via data URIs? Well, not everything works, but enough works to have a lot of what you’d want to do “in this neck of the woods” be possible.

<?php

var svg = document.querySelector('svg');
var img = document.querySelector('img');
var canvas = document.querySelector('canvas');

// get svg data
var xml = new XMLSerializer().serializeToString(svg);
//alert(xml);

// make it base64
var svg64 = ''; //btoa(xml);
var b64Start = ''; //'data:image/svg+xml;base64,';

<?php
$mb=maybedef('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAEX0lEQVQ4jUWUyW6cVRCFv7r3/kO3u912nNgZgESAAgGBCJgFgxhW7FkgxAbxMLwBEmIRITbsQAgxCEUiSIBAYIY4g1EmYjuDp457+Lv7n+4tFjbwAHVOnVPnlLz75ht67OhhZg/M0p6d5tD9C8SNBBs5XBJhI4uNLC4SREA0UI9yJr2c4e6QO+v3WF27w+rmNrv9Pm7hxDyHFg5yYGEOYxytuRY2SYiSCIwgRgBQIxgjEAKuZWg6R9S0SCS4qKLZElY3HC5tp7QPtmlMN7HOETUTXBJjrEGsAfgPFECsQbBIbDGJZUYgGE8ugQyPm+o0STtTuGZMnKZEjRjjLIgAirEOEQEBDQFBEFFEBWLFtVJmpENRl6hUuFanTRAlbTeZarcx0R6YNZagAdD/t5N9+QgCYAw2jrAhpjM3zaSY4OJGTDrVwEYOYw2qioigoviq5MqF31m9fg1V5fCx+zn11CLNVnufRhBrsVFE1Ihpthu4KDYYwz5YQIxFBG7duMZnH31IqHL6wwnGCLFd4pez3/DaG2/x4GNPgBhEZG/GGlxkMVFkiNMYay3Inqxed4eP33uf7Y0uu90xWkGolFAru7sZn5w5w921m3u+su8vinEO02hEWLN/ANnL2rkvv2an2yd4SCKLM0JVBsCgAYZZzrnPP0eDRzXgfaCuPHXwuEYjRgmIBlQVVLl8/hKI4fRzz3L6uWe5+PMvnHz6aa4uX+D4yYe5vXaLH86eoyoLjLF476l9oKo9pi5HWONRX8E+YznOef7Vl1h86QWurlwjbc+QpikPPfoIcZLS39pmMikp8pzae6q6oqgriqrGqS+xeLScoMYSVJlfOMTl5RXW1+5w5fJVnFGWf1/mxEMnWPppiclkTLM5RdJoUBYFZVlQ5DnZMMMV167gixKLoXXsKGqnOHnqOJ/+/CfZ+XUiZ0jTmFv5mAvf/YjEliQ2vPD8Ir6qqEcZkzt38cMRo5WruFvfL9FqpyRxQhj0qLOax5I2S08+Tu/lFiGUGOPormxwuyfMnjrGrJa88uIixeYWl776lmrzNjmw8vcG8sU7ixpHMXFsCUVg9tABjEvRgzP82j7AhbyiX5Qcv2+Bvy7dYGZ1k7efeQB/Y4PBqGBtdYvb3SFzLcfqToZc/OB1zYeBSpUwLBlvjZidmWaSB1yaYOfn6LqI/r0hyU6P+cRSlhXjbEI2zvnt7y79oqQ3qeg4g6vKjCIXehtDmi6m0UnxVnCRkPUHVNt9qkLJxgXOCYNOg34v48raPaamU2o89/KKsQ9sTSpc0JK7NwdcX8s43Ek5cnSOLC/Z2R6Rj0ra0w2W1/t0xyWn51uk2Ri1QtSO6OU5d7OSi72cQeWxKG7p/Dp//JXTy6C1Pcbc6DMpPRtjTxChEznWhwVZUCKrjCrPoPDczHLmnLBdBgZlRRWUEBR3ZKrme5TlrTGlV440Y1IrXM9qQGi6mkG5V6uza7tUIeCDElTZ1L26elX+fcH/ACJBPYTJ4X8tAAAAAElFTkSuQmCC');
$bemb="";
if (strpos($mb, "</svg>") !== false) {
$mb='<svg' . explode('<svg', explode('</svg>', $mb)[0])[1] . '</svg>';
$bemb='data:image/svg+xml;base64,' . base64_encode($mb);
}

if ($bemb == "") {
echo "\n svg64 = btoa(xml); \n";
echo "\n b64Start = 'data:image/svg+xml;base64,'; \n";
}
?>

// prepend a "header"
var image64 = <?php echo maybedef('b64Start + svg64'); ?>;

// set it as the source of the img element
img.onload = function() {
// draw the image onto the canvas
canvas.getContext('2d').drawImage(img, 0, 0);
}

<?php
if ($bemb != "") {
echo "\n img.src = '" . $bemb . "'; \n";
} else {
echo "\n img.src = image64; \n";
}
?>
}

?>

We’d like to thank html – Drawing an SVG file on a HTML5 canvas – Stack Overflow for the idea that we expand on with our “proof of concept” canvas_svg.php‘s live run web application (calling our changed inline_svg.php PHP tool’s PHP tool live run).


Previous relevant Emoji Borders and Backgrounds in Image Map Grid Tutorial is shown below.

Emoji Borders and Backgrounds in Image Map Grid Tutorial

Emoji Borders and Backgrounds in Image Map Grid Tutorial

Further to yesterday’s Emoji Borders and Backgrounds in Inhouse Slideshow Deployment Tutorial were you around when we presented Image Map Grid Styling Email Share Tutorial?

Well, it’s our “second cab off the rank” regarding a parent idea to oversee our current PHP tool idea for Emoji Borders and Backgrounds.

Anything new? Well, yes, quite a big concept too. With our PHP tool, today, we are allowing it, for a PHP parent (today’s changed imagegridmap.php‘s live run), to fill in a

<?php

var tableih='<table id=oneandonly style=\"' + tw + th + 'background:" . $opprefix . "URL(" . backg("' + indu + '") . ");background-repeat:no-repeat;background-size:' + tcover + ';' + tcss + '\"><tbody id=oneandonlytbody style=\"width:100%;' + 'height:100%;\"></tbody></table>';

?>

… background image (to a table element) data URI with mimetype image/svg+xml and base64 encoding via …

<?php

function backg($indef) {
global $prebimg, $bimg, $udirname, $poemoji;
$udirnameprebimg=$udirname . $prebimg;
if (isset($_GET['iurl'])) {
$udirnameprebimg=str_replace('+',' ',urldecode($_GET['iurl']));
} else if (isset($_POST['iurl'])) {
$udirnameprebimg=str_replace('+',' ',urldecode($_POST['iurl']));
}
if (isset($_GET['emoji'])) {
$poemoji='<input type=hidden id=emoji name=emoji value="' . str_replace('+','',urldecode($_GET['emoji'])) . '"></input>';
list($wdt, $hgt) = getimagesize($udirnameprebimg);
if ($wdt > 0 && $hgt > 0) {
//echo $udirname . "1:" . $hgt;
return file_get_contents($udirname . "../inline_svg.php?asbackground=y&imaXge=" . urlencode($udirnameprebimg) . "&width=" . (-20 + $wdt) . "&height=" . (-20 + $hgt) . "&insvg=" . str_replace('+','',urldecode($_GET['emoji']))) . '),URL(' . $indef;
} else {
//echo "2:" . $hgt;
return file_get_contents($udirname . "../inline_svg.php?asbackground=y&image=" . urlencode($udirnameprebimg) . "&insvg=" . str_replace('+','',urldecode($_GET['emoji']))) . '),URL(' . $indef;
}
} else if (isset($_POST['emoji'])) {
$poemoji='<input type=hidden id=emoji name=emoji value="' . str_replace('+','',urldecode($_POST['emoji'])) . '"></input>';
list($wdt, $hgt) = getimagesize($udirnameprebimg);
if ($wdt > 0 && $hgt > 0) {
return file_get_contents($udirname . "../inline_svg.php?asbackground=y&imaXge=" . urlencode($udirnameprebimg) . "&width=" . (-20 + $wdt) . "&height=" . (-20 + $hgt) . "&insvg=" . str_replace('+','',urldecode($_POST['emoji']))) . '),URL(' . $indef;
} else {
return file_get_contents($udirname . "../inline_svg.php?asbackground=y&image=" . urlencode($udirnameprebimg) . "&insvg=" . str_replace('+','',urldecode($_POST['emoji']))) . '),URL(' . $indef;
}
} else {
return $indef;
}
}

?>

Interesting idea, don’t you think?

It meant a division of two “threads” of modus operandi (possible by “overriding” the PHP echo function into an inhouse “ourecho” (wrapper style of) function), now, for our changed inline_svg.php PHP tool’s PHP tool live run

<?php

$asbkg=false;
$whati='image';

if (isset($_GET['asbackground']) || isset($_POST['asbackground'])) {
$asbkg=true;
$whati='youllneverfindthis';
} else {
header('Content-type: image/svg+xml');
}

// In here are echo"ourecho" codeline calls to construct the SVG+XML

function ourecho($inh) {
global $asbkg;
if ($asbkg) {
echo "data:image/svg+xml;base64," . base64_encode('<svg' . explode('<svg', explode('</svg>', $inh)[0])[1] . '</svg>');
} else {
echo $inh;
}
}


?>

And don’t you just love “the two steptwo thread jive”!


Previous relevant Emoji Borders and Backgrounds in Inhouse Slideshow Deployment Tutorial is shown below.

Emoji Borders and Backgrounds in Inhouse Slideshow Tutorial

Emoji Borders and Backgrounds in Inhouse Slideshow Deployment Tutorial

The deployment aspects to yesterday’s Emoji Borders and Backgrounds in Inhouse Slideshow Tutorial “Inhouse Slideshow” PHP functionality are in our sights today … happy holidays!

“Inhouse Slideshow” functionality can not avoid the serverside PHP (ie. the changed index.php PHP clone “original” and clone) in all its aspects, and so we still need …

  • the kind of clunky “many PHP clones” approach we talked about at Inhouse Slideshow Design Exif Korn Shell Deployment Tutorial for PHP serverside deployment (via the changed job.ksh Korn Shell script parent creator of and “asker” of therealchange.ksh file copying Korn Shell deployer command line script) aspects to “Inhouse Slideshows” (and as you can see with today’s tutorial animated GIF picture), but, as we introduced with this round of such … but as of yesterday …
  • for your more ephemeral “clientside only” tweaks we’ve started, today, with inhouse_slideshow.js to use Javascript junction “overrides” (of PHP Javascript ones above) are possible as a “single external Javascript code file” maintenance ongoing possibility for “Inhouse Slideshow” functionality …

    // inhouse_slideshow.js
    // RJM Programming
    // January, 2022
    // Help out with ephemeral aspects to Inhouse Slideshow PHPs

    function changeto(tvis) {
    if (tvis.toLowerCase().indexOf('exif') == 0) {
    if (document.URL.indexOf('?') == -1) {
    location.href=posturl(document.URL.split('#')[0] + '?exif=y');
    } else {
    location.href=posturl(document.URL.split('#')[0].replace(/pdf\=/g, 'pdTf=') + '&exif=y');
    }
    } else if (tvis.toLowerCase().indexOf('pdf') == 0) {
    if (document.URL.indexOf('?') == -1) {
    location.href=posturl(document.URL.split('#')[0] + '?pdf=y');
    } else {
    location.href=posturl(document.URL.split('#')[0].replace(/exif\=/g, 'exTif=') + '&pdf=y');
    }
    } else if (tvis.toLowerCase().indexOf('emoji') == 0) {
    //var borderis=prompt('Please enter comma separated HTML decimal entity(s) for your Emoji Border to slideshow. Can use an Emoji Menu entry.', '');
    borderblurb='Please enter comma separated HTML decimal entity(s) for your Emoji Border to slideshow. Can use an Emoji Menu entry (eg. control-command-space for macOS or Mac OS X, logo key + . (period) for Windows, control=space for iOS, top left + for Android keyboard). ';
    var borderis=prompt(borderblurb, '');
    var emojiy='';
    if (borderis == null) { borderis=''; } else { borderis=postbb(borderis); }
    if (borderis != '') { emojiy='emoji=' + encodeURIComponent(borderis); }
    if (emojiy != '') {
    if (document.URL.indexOf('?') == -1) {
    location.href=posturl(document.URL.split('#')[0] + '?' + emojiy);
    } else {
    location.href=posturl(document.URL.split('#')[0].replace(/emoji\=/g, 'emojTi=') + '&' + emojiy);
    }
    }
    } else {
    if (document.URL.indexOf('exif=') != -1 || document.URL.indexOf('pdf=') != -1) {
    location.href=posturl(document.URL.split('#')[0].replace(/exif\=/g, 'exTif=').replace(/pdf\=/g, 'pdTf='));
    } else {
    location.href=posturl(document.URL.split('#')[0] + '&eHuhxif=y');
    }
    }
    }


    function postbb(inp) {
    if (inp != '' && inp.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(/\&/g,'').replace(/\#/g,'').replace(/\;/g,'').replace(/\,/g,'') != '') {
    return inp;
    } else if (inp != '' && inp.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(/\,/g,'') == '') {
    if (eval('' + inp.split(',').length) >= 4) {
    eval('inp=String.fromCodePoint(' + inp + ')');
    }
    return inp;
    } else if (inp != '' && inp.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(/\&/g,'').replace(/\#/g,'').replace(/\;/g,'') == '') {
    var outp=inp.replace(/\&\#/g,',').replace(/\;/g,',');
    outp=outp.trim(',');
    outp=outp.replace(/\,\,\,\,/g,',');
    outp=outp.replace(/\,\,\,/g,',');
    outp=outp.replace(/\,\,/g,',');
    outp=outp.trim(',');
    outp=('~' + outp + '~').replace('~,','').replace(',~','').replace(/\~/g,'');
    if (eval('' + outp.split(',').length) >= 4) {
    eval('outp=String.fromCodePoint(' + outp + ')');
    }
    return outp;
    }
    //alert(String.fromHtmlEntities(inp));
    //alert(inp.toHtmlEntities());
    return inp;
    }


    function posturl(inpu) {
    return inpu;
    }

    … including that one change to Javascript prompt popup window wording as an example of an ephemeral “clientside only” tweak … becomes a possibility (which is optional … ie. the PHP won’t fail if such an external Javascript does not exist, as those of you actively trying our guinea pig Inhouse Slideshow yesterday might attest to?!)


Previous relevant Emoji Borders and Backgrounds in Inhouse Slideshow Tutorial is shown below.

Emoji Borders and Backgrounds in Inhouse Slideshow Tutorial

Emoji Borders and Backgrounds in Inhouse Slideshow Tutorial

Continuing on from yesterday’s Emoji Borders and Backgrounds via Emoji Menu Tutorial and harkening back to Emoji Borders and Backgrounds Image Text Parent Tutorial‘s …

… the functionalities that would be “cool” at the HTML/Javascript/CSS parent side, and then work out how to implement similar functionality, as possible, in SVG, and if possible, we should be able to pass arguments over to the “PHP tool” to eventually code it to be standalone to help other “parenting arrangements”.

… today’s “theme” concerns the first of those other “parenting arrangements” mentioned above, our PHP for Inhouse Slideshow presentation display options …

… the new “Emoji Border Slideshow” display option above calling into play our inline_svg.php PHP tool’s live run (“Are we there yet, as a tool, I mean … Mum … Dad … anyone?”) web application.

And in so doing, to use an Emoji Menu methodology of selecting your emoji border decoration is “right up your street, Inhouse Slideshow supervisor”.

You will find, examining the changed PHP code representative “first cab off the rank” and “guinea pig” live run that we introduce a non-existant external Javascript call …


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

… into the mix. Why? Well, perhaps, first off, you should read some history of this “Inhouse Slideshow” project over time at Inhouse Slideshow Temporary Unzip Tutorial and then see that this “external Javascript lark” could be better for a way to “future proof” the venture, with some improvements being changeable through one (into your chosen Document Root folder, wherever that may be (that is what the leading “/” infers)) external Javascript codefile rather than a myriad number of identical PHP codefiles.


Previous relevant Emoji Borders and Backgrounds via Emoji Menu Tutorial is shown below.

Emoji Borders and Backgrounds via Emoji Menu Tutorial

Emoji Borders and Backgrounds via Emoji Menu Tutorial

On this macOS MacBook Air we’re used to …


control-command-space

… bringing up an Emoji Menu from which an emoji can be selected and placed wherever the cursor had been placed before that menu display. That could be …

  • on an address bar where the cursor is placed
  • in a Javascript prompt window that is focussed

… both scenarios (amongst many others, no doubt) of which we will be interested with our current Emoji Borders and Background web application project. Today’s work develops our PHP tool ahead of its supervisory web application, and so we are interested in the first scenario above, as far as testing it goes with our changed underlying inline_svg.php PHP tool live run web application.

The argument “text” is already catered for from yesterday but the nature of the data this $_GET[‘text’] might contain had not catered for …

  • unicode data (via Emoji Menus) … but rather had catered for
  • Javascript call of String.fromCodePoint([comma separated list of HTML Decimal Entity(s)]);

… only, as of yesterday’s Emoji Borders and Backgrounds Image Text PHP SVG Tutorial. As you would probably concur, yesterday’s setup was quite user unfriendly, as so many of us now are used to those Emoji Menus being used to fill in your emoji data requirements.

The main gist of the PHP code changes goes …

<?php

$innards='';
$preinnards='';

function ingp($m) { // thanks to https://pretagteam.com/question/how-do-i-convert-unicode-special-characters-to-html-entities
global $innards, $preinnards;
if ($innards != '') {
$entity = preg_replace_callback('/[\x{80}-\x{10FFFF}]/u', function ($m) {
$char = current($m);
$utf = iconv('UTF-8', 'UCS-4', $char);
return sprintf("&#x%s;", ltrim(strtoupper(bin2hex($utf)), "0"));
}, $innards);
$preinnards=htmlentities($entity);
$innards='';
}
}

// And then later we change ...
if (isset($_GET['insvg'])) {
$innards=str_replace('+','',urldecode($_GET['insvg']));
if (trim(str_replace(',','',str_replace('0','',str_replace('1','',str_replace('2','',str_replace('3','',str_replace('4','',str_replace('5','',str_replace('6','',str_replace('7','',str_replace('8','',str_replace('9','',$innards)))))))))))) != '') {
ingp($innards);
}
if ($preinnards == '') {

$preinnards='&#' . str_replace(',',';&#',$innards) . ';';
}
// rest of if block code uses $preinnards as SVG text innerHTML ... but UTF-16 Surrogate pair scenarios can fail
}

?>


Previous relevant Emoji Borders and Backgrounds Image Text PHP SVG Tutorial is shown below.

Emoji Borders and Backgrounds Image Text PHP SVG Tutorial

Emoji Borders and Backgrounds Image Text PHP SVG Tutorial

To add to yesterday’s Emoji Borders and Backgrounds Image Text Parent Tutorial today it is “PHP tool” work catching up so as to say

  • emoji border … now with content control via comma separated list of emoji HTML decimal Entity(s) … argumented to PHP tool
  • emoji background … now with content control via comma separated list of emoji HTML decimal Entity(s) … argumented to PHP tool
  • centralized text (in foreground) … now with wording control via HTML span contenteditable=true elements … not yet argumented to PHP tool
    <?php

    if (isset($_GET['text'])) {
    $txt=str_replace("\n","<br>", str_replace('&nbsp;',' ',str_replace('+', ' ', urldecode($_GET['text']))));
    $minus30=($w / 2.0) - strlen(explode('<br>', $txt)[0]) * 3.1;
    $top30=($h / 2.0) + 25 - (sizeof(explode('<br>', $txt)) * 8);
    $lines=explode('<br>', $txt);
    for ($il=0; $il<sizeof($lines); $il++) {
    $textcontent.='<text x="' . $minus30 . '" y="' . $top30 . '">' . $lines[$il] . '</text>';
    $top30+=15;
    }
    } else if (isset($_POST['text'])) {
    $txt=str_replace("\n","<br>", str_replace('&nbsp;',' ',str_replace('+', ' ', urldecode($_POST['text']))));
    $minus30=($w / 2.0) - strlen(explode('<br>', $txt)[0]) * 3.1;
    $top30=($h / 2.0) + 25 - (sizeof(explode('<br>', $txt)) * 8);
    $lines=explode('<br>', $txt);
    for ($il=0; $il<sizeof($lines); $il++) {
    $textcontent.='<text x="' . $minus30 . '" y="' . $top30 . '">' . $lines[$il] . '</text>';
    $top30+=15;
    }
    }

    ?>
  • centralized image (in foreground) … including some width and height control … argumented to PHP tool

… via a new “text” argument arranged for the PHP and in readiness for some more aesthetic improvements in the display side of things with our emoji borders and backgrounds changed underlying inline_svg.php PHP tool live run web application (or in iframe).


Previous relevant Emoji Borders and Backgrounds Image Text Parent Tutorial is shown below.

Emoji Borders and Backgrounds Image Text Parent Tutorial

Emoji Borders and Backgrounds Image Text Parent Tutorial

Today’s work continues on from yesterday’s Emoji Borders and Backgrounds for Image Tutorial combining both …

… partnership during testing. Our final aim is to make the “underlying PHP” a proper standalone tool, but “that’s a ways off”, as they say. Why this extra level of complication? It’s easier to …

  • see
  • test
  • debug (via web browser web inspectors)

… the functionalities that would be “cool” at the HTML/Javascript/CSS parent side, and then work out how to implement similar functionality, as possible, in SVG, and if possible, we should be able to pass arguments over to the “PHP tool” to eventually code it to be standalone to help other “parenting arrangements”.

And so, today, we “get functional” the combination of parental control through to PHP SVG child display …

Optionally enter an image URL ( as needs be, suffix by &width=[preferredWidth]&height=[preferredHeight] and/or &background=y ) and/or # prefixed comma separated list of emoji HTML decimal Entity(s) ( eg. #127462,127465 ) ? Cancel if it is wording you want to change to the left there.

  • emoji border … now with content control via comma separated list of emoji HTML decimal Entity(s) … argumented to PHP tool
  • emoji background … now with content control via comma separated list of emoji HTML decimal Entity(s) … argumented to PHP tool
  • centralized text (in foreground) … now with wording control via HTML span contenteditable=true elements … not yet argumented to PHP tool
  • centralized image (in foreground) … including some width and height control … argumented to PHP tool


function ask(sois) {
var huhi=prompt('Optionally enter an image URL ( as needs be, suffix by &width=[preferredWidth]&height=[preferredHeight] and/or &background=y ) and/or # prefixed comma separated list of emoji HTML decimal Entity(s) ( eg. #127462,127465 ) ? Cancel if it is wording you want to change to the left there.','');
if (huhi == null) { huhi=''; }
if (huhi.trim() != '') {
if (document.URL.indexOf('rjmprogramming.com.au') == -1 && sois.title.indexOf('rjmprogramming.com.au') != -1) {
sois.title=document.URL.substring(0,8) + document.URL.substring(8).split('/')[0] + sois.title.split('rjmprogramming.com.au')[1];
}
if (huhi.indexOf('#') != -1) {
var huhis=huhi.split('#')[1];
for (var ihuhis=0; ihuhis<huhis.length; ihuhis++) {
if (eval('' + ihuhis) < eval('' + huhis.length)) {
if (huhis.substring(ihuhis).substring(0,1).replace('0','').replace('1','').replace('2','').replace('3','').replace('4','').replace('5','').replace('6','').replace('7','').replace('8','').replace('9','').replace(',','') != '') {
huhi=huhi.replace('#' + huhis.split(huhis.substring(ihuhis).substring(0,1))[0], '');
huhis=huhis.split(huhis.substring(ihuhis).substring(0,1))[0];
}
}
}
if (huhis == '') {
if (sois.title.indexOf('?insvg=') != -1) {
sois.title=sois.title.replace('?insvg=' + sois.title.split('?insvg=')[1].split('&')[0].split('#')[0],'');
} else if (sois.title.indexOf('&insvg=') != -1) {
sois.title=sois.title.replace('&insvg=' + sois.title.split('&insvg=')[1].split('&')[0].split('#')[0],'');
}
} else if (sois.title.indexOf('?insvg=') != -1) {
sois.title=sois.title.replace('?insvg=' + sois.title.split('?insvg=')[1].split('&')[0].split('#')[0],'?insvg=' + encodeURIComponent(huhis));
} else if (sois.title.indexOf('&insvg=') != -1) {
sois.title=sois.title.replace('&insvg=' + sois.title.split('&insvg=')[1].split('&')[0].split('#')[0],'&insvg=' + encodeURIComponent(huhis));
} else if (sois.title.indexOf('?') != -1) {
sois.title=sois.title.replace('?','?insvg=' + encodeURIComponent(huhis) + '&');
} else {
sois.title=sois.title.split('#')[0] + '?insvg=' + encodeURIComponent(huhis);
}
}
if (huhi.split('&')[0].split('#')[0].trim() != '') {
if (sois.title.indexOf('?image=') != -1) {
sois.title=sois.title.replace('?image=' + sois.title.split('?image=')[1].split('&')[0].split('#')[0],'');
} else if (sois.title.indexOf('&image=') != -1) {
sois.title=sois.title.replace('&image=' + sois.title.split('&image=')[1].split('&')[0].split('#')[0],'');
}
sois.title+='&image=' + encodeURIComponent(huhi.split('&')[0]) + huhi.replace(huhi.split('&')[0],'');
} else if (sois.title.indexOf('?image=') != -1) {
sois.title=sois.title.replace('?image=' + sois.title.split('?image=')[1].split('&')[0].split('#')[0],'');
} else if (sois.title.indexOf('&image=') != -1) {
sois.title=sois.title.replace('&image=' + sois.title.split('&image=')[1].split('&')[0].split('#')[0],'');
}
document.getElementById(sois.id.replace('span','if')).src=sois.title; //+='&image=' + encodeURIComponent(huhi.split('&')[0]) + huhi.replace(huhi.split('&')[0],'');
}
}


function snapshot(sio) {
lastih=sio.innerHTML;
lastio=-1;
for (var iuh=0; iuh<cds.length; iuh++) {
if (lastih == cds[iuh]) { lastio=iuh; } else if (sio.innerHTML.indexOf(' of ') != -1) { if (lastih.split(' of ')[0] == cds[iuh].split(' of ')[0]) { lastio=iuh; } }
}
}


function newwords(sio) {
if (lastih != sio.innerHTML && lastio >= 0) {
cds[lastio]=sio.innerHTML.replace(/\ \;/g,' ').replace(/\<br\>/g,String.fromCharCode(10));
var documentURL=document.URL.split('#')[0].split('?arr' + lastio + '=')[0].split('&arr' + lastio + '=')[0];
location.href=(documentURL + '&arr' + lastio + '=' + encodeURIComponent(cds[lastio])).replace('.html&','.html?').replace('.htm&','.htm?'); // fancystuff();
}
}


Previous relevant Emoji Borders and Backgrounds Context Tutorial is shown below.

Emoji Borders and Backgrounds Context Tutorial

Emoji Borders and Backgrounds Context Tutorial

It’s all fine and good creating the Emoji Borders and Backgrounds of yesterday’s Emoji Borders and Backgrounds Primer Tutorial, but it’s the context of their use that we are starting to take an interest in with today’s …

  1. take yesterday’s table as a starting bit to our …
  2. “making use of” “proof of concept” emoji_border_background.html live run link for you to contextualize and make use of those table’s iframe contents from yesterday …

… as we figure out, perhaps, some better “tool like generics” here. We’ll see (we hope)!

But, so far, how would we assess the approach, here? Well, what we had to do today reminded us a lot of what we do here, often, at this blog, when we talk about “overlay” webpage design approaches. CSS position:absolute and opacity and Javascript [element].getBoundingClientRect() all made guest appearances!


Previous relevant Emoji Borders and Backgrounds Primer Tutorial is shown below.

Emoji Borders and Backgrounds Primer Tutorial

Emoji Borders and Backgrounds Primer Tutorial

Time for a new project into the new year. It’s an “old chestnut” project, for us. Being able to handle …

  • borders made up of emoji images (in the form of “image/svg+xml” mimetype data)
  • backgrounds made up of emoji images (in the form of “image/svg+xml” mimetype data)

… via “proof of concept” (at least for our “Primer” tutorial start) inline_svg.php‘s single violin emoji or …

Description Iframe
Line of Doves of Peace Emojis
Border of Train Emojis
Background Flag of Andorra Emojis

Cute, huh?!

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 eLearning, Tutorials | Tagged , , , , , , , , , , , , , , , , , | Leave a comment

Javascript Console Warning Conditionals Tutorial

Javascript Console Warning Conditionals Tutorial

Javascript Console Warning Conditionals Tutorial

Yesterday’s YouTube API iOS Shower Song Subset Looping Tutorial‘s …

  • want to “move on” to a new song … via …
  • add to an “individual song looping subset” with another “individual looping song” … and it also serves another “arcane usage” to our mind, we explain below …
  • out and about using a laptop lassooed to a mobile (or just the mobile itself) using mobile data (rather than Wi-Fi) this web browser Shower Songs web application depends on a connection as a song starts and if you have run out of never before tapped buttons to choose from (and the web application has lost it’s connection) it can become an impotent web application, sometimes, so that to add to the web application’s possibilities of button tapping, and often reawakening it, the better, we figure

… work did not function for as many scenarios as we would like. This problem requires Javascript web browser clientside debugging via a Web Browser web inspector “Developer” style of debugging (ie. deep and meaningful).

When it gets to the “deep and meaningful” we mean “comparing” console tab “good versus bad” types of reporting, which becomes untenable if too much is already being reported in our favourite “reporting tool conduit” for us …


console.warn([some messaging text]);

… you can read more about at YouTube API Caller Phase Two Console Warning Tutorial. Over the three window hierarchies, over quite some time, we’ve filled console.warn web inspector tab with so much information it is untenable for what we have to do debugging the issues above.

And so, today, we’re showing a “conditional approach” to controlling “console.warn” logging via “grandchild level” substitution of all “console.warn(” for “consolewarn(” and then the new Javascript function …


function consolewarn(inms) {
if (window.self != window.parent) {
if (('' + top.document.URL).indexOf('consolewarnoptinall') != -1 || ('' + top.document.URL).indexOf('consolewarnoptingrandchild') != -1) {
console.warn(inms);
}
} else if (('' + document.URL).indexOf('consolewarnoptoutall') == -1) {
console.warn(inms);
}
}

… and at the “parent level” substitution of all “console.warn(” for “consolewarn(” and then the new Javascript function …


function consolewarn(inms) {
if (window.self != window.parent) {
if (('' + top.document.URL).indexOf('consolewarnoptinall') != -1 || ('' + top.document.URL).indexOf('consolewarnoptinchild') != -1) {
console.warn(inms);
}
} else if (('' + document.URL).indexOf('consolewarnoptoutall') == -1) {
console.warn(inms);
}
}

… as an address bar controlling URL via, for example …


https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?consolewarnoptinchild=y

… means by which we can better hone in on the debugging issues as they arrive, so that self contained relevance fits on the one screen, and the Clear Console icon becomes an additional friend to our work, within …


Previous relevant YouTube API iOS Shower Song Subset Looping Tutorial is shown below.

YouTube API iOS Shower Song Subset Looping Tutorial

YouTube API iOS Shower Song Subset Looping Tutorial

You’d think we’d be done with ablutions at this blog, but ingen måte … Luna (aka Måne) says … there’s all manner of molekylær interesse out there in and out of the fjords …

It’s not just H and the 2 and the O … it’s the art of the rollerulle.

… or so says “The Lu” (aka “Toalettet”) anyway!

Today’s Shower Songs tweak involves it’s “individual song looping” thinking. It occurred to us, that it’s use by a user might be what they want, it becomes a bit inflexible should they either …

  • want to “move on” to a new song … via …
  • add to an “individual song looping subset” with another “individual looping song” … and it also serves another “arcane usage” to our mind, we explain below …
  • out and about using a laptop lassooed to a mobile (or just the mobile itself) using mobile data (rather than Wi-Fi) this web browser Shower Songs web application depends on a connection as a song starts and if you have run out of never before tapped buttons to choose from (and the web application has lost it’s connection) it can become an impotent web application, sometimes, so that to add to the web applications’s possibilities of button tapping, and often reawakening it, the better, we figure

And so, moving on from yesterday’s YouTube API iOS Shortcuts Shower Song Tutorial code that changed involved …


Previous relevant YouTube API iOS Shortcuts Shower Song Tutorial is shown below.

YouTube API iOS Shortcuts Shower Song Tutorial

YouTube API iOS Shortcuts Shower Song Tutorial

Yesterday’s non-mobile YouTube API Command Line Shower Song Names Tutorial based work begs the question, for us …

At least, on “mobile” iOS (which we have access to) can any “command line” feel of playlists ending up at our Shower Songs web application be arranged?

Pretty pithy, huh?! Before we launch into the great iOS Shortcuts app (we’ve talked about before at Shortcuts iOS App Email Arrival Sounds Tutorial) helping here, let’s outline some other simpler ideas you might want to try yourself in the DIY range of ideas …

  • open one of these inhouse Radio Play (YouTube API song playlist and sequencing and loop supporting changed for today’s work swipe_media.html Tabular Single Row Media Gallery or Shower Songs) web applications on a web browser on an iOS device (eg. iPhone or iPad) … and at the juncture where your desired playlist is implemented … use Share icon menu of choices to …
    1. Add to Home Screen … with a tailored (Playlist) Title … this being our preferred option to future proof the remembering … but also available is …
    2. Add Bookmark … or …
    3. Add Favourite
    4. Make your web browser’s opening Home Page be a URL of interest (like one of these playlists) within that web browser app’s Settings area
  • as well as the Shower Songs (as well as Tabular Single Row Media Gallery) web application (with Playlists of 7) can have a dropdown be populated ready to choose and replay that Playlist (that can be email or SMS shared with a recipient)

Okay, all that being said, the great Shortcuts iOS app can serve two purposes a bit “above and beyond this” …

  1. you can DIY build an iOS feeling and “hybrid looking” amalgum of iOS and “old days” dialog box “desktop feeling” personalized application(s) …
  2. the act of constructing any one is sure to inspire other iOS automation ideas you might have

We’re sure lots of you more aux fait with the great iOS Shortcuts app can do better than the “bit kludgy” effort we came up with, and that is the joy of programming, huh?! It can come down to …

  • what you think is the most efficient …
  • you feel you can handle … and …
  • end up with a better automated solution … but …
  • it’s not “all about efficiency” always … it’s also learning about new methodologies you might have to spend more time discovering the ins and outs about

As a case in point, it will be hard to stop yours truly just (iOS mobile) opening the relevant Radio Play web application in a web browser, and going from there (with Bookmarks and Favourites), but there you go?! In this case, perhaps yes, but you should see all the other Messaging and automation possibilities that a peruse of the iOS Shortcuts app can open up to you!

Todays’ animated GIF presentation shows our endeavours “warts and all” (latching onto, intervention wise, when a user taps the Music mobile app icon) for your perusal.


Previous relevant YouTube API Command Line Shower Song Names Tutorial is shown below.

YouTube API Command Line Shower Song Names Tutorial

YouTube API Command Line Shower Song Names Tutorial

Yesterday’s YouTube API Command Line Shower Songs Tutorial‘s Operating System command line modes of access brought us to another issue.

Can a list of seven non-YouTube-ID comma separated values (ie. YouTube song search basis strings) be entered and still end up at the Shower Songs web application?

Well, yes, that’s possible if an intervention point can be arranged. After all, the command line prompt goes …

Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist … 7 for Shower Songs … egs. Tragedy,Boogie Wonderland,Down Among the Dead Men … random … Tragedy ,Imagine*3,Breezin … ordered 5 … Tragedy ,Pina Colada Son,Fast Car … audio … Tragedy ,Galveston,Fix You … audio ordered, and go.

… begging the question “What happens if we enter, at the command line …”


play
Tragedy ,Pina Colada Song,Fast Car,Breezin,Galveston,Fix You,Imagine

… ? Well, after our “better interfacing changes” to the swipe_media.html Tabular Single Row Media Gallery web application changes …


var ytlistis=location.search.split('youtube=')[1] ? anotherdecodeURIComponent(location.search.split('youtube=')[1].split('&')[0]) : '';


function anotherdecodeURIComponent(inplis) {
var thisplist=decodeURIComponent(inplis);


if (eval((thisplist + ',').replace(/[AEIMQUYcgkosw048]\,/g,'z').length) == 77 && eval(('' + thisplist).length) == 83 && eval(('' + encodeURIComponent(thisplist.replace(/\,/g,''))).length) == 77 && eval(('' + thisplist.split(',').length)) == 7) {
window.open('//www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=' + thisplist.trim(),'_blank','top=50,left=' + eval(-800 + screen.width) + ',width=800,height=800');
}

return thisplist;
}

… which mapped to URL …


https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=OiwDHHcHPh0,FXG_I_tf_i4,AIOAlaACuv4,G1QjyskJ9jw,HhKZLhxFFUY,k4V3Mo61fJM,MBIyH4WhOWg

… and that’s where “our fun” (chortle, chortle) began (yeh, right … after a Goose Chase with it being the seventh one) because that seventh YouTube video ID (involved with YouTube “Imagine” search (and something about this rings a bell)) comes back with …

This content can’t be played on your mobile browser. Get the YouTube app to start watching.

Ouch?! What to do? Looking optimistically on this, it’s good to discover it now (yeh, right).

Anyway, we mapped such unplayables to Nothing’s Gonna Stop Us Now – Starship – 1987 in …

… as our means to a solution.


Previous relevant YouTube API Command Line Shower Songs Tutorial is shown below.

YouTube API Command Line Shower Songs Tutorial

YouTube API Command Line Shower Songs Tutorial

Today, we’re combining the concepts behind …

  • the recent YouTube API Caller Radio Play Doctype Meta Tutorial‘s means by which …
    1. macOS
    2. Windows

    … command line “command verb” …

    play

    … can call our “Radio Play” YouTube API interfacing means to play music …

    • sequentially
    • continuously looping (through a set of songs) or just the one song looping

    … adding into those previous arrangements the capability to call the Shower Songs web application under conditions we outlined in …

  • the work of the day before yesterday’s Shower Songs Delimitation Hashtag Tutorial

… involving changed

  1. macOS (building on the changed play.sh shell script)

    #!/bin/bash
    rest=""
    if [ -z "$1" ]; then
    echo "Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... 7 such uses Shower Songs ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men flash ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Song,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go."
    read ans
    else
    preans="$1"
    ans="$1 $2 $3 $4 $5 $6 $7 $8 $9"
    while [ ! -z "$9" ]; do
    shift
    rest="${rest} $9"
    done
    ans="$ans${rest}"
    fi
    if [ ! -z "$ans" ]; then
    commas_only="${ans//[^,]}"
    if [ "${#preans}" == "83" ]; then
    if [ "${#commas_only}" == "6" ]; then
    open "https://www.rjmprogramming.com.au/$1"
    else
    open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
    fi
    else

    open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
    fi
    fi
    exit
  2. Windows (building on the changed play.bat script)

    @echo off
    rem play.bat
    rem RJM Programming
    rem November, 2025

    set passed=
    set rest=
    set seven=0

    if trick==trick%1 (
    set /p ans=Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... 7 for Shower Songs ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Son,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go.
    set ansplus="%ans% "

    if "%ansplus:~12,1%"=="," (
    if "%ansplus:~24,1%"=="," (
    if "%ansplus:~36,1%"=="," (
    if "%ansplus:~48,1%"=="," (
    if "%ansplus:~60,1%"=="," (
    if "%ansplus:~72,1%"=="," (
    if "%ansplus:~84,1%"==" " (
    set seven=7
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=%ans%"
    goto :end
    ) else (
    set seven=6
    )
    ) else (
    set seven=5
    )
    ) else (
    set seven=4
    )
    ) else (
    set seven=3
    )
    ) else (
    set seven=2
    )
    ) else (
    set seven=1
    )
    ) else (
    set seven=0
    )


    ) else (
    set ans="%1"

    set ansplus="%1,%2,%3,%4,%5,%6,%7 %8 "

    if "%ansplus:~12,1%"=="," (
    if "%ansplus:~24,1%"=="," (
    if "%ansplus:~36,1%"=="," (
    if "%ansplus:~48,1%"=="," (
    if "%ansplus:~60,1%"=="," (
    if "%ansplus:~72,1%"=="," (
    if trick==trick%8 (
    set seven=7
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=%1,%2,%3,%4,%5,%6,%7"
    goto :end
    ) else (
    set seven=6
    )
    ) else (
    set seven=5
    )
    ) else (
    set seven=4
    )
    ) else (
    set seven=3
    )
    ) else (
    set seven=2
    )
    ) else (
    set seven=1
    )
    ) else (
    set seven=0
    )


    set passed=yes
    if trick==trick%2 goto :loop
    set ans="%ans%,%2"
    if trick==trick%3 goto :loop
    set ans="%ans%,%3"
    if trick==trick%4 goto :loop
    set ans="%ans%,%4"
    if trick==trick%5 goto :loop
    set ans="%ans%,%5"
    if trick==trick%6 goto :loop
    set ans="%ans%,%6"
    if trick==trick%7 goto :loop
    set ans="%ans%,%7"
    if trick==trick%8 goto :loop
    set ans="%ans%,%8"
    if trick==trick%9 goto :loop
    set ans="%ans%,%9"
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans:"=%"
    :loop
    if "%9"=="" (
    @echo off
    ) else (
    shift
    set rest="%rest% %9"
    goto :loop
    )
    set ans="%ans%%rest%"
    set ans=%ans:"=%
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
    )
    if trick==trick%passed% (
    set ans=%ans:"=%
    if "%ans:,=%"=="%ans%" (
    echo "Nothing to do."
    ) else (
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
    )
    )
    rem exit
    :end

… and involving, if you are on macOS or Windows implementing accordingly …

… a command line …


play FtE3hoR_Nvo,W5IKT_xue4o,IfaGhyK78E8,BuN3yCmHb_U,TdiAwCPb_As,euZcUku9XiE,aMs0rNtBZJk

… can loop and continuously play through that list of seven YouTube video IDs via a web browser use of our Shower Songs web application.


Previous relevant YouTube API Caller Radio Play Doctype Meta Tutorial is shown below.

YouTube API Caller Radio Play Doctype Meta Tutorial

YouTube API Caller Radio Play Doctype Meta Tutorial

It took a session on this MacBook Air’s macOS Firefox web browser trying the Tabular Single Row Media Gallery web application to emphasise the importance of more consistency checking on …

  • doctype HTML tagdeclaration …

    <!DOCTYPE html>

    … and …
  • meta HTML display tagcharset attribute …

    <meta charset="UTF-8">

… existence in web applications we create, to the point that not having the second one defined was stopping proper webpage display on Firefox. Was this a portent of what is to come soon on more web browsers?!

Let’s look at the purpose of these two HTML tagthingos …

  • doctype HTML tagdeclaration

    All HTML documents must start with a declaration.

    The declaration is not an HTML tag. It is an “information” to the browser about what document type to expect.

    … and …

  • meta HTML display tagcharset attribute

    The charset attribute specifies the character encoding for the HTML document.

    The HTML5 specification encourages web developers to use the UTF-8 character set, which covers almost all of the characters and symbols in the world!

Regarding the same web application as yesterday’s YouTube API Caller Radio Play Playlist Windows Local System Tutorial talked about, why not revisit the tweaked swipe_media.html Tabular Single Row Media Gallery web application?


Previous relevant YouTube API Caller Radio Play Playlist Windows Local System Tutorial is shown below.

YouTube API Caller Radio Play Playlist Windows Local System Tutorial

YouTube API Caller Radio Play Playlist Windows Local System Tutorial

Further to the recent YouTube API Caller Radio Play Playlist Local System Tutorial macOS local system discussion, today, we code for …

play

… to mean something on the …

Windows

… “cmd” command accessible …

command line

What’s the scripting here? They are called batch files with extension *.bat we’re calling play.bat (going back to the DOS days of the ’70’s again). With *.bat you just need to plonk your play.bat anywhere within the Windows local system path, and the word (now command) “play” will do the rest anywhere in that user’s command line environment. And the batch file has …


@echo off
rem play.bat
rem RJM Programming
rem November, 2025

set passed=
set rest=

if trick==trick%1 (
set /p ans=Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Son,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go.
) else (
set ans="%1"
set passed=yes
if trick==trick%2 goto :loop
set ans="%ans%,%2"
if trick==trick%3 goto :loop
set ans="%ans%,%3"
if trick==trick%4 goto :loop
set ans="%ans%,%4"
if trick==trick%5 goto :loop
set ans="%ans%,%5"
if trick==trick%6 goto :loop
set ans="%ans%,%6"
if trick==trick%7 goto :loop
set ans="%ans%,%7"
if trick==trick%8 goto :loop
set ans="%ans%,%8"
if trick==trick%9 goto :loop
set ans="%ans%,%9"
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans:"=%"
:loop
if "%9"=="" (
@echo off
) else (
shift
set rest="%rest%,%9"
goto :loop
)
set ans="%ans%%rest%"
set ans=%ans:"=%
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
if trick==trick%passed% (
set ans=%ans:"=%
if "%ans:,=%"=="%ans%" (
echo "Nothing to do."
) else (
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
)
rem exit
:end

… as your starting gambit, here, where the equivalent of macOS’s “open” is “explorer.exe” on Windows (ie. the File Explorer) … almost as cute!


Previous relevant YouTube API Caller Radio Play Playlist Local System Tutorial is shown below.

YouTube API Caller Radio Play Playlist Local System Tutorial

YouTube API Caller Radio Play Playlist Local System Tutorial

The ..

command line

… of a laptop or notebook or personal computer can be an environment to relax from the GUI aspects of your modern operating systems and think about …

  • processes
  • batch driven tasks
  • task simplifications

… and in the category of that last one, on our local macOS operating system we envisaged a day we could slip back to the “quiet world” of the “command line” and type a command like …


play Tragedy,Imagine,Down Among the Dead Men PAN -

… and get somewhere playing those songs through a web browser accessing the YouTube API and our interfacings to it in webpage software form, playing in a continuous Radio Play style.

You see, with all the distractions, only having to remember …

play

… no matter where we were in “command line” woooorrrrllllddd seemed the ideal, and yes, it’s possible. However, we think explaining …


bash /Applications/MAMP/htdocs/play.ksh Tragedy,Imagine,Down Among the Dead Men PAN -

… is a necessary dividing line between two parts to the discussion. So what’s bash? It’s the shell we associate as your macOS default shell (we get to via the “out of the box” macOS desktop application called Terminal) … well, it used to be … anyway, the first line of (what started as play.ksh then play.sh and then eventually, just, play … as a filename that is) …


#!/bin/bash
rest=""
if [ -z "$1" ]; then
echo "Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Song,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go."
read ans
else
ans="$1 $2 $3 $4 $5 $6 $7 $8 $9"
while [ ! -z "$9" ]; do
shift
rest="${rest} $9"
done
ans="$ans${rest}"
fi
if [ ! -z "$ans" ]; then
open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
fi
exit

… tells the local system use the bash shell to interpret this what you might like to think of as an executable script (which we went chmod 777 play regarding to make it so).

Okay, so we wrote this script in /Applications/MAMP/htdocs/ and that …


bash /Applications/MAMP/htdocs/play Tragedy,Imagine,Down Among the Dead Men PAN -

… could swing it at this stage, or even being in /Applications/MAMP/htdocs/ and going …


./play Tragedy,Imagine,Down Among the Dead Men PAN -

… but (even in /Applications/MAMP/htdocs/) …


play Tragedy,Imagine,Down Among the Dead Men PAN -

… is most likely to reply something like …

zsh: no such command

As the programmer, perhaps you could leave it at that with your “insider knowledge”, or if “play” as a command already meant something (a test that would be good to do before any such proposed work), otherwise … do you really think you’ll remember next Wednesday? So …

  1. enter into the wooooorrrrllllddd of aliases (thanks to this great advice, thanks) … eg.

    alias play="/Applications/MAMP/htdocs/play"
  2. placed into …

    ~/.bashrc

    … via (in our case) …

    vi ~/.bashrc
  3. then …

    source ~/.bashrc

    … needs to be included into the login procedure of …

    ~/.profile

    …via (in our case) …

    vi ~/.profile
  4. to make …

    play

    … as the interactively asking alternative to the argumentative example of …

    play Tragedy,Imagine,Down Among the Dead Men PAN -

    … mean something … and anywhere

    … all of this possible because of the brilliantly useful macOS (not Linux nor unix) …


    open

    … opener of web browsers from the command line blowing of our tiny little rather still naive mind … mind you, VAX/VMS “phone” command from the ’70’s might have even been better?! And then there were those punch cards … in the hopper … and if you got a character wrong … back to the end of the queue.

    Sorry … we got a bit hot and bothered there!

    Anyway, as a layer of thought on top of the recent YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial‘s mildly changed swipe_media.html Tabular Single Row Media Gallery web application work it might be a thing you want to pursue yourself?

    By the way, this brought into play for us what your default web browser is. Ours is Safari yet we develop more on Google Chrome. Safari, for us, does more Popup Blocking, and it is a thing to look out for should a window not open when expected (and these command line methodologies don’t get past you still having to unmute and/or click/tap once before the Radio Play mode of play kicks off). To undo the Popup Block there will probably be a means to do this to the right of the web browser address bar.


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial

    Burp …

    Sorry to open with a quote, and sorry to repeat myself, like.

    And sorry to repeat myself, like, again.

    But there is a point. Today represents an improvement on yesterday’s arrangements for dynamic playlist creation regarding our Tabular Single Row Media Gallery web application via the playlist emoji button 🔀 click/tap or on the web browser command line. With yesterday’s scenario, had you entered as your internal playlist comma separated string …

    Born to Run,Born to Run,Born to Run,Born to Run

    … without the …

    Burp …

    that is you’d have ended up with the top find off a YouTube search repeated 4 times. Is this ideal? We asked Nala and Luna but, unfortunately they were busy, so they left me with the decision, and we came up with …

    That’s kind of silly.

    For these few reasons …

    • variety
    • album style Radio Play listening possibilities
    • perhaps getting around that …

      This video requires payment to watch YouTube

      … issue we talked about before … because you could uncheck it’s checkbox if the error appears

    • giving non-top search items a go

    … we decided to “mix it up” regarding entries like …

    Born to Run,Born to Run,Born to Run,Born to Run

    … as well as the simpler …

    Born to Run*4

    … so that repeats don’t cause users indigestion … chortle, chortle.

    Here’s the Javascript turning Born to Run*4 into Born to Run,Born to Run,Born to Run,Born to Run


    function expandrepeats(ocsl) {
    var numnum=0, minone=-1, interesting='', ninteresting='', pinteresting='', superinteresting='', imn=1;
    var retocsl=ocsl;
    var acarr=ocsl.split(',');
    for (var iac=0; iac<acarr.length; iac++) {
    numnum=0;
    minone=-1;
    if (acarr[iac].trim() != '') {
    if (acarr[iac].trim().slice(-1) >= '0' && acarr[iac].trim().slice(-1) <= '9') {
    while (('S' + acarr[iac].trim()).slice(minone).substring(0,1) >= '0' && ('S' + acarr[iac].trim()).slice(minone).substring(0,1) <= '9') {
    numnum++;
    minone--;
    }
    }
    if (numnum > 0 && numnum < eval('' + acarr[iac].trim().length)) {
    ninteresting=acarr[iac].trim().slice(-numnum);
    interesting=acarr[iac].trim().substring(0, eval(-numnum + eval('' + acarr[iac].trim().length)));
    superinteresting='';
    pinteresting='';
    if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ x\ $/g,'')) {
    pinteresting=interesting.slice(-3) + ninteresting;
    superinteresting=interesting.replace(/\ x\ $/g,'').replace(/\ X\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/x\ $/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/x\ $/g,'').replace(/X\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ x$/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\ x$/g,'').replace(/\ X$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/x$/g,'')) {
    pinteresting=interesting.slice(-1) + ninteresting;
    superinteresting=interesting.replace(/x$/g,'').replace(/X$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ \*\ $/g,'')) {
    pinteresting=interesting.slice(-3) + ninteresting;
    superinteresting=interesting.replace(/\ \*\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\*\ $/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\*\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ \*$/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\ \*$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\*$/g,'')) {
    pinteresting=interesting.slice(-1) + ninteresting;
    superinteresting=interesting.replace(/\*$/g,'');
    }
    if (superinteresting != '' && eval('' + ninteresting) >= 1) {
    for (imn=1; imn<=eval('' + ninteresting); imn++) {
    if (imn == 1) {
    retocsl=retocsl.replace(pinteresting, '');
    acarr[iac]=acarr[iac].replace(pinteresting, '');
    } else {
    retocsl=retocsl.replace(acarr[iac], acarr[iac] + ',' + superinteresting.trim());
    }
    }
    }
    }
    }
    }
    if (retocsl != ocsl) { outplist=retocsl; }
    return retocsl;
    }

    … in the changed swipe_media.html Tabular Single Row Media Gallery web application you can try for yourself (or try some more of The Boss), further to yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial.


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial

    Don’t know if you are like me, but especially when on this MacBook Air we’re, forever, using a web browser address bar to type in, what we’ve set up as, a Google search engine webpage query. Rather than even going to Google webpage first, that is!

    Most people don’t want to know about arcane web application argument arrangements … though we’re very fond of the 5 minute ones?!

    What’s wrong with some of you? Who would not relish the thought of …

    • adding onto the address bar …

      https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html

      … with new arguments( eg. https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html Born to Run,Jungleland ) …
    • ?ask=y # will get you straight to the Javascript playlist prompt window
    • &or?thelist=[commaSeparatedList_encodeURIComponent_ized] # will supply that prompt window with the answer [commaSeparatedList_decodeURIComponent_ized]
    • &or?andgo=y # will click the Radio button after all above (unless notgo is mentioned in the list somewhere), as relevant, with the programmatically determined derived YouTube ID list via YouTube search(es)
    • 💬🦆 Come On!
    • … when, after a bit of thought and tweaks to our RJM Programming domain’s Apache Document Root residing 404.shtml webpage Javascript …

      if (document.URL.indexOf('rjmprogramming.com.au/HTMLCSS/swipe_media.htm') != -1) {
      if (decodeURIComponent(document.URL).indexOf(',') != -1) {
      if (decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'')).toLowerCase().indexOf('notgo') != -1) {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?thelist=' + encodeURIComponent(decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace('notgo','').replace('NOTGO','').replace('Notgo','')));
      } else {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?andgo=y&thelist=' + encodeURIComponent(decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')));
      exit;
      }
      } else if (decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'')).toLowerCase().indexOf('ask') != -1) {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?ask=y';
      exit;
      }
      }

      … now all you need to add after that link above, on the web browser address bar is …

      [commaSeparatedList_decodeURIComponent_ized]

      … ie. just type a comma separated YouTube song search basis link after the link wording above
    • so 💬🦆 Come On down ye doubting Thomases!

    And so, further to yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial we have a changed swipe_media.html Tabular Single Row Media Gallery web application you can try for yourself.

    Stop Press

    On reflection, as well as …

    https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html Born to Run,Jungleland working up at the address bar, so, too, will https://www.rjmprogramming.com.au/ Born to Run,Jungleland


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial

    Around here, regarding web application work, we really like dropdown (ie. HTML select element) work because a lot of information can be …

    • stored
    • displayed (often taking up minimal webpage space)
    • it’s option subelements can have an event life of their own, or be part of the select element event whole picture
    • dropdown multiple selection mode (as with today’s work) can …
      1. still support your single choice scenario
      2. we’ve coded today’s dropdown to support, as applicable, ordered single click choices … versus …
      3. can allow for control key (sets of choices not necessarily adjacent) and shift key (blocks of choices)
      4. can respond (as with today’s dropdown) to preset selections established at creation via dropdown (ie. select) innerHTML option subelement selected attribute setting
    • dropdown events onmousedown and ontouchdown (as for today’s dropdown) and onclick can be harnessed ahead of an onchange event … and in today’s case can help unset any preset option subelement selected attribute setting(s)

    Just so flexible! Subelement option CSS styling can be less friendly, but even so, often background colouring is possible, and we do a bit of that with the work from yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Tutorial and today’s better “shored up” work you can see a bit of below (where your starting point might be that we “wrap” this particular Javascript prompt window through the Javascript overprompt function below) …


    var outplist='', kaconto=null, kacontoarr=[], rconeis=155, gconeis=255, bconeis=255;

    function overprompt(blb, defvl) {
    var tdsare=[], itdone=false, itds=0, baeis='', ivb=0, lastpassesmustard=true;
    var oklast=['A','E','I','M','Q','U','Y','c','g','k','o','s','w','0','4','8'];
    outplist=prompt(blb, defvl);
    if (outplist) {
    //alert(1);
    var outparrs=outplist.trim().split(',');
    //alert(11);
    if (eval('' + outparrs.length) > 1) {
    if (eval('' + outparrs[0].length) > 0) {
    if (oklast.indexOf(outparrs[0].slice(-1)) == -1) { lastpassesmustard=false; }
    }
    if ((outparrs[0] + baeis).replace(/\ \ \ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20%20%20';
    outparrs[0]=outparrs[0].replace(/\ \ \ $/g,'');
    } else if ((outparrs[0] + baeis).replace(/\ \ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20%20';
    outparrs[0]=outparrs[0].replace(/\ \ $/g,'');
    } else if ((outparrs[0] + baeis).replace(/\ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20';
    outparrs[0]=outparrs[0].replace(/\ $/g,'');
    } else {
    baeis='';
    }
    //alert(111);
    if (eval('' + outparrs[0].length) != 11 || !lastpassesmustard || encodeURIComponent(outparrs[0]) != outparrs[0]) {
    //alert(1111);
    tdsare=document.getElementsByTagName('td');
    for (itds=0; itds<tdsare.length; itds++) {
    //alert(tdsare[itds].innerHTML);
    if (!itdone && tdsare[itds].innerHTML == '' && ('' + tdsare[itds].id) != 'td0001') {
    itdone=true;
    //alert('here ' + outplist.trim().replace(/\,/g,'|!!|'));
    //tdsare[itds].innerHTML='<iframe onload=karlook(this); style="width:100%;height:100%;" id=karsearch name=karsearch src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outplist.trim().replace(/\,/g,'|!!|')) + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    tdsare[itds].innerHTML='<iframe onload=karlook(this); style="width:100%;height:80%;" id=karsearch name=karsearch src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outparrs[0]) + baeis + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    tdsare[itds].scrollIntoView();
    //alert('there ' + outplist.trim().replace(/\,/g,'|!!|'));
    baeis='';
    kacontoarr=[];
    for (ivb=1; ivb<outparrs.length; ivb++) {
    kacontoarr.push(null);
    }
    for (ivb=1; ivb<outparrs.length; ivb++) {
    tdsare[eval(itds + ivb)].innerHTML='<iframe onload=karlookagain(this,' + eval(-1 + ivb) + '); style="width:100%;height:80%;visibility:hidden;" id=karsearch' + ivb + ' src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outparrs[ivb]) + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    }
    return '';
    }
    }
    }
    }
    }
    return outplist;
    }

    function karlook(iois) {
    var aconto=null;
    aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    if (outplist.indexOf(',') != -1) {
    kaconto=aconto;
    setTimeout(function(){ kaconto.getElementById('ajaxs').style.cursor='progress'; }, 3000);
    setTimeout(postkarlook, 7000);
    } else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    kaconto=aconto;
    setTimeout(mpostkarlook, 7000);
    }
    }
    }
    }

    function karlookagain(iois,idxn) {
    var aconto=null;
    aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    if (eval('' + kacontoarr.length) > eval('' + idxn)) {
    kacontoarr[eval('' + idxn)]=aconto;
    } else {
    kacontoarr.push(aconto);
    }
    }
    }
    }

    function mpostkarlook() {
    if (kaconto.getElementById('ajaxs')) {
    var kbuts=kaconto.getElementsByTagName('input');
    for (var lbuts=0; lbuts<kbuts.length; lbuts++) {
    if (('' + kbuts[lbuts].type) == 'button') {
    if (('' + kbuts[lbuts].value).indexOf('Radio') == 0) {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', String.fromCharCode(10) + 'Radio');
    }
    }
    }
    } else {
    setTimeout(mpostkarlook, 5000);
    }
    }

    function postkarlook() {
    var selectedones='', oktogo=true, hihi=0;
    if (kaconto.getElementById('ajaxs')) {
    //alert(kaconto.getElementById('ajaxs').innerHTML);
    for (hihi=0; hihi<kacontoarr.length; hihi++) {
    if (!kacontoarr[hihi]) {
    oktogo=false;
    //alert('hihi=' + hihi + ' NOT okay');
    } else if (!kacontoarr[hihi].getElementById('ajaxs')) {
    oktogo=false;
    //alert('hihi=' + hihi + ' not okay');
    }
    }
    if (!oktogo) {
    setTimeout(postkarlook, 5000);
    } else if (kaconto.getElementById('ajaxs').innerHTML.indexOf('... and then ...') == -1) {
    kaconto.getElementById('ajaxs').style.cursor='pointer';
    var otherps=baeisf();
    if (otherps != '' || navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    var kbuts=kaconto.getElementsByTagName('input');
    for (var lbuts=0; lbuts<kbuts.length; lbuts++) {
    if (('' + kbuts[lbuts].type) == 'button') {
    if (('' + kbuts[lbuts].value).indexOf('Radio') == 0) {
    var wasvl=kbuts[lbuts].value;
    if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Ordered ' + String.fromCharCode(10) + 'Audio ' + String.fromCharCode(10) + 'Radio');
    } else if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Audio ' + String.fromCharCode(10) + 'Radio');
    } else if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Ordered ' + String.fromCharCode(10) + 'Radio');
    } else {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', String.fromCharCode(10) + 'Radio');
    }
    }
    }
    }
    }
    selectedones=(kaconto.getElementById('ajaxs').innerHTML.split(kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].split('</option>')[0] + '</option>').replace('>', ' class=uptop selected>');
    for (hihi=0; hihi<kacontoarr.length; hihi++) {
    if (rconeis == gconeis && rconeis == bconeis) {
    bconeis-=7;
    if (bconeis < 0) { bconeis+=255; }
    } else if (rconeis == gconeis) {
    gconeis-=7;
    if (gconeis < 0) { gconeis+=255; }
    } else {
    rconeis-=7;
    if (rconeis < 0) { rconeis+=255; }
    }
    selectedones+=((kacontoarr[hihi].getElementById('ajaxs').innerHTML.split(kacontoarr[hihi].getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].split('</option>')[0] + '</option>').replace('>', ' class=uptop selected>')).replace(/option\ onclick\=/g, 'option style=background-color:rgb(' + rconeis + ',' + gconeis + ',' + bconeis + '); onclick=');
    kaconto.getElementById('ajaxs').innerHTML+='<option value="">... and then ...</option>';
    kaconto.getElementById('ajaxs').innerHTML+=kacontoarr[hihi].getElementById('ajaxs').innerHTML.split(kacontoarr[hihi].getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].replace(/option\ onclick\=/g, 'option style=background-color:rgb(' + rconeis + ',' + gconeis + ',' + bconeis + '); onclick=');
    //alert(kacontoarr[hihi].getElementById('ajaxs').innerHTML);
    }
    //alert(selectedones);
    kaconto.getElementById('ajaxs').innerHTML=kaconto.getElementById('ajaxs').innerHTML.replace(kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>', kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>' + selectedones + (selectedones != '' ? '<option id=optclk value="">____ Selection above available (resettable via click here) as you click/tap button at right ____</option>' : ''));
    if (selectedones != '') {
    kaconto.getElementById('ajaxs').onmousedown=function(event){ if (event.target.parentNode.outerHTML.split('>')[0].indexOf(' data-flagged=') == -1) { event.target.parentNode.setAttribute('data-flagged','y'); event.target.parentNode.innerHTML=event.target.parentNode.innerHTML.replace(/\ selected/g, ' ').replace('____ Selection above available (resettable via click here) as you click/tap button at right ____','____ Please select choices in usual multiple choice dropdown ways ____'); } };
    kaconto.getElementById('ajaxs').ontouchdown=function(event){ if (event.target.parentNode.outerHTML.split('>')[0].indexOf(' data-flagged=') == -1) { event.target.parentNode.setAttribute('data-flagged','y'); event.target.parentNode.innerHTML=event.target.parentNode.innerHTML.replace(/\ selected/g, ' ').replace('____ Selection above available (resettable via click here) as you click/tap button at right ____','____ Please select choices in usual multiple choice dropdown ways ____'); } };
    }
    }
    }
    }

    function baeisf() {
    var outarrp=outplist.split(',');
    if (eval('' + outarrp.length) > 1) {
    return outarrp[0].replace(outarrp[0].trim(), '');
    }
    return '';
    }

    And so, today …

    • we add onto the default random ordering mode of Radio Play via YouTube search comma separated list, the further choices ordered or audio or audio ordered, as per the relevant Javascript prompt blurb that is now going …

      Enter YouTube 11 character code video (comma separated) or audio stream only of video (semicolon) list to Radio Play (and add ! to start in shuffle mode and/or # for the order you enter and/or & for whole list) … or a YouTube Search String basis for playlist via a Radio📻? button to activate, later. Comma separateds can be search ideas … egs. Tragedy,Boogie Wonderland,Down Among the Dead Men … random … Tragedy ,Imagine,Breezin … ordered … Tragedy  ,Pina Colada Song,Fast Car … audio … Tragedy   ,Galveston,Angel of the Morning … audio ordered. Double click on this cell for playlist redefinitions.

    • started allowing for dropdown events onmousedown and ontouchdown be able to reset the preset choices we programmatically select for the user should they be happy (but our motivation for this event work was the potential to run into a YouTube video that gives the error …

      This video requires payment to watch YouTube

      )

    Codewise, this involved …

    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

YouTube API iOS Shower Song Subset Looping Tutorial

YouTube API iOS Shower Song Subset Looping Tutorial

YouTube API iOS Shower Song Subset Looping Tutorial

You’d think we’d be done with ablutions at this blog, but ingen måte … Luna (aka Måne) says … there’s all manner of molekylær interesse out there in and out of the fjords …

It’s not just H and the 2 and the O … it’s the art of the rollerulle.

… or so says “The Lu” (aka “Toalettet”) anyway!

Today’s Shower Songs tweak involves it’s “individual song looping” thinking. It occurred to us, that it’s use by a user might be what they want, it becomes a bit inflexible should they either …

  • want to “move on” to a new song … via …
  • add to an “individual song looping subset” with another “individual looping song” … and it also serves another “arcane usage” to our mind, we explain below …
  • out and about using a laptop lassooed to a mobile (or just the mobile itself) using mobile data (rather than Wi-Fi) this web browser Shower Songs web application depends on a connection as a song starts and if you have run out of never before tapped buttons to choose from (and the web application has lost it’s connection) it can become an impotent web application, sometimes, so that to add to the web applications’s possibilities of button tapping, and often reawakening it, the better, we figure

And so, moving on from yesterday’s YouTube API iOS Shortcuts Shower Song Tutorial code that changed involved …


Previous relevant YouTube API iOS Shortcuts Shower Song Tutorial is shown below.

YouTube API iOS Shortcuts Shower Song Tutorial

YouTube API iOS Shortcuts Shower Song Tutorial

Yesterday’s non-mobile YouTube API Command Line Shower Song Names Tutorial based work begs the question, for us …

At least, on “mobile” iOS (which we have access to) can any “command line” feel of playlists ending up at our Shower Songs web application be arranged?

Pretty pithy, huh?! Before we launch into the great iOS Shortcuts app (we’ve talked about before at Shortcuts iOS App Email Arrival Sounds Tutorial) helping here, let’s outline some other simpler ideas you might want to try yourself in the DIY range of ideas …

  • open one of these inhouse Radio Play (YouTube API song playlist and sequencing and loop supporting changed for today’s work swipe_media.html Tabular Single Row Media Gallery or Shower Songs) web applications on a web browser on an iOS device (eg. iPhone or iPad) … and at the juncture where your desired playlist is implemented … use Share icon menu of choices to …
    1. Add to Home Screen … with a tailored (Playlist) Title … this being our preferred option to future proof the remembering … but also available is …
    2. Add Bookmark … or …
    3. Add Favourite
    4. Make your web browser’s opening Home Page be a URL of interest (like one of these playlists) within that web browser app’s Settings area
  • as well as the Shower Songs (as well as Tabular Single Row Media Gallery) web application (with Playlists of 7) can have a dropdown be populated ready to choose and replay that Playlist (that can be email or SMS shared with a recipient)

Okay, all that being said, the great Shortcuts iOS app can serve two purposes a bit “above and beyond this” …

  1. you can DIY build an iOS feeling and “hybrid looking” amalgum of iOS and “old days” dialog box “desktop feeling” personalized application(s) …
  2. the act of constructing any one is sure to inspire other iOS automation ideas you might have

We’re sure lots of you more aux fait with the great iOS Shortcuts app can do better than the “bit kludgy” effort we came up with, and that is the joy of programming, huh?! It can come down to …

  • what you think is the most efficient …
  • you feel you can handle … and …
  • end up with a better automated solution … but …
  • it’s not “all about efficiency” always … it’s also learning about new methodologies you might have to spend more time discovering the ins and outs about

As a case in point, it will be hard to stop yours truly just (iOS mobile) opening the relevant Radio Play web application in a web browser, and going from there (with Bookmarks and Favourites), but there you go?! In this case, perhaps yes, but you should see all the other Messaging and automation possibilities that a peruse of the iOS Shortcuts app can open up to you!

Todays’ animated GIF presentation shows our endeavours “warts and all” (latching onto, intervention wise, when a user taps the Music mobile app icon) for your perusal.


Previous relevant YouTube API Command Line Shower Song Names Tutorial is shown below.

YouTube API Command Line Shower Song Names Tutorial

YouTube API Command Line Shower Song Names Tutorial

Yesterday’s YouTube API Command Line Shower Songs Tutorial‘s Operating System command line modes of access brought us to another issue.

Can a list of seven non-YouTube-ID comma separated values (ie. YouTube song search basis strings) be entered and still end up at the Shower Songs web application?

Well, yes, that’s possible if an intervention point can be arranged. After all, the command line prompt goes …

Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist … 7 for Shower Songs … egs. Tragedy,Boogie Wonderland,Down Among the Dead Men … random … Tragedy ,Imagine*3,Breezin … ordered 5 … Tragedy ,Pina Colada Son,Fast Car … audio … Tragedy ,Galveston,Fix You … audio ordered, and go.

… begging the question “What happens if we enter, at the command line …”


play
Tragedy ,Pina Colada Song,Fast Car,Breezin,Galveston,Fix You,Imagine

… ? Well, after our “better interfacing changes” to the swipe_media.html Tabular Single Row Media Gallery web application changes …


var ytlistis=location.search.split('youtube=')[1] ? anotherdecodeURIComponent(location.search.split('youtube=')[1].split('&')[0]) : '';


function anotherdecodeURIComponent(inplis) {
var thisplist=decodeURIComponent(inplis);


if (eval((thisplist + ',').replace(/[AEIMQUYcgkosw048]\,/g,'z').length) == 77 && eval(('' + thisplist).length) == 83 && eval(('' + encodeURIComponent(thisplist.replace(/\,/g,''))).length) == 77 && eval(('' + thisplist.split(',').length)) == 7) {
window.open('//www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=' + thisplist.trim(),'_blank','top=50,left=' + eval(-800 + screen.width) + ',width=800,height=800');
}

return thisplist;
}

… which mapped to URL …


https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=OiwDHHcHPh0,FXG_I_tf_i4,AIOAlaACuv4,G1QjyskJ9jw,HhKZLhxFFUY,k4V3Mo61fJM,MBIyH4WhOWg

… and that’s where “our fun” (chortle, chortle) began (yeh, right … after a Goose Chase with it being the seventh one) because that seventh YouTube video ID (involved with YouTube “Imagine” search (and something about this rings a bell)) comes back with …

This content can’t be played on your mobile browser. Get the YouTube app to start watching.

Ouch?! What to do? Looking optimistically on this, it’s good to discover it now (yeh, right).

Anyway, we mapped such unplayables to Nothing’s Gonna Stop Us Now – Starship – 1987 in …

… as our means to a solution.


Previous relevant YouTube API Command Line Shower Songs Tutorial is shown below.

YouTube API Command Line Shower Songs Tutorial

YouTube API Command Line Shower Songs Tutorial

Today, we’re combining the concepts behind …

  • the recent YouTube API Caller Radio Play Doctype Meta Tutorial‘s means by which …
    1. macOS
    2. Windows

    … command line “command verb” …

    play

    … can call our “Radio Play” YouTube API interfacing means to play music …

    • sequentially
    • continuously looping (through a set of songs) or just the one song looping

    … adding into those previous arrangements the capability to call the Shower Songs web application under conditions we outlined in …

  • the work of the day before yesterday’s Shower Songs Delimitation Hashtag Tutorial

… involving changed

  1. macOS (building on the changed play.sh shell script)

    #!/bin/bash
    rest=""
    if [ -z "$1" ]; then
    echo "Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... 7 such uses Shower Songs ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men flash ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Song,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go."
    read ans
    else
    preans="$1"
    ans="$1 $2 $3 $4 $5 $6 $7 $8 $9"
    while [ ! -z "$9" ]; do
    shift
    rest="${rest} $9"
    done
    ans="$ans${rest}"
    fi
    if [ ! -z "$ans" ]; then
    commas_only="${ans//[^,]}"
    if [ "${#preans}" == "83" ]; then
    if [ "${#commas_only}" == "6" ]; then
    open "https://www.rjmprogramming.com.au/$1"
    else
    open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
    fi
    else

    open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
    fi
    fi
    exit
  2. Windows (building on the changed play.bat script)

    @echo off
    rem play.bat
    rem RJM Programming
    rem November, 2025

    set passed=
    set rest=
    set seven=0

    if trick==trick%1 (
    set /p ans=Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... 7 for Shower Songs ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Son,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go.
    set ansplus="%ans% "

    if "%ansplus:~12,1%"=="," (
    if "%ansplus:~24,1%"=="," (
    if "%ansplus:~36,1%"=="," (
    if "%ansplus:~48,1%"=="," (
    if "%ansplus:~60,1%"=="," (
    if "%ansplus:~72,1%"=="," (
    if "%ansplus:~84,1%"==" " (
    set seven=7
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=%ans%"
    goto :end
    ) else (
    set seven=6
    )
    ) else (
    set seven=5
    )
    ) else (
    set seven=4
    )
    ) else (
    set seven=3
    )
    ) else (
    set seven=2
    )
    ) else (
    set seven=1
    )
    ) else (
    set seven=0
    )


    ) else (
    set ans="%1"

    set ansplus="%1,%2,%3,%4,%5,%6,%7 %8 "

    if "%ansplus:~12,1%"=="," (
    if "%ansplus:~24,1%"=="," (
    if "%ansplus:~36,1%"=="," (
    if "%ansplus:~48,1%"=="," (
    if "%ansplus:~60,1%"=="," (
    if "%ansplus:~72,1%"=="," (
    if trick==trick%8 (
    set seven=7
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=%1,%2,%3,%4,%5,%6,%7"
    goto :end
    ) else (
    set seven=6
    )
    ) else (
    set seven=5
    )
    ) else (
    set seven=4
    )
    ) else (
    set seven=3
    )
    ) else (
    set seven=2
    )
    ) else (
    set seven=1
    )
    ) else (
    set seven=0
    )


    set passed=yes
    if trick==trick%2 goto :loop
    set ans="%ans%,%2"
    if trick==trick%3 goto :loop
    set ans="%ans%,%3"
    if trick==trick%4 goto :loop
    set ans="%ans%,%4"
    if trick==trick%5 goto :loop
    set ans="%ans%,%5"
    if trick==trick%6 goto :loop
    set ans="%ans%,%6"
    if trick==trick%7 goto :loop
    set ans="%ans%,%7"
    if trick==trick%8 goto :loop
    set ans="%ans%,%8"
    if trick==trick%9 goto :loop
    set ans="%ans%,%9"
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans:"=%"
    :loop
    if "%9"=="" (
    @echo off
    ) else (
    shift
    set rest="%rest% %9"
    goto :loop
    )
    set ans="%ans%%rest%"
    set ans=%ans:"=%
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
    )
    if trick==trick%passed% (
    set ans=%ans:"=%
    if "%ans:,=%"=="%ans%" (
    echo "Nothing to do."
    ) else (
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
    )
    )
    rem exit
    :end

… and involving, if you are on macOS or Windows implementing accordingly …

… a command line …


play FtE3hoR_Nvo,W5IKT_xue4o,IfaGhyK78E8,BuN3yCmHb_U,TdiAwCPb_As,euZcUku9XiE,aMs0rNtBZJk

… can loop and continuously play through that list of seven YouTube video IDs via a web browser use of our Shower Songs web application.


Previous relevant YouTube API Caller Radio Play Doctype Meta Tutorial is shown below.

YouTube API Caller Radio Play Doctype Meta Tutorial

YouTube API Caller Radio Play Doctype Meta Tutorial

It took a session on this MacBook Air’s macOS Firefox web browser trying the Tabular Single Row Media Gallery web application to emphasise the importance of more consistency checking on …

  • doctype HTML tagdeclaration …

    <!DOCTYPE html>

    … and …
  • meta HTML display tagcharset attribute …

    <meta charset="UTF-8">

… existence in web applications we create, to the point that not having the second one defined was stopping proper webpage display on Firefox. Was this a portent of what is to come soon on more web browsers?!

Let’s look at the purpose of these two HTML tagthingos …

  • doctype HTML tagdeclaration

    All HTML documents must start with a declaration.

    The declaration is not an HTML tag. It is an “information” to the browser about what document type to expect.

    … and …

  • meta HTML display tagcharset attribute

    The charset attribute specifies the character encoding for the HTML document.

    The HTML5 specification encourages web developers to use the UTF-8 character set, which covers almost all of the characters and symbols in the world!

Regarding the same web application as yesterday’s YouTube API Caller Radio Play Playlist Windows Local System Tutorial talked about, why not revisit the tweaked swipe_media.html Tabular Single Row Media Gallery web application?


Previous relevant YouTube API Caller Radio Play Playlist Windows Local System Tutorial is shown below.

YouTube API Caller Radio Play Playlist Windows Local System Tutorial

YouTube API Caller Radio Play Playlist Windows Local System Tutorial

Further to the recent YouTube API Caller Radio Play Playlist Local System Tutorial macOS local system discussion, today, we code for …

play

… to mean something on the …

Windows

… “cmd” command accessible …

command line

What’s the scripting here? They are called batch files with extension *.bat we’re calling play.bat (going back to the DOS days of the ’70’s again). With *.bat you just need to plonk your play.bat anywhere within the Windows local system path, and the word (now command) “play” will do the rest anywhere in that user’s command line environment. And the batch file has …


@echo off
rem play.bat
rem RJM Programming
rem November, 2025

set passed=
set rest=

if trick==trick%1 (
set /p ans=Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Son,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go.
) else (
set ans="%1"
set passed=yes
if trick==trick%2 goto :loop
set ans="%ans%,%2"
if trick==trick%3 goto :loop
set ans="%ans%,%3"
if trick==trick%4 goto :loop
set ans="%ans%,%4"
if trick==trick%5 goto :loop
set ans="%ans%,%5"
if trick==trick%6 goto :loop
set ans="%ans%,%6"
if trick==trick%7 goto :loop
set ans="%ans%,%7"
if trick==trick%8 goto :loop
set ans="%ans%,%8"
if trick==trick%9 goto :loop
set ans="%ans%,%9"
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans:"=%"
:loop
if "%9"=="" (
@echo off
) else (
shift
set rest="%rest%,%9"
goto :loop
)
set ans="%ans%%rest%"
set ans=%ans:"=%
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
if trick==trick%passed% (
set ans=%ans:"=%
if "%ans:,=%"=="%ans%" (
echo "Nothing to do."
) else (
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
)
rem exit
:end

… as your starting gambit, here, where the equivalent of macOS’s “open” is “explorer.exe” on Windows (ie. the File Explorer) … almost as cute!


Previous relevant YouTube API Caller Radio Play Playlist Local System Tutorial is shown below.

YouTube API Caller Radio Play Playlist Local System Tutorial

YouTube API Caller Radio Play Playlist Local System Tutorial

The ..

command line

… of a laptop or notebook or personal computer can be an environment to relax from the GUI aspects of your modern operating systems and think about …

  • processes
  • batch driven tasks
  • task simplifications

… and in the category of that last one, on our local macOS operating system we envisaged a day we could slip back to the “quiet world” of the “command line” and type a command like …


play Tragedy,Imagine,Down Among the Dead Men PAN -

… and get somewhere playing those songs through a web browser accessing the YouTube API and our interfacings to it in webpage software form, playing in a continuous Radio Play style.

You see, with all the distractions, only having to remember …

play

… no matter where we were in “command line” woooorrrrllllddd seemed the ideal, and yes, it’s possible. However, we think explaining …


bash /Applications/MAMP/htdocs/play.ksh Tragedy,Imagine,Down Among the Dead Men PAN -

… is a necessary dividing line between two parts to the discussion. So what’s bash? It’s the shell we associate as your macOS default shell (we get to via the “out of the box” macOS desktop application called Terminal) … well, it used to be … anyway, the first line of (what started as play.ksh then play.sh and then eventually, just, play … as a filename that is) …


#!/bin/bash
rest=""
if [ -z "$1" ]; then
echo "Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Song,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go."
read ans
else
ans="$1 $2 $3 $4 $5 $6 $7 $8 $9"
while [ ! -z "$9" ]; do
shift
rest="${rest} $9"
done
ans="$ans${rest}"
fi
if [ ! -z "$ans" ]; then
open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
fi
exit

… tells the local system use the bash shell to interpret this what you might like to think of as an executable script (which we went chmod 777 play regarding to make it so).

Okay, so we wrote this script in /Applications/MAMP/htdocs/ and that …


bash /Applications/MAMP/htdocs/play Tragedy,Imagine,Down Among the Dead Men PAN -

… could swing it at this stage, or even being in /Applications/MAMP/htdocs/ and going …


./play Tragedy,Imagine,Down Among the Dead Men PAN -

… but (even in /Applications/MAMP/htdocs/) …


play Tragedy,Imagine,Down Among the Dead Men PAN -

… is most likely to reply something like …

zsh: no such command

As the programmer, perhaps you could leave it at that with your “insider knowledge”, or if “play” as a command already meant something (a test that would be good to do before any such proposed work), otherwise … do you really think you’ll remember next Wednesday? So …

  1. enter into the wooooorrrrllllddd of aliases (thanks to this great advice, thanks) … eg.

    alias play="/Applications/MAMP/htdocs/play"
  2. placed into …

    ~/.bashrc

    … via (in our case) …

    vi ~/.bashrc
  3. then …

    source ~/.bashrc

    … needs to be included into the login procedure of …

    ~/.profile

    …via (in our case) …

    vi ~/.profile
  4. to make …

    play

    … as the interactively asking alternative to the argumentative example of …

    play Tragedy,Imagine,Down Among the Dead Men PAN -

    … mean something … and anywhere

    … all of this possible because of the brilliantly useful macOS (not Linux nor unix) …


    open

    … opener of web browsers from the command line blowing of our tiny little rather still naive mind … mind you, VAX/VMS “phone” command from the ’70’s might have even been better?! And then there were those punch cards … in the hopper … and if you got a character wrong … back to the end of the queue.

    Sorry … we got a bit hot and bothered there!

    Anyway, as a layer of thought on top of the recent YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial‘s mildly changed swipe_media.html Tabular Single Row Media Gallery web application work it might be a thing you want to pursue yourself?

    By the way, this brought into play for us what your default web browser is. Ours is Safari yet we develop more on Google Chrome. Safari, for us, does more Popup Blocking, and it is a thing to look out for should a window not open when expected (and these command line methodologies don’t get past you still having to unmute and/or click/tap once before the Radio Play mode of play kicks off). To undo the Popup Block there will probably be a means to do this to the right of the web browser address bar.


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial

    Burp …

    Sorry to open with a quote, and sorry to repeat myself, like.

    And sorry to repeat myself, like, again.

    But there is a point. Today represents an improvement on yesterday’s arrangements for dynamic playlist creation regarding our Tabular Single Row Media Gallery web application via the playlist emoji button 🔀 click/tap or on the web browser command line. With yesterday’s scenario, had you entered as your internal playlist comma separated string …

    Born to Run,Born to Run,Born to Run,Born to Run

    … without the …

    Burp …

    that is you’d have ended up with the top find off a YouTube search repeated 4 times. Is this ideal? We asked Nala and Luna but, unfortunately they were busy, so they left me with the decision, and we came up with …

    That’s kind of silly.

    For these few reasons …

    • variety
    • album style Radio Play listening possibilities
    • perhaps getting around that …

      This video requires payment to watch YouTube

      … issue we talked about before … because you could uncheck it’s checkbox if the error appears

    • giving non-top search items a go

    … we decided to “mix it up” regarding entries like …

    Born to Run,Born to Run,Born to Run,Born to Run

    … as well as the simpler …

    Born to Run*4

    … so that repeats don’t cause users indigestion … chortle, chortle.

    Here’s the Javascript turning Born to Run*4 into Born to Run,Born to Run,Born to Run,Born to Run


    function expandrepeats(ocsl) {
    var numnum=0, minone=-1, interesting='', ninteresting='', pinteresting='', superinteresting='', imn=1;
    var retocsl=ocsl;
    var acarr=ocsl.split(',');
    for (var iac=0; iac<acarr.length; iac++) {
    numnum=0;
    minone=-1;
    if (acarr[iac].trim() != '') {
    if (acarr[iac].trim().slice(-1) >= '0' && acarr[iac].trim().slice(-1) <= '9') {
    while (('S' + acarr[iac].trim()).slice(minone).substring(0,1) >= '0' && ('S' + acarr[iac].trim()).slice(minone).substring(0,1) <= '9') {
    numnum++;
    minone--;
    }
    }
    if (numnum > 0 && numnum < eval('' + acarr[iac].trim().length)) {
    ninteresting=acarr[iac].trim().slice(-numnum);
    interesting=acarr[iac].trim().substring(0, eval(-numnum + eval('' + acarr[iac].trim().length)));
    superinteresting='';
    pinteresting='';
    if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ x\ $/g,'')) {
    pinteresting=interesting.slice(-3) + ninteresting;
    superinteresting=interesting.replace(/\ x\ $/g,'').replace(/\ X\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/x\ $/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/x\ $/g,'').replace(/X\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ x$/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\ x$/g,'').replace(/\ X$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/x$/g,'')) {
    pinteresting=interesting.slice(-1) + ninteresting;
    superinteresting=interesting.replace(/x$/g,'').replace(/X$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ \*\ $/g,'')) {
    pinteresting=interesting.slice(-3) + ninteresting;
    superinteresting=interesting.replace(/\ \*\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\*\ $/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\*\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ \*$/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\ \*$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\*$/g,'')) {
    pinteresting=interesting.slice(-1) + ninteresting;
    superinteresting=interesting.replace(/\*$/g,'');
    }
    if (superinteresting != '' && eval('' + ninteresting) >= 1) {
    for (imn=1; imn<=eval('' + ninteresting); imn++) {
    if (imn == 1) {
    retocsl=retocsl.replace(pinteresting, '');
    acarr[iac]=acarr[iac].replace(pinteresting, '');
    } else {
    retocsl=retocsl.replace(acarr[iac], acarr[iac] + ',' + superinteresting.trim());
    }
    }
    }
    }
    }
    }
    if (retocsl != ocsl) { outplist=retocsl; }
    return retocsl;
    }

    … in the changed swipe_media.html Tabular Single Row Media Gallery web application you can try for yourself (or try some more of The Boss), further to yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial.


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial

    Don’t know if you are like me, but especially when on this MacBook Air we’re, forever, using a web browser address bar to type in, what we’ve set up as, a Google search engine webpage query. Rather than even going to Google webpage first, that is!

    Most people don’t want to know about arcane web application argument arrangements … though we’re very fond of the 5 minute ones?!

    What’s wrong with some of you? Who would not relish the thought of …

    • adding onto the address bar …

      https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html

      … with new arguments( eg. https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html Born to Run,Jungleland ) …
    • ?ask=y # will get you straight to the Javascript playlist prompt window
    • &or?thelist=[commaSeparatedList_encodeURIComponent_ized] # will supply that prompt window with the answer [commaSeparatedList_decodeURIComponent_ized]
    • &or?andgo=y # will click the Radio button after all above (unless notgo is mentioned in the list somewhere), as relevant, with the programmatically determined derived YouTube ID list via YouTube search(es)
    • 💬🦆 Come On!
    • … when, after a bit of thought and tweaks to our RJM Programming domain’s Apache Document Root residing 404.shtml webpage Javascript …

      if (document.URL.indexOf('rjmprogramming.com.au/HTMLCSS/swipe_media.htm') != -1) {
      if (decodeURIComponent(document.URL).indexOf(',') != -1) {
      if (decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'')).toLowerCase().indexOf('notgo') != -1) {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?thelist=' + encodeURIComponent(decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace('notgo','').replace('NOTGO','').replace('Notgo','')));
      } else {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?andgo=y&thelist=' + encodeURIComponent(decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')));
      exit;
      }
      } else if (decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'')).toLowerCase().indexOf('ask') != -1) {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?ask=y';
      exit;
      }
      }

      … now all you need to add after that link above, on the web browser address bar is …

      [commaSeparatedList_decodeURIComponent_ized]

      … ie. just type a comma separated YouTube song search basis link after the link wording above
    • so 💬🦆 Come On down ye doubting Thomases!

    And so, further to yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial we have a changed swipe_media.html Tabular Single Row Media Gallery web application you can try for yourself.

    Stop Press

    On reflection, as well as …

    https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html Born to Run,Jungleland working up at the address bar, so, too, will https://www.rjmprogramming.com.au/ Born to Run,Jungleland


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial

    Around here, regarding web application work, we really like dropdown (ie. HTML select element) work because a lot of information can be …

    • stored
    • displayed (often taking up minimal webpage space)
    • it’s option subelements can have an event life of their own, or be part of the select element event whole picture
    • dropdown multiple selection mode (as with today’s work) can …
      1. still support your single choice scenario
      2. we’ve coded today’s dropdown to support, as applicable, ordered single click choices … versus …
      3. can allow for control key (sets of choices not necessarily adjacent) and shift key (blocks of choices)
      4. can respond (as with today’s dropdown) to preset selections established at creation via dropdown (ie. select) innerHTML option subelement selected attribute setting
    • dropdown events onmousedown and ontouchdown (as for today’s dropdown) and onclick can be harnessed ahead of an onchange event … and in today’s case can help unset any preset option subelement selected attribute setting(s)

    Just so flexible! Subelement option CSS styling can be less friendly, but even so, often background colouring is possible, and we do a bit of that with the work from yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Tutorial and today’s better “shored up” work you can see a bit of below (where your starting point might be that we “wrap” this particular Javascript prompt window through the Javascript overprompt function below) …


    var outplist='', kaconto=null, kacontoarr=[], rconeis=155, gconeis=255, bconeis=255;

    function overprompt(blb, defvl) {
    var tdsare=[], itdone=false, itds=0, baeis='', ivb=0, lastpassesmustard=true;
    var oklast=['A','E','I','M','Q','U','Y','c','g','k','o','s','w','0','4','8'];
    outplist=prompt(blb, defvl);
    if (outplist) {
    //alert(1);
    var outparrs=outplist.trim().split(',');
    //alert(11);
    if (eval('' + outparrs.length) > 1) {
    if (eval('' + outparrs[0].length) > 0) {
    if (oklast.indexOf(outparrs[0].slice(-1)) == -1) { lastpassesmustard=false; }
    }
    if ((outparrs[0] + baeis).replace(/\ \ \ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20%20%20';
    outparrs[0]=outparrs[0].replace(/\ \ \ $/g,'');
    } else if ((outparrs[0] + baeis).replace(/\ \ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20%20';
    outparrs[0]=outparrs[0].replace(/\ \ $/g,'');
    } else if ((outparrs[0] + baeis).replace(/\ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20';
    outparrs[0]=outparrs[0].replace(/\ $/g,'');
    } else {
    baeis='';
    }
    //alert(111);
    if (eval('' + outparrs[0].length) != 11 || !lastpassesmustard || encodeURIComponent(outparrs[0]) != outparrs[0]) {
    //alert(1111);
    tdsare=document.getElementsByTagName('td');
    for (itds=0; itds<tdsare.length; itds++) {
    //alert(tdsare[itds].innerHTML);
    if (!itdone && tdsare[itds].innerHTML == '' && ('' + tdsare[itds].id) != 'td0001') {
    itdone=true;
    //alert('here ' + outplist.trim().replace(/\,/g,'|!!|'));
    //tdsare[itds].innerHTML='<iframe onload=karlook(this); style="width:100%;height:100%;" id=karsearch name=karsearch src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outplist.trim().replace(/\,/g,'|!!|')) + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    tdsare[itds].innerHTML='<iframe onload=karlook(this); style="width:100%;height:80%;" id=karsearch name=karsearch src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outparrs[0]) + baeis + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    tdsare[itds].scrollIntoView();
    //alert('there ' + outplist.trim().replace(/\,/g,'|!!|'));
    baeis='';
    kacontoarr=[];
    for (ivb=1; ivb<outparrs.length; ivb++) {
    kacontoarr.push(null);
    }
    for (ivb=1; ivb<outparrs.length; ivb++) {
    tdsare[eval(itds + ivb)].innerHTML='<iframe onload=karlookagain(this,' + eval(-1 + ivb) + '); style="width:100%;height:80%;visibility:hidden;" id=karsearch' + ivb + ' src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outparrs[ivb]) + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    }
    return '';
    }
    }
    }
    }
    }
    return outplist;
    }

    function karlook(iois) {
    var aconto=null;
    aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    if (outplist.indexOf(',') != -1) {
    kaconto=aconto;
    setTimeout(function(){ kaconto.getElementById('ajaxs').style.cursor='progress'; }, 3000);
    setTimeout(postkarlook, 7000);
    } else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    kaconto=aconto;
    setTimeout(mpostkarlook, 7000);
    }
    }
    }
    }

    function karlookagain(iois,idxn) {
    var aconto=null;
    aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    if (eval('' + kacontoarr.length) > eval('' + idxn)) {
    kacontoarr[eval('' + idxn)]=aconto;
    } else {
    kacontoarr.push(aconto);
    }
    }
    }
    }

    function mpostkarlook() {
    if (kaconto.getElementById('ajaxs')) {
    var kbuts=kaconto.getElementsByTagName('input');
    for (var lbuts=0; lbuts<kbuts.length; lbuts++) {
    if (('' + kbuts[lbuts].type) == 'button') {
    if (('' + kbuts[lbuts].value).indexOf('Radio') == 0) {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', String.fromCharCode(10) + 'Radio');
    }
    }
    }
    } else {
    setTimeout(mpostkarlook, 5000);
    }
    }

    function postkarlook() {
    var selectedones='', oktogo=true, hihi=0;
    if (kaconto.getElementById('ajaxs')) {
    //alert(kaconto.getElementById('ajaxs').innerHTML);
    for (hihi=0; hihi<kacontoarr.length; hihi++) {
    if (!kacontoarr[hihi]) {
    oktogo=false;
    //alert('hihi=' + hihi + ' NOT okay');
    } else if (!kacontoarr[hihi].getElementById('ajaxs')) {
    oktogo=false;
    //alert('hihi=' + hihi + ' not okay');
    }
    }
    if (!oktogo) {
    setTimeout(postkarlook, 5000);
    } else if (kaconto.getElementById('ajaxs').innerHTML.indexOf('... and then ...') == -1) {
    kaconto.getElementById('ajaxs').style.cursor='pointer';
    var otherps=baeisf();
    if (otherps != '' || navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    var kbuts=kaconto.getElementsByTagName('input');
    for (var lbuts=0; lbuts<kbuts.length; lbuts++) {
    if (('' + kbuts[lbuts].type) == 'button') {
    if (('' + kbuts[lbuts].value).indexOf('Radio') == 0) {
    var wasvl=kbuts[lbuts].value;
    if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Ordered ' + String.fromCharCode(10) + 'Audio ' + String.fromCharCode(10) + 'Radio');
    } else if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Audio ' + String.fromCharCode(10) + 'Radio');
    } else if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Ordered ' + String.fromCharCode(10) + 'Radio');
    } else {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', String.fromCharCode(10) + 'Radio');
    }
    }
    }
    }
    }
    selectedones=(kaconto.getElementById('ajaxs').innerHTML.split(kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].split('</option>')[0] + '</option>').replace('>', ' class=uptop selected>');
    for (hihi=0; hihi<kacontoarr.length; hihi++) {
    if (rconeis == gconeis && rconeis == bconeis) {
    bconeis-=7;
    if (bconeis < 0) { bconeis+=255; }
    } else if (rconeis == gconeis) {
    gconeis-=7;
    if (gconeis < 0) { gconeis+=255; }
    } else {
    rconeis-=7;
    if (rconeis < 0) { rconeis+=255; }
    }
    selectedones+=((kacontoarr[hihi].getElementById('ajaxs').innerHTML.split(kacontoarr[hihi].getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].split('</option>')[0] + '</option>').replace('>', ' class=uptop selected>')).replace(/option\ onclick\=/g, 'option style=background-color:rgb(' + rconeis + ',' + gconeis + ',' + bconeis + '); onclick=');
    kaconto.getElementById('ajaxs').innerHTML+='<option value="">... and then ...</option>';
    kaconto.getElementById('ajaxs').innerHTML+=kacontoarr[hihi].getElementById('ajaxs').innerHTML.split(kacontoarr[hihi].getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].replace(/option\ onclick\=/g, 'option style=background-color:rgb(' + rconeis + ',' + gconeis + ',' + bconeis + '); onclick=');
    //alert(kacontoarr[hihi].getElementById('ajaxs').innerHTML);
    }
    //alert(selectedones);
    kaconto.getElementById('ajaxs').innerHTML=kaconto.getElementById('ajaxs').innerHTML.replace(kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>', kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>' + selectedones + (selectedones != '' ? '<option id=optclk value="">____ Selection above available (resettable via click here) as you click/tap button at right ____</option>' : ''));
    if (selectedones != '') {
    kaconto.getElementById('ajaxs').onmousedown=function(event){ if (event.target.parentNode.outerHTML.split('>')[0].indexOf(' data-flagged=') == -1) { event.target.parentNode.setAttribute('data-flagged','y'); event.target.parentNode.innerHTML=event.target.parentNode.innerHTML.replace(/\ selected/g, ' ').replace('____ Selection above available (resettable via click here) as you click/tap button at right ____','____ Please select choices in usual multiple choice dropdown ways ____'); } };
    kaconto.getElementById('ajaxs').ontouchdown=function(event){ if (event.target.parentNode.outerHTML.split('>')[0].indexOf(' data-flagged=') == -1) { event.target.parentNode.setAttribute('data-flagged','y'); event.target.parentNode.innerHTML=event.target.parentNode.innerHTML.replace(/\ selected/g, ' ').replace('____ Selection above available (resettable via click here) as you click/tap button at right ____','____ Please select choices in usual multiple choice dropdown ways ____'); } };
    }
    }
    }
    }

    function baeisf() {
    var outarrp=outplist.split(',');
    if (eval('' + outarrp.length) > 1) {
    return outarrp[0].replace(outarrp[0].trim(), '');
    }
    return '';
    }

    And so, today …

    • we add onto the default random ordering mode of Radio Play via YouTube search comma separated list, the further choices ordered or audio or audio ordered, as per the relevant Javascript prompt blurb that is now going …

      Enter YouTube 11 character code video (comma separated) or audio stream only of video (semicolon) list to Radio Play (and add ! to start in shuffle mode and/or # for the order you enter and/or & for whole list) … or a YouTube Search String basis for playlist via a Radio📻? button to activate, later. Comma separateds can be search ideas … egs. Tragedy,Boogie Wonderland,Down Among the Dead Men … random … Tragedy ,Imagine,Breezin … ordered … Tragedy  ,Pina Colada Song,Fast Car … audio … Tragedy   ,Galveston,Angel of the Morning … audio ordered. Double click on this cell for playlist redefinitions.

    • started allowing for dropdown events onmousedown and ontouchdown be able to reset the preset choices we programmatically select for the user should they be happy (but our motivation for this event work was the potential to run into a YouTube video that gives the error …

      This video requires payment to watch YouTube

      )

    Codewise, this involved …

    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, iOS, Networking, Trips, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

YouTube API iOS Shortcuts Shower Song Tutorial

YouTube API iOS Shortcuts Shower Song Tutorial

YouTube API iOS Shortcuts Shower Song Tutorial

Yesterday’s non-mobile YouTube API Command Line Shower Song Names Tutorial based work begs the question, for us …

At least, on “mobile” iOS (which we have access to) can any “command line” feel of playlists ending up at our Shower Songs web application be arranged?

Pretty pithy, huh?! Before we launch into the great iOS Shortcuts app (we’ve talked about before at Shortcuts iOS App Email Arrival Sounds Tutorial) helping here, let’s outline some other simpler ideas you might want to try yourself in the DIY range of ideas …

  • open one of these inhouse Radio Play (YouTube API song playlist and sequencing and loop supporting changed for today’s work swipe_media.html Tabular Single Row Media Gallery or Shower Songs) web applications on a web browser on an iOS device (eg. iPhone or iPad) … and at the juncture where your desired playlist is implemented … use Share icon menu of choices to …
    1. Add to Home Screen … with a tailored (Playlist) Title … this being our preferred option to future proof the remembering … but also available is …
    2. Add Bookmark … or …
    3. Add Favourite
    4. Make your web browser’s opening Home Page be a URL of interest (like one of these playlists) within that web browser app’s Settings area
  • as well as the Shower Songs (as well as Tabular Single Row Media Gallery) web application (with Playlists of 7) can have a dropdown be populated ready to choose and replay that Playlist (that can be email or SMS shared with a recipient)

Okay, all that being said, the great Shortcuts iOS app can serve two purposes a bit “above and beyond this” …

  1. you can DIY build an iOS feeling and “hybrid looking” amalgum of iOS and “old days” dialog box “desktop feeling” personalized application(s) …
  2. the act of constructing any one is sure to inspire other iOS automation ideas you might have

We’re sure lots of you more aux fait with the great iOS Shortcuts app can do better than the “bit kludgy” effort we came up with, and that is the joy of programming, huh?! It can come down to …

  • what you think is the most efficient …
  • you feel you can handle … and …
  • end up with a better automated solution … but …
  • it’s not “all about efficiency” always … it’s also learning about new methodologies you might have to spend more time discovering the ins and outs about

As a case in point, it will be hard to stop yours truly just (iOS mobile) opening the relevant Radio Play web application in a web browser, and going from there (with Bookmarks and Favourites), but there you go?! In this case, perhaps yes, but you should see all the other Messaging and automation possibilities that a peruse of the iOS Shortcuts app can open up to you!

Todays’ animated GIF presentation shows our endeavours “warts and all” (latching onto, intervention wise, when a user taps the Music mobile app icon) for your perusal.


Previous relevant YouTube API Command Line Shower Song Names Tutorial is shown below.

YouTube API Command Line Shower Song Names Tutorial

YouTube API Command Line Shower Song Names Tutorial

Yesterday’s YouTube API Command Line Shower Songs Tutorial‘s Operating System command line modes of access brought us to another issue.

Can a list of seven non-YouTube-ID comma separated values (ie. YouTube song search basis strings) be entered and still end up at the Shower Songs web application?

Well, yes, that’s possible if an intervention point can be arranged. After all, the command line prompt goes …

Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist … 7 for Shower Songs … egs. Tragedy,Boogie Wonderland,Down Among the Dead Men … random … Tragedy ,Imagine*3,Breezin … ordered 5 … Tragedy ,Pina Colada Son,Fast Car … audio … Tragedy ,Galveston,Fix You … audio ordered, and go.

… begging the question “What happens if we enter, at the command line …”


play
Tragedy ,Pina Colada Song,Fast Car,Breezin,Galveston,Fix You,Imagine

… ? Well, after our “better interfacing changes” to the swipe_media.html Tabular Single Row Media Gallery web application changes …


var ytlistis=location.search.split('youtube=')[1] ? anotherdecodeURIComponent(location.search.split('youtube=')[1].split('&')[0]) : '';


function anotherdecodeURIComponent(inplis) {
var thisplist=decodeURIComponent(inplis);


if (eval((thisplist + ',').replace(/[AEIMQUYcgkosw048]\,/g,'z').length) == 77 && eval(('' + thisplist).length) == 83 && eval(('' + encodeURIComponent(thisplist.replace(/\,/g,''))).length) == 77 && eval(('' + thisplist.split(',').length)) == 7) {
window.open('//www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=' + thisplist.trim(),'_blank','top=50,left=' + eval(-800 + screen.width) + ',width=800,height=800');
}

return thisplist;
}

… which mapped to URL …


https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=OiwDHHcHPh0,FXG_I_tf_i4,AIOAlaACuv4,G1QjyskJ9jw,HhKZLhxFFUY,k4V3Mo61fJM,MBIyH4WhOWg

… and that’s where “our fun” (chortle, chortle) began (yeh, right … after a Goose Chase with it being the seventh one) because that seventh YouTube video ID (involved with YouTube “Imagine” search (and something about this rings a bell)) comes back with …

This content can’t be played on your mobile browser. Get the YouTube app to start watching.

Ouch?! What to do? Looking optimistically on this, it’s good to discover it now (yeh, right).

Anyway, we mapped such unplayables to Nothing’s Gonna Stop Us Now – Starship – 1987 in …

… as our means to a solution.


Previous relevant YouTube API Command Line Shower Songs Tutorial is shown below.

YouTube API Command Line Shower Songs Tutorial

YouTube API Command Line Shower Songs Tutorial

Today, we’re combining the concepts behind …

  • the recent YouTube API Caller Radio Play Doctype Meta Tutorial‘s means by which …
    1. macOS
    2. Windows

    … command line “command verb” …

    play

    … can call our “Radio Play” YouTube API interfacing means to play music …

    • sequentially
    • continuously looping (through a set of songs) or just the one song looping

    … adding into those previous arrangements the capability to call the Shower Songs web application under conditions we outlined in …

  • the work of the day before yesterday’s Shower Songs Delimitation Hashtag Tutorial

… involving changed

  1. macOS (building on the changed play.sh shell script)

    #!/bin/bash
    rest=""
    if [ -z "$1" ]; then
    echo "Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... 7 such uses Shower Songs ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men flash ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Song,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go."
    read ans
    else
    preans="$1"
    ans="$1 $2 $3 $4 $5 $6 $7 $8 $9"
    while [ ! -z "$9" ]; do
    shift
    rest="${rest} $9"
    done
    ans="$ans${rest}"
    fi
    if [ ! -z "$ans" ]; then
    commas_only="${ans//[^,]}"
    if [ "${#preans}" == "83" ]; then
    if [ "${#commas_only}" == "6" ]; then
    open "https://www.rjmprogramming.com.au/$1"
    else
    open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
    fi
    else

    open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
    fi
    fi
    exit
  2. Windows (building on the changed play.bat script)

    @echo off
    rem play.bat
    rem RJM Programming
    rem November, 2025

    set passed=
    set rest=
    set seven=0

    if trick==trick%1 (
    set /p ans=Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... 7 for Shower Songs ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Son,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go.
    set ansplus="%ans% "

    if "%ansplus:~12,1%"=="," (
    if "%ansplus:~24,1%"=="," (
    if "%ansplus:~36,1%"=="," (
    if "%ansplus:~48,1%"=="," (
    if "%ansplus:~60,1%"=="," (
    if "%ansplus:~72,1%"=="," (
    if "%ansplus:~84,1%"==" " (
    set seven=7
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=%ans%"
    goto :end
    ) else (
    set seven=6
    )
    ) else (
    set seven=5
    )
    ) else (
    set seven=4
    )
    ) else (
    set seven=3
    )
    ) else (
    set seven=2
    )
    ) else (
    set seven=1
    )
    ) else (
    set seven=0
    )


    ) else (
    set ans="%1"

    set ansplus="%1,%2,%3,%4,%5,%6,%7 %8 "

    if "%ansplus:~12,1%"=="," (
    if "%ansplus:~24,1%"=="," (
    if "%ansplus:~36,1%"=="," (
    if "%ansplus:~48,1%"=="," (
    if "%ansplus:~60,1%"=="," (
    if "%ansplus:~72,1%"=="," (
    if trick==trick%8 (
    set seven=7
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=%1,%2,%3,%4,%5,%6,%7"
    goto :end
    ) else (
    set seven=6
    )
    ) else (
    set seven=5
    )
    ) else (
    set seven=4
    )
    ) else (
    set seven=3
    )
    ) else (
    set seven=2
    )
    ) else (
    set seven=1
    )
    ) else (
    set seven=0
    )


    set passed=yes
    if trick==trick%2 goto :loop
    set ans="%ans%,%2"
    if trick==trick%3 goto :loop
    set ans="%ans%,%3"
    if trick==trick%4 goto :loop
    set ans="%ans%,%4"
    if trick==trick%5 goto :loop
    set ans="%ans%,%5"
    if trick==trick%6 goto :loop
    set ans="%ans%,%6"
    if trick==trick%7 goto :loop
    set ans="%ans%,%7"
    if trick==trick%8 goto :loop
    set ans="%ans%,%8"
    if trick==trick%9 goto :loop
    set ans="%ans%,%9"
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans:"=%"
    :loop
    if "%9"=="" (
    @echo off
    ) else (
    shift
    set rest="%rest% %9"
    goto :loop
    )
    set ans="%ans%%rest%"
    set ans=%ans:"=%
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
    )
    if trick==trick%passed% (
    set ans=%ans:"=%
    if "%ans:,=%"=="%ans%" (
    echo "Nothing to do."
    ) else (
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
    )
    )
    rem exit
    :end

… and involving, if you are on macOS or Windows implementing accordingly …

… a command line …


play FtE3hoR_Nvo,W5IKT_xue4o,IfaGhyK78E8,BuN3yCmHb_U,TdiAwCPb_As,euZcUku9XiE,aMs0rNtBZJk

… can loop and continuously play through that list of seven YouTube video IDs via a web browser use of our Shower Songs web application.


Previous relevant YouTube API Caller Radio Play Doctype Meta Tutorial is shown below.

YouTube API Caller Radio Play Doctype Meta Tutorial

YouTube API Caller Radio Play Doctype Meta Tutorial

It took a session on this MacBook Air’s macOS Firefox web browser trying the Tabular Single Row Media Gallery web application to emphasise the importance of more consistency checking on …

  • doctype HTML tagdeclaration …

    <!DOCTYPE html>

    … and …
  • meta HTML display tagcharset attribute …

    <meta charset="UTF-8">

… existence in web applications we create, to the point that not having the second one defined was stopping proper webpage display on Firefox. Was this a portent of what is to come soon on more web browsers?!

Let’s look at the purpose of these two HTML tagthingos …

  • doctype HTML tagdeclaration

    All HTML documents must start with a declaration.

    The declaration is not an HTML tag. It is an “information” to the browser about what document type to expect.

    … and …

  • meta HTML display tagcharset attribute

    The charset attribute specifies the character encoding for the HTML document.

    The HTML5 specification encourages web developers to use the UTF-8 character set, which covers almost all of the characters and symbols in the world!

Regarding the same web application as yesterday’s YouTube API Caller Radio Play Playlist Windows Local System Tutorial talked about, why not revisit the tweaked swipe_media.html Tabular Single Row Media Gallery web application?


Previous relevant YouTube API Caller Radio Play Playlist Windows Local System Tutorial is shown below.

YouTube API Caller Radio Play Playlist Windows Local System Tutorial

YouTube API Caller Radio Play Playlist Windows Local System Tutorial

Further to the recent YouTube API Caller Radio Play Playlist Local System Tutorial macOS local system discussion, today, we code for …

play

… to mean something on the …

Windows

… “cmd” command accessible …

command line

What’s the scripting here? They are called batch files with extension *.bat we’re calling play.bat (going back to the DOS days of the ’70’s again). With *.bat you just need to plonk your play.bat anywhere within the Windows local system path, and the word (now command) “play” will do the rest anywhere in that user’s command line environment. And the batch file has …


@echo off
rem play.bat
rem RJM Programming
rem November, 2025

set passed=
set rest=

if trick==trick%1 (
set /p ans=Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Son,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go.
) else (
set ans="%1"
set passed=yes
if trick==trick%2 goto :loop
set ans="%ans%,%2"
if trick==trick%3 goto :loop
set ans="%ans%,%3"
if trick==trick%4 goto :loop
set ans="%ans%,%4"
if trick==trick%5 goto :loop
set ans="%ans%,%5"
if trick==trick%6 goto :loop
set ans="%ans%,%6"
if trick==trick%7 goto :loop
set ans="%ans%,%7"
if trick==trick%8 goto :loop
set ans="%ans%,%8"
if trick==trick%9 goto :loop
set ans="%ans%,%9"
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans:"=%"
:loop
if "%9"=="" (
@echo off
) else (
shift
set rest="%rest%,%9"
goto :loop
)
set ans="%ans%%rest%"
set ans=%ans:"=%
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
if trick==trick%passed% (
set ans=%ans:"=%
if "%ans:,=%"=="%ans%" (
echo "Nothing to do."
) else (
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
)
rem exit
:end

… as your starting gambit, here, where the equivalent of macOS’s “open” is “explorer.exe” on Windows (ie. the File Explorer) … almost as cute!


Previous relevant YouTube API Caller Radio Play Playlist Local System Tutorial is shown below.

YouTube API Caller Radio Play Playlist Local System Tutorial

YouTube API Caller Radio Play Playlist Local System Tutorial

The ..

command line

… of a laptop or notebook or personal computer can be an environment to relax from the GUI aspects of your modern operating systems and think about …

  • processes
  • batch driven tasks
  • task simplifications

… and in the category of that last one, on our local macOS operating system we envisaged a day we could slip back to the “quiet world” of the “command line” and type a command like …


play Tragedy,Imagine,Down Among the Dead Men PAN -

… and get somewhere playing those songs through a web browser accessing the YouTube API and our interfacings to it in webpage software form, playing in a continuous Radio Play style.

You see, with all the distractions, only having to remember …

play

… no matter where we were in “command line” woooorrrrllllddd seemed the ideal, and yes, it’s possible. However, we think explaining …


bash /Applications/MAMP/htdocs/play.ksh Tragedy,Imagine,Down Among the Dead Men PAN -

… is a necessary dividing line between two parts to the discussion. So what’s bash? It’s the shell we associate as your macOS default shell (we get to via the “out of the box” macOS desktop application called Terminal) … well, it used to be … anyway, the first line of (what started as play.ksh then play.sh and then eventually, just, play … as a filename that is) …


#!/bin/bash
rest=""
if [ -z "$1" ]; then
echo "Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Song,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go."
read ans
else
ans="$1 $2 $3 $4 $5 $6 $7 $8 $9"
while [ ! -z "$9" ]; do
shift
rest="${rest} $9"
done
ans="$ans${rest}"
fi
if [ ! -z "$ans" ]; then
open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
fi
exit

… tells the local system use the bash shell to interpret this what you might like to think of as an executable script (which we went chmod 777 play regarding to make it so).

Okay, so we wrote this script in /Applications/MAMP/htdocs/ and that …


bash /Applications/MAMP/htdocs/play Tragedy,Imagine,Down Among the Dead Men PAN -

… could swing it at this stage, or even being in /Applications/MAMP/htdocs/ and going …


./play Tragedy,Imagine,Down Among the Dead Men PAN -

… but (even in /Applications/MAMP/htdocs/) …


play Tragedy,Imagine,Down Among the Dead Men PAN -

… is most likely to reply something like …

zsh: no such command

As the programmer, perhaps you could leave it at that with your “insider knowledge”, or if “play” as a command already meant something (a test that would be good to do before any such proposed work), otherwise … do you really think you’ll remember next Wednesday? So …

  1. enter into the wooooorrrrllllddd of aliases (thanks to this great advice, thanks) … eg.

    alias play="/Applications/MAMP/htdocs/play"
  2. placed into …

    ~/.bashrc

    … via (in our case) …

    vi ~/.bashrc
  3. then …

    source ~/.bashrc

    … needs to be included into the login procedure of …

    ~/.profile

    …via (in our case) …

    vi ~/.profile
  4. to make …

    play

    … as the interactively asking alternative to the argumentative example of …

    play Tragedy,Imagine,Down Among the Dead Men PAN -

    … mean something … and anywhere

    … all of this possible because of the brilliantly useful macOS (not Linux nor unix) …


    open

    … opener of web browsers from the command line blowing of our tiny little rather still naive mind … mind you, VAX/VMS “phone” command from the ’70’s might have even been better?! And then there were those punch cards … in the hopper … and if you got a character wrong … back to the end of the queue.

    Sorry … we got a bit hot and bothered there!

    Anyway, as a layer of thought on top of the recent YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial‘s mildly changed swipe_media.html Tabular Single Row Media Gallery web application work it might be a thing you want to pursue yourself?

    By the way, this brought into play for us what your default web browser is. Ours is Safari yet we develop more on Google Chrome. Safari, for us, does more Popup Blocking, and it is a thing to look out for should a window not open when expected (and these command line methodologies don’t get past you still having to unmute and/or click/tap once before the Radio Play mode of play kicks off). To undo the Popup Block there will probably be a means to do this to the right of the web browser address bar.


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial

    Burp …

    Sorry to open with a quote, and sorry to repeat myself, like.

    And sorry to repeat myself, like, again.

    But there is a point. Today represents an improvement on yesterday’s arrangements for dynamic playlist creation regarding our Tabular Single Row Media Gallery web application via the playlist emoji button 🔀 click/tap or on the web browser command line. With yesterday’s scenario, had you entered as your internal playlist comma separated string …

    Born to Run,Born to Run,Born to Run,Born to Run

    … without the …

    Burp …

    that is you’d have ended up with the top find off a YouTube search repeated 4 times. Is this ideal? We asked Nala and Luna but, unfortunately they were busy, so they left me with the decision, and we came up with …

    That’s kind of silly.

    For these few reasons …

    • variety
    • album style Radio Play listening possibilities
    • perhaps getting around that …

      This video requires payment to watch YouTube

      … issue we talked about before … because you could uncheck it’s checkbox if the error appears

    • giving non-top search items a go

    … we decided to “mix it up” regarding entries like …

    Born to Run,Born to Run,Born to Run,Born to Run

    … as well as the simpler …

    Born to Run*4

    … so that repeats don’t cause users indigestion … chortle, chortle.

    Here’s the Javascript turning Born to Run*4 into Born to Run,Born to Run,Born to Run,Born to Run


    function expandrepeats(ocsl) {
    var numnum=0, minone=-1, interesting='', ninteresting='', pinteresting='', superinteresting='', imn=1;
    var retocsl=ocsl;
    var acarr=ocsl.split(',');
    for (var iac=0; iac<acarr.length; iac++) {
    numnum=0;
    minone=-1;
    if (acarr[iac].trim() != '') {
    if (acarr[iac].trim().slice(-1) >= '0' && acarr[iac].trim().slice(-1) <= '9') {
    while (('S' + acarr[iac].trim()).slice(minone).substring(0,1) >= '0' && ('S' + acarr[iac].trim()).slice(minone).substring(0,1) <= '9') {
    numnum++;
    minone--;
    }
    }
    if (numnum > 0 && numnum < eval('' + acarr[iac].trim().length)) {
    ninteresting=acarr[iac].trim().slice(-numnum);
    interesting=acarr[iac].trim().substring(0, eval(-numnum + eval('' + acarr[iac].trim().length)));
    superinteresting='';
    pinteresting='';
    if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ x\ $/g,'')) {
    pinteresting=interesting.slice(-3) + ninteresting;
    superinteresting=interesting.replace(/\ x\ $/g,'').replace(/\ X\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/x\ $/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/x\ $/g,'').replace(/X\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ x$/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\ x$/g,'').replace(/\ X$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/x$/g,'')) {
    pinteresting=interesting.slice(-1) + ninteresting;
    superinteresting=interesting.replace(/x$/g,'').replace(/X$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ \*\ $/g,'')) {
    pinteresting=interesting.slice(-3) + ninteresting;
    superinteresting=interesting.replace(/\ \*\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\*\ $/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\*\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ \*$/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\ \*$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\*$/g,'')) {
    pinteresting=interesting.slice(-1) + ninteresting;
    superinteresting=interesting.replace(/\*$/g,'');
    }
    if (superinteresting != '' && eval('' + ninteresting) >= 1) {
    for (imn=1; imn<=eval('' + ninteresting); imn++) {
    if (imn == 1) {
    retocsl=retocsl.replace(pinteresting, '');
    acarr[iac]=acarr[iac].replace(pinteresting, '');
    } else {
    retocsl=retocsl.replace(acarr[iac], acarr[iac] + ',' + superinteresting.trim());
    }
    }
    }
    }
    }
    }
    if (retocsl != ocsl) { outplist=retocsl; }
    return retocsl;
    }

    … in the changed swipe_media.html Tabular Single Row Media Gallery web application you can try for yourself (or try some more of The Boss), further to yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial.


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial

    Don’t know if you are like me, but especially when on this MacBook Air we’re, forever, using a web browser address bar to type in, what we’ve set up as, a Google search engine webpage query. Rather than even going to Google webpage first, that is!

    Most people don’t want to know about arcane web application argument arrangements … though we’re very fond of the 5 minute ones?!

    What’s wrong with some of you? Who would not relish the thought of …

    • adding onto the address bar …

      https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html

      … with new arguments( eg. https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html Born to Run,Jungleland ) …
    • ?ask=y # will get you straight to the Javascript playlist prompt window
    • &or?thelist=[commaSeparatedList_encodeURIComponent_ized] # will supply that prompt window with the answer [commaSeparatedList_decodeURIComponent_ized]
    • &or?andgo=y # will click the Radio button after all above (unless notgo is mentioned in the list somewhere), as relevant, with the programmatically determined derived YouTube ID list via YouTube search(es)
    • 💬🦆 Come On!
    • … when, after a bit of thought and tweaks to our RJM Programming domain’s Apache Document Root residing 404.shtml webpage Javascript …

      if (document.URL.indexOf('rjmprogramming.com.au/HTMLCSS/swipe_media.htm') != -1) {
      if (decodeURIComponent(document.URL).indexOf(',') != -1) {
      if (decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'')).toLowerCase().indexOf('notgo') != -1) {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?thelist=' + encodeURIComponent(decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace('notgo','').replace('NOTGO','').replace('Notgo','')));
      } else {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?andgo=y&thelist=' + encodeURIComponent(decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')));
      exit;
      }
      } else if (decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'')).toLowerCase().indexOf('ask') != -1) {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?ask=y';
      exit;
      }
      }

      … now all you need to add after that link above, on the web browser address bar is …

      [commaSeparatedList_decodeURIComponent_ized]

      … ie. just type a comma separated YouTube song search basis link after the link wording above
    • so 💬🦆 Come On down ye doubting Thomases!

    And so, further to yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial we have a changed swipe_media.html Tabular Single Row Media Gallery web application you can try for yourself.

    Stop Press

    On reflection, as well as …

    https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html Born to Run,Jungleland working up at the address bar, so, too, will https://www.rjmprogramming.com.au/ Born to Run,Jungleland


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial

    Around here, regarding web application work, we really like dropdown (ie. HTML select element) work because a lot of information can be …

    • stored
    • displayed (often taking up minimal webpage space)
    • it’s option subelements can have an event life of their own, or be part of the select element event whole picture
    • dropdown multiple selection mode (as with today’s work) can …
      1. still support your single choice scenario
      2. we’ve coded today’s dropdown to support, as applicable, ordered single click choices … versus …
      3. can allow for control key (sets of choices not necessarily adjacent) and shift key (blocks of choices)
      4. can respond (as with today’s dropdown) to preset selections established at creation via dropdown (ie. select) innerHTML option subelement selected attribute setting
    • dropdown events onmousedown and ontouchdown (as for today’s dropdown) and onclick can be harnessed ahead of an onchange event … and in today’s case can help unset any preset option subelement selected attribute setting(s)

    Just so flexible! Subelement option CSS styling can be less friendly, but even so, often background colouring is possible, and we do a bit of that with the work from yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Tutorial and today’s better “shored up” work you can see a bit of below (where your starting point might be that we “wrap” this particular Javascript prompt window through the Javascript overprompt function below) …


    var outplist='', kaconto=null, kacontoarr=[], rconeis=155, gconeis=255, bconeis=255;

    function overprompt(blb, defvl) {
    var tdsare=[], itdone=false, itds=0, baeis='', ivb=0, lastpassesmustard=true;
    var oklast=['A','E','I','M','Q','U','Y','c','g','k','o','s','w','0','4','8'];
    outplist=prompt(blb, defvl);
    if (outplist) {
    //alert(1);
    var outparrs=outplist.trim().split(',');
    //alert(11);
    if (eval('' + outparrs.length) > 1) {
    if (eval('' + outparrs[0].length) > 0) {
    if (oklast.indexOf(outparrs[0].slice(-1)) == -1) { lastpassesmustard=false; }
    }
    if ((outparrs[0] + baeis).replace(/\ \ \ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20%20%20';
    outparrs[0]=outparrs[0].replace(/\ \ \ $/g,'');
    } else if ((outparrs[0] + baeis).replace(/\ \ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20%20';
    outparrs[0]=outparrs[0].replace(/\ \ $/g,'');
    } else if ((outparrs[0] + baeis).replace(/\ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20';
    outparrs[0]=outparrs[0].replace(/\ $/g,'');
    } else {
    baeis='';
    }
    //alert(111);
    if (eval('' + outparrs[0].length) != 11 || !lastpassesmustard || encodeURIComponent(outparrs[0]) != outparrs[0]) {
    //alert(1111);
    tdsare=document.getElementsByTagName('td');
    for (itds=0; itds<tdsare.length; itds++) {
    //alert(tdsare[itds].innerHTML);
    if (!itdone && tdsare[itds].innerHTML == '' && ('' + tdsare[itds].id) != 'td0001') {
    itdone=true;
    //alert('here ' + outplist.trim().replace(/\,/g,'|!!|'));
    //tdsare[itds].innerHTML='<iframe onload=karlook(this); style="width:100%;height:100%;" id=karsearch name=karsearch src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outplist.trim().replace(/\,/g,'|!!|')) + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    tdsare[itds].innerHTML='<iframe onload=karlook(this); style="width:100%;height:80%;" id=karsearch name=karsearch src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outparrs[0]) + baeis + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    tdsare[itds].scrollIntoView();
    //alert('there ' + outplist.trim().replace(/\,/g,'|!!|'));
    baeis='';
    kacontoarr=[];
    for (ivb=1; ivb<outparrs.length; ivb++) {
    kacontoarr.push(null);
    }
    for (ivb=1; ivb<outparrs.length; ivb++) {
    tdsare[eval(itds + ivb)].innerHTML='<iframe onload=karlookagain(this,' + eval(-1 + ivb) + '); style="width:100%;height:80%;visibility:hidden;" id=karsearch' + ivb + ' src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outparrs[ivb]) + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    }
    return '';
    }
    }
    }
    }
    }
    return outplist;
    }

    function karlook(iois) {
    var aconto=null;
    aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    if (outplist.indexOf(',') != -1) {
    kaconto=aconto;
    setTimeout(function(){ kaconto.getElementById('ajaxs').style.cursor='progress'; }, 3000);
    setTimeout(postkarlook, 7000);
    } else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    kaconto=aconto;
    setTimeout(mpostkarlook, 7000);
    }
    }
    }
    }

    function karlookagain(iois,idxn) {
    var aconto=null;
    aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    if (eval('' + kacontoarr.length) > eval('' + idxn)) {
    kacontoarr[eval('' + idxn)]=aconto;
    } else {
    kacontoarr.push(aconto);
    }
    }
    }
    }

    function mpostkarlook() {
    if (kaconto.getElementById('ajaxs')) {
    var kbuts=kaconto.getElementsByTagName('input');
    for (var lbuts=0; lbuts<kbuts.length; lbuts++) {
    if (('' + kbuts[lbuts].type) == 'button') {
    if (('' + kbuts[lbuts].value).indexOf('Radio') == 0) {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', String.fromCharCode(10) + 'Radio');
    }
    }
    }
    } else {
    setTimeout(mpostkarlook, 5000);
    }
    }

    function postkarlook() {
    var selectedones='', oktogo=true, hihi=0;
    if (kaconto.getElementById('ajaxs')) {
    //alert(kaconto.getElementById('ajaxs').innerHTML);
    for (hihi=0; hihi<kacontoarr.length; hihi++) {
    if (!kacontoarr[hihi]) {
    oktogo=false;
    //alert('hihi=' + hihi + ' NOT okay');
    } else if (!kacontoarr[hihi].getElementById('ajaxs')) {
    oktogo=false;
    //alert('hihi=' + hihi + ' not okay');
    }
    }
    if (!oktogo) {
    setTimeout(postkarlook, 5000);
    } else if (kaconto.getElementById('ajaxs').innerHTML.indexOf('... and then ...') == -1) {
    kaconto.getElementById('ajaxs').style.cursor='pointer';
    var otherps=baeisf();
    if (otherps != '' || navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    var kbuts=kaconto.getElementsByTagName('input');
    for (var lbuts=0; lbuts<kbuts.length; lbuts++) {
    if (('' + kbuts[lbuts].type) == 'button') {
    if (('' + kbuts[lbuts].value).indexOf('Radio') == 0) {
    var wasvl=kbuts[lbuts].value;
    if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Ordered ' + String.fromCharCode(10) + 'Audio ' + String.fromCharCode(10) + 'Radio');
    } else if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Audio ' + String.fromCharCode(10) + 'Radio');
    } else if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Ordered ' + String.fromCharCode(10) + 'Radio');
    } else {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', String.fromCharCode(10) + 'Radio');
    }
    }
    }
    }
    }
    selectedones=(kaconto.getElementById('ajaxs').innerHTML.split(kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].split('</option>')[0] + '</option>').replace('>', ' class=uptop selected>');
    for (hihi=0; hihi<kacontoarr.length; hihi++) {
    if (rconeis == gconeis && rconeis == bconeis) {
    bconeis-=7;
    if (bconeis < 0) { bconeis+=255; }
    } else if (rconeis == gconeis) {
    gconeis-=7;
    if (gconeis < 0) { gconeis+=255; }
    } else {
    rconeis-=7;
    if (rconeis < 0) { rconeis+=255; }
    }
    selectedones+=((kacontoarr[hihi].getElementById('ajaxs').innerHTML.split(kacontoarr[hihi].getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].split('</option>')[0] + '</option>').replace('>', ' class=uptop selected>')).replace(/option\ onclick\=/g, 'option style=background-color:rgb(' + rconeis + ',' + gconeis + ',' + bconeis + '); onclick=');
    kaconto.getElementById('ajaxs').innerHTML+='<option value="">... and then ...</option>';
    kaconto.getElementById('ajaxs').innerHTML+=kacontoarr[hihi].getElementById('ajaxs').innerHTML.split(kacontoarr[hihi].getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].replace(/option\ onclick\=/g, 'option style=background-color:rgb(' + rconeis + ',' + gconeis + ',' + bconeis + '); onclick=');
    //alert(kacontoarr[hihi].getElementById('ajaxs').innerHTML);
    }
    //alert(selectedones);
    kaconto.getElementById('ajaxs').innerHTML=kaconto.getElementById('ajaxs').innerHTML.replace(kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>', kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>' + selectedones + (selectedones != '' ? '<option id=optclk value="">____ Selection above available (resettable via click here) as you click/tap button at right ____</option>' : ''));
    if (selectedones != '') {
    kaconto.getElementById('ajaxs').onmousedown=function(event){ if (event.target.parentNode.outerHTML.split('>')[0].indexOf(' data-flagged=') == -1) { event.target.parentNode.setAttribute('data-flagged','y'); event.target.parentNode.innerHTML=event.target.parentNode.innerHTML.replace(/\ selected/g, ' ').replace('____ Selection above available (resettable via click here) as you click/tap button at right ____','____ Please select choices in usual multiple choice dropdown ways ____'); } };
    kaconto.getElementById('ajaxs').ontouchdown=function(event){ if (event.target.parentNode.outerHTML.split('>')[0].indexOf(' data-flagged=') == -1) { event.target.parentNode.setAttribute('data-flagged','y'); event.target.parentNode.innerHTML=event.target.parentNode.innerHTML.replace(/\ selected/g, ' ').replace('____ Selection above available (resettable via click here) as you click/tap button at right ____','____ Please select choices in usual multiple choice dropdown ways ____'); } };
    }
    }
    }
    }

    function baeisf() {
    var outarrp=outplist.split(',');
    if (eval('' + outarrp.length) > 1) {
    return outarrp[0].replace(outarrp[0].trim(), '');
    }
    return '';
    }

    And so, today …

    • we add onto the default random ordering mode of Radio Play via YouTube search comma separated list, the further choices ordered or audio or audio ordered, as per the relevant Javascript prompt blurb that is now going …

      Enter YouTube 11 character code video (comma separated) or audio stream only of video (semicolon) list to Radio Play (and add ! to start in shuffle mode and/or # for the order you enter and/or & for whole list) … or a YouTube Search String basis for playlist via a Radio📻? button to activate, later. Comma separateds can be search ideas … egs. Tragedy,Boogie Wonderland,Down Among the Dead Men … random … Tragedy ,Imagine,Breezin … ordered … Tragedy  ,Pina Colada Song,Fast Car … audio … Tragedy   ,Galveston,Angel of the Morning … audio ordered. Double click on this cell for playlist redefinitions.

    • started allowing for dropdown events onmousedown and ontouchdown be able to reset the preset choices we programmatically select for the user should they be happy (but our motivation for this event work was the potential to run into a YouTube video that gives the error …

      This video requires payment to watch YouTube

      )

    Codewise, this involved …

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

YouTube API Command Line Shower Song Names Tutorial

YouTube API Command Line Shower Song Names Tutorial

YouTube API Command Line Shower Song Names Tutorial

Yesterday’s YouTube API Command Line Shower Songs Tutorial‘s Operating System command line modes of access brought us to another issue.

Can a list of seven non-YouTube-ID comma separated values (ie. YouTube song search basis strings) be entered and still end up at the Shower Songs web application?

Well, yes, that’s possible if an intervention point can be arranged. After all, the command line prompt goes …

Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist … 7 for Shower Songs … egs. Tragedy,Boogie Wonderland,Down Among the Dead Men … random … Tragedy ,Imagine*3,Breezin … ordered 5 … Tragedy ,Pina Colada Son,Fast Car … audio … Tragedy ,Galveston,Fix You … audio ordered, and go.

… begging the question “What happens if we enter, at the command line …”


play
Tragedy ,Pina Colada Song,Fast Car,Breezin,Galveston,Fix You,Imagine

… ? Well, after our “better interfacing changes” to the swipe_media.html Tabular Single Row Media Gallery web application changes …


var ytlistis=location.search.split('youtube=')[1] ? anotherdecodeURIComponent(location.search.split('youtube=')[1].split('&')[0]) : '';


function anotherdecodeURIComponent(inplis) {
var thisplist=decodeURIComponent(inplis);


if (eval((thisplist + ',').replace(/[AEIMQUYcgkosw048]\,/g,'z').length) == 77 && eval(('' + thisplist).length) == 83 && eval(('' + encodeURIComponent(thisplist.replace(/\,/g,''))).length) == 77 && eval(('' + thisplist.split(',').length)) == 7) {
window.open('//www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=' + thisplist.trim(),'_blank','top=50,left=' + eval(-800 + screen.width) + ',width=800,height=800');
}

return thisplist;
}

… which mapped to URL …


https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=OiwDHHcHPh0,FXG_I_tf_i4,AIOAlaACuv4,G1QjyskJ9jw,HhKZLhxFFUY,k4V3Mo61fJM,MBIyH4WhOWg

… and that’s where “our fun” (chortle, chortle) began (yeh, right … after a Goose Chase with it being the seventh one) because that seventh YouTube video ID (involved with YouTube “Imagine” search (and something about this rings a bell)) comes back with …

This content can’t be played on your mobile browser. Get the YouTube app to start watching.

Ouch?! What to do? Looking optimistically on this, it’s good to discover it now (yeh, right).

Anyway, we mapped such unplayables to Nothing’s Gonna Stop Us Now – Starship – 1987 in …

… as our means to a solution.


Previous relevant YouTube API Command Line Shower Songs Tutorial is shown below.

YouTube API Command Line Shower Songs Tutorial

YouTube API Command Line Shower Songs Tutorial

Today, we’re combining the concepts behind …

  • the recent YouTube API Caller Radio Play Doctype Meta Tutorial‘s means by which …
    1. macOS
    2. Windows

    … command line “command verb” …

    play

    … can call our “Radio Play” YouTube API interfacing means to play music …

    • sequentially
    • continuously looping (through a set of songs) or just the one song looping

    … adding into those previous arrangements the capability to call the Shower Songs web application under conditions we outlined in …

  • the work of the day before yesterday’s Shower Songs Delimitation Hashtag Tutorial

… involving changed

  1. macOS (building on the changed play.sh shell script)

    #!/bin/bash
    rest=""
    if [ -z "$1" ]; then
    echo "Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... 7 such uses Shower Songs ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men flash ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Song,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go."
    read ans
    else
    preans="$1"
    ans="$1 $2 $3 $4 $5 $6 $7 $8 $9"
    while [ ! -z "$9" ]; do
    shift
    rest="${rest} $9"
    done
    ans="$ans${rest}"
    fi
    if [ ! -z "$ans" ]; then
    commas_only="${ans//[^,]}"
    if [ "${#preans}" == "83" ]; then
    if [ "${#commas_only}" == "6" ]; then
    open "https://www.rjmprogramming.com.au/$1"
    else
    open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
    fi
    else

    open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
    fi
    fi
    exit
  2. Windows (building on the changed play.bat script)

    @echo off
    rem play.bat
    rem RJM Programming
    rem November, 2025

    set passed=
    set rest=
    set seven=0

    if trick==trick%1 (
    set /p ans=Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... 7 for Shower Songs ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Son,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go.
    set ansplus="%ans% "

    if "%ansplus:~12,1%"=="," (
    if "%ansplus:~24,1%"=="," (
    if "%ansplus:~36,1%"=="," (
    if "%ansplus:~48,1%"=="," (
    if "%ansplus:~60,1%"=="," (
    if "%ansplus:~72,1%"=="," (
    if "%ansplus:~84,1%"==" " (
    set seven=7
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=%ans%"
    goto :end
    ) else (
    set seven=6
    )
    ) else (
    set seven=5
    )
    ) else (
    set seven=4
    )
    ) else (
    set seven=3
    )
    ) else (
    set seven=2
    )
    ) else (
    set seven=1
    )
    ) else (
    set seven=0
    )


    ) else (
    set ans="%1"

    set ansplus="%1,%2,%3,%4,%5,%6,%7 %8 "

    if "%ansplus:~12,1%"=="," (
    if "%ansplus:~24,1%"=="," (
    if "%ansplus:~36,1%"=="," (
    if "%ansplus:~48,1%"=="," (
    if "%ansplus:~60,1%"=="," (
    if "%ansplus:~72,1%"=="," (
    if trick==trick%8 (
    set seven=7
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=%1,%2,%3,%4,%5,%6,%7"
    goto :end
    ) else (
    set seven=6
    )
    ) else (
    set seven=5
    )
    ) else (
    set seven=4
    )
    ) else (
    set seven=3
    )
    ) else (
    set seven=2
    )
    ) else (
    set seven=1
    )
    ) else (
    set seven=0
    )


    set passed=yes
    if trick==trick%2 goto :loop
    set ans="%ans%,%2"
    if trick==trick%3 goto :loop
    set ans="%ans%,%3"
    if trick==trick%4 goto :loop
    set ans="%ans%,%4"
    if trick==trick%5 goto :loop
    set ans="%ans%,%5"
    if trick==trick%6 goto :loop
    set ans="%ans%,%6"
    if trick==trick%7 goto :loop
    set ans="%ans%,%7"
    if trick==trick%8 goto :loop
    set ans="%ans%,%8"
    if trick==trick%9 goto :loop
    set ans="%ans%,%9"
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans:"=%"
    :loop
    if "%9"=="" (
    @echo off
    ) else (
    shift
    set rest="%rest% %9"
    goto :loop
    )
    set ans="%ans%%rest%"
    set ans=%ans:"=%
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
    )
    if trick==trick%passed% (
    set ans=%ans:"=%
    if "%ans:,=%"=="%ans%" (
    echo "Nothing to do."
    ) else (
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
    )
    )
    rem exit
    :end

… and involving, if you are on macOS or Windows implementing accordingly …

… a command line …


play FtE3hoR_Nvo,W5IKT_xue4o,IfaGhyK78E8,BuN3yCmHb_U,TdiAwCPb_As,euZcUku9XiE,aMs0rNtBZJk

… can loop and continuously play through that list of seven YouTube video IDs via a web browser use of our Shower Songs web application.


Previous relevant YouTube API Caller Radio Play Doctype Meta Tutorial is shown below.

YouTube API Caller Radio Play Doctype Meta Tutorial

YouTube API Caller Radio Play Doctype Meta Tutorial

It took a session on this MacBook Air’s macOS Firefox web browser trying the Tabular Single Row Media Gallery web application to emphasise the importance of more consistency checking on …

  • doctype HTML tagdeclaration …

    <!DOCTYPE html>

    … and …
  • meta HTML display tagcharset attribute …

    <meta charset="UTF-8">

… existence in web applications we create, to the point that not having the second one defined was stopping proper webpage display on Firefox. Was this a portent of what is to come soon on more web browsers?!

Let’s look at the purpose of these two HTML tagthingos …

  • doctype HTML tagdeclaration

    All HTML documents must start with a declaration.

    The declaration is not an HTML tag. It is an “information” to the browser about what document type to expect.

    … and …

  • meta HTML display tagcharset attribute

    The charset attribute specifies the character encoding for the HTML document.

    The HTML5 specification encourages web developers to use the UTF-8 character set, which covers almost all of the characters and symbols in the world!

Regarding the same web application as yesterday’s YouTube API Caller Radio Play Playlist Windows Local System Tutorial talked about, why not revisit the tweaked swipe_media.html Tabular Single Row Media Gallery web application?


Previous relevant YouTube API Caller Radio Play Playlist Windows Local System Tutorial is shown below.

YouTube API Caller Radio Play Playlist Windows Local System Tutorial

YouTube API Caller Radio Play Playlist Windows Local System Tutorial

Further to the recent YouTube API Caller Radio Play Playlist Local System Tutorial macOS local system discussion, today, we code for …

play

… to mean something on the …

Windows

… “cmd” command accessible …

command line

What’s the scripting here? They are called batch files with extension *.bat we’re calling play.bat (going back to the DOS days of the ’70’s again). With *.bat you just need to plonk your play.bat anywhere within the Windows local system path, and the word (now command) “play” will do the rest anywhere in that user’s command line environment. And the batch file has …


@echo off
rem play.bat
rem RJM Programming
rem November, 2025

set passed=
set rest=

if trick==trick%1 (
set /p ans=Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Son,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go.
) else (
set ans="%1"
set passed=yes
if trick==trick%2 goto :loop
set ans="%ans%,%2"
if trick==trick%3 goto :loop
set ans="%ans%,%3"
if trick==trick%4 goto :loop
set ans="%ans%,%4"
if trick==trick%5 goto :loop
set ans="%ans%,%5"
if trick==trick%6 goto :loop
set ans="%ans%,%6"
if trick==trick%7 goto :loop
set ans="%ans%,%7"
if trick==trick%8 goto :loop
set ans="%ans%,%8"
if trick==trick%9 goto :loop
set ans="%ans%,%9"
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans:"=%"
:loop
if "%9"=="" (
@echo off
) else (
shift
set rest="%rest%,%9"
goto :loop
)
set ans="%ans%%rest%"
set ans=%ans:"=%
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
if trick==trick%passed% (
set ans=%ans:"=%
if "%ans:,=%"=="%ans%" (
echo "Nothing to do."
) else (
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
)
rem exit
:end

… as your starting gambit, here, where the equivalent of macOS’s “open” is “explorer.exe” on Windows (ie. the File Explorer) … almost as cute!


Previous relevant YouTube API Caller Radio Play Playlist Local System Tutorial is shown below.

YouTube API Caller Radio Play Playlist Local System Tutorial

YouTube API Caller Radio Play Playlist Local System Tutorial

The ..

command line

… of a laptop or notebook or personal computer can be an environment to relax from the GUI aspects of your modern operating systems and think about …

  • processes
  • batch driven tasks
  • task simplifications

… and in the category of that last one, on our local macOS operating system we envisaged a day we could slip back to the “quiet world” of the “command line” and type a command like …


play Tragedy,Imagine,Down Among the Dead Men PAN -

… and get somewhere playing those songs through a web browser accessing the YouTube API and our interfacings to it in webpage software form, playing in a continuous Radio Play style.

You see, with all the distractions, only having to remember …

play

… no matter where we were in “command line” woooorrrrllllddd seemed the ideal, and yes, it’s possible. However, we think explaining …


bash /Applications/MAMP/htdocs/play.ksh Tragedy,Imagine,Down Among the Dead Men PAN -

… is a necessary dividing line between two parts to the discussion. So what’s bash? It’s the shell we associate as your macOS default shell (we get to via the “out of the box” macOS desktop application called Terminal) … well, it used to be … anyway, the first line of (what started as play.ksh then play.sh and then eventually, just, play … as a filename that is) …


#!/bin/bash
rest=""
if [ -z "$1" ]; then
echo "Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Song,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go."
read ans
else
ans="$1 $2 $3 $4 $5 $6 $7 $8 $9"
while [ ! -z "$9" ]; do
shift
rest="${rest} $9"
done
ans="$ans${rest}"
fi
if [ ! -z "$ans" ]; then
open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
fi
exit

… tells the local system use the bash shell to interpret this what you might like to think of as an executable script (which we went chmod 777 play regarding to make it so).

Okay, so we wrote this script in /Applications/MAMP/htdocs/ and that …


bash /Applications/MAMP/htdocs/play Tragedy,Imagine,Down Among the Dead Men PAN -

… could swing it at this stage, or even being in /Applications/MAMP/htdocs/ and going …


./play Tragedy,Imagine,Down Among the Dead Men PAN -

… but (even in /Applications/MAMP/htdocs/) …


play Tragedy,Imagine,Down Among the Dead Men PAN -

… is most likely to reply something like …

zsh: no such command

As the programmer, perhaps you could leave it at that with your “insider knowledge”, or if “play” as a command already meant something (a test that would be good to do before any such proposed work), otherwise … do you really think you’ll remember next Wednesday? So …

  1. enter into the wooooorrrrllllddd of aliases (thanks to this great advice, thanks) … eg.

    alias play="/Applications/MAMP/htdocs/play"
  2. placed into …

    ~/.bashrc

    … via (in our case) …

    vi ~/.bashrc
  3. then …

    source ~/.bashrc

    … needs to be included into the login procedure of …

    ~/.profile

    …via (in our case) …

    vi ~/.profile
  4. to make …

    play

    … as the interactively asking alternative to the argumentative example of …

    play Tragedy,Imagine,Down Among the Dead Men PAN -

    … mean something … and anywhere

    … all of this possible because of the brilliantly useful macOS (not Linux nor unix) …


    open

    … opener of web browsers from the command line blowing of our tiny little rather still naive mind … mind you, VAX/VMS “phone” command from the ’70’s might have even been better?! And then there were those punch cards … in the hopper … and if you got a character wrong … back to the end of the queue.

    Sorry … we got a bit hot and bothered there!

    Anyway, as a layer of thought on top of the recent YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial‘s mildly changed swipe_media.html Tabular Single Row Media Gallery web application work it might be a thing you want to pursue yourself?

    By the way, this brought into play for us what your default web browser is. Ours is Safari yet we develop more on Google Chrome. Safari, for us, does more Popup Blocking, and it is a thing to look out for should a window not open when expected (and these command line methodologies don’t get past you still having to unmute and/or click/tap once before the Radio Play mode of play kicks off). To undo the Popup Block there will probably be a means to do this to the right of the web browser address bar.


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial

    Burp …

    Sorry to open with a quote, and sorry to repeat myself, like.

    And sorry to repeat myself, like, again.

    But there is a point. Today represents an improvement on yesterday’s arrangements for dynamic playlist creation regarding our Tabular Single Row Media Gallery web application via the playlist emoji button 🔀 click/tap or on the web browser command line. With yesterday’s scenario, had you entered as your internal playlist comma separated string …

    Born to Run,Born to Run,Born to Run,Born to Run

    … without the …

    Burp …

    that is you’d have ended up with the top find off a YouTube search repeated 4 times. Is this ideal? We asked Nala and Luna but, unfortunately they were busy, so they left me with the decision, and we came up with …

    That’s kind of silly.

    For these few reasons …

    • variety
    • album style Radio Play listening possibilities
    • perhaps getting around that …

      This video requires payment to watch YouTube

      … issue we talked about before … because you could uncheck it’s checkbox if the error appears

    • giving non-top search items a go

    … we decided to “mix it up” regarding entries like …

    Born to Run,Born to Run,Born to Run,Born to Run

    … as well as the simpler …

    Born to Run*4

    … so that repeats don’t cause users indigestion … chortle, chortle.

    Here’s the Javascript turning Born to Run*4 into Born to Run,Born to Run,Born to Run,Born to Run


    function expandrepeats(ocsl) {
    var numnum=0, minone=-1, interesting='', ninteresting='', pinteresting='', superinteresting='', imn=1;
    var retocsl=ocsl;
    var acarr=ocsl.split(',');
    for (var iac=0; iac<acarr.length; iac++) {
    numnum=0;
    minone=-1;
    if (acarr[iac].trim() != '') {
    if (acarr[iac].trim().slice(-1) >= '0' && acarr[iac].trim().slice(-1) <= '9') {
    while (('S' + acarr[iac].trim()).slice(minone).substring(0,1) >= '0' && ('S' + acarr[iac].trim()).slice(minone).substring(0,1) <= '9') {
    numnum++;
    minone--;
    }
    }
    if (numnum > 0 && numnum < eval('' + acarr[iac].trim().length)) {
    ninteresting=acarr[iac].trim().slice(-numnum);
    interesting=acarr[iac].trim().substring(0, eval(-numnum + eval('' + acarr[iac].trim().length)));
    superinteresting='';
    pinteresting='';
    if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ x\ $/g,'')) {
    pinteresting=interesting.slice(-3) + ninteresting;
    superinteresting=interesting.replace(/\ x\ $/g,'').replace(/\ X\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/x\ $/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/x\ $/g,'').replace(/X\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ x$/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\ x$/g,'').replace(/\ X$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/x$/g,'')) {
    pinteresting=interesting.slice(-1) + ninteresting;
    superinteresting=interesting.replace(/x$/g,'').replace(/X$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ \*\ $/g,'')) {
    pinteresting=interesting.slice(-3) + ninteresting;
    superinteresting=interesting.replace(/\ \*\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\*\ $/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\*\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ \*$/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\ \*$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\*$/g,'')) {
    pinteresting=interesting.slice(-1) + ninteresting;
    superinteresting=interesting.replace(/\*$/g,'');
    }
    if (superinteresting != '' && eval('' + ninteresting) >= 1) {
    for (imn=1; imn<=eval('' + ninteresting); imn++) {
    if (imn == 1) {
    retocsl=retocsl.replace(pinteresting, '');
    acarr[iac]=acarr[iac].replace(pinteresting, '');
    } else {
    retocsl=retocsl.replace(acarr[iac], acarr[iac] + ',' + superinteresting.trim());
    }
    }
    }
    }
    }
    }
    if (retocsl != ocsl) { outplist=retocsl; }
    return retocsl;
    }

    … in the changed swipe_media.html Tabular Single Row Media Gallery web application you can try for yourself (or try some more of The Boss), further to yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial.


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial

    Don’t know if you are like me, but especially when on this MacBook Air we’re, forever, using a web browser address bar to type in, what we’ve set up as, a Google search engine webpage query. Rather than even going to Google webpage first, that is!

    Most people don’t want to know about arcane web application argument arrangements … though we’re very fond of the 5 minute ones?!

    What’s wrong with some of you? Who would not relish the thought of …

    • adding onto the address bar …

      https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html

      … with new arguments( eg. https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html Born to Run,Jungleland ) …
    • ?ask=y # will get you straight to the Javascript playlist prompt window
    • &or?thelist=[commaSeparatedList_encodeURIComponent_ized] # will supply that prompt window with the answer [commaSeparatedList_decodeURIComponent_ized]
    • &or?andgo=y # will click the Radio button after all above (unless notgo is mentioned in the list somewhere), as relevant, with the programmatically determined derived YouTube ID list via YouTube search(es)
    • 💬🦆 Come On!
    • … when, after a bit of thought and tweaks to our RJM Programming domain’s Apache Document Root residing 404.shtml webpage Javascript …

      if (document.URL.indexOf('rjmprogramming.com.au/HTMLCSS/swipe_media.htm') != -1) {
      if (decodeURIComponent(document.URL).indexOf(',') != -1) {
      if (decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'')).toLowerCase().indexOf('notgo') != -1) {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?thelist=' + encodeURIComponent(decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace('notgo','').replace('NOTGO','').replace('Notgo','')));
      } else {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?andgo=y&thelist=' + encodeURIComponent(decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')));
      exit;
      }
      } else if (decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'')).toLowerCase().indexOf('ask') != -1) {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?ask=y';
      exit;
      }
      }

      … now all you need to add after that link above, on the web browser address bar is …

      [commaSeparatedList_decodeURIComponent_ized]

      … ie. just type a comma separated YouTube song search basis link after the link wording above
    • so 💬🦆 Come On down ye doubting Thomases!

    And so, further to yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial we have a changed swipe_media.html Tabular Single Row Media Gallery web application you can try for yourself.

    Stop Press

    On reflection, as well as …

    https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html Born to Run,Jungleland working up at the address bar, so, too, will https://www.rjmprogramming.com.au/ Born to Run,Jungleland


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial

    Around here, regarding web application work, we really like dropdown (ie. HTML select element) work because a lot of information can be …

    • stored
    • displayed (often taking up minimal webpage space)
    • it’s option subelements can have an event life of their own, or be part of the select element event whole picture
    • dropdown multiple selection mode (as with today’s work) can …
      1. still support your single choice scenario
      2. we’ve coded today’s dropdown to support, as applicable, ordered single click choices … versus …
      3. can allow for control key (sets of choices not necessarily adjacent) and shift key (blocks of choices)
      4. can respond (as with today’s dropdown) to preset selections established at creation via dropdown (ie. select) innerHTML option subelement selected attribute setting
    • dropdown events onmousedown and ontouchdown (as for today’s dropdown) and onclick can be harnessed ahead of an onchange event … and in today’s case can help unset any preset option subelement selected attribute setting(s)

    Just so flexible! Subelement option CSS styling can be less friendly, but even so, often background colouring is possible, and we do a bit of that with the work from yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Tutorial and today’s better “shored up” work you can see a bit of below (where your starting point might be that we “wrap” this particular Javascript prompt window through the Javascript overprompt function below) …


    var outplist='', kaconto=null, kacontoarr=[], rconeis=155, gconeis=255, bconeis=255;

    function overprompt(blb, defvl) {
    var tdsare=[], itdone=false, itds=0, baeis='', ivb=0, lastpassesmustard=true;
    var oklast=['A','E','I','M','Q','U','Y','c','g','k','o','s','w','0','4','8'];
    outplist=prompt(blb, defvl);
    if (outplist) {
    //alert(1);
    var outparrs=outplist.trim().split(',');
    //alert(11);
    if (eval('' + outparrs.length) > 1) {
    if (eval('' + outparrs[0].length) > 0) {
    if (oklast.indexOf(outparrs[0].slice(-1)) == -1) { lastpassesmustard=false; }
    }
    if ((outparrs[0] + baeis).replace(/\ \ \ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20%20%20';
    outparrs[0]=outparrs[0].replace(/\ \ \ $/g,'');
    } else if ((outparrs[0] + baeis).replace(/\ \ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20%20';
    outparrs[0]=outparrs[0].replace(/\ \ $/g,'');
    } else if ((outparrs[0] + baeis).replace(/\ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20';
    outparrs[0]=outparrs[0].replace(/\ $/g,'');
    } else {
    baeis='';
    }
    //alert(111);
    if (eval('' + outparrs[0].length) != 11 || !lastpassesmustard || encodeURIComponent(outparrs[0]) != outparrs[0]) {
    //alert(1111);
    tdsare=document.getElementsByTagName('td');
    for (itds=0; itds<tdsare.length; itds++) {
    //alert(tdsare[itds].innerHTML);
    if (!itdone && tdsare[itds].innerHTML == '' && ('' + tdsare[itds].id) != 'td0001') {
    itdone=true;
    //alert('here ' + outplist.trim().replace(/\,/g,'|!!|'));
    //tdsare[itds].innerHTML='<iframe onload=karlook(this); style="width:100%;height:100%;" id=karsearch name=karsearch src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outplist.trim().replace(/\,/g,'|!!|')) + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    tdsare[itds].innerHTML='<iframe onload=karlook(this); style="width:100%;height:80%;" id=karsearch name=karsearch src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outparrs[0]) + baeis + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    tdsare[itds].scrollIntoView();
    //alert('there ' + outplist.trim().replace(/\,/g,'|!!|'));
    baeis='';
    kacontoarr=[];
    for (ivb=1; ivb<outparrs.length; ivb++) {
    kacontoarr.push(null);
    }
    for (ivb=1; ivb<outparrs.length; ivb++) {
    tdsare[eval(itds + ivb)].innerHTML='<iframe onload=karlookagain(this,' + eval(-1 + ivb) + '); style="width:100%;height:80%;visibility:hidden;" id=karsearch' + ivb + ' src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outparrs[ivb]) + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    }
    return '';
    }
    }
    }
    }
    }
    return outplist;
    }

    function karlook(iois) {
    var aconto=null;
    aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    if (outplist.indexOf(',') != -1) {
    kaconto=aconto;
    setTimeout(function(){ kaconto.getElementById('ajaxs').style.cursor='progress'; }, 3000);
    setTimeout(postkarlook, 7000);
    } else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    kaconto=aconto;
    setTimeout(mpostkarlook, 7000);
    }
    }
    }
    }

    function karlookagain(iois,idxn) {
    var aconto=null;
    aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    if (eval('' + kacontoarr.length) > eval('' + idxn)) {
    kacontoarr[eval('' + idxn)]=aconto;
    } else {
    kacontoarr.push(aconto);
    }
    }
    }
    }

    function mpostkarlook() {
    if (kaconto.getElementById('ajaxs')) {
    var kbuts=kaconto.getElementsByTagName('input');
    for (var lbuts=0; lbuts<kbuts.length; lbuts++) {
    if (('' + kbuts[lbuts].type) == 'button') {
    if (('' + kbuts[lbuts].value).indexOf('Radio') == 0) {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', String.fromCharCode(10) + 'Radio');
    }
    }
    }
    } else {
    setTimeout(mpostkarlook, 5000);
    }
    }

    function postkarlook() {
    var selectedones='', oktogo=true, hihi=0;
    if (kaconto.getElementById('ajaxs')) {
    //alert(kaconto.getElementById('ajaxs').innerHTML);
    for (hihi=0; hihi<kacontoarr.length; hihi++) {
    if (!kacontoarr[hihi]) {
    oktogo=false;
    //alert('hihi=' + hihi + ' NOT okay');
    } else if (!kacontoarr[hihi].getElementById('ajaxs')) {
    oktogo=false;
    //alert('hihi=' + hihi + ' not okay');
    }
    }
    if (!oktogo) {
    setTimeout(postkarlook, 5000);
    } else if (kaconto.getElementById('ajaxs').innerHTML.indexOf('... and then ...') == -1) {
    kaconto.getElementById('ajaxs').style.cursor='pointer';
    var otherps=baeisf();
    if (otherps != '' || navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    var kbuts=kaconto.getElementsByTagName('input');
    for (var lbuts=0; lbuts<kbuts.length; lbuts++) {
    if (('' + kbuts[lbuts].type) == 'button') {
    if (('' + kbuts[lbuts].value).indexOf('Radio') == 0) {
    var wasvl=kbuts[lbuts].value;
    if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Ordered ' + String.fromCharCode(10) + 'Audio ' + String.fromCharCode(10) + 'Radio');
    } else if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Audio ' + String.fromCharCode(10) + 'Radio');
    } else if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Ordered ' + String.fromCharCode(10) + 'Radio');
    } else {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', String.fromCharCode(10) + 'Radio');
    }
    }
    }
    }
    }
    selectedones=(kaconto.getElementById('ajaxs').innerHTML.split(kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].split('</option>')[0] + '</option>').replace('>', ' class=uptop selected>');
    for (hihi=0; hihi<kacontoarr.length; hihi++) {
    if (rconeis == gconeis && rconeis == bconeis) {
    bconeis-=7;
    if (bconeis < 0) { bconeis+=255; }
    } else if (rconeis == gconeis) {
    gconeis-=7;
    if (gconeis < 0) { gconeis+=255; }
    } else {
    rconeis-=7;
    if (rconeis < 0) { rconeis+=255; }
    }
    selectedones+=((kacontoarr[hihi].getElementById('ajaxs').innerHTML.split(kacontoarr[hihi].getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].split('</option>')[0] + '</option>').replace('>', ' class=uptop selected>')).replace(/option\ onclick\=/g, 'option style=background-color:rgb(' + rconeis + ',' + gconeis + ',' + bconeis + '); onclick=');
    kaconto.getElementById('ajaxs').innerHTML+='<option value="">... and then ...</option>';
    kaconto.getElementById('ajaxs').innerHTML+=kacontoarr[hihi].getElementById('ajaxs').innerHTML.split(kacontoarr[hihi].getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].replace(/option\ onclick\=/g, 'option style=background-color:rgb(' + rconeis + ',' + gconeis + ',' + bconeis + '); onclick=');
    //alert(kacontoarr[hihi].getElementById('ajaxs').innerHTML);
    }
    //alert(selectedones);
    kaconto.getElementById('ajaxs').innerHTML=kaconto.getElementById('ajaxs').innerHTML.replace(kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>', kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>' + selectedones + (selectedones != '' ? '<option id=optclk value="">____ Selection above available (resettable via click here) as you click/tap button at right ____</option>' : ''));
    if (selectedones != '') {
    kaconto.getElementById('ajaxs').onmousedown=function(event){ if (event.target.parentNode.outerHTML.split('>')[0].indexOf(' data-flagged=') == -1) { event.target.parentNode.setAttribute('data-flagged','y'); event.target.parentNode.innerHTML=event.target.parentNode.innerHTML.replace(/\ selected/g, ' ').replace('____ Selection above available (resettable via click here) as you click/tap button at right ____','____ Please select choices in usual multiple choice dropdown ways ____'); } };
    kaconto.getElementById('ajaxs').ontouchdown=function(event){ if (event.target.parentNode.outerHTML.split('>')[0].indexOf(' data-flagged=') == -1) { event.target.parentNode.setAttribute('data-flagged','y'); event.target.parentNode.innerHTML=event.target.parentNode.innerHTML.replace(/\ selected/g, ' ').replace('____ Selection above available (resettable via click here) as you click/tap button at right ____','____ Please select choices in usual multiple choice dropdown ways ____'); } };
    }
    }
    }
    }

    function baeisf() {
    var outarrp=outplist.split(',');
    if (eval('' + outarrp.length) > 1) {
    return outarrp[0].replace(outarrp[0].trim(), '');
    }
    return '';
    }

    And so, today …

    • we add onto the default random ordering mode of Radio Play via YouTube search comma separated list, the further choices ordered or audio or audio ordered, as per the relevant Javascript prompt blurb that is now going …

      Enter YouTube 11 character code video (comma separated) or audio stream only of video (semicolon) list to Radio Play (and add ! to start in shuffle mode and/or # for the order you enter and/or & for whole list) … or a YouTube Search String basis for playlist via a Radio📻? button to activate, later. Comma separateds can be search ideas … egs. Tragedy,Boogie Wonderland,Down Among the Dead Men … random … Tragedy ,Imagine,Breezin … ordered … Tragedy  ,Pina Colada Song,Fast Car … audio … Tragedy   ,Galveston,Angel of the Morning … audio ordered. Double click on this cell for playlist redefinitions.

    • started allowing for dropdown events onmousedown and ontouchdown be able to reset the preset choices we programmatically select for the user should they be happy (but our motivation for this event work was the potential to run into a YouTube video that gives the error …

      This video requires payment to watch YouTube

      )

    Codewise, this involved …

    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, Operating System, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

YouTube API Command Line Shower Songs Tutorial

YouTube API Command Line Shower Songs Tutorial

YouTube API Command Line Shower Songs Tutorial

Today, we’re combining the concepts behind …

  • the recent YouTube API Caller Radio Play Doctype Meta Tutorial‘s means by which …
    1. macOS
    2. Windows

    … command line “command verb” …

    play

    … can call our “Radio Play” YouTube API interfacing means to play music …

    • sequentially
    • continuously looping (through a set of songs) or just the one song looping

    … adding into those previous arrangements the capability to call the Shower Songs web application under conditions we outlined in …

  • the work of the day before yesterday’s Shower Songs Delimitation Hashtag Tutorial

… involving changed

  1. macOS (building on the changed play.sh shell script)

    #!/bin/bash
    rest=""
    if [ -z "$1" ]; then
    echo "Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... 7 such uses Shower Songs ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men flash ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Song,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go."
    read ans
    else
    preans="$1"
    ans="$1 $2 $3 $4 $5 $6 $7 $8 $9"
    while [ ! -z "$9" ]; do
    shift
    rest="${rest} $9"
    done
    ans="$ans${rest}"
    fi
    if [ ! -z "$ans" ]; then
    commas_only="${ans//[^,]}"
    if [ "${#preans}" == "83" ]; then
    if [ "${#commas_only}" == "6" ]; then
    open "https://www.rjmprogramming.com.au/$1"
    else
    open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
    fi
    else

    open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
    fi
    fi
    exit
  2. Windows (building on the changed play.bat script)

    @echo off
    rem play.bat
    rem RJM Programming
    rem November, 2025

    set passed=
    set rest=
    set seven=0

    if trick==trick%1 (
    set /p ans=Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... 7 for Shower Songs ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Son,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go.
    set ansplus="%ans% "

    if "%ansplus:~12,1%"=="," (
    if "%ansplus:~24,1%"=="," (
    if "%ansplus:~36,1%"=="," (
    if "%ansplus:~48,1%"=="," (
    if "%ansplus:~60,1%"=="," (
    if "%ansplus:~72,1%"=="," (
    if "%ansplus:~84,1%"==" " (
    set seven=7
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=%ans%"
    goto :end
    ) else (
    set seven=6
    )
    ) else (
    set seven=5
    )
    ) else (
    set seven=4
    )
    ) else (
    set seven=3
    )
    ) else (
    set seven=2
    )
    ) else (
    set seven=1
    )
    ) else (
    set seven=0
    )


    ) else (
    set ans="%1"

    set ansplus="%1,%2,%3,%4,%5,%6,%7 %8 "

    if "%ansplus:~12,1%"=="," (
    if "%ansplus:~24,1%"=="," (
    if "%ansplus:~36,1%"=="," (
    if "%ansplus:~48,1%"=="," (
    if "%ansplus:~60,1%"=="," (
    if "%ansplus:~72,1%"=="," (
    if trick==trick%8 (
    set seven=7
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=%1,%2,%3,%4,%5,%6,%7"
    goto :end
    ) else (
    set seven=6
    )
    ) else (
    set seven=5
    )
    ) else (
    set seven=4
    )
    ) else (
    set seven=3
    )
    ) else (
    set seven=2
    )
    ) else (
    set seven=1
    )
    ) else (
    set seven=0
    )


    set passed=yes
    if trick==trick%2 goto :loop
    set ans="%ans%,%2"
    if trick==trick%3 goto :loop
    set ans="%ans%,%3"
    if trick==trick%4 goto :loop
    set ans="%ans%,%4"
    if trick==trick%5 goto :loop
    set ans="%ans%,%5"
    if trick==trick%6 goto :loop
    set ans="%ans%,%6"
    if trick==trick%7 goto :loop
    set ans="%ans%,%7"
    if trick==trick%8 goto :loop
    set ans="%ans%,%8"
    if trick==trick%9 goto :loop
    set ans="%ans%,%9"
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans:"=%"
    :loop
    if "%9"=="" (
    @echo off
    ) else (
    shift
    set rest="%rest% %9"
    goto :loop
    )
    set ans="%ans%%rest%"
    set ans=%ans:"=%
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
    )
    if trick==trick%passed% (
    set ans=%ans:"=%
    if "%ans:,=%"=="%ans%" (
    echo "Nothing to do."
    ) else (
    explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
    )
    )
    rem exit
    :end

… and involving, if you are on macOS or Windows implementing accordingly …

… a command line …


play FtE3hoR_Nvo,W5IKT_xue4o,IfaGhyK78E8,BuN3yCmHb_U,TdiAwCPb_As,euZcUku9XiE,aMs0rNtBZJk

… can loop and continuously play through that list of seven YouTube video IDs via a web browser use of our Shower Songs web application.


Previous relevant YouTube API Caller Radio Play Doctype Meta Tutorial is shown below.

YouTube API Caller Radio Play Doctype Meta Tutorial

YouTube API Caller Radio Play Doctype Meta Tutorial

It took a session on this MacBook Air’s macOS Firefox web browser trying the Tabular Single Row Media Gallery web application to emphasise the importance of more consistency checking on …

  • doctype HTML tagdeclaration …

    <!DOCTYPE html>

    … and …
  • meta HTML display tagcharset attribute …

    <meta charset="UTF-8">

… existence in web applications we create, to the point that not having the second one defined was stopping proper webpage display on Firefox. Was this a portent of what is to come soon on more web browsers?!

Let’s look at the purpose of these two HTML tagthingos …

  • doctype HTML tagdeclaration

    All HTML documents must start with a declaration.

    The declaration is not an HTML tag. It is an “information” to the browser about what document type to expect.

    … and …

  • meta HTML display tagcharset attribute

    The charset attribute specifies the character encoding for the HTML document.

    The HTML5 specification encourages web developers to use the UTF-8 character set, which covers almost all of the characters and symbols in the world!

Regarding the same web application as yesterday’s YouTube API Caller Radio Play Playlist Windows Local System Tutorial talked about, why not revisit the tweaked swipe_media.html Tabular Single Row Media Gallery web application?


Previous relevant YouTube API Caller Radio Play Playlist Windows Local System Tutorial is shown below.

YouTube API Caller Radio Play Playlist Windows Local System Tutorial

YouTube API Caller Radio Play Playlist Windows Local System Tutorial

Further to the recent YouTube API Caller Radio Play Playlist Local System Tutorial macOS local system discussion, today, we code for …

play

… to mean something on the …

Windows

… “cmd” command accessible …

command line

What’s the scripting here? They are called batch files with extension *.bat we’re calling play.bat (going back to the DOS days of the ’70’s again). With *.bat you just need to plonk your play.bat anywhere within the Windows local system path, and the word (now command) “play” will do the rest anywhere in that user’s command line environment. And the batch file has …


@echo off
rem play.bat
rem RJM Programming
rem November, 2025

set passed=
set rest=

if trick==trick%1 (
set /p ans=Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Son,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go.
) else (
set ans="%1"
set passed=yes
if trick==trick%2 goto :loop
set ans="%ans%,%2"
if trick==trick%3 goto :loop
set ans="%ans%,%3"
if trick==trick%4 goto :loop
set ans="%ans%,%4"
if trick==trick%5 goto :loop
set ans="%ans%,%5"
if trick==trick%6 goto :loop
set ans="%ans%,%6"
if trick==trick%7 goto :loop
set ans="%ans%,%7"
if trick==trick%8 goto :loop
set ans="%ans%,%8"
if trick==trick%9 goto :loop
set ans="%ans%,%9"
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans:"=%"
:loop
if "%9"=="" (
@echo off
) else (
shift
set rest="%rest%,%9"
goto :loop
)
set ans="%ans%%rest%"
set ans=%ans:"=%
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
if trick==trick%passed% (
set ans=%ans:"=%
if "%ans:,=%"=="%ans%" (
echo "Nothing to do."
) else (
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
)
rem exit
:end

… as your starting gambit, here, where the equivalent of macOS’s “open” is “explorer.exe” on Windows (ie. the File Explorer) … almost as cute!


Previous relevant YouTube API Caller Radio Play Playlist Local System Tutorial is shown below.

YouTube API Caller Radio Play Playlist Local System Tutorial

YouTube API Caller Radio Play Playlist Local System Tutorial

The ..

command line

… of a laptop or notebook or personal computer can be an environment to relax from the GUI aspects of your modern operating systems and think about …

  • processes
  • batch driven tasks
  • task simplifications

… and in the category of that last one, on our local macOS operating system we envisaged a day we could slip back to the “quiet world” of the “command line” and type a command like …


play Tragedy,Imagine,Down Among the Dead Men PAN -

… and get somewhere playing those songs through a web browser accessing the YouTube API and our interfacings to it in webpage software form, playing in a continuous Radio Play style.

You see, with all the distractions, only having to remember …

play

… no matter where we were in “command line” woooorrrrllllddd seemed the ideal, and yes, it’s possible. However, we think explaining …


bash /Applications/MAMP/htdocs/play.ksh Tragedy,Imagine,Down Among the Dead Men PAN -

… is a necessary dividing line between two parts to the discussion. So what’s bash? It’s the shell we associate as your macOS default shell (we get to via the “out of the box” macOS desktop application called Terminal) … well, it used to be … anyway, the first line of (what started as play.ksh then play.sh and then eventually, just, play … as a filename that is) …


#!/bin/bash
rest=""
if [ -z "$1" ]; then
echo "Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Song,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go."
read ans
else
ans="$1 $2 $3 $4 $5 $6 $7 $8 $9"
while [ ! -z "$9" ]; do
shift
rest="${rest} $9"
done
ans="$ans${rest}"
fi
if [ ! -z "$ans" ]; then
open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
fi
exit

… tells the local system use the bash shell to interpret this what you might like to think of as an executable script (which we went chmod 777 play regarding to make it so).

Okay, so we wrote this script in /Applications/MAMP/htdocs/ and that …


bash /Applications/MAMP/htdocs/play Tragedy,Imagine,Down Among the Dead Men PAN -

… could swing it at this stage, or even being in /Applications/MAMP/htdocs/ and going …


./play Tragedy,Imagine,Down Among the Dead Men PAN -

… but (even in /Applications/MAMP/htdocs/) …


play Tragedy,Imagine,Down Among the Dead Men PAN -

… is most likely to reply something like …

zsh: no such command

As the programmer, perhaps you could leave it at that with your “insider knowledge”, or if “play” as a command already meant something (a test that would be good to do before any such proposed work), otherwise … do you really think you’ll remember next Wednesday? So …

  1. enter into the wooooorrrrllllddd of aliases (thanks to this great advice, thanks) … eg.

    alias play="/Applications/MAMP/htdocs/play"
  2. placed into …

    ~/.bashrc

    … via (in our case) …

    vi ~/.bashrc
  3. then …

    source ~/.bashrc

    … needs to be included into the login procedure of …

    ~/.profile

    …via (in our case) …

    vi ~/.profile
  4. to make …

    play

    … as the interactively asking alternative to the argumentative example of …

    play Tragedy,Imagine,Down Among the Dead Men PAN -

    … mean something … and anywhere

    … all of this possible because of the brilliantly useful macOS (not Linux nor unix) …


    open

    … opener of web browsers from the command line blowing of our tiny little rather still naive mind … mind you, VAX/VMS “phone” command from the ’70’s might have even been better?! And then there were those punch cards … in the hopper … and if you got a character wrong … back to the end of the queue.

    Sorry … we got a bit hot and bothered there!

    Anyway, as a layer of thought on top of the recent YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial‘s mildly changed swipe_media.html Tabular Single Row Media Gallery web application work it might be a thing you want to pursue yourself?

    By the way, this brought into play for us what your default web browser is. Ours is Safari yet we develop more on Google Chrome. Safari, for us, does more Popup Blocking, and it is a thing to look out for should a window not open when expected (and these command line methodologies don’t get past you still having to unmute and/or click/tap once before the Radio Play mode of play kicks off). To undo the Popup Block there will probably be a means to do this to the right of the web browser address bar.


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial

    Burp …

    Sorry to open with a quote, and sorry to repeat myself, like.

    And sorry to repeat myself, like, again.

    But there is a point. Today represents an improvement on yesterday’s arrangements for dynamic playlist creation regarding our Tabular Single Row Media Gallery web application via the playlist emoji button 🔀 click/tap or on the web browser command line. With yesterday’s scenario, had you entered as your internal playlist comma separated string …

    Born to Run,Born to Run,Born to Run,Born to Run

    … without the …

    Burp …

    that is you’d have ended up with the top find off a YouTube search repeated 4 times. Is this ideal? We asked Nala and Luna but, unfortunately they were busy, so they left me with the decision, and we came up with …

    That’s kind of silly.

    For these few reasons …

    • variety
    • album style Radio Play listening possibilities
    • perhaps getting around that …

      This video requires payment to watch YouTube

      … issue we talked about before … because you could uncheck it’s checkbox if the error appears

    • giving non-top search items a go

    … we decided to “mix it up” regarding entries like …

    Born to Run,Born to Run,Born to Run,Born to Run

    … as well as the simpler …

    Born to Run*4

    … so that repeats don’t cause users indigestion … chortle, chortle.

    Here’s the Javascript turning Born to Run*4 into Born to Run,Born to Run,Born to Run,Born to Run


    function expandrepeats(ocsl) {
    var numnum=0, minone=-1, interesting='', ninteresting='', pinteresting='', superinteresting='', imn=1;
    var retocsl=ocsl;
    var acarr=ocsl.split(',');
    for (var iac=0; iac<acarr.length; iac++) {
    numnum=0;
    minone=-1;
    if (acarr[iac].trim() != '') {
    if (acarr[iac].trim().slice(-1) >= '0' && acarr[iac].trim().slice(-1) <= '9') {
    while (('S' + acarr[iac].trim()).slice(minone).substring(0,1) >= '0' && ('S' + acarr[iac].trim()).slice(minone).substring(0,1) <= '9') {
    numnum++;
    minone--;
    }
    }
    if (numnum > 0 && numnum < eval('' + acarr[iac].trim().length)) {
    ninteresting=acarr[iac].trim().slice(-numnum);
    interesting=acarr[iac].trim().substring(0, eval(-numnum + eval('' + acarr[iac].trim().length)));
    superinteresting='';
    pinteresting='';
    if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ x\ $/g,'')) {
    pinteresting=interesting.slice(-3) + ninteresting;
    superinteresting=interesting.replace(/\ x\ $/g,'').replace(/\ X\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/x\ $/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/x\ $/g,'').replace(/X\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ x$/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\ x$/g,'').replace(/\ X$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/x$/g,'')) {
    pinteresting=interesting.slice(-1) + ninteresting;
    superinteresting=interesting.replace(/x$/g,'').replace(/X$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ \*\ $/g,'')) {
    pinteresting=interesting.slice(-3) + ninteresting;
    superinteresting=interesting.replace(/\ \*\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\*\ $/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\*\ $/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\ \*$/g,'')) {
    pinteresting=interesting.slice(-2) + ninteresting;
    superinteresting=interesting.replace(/\ \*$/g,'');
    } else if (interesting.toLowerCase() != interesting.toLowerCase().replace(/\*$/g,'')) {
    pinteresting=interesting.slice(-1) + ninteresting;
    superinteresting=interesting.replace(/\*$/g,'');
    }
    if (superinteresting != '' && eval('' + ninteresting) >= 1) {
    for (imn=1; imn<=eval('' + ninteresting); imn++) {
    if (imn == 1) {
    retocsl=retocsl.replace(pinteresting, '');
    acarr[iac]=acarr[iac].replace(pinteresting, '');
    } else {
    retocsl=retocsl.replace(acarr[iac], acarr[iac] + ',' + superinteresting.trim());
    }
    }
    }
    }
    }
    }
    if (retocsl != ocsl) { outplist=retocsl; }
    return retocsl;
    }

    … in the changed swipe_media.html Tabular Single Row Media Gallery web application you can try for yourself (or try some more of The Boss), further to yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial.


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial

    Don’t know if you are like me, but especially when on this MacBook Air we’re, forever, using a web browser address bar to type in, what we’ve set up as, a Google search engine webpage query. Rather than even going to Google webpage first, that is!

    Most people don’t want to know about arcane web application argument arrangements … though we’re very fond of the 5 minute ones?!

    What’s wrong with some of you? Who would not relish the thought of …

    • adding onto the address bar …

      https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html

      … with new arguments( eg. https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html Born to Run,Jungleland ) …
    • ?ask=y # will get you straight to the Javascript playlist prompt window
    • &or?thelist=[commaSeparatedList_encodeURIComponent_ized] # will supply that prompt window with the answer [commaSeparatedList_decodeURIComponent_ized]
    • &or?andgo=y # will click the Radio button after all above (unless notgo is mentioned in the list somewhere), as relevant, with the programmatically determined derived YouTube ID list via YouTube search(es)
    • 💬🦆 Come On!
    • … when, after a bit of thought and tweaks to our RJM Programming domain’s Apache Document Root residing 404.shtml webpage Javascript …

      if (document.URL.indexOf('rjmprogramming.com.au/HTMLCSS/swipe_media.htm') != -1) {
      if (decodeURIComponent(document.URL).indexOf(',') != -1) {
      if (decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'')).toLowerCase().indexOf('notgo') != -1) {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?thelist=' + encodeURIComponent(decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace('notgo','').replace('NOTGO','').replace('Notgo','')));
      } else {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?andgo=y&thelist=' + encodeURIComponent(decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')));
      exit;
      }
      } else if (decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'')).toLowerCase().indexOf('ask') != -1) {
      location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?ask=y';
      exit;
      }
      }

      … now all you need to add after that link above, on the web browser address bar is …

      [commaSeparatedList_decodeURIComponent_ized]

      … ie. just type a comma separated YouTube song search basis link after the link wording above
    • so 💬🦆 Come On down ye doubting Thomases!

    And so, further to yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial we have a changed swipe_media.html Tabular Single Row Media Gallery web application you can try for yourself.

    Stop Press

    On reflection, as well as …

    https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html Born to Run,Jungleland working up at the address bar, so, too, will https://www.rjmprogramming.com.au/ Born to Run,Jungleland


    Previous relevant YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial is shown below.

    YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial

    Around here, regarding web application work, we really like dropdown (ie. HTML select element) work because a lot of information can be …

    • stored
    • displayed (often taking up minimal webpage space)
    • it’s option subelements can have an event life of their own, or be part of the select element event whole picture
    • dropdown multiple selection mode (as with today’s work) can …
      1. still support your single choice scenario
      2. we’ve coded today’s dropdown to support, as applicable, ordered single click choices … versus …
      3. can allow for control key (sets of choices not necessarily adjacent) and shift key (blocks of choices)
      4. can respond (as with today’s dropdown) to preset selections established at creation via dropdown (ie. select) innerHTML option subelement selected attribute setting
    • dropdown events onmousedown and ontouchdown (as for today’s dropdown) and onclick can be harnessed ahead of an onchange event … and in today’s case can help unset any preset option subelement selected attribute setting(s)

    Just so flexible! Subelement option CSS styling can be less friendly, but even so, often background colouring is possible, and we do a bit of that with the work from yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Tutorial and today’s better “shored up” work you can see a bit of below (where your starting point might be that we “wrap” this particular Javascript prompt window through the Javascript overprompt function below) …


    var outplist='', kaconto=null, kacontoarr=[], rconeis=155, gconeis=255, bconeis=255;

    function overprompt(blb, defvl) {
    var tdsare=[], itdone=false, itds=0, baeis='', ivb=0, lastpassesmustard=true;
    var oklast=['A','E','I','M','Q','U','Y','c','g','k','o','s','w','0','4','8'];
    outplist=prompt(blb, defvl);
    if (outplist) {
    //alert(1);
    var outparrs=outplist.trim().split(',');
    //alert(11);
    if (eval('' + outparrs.length) > 1) {
    if (eval('' + outparrs[0].length) > 0) {
    if (oklast.indexOf(outparrs[0].slice(-1)) == -1) { lastpassesmustard=false; }
    }
    if ((outparrs[0] + baeis).replace(/\ \ \ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20%20%20';
    outparrs[0]=outparrs[0].replace(/\ \ \ $/g,'');
    } else if ((outparrs[0] + baeis).replace(/\ \ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20%20';
    outparrs[0]=outparrs[0].replace(/\ \ $/g,'');
    } else if ((outparrs[0] + baeis).replace(/\ $/g,'') != (outparrs[0] + baeis)) {
    baeis='&domatters=&20';
    outparrs[0]=outparrs[0].replace(/\ $/g,'');
    } else {
    baeis='';
    }
    //alert(111);
    if (eval('' + outparrs[0].length) != 11 || !lastpassesmustard || encodeURIComponent(outparrs[0]) != outparrs[0]) {
    //alert(1111);
    tdsare=document.getElementsByTagName('td');
    for (itds=0; itds<tdsare.length; itds++) {
    //alert(tdsare[itds].innerHTML);
    if (!itdone && tdsare[itds].innerHTML == '' && ('' + tdsare[itds].id) != 'td0001') {
    itdone=true;
    //alert('here ' + outplist.trim().replace(/\,/g,'|!!|'));
    //tdsare[itds].innerHTML='<iframe onload=karlook(this); style="width:100%;height:100%;" id=karsearch name=karsearch src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outplist.trim().replace(/\,/g,'|!!|')) + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    tdsare[itds].innerHTML='<iframe onload=karlook(this); style="width:100%;height:80%;" id=karsearch name=karsearch src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outparrs[0]) + baeis + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    tdsare[itds].scrollIntoView();
    //alert('there ' + outplist.trim().replace(/\,/g,'|!!|'));
    baeis='';
    kacontoarr=[];
    for (ivb=1; ivb<outparrs.length; ivb++) {
    kacontoarr.push(null);
    }
    for (ivb=1; ivb<outparrs.length; ivb++) {
    tdsare[eval(itds + ivb)].innerHTML='<iframe onload=karlookagain(this,' + eval(-1 + ivb) + '); style="width:100%;height:80%;visibility:hidden;" id=karsearch' + ivb + ' src="/HTMLCSS/karaoke_youtube_api.htm?youtubeid=++++++++++++' + encodeURIComponent(outparrs[ivb]) + '&minimize=y&youtube_duration=&email=&emoji=on&clickcheck=y"></iframe>';
    }
    return '';
    }
    }
    }
    }
    }
    return outplist;
    }

    function karlook(iois) {
    var aconto=null;
    aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    if (outplist.indexOf(',') != -1) {
    kaconto=aconto;
    setTimeout(function(){ kaconto.getElementById('ajaxs').style.cursor='progress'; }, 3000);
    setTimeout(postkarlook, 7000);
    } else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    kaconto=aconto;
    setTimeout(mpostkarlook, 7000);
    }
    }
    }
    }

    function karlookagain(iois,idxn) {
    var aconto=null;
    aconto = (iois.contentWindow || iois.contentDocument);
    if (aconto != null) {
    if (aconto.document) { aconto = aconto.document; }
    if (aconto.body != null) {
    if (eval('' + kacontoarr.length) > eval('' + idxn)) {
    kacontoarr[eval('' + idxn)]=aconto;
    } else {
    kacontoarr.push(aconto);
    }
    }
    }
    }

    function mpostkarlook() {
    if (kaconto.getElementById('ajaxs')) {
    var kbuts=kaconto.getElementsByTagName('input');
    for (var lbuts=0; lbuts<kbuts.length; lbuts++) {
    if (('' + kbuts[lbuts].type) == 'button') {
    if (('' + kbuts[lbuts].value).indexOf('Radio') == 0) {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', String.fromCharCode(10) + 'Radio');
    }
    }
    }
    } else {
    setTimeout(mpostkarlook, 5000);
    }
    }

    function postkarlook() {
    var selectedones='', oktogo=true, hihi=0;
    if (kaconto.getElementById('ajaxs')) {
    //alert(kaconto.getElementById('ajaxs').innerHTML);
    for (hihi=0; hihi<kacontoarr.length; hihi++) {
    if (!kacontoarr[hihi]) {
    oktogo=false;
    //alert('hihi=' + hihi + ' NOT okay');
    } else if (!kacontoarr[hihi].getElementById('ajaxs')) {
    oktogo=false;
    //alert('hihi=' + hihi + ' not okay');
    }
    }
    if (!oktogo) {
    setTimeout(postkarlook, 5000);
    } else if (kaconto.getElementById('ajaxs').innerHTML.indexOf('... and then ...') == -1) {
    kaconto.getElementById('ajaxs').style.cursor='pointer';
    var otherps=baeisf();
    if (otherps != '' || navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
    var kbuts=kaconto.getElementsByTagName('input');
    for (var lbuts=0; lbuts<kbuts.length; lbuts++) {
    if (('' + kbuts[lbuts].type) == 'button') {
    if (('' + kbuts[lbuts].value).indexOf('Radio') == 0) {
    var wasvl=kbuts[lbuts].value;
    if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Ordered ' + String.fromCharCode(10) + 'Audio ' + String.fromCharCode(10) + 'Radio');
    } else if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Audio ' + String.fromCharCode(10) + 'Radio');
    } else if (otherps == ' ') {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Ordered ' + String.fromCharCode(10) + 'Radio');
    } else {
    kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', String.fromCharCode(10) + 'Radio');
    }
    }
    }
    }
    }
    selectedones=(kaconto.getElementById('ajaxs').innerHTML.split(kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].split('</option>')[0] + '</option>').replace('>', ' class=uptop selected>');
    for (hihi=0; hihi<kacontoarr.length; hihi++) {
    if (rconeis == gconeis && rconeis == bconeis) {
    bconeis-=7;
    if (bconeis < 0) { bconeis+=255; }
    } else if (rconeis == gconeis) {
    gconeis-=7;
    if (gconeis < 0) { gconeis+=255; }
    } else {
    rconeis-=7;
    if (rconeis < 0) { rconeis+=255; }
    }
    selectedones+=((kacontoarr[hihi].getElementById('ajaxs').innerHTML.split(kacontoarr[hihi].getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].split('</option>')[0] + '</option>').replace('>', ' class=uptop selected>')).replace(/option\ onclick\=/g, 'option style=background-color:rgb(' + rconeis + ',' + gconeis + ',' + bconeis + '); onclick=');
    kaconto.getElementById('ajaxs').innerHTML+='<option value="">... and then ...</option>';
    kaconto.getElementById('ajaxs').innerHTML+=kacontoarr[hihi].getElementById('ajaxs').innerHTML.split(kacontoarr[hihi].getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].replace(/option\ onclick\=/g, 'option style=background-color:rgb(' + rconeis + ',' + gconeis + ',' + bconeis + '); onclick=');
    //alert(kacontoarr[hihi].getElementById('ajaxs').innerHTML);
    }
    //alert(selectedones);
    kaconto.getElementById('ajaxs').innerHTML=kaconto.getElementById('ajaxs').innerHTML.replace(kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>', kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>' + selectedones + (selectedones != '' ? '<option id=optclk value="">____ Selection above available (resettable via click here) as you click/tap button at right ____</option>' : ''));
    if (selectedones != '') {
    kaconto.getElementById('ajaxs').onmousedown=function(event){ if (event.target.parentNode.outerHTML.split('>')[0].indexOf(' data-flagged=') == -1) { event.target.parentNode.setAttribute('data-flagged','y'); event.target.parentNode.innerHTML=event.target.parentNode.innerHTML.replace(/\ selected/g, ' ').replace('____ Selection above available (resettable via click here) as you click/tap button at right ____','____ Please select choices in usual multiple choice dropdown ways ____'); } };
    kaconto.getElementById('ajaxs').ontouchdown=function(event){ if (event.target.parentNode.outerHTML.split('>')[0].indexOf(' data-flagged=') == -1) { event.target.parentNode.setAttribute('data-flagged','y'); event.target.parentNode.innerHTML=event.target.parentNode.innerHTML.replace(/\ selected/g, ' ').replace('____ Selection above available (resettable via click here) as you click/tap button at right ____','____ Please select choices in usual multiple choice dropdown ways ____'); } };
    }
    }
    }
    }

    function baeisf() {
    var outarrp=outplist.split(',');
    if (eval('' + outarrp.length) > 1) {
    return outarrp[0].replace(outarrp[0].trim(), '');
    }
    return '';
    }

    And so, today …

    • we add onto the default random ordering mode of Radio Play via YouTube search comma separated list, the further choices ordered or audio or audio ordered, as per the relevant Javascript prompt blurb that is now going …

      Enter YouTube 11 character code video (comma separated) or audio stream only of video (semicolon) list to Radio Play (and add ! to start in shuffle mode and/or # for the order you enter and/or & for whole list) … or a YouTube Search String basis for playlist via a Radio📻? button to activate, later. Comma separateds can be search ideas … egs. Tragedy,Boogie Wonderland,Down Among the Dead Men … random … Tragedy ,Imagine,Breezin … ordered … Tragedy  ,Pina Colada Song,Fast Car … audio … Tragedy   ,Galveston,Angel of the Morning … audio ordered. Double click on this cell for playlist redefinitions.

    • started allowing for dropdown events onmousedown and ontouchdown be able to reset the preset choices we programmatically select for the user should they be happy (but our motivation for this event work was the potential to run into a YouTube video that gives the error …

      This video requires payment to watch YouTube

      )

    Codewise, this involved …

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


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


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


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


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


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


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


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

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

Keyboard Shortcuts for Bluetooth on macOS Tutorial

Keyboard Shortcuts for Bluetooth on macOS Tutorial

Keyboard Shortcuts for Bluetooth on macOS Tutorial

What is macOS Spotlight?

Spotlight is macOS’s built-in, system-wide search engine. Activated by pressing Command + Spacebar, it lets you instantly find files, launch apps, perform math calculations, convert currency, check weather, and run quick system commands without leaving your current window.

… or, for the purposes of today’s tutorial’s purposes, is the bosom buddy, on macOS, of …

Keyboard Shortcuts

… because, after that initial …

Command + Spacebar

… keyboard … shortcut … to get to the Spotlight desktop application, just about everything is possible to get to, to many degrees, without relying on any clicks anywhere, as the previous Windows and macOS Hanging Useful Keyboard Shortcuts Tutorial set the scene for, too.

So, why the interest?

Well, we got into a spot of bother where it became very useful to use (just keyboard) …

  1. Command + Spacebar
  2. Bluetooth
  3. Return key
  4. Arrow down to Bluetooth File Exchange
  5. Return key
  6. Arrow down to (in our case) M720 Triathlon
  7. Return key

… one day. Huh?!

Let me explain. We’ve had clicking problems with this MacBook Air’s trackpad to do with it’s clicking capabilities only (ie. swipe gestures still worked), and, as we gave a bit of the background to with Bluetooth Mouse Show Desktop Primer Tutorial the way we worked around this was to buy and install a bluetooth mouse from Logitech called the M720 Triathlon. All good for more than a year now. But one day we turned Bluetooth Off then rebooted the MacBook Air. Ouch?! Sure, we could log in to the desktop, but doing much else easily relied on …

  • a fully functional trackpad … or, what could of worked if we’d arranged it …
  • an installed USB lead based mouse … or even, perhaps, we’re not sure …
  • plugging in some USB lead based mouse that is plug and play

… none of which were available to me. But good ol’ Spotlight and Keyboard Shortcuts were (ie. to reconnect the bluetooth mouse)! Yayyyyyy!

Can hear some of you asking …

So, what happens when the M720 Triathlon runs out of battery? Isn’t it the same panic?

Well, it happened last week, and we were wondering too! A message comes up on the macOS screen to say the M720 Triathlon is low on battery power, and we just took that message at it’s word, changing the battery, and carried on.

Can hear some of you asking …

So, do the M720 Triathlon and what’s left of the trackpad’s functionality get in each other’s way?

No, they can either or both work at whatever they are capable of.


Previous relevant Windows and macOS Hanging Useful Keyboard Shortcuts Tutorial is shown below.

Windows and macOS Hanging Useful Keyboard Shortcuts Tutorial

Windows and macOS Hanging Useful Keyboard Shortcuts Tutorial

Revisiting the Dots and Boxes game of Dots and Boxes Game Parameterization Tutorial today, on this macOS MacBook Air …

Shock, Horror, Tragedy

… it gave us that very annoying “hanging experience” to the extent that our MacBook Air rebooted itself. And so, given this, we hereby apologize if a previous version of the Dots and Boxes game has caused you any grief.

But the fix to our dots_and_boxes_game.html Dots and Boxes game was a “one number different” fix, and rather than short change our readers … heaven forbid … we’re going to focus, today, more on what keyboard shortcuts on macOS or Windows might help you out in the bad scenario described above …

keyboard shortcut for force quit current application

For Mac, press Option + Command + Esc to open the Force Quit window, or hold Option + Command + Shift + Esc for three seconds to force quit the active app directly. For Windows, press Alt + F4 to close the active app, or Ctrl + Shift + Esc to open Task Manager to kill processes.

Mac Force Quit Shortcuts:
Force Quit Dialog: Option + Command + Esc
Force Quit Focused App: Option + Command + Shift + Esc (hold for 3 seconds)
Standard Quit: Command + Q

Windows Force Quit Shortcuts:
Close Active App: Alt + F4
Open Task Manager (to terminate app): Ctrl + Shift + Esc
Alternative Task Manager: Ctrl + Alt + Delete then select Task Manager

Linux/Other:
Xkill: Ctrl + Alt + Esc (often used to click and destroy a window)

These may or may not help depending on the severity of the memory issue you are facing, in which case …

keyboard shortcut for rebooting on operating system

For Windows, use Win + X then U then R for a fast restart. Alternatively, Alt + F4 on the desktop opens a shutdown menu. For Mac, use Control + Command + Power Button to force a restart. These methods allow full system control without a mouse.

Windows Restart Shortcuts
Power User Menu (Fastest): Press Win + X, then U, then R.
Desktop Shutdown: Press Alt + F4 while on the desktop to open the shutdown dialog, then select “Restart”.
Ctrl+Alt+Del: Press Ctrl + Alt + Del, use arrow keys to reach the power icon, press Enter, and select “Restart”.
Run Command: Press Win + R, type shutdown -r -t 0, and hit Enter.

macOS Restart Shortcuts
Force Restart: Control + Command + Power button (or Touch ID button).
Standard Restart: Control + Option + Command + Power button (closes apps, then restarts).

Linux/Other
Alt+SysRq+B: Forcibly reboots the system immediately.

We hope, one day, but not too soon, you find this useful?!


Previous relevant Dots and Boxes Game Parameterization Tutorial is shown below.

Dots and Boxes Game Parameterization Tutorial

Dots and Boxes Game Parameterization Tutorial

We quite like …

  • substitutional approaches to coding
  • interpretive approaches to coding
  • take a hardcoded string and either …
    1. parameterize it
    2. repurpose it

… and with the “Dots and Boxes Game” web application of yesterday’s Dots and Boxes Game Primer Tutorial it’s a case of parameterizing the table …

  • number of “span” cells across (used to be 100)
  • number of “span” cells down (used to be 20)

… as per the device width dependant …


var xacross=Math.min(100,Math.round(eval('' + screen.width) / 14.40)); //100;
var ydown=Math.round(eval(xacross / 5)); //20;

… teamed with changes to 100 and 20 and “near to” Javascript code hardcodings changed into forms of “xacross” and “ydown” variables above.

And then there is the hardcoding “Score” we wanted to repurpose so as to allow the user control of whether …

  • notifications
  • “say” audio
  • “toast” message box

… are persisted with, via “toggling code” as per …


var snotifications_on=true;
var osay_on=((('' + navigator.platform.toUpperCase()).indexOf('MAC') >= 0) ? true : false);
var etoast_on=(navigator.userAgent.match(/Android|BlackBerry|iPhone|iPod|Opera Mini|IEMobile/i) ? true : false);

function pse(insc, istoast) { // insc is "Score "
var outsc=insc;
if (outsc.indexOf('Score') == 0) {
outsc=outsc.replace('e', '<a title="Toggle toast show status ' + ('' + etoast_on) + '" onclick="etoast_on=!etoast_on; this.title+=String.fromCharCode(32) + etoast_on;" style="cursor:pointer;text-decoration:none;color:' + (istoast ? 'magenta' : 'magenta') + ';">e</a>');
outsc=outsc.replace('o', '<a title="Toggle say try status ' + ('' + osay_on) + '" onclick="osay_on=!osay_on; this.title+=String.fromCharCode(32) + osay_on;" style="cursor:pointer;text-decoration:none;color:' + (istoast ? 'white' : 'purple') + ';">o</a>');
outsc=outsc.replace('S', '<a title="Toggle notifications try status ' + ('' + osay_on) + '" onclick="snotifications_on=!snotifications_on; this.title+=String.fromCharCode(32) + snotifications_on;" style="cursor:pointer;text-decoration:none;color:' + (istoast ? 'white' : 'blue') + ';">S</a>');
}
return outsc;
}

… in all of the recent …


Previous relevant Dots and Boxes Game Primer Tutorial is shown below.

Dots and Boxes Game Primer Tutorial

Dots and Boxes Game Primer Tutorial

Today, do you fancy …

Morphing a clone

… or should that be …

Cloning a morph

… onto yesterday’s SOS Game Primer Tutorial with our new “Dots and Boxes” game?

Yes, that’s it for us today, simply because the “morphed into” is a lot like “the end result”, our new Dots and Boxes Game. After all, both are …

  • online games
  • on a board
  • with span cells
  • containing onclick logic
  • ideally for 2 or more players

And as for the onclick logic Javascript logic? We can’t remember relying on the outerHTML (ie. the entire HTML element expressed as HTML) of an HTML (span) element for the (onclick event) logic basis, as per (the plug in code different to (and the same as) yesterday’s code)


if (document.getElementById('names')) {
if (document.getElementById('names').value == '' && document.getElementById('names').placeholder.indexOf(',') != -1) {
document.getElementById('names').value=document.getElementById('names').placeholder;
//alert(1);
document.getElementById('numsel').value='' + document.getElementById('names').value.split(',').length;
//alert(document.getElementById('numsel').value);
nparrange(document.getElementById('numsel'));
//alert(11);
document.getElementById('smore').innerHTML=notify('Your go ' + anames[curplayer]);
}
}
console.log('1');
if (spano.innerHTML.toLowerCase() == 's' || spano.innerHTML.toLowerCase() == 'o') { return true; }
console.log('2');
var rtis=spano.getBoundingClientRect();
console.log('3');
e = e || window.event;
e.preventDefault();

if (e.touches) {
if (e.touches[0].pageX) {
xx = e.touches[0].pageX;
yy = e.touches[0].pageY;
} else {
xx = e.touches[0].clientX;
yy = e.touches[0].clientY;
}
//console.log('pos3=' + pos3 + ',pos4=' + pos4);
} else if (e.clientX || e.clientY) {
xx = e.clientX;
yy = e.clientY;
} else {
xx = e.pageX;
yy = e.pageY;
}


var topm=eval(yy - rtis.top);
var bottomm=eval(rtis.bottom - yy);
var leftm=eval(xx - rtis.left);
var rightm=eval(rtis.right - xx);


var sbl=eval('' + noc(spano.outerHTML).split('border-').length);
var sbc=eval('' + spano.outerHTML.split('background-color').length);


var thislet=' ';
var locsubscore=0;
var thisi=eval(spano.id.replace('span',''));
if (Math.min(topm, bottomm,leftm,rightm) == leftm || Math.min(topm, bottomm,leftm,rightm) == rightm) { // s
if (Math.min(topm, bottomm,leftm,rightm) == leftm) { // s
thislet='border-left:2px solid ' + bcols[curplayer]; //alert(56);
spano.style.borderLeft=thislet.split(':')[1];
//document.getElementById('myh4').style.fontSize='6px';
//document.getElementById('myh4').innerHTML='thisi=' + thisi + ' border-left and ' + eval(-1 + thisi) + ' is border-right ' + spano.outerHTML.replace(/\>/g,'>').replace(/\</g,'<');
if ((sbl == 4 && noc(spano.outerHTML).split('border-').length >= 4) && sbc == 1) {
//if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
//alert('' + sbl + ' 1:' + noc(spano.outerHTML).split('border-').length + ' ' + spano.outerHTML);
//}
spano.style.backgroundColor=bcols[curplayer];
//alert(1);
locsubscore++;
} //else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && sbl == 4 && sbc == 1) {
//alert('1:' + spano.outerHTML.split('border-').length + ' ' + spano.outerHTML);
//}
if (eval(thisi % 100) >= 1) {
sbl=eval('' + noc(document.getElementById('span' + eval(-1 + thisi)).outerHTML).split('border-').length);
sbc=eval('' + document.getElementById('span' + eval(-1 + thisi)).outerHTML.split('background-color').length);
document.getElementById('span' + eval(-1 + thisi)).style.borderRight=thislet.split(':')[1];
if ((sbl == 4 && noc(document.getElementById('span' + eval(-1 + thisi)).outerHTML).split('border-').length >= 4) && sbc == 1) { //if (document.getElementById('span' + eval(-1 + thisi)).outerHTML.split('border-').length == 5 && document.getElementById('span' + eval(-1 + thisi)).outerHTML.split('background-color').length == 1) {
document.getElementById('span' + eval(-1 + thisi)).style.backgroundColor=bcols[curplayer];
locsubscore++;
}
}
} else {
thislet='border-right:2px solid ' + bcols[curplayer]; //alert(56);
spano.style.borderRight=thislet.split(':')[1];
//document.getElementById('myh4').style.fontSize='6px';
//document.getElementById('myh4').innerHTML='thisi=' + thisi + ' border-right and ' + eval(1 + thisi) + ' is border-left ' + spano.outerHTML.replace(/\>/g,'>').replace(/\</g,'<');
if ((sbl == 4 && noc(spano.outerHTML).split('border-').length >= 4) && sbc == 1) {
spano.style.backgroundColor=bcols[curplayer];
//alert(2);
//if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
//alert('' + sbl + ' 2:' + noc(spano.outerHTML).split('border-').length + ' ' + spano.outerHTML);
//}
locsubscore++;
} //else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && sbl == 4 && sbc == 1) {
//alert('2:' + spano.outerHTML.split('border-').length + ' ' + spano.outerHTML);
//}
if (eval(thisi % 100) <= 98) {
sbl=eval('' + noc(document.getElementById('span' + eval(1 + thisi)).outerHTML).split('border-').length);
sbc=eval('' + document.getElementById('span' + eval(1 + thisi)).outerHTML.split('background-color').length);
document.getElementById('span' + eval(1 + thisi)).style.borderLeft=thislet.split(':')[1];
if ((sbl == 4 && noc(document.getElementById('span' + eval(1 + thisi)).outerHTML).split('border-').length >= 4) && sbc == 1) { //if (document.getElementById('span' + eval(1 + thisi)).outerHTML.split('border-').length == 5 && document.getElementById('span' + eval(1 + thisi)).outerHTML.split('background-color').length == 1) {
document.getElementById('span' + eval(1 + thisi)).style.backgroundColor=bcols[curplayer];
locsubscore++;
}
}
}
thislet='&nbsp;'; //'S';
spano.innerHTML=thislet;
spano.style.color='rgb(128,0,128)'; //'#000000';
} else {
if (Math.min(topm, bottomm,leftm,rightm) == bottomm) { // s
thislet='border-bottom:2px solid ' + bcols[curplayer]; //alert(56);
spano.style.borderBottom=thislet.split(':')[1];
//document.getElementById('myh4').style.fontSize='6px';
//document.getElementById('myh4').innerHTML='thisi=' + thisi + ' border-bottom and ' + eval(100 + thisi) + ' is border-top ' + spano.outerHTML.replace(/\>/g,'>').replace(/\</g,'<');
if ((sbl == 4 && spano.outerHTML.split('border-').length >= 4) && sbc == 1) {
spano.style.backgroundColor=bcols[curplayer];
//alert(3);
//if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
//alert('' + sbl + ' 3:' + spano.outerHTML.split('border-').length + ' ' + spano.outerHTML);
//}
locsubscore++;
} //else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && sbl == 4 && sbc == 1) {
//alert('3:' + spano.outerHTML.split('border-').length + ' ' + spano.outerHTML);
//}
if (eval(thisi / 100) <= 18) {
sbl=eval('' + noc(document.getElementById('span' + eval(100 + thisi)).outerHTML).split('border-').length);
sbc=eval('' + document.getElementById('span' + eval(100 + thisi)).outerHTML.split('background-color').length);
document.getElementById('span' + eval(100 + thisi)).style.borderTop=thislet.split(':')[1];
if ((sbl == 4 && noc(document.getElementById('span' + eval(100 + thisi)).outerHTML).split('border-').length >= 4) && sbc == 1) { //if (document.getElementById('span' + eval(100 + thisi)).outerHTML.split('border-').length == 5 && document.getElementById('span' + eval(100 + thisi)).outerHTML.split('background-color').length == 1) {
document.getElementById('span' + eval(100 + thisi)).style.backgroundColor=bcols[curplayer];
locsubscore++;
}
}
} else {
thislet='border-top:2px solid ' + bcols[curplayer]; //alert(56);
spano.style.borderTop=thislet.split(':')[1];
//document.getElementById('myh4').style.fontSize='6px';
//document.getElementById('myh4').innerHTML='thisi=' + thisi + ' border-top and ' + eval(-100 + thisi) + ' is border-bottom ' + spano.outerHTML.replace(/\>/g,'>').replace(/\</g,'<');
if ((sbl == 4 && noc(spano.outerHTML).split('border-').length >= 4) && sbc == 1) {
spano.style.backgroundColor=bcols[curplayer];
//alert(4);
//if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
//alert('' + sbl + ' 4:' + spano.outerHTML.split('border-').length + ' ' + spano.outerHTML);
//}
locsubscore++;
} //else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && sbl == 4 && sbc == 1) {
//alert('4:' + spano.outerHTML.split('border-').length + ' ' + spano.outerHTML);
//}
if (eval(thisi / 100) >= 1) {
sbl=eval('' + noc(document.getElementById('span' + eval(-100 + thisi)).outerHTML).split('border-').length);
sbc=eval('' + document.getElementById('span' + eval(-100 + thisi)).outerHTML.split('background-color').length);
document.getElementById('span' + eval(-100 + thisi)).style.borderBottom=thislet.split(':')[1];
if ((sbl == 4 && noc(document.getElementById('span' + eval(-100 + thisi)).outerHTML).split('border-').length >= 4) && sbc == 1) { //if (document.getElementById('span' + eval(-100 + thisi)).outerHTML.split('border-').length == 5 && document.getElementById('span' + eval(-100 + thisi)).outerHTML.split('background-color').length == 1) {
document.getElementById('span' + eval(-100 + thisi)).style.backgroundColor=bcols[curplayer];
locsubscore++;
}
}
}
thislet='&nbsp;'; //'O';
spano.innerHTML=thislet;
spano.style.color='#0000ff';
}

if (locsubscore > 0) {
//alert('locsubscore=' + locsubscore + ' yy=' + yy + ' rtis.top=' + rtis.top + ' rtis.y=' + rtis.y + ' rtis.bottom=' + rtis.bottom);
changeu=false;
subscore=locsubscore;
return cscore('pointer', locsubscore);
} else {
subscore=0;
changeu=true;
//alert('change');
return cscore('pointer', 0);
}

… in the “how we got there” dots_and_boxes_game.html Dots and Boxes Game you can also try below …


Previous relevant SOS Game Primer Tutorial is shown below.

SOS Game Primer Tutorial

SOS Game Primer Tutorial

Even though it took too long to get to yesterday’s Word Find Game Viewport Tutorial‘s Word Find Game’s level of satisfaction, for us, it was always going to be worth it, because when you overengineer it can mean cloning off that into another useful web application is a “paring down” exercise, more than anything, and this is infinitely easier than “a reinvention of the wheel” scenario, especially where it comes to “cross platform” game usage “user experience” issues.

The fun bit of such an approach, in thinking about what we end up with today is the thought that a …

  • Word Find Game … could be cloned or morphed into a …
  • SOS Game

… we remember from our days at high school, in less than a day. The memory of the SOS Game did not extend to the detail, and so we thank How to Play – SOS for reminders about the status of diagonality, while up versus down and forwards versus backwards concerns were a bit “per se” regarding “SOS”!

It was the confluence of one “onclick” type event to cover, regarding span elements set out in a grid initialized to a non-breaking space ( ie. &nbsp; ) …

  • fill in contents as “S”
  • fill in contents as “O”

… that set us to determining for the span “cell” click, was it positioned …

  • in the top half means “S” … or …
  • in the bottom half means “O”

? This had us converging on changes to the “clicks” mode onclick event Javascript logic …


function didclick(e, spano) {
if (document.getElementById('names')) {
if (document.getElementById('names').value == '' && document.getElementById('names').placeholder.indexOf(',') != -1) {
document.getElementById('names').value=document.getElementById('names').placeholder;
//alert(1);
document.getElementById('numsel').value='' + document.getElementById('names').value.split(',').length;
//alert(document.getElementById('numsel').value);
nparrange(document.getElementById('numsel'));
//alert(11);
document.getElementById('smore').innerHTML=notify('Your go ' + anames[curplayer]);
}
}
console.log('1');
if (spano.innerHTML.toLowerCase() == 's' || spano.innerHTML.toLowerCase() == 'o') { return true; }
console.log('2');
var rtis=spano.getBoundingClientRect();
console.log('3');
e = e || window.event;
e.preventDefault();

if (e.touches) {
if (e.touches[0].pageX) {
xx = e.touches[0].pageX;
yy = e.touches[0].pageY;
} else {
xx = e.touches[0].clientX;
yy = e.touches[0].clientY;
}
//console.log('pos3=' + pos3 + ',pos4=' + pos4);
} else if (e.clientX || e.clientY) {
xx = e.clientX;
yy = e.clientY;
} else {
xx = e.pageX;
yy = e.pageY;
}



var thislet=' ';
var locsubscore=0;
var thisi=eval(spano.id.replace('span',''));
if (eval(yy - rtis.top) <= eval(rtis.bottom - yy)) { // s
thislet='S';
spano.innerHTML=thislet;
spano.style.color='rgb(128,0,128)'; //'#000000';
} else {
thislet='O';
spano.innerHTML=thislet;
spano.style.color='#0000ff';
}
sbs=[];
if (eval(thisi % 100) >= 2) { // forwards we are at end
if ((sb(document.getElementById('span' + eval(-2 + thisi))).innerHTML + sb(document.getElementById('span' + eval(-1 + thisi))).innerHTML + sb(document.getElementById('span' + eval(thisi))).innerHTML) == 'SOS') {
sbord();
locsubscore++;
}
}
sbs=[];
if (eval(thisi % 100) >= 1 && eval(thisi % 100) <= 98) { // forwards we are in the middle
if ((sb(document.getElementById('span' + eval(-1 + thisi))).innerHTML + sb(document.getElementById('span' + eval(thisi))).innerHTML + sb(document.getElementById('span' + eval(1 + thisi))).innerHTML) == 'SOS') {
sbord();
locsubscore++;
}
}
sbs=[];
if (eval(thisi % 100) <= 97) { // forwards we are at start
if ((sb(document.getElementById('span' + eval(thisi))).innerHTML + sb(document.getElementById('span' + eval(1 + thisi))).innerHTML + sb(document.getElementById('span' + eval(2 + thisi))).innerHTML) == 'SOS') {
sbord();
locsubscore++;
}
}


if (updownallowed) {
sbs=[];
if (eval(thisi / 100) >= 2) { // down we are at end
if ((sb(document.getElementById('span' + eval(-200 + thisi))).innerHTML + sb(document.getElementById('span' + eval(-100 + thisi))).innerHTML + sb(document.getElementById('span' + eval(thisi))).innerHTML) == 'SOS') {
sbord();
locsubscore++;
}
}
sbs=[];
if (eval(thisi / 100) >= 1 && eval(thisi / 100) <= 18) { // down we are in the middle
if ((sb(document.getElementById('span' + eval(-100 + thisi))).innerHTML + sb(document.getElementById('span' + eval(thisi))).innerHTML + sb(document.getElementById('span' + eval(100 + thisi))).innerHTML) == 'SOS') {
sbord();
locsubscore++;
}
}
sbs=[];
if (eval(thisi / 100) <= 17) { // down we are at start
if ((sb(document.getElementById('span' + eval(thisi))).innerHTML + sb(document.getElementById('span' + eval(100 + thisi))).innerHTML + sb(document.getElementById('span' + eval(200 + thisi))).innerHTML) == 'SOS') {
sbord();
locsubscore++;
}
}
}

if (diagonalsallowed) {
sbs=[];
if (eval(thisi / 100) >= 2 && eval(thisi % 100) >= 2) { // diagonally we are at end
if ((sb(document.getElementById('span' + eval(-202 + thisi))).innerHTML + sb(document.getElementById('span' + eval(-101 + thisi))).innerHTML + sb(document.getElementById('span' + eval(thisi))).innerHTML) == 'SOS') {
sbord();
locsubscore++;
}
sbs=[];
if ((sb(document.getElementById('span' + eval(-198 + thisi))).innerHTML + sb(document.getElementById('span' + eval(-99 + thisi))).innerHTML + sb(document.getElementById('span' + eval(thisi))).innerHTML) == 'SOS') {
sbord();
locsubscore++;
}
}
sbs=[];
if (eval(thisi / 100) >= 1 && eval(thisi / 100) <= 18 && eval(thisi % 100) >= 1 && eval(thisi % 100) <= 98) { // diagonally we are in the middle
if ((sb(document.getElementById('span' + eval(-101 + thisi))).innerHTML + sb(document.getElementById('span' + eval(thisi))).innerHTML + sb(document.getElementById('span' + eval(101 + thisi))).innerHTML) == 'SOS') {
sbord();
locsubscore++;
}
sbs=[];
if ((sb(document.getElementById('span' + eval(-99 + thisi))).innerHTML + sb(document.getElementById('span' + eval(thisi))).innerHTML + sb(document.getElementById('span' + eval(99 + thisi))).innerHTML) == 'SOS') {
sbord();
locsubscore++;
}
}
sbs=[];
if (eval(thisi / 100) <= 17 && eval(thisi % 100) <= 97) { // diagonally we are at start
if ((sb(document.getElementById('span' + eval(thisi))).innerHTML + sb(document.getElementById('span' + eval(101 + thisi))).innerHTML + sb(document.getElementById('span' + eval(202 + thisi))).innerHTML) == 'SOS') {
sbord();
locsubscore++;
}
sbs=[];
if ((sb(document.getElementById('span' + eval(thisi))).innerHTML + sb(document.getElementById('span' + eval(99 + thisi))).innerHTML + sb(document.getElementById('span' + eval(198 + thisi))).innerHTML) == 'SOS') {
sbord();
locsubscore++;
}
}
}
sbs=[];

if (locsubscore > 0) {
//alert('locsubscore=' + locsubscore + ' yy=' + yy + ' rtis.top=' + rtis.top + ' rtis.y=' + rtis.y + ' rtis.bottom=' + rtis.bottom);
changeu=false;
subscore=locsubscore;
return cscore('pointer', locsubscore);
} else {
subscore=0;
changeu=true;
//alert('change');
return cscore('pointer', 0);
}



var newi=eval(spano.id.replace('span',''));
var documentgetSelectiontoString='', revsis='';
var wlen=0, ijh=0;
if (setsoftwo.length == 0) {
setsoftwo.push(newi);
document.getElementById('span' + newi).style.backgroundColor='yellow';
} else {
console.log('Newi=' + newi + ' and down=' + Math.abs(eval(newi % 100) - eval(setsoftwo[0] % 100)) + ' and across=' + Math.abs(Math.floor(newi / 100) - Math.floor(setsoftwo[0] / 100)) + ' via setsoftwo[0]=' + setsoftwo[0]);
if (Math.floor(newi / 100) == Math.floor(setsoftwo[0] / 100)) {
wlen=eval(1 + Math.abs(eval(setsoftwo[0] - newi)));
if (wlen == 3) { // >= 4) {
for (ijh=Math.min(setsoftwo[0], newi); ijh<=Math.max(setsoftwo[0], newi); ijh++) {
documentgetSelectiontoString+=document.getElementById('span' + ijh).innerHTML;
revsis=document.getElementById('span' + ijh).innerHTML + revsis;
document.getElementById('span' + ijh).style.backgroundColor='orange';
document.getElementById('span' + ijh).title=document.getElementById('span' + ijh).innerHTML;
document.getElementById('span' + ijh).style.cursor='progress';
}
subscore=eval(0 - eval('' + documentgetSelectiontoString.length));
findingnemo='';
if (!backwardsallowed) {
setTimeout(retry, 2000);
document.getElementById('nameif').title='';
} else {
setTimeout(retry, 8000);
document.getElementById('mytao').style.cursor='progress';
document.getElementById('nameif').title='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&second=y&iswordthere=' + encodeURIComponent(revsis);
}
document.getElementById('nameif').src='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&iswordthere=' + encodeURIComponent(documentgetSelectiontoString.toLowerCase());
setsoftwo=[];
} else {
document.getElementById('span' + ('' + setsoftwo[0]).replace('span','')).style.backgroundColor='#f0f0f0';
setsoftwo=[];
setsoftwo.push(newi);
document.getElementById('span' + newi).style.backgroundColor='yellow';
console.log('newi=' + newi + ' and down=' + Math.abs(eval(newi % 100) - eval(setsoftwo[0] % 100)) + ' and across=' + Math.abs(Math.floor(newi / 100) - Math.floor(setsoftwo[0] / 100)) + ' via setsoftwo[0]=' + setsoftwo[0]);
notify('Sorry, but too short.');
}

} else if (eval(newi % 100) == eval(setsoftwo[0] % 100)) {
if (updownallowed) {
console.log('up down');
wlen=eval(1 + Math.abs(eval(Math.floor(setsoftwo[0] / 100) - Math.floor(newi / 100))));
console.log('newi=' + newi + ' and wlen=' + wlen + ' via setsoftwo[0]=' + setsoftwo[0]);
if (wlen == 3) { // >= 4) {
for (ijh=Math.min(setsoftwo[0], newi); ijh<=Math.max(setsoftwo[0], newi); ijh+=100) {
documentgetSelectiontoString+=document.getElementById('span' + ijh).innerHTML;
revsis=document.getElementById('span' + ijh).innerHTML + revsis;
document.getElementById('span' + ijh).style.backgroundColor='orange';
document.getElementById('span' + ijh).title=document.getElementById('span' + ijh).innerHTML;
document.getElementById('span' + ijh).style.cursor='progress';
}
subscore=eval(0 - eval('' + documentgetSelectiontoString.length));
findingnemo='';
if (!backwardsallowed) {
setTimeout(retry, 2000);
document.getElementById('nameif').title='';
} else {
setTimeout(retry, 8000);
document.getElementById('mytao').style.cursor='progress';
document.getElementById('nameif').title='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&second=y&iswordthere=' + encodeURIComponent(revsis);
}
document.getElementById('nameif').src='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&iswordthere=' + encodeURIComponent(documentgetSelectiontoString.toLowerCase());
setsoftwo=[];
} else {
document.getElementById('span' + ('' + setsoftwo[0]).replace('span','')).style.backgroundColor='#f0f0f0';
setsoftwo=[];
setsoftwo.push(newi);
document.getElementById('span' + newi).style.backgroundColor='yellow';
console.log('newi=' + newi + ' and down=' + Math.abs(eval(newi % 100) - eval(setsoftwo[0] % 100)) + ' and across=' + Math.abs(Math.floor(newi / 100) - Math.floor(setsoftwo[0] / 100)) + ' via setsoftwo[0]=' + setsoftwo[0]);
notify('Sorry, need four or more letters.');
}

} else {
document.getElementById('span' + ('' + setsoftwo[0]).replace('span','')).style.backgroundColor='#f0f0f0';
setsoftwo=[];
setsoftwo.push(newi);
document.getElementById('span' + newi).style.backgroundColor='yellow';
console.log('newi=' + newi + ' and down=' + Math.abs(eval(newi % 100) - eval(setsoftwo[0] % 100)) + ' and across=' + Math.abs(Math.floor(newi / 100) - Math.floor(setsoftwo[0] / 100)) + ' via setsoftwo[0]=' + setsoftwo[0]);
notify('Sorry, no up or downs allowed.');
}

} else if (Math.abs(Math.floor(eval(newi / 100)) - Math.floor(eval(setsoftwo[0] / 100))) == Math.abs(eval(newi % 100) - eval(setsoftwo[0] % 100))) {
if (diagonalsallowed) {
console.log('diagonal');

wlen=eval(1 + Math.abs(eval(Math.floor(setsoftwo[0] / 100) - Math.floor(newi / 100))));
console.log('newi=' + newi + ' and wlen=' + wlen + ' via setsoftwo[0]=' + setsoftwo[0]);
if (wlen == 3) { // >= 4) {
for (ijh=Math.min(setsoftwo[0], newi); ijh<=Math.max(setsoftwo[0], newi); ijh+=eval(eval(Math.max(setsoftwo[0], newi) - Math.min(setsoftwo[0], newi)) / eval(-1 + wlen))) {
documentgetSelectiontoString+=document.getElementById('span' + ijh).innerHTML;
revsis=document.getElementById('span' + ijh).innerHTML + revsis;
document.getElementById('span' + ijh).style.backgroundColor='orange';
document.getElementById('span' + ijh).title=document.getElementById('span' + ijh).innerHTML;
document.getElementById('span' + ijh).style.cursor='progress';
}
subscore=eval(0 - eval('' + documentgetSelectiontoString.length));
findingnemo='';
if (!backwardsallowed) {
setTimeout(retry, 2000);
document.getElementById('nameif').title='';
} else {
setTimeout(retry, 8000);
document.getElementById('mytao').style.cursor='progress';
document.getElementById('nameif').title='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&second=y&iswordthere=' + encodeURIComponent(revsis);
}
document.getElementById('nameif').src='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&iswordthere=' + encodeURIComponent(documentgetSelectiontoString.toLowerCase());
setsoftwo=[];
} else {
document.getElementById('span' + ('' + setsoftwo[0]).replace('span','')).style.backgroundColor='#f0f0f0';
setsoftwo=[];
setsoftwo.push(newi);
document.getElementById('span' + newi).style.backgroundColor='yellow';
console.log('newi=' + newi + ' and down=' + Math.abs(eval(newi % 100) - eval(setsoftwo[0] % 100)) + ' and across=' + Math.abs(Math.floor(newi / 100) - Math.floor(setsoftwo[0] / 100)) + ' via setsoftwo[0]=' + setsoftwo[0]);
notify('Too short, sorry.');
}

} else {
document.getElementById('span' + ('' + setsoftwo[0]).replace('span','')).style.backgroundColor='#f0f0f0';
setsoftwo=[];
setsoftwo.push(newi);
document.getElementById('span' + newi).style.backgroundColor='yellow';
console.log('newi=' + newi + ' and down=' + Math.abs(eval(newi % 100) - eval(setsoftwo[0] % 100)) + ' and across=' + Math.abs(Math.floor(newi / 100) - Math.floor(setsoftwo[0] / 100)) + ' via setsoftwo[0]=' + setsoftwo[0]);
notify('Sorry, no diagonals allowed.');
}

} else {
document.getElementById('span' + ('' + setsoftwo[0]).replace('span','')).style.backgroundColor='#f0f0f0';
setsoftwo=[];
setsoftwo.push(newi);
document.getElementById('span' + newi).style.backgroundColor='yellow';
console.log('newi=' + newi + ' and down=' + Math.abs(eval(newi % 100) - eval(setsoftwo[0] % 100)) + ' and across=' + Math.abs(Math.floor(newi / 100) - Math.floor(setsoftwo[0] / 100)) + ' via setsoftwo[0]=' + setsoftwo[0]);
}
}
//alert('id=' + spano.id + ' ' + spano.innerHTML);
}

… which on non-mobile platforms compliments the CSS styling …

<style>

span.wunderlay:hover {
background-image: linear-gradient(to bottom, rgba(128,0,128,0.5) , rgba(0,0,255,0.5));
}

</style>

… quite nicely, in a colour coded sense, in the “how we got there” sos_game.html SOS Game you can also try below …


Previous relevant Word Find Game Aesthetics Tutorial is shown below.

Word Find Game Aesthetics Tutorial

Word Find Game Aesthetics Tutorial

CSS styling keeps getting better for webpages, with extended functionality, as proven when CSS3 came to being. Two styling features we find quite impactive are …

  • CSS animation … and …
  • CSS linear gradients

… we use, respectively, regarding …

  • “selection” textarea and “click” div of span elements … helping create a colour coded border “glow” 3D effect …

    <style>

    /* Thanks to https://www.w3schools.com/howto/tryit.asp?filename=tryhow_css_glowing_text */

    @-webkit-keyframes glow {
    from {
    box-shadow: 0 0 3px #fff, 0 0 5px #fff, 0 0 37px #e60073, 0 0 9px #e60073, 0 0 11px #e60073, 0 0 13px #e60073, 0 0 15px #e60073;
    }

    to {
    box-shadow: 0 0 24px #fff, 0 0 6px #ff4da6, 0 0 8px #ff4da6, 0 0 10px #ff4da6, 0 0 12px #ff4da6, 0 0 14px #ff4da6, 0 0 16px #ff4da6;
    }
    }

    @-webkit-keyframes wglow {
    from {
    box-shadow: 0 0 3px #fff, 0 0 5px #fff, 0 0 37px #7300e6, 0 0 9px #7300e6, 0 0 11px #7300e6, 0 0 13px #7300e6, 0 0 15px #7300e6;
    }

    to {
    box-shadow: 0 0 24px #fff, 0 0 6px #ff4da6, 0 0 8px #a64dff, 0 0 10px #a64dff, 0 0 12px #a64dff, 0 0 14px #a64dff, 0 0 16px #a64dff;
    }
    }


    textarea {
    font-family: Courier New;
    font-size: 20px;
    opacity: 0.9;
    z-index: 9;
    padding: 0 0 0 0;
    margin: 0 0 0 0;
    text-shadow: -1px 1px 1px #952dff;
    -webkit-animation: glow 1s linear infinite alternate;
    -moz-animation: glow 1s linear infinite alternate;
    animation: glow 1s linear infinite alternate;

    }


    #wunderlay {
    font-family: Courier New;
    font-size: 20px;
    opacity: 0.3;
    z-index: 11;
    padding: 0 0 0 0;
    margin: 0 0 0 0;
    -webkit-animation: glow 1s linear infinite alternate;
    -moz-animation: glow 1s linear infinite alternate;
    animation: glow 1s linear infinite alternate;

    }
    </style>

    … that is dynamically changed to “wglow” (and font-family Courier) should the user select “click” mode of interactive entry
  • background-image CSS property linear gradient background to dropdown and textbox element effect …

    <style>
    /* Thanks to https://medium.com/thirty-9/3-tips-for-using-subtle-css-gradients-f5691e453602 */

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


    #names {
    background-image: linear-gradient(to right bottom, #eeeeee, #ebe9eb, #e8e5e7, #e7e0e2, #e5dbdb);
    }


    select {
    background-image: linear-gradient(to right bottom, white, yellow, pink, silver, lightgray);
    }
    </style>

And so, improving on yesterday’s Word Find Game Mobile Tutorial we have in our changed word_find_game.html Word Find Game you can also try, yes, yet again, below.


Previous relevant Word Find Game Mobile Tutorial is shown below.

Word Find Game Mobile Tutorial

Word Find Game Mobile Tutorial

Yesterday’s Word Find Game Personalization Tutorial, and the Word Find Game from versions before all had an unwieldy relationship with mobile platforms. The …

  • selection, via Selection API, using HTML textarea, suits non-mobile well … but we think today’s newly coded for …
  • click, via HTML span element onclick logics, work better on mobile platforms

… and so we’ve coded for a new dropdown to offer both modus operandi as options, with new “click” modus operandi Javascript …


function didclick(spano) {
var newi=eval(spano.id.replace('span',''));
var documentgetSelectiontoString='', revsis='';
var wlen=0, ijh=0;
if (setsoftwo.length == 0) {
setsoftwo.push(newi);
document.getElementById('span' + newi).style.backgroundColor='yellow';
} else {
console.log('Newi=' + newi + ' and down=' + Math.abs(eval(newi % 100) - eval(setsoftwo[0] % 100)) + ' and across=' + Math.abs(Math.floor(newi / 100) - Math.floor(setsoftwo[0] / 100)) + ' via setsoftwo[0]=' + setsoftwo[0]);
if (Math.floor(newi / 100) == Math.floor(setsoftwo[0] / 100)) {
wlen=eval(1 + Math.abs(eval(setsoftwo[0] - newi)));
if (wlen >= 4) {
for (ijh=Math.min(setsoftwo[0], newi); ijh<=Math.max(setsoftwo[0], newi); ijh++) {
documentgetSelectiontoString+=document.getElementById('span' + ijh).innerHTML;
revsis=document.getElementById('span' + ijh).innerHTML + revsis;
document.getElementById('span' + ijh).style.backgroundColor='orange';
document.getElementById('span' + ijh).title=document.getElementById('span' + ijh).innerHTML;
document.getElementById('span' + ijh).style.cursor='progress';
}
subscore=eval(0 - eval('' + documentgetSelectiontoString.length));
findingnemo='';
if (!backwardsallowed) {
setTimeout(retry, 2000);
document.getElementById('nameif').title='';
} else {
setTimeout(retry, 8000);
document.getElementById('mytao').style.cursor='progress';
document.getElementById('nameif').title='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&second=y&iswordthere=' + encodeURIComponent(revsis);
}
document.getElementById('nameif').src='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&iswordthere=' + encodeURIComponent(documentgetSelectiontoString.toLowerCase());
setsoftwo=[];
}
} else if (eval(newi % 100) == eval(setsoftwo[0] % 100)) {
if (updownallowed) {
console.log('up down');
wlen=eval(1 + Math.abs(eval(Math.floor(setsoftwo[0] / 100) - Math.floor(newi / 100))));
console.log('newi=' + newi + ' and wlen=' + wlen + ' via setsoftwo[0]=' + setsoftwo[0]);
if (wlen >= 4) {
for (ijh=Math.min(setsoftwo[0], newi); ijh<=Math.max(setsoftwo[0], newi); ijh+=100) {
documentgetSelectiontoString+=document.getElementById('span' + ijh).innerHTML;
revsis=document.getElementById('span' + ijh).innerHTML + revsis;
document.getElementById('span' + ijh).style.backgroundColor='orange';
document.getElementById('span' + ijh).title=document.getElementById('span' + ijh).innerHTML;
document.getElementById('span' + ijh).style.cursor='progress';
}
subscore=eval(0 - eval('' + documentgetSelectiontoString.length));
findingnemo='';
if (!backwardsallowed) {
setTimeout(retry, 2000);
document.getElementById('nameif').title='';
} else {
setTimeout(retry, 8000);
document.getElementById('mytao').style.cursor='progress';
document.getElementById('nameif').title='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&second=y&iswordthere=' + encodeURIComponent(revsis);
}
document.getElementById('nameif').src='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&iswordthere=' + encodeURIComponent(documentgetSelectiontoString.toLowerCase());
setsoftwo=[];
}
}
} else if (Math.abs(Math.floor(eval(newi / 100)) - Math.floor(eval(setsoftwo[0] / 100))) == Math.abs(eval(newi % 100) - eval(setsoftwo[0] % 100))) {
if (diagonalsallowed) {
console.log('diagonal');

wlen=eval(1 + Math.abs(eval(Math.floor(setsoftwo[0] / 100) - Math.floor(newi / 100))));
console.log('newi=' + newi + ' and wlen=' + wlen + ' via setsoftwo[0]=' + setsoftwo[0]);
if (wlen >= 4) {
for (ijh=Math.min(setsoftwo[0], newi); ijh<=Math.max(setsoftwo[0], newi); ijh+=eval(eval(Math.max(setsoftwo[0], newi) - Math.min(setsoftwo[0], newi)) / eval(-1 + wlen))) {
documentgetSelectiontoString+=document.getElementById('span' + ijh).innerHTML;
revsis=document.getElementById('span' + ijh).innerHTML + revsis;
document.getElementById('span' + ijh).style.backgroundColor='orange';
document.getElementById('span' + ijh).title=document.getElementById('span' + ijh).innerHTML;
document.getElementById('span' + ijh).style.cursor='progress';
}
subscore=eval(0 - eval('' + documentgetSelectiontoString.length));
findingnemo='';
if (!backwardsallowed) {
setTimeout(retry, 2000);
document.getElementById('nameif').title='';
} else {
setTimeout(retry, 8000);
document.getElementById('mytao').style.cursor='progress';
document.getElementById('nameif').title='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&second=y&iswordthere=' + encodeURIComponent(revsis);
}
document.getElementById('nameif').src='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&iswordthere=' + encodeURIComponent(documentgetSelectiontoString.toLowerCase());
setsoftwo=[];
}
}
} else {
console.log('newi=' + newi + ' and down=' + Math.abs(eval(newi % 100) - eval(setsoftwo[0] % 100)) + ' and across=' + Math.abs(Math.floor(newi / 100) - Math.floor(setsoftwo[0] / 100)) + ' via setsoftwo[0]=' + setsoftwo[0]);
}
}
//alert('id=' + spano.id + ' ' + spano.innerHTML);
}

… in our changed word_find_game.html Word Find Game you can also try, yes, again, below.


Previous relevant Word Find Game Personalization Tutorial is shown below.

Word Find Game Underlay Tutorial

Word Find Game Personalization Tutorial

Yesterday’s Word Find Game Modes of Use Tutorial gave us the means by which we could have multiple players in our “Finding the Word” game, as a number. But many users prefer “names” to “numbers”. And so …

  • we start asking for an optional (comma separated) user name list … that if used …
  • starts looking for Notifications API functionality to keep the players informed about proceedings … and …
  • if underlying Navigator API navigator.platform points at an underlying macOS operating system, also offer the user the chance to turn notification wording to audio commentary, as well

… as per Javascript …


function notify(what) {
if (what.trim() != '' && anames[0].replace('Player 1','').trim() != '') {
if (what != lastwhat) {
lastwhat=what;
setTimeout(lwn, 8000);
document.getElementById('notif').src='./notifications_ideas.php?scheduledblurb=' + encodeURIComponent(what);
if (trysay) { //alert('HTTP://localhost:8888/macos_say_record.php?andsoonclose=y&docronwork=say%20' + encodeURIComponent(what));
window.open('HTTP://localhost:8888/macos_say_record.php?andsoonclose=y&docronwork=say%20' + encodeURIComponent(what), 'sayif', 'top=50,left=50,width=500,height=500');
}
}
}
return what;
}

… showing two different uses of two different invisible HTML iframe elements …


<iframe id=notif style='display:none;' src=></iframe>
<iframe id=sayif name=sayif style='display:none;' src=></iframe>

… in our changed word_find_game.html Word Find Game you can also try, yet again, below.


Previous relevant Word Find Game Modes of Use Tutorial is shown below.

Word Find Game Underlay Tutorial

Word Find Game Modes of Use Tutorial

Online games often feature …

  • degree of difficulty
  • number of player(s)

… modes of use that the user(s) can control. And so, with this in mind, to improve on yesterday’s Word Find Game Underlay Tutorial we’ve set out providing ways the users can control these two concepts via two new dropdowns …


<h1>Word Find Game <select onchange="restart(this);"><option value="hard">Hard</option><option value="easy">Easy</option><option value="easier">Easier</option><option value="easiest">Easiest</option></select> <span id=curbit>for</span> <select id=numsel onchange='nparrange(this);'><option value=1>1 player</option><option value=2>2 players</option><option value=3>3 players</option><option value=4>4 players</option><option value=5>5 players</option></select></h1>

… along with a span element showing the current player number all within that topmost h1 element, and helped out by two new dropdown (ie. select element) onchange event Javascript logics …


var numplayers=1;
var curplayer=0;
var ascores=[0], agoes=[0];
var backwardsallowed=true;
var updownallowed=true;
var diagonalsallowed=true;

var zdebye='';
var zzdebye='';
var lastzdebye='';
var goutstris='';
var delayis=0;
var sofar=';';
var score=0, goes=0, subscore=0;

function nparrange(sio) {
if (eval('' + sio.value) > eval('' + ascores.length)) {
while (eval('' + sio.value) > eval('' + ascores.length)) {
ascores.push(0);
agoes.push(0);
}
numplayers=eval('' + ascores.length);
document.getElementById('curbit').innerHTML='for <font color=green>' + eval(1 + eval('' + curplayer)) + '</font> of';
if (eval('' + ascores.length) > 1) {
var cscores='';
var cgoes='';
var betw='';
//if (eval(0 + eval('' + curplayer)) == 0) { betw='<font color=red>'; }
if (eval(1 + eval('' + curplayer)) >= eval('' + ascores.length)) { betw='<font color=red>'; }
for (var inp=0; inp<eval('' + ascores.length); inp++) {
if (eval('' + curplayer) == inp) {
cscores+=betw + '<font color=green>' + ascores[inp] + '</font>';
cgoes+=betw + '<font color=green>' + agoes[inp] + '</font>';
betw=':<font color=red>';
} else {
cscores+=betw + ascores[inp] + betw.replace(':','').replace('<font color=red>', '</font>').replace('<font color=green>', '</font>');
cgoes+=betw + agoes[inp] + betw.replace(':','').replace('<font color=red>', '</font>').replace('<font color=green>', '</font>');
//betw=':';
betw=(':' + betw.replace(':','')).replace('<font color=red>','').replace('<font color=green>','<font color=red>');
}
console.log('numplayers=' + numplayers + ' at ' + inp + ' vs curplayer=' + curplayer + ' ' + cscores + '/' + cgoes);
}
document.getElementById('score').innerHTML='' + cscores + '/' + cgoes;
//curplayer++;
//if (curplayer >= eval('' + ascores.length)) { curplayer=0; }
//scores=ascores[curplayer];
//goes=agoes[curplayer];
}
}
}

function restart(sio) {
var myblurb=document.getElementById('blurb').innerHTML; // Forwards, backwards, up, down, diagonal 4 letters or more highlight below
var setn=[8,1,1,3,11,1,2,1,8,0,0,3,1,5,7,1,0,5,3,5,3,1,1,0,1,0];
if (sio.value == 'hard') { location.href=document.URL; }
if (sio.value != 'hard' && eval('' + letters.length) == 26) {
myblurb=myblurb.replace(' letters ', ' more common set of letters ');
// A-9, B-2, C-2, D-4, E-12, F-2, G-3, H-2, I-9, J-1, K-1, L-4, M-2, N-6, O-8, P-2, Q-1, R-6, S-4, T-6, U-4, V-2, W-2, X-1, Y-2, Z-1
var kbye=eval('' + letters.length);
for (ibye=0; ibye<kbye; ibye++) {
for (jbye=1; jbye<=setn[ibye]; jbye++) {
letters.push(letters[ibye]);
}
}
}
if (sio.value == 'easiest') {
myblurb=myblurb.replace(', diagonal', '');
myblurb=myblurb.replace(', up, down', '');
myblurb=myblurb.replace(', backwards', '');
backwardsallowed=false;
updownallowed=false;
diagonalsallowed=false;
}
if (sio.value == 'easier') {
myblurb=myblurb.replace(', diagonal', '');
myblurb=myblurb.replace(', up, down', '');
myblurb=myblurb.replace('Forwards 4', 'Forwards, backwards 4');
backwardsallowed=true;
updownallowed=false;
diagonalsallowed=false;
}
if (sio.value == 'easy') {
myblurb=myblurb.replace('Forwards 4', 'Forwards, backwards, up, down, diagonal 4');
myblurb=myblurb.replace('Forwards, backwards 4', 'Forwards, backwards, up, down, diagonal 4');
backwardsallowed=true;
updownallowed=true;
diagonalsallowed=true;
}
document.getElementById('blurb').innerHTML=myblurb;
ebye='';
ibye=0;
jbye=0;
debye='';
aletter=' ';
for (ibye=0; ibye<20; ibye++) {
for (jbye=0; jbye<100; jbye++) {
aletter=letters[Math.floor(Math.random() * letters.length)];
ebye+=aletter;
debye+=aletter;
}
ebye+=String.fromCharCode(10);
debye+='<br>';
}
zdebye='';
zzdebye='';
lastzdebye='';
goutstris='';
delayis=0;
sofar=';';
document.getElementById('mytao').value=ebye;
var divs=document.getElementsByTagName('div');
for (kdivs=0; kdivs<divs.length; kdivs++) {
divs[kdivs].innerHTML='';
}
document.getElementById('underlay').innerHTML=debye;

}

… to help encourage some optional collaboration aspects to our changed word_find_game.html Word Find Game you can also try, again, below.


Previous relevant Word Find Game Underlay Tutorial is shown below.

Word Find Game Underlay Tutorial

Word Find Game Underlay Tutorial

If you are a regular reader at this blog, you will know we discuss the CSS styling idea of …

… but there is essentially only the difference in the control of “z-index” (and maybe “opacity”) property different about the concepts, and to deploy to improve on for the start we made with yesterday’s Word Find Game Primer Tutorial.

“Underlay” usefulness, to us, goes like this …

  • what you “underlay” … for us within the new CSS styling …

    <style>
    textarea {
    font-family: Courier New;
    font-size: 20px;
    opacity: 0.9;
    z-index: 9;
    padding: 0 0 0 0;
    margin: 0 0 0 0;

    }

    #underlay {
    font-family: Courier New;
    font-size: 20px;
    opacity: 0.3;
    z-index: 1;
    padding: 0 0 0 0;
    margin: 0 0 0 0;
    }

    div.underlay {
    font-family: Courier New;
    font-size: 20px;
    opacity: 0.3;
    z-index: 2;
    padding: 0 0 0 0;
    margin: 0 0 0 0;
    }

    </style>

    … regimen …
  • has nothing to do with interactive entry, which should be more in your “overlay” thinking, else the user is stumped … but …
  • can help with dynamically enhanced markup jobs that value add to the aesthetics of the webpage

… specifically showing the user “where they’ve been” amongst the “sea of letters” of our changed word_find_game.html Word Find Game you can also try below.


Previous relevant Word Find Game Primer Tutorial is shown below.

Word Find Game Primer Tutorial

Word Find Game Primer Tutorial

Today’s “Word Find Game” gets its inspirations from two sources …

Today we just do the “proof of concept” first draft word_find_game.html, because the Selection API highlighting really suits …

  • horizontal forwards
  • horizontal backwards

… word finding in the game, but we also want to allow for …

  • vertical down
  • vertical up
  • diagonal right down
  • diagonal right up
  • diagonal left down
  • diagonal left up

… which can be handled, but in a pretty kludgy way …


function retry() {
if (('' + document.getElementById('nameif').title).trim() != '') {
document.getElementById('nameif').src=document.getElementById('nameif').title;
document.getElementById('nameif').title='';
} else {
document.getElementById('mytao').style.cursor=cscore('pointer', subscore);
}
}


function cscore(cursortype, ssc) {
if (ssc != 0) { goes++; }
if (ssc > 0) { score+=ssc; }
document.getElementById('score').innerHTML='' + score + '/' + goes;
subscore=0;
return cursortype;
}


function checkname(iois, iserror) {
var ifnd=-1, newname='';
var revsisc='', jrev=0;
console.log('checkname1');
if (iserror) {
if (iois.src.indexOf('second=') == -1 && iois.src.indexOf('iswordthere=') != -1) {
if (('' + iois.title).trim() != '') {
//document.getElementById('mytao').style.cursor='pointer';
document.body.title='';
iois.src=iois.title;
iois.title='';
} else {
//alert(1);
for (jrev=eval(-1 + eval('' + decodeURIComponent(iois.src.split('iswordthere=')[1].split('&')[0].split('#')[0]).length)); jrev>=0; jrev--) {
revsisc+=decodeURIComponent(iois.src.split('iswordthere=')[1].split('&')[0].split('#')[0]).substring(jrev, eval(1 + jrev));
}
//alert('Newname=' + revsisc);
document.body.title='';
iois.title='';
iois.src=iois.src.split('iswordthere=')[0] + 'second=y&iswordthere=' + encodeURIComponent(revsisc);
}
} else {
document.getElementById('mytao').style.cursor=cscore('pointer', subscore);
}
} else {
if (iois != null) {
ifnd=iois.src.indexOf('iswordthere=');
console.log('checkname2 ' + ifnd);
var aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null && ifnd != -1) {
console.log('checkname3 ' + ifnd);
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
console.log('checkname4 ' + ifnd);
if (aconto.body.innerHTML.indexOf('</p>') != -1 && aconto.body.innerHTML.indexOf('></p>') == -1) {
document.body.title='';
iois.title='';
document.getElementById('mytao').style.cursor=cscore('pointer', Math.abs(subscore));
console.log('Found name ' + aconto.body.innerHTML.split('</p>')[0].split('>')[eval(-1 + aconto.body.innerHTML.indexOf('</p>')[0].split('>').length)]);
} else if (aconto.body.innerHTML.indexOf('<') == -1 && aconto.body.innerHTML.trim() != '') {
document.body.title='';
iois.title='';
document.getElementById('mytao').style.cursor=cscore('pointer', Math.abs(subscore));
console.log('Found name ' + aconto.body.innerHTML);
} else if (iois.src.indexOf('second=') == -1 && iois.src.indexOf('iswordthere=') != -1) {
if (('' + iois.title).trim() != '') {
//document.getElementById('mytao').style.cursor='pointer';
document.body.title='';
iois.src=iois.title;
iois.title='';
} else {
//alert(1);
for (jrev=eval(-1 + eval('' + decodeURIComponent(iois.src.split('iswordthere=')[1].split('&')[0].split('#')[0]).length)); jrev>=0; jrev--) {
revsisc+=decodeURIComponent(iois.src.split('iswordthere=')[1].split('&')[0].split('#')[0]).substring(jrev, eval(1 + jrev));
}
//alert('Newname=' + revsisc);
document.body.title='';
iois.title='';
iois.src=iois.src.split('iswordthere=')[0] + 'second=y&iswordthere=' + encodeURIComponent(revsisc);
}
} else {
document.getElementById('mytao').style.cursor=cscore('pointer', subscore);
}
} else {
console.log('checkname5 ' + ifnd);
//alert('WhY?');
document.getElementById('mytao').style.cursor=cscore('pointer', subscore);
}
} else if (ifnd != -1) {
console.log('checkname6 ' + ifnd);
ifnd=ifnd;
if (iois.src.indexOf('second=') == -1 && iois.src.indexOf('iswordthere=') != -1) {
//alert(11);
for (jrev=eval(-1 + eval('' + decodeURIComponent(iois.src.split('iswordthere=')[1].split('&')[0].split('#')[0]).length)); jrev>=0; jrev--) {
revsisc+=decodeURIComponent(iois.src.split('iswordthere=')[1].split('&')[0].split('#')[0]).substring(jrev, eval(1 + jrev));
}
//alert('newname=' + revsisc);
iois.src=iois.src.split('iswordthere=')[0] + 'second=y&iswordthere=' + encodeURIComponent(revsisc);
} else {
document.getElementById('mytao').style.cursor=cscore('pointer', subscore);
}
}
}
}
}


function getmltrans(instris) {
goutstris='';
outstris=instris;
var ebay=ebye, jb=0, kb=2;
while (outstris.indexOf(String.fromCharCode(10)) != -1) {
outstris=outstris.replace(/\ /g,'').replace(String.fromCharCode(10),'');
}
while (ebay.indexOf(String.fromCharCode(10)) != -1) {
ebay=ebay.replace(/\ /g,'').replace(String.fromCharCode(10),'');
}
var linesare=instris.split(String.fromCharCode(10));
var xlinesare=ebye.split(String.fromCharCode(10));
if (eval('' + linesare.length) == 1) { return outstris; }
if (eval('' + linesare.length) > 3) {
var onepos=ebay.indexOf(outstris);
var startpos=eval(onepos % 100);
var endpos=eval(eval(onepos + eval('' + outstris.length)) % 100);
var izero=Math.floor(onepos / 100);
if (startpos > endpos) {
if (eval(startpos - eval(-2 + eval('' + linesare.length))) == endpos) {
outstris=xlinesare[izero].substring(startpos, eval(1 + startpos));
//alert('first character is ' + outstris + ' is startpos=' + startpos + ' in xlinesare[' + izero + ']=' + xlinesare[izero]);
izero++;
for (jb=izero; jb<xlinesare.length; jb++) {
if (kb <= eval('' + linesare.length)) {
startpos--;
outstris+=xlinesare[jb].substring(startpos, eval(1 + startpos));
}
kb++;
}
goutstris=outstris;
delayis=500;
setTimeout(afterbit, delayis);
//alert('izero=' + izero + ' ' + outstris + ' left diagonal string potentially ' + linesare.length + ' long starting at ' + eval(onepos % 100) + ' and ending at ' + endpos);
} else {
outstris='';
}
} else {
if (eval(endpos - eval(-2 + eval('' + linesare.length))) == startpos) {
outstris=xlinesare[izero].substring(startpos, eval(1 + startpos));
izero++;
for (jb=izero; jb<xlinesare.length; jb++) {
if (kb <= eval('' + linesare.length)) {
startpos++;
outstris+=xlinesare[jb].substring(startpos, eval(1 + startpos));
}
kb++;
}
goutstris=outstris;
delayis=500;
setTimeout(afterbit, delayis);
//alert(outstris + ' right diagonal string potentially ' + linesare.length + ' long starting at ' + eval(onepos % 100) + ' and ending at ' + endpos);
} else if (eval(-1 + endpos) == startpos) {
outstris=xlinesare[izero].substring(startpos, eval(1 + startpos));
izero++;
for (jb=izero; jb<xlinesare.length; jb++) {
if (kb <= eval('' + linesare.length)) {
outstris+=xlinesare[jb].substring(startpos, eval(1 + startpos));
}
kb++;
}
goutstris=outstris;
delayis=500;
setTimeout(afterbit, delayis);
//alert('izero=' + izero + ' ' + outstris + ' up or down');
} else {
outstris='';
}
}
//alert('string potentially ' + linesare.length + ' long starting at ' + eval(onepos % 100) + ' and ending at ' + eval(eval(onepos + eval('' + outstris.length)) % 100));
}


return outstris;
}


function afterbit() {
if (goutstris == '') { return ''; }
var revsis='';
var documentgetSelectiontoString=goutstris;
if (eval('' + documentgetSelectiontoString.length) >= 4) {
goutstris='';
//document.getElementById('emailsms').style.display='table-cell';
document.getElementById('mytao').title=documentgetSelectiontoString;
aemailurl=origemailurl + encodeURIComponent(documentgetSelectiontoString);
document.getElementById('aemail').href=aemailurl;
asmsurl=origsmsurl + encodeURIComponent(String.fromCharCode(10) + documentgetSelectiontoString);
document.getElementById('asms').href=asmsurl;
for (var irev=eval(-1 + eval('' + documentgetSelectiontoString.length)); irev>=0; irev--) {
revsis+=documentgetSelectiontoString.substring(irev, eval(1 + irev));
}
console.log(documentgetSelectiontoString);
subscore=eval(0 - eval('' + documentgetSelectiontoString.length));
console.log('../PHP/surprise.php?min=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&max=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&iswordthere=' + documentgetSelectiontoString.toLowerCase());
setTimeout(retry, 8000);
document.getElementById('mytao').style.cursor='progress';
document.getElementById('nameif').title='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&second=y&iswordthere=' + encodeURIComponent(revsis);
document.getElementById('nameif').src='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&iswordthere=' + encodeURIComponent(documentgetSelectiontoString.toLowerCase());
} else {
document.getElementById('mytao').style.cursor='not-allowed';
document.body.title='Already tried.';
}
return goutstris;
}


// addEventListener version
document.addEventListener('selectionchange', () => {
var revsis='';
var documentgetSelectiontoString=getmltrans(document.getSelection().toString());
if (eval('' + documentgetSelectiontoString.length) >= 4) {
if (sofar.indexOf(';' + documentgetSelectiontoString + ';') == -1) {
sofar+=documentgetSelectiontoString + ';';
if (goutstris == '') {
//document.getElementById('emailsms').style.display='table-cell';
document.getElementById('mytao').title=documentgetSelectiontoString;
aemailurl=origemailurl + encodeURIComponent(documentgetSelectiontoString);
document.getElementById('aemail').href=aemailurl;
asmsurl=origsmsurl + encodeURIComponent(String.fromCharCode(10) + documentgetSelectiontoString);
document.getElementById('asms').href=asmsurl;
for (var irev=eval(-1 + eval('' + documentgetSelectiontoString.length)); irev>=0; irev--) {
revsis+=documentgetSelectiontoString.substring(irev, eval(1 + irev));
}
console.log(documentgetSelectiontoString);
subscore=eval(0 - eval('' + documentgetSelectiontoString.length));
console.log('../PHP/surprise.php?min=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&max=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&iswordthere=' + documentgetSelectiontoString.toLowerCase());
setTimeout(retry, 8000);
document.getElementById('mytao').style.cursor='progress';
document.getElementById('nameif').title='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&second=y&iswordthere=' + encodeURIComponent(revsis);
document.getElementById('nameif').src='../PHP/surprise.php?miZn=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&maZx=' + eval(1 + eval('' + documentgetSelectiontoString.length)) + '&firstJUNKname=y&youllneverfindthis=y' + '&iswordthere=' + encodeURIComponent(documentgetSelectiontoString.toLowerCase());
}
} else {
goutstris='';
document.getElementById('mytao').style.cursor='not-allowed';
document.body.title='Already tried.';
}
}
});


// addEventListener version
document.addEventListener('selectstart', () => {
document.getElementById('mytao').title='';
aemailurl=origemailurl;
asmsurl=origsmsurl;
document.getElementById('mytao').style.cursor=cscore('pointer', subscore);
document.body.title='';
console.log('Selection started');
});

… just relying on Selection API text highlighting in an HTML textarea element. Other ideas to improve await for follow up versions!


Previous relevant Selection API and Clipboard API Tutorial is shown below.

Selection API and Clipboard API Tutorial

Selection API and Clipboard API Tutorial

There’s the …

  • clipboard, the “cut and copy and paste ideas”, for text, as we showed you with Clipboard API Image Tutorial and Clipboard API Primer Tutorial … but there’s also the bit before you reach the clipboard using the …
  • text selection (ie. the bit of text you highlight using your mouse or touchpad) … accessible, today, via our introduction to the Selection API

… using HTML changed code


<table><tr><td><textarea id=mytao class=editor rows=7 cols=120 onmousedown="mustnot=true; setTimeout(mnoff, 2000);" ontouchstart="mustnot=true; setTimeout(mnoff, 2000);"></textarea></td></TR><TR><td id=emailsms style=display:none;vertical-align:top;> <a target=_blank href='mailto:?subject=My%20Selection%20...&body=' id=aemail title=Email>&#128231;</a> <a target=_blank onmouseover="if (smsee.length == 0 && origsmsurl.indexOf('sms:&') != -1) { smsee=prompt('Please enter SMS number to send to.', ''); if (smsee == null) { smsee=''; } else { origsmsurl=origsmsurl.replace('sms:&','sms:' + smsee + '&'); asmsurl=asmsurl.replace('sms:&','sms:' + smsee + '&'); this.href=asmsurl; } }" ontouchstart="if (smsee.length == 0 && origsmsurl.indexOf('sms:&') != -1) { smsee=prompt('Please enter SMS number to send to.', ''); if (smsee == null) { smsee=''; } else { origsmsurl=origsmsurl.replace('sms:&','sms:' + smsee + '&'); asmsurl=asmsurl.replace('sms:&','sms:' + smsee + '&'); this.href=asmsurl; } }" href='sms:&body=My%20Selection%20...' id=asms title=SMS>&#128223;</a></td></tr></table><br><br>

… supported by new Javascript event interventional code …


var origemailurl='mailto:?subject=My%20Selection%20...&body=';
var origsmsurl='sms:&body=My%20Selection%20...';
var smsee='';

// addEventListener version
document.addEventListener('selectionchange', () => {
document.getElementById('emailsms').style.display='table-cell';
document.getElementById('mytao').title=document.getSelection().toString();
aemailurl=origemailurl + encodeURIComponent(document.getSelection().toString());
document.getElementById('aemail').href=aemailurl;
asmsurl=origsmsurl + encodeURIComponent(String.fromCharCode(10) + document.getSelection().toString());
document.getElementById('asms').href=asmsurl;
console.log(document.getSelection().toString());
});

// addEventListener version
document.addEventListener('selectstart', () => {
document.getElementById('mytao').title='';
aemailurl=origemailurl;
asmsurl=origsmsurl;
console.log('Selection started');
});

… to be able to share your highlighted text snippets via email or SMS in the changed clipboard_api_test.html Selection API usage web application you can also try below.


Previous relevant Clipboard API Image Tutorial is shown below.

Clipboard API Image Tutorial

Clipboard API Image Tutorial

Yes, yesterday’s Clipboard API Primer Tutorial‘s Clipboard API usages just involved …

  • text based data … and today we turn our attention to …
  • image based data

… to extend the functionality and interest of our changed clipboard_api_test.htm proof of concept
text and image clipboard using webpage.

It’s lucky for us that there are so many good resources out there to help, one link of real interest, for us, being this excellent link, thanks, getting us to use this new Javascript function …


async function pasteImage() {
//event.stopPropagation();
try {
const permission = await navigator.permissions.query({ name: 'clipboard-read' });
if (permission.state === 'denied') {
throw new Error('Not allowed to read clipboard.');
}
const clipboardContents = await navigator.clipboard.read();
for (const item of clipboardContents) {
if (!item.types.includes('image/png')) {
throw new Error('Clipboard contains non-image data.');
}
const blob = await item.getType('image/png');
imgz = new Image();
anothercell();
imgz.onload = () => {
destinationImage.style.width='' + imgz.width + 'px';
destinationImage.style.height='' + imgz.height + 'px';
prevw=eval('' + ('' + cnv.style.width).replace('px',''));
prevh=eval('' + ('' + cnv.style.height).replace('px',''));
console.log('canvas width becomes ' + eval('' + cnv.width) + ' + ' + eval('' + imgz.width) + ' = ' + '' + eval(eval('' + cnv.width) + eval('' + imgz.width)) + 'px');
cnv.style.width='' + eval(eval('' + ('' + cnv.style.width).replace('px','')) + eval('' + imgz.width)) + 'px';
cnv.style.height='' + eval(eval('' + ('' + cnv.style.height).replace('px','')) + eval('' + imgz.height)) + 'px';
cnv.width='' + ('' + cnv.style.width).replace('px','') + 'px';
cnv.height='' + ('' + cnv.style.height).replace('px','') + 'px';
if (mmode == 'mbefore' || 1 == 1) {
ctx.drawImage(imgz, prevw, prevh);
if (wo) {
wo.close();
wo=null;
}
cnv.style.display='block';
//wo=window.open('','_blank','top=50,left=50,height=600,width=600');
//wo.document.write(cnv.toDataURL('image/png'));
}
};
imgz.src = URL.createObjectURL(blob);
destinationImage.src = URL.createObjectURL(blob);
//cnv.style.backgroundRepeat=(('' + cnv.style.backgroundRepeat) + ',no-repeat').replace(/^\,/g,'');
//if (('' + cnv.style.background + ' ').trim() != '') { document.getElementById('mysummary').innerHTML='Conglomerated Images below ...'; }
cnv.style.background=(('' + cnv.style.background) + ',url(' + destinationImage.src + ') no-repeat').replace(/^\,/g,'');
//document.querySelector(".editor").style.display='block';
//destinationImage.style.display='none';
setTimeout(anothercellz, 6000);
}
}
catch (error) {
console.error(error.message);
}
}

… to achieve a lot of this image data use of the Clipboard API functionality.


Previous relevant Clipboard API Primer Tutorial is shown below.

Clipboard API Primer Tutorial

Clipboard API Primer Tutorial

Here’s another day of testing a Javascript API today, which has that “desktop feel”, that being the Clipboard API

The Clipboard API provides the ability to respond to clipboard commands (cut, copy, and paste) as well as to asynchronously read from and write to the system clipboard.

… our clipboard_api_test.html proof of concept version offering “text clipboard data” functionality from the text based clipboard into an HTML textarea element via …

  • append
  • prepend
  • at cursor

… modes of use, you can also try below (or get a sneak peak at tomorrow’s ideas) …

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 eLearning, Hardware, Operating System | Tagged , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Shower Songs Delimitation Hashtag Tutorial

Shower Songs Delimitation Hashtag Tutorial

Shower Songs Delimitation Hashtag Tutorial

Hashtag … doh!

Around here the hashtag means of constructing URLs, especially regarding “a” email mailto: and SMS sms: URL links, has saved the day manys the time, given our emphasis away from mail server based communication logics.

And today, it is used internally, in URLs, as well. That is because the titles for the seven songs can go beyond the ? and & get argument URL length limits for this blog’s domain Apache/PHP/MySql web server.

In this project, we’ve had the good luck to always organize the shaping of the Song Title data arguments to the end of the ? and & get argument parts of the URLs, wherever they be used. As such, the simple arrangement to not be haunted by URL length restrictions just via a …


var urlofinterest=urlofinterest.replace('&thetlist=', '#thetlist'); // hence ... doh!

… type of Javascript code arrangement. Cute, huh?!

Also, today, after yesterday’s Shower Songs Delimitation Remembering Tutorial, we allow for …

  • as well as that reorder allowance as of yesterday, today we extend that to a “shuffle” piece of functionality
  • a way to unremember

… within …

… yet, still, using the RJM Programming’s 404.shtml HTTP Error Code 404 supervisor …


if (eval(('' + encodeURIComponent((decodeURIComponent(document.URL.replace(anybitstoignore,'').replace('.au ','.au/').replace('.au%20','.au/').split('rjmprogramming.com.au/')[1].replace(/^index\.php/g,'').replace(/^index\.html/g,'').replace(/^index\.htm/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')) + ',').replace(/[AEIMQUYcgkosw048]\,/g,'z'))).length) == 77 && eval(('' + decodeURIComponent(document.URL.replace(anybitstoignore,'').replace('.au ','.au/').replace('.au%20','.au/').split('rjmprogramming.com.au/')[1].replace(/^index\.php/g,'').replace(/^index\.html/g,'').replace(/^index\.htm/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,''))).length) == 83 && eval('' + decodeURIComponent(document.URL.replace(anybitstoignore,'').replace('.au ','.au/').replace('.au%20','.au/').split('rjmprogramming.com.au/')[1].replace(/^index\.php/g,'').replace(/^index\.html/g,'').replace(/^index\.htm/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')).split(',').length) == 7) {
location.href='//www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=' + encodeURIComponent(decodeURIComponent(document.URL.replace(anybitstoignore,'').replace('.au ','.au/').replace('.au%20','.au/').split('rjmprogramming.com.au/')[1].replace(/^index\.php/g,'').replace(/^index\.html/g,'').replace(/^index\.htm/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')));
}

making it swing the Shower Songs into play with an erroneous URL such as …


https://www.rjmprogramming.com.au/FtE3hoR_Nvo,W5IKT_xue4o,IfaGhyK78E8,BuN3yCmHb_U,TdiAwCPb_As,euZcUku9XiE,aMs0rNtBZJk


Previous relevant Shower Songs Delimitation Remembering Tutorial is shown below.

Shower Songs Delimitation Remembering Tutorial

Shower Songs Delimitation Remembering Tutorial

Our steps forward onto yesterday’s Shower Songs Delimitation Role Tutorial involve window.localStorage remembering of lists that land within the orbit of Shower Songs YouTube API “radio play” web application.

In a “remembering and recall” scenario …

  • first you have to store such a listing URL into window.localStorage …

    if (('' + window.localStorage.getItem('song_list_' + decodeURIComponent(document.URL.split('thelist=')[1].split('&')[0].split('#')[0]))).replace(/^undefined/g,'').replace(/^null/g,'') == '') {
    window.localStorage.setItem('song_list_' + decodeURIComponent(document.URL.split('thelist=')[1].split('&')[0].split('#')[0]), newerproposedurl.replace('?', '?subject=' + encodeURIComponent(document.getElementById('mys1').innerText) + '&'));
    } else {
    window.localStorage.removeItem('song_list_' + decodeURIComponent(document.URL.split('thelist=')[1].split('&')[0].split('#')[0]));
    window.localStorage.setItem('song_list_' + decodeURIComponent(document.URL.split('thelist=')[1].split('&')[0].split('#')[0]), newerproposedurl.replace('?', '?subject=' + encodeURIComponent(document.getElementById('mys1').innerText) + '&'));
    }

    … and then …
  • you should recall these stored settings so that they can be reused …

    function ourblurb(inurlidea) {
    return String.fromCharCode(10) + decodeURIComponent(('' + inurlidea + '#thetlist=').split('thetlist=')[1].split('&')[0].split('#')[0]).replace(/\|/g,' ... then ... ' + String.fromCharCode(10));
    }

    function thenagain(inurlidea) {
    var outurlidea=inurlidea, isokayhere=true, iuyx=0;
    //alert(inurlidea + ' becomes ' + ('' + inurlidea + '#order=').split('order=')[1].trim());
    if (inurlidea.indexOf('thelist=') != -1 && eval('' + ('' + inurlidea + '#order=').split('order=')[1].split('#')[0].trim().split(',').length) == 7) {
    //alert(inurlidea + ' Becomes ' + ('' + inurlidea + '#order=').split('order=')[1].split('#')[0] + ' of length ' + eval('' + ('' + inurlidea + '#order=').split('order=')[1].split('#')[0].length));
    if (eval('' + ('' + inurlidea + '#order=').split('order=')[1].split('#')[0].length) == 13) {
    //alert(inurlidea + ' becomeS ' + ('' + inurlidea + '#order=').split('order=')[1].split('#')[0].trim());
    var theseurlsare=('' + inurlidea + '#thelist=').split('thelist=')[1].split('&')[0].split('#')[0];
    var newurlsare=theseurlsare;
    var theurlsare=decodeURIComponent(theseurlsare.split('&')[0].split('#')[0]).split(',');
    var thesetsare=('' + inurlidea + '#thetlist=').split('thetlist=')[1].split('&')[0].split('#')[0];
    var newtsare=thesetsare;
    var thetsare=decodeURIComponent(thesetsare.split('&')[0].split('#')[0]).split('|');
    var thenumsarehere=('' + inurlidea + '#order=').split('order=')[1].split('#')[0].trim().split(',');
    var minone=-1;
    if ((',' + ('' + inurlidea + '#order=').split('order=')[1].trim() + ',').indexOf(',0,') != -1) {
    minone=0;
    }
    //alert(inurlidea + ' becOmeS ' + ('' + inurlidea + '#order=').split('order=')[1].split('#')[0].trim());

    for (iuyx=0; iuyx<thenumsarehere.length; iuyx++) {
    if (eval(minone + eval('' + thenumsarehere[iuyx])) < eval('' + eval('' + theurlsare.length))) {
    isokayhere=isokayhere;
    } else {
    isokayhere=false;
    }
    }

    //alert(33);

    if (!isokayhere) { return outurlidea; }

    newurlsare='';
    newtsare='';

    //alert(5);

    for (iuyx=0; iuyx<thenumsarehere.length; iuyx++) {
    if (eval(minone + eval('' + thenumsarehere[iuyx])) < eval('' + eval('' + theurlsare.length))) {
    if (newurlsare == '') {
    newurlsare=encodeURIComponent(theurlsare[eval(minone + eval('' + thenumsarehere[iuyx]))]);
    } else {
    newurlsare+=encodeURIComponent(',' + theurlsare[eval(minone + eval('' + thenumsarehere[iuyx]))]);
    }
    }
    if (eval(minone + eval('' + thenumsarehere[iuyx])) < eval('' + eval('' + thetsare.length))) {
    if (newtsare == '') {
    newtsare=encodeURIComponent(thetsare[eval(minone + eval('' + thenumsarehere[iuyx]))]);
    } else {
    newtsare+=encodeURIComponent('|' + thetsare[eval(minone + eval('' + thenumsarehere[iuyx]))]);
    }
    }
    }


    //alert(55);
    if (thesetsare != '') {
    //alert('0:' + theseurlsare + ' vs ' + newurlsare);
    inurlidea=inurlidea.replace(theseurlsare, newurlsare).replace(thesetsare, newtsare);
    } else if (theseurlsare != '') {
    //alert('1:' + theseurlsare + ' vs ' + newurlsare);
    inurlidea=inurlidea.replace(theseurlsare, newurlsare);
    } else {
    //alert('2:' + theseurlsare + ' vs ' + newurlsare);
    return outurlidea;
    }
    if (isokayhere) { return inurlidea.split('order=')[0].replace(/\?$/g,'').replace(/\&$/g,'').replace(/\#$/g,''); }
    }
    }
    return outurlidea;
    }

    if (document.URL.indexOf('/shower_songs.htm') != -1) {
    setTimeout(function(){
    Object.keys(window.localStorage).forEach(function(key){
    if (document.URL.indexOf('/shower_songs.htm') != -1) {
    var compagainst=('thelist=' + (document.URL + '#thelist=').split('thelist=')[1].split('&')[0].split('#')[0]).replace(/^thelist\=$/g,'');
    var listblurbis='';
    if (('' + key).indexOf('song_list_') == 0) { {
    //alert(1);
    if (document.getElementById('myh3')) {
    //alert(11);
    if (potsel == '') {
    potsel='<select id=selpot title="Remembered song lists which are optionally recallable." style=width:60px;display:inline-block;margin-left:25px; onchange="if (this.value.trim().length != 0) { if (this.value.indexOf(' + "'hT'" + ') == 0) { var xzsuff=ourblurb(this.value); xxzz=prompt(' + "'Optionally change order as presented' + xzsuff" + ',' + "'&order=1,2,3,4,5,6,7'" + '); window.open(thenagain(this.value + (xxzz == null ? String.fromCharCode(32).trim() : xxzz)),' + "'_self'" + '); } else { window.open(this.value,' + "'_self'" + '); } }"><option value=>++</option></select>';
    //alert(potsel);
    document.getElementById('myh3').innerHTML+=potsel;
    }
    if (compagainst != '' && document.URL.indexOf('thetlist=') == -1) {
    if (compagainst.indexOf('thelist=' + (('' + key).split('song_list_')[1])) != -1) {
    window.open(window.localStorage.getItem(key), '_blank');
    location.href=document.URL.split('?')[0].split('#')[0];
    }
    }
    if (('' + window.localStorage.getItem(key)).indexOf('thetlist=') != -1) {
    if (document.getElementById('selpot')) {
    document.getElementById('selpot').innerHTML+='<option value="' + window.localStorage.getItem(key) + '">First song is ' + decodeURIComponent(('' + window.localStorage.getItem(key).split('thetlist=')[1])).split('|')[0] + '</option>';
    potsel='';
    if (7 == 7 || (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) <= 0 && document.URL.indexOf('.9JUNK5.247/') == -1)) {
    document.getElementById('selpot').innerHTML+='<option value="' + window.localStorage.getItem(key).replace(/^HT/g,'hT').replace(/^ht/g,'hT') + '">Reorder list where first song is ' + decodeURIComponent(('' + window.localStorage.getItem(key)).split('thetlist=')[1]).split('|')[0] + '</option>';
    //alert(22);
    }
    } else {
    potsel=potsel.replace('</select>', '<option value="' + window.localStorage.getItem(key) + '">First song is ' + decodeURIComponent(('' + window.localStorage.getItem(key).split('thetlist=')[1])).split('|')[0] + '</option></select>');
    if (7 == 7 || (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) <= 0 && document.URL.indexOf('.9JUNK5.247/') == -1)) {
    potsel=potsel.replace('</select>', '<option value="' + window.localStorage.getItem(key).replace(/^HT/g,'hT').replace(/^ht/g,'hT') + '">Reorder list where first song is ' + decodeURIComponent(('' + window.localStorage.getItem(key)).split('thetlist=')[1]).split('|')[0] + '</option></select>');
    //alert(122);
    }
    }
    } else {
    if (document.getElementById('selpot')) {
    document.getElementById('selpot').innerHTML+='<option value="' + window.localStorage.getItem(key) + '">First song is ' + decodeURIComponent(('' + window.localStorage.getItem(key))) + '">First YouTube video ID is ' + decodeURIComponent(('' + window.localStorage.getItem(key)).split('thelist=')[1]).split(',')[0] + '</option>';
    potsel='';
    if (7 == 7 || (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) <= 0 && document.URL.indexOf('.9JUNK5.247/') == -1)) {
    document.getElementById('selpot').innerHTML+='<option value="' + window.localStorage.getItem(key).replace(/^HT/g,'hT').replace(/^ht/g,'hT') + '">Reorder list where first song is ' + decodeURIComponent(('' + window.localStorage.getItem(key))) + '">First YouTube video ID is ' + decodeURIComponent(('' + window.localStorage.getItem(key)).split('thelist=')[1]).split(',')[0] + '</option>';
    //alert(222);
    }
    } else {
    potsel=potsel.replace('</select>', '<option value="' + window.localStorage.getItem(key) + '">First YouTube video ID is ' + decodeURIComponent(('' + window.localStorage.getItem(key).split('thelist=')[1])).split(',')[0] + '</option></select>');
    if (7 == 7 || (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) <= 0 && document.URL.indexOf('.9JUNK5.247/') == -1)) {
    potsel=potsel.replace('</select>', '<option value="' + window.localStorage.getItem(key).replace(/^HT/g,'hT').replace(/^ht/g,'hT') + '">Reorder list where first YouTube video ID is ' + decodeURIComponent(('' + window.localStorage.getItem(key).split('thelist=')[1])).split(',')[0] + '</option></select>');
    //alert(2222);
    }
    }
    }
    }
    }
    }
    }
    });
    if (potsel != '' && !document.getElementById('selpot')) {
    document.getElementById('divcbi').innerHTML+=potsel;
    }
    }, 500);
    }

… in …

… still using the RJM Programming’s 404.shtml HTTP Error Code 404 supervisor …


if (eval(('' + encodeURIComponent((decodeURIComponent(document.URL.replace(anybitstoignore,'').replace('.au ','.au/').replace('.au%20','.au/').split('rjmprogramming.com.au/')[1].replace(/^index\.php/g,'').replace(/^index\.html/g,'').replace(/^index\.htm/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')) + ',').replace(/[AEIMQUYcgkosw048]\,/g,'z'))).length) == 77 && eval(('' + decodeURIComponent(document.URL.replace(anybitstoignore,'').replace('.au ','.au/').replace('.au%20','.au/').split('rjmprogramming.com.au/')[1].replace(/^index\.php/g,'').replace(/^index\.html/g,'').replace(/^index\.htm/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,''))).length) == 83 && eval('' + decodeURIComponent(document.URL.replace(anybitstoignore,'').replace('.au ','.au/').replace('.au%20','.au/').split('rjmprogramming.com.au/')[1].replace(/^index\.php/g,'').replace(/^index\.html/g,'').replace(/^index\.htm/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')).split(',').length) == 7) {
location.href='//www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=' + encodeURIComponent(decodeURIComponent(document.URL.replace(anybitstoignore,'').replace('.au ','.au/').replace('.au%20','.au/').split('rjmprogramming.com.au/')[1].replace(/^index\.php/g,'').replace(/^index\.html/g,'').replace(/^index\.htm/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')));
}

making it swing the Shower Songs into play with an erroneous URL such as …


https://www.rjmprogramming.com.au/FtE3hoR_Nvo,W5IKT_xue4o,IfaGhyK78E8,BuN3yCmHb_U,TdiAwCPb_As,euZcUku9XiE,aMs0rNtBZJk


Previous relevant Shower Songs Delimitation Role Tutorial is shown below.

Shower Songs Delimitation Role Tutorial

Shower Songs Delimitation Role Tutorial

You’d think we’d be done with ablutions at this blog, but noooooo wayyyy … Luna says … there’s all manner of molecular interest out there …

It’s not just H and the 2 and the O … it’s the art of the roleroll.

… or so says “The Lu” anyway!

We wanted our recent Shower Songs web application be the application of choice for URLs at RJM Programming involving our Shower Songs web application YouTube API “radio play” web application.

In a “remembering and recall” scenario …

  • first you have to store such a listing URL into window.localStorage …


    … and then …
  • you should recall these stored settings so that they can be reused …

… in …

… still using the RJM Programming’s 404.shtml HTTP Error Code 404 supervisor …


if (eval(('' + encodeURIComponent((decodeURIComponent(document.URL.replace(anybitstoignore,'').replace('.au ','.au/').replace('.au%20','.au/').split('rjmprogramming.com.au/')[1].replace(/^index\.php/g,'').replace(/^index\.html/g,'').replace(/^index\.htm/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')) + ',').replace(/[AEIMQUYcgkosw048]\,/g,'z'))).length) == 77 && eval(('' + decodeURIComponent(document.URL.replace(anybitstoignore,'').replace('.au ','.au/').replace('.au%20','.au/').split('rjmprogramming.com.au/')[1].replace(/^index\.php/g,'').replace(/^index\.html/g,'').replace(/^index\.htm/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,''))).length) == 83 && eval('' + decodeURIComponent(document.URL.replace(anybitstoignore,'').replace('.au ','.au/').replace('.au%20','.au/').split('rjmprogramming.com.au/')[1].replace(/^index\.php/g,'').replace(/^index\.html/g,'').replace(/^index\.htm/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')).split(',').length) == 7) {
location.href='//www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=' + encodeURIComponent(decodeURIComponent(document.URL.replace(anybitstoignore,'').replace('.au ','.au/').replace('.au%20','.au/').split('rjmprogramming.com.au/')[1].replace(/^index\.php/g,'').replace(/^index\.html/g,'').replace(/^index\.htm/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')));
}

making it swing the Shower Songs into play with an erroneous URL such as …


https://www.rjmprogramming.com.au/FtE3hoR_Nvo,W5IKT_xue4o,IfaGhyK78E8,BuN3yCmHb_U,TdiAwCPb_As,euZcUku9XiE,aMs0rNtBZJk


Previous relevant Shower Songs Colour Coding Tutorial is shown below.

Shower Songs Colour Coding Tutorial

Shower Songs Colour Coding Tutorial

YouTube API Songname Providence Shower Songs Tutorial of recent times had us interfacing …

  • song providence via Wikipedia ideas … with …
  • our inhouse Shower Songs project using YouTube API means to “Radio Play” some, let’s say, “theatrical pursuits by the water”

A couple of times now, we’ve used it as company in the bath via an iPhone, preparing the list ahead of ever having to tap another anything, to hear some songs in the sequence the user establishes ahead of time … ie. the purpose of this web application.

However, we made some bad colour choices, especially regarding the mobile red button overlayed by black text containing the song title. It was hard to see. It is easier now, that text being yellow.

While there, we decided on a pale green background colour to apply to the textarea user interactive input and progress displaying conduit, when it’s relevant YouTube video is playing (in audio stream only mode), and another principle of our Shower Songs logic is that you should only see one pale green textarea for any great period of time … ie. the songs play in sequence, and looping around in continuous play, like on the radio.

Believe it or not, the actual top level hierarchy Shower Songs window needs no changes for this, but …

  • the changed

    <script type=text/javascript>
    if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) || eval('' + navigator.maxTouchPoints) > 0) {
    if (window.parent != window.self) {
    if (('' + top.document.URL).indexOf('/shower_songs.htm') != -1 || ('' + parent.document.URL).indexOf('/shower_songs.htm') != -1) {
    document.write('<div><sty' + 'le> button { color: yellow !important; font-weight: bold !important; text-shadow: -1px 1px 1px #e52dff !important; } </sty' + 'le></div>');
    }
    }
    }
    </script>
    </body>

    karaoke_youtube_api.htm inhouse YouTube video interfacer helps with the yellow font via CSS … while with the supervised we have …
  • a changed two scenario Javascript situation …

    // textarea gets a pale green background
    if (('' + top.document.URL).indexOf('/shower_songs.htm') != -1 || ('' + parent.parent.document.URL).indexOf('/shower_songs.htm') != -1) {
    parent.parent.document.getElementById(location.hash.replace(/\#/g,'')).style.backgroundColor='#F0FFF0';
    }
    parent.parent.document.getElementById(location.hash.replace(/\#/g,'')).placeholder='' + secscnt + '/' + duration + ' ... ' + 'P=pause/play S=stop M=mute U=unmute Y=YouTube G=Google W=Wikipedia L=loop ';
    //
    // textarea gets usual white background
    if (('' + top.document.URL).indexOf('/shower_songs.htm') != -1 || ('' + parent.parent.document.URL).indexOf('/shower_songs.htm') != -1) {
    parent.parent.document.getElementById(location.hash.replace(/\#/g,'')).style.backgroundColor='white';
    }
    parent.parent.document.getElementById(location.hash.replace(/\#/g,'')).placeholder='' + Math.round(cen) + '/' + duration + ' ... ' + 'P=play/pause S=stop M=' + mletter + 'ute U=' + uletter + 'nmute Y=YouTube G=Google W=Wikipedia L=loop' + psuf;

    … where stop_start_youtube.html controls those textarea element background colours in that grandchild YouTube API inhouse interfacer

… were needed to make this colour coding logic happen to improve how the user uses this web application, we’re hoping. Ie. bye for now.

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