We break with our normal transmission, because we read something …
… Luuunnnaa?! Sarcasm does not look good on you (though lilac green’s not bad). And wipe that sardonic grin off your breakfast bowl food rearrangements you’ve just made?!
A feather to our boa constrictor … Luuunnnaa?! … get off the keyboard now … don’t you have some bone to pick, or that book about Dogma (tee hee) to read?!w
… on that Shower Songs YouTube embedded iframe inhouse playlist concept, further to Shower Songs Playlist Subset Revisit Tutorial. Some people, like Luna today, may want to bypass our Shower Songs just audio paradigm to dynamically create a temporary YouTube playlist and play video and audio together a playlist in sequential order.
Anyway, we tweaked stuff to start the ball rolling making this be a possibility, as well as involving YouTube video ID PtR4cWb4HNg in the list to spark this concept into action. And later we’ll explain maybe why PtR4cWb4HNg should lead the comma separated list.
Radio Play via comma separate YouTube 11 character IDs or search ideas for an inhouse playlist (if any in a comma separated list is PtR4cWb4HNg temporary YouTube playlist audio and video play can be attempted) … 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,
Did You Know?
If at the time of launching (and deploying) into making one of these temporary YouTube playlists and you are logged into your own YouTube channel, more possibilities present, and today’s tutorial animated GIF shows a bit of this (though we found out about the virtue of putting PtR4cWb4HNg first later, alas).
The playlist gets played, and on non-mobile it may start itself. For each track you can use the Save button down near the bottom to save to a new (where we are recommending PtR4cWb4HNg to go first) or pre-existing public or private playlist. Okay, so you have this new YouTube playlist.
… in which case a brief error message may happen and it may start playing (on non-mobile) that YouTube playlist at track 2 … hence my advice regarding PtR4cWb4HNg … or …
A few attempts we made failed to “curb the enthusiasm” of the parent window left behind by the new window.open window of these Playlist Subsets the user defines, until we did something we can not recall ever doing before, namely …
var tdsarea=document.getElementsByTagName('td');
for (var iopj=eval(-1 + tdsarea.length); iopj>=0; iopj--) {
tdsarea[iopj].innerHTML=tdsarea[iopj].innerText;
}
… to not only be “curbing it’s enthusiasm to play” but also making that parent window end up being a “display snapshot only” of what had been going on before the user set up more than one “L=loop” looping textarea functionalities that defines a playlist subset scenario where that new window takes on the role of “enthusiastic play”.
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 …
… 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 …
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
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 …
Add to Home Screen … with a tailored (Playlist) Title … this being our preferred option to future proof the remembering … but also available is …
Add Bookmark … or …
Add Favourite
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” …
you can DIY build an iOS feeling and “hybrid looking” amalgum of iOS and “old days” dialog box “desktop feeling” personalized application(s) …
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.
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
… 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).
macOS (building onthe changedplay.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
Windows (building onthe changedplay.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 …
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 …
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!
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 …
enter into the wooooorrrrllllddd of aliases (thanks to this great advice, thanks) … eg.
alias play="/Applications/MAMP/htdocs/play"
placed into …
~/.bashrc
… via (in our case) …
vi ~/.bashrc
then …
source ~/.bashrc
… needs to be included into the login procedure of …
~/.profile
…via (in our case) …
vi ~/.profile
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) …
… 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.
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.
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 …
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 …
&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
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 …
still support your single choice scenario
we’ve coded today’s dropdown to support, as applicable, ordered single click choices … versus …
can allow for control key (sets of choices not necessarily adjacent) and shift key (blocks of choices)
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 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 …
Because the theme of our current Editable Calendar web application revolves around time stamps and day names and month names regarding yesterday’s Editable Calendar Google Translate Tutorial that means, regarding language internationalization ideas …
as well as yesterday’s Google Translate ideas … also available is …
Yesterday’s Editable Calendar Primer Tutorial‘s start to our Editable Calendar project was a very anglo-centric exercise. Today, we want to use the great …
… to help translate our inhouse burgeoning Editable Calendar skeletal contents to some non English languages.
Why the skeletal here? Well, your own entries made before you select a dropdown non English language choice are stripped out in this changedsecond draftEditable Calendar you can try below, because we’re using the Google Translate “static URL” approach to the translations. But we will examine, down the track, if we can do better?! Again, stay tuned for more progression and internationalization over the days on this Editable Calendar project.
we’re channelling how in emails “word strings” starting with “http” become links … and so …
in our event in month “blurb” textarea elements we allow user highlighted text containing such “http” “word strings” be opened in popup windows showing the content of those URLs, as available
Here is the relevant Javascript we ended up with, for this …
Just briefly, delved into the wooooorrrrllllldddd of days of the week before 1582 debate … you had to be there … and in the words of Lleyton … Come on!!!! And we came out the other side. Good times! Anyway, thanks for all the interesting discussion, which we recommend you start at with this gem. Anyway, we now allow dates after 1582 (after this was previously set at 1970) in all respects and dates between 0000 and 1581 only via tweaks to the address bar URL you do yourself and we just hide the day of the week string. Otherwise … this could be needed?!
When doing our inhouse testing for Event Calendar Collaboration Tutorial the other day, it got us “peeved”, shall we say. We wanted a mechanism, with those “a” link “mailto:” emailing arrangements, of not having to fill out the email address in the “To:” field each time. First world problem alert! Still and all …
When it comes to procedures …
Aaaaaarrrrgggghhhh …
Nuances count … regarding …
Errrrrrr …
Saving time …
Saving frustration
… resulting in the “easy to remember” acronym WANESS … we rest our cases!
What can help here? Well, it is a personalization … so … anyone, anyone? Yes, Lou, back from holidays, a month late … yes, well, okay … we can see you’ve put some thought into this … HTTP Cookies could be used. Yes, Shwetank, you’ve had your hand up some time now. We agree, Web Storage window.localStorage allows for more data, so we’ll go with that, though either style of approach would work here.
Global variables initialization …
var defemail='', defsms='';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
Within document.body onload event logic …
if (document.getElementById('semail') && document.getElementById('ssms')) {
document.getElementById('semail').oncontextmenu=function(){ emailaskit(); };
document.getElementById('semail').ontouchmove=function(){ emailaskit(); };
document.getElementById('ssms').oncontextmenu=function(){ smsaskit(); };
document.getElementById('ssms').ontouchmove=function(){ smsaskit(); };
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('semail').title+=' Move gesture here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Move gesture here can ask for new default remembered SMS number for collaboration purposes';
} else {
document.getElementById('semail').title+=' Right click here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Right click here can ask for new default remembered SMS number for collaboration purposes';
}
}
Calling these two Javascript function helpers …
function emailaskit() {
if (defemail == defemail.trim()) {
defemail=defemail.trim() + ' ';
var emailm=prompt('Enter default email address.', defemail.trim());
if (emailm == null) { emailm=''; }
if (emailm.trim() != '' && emailm.trim().indexOf('@') != -1) {
defemail=emailm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', emailm.trim());
}
}
defemail=defemail.trim() + ' ';
}
function smsaskit() {
if (defsms == defsms.trim()) {
defsms=defsms.trim() + ' ';
var smsm=prompt('Enter default SMS number.', defsms.trim());
if (smsm == null) { smsm=''; }
if (smsm.trim() != '' && smsm.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
defsms=smsm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', smsm.trim());
}
}
defsms=defsms.trim() + ' ';
}
And allow control, as well, at the SMS prompt window logic …
function dosms() {
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
//alert('' + eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length));
if (eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length) >= 18000) {
snum=('' + prompt('Please enter SMS number to send to. We suspect message is too long for an SMS and if you enter an email address here instead, we will try to send an email instead. Append space(s) to remember, whatever you enter, for next time.', snum)).replace(/^null/g, (defemail.indexOf('@') != -1 ? defemail : (defsms != '' ? defsms : '')) );
} else {
snum=('' + prompt('Please enter SMS number to send to. Append space(s) to remember for next time.', snum)).replace(/^null/g, (defsms != '' ? defsms : (defemail.indexOf('@') != -1 ? defemail : '')));
}
if (snum == null) { snum=''; }
if (snum.indexOf('@') != -1) {
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', snum);
defemail=snum;
}
return doemail(snum);
} else if (snum.trim() != '' && snum.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
//alert('Snum=' + snum + '?');
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', snum);
defsms=snum;
}
var azx=top.document.getElementById('xas' + 'ms');
if (azx == null) { azx=top.document.createElement("a"); }
//if (1 == 1) {
// document.getElementById('divas').appendChild(azx);
//} else {
top.document.body.appendChild(azx);
// }
azx.id = 'xas' + 'ms';
azx.target = "_top";
azx.style = "display: none";
azx.href = 'sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()));
azx.click();
}
return '';
}
Also, today, we battled the logic to allow the textarea element onblur events also open the door to emailing and SMS “work in progress”. Believe it or not, this timing change was quite difficult in the changedevents_in_month.htm parent of the Events in Month web application. Never a dull moment in web application I.T. we’d say!
it did not have a fully fleshed out collaboration or sharing set of functionalities … at the time, probably, because …
each Monthly calendar filled out, and wanting to be saved, could involve much more than the 850 characters available to previous “mailto:” or “sms:” communication conduits, back to when we first tackled this project … but now …
hashtagging parts to the “mailto:” URLs (and maybe sometimes the “sms:” URL) might cover the data length needs
… so that this Event Calendar could be a web application at the center of a collaboration network of people working on that event organization. Much more useful, we figure!
Timing became really important with this integration of …
email
SMS
… communication conduit possibilities. With its design we have to wait until the point where the user is filling in textarea elements regarding a designated …
Month
Year
… of relevance, before we allow the email 📧 and SMS 📟 emoji buttons be shown. In the code …
Amended HTML h1 element static HTML to add, later shown, perhaps, email 📧 and SMS 📟 emoji buttons …
<h1>Events in Month <button style=display:none; title='Share via Email' id=semail onclick="doemail('');">📧</button> <button style=display:none; title='Share via SMS' id=ssms onclick=dosms();>📟</button> </h1>
New static HTML div element placed to the bottom of the body element …
<div id=divas></div>
New Javascript global variables (picking up hashtagging parts of the address bar URL, perhaps linked off an email or SMS link clicked) …
Client meets server today, allowing the PHP data storage talents in yesterday’s Event Calendar PHP Tutorial‘s work to meet a “clientside” way to …
Record to Remember via Bookmark
… use the web browser Bookmarks to help you recall an Events in Month report with long entries.
Involving a Bookmark still needs those “get” ? and & arguments, and we allow the PHP to lookup for us the data underscoring an address bar URL such as …
… that mapping being possible, now, making use of a pseudo hashtag arrangement … your Clayton‘s hashtag, if you will!
To start to use a hashtag suits, as your hashtag navigation only makes sense in the “clientside” woooorrrrrllllddd, and even there, really using one only tries to position a webpage where an element with an ID matching the hashtag sits (and we are never going to have this ID element in our work), and in the meantime we’ve passed across from the child PHP to the parent HTML a valuable piece of information helping the link to the Bookmark system be possible. The Javascript codeline (you may have noticed) …
var documentURL=document.URL;
… as stupid and simple looking as it is, is crucial for us. We get child webpage parts (like our PHP) to change document.URL to a far too long in normal circumstances address bar URL the rest of the code feeds off. It’s just that now, that far too long in normal circumstances address bar URL has a #[hashtag] appended such as …
#August__2023_00000__1
… uniquifying a Month, Year Events in Month identifier part with a version of the user’s IP address (so that they only see what is relevant to them).
Address bar URLs such as “https://www.rjmprogramming.com.au/HTMLCSS/events_in_month.php?exactlabel=August__2023_00000__1” are Bookmarkable, and so we allow for similar outcomes with less concern about how much data is being “recorded” and recallable (via that web browser’s Bookmark system).
Also, today, a lot of CSS tweaks, so that the CSS styling now looks like …
… form submit button (toggling) value to start involving PHP with those longer datasets of Event in Month descriptions, in our most recent project. What do we use as the data conduit? No, not a database. No, not a serverside flat file. No, not clientside window.localStorage nor window.sessionStorage nor HTTP Cookies. We store long Event in Month description data in our new events_in_month.php PHP itself. And this same PHP can populate options in a new dropdown element in the parent to facilitate the recalling of any relevant “Record to Remember” recordings.
The PHP is kind of short, so we will show it below, including one MAMP example of that “self storage” …
<?php
// events_in_month.php
// RJM Programming
// August, 2023
// Help out events_in_month.htm
But, there’s an inherent weakness with the design, we’ll go into more into the future.
… well … it’s a perennial for us, regarding how if you stick with clientside thinking, only, web applications, when the amount of data to remember starts adding up, the “get arguments approach” ( ie. use ? and & arguments at the address bar ) is restricted by length restrictions regarding URL lengths.
Rather than jump to PHP serverside ideas just yet, we wanted to show some more ideas, staying with “clientside only thinking”, today, as well as improving the UX (user experience) and small steps forward regarding styling.
Okay then, regarding the idea to remember an Event in Month form, when there is a lot of data, and staying “just clientside”, we’ve coded for a “New Window” idea, albeit not as memorable as the default “Remember in Bookmark” possible for your smaller datasets. However, in saying that, we found that within this new window, with our Google Chrome web browser, we could …
bring up Context Menu with a right click or two finger gesture within the popup window webpage content …
pick Inspect option …
be in Elements tab of your Web Inspector … and …
highlight top <html> tag …
Context Menu with a right click or two finger gesture …
pick Copy -> Copy outerHTML … so that …
your Event Calendar for your Events in Month choice is in a text buffer … ready for you to …
Paste into a Text Editor that Events in Month webpage to store (perhaps in a MAMP local Apache/PHP/mySql web server environment, where you can further look at and develop your own ideas)
The user is told when the switch to “New Window” compromise becomes active, decided upon by reconstructing the proposed address bar URL regularly and when too long …
function formanalyze() {
var fio=document.getElementsByTagName('form')[0];
var delm='?';
var fioih=fio.innerHTML;
var fions=fioih.split(' name="');
var testurl=documentURL.split('?')[0].split('#')[0];
for (var ijk=1; ijk<fions.length; ijk++) {
testurl+=delm + fions[ijk].split('"')[0] + '=' + encodeURIComponent(document.getElementById(fions[ijk].split('"')[0]).value);
delm='&';
}
setTimeout(formanalyze, 3000);
if (eval('' + testurl.length) >= 750) {
if (document.getElementById('remember')) { document.getElementById('remember').value='New window'; }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value='New window'; }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value='New window'; }
} else {
if (document.getElementById('remember')) { document.getElementById('remember').value=document.getElementById('remember').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value=document.getElementById('rememberme').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value=document.getElementById('remembermoi').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
}
return eval('' + testurl.length);
}
… the form submit buttons are reworded accordingly.
Another idea from this blog thread’s inspiration …
… we’ve now addressed in today’s “second draft” is allowing for an optional bold Event Day Blurb Title, available to the user via a new dropdown “Bold Title” option.
And, how can we do more with colour, to help the right bits stand out, and be consistent? We thought …
text shadow means by which the text of Event Calendar can be more impactive …
<div style="text-shadow:-1px 1px 1px #ff2d95;" id=eventcalendar></div>
Yesterday’s Editable Calendar Primer Tutorial‘s start to our Editable Calendar project was a very anglo-centric exercise. Today, we want to use the great …
… to help translate our inhouse burgeoning Editable Calendar skeletal contents to some non English languages.
Why the skeletal here? Well, your own entries made before you select a dropdown non English language choice are stripped out in this changedsecond draftEditable Calendar you can try below, because we’re using the Google Translate “static URL” approach to the translations. But we will examine, down the track, if we can do better?! Again, stay tuned for more progression and internationalization over the days on this Editable Calendar project.
we’re channelling how in emails “word strings” starting with “http” become links … and so …
in our event in month “blurb” textarea elements we allow user highlighted text containing such “http” “word strings” be opened in popup windows showing the content of those URLs, as available
Here is the relevant Javascript we ended up with, for this …
Just briefly, delved into the wooooorrrrllllldddd of days of the week before 1582 debate … you had to be there … and in the words of Lleyton … Come on!!!! And we came out the other side. Good times! Anyway, thanks for all the interesting discussion, which we recommend you start at with this gem. Anyway, we now allow dates after 1582 (after this was previously set at 1970) in all respects and dates between 0000 and 1581 only via tweaks to the address bar URL you do yourself and we just hide the day of the week string. Otherwise … this could be needed?!
When doing our inhouse testing for Event Calendar Collaboration Tutorial the other day, it got us “peeved”, shall we say. We wanted a mechanism, with those “a” link “mailto:” emailing arrangements, of not having to fill out the email address in the “To:” field each time. First world problem alert! Still and all …
When it comes to procedures …
Aaaaaarrrrgggghhhh …
Nuances count … regarding …
Errrrrrr …
Saving time …
Saving frustration
… resulting in the “easy to remember” acronym WANESS … we rest our cases!
What can help here? Well, it is a personalization … so … anyone, anyone? Yes, Lou, back from holidays, a month late … yes, well, okay … we can see you’ve put some thought into this … HTTP Cookies could be used. Yes, Shwetank, you’ve had your hand up some time now. We agree, Web Storage window.localStorage allows for more data, so we’ll go with that, though either style of approach would work here.
Global variables initialization …
var defemail='', defsms='';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
Within document.body onload event logic …
if (document.getElementById('semail') && document.getElementById('ssms')) {
document.getElementById('semail').oncontextmenu=function(){ emailaskit(); };
document.getElementById('semail').ontouchmove=function(){ emailaskit(); };
document.getElementById('ssms').oncontextmenu=function(){ smsaskit(); };
document.getElementById('ssms').ontouchmove=function(){ smsaskit(); };
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('semail').title+=' Move gesture here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Move gesture here can ask for new default remembered SMS number for collaboration purposes';
} else {
document.getElementById('semail').title+=' Right click here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Right click here can ask for new default remembered SMS number for collaboration purposes';
}
}
Calling these two Javascript function helpers …
function emailaskit() {
if (defemail == defemail.trim()) {
defemail=defemail.trim() + ' ';
var emailm=prompt('Enter default email address.', defemail.trim());
if (emailm == null) { emailm=''; }
if (emailm.trim() != '' && emailm.trim().indexOf('@') != -1) {
defemail=emailm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', emailm.trim());
}
}
defemail=defemail.trim() + ' ';
}
function smsaskit() {
if (defsms == defsms.trim()) {
defsms=defsms.trim() + ' ';
var smsm=prompt('Enter default SMS number.', defsms.trim());
if (smsm == null) { smsm=''; }
if (smsm.trim() != '' && smsm.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
defsms=smsm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', smsm.trim());
}
}
defsms=defsms.trim() + ' ';
}
And allow control, as well, at the SMS prompt window logic …
function dosms() {
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
//alert('' + eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length));
if (eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length) >= 18000) {
snum=('' + prompt('Please enter SMS number to send to. We suspect message is too long for an SMS and if you enter an email address here instead, we will try to send an email instead. Append space(s) to remember, whatever you enter, for next time.', snum)).replace(/^null/g, (defemail.indexOf('@') != -1 ? defemail : (defsms != '' ? defsms : '')) );
} else {
snum=('' + prompt('Please enter SMS number to send to. Append space(s) to remember for next time.', snum)).replace(/^null/g, (defsms != '' ? defsms : (defemail.indexOf('@') != -1 ? defemail : '')));
}
if (snum == null) { snum=''; }
if (snum.indexOf('@') != -1) {
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', snum);
defemail=snum;
}
return doemail(snum);
} else if (snum.trim() != '' && snum.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
//alert('Snum=' + snum + '?');
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', snum);
defsms=snum;
}
var azx=top.document.getElementById('xas' + 'ms');
if (azx == null) { azx=top.document.createElement("a"); }
//if (1 == 1) {
// document.getElementById('divas').appendChild(azx);
//} else {
top.document.body.appendChild(azx);
// }
azx.id = 'xas' + 'ms';
azx.target = "_top";
azx.style = "display: none";
azx.href = 'sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()));
azx.click();
}
return '';
}
Also, today, we battled the logic to allow the textarea element onblur events also open the door to emailing and SMS “work in progress”. Believe it or not, this timing change was quite difficult in the changedevents_in_month.htm parent of the Events in Month web application. Never a dull moment in web application I.T. we’d say!
it did not have a fully fleshed out collaboration or sharing set of functionalities … at the time, probably, because …
each Monthly calendar filled out, and wanting to be saved, could involve much more than the 850 characters available to previous “mailto:” or “sms:” communication conduits, back to when we first tackled this project … but now …
hashtagging parts to the “mailto:” URLs (and maybe sometimes the “sms:” URL) might cover the data length needs
… so that this Event Calendar could be a web application at the center of a collaboration network of people working on that event organization. Much more useful, we figure!
Timing became really important with this integration of …
email
SMS
… communication conduit possibilities. With its design we have to wait until the point where the user is filling in textarea elements regarding a designated …
Month
Year
… of relevance, before we allow the email 📧 and SMS 📟 emoji buttons be shown. In the code …
Amended HTML h1 element static HTML to add, later shown, perhaps, email 📧 and SMS 📟 emoji buttons …
<h1>Events in Month <button style=display:none; title='Share via Email' id=semail onclick="doemail('');">📧</button> <button style=display:none; title='Share via SMS' id=ssms onclick=dosms();>📟</button> </h1>
New static HTML div element placed to the bottom of the body element …
<div id=divas></div>
New Javascript global variables (picking up hashtagging parts of the address bar URL, perhaps linked off an email or SMS link clicked) …
Client meets server today, allowing the PHP data storage talents in yesterday’s Event Calendar PHP Tutorial‘s work to meet a “clientside” way to …
Record to Remember via Bookmark
… use the web browser Bookmarks to help you recall an Events in Month report with long entries.
Involving a Bookmark still needs those “get” ? and & arguments, and we allow the PHP to lookup for us the data underscoring an address bar URL such as …
… that mapping being possible, now, making use of a pseudo hashtag arrangement … your Clayton‘s hashtag, if you will!
To start to use a hashtag suits, as your hashtag navigation only makes sense in the “clientside” woooorrrrrllllddd, and even there, really using one only tries to position a webpage where an element with an ID matching the hashtag sits (and we are never going to have this ID element in our work), and in the meantime we’ve passed across from the child PHP to the parent HTML a valuable piece of information helping the link to the Bookmark system be possible. The Javascript codeline (you may have noticed) …
var documentURL=document.URL;
… as stupid and simple looking as it is, is crucial for us. We get child webpage parts (like our PHP) to change document.URL to a far too long in normal circumstances address bar URL the rest of the code feeds off. It’s just that now, that far too long in normal circumstances address bar URL has a #[hashtag] appended such as …
#August__2023_00000__1
… uniquifying a Month, Year Events in Month identifier part with a version of the user’s IP address (so that they only see what is relevant to them).
Address bar URLs such as “https://www.rjmprogramming.com.au/HTMLCSS/events_in_month.php?exactlabel=August__2023_00000__1” are Bookmarkable, and so we allow for similar outcomes with less concern about how much data is being “recorded” and recallable (via that web browser’s Bookmark system).
Also, today, a lot of CSS tweaks, so that the CSS styling now looks like …
… form submit button (toggling) value to start involving PHP with those longer datasets of Event in Month descriptions, in our most recent project. What do we use as the data conduit? No, not a database. No, not a serverside flat file. No, not clientside window.localStorage nor window.sessionStorage nor HTTP Cookies. We store long Event in Month description data in our new events_in_month.php PHP itself. And this same PHP can populate options in a new dropdown element in the parent to facilitate the recalling of any relevant “Record to Remember” recordings.
The PHP is kind of short, so we will show it below, including one MAMP example of that “self storage” …
<?php
// events_in_month.php
// RJM Programming
// August, 2023
// Help out events_in_month.htm
But, there’s an inherent weakness with the design, we’ll go into more into the future.
… well … it’s a perennial for us, regarding how if you stick with clientside thinking, only, web applications, when the amount of data to remember starts adding up, the “get arguments approach” ( ie. use ? and & arguments at the address bar ) is restricted by length restrictions regarding URL lengths.
Rather than jump to PHP serverside ideas just yet, we wanted to show some more ideas, staying with “clientside only thinking”, today, as well as improving the UX (user experience) and small steps forward regarding styling.
Okay then, regarding the idea to remember an Event in Month form, when there is a lot of data, and staying “just clientside”, we’ve coded for a “New Window” idea, albeit not as memorable as the default “Remember in Bookmark” possible for your smaller datasets. However, in saying that, we found that within this new window, with our Google Chrome web browser, we could …
bring up Context Menu with a right click or two finger gesture within the popup window webpage content …
pick Inspect option …
be in Elements tab of your Web Inspector … and …
highlight top <html> tag …
Context Menu with a right click or two finger gesture …
pick Copy -> Copy outerHTML … so that …
your Event Calendar for your Events in Month choice is in a text buffer … ready for you to …
Paste into a Text Editor that Events in Month webpage to store (perhaps in a MAMP local Apache/PHP/mySql web server environment, where you can further look at and develop your own ideas)
The user is told when the switch to “New Window” compromise becomes active, decided upon by reconstructing the proposed address bar URL regularly and when too long …
function formanalyze() {
var fio=document.getElementsByTagName('form')[0];
var delm='?';
var fioih=fio.innerHTML;
var fions=fioih.split(' name="');
var testurl=documentURL.split('?')[0].split('#')[0];
for (var ijk=1; ijk<fions.length; ijk++) {
testurl+=delm + fions[ijk].split('"')[0] + '=' + encodeURIComponent(document.getElementById(fions[ijk].split('"')[0]).value);
delm='&';
}
setTimeout(formanalyze, 3000);
if (eval('' + testurl.length) >= 750) {
if (document.getElementById('remember')) { document.getElementById('remember').value='New window'; }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value='New window'; }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value='New window'; }
} else {
if (document.getElementById('remember')) { document.getElementById('remember').value=document.getElementById('remember').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value=document.getElementById('rememberme').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value=document.getElementById('remembermoi').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
}
return eval('' + testurl.length);
}
… the form submit buttons are reworded accordingly.
Another idea from this blog thread’s inspiration …
… we’ve now addressed in today’s “second draft” is allowing for an optional bold Event Day Blurb Title, available to the user via a new dropdown “Bold Title” option.
And, how can we do more with colour, to help the right bits stand out, and be consistent? We thought …
text shadow means by which the text of Event Calendar can be more impactive …
<div style="text-shadow:-1px 1px 1px #ff2d95;" id=eventcalendar></div>
we’re channelling how in emails “word strings” starting with “http” become links … and so …
in our event in month “blurb” textarea elements we allow user highlighted text containing such “http” “word strings” be opened in popup windows showing the content of those URLs, as available
Here is the relevant Javascript we ended up with, for this …
Just briefly, delved into the wooooorrrrllllldddd of days of the week before 1582 debate … you had to be there … and in the words of Lleyton … Come on!!!! And we came out the other side. Good times! Anyway, thanks for all the interesting discussion, which we recommend you start at with this gem. Anyway, we now allow dates after 1582 (after this was previously set at 1970) in all respects and dates between 0000 and 1581 only via tweaks to the address bar URL you do yourself and we just hide the day of the week string. Otherwise … this could be needed?!
When doing our inhouse testing for Event Calendar Collaboration Tutorial the other day, it got us “peeved”, shall we say. We wanted a mechanism, with those “a” link “mailto:” emailing arrangements, of not having to fill out the email address in the “To:” field each time. First world problem alert! Still and all …
When it comes to procedures …
Aaaaaarrrrgggghhhh …
Nuances count … regarding …
Errrrrrr …
Saving time …
Saving frustration
… resulting in the “easy to remember” acronym WANESS … we rest our cases!
What can help here? Well, it is a personalization … so … anyone, anyone? Yes, Lou, back from holidays, a month late … yes, well, okay … we can see you’ve put some thought into this … HTTP Cookies could be used. Yes, Shwetank, you’ve had your hand up some time now. We agree, Web Storage window.localStorage allows for more data, so we’ll go with that, though either style of approach would work here.
Global variables initialization …
var defemail='', defsms='';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
Within document.body onload event logic …
if (document.getElementById('semail') && document.getElementById('ssms')) {
document.getElementById('semail').oncontextmenu=function(){ emailaskit(); };
document.getElementById('semail').ontouchmove=function(){ emailaskit(); };
document.getElementById('ssms').oncontextmenu=function(){ smsaskit(); };
document.getElementById('ssms').ontouchmove=function(){ smsaskit(); };
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('semail').title+=' Move gesture here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Move gesture here can ask for new default remembered SMS number for collaboration purposes';
} else {
document.getElementById('semail').title+=' Right click here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Right click here can ask for new default remembered SMS number for collaboration purposes';
}
}
Calling these two Javascript function helpers …
function emailaskit() {
if (defemail == defemail.trim()) {
defemail=defemail.trim() + ' ';
var emailm=prompt('Enter default email address.', defemail.trim());
if (emailm == null) { emailm=''; }
if (emailm.trim() != '' && emailm.trim().indexOf('@') != -1) {
defemail=emailm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', emailm.trim());
}
}
defemail=defemail.trim() + ' ';
}
function smsaskit() {
if (defsms == defsms.trim()) {
defsms=defsms.trim() + ' ';
var smsm=prompt('Enter default SMS number.', defsms.trim());
if (smsm == null) { smsm=''; }
if (smsm.trim() != '' && smsm.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
defsms=smsm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', smsm.trim());
}
}
defsms=defsms.trim() + ' ';
}
And allow control, as well, at the SMS prompt window logic …
function dosms() {
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
//alert('' + eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length));
if (eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length) >= 18000) {
snum=('' + prompt('Please enter SMS number to send to. We suspect message is too long for an SMS and if you enter an email address here instead, we will try to send an email instead. Append space(s) to remember, whatever you enter, for next time.', snum)).replace(/^null/g, (defemail.indexOf('@') != -1 ? defemail : (defsms != '' ? defsms : '')) );
} else {
snum=('' + prompt('Please enter SMS number to send to. Append space(s) to remember for next time.', snum)).replace(/^null/g, (defsms != '' ? defsms : (defemail.indexOf('@') != -1 ? defemail : '')));
}
if (snum == null) { snum=''; }
if (snum.indexOf('@') != -1) {
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', snum);
defemail=snum;
}
return doemail(snum);
} else if (snum.trim() != '' && snum.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
//alert('Snum=' + snum + '?');
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', snum);
defsms=snum;
}
var azx=top.document.getElementById('xas' + 'ms');
if (azx == null) { azx=top.document.createElement("a"); }
//if (1 == 1) {
// document.getElementById('divas').appendChild(azx);
//} else {
top.document.body.appendChild(azx);
// }
azx.id = 'xas' + 'ms';
azx.target = "_top";
azx.style = "display: none";
azx.href = 'sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()));
azx.click();
}
return '';
}
Also, today, we battled the logic to allow the textarea element onblur events also open the door to emailing and SMS “work in progress”. Believe it or not, this timing change was quite difficult in the changedevents_in_month.htm parent of the Events in Month web application. Never a dull moment in web application I.T. we’d say!
it did not have a fully fleshed out collaboration or sharing set of functionalities … at the time, probably, because …
each Monthly calendar filled out, and wanting to be saved, could involve much more than the 850 characters available to previous “mailto:” or “sms:” communication conduits, back to when we first tackled this project … but now …
hashtagging parts to the “mailto:” URLs (and maybe sometimes the “sms:” URL) might cover the data length needs
… so that this Event Calendar could be a web application at the center of a collaboration network of people working on that event organization. Much more useful, we figure!
Timing became really important with this integration of …
email
SMS
… communication conduit possibilities. With its design we have to wait until the point where the user is filling in textarea elements regarding a designated …
Month
Year
… of relevance, before we allow the email 📧 and SMS 📟 emoji buttons be shown. In the code …
Amended HTML h1 element static HTML to add, later shown, perhaps, email 📧 and SMS 📟 emoji buttons …
<h1>Events in Month <button style=display:none; title='Share via Email' id=semail onclick="doemail('');">📧</button> <button style=display:none; title='Share via SMS' id=ssms onclick=dosms();>📟</button> </h1>
New static HTML div element placed to the bottom of the body element …
<div id=divas></div>
New Javascript global variables (picking up hashtagging parts of the address bar URL, perhaps linked off an email or SMS link clicked) …
Client meets server today, allowing the PHP data storage talents in yesterday’s Event Calendar PHP Tutorial‘s work to meet a “clientside” way to …
Record to Remember via Bookmark
… use the web browser Bookmarks to help you recall an Events in Month report with long entries.
Involving a Bookmark still needs those “get” ? and & arguments, and we allow the PHP to lookup for us the data underscoring an address bar URL such as …
… that mapping being possible, now, making use of a pseudo hashtag arrangement … your Clayton‘s hashtag, if you will!
To start to use a hashtag suits, as your hashtag navigation only makes sense in the “clientside” woooorrrrrllllddd, and even there, really using one only tries to position a webpage where an element with an ID matching the hashtag sits (and we are never going to have this ID element in our work), and in the meantime we’ve passed across from the child PHP to the parent HTML a valuable piece of information helping the link to the Bookmark system be possible. The Javascript codeline (you may have noticed) …
var documentURL=document.URL;
… as stupid and simple looking as it is, is crucial for us. We get child webpage parts (like our PHP) to change document.URL to a far too long in normal circumstances address bar URL the rest of the code feeds off. It’s just that now, that far too long in normal circumstances address bar URL has a #[hashtag] appended such as …
#August__2023_00000__1
… uniquifying a Month, Year Events in Month identifier part with a version of the user’s IP address (so that they only see what is relevant to them).
Address bar URLs such as “https://www.rjmprogramming.com.au/HTMLCSS/events_in_month.php?exactlabel=August__2023_00000__1” are Bookmarkable, and so we allow for similar outcomes with less concern about how much data is being “recorded” and recallable (via that web browser’s Bookmark system).
Also, today, a lot of CSS tweaks, so that the CSS styling now looks like …
… form submit button (toggling) value to start involving PHP with those longer datasets of Event in Month descriptions, in our most recent project. What do we use as the data conduit? No, not a database. No, not a serverside flat file. No, not clientside window.localStorage nor window.sessionStorage nor HTTP Cookies. We store long Event in Month description data in our new events_in_month.php PHP itself. And this same PHP can populate options in a new dropdown element in the parent to facilitate the recalling of any relevant “Record to Remember” recordings.
The PHP is kind of short, so we will show it below, including one MAMP example of that “self storage” …
<?php
// events_in_month.php
// RJM Programming
// August, 2023
// Help out events_in_month.htm
But, there’s an inherent weakness with the design, we’ll go into more into the future.
… well … it’s a perennial for us, regarding how if you stick with clientside thinking, only, web applications, when the amount of data to remember starts adding up, the “get arguments approach” ( ie. use ? and & arguments at the address bar ) is restricted by length restrictions regarding URL lengths.
Rather than jump to PHP serverside ideas just yet, we wanted to show some more ideas, staying with “clientside only thinking”, today, as well as improving the UX (user experience) and small steps forward regarding styling.
Okay then, regarding the idea to remember an Event in Month form, when there is a lot of data, and staying “just clientside”, we’ve coded for a “New Window” idea, albeit not as memorable as the default “Remember in Bookmark” possible for your smaller datasets. However, in saying that, we found that within this new window, with our Google Chrome web browser, we could …
bring up Context Menu with a right click or two finger gesture within the popup window webpage content …
pick Inspect option …
be in Elements tab of your Web Inspector … and …
highlight top <html> tag …
Context Menu with a right click or two finger gesture …
pick Copy -> Copy outerHTML … so that …
your Event Calendar for your Events in Month choice is in a text buffer … ready for you to …
Paste into a Text Editor that Events in Month webpage to store (perhaps in a MAMP local Apache/PHP/mySql web server environment, where you can further look at and develop your own ideas)
The user is told when the switch to “New Window” compromise becomes active, decided upon by reconstructing the proposed address bar URL regularly and when too long …
function formanalyze() {
var fio=document.getElementsByTagName('form')[0];
var delm='?';
var fioih=fio.innerHTML;
var fions=fioih.split(' name="');
var testurl=documentURL.split('?')[0].split('#')[0];
for (var ijk=1; ijk<fions.length; ijk++) {
testurl+=delm + fions[ijk].split('"')[0] + '=' + encodeURIComponent(document.getElementById(fions[ijk].split('"')[0]).value);
delm='&';
}
setTimeout(formanalyze, 3000);
if (eval('' + testurl.length) >= 750) {
if (document.getElementById('remember')) { document.getElementById('remember').value='New window'; }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value='New window'; }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value='New window'; }
} else {
if (document.getElementById('remember')) { document.getElementById('remember').value=document.getElementById('remember').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value=document.getElementById('rememberme').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value=document.getElementById('remembermoi').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
}
return eval('' + testurl.length);
}
… the form submit buttons are reworded accordingly.
Another idea from this blog thread’s inspiration …
… we’ve now addressed in today’s “second draft” is allowing for an optional bold Event Day Blurb Title, available to the user via a new dropdown “Bold Title” option.
And, how can we do more with colour, to help the right bits stand out, and be consistent? We thought …
text shadow means by which the text of Event Calendar can be more impactive …
<div style="text-shadow:-1px 1px 1px #ff2d95;" id=eventcalendar></div>
Yes, today’s blog posting title kind of gives the game away, regarding what we were getting at with yesterday’s Horizontal Game Soft Link Resources Tutorial‘s operating system Soft Links preparation work, help with a …
Horizontal Block Calendar Game
… being that new possibility. Yesterday’s work allowed that any day number within a month of any year can be linked to an image, and because, in that form, it only has to be in the Stock section, where it has …
filter: brightness(0);
… anonymity anyway, and then can be adjusted for the visible cells of dominoes above that to continue on as a Dominoes Horizontal Block Game.
This way these Horizontal Block Calendar Game differences from the Dominoes Horizontal Block Game are three fold …
dominoes in the Stock are organized in a Calendar fashion …
for each first time selection of dominoes for each of the two players, sets of 7 dominoes are selected by each player, rather than the web application doing this programmatically
months with more than 28 (the number of domino tiles) will yield up to 3 mystery cell scoring opportunity cells
… reminiscent of our start to the current “Dominoes Game And On” blog thread back in it’s early days Dominoes Game Sections Tutorial discussion.
Perhaps we should hone in on a subtitle of …
pseudo resources
… for today’s revisit here. Why? Well, on macOS (here with our MAMP local Apache/PHP/MySql web server) and the Linux operating system of our RJM Programming Apache/PHP/MySql web server there is this wonderful concept of …
… (or Symbolic Links) available to us via those operating system smarts. And, not often, but sometimes, regarding web applications, those “soft link” ideas can be harnessed for “the practical good” … aaaaaaaahhhhhhhhh!
We are not letting on, yet, what the future plan for using this is (though you can probably guess?!), but we wrote this Korn Shell (placed in the web server relevant Games/Dominoes folder (cding to it before running)) …
# ls -la dominoes_[0-9]*.png
-rw-r--r-- 1 rjmprogr rjmprogr 6281 Aug 11 20:23 dominoes_0_0.png
-rw-r--r-- 1 rjmprogr rjmprogr 8277 Aug 11 20:23 dominoes_0_1.png
-rw-r--r-- 1 rjmprogr rjmprogr 10040 Aug 11 20:22 dominoes_0_2.png
-rw-r--r-- 1 rjmprogr rjmprogr 11113 Aug 11 20:22 dominoes_0_3.png
-rw-r--r-- 1 rjmprogr rjmprogr 12169 Aug 11 20:22 dominoes_0_4.png
-rw-r--r-- 1 rjmprogr rjmprogr 14102 Aug 11 20:22 dominoes_0_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 13251 Aug 11 20:22 dominoes_0_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_0_7.png -> dominoes_0_3.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_0_8.png -> dominoes_1_3.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_0_9.png -> dominoes_2_3.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_1_0.png -> dominoes_0_1.png
-rw-r--r-- 1 rjmprogr rjmprogr 6281 Aug 11 20:22 dominoes_1_1_no.png
-rw-r--r-- 1 rjmprogr rjmprogr 8116 Aug 14 08:55 dominoes_1_1.png
-rw-r--r-- 1 rjmprogr rjmprogr 11536 Aug 11 20:22 dominoes_1_2.png
-rw-r--r-- 1 rjmprogr rjmprogr 12818 Aug 11 20:22 dominoes_1_3.png
-rw-r--r-- 1 rjmprogr rjmprogr 13721 Aug 11 20:22 dominoes_1_4.png
-rw-r--r-- 1 rjmprogr rjmprogr 15084 Aug 11 20:22 dominoes_1_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 16783 Aug 11 20:22 dominoes_1_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_1_7.png -> dominoes_0_4.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_1_8.png -> dominoes_1_4.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_1_9.png -> dominoes_2_4.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_2_0.png -> dominoes_0_2.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_2_1.png -> dominoes_1_2.png
-rw-r--r-- 1 rjmprogr rjmprogr 12019 Aug 11 20:22 dominoes_2_2.png
-rw-r--r-- 1 rjmprogr rjmprogr 13607 Aug 11 20:22 dominoes_2_3.png
-rw-r--r-- 1 rjmprogr rjmprogr 15685 Aug 11 20:22 dominoes_2_4.png
-rw-r--r-- 1 rjmprogr rjmprogr 15690 Aug 11 20:22 dominoes_2_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 16173 Aug 11 20:22 dominoes_2_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_2_7.png -> dominoes_0_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_2_8.png -> dominoes_1_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_2_9.png -> dominoes_2_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_3_0.png -> dominoes_0_3.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_3_1.png -> dominoes_1_3.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_3_2.png -> dominoes_2_3.png
-rw-r--r-- 1 rjmprogr rjmprogr 15734 Aug 11 20:22 dominoes_3_3.png
-rw-r--r-- 1 rjmprogr rjmprogr 17045 Aug 11 20:22 dominoes_3_4.png
-rw-r--r-- 1 rjmprogr rjmprogr 16989 Aug 11 20:22 dominoes_3_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 17698 Aug 11 20:22 dominoes_3_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_4_0.png -> dominoes_0_4.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_4_1.png -> dominoes_1_4.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_4_2.png -> dominoes_2_4.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_4_3.png -> dominoes_3_4.png
-rw-r--r-- 1 rjmprogr rjmprogr 18465 Aug 11 20:21 dominoes_4_4.png
-rw-r--r-- 1 rjmprogr rjmprogr 19055 Aug 11 20:21 dominoes_4_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 18958 Aug 11 20:21 dominoes_4_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_5_0.png -> dominoes_0_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_5_1.png -> dominoes_1_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_5_2.png -> dominoes_2_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_5_3.png -> dominoes_3_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_5_4.png -> dominoes_4_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 19755 Aug 11 20:21 dominoes_5_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 21364 Aug 11 20:21 dominoes_5_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_6_0.png -> dominoes_0_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_6_1.png -> dominoes_1_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_6_2.png -> dominoes_2_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_6_3.png -> dominoes_3_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_6_4.png -> dominoes_4_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_6_5.png -> dominoes_5_6.png
-rw-r--r-- 1 rjmprogr rjmprogr 19781 Aug 11 20:21 dominoes_6_6.png
… resulted, and all those new ” -> ” resources being (“pseudo”) resources whose name can be referenced in web applications (as successfully used by our small proof of conceptthrough.html tester) (“in name” pointing at real existant web server image files) and did no harm to “the main game” Block Game, also way below, we’ve been, and still are, working on, around here.
Around here, further to the recent Horizontal Block Game Less Personal Types Tutorial‘s Horizontal Block Game incarnation developments, today we present two new Random Image choices we turn to quite a bit, those being …
… that last one the only “Personalized” one for us here, near Sydney, Australia.
And that second last one, accessing Wikipedia image URLs, thanks, involving other TimeZones (we’ve found out about using PHP TimeZone information functionality in the past), to make happen, involved a dropdown off a dropdown, as per (this Javascript DOM positioning this second dropdown, as the user has selected this second last option) …
… as we return to another image (element img) scenario, except this time they take the form of …
Background image pairs (thanks to Wikipedia, here) for the left and right span element amigos of a Domino tile image's hosting span element (introduced in yesterday's work)
So what’s the “Personalized” about this? Well, we add a new type that is the user’s local (ie. from the client side …
var qwr='' + Intl.DateTimeFormat().resolvedOptions().timeZone;
) … timezone, as an intrinsic part of what goes to make up the datetime stamp in your neck of the woods, whether you think much about it, or not. This functionality benefits from dynamic CSS like …
That being the case, as of today (but as of tomorrow, who knows?) the last dropdown option, adding onto yesterday’s mostly emoji overlay options, being the unique part of your local TimeZone, differs around the world for people trying the changedfourteenth draftDominoes Block Game you can try below.
This “width” issue would probably disappear if Dominoes ever become emojis
… and today’s work fulfills that wish … somewhat? It’s not that dominoes have become emojis, yet, but we thought we’d embellish our …
Domino basis in code
… with overlayed (to any one Domino tile) left hand and right hand emojis, so that we can offer …
… set of 5 emoji overlayed and 1 domino image and an email snapshot set of extended functionalities onto that one original game type, accessible via a new URL argument type …
New initialization Javascript code …
var svgis='<svg xmlns="http://w3.org" style="position: absolute; width: 0; height: 0;" aria-hidden="true"><filter id="edge-detection"><feConvolveMatrix order="3 3" kernelMatrix="-1 -2 -1 0 0 0 1 2 1" preserveAlpha="true" /></filter></svg>';
var shapeis=["\\002739","\\002737","\\002729","\\002727","\\002719","\\002724","\\002713"];
var foodis=["\\01f371","\\01f358","\\01f359","\\01f35a","\\01f35b","\\01f35c","\\01f35d","\\01f360","\\01f362","\\01f363","\\01f364","\\01f365","\\01f361","\\01F366","\\01F367","\\01F368","\\01F369","\\01F36A","\\01F382","\\01F370"];
var animalis=['128028','128018','128030','128029','128012','128040','129408','128060','128027','129413','128044','129445'];
var transportis=["\\002708","\\01F680","\\01F681","\\01F686","\\01F687","\\01F68C","\\01F68F","\\01F5FA"];
var activityis=["\\0026BD","\\01F3C0","\\01F3C2","\\0026BE","\\01F3C1","\\01F3D0","\\01F3C9","\\01F3B1"];
var animgprefix='', animgsuffix='', anothertype='', newtypes=[], thisemhe='', thisem='';
var othertype=(location.search.split('type=')[1] ? decodeURIComponent(location.search.split('type=')[1].split('&')[0]) : '');
var anothertype=othertype.toLowerCase() + 'is', numarr=0;
var templateprefix='<span class="image-wrapper">', templatesuffix='<span style="visibility:visible;" class="doml dominoes5"></span><span style="visibility:visible;" class="domr dominoes6"></span></span>';
if (othertype.toLowerCase().replace('dominoes', '') != '') {
if (typeof anothertype == "string") {
setTimeout(alat, 3000);
animgprefix=templateprefix;
animgsuffix=templatesuffix;
}
}
… andnot drop new Javascript logic. This last idea, where only what happens to HTML img element (by default draggable=”true”) …
draggable … attribute “true” for “dragging available” and “false” for “dragging not available” … and …
ondragstart … event, only, of interest, and if interested and draggable=”true” mimic what the onclick event does
… is of interest to us, is a wish we can remember from the past, but then we probably still followed through coding for drop in the past. However, when you want to control where (a Domino tile) image ends up, allowing willy-nillydrop user interactions is unnecessary.
We’re going to call this “buttoned down drag”!
There is another reason to code for this. It means controlling that draggable attribute can stop any “other player peaking (to some degree), even accidentally” episodes, during the Dominoes game …
// Player 1's first go scenario ... set up Player 1 Domino tiles
document.getElementById('seven1').innerHTML+=brhuh + '<img draggable="true" ondragstart="goone(event.target);" onclick="goone(this);" style=width:80px; class="player1" id="' + player1arr[ij] + '" src="' + player1arr[ij] + '.png"></img>';
// Player 1's first go scenario ... set up Player 2 Domino tiles
document.getElementById('seven2').innerHTML+=brhuh + '<img draggable="false" ondragstart="gotwo(event.target);" onclick="gotwo(this);" style=width:80px;filter:brightness(0); class="player2" id="' + player2arr[ij] + '" src="' + player2arr[ij] + '.png"></img>';
A stalemate in dominoes is most commonly called a blocked game or a locked game, and the layout itself is referred to as being blocked or closed.
… where a user cannot play themselves and there are no Domino tiles left in the stock. And now that yesterday saw us continuously hashtagging the game status, some web browser address bar URL refreshing would land you back into the same pickle.
And so …
we turned a hardcopy into a span, potentially dynamic, element …
<h1 id=myh1>Dominoes Horizontal Block <span id=sgame>Game</span></h1>
that when detecting the stock is empty …
if (eval('' + document.getElementById('thstock').innerHTML.split('none;').length) >= 14) {
if (document.getElementById('sgame').innerHTML == 'Game') {
document.getElementById('sgame').innerHTML='<button title=" ... or blocked game" onclick=newstockgame();>New</button> Game';
}
}
…
has the capacity to call a new Javascript function …
function newstockgame() {
location.href=document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 1989786) + '&score1=' + document.getElementById('score1').innerHTML.replace('Score: ','') + '&score2=' + document.getElementById('score2').innerHTML.replace('Score: ','');
}
… to “exit the pickle”, available now, to a user reaching the stalemateblocked game scenario
… and found that “for dynamic updating sake” we needed to “borrow” from how we were shaping to share with email or SMS, and use that similar hashtagging “state of play” simulations to the document.URL scenarios as the game is playing, via, at the relevant points of time, after the global var prevlhis=”, lhis=”; initialization, that is …
Dominoes Horizontal Block Game Mobile Speech to Text Tutorial
We were researching ways an iPhone or iPad could be a second monitor for a macOS MacBook Air (and with our Dominoes game intelligently differently program the display on the second monitor) when researching …
… means, whereas, we thought, easier than all this, particularly as it was looking like both parties could not interact with both being “pointing capable” anyway, why not revisit the recent Dominoes Horizontal Block Game Speech to Text Tutorial‘s …
in single device Dominoes Horizontal Block Game mode a single mobile device could be handed around corresponding to when a player is allowed to see … or …
mobile device on Google Chrome could be the interactive device but be displayed on macOS MacBook Air nearby and at proper times a user can speak their Domino tile choice into the awaiting mobile device microphone
… are viable options to play the Dominoes game in more varieties of “usage guises” …
if ((6 == 6 || (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) <= 0)) && document.URL.indexOf('https:') == 0 && (5 == 5 || document.URL.indexOf('?') == -1) && document.URL.indexOf('rjmprogramming.com.au/Games/Dominoes') != -1) {
if (('' + window.navigator.userAgent).toLowerCase().replace('crios','chrome').indexOf('chrom') != -1) {
if (window.parent == window.self) {
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) || eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
setTimeout(function(){
document.getElementById('myh1').innerHTML+=" <a onclick='if (!alldoneanddusted) { abitlater(this); }' style='text-decoration:none;cursor:pointer;border:3px dotted yellow;' href='#preifp' title='Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak. Is opt in via initial tap here for Google Chrome mobile users.'>🎤</a>";
}, 2000);
} else {
alldoneanddusted=true;
setTimeout(function(){
document.getElementById('preifp').style.display='block';
document.getElementById('ifblank').style.display='block';
speechtotextwo=window.open('https://www.rjmprogramming.com.au/PHP/speech_supervisor.php?mode=4&raxnd=' + Math.floor(Math.random() * 1989675), 'ifblank'); //, 'top=0,left=' + eval(-600 + screen.width) + ',width=600,height=' + eval(-100 + screen.height));
document.getElementById('myh1').innerHTML+=" <a style=text-decoration:none;cursor:pointer; href='#preifp' title='Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak.'>🎤</a>";
setTimeout(function(){
document.getElementById('myh1').scrollIntoView(); //window.scrollTo(0,0);
//window.top.scrollTo(0,0);
}, 2000);
}, 3000);
}
}
setInterval(scheckwo, 4000);
}
}
function abitlater(oa) {
alldoneanddusted=true;
oa.style.border='1px solid green';
setTimeout(function(){
document.getElementById('preifp').style.display='block';
document.getElementById('ifblank').style.display='block';
speechtotextwo=window.open('https://www.rjmprogramming.com.au/PHP/speech_supervisor.php?mode=4&raxnd=' + Math.floor(Math.random() * 1989675), 'ifblank'); //, 'top=0,left=' + eval(-600 + screen.width) + ',width=600,height=' + eval(-100 + screen.height));
//document.getElementById('myh1').innerHTML+=" <a style=text-decoration:none;cursor:pointer; href='#preifp' title='Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak.'>🎤</a>";
setTimeout(function(){
document.getElementById('myh1').scrollIntoView(); //window.scrollTo(0,0);
//window.top.scrollTo(0,0);
}, 2000);
}, 3000);
}
We have usually opened this Speech to Text window in a popup window, but today we open it in an iframe “below the fold” and we think into the future we may do this a bit more, especially as it’s functionality, anyway, flags when it is ready for the user to speak by displaying an orange microphone icon up near the top of the Google Chrome web browser window (and so matters less whether you see it’s inner workings, as you speak), and a new …
Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak.
… hashtag navigator can position the user to those “inner workings” (and back) as required.
This Speech to Text logic is expecting numbers describing Domino tiles to click, as per the new Javascript …
function acton(wdsl) {
var pidis='', pidarr=[];
if (wdsl.trim() != '') {
if (wdsl.toLowerCase() == 'stock' || wdsl.toLowerCase().substring(0,1) == '-') {
if (document.getElementById('thstock').innerHTML.indexOf('dominoes_') != -1) {
pidarr=document.getElementById('thstock').innerHTML.split('dominoes_');
pidis='dominoes_' + pidarr[Math.max(1,Math.floor(Math.random() * pidarr.length))].split('"')[0].split("'")[0].split('>')[0];
}
} else if (wdsl.toLowerCase().substring(0,1) >= '0' && wdsl.toLowerCase().substring(0,1) <= '9') {
if (eval('' + wdsl.length) == 1) {
pidis='dominoes_' + wdsl + '_' + wdsl;
} else if (wdsl.substring(0,1) <= wdsl.substring(1).substring(0,1)) {
pidis='dominoes_' + wdsl.substring(0,1) + '_' + wdsl.substring(1).substring(0,1);
} else {
pidis='dominoes_' + wdsl.substring(1).substring(0,1) + '_' + wdsl.substring(0,1);
}
} else if (wdsl.toLowerCase() == 'ten') {
pidis='dominoes_0_1';
} else if (wdsl.toLowerCase() == 'eleven') {
pidis='dominoes_1_1';
} else if (wdsl.toLowerCase() == 'twelve') {
pidis='dominoes_1_2';
} else if (wdsl.toLowerCase() == 'thirteen') {
pidis='dominoes_1_3';
} else if (wdsl.toLowerCase() == 'fourteen') {
pidis='dominoes_1_4';
} else if (wdsl.toLowerCase() == 'fifteen') {
pidis='dominoes_1_5';
} else if (wdsl.toLowerCase() == 'sixteen') {
pidis='dominoes_1_6';
} else if (wdsl.toLowerCase() == 'twenty') {
pidis='dominoes_0_2';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentyone') {
pidis='dominoes_1_2';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentytwo') {
pidis='dominoes_2_2';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentythree') {
pidis='dominoes_2_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentyfour') {
pidis='dominoes_2_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentyfive') {
pidis='dominoes_2_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentysix') {
pidis='dominoes_2_6';
} else if (wdsl.toLowerCase() == 'thirty') {
pidis='dominoes_0_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtyone') {
pidis='dominoes_1_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtytwo') {
pidis='dominoes_2_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtythree') {
pidis='dominoes_3_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtyfour') {
pidis='dominoes_3_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtyfive') {
pidis='dominoes_3_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtysix') {
pidis='dominoes_3_6';
} else if (wdsl.toLowerCase() == 'forty') {
pidis='dominoes_0_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortyone') {
pidis='dominoes_1_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortytwo') {
pidis='dominoes_2_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortythree') {
pidis='dominoes_3_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortyfour') {
pidis='dominoes_4_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortyfive') {
pidis='dominoes_4_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortysix') {
pidis='dominoes_4_6';
} else if (wdsl.toLowerCase() == 'fifty') {
pidis='dominoes_0_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftyone') {
pidis='dominoes_1_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftytwo') {
pidis='dominoes_2_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftythree') {
pidis='dominoes_3_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftyfour') {
pidis='dominoes_4_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftyfive') {
pidis='dominoes_5_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftysix') {
pidis='dominoes_5_6';
} else if (wdsl.toLowerCase() == 'sixty') {
pidis='dominoes_0_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtyone') {
pidis='dominoes_1_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtytwo') {
pidis='dominoes_2_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtythree') {
pidis='dominoes_3_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtyfour') {
pidis='dominoes_4_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtyfive') {
pidis='dominoes_5_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtysix') {
pidis='dominoes_6_6';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero') == 'zero') {
pidis='dominoes_0_0';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerozero') {
pidis='dominoes_0_0';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zeroone') {
pidis='dominoes_0_1';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerotwo') {
pidis='dominoes_0_2';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerothree') {
pidis='dominoes_0_3';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerofour') {
pidis='dominoes_0_4';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerofive') {
pidis='dominoes_0_5';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerosix') {
pidis='dominoes_0_6';
} else if (wdsl.toLowerCase() == 'one') {
if (document.getElementById('dominoes_0_1')) {
pidis='dominoes_0_1';
} else {
pidis='dominoes_1_1';
}
} else if (wdsl.toLowerCase() == 'two') {
if (document.getElementById('dominoes_0_2')) {
pidis='dominoes_0_2';
} else {
pidis='dominoes_2_2';
}
} else if (wdsl.toLowerCase() == 'three') {
if (document.getElementById('dominoes_0_3')) {
pidis='dominoes_0_3';
} else {
pidis='dominoes_3_3';
}
} else if (wdsl.toLowerCase() == 'four') {
if (document.getElementById('dominoes_0_4')) {
pidis='dominoes_0_4';
} else {
pidis='dominoes_4_4';
}
} else if (wdsl.toLowerCase() == 'five') {
if (document.getElementById('dominoes_0_5')) {
pidis='dominoes_0_5';
} else {
pidis='dominoes_5_5';
}
} else if (wdsl.toLowerCase() == 'six') {
if (document.getElementById('dominoes_0_6')) {
pidis='dominoes_0_6';
} else {
pidis='dominoes_6_6';
}
} else if (wdsl.toLowerCase() == 'seven') {
} else if (wdsl.toLowerCase() == 'eight') {
} else if (wdsl.toLowerCase() == 'nine') {
}
}
if (pidis.trim() != '') {
if (document.getElementById(pidis)) {
if (document.getElementById(pidis).outerHTML.replace('display: ','display:').indexOf('display:none') == -1) {
document.getElementById(pidis).click();
}
}
}
}
This “width” issue would probably disappear if Dominoes ever become emojis (where we’d start controlling textual HTML element CSS font-size property to control Domino tile size, or more specifically, width), but being they are images, yes we can size them quite small, but there are limits, regarding readability, meaning to have too many of these Domino images across an iPhone screen, for example, we found it an improvement to …
Recognise the environments where the issue might occur …
Start right justifying, within the left cell of the two, for Player 1, their images, and for the Stock center justify to lessen the overall width a narrow device has to concern itself with, via CSS …
Separate player focus, to a degree, via controlled “to left” (Player 1) or “to right” (Player 2) webpage scrolling in X (only … something we can’t remember considering before, but is a really useful concept) (ie. a width thaing)…
some recessed feeling (via box-shadow) to span element contenteditable=true so as to flag that interaction may be available (and with this, a double click on the body element will help mobile users see the on hover advice non-mobile users see regarding these collaboration possibilities), via the CSS …
<style>
#name1 { z-index: 67; padding: 8 8 8 8; box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4); background-color: rgb(240,240,240); color: purple; border-radius: 8px; }
#name2 { z-index: 67; padding: 8 8 8 8; box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4); background-color: rgb(240,240,240); color: green; border-radius: 8px; }
</style>
use of outline CSS property for erroneously clicked Dominoes, but not interfering with the deliberate margins, differentiating these from Dominoes committed in game play, via Javascript DOM …
iobj.style.outline='1px dotted orange';
… remembering recent discoveries where the outline property display is not part of the element, but can be a display enhancer (we found better than trying the CSS “active” pseudo class idea #reveal1:active,#reveal2:active { background-color: orange; } # causing some deliberate margins to disappear)
there’s a sliver of accidental overlay that can come into play with the smaller widths, and that z-index curious CSS above dovetails with CSS …
<style>
#reveal1,#reveal2 { margin-top: 3px; gap: 4px; z-index: 76; }
</style>
… so that the button tap/click takes precedence over any span contenteditable=true tap/click to focus (we kept doing accidentally) … that gap property may work to separate wrapped elements with a sliver of whitespace to preceding elements, but did not seem to work for us?!
Stop Press
Thinking more regarding …
some recessed feeling (via box-shadow) to span element contenteditable=true so as to flag that interaction may be available (and with this, a double click on the body element will help mobile users see the on hover advice non-mobile users see regarding these collaboration possibilities), via the CSS …
… above, for any mobile device with no on hover (title attribute) means of conveying information, why not intervene at those span element onfocus events (Javascript functions focusone and focustwo respectively) …
var spanoonedone=false, spanoonedtwo=false;
function focusone(ospan) {
if (!spanoonedone && navigator.userAgent.match(/Android|BlackBerry|iPad|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
var ansis=prompt(ospan.title, ospan.innerText);
if (ansis == null) { ansis=ospan.innerText; }
if (ansis != '' && ansis != ospan.innerText) { if (ansis.indexOf('],') != -1) { spanoonedtwo=true; } ospan.innerHTML=ansis; nameone(ospan); }
}
spanoonedone=true;
}
function focustwo(ospan) {
if (!spanoonedtwo && navigator.userAgent.match(/Android|BlackBerry|iPad|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
var ansis=prompt(ospan.title, ospan.innerText);
if (ansis == null) { ansis=ospan.innerText; }
if (ansis != '' && ansis != ospan.innerText) { if (ansis.indexOf('],') != -1) { spanoonedone=true; } ospan.innerHTML=ansis; nametwo(ospan); }
}
spanoonedtwo=true;
}
… so that information can be imparted as a matter of course should the user show an interest? It is water off a duck’s back whether the mobile device keyboard activity occurs in a Javascript prompt window or at the span contenteditable=true element itself, after all, regarding our further changedsixth draftDominoes Block Game you can try below.
as well as yesterday’s player “Turn Away Paradigm” for one device scenarios of play … today we add …
collaboration, via …
email … or …
SMS … where either of those “Player” HTML span elements are contenteditable=true and via their onblur event Javascript logics …
Player names are editable and if you use name such as RM[rmetcalfe15@gmail.com] (collaboration can occur with similar other Player change) or RM[rmetcalfe15@gmail.com],RMet[rmetcalfe@rjmprogramming.com.au] (collaboration occurs with other Player name changed accordingly).
… applies to them
… for a two device (presumably) and two player Dominoes play scenario
… as an alternative mode of play. We were proceeding along quite well, until we started into the SMS testing.
We did it!
We reached a URL with huge hashtag SMS length limit! Don’t know why we are so excited, because the rearrangement had us reaching for this PHP dominoes_block_game.php helper …
<?php
// dominoes_block_game.php
// Help out dominoes_block_game.html with SMS messages
// August, 2026
… paradigm whereby two players can play a Dominoes Game sharing the one device, that game may benefit by a user instigated “beep paradigm” in play (but be aware if you have dogs in the house like “The Lu” she gets put off by this optional beeping).
Further to yesterday’s Dominoes Game Resources Tutorial‘s start to our Dominoes online game quest, and reading more about the rules of play regarding a Block Game version we’ve settled for the following sections on this game’s webpage designed for two players sharing the one screen (so far) …
header parts
playing area … where the tiles players play are placed
left and right player areas … show player names and score and current button of applicability …
left and right player tiles area … sometimes showing individual player tiles, sometimes showing underside of tile, with an honour system in play that the player whose turn it is not, turns away when asked …
stock area … contains the rest of the 28 dominoes not yet in play, showing underside of tile
Our strategy will be the first player to play is determined by whether left or right button is first selected, and from there in the game the order of play proceeds as per the rules of the Dominoes Block Game.
So far we think we’ll rewrite button content constantly according to what the status of the game at any given time. We can do that because the button elements are hosted by span hosting HTML elements.
… you can think of in programming (and many IDE) parlance as “resources”, and such games can lend themselves towards Object Oriented Programming (ie. OOP) code design, perhaps, and a set aside block of time preparing resources ahead of starting any coding. So it is with today’s start, for us, in creating a …
… game, as an online web application. We vaguely remember Dominoes from a while back and it involves …
dominoes (we think of as tiles) … as the resource …
randomosity … as many games do, regarding them being turned over to them all looking the same, and players randomly selecting their own tiles to play the game …
a way to score … as many games do
This first day of work had us …
find a good online source at this useful link … thanks … to create a “parent resource” …
… dominoes.png … via …
form rectangle around the white on black section of tiles
Edit -> Copy
File -> New from Clipboard
File -> Save As… dominoes.png
28 x
form rectangle around the white on black subsection of dominoes.png
Edit -> Copy
File -> New from Clipboard
File -> Save As… dominoes_[leftHandDotCount]_[rightHandDotCount].png
7 x
form rectangle around the uniquely encountered leftHandDotCount left hand side of a dominoes_[leftHandDotCount]_[rightHandDotCount].png
Edit -> Copy
File -> New from Clipboard
File -> Save As… dominoes_[leftHandDotCount].png
… off memories of how Dominoes might ask of us “resources” wise.
That left us, after using FileZilla uploading to a new RJM Programming /Games/Dominoes folder off that web server’s ApacheDocument Root folder, as a folder full of image files only.
In this early scenario here, there is an adage we try to maintain, but let’s ask why …
Not having an index file like index.html, index.htm, or index.php in an Apache folder is a bad idea because it exposes your entire directory structure and source files to the public via Apache’s automatic directory listing. This vulnerability, known as Directory Browsing or Information Disclosure, allows attackers to easily map your application, find sensitive backup files, and locate hidden scripts.
FileZilla is really great at remedying them, often times temporary dilemma, quickly. Within a web server folder a context menu option Create New File (we called index.html) in that folder (even zero length) is going to stop that issue weakness talked about above. Aaaaaaah! Now we can think more clearly on ways to design the online Dominoes version game play.
Animated Plane and Coconut Hunt Game Nuances Tutorial
Today’s a day of nuanced progress, after yesterday’s Coconut Hunt Game Tutorial‘s “filling in sideways” work on our Animated Plane and Coconut Hunt Game web application. Today, we …
fixed some document.body.title annoyances whereby it would appear too often
worked on the default A option textarea via …
some “panda 🐼 led recovery” modelling of a p emoji usage (with animation) and span emoji usage (without animation) … and …
modelling of how iframe onload event can be used to develop dynamic Javascript (the default example changing the coconut 🥥 hunt into a bear 🐻 hunt?!) … as opposed to a document.createElement(‘script’) alternative approach
fixed some window.open too small size annoyances
allowed for screen co-ordinates cursor (on non-mobile), via onmousemove event logic, to assist intrepid users going above and beyond “overlay” positioning their own elements via position:absolute; left:?; top:?; in A option textareas
allowed for toggling of non-mobile cursor between as above and crosshair via right click
allowed for the last left:?; top:?; as above detected be remembered and involve itself as the default position:absolute; “overlay” positioning of the A option textarea default “panda 🐼 led recovery” emoji of above
allow for 8 seconds of time for a user to change default coconut 🥥 emoji to some other text via contenteditable=true ahead of the Hunt Game starting … thanks to this useful link regarding hiding a contenteditable=true focus border
Are you a reader who has been amused or bemused by the word Game being in the blog posting titles lately, up to yesterday’s Animated Plane Game User Animations and Styling Tutorial, when No Game really, about any of it? Well, today, it’s …
Game On
Do you like coconuts? Can I ask you, have you ever looked into a coconut, and asked yourself …
? Well, have we got the game for you?! Start the ball rollingshell shaking via the first click/top on the coconut fallen from the tree. And from there, it’s a fast reactions game, to score well! Good luck, in the changed“latest draft”Animated Plane Coconut Hunt Game web application below!
… today we wanted to offer two more user controllable parts to this Animated Plane Game web application, those being …
CSS styling … easy, as CSS can be dynamically added to a web application at the clientside, as the Javascript is executing … and, a bit more of a learning curve for beginners is …
user animations … we’re envisaging, in it’s “easiest to understand encapsulation for a newbie” uses …
… a whole big wooooorrrrlllldddd of animation study just by itself (and in order for modelling to, perhaps, help we used an example from this excellent link, thanks, as the default option A textarea usage model)
… but a hell of a lot easier for a user to establish than some arcane Javascript DOM animations involving setTimeout or setInterval timers?!
For these two new ideas, popup textarea windows appear to give the user plenty of space to play around in. As ever, email and SMS can follow up for that user to share with others what their animation ideas are, perhaps far removed from the original plane and gymnast scenario by the time they finish. And here it may be pertinent to point out that even using hashtag emailing (and even more so with SMSing) there must be message size limits that will stop you event-u-al-ly!
In yesterday’s “noun” work we talked about “content” defined by the user in terms of real references to media data URIs or URLs. Well, the other way a user can now affect “content” is via CSS. Below we make the plane and gymnast disappear via the C (for CSS styling) option (that can take you to a popup window textarea where you can Apply this) …
<style>
#myif { /* plane */
display:none; /* other choice could be visibility:hidden; */
}
#mytwoif { /* gymnast */
visibility:hidden; /* other choice could be display:none; */
}
</style>
… each of which has a relationship to a piece of media content. The border-image (ie. ground) content aspects we allow a user to define emoji text for, but the rest are associated with a data URI or URL.
Today’s work is to allow the user to specify these “content” data items themselves, as well as share this via email or SMS to another user, with those user “content” data items recreated for the recipient user clicking the email or SMS link containing those hashtagged user data components. Later we hope to expand the functionality more, from today’s …
function getsrc(fromoh) {
var forvpre='Currently this content points at ... ' + String.fromCharCode(10);
var forvsuf=String.fromCharCode(10) + 'Enter an alternative content URL (can be clipart style data URI you see often using Google Image (Copy Image Address via right click) Searches) ... or ... ' + String.fromCharCode(10) + String.fromCharCode(10) + '1[:URL] for trees, 2[:URL] for plane, 3[:URL] for gymnast, 4[:URL] for clouds, 5[:emoji(s)] for ground, E for email, S for SMS';
if (fromoh.indexOf(' src="//') != -1) {
return forvpre + document.URL.split('//')[0] + fromoh.split(' src="')[1].split('"')[0] + forvsuf;
} else if (fromoh.indexOf(" src='//") != -1) {
return forvpre + document.URL.split('//')[0] + fromoh.split(" src='")[1].split("'")[0] + forvsuf;
} else if (fromoh.indexOf(" src=//") != -1) {
return forvpre + document.URL.split('//')[0] + fromoh.split(" src=")[1].split(" ")[0].split(">")[0] + forvsuf;
} else if (fromoh.indexOf(' src="') != -1) {
return forvpre + fromoh.split(' src="')[1].split('"')[0] + forvsuf;
} else if (fromoh.indexOf(" src='") != -1) {
return forvpre + fromoh.split(" src='")[1].split("'")[0] + forvsuf;
} else if (fromoh.indexOf(" src=") != -1) {
return forvpre + fromoh.split(" src=")[1].split(" ")[0].split(">")[0] + forvsuf;
}
return fromoh;
}
function yourprompt(ino, intlis) {
var ei=-1, si=-1;
isac=true;
var opsd=prompt(getsrc(ino.outerHTML), '');
if (opsd == null) { isac=false; return false; }
if (opsd.trim() != '') {
switch (opsd.substring(0,1).toLowerCase().replace('+','s')) {
case '1': // trees
if ((opsd + ' ').substring(0,2) == '1:') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + (opsd + ' ').substring(2) + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
} else {
opsd=prompt('Enter your (perhaps clipart via Google image search) data URI or URL suiting where trees are.', '');
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
}
break;
case '2': // plane
if ((opsd + ' ').substring(0,2) == '2:') {
planealt='&planealt=' + encodeURIComponent(opsd);
document.getElementById('myif').style.backgroundImage='url(' + ((opsd + ' ').substring(2)).replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
} else {
opsd=prompt('Enter your (perhaps clipart via Google image search) data URI or URL suiting where plane is.', '');
if (opsd != null) {
if (opsd.trim() != '') {
planealt='&planealt=' + encodeURIComponent(opsd);
document.getElementById('myif').style.backgroundImage='url(' + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
}
}
}
break;
case '3': // gymnast
if ((opsd + ' ').substring(0,2) == '3:') {
gymnastalt='&gymnastalt=' + encodeURIComponent(opsd);
document.getElementById('mytwoif').style.backgroundImage='url(' + ((opsd + ' ').substring(2)).replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
} else {
opsd=prompt('Enter your (perhaps clipart via Google image search) data URI or URL suiting where gymnast is.', '');
if (opsd != null) {
if (opsd.trim() != '') {
gymnastalt='&gymnastalt=' + encodeURIComponent(opsd);
document.getElementById('mytwoif').style.backgroundImage='url(' + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
}
}
}
break;
case '4': // clouds
if ((opsd + ' ').substring(0,2) == '4:') {
cloudsalt='&cloudsalt=' + encodeURIComponent(opsd);
document.body.style.backgroundImage='url(' + ((opsd + ' ').substring(2)).replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
} else {
opsd=prompt('Enter your (perhaps via Google image search) data URI or URL suiting where cloud background image is.', '');
if (opsd != null) {
if (opsd.trim() != '') {
cloudsalt='&cloudsalt=' + encodeURIComponent(opsd);
document.body.style.backgroundImage='url(' + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
}
}
}
break;
The mix-blend-mode:multiply; discoveries (along with those naive previous usage without realizing it’s implications) we made creating Periodic Table Image Map Primer Tutorial recently has opened up new “vistas of possibility” (VOP, of course) for us, and has inspired us to give “just Javascript and CSS and HTML animated games” (aided in large part by clipart free content components) another go …
… with a “widget feel” now realizable, for us, knowing that white backgrounded HTML iframe content no longer has to hold us back piecing together animations (in an “OOP feeling” way) consisting of …
base webpage CSS and HTML and Javascript (DOM, also helping out the control of) …
HTML iframe components (and in our case the image content is it’s background image with background-size:contain; and background-repeat:no-repeat; along with a specific iframe width and height) for any one “noun” (or class of object) in your game storyboard … if you will … if you will … if you will … and …
HTML img components in a similar vein … but today’s trees did not need mix-blend-mode:multiply; because the originator made the background transparent (ie. another option with all this “animated pieces thinking”)
Animation(s) can be CSS @keyframe transitions (though not yet with animation above) or Javascript DOM logic via setTimeout (or setInterval) timers or animated GIF/webp content or, we daresay, many other approaches.
We’re going to tabularize below “how we got to the result above” below …
We started with a “first draft” … getting plane image animated with a rudimentary green border-bottom representing the ground …
… then to“second draft” … adding animated GIF cloud background to go with edited because mix-blend-mode:multiply will not mask out the non heterogenous bluish clouds in the image …
Thanks to Image by brgfx on Freepik and https://i.makeagif.com/media/8-11-2023/Xu_roP.gif and https://procul.org/images/2025/Animated-Clouds-Gif/ and and https://au.pinterest.com/pin/587930926347995281/ and https://giphy.com/explore/trees-swaying-stickers
… then to“sixth draft” … added animated GIF gymnast background and thereby proving that overlapping “iframe widgets” (helped out by mix-blend-mode:multiply presumably) was possible, and important …
… then to“seventh draft” … added animated (and transparently backgrounded) webp swaying trees image along with tweaked now animated GIF to animate the plane itself a little, in place, separate to the Javascript DOM based animation moving across the screen … for today’s final draft …
Stop Press
In tomorrow’s installment we allow for user defined content, and sharing, as per …
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
hr>
If this was interesting you may be interested in this too.
… reminiscent of our start to the current “Dominoes Game And On” blog thread back in it’s early days Dominoes Game Sections Tutorial discussion.
Perhaps we should hone in on a subtitle of …
pseudo resources
… for today’s revisit here. Why? Well, on macOS (here with our MAMP local Apache/PHP/MySql web server) and the Linux operating system of our RJM Programming Apache/PHP/MySql web server there is this wonderful concept of …
… (or Symbolic Links) available to us via those operating system smarts. And, not often, but sometimes, regarding web applications, those “soft link” ideas can be harnessed for “the practical good” … aaaaaaaahhhhhhhhh!
We are not letting on, yet, what the future plan for using this is (though you can probably guess?!), but we wrote this Korn Shell (placed in the web server relevant Games/Dominoes folder (cding to it before running)) …
# ls -la dominoes_[0-9]*.png
-rw-r--r-- 1 rjmprogr rjmprogr 6281 Aug 11 20:23 dominoes_0_0.png
-rw-r--r-- 1 rjmprogr rjmprogr 8277 Aug 11 20:23 dominoes_0_1.png
-rw-r--r-- 1 rjmprogr rjmprogr 10040 Aug 11 20:22 dominoes_0_2.png
-rw-r--r-- 1 rjmprogr rjmprogr 11113 Aug 11 20:22 dominoes_0_3.png
-rw-r--r-- 1 rjmprogr rjmprogr 12169 Aug 11 20:22 dominoes_0_4.png
-rw-r--r-- 1 rjmprogr rjmprogr 14102 Aug 11 20:22 dominoes_0_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 13251 Aug 11 20:22 dominoes_0_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_0_7.png -> dominoes_0_3.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_0_8.png -> dominoes_1_3.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_0_9.png -> dominoes_2_3.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_1_0.png -> dominoes_0_1.png
-rw-r--r-- 1 rjmprogr rjmprogr 6281 Aug 11 20:22 dominoes_1_1_no.png
-rw-r--r-- 1 rjmprogr rjmprogr 8116 Aug 14 08:55 dominoes_1_1.png
-rw-r--r-- 1 rjmprogr rjmprogr 11536 Aug 11 20:22 dominoes_1_2.png
-rw-r--r-- 1 rjmprogr rjmprogr 12818 Aug 11 20:22 dominoes_1_3.png
-rw-r--r-- 1 rjmprogr rjmprogr 13721 Aug 11 20:22 dominoes_1_4.png
-rw-r--r-- 1 rjmprogr rjmprogr 15084 Aug 11 20:22 dominoes_1_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 16783 Aug 11 20:22 dominoes_1_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_1_7.png -> dominoes_0_4.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_1_8.png -> dominoes_1_4.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_1_9.png -> dominoes_2_4.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_2_0.png -> dominoes_0_2.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_2_1.png -> dominoes_1_2.png
-rw-r--r-- 1 rjmprogr rjmprogr 12019 Aug 11 20:22 dominoes_2_2.png
-rw-r--r-- 1 rjmprogr rjmprogr 13607 Aug 11 20:22 dominoes_2_3.png
-rw-r--r-- 1 rjmprogr rjmprogr 15685 Aug 11 20:22 dominoes_2_4.png
-rw-r--r-- 1 rjmprogr rjmprogr 15690 Aug 11 20:22 dominoes_2_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 16173 Aug 11 20:22 dominoes_2_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_2_7.png -> dominoes_0_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_2_8.png -> dominoes_1_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_2_9.png -> dominoes_2_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_3_0.png -> dominoes_0_3.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_3_1.png -> dominoes_1_3.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_3_2.png -> dominoes_2_3.png
-rw-r--r-- 1 rjmprogr rjmprogr 15734 Aug 11 20:22 dominoes_3_3.png
-rw-r--r-- 1 rjmprogr rjmprogr 17045 Aug 11 20:22 dominoes_3_4.png
-rw-r--r-- 1 rjmprogr rjmprogr 16989 Aug 11 20:22 dominoes_3_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 17698 Aug 11 20:22 dominoes_3_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_4_0.png -> dominoes_0_4.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_4_1.png -> dominoes_1_4.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_4_2.png -> dominoes_2_4.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_4_3.png -> dominoes_3_4.png
-rw-r--r-- 1 rjmprogr rjmprogr 18465 Aug 11 20:21 dominoes_4_4.png
-rw-r--r-- 1 rjmprogr rjmprogr 19055 Aug 11 20:21 dominoes_4_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 18958 Aug 11 20:21 dominoes_4_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_5_0.png -> dominoes_0_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_5_1.png -> dominoes_1_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_5_2.png -> dominoes_2_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_5_3.png -> dominoes_3_5.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_5_4.png -> dominoes_4_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 19755 Aug 11 20:21 dominoes_5_5.png
-rw-r--r-- 1 rjmprogr rjmprogr 21364 Aug 11 20:21 dominoes_5_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_6_0.png -> dominoes_0_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_6_1.png -> dominoes_1_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_6_2.png -> dominoes_2_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_6_3.png -> dominoes_3_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_6_4.png -> dominoes_4_6.png
lrwxrwxrwx 1 root root 16 Aug 31 10:28 dominoes_6_5.png -> dominoes_5_6.png
-rw-r--r-- 1 rjmprogr rjmprogr 19781 Aug 11 20:21 dominoes_6_6.png
… resulted, and all those new ” -> ” resources being (“pseudo”) resources whose name can be referenced in web applications (as successfully used by our small proof of conceptthrough.html tester) (“in name” pointing at real existant web server image files) and did no harm to “the main game” Block Game, also way below, we’ve been, and still are, working on, around here.
Around here, further to the recent Horizontal Block Game Less Personal Types Tutorial‘s Horizontal Block Game incarnation developments, today we present two new Random Image choices we turn to quite a bit, those being …
… that last one the only “Personalized” one for us here, near Sydney, Australia.
And that second last one, accessing Wikipedia image URLs, thanks, involving other TimeZones (we’ve found out about using PHP TimeZone information functionality in the past), to make happen, involved a dropdown off a dropdown, as per (this Javascript DOM positioning this second dropdown, as the user has selected this second last option) …
… as we return to another image (element img) scenario, except this time they take the form of …
Background image pairs (thanks to Wikipedia, here) for the left and right span element amigos of a Domino tile image's hosting span element (introduced in yesterday's work)
So what’s the “Personalized” about this? Well, we add a new type that is the user’s local (ie. from the client side …
var qwr='' + Intl.DateTimeFormat().resolvedOptions().timeZone;
) … timezone, as an intrinsic part of what goes to make up the datetime stamp in your neck of the woods, whether you think much about it, or not. This functionality benefits from dynamic CSS like …
That being the case, as of today (but as of tomorrow, who knows?) the last dropdown option, adding onto yesterday’s mostly emoji overlay options, being the unique part of your local TimeZone, differs around the world for people trying the changedfourteenth draftDominoes Block Game you can try below.
This “width” issue would probably disappear if Dominoes ever become emojis
… and today’s work fulfills that wish … somewhat? It’s not that dominoes have become emojis, yet, but we thought we’d embellish our …
Domino basis in code
… with overlayed (to any one Domino tile) left hand and right hand emojis, so that we can offer …
… set of 5 emoji overlayed and 1 domino image and an email snapshot set of extended functionalities onto that one original game type, accessible via a new URL argument type …
New initialization Javascript code …
var svgis='<svg xmlns="http://w3.org" style="position: absolute; width: 0; height: 0;" aria-hidden="true"><filter id="edge-detection"><feConvolveMatrix order="3 3" kernelMatrix="-1 -2 -1 0 0 0 1 2 1" preserveAlpha="true" /></filter></svg>';
var shapeis=["\\002739","\\002737","\\002729","\\002727","\\002719","\\002724","\\002713"];
var foodis=["\\01f371","\\01f358","\\01f359","\\01f35a","\\01f35b","\\01f35c","\\01f35d","\\01f360","\\01f362","\\01f363","\\01f364","\\01f365","\\01f361","\\01F366","\\01F367","\\01F368","\\01F369","\\01F36A","\\01F382","\\01F370"];
var animalis=['128028','128018','128030','128029','128012','128040','129408','128060','128027','129413','128044','129445'];
var transportis=["\\002708","\\01F680","\\01F681","\\01F686","\\01F687","\\01F68C","\\01F68F","\\01F5FA"];
var activityis=["\\0026BD","\\01F3C0","\\01F3C2","\\0026BE","\\01F3C1","\\01F3D0","\\01F3C9","\\01F3B1"];
var animgprefix='', animgsuffix='', anothertype='', newtypes=[], thisemhe='', thisem='';
var othertype=(location.search.split('type=')[1] ? decodeURIComponent(location.search.split('type=')[1].split('&')[0]) : '');
var anothertype=othertype.toLowerCase() + 'is', numarr=0;
var templateprefix='<span class="image-wrapper">', templatesuffix='<span style="visibility:visible;" class="doml dominoes5"></span><span style="visibility:visible;" class="domr dominoes6"></span></span>';
if (othertype.toLowerCase().replace('dominoes', '') != '') {
if (typeof anothertype == "string") {
setTimeout(alat, 3000);
animgprefix=templateprefix;
animgsuffix=templatesuffix;
}
}
… andnot drop new Javascript logic. This last idea, where only what happens to HTML img element (by default draggable=”true”) …
draggable … attribute “true” for “dragging available” and “false” for “dragging not available” … and …
ondragstart … event, only, of interest, and if interested and draggable=”true” mimic what the onclick event does
… is of interest to us, is a wish we can remember from the past, but then we probably still followed through coding for drop in the past. However, when you want to control where (a Domino tile) image ends up, allowing willy-nillydrop user interactions is unnecessary.
We’re going to call this “buttoned down drag”!
There is another reason to code for this. It means controlling that draggable attribute can stop any “other player peaking (to some degree), even accidentally” episodes, during the Dominoes game …
// Player 1's first go scenario ... set up Player 1 Domino tiles
document.getElementById('seven1').innerHTML+=brhuh + '<img draggable="true" ondragstart="goone(event.target);" onclick="goone(this);" style=width:80px; class="player1" id="' + player1arr[ij] + '" src="' + player1arr[ij] + '.png"></img>';
// Player 1's first go scenario ... set up Player 2 Domino tiles
document.getElementById('seven2').innerHTML+=brhuh + '<img draggable="false" ondragstart="gotwo(event.target);" onclick="gotwo(this);" style=width:80px;filter:brightness(0); class="player2" id="' + player2arr[ij] + '" src="' + player2arr[ij] + '.png"></img>';
A stalemate in dominoes is most commonly called a blocked game or a locked game, and the layout itself is referred to as being blocked or closed.
… where a user cannot play themselves and there are no Domino tiles left in the stock. And now that yesterday saw us continuously hashtagging the game status, some web browser address bar URL refreshing would land you back into the same pickle.
And so …
we turned a hardcopy into a span, potentially dynamic, element …
<h1 id=myh1>Dominoes Horizontal Block <span id=sgame>Game</span></h1>
that when detecting the stock is empty …
if (eval('' + document.getElementById('thstock').innerHTML.split('none;').length) >= 14) {
if (document.getElementById('sgame').innerHTML == 'Game') {
document.getElementById('sgame').innerHTML='<button title=" ... or blocked game" onclick=newstockgame();>New</button> Game';
}
}
…
has the capacity to call a new Javascript function …
function newstockgame() {
location.href=document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 1989786) + '&score1=' + document.getElementById('score1').innerHTML.replace('Score: ','') + '&score2=' + document.getElementById('score2').innerHTML.replace('Score: ','');
}
… to “exit the pickle”, available now, to a user reaching the stalemateblocked game scenario
… and found that “for dynamic updating sake” we needed to “borrow” from how we were shaping to share with email or SMS, and use that similar hashtagging “state of play” simulations to the document.URL scenarios as the game is playing, via, at the relevant points of time, after the global var prevlhis=”, lhis=”; initialization, that is …
Dominoes Horizontal Block Game Mobile Speech to Text Tutorial
We were researching ways an iPhone or iPad could be a second monitor for a macOS MacBook Air (and with our Dominoes game intelligently differently program the display on the second monitor) when researching …
… means, whereas, we thought, easier than all this, particularly as it was looking like both parties could not interact with both being “pointing capable” anyway, why not revisit the recent Dominoes Horizontal Block Game Speech to Text Tutorial‘s …
in single device Dominoes Horizontal Block Game mode a single mobile device could be handed around corresponding to when a player is allowed to see … or …
mobile device on Google Chrome could be the interactive device but be displayed on macOS MacBook Air nearby and at proper times a user can speak their Domino tile choice into the awaiting mobile device microphone
… are viable options to play the Dominoes game in more varieties of “usage guises” …
if ((6 == 6 || (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) <= 0)) && document.URL.indexOf('https:') == 0 && (5 == 5 || document.URL.indexOf('?') == -1) && document.URL.indexOf('rjmprogramming.com.au/Games/Dominoes') != -1) {
if (('' + window.navigator.userAgent).toLowerCase().replace('crios','chrome').indexOf('chrom') != -1) {
if (window.parent == window.self) {
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) || eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
setTimeout(function(){
document.getElementById('myh1').innerHTML+=" <a onclick='if (!alldoneanddusted) { abitlater(this); }' style='text-decoration:none;cursor:pointer;border:3px dotted yellow;' href='#preifp' title='Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak. Is opt in via initial tap here for Google Chrome mobile users.'>🎤</a>";
}, 2000);
} else {
alldoneanddusted=true;
setTimeout(function(){
document.getElementById('preifp').style.display='block';
document.getElementById('ifblank').style.display='block';
speechtotextwo=window.open('https://www.rjmprogramming.com.au/PHP/speech_supervisor.php?mode=4&raxnd=' + Math.floor(Math.random() * 1989675), 'ifblank'); //, 'top=0,left=' + eval(-600 + screen.width) + ',width=600,height=' + eval(-100 + screen.height));
document.getElementById('myh1').innerHTML+=" <a style=text-decoration:none;cursor:pointer; href='#preifp' title='Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak.'>🎤</a>";
setTimeout(function(){
document.getElementById('myh1').scrollIntoView(); //window.scrollTo(0,0);
//window.top.scrollTo(0,0);
}, 2000);
}, 3000);
}
}
setInterval(scheckwo, 4000);
}
}
function abitlater(oa) {
alldoneanddusted=true;
oa.style.border='1px solid green';
setTimeout(function(){
document.getElementById('preifp').style.display='block';
document.getElementById('ifblank').style.display='block';
speechtotextwo=window.open('https://www.rjmprogramming.com.au/PHP/speech_supervisor.php?mode=4&raxnd=' + Math.floor(Math.random() * 1989675), 'ifblank'); //, 'top=0,left=' + eval(-600 + screen.width) + ',width=600,height=' + eval(-100 + screen.height));
//document.getElementById('myh1').innerHTML+=" <a style=text-decoration:none;cursor:pointer; href='#preifp' title='Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak.'>🎤</a>";
setTimeout(function(){
document.getElementById('myh1').scrollIntoView(); //window.scrollTo(0,0);
//window.top.scrollTo(0,0);
}, 2000);
}, 3000);
}
We have usually opened this Speech to Text window in a popup window, but today we open it in an iframe “below the fold” and we think into the future we may do this a bit more, especially as it’s functionality, anyway, flags when it is ready for the user to speak by displaying an orange microphone icon up near the top of the Google Chrome web browser window (and so matters less whether you see it’s inner workings, as you speak), and a new …
Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak.
… hashtag navigator can position the user to those “inner workings” (and back) as required.
This Speech to Text logic is expecting numbers describing Domino tiles to click, as per the new Javascript …
function acton(wdsl) {
var pidis='', pidarr=[];
if (wdsl.trim() != '') {
if (wdsl.toLowerCase() == 'stock' || wdsl.toLowerCase().substring(0,1) == '-') {
if (document.getElementById('thstock').innerHTML.indexOf('dominoes_') != -1) {
pidarr=document.getElementById('thstock').innerHTML.split('dominoes_');
pidis='dominoes_' + pidarr[Math.max(1,Math.floor(Math.random() * pidarr.length))].split('"')[0].split("'")[0].split('>')[0];
}
} else if (wdsl.toLowerCase().substring(0,1) >= '0' && wdsl.toLowerCase().substring(0,1) <= '9') {
if (eval('' + wdsl.length) == 1) {
pidis='dominoes_' + wdsl + '_' + wdsl;
} else if (wdsl.substring(0,1) <= wdsl.substring(1).substring(0,1)) {
pidis='dominoes_' + wdsl.substring(0,1) + '_' + wdsl.substring(1).substring(0,1);
} else {
pidis='dominoes_' + wdsl.substring(1).substring(0,1) + '_' + wdsl.substring(0,1);
}
} else if (wdsl.toLowerCase() == 'ten') {
pidis='dominoes_0_1';
} else if (wdsl.toLowerCase() == 'eleven') {
pidis='dominoes_1_1';
} else if (wdsl.toLowerCase() == 'twelve') {
pidis='dominoes_1_2';
} else if (wdsl.toLowerCase() == 'thirteen') {
pidis='dominoes_1_3';
} else if (wdsl.toLowerCase() == 'fourteen') {
pidis='dominoes_1_4';
} else if (wdsl.toLowerCase() == 'fifteen') {
pidis='dominoes_1_5';
} else if (wdsl.toLowerCase() == 'sixteen') {
pidis='dominoes_1_6';
} else if (wdsl.toLowerCase() == 'twenty') {
pidis='dominoes_0_2';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentyone') {
pidis='dominoes_1_2';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentytwo') {
pidis='dominoes_2_2';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentythree') {
pidis='dominoes_2_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentyfour') {
pidis='dominoes_2_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentyfive') {
pidis='dominoes_2_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentysix') {
pidis='dominoes_2_6';
} else if (wdsl.toLowerCase() == 'thirty') {
pidis='dominoes_0_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtyone') {
pidis='dominoes_1_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtytwo') {
pidis='dominoes_2_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtythree') {
pidis='dominoes_3_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtyfour') {
pidis='dominoes_3_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtyfive') {
pidis='dominoes_3_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtysix') {
pidis='dominoes_3_6';
} else if (wdsl.toLowerCase() == 'forty') {
pidis='dominoes_0_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortyone') {
pidis='dominoes_1_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortytwo') {
pidis='dominoes_2_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortythree') {
pidis='dominoes_3_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortyfour') {
pidis='dominoes_4_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortyfive') {
pidis='dominoes_4_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortysix') {
pidis='dominoes_4_6';
} else if (wdsl.toLowerCase() == 'fifty') {
pidis='dominoes_0_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftyone') {
pidis='dominoes_1_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftytwo') {
pidis='dominoes_2_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftythree') {
pidis='dominoes_3_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftyfour') {
pidis='dominoes_4_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftyfive') {
pidis='dominoes_5_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftysix') {
pidis='dominoes_5_6';
} else if (wdsl.toLowerCase() == 'sixty') {
pidis='dominoes_0_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtyone') {
pidis='dominoes_1_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtytwo') {
pidis='dominoes_2_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtythree') {
pidis='dominoes_3_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtyfour') {
pidis='dominoes_4_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtyfive') {
pidis='dominoes_5_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtysix') {
pidis='dominoes_6_6';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero') == 'zero') {
pidis='dominoes_0_0';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerozero') {
pidis='dominoes_0_0';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zeroone') {
pidis='dominoes_0_1';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerotwo') {
pidis='dominoes_0_2';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerothree') {
pidis='dominoes_0_3';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerofour') {
pidis='dominoes_0_4';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerofive') {
pidis='dominoes_0_5';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerosix') {
pidis='dominoes_0_6';
} else if (wdsl.toLowerCase() == 'one') {
if (document.getElementById('dominoes_0_1')) {
pidis='dominoes_0_1';
} else {
pidis='dominoes_1_1';
}
} else if (wdsl.toLowerCase() == 'two') {
if (document.getElementById('dominoes_0_2')) {
pidis='dominoes_0_2';
} else {
pidis='dominoes_2_2';
}
} else if (wdsl.toLowerCase() == 'three') {
if (document.getElementById('dominoes_0_3')) {
pidis='dominoes_0_3';
} else {
pidis='dominoes_3_3';
}
} else if (wdsl.toLowerCase() == 'four') {
if (document.getElementById('dominoes_0_4')) {
pidis='dominoes_0_4';
} else {
pidis='dominoes_4_4';
}
} else if (wdsl.toLowerCase() == 'five') {
if (document.getElementById('dominoes_0_5')) {
pidis='dominoes_0_5';
} else {
pidis='dominoes_5_5';
}
} else if (wdsl.toLowerCase() == 'six') {
if (document.getElementById('dominoes_0_6')) {
pidis='dominoes_0_6';
} else {
pidis='dominoes_6_6';
}
} else if (wdsl.toLowerCase() == 'seven') {
} else if (wdsl.toLowerCase() == 'eight') {
} else if (wdsl.toLowerCase() == 'nine') {
}
}
if (pidis.trim() != '') {
if (document.getElementById(pidis)) {
if (document.getElementById(pidis).outerHTML.replace('display: ','display:').indexOf('display:none') == -1) {
document.getElementById(pidis).click();
}
}
}
}
This “width” issue would probably disappear if Dominoes ever become emojis (where we’d start controlling textual HTML element CSS font-size property to control Domino tile size, or more specifically, width), but being they are images, yes we can size them quite small, but there are limits, regarding readability, meaning to have too many of these Domino images across an iPhone screen, for example, we found it an improvement to …
Recognise the environments where the issue might occur …
Start right justifying, within the left cell of the two, for Player 1, their images, and for the Stock center justify to lessen the overall width a narrow device has to concern itself with, via CSS …
Separate player focus, to a degree, via controlled “to left” (Player 1) or “to right” (Player 2) webpage scrolling in X (only … something we can’t remember considering before, but is a really useful concept) (ie. a width thaing)…
some recessed feeling (via box-shadow) to span element contenteditable=true so as to flag that interaction may be available (and with this, a double click on the body element will help mobile users see the on hover advice non-mobile users see regarding these collaboration possibilities), via the CSS …
<style>
#name1 { z-index: 67; padding: 8 8 8 8; box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4); background-color: rgb(240,240,240); color: purple; border-radius: 8px; }
#name2 { z-index: 67; padding: 8 8 8 8; box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4); background-color: rgb(240,240,240); color: green; border-radius: 8px; }
</style>
use of outline CSS property for erroneously clicked Dominoes, but not interfering with the deliberate margins, differentiating these from Dominoes committed in game play, via Javascript DOM …
iobj.style.outline='1px dotted orange';
… remembering recent discoveries where the outline property display is not part of the element, but can be a display enhancer (we found better than trying the CSS “active” pseudo class idea #reveal1:active,#reveal2:active { background-color: orange; } # causing some deliberate margins to disappear)
there’s a sliver of accidental overlay that can come into play with the smaller widths, and that z-index curious CSS above dovetails with CSS …
<style>
#reveal1,#reveal2 { margin-top: 3px; gap: 4px; z-index: 76; }
</style>
… so that the button tap/click takes precedence over any span contenteditable=true tap/click to focus (we kept doing accidentally) … that gap property may work to separate wrapped elements with a sliver of whitespace to preceding elements, but did not seem to work for us?!
Stop Press
Thinking more regarding …
some recessed feeling (via box-shadow) to span element contenteditable=true so as to flag that interaction may be available (and with this, a double click on the body element will help mobile users see the on hover advice non-mobile users see regarding these collaboration possibilities), via the CSS …
… above, for any mobile device with no on hover (title attribute) means of conveying information, why not intervene at those span element onfocus events (Javascript functions focusone and focustwo respectively) …
var spanoonedone=false, spanoonedtwo=false;
function focusone(ospan) {
if (!spanoonedone && navigator.userAgent.match(/Android|BlackBerry|iPad|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
var ansis=prompt(ospan.title, ospan.innerText);
if (ansis == null) { ansis=ospan.innerText; }
if (ansis != '' && ansis != ospan.innerText) { if (ansis.indexOf('],') != -1) { spanoonedtwo=true; } ospan.innerHTML=ansis; nameone(ospan); }
}
spanoonedone=true;
}
function focustwo(ospan) {
if (!spanoonedtwo && navigator.userAgent.match(/Android|BlackBerry|iPad|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
var ansis=prompt(ospan.title, ospan.innerText);
if (ansis == null) { ansis=ospan.innerText; }
if (ansis != '' && ansis != ospan.innerText) { if (ansis.indexOf('],') != -1) { spanoonedone=true; } ospan.innerHTML=ansis; nametwo(ospan); }
}
spanoonedtwo=true;
}
… so that information can be imparted as a matter of course should the user show an interest? It is water off a duck’s back whether the mobile device keyboard activity occurs in a Javascript prompt window or at the span contenteditable=true element itself, after all, regarding our further changedsixth draftDominoes Block Game you can try below.
as well as yesterday’s player “Turn Away Paradigm” for one device scenarios of play … today we add …
collaboration, via …
email … or …
SMS … where either of those “Player” HTML span elements are contenteditable=true and via their onblur event Javascript logics …
Player names are editable and if you use name such as RM[rmetcalfe15@gmail.com] (collaboration can occur with similar other Player change) or RM[rmetcalfe15@gmail.com],RMet[rmetcalfe@rjmprogramming.com.au] (collaboration occurs with other Player name changed accordingly).
… applies to them
… for a two device (presumably) and two player Dominoes play scenario
… as an alternative mode of play. We were proceeding along quite well, until we started into the SMS testing.
We did it!
We reached a URL with huge hashtag SMS length limit! Don’t know why we are so excited, because the rearrangement had us reaching for this PHP dominoes_block_game.php helper …
<?php
// dominoes_block_game.php
// Help out dominoes_block_game.html with SMS messages
// August, 2026
… paradigm whereby two players can play a Dominoes Game sharing the one device, that game may benefit by a user instigated “beep paradigm” in play (but be aware if you have dogs in the house like “The Lu” she gets put off by this optional beeping).
Further to yesterday’s Dominoes Game Resources Tutorial‘s start to our Dominoes online game quest, and reading more about the rules of play regarding a Block Game version we’ve settled for the following sections on this game’s webpage designed for two players sharing the one screen (so far) …
header parts
playing area … where the tiles players play are placed
left and right player areas … show player names and score and current button of applicability …
left and right player tiles area … sometimes showing individual player tiles, sometimes showing underside of tile, with an honour system in play that the player whose turn it is not, turns away when asked …
stock area … contains the rest of the 28 dominoes not yet in play, showing underside of tile
Our strategy will be the first player to play is determined by whether left or right button is first selected, and from there in the game the order of play proceeds as per the rules of the Dominoes Block Game.
So far we think we’ll rewrite button content constantly according to what the status of the game at any given time. We can do that because the button elements are hosted by span hosting HTML elements.
… you can think of in programming (and many IDE) parlance as “resources”, and such games can lend themselves towards Object Oriented Programming (ie. OOP) code design, perhaps, and a set aside block of time preparing resources ahead of starting any coding. So it is with today’s start, for us, in creating a …
… game, as an online web application. We vaguely remember Dominoes from a while back and it involves …
dominoes (we think of as tiles) … as the resource …
randomosity … as many games do, regarding them being turned over to them all looking the same, and players randomly selecting their own tiles to play the game …
a way to score … as many games do
This first day of work had us …
find a good online source at this useful link … thanks … to create a “parent resource” …
… dominoes.png … via …
form rectangle around the white on black section of tiles
Edit -> Copy
File -> New from Clipboard
File -> Save As… dominoes.png
28 x
form rectangle around the white on black subsection of dominoes.png
Edit -> Copy
File -> New from Clipboard
File -> Save As… dominoes_[leftHandDotCount]_[rightHandDotCount].png
7 x
form rectangle around the uniquely encountered leftHandDotCount left hand side of a dominoes_[leftHandDotCount]_[rightHandDotCount].png
Edit -> Copy
File -> New from Clipboard
File -> Save As… dominoes_[leftHandDotCount].png
… off memories of how Dominoes might ask of us “resources” wise.
That left us, after using FileZilla uploading to a new RJM Programming /Games/Dominoes folder off that web server’s ApacheDocument Root folder, as a folder full of image files only.
In this early scenario here, there is an adage we try to maintain, but let’s ask why …
Not having an index file like index.html, index.htm, or index.php in an Apache folder is a bad idea because it exposes your entire directory structure and source files to the public via Apache’s automatic directory listing. This vulnerability, known as Directory Browsing or Information Disclosure, allows attackers to easily map your application, find sensitive backup files, and locate hidden scripts.
FileZilla is really great at remedying them, often times temporary dilemma, quickly. Within a web server folder a context menu option Create New File (we called index.html) in that folder (even zero length) is going to stop that issue weakness talked about above. Aaaaaaah! Now we can think more clearly on ways to design the online Dominoes version game play.
Animated Plane and Coconut Hunt Game Nuances Tutorial
Today’s a day of nuanced progress, after yesterday’s Coconut Hunt Game Tutorial‘s “filling in sideways” work on our Animated Plane and Coconut Hunt Game web application. Today, we …
fixed some document.body.title annoyances whereby it would appear too often
worked on the default A option textarea via …
some “panda 🐼 led recovery” modelling of a p emoji usage (with animation) and span emoji usage (without animation) … and …
modelling of how iframe onload event can be used to develop dynamic Javascript (the default example changing the coconut 🥥 hunt into a bear 🐻 hunt?!) … as opposed to a document.createElement(‘script’) alternative approach
fixed some window.open too small size annoyances
allowed for screen co-ordinates cursor (on non-mobile), via onmousemove event logic, to assist intrepid users going above and beyond “overlay” positioning their own elements via position:absolute; left:?; top:?; in A option textareas
allowed for toggling of non-mobile cursor between as above and crosshair via right click
allowed for the last left:?; top:?; as above detected be remembered and involve itself as the default position:absolute; “overlay” positioning of the A option textarea default “panda 🐼 led recovery” emoji of above
allow for 8 seconds of time for a user to change default coconut 🥥 emoji to some other text via contenteditable=true ahead of the Hunt Game starting … thanks to this useful link regarding hiding a contenteditable=true focus border
Are you a reader who has been amused or bemused by the word Game being in the blog posting titles lately, up to yesterday’s Animated Plane Game User Animations and Styling Tutorial, when No Game really, about any of it? Well, today, it’s …
Game On
Do you like coconuts? Can I ask you, have you ever looked into a coconut, and asked yourself …
? Well, have we got the game for you?! Start the ball rollingshell shaking via the first click/top on the coconut fallen from the tree. And from there, it’s a fast reactions game, to score well! Good luck, in the changed“latest draft”Animated Plane Coconut Hunt Game web application below!
… today we wanted to offer two more user controllable parts to this Animated Plane Game web application, those being …
CSS styling … easy, as CSS can be dynamically added to a web application at the clientside, as the Javascript is executing … and, a bit more of a learning curve for beginners is …
user animations … we’re envisaging, in it’s “easiest to understand encapsulation for a newbie” uses …
… a whole big wooooorrrrlllldddd of animation study just by itself (and in order for modelling to, perhaps, help we used an example from this excellent link, thanks, as the default option A textarea usage model)
… but a hell of a lot easier for a user to establish than some arcane Javascript DOM animations involving setTimeout or setInterval timers?!
For these two new ideas, popup textarea windows appear to give the user plenty of space to play around in. As ever, email and SMS can follow up for that user to share with others what their animation ideas are, perhaps far removed from the original plane and gymnast scenario by the time they finish. And here it may be pertinent to point out that even using hashtag emailing (and even more so with SMSing) there must be message size limits that will stop you event-u-al-ly!
In yesterday’s “noun” work we talked about “content” defined by the user in terms of real references to media data URIs or URLs. Well, the other way a user can now affect “content” is via CSS. Below we make the plane and gymnast disappear via the C (for CSS styling) option (that can take you to a popup window textarea where you can Apply this) …
<style>
#myif { /* plane */
display:none; /* other choice could be visibility:hidden; */
}
#mytwoif { /* gymnast */
visibility:hidden; /* other choice could be display:none; */
}
</style>
… each of which has a relationship to a piece of media content. The border-image (ie. ground) content aspects we allow a user to define emoji text for, but the rest are associated with a data URI or URL.
Today’s work is to allow the user to specify these “content” data items themselves, as well as share this via email or SMS to another user, with those user “content” data items recreated for the recipient user clicking the email or SMS link containing those hashtagged user data components. Later we hope to expand the functionality more, from today’s …
function getsrc(fromoh) {
var forvpre='Currently this content points at ... ' + String.fromCharCode(10);
var forvsuf=String.fromCharCode(10) + 'Enter an alternative content URL (can be clipart style data URI you see often using Google Image (Copy Image Address via right click) Searches) ... or ... ' + String.fromCharCode(10) + String.fromCharCode(10) + '1[:URL] for trees, 2[:URL] for plane, 3[:URL] for gymnast, 4[:URL] for clouds, 5[:emoji(s)] for ground, E for email, S for SMS';
if (fromoh.indexOf(' src="//') != -1) {
return forvpre + document.URL.split('//')[0] + fromoh.split(' src="')[1].split('"')[0] + forvsuf;
} else if (fromoh.indexOf(" src='//") != -1) {
return forvpre + document.URL.split('//')[0] + fromoh.split(" src='")[1].split("'")[0] + forvsuf;
} else if (fromoh.indexOf(" src=//") != -1) {
return forvpre + document.URL.split('//')[0] + fromoh.split(" src=")[1].split(" ")[0].split(">")[0] + forvsuf;
} else if (fromoh.indexOf(' src="') != -1) {
return forvpre + fromoh.split(' src="')[1].split('"')[0] + forvsuf;
} else if (fromoh.indexOf(" src='") != -1) {
return forvpre + fromoh.split(" src='")[1].split("'")[0] + forvsuf;
} else if (fromoh.indexOf(" src=") != -1) {
return forvpre + fromoh.split(" src=")[1].split(" ")[0].split(">")[0] + forvsuf;
}
return fromoh;
}
function yourprompt(ino, intlis) {
var ei=-1, si=-1;
isac=true;
var opsd=prompt(getsrc(ino.outerHTML), '');
if (opsd == null) { isac=false; return false; }
if (opsd.trim() != '') {
switch (opsd.substring(0,1).toLowerCase().replace('+','s')) {
case '1': // trees
if ((opsd + ' ').substring(0,2) == '1:') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + (opsd + ' ').substring(2) + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
} else {
opsd=prompt('Enter your (perhaps clipart via Google image search) data URI or URL suiting where trees are.', '');
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
}
break;
case '2': // plane
if ((opsd + ' ').substring(0,2) == '2:') {
planealt='&planealt=' + encodeURIComponent(opsd);
document.getElementById('myif').style.backgroundImage='url(' + ((opsd + ' ').substring(2)).replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
} else {
opsd=prompt('Enter your (perhaps clipart via Google image search) data URI or URL suiting where plane is.', '');
if (opsd != null) {
if (opsd.trim() != '') {
planealt='&planealt=' + encodeURIComponent(opsd);
document.getElementById('myif').style.backgroundImage='url(' + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
}
}
}
break;
case '3': // gymnast
if ((opsd + ' ').substring(0,2) == '3:') {
gymnastalt='&gymnastalt=' + encodeURIComponent(opsd);
document.getElementById('mytwoif').style.backgroundImage='url(' + ((opsd + ' ').substring(2)).replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
} else {
opsd=prompt('Enter your (perhaps clipart via Google image search) data URI or URL suiting where gymnast is.', '');
if (opsd != null) {
if (opsd.trim() != '') {
gymnastalt='&gymnastalt=' + encodeURIComponent(opsd);
document.getElementById('mytwoif').style.backgroundImage='url(' + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
}
}
}
break;
case '4': // clouds
if ((opsd + ' ').substring(0,2) == '4:') {
cloudsalt='&cloudsalt=' + encodeURIComponent(opsd);
document.body.style.backgroundImage='url(' + ((opsd + ' ').substring(2)).replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
} else {
opsd=prompt('Enter your (perhaps via Google image search) data URI or URL suiting where cloud background image is.', '');
if (opsd != null) {
if (opsd.trim() != '') {
cloudsalt='&cloudsalt=' + encodeURIComponent(opsd);
document.body.style.backgroundImage='url(' + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
}
}
}
break;
The mix-blend-mode:multiply; discoveries (along with those naive previous usage without realizing it’s implications) we made creating Periodic Table Image Map Primer Tutorial recently has opened up new “vistas of possibility” (VOP, of course) for us, and has inspired us to give “just Javascript and CSS and HTML animated games” (aided in large part by clipart free content components) another go …
… with a “widget feel” now realizable, for us, knowing that white backgrounded HTML iframe content no longer has to hold us back piecing together animations (in an “OOP feeling” way) consisting of …
base webpage CSS and HTML and Javascript (DOM, also helping out the control of) …
HTML iframe components (and in our case the image content is it’s background image with background-size:contain; and background-repeat:no-repeat; along with a specific iframe width and height) for any one “noun” (or class of object) in your game storyboard … if you will … if you will … if you will … and …
HTML img components in a similar vein … but today’s trees did not need mix-blend-mode:multiply; because the originator made the background transparent (ie. another option with all this “animated pieces thinking”)
Animation(s) can be CSS @keyframe transitions (though not yet with animation above) or Javascript DOM logic via setTimeout (or setInterval) timers or animated GIF/webp content or, we daresay, many other approaches.
We’re going to tabularize below “how we got to the result above” below …
We started with a “first draft” … getting plane image animated with a rudimentary green border-bottom representing the ground …
… then to“second draft” … adding animated GIF cloud background to go with edited because mix-blend-mode:multiply will not mask out the non heterogenous bluish clouds in the image …
Thanks to Image by brgfx on Freepik and https://i.makeagif.com/media/8-11-2023/Xu_roP.gif and https://procul.org/images/2025/Animated-Clouds-Gif/ and and https://au.pinterest.com/pin/587930926347995281/ and https://giphy.com/explore/trees-swaying-stickers
… then to“sixth draft” … added animated GIF gymnast background and thereby proving that overlapping “iframe widgets” (helped out by mix-blend-mode:multiply presumably) was possible, and important …
… then to“seventh draft” … added animated (and transparently backgrounded) webp swaying trees image along with tweaked now animated GIF to animate the plane itself a little, in place, separate to the Javascript DOM based animation moving across the screen … for today’s final draft …
Stop Press
In tomorrow’s installment we allow for user defined content, and sharing, as per …
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
Around here, further to the recent Horizontal Block Game Less Personal Types Tutorial‘s Horizontal Block Game incarnation developments, today we present two new Random Image choices we turn to quite a bit, those being …
… that last one the only “Personalized” one for us here, near Sydney, Australia.
And that second last one, accessing Wikipedia image URLs, thanks, involving other TimeZones (we’ve found out about using PHP TimeZone information functionality in the past), to make happen, involved a dropdown off a dropdown, as per (this Javascript DOM positioning this second dropdown, as the user has selected this second last option) …
… as we return to another image (element img) scenario, except this time they take the form of …
Background image pairs (thanks to Wikipedia, here) for the left and right span element amigos of a Domino tile image's hosting span element (introduced in yesterday's work)
So what’s the “Personalized” about this? Well, we add a new type that is the user’s local (ie. from the client side …
var qwr='' + Intl.DateTimeFormat().resolvedOptions().timeZone;
) … timezone, as an intrinsic part of what goes to make up the datetime stamp in your neck of the woods, whether you think much about it, or not. This functionality benefits from dynamic CSS like …
That being the case, as of today (but as of tomorrow, who knows?) the last dropdown option, adding onto yesterday’s mostly emoji overlay options, being the unique part of your local TimeZone, differs around the world for people trying the changedfourteenth draftDominoes Block Game you can try below.
This “width” issue would probably disappear if Dominoes ever become emojis
… and today’s work fulfills that wish … somewhat? It’s not that dominoes have become emojis, yet, but we thought we’d embellish our …
Domino basis in code
… with overlayed (to any one Domino tile) left hand and right hand emojis, so that we can offer …
… set of 5 emoji overlayed and 1 domino image and an email snapshot set of extended functionalities onto that one original game type, accessible via a new URL argument type …
New initialization Javascript code …
var svgis='<svg xmlns="http://w3.org" style="position: absolute; width: 0; height: 0;" aria-hidden="true"><filter id="edge-detection"><feConvolveMatrix order="3 3" kernelMatrix="-1 -2 -1 0 0 0 1 2 1" preserveAlpha="true" /></filter></svg>';
var shapeis=["\\002739","\\002737","\\002729","\\002727","\\002719","\\002724","\\002713"];
var foodis=["\\01f371","\\01f358","\\01f359","\\01f35a","\\01f35b","\\01f35c","\\01f35d","\\01f360","\\01f362","\\01f363","\\01f364","\\01f365","\\01f361","\\01F366","\\01F367","\\01F368","\\01F369","\\01F36A","\\01F382","\\01F370"];
var animalis=['128028','128018','128030','128029','128012','128040','129408','128060','128027','129413','128044','129445'];
var transportis=["\\002708","\\01F680","\\01F681","\\01F686","\\01F687","\\01F68C","\\01F68F","\\01F5FA"];
var activityis=["\\0026BD","\\01F3C0","\\01F3C2","\\0026BE","\\01F3C1","\\01F3D0","\\01F3C9","\\01F3B1"];
var animgprefix='', animgsuffix='', anothertype='', newtypes=[], thisemhe='', thisem='';
var othertype=(location.search.split('type=')[1] ? decodeURIComponent(location.search.split('type=')[1].split('&')[0]) : '');
var anothertype=othertype.toLowerCase() + 'is', numarr=0;
var templateprefix='<span class="image-wrapper">', templatesuffix='<span style="visibility:visible;" class="doml dominoes5"></span><span style="visibility:visible;" class="domr dominoes6"></span></span>';
if (othertype.toLowerCase().replace('dominoes', '') != '') {
if (typeof anothertype == "string") {
setTimeout(alat, 3000);
animgprefix=templateprefix;
animgsuffix=templatesuffix;
}
}
… andnot drop new Javascript logic. This last idea, where only what happens to HTML img element (by default draggable=”true”) …
draggable … attribute “true” for “dragging available” and “false” for “dragging not available” … and …
ondragstart … event, only, of interest, and if interested and draggable=”true” mimic what the onclick event does
… is of interest to us, is a wish we can remember from the past, but then we probably still followed through coding for drop in the past. However, when you want to control where (a Domino tile) image ends up, allowing willy-nillydrop user interactions is unnecessary.
We’re going to call this “buttoned down drag”!
There is another reason to code for this. It means controlling that draggable attribute can stop any “other player peaking (to some degree), even accidentally” episodes, during the Dominoes game …
// Player 1's first go scenario ... set up Player 1 Domino tiles
document.getElementById('seven1').innerHTML+=brhuh + '<img draggable="true" ondragstart="goone(event.target);" onclick="goone(this);" style=width:80px; class="player1" id="' + player1arr[ij] + '" src="' + player1arr[ij] + '.png"></img>';
// Player 1's first go scenario ... set up Player 2 Domino tiles
document.getElementById('seven2').innerHTML+=brhuh + '<img draggable="false" ondragstart="gotwo(event.target);" onclick="gotwo(this);" style=width:80px;filter:brightness(0); class="player2" id="' + player2arr[ij] + '" src="' + player2arr[ij] + '.png"></img>';
A stalemate in dominoes is most commonly called a blocked game or a locked game, and the layout itself is referred to as being blocked or closed.
… where a user cannot play themselves and there are no Domino tiles left in the stock. And now that yesterday saw us continuously hashtagging the game status, some web browser address bar URL refreshing would land you back into the same pickle.
And so …
we turned a hardcopy into a span, potentially dynamic, element …
<h1 id=myh1>Dominoes Horizontal Block <span id=sgame>Game</span></h1>
that when detecting the stock is empty …
if (eval('' + document.getElementById('thstock').innerHTML.split('none;').length) >= 14) {
if (document.getElementById('sgame').innerHTML == 'Game') {
document.getElementById('sgame').innerHTML='<button title=" ... or blocked game" onclick=newstockgame();>New</button> Game';
}
}
…
has the capacity to call a new Javascript function …
function newstockgame() {
location.href=document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 1989786) + '&score1=' + document.getElementById('score1').innerHTML.replace('Score: ','') + '&score2=' + document.getElementById('score2').innerHTML.replace('Score: ','');
}
… to “exit the pickle”, available now, to a user reaching the stalemateblocked game scenario
… and found that “for dynamic updating sake” we needed to “borrow” from how we were shaping to share with email or SMS, and use that similar hashtagging “state of play” simulations to the document.URL scenarios as the game is playing, via, at the relevant points of time, after the global var prevlhis=”, lhis=”; initialization, that is …
Dominoes Horizontal Block Game Mobile Speech to Text Tutorial
We were researching ways an iPhone or iPad could be a second monitor for a macOS MacBook Air (and with our Dominoes game intelligently differently program the display on the second monitor) when researching …
… means, whereas, we thought, easier than all this, particularly as it was looking like both parties could not interact with both being “pointing capable” anyway, why not revisit the recent Dominoes Horizontal Block Game Speech to Text Tutorial‘s …
in single device Dominoes Horizontal Block Game mode a single mobile device could be handed around corresponding to when a player is allowed to see … or …
mobile device on Google Chrome could be the interactive device but be displayed on macOS MacBook Air nearby and at proper times a user can speak their Domino tile choice into the awaiting mobile device microphone
… are viable options to play the Dominoes game in more varieties of “usage guises” …
if ((6 == 6 || (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) <= 0)) && document.URL.indexOf('https:') == 0 && (5 == 5 || document.URL.indexOf('?') == -1) && document.URL.indexOf('rjmprogramming.com.au/Games/Dominoes') != -1) {
if (('' + window.navigator.userAgent).toLowerCase().replace('crios','chrome').indexOf('chrom') != -1) {
if (window.parent == window.self) {
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) || eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
setTimeout(function(){
document.getElementById('myh1').innerHTML+=" <a onclick='if (!alldoneanddusted) { abitlater(this); }' style='text-decoration:none;cursor:pointer;border:3px dotted yellow;' href='#preifp' title='Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak. Is opt in via initial tap here for Google Chrome mobile users.'>🎤</a>";
}, 2000);
} else {
alldoneanddusted=true;
setTimeout(function(){
document.getElementById('preifp').style.display='block';
document.getElementById('ifblank').style.display='block';
speechtotextwo=window.open('https://www.rjmprogramming.com.au/PHP/speech_supervisor.php?mode=4&raxnd=' + Math.floor(Math.random() * 1989675), 'ifblank'); //, 'top=0,left=' + eval(-600 + screen.width) + ',width=600,height=' + eval(-100 + screen.height));
document.getElementById('myh1').innerHTML+=" <a style=text-decoration:none;cursor:pointer; href='#preifp' title='Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak.'>🎤</a>";
setTimeout(function(){
document.getElementById('myh1').scrollIntoView(); //window.scrollTo(0,0);
//window.top.scrollTo(0,0);
}, 2000);
}, 3000);
}
}
setInterval(scheckwo, 4000);
}
}
function abitlater(oa) {
alldoneanddusted=true;
oa.style.border='1px solid green';
setTimeout(function(){
document.getElementById('preifp').style.display='block';
document.getElementById('ifblank').style.display='block';
speechtotextwo=window.open('https://www.rjmprogramming.com.au/PHP/speech_supervisor.php?mode=4&raxnd=' + Math.floor(Math.random() * 1989675), 'ifblank'); //, 'top=0,left=' + eval(-600 + screen.width) + ',width=600,height=' + eval(-100 + screen.height));
//document.getElementById('myh1').innerHTML+=" <a style=text-decoration:none;cursor:pointer; href='#preifp' title='Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak.'>🎤</a>";
setTimeout(function(){
document.getElementById('myh1').scrollIntoView(); //window.scrollTo(0,0);
//window.top.scrollTo(0,0);
}, 2000);
}, 3000);
}
We have usually opened this Speech to Text window in a popup window, but today we open it in an iframe “below the fold” and we think into the future we may do this a bit more, especially as it’s functionality, anyway, flags when it is ready for the user to speak by displaying an orange microphone icon up near the top of the Google Chrome web browser window (and so matters less whether you see it’s inner workings, as you speak), and a new …
Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak.
… hashtag navigator can position the user to those “inner workings” (and back) as required.
This Speech to Text logic is expecting numbers describing Domino tiles to click, as per the new Javascript …
function acton(wdsl) {
var pidis='', pidarr=[];
if (wdsl.trim() != '') {
if (wdsl.toLowerCase() == 'stock' || wdsl.toLowerCase().substring(0,1) == '-') {
if (document.getElementById('thstock').innerHTML.indexOf('dominoes_') != -1) {
pidarr=document.getElementById('thstock').innerHTML.split('dominoes_');
pidis='dominoes_' + pidarr[Math.max(1,Math.floor(Math.random() * pidarr.length))].split('"')[0].split("'")[0].split('>')[0];
}
} else if (wdsl.toLowerCase().substring(0,1) >= '0' && wdsl.toLowerCase().substring(0,1) <= '9') {
if (eval('' + wdsl.length) == 1) {
pidis='dominoes_' + wdsl + '_' + wdsl;
} else if (wdsl.substring(0,1) <= wdsl.substring(1).substring(0,1)) {
pidis='dominoes_' + wdsl.substring(0,1) + '_' + wdsl.substring(1).substring(0,1);
} else {
pidis='dominoes_' + wdsl.substring(1).substring(0,1) + '_' + wdsl.substring(0,1);
}
} else if (wdsl.toLowerCase() == 'ten') {
pidis='dominoes_0_1';
} else if (wdsl.toLowerCase() == 'eleven') {
pidis='dominoes_1_1';
} else if (wdsl.toLowerCase() == 'twelve') {
pidis='dominoes_1_2';
} else if (wdsl.toLowerCase() == 'thirteen') {
pidis='dominoes_1_3';
} else if (wdsl.toLowerCase() == 'fourteen') {
pidis='dominoes_1_4';
} else if (wdsl.toLowerCase() == 'fifteen') {
pidis='dominoes_1_5';
} else if (wdsl.toLowerCase() == 'sixteen') {
pidis='dominoes_1_6';
} else if (wdsl.toLowerCase() == 'twenty') {
pidis='dominoes_0_2';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentyone') {
pidis='dominoes_1_2';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentytwo') {
pidis='dominoes_2_2';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentythree') {
pidis='dominoes_2_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentyfour') {
pidis='dominoes_2_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentyfive') {
pidis='dominoes_2_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentysix') {
pidis='dominoes_2_6';
} else if (wdsl.toLowerCase() == 'thirty') {
pidis='dominoes_0_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtyone') {
pidis='dominoes_1_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtytwo') {
pidis='dominoes_2_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtythree') {
pidis='dominoes_3_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtyfour') {
pidis='dominoes_3_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtyfive') {
pidis='dominoes_3_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtysix') {
pidis='dominoes_3_6';
} else if (wdsl.toLowerCase() == 'forty') {
pidis='dominoes_0_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortyone') {
pidis='dominoes_1_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortytwo') {
pidis='dominoes_2_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortythree') {
pidis='dominoes_3_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortyfour') {
pidis='dominoes_4_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortyfive') {
pidis='dominoes_4_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortysix') {
pidis='dominoes_4_6';
} else if (wdsl.toLowerCase() == 'fifty') {
pidis='dominoes_0_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftyone') {
pidis='dominoes_1_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftytwo') {
pidis='dominoes_2_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftythree') {
pidis='dominoes_3_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftyfour') {
pidis='dominoes_4_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftyfive') {
pidis='dominoes_5_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftysix') {
pidis='dominoes_5_6';
} else if (wdsl.toLowerCase() == 'sixty') {
pidis='dominoes_0_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtyone') {
pidis='dominoes_1_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtytwo') {
pidis='dominoes_2_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtythree') {
pidis='dominoes_3_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtyfour') {
pidis='dominoes_4_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtyfive') {
pidis='dominoes_5_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtysix') {
pidis='dominoes_6_6';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero') == 'zero') {
pidis='dominoes_0_0';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerozero') {
pidis='dominoes_0_0';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zeroone') {
pidis='dominoes_0_1';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerotwo') {
pidis='dominoes_0_2';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerothree') {
pidis='dominoes_0_3';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerofour') {
pidis='dominoes_0_4';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerofive') {
pidis='dominoes_0_5';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerosix') {
pidis='dominoes_0_6';
} else if (wdsl.toLowerCase() == 'one') {
if (document.getElementById('dominoes_0_1')) {
pidis='dominoes_0_1';
} else {
pidis='dominoes_1_1';
}
} else if (wdsl.toLowerCase() == 'two') {
if (document.getElementById('dominoes_0_2')) {
pidis='dominoes_0_2';
} else {
pidis='dominoes_2_2';
}
} else if (wdsl.toLowerCase() == 'three') {
if (document.getElementById('dominoes_0_3')) {
pidis='dominoes_0_3';
} else {
pidis='dominoes_3_3';
}
} else if (wdsl.toLowerCase() == 'four') {
if (document.getElementById('dominoes_0_4')) {
pidis='dominoes_0_4';
} else {
pidis='dominoes_4_4';
}
} else if (wdsl.toLowerCase() == 'five') {
if (document.getElementById('dominoes_0_5')) {
pidis='dominoes_0_5';
} else {
pidis='dominoes_5_5';
}
} else if (wdsl.toLowerCase() == 'six') {
if (document.getElementById('dominoes_0_6')) {
pidis='dominoes_0_6';
} else {
pidis='dominoes_6_6';
}
} else if (wdsl.toLowerCase() == 'seven') {
} else if (wdsl.toLowerCase() == 'eight') {
} else if (wdsl.toLowerCase() == 'nine') {
}
}
if (pidis.trim() != '') {
if (document.getElementById(pidis)) {
if (document.getElementById(pidis).outerHTML.replace('display: ','display:').indexOf('display:none') == -1) {
document.getElementById(pidis).click();
}
}
}
}
This “width” issue would probably disappear if Dominoes ever become emojis (where we’d start controlling textual HTML element CSS font-size property to control Domino tile size, or more specifically, width), but being they are images, yes we can size them quite small, but there are limits, regarding readability, meaning to have too many of these Domino images across an iPhone screen, for example, we found it an improvement to …
Recognise the environments where the issue might occur …
Start right justifying, within the left cell of the two, for Player 1, their images, and for the Stock center justify to lessen the overall width a narrow device has to concern itself with, via CSS …
Separate player focus, to a degree, via controlled “to left” (Player 1) or “to right” (Player 2) webpage scrolling in X (only … something we can’t remember considering before, but is a really useful concept) (ie. a width thaing)…
some recessed feeling (via box-shadow) to span element contenteditable=true so as to flag that interaction may be available (and with this, a double click on the body element will help mobile users see the on hover advice non-mobile users see regarding these collaboration possibilities), via the CSS …
<style>
#name1 { z-index: 67; padding: 8 8 8 8; box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4); background-color: rgb(240,240,240); color: purple; border-radius: 8px; }
#name2 { z-index: 67; padding: 8 8 8 8; box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4); background-color: rgb(240,240,240); color: green; border-radius: 8px; }
</style>
use of outline CSS property for erroneously clicked Dominoes, but not interfering with the deliberate margins, differentiating these from Dominoes committed in game play, via Javascript DOM …
iobj.style.outline='1px dotted orange';
… remembering recent discoveries where the outline property display is not part of the element, but can be a display enhancer (we found better than trying the CSS “active” pseudo class idea #reveal1:active,#reveal2:active { background-color: orange; } # causing some deliberate margins to disappear)
there’s a sliver of accidental overlay that can come into play with the smaller widths, and that z-index curious CSS above dovetails with CSS …
<style>
#reveal1,#reveal2 { margin-top: 3px; gap: 4px; z-index: 76; }
</style>
… so that the button tap/click takes precedence over any span contenteditable=true tap/click to focus (we kept doing accidentally) … that gap property may work to separate wrapped elements with a sliver of whitespace to preceding elements, but did not seem to work for us?!
Stop Press
Thinking more regarding …
some recessed feeling (via box-shadow) to span element contenteditable=true so as to flag that interaction may be available (and with this, a double click on the body element will help mobile users see the on hover advice non-mobile users see regarding these collaboration possibilities), via the CSS …
… above, for any mobile device with no on hover (title attribute) means of conveying information, why not intervene at those span element onfocus events (Javascript functions focusone and focustwo respectively) …
var spanoonedone=false, spanoonedtwo=false;
function focusone(ospan) {
if (!spanoonedone && navigator.userAgent.match(/Android|BlackBerry|iPad|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
var ansis=prompt(ospan.title, ospan.innerText);
if (ansis == null) { ansis=ospan.innerText; }
if (ansis != '' && ansis != ospan.innerText) { if (ansis.indexOf('],') != -1) { spanoonedtwo=true; } ospan.innerHTML=ansis; nameone(ospan); }
}
spanoonedone=true;
}
function focustwo(ospan) {
if (!spanoonedtwo && navigator.userAgent.match(/Android|BlackBerry|iPad|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
var ansis=prompt(ospan.title, ospan.innerText);
if (ansis == null) { ansis=ospan.innerText; }
if (ansis != '' && ansis != ospan.innerText) { if (ansis.indexOf('],') != -1) { spanoonedone=true; } ospan.innerHTML=ansis; nametwo(ospan); }
}
spanoonedtwo=true;
}
… so that information can be imparted as a matter of course should the user show an interest? It is water off a duck’s back whether the mobile device keyboard activity occurs in a Javascript prompt window or at the span contenteditable=true element itself, after all, regarding our further changedsixth draftDominoes Block Game you can try below.
as well as yesterday’s player “Turn Away Paradigm” for one device scenarios of play … today we add …
collaboration, via …
email … or …
SMS … where either of those “Player” HTML span elements are contenteditable=true and via their onblur event Javascript logics …
Player names are editable and if you use name such as RM[rmetcalfe15@gmail.com] (collaboration can occur with similar other Player change) or RM[rmetcalfe15@gmail.com],RMet[rmetcalfe@rjmprogramming.com.au] (collaboration occurs with other Player name changed accordingly).
… applies to them
… for a two device (presumably) and two player Dominoes play scenario
… as an alternative mode of play. We were proceeding along quite well, until we started into the SMS testing.
We did it!
We reached a URL with huge hashtag SMS length limit! Don’t know why we are so excited, because the rearrangement had us reaching for this PHP dominoes_block_game.php helper …
<?php
// dominoes_block_game.php
// Help out dominoes_block_game.html with SMS messages
// August, 2026
… paradigm whereby two players can play a Dominoes Game sharing the one device, that game may benefit by a user instigated “beep paradigm” in play (but be aware if you have dogs in the house like “The Lu” she gets put off by this optional beeping).
Further to yesterday’s Dominoes Game Resources Tutorial‘s start to our Dominoes online game quest, and reading more about the rules of play regarding a Block Game version we’ve settled for the following sections on this game’s webpage designed for two players sharing the one screen (so far) …
header parts
playing area … where the tiles players play are placed
left and right player areas … show player names and score and current button of applicability …
left and right player tiles area … sometimes showing individual player tiles, sometimes showing underside of tile, with an honour system in play that the player whose turn it is not, turns away when asked …
stock area … contains the rest of the 28 dominoes not yet in play, showing underside of tile
Our strategy will be the first player to play is determined by whether left or right button is first selected, and from there in the game the order of play proceeds as per the rules of the Dominoes Block Game.
So far we think we’ll rewrite button content constantly according to what the status of the game at any given time. We can do that because the button elements are hosted by span hosting HTML elements.
… you can think of in programming (and many IDE) parlance as “resources”, and such games can lend themselves towards Object Oriented Programming (ie. OOP) code design, perhaps, and a set aside block of time preparing resources ahead of starting any coding. So it is with today’s start, for us, in creating a …
… game, as an online web application. We vaguely remember Dominoes from a while back and it involves …
dominoes (we think of as tiles) … as the resource …
randomosity … as many games do, regarding them being turned over to them all looking the same, and players randomly selecting their own tiles to play the game …
a way to score … as many games do
This first day of work had us …
find a good online source at this useful link … thanks … to create a “parent resource” …
… dominoes.png … via …
form rectangle around the white on black section of tiles
Edit -> Copy
File -> New from Clipboard
File -> Save As… dominoes.png
28 x
form rectangle around the white on black subsection of dominoes.png
Edit -> Copy
File -> New from Clipboard
File -> Save As… dominoes_[leftHandDotCount]_[rightHandDotCount].png
7 x
form rectangle around the uniquely encountered leftHandDotCount left hand side of a dominoes_[leftHandDotCount]_[rightHandDotCount].png
Edit -> Copy
File -> New from Clipboard
File -> Save As… dominoes_[leftHandDotCount].png
… off memories of how Dominoes might ask of us “resources” wise.
That left us, after using FileZilla uploading to a new RJM Programming /Games/Dominoes folder off that web server’s ApacheDocument Root folder, as a folder full of image files only.
In this early scenario here, there is an adage we try to maintain, but let’s ask why …
Not having an index file like index.html, index.htm, or index.php in an Apache folder is a bad idea because it exposes your entire directory structure and source files to the public via Apache’s automatic directory listing. This vulnerability, known as Directory Browsing or Information Disclosure, allows attackers to easily map your application, find sensitive backup files, and locate hidden scripts.
FileZilla is really great at remedying them, often times temporary dilemma, quickly. Within a web server folder a context menu option Create New File (we called index.html) in that folder (even zero length) is going to stop that issue weakness talked about above. Aaaaaaah! Now we can think more clearly on ways to design the online Dominoes version game play.
Animated Plane and Coconut Hunt Game Nuances Tutorial
Today’s a day of nuanced progress, after yesterday’s Coconut Hunt Game Tutorial‘s “filling in sideways” work on our Animated Plane and Coconut Hunt Game web application. Today, we …
fixed some document.body.title annoyances whereby it would appear too often
worked on the default A option textarea via …
some “panda 🐼 led recovery” modelling of a p emoji usage (with animation) and span emoji usage (without animation) … and …
modelling of how iframe onload event can be used to develop dynamic Javascript (the default example changing the coconut 🥥 hunt into a bear 🐻 hunt?!) … as opposed to a document.createElement(‘script’) alternative approach
fixed some window.open too small size annoyances
allowed for screen co-ordinates cursor (on non-mobile), via onmousemove event logic, to assist intrepid users going above and beyond “overlay” positioning their own elements via position:absolute; left:?; top:?; in A option textareas
allowed for toggling of non-mobile cursor between as above and crosshair via right click
allowed for the last left:?; top:?; as above detected be remembered and involve itself as the default position:absolute; “overlay” positioning of the A option textarea default “panda 🐼 led recovery” emoji of above
allow for 8 seconds of time for a user to change default coconut 🥥 emoji to some other text via contenteditable=true ahead of the Hunt Game starting … thanks to this useful link regarding hiding a contenteditable=true focus border
Are you a reader who has been amused or bemused by the word Game being in the blog posting titles lately, up to yesterday’s Animated Plane Game User Animations and Styling Tutorial, when No Game really, about any of it? Well, today, it’s …
Game On
Do you like coconuts? Can I ask you, have you ever looked into a coconut, and asked yourself …
? Well, have we got the game for you?! Start the ball rollingshell shaking via the first click/top on the coconut fallen from the tree. And from there, it’s a fast reactions game, to score well! Good luck, in the changed“latest draft”Animated Plane Coconut Hunt Game web application below!
… today we wanted to offer two more user controllable parts to this Animated Plane Game web application, those being …
CSS styling … easy, as CSS can be dynamically added to a web application at the clientside, as the Javascript is executing … and, a bit more of a learning curve for beginners is …
user animations … we’re envisaging, in it’s “easiest to understand encapsulation for a newbie” uses …
… a whole big wooooorrrrlllldddd of animation study just by itself (and in order for modelling to, perhaps, help we used an example from this excellent link, thanks, as the default option A textarea usage model)
… but a hell of a lot easier for a user to establish than some arcane Javascript DOM animations involving setTimeout or setInterval timers?!
For these two new ideas, popup textarea windows appear to give the user plenty of space to play around in. As ever, email and SMS can follow up for that user to share with others what their animation ideas are, perhaps far removed from the original plane and gymnast scenario by the time they finish. And here it may be pertinent to point out that even using hashtag emailing (and even more so with SMSing) there must be message size limits that will stop you event-u-al-ly!
In yesterday’s “noun” work we talked about “content” defined by the user in terms of real references to media data URIs or URLs. Well, the other way a user can now affect “content” is via CSS. Below we make the plane and gymnast disappear via the C (for CSS styling) option (that can take you to a popup window textarea where you can Apply this) …
<style>
#myif { /* plane */
display:none; /* other choice could be visibility:hidden; */
}
#mytwoif { /* gymnast */
visibility:hidden; /* other choice could be display:none; */
}
</style>
… each of which has a relationship to a piece of media content. The border-image (ie. ground) content aspects we allow a user to define emoji text for, but the rest are associated with a data URI or URL.
Today’s work is to allow the user to specify these “content” data items themselves, as well as share this via email or SMS to another user, with those user “content” data items recreated for the recipient user clicking the email or SMS link containing those hashtagged user data components. Later we hope to expand the functionality more, from today’s …
function getsrc(fromoh) {
var forvpre='Currently this content points at ... ' + String.fromCharCode(10);
var forvsuf=String.fromCharCode(10) + 'Enter an alternative content URL (can be clipart style data URI you see often using Google Image (Copy Image Address via right click) Searches) ... or ... ' + String.fromCharCode(10) + String.fromCharCode(10) + '1[:URL] for trees, 2[:URL] for plane, 3[:URL] for gymnast, 4[:URL] for clouds, 5[:emoji(s)] for ground, E for email, S for SMS';
if (fromoh.indexOf(' src="//') != -1) {
return forvpre + document.URL.split('//')[0] + fromoh.split(' src="')[1].split('"')[0] + forvsuf;
} else if (fromoh.indexOf(" src='//") != -1) {
return forvpre + document.URL.split('//')[0] + fromoh.split(" src='")[1].split("'")[0] + forvsuf;
} else if (fromoh.indexOf(" src=//") != -1) {
return forvpre + document.URL.split('//')[0] + fromoh.split(" src=")[1].split(" ")[0].split(">")[0] + forvsuf;
} else if (fromoh.indexOf(' src="') != -1) {
return forvpre + fromoh.split(' src="')[1].split('"')[0] + forvsuf;
} else if (fromoh.indexOf(" src='") != -1) {
return forvpre + fromoh.split(" src='")[1].split("'")[0] + forvsuf;
} else if (fromoh.indexOf(" src=") != -1) {
return forvpre + fromoh.split(" src=")[1].split(" ")[0].split(">")[0] + forvsuf;
}
return fromoh;
}
function yourprompt(ino, intlis) {
var ei=-1, si=-1;
isac=true;
var opsd=prompt(getsrc(ino.outerHTML), '');
if (opsd == null) { isac=false; return false; }
if (opsd.trim() != '') {
switch (opsd.substring(0,1).toLowerCase().replace('+','s')) {
case '1': // trees
if ((opsd + ' ').substring(0,2) == '1:') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + (opsd + ' ').substring(2) + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
} else {
opsd=prompt('Enter your (perhaps clipart via Google image search) data URI or URL suiting where trees are.', '');
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
}
break;
case '2': // plane
if ((opsd + ' ').substring(0,2) == '2:') {
planealt='&planealt=' + encodeURIComponent(opsd);
document.getElementById('myif').style.backgroundImage='url(' + ((opsd + ' ').substring(2)).replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
} else {
opsd=prompt('Enter your (perhaps clipart via Google image search) data URI or URL suiting where plane is.', '');
if (opsd != null) {
if (opsd.trim() != '') {
planealt='&planealt=' + encodeURIComponent(opsd);
document.getElementById('myif').style.backgroundImage='url(' + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
}
}
}
break;
case '3': // gymnast
if ((opsd + ' ').substring(0,2) == '3:') {
gymnastalt='&gymnastalt=' + encodeURIComponent(opsd);
document.getElementById('mytwoif').style.backgroundImage='url(' + ((opsd + ' ').substring(2)).replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
} else {
opsd=prompt('Enter your (perhaps clipart via Google image search) data URI or URL suiting where gymnast is.', '');
if (opsd != null) {
if (opsd.trim() != '') {
gymnastalt='&gymnastalt=' + encodeURIComponent(opsd);
document.getElementById('mytwoif').style.backgroundImage='url(' + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
}
}
}
break;
case '4': // clouds
if ((opsd + ' ').substring(0,2) == '4:') {
cloudsalt='&cloudsalt=' + encodeURIComponent(opsd);
document.body.style.backgroundImage='url(' + ((opsd + ' ').substring(2)).replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
} else {
opsd=prompt('Enter your (perhaps via Google image search) data URI or URL suiting where cloud background image is.', '');
if (opsd != null) {
if (opsd.trim() != '') {
cloudsalt='&cloudsalt=' + encodeURIComponent(opsd);
document.body.style.backgroundImage='url(' + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
}
}
}
break;
The mix-blend-mode:multiply; discoveries (along with those naive previous usage without realizing it’s implications) we made creating Periodic Table Image Map Primer Tutorial recently has opened up new “vistas of possibility” (VOP, of course) for us, and has inspired us to give “just Javascript and CSS and HTML animated games” (aided in large part by clipart free content components) another go …
… with a “widget feel” now realizable, for us, knowing that white backgrounded HTML iframe content no longer has to hold us back piecing together animations (in an “OOP feeling” way) consisting of …
base webpage CSS and HTML and Javascript (DOM, also helping out the control of) …
HTML iframe components (and in our case the image content is it’s background image with background-size:contain; and background-repeat:no-repeat; along with a specific iframe width and height) for any one “noun” (or class of object) in your game storyboard … if you will … if you will … if you will … and …
HTML img components in a similar vein … but today’s trees did not need mix-blend-mode:multiply; because the originator made the background transparent (ie. another option with all this “animated pieces thinking”)
Animation(s) can be CSS @keyframe transitions (though not yet with animation above) or Javascript DOM logic via setTimeout (or setInterval) timers or animated GIF/webp content or, we daresay, many other approaches.
We’re going to tabularize below “how we got to the result above” below …
We started with a “first draft” … getting plane image animated with a rudimentary green border-bottom representing the ground …
… then to“second draft” … adding animated GIF cloud background to go with edited because mix-blend-mode:multiply will not mask out the non heterogenous bluish clouds in the image …
Thanks to Image by brgfx on Freepik and https://i.makeagif.com/media/8-11-2023/Xu_roP.gif and https://procul.org/images/2025/Animated-Clouds-Gif/ and and https://au.pinterest.com/pin/587930926347995281/ and https://giphy.com/explore/trees-swaying-stickers
… then to“sixth draft” … added animated GIF gymnast background and thereby proving that overlapping “iframe widgets” (helped out by mix-blend-mode:multiply presumably) was possible, and important …
… then to“seventh draft” … added animated (and transparently backgrounded) webp swaying trees image along with tweaked now animated GIF to animate the plane itself a little, in place, separate to the Javascript DOM based animation moving across the screen … for today’s final draft …
Stop Press
In tomorrow’s installment we allow for user defined content, and sharing, as per …
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
Around here, further to the recent Horizontal Block Game Less Personal Types Tutorial‘s Horizontal Block Game incarnation developments, today we present two new Random Image choices we turn to quite a bit, those being …
… that last one the only “Personalized” one for us here, near Sydney, Australia.
And that second last one, accessing Wikipedia image URLs, thanks, involving other TimeZones (we’ve found out about using PHP TimeZone information functionality in the past), to make happen, involved a dropdown off a dropdown, as per (this Javascript DOM positioning this second dropdown, as the user has selected this second last option) …
… as we return to another image (element img) scenario, except this time they take the form of …
Background image pairs (thanks to Wikipedia, here) for the left and right span element amigos of a Domino tile image's hosting span element (introduced in yesterday's work)
So what’s the “Personalized” about this? Well, we add a new type that is the user’s local (ie. from the client side …
var qwr='' + Intl.DateTimeFormat().resolvedOptions().timeZone;
) … timezone, as an intrinsic part of what goes to make up the datetime stamp in your neck of the woods, whether you think much about it, or not. This functionality benefits from dynamic CSS like …
That being the case, as of today (but as of tomorrow, who knows?) the last dropdown option, adding onto yesterday’s mostly emoji overlay options, being the unique part of your local TimeZone, differs around the world for people trying the changedfourteenth draftDominoes Block Game you can try below.
This “width” issue would probably disappear if Dominoes ever become emojis
… and today’s work fulfills that wish … somewhat? It’s not that dominoes have become emojis, yet, but we thought we’d embellish our …
Domino basis in code
… with overlayed (to any one Domino tile) left hand and right hand emojis, so that we can offer …
… set of 5 emoji overlayed and 1 domino image and an email snapshot set of extended functionalities onto that one original game type, accessible via a new URL argument type …
New initialization Javascript code …
var svgis='<svg xmlns="http://w3.org" style="position: absolute; width: 0; height: 0;" aria-hidden="true"><filter id="edge-detection"><feConvolveMatrix order="3 3" kernelMatrix="-1 -2 -1 0 0 0 1 2 1" preserveAlpha="true" /></filter></svg>';
var shapeis=["\\002739","\\002737","\\002729","\\002727","\\002719","\\002724","\\002713"];
var foodis=["\\01f371","\\01f358","\\01f359","\\01f35a","\\01f35b","\\01f35c","\\01f35d","\\01f360","\\01f362","\\01f363","\\01f364","\\01f365","\\01f361","\\01F366","\\01F367","\\01F368","\\01F369","\\01F36A","\\01F382","\\01F370"];
var animalis=['128028','128018','128030','128029','128012','128040','129408','128060','128027','129413','128044','129445'];
var transportis=["\\002708","\\01F680","\\01F681","\\01F686","\\01F687","\\01F68C","\\01F68F","\\01F5FA"];
var activityis=["\\0026BD","\\01F3C0","\\01F3C2","\\0026BE","\\01F3C1","\\01F3D0","\\01F3C9","\\01F3B1"];
var animgprefix='', animgsuffix='', anothertype='', newtypes=[], thisemhe='', thisem='';
var othertype=(location.search.split('type=')[1] ? decodeURIComponent(location.search.split('type=')[1].split('&')[0]) : '');
var anothertype=othertype.toLowerCase() + 'is', numarr=0;
var templateprefix='<span class="image-wrapper">', templatesuffix='<span style="visibility:visible;" class="doml dominoes5"></span><span style="visibility:visible;" class="domr dominoes6"></span></span>';
if (othertype.toLowerCase().replace('dominoes', '') != '') {
if (typeof anothertype == "string") {
setTimeout(alat, 3000);
animgprefix=templateprefix;
animgsuffix=templatesuffix;
}
}
… andnot drop new Javascript logic. This last idea, where only what happens to HTML img element (by default draggable=”true”) …
draggable … attribute “true” for “dragging available” and “false” for “dragging not available” … and …
ondragstart … event, only, of interest, and if interested and draggable=”true” mimic what the onclick event does
… is of interest to us, is a wish we can remember from the past, but then we probably still followed through coding for drop in the past. However, when you want to control where (a Domino tile) image ends up, allowing willy-nillydrop user interactions is unnecessary.
We’re going to call this “buttoned down drag”!
There is another reason to code for this. It means controlling that draggable attribute can stop any “other player peaking (to some degree), even accidentally” episodes, during the Dominoes game …
// Player 1's first go scenario ... set up Player 1 Domino tiles
document.getElementById('seven1').innerHTML+=brhuh + '<img draggable="true" ondragstart="goone(event.target);" onclick="goone(this);" style=width:80px; class="player1" id="' + player1arr[ij] + '" src="' + player1arr[ij] + '.png"></img>';
// Player 1's first go scenario ... set up Player 2 Domino tiles
document.getElementById('seven2').innerHTML+=brhuh + '<img draggable="false" ondragstart="gotwo(event.target);" onclick="gotwo(this);" style=width:80px;filter:brightness(0); class="player2" id="' + player2arr[ij] + '" src="' + player2arr[ij] + '.png"></img>';
A stalemate in dominoes is most commonly called a blocked game or a locked game, and the layout itself is referred to as being blocked or closed.
… where a user cannot play themselves and there are no Domino tiles left in the stock. And now that yesterday saw us continuously hashtagging the game status, some web browser address bar URL refreshing would land you back into the same pickle.
And so …
we turned a hardcopy into a span, potentially dynamic, element …
<h1 id=myh1>Dominoes Horizontal Block <span id=sgame>Game</span></h1>
that when detecting the stock is empty …
if (eval('' + document.getElementById('thstock').innerHTML.split('none;').length) >= 14) {
if (document.getElementById('sgame').innerHTML == 'Game') {
document.getElementById('sgame').innerHTML='<button title=" ... or blocked game" onclick=newstockgame();>New</button> Game';
}
}
…
has the capacity to call a new Javascript function …
function newstockgame() {
location.href=document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 1989786) + '&score1=' + document.getElementById('score1').innerHTML.replace('Score: ','') + '&score2=' + document.getElementById('score2').innerHTML.replace('Score: ','');
}
… to “exit the pickle”, available now, to a user reaching the stalemateblocked game scenario
… and found that “for dynamic updating sake” we needed to “borrow” from how we were shaping to share with email or SMS, and use that similar hashtagging “state of play” simulations to the document.URL scenarios as the game is playing, via, at the relevant points of time, after the global var prevlhis=”, lhis=”; initialization, that is …
Dominoes Horizontal Block Game Mobile Speech to Text Tutorial
We were researching ways an iPhone or iPad could be a second monitor for a macOS MacBook Air (and with our Dominoes game intelligently differently program the display on the second monitor) when researching …
… means, whereas, we thought, easier than all this, particularly as it was looking like both parties could not interact with both being “pointing capable” anyway, why not revisit the recent Dominoes Horizontal Block Game Speech to Text Tutorial‘s …
in single device Dominoes Horizontal Block Game mode a single mobile device could be handed around corresponding to when a player is allowed to see … or …
mobile device on Google Chrome could be the interactive device but be displayed on macOS MacBook Air nearby and at proper times a user can speak their Domino tile choice into the awaiting mobile device microphone
… are viable options to play the Dominoes game in more varieties of “usage guises” …
if ((6 == 6 || (!navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) <= 0)) && document.URL.indexOf('https:') == 0 && (5 == 5 || document.URL.indexOf('?') == -1) && document.URL.indexOf('rjmprogramming.com.au/Games/Dominoes') != -1) {
if (('' + window.navigator.userAgent).toLowerCase().replace('crios','chrome').indexOf('chrom') != -1) {
if (window.parent == window.self) {
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) || eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
setTimeout(function(){
document.getElementById('myh1').innerHTML+=" <a onclick='if (!alldoneanddusted) { abitlater(this); }' style='text-decoration:none;cursor:pointer;border:3px dotted yellow;' href='#preifp' title='Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak. Is opt in via initial tap here for Google Chrome mobile users.'>🎤</a>";
}, 2000);
} else {
alldoneanddusted=true;
setTimeout(function(){
document.getElementById('preifp').style.display='block';
document.getElementById('ifblank').style.display='block';
speechtotextwo=window.open('https://www.rjmprogramming.com.au/PHP/speech_supervisor.php?mode=4&raxnd=' + Math.floor(Math.random() * 1989675), 'ifblank'); //, 'top=0,left=' + eval(-600 + screen.width) + ',width=600,height=' + eval(-100 + screen.height));
document.getElementById('myh1').innerHTML+=" <a style=text-decoration:none;cursor:pointer; href='#preifp' title='Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak.'>🎤</a>";
setTimeout(function(){
document.getElementById('myh1').scrollIntoView(); //window.scrollTo(0,0);
//window.top.scrollTo(0,0);
}, 2000);
}, 3000);
}
}
setInterval(scheckwo, 4000);
}
}
function abitlater(oa) {
alldoneanddusted=true;
oa.style.border='1px solid green';
setTimeout(function(){
document.getElementById('preifp').style.display='block';
document.getElementById('ifblank').style.display='block';
speechtotextwo=window.open('https://www.rjmprogramming.com.au/PHP/speech_supervisor.php?mode=4&raxnd=' + Math.floor(Math.random() * 1989675), 'ifblank'); //, 'top=0,left=' + eval(-600 + screen.width) + ',width=600,height=' + eval(-100 + screen.height));
//document.getElementById('myh1').innerHTML+=" <a style=text-decoration:none;cursor:pointer; href='#preifp' title='Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak.'>🎤</a>";
setTimeout(function(){
document.getElementById('myh1').scrollIntoView(); //window.scrollTo(0,0);
//window.top.scrollTo(0,0);
}, 2000);
}, 3000);
}
We have usually opened this Speech to Text window in a popup window, but today we open it in an iframe “below the fold” and we think into the future we may do this a bit more, especially as it’s functionality, anyway, flags when it is ready for the user to speak by displaying an orange microphone icon up near the top of the Google Chrome web browser window (and so matters less whether you see it’s inner workings, as you speak), and a new …
Speech to Text eg. 25 will click domino with 2 pips then 5 pips. Orange microphone icon up the top of web browser indicates it is primed to hear you speak.
… hashtag navigator can position the user to those “inner workings” (and back) as required.
This Speech to Text logic is expecting numbers describing Domino tiles to click, as per the new Javascript …
function acton(wdsl) {
var pidis='', pidarr=[];
if (wdsl.trim() != '') {
if (wdsl.toLowerCase() == 'stock' || wdsl.toLowerCase().substring(0,1) == '-') {
if (document.getElementById('thstock').innerHTML.indexOf('dominoes_') != -1) {
pidarr=document.getElementById('thstock').innerHTML.split('dominoes_');
pidis='dominoes_' + pidarr[Math.max(1,Math.floor(Math.random() * pidarr.length))].split('"')[0].split("'")[0].split('>')[0];
}
} else if (wdsl.toLowerCase().substring(0,1) >= '0' && wdsl.toLowerCase().substring(0,1) <= '9') {
if (eval('' + wdsl.length) == 1) {
pidis='dominoes_' + wdsl + '_' + wdsl;
} else if (wdsl.substring(0,1) <= wdsl.substring(1).substring(0,1)) {
pidis='dominoes_' + wdsl.substring(0,1) + '_' + wdsl.substring(1).substring(0,1);
} else {
pidis='dominoes_' + wdsl.substring(1).substring(0,1) + '_' + wdsl.substring(0,1);
}
} else if (wdsl.toLowerCase() == 'ten') {
pidis='dominoes_0_1';
} else if (wdsl.toLowerCase() == 'eleven') {
pidis='dominoes_1_1';
} else if (wdsl.toLowerCase() == 'twelve') {
pidis='dominoes_1_2';
} else if (wdsl.toLowerCase() == 'thirteen') {
pidis='dominoes_1_3';
} else if (wdsl.toLowerCase() == 'fourteen') {
pidis='dominoes_1_4';
} else if (wdsl.toLowerCase() == 'fifteen') {
pidis='dominoes_1_5';
} else if (wdsl.toLowerCase() == 'sixteen') {
pidis='dominoes_1_6';
} else if (wdsl.toLowerCase() == 'twenty') {
pidis='dominoes_0_2';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentyone') {
pidis='dominoes_1_2';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentytwo') {
pidis='dominoes_2_2';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentythree') {
pidis='dominoes_2_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentyfour') {
pidis='dominoes_2_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentyfive') {
pidis='dominoes_2_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'twentysix') {
pidis='dominoes_2_6';
} else if (wdsl.toLowerCase() == 'thirty') {
pidis='dominoes_0_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtyone') {
pidis='dominoes_1_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtytwo') {
pidis='dominoes_2_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtythree') {
pidis='dominoes_3_3';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtyfour') {
pidis='dominoes_3_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtyfive') {
pidis='dominoes_3_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'thirtysix') {
pidis='dominoes_3_6';
} else if (wdsl.toLowerCase() == 'forty') {
pidis='dominoes_0_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortyone') {
pidis='dominoes_1_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortytwo') {
pidis='dominoes_2_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortythree') {
pidis='dominoes_3_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortyfour') {
pidis='dominoes_4_4';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortyfive') {
pidis='dominoes_4_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fortysix') {
pidis='dominoes_4_6';
} else if (wdsl.toLowerCase() == 'fifty') {
pidis='dominoes_0_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftyone') {
pidis='dominoes_1_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftytwo') {
pidis='dominoes_2_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftythree') {
pidis='dominoes_3_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftyfour') {
pidis='dominoes_4_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftyfive') {
pidis='dominoes_5_5';
} else if (wdsl.toLowerCase().replace(' ','') == 'fiftysix') {
pidis='dominoes_5_6';
} else if (wdsl.toLowerCase() == 'sixty') {
pidis='dominoes_0_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtyone') {
pidis='dominoes_1_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtytwo') {
pidis='dominoes_2_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtythree') {
pidis='dominoes_3_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtyfour') {
pidis='dominoes_4_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtyfive') {
pidis='dominoes_5_6';
} else if (wdsl.toLowerCase().replace(' ','') == 'sixtysix') {
pidis='dominoes_6_6';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero') == 'zero') {
pidis='dominoes_0_0';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerozero') {
pidis='dominoes_0_0';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zeroone') {
pidis='dominoes_0_1';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerotwo') {
pidis='dominoes_0_2';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerothree') {
pidis='dominoes_0_3';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerofour') {
pidis='dominoes_0_4';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerofive') {
pidis='dominoes_0_5';
} else if (wdsl.toLowerCase().replace('blank','zero').replace('blank','zero').replace(' ','') == 'zerosix') {
pidis='dominoes_0_6';
} else if (wdsl.toLowerCase() == 'one') {
if (document.getElementById('dominoes_0_1')) {
pidis='dominoes_0_1';
} else {
pidis='dominoes_1_1';
}
} else if (wdsl.toLowerCase() == 'two') {
if (document.getElementById('dominoes_0_2')) {
pidis='dominoes_0_2';
} else {
pidis='dominoes_2_2';
}
} else if (wdsl.toLowerCase() == 'three') {
if (document.getElementById('dominoes_0_3')) {
pidis='dominoes_0_3';
} else {
pidis='dominoes_3_3';
}
} else if (wdsl.toLowerCase() == 'four') {
if (document.getElementById('dominoes_0_4')) {
pidis='dominoes_0_4';
} else {
pidis='dominoes_4_4';
}
} else if (wdsl.toLowerCase() == 'five') {
if (document.getElementById('dominoes_0_5')) {
pidis='dominoes_0_5';
} else {
pidis='dominoes_5_5';
}
} else if (wdsl.toLowerCase() == 'six') {
if (document.getElementById('dominoes_0_6')) {
pidis='dominoes_0_6';
} else {
pidis='dominoes_6_6';
}
} else if (wdsl.toLowerCase() == 'seven') {
} else if (wdsl.toLowerCase() == 'eight') {
} else if (wdsl.toLowerCase() == 'nine') {
}
}
if (pidis.trim() != '') {
if (document.getElementById(pidis)) {
if (document.getElementById(pidis).outerHTML.replace('display: ','display:').indexOf('display:none') == -1) {
document.getElementById(pidis).click();
}
}
}
}
This “width” issue would probably disappear if Dominoes ever become emojis (where we’d start controlling textual HTML element CSS font-size property to control Domino tile size, or more specifically, width), but being they are images, yes we can size them quite small, but there are limits, regarding readability, meaning to have too many of these Domino images across an iPhone screen, for example, we found it an improvement to …
Recognise the environments where the issue might occur …
Start right justifying, within the left cell of the two, for Player 1, their images, and for the Stock center justify to lessen the overall width a narrow device has to concern itself with, via CSS …
Separate player focus, to a degree, via controlled “to left” (Player 1) or “to right” (Player 2) webpage scrolling in X (only … something we can’t remember considering before, but is a really useful concept) (ie. a width thaing)…
some recessed feeling (via box-shadow) to span element contenteditable=true so as to flag that interaction may be available (and with this, a double click on the body element will help mobile users see the on hover advice non-mobile users see regarding these collaboration possibilities), via the CSS …
<style>
#name1 { z-index: 67; padding: 8 8 8 8; box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4); background-color: rgb(240,240,240); color: purple; border-radius: 8px; }
#name2 { z-index: 67; padding: 8 8 8 8; box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4); background-color: rgb(240,240,240); color: green; border-radius: 8px; }
</style>
use of outline CSS property for erroneously clicked Dominoes, but not interfering with the deliberate margins, differentiating these from Dominoes committed in game play, via Javascript DOM …
iobj.style.outline='1px dotted orange';
… remembering recent discoveries where the outline property display is not part of the element, but can be a display enhancer (we found better than trying the CSS “active” pseudo class idea #reveal1:active,#reveal2:active { background-color: orange; } # causing some deliberate margins to disappear)
there’s a sliver of accidental overlay that can come into play with the smaller widths, and that z-index curious CSS above dovetails with CSS …
<style>
#reveal1,#reveal2 { margin-top: 3px; gap: 4px; z-index: 76; }
</style>
… so that the button tap/click takes precedence over any span contenteditable=true tap/click to focus (we kept doing accidentally) … that gap property may work to separate wrapped elements with a sliver of whitespace to preceding elements, but did not seem to work for us?!
Stop Press
Thinking more regarding …
some recessed feeling (via box-shadow) to span element contenteditable=true so as to flag that interaction may be available (and with this, a double click on the body element will help mobile users see the on hover advice non-mobile users see regarding these collaboration possibilities), via the CSS …
… above, for any mobile device with no on hover (title attribute) means of conveying information, why not intervene at those span element onfocus events (Javascript functions focusone and focustwo respectively) …
var spanoonedone=false, spanoonedtwo=false;
function focusone(ospan) {
if (!spanoonedone && navigator.userAgent.match(/Android|BlackBerry|iPad|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
var ansis=prompt(ospan.title, ospan.innerText);
if (ansis == null) { ansis=ospan.innerText; }
if (ansis != '' && ansis != ospan.innerText) { if (ansis.indexOf('],') != -1) { spanoonedtwo=true; } ospan.innerHTML=ansis; nameone(ospan); }
}
spanoonedone=true;
}
function focustwo(ospan) {
if (!spanoonedtwo && navigator.userAgent.match(/Android|BlackBerry|iPad|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
var ansis=prompt(ospan.title, ospan.innerText);
if (ansis == null) { ansis=ospan.innerText; }
if (ansis != '' && ansis != ospan.innerText) { if (ansis.indexOf('],') != -1) { spanoonedone=true; } ospan.innerHTML=ansis; nametwo(ospan); }
}
spanoonedtwo=true;
}
… so that information can be imparted as a matter of course should the user show an interest? It is water off a duck’s back whether the mobile device keyboard activity occurs in a Javascript prompt window or at the span contenteditable=true element itself, after all, regarding our further changedsixth draftDominoes Block Game you can try below.
as well as yesterday’s player “Turn Away Paradigm” for one device scenarios of play … today we add …
collaboration, via …
email … or …
SMS … where either of those “Player” HTML span elements are contenteditable=true and via their onblur event Javascript logics …
Player names are editable and if you use name such as RM[rmetcalfe15@gmail.com] (collaboration can occur with similar other Player change) or RM[rmetcalfe15@gmail.com],RMet[rmetcalfe@rjmprogramming.com.au] (collaboration occurs with other Player name changed accordingly).
… applies to them
… for a two device (presumably) and two player Dominoes play scenario
… as an alternative mode of play. We were proceeding along quite well, until we started into the SMS testing.
We did it!
We reached a URL with huge hashtag SMS length limit! Don’t know why we are so excited, because the rearrangement had us reaching for this PHP dominoes_block_game.php helper …
<?php
// dominoes_block_game.php
// Help out dominoes_block_game.html with SMS messages
// August, 2026
… paradigm whereby two players can play a Dominoes Game sharing the one device, that game may benefit by a user instigated “beep paradigm” in play (but be aware if you have dogs in the house like “The Lu” she gets put off by this optional beeping).
Further to yesterday’s Dominoes Game Resources Tutorial‘s start to our Dominoes online game quest, and reading more about the rules of play regarding a Block Game version we’ve settled for the following sections on this game’s webpage designed for two players sharing the one screen (so far) …
header parts
playing area … where the tiles players play are placed
left and right player areas … show player names and score and current button of applicability …
left and right player tiles area … sometimes showing individual player tiles, sometimes showing underside of tile, with an honour system in play that the player whose turn it is not, turns away when asked …
stock area … contains the rest of the 28 dominoes not yet in play, showing underside of tile
Our strategy will be the first player to play is determined by whether left or right button is first selected, and from there in the game the order of play proceeds as per the rules of the Dominoes Block Game.
So far we think we’ll rewrite button content constantly according to what the status of the game at any given time. We can do that because the button elements are hosted by span hosting HTML elements.
… you can think of in programming (and many IDE) parlance as “resources”, and such games can lend themselves towards Object Oriented Programming (ie. OOP) code design, perhaps, and a set aside block of time preparing resources ahead of starting any coding. So it is with today’s start, for us, in creating a …
… game, as an online web application. We vaguely remember Dominoes from a while back and it involves …
dominoes (we think of as tiles) … as the resource …
randomosity … as many games do, regarding them being turned over to them all looking the same, and players randomly selecting their own tiles to play the game …
a way to score … as many games do
This first day of work had us …
find a good online source at this useful link … thanks … to create a “parent resource” …
… dominoes.png … via …
form rectangle around the white on black section of tiles
Edit -> Copy
File -> New from Clipboard
File -> Save As… dominoes.png
28 x
form rectangle around the white on black subsection of dominoes.png
Edit -> Copy
File -> New from Clipboard
File -> Save As… dominoes_[leftHandDotCount]_[rightHandDotCount].png
7 x
form rectangle around the uniquely encountered leftHandDotCount left hand side of a dominoes_[leftHandDotCount]_[rightHandDotCount].png
Edit -> Copy
File -> New from Clipboard
File -> Save As… dominoes_[leftHandDotCount].png
… off memories of how Dominoes might ask of us “resources” wise.
That left us, after using FileZilla uploading to a new RJM Programming /Games/Dominoes folder off that web server’s ApacheDocument Root folder, as a folder full of image files only.
In this early scenario here, there is an adage we try to maintain, but let’s ask why …
Not having an index file like index.html, index.htm, or index.php in an Apache folder is a bad idea because it exposes your entire directory structure and source files to the public via Apache’s automatic directory listing. This vulnerability, known as Directory Browsing or Information Disclosure, allows attackers to easily map your application, find sensitive backup files, and locate hidden scripts.
FileZilla is really great at remedying them, often times temporary dilemma, quickly. Within a web server folder a context menu option Create New File (we called index.html) in that folder (even zero length) is going to stop that issue weakness talked about above. Aaaaaaah! Now we can think more clearly on ways to design the online Dominoes version game play.
Animated Plane and Coconut Hunt Game Nuances Tutorial
Today’s a day of nuanced progress, after yesterday’s Coconut Hunt Game Tutorial‘s “filling in sideways” work on our Animated Plane and Coconut Hunt Game web application. Today, we …
fixed some document.body.title annoyances whereby it would appear too often
worked on the default A option textarea via …
some “panda 🐼 led recovery” modelling of a p emoji usage (with animation) and span emoji usage (without animation) … and …
modelling of how iframe onload event can be used to develop dynamic Javascript (the default example changing the coconut 🥥 hunt into a bear 🐻 hunt?!) … as opposed to a document.createElement(‘script’) alternative approach
fixed some window.open too small size annoyances
allowed for screen co-ordinates cursor (on non-mobile), via onmousemove event logic, to assist intrepid users going above and beyond “overlay” positioning their own elements via position:absolute; left:?; top:?; in A option textareas
allowed for toggling of non-mobile cursor between as above and crosshair via right click
allowed for the last left:?; top:?; as above detected be remembered and involve itself as the default position:absolute; “overlay” positioning of the A option textarea default “panda 🐼 led recovery” emoji of above
allow for 8 seconds of time for a user to change default coconut 🥥 emoji to some other text via contenteditable=true ahead of the Hunt Game starting … thanks to this useful link regarding hiding a contenteditable=true focus border
Are you a reader who has been amused or bemused by the word Game being in the blog posting titles lately, up to yesterday’s Animated Plane Game User Animations and Styling Tutorial, when No Game really, about any of it? Well, today, it’s …
Game On
Do you like coconuts? Can I ask you, have you ever looked into a coconut, and asked yourself …
? Well, have we got the game for you?! Start the ball rollingshell shaking via the first click/top on the coconut fallen from the tree. And from there, it’s a fast reactions game, to score well! Good luck, in the changed“latest draft”Animated Plane Coconut Hunt Game web application below!
… today we wanted to offer two more user controllable parts to this Animated Plane Game web application, those being …
CSS styling … easy, as CSS can be dynamically added to a web application at the clientside, as the Javascript is executing … and, a bit more of a learning curve for beginners is …
user animations … we’re envisaging, in it’s “easiest to understand encapsulation for a newbie” uses …
… a whole big wooooorrrrlllldddd of animation study just by itself (and in order for modelling to, perhaps, help we used an example from this excellent link, thanks, as the default option A textarea usage model)
… but a hell of a lot easier for a user to establish than some arcane Javascript DOM animations involving setTimeout or setInterval timers?!
For these two new ideas, popup textarea windows appear to give the user plenty of space to play around in. As ever, email and SMS can follow up for that user to share with others what their animation ideas are, perhaps far removed from the original plane and gymnast scenario by the time they finish. And here it may be pertinent to point out that even using hashtag emailing (and even more so with SMSing) there must be message size limits that will stop you event-u-al-ly!
In yesterday’s “noun” work we talked about “content” defined by the user in terms of real references to media data URIs or URLs. Well, the other way a user can now affect “content” is via CSS. Below we make the plane and gymnast disappear via the C (for CSS styling) option (that can take you to a popup window textarea where you can Apply this) …
<style>
#myif { /* plane */
display:none; /* other choice could be visibility:hidden; */
}
#mytwoif { /* gymnast */
visibility:hidden; /* other choice could be display:none; */
}
</style>
… each of which has a relationship to a piece of media content. The border-image (ie. ground) content aspects we allow a user to define emoji text for, but the rest are associated with a data URI or URL.
Today’s work is to allow the user to specify these “content” data items themselves, as well as share this via email or SMS to another user, with those user “content” data items recreated for the recipient user clicking the email or SMS link containing those hashtagged user data components. Later we hope to expand the functionality more, from today’s …
function getsrc(fromoh) {
var forvpre='Currently this content points at ... ' + String.fromCharCode(10);
var forvsuf=String.fromCharCode(10) + 'Enter an alternative content URL (can be clipart style data URI you see often using Google Image (Copy Image Address via right click) Searches) ... or ... ' + String.fromCharCode(10) + String.fromCharCode(10) + '1[:URL] for trees, 2[:URL] for plane, 3[:URL] for gymnast, 4[:URL] for clouds, 5[:emoji(s)] for ground, E for email, S for SMS';
if (fromoh.indexOf(' src="//') != -1) {
return forvpre + document.URL.split('//')[0] + fromoh.split(' src="')[1].split('"')[0] + forvsuf;
} else if (fromoh.indexOf(" src='//") != -1) {
return forvpre + document.URL.split('//')[0] + fromoh.split(" src='")[1].split("'")[0] + forvsuf;
} else if (fromoh.indexOf(" src=//") != -1) {
return forvpre + document.URL.split('//')[0] + fromoh.split(" src=")[1].split(" ")[0].split(">")[0] + forvsuf;
} else if (fromoh.indexOf(' src="') != -1) {
return forvpre + fromoh.split(' src="')[1].split('"')[0] + forvsuf;
} else if (fromoh.indexOf(" src='") != -1) {
return forvpre + fromoh.split(" src='")[1].split("'")[0] + forvsuf;
} else if (fromoh.indexOf(" src=") != -1) {
return forvpre + fromoh.split(" src=")[1].split(" ")[0].split(">")[0] + forvsuf;
}
return fromoh;
}
function yourprompt(ino, intlis) {
var ei=-1, si=-1;
isac=true;
var opsd=prompt(getsrc(ino.outerHTML), '');
if (opsd == null) { isac=false; return false; }
if (opsd.trim() != '') {
switch (opsd.substring(0,1).toLowerCase().replace('+','s')) {
case '1': // trees
if ((opsd + ' ').substring(0,2) == '1:') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + (opsd + ' ').substring(2) + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
} else {
opsd=prompt('Enter your (perhaps clipart via Google image search) data URI or URL suiting where trees are.', '');
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
}
break;
case '2': // plane
if ((opsd + ' ').substring(0,2) == '2:') {
planealt='&planealt=' + encodeURIComponent(opsd);
document.getElementById('myif').style.backgroundImage='url(' + ((opsd + ' ').substring(2)).replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
} else {
opsd=prompt('Enter your (perhaps clipart via Google image search) data URI or URL suiting where plane is.', '');
if (opsd != null) {
if (opsd.trim() != '') {
planealt='&planealt=' + encodeURIComponent(opsd);
document.getElementById('myif').style.backgroundImage='url(' + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
}
}
}
break;
case '3': // gymnast
if ((opsd + ' ').substring(0,2) == '3:') {
gymnastalt='&gymnastalt=' + encodeURIComponent(opsd);
document.getElementById('mytwoif').style.backgroundImage='url(' + ((opsd + ' ').substring(2)).replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
} else {
opsd=prompt('Enter your (perhaps clipart via Google image search) data URI or URL suiting where gymnast is.', '');
if (opsd != null) {
if (opsd.trim() != '') {
gymnastalt='&gymnastalt=' + encodeURIComponent(opsd);
document.getElementById('mytwoif').style.backgroundImage='url(' + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
}
}
}
break;
case '4': // clouds
if ((opsd + ' ').substring(0,2) == '4:') {
cloudsalt='&cloudsalt=' + encodeURIComponent(opsd);
document.body.style.backgroundImage='url(' + ((opsd + ' ').substring(2)).replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
} else {
opsd=prompt('Enter your (perhaps via Google image search) data URI or URL suiting where cloud background image is.', '');
if (opsd != null) {
if (opsd.trim() != '') {
cloudsalt='&cloudsalt=' + encodeURIComponent(opsd);
document.body.style.backgroundImage='url(' + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + ')';
}
}
}
break;
The mix-blend-mode:multiply; discoveries (along with those naive previous usage without realizing it’s implications) we made creating Periodic Table Image Map Primer Tutorial recently has opened up new “vistas of possibility” (VOP, of course) for us, and has inspired us to give “just Javascript and CSS and HTML animated games” (aided in large part by clipart free content components) another go …
… with a “widget feel” now realizable, for us, knowing that white backgrounded HTML iframe content no longer has to hold us back piecing together animations (in an “OOP feeling” way) consisting of …
base webpage CSS and HTML and Javascript (DOM, also helping out the control of) …
HTML iframe components (and in our case the image content is it’s background image with background-size:contain; and background-repeat:no-repeat; along with a specific iframe width and height) for any one “noun” (or class of object) in your game storyboard … if you will … if you will … if you will … and …
HTML img components in a similar vein … but today’s trees did not need mix-blend-mode:multiply; because the originator made the background transparent (ie. another option with all this “animated pieces thinking”)
Animation(s) can be CSS @keyframe transitions (though not yet with animation above) or Javascript DOM logic via setTimeout (or setInterval) timers or animated GIF/webp content or, we daresay, many other approaches.
We’re going to tabularize below “how we got to the result above” below …
We started with a “first draft” … getting plane image animated with a rudimentary green border-bottom representing the ground …
… then to“second draft” … adding animated GIF cloud background to go with edited because mix-blend-mode:multiply will not mask out the non heterogenous bluish clouds in the image …
Thanks to Image by brgfx on Freepik and https://i.makeagif.com/media/8-11-2023/Xu_roP.gif and https://procul.org/images/2025/Animated-Clouds-Gif/ and and https://au.pinterest.com/pin/587930926347995281/ and https://giphy.com/explore/trees-swaying-stickers
… then to“sixth draft” … added animated GIF gymnast background and thereby proving that overlapping “iframe widgets” (helped out by mix-blend-mode:multiply presumably) was possible, and important …
… then to“seventh draft” … added animated (and transparently backgrounded) webp swaying trees image along with tweaked now animated GIF to animate the plane itself a little, in place, separate to the Javascript DOM based animation moving across the screen … for today’s final draft …
Stop Press
In tomorrow’s installment we allow for user defined content, and sharing, as per …
If this was interesting you may be interested in 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.