Walking Trip …

Walking Trip

Walking Trip

Offenbach's Suite ... Warts 'n All

Offenbach's Suite ... Warts 'n All

 📅  

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

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

Shower Songs Temporary YouTube Playlist Tutorial

Shower Songs Temporary YouTube Playlist Tutorial

Shower Songs Temporary YouTube Playlist Tutorial

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?!

Now where were we? Oh yes … we read something from Can a youtube playlist be created via a web browser add bar url?, thanks, we think can add …

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.

… where those last two’s blurb now goes

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.

Once in a YouTube playlist, you can loop (through the playlist again) and/or shuffle (the playlist) with that video and audio play.

Why PtR4cWb4HNg? 💬🦆 Come On!


Previous relevant Shower Songs Playlist Subset Revisit Tutorial is shown below.

Shower Songs Playlist Subset Revisit Tutorial

Shower Songs Playlist Subset Revisit Tutorial

The recent Javascript Console Warning Conditionals Tutorial‘s crabwise response to YouTube API iOS Shower Song Subset Looping Tutorial‘s functionality helped us come to the conclusion that we would open a new window for these “Playlist Subsets” of our inhouse Shower Songs web application.

With this in mind we allowed for incoming URLs with playlists less than 7 in length at the document.body onload Javascript as partly shown below …


function inlistcheck() {
var kok=0, nomore=false;
var inlistis=location.search.split('thelist=')[1] ? decodeURIComponent(location.search.split('thelist=')[1].split('&')[0]) : "";
var intlistis=(document.URL + ('#' + location.hash)).split('thetlist=')[1] ? decodeURIComponent((document.URL + ('#' + location.hash)).split('thetlist=')[1].split('#')[0]) : "";
//alert(intlistis);
var inlistisa=inlistis.split(',');
var intlistisa=intlistis.split('|');
if (eval('' + inlistisa.length) > 0) {
if (eval('' + intlistisa.length) >= 2 && eval('' + inlistisa.length) >= 2 && eval('' + intlistisa.length) <= 6 && eval('' + inlistisa.length) <= 6) {
if (eval('' + intlistisa.length) == 2) {
inlistisa.push(inlistisa[0]);
intlistisa.push(intlistisa[0]);
inlistisa.push(inlistisa[1]);
intlistisa.push(intlistisa[1]);
inlistisa.push(inlistisa[0]);
intlistisa.push(intlistisa[0]);
inlistisa.push(inlistisa[1]);
intlistisa.push(intlistisa[1]);
inlistisa.push(('cGdz3GNhEQ4').replace('cGdz3GNhEQ4','3wxyN3z9PL4'));
intlistisa.push(('Luna and Nala in the Park').replace('Luna and Nala in the Park','Nothing`s Gonna Stop Us Now-Starship-1987'));
} else if (eval('' + intlistisa.length) == 3) {
inlistisa.push(inlistisa[0]);
intlistisa.push(intlistisa[0]);
inlistisa.push(inlistisa[1]);
intlistisa.push(intlistisa[1]);
inlistisa.push(inlistisa[2]);
intlistisa.push(intlistisa[2]);
inlistisa.push(('cGdz3GNhEQ4').replace('cGdz3GNhEQ4','3wxyN3z9PL4'));
intlistisa.push(('Luna and Nala in the Park').replace('Luna and Nala in the Park','Nothing`s Gonna Stop Us Now-Starship-1987'));
} else {
while (eval('' + intlistisa.length) < 7) {
inlistisa.push(('cGdz3GNhEQ4').replace('cGdz3GNhEQ4','3wxyN3z9PL4'));
intlistisa.push(('Luna and Nala in the Park').replace('Luna and Nala in the Park','Nothing`s Gonna Stop Us Now-Starship-1987'));
}
}
} else if (eval('' + inlistisa.length) >= 2 && eval('' + inlistisa.length) <= 6) {
if (eval('' + inlistisa.length) == 2) {
inlistisa.push(inlistisa[0]);
inlistisa.push(inlistisa[1]);
inlistisa.push(inlistisa[0]);
inlistisa.push(inlistisa[1]);
inlistisa.push(('cGdz3GNhEQ4').replace('cGdz3GNhEQ4','3wxyN3z9PL4'));
} else if (eval('' + inlistisa.length) == 3) {
inlistisa.push(inlistisa[0]);
inlistisa.push(inlistisa[1]);
inlistisa.push(inlistisa[2]);
inlistisa.push(('cGdz3GNhEQ4').replace('cGdz3GNhEQ4','3wxyN3z9PL4'));
} else {
while (eval('' + inlistisa.length) < 7) {
inlistisa.push(('cGdz3GNhEQ4').replace('cGdz3GNhEQ4','3wxyN3z9PL4'));
}
}
} else if (eval('' + intlistisa.length) == 1 && eval('' + inlistisa.length) == 1) {
if (intlistisa[0].trim() != '' && eval('' + encodeURIComponent(inlistisa[0]).length) == 11 && eval('' + (inlistisa[0] + ',').replace(/[AEIMQUYcgkosw048]\,$/g,'z').length) == 11) {
inlistisa.push(inlistisa[0]);
intlistisa.push(intlistisa[0]);
inlistisa.push(inlistisa[0]);
intlistisa.push(intlistisa[0]);
inlistisa.push(inlistisa[0]);
intlistisa.push(intlistisa[0]);
inlistisa.push(inlistisa[0]);
intlistisa.push(intlistisa[0]);
inlistisa.push(inlistisa[0]);
intlistisa.push(intlistisa[0]);
inlistisa.push(inlistisa[0]);
intlistisa.push(intlistisa[0]);
}
}

if (eval('' + intlistisa.length) >= 7 && eval('' + inlistisa.length) >= 7) {
// rest of if follows
}
// rest of function inlistcheck() follows
}

… in a changed shower_songs.html external Javascript powered Shower Songs web application.

Did You Know?

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”.


Previous relevant Javascript Console Warning Conditionals Tutorial is shown below.

Javascript Console Warning Conditionals Tutorial

Javascript Console Warning Conditionals Tutorial

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

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

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

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


console.warn([some messaging text]);

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

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


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

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


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

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


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

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


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

YouTube API iOS Shower Song Subset Looping Tutorial

YouTube API iOS Shower Song Subset Looping Tutorial

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

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

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

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

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

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


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

YouTube API iOS Shortcuts Shower Song Tutorial

YouTube API iOS Shortcuts Shower Song Tutorial

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

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

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

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

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

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

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

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

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

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


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

YouTube API Command Line Shower Song Names Tutorial

YouTube API Command Line Shower Song Names Tutorial

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

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

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

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

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


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

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


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


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


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

return thisplist;
}

… which mapped to URL …


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

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

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

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

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

… as our means to a solution.


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

YouTube API Command Line Shower Songs Tutorial

YouTube API Command Line Shower Songs Tutorial

Today, we’re combining the concepts behind …

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

    … command line “command verb” …

    play

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

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

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

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

… involving changed

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

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

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

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

    set passed=
    set rest=
    set seven=0

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

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


    ) else (
    set ans="%1"

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

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


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

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

… a command line …


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

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


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

YouTube API Caller Radio Play Doctype Meta Tutorial

YouTube API Caller Radio Play Doctype Meta Tutorial

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

  • doctype HTML tagdeclaration …

    <!DOCTYPE html>

    … and …
  • meta HTML display tagcharset attribute …

    <meta charset="UTF-8">

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

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

  • doctype HTML tagdeclaration

    All HTML documents must start with a declaration.

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

    … and …

  • meta HTML display tagcharset attribute

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

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

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


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

YouTube API Caller Radio Play Playlist Windows Local System Tutorial

YouTube API Caller Radio Play Playlist Windows Local System Tutorial

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

play

… to mean something on the …

Windows

… “cmd” command accessible …

command line

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


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

set passed=
set rest=

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

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


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

YouTube API Caller Radio Play Playlist Local System Tutorial

YouTube API Caller Radio Play Playlist Local System Tutorial

The ..

command line

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

  • processes
  • batch driven tasks
  • task simplifications

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


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

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

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

play

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


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

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


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

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

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


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

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


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

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


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

… is most likely to reply something like …

zsh: no such command

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

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

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

    ~/.bashrc

    … via (in our case) …

    vi ~/.bashrc
  3. then …

    source ~/.bashrc

    … needs to be included into the login procedure of …

    ~/.profile

    …via (in our case) …

    vi ~/.profile
  4. to make …

    play

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

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

    … mean something … and anywhere

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


    open

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

    Sorry … we got a bit hot and bothered there!

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

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


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

    YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Repeats Tutorial

    Burp …

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

    And sorry to repeat myself, like, again.

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

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

    … without the …

    Burp …

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

    That’s kind of silly.

    For these few reasons …

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

      This video requires payment to watch YouTube

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

    • giving non-top search items a go

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

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

    … as well as the simpler …

    Born to Run*4

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

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


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

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


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

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

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

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

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

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

    • adding onto the address bar …

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

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

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

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

      [commaSeparatedList_decodeURIComponent_ized]

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

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

    Stop Press

    On reflection, as well as …

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


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

    YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial

    YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial

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

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

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


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

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

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

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

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

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

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

    And so, today …

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

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

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

      This video requires payment to watch YouTube

      )

    Codewise, this involved …

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


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


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


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


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


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


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


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


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


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


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


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


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


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

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

Editable Calendar Intl Tutorial

Editable Calendar Intl Tutorial

Editable Calendar Intl Tutorial

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 …
  • JavaScript Intl Object Reference ideas

… that can help with language translations, and we make available to the user via a toggling “-” (to “+”) HTML element modus operandi.

Especially, as we need more work improving the Google Translate interfacing, trying this changed third draft Editable Calendar you can try below, is definitely worth considering.


Previous relevant Editable Calendar Google Translate Tutorial is shown below.

Editable Calendar Google Translate Tutorial

Editable Calendar Google Translate Tutorial

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 …


Google Translate

… 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 changed second draft Editable 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.


Previous relevant Editable Calendar Primer Tutorial is shown below.

Editable Calendar Primer Tutorial

Editable Calendar Primer Tutorial

Today’s new Editable Calendar themed inhouse web application combines …

Today’s steps of progress in this project …

  1. establish the current month and year’s “month showing” calendar into a webpage … and …
  2. within that calendar date cell we place a span element with contenteditable=true … allowing …
  3. user to add content into the calendar

… in this first draft “proof of new to us concept” Editable Calendar you can try below. We hope you tune in tomorrow for more progress!


Previous relevant Event Calendar Collaboration Textarea Highlight Linking Tutorial is shown below.

Event Calendar Collaboration Textarea Highlight Linking Tutorial

Event Calendar Collaboration Textarea Highlight Linking Tutorial

For the first time we can remember, with our Events in Month web application of yesterday’s Event Calendar Collaboration Remembering Recipient Tutorial

  • 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 …


var thesel='', showsel=false, lastsel='';

function showthesel() {
var uwords=[], iuw=1, ils=0;
if (showsel) {
showsel=false;
if (lastsel != thesel && thesel.toLowerCase().replace('https:', 'http:').indexOf('http://') >= 0) {
lastsel=thesel;
thesel='';
}
if (lastsel != '' && thesel == '') {
uwords=lastsel.toLowerCase().split('http');
ils=eval(4 + eval('' + uwords[0].length));
for (iuw=1; iuw<uwords.length; iuw++) {
window.open('//' + lastsel.substring(ils).split('//')[1].split(' ')[0].split(String.fromCharCode(10))[0].split(String.fromCharCode(13))[0], '_blank', 'top=' + eval(10 * iuw + 50) + ',left=' + eval(10 * iuw + 50) + ',width=600,height=600');
ils+=eval(4 + eval('' + uwords[iuw].length));
}
}
}
}

function handleSelection() { // thanks to https://stackoverflow.com/questions/46651479/reacting-to-selection-changes-in-an-html-textarea
const activeElement = document.activeElement;

// Make sure this is your textarea
if (activeElement && activeElement.outerHTML.indexOf('<textarea') == 0) {
const range = {
start: activeElement.selectionStart,
end: activeElement.selectionEnd
};
// Do something with your range
if (eval('' + range.end) > eval('' + range.start)) {
thesel=(activeElement.value.substring(range.start).substring(0, eval(eval('' + range.end) - eval('' + range.start) )));
if (!showsel && thesel.toLowerCase().replace('https:', 'http:').indexOf('http://') >= 0) {
showsel=true;
setTimeout(showthesel, 5000);
}
}
}
}

document.addEventListener('selectionchange', handleSelection);

Also, today, we have a few CSS tweaks in the changed events_in_month.htm parent of the Events in Month web application. Feel free to try it for yourself.

Stop Press

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?!


Previous relevant Event Calendar Collaboration Remembering Recipient Tutorial is shown below.

Event Calendar Collaboration Remembering Recipient Tutorial

Event Calendar Collaboration Remembering Recipient Tutorial

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 changed events_in_month.htm parent of the Events in Month web application. Never a dull moment in web application I.T. we’d say!


Previous relevant Event Calendar Collaboration Tutorial is shown below.

Event Calendar Collaboration Tutorial

Event Calendar Collaboration Tutorial

The Event Calendar web application project, of Event Calendar PHP Bookmark Tutorial, from last year is worth a revisit, the reason being …

  • 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 …

  1. Month
  2. 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 &nbsp;&nbsp;<button style=display:none; title='Share via Email' id=semail onclick="doemail('');">&#128231;</button> <button style=display:none; title='Share via SMS' id=ssms onclick=dosms();>&#128223;</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) …

var bigbih=('' + ('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'')).split('bih=')[1] ? (decodeURIComponent(('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'')).split('bih=')[1].split('&')[0]) : '';
if (bigbih != '' && bigbih.indexOf('xae' + 'mail') == -1) {
bigbih+='<a target=_blank id=xae' + 'mail style=display:none; href="mailto:"></a>';
}
if (bigbih != '' && bigbih.indexOf('xas' + 'ms') == -1) {
bigbih+='<a target=_blank id=xas' + 'ms style=display:none; href="sms:"></a>';
}
var viatext='', smallbih='', wes=null, sparewes=null;
On or around document.body onload event we can analyze any such location.hash hashtagging data …

if (bigbih.indexOf('</he' + 'ad>') != -1 || bigbih.indexOf('<b' + 'o' + 'dy') != -1 || bigbih.indexOf('<h' + '1') == 0) {
//bigbih=bigbih.replace('" id="eventcalendar"', 'margin-top:50px;" id="eventcalendar"');
viatext=' (via contact at ' + ('' + new Date()) + ')';
if (bigbih.indexOf('<h' + '1') == 0) {
smallbih=bigbih;
} else {
smallbih=bigbih.split('<b' + 'o' + '')[1].split('</b' + 'o' + 'd' + 'y>')[0].replace(bigbih.split('<b' + 'o' + '')[1].split('</b' + 'o' + 'd' + 'y>')[0].split('>')[0] + '>', '');
}
wes=windowopen('./events_in_month.htm','_blank','top=40,left=40,width=800,height=800');
//alert(bigbih);
if (wes) {
setTimeout(function(){
wes.document.write(bigbih);
}, 3000);
//document.body.innerHTML=bigbih;
setTimeout(function(){
wes.document.getElementById('semail').style.display='inline-block';
wes.document.getElementById('ssms').style.display='inline-block';
wes.document.getElementsByTagName('h1')[0].style.display='none';
wes.document.getElementsByTagName('h3')[0].style.display='none';
//wes.setviatext(viatext);
//wes.setphpthere(' ');
//wes.togglewords();
}, 5000);
}
}
A window.open wrapper windowopen Javascript function …

function windowopen(poneis, ptwois, pthreeis) {
document.getElementById('divas').innerHTML='<iframe name=ovif id=ovif style="position:absolute;top:140px;left:0px;width:100%;height:100%;z-index:99;" src="' + poneis + '" onload=wopencheck(this);></iframe>';
//document.getElementsByTagName('h1')[0].style.opacity='0.0';
//document.getElementsByTagName('h3')[0].style.opacity='0.0';
sparewes=window.open(poneis.split('.htm')[0] + '.php', 'ovif');
//sparewes=window.open(poneis, 'ovif');
sparewes.document.write(bigbih);
setTimeout(function(){
sparewes.document.getElementById('semail').style.display='inline-block';
sparewes.document.getElementById('ssms').style.display='inline-block';
var sdem=sparewes.document.getElementById('semail').outerHTML;
var sdss=sparewes.document.getElementById('ssms').outerHTML;
sparewes.document.getElementsByTagName('h1')[0].innerHTML=sparewes.document.getElementsByTagName('h1')[0].innerHTML.replace(sdss,'');
sparewes.document.getElementsByTagName('h1')[0].innerHTML=sparewes.document.getElementsByTagName('h1')[0].innerHTML.replace(sdem,'');
sparewes.document.getElementsByTagName('h1')[0].style.display='none';
sparewes.document.getElementsByTagName('h3')[0].style.display='none';
sparewes.document.getElementById('dmore').innerHTML+=(' ' + sdem.replace('doeJUNKmail(', 'parent.doe' + 'mail(') + ' ' + sdss.replace('dosJUNKms(', 'parent.dos' + 'ms(') + '<br>');
//sparewes.setviatext(viatext);
//sparewes.setphpthere(' ');
//sparewes.togglewords();
}, 5000);
return null;
}
Is augmented by other new Javascript functions …

function hfanalyze() {
var fio=document.getElementById('ecform');
if (forceit) { forceit=false; return true; }
var delm='?';
var fioih=fio.innerHTML;
var fions=fioih.split(' name="');
var testurl=documentURL.split('?')[0].split('#')[0];
//alert(fions.length);
for (var ijk=1; ijk<fions.length; ijk++) {
testurl+=delm + fions[ijk].split('"')[0] + '=' + encodeURIComponent(document.getElementById(fions[ijk].split('"')[0]).value.replace(/\?\>/g,'? >'));
delm='&';
}
//alert(testurl.length);
//if (eval('' + testurl.length) < 750) { return true; }
//if (lastbut.value.indexOf('New') == 0 || 11 == 11) {
if (22 == 22) {
//wo=window.open('', '_blank', 'top=50,left=50,height=600,width=600');
//wo.document.write('<html><head>' + hih.replace("=docum" + "ent.URL", "='" + testurl.replace(/\'/g, "' + String.fromCharCode(39) + '") + "'") + boh + '</html>');
return ('<html><head>' + hih.replace("=docum" + "ent.URL", "='" + testurl.replace(/\'/g, "' + String.fromCharCode(39) + '") + "'") + boh + '</html>');
} else if (phpthere != '') {
if (1 == 1) {
postit(fio, false, testurl);
} else {
fio.target='phpif';
fio.method='POST';
fio.action='./events_in_month.php';
if (!document.getElementById('dmore')) {
document.getElementById('ddmore').innerHTML='<input type=hidden id=caltitle name=caltitle value="' + document.getElementById('myoldsel').options[document.getElementById('myoldsel').selectedIndex].innerText + '"></input><input type=hidden id=phpthere name=phpthere value="' + phpthere + '"></input><input type=hidden id=bigurl name=bigurl value="' + testurl + '"></input>';
} else {
document.getElementById('dmore').innerHTML='<input type=hidden id=phpthere name=phpthere value="' + phpthere + '"></input><input type=hidden id=bigurl name=bigurl value="' + testurl + '"></input>';
}
}
return 'true';
}
return 'false';
}

function doemail(inidea) {
var azx=document.getElementById('xae' + 'mail');
if (!azx) { azx=document.createElement("a"); }
//if (1 == 1) {
//document.getElementById('divas').appendChild(azx);
//} else {
document.body.appendChild(azx);
//}
azx.style = "display: none";
azx.id = 'xaem' + 'ail';
azx.href = 'mailto:' + inidea + '?subject=' + encodeURIComponent(document.getElementsByTagName('h2')[0].innerHTML.split('&')[0].split('<')[0].replace(/\`/g,'').replace(/^Events\ in\ /g, 'Events in Month ').substring(0)) + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(hfanalyze())); //encodeURIComponent(document.URL.split('#')[0] + '<h2' + document.body.innerHTML.split('<h2')[1]));
azx.click();
return '';
}

function dosms() {
//alert('' + eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(hfanalyze()))).length));
if (eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(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.', snum)).replace(/^null/g,'');
} else {
snum=('' + prompt('Please enter SMS number to send to.', snum)).replace(/^null/g,'');
}
if (snum.indexOf('@') != -1) {
return doemail(snum);
} else if (snum.trim() != '') {
alert('Snum=' + snum + '?');
var azx=document.getElementById('xas' + 'ms');
if (azx == null) { azx=document.createElement("a"); }
//if (1 == 1) {
// document.getElementById('divas').appendChild(azx);
//} else {
document.body.appendChild(azx);
// }
azx.id = 'xas' + 'ms';
azx.style = "display: none";
azx.href = 'sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(hfanalyze()));
azx.click();
}
return '';
}

function wopencheck(iois) {
var aconto = null;
aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
aconto.body.innerHTML=smallbih;
aconto.setviatext(viatext);
}
}
}

function setviatext(towhat) {
viatext=towhat;
}

… to help bed down this new sharing and collaboration functionality in a changed events_in_month.htm parent of the Events in Month web application.


Previous relevant Event Calendar PHP Bookmark Tutorial is shown below.

Event Calendar PHP Bookmark Tutorial

Event Calendar PHP Bookmark Tutorial

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 …


https://www.rjmprogramming.com.au/HTMLCSS/events_in_month.php?exactlabel=August__2023_00000__1

… 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 …


<style>
#eventcalendar {
background-color: #fcfcfc;
}

td {
padding-top: 2px;
padding-left: 2px;
padding-right: 2px;
padding-bottom: 12px;
}

.dayb {
color: white;
background-color: red;
padding: 5 5 5 5;
border-radius: 80px;
margin-bottom: 15px;
}

.dow {
color: purple;
font-style: bold;
}

.selday {
margin-left: 8px;
background-color: rgba(255,0,0,0.7);
display: inline-block;
width: 50px;
border-color: transparent;
text-overflow: ellipsis;
}

.tablurb {
background: linear-gradient(to right, white, lightpink, pink);
}

input[type="submit"] {
margin-bottom: 3px;
border-radius: 180px;
}

input[type="number"] {
margin-left: 3px;
margin-right: 3px;
border-radius: 180px;
background-color: #f3f3f3;
padding: 2 2 2 2;
}

#smonth {
margin-left: 3px;
margin-right: 3px;
border-radius: 180px;
background-color: #f9f9f9;
padding: 2 2 2 2;
}

.boldtitle {
background-color: rgba(0, 211, 107, 0.2);
}

.boldtitle + .tablurb {
margin-top: 8px;
}


.selhistory {
border-radius: 180px;
background-color: lightpink;
padding: 2 2 2 2;
}
</style>

… and we thank this webpage for the heads up regarding how to calculate week numbers within a year data item displays now available in …


Previous relevant Event Calendar PHP Tutorial is shown below.

Event Calendar PHP Tutorial

Event Calendar PHP Tutorial

Let’s face it. Serverside PHP is just great! It opens up so many opportunities regarding data in your web applications.

As such, onto yesterday’s Event Calendar New Window Tutorial logic we now have a …


Record to Remember

… 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

$hcont=file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'events_in_month.htm');
$cont=file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'events_in_month.php');
$ipad=server_remote_addr();
$ipadless=$ipad;
$js='';

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

$itdone=false;
if (isset($_GET['init'])) {
if (strpos($cont, '_' . $ipad . '=') !== false) {
$things=explode('_' . $ipad . '=', $cont);
for ($it=1; $it<sizeof($things); $it++) {
if ($it == 1 && !$itdone) {
$itdone=true;
$js.="\n parent.document.getElementById('myoldsel').style.display='inline-block'; \n";
}
$js.="\n parent.document.getElementById('myoldsel').innerHTML+='<option value=\"" . explode("\n", $things[$it])[0] . "\">" . explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[0] . ', ' . explode('_', explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[1])[0] . "</option>'; \n";
}
}
if (strpos($cont, '0' . $ipadless . '=') !== false) {
$things=explode('0' . $ipadless . '=', $cont);
for ($it=1; $it<sizeof($things); $it++) {
if ($it == 1 && !$itdone) {
$itdone=true;
$js.="\n parent.document.getElementById('myoldsel').style.display='inline-block'; \n";
}
$js.="\n parent.document.getElementById('myoldsel').innerHTML+='<option value=\"" . explode("\n", $things[$it])[0] . "\">" . explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[0] . ', ' . explode('_', explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[1])[0] . "</option>'; \n";
}
}
echo "<html><head><script type='text/javascript'> " . $js . " </script></head><body><p>" . $ipad . "</p></body></html>";
} else if (isset($_POST['phpthere']) && isset($_POST['bigurl']) && isset($_POST['caltitle'])) {
//file_put_contents('xz.xz', 'l');
if (strpos($cont, '// ' . str_replace(' ','_',str_replace(',','_',str_replace('+',' ',urldecode($_POST['caltitle'])))) . '_' . str_replace('+',' ',urldecode($_POST['phpthere'])) . '=' . $_POST['bigurl'] . "\n") === false) {
//file_put_contents('xz.xzz', 'l');
$cont=str_replace('?' . '>', '// ' . str_replace(' ','_',str_replace(',','_',str_replace('+',' ',urldecode($_POST['caltitle'])))) . '_' . str_replace('+',' ',urldecode($_POST['phpthere'])) . '=' . $_POST['bigurl'] . "\n" . '?' . '>', $cont);
file_put_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'events_in_month.php', $cont);
}
if (strpos($cont, '_' . $ipad . '=') !== false) {
$things=explode('_' . $ipad . '=', $cont);
for ($it=1; $it<sizeof($things); $it++) {
if ($it == 1 && !$itdone) {
$itdone=true;
$js.="\n parent.document.getElementById('myoldsel').style.display='inline-block'; \n";
}
$js.="\n parent.document.getElementById('myoldsel').innerHTML+='<option value=\"" . explode("\n", $things[$it])[0] . "\">" . explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[0] . ', ' . explode('_', explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[1])[0] . "</option>'; \n";
}
}
if (strpos($cont, '0' . $ipadless . '=') !== false) {
$things=explode('0' . $ipadless . '=', $cont);
for ($it=1; $it<sizeof($things); $it++) {
if ($it == 1 && !$itdone) {
$itdone=true;
$js.="\n parent.document.getElementById('myoldsel').style.display='inline-block'; \n";
}
$js.="\n parent.document.getElementById('myoldsel').innerHTML+='<option value=\"" . explode("\n", $things[$it])[0] . "\">" . explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[0] . ', ' . explode('_', explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[1])[0] . "</option>'; \n";
}
}
//file_put_contents('xz.xzzz', "<html><head><script type='text/javascript'> " . $js . "\n parent.checkif(parent.document.getElementById('phpif')); \n" . " </script></head><body><p>" . str_replace(' ','%20',str_replace('+',' ',urldecode($_POST['bigurl']))) . "</p></body></html>");
echo "<html><head><script type='text/javascript'> " . $js . "\n parent.checkif(parent.document.getElementById('phpif')); \n" . " </script></head><body><p>" . str_replace(' ','%20',str_replace('+',' ',urldecode($_POST['bigurl']))) . "</p></body></html>";
} else {
echo $hcont;
}
exit;

//
//
// January__1970_00000__1=http://localhost:8888/events_in_month.htm?caltitle=January%2C%201970&i01.00=&ta01.00=kgjfjhf%20jhgfjhf%20jhkgkjhg%20jhgkjhg%20jkghhg%20jkhgkjhg%20kjhgkjhg&i02.00=&ta02.00=kjhgkjh%20kjhgkjhg%20jkhgkjhg%20kjhgkjhg%20kjhgkjhg%20jhkgkjhg%20kjgkjhg&i03.00=&ta03.00=kjhgkjhg%20kjhgkjhg%20kjhgkjhg%20kjhgkjhg%20kjhgkjhg%20jhkgkjhg&i04.00=&ta04.00=&i05.00=&ta05.00=&i06.00=&ta06.00=&i07.00=&ta07.00=&i08.00=&ta08.00=&i09.00=&ta09.00=&i10.00=&ta10.00=&i11.00=&ta11.00=&i12.00=&ta12.00=&i13.00=&ta13.00=&i14.00=&ta14.00=&i15.00=&ta15.00=&i16.00=&ta16.00=&i17.00=&ta17.00=&i18.00=&ta18.00=&i19.00=&ta19.00=&i20.00=&ta20.00=&i21.00=&ta21.00=&i22.00=&ta22.00=&i23.00=&ta23.00=&i24.00=&ta24.00=&i25.00=&ta25.00=&i26.00=&ta26.00=&i27.00=&ta27.00=&i28.00=&ta28.00=&i29.00=&ta29.00=&i30.00=&ta30.00=&i31.00=&ta31.00=
?>

Yes, the parent needed to change for our events_in_month.htm parent of Events in Month web application role.


Previous relevant Event Calendar New Window Tutorial is shown below.

Event Calendar New Window Tutorial

Event Calendar New Window Tutorial

Onto yesterday’s Event Calendar Remembered Tutorial‘s “Mystery Dilemma”

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 …

  1. bring up Context Menu with a right click or two finger gesture within the popup window webpage content …
  2. pick Inspect option …
  3. be in Elements tab of your Web Inspector … and …
  4. highlight top <html> tag …
  5. Context Menu with a right click or two finger gesture …
  6. pick Copy -> Copy outerHTML … so that …
  7. your Event Calendar for your Events in Month choice is in a text buffer … ready for you to …
  8. 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>
  • dropdown element conditional styling

    <style>
    .dayb {
    color: white;
    background-color: red;
    padding: 5 5 5 5;
    }


    .dow {
    color: purple;
    font-style: bold;
    }

    .selday {
    margin-left: 8px;
    background-color: rgba(255,0,0,0.7);
    display: inline-block;
    width: 50px;
    }
    </style>



    if (thislabel.substring(0,1) == 'i') {
    if (thisval.trim() != '') {
    document.getElementById(thislabel.replace('i', 'sel')).style.color='white';
    document.getElementById(thislabel.replace('i', 'sel')).style.backgroundColor='red';

    }
    document.getElementById(thislabel.replace('i', 'opt')).innerText=thisval.replace(/\+/g, ' ').replace(/\ \ \ /g, ' + '); //.replace(/\+$/g, ' ');
    document.getElementById(thislabel).value=thisval.replace(/\+$/g, ' ');
    } else {
    document.getElementById(thislabel).value=thisval.replace(/\+/g, ' ').replace(/\ \ \ /g, ' + ');
    }
    }
  • placeholder on Blurb conditional existence

    var ourdata='';
    // ...
    if (documentURL.indexOf('?') != -1) {
    if (documentURL.indexOf('?caltitle=') != -1) { ourdata='data-'; }
    // ...
    trtemplate='<tr id=tr01.00><td style=width:22%;><span id=sone01.00 class=dow>' + dotw[adate.getDay()].toUpperCase().substring(0,3) + '</span><br><br><span id=stwo01.00 class=dayb>1<span onblur=sepit(this); contenteditable=true id=sp01.00></span><input type=hidden id=i01.00 name=i01.00 value=""></input><select data-dow=' + dotw[adate.getDay()].toUpperCase().substring(0,3) + ' class=selday onchange="selit(this);" id=sel01.00><option id=opt01.00 value=""></option><option title="All such in month (ie. weekly)" value="...">...</option><option title="And ..." value="&...">&</option><option value=Bold>Bold Title</option><option value=Clone>Clone</option></select></span></td><td class=blurb title="What is on?" id=tb01.00><span title="Event title" style="font-style:bold;color:blue;" id=bd01.00></span><textarea name=ta01.00 id=ta01.00 style="width:100%;height=100%;" ' + ourdata + 'placeholder="Blurb ..." class=tablurb></textarea></td></tr>';
    // ...
    }
    // ...
    }

… for our “second draft” events_in_month.htm Events in Month web application.


Previous relevant Event Calendar Remembered Tutorial is shown below.

Event Calendar Remembered Tutorial

Event Calendar Remembered Tutorial

We were inspired by an Event Calendar pamplette we saw the other day …

… to write a new “proof of concept” Events in Month web application, whose content can be recalled via the web browser’s Bookmark methodologies.

We liked the ideas for day of week and/or date of month grouping arrangements we included, being, the way we interpreted it …

  • just on this day in this month … default
  • on this day of the week throughout the month in question … “
  • on this day and some others in that month in question … “&” … to start with and further amendments available via contenteditable=true span element
  • “Clone” value allows for multiple separated “blurbs” for the one signature day

But, there’s an inherent weakness with the design, we’ll go into more into the future. For now, you can try it yourself below …

Stop Press

This is where we get to for a “second draft” we’ll get into, further, tomorrow …

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


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


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


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


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


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


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


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


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


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

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

Editable Calendar Google Translate Tutorial

Editable Calendar Google Translate Tutorial

Editable Calendar Google Translate Tutorial

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 …


Google Translate

… 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 changed second draft Editable 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.


Previous relevant Editable Calendar Primer Tutorial is shown below.

Editable Calendar Primer Tutorial

Editable Calendar Primer Tutorial

Today’s new Editable Calendar themed inhouse web application combines …

Today’s steps of progress in this project …

  1. establish the current month and year’s “month showing” calendar into a webpage … and …
  2. within that calendar date cell we place a span element with contenteditable=true … allowing …
  3. user to add content into the calendar

… in this first draft “proof of new to us concept” Editable Calendar you can try below. We hope you tune in tomorrow for more progress!


Previous relevant Event Calendar Collaboration Textarea Highlight Linking Tutorial is shown below.

Event Calendar Collaboration Textarea Highlight Linking Tutorial

Event Calendar Collaboration Textarea Highlight Linking Tutorial

For the first time we can remember, with our Events in Month web application of yesterday’s Event Calendar Collaboration Remembering Recipient Tutorial

  • 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 …


var thesel='', showsel=false, lastsel='';

function showthesel() {
var uwords=[], iuw=1, ils=0;
if (showsel) {
showsel=false;
if (lastsel != thesel && thesel.toLowerCase().replace('https:', 'http:').indexOf('http://') >= 0) {
lastsel=thesel;
thesel='';
}
if (lastsel != '' && thesel == '') {
uwords=lastsel.toLowerCase().split('http');
ils=eval(4 + eval('' + uwords[0].length));
for (iuw=1; iuw<uwords.length; iuw++) {
window.open('//' + lastsel.substring(ils).split('//')[1].split(' ')[0].split(String.fromCharCode(10))[0].split(String.fromCharCode(13))[0], '_blank', 'top=' + eval(10 * iuw + 50) + ',left=' + eval(10 * iuw + 50) + ',width=600,height=600');
ils+=eval(4 + eval('' + uwords[iuw].length));
}
}
}
}

function handleSelection() { // thanks to https://stackoverflow.com/questions/46651479/reacting-to-selection-changes-in-an-html-textarea
const activeElement = document.activeElement;

// Make sure this is your textarea
if (activeElement && activeElement.outerHTML.indexOf('<textarea') == 0) {
const range = {
start: activeElement.selectionStart,
end: activeElement.selectionEnd
};
// Do something with your range
if (eval('' + range.end) > eval('' + range.start)) {
thesel=(activeElement.value.substring(range.start).substring(0, eval(eval('' + range.end) - eval('' + range.start) )));
if (!showsel && thesel.toLowerCase().replace('https:', 'http:').indexOf('http://') >= 0) {
showsel=true;
setTimeout(showthesel, 5000);
}
}
}
}

document.addEventListener('selectionchange', handleSelection);

Also, today, we have a few CSS tweaks in the changed events_in_month.htm parent of the Events in Month web application. Feel free to try it for yourself.

Stop Press

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?!


Previous relevant Event Calendar Collaboration Remembering Recipient Tutorial is shown below.

Event Calendar Collaboration Remembering Recipient Tutorial

Event Calendar Collaboration Remembering Recipient Tutorial

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 changed events_in_month.htm parent of the Events in Month web application. Never a dull moment in web application I.T. we’d say!


Previous relevant Event Calendar Collaboration Tutorial is shown below.

Event Calendar Collaboration Tutorial

Event Calendar Collaboration Tutorial

The Event Calendar web application project, of Event Calendar PHP Bookmark Tutorial, from last year is worth a revisit, the reason being …

  • 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 …

  1. Month
  2. 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 &nbsp;&nbsp;<button style=display:none; title='Share via Email' id=semail onclick="doemail('');">&#128231;</button> <button style=display:none; title='Share via SMS' id=ssms onclick=dosms();>&#128223;</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) …

var bigbih=('' + ('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'')).split('bih=')[1] ? (decodeURIComponent(('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'')).split('bih=')[1].split('&')[0]) : '';
if (bigbih != '' && bigbih.indexOf('xae' + 'mail') == -1) {
bigbih+='<a target=_blank id=xae' + 'mail style=display:none; href="mailto:"></a>';
}
if (bigbih != '' && bigbih.indexOf('xas' + 'ms') == -1) {
bigbih+='<a target=_blank id=xas' + 'ms style=display:none; href="sms:"></a>';
}
var viatext='', smallbih='', wes=null, sparewes=null;
On or around document.body onload event we can analyze any such location.hash hashtagging data …

if (bigbih.indexOf('</he' + 'ad>') != -1 || bigbih.indexOf('<b' + 'o' + 'dy') != -1 || bigbih.indexOf('<h' + '1') == 0) {
//bigbih=bigbih.replace('" id="eventcalendar"', 'margin-top:50px;" id="eventcalendar"');
viatext=' (via contact at ' + ('' + new Date()) + ')';
if (bigbih.indexOf('<h' + '1') == 0) {
smallbih=bigbih;
} else {
smallbih=bigbih.split('<b' + 'o' + '')[1].split('</b' + 'o' + 'd' + 'y>')[0].replace(bigbih.split('<b' + 'o' + '')[1].split('</b' + 'o' + 'd' + 'y>')[0].split('>')[0] + '>', '');
}
wes=windowopen('./events_in_month.htm','_blank','top=40,left=40,width=800,height=800');
//alert(bigbih);
if (wes) {
setTimeout(function(){
wes.document.write(bigbih);
}, 3000);
//document.body.innerHTML=bigbih;
setTimeout(function(){
wes.document.getElementById('semail').style.display='inline-block';
wes.document.getElementById('ssms').style.display='inline-block';
wes.document.getElementsByTagName('h1')[0].style.display='none';
wes.document.getElementsByTagName('h3')[0].style.display='none';
//wes.setviatext(viatext);
//wes.setphpthere(' ');
//wes.togglewords();
}, 5000);
}
}
A window.open wrapper windowopen Javascript function …

function windowopen(poneis, ptwois, pthreeis) {
document.getElementById('divas').innerHTML='<iframe name=ovif id=ovif style="position:absolute;top:140px;left:0px;width:100%;height:100%;z-index:99;" src="' + poneis + '" onload=wopencheck(this);></iframe>';
//document.getElementsByTagName('h1')[0].style.opacity='0.0';
//document.getElementsByTagName('h3')[0].style.opacity='0.0';
sparewes=window.open(poneis.split('.htm')[0] + '.php', 'ovif');
//sparewes=window.open(poneis, 'ovif');
sparewes.document.write(bigbih);
setTimeout(function(){
sparewes.document.getElementById('semail').style.display='inline-block';
sparewes.document.getElementById('ssms').style.display='inline-block';
var sdem=sparewes.document.getElementById('semail').outerHTML;
var sdss=sparewes.document.getElementById('ssms').outerHTML;
sparewes.document.getElementsByTagName('h1')[0].innerHTML=sparewes.document.getElementsByTagName('h1')[0].innerHTML.replace(sdss,'');
sparewes.document.getElementsByTagName('h1')[0].innerHTML=sparewes.document.getElementsByTagName('h1')[0].innerHTML.replace(sdem,'');
sparewes.document.getElementsByTagName('h1')[0].style.display='none';
sparewes.document.getElementsByTagName('h3')[0].style.display='none';
sparewes.document.getElementById('dmore').innerHTML+=(' ' + sdem.replace('doeJUNKmail(', 'parent.doe' + 'mail(') + ' ' + sdss.replace('dosJUNKms(', 'parent.dos' + 'ms(') + '<br>');
//sparewes.setviatext(viatext);
//sparewes.setphpthere(' ');
//sparewes.togglewords();
}, 5000);
return null;
}
Is augmented by other new Javascript functions …

function hfanalyze() {
var fio=document.getElementById('ecform');
if (forceit) { forceit=false; return true; }
var delm='?';
var fioih=fio.innerHTML;
var fions=fioih.split(' name="');
var testurl=documentURL.split('?')[0].split('#')[0];
//alert(fions.length);
for (var ijk=1; ijk<fions.length; ijk++) {
testurl+=delm + fions[ijk].split('"')[0] + '=' + encodeURIComponent(document.getElementById(fions[ijk].split('"')[0]).value.replace(/\?\>/g,'? >'));
delm='&';
}
//alert(testurl.length);
//if (eval('' + testurl.length) < 750) { return true; }
//if (lastbut.value.indexOf('New') == 0 || 11 == 11) {
if (22 == 22) {
//wo=window.open('', '_blank', 'top=50,left=50,height=600,width=600');
//wo.document.write('<html><head>' + hih.replace("=docum" + "ent.URL", "='" + testurl.replace(/\'/g, "' + String.fromCharCode(39) + '") + "'") + boh + '</html>');
return ('<html><head>' + hih.replace("=docum" + "ent.URL", "='" + testurl.replace(/\'/g, "' + String.fromCharCode(39) + '") + "'") + boh + '</html>');
} else if (phpthere != '') {
if (1 == 1) {
postit(fio, false, testurl);
} else {
fio.target='phpif';
fio.method='POST';
fio.action='./events_in_month.php';
if (!document.getElementById('dmore')) {
document.getElementById('ddmore').innerHTML='<input type=hidden id=caltitle name=caltitle value="' + document.getElementById('myoldsel').options[document.getElementById('myoldsel').selectedIndex].innerText + '"></input><input type=hidden id=phpthere name=phpthere value="' + phpthere + '"></input><input type=hidden id=bigurl name=bigurl value="' + testurl + '"></input>';
} else {
document.getElementById('dmore').innerHTML='<input type=hidden id=phpthere name=phpthere value="' + phpthere + '"></input><input type=hidden id=bigurl name=bigurl value="' + testurl + '"></input>';
}
}
return 'true';
}
return 'false';
}

function doemail(inidea) {
var azx=document.getElementById('xae' + 'mail');
if (!azx) { azx=document.createElement("a"); }
//if (1 == 1) {
//document.getElementById('divas').appendChild(azx);
//} else {
document.body.appendChild(azx);
//}
azx.style = "display: none";
azx.id = 'xaem' + 'ail';
azx.href = 'mailto:' + inidea + '?subject=' + encodeURIComponent(document.getElementsByTagName('h2')[0].innerHTML.split('&')[0].split('<')[0].replace(/\`/g,'').replace(/^Events\ in\ /g, 'Events in Month ').substring(0)) + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(hfanalyze())); //encodeURIComponent(document.URL.split('#')[0] + '<h2' + document.body.innerHTML.split('<h2')[1]));
azx.click();
return '';
}

function dosms() {
//alert('' + eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(hfanalyze()))).length));
if (eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(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.', snum)).replace(/^null/g,'');
} else {
snum=('' + prompt('Please enter SMS number to send to.', snum)).replace(/^null/g,'');
}
if (snum.indexOf('@') != -1) {
return doemail(snum);
} else if (snum.trim() != '') {
alert('Snum=' + snum + '?');
var azx=document.getElementById('xas' + 'ms');
if (azx == null) { azx=document.createElement("a"); }
//if (1 == 1) {
// document.getElementById('divas').appendChild(azx);
//} else {
document.body.appendChild(azx);
// }
azx.id = 'xas' + 'ms';
azx.style = "display: none";
azx.href = 'sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(hfanalyze()));
azx.click();
}
return '';
}

function wopencheck(iois) {
var aconto = null;
aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
aconto.body.innerHTML=smallbih;
aconto.setviatext(viatext);
}
}
}

function setviatext(towhat) {
viatext=towhat;
}

… to help bed down this new sharing and collaboration functionality in a changed events_in_month.htm parent of the Events in Month web application.


Previous relevant Event Calendar PHP Bookmark Tutorial is shown below.

Event Calendar PHP Bookmark Tutorial

Event Calendar PHP Bookmark Tutorial

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 …


https://www.rjmprogramming.com.au/HTMLCSS/events_in_month.php?exactlabel=August__2023_00000__1

… 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 …


<style>
#eventcalendar {
background-color: #fcfcfc;
}

td {
padding-top: 2px;
padding-left: 2px;
padding-right: 2px;
padding-bottom: 12px;
}

.dayb {
color: white;
background-color: red;
padding: 5 5 5 5;
border-radius: 80px;
margin-bottom: 15px;
}

.dow {
color: purple;
font-style: bold;
}

.selday {
margin-left: 8px;
background-color: rgba(255,0,0,0.7);
display: inline-block;
width: 50px;
border-color: transparent;
text-overflow: ellipsis;
}

.tablurb {
background: linear-gradient(to right, white, lightpink, pink);
}

input[type="submit"] {
margin-bottom: 3px;
border-radius: 180px;
}

input[type="number"] {
margin-left: 3px;
margin-right: 3px;
border-radius: 180px;
background-color: #f3f3f3;
padding: 2 2 2 2;
}

#smonth {
margin-left: 3px;
margin-right: 3px;
border-radius: 180px;
background-color: #f9f9f9;
padding: 2 2 2 2;
}

.boldtitle {
background-color: rgba(0, 211, 107, 0.2);
}

.boldtitle + .tablurb {
margin-top: 8px;
}


.selhistory {
border-radius: 180px;
background-color: lightpink;
padding: 2 2 2 2;
}
</style>

… and we thank this webpage for the heads up regarding how to calculate week numbers within a year data item displays now available in …


Previous relevant Event Calendar PHP Tutorial is shown below.

Event Calendar PHP Tutorial

Event Calendar PHP Tutorial

Let’s face it. Serverside PHP is just great! It opens up so many opportunities regarding data in your web applications.

As such, onto yesterday’s Event Calendar New Window Tutorial logic we now have a …


Record to Remember

… 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

$hcont=file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'events_in_month.htm');
$cont=file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'events_in_month.php');
$ipad=server_remote_addr();
$ipadless=$ipad;
$js='';

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

$itdone=false;
if (isset($_GET['init'])) {
if (strpos($cont, '_' . $ipad . '=') !== false) {
$things=explode('_' . $ipad . '=', $cont);
for ($it=1; $it<sizeof($things); $it++) {
if ($it == 1 && !$itdone) {
$itdone=true;
$js.="\n parent.document.getElementById('myoldsel').style.display='inline-block'; \n";
}
$js.="\n parent.document.getElementById('myoldsel').innerHTML+='<option value=\"" . explode("\n", $things[$it])[0] . "\">" . explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[0] . ', ' . explode('_', explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[1])[0] . "</option>'; \n";
}
}
if (strpos($cont, '0' . $ipadless . '=') !== false) {
$things=explode('0' . $ipadless . '=', $cont);
for ($it=1; $it<sizeof($things); $it++) {
if ($it == 1 && !$itdone) {
$itdone=true;
$js.="\n parent.document.getElementById('myoldsel').style.display='inline-block'; \n";
}
$js.="\n parent.document.getElementById('myoldsel').innerHTML+='<option value=\"" . explode("\n", $things[$it])[0] . "\">" . explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[0] . ', ' . explode('_', explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[1])[0] . "</option>'; \n";
}
}
echo "<html><head><script type='text/javascript'> " . $js . " </script></head><body><p>" . $ipad . "</p></body></html>";
} else if (isset($_POST['phpthere']) && isset($_POST['bigurl']) && isset($_POST['caltitle'])) {
//file_put_contents('xz.xz', 'l');
if (strpos($cont, '// ' . str_replace(' ','_',str_replace(',','_',str_replace('+',' ',urldecode($_POST['caltitle'])))) . '_' . str_replace('+',' ',urldecode($_POST['phpthere'])) . '=' . $_POST['bigurl'] . "\n") === false) {
//file_put_contents('xz.xzz', 'l');
$cont=str_replace('?' . '>', '// ' . str_replace(' ','_',str_replace(',','_',str_replace('+',' ',urldecode($_POST['caltitle'])))) . '_' . str_replace('+',' ',urldecode($_POST['phpthere'])) . '=' . $_POST['bigurl'] . "\n" . '?' . '>', $cont);
file_put_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'events_in_month.php', $cont);
}
if (strpos($cont, '_' . $ipad . '=') !== false) {
$things=explode('_' . $ipad . '=', $cont);
for ($it=1; $it<sizeof($things); $it++) {
if ($it == 1 && !$itdone) {
$itdone=true;
$js.="\n parent.document.getElementById('myoldsel').style.display='inline-block'; \n";
}
$js.="\n parent.document.getElementById('myoldsel').innerHTML+='<option value=\"" . explode("\n", $things[$it])[0] . "\">" . explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[0] . ', ' . explode('_', explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[1])[0] . "</option>'; \n";
}
}
if (strpos($cont, '0' . $ipadless . '=') !== false) {
$things=explode('0' . $ipadless . '=', $cont);
for ($it=1; $it<sizeof($things); $it++) {
if ($it == 1 && !$itdone) {
$itdone=true;
$js.="\n parent.document.getElementById('myoldsel').style.display='inline-block'; \n";
}
$js.="\n parent.document.getElementById('myoldsel').innerHTML+='<option value=\"" . explode("\n", $things[$it])[0] . "\">" . explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[0] . ', ' . explode('_', explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[1])[0] . "</option>'; \n";
}
}
//file_put_contents('xz.xzzz', "<html><head><script type='text/javascript'> " . $js . "\n parent.checkif(parent.document.getElementById('phpif')); \n" . " </script></head><body><p>" . str_replace(' ','%20',str_replace('+',' ',urldecode($_POST['bigurl']))) . "</p></body></html>");
echo "<html><head><script type='text/javascript'> " . $js . "\n parent.checkif(parent.document.getElementById('phpif')); \n" . " </script></head><body><p>" . str_replace(' ','%20',str_replace('+',' ',urldecode($_POST['bigurl']))) . "</p></body></html>";
} else {
echo $hcont;
}
exit;

//
//
// January__1970_00000__1=http://localhost:8888/events_in_month.htm?caltitle=January%2C%201970&i01.00=&ta01.00=kgjfjhf%20jhgfjhf%20jhkgkjhg%20jhgkjhg%20jkghhg%20jkhgkjhg%20kjhgkjhg&i02.00=&ta02.00=kjhgkjh%20kjhgkjhg%20jkhgkjhg%20kjhgkjhg%20kjhgkjhg%20jhkgkjhg%20kjgkjhg&i03.00=&ta03.00=kjhgkjhg%20kjhgkjhg%20kjhgkjhg%20kjhgkjhg%20kjhgkjhg%20jhkgkjhg&i04.00=&ta04.00=&i05.00=&ta05.00=&i06.00=&ta06.00=&i07.00=&ta07.00=&i08.00=&ta08.00=&i09.00=&ta09.00=&i10.00=&ta10.00=&i11.00=&ta11.00=&i12.00=&ta12.00=&i13.00=&ta13.00=&i14.00=&ta14.00=&i15.00=&ta15.00=&i16.00=&ta16.00=&i17.00=&ta17.00=&i18.00=&ta18.00=&i19.00=&ta19.00=&i20.00=&ta20.00=&i21.00=&ta21.00=&i22.00=&ta22.00=&i23.00=&ta23.00=&i24.00=&ta24.00=&i25.00=&ta25.00=&i26.00=&ta26.00=&i27.00=&ta27.00=&i28.00=&ta28.00=&i29.00=&ta29.00=&i30.00=&ta30.00=&i31.00=&ta31.00=
?>

Yes, the parent needed to change for our events_in_month.htm parent of Events in Month web application role.


Previous relevant Event Calendar New Window Tutorial is shown below.

Event Calendar New Window Tutorial

Event Calendar New Window Tutorial

Onto yesterday’s Event Calendar Remembered Tutorial‘s “Mystery Dilemma”

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 …

  1. bring up Context Menu with a right click or two finger gesture within the popup window webpage content …
  2. pick Inspect option …
  3. be in Elements tab of your Web Inspector … and …
  4. highlight top <html> tag …
  5. Context Menu with a right click or two finger gesture …
  6. pick Copy -> Copy outerHTML … so that …
  7. your Event Calendar for your Events in Month choice is in a text buffer … ready for you to …
  8. 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>
  • dropdown element conditional styling

    <style>
    .dayb {
    color: white;
    background-color: red;
    padding: 5 5 5 5;
    }


    .dow {
    color: purple;
    font-style: bold;
    }

    .selday {
    margin-left: 8px;
    background-color: rgba(255,0,0,0.7);
    display: inline-block;
    width: 50px;
    }
    </style>



    if (thislabel.substring(0,1) == 'i') {
    if (thisval.trim() != '') {
    document.getElementById(thislabel.replace('i', 'sel')).style.color='white';
    document.getElementById(thislabel.replace('i', 'sel')).style.backgroundColor='red';

    }
    document.getElementById(thislabel.replace('i', 'opt')).innerText=thisval.replace(/\+/g, ' ').replace(/\ \ \ /g, ' + '); //.replace(/\+$/g, ' ');
    document.getElementById(thislabel).value=thisval.replace(/\+$/g, ' ');
    } else {
    document.getElementById(thislabel).value=thisval.replace(/\+/g, ' ').replace(/\ \ \ /g, ' + ');
    }
    }
  • placeholder on Blurb conditional existence

    var ourdata='';
    // ...
    if (documentURL.indexOf('?') != -1) {
    if (documentURL.indexOf('?caltitle=') != -1) { ourdata='data-'; }
    // ...
    trtemplate='<tr id=tr01.00><td style=width:22%;><span id=sone01.00 class=dow>' + dotw[adate.getDay()].toUpperCase().substring(0,3) + '</span><br><br><span id=stwo01.00 class=dayb>1<span onblur=sepit(this); contenteditable=true id=sp01.00></span><input type=hidden id=i01.00 name=i01.00 value=""></input><select data-dow=' + dotw[adate.getDay()].toUpperCase().substring(0,3) + ' class=selday onchange="selit(this);" id=sel01.00><option id=opt01.00 value=""></option><option title="All such in month (ie. weekly)" value="...">...</option><option title="And ..." value="&...">&</option><option value=Bold>Bold Title</option><option value=Clone>Clone</option></select></span></td><td class=blurb title="What is on?" id=tb01.00><span title="Event title" style="font-style:bold;color:blue;" id=bd01.00></span><textarea name=ta01.00 id=ta01.00 style="width:100%;height=100%;" ' + ourdata + 'placeholder="Blurb ..." class=tablurb></textarea></td></tr>';
    // ...
    }
    // ...
    }

… for our “second draft” events_in_month.htm Events in Month web application.


Previous relevant Event Calendar Remembered Tutorial is shown below.

Event Calendar Remembered Tutorial

Event Calendar Remembered Tutorial

We were inspired by an Event Calendar pamplette we saw the other day …

… to write a new “proof of concept” Events in Month web application, whose content can be recalled via the web browser’s Bookmark methodologies.

We liked the ideas for day of week and/or date of month grouping arrangements we included, being, the way we interpreted it …

  • just on this day in this month … default
  • on this day of the week throughout the month in question … “
  • on this day and some others in that month in question … “&” … to start with and further amendments available via contenteditable=true span element
  • “Clone” value allows for multiple separated “blurbs” for the one signature day

But, there’s an inherent weakness with the design, we’ll go into more into the future. For now, you can try it yourself below …

Stop Press

This is where we get to for a “second draft” we’ll get into, further, tomorrow …

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


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


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


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


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


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


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


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


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

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

Editable Calendar Primer Tutorial

Editable Calendar Primer Tutorial

Editable Calendar Primer Tutorial

Today’s new Editable Calendar themed inhouse web application combines …

Today’s steps of progress in this project …

  1. establish the current month and year’s “month showing” calendar into a webpage … and …
  2. within that calendar date cell we place a span element with contenteditable=true … allowing …
  3. user to add content into the calendar

… in this first draft “proof of new to us concept” Editable Calendar you can try below. We hope you tune in tomorrow for more progress!


Previous relevant Event Calendar Collaboration Textarea Highlight Linking Tutorial is shown below.

Event Calendar Collaboration Textarea Highlight Linking Tutorial

Event Calendar Collaboration Textarea Highlight Linking Tutorial

For the first time we can remember, with our Events in Month web application of yesterday’s Event Calendar Collaboration Remembering Recipient Tutorial

  • 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 …


var thesel='', showsel=false, lastsel='';

function showthesel() {
var uwords=[], iuw=1, ils=0;
if (showsel) {
showsel=false;
if (lastsel != thesel && thesel.toLowerCase().replace('https:', 'http:').indexOf('http://') >= 0) {
lastsel=thesel;
thesel='';
}
if (lastsel != '' && thesel == '') {
uwords=lastsel.toLowerCase().split('http');
ils=eval(4 + eval('' + uwords[0].length));
for (iuw=1; iuw<uwords.length; iuw++) {
window.open('//' + lastsel.substring(ils).split('//')[1].split(' ')[0].split(String.fromCharCode(10))[0].split(String.fromCharCode(13))[0], '_blank', 'top=' + eval(10 * iuw + 50) + ',left=' + eval(10 * iuw + 50) + ',width=600,height=600');
ils+=eval(4 + eval('' + uwords[iuw].length));
}
}
}
}

function handleSelection() { // thanks to https://stackoverflow.com/questions/46651479/reacting-to-selection-changes-in-an-html-textarea
const activeElement = document.activeElement;

// Make sure this is your textarea
if (activeElement && activeElement.outerHTML.indexOf('<textarea') == 0) {
const range = {
start: activeElement.selectionStart,
end: activeElement.selectionEnd
};
// Do something with your range
if (eval('' + range.end) > eval('' + range.start)) {
thesel=(activeElement.value.substring(range.start).substring(0, eval(eval('' + range.end) - eval('' + range.start) )));
if (!showsel && thesel.toLowerCase().replace('https:', 'http:').indexOf('http://') >= 0) {
showsel=true;
setTimeout(showthesel, 5000);
}
}
}
}

document.addEventListener('selectionchange', handleSelection);

Also, today, we have a few CSS tweaks in the changed events_in_month.htm parent of the Events in Month web application. Feel free to try it for yourself.

Stop Press

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?!


Previous relevant Event Calendar Collaboration Remembering Recipient Tutorial is shown below.

Event Calendar Collaboration Remembering Recipient Tutorial

Event Calendar Collaboration Remembering Recipient Tutorial

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 changed events_in_month.htm parent of the Events in Month web application. Never a dull moment in web application I.T. we’d say!


Previous relevant Event Calendar Collaboration Tutorial is shown below.

Event Calendar Collaboration Tutorial

Event Calendar Collaboration Tutorial

The Event Calendar web application project, of Event Calendar PHP Bookmark Tutorial, from last year is worth a revisit, the reason being …

  • 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 …

  1. Month
  2. 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 &nbsp;&nbsp;<button style=display:none; title='Share via Email' id=semail onclick="doemail('');">&#128231;</button> <button style=display:none; title='Share via SMS' id=ssms onclick=dosms();>&#128223;</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) …

var bigbih=('' + ('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'')).split('bih=')[1] ? (decodeURIComponent(('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'')).split('bih=')[1].split('&')[0]) : '';
if (bigbih != '' && bigbih.indexOf('xae' + 'mail') == -1) {
bigbih+='<a target=_blank id=xae' + 'mail style=display:none; href="mailto:"></a>';
}
if (bigbih != '' && bigbih.indexOf('xas' + 'ms') == -1) {
bigbih+='<a target=_blank id=xas' + 'ms style=display:none; href="sms:"></a>';
}
var viatext='', smallbih='', wes=null, sparewes=null;
On or around document.body onload event we can analyze any such location.hash hashtagging data …

if (bigbih.indexOf('</he' + 'ad>') != -1 || bigbih.indexOf('<b' + 'o' + 'dy') != -1 || bigbih.indexOf('<h' + '1') == 0) {
//bigbih=bigbih.replace('" id="eventcalendar"', 'margin-top:50px;" id="eventcalendar"');
viatext=' (via contact at ' + ('' + new Date()) + ')';
if (bigbih.indexOf('<h' + '1') == 0) {
smallbih=bigbih;
} else {
smallbih=bigbih.split('<b' + 'o' + '')[1].split('</b' + 'o' + 'd' + 'y>')[0].replace(bigbih.split('<b' + 'o' + '')[1].split('</b' + 'o' + 'd' + 'y>')[0].split('>')[0] + '>', '');
}
wes=windowopen('./events_in_month.htm','_blank','top=40,left=40,width=800,height=800');
//alert(bigbih);
if (wes) {
setTimeout(function(){
wes.document.write(bigbih);
}, 3000);
//document.body.innerHTML=bigbih;
setTimeout(function(){
wes.document.getElementById('semail').style.display='inline-block';
wes.document.getElementById('ssms').style.display='inline-block';
wes.document.getElementsByTagName('h1')[0].style.display='none';
wes.document.getElementsByTagName('h3')[0].style.display='none';
//wes.setviatext(viatext);
//wes.setphpthere(' ');
//wes.togglewords();
}, 5000);
}
}
A window.open wrapper windowopen Javascript function …

function windowopen(poneis, ptwois, pthreeis) {
document.getElementById('divas').innerHTML='<iframe name=ovif id=ovif style="position:absolute;top:140px;left:0px;width:100%;height:100%;z-index:99;" src="' + poneis + '" onload=wopencheck(this);></iframe>';
//document.getElementsByTagName('h1')[0].style.opacity='0.0';
//document.getElementsByTagName('h3')[0].style.opacity='0.0';
sparewes=window.open(poneis.split('.htm')[0] + '.php', 'ovif');
//sparewes=window.open(poneis, 'ovif');
sparewes.document.write(bigbih);
setTimeout(function(){
sparewes.document.getElementById('semail').style.display='inline-block';
sparewes.document.getElementById('ssms').style.display='inline-block';
var sdem=sparewes.document.getElementById('semail').outerHTML;
var sdss=sparewes.document.getElementById('ssms').outerHTML;
sparewes.document.getElementsByTagName('h1')[0].innerHTML=sparewes.document.getElementsByTagName('h1')[0].innerHTML.replace(sdss,'');
sparewes.document.getElementsByTagName('h1')[0].innerHTML=sparewes.document.getElementsByTagName('h1')[0].innerHTML.replace(sdem,'');
sparewes.document.getElementsByTagName('h1')[0].style.display='none';
sparewes.document.getElementsByTagName('h3')[0].style.display='none';
sparewes.document.getElementById('dmore').innerHTML+=(' ' + sdem.replace('doeJUNKmail(', 'parent.doe' + 'mail(') + ' ' + sdss.replace('dosJUNKms(', 'parent.dos' + 'ms(') + '<br>');
//sparewes.setviatext(viatext);
//sparewes.setphpthere(' ');
//sparewes.togglewords();
}, 5000);
return null;
}
Is augmented by other new Javascript functions …

function hfanalyze() {
var fio=document.getElementById('ecform');
if (forceit) { forceit=false; return true; }
var delm='?';
var fioih=fio.innerHTML;
var fions=fioih.split(' name="');
var testurl=documentURL.split('?')[0].split('#')[0];
//alert(fions.length);
for (var ijk=1; ijk<fions.length; ijk++) {
testurl+=delm + fions[ijk].split('"')[0] + '=' + encodeURIComponent(document.getElementById(fions[ijk].split('"')[0]).value.replace(/\?\>/g,'? >'));
delm='&';
}
//alert(testurl.length);
//if (eval('' + testurl.length) < 750) { return true; }
//if (lastbut.value.indexOf('New') == 0 || 11 == 11) {
if (22 == 22) {
//wo=window.open('', '_blank', 'top=50,left=50,height=600,width=600');
//wo.document.write('<html><head>' + hih.replace("=docum" + "ent.URL", "='" + testurl.replace(/\'/g, "' + String.fromCharCode(39) + '") + "'") + boh + '</html>');
return ('<html><head>' + hih.replace("=docum" + "ent.URL", "='" + testurl.replace(/\'/g, "' + String.fromCharCode(39) + '") + "'") + boh + '</html>');
} else if (phpthere != '') {
if (1 == 1) {
postit(fio, false, testurl);
} else {
fio.target='phpif';
fio.method='POST';
fio.action='./events_in_month.php';
if (!document.getElementById('dmore')) {
document.getElementById('ddmore').innerHTML='<input type=hidden id=caltitle name=caltitle value="' + document.getElementById('myoldsel').options[document.getElementById('myoldsel').selectedIndex].innerText + '"></input><input type=hidden id=phpthere name=phpthere value="' + phpthere + '"></input><input type=hidden id=bigurl name=bigurl value="' + testurl + '"></input>';
} else {
document.getElementById('dmore').innerHTML='<input type=hidden id=phpthere name=phpthere value="' + phpthere + '"></input><input type=hidden id=bigurl name=bigurl value="' + testurl + '"></input>';
}
}
return 'true';
}
return 'false';
}

function doemail(inidea) {
var azx=document.getElementById('xae' + 'mail');
if (!azx) { azx=document.createElement("a"); }
//if (1 == 1) {
//document.getElementById('divas').appendChild(azx);
//} else {
document.body.appendChild(azx);
//}
azx.style = "display: none";
azx.id = 'xaem' + 'ail';
azx.href = 'mailto:' + inidea + '?subject=' + encodeURIComponent(document.getElementsByTagName('h2')[0].innerHTML.split('&')[0].split('<')[0].replace(/\`/g,'').replace(/^Events\ in\ /g, 'Events in Month ').substring(0)) + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(hfanalyze())); //encodeURIComponent(document.URL.split('#')[0] + '<h2' + document.body.innerHTML.split('<h2')[1]));
azx.click();
return '';
}

function dosms() {
//alert('' + eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(hfanalyze()))).length));
if (eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(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.', snum)).replace(/^null/g,'');
} else {
snum=('' + prompt('Please enter SMS number to send to.', snum)).replace(/^null/g,'');
}
if (snum.indexOf('@') != -1) {
return doemail(snum);
} else if (snum.trim() != '') {
alert('Snum=' + snum + '?');
var azx=document.getElementById('xas' + 'ms');
if (azx == null) { azx=document.createElement("a"); }
//if (1 == 1) {
// document.getElementById('divas').appendChild(azx);
//} else {
document.body.appendChild(azx);
// }
azx.id = 'xas' + 'ms';
azx.style = "display: none";
azx.href = 'sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(hfanalyze()));
azx.click();
}
return '';
}

function wopencheck(iois) {
var aconto = null;
aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
aconto.body.innerHTML=smallbih;
aconto.setviatext(viatext);
}
}
}

function setviatext(towhat) {
viatext=towhat;
}

… to help bed down this new sharing and collaboration functionality in a changed events_in_month.htm parent of the Events in Month web application.


Previous relevant Event Calendar PHP Bookmark Tutorial is shown below.

Event Calendar PHP Bookmark Tutorial

Event Calendar PHP Bookmark Tutorial

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 …


https://www.rjmprogramming.com.au/HTMLCSS/events_in_month.php?exactlabel=August__2023_00000__1

… 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 …


<style>
#eventcalendar {
background-color: #fcfcfc;
}

td {
padding-top: 2px;
padding-left: 2px;
padding-right: 2px;
padding-bottom: 12px;
}

.dayb {
color: white;
background-color: red;
padding: 5 5 5 5;
border-radius: 80px;
margin-bottom: 15px;
}

.dow {
color: purple;
font-style: bold;
}

.selday {
margin-left: 8px;
background-color: rgba(255,0,0,0.7);
display: inline-block;
width: 50px;
border-color: transparent;
text-overflow: ellipsis;
}

.tablurb {
background: linear-gradient(to right, white, lightpink, pink);
}

input[type="submit"] {
margin-bottom: 3px;
border-radius: 180px;
}

input[type="number"] {
margin-left: 3px;
margin-right: 3px;
border-radius: 180px;
background-color: #f3f3f3;
padding: 2 2 2 2;
}

#smonth {
margin-left: 3px;
margin-right: 3px;
border-radius: 180px;
background-color: #f9f9f9;
padding: 2 2 2 2;
}

.boldtitle {
background-color: rgba(0, 211, 107, 0.2);
}

.boldtitle + .tablurb {
margin-top: 8px;
}


.selhistory {
border-radius: 180px;
background-color: lightpink;
padding: 2 2 2 2;
}
</style>

… and we thank this webpage for the heads up regarding how to calculate week numbers within a year data item displays now available in …


Previous relevant Event Calendar PHP Tutorial is shown below.

Event Calendar PHP Tutorial

Event Calendar PHP Tutorial

Let’s face it. Serverside PHP is just great! It opens up so many opportunities regarding data in your web applications.

As such, onto yesterday’s Event Calendar New Window Tutorial logic we now have a …


Record to Remember

… 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

$hcont=file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'events_in_month.htm');
$cont=file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'events_in_month.php');
$ipad=server_remote_addr();
$ipadless=$ipad;
$js='';

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

$itdone=false;
if (isset($_GET['init'])) {
if (strpos($cont, '_' . $ipad . '=') !== false) {
$things=explode('_' . $ipad . '=', $cont);
for ($it=1; $it<sizeof($things); $it++) {
if ($it == 1 && !$itdone) {
$itdone=true;
$js.="\n parent.document.getElementById('myoldsel').style.display='inline-block'; \n";
}
$js.="\n parent.document.getElementById('myoldsel').innerHTML+='<option value=\"" . explode("\n", $things[$it])[0] . "\">" . explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[0] . ', ' . explode('_', explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[1])[0] . "</option>'; \n";
}
}
if (strpos($cont, '0' . $ipadless . '=') !== false) {
$things=explode('0' . $ipadless . '=', $cont);
for ($it=1; $it<sizeof($things); $it++) {
if ($it == 1 && !$itdone) {
$itdone=true;
$js.="\n parent.document.getElementById('myoldsel').style.display='inline-block'; \n";
}
$js.="\n parent.document.getElementById('myoldsel').innerHTML+='<option value=\"" . explode("\n", $things[$it])[0] . "\">" . explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[0] . ', ' . explode('_', explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[1])[0] . "</option>'; \n";
}
}
echo "<html><head><script type='text/javascript'> " . $js . " </script></head><body><p>" . $ipad . "</p></body></html>";
} else if (isset($_POST['phpthere']) && isset($_POST['bigurl']) && isset($_POST['caltitle'])) {
//file_put_contents('xz.xz', 'l');
if (strpos($cont, '// ' . str_replace(' ','_',str_replace(',','_',str_replace('+',' ',urldecode($_POST['caltitle'])))) . '_' . str_replace('+',' ',urldecode($_POST['phpthere'])) . '=' . $_POST['bigurl'] . "\n") === false) {
//file_put_contents('xz.xzz', 'l');
$cont=str_replace('?' . '>', '// ' . str_replace(' ','_',str_replace(',','_',str_replace('+',' ',urldecode($_POST['caltitle'])))) . '_' . str_replace('+',' ',urldecode($_POST['phpthere'])) . '=' . $_POST['bigurl'] . "\n" . '?' . '>', $cont);
file_put_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'events_in_month.php', $cont);
}
if (strpos($cont, '_' . $ipad . '=') !== false) {
$things=explode('_' . $ipad . '=', $cont);
for ($it=1; $it<sizeof($things); $it++) {
if ($it == 1 && !$itdone) {
$itdone=true;
$js.="\n parent.document.getElementById('myoldsel').style.display='inline-block'; \n";
}
$js.="\n parent.document.getElementById('myoldsel').innerHTML+='<option value=\"" . explode("\n", $things[$it])[0] . "\">" . explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[0] . ', ' . explode('_', explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[1])[0] . "</option>'; \n";
}
}
if (strpos($cont, '0' . $ipadless . '=') !== false) {
$things=explode('0' . $ipadless . '=', $cont);
for ($it=1; $it<sizeof($things); $it++) {
if ($it == 1 && !$itdone) {
$itdone=true;
$js.="\n parent.document.getElementById('myoldsel').style.display='inline-block'; \n";
}
$js.="\n parent.document.getElementById('myoldsel').innerHTML+='<option value=\"" . explode("\n", $things[$it])[0] . "\">" . explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[0] . ', ' . explode('_', explode('__', explode(' ' . ' ' . ' ', $things[-1 + $it])[-1 + sizeof(explode(' ' . ' ' . ' ', $things[-1 + $it]))])[1])[0] . "</option>'; \n";
}
}
//file_put_contents('xz.xzzz', "<html><head><script type='text/javascript'> " . $js . "\n parent.checkif(parent.document.getElementById('phpif')); \n" . " </script></head><body><p>" . str_replace(' ','%20',str_replace('+',' ',urldecode($_POST['bigurl']))) . "</p></body></html>");
echo "<html><head><script type='text/javascript'> " . $js . "\n parent.checkif(parent.document.getElementById('phpif')); \n" . " </script></head><body><p>" . str_replace(' ','%20',str_replace('+',' ',urldecode($_POST['bigurl']))) . "</p></body></html>";
} else {
echo $hcont;
}
exit;

//
//
// January__1970_00000__1=http://localhost:8888/events_in_month.htm?caltitle=January%2C%201970&i01.00=&ta01.00=kgjfjhf%20jhgfjhf%20jhkgkjhg%20jhgkjhg%20jkghhg%20jkhgkjhg%20kjhgkjhg&i02.00=&ta02.00=kjhgkjh%20kjhgkjhg%20jkhgkjhg%20kjhgkjhg%20kjhgkjhg%20jhkgkjhg%20kjgkjhg&i03.00=&ta03.00=kjhgkjhg%20kjhgkjhg%20kjhgkjhg%20kjhgkjhg%20kjhgkjhg%20jhkgkjhg&i04.00=&ta04.00=&i05.00=&ta05.00=&i06.00=&ta06.00=&i07.00=&ta07.00=&i08.00=&ta08.00=&i09.00=&ta09.00=&i10.00=&ta10.00=&i11.00=&ta11.00=&i12.00=&ta12.00=&i13.00=&ta13.00=&i14.00=&ta14.00=&i15.00=&ta15.00=&i16.00=&ta16.00=&i17.00=&ta17.00=&i18.00=&ta18.00=&i19.00=&ta19.00=&i20.00=&ta20.00=&i21.00=&ta21.00=&i22.00=&ta22.00=&i23.00=&ta23.00=&i24.00=&ta24.00=&i25.00=&ta25.00=&i26.00=&ta26.00=&i27.00=&ta27.00=&i28.00=&ta28.00=&i29.00=&ta29.00=&i30.00=&ta30.00=&i31.00=&ta31.00=
?>

Yes, the parent needed to change for our events_in_month.htm parent of Events in Month web application role.


Previous relevant Event Calendar New Window Tutorial is shown below.

Event Calendar New Window Tutorial

Event Calendar New Window Tutorial

Onto yesterday’s Event Calendar Remembered Tutorial‘s “Mystery Dilemma”

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 …

  1. bring up Context Menu with a right click or two finger gesture within the popup window webpage content …
  2. pick Inspect option …
  3. be in Elements tab of your Web Inspector … and …
  4. highlight top <html> tag …
  5. Context Menu with a right click or two finger gesture …
  6. pick Copy -> Copy outerHTML … so that …
  7. your Event Calendar for your Events in Month choice is in a text buffer … ready for you to …
  8. 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>
  • dropdown element conditional styling

    <style>
    .dayb {
    color: white;
    background-color: red;
    padding: 5 5 5 5;
    }


    .dow {
    color: purple;
    font-style: bold;
    }

    .selday {
    margin-left: 8px;
    background-color: rgba(255,0,0,0.7);
    display: inline-block;
    width: 50px;
    }
    </style>



    if (thislabel.substring(0,1) == 'i') {
    if (thisval.trim() != '') {
    document.getElementById(thislabel.replace('i', 'sel')).style.color='white';
    document.getElementById(thislabel.replace('i', 'sel')).style.backgroundColor='red';

    }
    document.getElementById(thislabel.replace('i', 'opt')).innerText=thisval.replace(/\+/g, ' ').replace(/\ \ \ /g, ' + '); //.replace(/\+$/g, ' ');
    document.getElementById(thislabel).value=thisval.replace(/\+$/g, ' ');
    } else {
    document.getElementById(thislabel).value=thisval.replace(/\+/g, ' ').replace(/\ \ \ /g, ' + ');
    }
    }
  • placeholder on Blurb conditional existence

    var ourdata='';
    // ...
    if (documentURL.indexOf('?') != -1) {
    if (documentURL.indexOf('?caltitle=') != -1) { ourdata='data-'; }
    // ...
    trtemplate='<tr id=tr01.00><td style=width:22%;><span id=sone01.00 class=dow>' + dotw[adate.getDay()].toUpperCase().substring(0,3) + '</span><br><br><span id=stwo01.00 class=dayb>1<span onblur=sepit(this); contenteditable=true id=sp01.00></span><input type=hidden id=i01.00 name=i01.00 value=""></input><select data-dow=' + dotw[adate.getDay()].toUpperCase().substring(0,3) + ' class=selday onchange="selit(this);" id=sel01.00><option id=opt01.00 value=""></option><option title="All such in month (ie. weekly)" value="...">...</option><option title="And ..." value="&...">&</option><option value=Bold>Bold Title</option><option value=Clone>Clone</option></select></span></td><td class=blurb title="What is on?" id=tb01.00><span title="Event title" style="font-style:bold;color:blue;" id=bd01.00></span><textarea name=ta01.00 id=ta01.00 style="width:100%;height=100%;" ' + ourdata + 'placeholder="Blurb ..." class=tablurb></textarea></td></tr>';
    // ...
    }
    // ...
    }

… for our “second draft” events_in_month.htm Events in Month web application.


Previous relevant Event Calendar Remembered Tutorial is shown below.

Event Calendar Remembered Tutorial

Event Calendar Remembered Tutorial

We were inspired by an Event Calendar pamplette we saw the other day …

… to write a new “proof of concept” Events in Month web application, whose content can be recalled via the web browser’s Bookmark methodologies.

We liked the ideas for day of week and/or date of month grouping arrangements we included, being, the way we interpreted it …

  • just on this day in this month … default
  • on this day of the week throughout the month in question … “
  • on this day and some others in that month in question … “&” … to start with and further amendments available via contenteditable=true span element
  • “Clone” value allows for multiple separated “blurbs” for the one signature day

But, there’s an inherent weakness with the design, we’ll go into more into the future. For now, you can try it yourself below …

Stop Press

This is where we get to for a “second draft” we’ll get into, further, tomorrow …

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


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


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


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


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


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


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


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

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

Horizontal Block Calendar Game Tutorial

Horizontal Block Calendar Game Tutorial

Horizontal Block Calendar Game Tutorial

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 …

  1. dominoes in the Stock are organized in a Calendar fashion …
  2. 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
  3. months with more than 28 (the number of domino tiles) will yield up to 3 mystery cell scoring opportunity cells

… in the changed eighteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Game Soft Link Resources Tutorial is shown below.

Horizontal Game Soft Link Resources Tutorial

Horizontal Game Soft Link Resources Tutorial

After yesterday’s Horizontal Block Game CSS Animation Tutorial, today we’re revisiting …

resources

… 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 …


Soft Links

(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)) …


#!/bin/ksh
# dominoes_(3 + 1)_(9 % 7).png ... then swap as required
ln -s dominoes_2_4.png dominoes_1_9.png
ln -s dominoes_1_4.png dominoes_1_8.png
ln -s dominoes_0_4.png dominoes_1_7.png

# dominoes_(3 + 0)_(9 % 7).png ... then swap as required
ln -s dominoes_2_3.png dominoes_0_9.png
ln -s dominoes_1_3.png dominoes_0_8.png
ln -s dominoes_0_3.png dominoes_0_7.png

# dominoes_(3 + 2)_(9 % 7).png ... then swap as required
ln -s dominoes_2_5.png dominoes_2_9.png
ln -s dominoes_1_5.png dominoes_2_8.png
ln -s dominoes_0_5.png dominoes_2_7.png

ln -s dominoes_0_1.png dominoes_1_0.png
ln -s dominoes_0_2.png dominoes_2_0.png
ln -s dominoes_0_3.png dominoes_3_0.png
ln -s dominoes_0_4.png dominoes_4_0.png
ln -s dominoes_0_5.png dominoes_5_0.png
ln -s dominoes_0_6.png dominoes_6_0.png

ln -s dominoes_1_2.png dominoes_2_1.png
ln -s dominoes_1_3.png dominoes_3_1.png
ln -s dominoes_1_4.png dominoes_4_1.png
ln -s dominoes_1_5.png dominoes_5_1.png
ln -s dominoes_1_6.png dominoes_6_1.png

ln -s dominoes_2_3.png dominoes_3_2.png
ln -s dominoes_2_4.png dominoes_4_2.png
ln -s dominoes_2_5.png dominoes_5_2.png
ln -s dominoes_2_6.png dominoes_6_2.png

ln -s dominoes_3_4.png dominoes_4_3.png
ln -s dominoes_3_5.png dominoes_5_3.png
ln -s dominoes_3_6.png dominoes_6_3.png

ln -s dominoes_4_5.png dominoes_5_4.png
ln -s dominoes_4_6.png dominoes_6_4.png

ln -s dominoes_5_6.png dominoes_6_5.png

… and in our web server’s cPanel Terminal ran that via …


ksh -x dominoes_more.ksh

… to create soft links, so that …


# 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 concept through.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.


Previous relevant Horizontal Block Game CSS Animation Tutorial is shown below.

Horizontal Block Game CSS Animation Tutorial

Horizontal Block Game CSS Animation Tutorial

Today we …

  • extend yesterday’s Horizontal Block Game Random Image Types Tutorial‘s ondblclick and oncontextmenu (or ontouchmove) “drill downs” to other Wikipedia image Block Game choices … and …
  • allow for a CSS @keyframes animation definition to affect …
    CSS @keyframes animation default initialization that may be dynamically called into play at a later time …

    <style>
    @keyframes myanim { 0%, 58.33% { filter: invert(0%) contrast(100%); } 75%, 100% { filter: invert(100%) contrast(800%); } }
    </style>

    … and editable via Javascript …

    animans=prompt('Optionally enter CSS @keyframes animation definition.', (animval == 'y' ? document.getElementById('mysel').getAttribute('data-anim') : animval));

    … via a new dropdown option …
    Optionally passed across in a new animated argument, processed by initialization Javascript …

    var animgprefix='', animgsuffix='';
    var animval='y', animdef="@keyframes myanim { 0%, 58.33% { filter: invert(0%) contrast(100%); } 75%, 100% { filter: invert(100%) contrast(800%); } } ";
    var animclass=(location.search.split('animated=')[1] ? decodeURIComponent(location.search.split('animated=')[1].split('&')[0]) : '');
    if (animclass != '') {
    if (('' + animclass).toLowerCase().indexOf('@keyframes') != -1) { animval=animclass; } else if (('' + animclass).toLowerCase() == 'y') { animval=animdef; }
    animclass=' animated';
    }

    … as well as document.body onload called …

    if (('' + animval).toLowerCase().indexOf('@keyframes') != -1) {
    if (animval != document.getElementById('mysel').getAttribute('data-anim')) {
    document.getElementById('mysel').setAttribute('data-anim', animval);
    }
    document.getElementById('dstyle').innerHTML+='<st' + 'yle> ' + animval + ' </st' + 'yle>';
    document.getElementById('optanim').innerHTML='Animation ' + animval + ' ... ';
    }
    In Play at the time of relevance …

    <style>
    .animated:not([style*="filter"]) { animation: myanim 12s infinite; }
    </style>
    Javascript dynamically called into play wherever in the code

    document.getElementById('dstyle').innerHTML+='<st' + 'yle> ' + animval + ' </st' + 'yle>';

    … and relevant HTML elements have class=animated applied to them dynamically … for example

    document.getElementById('seven1').innerHTML+=brhuh + othersmaybe('<img' + (animclass == '' ? '' : ' class=animated') + ' draggable="true" ondragstart="goone(event.target);" onclick="goone(this);" style=width:80px; class="player1" id="' + player1arr[ij] + '" src="' + player1arr[ij] + '.png"></img>');

    … happens …

… to add to the changed seventeenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Random Image Types Tutorial is shown below.

Horizontal Block Game Random Image Types Tutorial

Horizontal Block Game Random Image Types Tutorial

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 …

… offering both …

  • image randomosity possibilities … as well as …
  • means to recall same content

… via ondblclick …


function odc(evt) {
var evttarget=evt.target, spanarr=[], jspan=0;
evt.stopPropagation();
if (evttarget.outerHTML.indexOf('<img') == 0) {
spanarr=document.getElementsByTagName('span');
for (jspan=0; jspan<spanarr.length; jspan++) {
if (evttarget.outerHTML.indexOf('<img') == 0) {
if (spanarr[jspan].innerHTML.indexOf(evt.target.outerHTML) != -1) { evttarget=spanarr[jspan]; }
}
}
}
if (eval('' + evttarget.innerHTML.split(' data-url="').length) >= 2) {
etarget=evttarget;
window.open(evttarget.innerHTML.split(' data-url="')[1].split('"')[0], '_blank', 'top=10,left=' + eval(-600 + screen.width) + ',width=600,height=800');
}
}

… and oncontextmenu (or ontouchmove) …


function onc(evt) {
var evttarget=evt.target, spanarr=[], jspan=0;
evt.preventDefault();
if (evttarget.outerHTML.indexOf('<img') == 0) {
spanarr=document.getElementsByTagName('span');
for (jspan=0; jspan<spanarr.length; jspan++) {
if (evttarget.outerHTML.indexOf('<img') == 0) {
if (spanarr[jspan].innerHTML.indexOf(evt.target.outerHTML) != -1) { evttarget=spanarr[jspan]; }
}
}
}
if (eval('' + evttarget.innerHTML.split(' data-url="').length) >= 3) {
window.open(evttarget.innerHTML.split(' data-url="')[2].split('"')[0], '_blank', 'top=10,left=' + eval(-600 + screen.width) + ',width=600,height=800');
}
}

… conduits, for an inquisitive user, as well, in the changed sixteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Less Personal Types Tutorial is shown below.

Horizontal Block Game Less Personal Types Tutorial

Horizontal Block Game Less Personal Types Tutorial

Onto yesterday’s Horizontal Block Game Personalized Second Image Type Tutorial‘s new Horizontal Block Game types, today, we add a variety more number of emoji and image type game incarnations, as per …

… 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)


document.getElementById('sele').style.position='absolute';
osel.style.width='290px';
document.getElementById('sele').style.left='' + eval(-30 + eval('' + osel.getBoundingClientRect().right)) + 'px';
document.getElementById('sele').style.top='' + eval(36 + eval('' + osel.getBoundingClientRect().top)) + 'px';
document.getElementById('sele').style.zIndex='211';
document.getElementById('sele').style.display='block';

… in the changed fifteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Personalized Second Image Type Tutorial is shown below.

Horizontal Block Game Personalized Second Image Type Tutorial

Horizontal Block Game Personalized Second Image Type Tutorial

After yesterday’s Horizontal Block Game Types Tutorial a cruel streak in us might say …

Emojis Smemojis

… 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 …


<style> .dominoes0:after { background-image:url(//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/St_Mary%27s_Cathedral_-_panoramio.jpg/250px-St_Mary%27s_Cathedral_-_panoramio.jpg?utm_source=en.wikipedia.org&utm_campaign=parser&utm_content=thumbnail); background-size:cover; background-repeat:no-repeat; color:transparent; } </style>

… added as the need arises.

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 changed fourteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Types Tutorial is shown below.

Horizontal Block Game Types Tutorial

Horizontal Block Game Types Tutorial

Do you remember, way before yesterday’s Dominoes Horizontal Block Game Drag Tutorial, way back at Dominoes Horizontal Block Game Width Tutorial, we commented …

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;
}
}
New initialization Javascript function …

function alat() {
document.getElementById('gtype').innerHTML=othertype;
if (anothertype != 'shapeis' && document.getElementById('dstyle').innerHTML.indexOf('.dominoes0') == -1) {
eval(' numarr=' + anothertype + '.length');
while (eval('' + newtypes.length) < 7) {
thisemhe=Math.floor(Math.random() * numarr);
while (newtypes.indexOf(thisemhe) != -1) {
thisemhe=Math.floor(Math.random() * numarr);
}
eval(' thisem=' + anothertype + '[' + thisemhe + ']');
if (thisem.indexOf(String.fromCharCode(92)) != -1) {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '" + thisem + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
} else if (thisem.indexOf('x') != -1) {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '\\" + ('000000' + ('' + thisem.replace(String.fromCharCode(92),"").replace("0x","").toString(16).padStart(2, '0'))).slice(-6).replace(/\ /g,'0') + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
} else if (thisem.toLowerCase().indexOf('a') != -1 || thisem.toLowerCase().indexOf('b') != -1 || thisem.toLowerCase().indexOf('c') != -1 || thisem.toLowerCase().indexOf('d') != -1 || thisem.toLowerCase().indexOf('e') != -1 || thisem.toLowerCase().indexOf('f') != -1) {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '\\" + ('000000' + ('' + thisem)).slice(-6).replace(/\ /g,'0') + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
} else {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '\\" + ('000000' + eval(thisem).toString(16).padStart(2, '0')).slice(-6) + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
}
}
}
}
Augmented other Javascript functions …

function lessen(inthih) {
return inthih.replace(/visible/g, 'hidden');
alert('lessen this ' + inthih + ' to ' + inthih.replace('><img', '--><img').replace('<', '<!--').replace(/<span/g, '<!--span').replace(/<\/span>/g, '</span-->'));
return inthih.replace('><img', '--><img').replace('<', '<!--').replace(/<span/g, '<!--span').replace(/<\/span>/g, '</span-->');
}

function fixdomlr() {
if (newspanoid != '') {
if (document.getElementById('p' + newspanoid)) {
if (document.getElementById('p' + newspanoid).innerHTML.indexOf('(-1)') != -1) {
document.getElementById('p' + newspanoid).innerHTML=document.getElementById('p' + newspanoid).innerHTML.replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
}
if (document.getElementById(newspanoid)) {
if (document.getElementById('seven1').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(1);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
} else if (document.getElementById('seven2').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(2);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
}
document.getElementById(newspanoid).innerHTML=document.getElementById(newspanoid).innerHTML.replace(/visible/g,'hidden'); //alert('and then ' + document.getElementById(newspanoid).outerHTML);
}
} else if (document.getElementById('s' + newspanoid)) {
if (document.getElementById('s' + newspanoid).innerHTML.indexOf('(-1)') != -1) {
document.getElementById('s' + newspanoid).innerHTML=document.getElementById('s' + newspanoid).innerHTML.replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
}
if (document.getElementById(newspanoid)) {
if (document.getElementById('seven1').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(3);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
} else if (document.getElementById('seven2').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(4);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
}
document.getElementById(newspanoid).innerHTML=document.getElementById(newspanoid).innerHTML.replace(/visible/g,'hidden'); //alert('anD then ' + document.getElementById(newspanoid).outerHTML);
}
} else if (document.getElementById(newspanoid)) {
if (document.getElementById(newspanoid).innerHTML.indexOf('(-1)') != -1) {
document.getElementById('' + newspanoid).innerHTML=document.getElementById('' + newspanoid).innerHTML.replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
}
}
}
newspanoid='';
}

function othersmaybe(inimg) {
var lbit='', rbit='';
newspano=null;
if (inimg.indexOf(cgostock) != -1) { return inimg; }
//if (inimg.indexOf(' draggable="false') != -1) { return inimg; }
if (animgprefix != '') {
// do more here perhaps
if (inimg.indexOf('dominoes_') != -1) {
lbit=inimg.split('dominoes_')[1].substring(0,1);
rbit=inimg.split('dominoes_')[1].split('_')[1].substring(0,1);
if (document.getElementById('dom' + lbit + rbit)) {
//alert('already there ' + inimg);
newspano=document.getElementById('dom' + lbit + rbit);
newspanoid='dom' + lbit + rbit;
if (newspano) {
setTimeout(fixdomlr, 500);
}
}
animgprefix=templateprefix.replace(' ', ' id="dom' + lbit + rbit + '" ');
if (inimg.indexOf('(0)') != -1) {
if (inimg.indexOf('(-1)') != -1) {
//alert(43);
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"').replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ').replace(/visible/g,'hidden');
} else {
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"').replace(/visible/g,'hidden');
}
} else {
if (inimg.indexOf('(-1)') != -1) {
//alert(4);
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"').replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
} else {
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"');
}
}
}

}
//alert(inimg);
if (nestero) {
nestero.className+=' disnon';
nestero=null;
}
return animgprefix + inimg + animgsuffix;
}

function typeize(osel) {
if (osel.value != '') {
if (osel.value.toLowerCase() == 'email') {
var anchor = document.createElement('a');
anchor.target='_top';
anchor.href = 'mailto:?subject=' + (othertype == '' ? 'Dominoes' : othertype) + '%20Game%20snapshot&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?type=' + othertype + '&rand=' + Math.floor(Math.random() * 1989786) + '&score1=' + document.getElementById('score1').innerHTML.replace('Score: ','') + '&score2=' + document.getElementById('score2').innerHTML.replace('Score: ','') + '#' + encodeURIComponent(document.body.innerHTML.split('<fo' + 'rm ')[0].split('<a' + ' target="_top"')[0]));
document.body.appendChild(anchor);
anchor.click();
anchor.remove();
} else {
othertype=osel.value.replace('Dominoes','');
newstockgame();
}
osel.value='';
}
}
New CSS styling …

<style>
.image-wrapper {
position: relative; /* Acts as the anchor point */
display: inline-block;
}

.image-wrapper img {
display: block;
width: 80px; /* Set your desired image width */
height: auto;
opacity:0.2; /* visibility: hidden; */
filter: url('#edge-detection');
}

.disnon span {
display: none;
}

.domr {
position: absolute;
top: -6px; /* Distance from the top edge */
right: 0px; /* Distance from the right edge */
font-size: 45px; /* Adjust emoji size */
pointer-events: none;
}

.doml {
position: absolute;
top: -6px; /* Distance from the top edge */
left: 0px; /* Distance from the right edge */
font-size: 45px; /* Adjust emoji size */
border-right: 1px solid black;
pointer-events: none;
}

.dominoes0:after {
content: '\002739';
}

.dominoes1:after {
content: '\002737';
}

.dominoes2:after {
content: '\002729';
}

.dominoes3:after {
content: '\002727';
}

.dominoes4:after {
content: '\002719';
}

.dominoes5:after {
content: '\002724';
}

.dominoes6:after {
content: '\002713';
}
</style>

… thanks, a lot, to Google’s overlay emoji characters on top of html img element‘s (back to W3schools‘s) advice in the changed thirteenth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Drag Tutorial is shown below.

Dominoes Horizontal Block Game Drag Tutorial

Dominoes Horizontal Block Game Drag Tutorial

Another layer of thinking onto yesterday’s Dominoes Horizontal Blocked Game Tutorial, we think, can be …

drag

andnot drop new Javascript logic. This last idea, where only what happens to HTML img element (by default draggable=”true”) …

  1. draggable … attribute “true” for “dragging available” and “false” for “dragging not available” … and …
  2. 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-nilly drop 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>';

… in the changed twelfth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Blocked Game Tutorial is shown below.

Dominoes Horizontal Blocked Game Tutorial

Dominoes Horizontal Blocked Game Tutorial

Playing a Dominoes Horizontal Block Game after yesterday’s Dominoes Horizontal Block Game Handoff Friendly Tutorial was where we realized you could have a “stalemate” (in chess parlance) in a Dominoes game, as per “what is stalemate called in a dominoes game”

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 …

  1. we turned a hardcopy into a span, potentially dynamic, element …

    <h1 id=myh1>Dominoes Horizontal Block <span id=sgame>Game</span></h1>
  2. 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';
    }
    }

  3. 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

… in the changed eleventh draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Handoff Friendly Tutorial is shown below.

Dominoes Horizontal Block Game Handoff Friendly Tutorial

Dominoes Horizontal Block Game Handoff Friendly Tutorial

After yesterday’s Dominoes Horizontal Block Game Mobile Speech to Text Tutorial we started delving more into Apple’s Handoff concepts here sharing between an iPhone and a MacBook Air …

  • on same WiFi network
  • Bluetooth on

… 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 …


lhis='#' + encodeURIComponent(document.body.innerHTML);
prevlhis=lhis;
location.href=lhis;

… as a way to tell Handoff, if used, situations in the Domino game had changed.

Also, we needed to, at document.body onload, code …


lhis=('' + location.hash);
prevlhis=lhis;
setInterval(lhcheck, 5000);

… utilizing new Javascript function …


function lhcheck() {
lhis=('' + location.hash);
if (prevlhis != lhis) {
prevlhis=lhis;
if (document.URL.indexOf('#' + encodeURIComponent('<h1')) != -1 || document.URL.indexOf('#' + encodeURIComponent(String.fromCharCode(10) + '<h1')) != -1 || document.URL.indexOf('#' + encodeURIComponent('<t')) != -1 || document.URL.indexOf('#' + encodeURIComponent(String.fromCharCode(10) + '<t')) != -1) {
if (document.URL.indexOf('#' + encodeURIComponent('<t')) != -1) {
if (document.URL.split('#' + encodeURIComponent('<t'))[1].substring(0,1) >= '0' && document.URL.split('#' + encodeURIComponent('<t'))[1].substring(0,1) <= '9') {
//alert(document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent('<t'))[1]);
document.getElementById('ifp').src=document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent('<t'))[1];
} else {
allbuthash=document.URL.split('#')[0];
document.getElementById('mytable').innerHTML='' + decodeURIComponent(document.URL.substring(document.URL.indexOf(encodeURIComponent('<t'))).replace(/\%7E/g,symbolize)) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
}
} else if (document.URL.indexOf('#' + encodeURIComponent(String.fromCharCode(10) + '<t')) != -1) {
if (document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<t'))[1].substring(0,1) >= '0' && document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<t'))[1].substring(0,1) <= '9') {
//alert(document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<t'))[1]);
document.getElementById('ifp').src=document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent('<t'))[1];
} else {
allbuthash=document.URL.split('#')[0];
document.getElementById('mytable').innerHTML='' + decodeURIComponent(document.URL.substring(document.URL.indexOf(encodeURIComponent(String.fromCharCode(10) + '<t'))).replace(/\%7E/g,symbolize)) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
}
} else if (document.URL.indexOf('#' + encodeURIComponent('<h1')) != -1) {
allbuthash=document.URL.split('#')[0];
document.body.innerHTML='<h1' + decodeURIComponent(document.URL.split('#' + encodeURIComponent('<h1'))[1]) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
} else {
allbuthash=document.URL.split('#')[0];
document.body.innerHTML='<h1' + decodeURIComponent(document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<h1'))[1]) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
}
thescore1=eval('' + document.getElementById('score1').innerHTML.replace('Score: ',''));
thescore2=eval('' + document.getElementById('score2').innerHTML.replace('Score: ',''));
if (document.URL.indexOf('winnerblurb=') != -1 && (document.URL + '&').indexOf('winnerblurb=&') == -1) {
//alert(87);
setTimeout(newremotegame, 3000);
} else {
//alert(487);
thetilearr.push('dominoes.png');
inithave();
}
pip1cnt=(location.search.split('pip1cnt=')[1] ? decodeURIComponent(location.search.split('pip1cnt=')[1].split('&')[0]) : pip1cnt);
pip2cnt=(location.search.split('pip2cnt=')[1] ? decodeURIComponent(location.search.split('pip2cnt=')[1].split('&')[0]) : pip2cnt);
}
}
}

… in the changed tenth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Mobile Speech to Text Tutorial is shown below.

Dominoes Horizontal Block Game Mobile Speech to Text Tutorial

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 …

  • Screen Mirroring
  • AirPlay
  • Handoff
  • QuickTime Player
  • Safari Web Inspector

… 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 …

… and, yes, the mobile Google Chrome web browser can help, though microphone usage security questions are asked. No biggie!.

And it’s means of Speech to Text (based on Google’s excellent Web Speech API Demonstration) can mean either …

  • 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” …


var lwds='', alldoneanddusted=false;

if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
everyfour=4;
}

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);
}

… in the changed ninth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Speech to Text Tutorial is shown below.

Dominoes Horizontal Block Game Speech to Text Tutorial

Dominoes Horizontal Block Game Speech to Text Tutorial

Today, we’ve added on to the functionality of yesterday’s Dominoes Horizontal Block Game Width Tutorial if

… with some changed PHP code of speech_supervisor.php with it’s Speech to Text means (based on Google’s excellent Web Speech API Demonstration) for a user to say what Domino tile they want to click rather than click it with a pointing means.

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 …


🎤

… with it’s on hover explanation …

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();
}
}
}
}

… in our changed seventh draft Dominoes Block Game you can try below.

Stop Press

“The Jiggles” in web applications can be a pain, especially regarding parent webpage calling child iframe arrangements, involving, perhaps …

  • [element].focus(); // calls … or, perhaps …
  • location.href=’#[elementID]’; // scenarios … or, perhaps …
  • [element].scrollIntoView(); // calls

We decided to undo some of the [element].focus(); we were doing for the iframe further tweaked PHP code of speech_supervisor.php Speech to Text we are invoking here, and time, more precisely, a parent created “refresh” of the “microphone being on” timed better for when a user might need to speak regarding our changed eighth draft Dominoes Block Game you can try below. This all working as an improvement, we reckon, gave us the confidence to loosen the “no arguments on the top window’s web browser’s address bar URL” restriction above, as a result.


Previous relevant Dominoes Horizontal Block Game Width Tutorial is shown below.

Dominoes Horizontal Block Game Width Tutorial

Dominoes Horizontal Block Game Width Tutorial

Specifically, it is your smaller mobile device …

width

… in their “portrait” modes of orientation, that is the focus of today’s work, further to yesterday’s Dominoes Horizontal Block Game Collaboration Tutorial, improving our Dominoes Horizontal Block Game here.

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 …

var everyfour=-1;

if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
everyfour=4;
}
Separate sets of images by a line break, as required using Javascript exemplified by …

var brhuh='';

huhlen=eval(-1 + eval('' + document.getElementById('seven1').innerHTML.split('<img').length));
for (ij=0; ij<player1arr.length; ij++) {
brhuh='';
if (everyfour > 0) {
if (eval(huhlen % 4) == 0) { brhuh='<br>'; }
}

document.getElementById('seven1').innerHTML+=brhuh + '<img onclick="goone(this);" style=width:80px; class="player1" id="' + player1arr[ij] + '" src="' + player1arr[ij] + '.png"></img>';
huhlen++;
brhuh='';
}
huhlen=eval(-1 + eval('' + document.getElementById('seven2').innerHTML.split('<img').length));
for (ij=0; ij<player1arr.length; ij++) {
brhuh='';
if (everyfour > 0) {
if (eval(huhlen % 4) == 0) { brhuh='<br>'; }
}

document.getElementById('seven2').innerHTML+=brhuh + '<img onclick="gotwo(this);" style=width:80px;filter:brightness(0); class="player2" id="' + player2arr[ij] + '" src="' + player2arr[ij] + '.png"></img>';
huhlen++;
brhuh='';
}
huhlen=eval(-1 + eval('' + document.getElementById('thstock').innerHTML.split('<img').length));
for (ij=0; ij<stockarr.length; ij++) {
bbrhuh='';
if (everyfour > 0) {
if (eval(huhlen % 7) == 0) { brhuh='<br>'; }
}

document.getElementById('thstock').innerHTML+=bbrhuh + '<img onclick="gostock(this);" style=width:80px;filter:brightness(0); class="stock" id="' + stockarr[ij] + '" src="' + stockarr[ij] + '.png"></img>';
huhlen++;
brhuh='';
}
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 …

<style>
#seven1 { text-align: right; }
#thstock { text-align: center; }
.right {
text-align: right;
margin-right: 1em;
}
.left {
text-align: left;
margin-left: 1em;
}
</style>
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)…

// For Player 1 (at left)
if (everyfour > 0) {
setTimeout(function(){
window.scrollTo({ left: 0 }); //, eval('' + document.getElementById('mytable').getBoundingClientRect().top)); //{ right: 0 }); //eval(0.3 * screen.width) });
setTimeout(function(){
document.getElementById('thtop').className='left'; //document.getElementById('thtop').style.float='lerft';
}, 989);
}, 989);
}
// For Player 2 (at right)
if (everyfour > 0) {
setTimeout(function(){
window.scrollTo({ left: eval('' + document.body.scrollWidth) }); //, eval('' + document.getElementById('mytable').getBoundingClientRect().top)); //{ right: 0 }); //eval(0.3 * screen.width) });
setTimeout(function(){
document.getElementById('thtop').className='right'; //document.getElementById('thtop').style.float='right';
}, 989);
}, 989);
}

… thanks to …

… regarding our changed fifth draft Dominoes Block Game you can try below, where you may discern, also …

  • some 3D looking shadow effects (via drop-shadow) in CSS …

    <style>
    img { filter: drop-shadow( 3px 3px 2px rgba(10, 10, 10, .7)); }
    button { filter: drop-shadow( 3px 3px 2px rgba(0, 0, 255, .7)); }
    </style>
  • thicker cell borders from 2px to 4px
  • some border-radius CSS nuance …

    <style>
    button { padding 8 8 8 8; border-radius: 20px; }
    td,th { border-radius: 6px; }
    </style>
  • 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 changed sixth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Collaboration Tutorial is shown below.

Dominoes Horizontal Block Game Collaboration Tutorial

Dominoes Horizontal Block Game Collaboration Tutorial

Onto yesterday’s Dominoes Horizontal Block Game User Experience Tutorial‘s progress regarding our Dominoes Horizontal Block Game …

  • as well as yesterday’s player “Turn Away Paradigm” for one device scenarios of play … today we add …
  • collaboration, via …
    1. email … or …
    2. 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

if (isset($_GET['intnum'])) {
//file_put_contents('./x.x', '1');
if (file_exists(dirname(__FILE__) . '/t' . $_GET['intnum'] . '.txt')) {
//file_put_contents('./x.x2', '1');
$innards=file_get_contents(dirname(__FILE__) . '/t' . $_GET['intnum'] . '.txt');
//file_put_contents('./x.x3', '1');
unlink(dirname(__FILE__) . '/t' . $_GET['intnum'] . '.txt');
//file_put_contents('./x.x4', "<html><body onload=\" parent.location.href=parent.document.URL.replace('#','&rd=' + Math.floor(Math.random() * 19897675) + '#').replace('%3Ct" . $_GET['intnum'] . "', '" . $innards . "'); \"></body></html>");
echo "<html><body onload=\" parent.location.href=parent.document.URL.replace('#','&rd=' + Math.floor(Math.random() * 19897675) + '#').replace('%3Ct" . $_GET['intnum'] . "', '" . $innards . "'); \"></body></html>";
//file_put_contents('./x.x5', '1');
exit;
}
} else if (isset($_POST['makenum'])) {
$newnum=rand(123,7876543);
//file_put_contents(dirname(__FILE__) . '/t' . $newnum . '.txt', str_replace('+','%20',urlencode($_POST['makenum'])));
echo "<html><body onload=\" parent.document.getElementById('makenum').title='" . $newnum . "'; parent.document.getElementById('asms').href=parent.document.getElementById('asms').href.split('tbody')[0] + 't" . $newnum . "'; \"></body></html>";
exit;
}

?>

… which is more trouble than we’d factored in for this change …

… regarding our changed fourth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game User Experience Tutorial is shown below.

Dominoes Horizontal Block Game User Experience Tutorial

Dominoes Horizontal Block Game User Experience Tutorial

To improve yesterday’s Dominoes Horizontal Block Game Tutorial

Turn Away From

… 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).

We can deploy this mainly through the external Javascript we talked about at Country Quizzes Beep Tutorial via …


<script type=text/javascript src='//www.rjmprogramming.com.au/beep.js?iam=song_lyric_faux_pas.html&rand=76576533' data-defer=defer></script>

That placement of one beep (for player 1 “turn away”) or two beeps (for player 2 “turn away”) can both tell players …

  • when they should turn away … as well as …
  • when they should re-engage

… regarding our changed third draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Tutorial is shown below.

Dominoes Horizontal Block Game Tutorial

Dominoes Horizontal Block Game Tutorial

After yesterday’s Dominoes Game Sections Tutorial we have a …

Dominoes Horizontal Block Game

… initially coded for. Why the “Horizontal” here? Well, to allow “vertical roaming” we need to think a bit more, on it.

This ask of Google … css flip image‘s …

To flip an image using CSS, use the transform property with either the scaleX() or scaleY() function.

Quick Reference

Horizontal Flip (Mirror):
transform: scaleX(-1);

Vertical Flip (Upside Down):
transform: scaleY(-1);

Both (180-degree rotation):
transform: scale(-1, -1);

transform: scaleX(-1) idea was useful, thanks, as was css filter to blacken image out‘s …

To completely blacken an image out using a CSS filter, use filter: brightness(0);.

Quick Reference

css.blackout-image {
filter: brightness(0);
}

… this idea, thanks applied to our changed second draft Dominoes Block Game you can try below.


Previous relevant Dominoes Game Sections Tutorial is shown below.

Dominoes Game Sections Tutorial

Dominoes Game Sections Tutorial

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.

And so, that is the plan regarding our first draft sections showing of proposed Dominoes Block Game, today.


Previous relevant Dominoes Game Resources Tutorial is shown below.

Dominoes Game Resources Tutorial

Dominoes Game Resources Tutorial

When creating an online web application game, like Animated Plane and Coconut Hunt Game Nuances Tutorial‘s Animated Plane and Coconut Hunt Game or games like playing card games, they involve “things” or …

nouns

… 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 …


Dominoes

… game, as an online web application. We vaguely remember Dominoes from a while back and it involves …

  1. dominoes (we think of as tiles) … as the resource …
  2. 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 …
  3. 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 …

    1. control-command-shift-3 of that webpage
    2. open macOS PaintBrush desktop application
    3. File -> New from Clipboard
    4. form rectangle around the white on black section of tiles
    5. Edit -> Copy
    6. File -> New from Clipboard
    7. File -> Save As… dominoes.png
  • 28 x
    1. form rectangle around the white on black subsection of dominoes.png
    2. Edit -> Copy
    3. File -> New from Clipboard
    4. File -> Save As… dominoes_[leftHandDotCount]_[rightHandDotCount].png
  • 7 x
    1. form rectangle around the uniquely encountered leftHandDotCount left hand side of a dominoes_[leftHandDotCount]_[rightHandDotCount].png
    2. Edit -> Copy
    3. File -> New from Clipboard
    4. 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 Apache Document 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 …


Why on an Apache and PHP web server is it a bad idea to not have an index.html nor index.htm nor index.php within a web server folder?

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.


Previous relevant Animated Plane and Coconut Hunt Game Nuances Tutorial is shown below.

Animated Plane and Coconut Hunt Game Nuances Tutorial

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 …
    1. some “panda 🐼 led recovery” modelling of a p emoji usage (with animation) and span emoji usage (without animation) … and …
    2. 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
  • allow for sharing of the Hunt Game
  • Hunt Game sound effects

Feel free to try these tweaks to our Animated Plane and Coconut Hunt Game, in a nuanced “latest draft” Animated Plane Coconut Hunt Game web application below!


Previous relevant Coconut Hunt Game Tutorial is shown below.

Coconut Hunt Game Tutorial

Coconut Hunt Game Tutorial

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 …

I shell always love you.

? 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!


Previous relevant Animated Plane Game User Animations and Styling Tutorial is shown below.

Animated Plane Game User Animations and Styling Tutorial

Animated Plane Game User Animations and Styling Tutorial

On top of yesterday’s Animated Plane Game User Content Sharing Tutorial‘s honing in on the five “nouns” of interest …

  • trees
  • plane
  • gymnast
  • clouds
  • ground

… 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 …
    1. @keyframes
    2. transition

    … 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!

Try this in the changed “latest draft” Animated Plane Game web application below.

Did you know?

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>


Previous relevant Animated Plane Game User Content Sharing Tutorial is shown below.

Animated Plane Game User Content Sharing Tutorial

Animated Plane Game User Content Sharing Tutorial

Yesterday’s Animated Plane Game Primer Tutorial set up five “nouns” of interest …

  • trees
  • plane
  • gymnast
  • clouds
  • ground

… 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;

case '5': // ground
if ((opsd + ' ').substring(0,2) == '5:') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + (opsd + ' ').substring(2) + suffixbiu + '") !important; </sty' + 'le>'
} else {
opsd=prompt('Enter your (probably quite long) emoji (we are guessing) border image text.', '');
if (opsd != null) {
if (opsd != '') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + suffixbiu + '") !important; </sty' + 'le>'
} else {
groundalt='&groundalt='; // + encodeURIComponent(opsd);
document.body.style.borderImage='none';
document.body.style.borderBottom='1px solid transparent';
document.body.style.borderBottomWidth='0px';
//document.body.innerHTML+='<sty' + 'le> body { border-bottom-width:0px !important; } </sty' + 'le>';
}
}
}
break;

case 'e': // email
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.trim().indexOf('@') != -1) {
anchor.href = 'mailto:' + opsd.split('@')[0].split(' ')[eval(-1 + opsd.split('@')[0].split(' ').length)] + opsd.split(opsd.split('@')[0])[1].split(' ')[0] + '?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'mailto:?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

case 's': // SMS
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.substring(0,1).toLowerCase() == '+') {
anchor.href = 'sms:' + opsd.split(' ')[0] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else if (opsd.indexOf(' ') != -1) {
anchor.href = 'sms:' + opsd.split(' ')[eval(-1 + opsd.split(' ').length)] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

default:
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
break;
}
} else {
setTimeout(function(){ ino.click(); }, 100); return true;
}
isac=false;
return false;
}

function anyprompt(opsd) {
if (opsd.trim() != '') {
opsd=opsd;
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;

case '5': // ground
if ((opsd + ' ').substring(0,2) == '5:') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + (opsd + ' ').substring(2) + suffixbiu + '") !important; </sty' + 'le>'
} else {
opsd=prompt('Enter your (probably quite long) emoji (we are guessing) border image text.', '');
if (opsd != null) {
if (opsd != '') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + suffixbiu + '") !important; </sty' + 'le>'
} else {
groundalt='&groundalt='; // + encodeURIComponent(opsd);
document.body.style.borderImage='none';
document.body.style.borderBottom='1px solid transparent';
document.body.style.borderBottomWidth='0px';
//document.body.innerHTML+='<sty' + 'le> body { border-bottom-width:0px !important; } </sty' + 'le>';
}
}
}
break;

case 'e': // email
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.trim().indexOf('@') != -1) {
anchor.href = 'mailto:' + opsd.split('@')[0].split(' ')[eval(-1 + opsd.split('@')[0].split(' ').length)] + opsd.split(opsd.split('@')[0])[1].split(' ')[0] + '?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'mailto:?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

case 's': // SMS
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.substring(0,1).toLowerCase() == '+') {
anchor.href = 'sms:' + opsd.split(' ')[0] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else if (opsd.indexOf(' ') != -1) {
anchor.href = 'sms:' + opsd.split(' ')[eval(-1 + opsd.split(' ').length)] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

default:
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
break;
}
}
}

function ourprompt(ino, intlis) {
var ei=-1, si=-1;
isac=true;
var opsd=null;
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
opsd=prompt(intlis + String.fromCharCode(10) + String.fromCharCode(10) + intlis, '');
} else {
opsd=prompt(getsrc(document.getElementById('myimg').outerHTML), '');
}
if (opsd == null) { isac=false; return false; }
if (opsd.trim() != '') {
opsd=opsd;
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;

case '5': // ground
if ((opsd + ' ').substring(0,2) == '5:') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + (opsd + ' ').substring(2) + suffixbiu + '") !important; </sty' + 'le>'
} else {
opsd=prompt('Enter your (probably quite long) emoji (we are guessing) border image text.', '');
if (opsd != null) {
if (opsd != '') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + suffixbiu + '") !important; </sty' + 'le>'
} else {
groundalt='&groundalt='; // + encodeURIComponent(opsd);
document.body.style.borderImage='none';
document.body.style.borderBottom='1px solid transparent';
document.body.style.borderBottomWidth='0px';
//document.body.innerHTML+='<sty' + 'le> body { border-bottom-width:0px !important; } </sty' + 'le>';
}
}
}
break;

case 'e': // email
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.trim().indexOf('@') != -1) {
anchor.href = 'mailto:' + opsd.split('@')[0].split(' ')[eval(-1 + opsd.split('@')[0].split(' ').length)] + opsd.split(opsd.split('@')[0])[1].split(' ')[0] + '?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'mailto:?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

case 's': // SMS
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.substring(0,1).toLowerCase() == '+') {
anchor.href = 'sms:' + opsd.split(' ')[0] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else if (opsd.indexOf(' ') != -1) {
anchor.href = 'sms:' + opsd.split(' ')[eval(-1 + opsd.split(' ').length)] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

default:
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
break;
}
} else {
setTimeout(function(){ ino.click(); }, 100); return true;
}
isac=false;
return false;
}

… in the changed “eighth draft” Animated Plane Game web application.


Previous relevant Animated Plane Game Primer Tutorial is shown below.

Animated Plane Game Primer Tutorial

Animated Plane Game Primer Tutorial

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 Freepik image plane image animated with a rudimentary green border-bottom representing the ground …
then to “second draft” … adding https://i.makeagif.com/media/8-11-2023/Xu_roP.gif animated GIF cloud background to go with edited Freepik image because mix-blend-mode:multiply will not mask out the non heterogenous bluish clouds in the image …
then to “third draft” … tweaking https://i.makeagif.com/media/8-11-2023/Xu_roP.gif animated GIF cloud background … …
then to “fourth draft” … establishing an SVG+XML (with SVG text emoji content) border-image for the bottom border representing the ground …
then to “fifth draft” … added acknowledgements for all the help …

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 https://au.pinterest.com/pin/587930926347995281/ 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 https://giphy.com/explore/trees-swaying-stickers giphy.com/explore/trees-swaying-stickers animated (and transparently backgrounded) webp swaying trees image along with tweaked Freepik image 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.

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

Horizontal Game Soft Link Resources Tutorial

Horizontal Game Soft Link Resources Tutorial

Horizontal Game Soft Link Resources Tutorial

After yesterday’s Horizontal Block Game CSS Animation Tutorial, today we’re revisiting …

resources

… 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 …


Soft Links

(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)) …


#!/bin/ksh
# dominoes_(3 + 1)_(9 % 7).png ... then swap as required
ln -s dominoes_2_4.png dominoes_1_9.png
ln -s dominoes_1_4.png dominoes_1_8.png
ln -s dominoes_0_4.png dominoes_1_7.png

# dominoes_(3 + 0)_(9 % 7).png ... then swap as required
ln -s dominoes_2_3.png dominoes_0_9.png
ln -s dominoes_1_3.png dominoes_0_8.png
ln -s dominoes_0_3.png dominoes_0_7.png

# dominoes_(3 + 2)_(9 % 7).png ... then swap as required
ln -s dominoes_2_5.png dominoes_2_9.png
ln -s dominoes_1_5.png dominoes_2_8.png
ln -s dominoes_0_5.png dominoes_2_7.png

ln -s dominoes_0_1.png dominoes_1_0.png
ln -s dominoes_0_2.png dominoes_2_0.png
ln -s dominoes_0_3.png dominoes_3_0.png
ln -s dominoes_0_4.png dominoes_4_0.png
ln -s dominoes_0_5.png dominoes_5_0.png
ln -s dominoes_0_6.png dominoes_6_0.png

ln -s dominoes_1_2.png dominoes_2_1.png
ln -s dominoes_1_3.png dominoes_3_1.png
ln -s dominoes_1_4.png dominoes_4_1.png
ln -s dominoes_1_5.png dominoes_5_1.png
ln -s dominoes_1_6.png dominoes_6_1.png

ln -s dominoes_2_3.png dominoes_3_2.png
ln -s dominoes_2_4.png dominoes_4_2.png
ln -s dominoes_2_5.png dominoes_5_2.png
ln -s dominoes_2_6.png dominoes_6_2.png

ln -s dominoes_3_4.png dominoes_4_3.png
ln -s dominoes_3_5.png dominoes_5_3.png
ln -s dominoes_3_6.png dominoes_6_3.png

ln -s dominoes_4_5.png dominoes_5_4.png
ln -s dominoes_4_6.png dominoes_6_4.png

ln -s dominoes_5_6.png dominoes_6_5.png

… and in our web server’s cPanel Terminal ran that via …


ksh -x dominoes_more.ksh

… to create soft links, so that …


# 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 concept through.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.


Previous relevant Horizontal Block Game CSS Animation Tutorial is shown below.

Horizontal Block Game CSS Animation Tutorial

Horizontal Block Game CSS Animation Tutorial

Today we …

  • extend yesterday’s Horizontal Block Game Random Image Types Tutorial‘s ondblclick and oncontextmenu (or ontouchmove) “drill downs” to other Wikipedia image Block Game choices … and …
  • allow for a CSS @keyframes animation definition to affect …
    CSS @keyframes animation default initialization that may be dynamically called into play at a later time …

    <style>
    @keyframes myanim { 0%, 58.33% { filter: invert(0%) contrast(100%); } 75%, 100% { filter: invert(100%) contrast(800%); } }
    </style>

    … and editable via Javascript …

    animans=prompt('Optionally enter CSS @keyframes animation definition.', (animval == 'y' ? document.getElementById('mysel').getAttribute('data-anim') : animval));

    … via a new dropdown option …
    Optionally passed across in a new animated argument, processed by initialization Javascript …

    var animgprefix='', animgsuffix='';
    var animval='y', animdef="@keyframes myanim { 0%, 58.33% { filter: invert(0%) contrast(100%); } 75%, 100% { filter: invert(100%) contrast(800%); } } ";
    var animclass=(location.search.split('animated=')[1] ? decodeURIComponent(location.search.split('animated=')[1].split('&')[0]) : '');
    if (animclass != '') {
    if (('' + animclass).toLowerCase().indexOf('@keyframes') != -1) { animval=animclass; } else if (('' + animclass).toLowerCase() == 'y') { animval=animdef; }
    animclass=' animated';
    }

    … as well as document.body onload called …

    if (('' + animval).toLowerCase().indexOf('@keyframes') != -1) {
    if (animval != document.getElementById('mysel').getAttribute('data-anim')) {
    document.getElementById('mysel').setAttribute('data-anim', animval);
    }
    document.getElementById('dstyle').innerHTML+='<st' + 'yle> ' + animval + ' </st' + 'yle>';
    document.getElementById('optanim').innerHTML='Animation ' + animval + ' ... ';
    }
    In Play at the time of relevance …

    <style>
    .animated:not([style*="filter"]) { animation: myanim 12s infinite; }
    </style>
    Javascript dynamically called into play wherever in the code

    document.getElementById('dstyle').innerHTML+='<st' + 'yle> ' + animval + ' </st' + 'yle>';

    … and relevant HTML elements have class=animated applied to them dynamically … for example

    document.getElementById('seven1').innerHTML+=brhuh + othersmaybe('<img' + (animclass == '' ? '' : ' class=animated') + ' draggable="true" ondragstart="goone(event.target);" onclick="goone(this);" style=width:80px; class="player1" id="' + player1arr[ij] + '" src="' + player1arr[ij] + '.png"></img>');

    … happens …

… to add to the changed seventeenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Random Image Types Tutorial is shown below.

Horizontal Block Game Random Image Types Tutorial

Horizontal Block Game Random Image Types Tutorial

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 …

… offering both …

  • image randomosity possibilities … as well as …
  • means to recall same content

… via ondblclick …


function odc(evt) {
var evttarget=evt.target, spanarr=[], jspan=0;
evt.stopPropagation();
if (evttarget.outerHTML.indexOf('<img') == 0) {
spanarr=document.getElementsByTagName('span');
for (jspan=0; jspan<spanarr.length; jspan++) {
if (evttarget.outerHTML.indexOf('<img') == 0) {
if (spanarr[jspan].innerHTML.indexOf(evt.target.outerHTML) != -1) { evttarget=spanarr[jspan]; }
}
}
}
if (eval('' + evttarget.innerHTML.split(' data-url="').length) >= 2) {
etarget=evttarget;
window.open(evttarget.innerHTML.split(' data-url="')[1].split('"')[0], '_blank', 'top=10,left=' + eval(-600 + screen.width) + ',width=600,height=800');
}
}

… and oncontextmenu (or ontouchmove) …


function onc(evt) {
var evttarget=evt.target, spanarr=[], jspan=0;
evt.preventDefault();
if (evttarget.outerHTML.indexOf('<img') == 0) {
spanarr=document.getElementsByTagName('span');
for (jspan=0; jspan<spanarr.length; jspan++) {
if (evttarget.outerHTML.indexOf('<img') == 0) {
if (spanarr[jspan].innerHTML.indexOf(evt.target.outerHTML) != -1) { evttarget=spanarr[jspan]; }
}
}
}
if (eval('' + evttarget.innerHTML.split(' data-url="').length) >= 3) {
window.open(evttarget.innerHTML.split(' data-url="')[2].split('"')[0], '_blank', 'top=10,left=' + eval(-600 + screen.width) + ',width=600,height=800');
}
}

… conduits, for an inquisitive user, as well, in the changed sixteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Less Personal Types Tutorial is shown below.

Horizontal Block Game Less Personal Types Tutorial

Horizontal Block Game Less Personal Types Tutorial

Onto yesterday’s Horizontal Block Game Personalized Second Image Type Tutorial‘s new Horizontal Block Game types, today, we add a variety more number of emoji and image type game incarnations, as per …

… 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)


document.getElementById('sele').style.position='absolute';
osel.style.width='290px';
document.getElementById('sele').style.left='' + eval(-30 + eval('' + osel.getBoundingClientRect().right)) + 'px';
document.getElementById('sele').style.top='' + eval(36 + eval('' + osel.getBoundingClientRect().top)) + 'px';
document.getElementById('sele').style.zIndex='211';
document.getElementById('sele').style.display='block';

… in the changed fifteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Personalized Second Image Type Tutorial is shown below.

Horizontal Block Game Personalized Second Image Type Tutorial

Horizontal Block Game Personalized Second Image Type Tutorial

After yesterday’s Horizontal Block Game Types Tutorial a cruel streak in us might say …

Emojis Smemojis

… 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 …


<style> .dominoes0:after { background-image:url(//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/St_Mary%27s_Cathedral_-_panoramio.jpg/250px-St_Mary%27s_Cathedral_-_panoramio.jpg?utm_source=en.wikipedia.org&utm_campaign=parser&utm_content=thumbnail); background-size:cover; background-repeat:no-repeat; color:transparent; } </style>

… added as the need arises.

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 changed fourteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Types Tutorial is shown below.

Horizontal Block Game Types Tutorial

Horizontal Block Game Types Tutorial

Do you remember, way before yesterday’s Dominoes Horizontal Block Game Drag Tutorial, way back at Dominoes Horizontal Block Game Width Tutorial, we commented …

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;
}
}
New initialization Javascript function …

function alat() {
document.getElementById('gtype').innerHTML=othertype;
if (anothertype != 'shapeis' && document.getElementById('dstyle').innerHTML.indexOf('.dominoes0') == -1) {
eval(' numarr=' + anothertype + '.length');
while (eval('' + newtypes.length) < 7) {
thisemhe=Math.floor(Math.random() * numarr);
while (newtypes.indexOf(thisemhe) != -1) {
thisemhe=Math.floor(Math.random() * numarr);
}
eval(' thisem=' + anothertype + '[' + thisemhe + ']');
if (thisem.indexOf(String.fromCharCode(92)) != -1) {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '" + thisem + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
} else if (thisem.indexOf('x') != -1) {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '\\" + ('000000' + ('' + thisem.replace(String.fromCharCode(92),"").replace("0x","").toString(16).padStart(2, '0'))).slice(-6).replace(/\ /g,'0') + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
} else if (thisem.toLowerCase().indexOf('a') != -1 || thisem.toLowerCase().indexOf('b') != -1 || thisem.toLowerCase().indexOf('c') != -1 || thisem.toLowerCase().indexOf('d') != -1 || thisem.toLowerCase().indexOf('e') != -1 || thisem.toLowerCase().indexOf('f') != -1) {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '\\" + ('000000' + ('' + thisem)).slice(-6).replace(/\ /g,'0') + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
} else {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '\\" + ('000000' + eval(thisem).toString(16).padStart(2, '0')).slice(-6) + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
}
}
}
}
Augmented other Javascript functions …

function lessen(inthih) {
return inthih.replace(/visible/g, 'hidden');
alert('lessen this ' + inthih + ' to ' + inthih.replace('><img', '--><img').replace('<', '<!--').replace(/<span/g, '<!--span').replace(/<\/span>/g, '</span-->'));
return inthih.replace('><img', '--><img').replace('<', '<!--').replace(/<span/g, '<!--span').replace(/<\/span>/g, '</span-->');
}

function fixdomlr() {
if (newspanoid != '') {
if (document.getElementById('p' + newspanoid)) {
if (document.getElementById('p' + newspanoid).innerHTML.indexOf('(-1)') != -1) {
document.getElementById('p' + newspanoid).innerHTML=document.getElementById('p' + newspanoid).innerHTML.replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
}
if (document.getElementById(newspanoid)) {
if (document.getElementById('seven1').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(1);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
} else if (document.getElementById('seven2').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(2);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
}
document.getElementById(newspanoid).innerHTML=document.getElementById(newspanoid).innerHTML.replace(/visible/g,'hidden'); //alert('and then ' + document.getElementById(newspanoid).outerHTML);
}
} else if (document.getElementById('s' + newspanoid)) {
if (document.getElementById('s' + newspanoid).innerHTML.indexOf('(-1)') != -1) {
document.getElementById('s' + newspanoid).innerHTML=document.getElementById('s' + newspanoid).innerHTML.replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
}
if (document.getElementById(newspanoid)) {
if (document.getElementById('seven1').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(3);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
} else if (document.getElementById('seven2').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(4);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
}
document.getElementById(newspanoid).innerHTML=document.getElementById(newspanoid).innerHTML.replace(/visible/g,'hidden'); //alert('anD then ' + document.getElementById(newspanoid).outerHTML);
}
} else if (document.getElementById(newspanoid)) {
if (document.getElementById(newspanoid).innerHTML.indexOf('(-1)') != -1) {
document.getElementById('' + newspanoid).innerHTML=document.getElementById('' + newspanoid).innerHTML.replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
}
}
}
newspanoid='';
}

function othersmaybe(inimg) {
var lbit='', rbit='';
newspano=null;
if (inimg.indexOf(cgostock) != -1) { return inimg; }
//if (inimg.indexOf(' draggable="false') != -1) { return inimg; }
if (animgprefix != '') {
// do more here perhaps
if (inimg.indexOf('dominoes_') != -1) {
lbit=inimg.split('dominoes_')[1].substring(0,1);
rbit=inimg.split('dominoes_')[1].split('_')[1].substring(0,1);
if (document.getElementById('dom' + lbit + rbit)) {
//alert('already there ' + inimg);
newspano=document.getElementById('dom' + lbit + rbit);
newspanoid='dom' + lbit + rbit;
if (newspano) {
setTimeout(fixdomlr, 500);
}
}
animgprefix=templateprefix.replace(' ', ' id="dom' + lbit + rbit + '" ');
if (inimg.indexOf('(0)') != -1) {
if (inimg.indexOf('(-1)') != -1) {
//alert(43);
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"').replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ').replace(/visible/g,'hidden');
} else {
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"').replace(/visible/g,'hidden');
}
} else {
if (inimg.indexOf('(-1)') != -1) {
//alert(4);
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"').replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
} else {
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"');
}
}
}

}
//alert(inimg);
if (nestero) {
nestero.className+=' disnon';
nestero=null;
}
return animgprefix + inimg + animgsuffix;
}

function typeize(osel) {
if (osel.value != '') {
if (osel.value.toLowerCase() == 'email') {
var anchor = document.createElement('a');
anchor.target='_top';
anchor.href = 'mailto:?subject=' + (othertype == '' ? 'Dominoes' : othertype) + '%20Game%20snapshot&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?type=' + othertype + '&rand=' + Math.floor(Math.random() * 1989786) + '&score1=' + document.getElementById('score1').innerHTML.replace('Score: ','') + '&score2=' + document.getElementById('score2').innerHTML.replace('Score: ','') + '#' + encodeURIComponent(document.body.innerHTML.split('<fo' + 'rm ')[0].split('<a' + ' target="_top"')[0]));
document.body.appendChild(anchor);
anchor.click();
anchor.remove();
} else {
othertype=osel.value.replace('Dominoes','');
newstockgame();
}
osel.value='';
}
}
New CSS styling …

<style>
.image-wrapper {
position: relative; /* Acts as the anchor point */
display: inline-block;
}

.image-wrapper img {
display: block;
width: 80px; /* Set your desired image width */
height: auto;
opacity:0.2; /* visibility: hidden; */
filter: url('#edge-detection');
}

.disnon span {
display: none;
}

.domr {
position: absolute;
top: -6px; /* Distance from the top edge */
right: 0px; /* Distance from the right edge */
font-size: 45px; /* Adjust emoji size */
pointer-events: none;
}

.doml {
position: absolute;
top: -6px; /* Distance from the top edge */
left: 0px; /* Distance from the right edge */
font-size: 45px; /* Adjust emoji size */
border-right: 1px solid black;
pointer-events: none;
}

.dominoes0:after {
content: '\002739';
}

.dominoes1:after {
content: '\002737';
}

.dominoes2:after {
content: '\002729';
}

.dominoes3:after {
content: '\002727';
}

.dominoes4:after {
content: '\002719';
}

.dominoes5:after {
content: '\002724';
}

.dominoes6:after {
content: '\002713';
}
</style>

… thanks, a lot, to Google’s overlay emoji characters on top of html img element‘s (back to W3schools‘s) advice in the changed thirteenth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Drag Tutorial is shown below.

Dominoes Horizontal Block Game Drag Tutorial

Dominoes Horizontal Block Game Drag Tutorial

Another layer of thinking onto yesterday’s Dominoes Horizontal Blocked Game Tutorial, we think, can be …

drag

andnot drop new Javascript logic. This last idea, where only what happens to HTML img element (by default draggable=”true”) …

  1. draggable … attribute “true” for “dragging available” and “false” for “dragging not available” … and …
  2. 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-nilly drop 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>';

… in the changed twelfth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Blocked Game Tutorial is shown below.

Dominoes Horizontal Blocked Game Tutorial

Dominoes Horizontal Blocked Game Tutorial

Playing a Dominoes Horizontal Block Game after yesterday’s Dominoes Horizontal Block Game Handoff Friendly Tutorial was where we realized you could have a “stalemate” (in chess parlance) in a Dominoes game, as per “what is stalemate called in a dominoes game”

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 …

  1. we turned a hardcopy into a span, potentially dynamic, element …

    <h1 id=myh1>Dominoes Horizontal Block <span id=sgame>Game</span></h1>
  2. 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';
    }
    }

  3. 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

… in the changed eleventh draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Handoff Friendly Tutorial is shown below.

Dominoes Horizontal Block Game Handoff Friendly Tutorial

Dominoes Horizontal Block Game Handoff Friendly Tutorial

After yesterday’s Dominoes Horizontal Block Game Mobile Speech to Text Tutorial we started delving more into Apple’s Handoff concepts here sharing between an iPhone and a MacBook Air …

  • on same WiFi network
  • Bluetooth on

… 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 …


lhis='#' + encodeURIComponent(document.body.innerHTML);
prevlhis=lhis;
location.href=lhis;

… as a way to tell Handoff, if used, situations in the Domino game had changed.

Also, we needed to, at document.body onload, code …


lhis=('' + location.hash);
prevlhis=lhis;
setInterval(lhcheck, 5000);

… utilizing new Javascript function …


function lhcheck() {
lhis=('' + location.hash);
if (prevlhis != lhis) {
prevlhis=lhis;
if (document.URL.indexOf('#' + encodeURIComponent('<h1')) != -1 || document.URL.indexOf('#' + encodeURIComponent(String.fromCharCode(10) + '<h1')) != -1 || document.URL.indexOf('#' + encodeURIComponent('<t')) != -1 || document.URL.indexOf('#' + encodeURIComponent(String.fromCharCode(10) + '<t')) != -1) {
if (document.URL.indexOf('#' + encodeURIComponent('<t')) != -1) {
if (document.URL.split('#' + encodeURIComponent('<t'))[1].substring(0,1) >= '0' && document.URL.split('#' + encodeURIComponent('<t'))[1].substring(0,1) <= '9') {
//alert(document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent('<t'))[1]);
document.getElementById('ifp').src=document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent('<t'))[1];
} else {
allbuthash=document.URL.split('#')[0];
document.getElementById('mytable').innerHTML='' + decodeURIComponent(document.URL.substring(document.URL.indexOf(encodeURIComponent('<t'))).replace(/\%7E/g,symbolize)) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
}
} else if (document.URL.indexOf('#' + encodeURIComponent(String.fromCharCode(10) + '<t')) != -1) {
if (document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<t'))[1].substring(0,1) >= '0' && document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<t'))[1].substring(0,1) <= '9') {
//alert(document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<t'))[1]);
document.getElementById('ifp').src=document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent('<t'))[1];
} else {
allbuthash=document.URL.split('#')[0];
document.getElementById('mytable').innerHTML='' + decodeURIComponent(document.URL.substring(document.URL.indexOf(encodeURIComponent(String.fromCharCode(10) + '<t'))).replace(/\%7E/g,symbolize)) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
}
} else if (document.URL.indexOf('#' + encodeURIComponent('<h1')) != -1) {
allbuthash=document.URL.split('#')[0];
document.body.innerHTML='<h1' + decodeURIComponent(document.URL.split('#' + encodeURIComponent('<h1'))[1]) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
} else {
allbuthash=document.URL.split('#')[0];
document.body.innerHTML='<h1' + decodeURIComponent(document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<h1'))[1]) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
}
thescore1=eval('' + document.getElementById('score1').innerHTML.replace('Score: ',''));
thescore2=eval('' + document.getElementById('score2').innerHTML.replace('Score: ',''));
if (document.URL.indexOf('winnerblurb=') != -1 && (document.URL + '&').indexOf('winnerblurb=&') == -1) {
//alert(87);
setTimeout(newremotegame, 3000);
} else {
//alert(487);
thetilearr.push('dominoes.png');
inithave();
}
pip1cnt=(location.search.split('pip1cnt=')[1] ? decodeURIComponent(location.search.split('pip1cnt=')[1].split('&')[0]) : pip1cnt);
pip2cnt=(location.search.split('pip2cnt=')[1] ? decodeURIComponent(location.search.split('pip2cnt=')[1].split('&')[0]) : pip2cnt);
}
}
}

… in the changed tenth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Mobile Speech to Text Tutorial is shown below.

Dominoes Horizontal Block Game Mobile Speech to Text Tutorial

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 …

  • Screen Mirroring
  • AirPlay
  • Handoff
  • QuickTime Player
  • Safari Web Inspector

… 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 …

… and, yes, the mobile Google Chrome web browser can help, though microphone usage security questions are asked. No biggie!.

And it’s means of Speech to Text (based on Google’s excellent Web Speech API Demonstration) can mean either …

  • 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” …


var lwds='', alldoneanddusted=false;

if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
everyfour=4;
}

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);
}

… in the changed ninth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Speech to Text Tutorial is shown below.

Dominoes Horizontal Block Game Speech to Text Tutorial

Dominoes Horizontal Block Game Speech to Text Tutorial

Today, we’ve added on to the functionality of yesterday’s Dominoes Horizontal Block Game Width Tutorial if

… with some changed PHP code of speech_supervisor.php with it’s Speech to Text means (based on Google’s excellent Web Speech API Demonstration) for a user to say what Domino tile they want to click rather than click it with a pointing means.

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 …


🎤

… with it’s on hover explanation …

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();
}
}
}
}

… in our changed seventh draft Dominoes Block Game you can try below.

Stop Press

“The Jiggles” in web applications can be a pain, especially regarding parent webpage calling child iframe arrangements, involving, perhaps …

  • [element].focus(); // calls … or, perhaps …
  • location.href=’#[elementID]’; // scenarios … or, perhaps …
  • [element].scrollIntoView(); // calls

We decided to undo some of the [element].focus(); we were doing for the iframe further tweaked PHP code of speech_supervisor.php Speech to Text we are invoking here, and time, more precisely, a parent created “refresh” of the “microphone being on” timed better for when a user might need to speak regarding our changed eighth draft Dominoes Block Game you can try below. This all working as an improvement, we reckon, gave us the confidence to loosen the “no arguments on the top window’s web browser’s address bar URL” restriction above, as a result.


Previous relevant Dominoes Horizontal Block Game Width Tutorial is shown below.

Dominoes Horizontal Block Game Width Tutorial

Dominoes Horizontal Block Game Width Tutorial

Specifically, it is your smaller mobile device …

width

… in their “portrait” modes of orientation, that is the focus of today’s work, further to yesterday’s Dominoes Horizontal Block Game Collaboration Tutorial, improving our Dominoes Horizontal Block Game here.

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 …

var everyfour=-1;

if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
everyfour=4;
}
Separate sets of images by a line break, as required using Javascript exemplified by …

var brhuh='';

huhlen=eval(-1 + eval('' + document.getElementById('seven1').innerHTML.split('<img').length));
for (ij=0; ij<player1arr.length; ij++) {
brhuh='';
if (everyfour > 0) {
if (eval(huhlen % 4) == 0) { brhuh='<br>'; }
}

document.getElementById('seven1').innerHTML+=brhuh + '<img onclick="goone(this);" style=width:80px; class="player1" id="' + player1arr[ij] + '" src="' + player1arr[ij] + '.png"></img>';
huhlen++;
brhuh='';
}
huhlen=eval(-1 + eval('' + document.getElementById('seven2').innerHTML.split('<img').length));
for (ij=0; ij<player1arr.length; ij++) {
brhuh='';
if (everyfour > 0) {
if (eval(huhlen % 4) == 0) { brhuh='<br>'; }
}

document.getElementById('seven2').innerHTML+=brhuh + '<img onclick="gotwo(this);" style=width:80px;filter:brightness(0); class="player2" id="' + player2arr[ij] + '" src="' + player2arr[ij] + '.png"></img>';
huhlen++;
brhuh='';
}
huhlen=eval(-1 + eval('' + document.getElementById('thstock').innerHTML.split('<img').length));
for (ij=0; ij<stockarr.length; ij++) {
bbrhuh='';
if (everyfour > 0) {
if (eval(huhlen % 7) == 0) { brhuh='<br>'; }
}

document.getElementById('thstock').innerHTML+=bbrhuh + '<img onclick="gostock(this);" style=width:80px;filter:brightness(0); class="stock" id="' + stockarr[ij] + '" src="' + stockarr[ij] + '.png"></img>';
huhlen++;
brhuh='';
}
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 …

<style>
#seven1 { text-align: right; }
#thstock { text-align: center; }
.right {
text-align: right;
margin-right: 1em;
}
.left {
text-align: left;
margin-left: 1em;
}
</style>
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)…

// For Player 1 (at left)
if (everyfour > 0) {
setTimeout(function(){
window.scrollTo({ left: 0 }); //, eval('' + document.getElementById('mytable').getBoundingClientRect().top)); //{ right: 0 }); //eval(0.3 * screen.width) });
setTimeout(function(){
document.getElementById('thtop').className='left'; //document.getElementById('thtop').style.float='lerft';
}, 989);
}, 989);
}
// For Player 2 (at right)
if (everyfour > 0) {
setTimeout(function(){
window.scrollTo({ left: eval('' + document.body.scrollWidth) }); //, eval('' + document.getElementById('mytable').getBoundingClientRect().top)); //{ right: 0 }); //eval(0.3 * screen.width) });
setTimeout(function(){
document.getElementById('thtop').className='right'; //document.getElementById('thtop').style.float='right';
}, 989);
}, 989);
}

… thanks to …

… regarding our changed fifth draft Dominoes Block Game you can try below, where you may discern, also …

  • some 3D looking shadow effects (via drop-shadow) in CSS …

    <style>
    img { filter: drop-shadow( 3px 3px 2px rgba(10, 10, 10, .7)); }
    button { filter: drop-shadow( 3px 3px 2px rgba(0, 0, 255, .7)); }
    </style>
  • thicker cell borders from 2px to 4px
  • some border-radius CSS nuance …

    <style>
    button { padding 8 8 8 8; border-radius: 20px; }
    td,th { border-radius: 6px; }
    </style>
  • 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 changed sixth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Collaboration Tutorial is shown below.

Dominoes Horizontal Block Game Collaboration Tutorial

Dominoes Horizontal Block Game Collaboration Tutorial

Onto yesterday’s Dominoes Horizontal Block Game User Experience Tutorial‘s progress regarding our Dominoes Horizontal Block Game …

  • as well as yesterday’s player “Turn Away Paradigm” for one device scenarios of play … today we add …
  • collaboration, via …
    1. email … or …
    2. 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

if (isset($_GET['intnum'])) {
//file_put_contents('./x.x', '1');
if (file_exists(dirname(__FILE__) . '/t' . $_GET['intnum'] . '.txt')) {
//file_put_contents('./x.x2', '1');
$innards=file_get_contents(dirname(__FILE__) . '/t' . $_GET['intnum'] . '.txt');
//file_put_contents('./x.x3', '1');
unlink(dirname(__FILE__) . '/t' . $_GET['intnum'] . '.txt');
//file_put_contents('./x.x4', "<html><body onload=\" parent.location.href=parent.document.URL.replace('#','&rd=' + Math.floor(Math.random() * 19897675) + '#').replace('%3Ct" . $_GET['intnum'] . "', '" . $innards . "'); \"></body></html>");
echo "<html><body onload=\" parent.location.href=parent.document.URL.replace('#','&rd=' + Math.floor(Math.random() * 19897675) + '#').replace('%3Ct" . $_GET['intnum'] . "', '" . $innards . "'); \"></body></html>";
//file_put_contents('./x.x5', '1');
exit;
}
} else if (isset($_POST['makenum'])) {
$newnum=rand(123,7876543);
//file_put_contents(dirname(__FILE__) . '/t' . $newnum . '.txt', str_replace('+','%20',urlencode($_POST['makenum'])));
echo "<html><body onload=\" parent.document.getElementById('makenum').title='" . $newnum . "'; parent.document.getElementById('asms').href=parent.document.getElementById('asms').href.split('tbody')[0] + 't" . $newnum . "'; \"></body></html>";
exit;
}

?>

… which is more trouble than we’d factored in for this change …

… regarding our changed fourth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game User Experience Tutorial is shown below.

Dominoes Horizontal Block Game User Experience Tutorial

Dominoes Horizontal Block Game User Experience Tutorial

To improve yesterday’s Dominoes Horizontal Block Game Tutorial

Turn Away From

… 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).

We can deploy this mainly through the external Javascript we talked about at Country Quizzes Beep Tutorial via …


<script type=text/javascript src='//www.rjmprogramming.com.au/beep.js?iam=song_lyric_faux_pas.html&rand=76576533' data-defer=defer></script>

That placement of one beep (for player 1 “turn away”) or two beeps (for player 2 “turn away”) can both tell players …

  • when they should turn away … as well as …
  • when they should re-engage

… regarding our changed third draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Tutorial is shown below.

Dominoes Horizontal Block Game Tutorial

Dominoes Horizontal Block Game Tutorial

After yesterday’s Dominoes Game Sections Tutorial we have a …

Dominoes Horizontal Block Game

… initially coded for. Why the “Horizontal” here? Well, to allow “vertical roaming” we need to think a bit more, on it.

This ask of Google … css flip image‘s …

To flip an image using CSS, use the transform property with either the scaleX() or scaleY() function.

Quick Reference

Horizontal Flip (Mirror):
transform: scaleX(-1);

Vertical Flip (Upside Down):
transform: scaleY(-1);

Both (180-degree rotation):
transform: scale(-1, -1);

transform: scaleX(-1) idea was useful, thanks, as was css filter to blacken image out‘s …

To completely blacken an image out using a CSS filter, use filter: brightness(0);.

Quick Reference

css.blackout-image {
filter: brightness(0);
}

… this idea, thanks applied to our changed second draft Dominoes Block Game you can try below.


Previous relevant Dominoes Game Sections Tutorial is shown below.

Dominoes Game Sections Tutorial

Dominoes Game Sections Tutorial

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.

And so, that is the plan regarding our first draft sections showing of proposed Dominoes Block Game, today.


Previous relevant Dominoes Game Resources Tutorial is shown below.

Dominoes Game Resources Tutorial

Dominoes Game Resources Tutorial

When creating an online web application game, like Animated Plane and Coconut Hunt Game Nuances Tutorial‘s Animated Plane and Coconut Hunt Game or games like playing card games, they involve “things” or …

nouns

… 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 …


Dominoes

… game, as an online web application. We vaguely remember Dominoes from a while back and it involves …

  1. dominoes (we think of as tiles) … as the resource …
  2. 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 …
  3. 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 …

    1. control-command-shift-3 of that webpage
    2. open macOS PaintBrush desktop application
    3. File -> New from Clipboard
    4. form rectangle around the white on black section of tiles
    5. Edit -> Copy
    6. File -> New from Clipboard
    7. File -> Save As… dominoes.png
  • 28 x
    1. form rectangle around the white on black subsection of dominoes.png
    2. Edit -> Copy
    3. File -> New from Clipboard
    4. File -> Save As… dominoes_[leftHandDotCount]_[rightHandDotCount].png
  • 7 x
    1. form rectangle around the uniquely encountered leftHandDotCount left hand side of a dominoes_[leftHandDotCount]_[rightHandDotCount].png
    2. Edit -> Copy
    3. File -> New from Clipboard
    4. 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 Apache Document 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 …


Why on an Apache and PHP web server is it a bad idea to not have an index.html nor index.htm nor index.php within a web server folder?

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.


Previous relevant Animated Plane and Coconut Hunt Game Nuances Tutorial is shown below.

Animated Plane and Coconut Hunt Game Nuances Tutorial

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 …
    1. some “panda 🐼 led recovery” modelling of a p emoji usage (with animation) and span emoji usage (without animation) … and …
    2. 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
  • allow for sharing of the Hunt Game
  • Hunt Game sound effects

Feel free to try these tweaks to our Animated Plane and Coconut Hunt Game, in a nuanced “latest draft” Animated Plane Coconut Hunt Game web application below!


Previous relevant Coconut Hunt Game Tutorial is shown below.

Coconut Hunt Game Tutorial

Coconut Hunt Game Tutorial

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 …

I shell always love you.

? 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!


Previous relevant Animated Plane Game User Animations and Styling Tutorial is shown below.

Animated Plane Game User Animations and Styling Tutorial

Animated Plane Game User Animations and Styling Tutorial

On top of yesterday’s Animated Plane Game User Content Sharing Tutorial‘s honing in on the five “nouns” of interest …

  • trees
  • plane
  • gymnast
  • clouds
  • ground

… 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 …
    1. @keyframes
    2. transition

    … 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!

Try this in the changed “latest draft” Animated Plane Game web application below.

Did you know?

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>


Previous relevant Animated Plane Game User Content Sharing Tutorial is shown below.

Animated Plane Game User Content Sharing Tutorial

Animated Plane Game User Content Sharing Tutorial

Yesterday’s Animated Plane Game Primer Tutorial set up five “nouns” of interest …

  • trees
  • plane
  • gymnast
  • clouds
  • ground

… 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;

case '5': // ground
if ((opsd + ' ').substring(0,2) == '5:') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + (opsd + ' ').substring(2) + suffixbiu + '") !important; </sty' + 'le>'
} else {
opsd=prompt('Enter your (probably quite long) emoji (we are guessing) border image text.', '');
if (opsd != null) {
if (opsd != '') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + suffixbiu + '") !important; </sty' + 'le>'
} else {
groundalt='&groundalt='; // + encodeURIComponent(opsd);
document.body.style.borderImage='none';
document.body.style.borderBottom='1px solid transparent';
document.body.style.borderBottomWidth='0px';
//document.body.innerHTML+='<sty' + 'le> body { border-bottom-width:0px !important; } </sty' + 'le>';
}
}
}
break;

case 'e': // email
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.trim().indexOf('@') != -1) {
anchor.href = 'mailto:' + opsd.split('@')[0].split(' ')[eval(-1 + opsd.split('@')[0].split(' ').length)] + opsd.split(opsd.split('@')[0])[1].split(' ')[0] + '?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'mailto:?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

case 's': // SMS
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.substring(0,1).toLowerCase() == '+') {
anchor.href = 'sms:' + opsd.split(' ')[0] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else if (opsd.indexOf(' ') != -1) {
anchor.href = 'sms:' + opsd.split(' ')[eval(-1 + opsd.split(' ').length)] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

default:
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
break;
}
} else {
setTimeout(function(){ ino.click(); }, 100); return true;
}
isac=false;
return false;
}

function anyprompt(opsd) {
if (opsd.trim() != '') {
opsd=opsd;
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;

case '5': // ground
if ((opsd + ' ').substring(0,2) == '5:') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + (opsd + ' ').substring(2) + suffixbiu + '") !important; </sty' + 'le>'
} else {
opsd=prompt('Enter your (probably quite long) emoji (we are guessing) border image text.', '');
if (opsd != null) {
if (opsd != '') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + suffixbiu + '") !important; </sty' + 'le>'
} else {
groundalt='&groundalt='; // + encodeURIComponent(opsd);
document.body.style.borderImage='none';
document.body.style.borderBottom='1px solid transparent';
document.body.style.borderBottomWidth='0px';
//document.body.innerHTML+='<sty' + 'le> body { border-bottom-width:0px !important; } </sty' + 'le>';
}
}
}
break;

case 'e': // email
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.trim().indexOf('@') != -1) {
anchor.href = 'mailto:' + opsd.split('@')[0].split(' ')[eval(-1 + opsd.split('@')[0].split(' ').length)] + opsd.split(opsd.split('@')[0])[1].split(' ')[0] + '?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'mailto:?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

case 's': // SMS
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.substring(0,1).toLowerCase() == '+') {
anchor.href = 'sms:' + opsd.split(' ')[0] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else if (opsd.indexOf(' ') != -1) {
anchor.href = 'sms:' + opsd.split(' ')[eval(-1 + opsd.split(' ').length)] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

default:
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
break;
}
}
}

function ourprompt(ino, intlis) {
var ei=-1, si=-1;
isac=true;
var opsd=null;
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
opsd=prompt(intlis + String.fromCharCode(10) + String.fromCharCode(10) + intlis, '');
} else {
opsd=prompt(getsrc(document.getElementById('myimg').outerHTML), '');
}
if (opsd == null) { isac=false; return false; }
if (opsd.trim() != '') {
opsd=opsd;
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;

case '5': // ground
if ((opsd + ' ').substring(0,2) == '5:') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + (opsd + ' ').substring(2) + suffixbiu + '") !important; </sty' + 'le>'
} else {
opsd=prompt('Enter your (probably quite long) emoji (we are guessing) border image text.', '');
if (opsd != null) {
if (opsd != '') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + suffixbiu + '") !important; </sty' + 'le>'
} else {
groundalt='&groundalt='; // + encodeURIComponent(opsd);
document.body.style.borderImage='none';
document.body.style.borderBottom='1px solid transparent';
document.body.style.borderBottomWidth='0px';
//document.body.innerHTML+='<sty' + 'le> body { border-bottom-width:0px !important; } </sty' + 'le>';
}
}
}
break;

case 'e': // email
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.trim().indexOf('@') != -1) {
anchor.href = 'mailto:' + opsd.split('@')[0].split(' ')[eval(-1 + opsd.split('@')[0].split(' ').length)] + opsd.split(opsd.split('@')[0])[1].split(' ')[0] + '?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'mailto:?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

case 's': // SMS
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.substring(0,1).toLowerCase() == '+') {
anchor.href = 'sms:' + opsd.split(' ')[0] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else if (opsd.indexOf(' ') != -1) {
anchor.href = 'sms:' + opsd.split(' ')[eval(-1 + opsd.split(' ').length)] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

default:
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
break;
}
} else {
setTimeout(function(){ ino.click(); }, 100); return true;
}
isac=false;
return false;
}

… in the changed “eighth draft” Animated Plane Game web application.


Previous relevant Animated Plane Game Primer Tutorial is shown below.

Animated Plane Game Primer Tutorial

Animated Plane Game Primer Tutorial

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 Freepik image plane image animated with a rudimentary green border-bottom representing the ground …
then to “second draft” … adding https://i.makeagif.com/media/8-11-2023/Xu_roP.gif animated GIF cloud background to go with edited Freepik image because mix-blend-mode:multiply will not mask out the non heterogenous bluish clouds in the image …
then to “third draft” … tweaking https://i.makeagif.com/media/8-11-2023/Xu_roP.gif animated GIF cloud background … …
then to “fourth draft” … establishing an SVG+XML (with SVG text emoji content) border-image for the bottom border representing the ground …
then to “fifth draft” … added acknowledgements for all the help …

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 https://au.pinterest.com/pin/587930926347995281/ 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 https://giphy.com/explore/trees-swaying-stickers giphy.com/explore/trees-swaying-stickers animated (and transparently backgrounded) webp swaying trees image along with tweaked Freepik image 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.

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

Horizontal Block Game CSS Animation Tutorial

Horizontal Block Game CSS Animation Tutorial

Horizontal Block Game CSS Animation Tutorial

Today we …

  • extend yesterday’s Horizontal Block Game Random Image Types Tutorial‘s ondblclick and oncontextmenu (or ontouchmove) “drill downs” to other Wikipedia image Block Game choices … and …
  • allow for a CSS @keyframes animation definition to affect …
    CSS @keyframes animation default initialization that may be dynamically called into play at a later time …

    <style>
    @keyframes myanim { 0%, 58.33% { filter: invert(0%) contrast(100%); } 75%, 100% { filter: invert(100%) contrast(800%); } }
    </style>

    … and editable via Javascript …

    animans=prompt('Optionally enter CSS @keyframes animation definition.', (animval == 'y' ? document.getElementById('mysel').getAttribute('data-anim') : animval));

    … via a new dropdown option …
    Optionally passed across in a new animated argument, processed by initialization Javascript …

    var animgprefix='', animgsuffix='';
    var animval='y', animdef="@keyframes myanim { 0%, 58.33% { filter: invert(0%) contrast(100%); } 75%, 100% { filter: invert(100%) contrast(800%); } } ";
    var animclass=(location.search.split('animated=')[1] ? decodeURIComponent(location.search.split('animated=')[1].split('&')[0]) : '');
    if (animclass != '') {
    if (('' + animclass).toLowerCase().indexOf('@keyframes') != -1) { animval=animclass; } else if (('' + animclass).toLowerCase() == 'y') { animval=animdef; }
    animclass=' animated';
    }

    … as well as document.body onload called …

    if (('' + animval).toLowerCase().indexOf('@keyframes') != -1) {
    if (animval != document.getElementById('mysel').getAttribute('data-anim')) {
    document.getElementById('mysel').setAttribute('data-anim', animval);
    }
    document.getElementById('dstyle').innerHTML+='<st' + 'yle> ' + animval + ' </st' + 'yle>';
    document.getElementById('optanim').innerHTML='Animation ' + animval + ' ... ';
    }
    In Play at the time of relevance …

    <style>
    .animated:not([style*="filter"]) { animation: myanim 12s infinite; }
    </style>
    Javascript dynamically called into play wherever in the code

    document.getElementById('dstyle').innerHTML+='<st' + 'yle> ' + animval + ' </st' + 'yle>';

    … and relevant HTML elements have class=animated applied to them dynamically … for example

    document.getElementById('seven1').innerHTML+=brhuh + othersmaybe('<img' + (animclass == '' ? '' : ' class=animated') + ' draggable="true" ondragstart="goone(event.target);" onclick="goone(this);" style=width:80px; class="player1" id="' + player1arr[ij] + '" src="' + player1arr[ij] + '.png"></img>');

    … happens …

… to add to the changed seventeenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Random Image Types Tutorial is shown below.

Horizontal Block Game Random Image Types Tutorial

Horizontal Block Game Random Image Types Tutorial

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 …

… offering both …

  • image randomosity possibilities … as well as …
  • means to recall same content

… via ondblclick …


function odc(evt) {
var evttarget=evt.target, spanarr=[], jspan=0;
evt.stopPropagation();
if (evttarget.outerHTML.indexOf('<img') == 0) {
spanarr=document.getElementsByTagName('span');
for (jspan=0; jspan<spanarr.length; jspan++) {
if (evttarget.outerHTML.indexOf('<img') == 0) {
if (spanarr[jspan].innerHTML.indexOf(evt.target.outerHTML) != -1) { evttarget=spanarr[jspan]; }
}
}
}
if (eval('' + evttarget.innerHTML.split(' data-url="').length) >= 2) {
etarget=evttarget;
window.open(evttarget.innerHTML.split(' data-url="')[1].split('"')[0], '_blank', 'top=10,left=' + eval(-600 + screen.width) + ',width=600,height=800');
}
}

… and oncontextmenu (or ontouchmove) …


function onc(evt) {
var evttarget=evt.target, spanarr=[], jspan=0;
evt.preventDefault();
if (evttarget.outerHTML.indexOf('<img') == 0) {
spanarr=document.getElementsByTagName('span');
for (jspan=0; jspan<spanarr.length; jspan++) {
if (evttarget.outerHTML.indexOf('<img') == 0) {
if (spanarr[jspan].innerHTML.indexOf(evt.target.outerHTML) != -1) { evttarget=spanarr[jspan]; }
}
}
}
if (eval('' + evttarget.innerHTML.split(' data-url="').length) >= 3) {
window.open(evttarget.innerHTML.split(' data-url="')[2].split('"')[0], '_blank', 'top=10,left=' + eval(-600 + screen.width) + ',width=600,height=800');
}
}

… conduits, for an inquisitive user, as well, in the changed sixteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Less Personal Types Tutorial is shown below.

Horizontal Block Game Less Personal Types Tutorial

Horizontal Block Game Less Personal Types Tutorial

Onto yesterday’s Horizontal Block Game Personalized Second Image Type Tutorial‘s new Horizontal Block Game types, today, we add a variety more number of emoji and image type game incarnations, as per …

… 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)


document.getElementById('sele').style.position='absolute';
osel.style.width='290px';
document.getElementById('sele').style.left='' + eval(-30 + eval('' + osel.getBoundingClientRect().right)) + 'px';
document.getElementById('sele').style.top='' + eval(36 + eval('' + osel.getBoundingClientRect().top)) + 'px';
document.getElementById('sele').style.zIndex='211';
document.getElementById('sele').style.display='block';

… in the changed fifteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Personalized Second Image Type Tutorial is shown below.

Horizontal Block Game Personalized Second Image Type Tutorial

Horizontal Block Game Personalized Second Image Type Tutorial

After yesterday’s Horizontal Block Game Types Tutorial a cruel streak in us might say …

Emojis Smemojis

… 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 …


<style> .dominoes0:after { background-image:url(//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/St_Mary%27s_Cathedral_-_panoramio.jpg/250px-St_Mary%27s_Cathedral_-_panoramio.jpg?utm_source=en.wikipedia.org&utm_campaign=parser&utm_content=thumbnail); background-size:cover; background-repeat:no-repeat; color:transparent; } </style>

… added as the need arises.

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 changed fourteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Types Tutorial is shown below.

Horizontal Block Game Types Tutorial

Horizontal Block Game Types Tutorial

Do you remember, way before yesterday’s Dominoes Horizontal Block Game Drag Tutorial, way back at Dominoes Horizontal Block Game Width Tutorial, we commented …

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;
}
}
New initialization Javascript function …

function alat() {
document.getElementById('gtype').innerHTML=othertype;
if (anothertype != 'shapeis' && document.getElementById('dstyle').innerHTML.indexOf('.dominoes0') == -1) {
eval(' numarr=' + anothertype + '.length');
while (eval('' + newtypes.length) < 7) {
thisemhe=Math.floor(Math.random() * numarr);
while (newtypes.indexOf(thisemhe) != -1) {
thisemhe=Math.floor(Math.random() * numarr);
}
eval(' thisem=' + anothertype + '[' + thisemhe + ']');
if (thisem.indexOf(String.fromCharCode(92)) != -1) {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '" + thisem + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
} else if (thisem.indexOf('x') != -1) {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '\\" + ('000000' + ('' + thisem.replace(String.fromCharCode(92),"").replace("0x","").toString(16).padStart(2, '0'))).slice(-6).replace(/\ /g,'0') + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
} else if (thisem.toLowerCase().indexOf('a') != -1 || thisem.toLowerCase().indexOf('b') != -1 || thisem.toLowerCase().indexOf('c') != -1 || thisem.toLowerCase().indexOf('d') != -1 || thisem.toLowerCase().indexOf('e') != -1 || thisem.toLowerCase().indexOf('f') != -1) {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '\\" + ('000000' + ('' + thisem)).slice(-6).replace(/\ /g,'0') + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
} else {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '\\" + ('000000' + eval(thisem).toString(16).padStart(2, '0')).slice(-6) + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
}
}
}
}
Augmented other Javascript functions …

function lessen(inthih) {
return inthih.replace(/visible/g, 'hidden');
alert('lessen this ' + inthih + ' to ' + inthih.replace('><img', '--><img').replace('<', '<!--').replace(/<span/g, '<!--span').replace(/<\/span>/g, '</span-->'));
return inthih.replace('><img', '--><img').replace('<', '<!--').replace(/<span/g, '<!--span').replace(/<\/span>/g, '</span-->');
}

function fixdomlr() {
if (newspanoid != '') {
if (document.getElementById('p' + newspanoid)) {
if (document.getElementById('p' + newspanoid).innerHTML.indexOf('(-1)') != -1) {
document.getElementById('p' + newspanoid).innerHTML=document.getElementById('p' + newspanoid).innerHTML.replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
}
if (document.getElementById(newspanoid)) {
if (document.getElementById('seven1').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(1);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
} else if (document.getElementById('seven2').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(2);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
}
document.getElementById(newspanoid).innerHTML=document.getElementById(newspanoid).innerHTML.replace(/visible/g,'hidden'); //alert('and then ' + document.getElementById(newspanoid).outerHTML);
}
} else if (document.getElementById('s' + newspanoid)) {
if (document.getElementById('s' + newspanoid).innerHTML.indexOf('(-1)') != -1) {
document.getElementById('s' + newspanoid).innerHTML=document.getElementById('s' + newspanoid).innerHTML.replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
}
if (document.getElementById(newspanoid)) {
if (document.getElementById('seven1').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(3);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
} else if (document.getElementById('seven2').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(4);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
}
document.getElementById(newspanoid).innerHTML=document.getElementById(newspanoid).innerHTML.replace(/visible/g,'hidden'); //alert('anD then ' + document.getElementById(newspanoid).outerHTML);
}
} else if (document.getElementById(newspanoid)) {
if (document.getElementById(newspanoid).innerHTML.indexOf('(-1)') != -1) {
document.getElementById('' + newspanoid).innerHTML=document.getElementById('' + newspanoid).innerHTML.replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
}
}
}
newspanoid='';
}

function othersmaybe(inimg) {
var lbit='', rbit='';
newspano=null;
if (inimg.indexOf(cgostock) != -1) { return inimg; }
//if (inimg.indexOf(' draggable="false') != -1) { return inimg; }
if (animgprefix != '') {
// do more here perhaps
if (inimg.indexOf('dominoes_') != -1) {
lbit=inimg.split('dominoes_')[1].substring(0,1);
rbit=inimg.split('dominoes_')[1].split('_')[1].substring(0,1);
if (document.getElementById('dom' + lbit + rbit)) {
//alert('already there ' + inimg);
newspano=document.getElementById('dom' + lbit + rbit);
newspanoid='dom' + lbit + rbit;
if (newspano) {
setTimeout(fixdomlr, 500);
}
}
animgprefix=templateprefix.replace(' ', ' id="dom' + lbit + rbit + '" ');
if (inimg.indexOf('(0)') != -1) {
if (inimg.indexOf('(-1)') != -1) {
//alert(43);
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"').replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ').replace(/visible/g,'hidden');
} else {
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"').replace(/visible/g,'hidden');
}
} else {
if (inimg.indexOf('(-1)') != -1) {
//alert(4);
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"').replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
} else {
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"');
}
}
}

}
//alert(inimg);
if (nestero) {
nestero.className+=' disnon';
nestero=null;
}
return animgprefix + inimg + animgsuffix;
}

function typeize(osel) {
if (osel.value != '') {
if (osel.value.toLowerCase() == 'email') {
var anchor = document.createElement('a');
anchor.target='_top';
anchor.href = 'mailto:?subject=' + (othertype == '' ? 'Dominoes' : othertype) + '%20Game%20snapshot&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?type=' + othertype + '&rand=' + Math.floor(Math.random() * 1989786) + '&score1=' + document.getElementById('score1').innerHTML.replace('Score: ','') + '&score2=' + document.getElementById('score2').innerHTML.replace('Score: ','') + '#' + encodeURIComponent(document.body.innerHTML.split('<fo' + 'rm ')[0].split('<a' + ' target="_top"')[0]));
document.body.appendChild(anchor);
anchor.click();
anchor.remove();
} else {
othertype=osel.value.replace('Dominoes','');
newstockgame();
}
osel.value='';
}
}
New CSS styling …

<style>
.image-wrapper {
position: relative; /* Acts as the anchor point */
display: inline-block;
}

.image-wrapper img {
display: block;
width: 80px; /* Set your desired image width */
height: auto;
opacity:0.2; /* visibility: hidden; */
filter: url('#edge-detection');
}

.disnon span {
display: none;
}

.domr {
position: absolute;
top: -6px; /* Distance from the top edge */
right: 0px; /* Distance from the right edge */
font-size: 45px; /* Adjust emoji size */
pointer-events: none;
}

.doml {
position: absolute;
top: -6px; /* Distance from the top edge */
left: 0px; /* Distance from the right edge */
font-size: 45px; /* Adjust emoji size */
border-right: 1px solid black;
pointer-events: none;
}

.dominoes0:after {
content: '\002739';
}

.dominoes1:after {
content: '\002737';
}

.dominoes2:after {
content: '\002729';
}

.dominoes3:after {
content: '\002727';
}

.dominoes4:after {
content: '\002719';
}

.dominoes5:after {
content: '\002724';
}

.dominoes6:after {
content: '\002713';
}
</style>

… thanks, a lot, to Google’s overlay emoji characters on top of html img element‘s (back to W3schools‘s) advice in the changed thirteenth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Drag Tutorial is shown below.

Dominoes Horizontal Block Game Drag Tutorial

Dominoes Horizontal Block Game Drag Tutorial

Another layer of thinking onto yesterday’s Dominoes Horizontal Blocked Game Tutorial, we think, can be …

drag

andnot drop new Javascript logic. This last idea, where only what happens to HTML img element (by default draggable=”true”) …

  1. draggable … attribute “true” for “dragging available” and “false” for “dragging not available” … and …
  2. 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-nilly drop 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>';

… in the changed twelfth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Blocked Game Tutorial is shown below.

Dominoes Horizontal Blocked Game Tutorial

Dominoes Horizontal Blocked Game Tutorial

Playing a Dominoes Horizontal Block Game after yesterday’s Dominoes Horizontal Block Game Handoff Friendly Tutorial was where we realized you could have a “stalemate” (in chess parlance) in a Dominoes game, as per “what is stalemate called in a dominoes game”

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 …

  1. we turned a hardcopy into a span, potentially dynamic, element …

    <h1 id=myh1>Dominoes Horizontal Block <span id=sgame>Game</span></h1>
  2. 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';
    }
    }

  3. 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

… in the changed eleventh draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Handoff Friendly Tutorial is shown below.

Dominoes Horizontal Block Game Handoff Friendly Tutorial

Dominoes Horizontal Block Game Handoff Friendly Tutorial

After yesterday’s Dominoes Horizontal Block Game Mobile Speech to Text Tutorial we started delving more into Apple’s Handoff concepts here sharing between an iPhone and a MacBook Air …

  • on same WiFi network
  • Bluetooth on

… 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 …


lhis='#' + encodeURIComponent(document.body.innerHTML);
prevlhis=lhis;
location.href=lhis;

… as a way to tell Handoff, if used, situations in the Domino game had changed.

Also, we needed to, at document.body onload, code …


lhis=('' + location.hash);
prevlhis=lhis;
setInterval(lhcheck, 5000);

… utilizing new Javascript function …


function lhcheck() {
lhis=('' + location.hash);
if (prevlhis != lhis) {
prevlhis=lhis;
if (document.URL.indexOf('#' + encodeURIComponent('<h1')) != -1 || document.URL.indexOf('#' + encodeURIComponent(String.fromCharCode(10) + '<h1')) != -1 || document.URL.indexOf('#' + encodeURIComponent('<t')) != -1 || document.URL.indexOf('#' + encodeURIComponent(String.fromCharCode(10) + '<t')) != -1) {
if (document.URL.indexOf('#' + encodeURIComponent('<t')) != -1) {
if (document.URL.split('#' + encodeURIComponent('<t'))[1].substring(0,1) >= '0' && document.URL.split('#' + encodeURIComponent('<t'))[1].substring(0,1) <= '9') {
//alert(document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent('<t'))[1]);
document.getElementById('ifp').src=document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent('<t'))[1];
} else {
allbuthash=document.URL.split('#')[0];
document.getElementById('mytable').innerHTML='' + decodeURIComponent(document.URL.substring(document.URL.indexOf(encodeURIComponent('<t'))).replace(/\%7E/g,symbolize)) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
}
} else if (document.URL.indexOf('#' + encodeURIComponent(String.fromCharCode(10) + '<t')) != -1) {
if (document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<t'))[1].substring(0,1) >= '0' && document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<t'))[1].substring(0,1) <= '9') {
//alert(document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<t'))[1]);
document.getElementById('ifp').src=document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent('<t'))[1];
} else {
allbuthash=document.URL.split('#')[0];
document.getElementById('mytable').innerHTML='' + decodeURIComponent(document.URL.substring(document.URL.indexOf(encodeURIComponent(String.fromCharCode(10) + '<t'))).replace(/\%7E/g,symbolize)) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
}
} else if (document.URL.indexOf('#' + encodeURIComponent('<h1')) != -1) {
allbuthash=document.URL.split('#')[0];
document.body.innerHTML='<h1' + decodeURIComponent(document.URL.split('#' + encodeURIComponent('<h1'))[1]) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
} else {
allbuthash=document.URL.split('#')[0];
document.body.innerHTML='<h1' + decodeURIComponent(document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<h1'))[1]) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
}
thescore1=eval('' + document.getElementById('score1').innerHTML.replace('Score: ',''));
thescore2=eval('' + document.getElementById('score2').innerHTML.replace('Score: ',''));
if (document.URL.indexOf('winnerblurb=') != -1 && (document.URL + '&').indexOf('winnerblurb=&') == -1) {
//alert(87);
setTimeout(newremotegame, 3000);
} else {
//alert(487);
thetilearr.push('dominoes.png');
inithave();
}
pip1cnt=(location.search.split('pip1cnt=')[1] ? decodeURIComponent(location.search.split('pip1cnt=')[1].split('&')[0]) : pip1cnt);
pip2cnt=(location.search.split('pip2cnt=')[1] ? decodeURIComponent(location.search.split('pip2cnt=')[1].split('&')[0]) : pip2cnt);
}
}
}

… in the changed tenth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Mobile Speech to Text Tutorial is shown below.

Dominoes Horizontal Block Game Mobile Speech to Text Tutorial

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 …

  • Screen Mirroring
  • AirPlay
  • Handoff
  • QuickTime Player
  • Safari Web Inspector

… 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 …

… and, yes, the mobile Google Chrome web browser can help, though microphone usage security questions are asked. No biggie!.

And it’s means of Speech to Text (based on Google’s excellent Web Speech API Demonstration) can mean either …

  • 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” …


var lwds='', alldoneanddusted=false;

if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
everyfour=4;
}

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);
}

… in the changed ninth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Speech to Text Tutorial is shown below.

Dominoes Horizontal Block Game Speech to Text Tutorial

Dominoes Horizontal Block Game Speech to Text Tutorial

Today, we’ve added on to the functionality of yesterday’s Dominoes Horizontal Block Game Width Tutorial if

… with some changed PHP code of speech_supervisor.php with it’s Speech to Text means (based on Google’s excellent Web Speech API Demonstration) for a user to say what Domino tile they want to click rather than click it with a pointing means.

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 …


🎤

… with it’s on hover explanation …

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();
}
}
}
}

… in our changed seventh draft Dominoes Block Game you can try below.

Stop Press

“The Jiggles” in web applications can be a pain, especially regarding parent webpage calling child iframe arrangements, involving, perhaps …

  • [element].focus(); // calls … or, perhaps …
  • location.href=’#[elementID]’; // scenarios … or, perhaps …
  • [element].scrollIntoView(); // calls

We decided to undo some of the [element].focus(); we were doing for the iframe further tweaked PHP code of speech_supervisor.php Speech to Text we are invoking here, and time, more precisely, a parent created “refresh” of the “microphone being on” timed better for when a user might need to speak regarding our changed eighth draft Dominoes Block Game you can try below. This all working as an improvement, we reckon, gave us the confidence to loosen the “no arguments on the top window’s web browser’s address bar URL” restriction above, as a result.


Previous relevant Dominoes Horizontal Block Game Width Tutorial is shown below.

Dominoes Horizontal Block Game Width Tutorial

Dominoes Horizontal Block Game Width Tutorial

Specifically, it is your smaller mobile device …

width

… in their “portrait” modes of orientation, that is the focus of today’s work, further to yesterday’s Dominoes Horizontal Block Game Collaboration Tutorial, improving our Dominoes Horizontal Block Game here.

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 …

var everyfour=-1;

if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
everyfour=4;
}
Separate sets of images by a line break, as required using Javascript exemplified by …

var brhuh='';

huhlen=eval(-1 + eval('' + document.getElementById('seven1').innerHTML.split('<img').length));
for (ij=0; ij<player1arr.length; ij++) {
brhuh='';
if (everyfour > 0) {
if (eval(huhlen % 4) == 0) { brhuh='<br>'; }
}

document.getElementById('seven1').innerHTML+=brhuh + '<img onclick="goone(this);" style=width:80px; class="player1" id="' + player1arr[ij] + '" src="' + player1arr[ij] + '.png"></img>';
huhlen++;
brhuh='';
}
huhlen=eval(-1 + eval('' + document.getElementById('seven2').innerHTML.split('<img').length));
for (ij=0; ij<player1arr.length; ij++) {
brhuh='';
if (everyfour > 0) {
if (eval(huhlen % 4) == 0) { brhuh='<br>'; }
}

document.getElementById('seven2').innerHTML+=brhuh + '<img onclick="gotwo(this);" style=width:80px;filter:brightness(0); class="player2" id="' + player2arr[ij] + '" src="' + player2arr[ij] + '.png"></img>';
huhlen++;
brhuh='';
}
huhlen=eval(-1 + eval('' + document.getElementById('thstock').innerHTML.split('<img').length));
for (ij=0; ij<stockarr.length; ij++) {
bbrhuh='';
if (everyfour > 0) {
if (eval(huhlen % 7) == 0) { brhuh='<br>'; }
}

document.getElementById('thstock').innerHTML+=bbrhuh + '<img onclick="gostock(this);" style=width:80px;filter:brightness(0); class="stock" id="' + stockarr[ij] + '" src="' + stockarr[ij] + '.png"></img>';
huhlen++;
brhuh='';
}
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 …

<style>
#seven1 { text-align: right; }
#thstock { text-align: center; }
.right {
text-align: right;
margin-right: 1em;
}
.left {
text-align: left;
margin-left: 1em;
}
</style>
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)…

// For Player 1 (at left)
if (everyfour > 0) {
setTimeout(function(){
window.scrollTo({ left: 0 }); //, eval('' + document.getElementById('mytable').getBoundingClientRect().top)); //{ right: 0 }); //eval(0.3 * screen.width) });
setTimeout(function(){
document.getElementById('thtop').className='left'; //document.getElementById('thtop').style.float='lerft';
}, 989);
}, 989);
}
// For Player 2 (at right)
if (everyfour > 0) {
setTimeout(function(){
window.scrollTo({ left: eval('' + document.body.scrollWidth) }); //, eval('' + document.getElementById('mytable').getBoundingClientRect().top)); //{ right: 0 }); //eval(0.3 * screen.width) });
setTimeout(function(){
document.getElementById('thtop').className='right'; //document.getElementById('thtop').style.float='right';
}, 989);
}, 989);
}

… thanks to …

… regarding our changed fifth draft Dominoes Block Game you can try below, where you may discern, also …

  • some 3D looking shadow effects (via drop-shadow) in CSS …

    <style>
    img { filter: drop-shadow( 3px 3px 2px rgba(10, 10, 10, .7)); }
    button { filter: drop-shadow( 3px 3px 2px rgba(0, 0, 255, .7)); }
    </style>
  • thicker cell borders from 2px to 4px
  • some border-radius CSS nuance …

    <style>
    button { padding 8 8 8 8; border-radius: 20px; }
    td,th { border-radius: 6px; }
    </style>
  • 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 changed sixth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Collaboration Tutorial is shown below.

Dominoes Horizontal Block Game Collaboration Tutorial

Dominoes Horizontal Block Game Collaboration Tutorial

Onto yesterday’s Dominoes Horizontal Block Game User Experience Tutorial‘s progress regarding our Dominoes Horizontal Block Game …

  • as well as yesterday’s player “Turn Away Paradigm” for one device scenarios of play … today we add …
  • collaboration, via …
    1. email … or …
    2. 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

if (isset($_GET['intnum'])) {
//file_put_contents('./x.x', '1');
if (file_exists(dirname(__FILE__) . '/t' . $_GET['intnum'] . '.txt')) {
//file_put_contents('./x.x2', '1');
$innards=file_get_contents(dirname(__FILE__) . '/t' . $_GET['intnum'] . '.txt');
//file_put_contents('./x.x3', '1');
unlink(dirname(__FILE__) . '/t' . $_GET['intnum'] . '.txt');
//file_put_contents('./x.x4', "<html><body onload=\" parent.location.href=parent.document.URL.replace('#','&rd=' + Math.floor(Math.random() * 19897675) + '#').replace('%3Ct" . $_GET['intnum'] . "', '" . $innards . "'); \"></body></html>");
echo "<html><body onload=\" parent.location.href=parent.document.URL.replace('#','&rd=' + Math.floor(Math.random() * 19897675) + '#').replace('%3Ct" . $_GET['intnum'] . "', '" . $innards . "'); \"></body></html>";
//file_put_contents('./x.x5', '1');
exit;
}
} else if (isset($_POST['makenum'])) {
$newnum=rand(123,7876543);
//file_put_contents(dirname(__FILE__) . '/t' . $newnum . '.txt', str_replace('+','%20',urlencode($_POST['makenum'])));
echo "<html><body onload=\" parent.document.getElementById('makenum').title='" . $newnum . "'; parent.document.getElementById('asms').href=parent.document.getElementById('asms').href.split('tbody')[0] + 't" . $newnum . "'; \"></body></html>";
exit;
}

?>

… which is more trouble than we’d factored in for this change …

… regarding our changed fourth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game User Experience Tutorial is shown below.

Dominoes Horizontal Block Game User Experience Tutorial

Dominoes Horizontal Block Game User Experience Tutorial

To improve yesterday’s Dominoes Horizontal Block Game Tutorial

Turn Away From

… 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).

We can deploy this mainly through the external Javascript we talked about at Country Quizzes Beep Tutorial via …


<script type=text/javascript src='//www.rjmprogramming.com.au/beep.js?iam=song_lyric_faux_pas.html&rand=76576533' data-defer=defer></script>

That placement of one beep (for player 1 “turn away”) or two beeps (for player 2 “turn away”) can both tell players …

  • when they should turn away … as well as …
  • when they should re-engage

… regarding our changed third draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Tutorial is shown below.

Dominoes Horizontal Block Game Tutorial

Dominoes Horizontal Block Game Tutorial

After yesterday’s Dominoes Game Sections Tutorial we have a …

Dominoes Horizontal Block Game

… initially coded for. Why the “Horizontal” here? Well, to allow “vertical roaming” we need to think a bit more, on it.

This ask of Google … css flip image‘s …

To flip an image using CSS, use the transform property with either the scaleX() or scaleY() function.

Quick Reference

Horizontal Flip (Mirror):
transform: scaleX(-1);

Vertical Flip (Upside Down):
transform: scaleY(-1);

Both (180-degree rotation):
transform: scale(-1, -1);

transform: scaleX(-1) idea was useful, thanks, as was css filter to blacken image out‘s …

To completely blacken an image out using a CSS filter, use filter: brightness(0);.

Quick Reference

css.blackout-image {
filter: brightness(0);
}

… this idea, thanks applied to our changed second draft Dominoes Block Game you can try below.


Previous relevant Dominoes Game Sections Tutorial is shown below.

Dominoes Game Sections Tutorial

Dominoes Game Sections Tutorial

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.

And so, that is the plan regarding our first draft sections showing of proposed Dominoes Block Game, today.


Previous relevant Dominoes Game Resources Tutorial is shown below.

Dominoes Game Resources Tutorial

Dominoes Game Resources Tutorial

When creating an online web application game, like Animated Plane and Coconut Hunt Game Nuances Tutorial‘s Animated Plane and Coconut Hunt Game or games like playing card games, they involve “things” or …

nouns

… 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 …


Dominoes

… game, as an online web application. We vaguely remember Dominoes from a while back and it involves …

  1. dominoes (we think of as tiles) … as the resource …
  2. 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 …
  3. 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 …

    1. control-command-shift-3 of that webpage
    2. open macOS PaintBrush desktop application
    3. File -> New from Clipboard
    4. form rectangle around the white on black section of tiles
    5. Edit -> Copy
    6. File -> New from Clipboard
    7. File -> Save As… dominoes.png
  • 28 x
    1. form rectangle around the white on black subsection of dominoes.png
    2. Edit -> Copy
    3. File -> New from Clipboard
    4. File -> Save As… dominoes_[leftHandDotCount]_[rightHandDotCount].png
  • 7 x
    1. form rectangle around the uniquely encountered leftHandDotCount left hand side of a dominoes_[leftHandDotCount]_[rightHandDotCount].png
    2. Edit -> Copy
    3. File -> New from Clipboard
    4. 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 Apache Document 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 …


Why on an Apache and PHP web server is it a bad idea to not have an index.html nor index.htm nor index.php within a web server folder?

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.


Previous relevant Animated Plane and Coconut Hunt Game Nuances Tutorial is shown below.

Animated Plane and Coconut Hunt Game Nuances Tutorial

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 …
    1. some “panda 🐼 led recovery” modelling of a p emoji usage (with animation) and span emoji usage (without animation) … and …
    2. 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
  • allow for sharing of the Hunt Game
  • Hunt Game sound effects

Feel free to try these tweaks to our Animated Plane and Coconut Hunt Game, in a nuanced “latest draft” Animated Plane Coconut Hunt Game web application below!


Previous relevant Coconut Hunt Game Tutorial is shown below.

Coconut Hunt Game Tutorial

Coconut Hunt Game Tutorial

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 …

I shell always love you.

? 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!


Previous relevant Animated Plane Game User Animations and Styling Tutorial is shown below.

Animated Plane Game User Animations and Styling Tutorial

Animated Plane Game User Animations and Styling Tutorial

On top of yesterday’s Animated Plane Game User Content Sharing Tutorial‘s honing in on the five “nouns” of interest …

  • trees
  • plane
  • gymnast
  • clouds
  • ground

… 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 …
    1. @keyframes
    2. transition

    … 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!

Try this in the changed “latest draft” Animated Plane Game web application below.

Did you know?

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>


Previous relevant Animated Plane Game User Content Sharing Tutorial is shown below.

Animated Plane Game User Content Sharing Tutorial

Animated Plane Game User Content Sharing Tutorial

Yesterday’s Animated Plane Game Primer Tutorial set up five “nouns” of interest …

  • trees
  • plane
  • gymnast
  • clouds
  • ground

… 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;

case '5': // ground
if ((opsd + ' ').substring(0,2) == '5:') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + (opsd + ' ').substring(2) + suffixbiu + '") !important; </sty' + 'le>'
} else {
opsd=prompt('Enter your (probably quite long) emoji (we are guessing) border image text.', '');
if (opsd != null) {
if (opsd != '') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + suffixbiu + '") !important; </sty' + 'le>'
} else {
groundalt='&groundalt='; // + encodeURIComponent(opsd);
document.body.style.borderImage='none';
document.body.style.borderBottom='1px solid transparent';
document.body.style.borderBottomWidth='0px';
//document.body.innerHTML+='<sty' + 'le> body { border-bottom-width:0px !important; } </sty' + 'le>';
}
}
}
break;

case 'e': // email
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.trim().indexOf('@') != -1) {
anchor.href = 'mailto:' + opsd.split('@')[0].split(' ')[eval(-1 + opsd.split('@')[0].split(' ').length)] + opsd.split(opsd.split('@')[0])[1].split(' ')[0] + '?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'mailto:?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

case 's': // SMS
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.substring(0,1).toLowerCase() == '+') {
anchor.href = 'sms:' + opsd.split(' ')[0] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else if (opsd.indexOf(' ') != -1) {
anchor.href = 'sms:' + opsd.split(' ')[eval(-1 + opsd.split(' ').length)] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

default:
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
break;
}
} else {
setTimeout(function(){ ino.click(); }, 100); return true;
}
isac=false;
return false;
}

function anyprompt(opsd) {
if (opsd.trim() != '') {
opsd=opsd;
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;

case '5': // ground
if ((opsd + ' ').substring(0,2) == '5:') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + (opsd + ' ').substring(2) + suffixbiu + '") !important; </sty' + 'le>'
} else {
opsd=prompt('Enter your (probably quite long) emoji (we are guessing) border image text.', '');
if (opsd != null) {
if (opsd != '') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + suffixbiu + '") !important; </sty' + 'le>'
} else {
groundalt='&groundalt='; // + encodeURIComponent(opsd);
document.body.style.borderImage='none';
document.body.style.borderBottom='1px solid transparent';
document.body.style.borderBottomWidth='0px';
//document.body.innerHTML+='<sty' + 'le> body { border-bottom-width:0px !important; } </sty' + 'le>';
}
}
}
break;

case 'e': // email
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.trim().indexOf('@') != -1) {
anchor.href = 'mailto:' + opsd.split('@')[0].split(' ')[eval(-1 + opsd.split('@')[0].split(' ').length)] + opsd.split(opsd.split('@')[0])[1].split(' ')[0] + '?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'mailto:?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

case 's': // SMS
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.substring(0,1).toLowerCase() == '+') {
anchor.href = 'sms:' + opsd.split(' ')[0] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else if (opsd.indexOf(' ') != -1) {
anchor.href = 'sms:' + opsd.split(' ')[eval(-1 + opsd.split(' ').length)] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

default:
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
break;
}
}
}

function ourprompt(ino, intlis) {
var ei=-1, si=-1;
isac=true;
var opsd=null;
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
opsd=prompt(intlis + String.fromCharCode(10) + String.fromCharCode(10) + intlis, '');
} else {
opsd=prompt(getsrc(document.getElementById('myimg').outerHTML), '');
}
if (opsd == null) { isac=false; return false; }
if (opsd.trim() != '') {
opsd=opsd;
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;

case '5': // ground
if ((opsd + ' ').substring(0,2) == '5:') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + (opsd + ' ').substring(2) + suffixbiu + '") !important; </sty' + 'le>'
} else {
opsd=prompt('Enter your (probably quite long) emoji (we are guessing) border image text.', '');
if (opsd != null) {
if (opsd != '') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + suffixbiu + '") !important; </sty' + 'le>'
} else {
groundalt='&groundalt='; // + encodeURIComponent(opsd);
document.body.style.borderImage='none';
document.body.style.borderBottom='1px solid transparent';
document.body.style.borderBottomWidth='0px';
//document.body.innerHTML+='<sty' + 'le> body { border-bottom-width:0px !important; } </sty' + 'le>';
}
}
}
break;

case 'e': // email
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.trim().indexOf('@') != -1) {
anchor.href = 'mailto:' + opsd.split('@')[0].split(' ')[eval(-1 + opsd.split('@')[0].split(' ').length)] + opsd.split(opsd.split('@')[0])[1].split(' ')[0] + '?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'mailto:?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

case 's': // SMS
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.substring(0,1).toLowerCase() == '+') {
anchor.href = 'sms:' + opsd.split(' ')[0] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else if (opsd.indexOf(' ') != -1) {
anchor.href = 'sms:' + opsd.split(' ')[eval(-1 + opsd.split(' ').length)] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

default:
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
break;
}
} else {
setTimeout(function(){ ino.click(); }, 100); return true;
}
isac=false;
return false;
}

… in the changed “eighth draft” Animated Plane Game web application.


Previous relevant Animated Plane Game Primer Tutorial is shown below.

Animated Plane Game Primer Tutorial

Animated Plane Game Primer Tutorial

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 Freepik image plane image animated with a rudimentary green border-bottom representing the ground …
then to “second draft” … adding https://i.makeagif.com/media/8-11-2023/Xu_roP.gif animated GIF cloud background to go with edited Freepik image because mix-blend-mode:multiply will not mask out the non heterogenous bluish clouds in the image …
then to “third draft” … tweaking https://i.makeagif.com/media/8-11-2023/Xu_roP.gif animated GIF cloud background … …
then to “fourth draft” … establishing an SVG+XML (with SVG text emoji content) border-image for the bottom border representing the ground …
then to “fifth draft” … added acknowledgements for all the help …

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 https://au.pinterest.com/pin/587930926347995281/ 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 https://giphy.com/explore/trees-swaying-stickers giphy.com/explore/trees-swaying-stickers animated (and transparently backgrounded) webp swaying trees image along with tweaked Freepik image 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.

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

Horizontal Block Game Random Image Types Tutorial

Horizontal Block Game Random Image Types Tutorial

Horizontal Block Game Random Image Types Tutorial

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 …

… offering both …

  • image randomosity possibilities … as well as …
  • means to recall same content

… via ondblclick …


function odc(evt) {
var evttarget=evt.target, spanarr=[], jspan=0;
evt.stopPropagation();
if (evttarget.outerHTML.indexOf('<img') == 0) {
spanarr=document.getElementsByTagName('span');
for (jspan=0; jspan<spanarr.length; jspan++) {
if (evttarget.outerHTML.indexOf('<img') == 0) {
if (spanarr[jspan].innerHTML.indexOf(evt.target.outerHTML) != -1) { evttarget=spanarr[jspan]; }
}
}
}
if (eval('' + evttarget.innerHTML.split(' data-url="').length) >= 2) {
etarget=evttarget;
window.open(evttarget.innerHTML.split(' data-url="')[1].split('"')[0], '_blank', 'top=10,left=' + eval(-600 + screen.width) + ',width=600,height=800');
}
}

… and oncontextmenu (or ontouchmove) …


function onc(evt) {
var evttarget=evt.target, spanarr=[], jspan=0;
evt.preventDefault();
if (evttarget.outerHTML.indexOf('<img') == 0) {
spanarr=document.getElementsByTagName('span');
for (jspan=0; jspan<spanarr.length; jspan++) {
if (evttarget.outerHTML.indexOf('<img') == 0) {
if (spanarr[jspan].innerHTML.indexOf(evt.target.outerHTML) != -1) { evttarget=spanarr[jspan]; }
}
}
}
if (eval('' + evttarget.innerHTML.split(' data-url="').length) >= 3) {
window.open(evttarget.innerHTML.split(' data-url="')[2].split('"')[0], '_blank', 'top=10,left=' + eval(-600 + screen.width) + ',width=600,height=800');
}
}

… conduits, for an inquisitive user, as well, in the changed sixteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Less Personal Types Tutorial is shown below.

Horizontal Block Game Less Personal Types Tutorial

Horizontal Block Game Less Personal Types Tutorial

Onto yesterday’s Horizontal Block Game Personalized Second Image Type Tutorial‘s new Horizontal Block Game types, today, we add a variety more number of emoji and image type game incarnations, as per …

… 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)


document.getElementById('sele').style.position='absolute';
osel.style.width='290px';
document.getElementById('sele').style.left='' + eval(-30 + eval('' + osel.getBoundingClientRect().right)) + 'px';
document.getElementById('sele').style.top='' + eval(36 + eval('' + osel.getBoundingClientRect().top)) + 'px';
document.getElementById('sele').style.zIndex='211';
document.getElementById('sele').style.display='block';

… in the changed fifteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Personalized Second Image Type Tutorial is shown below.

Horizontal Block Game Personalized Second Image Type Tutorial

Horizontal Block Game Personalized Second Image Type Tutorial

After yesterday’s Horizontal Block Game Types Tutorial a cruel streak in us might say …

Emojis Smemojis

… 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 …


<style> .dominoes0:after { background-image:url(//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/St_Mary%27s_Cathedral_-_panoramio.jpg/250px-St_Mary%27s_Cathedral_-_panoramio.jpg?utm_source=en.wikipedia.org&utm_campaign=parser&utm_content=thumbnail); background-size:cover; background-repeat:no-repeat; color:transparent; } </style>

… added as the need arises.

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 changed fourteenth draft Dominoes Block Game you can try below.


Previous relevant Horizontal Block Game Types Tutorial is shown below.

Horizontal Block Game Types Tutorial

Horizontal Block Game Types Tutorial

Do you remember, way before yesterday’s Dominoes Horizontal Block Game Drag Tutorial, way back at Dominoes Horizontal Block Game Width Tutorial, we commented …

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;
}
}
New initialization Javascript function …

function alat() {
document.getElementById('gtype').innerHTML=othertype;
if (anothertype != 'shapeis' && document.getElementById('dstyle').innerHTML.indexOf('.dominoes0') == -1) {
eval(' numarr=' + anothertype + '.length');
while (eval('' + newtypes.length) < 7) {
thisemhe=Math.floor(Math.random() * numarr);
while (newtypes.indexOf(thisemhe) != -1) {
thisemhe=Math.floor(Math.random() * numarr);
}
eval(' thisem=' + anothertype + '[' + thisemhe + ']');
if (thisem.indexOf(String.fromCharCode(92)) != -1) {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '" + thisem + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
} else if (thisem.indexOf('x') != -1) {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '\\" + ('000000' + ('' + thisem.replace(String.fromCharCode(92),"").replace("0x","").toString(16).padStart(2, '0'))).slice(-6).replace(/\ /g,'0') + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
} else if (thisem.toLowerCase().indexOf('a') != -1 || thisem.toLowerCase().indexOf('b') != -1 || thisem.toLowerCase().indexOf('c') != -1 || thisem.toLowerCase().indexOf('d') != -1 || thisem.toLowerCase().indexOf('e') != -1 || thisem.toLowerCase().indexOf('f') != -1) {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '\\" + ('000000' + ('' + thisem)).slice(-6).replace(/\ /g,'0') + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
} else {
document.getElementById('dstyle').innerHTML+='<sty' + 'le> .dominoes' + newtypes.length + ":after { content: '\\" + ('000000' + eval(thisem).toString(16).padStart(2, '0')).slice(-6) + "'; } </sty" + 'le>';
newtypes.push(thisemhe);
}
}
}
}
Augmented other Javascript functions …

function lessen(inthih) {
return inthih.replace(/visible/g, 'hidden');
alert('lessen this ' + inthih + ' to ' + inthih.replace('><img', '--><img').replace('<', '<!--').replace(/<span/g, '<!--span').replace(/<\/span>/g, '</span-->'));
return inthih.replace('><img', '--><img').replace('<', '<!--').replace(/<span/g, '<!--span').replace(/<\/span>/g, '</span-->');
}

function fixdomlr() {
if (newspanoid != '') {
if (document.getElementById('p' + newspanoid)) {
if (document.getElementById('p' + newspanoid).innerHTML.indexOf('(-1)') != -1) {
document.getElementById('p' + newspanoid).innerHTML=document.getElementById('p' + newspanoid).innerHTML.replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
}
if (document.getElementById(newspanoid)) {
if (document.getElementById('seven1').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(1);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
} else if (document.getElementById('seven2').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(2);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
}
document.getElementById(newspanoid).innerHTML=document.getElementById(newspanoid).innerHTML.replace(/visible/g,'hidden'); //alert('and then ' + document.getElementById(newspanoid).outerHTML);
}
} else if (document.getElementById('s' + newspanoid)) {
if (document.getElementById('s' + newspanoid).innerHTML.indexOf('(-1)') != -1) {
document.getElementById('s' + newspanoid).innerHTML=document.getElementById('s' + newspanoid).innerHTML.replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
}
if (document.getElementById(newspanoid)) {
if (document.getElementById('seven1').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(3);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
} else if (document.getElementById('seven2').innerHTML.indexOf(document.getElementById(newspanoid).innerHTML) != -1) {
document.getElementById(newspanoid).style.display='none'; //alert(4);
document.getElementById(newspanoid).className='disnon'; //document.getElementById('dstyle').innerHTML+='<sty' + 'le> #' + newspanoid + ' span { display: none; } </sty' + 'le>';
}
document.getElementById(newspanoid).innerHTML=document.getElementById(newspanoid).innerHTML.replace(/visible/g,'hidden'); //alert('anD then ' + document.getElementById(newspanoid).outerHTML);
}
} else if (document.getElementById(newspanoid)) {
if (document.getElementById(newspanoid).innerHTML.indexOf('(-1)') != -1) {
document.getElementById('' + newspanoid).innerHTML=document.getElementById('' + newspanoid).innerHTML.replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
}
}
}
newspanoid='';
}

function othersmaybe(inimg) {
var lbit='', rbit='';
newspano=null;
if (inimg.indexOf(cgostock) != -1) { return inimg; }
//if (inimg.indexOf(' draggable="false') != -1) { return inimg; }
if (animgprefix != '') {
// do more here perhaps
if (inimg.indexOf('dominoes_') != -1) {
lbit=inimg.split('dominoes_')[1].substring(0,1);
rbit=inimg.split('dominoes_')[1].split('_')[1].substring(0,1);
if (document.getElementById('dom' + lbit + rbit)) {
//alert('already there ' + inimg);
newspano=document.getElementById('dom' + lbit + rbit);
newspanoid='dom' + lbit + rbit;
if (newspano) {
setTimeout(fixdomlr, 500);
}
}
animgprefix=templateprefix.replace(' ', ' id="dom' + lbit + rbit + '" ');
if (inimg.indexOf('(0)') != -1) {
if (inimg.indexOf('(-1)') != -1) {
//alert(43);
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"').replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ').replace(/visible/g,'hidden');
} else {
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"').replace(/visible/g,'hidden');
}
} else {
if (inimg.indexOf('(-1)') != -1) {
//alert(4);
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"').replace('doml ','domR ').replace('domr ','doml ').replace('domR ','domr ');
} else {
animgsuffix=templatesuffix.replace('6"', rbit + '"').replace('5"', lbit + '"');
}
}
}

}
//alert(inimg);
if (nestero) {
nestero.className+=' disnon';
nestero=null;
}
return animgprefix + inimg + animgsuffix;
}

function typeize(osel) {
if (osel.value != '') {
if (osel.value.toLowerCase() == 'email') {
var anchor = document.createElement('a');
anchor.target='_top';
anchor.href = 'mailto:?subject=' + (othertype == '' ? 'Dominoes' : othertype) + '%20Game%20snapshot&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?type=' + othertype + '&rand=' + Math.floor(Math.random() * 1989786) + '&score1=' + document.getElementById('score1').innerHTML.replace('Score: ','') + '&score2=' + document.getElementById('score2').innerHTML.replace('Score: ','') + '#' + encodeURIComponent(document.body.innerHTML.split('<fo' + 'rm ')[0].split('<a' + ' target="_top"')[0]));
document.body.appendChild(anchor);
anchor.click();
anchor.remove();
} else {
othertype=osel.value.replace('Dominoes','');
newstockgame();
}
osel.value='';
}
}
New CSS styling …

<style>
.image-wrapper {
position: relative; /* Acts as the anchor point */
display: inline-block;
}

.image-wrapper img {
display: block;
width: 80px; /* Set your desired image width */
height: auto;
opacity:0.2; /* visibility: hidden; */
filter: url('#edge-detection');
}

.disnon span {
display: none;
}

.domr {
position: absolute;
top: -6px; /* Distance from the top edge */
right: 0px; /* Distance from the right edge */
font-size: 45px; /* Adjust emoji size */
pointer-events: none;
}

.doml {
position: absolute;
top: -6px; /* Distance from the top edge */
left: 0px; /* Distance from the right edge */
font-size: 45px; /* Adjust emoji size */
border-right: 1px solid black;
pointer-events: none;
}

.dominoes0:after {
content: '\002739';
}

.dominoes1:after {
content: '\002737';
}

.dominoes2:after {
content: '\002729';
}

.dominoes3:after {
content: '\002727';
}

.dominoes4:after {
content: '\002719';
}

.dominoes5:after {
content: '\002724';
}

.dominoes6:after {
content: '\002713';
}
</style>

… thanks, a lot, to Google’s overlay emoji characters on top of html img element‘s (back to W3schools‘s) advice in the changed thirteenth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Drag Tutorial is shown below.

Dominoes Horizontal Block Game Drag Tutorial

Dominoes Horizontal Block Game Drag Tutorial

Another layer of thinking onto yesterday’s Dominoes Horizontal Blocked Game Tutorial, we think, can be …

drag

andnot drop new Javascript logic. This last idea, where only what happens to HTML img element (by default draggable=”true”) …

  1. draggable … attribute “true” for “dragging available” and “false” for “dragging not available” … and …
  2. 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-nilly drop 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>';

… in the changed twelfth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Blocked Game Tutorial is shown below.

Dominoes Horizontal Blocked Game Tutorial

Dominoes Horizontal Blocked Game Tutorial

Playing a Dominoes Horizontal Block Game after yesterday’s Dominoes Horizontal Block Game Handoff Friendly Tutorial was where we realized you could have a “stalemate” (in chess parlance) in a Dominoes game, as per “what is stalemate called in a dominoes game”

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 …

  1. we turned a hardcopy into a span, potentially dynamic, element …

    <h1 id=myh1>Dominoes Horizontal Block <span id=sgame>Game</span></h1>
  2. 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';
    }
    }

  3. 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

… in the changed eleventh draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Handoff Friendly Tutorial is shown below.

Dominoes Horizontal Block Game Handoff Friendly Tutorial

Dominoes Horizontal Block Game Handoff Friendly Tutorial

After yesterday’s Dominoes Horizontal Block Game Mobile Speech to Text Tutorial we started delving more into Apple’s Handoff concepts here sharing between an iPhone and a MacBook Air …

  • on same WiFi network
  • Bluetooth on

… 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 …


lhis='#' + encodeURIComponent(document.body.innerHTML);
prevlhis=lhis;
location.href=lhis;

… as a way to tell Handoff, if used, situations in the Domino game had changed.

Also, we needed to, at document.body onload, code …


lhis=('' + location.hash);
prevlhis=lhis;
setInterval(lhcheck, 5000);

… utilizing new Javascript function …


function lhcheck() {
lhis=('' + location.hash);
if (prevlhis != lhis) {
prevlhis=lhis;
if (document.URL.indexOf('#' + encodeURIComponent('<h1')) != -1 || document.URL.indexOf('#' + encodeURIComponent(String.fromCharCode(10) + '<h1')) != -1 || document.URL.indexOf('#' + encodeURIComponent('<t')) != -1 || document.URL.indexOf('#' + encodeURIComponent(String.fromCharCode(10) + '<t')) != -1) {
if (document.URL.indexOf('#' + encodeURIComponent('<t')) != -1) {
if (document.URL.split('#' + encodeURIComponent('<t'))[1].substring(0,1) >= '0' && document.URL.split('#' + encodeURIComponent('<t'))[1].substring(0,1) <= '9') {
//alert(document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent('<t'))[1]);
document.getElementById('ifp').src=document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent('<t'))[1];
} else {
allbuthash=document.URL.split('#')[0];
document.getElementById('mytable').innerHTML='' + decodeURIComponent(document.URL.substring(document.URL.indexOf(encodeURIComponent('<t'))).replace(/\%7E/g,symbolize)) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
}
} else if (document.URL.indexOf('#' + encodeURIComponent(String.fromCharCode(10) + '<t')) != -1) {
if (document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<t'))[1].substring(0,1) >= '0' && document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<t'))[1].substring(0,1) <= '9') {
//alert(document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<t'))[1]);
document.getElementById('ifp').src=document.URL.split('.htm')[0] + '.php?intnum=' + document.URL.split('#' + encodeURIComponent('<t'))[1];
} else {
allbuthash=document.URL.split('#')[0];
document.getElementById('mytable').innerHTML='' + decodeURIComponent(document.URL.substring(document.URL.indexOf(encodeURIComponent(String.fromCharCode(10) + '<t'))).replace(/\%7E/g,symbolize)) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
}
} else if (document.URL.indexOf('#' + encodeURIComponent('<h1')) != -1) {
allbuthash=document.URL.split('#')[0];
document.body.innerHTML='<h1' + decodeURIComponent(document.URL.split('#' + encodeURIComponent('<h1'))[1]) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
} else {
allbuthash=document.URL.split('#')[0];
document.body.innerHTML='<h1' + decodeURIComponent(document.URL.split('#' + encodeURIComponent(String.fromCharCode(10) + '<h1'))[1]) + topmore; //'<a target="_top" id=aemail style=display:none; href="mailto:?subject=Dominoes%20Game&body=">Email</a><a target="_top" id=asms style=display:none; href="sms:&body=">SMS</a>';
}
thescore1=eval('' + document.getElementById('score1').innerHTML.replace('Score: ',''));
thescore2=eval('' + document.getElementById('score2').innerHTML.replace('Score: ',''));
if (document.URL.indexOf('winnerblurb=') != -1 && (document.URL + '&').indexOf('winnerblurb=&') == -1) {
//alert(87);
setTimeout(newremotegame, 3000);
} else {
//alert(487);
thetilearr.push('dominoes.png');
inithave();
}
pip1cnt=(location.search.split('pip1cnt=')[1] ? decodeURIComponent(location.search.split('pip1cnt=')[1].split('&')[0]) : pip1cnt);
pip2cnt=(location.search.split('pip2cnt=')[1] ? decodeURIComponent(location.search.split('pip2cnt=')[1].split('&')[0]) : pip2cnt);
}
}
}

… in the changed tenth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Mobile Speech to Text Tutorial is shown below.

Dominoes Horizontal Block Game Mobile Speech to Text Tutorial

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 …

  • Screen Mirroring
  • AirPlay
  • Handoff
  • QuickTime Player
  • Safari Web Inspector

… 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 …

… and, yes, the mobile Google Chrome web browser can help, though microphone usage security questions are asked. No biggie!.

And it’s means of Speech to Text (based on Google’s excellent Web Speech API Demonstration) can mean either …

  • 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” …


var lwds='', alldoneanddusted=false;

if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
everyfour=4;
}

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);
}

… in the changed ninth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Speech to Text Tutorial is shown below.

Dominoes Horizontal Block Game Speech to Text Tutorial

Dominoes Horizontal Block Game Speech to Text Tutorial

Today, we’ve added on to the functionality of yesterday’s Dominoes Horizontal Block Game Width Tutorial if

… with some changed PHP code of speech_supervisor.php with it’s Speech to Text means (based on Google’s excellent Web Speech API Demonstration) for a user to say what Domino tile they want to click rather than click it with a pointing means.

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 …


🎤

… with it’s on hover explanation …

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();
}
}
}
}

… in our changed seventh draft Dominoes Block Game you can try below.

Stop Press

“The Jiggles” in web applications can be a pain, especially regarding parent webpage calling child iframe arrangements, involving, perhaps …

  • [element].focus(); // calls … or, perhaps …
  • location.href=’#[elementID]’; // scenarios … or, perhaps …
  • [element].scrollIntoView(); // calls

We decided to undo some of the [element].focus(); we were doing for the iframe further tweaked PHP code of speech_supervisor.php Speech to Text we are invoking here, and time, more precisely, a parent created “refresh” of the “microphone being on” timed better for when a user might need to speak regarding our changed eighth draft Dominoes Block Game you can try below. This all working as an improvement, we reckon, gave us the confidence to loosen the “no arguments on the top window’s web browser’s address bar URL” restriction above, as a result.


Previous relevant Dominoes Horizontal Block Game Width Tutorial is shown below.

Dominoes Horizontal Block Game Width Tutorial

Dominoes Horizontal Block Game Width Tutorial

Specifically, it is your smaller mobile device …

width

… in their “portrait” modes of orientation, that is the focus of today’s work, further to yesterday’s Dominoes Horizontal Block Game Collaboration Tutorial, improving our Dominoes Horizontal Block Game here.

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 …

var everyfour=-1;

if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPod|Opera Mini|IEMobile/i) && eval(String.fromCharCode(32).trim() + navigator.maxTouchPoints) > 0) {
everyfour=4;
}
Separate sets of images by a line break, as required using Javascript exemplified by …

var brhuh='';

huhlen=eval(-1 + eval('' + document.getElementById('seven1').innerHTML.split('<img').length));
for (ij=0; ij<player1arr.length; ij++) {
brhuh='';
if (everyfour > 0) {
if (eval(huhlen % 4) == 0) { brhuh='<br>'; }
}

document.getElementById('seven1').innerHTML+=brhuh + '<img onclick="goone(this);" style=width:80px; class="player1" id="' + player1arr[ij] + '" src="' + player1arr[ij] + '.png"></img>';
huhlen++;
brhuh='';
}
huhlen=eval(-1 + eval('' + document.getElementById('seven2').innerHTML.split('<img').length));
for (ij=0; ij<player1arr.length; ij++) {
brhuh='';
if (everyfour > 0) {
if (eval(huhlen % 4) == 0) { brhuh='<br>'; }
}

document.getElementById('seven2').innerHTML+=brhuh + '<img onclick="gotwo(this);" style=width:80px;filter:brightness(0); class="player2" id="' + player2arr[ij] + '" src="' + player2arr[ij] + '.png"></img>';
huhlen++;
brhuh='';
}
huhlen=eval(-1 + eval('' + document.getElementById('thstock').innerHTML.split('<img').length));
for (ij=0; ij<stockarr.length; ij++) {
bbrhuh='';
if (everyfour > 0) {
if (eval(huhlen % 7) == 0) { brhuh='<br>'; }
}

document.getElementById('thstock').innerHTML+=bbrhuh + '<img onclick="gostock(this);" style=width:80px;filter:brightness(0); class="stock" id="' + stockarr[ij] + '" src="' + stockarr[ij] + '.png"></img>';
huhlen++;
brhuh='';
}
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 …

<style>
#seven1 { text-align: right; }
#thstock { text-align: center; }
.right {
text-align: right;
margin-right: 1em;
}
.left {
text-align: left;
margin-left: 1em;
}
</style>
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)…

// For Player 1 (at left)
if (everyfour > 0) {
setTimeout(function(){
window.scrollTo({ left: 0 }); //, eval('' + document.getElementById('mytable').getBoundingClientRect().top)); //{ right: 0 }); //eval(0.3 * screen.width) });
setTimeout(function(){
document.getElementById('thtop').className='left'; //document.getElementById('thtop').style.float='lerft';
}, 989);
}, 989);
}
// For Player 2 (at right)
if (everyfour > 0) {
setTimeout(function(){
window.scrollTo({ left: eval('' + document.body.scrollWidth) }); //, eval('' + document.getElementById('mytable').getBoundingClientRect().top)); //{ right: 0 }); //eval(0.3 * screen.width) });
setTimeout(function(){
document.getElementById('thtop').className='right'; //document.getElementById('thtop').style.float='right';
}, 989);
}, 989);
}

… thanks to …

… regarding our changed fifth draft Dominoes Block Game you can try below, where you may discern, also …

  • some 3D looking shadow effects (via drop-shadow) in CSS …

    <style>
    img { filter: drop-shadow( 3px 3px 2px rgba(10, 10, 10, .7)); }
    button { filter: drop-shadow( 3px 3px 2px rgba(0, 0, 255, .7)); }
    </style>
  • thicker cell borders from 2px to 4px
  • some border-radius CSS nuance …

    <style>
    button { padding 8 8 8 8; border-radius: 20px; }
    td,th { border-radius: 6px; }
    </style>
  • 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 changed sixth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Collaboration Tutorial is shown below.

Dominoes Horizontal Block Game Collaboration Tutorial

Dominoes Horizontal Block Game Collaboration Tutorial

Onto yesterday’s Dominoes Horizontal Block Game User Experience Tutorial‘s progress regarding our Dominoes Horizontal Block Game …

  • as well as yesterday’s player “Turn Away Paradigm” for one device scenarios of play … today we add …
  • collaboration, via …
    1. email … or …
    2. 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

if (isset($_GET['intnum'])) {
//file_put_contents('./x.x', '1');
if (file_exists(dirname(__FILE__) . '/t' . $_GET['intnum'] . '.txt')) {
//file_put_contents('./x.x2', '1');
$innards=file_get_contents(dirname(__FILE__) . '/t' . $_GET['intnum'] . '.txt');
//file_put_contents('./x.x3', '1');
unlink(dirname(__FILE__) . '/t' . $_GET['intnum'] . '.txt');
//file_put_contents('./x.x4', "<html><body onload=\" parent.location.href=parent.document.URL.replace('#','&rd=' + Math.floor(Math.random() * 19897675) + '#').replace('%3Ct" . $_GET['intnum'] . "', '" . $innards . "'); \"></body></html>");
echo "<html><body onload=\" parent.location.href=parent.document.URL.replace('#','&rd=' + Math.floor(Math.random() * 19897675) + '#').replace('%3Ct" . $_GET['intnum'] . "', '" . $innards . "'); \"></body></html>";
//file_put_contents('./x.x5', '1');
exit;
}
} else if (isset($_POST['makenum'])) {
$newnum=rand(123,7876543);
//file_put_contents(dirname(__FILE__) . '/t' . $newnum . '.txt', str_replace('+','%20',urlencode($_POST['makenum'])));
echo "<html><body onload=\" parent.document.getElementById('makenum').title='" . $newnum . "'; parent.document.getElementById('asms').href=parent.document.getElementById('asms').href.split('tbody')[0] + 't" . $newnum . "'; \"></body></html>";
exit;
}

?>

… which is more trouble than we’d factored in for this change …

… regarding our changed fourth draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game User Experience Tutorial is shown below.

Dominoes Horizontal Block Game User Experience Tutorial

Dominoes Horizontal Block Game User Experience Tutorial

To improve yesterday’s Dominoes Horizontal Block Game Tutorial

Turn Away From

… 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).

We can deploy this mainly through the external Javascript we talked about at Country Quizzes Beep Tutorial via …


<script type=text/javascript src='//www.rjmprogramming.com.au/beep.js?iam=song_lyric_faux_pas.html&rand=76576533' data-defer=defer></script>

That placement of one beep (for player 1 “turn away”) or two beeps (for player 2 “turn away”) can both tell players …

  • when they should turn away … as well as …
  • when they should re-engage

… regarding our changed third draft Dominoes Block Game you can try below.


Previous relevant Dominoes Horizontal Block Game Tutorial is shown below.

Dominoes Horizontal Block Game Tutorial

Dominoes Horizontal Block Game Tutorial

After yesterday’s Dominoes Game Sections Tutorial we have a …

Dominoes Horizontal Block Game

… initially coded for. Why the “Horizontal” here? Well, to allow “vertical roaming” we need to think a bit more, on it.

This ask of Google … css flip image‘s …

To flip an image using CSS, use the transform property with either the scaleX() or scaleY() function.

Quick Reference

Horizontal Flip (Mirror):
transform: scaleX(-1);

Vertical Flip (Upside Down):
transform: scaleY(-1);

Both (180-degree rotation):
transform: scale(-1, -1);

transform: scaleX(-1) idea was useful, thanks, as was css filter to blacken image out‘s …

To completely blacken an image out using a CSS filter, use filter: brightness(0);.

Quick Reference

css.blackout-image {
filter: brightness(0);
}

… this idea, thanks applied to our changed second draft Dominoes Block Game you can try below.


Previous relevant Dominoes Game Sections Tutorial is shown below.

Dominoes Game Sections Tutorial

Dominoes Game Sections Tutorial

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.

And so, that is the plan regarding our first draft sections showing of proposed Dominoes Block Game, today.


Previous relevant Dominoes Game Resources Tutorial is shown below.

Dominoes Game Resources Tutorial

Dominoes Game Resources Tutorial

When creating an online web application game, like Animated Plane and Coconut Hunt Game Nuances Tutorial‘s Animated Plane and Coconut Hunt Game or games like playing card games, they involve “things” or …

nouns

… 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 …


Dominoes

… game, as an online web application. We vaguely remember Dominoes from a while back and it involves …

  1. dominoes (we think of as tiles) … as the resource …
  2. 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 …
  3. 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 …

    1. control-command-shift-3 of that webpage
    2. open macOS PaintBrush desktop application
    3. File -> New from Clipboard
    4. form rectangle around the white on black section of tiles
    5. Edit -> Copy
    6. File -> New from Clipboard
    7. File -> Save As… dominoes.png
  • 28 x
    1. form rectangle around the white on black subsection of dominoes.png
    2. Edit -> Copy
    3. File -> New from Clipboard
    4. File -> Save As… dominoes_[leftHandDotCount]_[rightHandDotCount].png
  • 7 x
    1. form rectangle around the uniquely encountered leftHandDotCount left hand side of a dominoes_[leftHandDotCount]_[rightHandDotCount].png
    2. Edit -> Copy
    3. File -> New from Clipboard
    4. 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 Apache Document 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 …


Why on an Apache and PHP web server is it a bad idea to not have an index.html nor index.htm nor index.php within a web server folder?

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.


Previous relevant Animated Plane and Coconut Hunt Game Nuances Tutorial is shown below.

Animated Plane and Coconut Hunt Game Nuances Tutorial

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 …
    1. some “panda 🐼 led recovery” modelling of a p emoji usage (with animation) and span emoji usage (without animation) … and …
    2. 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
  • allow for sharing of the Hunt Game
  • Hunt Game sound effects

Feel free to try these tweaks to our Animated Plane and Coconut Hunt Game, in a nuanced “latest draft” Animated Plane Coconut Hunt Game web application below!


Previous relevant Coconut Hunt Game Tutorial is shown below.

Coconut Hunt Game Tutorial

Coconut Hunt Game Tutorial

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 …

I shell always love you.

? 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!


Previous relevant Animated Plane Game User Animations and Styling Tutorial is shown below.

Animated Plane Game User Animations and Styling Tutorial

Animated Plane Game User Animations and Styling Tutorial

On top of yesterday’s Animated Plane Game User Content Sharing Tutorial‘s honing in on the five “nouns” of interest …

  • trees
  • plane
  • gymnast
  • clouds
  • ground

… 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 …
    1. @keyframes
    2. transition

    … 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!

Try this in the changed “latest draft” Animated Plane Game web application below.

Did you know?

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>


Previous relevant Animated Plane Game User Content Sharing Tutorial is shown below.

Animated Plane Game User Content Sharing Tutorial

Animated Plane Game User Content Sharing Tutorial

Yesterday’s Animated Plane Game Primer Tutorial set up five “nouns” of interest …

  • trees
  • plane
  • gymnast
  • clouds
  • ground

… 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;

case '5': // ground
if ((opsd + ' ').substring(0,2) == '5:') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + (opsd + ' ').substring(2) + suffixbiu + '") !important; </sty' + 'le>'
} else {
opsd=prompt('Enter your (probably quite long) emoji (we are guessing) border image text.', '');
if (opsd != null) {
if (opsd != '') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + suffixbiu + '") !important; </sty' + 'le>'
} else {
groundalt='&groundalt='; // + encodeURIComponent(opsd);
document.body.style.borderImage='none';
document.body.style.borderBottom='1px solid transparent';
document.body.style.borderBottomWidth='0px';
//document.body.innerHTML+='<sty' + 'le> body { border-bottom-width:0px !important; } </sty' + 'le>';
}
}
}
break;

case 'e': // email
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.trim().indexOf('@') != -1) {
anchor.href = 'mailto:' + opsd.split('@')[0].split(' ')[eval(-1 + opsd.split('@')[0].split(' ').length)] + opsd.split(opsd.split('@')[0])[1].split(' ')[0] + '?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'mailto:?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

case 's': // SMS
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.substring(0,1).toLowerCase() == '+') {
anchor.href = 'sms:' + opsd.split(' ')[0] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else if (opsd.indexOf(' ') != -1) {
anchor.href = 'sms:' + opsd.split(' ')[eval(-1 + opsd.split(' ').length)] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

default:
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
break;
}
} else {
setTimeout(function(){ ino.click(); }, 100); return true;
}
isac=false;
return false;
}

function anyprompt(opsd) {
if (opsd.trim() != '') {
opsd=opsd;
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;

case '5': // ground
if ((opsd + ' ').substring(0,2) == '5:') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + (opsd + ' ').substring(2) + suffixbiu + '") !important; </sty' + 'le>'
} else {
opsd=prompt('Enter your (probably quite long) emoji (we are guessing) border image text.', '');
if (opsd != null) {
if (opsd != '') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + suffixbiu + '") !important; </sty' + 'le>'
} else {
groundalt='&groundalt='; // + encodeURIComponent(opsd);
document.body.style.borderImage='none';
document.body.style.borderBottom='1px solid transparent';
document.body.style.borderBottomWidth='0px';
//document.body.innerHTML+='<sty' + 'le> body { border-bottom-width:0px !important; } </sty' + 'le>';
}
}
}
break;

case 'e': // email
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.trim().indexOf('@') != -1) {
anchor.href = 'mailto:' + opsd.split('@')[0].split(' ')[eval(-1 + opsd.split('@')[0].split(' ').length)] + opsd.split(opsd.split('@')[0])[1].split(' ')[0] + '?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'mailto:?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

case 's': // SMS
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.substring(0,1).toLowerCase() == '+') {
anchor.href = 'sms:' + opsd.split(' ')[0] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else if (opsd.indexOf(' ') != -1) {
anchor.href = 'sms:' + opsd.split(' ')[eval(-1 + opsd.split(' ').length)] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

default:
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
break;
}
}
}

function ourprompt(ino, intlis) {
var ei=-1, si=-1;
isac=true;
var opsd=null;
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
opsd=prompt(intlis + String.fromCharCode(10) + String.fromCharCode(10) + intlis, '');
} else {
opsd=prompt(getsrc(document.getElementById('myimg').outerHTML), '');
}
if (opsd == null) { isac=false; return false; }
if (opsd.trim() != '') {
opsd=opsd;
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;

case '5': // ground
if ((opsd + ' ').substring(0,2) == '5:') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + (opsd + ' ').substring(2) + suffixbiu + '") !important; </sty' + 'le>'
} else {
opsd=prompt('Enter your (probably quite long) emoji (we are guessing) border image text.', '');
if (opsd != null) {
if (opsd != '') {
groundalt='&groundalt=' + encodeURIComponent(opsd);
document.body.innerHTML+='<sty' + 'le> body { border-image:url("' + prefixbiu + opsd.replace(/^http\:/g,'').replace(/^https\:/g,'') + suffixbiu + '") !important; </sty' + 'le>'
} else {
groundalt='&groundalt='; // + encodeURIComponent(opsd);
document.body.style.borderImage='none';
document.body.style.borderBottom='1px solid transparent';
document.body.style.borderBottomWidth='0px';
//document.body.innerHTML+='<sty' + 'le> body { border-bottom-width:0px !important; } </sty' + 'le>';
}
}
}
break;

case 'e': // email
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.trim().indexOf('@') != -1) {
anchor.href = 'mailto:' + opsd.split('@')[0].split(' ')[eval(-1 + opsd.split('@')[0].split(' ').length)] + opsd.split(opsd.split('@')[0])[1].split(' ')[0] + '?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'mailto:?subject=My%20Animation&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

case 's': // SMS
opsd=opsd.replace(/\:/g,' ');
anchor = document.createElement('a');
if (opsd.substring(0,1).toLowerCase() == '+') {
anchor.href = 'sms:' + opsd.split(' ')[0] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else if (opsd.indexOf(' ') != -1) {
anchor.href = 'sms:' + opsd.split(' ')[eval(-1 + opsd.split(' ').length)] + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
} else {
anchor.href = 'sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?rand=' + Math.floor(Math.random() * 19897865) + '#' + treesalt + planealt + gymnastalt + cloudsalt + groundalt);
}
anchor.style.display='none';
document.body.appendChild(anchor);
anchor.innerHTML='Email';
anchor.target='_top';
anchor.click();
break;

default:
if (opsd != null) {
if (opsd.trim() != '') {
treesalt='&treesalt=' + encodeURIComponent(opsd);
document.getElementById('myimg').src=('' + opsd + '').replace(/^http\:/g,'').replace(/^https\:/g,'');
}
}
break;
}
} else {
setTimeout(function(){ ino.click(); }, 100); return true;
}
isac=false;
return false;
}

… in the changed “eighth draft” Animated Plane Game web application.


Previous relevant Animated Plane Game Primer Tutorial is shown below.

Animated Plane Game Primer Tutorial

Animated Plane Game Primer Tutorial

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 Freepik image plane image animated with a rudimentary green border-bottom representing the ground …
then to “second draft” … adding https://i.makeagif.com/media/8-11-2023/Xu_roP.gif animated GIF cloud background to go with edited Freepik image because mix-blend-mode:multiply will not mask out the non heterogenous bluish clouds in the image …
then to “third draft” … tweaking https://i.makeagif.com/media/8-11-2023/Xu_roP.gif animated GIF cloud background … …
then to “fourth draft” … establishing an SVG+XML (with SVG text emoji content) border-image for the bottom border representing the ground …
then to “fifth draft” … added acknowledgements for all the help …

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 https://au.pinterest.com/pin/587930926347995281/ 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 https://giphy.com/explore/trees-swaying-stickers giphy.com/explore/trees-swaying-stickers animated (and transparently backgrounded) webp swaying trees image along with tweaked Freepik image 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.

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