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 Mobile Out and About Usage Tips Tutorial

Shower Songs Mobile Out and About Usage Tips Tutorial

Shower Songs Mobile Out and About Usage Tips Tutorial

We stumbled upon something regarding out and about mobile device Shower Songs “radio play” usage of …

  • our inhouse Shower Songs (last talked about at Shower Songs Audio and Video Remembering Tutorial (where a new YouTube temporary playlist play scenario paradigm is discussed if it’s the visuals you want as well)) “radio play” (ie. audio only)
  • out and about (using mobile data but not WiFi, perhaps Bluetooth off, volume reasonable)
  • not being charged

… scenarios. We were at first amazed but got back to “WiFi Land” doing research about our use of an iPhone’s Control Center screen (we know of, as the one with the Torch) to avoid having to effectively be touching the iPhone screen to keep it awake semi regularly (that “awake” state the ideal state for our Shower Songs “radio play” executions). We succeeded on a car trip with this but back at “WiFi Land” our research …

When out and about with an iPhone are there any benefits to having the Control Center screen on while looping music is playing?

Is it so that if you have the torch screen open when out and about with an iPhone even if it is not charging it will not fall asleep?

Is it so that if you have the Control Center screen open when out and about with an iPhone even if it is not charging it will not fall asleep?
On iphone what is the torch screen called?

Is it so that if you have the Control Center screen open when out and about with an iPhone even if it is not charging the screen will fade less?

Is it so that if you have the Control Center screen while wirelessly charging an iPhone in the car the screen will fade less frequently?

… filled with “No” led us, for a couple of days, to thinking this must have been a figment of our imagination. But, today, out and about, this time not in a car, but under those conditions above, it happened again. The use of the iPhone’s Control Center screen helped not have to keep the iPhone awake at semi-regular intervals. Perhaps our Shower Songs YouTube API methodologies (not recognized as “Media” in many car Bluetooth systems, for instance) do not exactly fit in with your typical scenario all the references above are saying “No” to? Who knows? But below is our (tweaked via experience) advice regarding our inhouse Shower Songs “radio play” out and about on a mobile device …

  1. on a well charged (ahead of time) mobile device (such as an iPhone with iOS, that all the technical terminology below references) out and about (using mobile data but not WiFi) and not being charged
  2. close unnecessary apps you have open that are not the web browser you are going to use to …
  3. if you are in a car we often find it best turning Bluetooth off and use the iPhone speakers (with a decent volume applied)
  4. open our inhouse Shower Songs web application in a mobile web browser application
  5. arrange the playlist with it’s emergent red buttons you can tap as they arrive if you are impatient (perhaps leaving some unselected)
  6. once satisfied with your ordering and music is playing …
  7. in our iPhone’s case, swipe down and left from top right, to reveal that iPhone’s Control Center display (with the Torch!)
  8. especially as you have Shower Songs “radio play, just music” happening feel free to dim the display brightness … because we got a “Yes” combating, somewhat, one of the issues cited above … finally …

    Is it so that if you have an iPhone Control Center screen open dimming it helps with burning in issues and uses less power?
  9. to loop and continuously play with much less need to “tap to wake” (but if you do, just unswipe the Control Center to tweak the Shower Songs music play settings, as required, or if the connection drops (hence the “perhaps leaving some unselected” advice above))

  10. Previous relevant Shower Songs Audio and Video Remembering Tutorial is shown below.

    Shower Songs Audio and Video Remembering Tutorial

    Shower Songs Audio and Video Remembering Tutorial

    Further to yesterday’s Shower Songs Temporary YouTube Playlist Tutorial, another player in integration to …

    • Shower Songs “was just audio” … but, as of yesterday …
    • “can also include video” … via a YouTube temporary playlist play scenario

    … is … doh! … the Shower Songs web application itself. It needs to, to our minds …

    1. offer what used to be just a “-” part to an HTML element into an HTML button element starting with …

      - 📹

      (as “just audio”) but now, via a click, able to toggle to …

      + 📹

      (as “can also include video”) … and then …
    2. via new Javascript …

      function toggleav(obut) {
      var alst=[], alstc='', alstcd='', yestothis=true;
      if (obut.innerHTML.substring(0,1) == '-') {
      obut.innerHTML='+ 📹';
      var aisare=document.getElementsByTagName('a');
      for (var ii=0; ii<aisare.length; ii++) {
      //alert(aisare[ii].href);
      if (aisare[ii].href.replace('youtubeid=','?v=').replace('/embed/','?v=').indexOf('?v=') != -1) {
      if (alst.indexOf(aisare[ii].href.replace('youtubeid=','?v=').replace('/embed/','?v=').split('?v=')[1].substring(0,11)) == -1 && aisare[ii].href.replace('youtubeid=','?v=').replace('/embed/','?v=').split('?v=')[1].trim() != '') {
      alst.push(aisare[ii].href.replace('youtubeid=','?v=').replace('/embed/','?v=').split('?v=')[1].substring(0,11));
      yestothis=true;
      if (eval('' + tas.length) > 0) {
      if (tas.indexOf(('000' + eval(1 + ii)).slice(-3)) == -1) {
      yestothis=false;
      }
      }
      if (yestothis) {
      alstc+=alstcd + aisare[ii].href.replace('youtubeid=','?v=').replace('/embed/','?v=').split('?v=')[1].substring(0,11);
      alstcd=',';
      }
      //alert('' + alst.length + ': ' + aisare[ii].href.replace('youtubeid=','?v=').replace('/embed/','?v=').split('?v=')[1].substring(0,11));
      }
      }
      }
      //if (eval('' + tas.length) > 0) {
      //} else {
      if (alstc != '') {
      //window.open('//www.youtube.com/watch_videos?video_ids=' + alstc + ',PtR4cWb4HNg', '_blank', 'top=50,left=' + eval(-600 + screen.width) + ',width=600,height=800');
      try {
      window.localStorage.removeItem('song_list_' + alstc + ',PtR4cWb4HNg');
      } catch(jygf) { }
      window.localStorage.setItem('song_list_' + alstc + ',PtR4cWb4HNg', 'https://www.rjmprogramming.com.au/' + alstc + ',PtR4cWb4HNg');

      window.open('//www.rjmprogramming.com.au/' + alstc + ',PtR4cWb4HNg', '_blank', 'top=50,left=' + eval(-600 + screen.width) + ',width=600,height=800');
      }
      //}
      //console.warn(tas);
      //console.warn(taids);
      //console.warn(vidminus);
      //console.warn(vidplus);
      } else if (obut.innerHTML.substring(0,1) == '+') {
      obut.innerHTML='- &#x1F4F9;';
      }
      }

      … be able to open a new popup window to the right which is a YouTube temporary playlist play scenario webpage, as well as remember this, and recreate this, for the next time

    … in a changed shower_songs.html Shower Songs web application, helped out by the changed ytaudioonly.js external Javascript helper.


    Previous relevant Shower Songs Temporary YouTube Playlist Tutorial is shown below.

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


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


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

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

Editable Calendar Get Arguments Tutorial

Editable Calendar Get Arguments Tutorial

Editable Calendar Get Arguments Tutorial

Get arguments are those ? or & delimited parts to URLs you sometimes see up at the address bar of web browsers. We’d be lost without them. And, though Google Translate uses it’s own set arrangement of get arguments for this “static URL” language translation mode of use we’ve been using in this Editable Calendar recent project, it does not mean that Google Translate will stop you also using any of your own “personalized” get argument arrangements as well, that it just ends up “sending through to the keeper” …


if (document.URL.indexOf('month=') != -1 && document.URL.indexOf('year=') != -1 && firstlook) {
now = new Date(eval('' + document.URL.split('year=')[1].split('&')[0].split('#')[0]), eval('' + document.URL.split('month=')[1].split('&')[0].split('#')[0]), 1);
} else if (('' + parent.document.URL).indexOf('month=') != -1 && ('' + parent.document.URL).indexOf('year=') != -1 && firstlook) {
now = new Date(eval('' + ('' + parent.document.URL).split('year=')[1].split('&')[0].split('#')[0]), eval('' + ('' + parent.document.URL).split('month=')[1].split('&')[0].split('#')[0]), 1);
}

Yes, the first cab off the rank, tipping our toes into thoughts using this, building on yesterday’s Editable Calendar English User Entry Translation Tutorial, is to …

  • take what used to be a pretty static …

    Month, Year

    … HTML caption element … and …

  • apply the global attribute …

    contenteditable=true

    … to it, making it editable and open to more personalization regarding your Editable Calendar, on the way to what we hope ends up being a more useful web application tool … while …
  • that HTML caption element’s onblur event …

    var now = new Date(), firstDayIndex=0, daysThisMonth=0;
    var origih=''; // is filled with innards of the original calendar table element at document.body onload
    var calcapv=''; // is updated with HTML caption element innards before any user interaction
    var usuff=''; // personalized get arguments go here
    var changesmade=false; // goes to true when user blurb onkeypress happens within calendar tbody span elements or if the Month, Year changes

    function newmy(ocap) {
    if (ocap.innerHTML != calcapv) {
    if (ocap.innerHTML.indexOf(',') != -1) {
    if (mths.indexOf(ocap.innerHTML.split(',')[0].trim()) != -1 && eval('' + ocap.innerHTML.split(',')[1].trim().length) == 4) {
    //changesmade=true;
    usuff='&year=' + ocap.innerHTML.split(',')[1].trim() + '&month=' + mths.indexOf(ocap.innerHTML.split(',')[0].trim());
    now = new Date(eval('' + ocap.innerHTML.split(',')[1].trim()), eval('' + mths.indexOf(ocap.innerHTML.split(',')[0].trim())), 1);
    document.getElementById('wp-calendar').innerHTML=origih;
    thismonth();
    }
    }
    }
    }

    … can be used to store our “personalized get arguments”
  • ready to be appended to the (web browser address bar) URL reaching Google Translate …

    var valvalue='';

    function ChangeLcodeNow(){
    var val = document.getElementById('language'), dd=null, pprefix='';
    docURL=documentURL.split('rjmprogramming.com.au/')[eval(-1 + documentURL.split('rjmprogramming.com.au/').length)];
    if (docURL.indexOf('.translate.goog/') != -1) { docURL=docURL.split('.translate.goog/')[1]; }
    if (changesmade) { docURL=docURL.replace('.html','.php').replace('.htm','.php'); ajaxit(); }
    if (documentURL.indexOf('&_x_tr_tl=') == -1) {
    if (val.value.length != 0 && val.value.indexOf('en') == (0 - 1)) {
    pprefix = val[val.selectedIndex].id;
    dd=new Date();
    if (documentURL.indexOf('localhost') != -1 || useintl) {
    if (changesmade) {
    window.open(document.URL.split('?')[0].split('#')[0] + '?_x_tr_tl=' + val.value + usuff, blankis, 'top=0,width=800,height=800,left=' + eval(-800 + screen.width));
    } else {
    window.open(document.URL.split('?')[0].split('#')[0] + '?_x_tr_tl=' + val.value, blankis, 'top=0,width=800,height=800,left=' + eval(-800 + screen.width));
    }
    document.getElementById('language').value='';
    } else {
    valvalue='//www-rjmprogramming-com-au.translate.goog/' + docURL.split('?')[0].split('#')[0] + '?_x_tr_sl=en&_x_tr_hl=en-GB&_x_tr_pto=nui&_x_tr_tl=' + val.value + usuff;
    setTimeout(function(){
    window.open(valvalue, '_blank', 'top=0,width=800,height=800,left=' + eval(-800 + screen.width));
    }, 2000);
    document.getElementById('language').value='';
    }
    }
    documentURL=documentURL.replace('&_x_tr_tl=', '&xtrtl=');
    } else if (documentURL.indexOf('&xtrtl=') == -1) {
    if (val.value.length != 0 && val.value.indexOf('en') == (0 - 1)) {
    pprefix = val[val.selectedIndex].id;
    dd=new Date();
    if (documentURL.indexOf('localhost') != -1 || useintl) {
    if (changesmade) {
    window.open(document.URL.split('?')[0].split('#')[0] + '?_x_tr_tl=' + val.value + usuff, blankis, 'top=0,width=800,height=800,left=' + eval(-800 + screen.width));
    } else {
    window.open(document.URL.split('?')[0].split('#')[0] + '?_x_tr_tl=' + val.value, blankis, 'top=0,width=800,height=800,left=' + eval(-800 + screen.width));
    }
    document.getElementById('language').value='';
    } else {
    valvalue='//www-rjmprogramming-com-au.translate.goog/' + docURL.split('?')[0].split('#')[0] + '?_x_tr_sl=en&_x_tr_hl=en-GB&_x_tr_pto=nui&_x_tr_tl=' + val.value + usuff;
    setTimeout(function(){
    window.open(valvalue, '_top');
    }, 2000);
    document.getElementById('language').value='';
    }
    }
    }
    }

    … and through to our own RJM Programming code

… the one in today’s tutorial picture featuring …


https://www-rjmprogramming-com-au.translate.goog/calendar_contenteditable?_x_tr_sl=en&_x_tr_hl=en-GB&_x_tr_pto=nui&_x_tr_tl=zh-CN&year=2026&month=1

Again, feel free to try this in the changed fifth draft Editable Calendar you can try below, helped out by a tweaked calendar_contenteditable.php helping PHP newish player.


Previous relevant Editable Calendar English User Entry Translation Tutorial is shown below.

Editable Calendar English User Entry Translation Tutorial

Editable Calendar English User Entry Translation Tutorial

For today’s work, we were thinking of using window.sessionStorage logic, but because of the advice of Can a window.open Google Translate popup window access the sessionStorage written by the originating window from another domain? warning us off, that what we regard as an “ever so cute” solution is not a goer, alas! So, what else is going to help regarding the dilemma …

Why the skeletal here? Well, your own entries made before you select a dropdown non English language choice are stripped out …

… we referenced when presenting Editable Calendar Google Translate Tutorial before the recent Editable Calendar Intl Tutorial? Today’s work plonks them back in by involving PHP, as our server side language that can write to and read from ascii text files stored on our RJM Programming domain web server. By, when needed, getting Google Translate to, when required (ie. we’ve decided this is when the keyboard onkeypress happens), reference a .php based RJM Programming URL, leaves that opportunity to …

Shape to write the calendar table innards to an ascii web server text file via Ajax … client side …

function ajaxit() {
var zhr = new XMLHttpRequest();
var zform = new FormData();
zform.append('tihis', document.getElementById('wp-calendar').innerHTML);
zhr.open('post', '/' + docURL.split('?')[0].split('#')[0].replace('.html','.php').replace('.htm','.php'), true);
zhr.send(zform);
}
Write the calendar table innards to an ascii web server text file via PHP … server side …
<?php

if (isset($_POST['tihis'])) {
file_put_contents('tihis.txt', str_replace('+',' ',urldecode($_POST['tihis'])));
exit;
}

?>
As needed, very soon after, as Google Translate is called with a .php based URL, substitute this saved table innards into a read from default representation of the HTML via PHP … server side …
<?php

if (file_exists('tihis.txt')) {
$newih=file_get_contents('tihis.txt');
unlink('tihis.txt');
if (strpos($newih, '<cap' . 'tion ') !== false) {
$usualis=file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'calendar_contenteditable.html');
$bittochange='<cap' . 'tion ' . explode('</table>', explode('<cap' . 'tion ', $usualis)[-1 + sizeof(explode('<cap' . 'tion ', $usualis))])[0];
echo str_replace($bittochange, $newih, $usualis);
exit;
} else {
header('Location: /calendar_contenteditable.html');
exit;
}
}

?>
Leaving any document.body onload event logics out (in first codeline of such onload event Javascript function), in such a scenario, leaving it all to Google Translate’s talents … client side …

if (('' + parent.document.URL).indexOf('.php') != -1) { return ''; }

Feel free to try this in the changed fourth draft Editable Calendar you can try below, helped out by a new calendar_contenteditable.php helping PHP new player.


Previous relevant Editable Calendar Intl Tutorial is shown below.

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.


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


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

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

Editable Calendar English User Entry Translation Tutorial

Editable Calendar English User Entry Translation Tutorial

Editable Calendar English User Entry Translation Tutorial

For today’s work, we were thinking of using window.sessionStorage logic, but because of the advice of Can a window.open Google Translate popup window access the sessionStorage written by the originating window from another domain? warning us off, that what we regard as an “ever so cute” solution is not a goer, alas! So, what else is going to help regarding the dilemma …

Why the skeletal here? Well, your own entries made before you select a dropdown non English language choice are stripped out …

… we referenced when presenting Editable Calendar Google Translate Tutorial before the recent Editable Calendar Intl Tutorial? Today’s work plonks them back in by involving PHP, as our server side language that can write to and read from ascii text files stored on our RJM Programming domain web server. By, when needed, getting Google Translate to, when required (ie. we’ve decided this is when the keyboard onkeypress happens), reference a .php based RJM Programming URL, leaves that opportunity to …

Shape to write the calendar table innards to an ascii web server text file via Ajax … client side …

function ajaxit() {
var zhr = new XMLHttpRequest();
var zform = new FormData();
zform.append('tihis', document.getElementById('wp-calendar').innerHTML);
zhr.open('post', '/' + docURL.split('?')[0].split('#')[0].replace('.html','.php').replace('.htm','.php'), true);
zhr.send(zform);
}
Write the calendar table innards to an ascii web server text file via PHP … server side …
<?php

if (isset($_POST['tihis'])) {
file_put_contents('tihis.txt', str_replace('+',' ',urldecode($_POST['tihis'])));
exit;
}

?>
As needed, very soon after, as Google Translate is called with a .php based URL, substitute this saved table innards into a read from default representation of the HTML via PHP … server side …
<?php

if (file_exists('tihis.txt')) {
$newih=file_get_contents('tihis.txt');
unlink('tihis.txt');
if (strpos($newih, '<cap' . 'tion ') !== false) {
$usualis=file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'calendar_contenteditable.html');
$bittochange='<cap' . 'tion ' . explode('</table>', explode('<cap' . 'tion ', $usualis)[-1 + sizeof(explode('<cap' . 'tion ', $usualis))])[0];
echo str_replace($bittochange, $newih, $usualis);
exit;
} else {
header('Location: /calendar_contenteditable.html');
exit;
}
}

?>
Leaving any document.body onload event logics out (in first codeline of such onload event Javascript function), in such a scenario, leaving it all to Google Translate’s talents … client side …

if (('' + parent.document.URL).indexOf('.php') != -1) { return ''; }

Feel free to try this in the changed fourth draft Editable Calendar you can try below, helped out by a new calendar_contenteditable.php helping PHP new player.


Previous relevant Editable Calendar Intl Tutorial is shown below.

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.


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

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

Shower Songs Audio and Video Remembering Tutorial

Shower Songs Audio and Video Remembering Tutorial

Shower Songs Audio and Video Remembering Tutorial

Further to yesterday’s Shower Songs Temporary YouTube Playlist Tutorial, another player in integration to …

  • Shower Songs “was just audio” … but, as of yesterday …
  • “can also include video” … via a YouTube temporary playlist play scenario

… is … doh! … the Shower Songs web application itself. It needs to, to our minds …

  1. offer what used to be just a “-” part to an HTML element into an HTML button element starting with …

    - 📹

    (as “just audio”) but now, via a click, able to toggle to …

    + 📹

    (as “can also include video”) … and then …
  2. via new Javascript …

    function toggleav(obut) {
    var alst=[], alstc='', alstcd='', yestothis=true;
    if (obut.innerHTML.substring(0,1) == '-') {
    obut.innerHTML='+ &#x1F4F9;';
    var aisare=document.getElementsByTagName('a');
    for (var ii=0; ii<aisare.length; ii++) {
    //alert(aisare[ii].href);
    if (aisare[ii].href.replace('youtubeid=','?v=').replace('/embed/','?v=').indexOf('?v=') != -1) {
    if (alst.indexOf(aisare[ii].href.replace('youtubeid=','?v=').replace('/embed/','?v=').split('?v=')[1].substring(0,11)) == -1 && aisare[ii].href.replace('youtubeid=','?v=').replace('/embed/','?v=').split('?v=')[1].trim() != '') {
    alst.push(aisare[ii].href.replace('youtubeid=','?v=').replace('/embed/','?v=').split('?v=')[1].substring(0,11));
    yestothis=true;
    if (eval('' + tas.length) > 0) {
    if (tas.indexOf(('000' + eval(1 + ii)).slice(-3)) == -1) {
    yestothis=false;
    }
    }
    if (yestothis) {
    alstc+=alstcd + aisare[ii].href.replace('youtubeid=','?v=').replace('/embed/','?v=').split('?v=')[1].substring(0,11);
    alstcd=',';
    }
    //alert('' + alst.length + ': ' + aisare[ii].href.replace('youtubeid=','?v=').replace('/embed/','?v=').split('?v=')[1].substring(0,11));
    }
    }
    }
    //if (eval('' + tas.length) > 0) {
    //} else {
    if (alstc != '') {
    //window.open('//www.youtube.com/watch_videos?video_ids=' + alstc + ',PtR4cWb4HNg', '_blank', 'top=50,left=' + eval(-600 + screen.width) + ',width=600,height=800');
    try {
    window.localStorage.removeItem('song_list_' + alstc + ',PtR4cWb4HNg');
    } catch(jygf) { }
    window.localStorage.setItem('song_list_' + alstc + ',PtR4cWb4HNg', 'https://www.rjmprogramming.com.au/' + alstc + ',PtR4cWb4HNg');

    window.open('//www.rjmprogramming.com.au/' + alstc + ',PtR4cWb4HNg', '_blank', 'top=50,left=' + eval(-600 + screen.width) + ',width=600,height=800');
    }
    //}
    //console.warn(tas);
    //console.warn(taids);
    //console.warn(vidminus);
    //console.warn(vidplus);
    } else if (obut.innerHTML.substring(0,1) == '+') {
    obut.innerHTML='- &#x1F4F9;';
    }
    }

    … be able to open a new popup window to the right which is a YouTube temporary playlist play scenario webpage, as well as remember this, and recreate this, for the next time

… in a changed shower_songs.html Shower Songs web application, helped out by the changed ytaudioonly.js external Javascript helper.


Previous relevant Shower Songs Temporary YouTube Playlist Tutorial is shown below.

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


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

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

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