PHP macOS say Supervising Google Translate Sharing Tutorial
Today’s integration of the Javascript clientside window.postMessage into …
our inhouse PHP macOS say Supervisor, or Voiceover Ideas, talked about at PHP macOS say Supervising a Retrained Siri Nuance Tutorial, regarding it’s Google Translate dropdown option (used as a Voiceover Idea both with the macOS PHP MAMP environment and the live RJM Programming version) … benefits from the recent …
… cross domain concepts, which is used, here, as of today, in the usage scenario we’ll outline later, whereby English to Non-English language translations become a possibility into the “functionality mix”
<?php echo ”
window.addEventListener(\"message\", (event) => { // thanks to https://www.google.com/search?q=Undef+what+conditions+can+window.opener.parentfunc()+type+of+call+work+when+the+domains+are+different%3F&rlz=1C5OZZY_en&oq=Undef+what+conditions+can+window.opener.parentfunc()+type+of+call+work+when+the+domains+are+different%3F&gs_lcrp=EgZjaHJvbWUyBggAEEUYOdIBCTI2NzQwajBqN6gCALACAA&sourceid=chrome&source=chrome.ob&ie=UTF-8
// Always verify the origin of the sender for security
if (event.origin !== \"https://www-rjmprogramming-com-au.translate.goog\") return;
lasttrans=decodeURIComponent(decodeURIComponent(event.data));
document.getElementById('thewords').title=document.getElementById('thewords').value;
document.getElementById('thewords').value=decodeURIComponent(decodeURIComponent(event.data));
});
“; ?>
… for a usage scenario like …
in a web browser link to our inhouse Voiceover Ideas as the “parent” window
if not already selected select Google Translate in top “mode of use” dropdown
in the Language Code dropdown select a language such as Hindi
this populates the Words textarea with some phrasing macOS say command associates with a Voice speaking that selected language
now here, perhaps you would not think to do this, but we’re saying a user might override those Hindi default words with some English words the user enters
click/tap Hear These Words button
as of today, in this type of scenario, as well as one Google Translate popup window appearing, under it, in this scenario another Google Translate of RJM Programming Landing Page with Tailored Arguments “child” window is created, and which …
is able to communicate back to the “parent” window via window.postMessage …
so as to make it that the displayed content of the Words textarea can become the Hindi translation of the English while the on hover title attribute can become the originating English … and …
in this scenario a Words textarea ondblclick (for a double click/tap) toggles the roles above
confusing … in the way first one we’re asking you not to click the button but others we do
you may want to replay the audio from a previous Siri command
first say invocation a bit slow (on the uptake)
That third one is the most interesting. You see, macOS say likes to output any audio output asked of it to an audio/aiff format, which browsers like Google Chrome will not play. To overcome this, we start with …
Yes, ideally we’d like you, on your macOS system, to have installed the amazing, the stupendous, the good ol’ ffmpeg command line tool, as an “optional” here.
And then, back at the “client side ranch” …
function getthenextone() {
if (retridx > 0) {
if (document.getElementById('mysiriaudio')) {
document.getElementById('mysiriaudio').style.display='inline-block';
if (document.getElementById('mysirisource').src.indexOf('?') == -1) {
document.getElementById('mysirisource').src+='?rand=' + Math.floor(Math.random() * 167564);
} else {
document.getElementById('mysirisource').src+=('' + Math.floor(Math.random() * 9))
}
if (document.getElementById('mysirisourcetwo').src.indexOf('?') == -1) {
document.getElementById('mysirisourcetwo').src+='?rand=' + Math.floor(Math.random() * 167564);
} else {
document.getElementById('mysirisourcetwo').src+=('' + Math.floor(Math.random() * 9))
}
if (document.getElementById('spaudio')) {
document.getElementById('spaudio').innerHTML=document.getElementById('spaudio').innerHTML;
}
}
if (retridx < eval('' + retrainings.length)) {
document.getElementById('saysub').disabled=false;
document.getElementById('saysub').style.cursor='pointer';
document.getElementById('saysub').value='Hear These Words ... ' + retrainings[retridx] + ' (when you click/tap)';
document.getElementById('thewords').value=retrainings[retridx];
retridx++;
}
}
}
PHP macOS say Supervising a Retrained Siri Tutorial
Here Siri, it’s time for a retraining session.
Hey Bud, I only respond to Hey.
Sorry, Bud … but as the provider of your treats … smirk … Hey Siri, it’s time for a retraining session.
Why retrain Siri? Well, let me ask (not you Siri) …
Do you cringe at the sound of your own voice? Even in a cupboard? Especially in a cupboard?!
… and then …
And yet, you can see the advantages of Siri if it did not involve the sound of your own voice? Even in a cupboard? Especially in a cupboard?!
Yes? Well …
if you have an iOS device to be the Siri conduit …
if you have a macOS device (and so access to the great say Text to Speech command via PHP exec command), such as the MacBook Air, here, today … installed with …
MAMP … Apache/PHP/MySql local web server … and have downloaded the latest (at time of writing) …
http://localhost:8888/macos_say_record.php into that MAMP‘s macOS (default port) Document Root folder
http://localhost:8888/HTMLCSS/client_browsing.htm into that MAMP’s macOS (default port) Document Root folder’s HTMLCSS subfolder
… phew!!! Have we got news for you?!!!
Yes, it might be worthwhile for people still reading to force a retraining of Siri in favour of a macOS Voice of Choice.
Assuming you’re ready for Siri retraining class (further to PHP macOS say Supervisor Modes of Use Tutorial below), and you have cancelled your own voice settings and being asked by the Siri setup, below are what we as that ever so fluid a concept were asked to “Say” “Hey” …
It seems a bit strange to be talking about macOS and command line “say” commands, and not, on top of its …
usual “surfing the net” via the web browser address bar mode of use … to, today, add …
a “command line” mode of use … and …
the manufactured feeling “curl” mode of use
… to its talents so that “say” on the macOS command line can have equivalencies with …
<?php
if (isset($argv)) { // command line
$commandsofar="say ";
$numargs = sizeof($argv);
if ($numargs > 1) {
if (PHP_OS == "Darwin") {
for ($ii=1; $ii<$numargs; $ii++) {
if ($ii == 1 && strtolower($argv[$ii]) == 'say') {
$commandsofar="say ";
} else {
$commandsofar.=' ' . $argv[$ii];
}
}
passthru($commandsofar);
exit;
}
} else {
if (PHP_OS == "Darwin") {
passthru("info say");
exit;
}
}
} else if (isset($_GET['curlit'])) { // curl
$commandsofar="say ";
if (PHP_OS == "Darwin") {
passthru(str_replace("say say ","say ","say " . str_replace('+',' ',urldecode($_GET['curlit']))));
exit;
}
}
?>
a “command line” mode of use … where “say blah-blah-blah” on a command line can be equivalent to, say, “php ./macos_say_record.php blah-blah-blah” …
the manufactured feeling “curl” mode of use asks of the user a way to use a command like “curl ‘HTTP://localhost:8888/macos_say_record.php?curlit=blah-blah-blah‘” (where blah-blah-blah = encodeURIComponent(blah-blah-blah))
We also increased “say” functionality by not forcing …
the default output, for “say” use, of creating an audio file … and, as of today, adding that, as an alternative …
if the audio file is set to blank by the user the “say” operating system command is performed behind the scenes …
<?php
if (str_replace("+"," ",urldecode($_GET['audioname'])) == "") { passthru("say" . $sayprefix . " " . str_replace("\n",",,,,,,",$thewords) . " > " . dirname(__FILE__) . "/sayout.out" . " 2> " . dirname(__FILE__) . "/sayerr.err");
exit;
} else {
exec("say" . $sayprefix . " -o " . dirname(__FILE__) . "/" . str_replace("+"," ",urldecode($_GET['audioname'])) . " " . str_replace("\n",",,,,,,",$thewords) . " > " . dirname(__FILE__) . "/sayout.out" . " 2> " . dirname(__FILE__) . "/sayerr.err");
}
?>
… getting us to moderate that “audiofile” textbox functionality this way …
<?php
$audioft="";
if (PHP_OS == "Darwin") {
$audioft=' title="This made to be blank and the topmost say dropdown choice will cause the text to audio to play through your speakers." onblur="if (this.value.trim().length == 0 && document.getElementById(' . "'" . 'saymode' . "'" . ').value.length == 0) { document.getElementById(' . "'" . 'saysub' . "'" . ').value=document.getElementById(' . "'" . 'saysub' . "'" . ').value.replace(' . "'" . 'Record ' . "'" . ',' . "'" . 'Say ' . "'" . '); } else if (this.value.trim().length != 0 && document.getElementById(' . "'" . 'saymode' . "'" . ').value.length == 0) { document.getElementById(' . "'" . 'saysub' . "'" . ').value=document.getElementById(' . "'" . 'saysub' . "'" . ').value.replace(' . "'" . 'Say ' . "'" . ',' . "'" . 'Record ' . "'" . '); }"';
}
Windows 10 Camera app … photographing the slide contents of yesterday’s video presentation
Windows 10 Photos app … turning the slides above into yesterday’s video presentation … along with its Share option Mail to email off and sftp into place
Don’t be concerned, it will not harm you
It’s only me pursuing somethin’ I’m not sure of
Across my dreams with nets of wonder
I chase the bright elusive butterfly of love
… ilk of things, a creeping up on our interest in a programmable link between …
macOS say (via crontab or at (macOS command scheduling functionality), eventually) control
And our verdict, after today’s iPhone Siri setup (which gets you to “say”, modelling …
say “Hey Siri”
say “Hey Siri, send a message”
say “Hey Siri, how’s the weather today”
say “Hey Siri, set a timer for three minutes”
say “Hey Siri, play some music”
… sentences above to configure the relevant voice) along with a macOS command line “say” arrangement, is … da, da da da da da, da, da da we could go on with the whole lion bit, but we’ll spare you … yes, we can get “say” command on macOS work a …
Hey Siri, Play U2
say “Hey Siri, Play U2”
… type of Siri dictation command onto (our) iPhone’s (default Spotify) music app to play a song. It’s just that … first wooooorrrrlllldddd problem alert … the “say” command was not that flash at …
Hey Siri, Stop
say “Hey Siri, Stop”
… to stop the music, as well as our own … yoo hoo … voice is. And so, our recommendation is to setup Siri for multiple voices. How? Hard to believe, but it seems, in iPhone’s Settings -> Siri & Search screen, turning the top green (Listen for “Hey Siri”) switch in the settings to off and then back on is the go?! The resultant procedure is where you can “train” Siri to recognize a macOS “say” voice, as well as your own voice, or a bunch of other “Siri Voice” (menu) choices offered “out of the box” with the iPhone iOS installed. It may be that you should explore macOS “say” -v [VoiceName] choices, as well, here.
How does this work sit with macOS crontab “say” command thinking that goes with our changed inhousemacos_say_record.php (we recommend you download to macOS MAMP local web server and startup via HTTP://localhost:8888/macos_say_record.php web address URL) MacOS Text to Audio online PHP supervisor talked about with MacOS Text to Audio Scheduling Tutorial? Well, without reliable “stop” … first wooooorrrrlllldddd problem or not … we are going to continue research, but we’re not sure that you will be totally spared from your own voice interventions for stopping (of music) purposes … or perhaps get yourselves an Apple HomePod mini …
We’re resetting the iOS Siri app mentioned in Siri on iPad Mail Dictate Tutorial on another iPad today. We wanted to set it up (via Settings -> Siri & Search) to play songs on Apple Music with spoken words (directed to Siri) such as …
Hope you are not like me and feel like going into a cupboard to use a microphone on a mobile device. If this is not you, and you have a half recent version of iOS on an iPad or iPhone, and you have Siri available as an app, then today’s tutorial may be of interest.
Siri can be like a personal assistant, and the way we best think of it as such, is as a tool to help dictate an email, using the Mail app on our iPad. To get to that, though, if you’ve never used Siri before, you should consult this Apple webpage, or our previous Apple iOS Siri Audio Commentary Tutorial to get started. Once you’re setup for Siri in this way it is very easy to start using Siri when composing emails.
Open the Mail app
Fill in the To field via the keyboard … Siri can’t do this very well … but while you are at the keyboard, what’s the third button from the left on the bottom row? Yes, the “microphone” button gets you to Siri functionality … cute, huh?!
Guess we don’t need to say, but will, that this microphone button becomes useful as soon as you tap in a “keyboard” anything … Siri can be there to assist … personally!
But a word of caution here, is to check about homonyms like today’s “in all innocence” …
The rain in Spain falls mainly on the plane
… Siri faux pas. This is a small concern compared to how much it can do that is correct. Hands free dictation can be very useful for those users on the go, or those kinaesthetic thinkers, perhaps.
On the iPad latest iOS, which we’ll have to talk about soon, there are other good suggestions for Siri use to add to …
Mail (app) … those being …
Safari
Photos
Camera
Settings … and
Numerous Third Party and homegrown apps that access the keyboard, and so, Siri “microphone”
Hope this is food for thought, and we’ll leave you with today’s PDF presentation of a Mail app session using Siri to help build up the body section email content, here.
Now that idea’s first, second and everything aside from ‘HTML audio elements that allow for an audio commentary of the 9 “subimages”‘ of the third parts we’ve been consistent on, but the idea to do this in the first place was secondly inspired by reading this interesting link referring to the CSS selectors :before and :after use of the content property, especially where it says …
url(url) Sets the content to be some kind of media (an image, a sound, a video, etc.)
… not quite believing it could be true … yes, an image, but “a sound, a video“? No way! Well, alas, as of this date, yes … no way … yet. Then seeing this CSS approach wasn’t working … lo and behold … this link explains more … thanks.
But this setback is not the end of the world, and the other backup plan of …
HTML area elements of the HTML map element will be given onmouseover and onclick event logic added to it while using the Mobilefish online map creator … and we’ll massage the resultant HTML to put this logic in as well as the HTML audio element “shells” as well as …
Define audio file comma separated lists in the HTML area elements’ alt attributes
… involves this Javascript DOM code to make the audio commentary be controlled by a hover (but not on mobile devices) and/or click/touch of a “subimage” of interest from the main image …
<script type='text/javascript'>
var lastomo='';
var lastoc='';
var e, prebits, bits, i;
After the tutorial two days back, with Windows 10 and its Cortana voice recognition “personal assistant” (that we tested out with Windows 10 Cortana Primer Tutorial below) you’d be wondering if Apple has an equivalent, and yes, for iOS, which we are going to show today on an iPad, and there are “kind of” ways for Mac OS X El Capitan you can read about here.
Siri lets you use your voice to send messages, schedule meetings, place phone calls and more. Ask Siri to do things just by talking the way you talk. Siri understands what you say, knows what you mean and even talks back. Siri is so easy to use and does so much, you’ll keep finding more and more ways to use it.
This being an iPad, and this being iOS, we had no issues with microphones setting up Siri. The microphone is well integrated into iPad normal usage, and the main job for today’s iPad Siri setup that you get to via …
In the area of robotics and artificial intelligence, perhaps the best known concept to we “mere mortals” is “voice recognition”. Perhaps because research into it goes back to 1932, before the Second World War … and 66 years before the “Worm Farm Incident of Simmons Street Disaster” … but we digress … and no … “I’m not ready to open up about this at this delicate stage of my life, yet, Brad.”.
Voice recognition has come a long way from those earliest endeavours when the speech recognition relied on training software for an individual voice. This became apparent to me trying out Cortana in Windows 10. Once working, it didn’t seem to matter who in our house asked the same question of Cortana, the speech recognition software recognized and translated the speech into the same text for all of us. Actually, Microsoft describes Cortana this way …
Cortana is your clever new personal assistant.
Cortana will help you find things on your PC, manage your calendar, track packages, find files, chat with you, and tell jokes. The more you use Cortana, the more personalized your experience will be.
To get started, type a question in the search box on the taskbar. Or select the microphone icon and talk to Cortana. (Typing works for all types of PCs, but you need a mic to talk.)
… and I see what they mean by this, because you can work Cortana without the voice recognition part, if you like, or if you have the urge to run for the nearest cupboard before being caught talking into a computer (microphone). Perhaps Cortana should have a special “Darkroom Edition” for people who …
have the urge to run for the nearest cupboard before being caught talking into a computer (microphone) … and who …
have a hobby developing and printing photographs
Anyway, we agree with Microsoft that Cortana is clever, and it’s nice for us to find another use for the microphone (brand called MXL Tempo) we used with WebEx work we talked about with WebEx Presentation with Microphone Tutorial below.
There is not much to setting up Cortana, except, perhaps, for the microphone bit, which we’ll talk more about later. Cortana’s “personal assistant” and interface down next to the Windows icon at the bottom left of the screen guides you well through what you have to do.
We got stuck a bit, regarding setting up the microphone, with a cycle of it presenting this voice recognition test always resulting in a message wondering whether we had the microphone set to “mute on”, which wasn’t the case. But what was the case, and remedied this problem was to use a USB 2 port rather than a USB 3 port … in case this happens to you.
Other than that, Cortana is pretty cute, and could be a good enough reason on its own to upgrade to Windows 10 from Windows 7, Windows 8.1, Windows Phone 8.1 or Windows 9 operating systems before Friday, 29th July 2016 which is the cut off day for free upgrades. Our experience of the upgrade was talked about at Windows 10 Upgrade Primer Tutorial (and backups were discussed at Windows File History Backup Primer Tutorial).
We’ve been doing some more WebEx (by Cisco) lately, and realised, at least with using a MacBook Pro laptop, we needed to invest in a microphone, to be heard, as the inbuilt microphone systems were not up to it.
We opted for a USB connected microphone brand called MXL Tempo, sold here in Australia, and have found it to be good, especially mounted on the stand provided … well, no complaints, anyway?! Where it has a 1/8″ (3.5mm) Headphone Jack we plugged in our own speakers, though you could use headphones here as well.
Of course we’ll also be constructing a garage, and buying a guitar, and calling on “tree fellers”karaoke backing track of Peter, Paul and Mary to complete the picture of this week’s project … getting the new microphone to make breakfast in the morning before you even knew you needed breakfast get me on The Voices.
In the WebEx “Audio Connection” menu via “Call Using Computer” option have both input and output audio be handled by “USB audio CODEC” (if they are options … if not, there is a hardware (perhaps configuration) problem with your audio and microphone connection) as you can see at today’s tutorial picture. So long as you succeed and have the USB connected, the audio connection will default to this arrangement for the next time. Cute, huh?!
To make it permanent that the MXL Tempo microphone arrangement is the default device for recordings …
click on System Preferences off the Apple menu
click the Sound option
click the Output tab
pick USB audio CODEC
if you intend using speakers or headphones connected off this microphone from its 1/8″ (3.5mm) Headphone Jack, click the Input tab
… regarding video conferencing products we’ve tried at this blog.
Have to say, WebEx is great, even with respect to the “wide eyed and bushy tailed” reaction “this little black duck” has to all these networky communicaty ideas on the net (at least we spelt “net” correctly).
Have to thank my wife, Maree, for her expertise and the facilities her company, Thomson Reuters, supplies for the serving of WebEx recordings … thanks everyone. Have been assured they are periodically deleted, and my lame impersonations of the old “ducks on the wall” can rest in peace shortly.
And so, we have a slideshow starting with a WebEx email link to join a meeting, and we pan down the email to show you other WebEx functionalities, such as adding a Calendar reference to the meeting time, and though we haven’t shown you detail here, rest assured it handles timezone scenarios very well, unless you lie about living in Antarctica, that is … sorry, scientists in Antarctica reading this blog posting … all 237 of you.
During this “earlier than today exploration of WebEx” session the necessary software installs just happened for this MacBook Pro Mac OS X laptop as if we were shelling peas … it’s always good to have some handy when installing any software. So we won’t show you this unless we deem it essential at a later date. You can perhaps do as I did, and ask a real WebEx user invite you to a meeting, to set yourself up. In fact, today’s session meeting creation time you may notice is well in the past from that earlier introductory learning session Maree and I had, and you can bring back up that old email, and resurrect that meeting again and again, if you like … am not sure if there is an expiry date on this too, like with server stored WebEx prerecordings.
So also rest assured, WebEx handles …
video via webcam on your device
audio via microphone on your device (“Use Computer”) or via a phone line
the synchronization of the two above
mobile devices
Did you know?
A .ics extension file, as you can see being used as an email attachment file extension in is, as explained in this link‘s sublink …
ICS is a global format for calendar files widely being utilized by various calendar and email programs including Google Calendar, Apple iCal, and Microsoft Outlook. These files enable users to share and publish information directly from their calendars over email or via uploading it to the world wide web.
… as helping interface meetings to online calendar appointments. Cute, huh?!
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
If this was interesting you may be interested in this too.
sharing … and caring and we all know sharing can lead to …
collaboration
… and today we’re encouraging users to join in with others sharing editable calendars via email (and though the hashtagging goes beyond SMS lengths we’re including that as an option too, and we may find a way down the track that the lengths of data can be reduced to suit an SMS message …
… is our go to regarding the internationalization and language translation functionality. We get to Google Translate, where permitted (up to you, and whether you have popup blockers happening with the web browser you are using), via a popup window, which means, in that scenario, there are two distinct domains in play …
Be listening out at the RJM Programming domain document.URL scenario “parent” window …
window.addEventListener("message", (event) => { // thanks to https://www.google.com/search?q=Undef+what+conditions+can+window.opener.parentfunc()+type+of+call+work+when+the+domains+are+different%3F&rlz=1C5OZZY_en&oq=Undef+what+conditions+can+window.opener.parentfunc()+type+of+call+work+when+the+domains+are+different%3F&gs_lcrp=EgZjaHJvbWUyBggAEEUYOdIBCTI2NzQwajBqN6gCALACAA&sourceid=chrome&source=chrome.ob&ie=UTF-8
var thislang='';
// Always verify the origin of the sender for security
if (event.origin !== "https://www-rjmprogramming-com-au.translate.goog") return;
Today is Styling Day regarding our current Editable Calendar project we last talked about with yesterday’s Editable Calendar Save and Recall Tutorial. We cannot recall ever arranging the body element background exactly as we did (probably because we only had the top and the bottom of the screen for context, the middle being the calendar) in the CSS below …
body {
background-image: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),url(https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSAMB0R0_H50ZU4AW0t51IqB0WwOyF1BEmSPy3MMxisNythxHs69b4lcx8&s=10);
background-size: contain;
background-repeat: repeat;
}
</style>
… where some judiciously placed background-color:transparent helps this out with transparency ideas. We find applying border-radius a good way to “soften” the look, and “text-shadow” as a way to allow for a 3D look to innerHTML contenteditable=true types of elements.
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);
}
… 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='';
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 …
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 ''; }
Because the theme of our current Editable Calendar web application revolves around time stamps and day names and month names regarding yesterday’s Editable Calendar Google Translate Tutorial that means, regarding language internationalization ideas …
as well as yesterday’s Google Translate ideas … also available is …
Yesterday’s Editable Calendar Primer Tutorial‘s start to our Editable Calendar project was a very anglo-centric exercise. Today, we want to use the great …
… to help translate our inhouse burgeoning Editable Calendar skeletal contents to some non English languages.
Why the skeletal here? Well, your own entries made before you select a dropdown non English language choice are stripped out in this changedsecond draftEditable Calendar you can try below, because we’re using the Google Translate “static URL” approach to the translations. But we will examine, down the track, if we can do better?! Again, stay tuned for more progression and internationalization over the days on this Editable Calendar project.
we’re channelling how in emails “word strings” starting with “http” become links … and so …
in our event in month “blurb” textarea elements we allow user highlighted text containing such “http” “word strings” be opened in popup windows showing the content of those URLs, as available
Here is the relevant Javascript we ended up with, for this …
Just briefly, delved into the wooooorrrrllllldddd of days of the week before 1582 debate … you had to be there … and in the words of Lleyton … Come on!!!! And we came out the other side. Good times! Anyway, thanks for all the interesting discussion, which we recommend you start at with this gem. Anyway, we now allow dates after 1582 (after this was previously set at 1970) in all respects and dates between 0000 and 1581 only via tweaks to the address bar URL you do yourself and we just hide the day of the week string. Otherwise … this could be needed?!
When doing our inhouse testing for Event Calendar Collaboration Tutorial the other day, it got us “peeved”, shall we say. We wanted a mechanism, with those “a” link “mailto:” emailing arrangements, of not having to fill out the email address in the “To:” field each time. First world problem alert! Still and all …
When it comes to procedures …
Aaaaaarrrrgggghhhh …
Nuances count … regarding …
Errrrrrr …
Saving time …
Saving frustration
… resulting in the “easy to remember” acronym WANESS … we rest our cases!
What can help here? Well, it is a personalization … so … anyone, anyone? Yes, Lou, back from holidays, a month late … yes, well, okay … we can see you’ve put some thought into this … HTTP Cookies could be used. Yes, Shwetank, you’ve had your hand up some time now. We agree, Web Storage window.localStorage allows for more data, so we’ll go with that, though either style of approach would work here.
Global variables initialization …
var defemail='', defsms='';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
Within document.body onload event logic …
if (document.getElementById('semail') && document.getElementById('ssms')) {
document.getElementById('semail').oncontextmenu=function(){ emailaskit(); };
document.getElementById('semail').ontouchmove=function(){ emailaskit(); };
document.getElementById('ssms').oncontextmenu=function(){ smsaskit(); };
document.getElementById('ssms').ontouchmove=function(){ smsaskit(); };
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('semail').title+=' Move gesture here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Move gesture here can ask for new default remembered SMS number for collaboration purposes';
} else {
document.getElementById('semail').title+=' Right click here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Right click here can ask for new default remembered SMS number for collaboration purposes';
}
}
Calling these two Javascript function helpers …
function emailaskit() {
if (defemail == defemail.trim()) {
defemail=defemail.trim() + ' ';
var emailm=prompt('Enter default email address.', defemail.trim());
if (emailm == null) { emailm=''; }
if (emailm.trim() != '' && emailm.trim().indexOf('@') != -1) {
defemail=emailm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', emailm.trim());
}
}
defemail=defemail.trim() + ' ';
}
function smsaskit() {
if (defsms == defsms.trim()) {
defsms=defsms.trim() + ' ';
var smsm=prompt('Enter default SMS number.', defsms.trim());
if (smsm == null) { smsm=''; }
if (smsm.trim() != '' && smsm.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
defsms=smsm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', smsm.trim());
}
}
defsms=defsms.trim() + ' ';
}
And allow control, as well, at the SMS prompt window logic …
function dosms() {
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
//alert('' + eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length));
if (eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length) >= 18000) {
snum=('' + prompt('Please enter SMS number to send to. We suspect message is too long for an SMS and if you enter an email address here instead, we will try to send an email instead. Append space(s) to remember, whatever you enter, for next time.', snum)).replace(/^null/g, (defemail.indexOf('@') != -1 ? defemail : (defsms != '' ? defsms : '')) );
} else {
snum=('' + prompt('Please enter SMS number to send to. Append space(s) to remember for next time.', snum)).replace(/^null/g, (defsms != '' ? defsms : (defemail.indexOf('@') != -1 ? defemail : '')));
}
if (snum == null) { snum=''; }
if (snum.indexOf('@') != -1) {
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', snum);
defemail=snum;
}
return doemail(snum);
} else if (snum.trim() != '' && snum.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
//alert('Snum=' + snum + '?');
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', snum);
defsms=snum;
}
var azx=top.document.getElementById('xas' + 'ms');
if (azx == null) { azx=top.document.createElement("a"); }
//if (1 == 1) {
// document.getElementById('divas').appendChild(azx);
//} else {
top.document.body.appendChild(azx);
// }
azx.id = 'xas' + 'ms';
azx.target = "_top";
azx.style = "display: none";
azx.href = 'sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()));
azx.click();
}
return '';
}
Also, today, we battled the logic to allow the textarea element onblur events also open the door to emailing and SMS “work in progress”. Believe it or not, this timing change was quite difficult in the changedevents_in_month.htm parent of the Events in Month web application. Never a dull moment in web application I.T. we’d say!
it did not have a fully fleshed out collaboration or sharing set of functionalities … at the time, probably, because …
each Monthly calendar filled out, and wanting to be saved, could involve much more than the 850 characters available to previous “mailto:” or “sms:” communication conduits, back to when we first tackled this project … but now …
hashtagging parts to the “mailto:” URLs (and maybe sometimes the “sms:” URL) might cover the data length needs
… so that this Event Calendar could be a web application at the center of a collaboration network of people working on that event organization. Much more useful, we figure!
Timing became really important with this integration of …
email
SMS
… communication conduit possibilities. With its design we have to wait until the point where the user is filling in textarea elements regarding a designated …
Month
Year
… of relevance, before we allow the email 📧 and SMS 📟 emoji buttons be shown. In the code …
Amended HTML h1 element static HTML to add, later shown, perhaps, email 📧 and SMS 📟 emoji buttons …
<h1>Events in Month <button style=display:none; title='Share via Email' id=semail onclick="doemail('');">📧</button> <button style=display:none; title='Share via SMS' id=ssms onclick=dosms();>📟</button> </h1>
New static HTML div element placed to the bottom of the body element …
<div id=divas></div>
New Javascript global variables (picking up hashtagging parts of the address bar URL, perhaps linked off an email or SMS link clicked) …
Client meets server today, allowing the PHP data storage talents in yesterday’s Event Calendar PHP Tutorial‘s work to meet a “clientside” way to …
Record to Remember via Bookmark
… use the web browser Bookmarks to help you recall an Events in Month report with long entries.
Involving a Bookmark still needs those “get” ? and & arguments, and we allow the PHP to lookup for us the data underscoring an address bar URL such as …
… that mapping being possible, now, making use of a pseudo hashtag arrangement … your Clayton‘s hashtag, if you will!
To start to use a hashtag suits, as your hashtag navigation only makes sense in the “clientside” woooorrrrrllllddd, and even there, really using one only tries to position a webpage where an element with an ID matching the hashtag sits (and we are never going to have this ID element in our work), and in the meantime we’ve passed across from the child PHP to the parent HTML a valuable piece of information helping the link to the Bookmark system be possible. The Javascript codeline (you may have noticed) …
var documentURL=document.URL;
… as stupid and simple looking as it is, is crucial for us. We get child webpage parts (like our PHP) to change document.URL to a far too long in normal circumstances address bar URL the rest of the code feeds off. It’s just that now, that far too long in normal circumstances address bar URL has a #[hashtag] appended such as …
#August__2023_00000__1
… uniquifying a Month, Year Events in Month identifier part with a version of the user’s IP address (so that they only see what is relevant to them).
Address bar URLs such as “https://www.rjmprogramming.com.au/HTMLCSS/events_in_month.php?exactlabel=August__2023_00000__1” are Bookmarkable, and so we allow for similar outcomes with less concern about how much data is being “recorded” and recallable (via that web browser’s Bookmark system).
Also, today, a lot of CSS tweaks, so that the CSS styling now looks like …
… form submit button (toggling) value to start involving PHP with those longer datasets of Event in Month descriptions, in our most recent project. What do we use as the data conduit? No, not a database. No, not a serverside flat file. No, not clientside window.localStorage nor window.sessionStorage nor HTTP Cookies. We store long Event in Month description data in our new events_in_month.php PHP itself. And this same PHP can populate options in a new dropdown element in the parent to facilitate the recalling of any relevant “Record to Remember” recordings.
The PHP is kind of short, so we will show it below, including one MAMP example of that “self storage” …
<?php
// events_in_month.php
// RJM Programming
// August, 2023
// Help out events_in_month.htm
But, there’s an inherent weakness with the design, we’ll go into more into the future.
… well … it’s a perennial for us, regarding how if you stick with clientside thinking, only, web applications, when the amount of data to remember starts adding up, the “get arguments approach” ( ie. use ? and & arguments at the address bar ) is restricted by length restrictions regarding URL lengths.
Rather than jump to PHP serverside ideas just yet, we wanted to show some more ideas, staying with “clientside only thinking”, today, as well as improving the UX (user experience) and small steps forward regarding styling.
Okay then, regarding the idea to remember an Event in Month form, when there is a lot of data, and staying “just clientside”, we’ve coded for a “New Window” idea, albeit not as memorable as the default “Remember in Bookmark” possible for your smaller datasets. However, in saying that, we found that within this new window, with our Google Chrome web browser, we could …
bring up Context Menu with a right click or two finger gesture within the popup window webpage content …
pick Inspect option …
be in Elements tab of your Web Inspector … and …
highlight top <html> tag …
Context Menu with a right click or two finger gesture …
pick Copy -> Copy outerHTML … so that …
your Event Calendar for your Events in Month choice is in a text buffer … ready for you to …
Paste into a Text Editor that Events in Month webpage to store (perhaps in a MAMP local Apache/PHP/mySql web server environment, where you can further look at and develop your own ideas)
The user is told when the switch to “New Window” compromise becomes active, decided upon by reconstructing the proposed address bar URL regularly and when too long …
function formanalyze() {
var fio=document.getElementsByTagName('form')[0];
var delm='?';
var fioih=fio.innerHTML;
var fions=fioih.split(' name="');
var testurl=documentURL.split('?')[0].split('#')[0];
for (var ijk=1; ijk<fions.length; ijk++) {
testurl+=delm + fions[ijk].split('"')[0] + '=' + encodeURIComponent(document.getElementById(fions[ijk].split('"')[0]).value);
delm='&';
}
setTimeout(formanalyze, 3000);
if (eval('' + testurl.length) >= 750) {
if (document.getElementById('remember')) { document.getElementById('remember').value='New window'; }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value='New window'; }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value='New window'; }
} else {
if (document.getElementById('remember')) { document.getElementById('remember').value=document.getElementById('remember').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value=document.getElementById('rememberme').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value=document.getElementById('remembermoi').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
}
return eval('' + testurl.length);
}
… the form submit buttons are reworded accordingly.
Another idea from this blog thread’s inspiration …
… we’ve now addressed in today’s “second draft” is allowing for an optional bold Event Day Blurb Title, available to the user via a new dropdown “Bold Title” option.
And, how can we do more with colour, to help the right bits stand out, and be consistent? We thought …
text shadow means by which the text of Event Calendar can be more impactive …
<div style="text-shadow:-1px 1px 1px #ff2d95;" id=eventcalendar></div>
… is our go to regarding the internationalization and language translation functionality. We get to Google Translate, where permitted (up to you, and whether you have popup blockers happening with the web browser you are using), via a popup window, which means, in that scenario, there are two distinct domains in play …
Be listening out at the RJM Programming domain document.URL scenario “parent” window …
window.addEventListener("message", (event) => { // thanks to https://www.google.com/search?q=Undef+what+conditions+can+window.opener.parentfunc()+type+of+call+work+when+the+domains+are+different%3F&rlz=1C5OZZY_en&oq=Undef+what+conditions+can+window.opener.parentfunc()+type+of+call+work+when+the+domains+are+different%3F&gs_lcrp=EgZjaHJvbWUyBggAEEUYOdIBCTI2NzQwajBqN6gCALACAA&sourceid=chrome&source=chrome.ob&ie=UTF-8
var thislang='';
// Always verify the origin of the sender for security
if (event.origin !== "https://www-rjmprogramming-com-au.translate.goog") return;
Today is Styling Day regarding our current Editable Calendar project we last talked about with yesterday’s Editable Calendar Save and Recall Tutorial. We cannot recall ever arranging the body element background exactly as we did (probably because we only had the top and the bottom of the screen for context, the middle being the calendar) in the CSS below …
body {
background-image: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),url(https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSAMB0R0_H50ZU4AW0t51IqB0WwOyF1BEmSPy3MMxisNythxHs69b4lcx8&s=10);
background-size: contain;
background-repeat: repeat;
}
</style>
… where some judiciously placed background-color:transparent helps this out with transparency ideas. We find applying border-radius a good way to “soften” the look, and “text-shadow” as a way to allow for a 3D look to innerHTML contenteditable=true types of elements.
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);
}
… 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='';
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 …
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 ''; }
Because the theme of our current Editable Calendar web application revolves around time stamps and day names and month names regarding yesterday’s Editable Calendar Google Translate Tutorial that means, regarding language internationalization ideas …
as well as yesterday’s Google Translate ideas … also available is …
Yesterday’s Editable Calendar Primer Tutorial‘s start to our Editable Calendar project was a very anglo-centric exercise. Today, we want to use the great …
… to help translate our inhouse burgeoning Editable Calendar skeletal contents to some non English languages.
Why the skeletal here? Well, your own entries made before you select a dropdown non English language choice are stripped out in this changedsecond draftEditable Calendar you can try below, because we’re using the Google Translate “static URL” approach to the translations. But we will examine, down the track, if we can do better?! Again, stay tuned for more progression and internationalization over the days on this Editable Calendar project.
we’re channelling how in emails “word strings” starting with “http” become links … and so …
in our event in month “blurb” textarea elements we allow user highlighted text containing such “http” “word strings” be opened in popup windows showing the content of those URLs, as available
Here is the relevant Javascript we ended up with, for this …
Just briefly, delved into the wooooorrrrllllldddd of days of the week before 1582 debate … you had to be there … and in the words of Lleyton … Come on!!!! And we came out the other side. Good times! Anyway, thanks for all the interesting discussion, which we recommend you start at with this gem. Anyway, we now allow dates after 1582 (after this was previously set at 1970) in all respects and dates between 0000 and 1581 only via tweaks to the address bar URL you do yourself and we just hide the day of the week string. Otherwise … this could be needed?!
When doing our inhouse testing for Event Calendar Collaboration Tutorial the other day, it got us “peeved”, shall we say. We wanted a mechanism, with those “a” link “mailto:” emailing arrangements, of not having to fill out the email address in the “To:” field each time. First world problem alert! Still and all …
When it comes to procedures …
Aaaaaarrrrgggghhhh …
Nuances count … regarding …
Errrrrrr …
Saving time …
Saving frustration
… resulting in the “easy to remember” acronym WANESS … we rest our cases!
What can help here? Well, it is a personalization … so … anyone, anyone? Yes, Lou, back from holidays, a month late … yes, well, okay … we can see you’ve put some thought into this … HTTP Cookies could be used. Yes, Shwetank, you’ve had your hand up some time now. We agree, Web Storage window.localStorage allows for more data, so we’ll go with that, though either style of approach would work here.
Global variables initialization …
var defemail='', defsms='';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
Within document.body onload event logic …
if (document.getElementById('semail') && document.getElementById('ssms')) {
document.getElementById('semail').oncontextmenu=function(){ emailaskit(); };
document.getElementById('semail').ontouchmove=function(){ emailaskit(); };
document.getElementById('ssms').oncontextmenu=function(){ smsaskit(); };
document.getElementById('ssms').ontouchmove=function(){ smsaskit(); };
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('semail').title+=' Move gesture here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Move gesture here can ask for new default remembered SMS number for collaboration purposes';
} else {
document.getElementById('semail').title+=' Right click here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Right click here can ask for new default remembered SMS number for collaboration purposes';
}
}
Calling these two Javascript function helpers …
function emailaskit() {
if (defemail == defemail.trim()) {
defemail=defemail.trim() + ' ';
var emailm=prompt('Enter default email address.', defemail.trim());
if (emailm == null) { emailm=''; }
if (emailm.trim() != '' && emailm.trim().indexOf('@') != -1) {
defemail=emailm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', emailm.trim());
}
}
defemail=defemail.trim() + ' ';
}
function smsaskit() {
if (defsms == defsms.trim()) {
defsms=defsms.trim() + ' ';
var smsm=prompt('Enter default SMS number.', defsms.trim());
if (smsm == null) { smsm=''; }
if (smsm.trim() != '' && smsm.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
defsms=smsm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', smsm.trim());
}
}
defsms=defsms.trim() + ' ';
}
And allow control, as well, at the SMS prompt window logic …
function dosms() {
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
//alert('' + eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length));
if (eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length) >= 18000) {
snum=('' + prompt('Please enter SMS number to send to. We suspect message is too long for an SMS and if you enter an email address here instead, we will try to send an email instead. Append space(s) to remember, whatever you enter, for next time.', snum)).replace(/^null/g, (defemail.indexOf('@') != -1 ? defemail : (defsms != '' ? defsms : '')) );
} else {
snum=('' + prompt('Please enter SMS number to send to. Append space(s) to remember for next time.', snum)).replace(/^null/g, (defsms != '' ? defsms : (defemail.indexOf('@') != -1 ? defemail : '')));
}
if (snum == null) { snum=''; }
if (snum.indexOf('@') != -1) {
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', snum);
defemail=snum;
}
return doemail(snum);
} else if (snum.trim() != '' && snum.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
//alert('Snum=' + snum + '?');
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', snum);
defsms=snum;
}
var azx=top.document.getElementById('xas' + 'ms');
if (azx == null) { azx=top.document.createElement("a"); }
//if (1 == 1) {
// document.getElementById('divas').appendChild(azx);
//} else {
top.document.body.appendChild(azx);
// }
azx.id = 'xas' + 'ms';
azx.target = "_top";
azx.style = "display: none";
azx.href = 'sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()));
azx.click();
}
return '';
}
Also, today, we battled the logic to allow the textarea element onblur events also open the door to emailing and SMS “work in progress”. Believe it or not, this timing change was quite difficult in the changedevents_in_month.htm parent of the Events in Month web application. Never a dull moment in web application I.T. we’d say!
it did not have a fully fleshed out collaboration or sharing set of functionalities … at the time, probably, because …
each Monthly calendar filled out, and wanting to be saved, could involve much more than the 850 characters available to previous “mailto:” or “sms:” communication conduits, back to when we first tackled this project … but now …
hashtagging parts to the “mailto:” URLs (and maybe sometimes the “sms:” URL) might cover the data length needs
… so that this Event Calendar could be a web application at the center of a collaboration network of people working on that event organization. Much more useful, we figure!
Timing became really important with this integration of …
email
SMS
… communication conduit possibilities. With its design we have to wait until the point where the user is filling in textarea elements regarding a designated …
Month
Year
… of relevance, before we allow the email 📧 and SMS 📟 emoji buttons be shown. In the code …
Amended HTML h1 element static HTML to add, later shown, perhaps, email 📧 and SMS 📟 emoji buttons …
<h1>Events in Month <button style=display:none; title='Share via Email' id=semail onclick="doemail('');">📧</button> <button style=display:none; title='Share via SMS' id=ssms onclick=dosms();>📟</button> </h1>
New static HTML div element placed to the bottom of the body element …
<div id=divas></div>
New Javascript global variables (picking up hashtagging parts of the address bar URL, perhaps linked off an email or SMS link clicked) …
Client meets server today, allowing the PHP data storage talents in yesterday’s Event Calendar PHP Tutorial‘s work to meet a “clientside” way to …
Record to Remember via Bookmark
… use the web browser Bookmarks to help you recall an Events in Month report with long entries.
Involving a Bookmark still needs those “get” ? and & arguments, and we allow the PHP to lookup for us the data underscoring an address bar URL such as …
… that mapping being possible, now, making use of a pseudo hashtag arrangement … your Clayton‘s hashtag, if you will!
To start to use a hashtag suits, as your hashtag navigation only makes sense in the “clientside” woooorrrrrllllddd, and even there, really using one only tries to position a webpage where an element with an ID matching the hashtag sits (and we are never going to have this ID element in our work), and in the meantime we’ve passed across from the child PHP to the parent HTML a valuable piece of information helping the link to the Bookmark system be possible. The Javascript codeline (you may have noticed) …
var documentURL=document.URL;
… as stupid and simple looking as it is, is crucial for us. We get child webpage parts (like our PHP) to change document.URL to a far too long in normal circumstances address bar URL the rest of the code feeds off. It’s just that now, that far too long in normal circumstances address bar URL has a #[hashtag] appended such as …
#August__2023_00000__1
… uniquifying a Month, Year Events in Month identifier part with a version of the user’s IP address (so that they only see what is relevant to them).
Address bar URLs such as “https://www.rjmprogramming.com.au/HTMLCSS/events_in_month.php?exactlabel=August__2023_00000__1” are Bookmarkable, and so we allow for similar outcomes with less concern about how much data is being “recorded” and recallable (via that web browser’s Bookmark system).
Also, today, a lot of CSS tweaks, so that the CSS styling now looks like …
… form submit button (toggling) value to start involving PHP with those longer datasets of Event in Month descriptions, in our most recent project. What do we use as the data conduit? No, not a database. No, not a serverside flat file. No, not clientside window.localStorage nor window.sessionStorage nor HTTP Cookies. We store long Event in Month description data in our new events_in_month.php PHP itself. And this same PHP can populate options in a new dropdown element in the parent to facilitate the recalling of any relevant “Record to Remember” recordings.
The PHP is kind of short, so we will show it below, including one MAMP example of that “self storage” …
<?php
// events_in_month.php
// RJM Programming
// August, 2023
// Help out events_in_month.htm
But, there’s an inherent weakness with the design, we’ll go into more into the future.
… well … it’s a perennial for us, regarding how if you stick with clientside thinking, only, web applications, when the amount of data to remember starts adding up, the “get arguments approach” ( ie. use ? and & arguments at the address bar ) is restricted by length restrictions regarding URL lengths.
Rather than jump to PHP serverside ideas just yet, we wanted to show some more ideas, staying with “clientside only thinking”, today, as well as improving the UX (user experience) and small steps forward regarding styling.
Okay then, regarding the idea to remember an Event in Month form, when there is a lot of data, and staying “just clientside”, we’ve coded for a “New Window” idea, albeit not as memorable as the default “Remember in Bookmark” possible for your smaller datasets. However, in saying that, we found that within this new window, with our Google Chrome web browser, we could …
bring up Context Menu with a right click or two finger gesture within the popup window webpage content …
pick Inspect option …
be in Elements tab of your Web Inspector … and …
highlight top <html> tag …
Context Menu with a right click or two finger gesture …
pick Copy -> Copy outerHTML … so that …
your Event Calendar for your Events in Month choice is in a text buffer … ready for you to …
Paste into a Text Editor that Events in Month webpage to store (perhaps in a MAMP local Apache/PHP/mySql web server environment, where you can further look at and develop your own ideas)
The user is told when the switch to “New Window” compromise becomes active, decided upon by reconstructing the proposed address bar URL regularly and when too long …
function formanalyze() {
var fio=document.getElementsByTagName('form')[0];
var delm='?';
var fioih=fio.innerHTML;
var fions=fioih.split(' name="');
var testurl=documentURL.split('?')[0].split('#')[0];
for (var ijk=1; ijk<fions.length; ijk++) {
testurl+=delm + fions[ijk].split('"')[0] + '=' + encodeURIComponent(document.getElementById(fions[ijk].split('"')[0]).value);
delm='&';
}
setTimeout(formanalyze, 3000);
if (eval('' + testurl.length) >= 750) {
if (document.getElementById('remember')) { document.getElementById('remember').value='New window'; }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value='New window'; }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value='New window'; }
} else {
if (document.getElementById('remember')) { document.getElementById('remember').value=document.getElementById('remember').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value=document.getElementById('rememberme').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value=document.getElementById('remembermoi').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
}
return eval('' + testurl.length);
}
… the form submit buttons are reworded accordingly.
Another idea from this blog thread’s inspiration …
… we’ve now addressed in today’s “second draft” is allowing for an optional bold Event Day Blurb Title, available to the user via a new dropdown “Bold Title” option.
And, how can we do more with colour, to help the right bits stand out, and be consistent? We thought …
text shadow means by which the text of Event Calendar can be more impactive …
<div style="text-shadow:-1px 1px 1px #ff2d95;" id=eventcalendar></div>
Today is Styling Day regarding our current Editable Calendar project we last talked about with yesterday’s Editable Calendar Save and Recall Tutorial. We cannot recall ever arranging the body element background exactly as we did (probably because we only had the top and the bottom of the screen for context, the middle being the calendar) in the CSS below …
body {
background-image: linear-gradient(rgba(255,255,255,0.8),rgba(255,255,255,0.8)),url(https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSAMB0R0_H50ZU4AW0t51IqB0WwOyF1BEmSPy3MMxisNythxHs69b4lcx8&s=10);
background-size: contain;
background-repeat: repeat;
}
</style>
… where some judiciously placed background-color:transparent helps this out with transparency ideas. We find applying border-radius a good way to “soften” the look, and “text-shadow” as a way to allow for a 3D look to innerHTML contenteditable=true types of elements.
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);
}
… 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='';
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 …
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 ''; }
Because the theme of our current Editable Calendar web application revolves around time stamps and day names and month names regarding yesterday’s Editable Calendar Google Translate Tutorial that means, regarding language internationalization ideas …
as well as yesterday’s Google Translate ideas … also available is …
Yesterday’s Editable Calendar Primer Tutorial‘s start to our Editable Calendar project was a very anglo-centric exercise. Today, we want to use the great …
… to help translate our inhouse burgeoning Editable Calendar skeletal contents to some non English languages.
Why the skeletal here? Well, your own entries made before you select a dropdown non English language choice are stripped out in this changedsecond draftEditable Calendar you can try below, because we’re using the Google Translate “static URL” approach to the translations. But we will examine, down the track, if we can do better?! Again, stay tuned for more progression and internationalization over the days on this Editable Calendar project.
we’re channelling how in emails “word strings” starting with “http” become links … and so …
in our event in month “blurb” textarea elements we allow user highlighted text containing such “http” “word strings” be opened in popup windows showing the content of those URLs, as available
Here is the relevant Javascript we ended up with, for this …
Just briefly, delved into the wooooorrrrllllldddd of days of the week before 1582 debate … you had to be there … and in the words of Lleyton … Come on!!!! And we came out the other side. Good times! Anyway, thanks for all the interesting discussion, which we recommend you start at with this gem. Anyway, we now allow dates after 1582 (after this was previously set at 1970) in all respects and dates between 0000 and 1581 only via tweaks to the address bar URL you do yourself and we just hide the day of the week string. Otherwise … this could be needed?!
When doing our inhouse testing for Event Calendar Collaboration Tutorial the other day, it got us “peeved”, shall we say. We wanted a mechanism, with those “a” link “mailto:” emailing arrangements, of not having to fill out the email address in the “To:” field each time. First world problem alert! Still and all …
When it comes to procedures …
Aaaaaarrrrgggghhhh …
Nuances count … regarding …
Errrrrrr …
Saving time …
Saving frustration
… resulting in the “easy to remember” acronym WANESS … we rest our cases!
What can help here? Well, it is a personalization … so … anyone, anyone? Yes, Lou, back from holidays, a month late … yes, well, okay … we can see you’ve put some thought into this … HTTP Cookies could be used. Yes, Shwetank, you’ve had your hand up some time now. We agree, Web Storage window.localStorage allows for more data, so we’ll go with that, though either style of approach would work here.
Global variables initialization …
var defemail='', defsms='';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
Within document.body onload event logic …
if (document.getElementById('semail') && document.getElementById('ssms')) {
document.getElementById('semail').oncontextmenu=function(){ emailaskit(); };
document.getElementById('semail').ontouchmove=function(){ emailaskit(); };
document.getElementById('ssms').oncontextmenu=function(){ smsaskit(); };
document.getElementById('ssms').ontouchmove=function(){ smsaskit(); };
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('semail').title+=' Move gesture here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Move gesture here can ask for new default remembered SMS number for collaboration purposes';
} else {
document.getElementById('semail').title+=' Right click here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Right click here can ask for new default remembered SMS number for collaboration purposes';
}
}
Calling these two Javascript function helpers …
function emailaskit() {
if (defemail == defemail.trim()) {
defemail=defemail.trim() + ' ';
var emailm=prompt('Enter default email address.', defemail.trim());
if (emailm == null) { emailm=''; }
if (emailm.trim() != '' && emailm.trim().indexOf('@') != -1) {
defemail=emailm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', emailm.trim());
}
}
defemail=defemail.trim() + ' ';
}
function smsaskit() {
if (defsms == defsms.trim()) {
defsms=defsms.trim() + ' ';
var smsm=prompt('Enter default SMS number.', defsms.trim());
if (smsm == null) { smsm=''; }
if (smsm.trim() != '' && smsm.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
defsms=smsm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', smsm.trim());
}
}
defsms=defsms.trim() + ' ';
}
And allow control, as well, at the SMS prompt window logic …
function dosms() {
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
//alert('' + eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length));
if (eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length) >= 18000) {
snum=('' + prompt('Please enter SMS number to send to. We suspect message is too long for an SMS and if you enter an email address here instead, we will try to send an email instead. Append space(s) to remember, whatever you enter, for next time.', snum)).replace(/^null/g, (defemail.indexOf('@') != -1 ? defemail : (defsms != '' ? defsms : '')) );
} else {
snum=('' + prompt('Please enter SMS number to send to. Append space(s) to remember for next time.', snum)).replace(/^null/g, (defsms != '' ? defsms : (defemail.indexOf('@') != -1 ? defemail : '')));
}
if (snum == null) { snum=''; }
if (snum.indexOf('@') != -1) {
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', snum);
defemail=snum;
}
return doemail(snum);
} else if (snum.trim() != '' && snum.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
//alert('Snum=' + snum + '?');
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', snum);
defsms=snum;
}
var azx=top.document.getElementById('xas' + 'ms');
if (azx == null) { azx=top.document.createElement("a"); }
//if (1 == 1) {
// document.getElementById('divas').appendChild(azx);
//} else {
top.document.body.appendChild(azx);
// }
azx.id = 'xas' + 'ms';
azx.target = "_top";
azx.style = "display: none";
azx.href = 'sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()));
azx.click();
}
return '';
}
Also, today, we battled the logic to allow the textarea element onblur events also open the door to emailing and SMS “work in progress”. Believe it or not, this timing change was quite difficult in the changedevents_in_month.htm parent of the Events in Month web application. Never a dull moment in web application I.T. we’d say!
it did not have a fully fleshed out collaboration or sharing set of functionalities … at the time, probably, because …
each Monthly calendar filled out, and wanting to be saved, could involve much more than the 850 characters available to previous “mailto:” or “sms:” communication conduits, back to when we first tackled this project … but now …
hashtagging parts to the “mailto:” URLs (and maybe sometimes the “sms:” URL) might cover the data length needs
… so that this Event Calendar could be a web application at the center of a collaboration network of people working on that event organization. Much more useful, we figure!
Timing became really important with this integration of …
email
SMS
… communication conduit possibilities. With its design we have to wait until the point where the user is filling in textarea elements regarding a designated …
Month
Year
… of relevance, before we allow the email 📧 and SMS 📟 emoji buttons be shown. In the code …
Amended HTML h1 element static HTML to add, later shown, perhaps, email 📧 and SMS 📟 emoji buttons …
<h1>Events in Month <button style=display:none; title='Share via Email' id=semail onclick="doemail('');">📧</button> <button style=display:none; title='Share via SMS' id=ssms onclick=dosms();>📟</button> </h1>
New static HTML div element placed to the bottom of the body element …
<div id=divas></div>
New Javascript global variables (picking up hashtagging parts of the address bar URL, perhaps linked off an email or SMS link clicked) …
Client meets server today, allowing the PHP data storage talents in yesterday’s Event Calendar PHP Tutorial‘s work to meet a “clientside” way to …
Record to Remember via Bookmark
… use the web browser Bookmarks to help you recall an Events in Month report with long entries.
Involving a Bookmark still needs those “get” ? and & arguments, and we allow the PHP to lookup for us the data underscoring an address bar URL such as …
… that mapping being possible, now, making use of a pseudo hashtag arrangement … your Clayton‘s hashtag, if you will!
To start to use a hashtag suits, as your hashtag navigation only makes sense in the “clientside” woooorrrrrllllddd, and even there, really using one only tries to position a webpage where an element with an ID matching the hashtag sits (and we are never going to have this ID element in our work), and in the meantime we’ve passed across from the child PHP to the parent HTML a valuable piece of information helping the link to the Bookmark system be possible. The Javascript codeline (you may have noticed) …
var documentURL=document.URL;
… as stupid and simple looking as it is, is crucial for us. We get child webpage parts (like our PHP) to change document.URL to a far too long in normal circumstances address bar URL the rest of the code feeds off. It’s just that now, that far too long in normal circumstances address bar URL has a #[hashtag] appended such as …
#August__2023_00000__1
… uniquifying a Month, Year Events in Month identifier part with a version of the user’s IP address (so that they only see what is relevant to them).
Address bar URLs such as “https://www.rjmprogramming.com.au/HTMLCSS/events_in_month.php?exactlabel=August__2023_00000__1” are Bookmarkable, and so we allow for similar outcomes with less concern about how much data is being “recorded” and recallable (via that web browser’s Bookmark system).
Also, today, a lot of CSS tweaks, so that the CSS styling now looks like …
… form submit button (toggling) value to start involving PHP with those longer datasets of Event in Month descriptions, in our most recent project. What do we use as the data conduit? No, not a database. No, not a serverside flat file. No, not clientside window.localStorage nor window.sessionStorage nor HTTP Cookies. We store long Event in Month description data in our new events_in_month.php PHP itself. And this same PHP can populate options in a new dropdown element in the parent to facilitate the recalling of any relevant “Record to Remember” recordings.
The PHP is kind of short, so we will show it below, including one MAMP example of that “self storage” …
<?php
// events_in_month.php
// RJM Programming
// August, 2023
// Help out events_in_month.htm
But, there’s an inherent weakness with the design, we’ll go into more into the future.
… well … it’s a perennial for us, regarding how if you stick with clientside thinking, only, web applications, when the amount of data to remember starts adding up, the “get arguments approach” ( ie. use ? and & arguments at the address bar ) is restricted by length restrictions regarding URL lengths.
Rather than jump to PHP serverside ideas just yet, we wanted to show some more ideas, staying with “clientside only thinking”, today, as well as improving the UX (user experience) and small steps forward regarding styling.
Okay then, regarding the idea to remember an Event in Month form, when there is a lot of data, and staying “just clientside”, we’ve coded for a “New Window” idea, albeit not as memorable as the default “Remember in Bookmark” possible for your smaller datasets. However, in saying that, we found that within this new window, with our Google Chrome web browser, we could …
bring up Context Menu with a right click or two finger gesture within the popup window webpage content …
pick Inspect option …
be in Elements tab of your Web Inspector … and …
highlight top <html> tag …
Context Menu with a right click or two finger gesture …
pick Copy -> Copy outerHTML … so that …
your Event Calendar for your Events in Month choice is in a text buffer … ready for you to …
Paste into a Text Editor that Events in Month webpage to store (perhaps in a MAMP local Apache/PHP/mySql web server environment, where you can further look at and develop your own ideas)
The user is told when the switch to “New Window” compromise becomes active, decided upon by reconstructing the proposed address bar URL regularly and when too long …
function formanalyze() {
var fio=document.getElementsByTagName('form')[0];
var delm='?';
var fioih=fio.innerHTML;
var fions=fioih.split(' name="');
var testurl=documentURL.split('?')[0].split('#')[0];
for (var ijk=1; ijk<fions.length; ijk++) {
testurl+=delm + fions[ijk].split('"')[0] + '=' + encodeURIComponent(document.getElementById(fions[ijk].split('"')[0]).value);
delm='&';
}
setTimeout(formanalyze, 3000);
if (eval('' + testurl.length) >= 750) {
if (document.getElementById('remember')) { document.getElementById('remember').value='New window'; }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value='New window'; }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value='New window'; }
} else {
if (document.getElementById('remember')) { document.getElementById('remember').value=document.getElementById('remember').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value=document.getElementById('rememberme').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value=document.getElementById('remembermoi').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
}
return eval('' + testurl.length);
}
… the form submit buttons are reworded accordingly.
Another idea from this blog thread’s inspiration …
… we’ve now addressed in today’s “second draft” is allowing for an optional bold Event Day Blurb Title, available to the user via a new dropdown “Bold Title” option.
And, how can we do more with colour, to help the right bits stand out, and be consistent? We thought …
text shadow means by which the text of Event Calendar can be more impactive …
<div style="text-shadow:-1px 1px 1px #ff2d95;" id=eventcalendar></div>
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);
}
… 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='';
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 …
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 ''; }
Because the theme of our current Editable Calendar web application revolves around time stamps and day names and month names regarding yesterday’s Editable Calendar Google Translate Tutorial that means, regarding language internationalization ideas …
as well as yesterday’s Google Translate ideas … also available is …
Yesterday’s Editable Calendar Primer Tutorial‘s start to our Editable Calendar project was a very anglo-centric exercise. Today, we want to use the great …
… to help translate our inhouse burgeoning Editable Calendar skeletal contents to some non English languages.
Why the skeletal here? Well, your own entries made before you select a dropdown non English language choice are stripped out in this changedsecond draftEditable Calendar you can try below, because we’re using the Google Translate “static URL” approach to the translations. But we will examine, down the track, if we can do better?! Again, stay tuned for more progression and internationalization over the days on this Editable Calendar project.
we’re channelling how in emails “word strings” starting with “http” become links … and so …
in our event in month “blurb” textarea elements we allow user highlighted text containing such “http” “word strings” be opened in popup windows showing the content of those URLs, as available
Here is the relevant Javascript we ended up with, for this …
Just briefly, delved into the wooooorrrrllllldddd of days of the week before 1582 debate … you had to be there … and in the words of Lleyton … Come on!!!! And we came out the other side. Good times! Anyway, thanks for all the interesting discussion, which we recommend you start at with this gem. Anyway, we now allow dates after 1582 (after this was previously set at 1970) in all respects and dates between 0000 and 1581 only via tweaks to the address bar URL you do yourself and we just hide the day of the week string. Otherwise … this could be needed?!
When doing our inhouse testing for Event Calendar Collaboration Tutorial the other day, it got us “peeved”, shall we say. We wanted a mechanism, with those “a” link “mailto:” emailing arrangements, of not having to fill out the email address in the “To:” field each time. First world problem alert! Still and all …
When it comes to procedures …
Aaaaaarrrrgggghhhh …
Nuances count … regarding …
Errrrrrr …
Saving time …
Saving frustration
… resulting in the “easy to remember” acronym WANESS … we rest our cases!
What can help here? Well, it is a personalization … so … anyone, anyone? Yes, Lou, back from holidays, a month late … yes, well, okay … we can see you’ve put some thought into this … HTTP Cookies could be used. Yes, Shwetank, you’ve had your hand up some time now. We agree, Web Storage window.localStorage allows for more data, so we’ll go with that, though either style of approach would work here.
Global variables initialization …
var defemail='', defsms='';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
Within document.body onload event logic …
if (document.getElementById('semail') && document.getElementById('ssms')) {
document.getElementById('semail').oncontextmenu=function(){ emailaskit(); };
document.getElementById('semail').ontouchmove=function(){ emailaskit(); };
document.getElementById('ssms').oncontextmenu=function(){ smsaskit(); };
document.getElementById('ssms').ontouchmove=function(){ smsaskit(); };
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('semail').title+=' Move gesture here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Move gesture here can ask for new default remembered SMS number for collaboration purposes';
} else {
document.getElementById('semail').title+=' Right click here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Right click here can ask for new default remembered SMS number for collaboration purposes';
}
}
Calling these two Javascript function helpers …
function emailaskit() {
if (defemail == defemail.trim()) {
defemail=defemail.trim() + ' ';
var emailm=prompt('Enter default email address.', defemail.trim());
if (emailm == null) { emailm=''; }
if (emailm.trim() != '' && emailm.trim().indexOf('@') != -1) {
defemail=emailm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', emailm.trim());
}
}
defemail=defemail.trim() + ' ';
}
function smsaskit() {
if (defsms == defsms.trim()) {
defsms=defsms.trim() + ' ';
var smsm=prompt('Enter default SMS number.', defsms.trim());
if (smsm == null) { smsm=''; }
if (smsm.trim() != '' && smsm.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
defsms=smsm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', smsm.trim());
}
}
defsms=defsms.trim() + ' ';
}
And allow control, as well, at the SMS prompt window logic …
function dosms() {
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
//alert('' + eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length));
if (eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length) >= 18000) {
snum=('' + prompt('Please enter SMS number to send to. We suspect message is too long for an SMS and if you enter an email address here instead, we will try to send an email instead. Append space(s) to remember, whatever you enter, for next time.', snum)).replace(/^null/g, (defemail.indexOf('@') != -1 ? defemail : (defsms != '' ? defsms : '')) );
} else {
snum=('' + prompt('Please enter SMS number to send to. Append space(s) to remember for next time.', snum)).replace(/^null/g, (defsms != '' ? defsms : (defemail.indexOf('@') != -1 ? defemail : '')));
}
if (snum == null) { snum=''; }
if (snum.indexOf('@') != -1) {
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', snum);
defemail=snum;
}
return doemail(snum);
} else if (snum.trim() != '' && snum.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
//alert('Snum=' + snum + '?');
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', snum);
defsms=snum;
}
var azx=top.document.getElementById('xas' + 'ms');
if (azx == null) { azx=top.document.createElement("a"); }
//if (1 == 1) {
// document.getElementById('divas').appendChild(azx);
//} else {
top.document.body.appendChild(azx);
// }
azx.id = 'xas' + 'ms';
azx.target = "_top";
azx.style = "display: none";
azx.href = 'sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()));
azx.click();
}
return '';
}
Also, today, we battled the logic to allow the textarea element onblur events also open the door to emailing and SMS “work in progress”. Believe it or not, this timing change was quite difficult in the changedevents_in_month.htm parent of the Events in Month web application. Never a dull moment in web application I.T. we’d say!
it did not have a fully fleshed out collaboration or sharing set of functionalities … at the time, probably, because …
each Monthly calendar filled out, and wanting to be saved, could involve much more than the 850 characters available to previous “mailto:” or “sms:” communication conduits, back to when we first tackled this project … but now …
hashtagging parts to the “mailto:” URLs (and maybe sometimes the “sms:” URL) might cover the data length needs
… so that this Event Calendar could be a web application at the center of a collaboration network of people working on that event organization. Much more useful, we figure!
Timing became really important with this integration of …
email
SMS
… communication conduit possibilities. With its design we have to wait until the point where the user is filling in textarea elements regarding a designated …
Month
Year
… of relevance, before we allow the email 📧 and SMS 📟 emoji buttons be shown. In the code …
Amended HTML h1 element static HTML to add, later shown, perhaps, email 📧 and SMS 📟 emoji buttons …
<h1>Events in Month <button style=display:none; title='Share via Email' id=semail onclick="doemail('');">📧</button> <button style=display:none; title='Share via SMS' id=ssms onclick=dosms();>📟</button> </h1>
New static HTML div element placed to the bottom of the body element …
<div id=divas></div>
New Javascript global variables (picking up hashtagging parts of the address bar URL, perhaps linked off an email or SMS link clicked) …
Client meets server today, allowing the PHP data storage talents in yesterday’s Event Calendar PHP Tutorial‘s work to meet a “clientside” way to …
Record to Remember via Bookmark
… use the web browser Bookmarks to help you recall an Events in Month report with long entries.
Involving a Bookmark still needs those “get” ? and & arguments, and we allow the PHP to lookup for us the data underscoring an address bar URL such as …
… that mapping being possible, now, making use of a pseudo hashtag arrangement … your Clayton‘s hashtag, if you will!
To start to use a hashtag suits, as your hashtag navigation only makes sense in the “clientside” woooorrrrrllllddd, and even there, really using one only tries to position a webpage where an element with an ID matching the hashtag sits (and we are never going to have this ID element in our work), and in the meantime we’ve passed across from the child PHP to the parent HTML a valuable piece of information helping the link to the Bookmark system be possible. The Javascript codeline (you may have noticed) …
var documentURL=document.URL;
… as stupid and simple looking as it is, is crucial for us. We get child webpage parts (like our PHP) to change document.URL to a far too long in normal circumstances address bar URL the rest of the code feeds off. It’s just that now, that far too long in normal circumstances address bar URL has a #[hashtag] appended such as …
#August__2023_00000__1
… uniquifying a Month, Year Events in Month identifier part with a version of the user’s IP address (so that they only see what is relevant to them).
Address bar URLs such as “https://www.rjmprogramming.com.au/HTMLCSS/events_in_month.php?exactlabel=August__2023_00000__1” are Bookmarkable, and so we allow for similar outcomes with less concern about how much data is being “recorded” and recallable (via that web browser’s Bookmark system).
Also, today, a lot of CSS tweaks, so that the CSS styling now looks like …
… form submit button (toggling) value to start involving PHP with those longer datasets of Event in Month descriptions, in our most recent project. What do we use as the data conduit? No, not a database. No, not a serverside flat file. No, not clientside window.localStorage nor window.sessionStorage nor HTTP Cookies. We store long Event in Month description data in our new events_in_month.php PHP itself. And this same PHP can populate options in a new dropdown element in the parent to facilitate the recalling of any relevant “Record to Remember” recordings.
The PHP is kind of short, so we will show it below, including one MAMP example of that “self storage” …
<?php
// events_in_month.php
// RJM Programming
// August, 2023
// Help out events_in_month.htm
But, there’s an inherent weakness with the design, we’ll go into more into the future.
… well … it’s a perennial for us, regarding how if you stick with clientside thinking, only, web applications, when the amount of data to remember starts adding up, the “get arguments approach” ( ie. use ? and & arguments at the address bar ) is restricted by length restrictions regarding URL lengths.
Rather than jump to PHP serverside ideas just yet, we wanted to show some more ideas, staying with “clientside only thinking”, today, as well as improving the UX (user experience) and small steps forward regarding styling.
Okay then, regarding the idea to remember an Event in Month form, when there is a lot of data, and staying “just clientside”, we’ve coded for a “New Window” idea, albeit not as memorable as the default “Remember in Bookmark” possible for your smaller datasets. However, in saying that, we found that within this new window, with our Google Chrome web browser, we could …
bring up Context Menu with a right click or two finger gesture within the popup window webpage content …
pick Inspect option …
be in Elements tab of your Web Inspector … and …
highlight top <html> tag …
Context Menu with a right click or two finger gesture …
pick Copy -> Copy outerHTML … so that …
your Event Calendar for your Events in Month choice is in a text buffer … ready for you to …
Paste into a Text Editor that Events in Month webpage to store (perhaps in a MAMP local Apache/PHP/mySql web server environment, where you can further look at and develop your own ideas)
The user is told when the switch to “New Window” compromise becomes active, decided upon by reconstructing the proposed address bar URL regularly and when too long …
function formanalyze() {
var fio=document.getElementsByTagName('form')[0];
var delm='?';
var fioih=fio.innerHTML;
var fions=fioih.split(' name="');
var testurl=documentURL.split('?')[0].split('#')[0];
for (var ijk=1; ijk<fions.length; ijk++) {
testurl+=delm + fions[ijk].split('"')[0] + '=' + encodeURIComponent(document.getElementById(fions[ijk].split('"')[0]).value);
delm='&';
}
setTimeout(formanalyze, 3000);
if (eval('' + testurl.length) >= 750) {
if (document.getElementById('remember')) { document.getElementById('remember').value='New window'; }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value='New window'; }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value='New window'; }
} else {
if (document.getElementById('remember')) { document.getElementById('remember').value=document.getElementById('remember').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value=document.getElementById('rememberme').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value=document.getElementById('remembermoi').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
}
return eval('' + testurl.length);
}
… the form submit buttons are reworded accordingly.
Another idea from this blog thread’s inspiration …
… we’ve now addressed in today’s “second draft” is allowing for an optional bold Event Day Blurb Title, available to the user via a new dropdown “Bold Title” option.
And, how can we do more with colour, to help the right bits stand out, and be consistent? We thought …
text shadow means by which the text of Event Calendar can be more impactive …
<div style="text-shadow:-1px 1px 1px #ff2d95;" id=eventcalendar></div>
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 …
… 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 …
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
close unnecessary apps you have open that are not the web browser you are going to use to …
if you are in a car we often find it best turning Bluetooth off and use the iPhone speakers (with a decent volume applied)
open our inhouse Shower Songs web application in a mobile web browser application
arrange the playlist with it’s emergent red buttons you can tap as they arrive if you are impatient (perhaps leaving some unselected)
once satisfied with your ordering and music is playing …
in our iPhone’s case, swipe down and left from top right, to reveal that iPhone’s Control Center display (with the Torch!)
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))
… 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
We break with our normal transmission, because we read something …
… Luuunnnaa?! Sarcasm does not look good on you (though lilac green’s not bad). And wipe that sardonic grin off your breakfast bowl food rearrangements you’ve just made?!
A feather to our boa constrictor … Luuunnnaa?! … get off the keyboard now … don’t you have some bone to pick, or that book about Dogma (tee hee) to read?!w
… on that Shower Songs YouTube embedded iframe inhouse playlist concept, further to Shower Songs Playlist Subset Revisit Tutorial. Some people, like Luna today, may want to bypass our Shower Songs just audio paradigm to dynamically create a temporary YouTube playlist and play video and audio together 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.
Radio Play via comma separate YouTube 11 character IDs or search ideas for an inhouse playlist (if any in a comma separated list is PtR4cWb4HNg temporary YouTube playlist audio and video play can be attempted) … 7 such uses Shower Songs … egs. Tragedy,Boogie Wonderland,Down Among the Dead Men flash … random … Tragedy ,Imagine*3,Breezin … ordered 5 … Tragedy ,Pina Colada Song,Fast Car … audio … Tragedy ,Galveston,Fix You … audio ordered,
Did You Know?
If at the time of launching (and deploying) into making one of these temporary YouTube playlists and you are logged into your own YouTube channel, more possibilities present, and today’s tutorial animated GIF shows a bit of this (though we found out about the virtue of putting PtR4cWb4HNg first later, alas).
The playlist gets played, and on non-mobile it may start itself. For each track you can use the Save button down near the bottom to save to a new (where we are recommending PtR4cWb4HNg to go first) or pre-existing public or private playlist. Okay, so you have this new YouTube playlist.
… in which case a brief error message may happen and it may start playing (on non-mobile) that YouTube playlist at track 2 … hence my advice regarding PtR4cWb4HNg … or …
A few attempts we made failed to “curb the enthusiasm” of the parent window left behind by the new window.open window of these Playlist Subsets the user defines, until we did something we can not recall ever doing before, namely …
var tdsarea=document.getElementsByTagName('td');
for (var iopj=eval(-1 + tdsarea.length); iopj>=0; iopj--) {
tdsarea[iopj].innerHTML=tdsarea[iopj].innerText;
}
… to not only be “curbing it’s enthusiasm to play” but also making that parent window end up being a “display snapshot only” of what had been going on before the user set up more than one “L=loop” looping textarea functionalities that defines a playlist subset scenario where that new window takes on the role of “enthusiastic play”.
add to an “individual song looping subset” with another “individual looping song” … and it also serves another “arcane usage” to our mind, we explain below …
out and about using a laptop lassooed to a mobile (or just the mobile itself) using mobile data (rather than Wi-Fi) this web browser Shower Songs web application depends on a connection as a song starts and if you have run out of never before tapped buttons to choose from (and the web application has lost it’s connection) it can become an impotent web application, sometimes, so that to add to the web application’s possibilities of button tapping, and often reawakening it, the better, we figure
… work did not function for as many scenarios as we would like. This problem requires Javascript web browser clientside debugging via a Web Browser web inspector “Developer” style of debugging (ie. deep and meaningful).
When it gets to the “deep and meaningful” we mean “comparing” console tab “good versus bad” types of reporting, which becomes untenable if too much is already being reported in our favourite “reporting tool conduit” for us …
console.warn([some messaging text]);
… you can read more about at YouTube API Caller Phase Two Console Warning Tutorial. Over the three window hierarchies, over quite some time, we’ve filled console.warn web inspector tab with so much information it is untenable for what we have to do debugging the issues above.
And so, today, we’re showing a “conditional approach” to controlling “console.warn” logging via “grandchild level” substitution of all “console.warn(” for “consolewarn(” and then the new Javascript function …
function consolewarn(inms) {
if (window.self != window.parent) {
if (('' + top.document.URL).indexOf('consolewarnoptinall') != -1 || ('' + top.document.URL).indexOf('consolewarnoptingrandchild') != -1) {
console.warn(inms);
}
} else if (('' + document.URL).indexOf('consolewarnoptoutall') == -1) {
console.warn(inms);
}
}
… and at the “parent level” substitution of all “console.warn(” for “consolewarn(” and then the new Javascript function …
function consolewarn(inms) {
if (window.self != window.parent) {
if (('' + top.document.URL).indexOf('consolewarnoptinall') != -1 || ('' + top.document.URL).indexOf('consolewarnoptinchild') != -1) {
console.warn(inms);
}
} else if (('' + document.URL).indexOf('consolewarnoptoutall') == -1) {
console.warn(inms);
}
}
… as an address bar controlling URL via, for example …
… means by which we can better hone in on the debugging issues as they arrive, so that self contained relevance fits on the one screen, and the Clear Console icon becomes an additional friend to our work, within …
YouTube API iOS Shower Song Subset Looping Tutorial
You’d think we’d be done with ablutions at this blog, but ingen måte … Luna (aka Måne) says … there’s all manner of molekylær interesse out there in and out of the fjords …
It’s not just H and the 2 and the O … it’s the art of the rollerulle.
… or so says “The Lu” (aka “Toalettet”) anyway!
Today’s Shower Songs tweak involves it’s “individual song looping” thinking. It occurred to us, that it’s use by a user might be what they want, it becomes a bit inflexible should they either …
want to “move on” to a new song … via …
add to an “individual song looping subset” with another “individual looping song” … and it also serves another “arcane usage” to our mind, we explain below …
out and about using a laptop lassooed to a mobile (or just the mobile itself) using mobile data (rather than Wi-Fi) this web browser Shower Songs web application depends on a connection as a song starts and if you have run out of never before tapped buttons to choose from (and the web application has lost it’s connection) it can become an impotent web application, sometimes, so that to add to the web applications’s possibilities of button tapping, and often reawakening it, the better, we figure
At least, on “mobile” iOS (which we have access to) can any “command line” feel of playlists ending up at our Shower Songs web application be arranged?
Pretty pithy, huh?! Before we launch into the great iOS Shortcuts app (we’ve talked about before at Shortcuts iOS App Email Arrival Sounds Tutorial) helping here, let’s outline some other simpler ideas you might want to try yourself in the DIY range of ideas …
Add to Home Screen … with a tailored (Playlist) Title … this being our preferred option to future proof the remembering … but also available is …
Add Bookmark … or …
Add Favourite
Make your web browser’s opening Home Page be a URL of interest (like one of these playlists) within that web browser app’s Settings area
as well as the Shower Songs (as well as Tabular Single Row Media Gallery) web application (with Playlists of 7) can have a dropdown be populated ready to choose and replay that Playlist (that can be email or SMS shared with a recipient)
Okay, all that being said, the great Shortcuts iOS app can serve two purposes a bit “above and beyond this” …
you can DIY build an iOS feeling and “hybrid looking” amalgum of iOS and “old days” dialog box “desktop feeling” personalized application(s) …
the act of constructing any one is sure to inspire other iOS automation ideas you might have
We’re sure lots of you more aux fait with the great iOS Shortcuts app can do better than the “bit kludgy” effort we came up with, and that is the joy of programming, huh?! It can come down to …
what you think is the most efficient …
you feel you can handle … and …
end up with a better automated solution … but …
it’s not “all about efficiency” always … it’s also learning about new methodologies you might have to spend more time discovering the ins and outs about
As a case in point, it will be hard to stop yours truly just (iOS mobile) opening the relevant Radio Play web application in a web browser, and going from there (with Bookmarks and Favourites), but there you go?! In this case, perhaps yes, but you should see all the other Messaging and automation possibilities that a peruse of the iOS Shortcuts app can open up to you!
Todays’ animated GIF presentation shows our endeavours “warts and all” (latching onto, intervention wise, when a user taps the Music mobile app icon) for your perusal.
Can a list of seven non-YouTube-ID comma separated values (ie. YouTube song search basis strings) be entered and still end up at the Shower Songs web application?
Well, yes, that’s possible if an intervention point can be arranged. After all, the command line prompt goes …
Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist … 7 for Shower Songs … egs. Tragedy,Boogie Wonderland,Down Among the Dead Men … random … Tragedy ,Imagine*3,Breezin … ordered 5 … Tragedy ,Pina Colada Son,Fast Car … audio … Tragedy ,Galveston,Fix You … audio ordered, and go.
… begging the question “What happens if we enter, at the command line …”
play
Tragedy ,Pina Colada Song,Fast Car,Breezin,Galveston,Fix You,Imagine
… and that’s where “our fun” (chortle, chortle) began (yeh, right … after a Goose Chase with it being the seventh one) because that seventh YouTube video ID (involved with YouTube “Imagine” search (and something about this rings a bell)) comes back with …
This content can’t be played on your mobile browser. Get the YouTube app to start watching.
Ouch?! What to do? Looking optimistically on this, it’s good to discover it now (yeh, right).
macOS (building onthe changedplay.sh shell script) …
#!/bin/bash
rest=""
if [ -z "$1" ]; then
echo "Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... 7 such uses Shower Songs ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men flash ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Song,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go."
read ans
else
preans="$1"
ans="$1 $2 $3 $4 $5 $6 $7 $8 $9"
while [ ! -z "$9" ]; do
shift
rest="${rest} $9"
done
ans="$ans${rest}"
fi
if [ ! -z "$ans" ]; then
commas_only="${ans//[^,]}"
if [ "${#preans}" == "83" ]; then
if [ "${#commas_only}" == "6" ]; then
open "https://www.rjmprogramming.com.au/$1"
else
open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
fi
else
open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
fi
fi
exit
Windows (building onthe changedplay.bat script) …
@echo off
rem play.bat
rem RJM Programming
rem November, 2025
set passed=
set rest=
set seven=0
if trick==trick%1 (
set /p ans=Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... 7 for Shower Songs ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Son,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go.
set ansplus="%ans% "
if "%ansplus:~12,1%"=="," (
if "%ansplus:~24,1%"=="," (
if "%ansplus:~36,1%"=="," (
if "%ansplus:~48,1%"=="," (
if "%ansplus:~60,1%"=="," (
if "%ansplus:~72,1%"=="," (
if "%ansplus:~84,1%"==" " (
set seven=7
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=%ans%"
goto :end
) else (
set seven=6
)
) else (
set seven=5
)
) else (
set seven=4
)
) else (
set seven=3
)
) else (
set seven=2
)
) else (
set seven=1
)
) else (
set seven=0
)
) else (
set ans="%1"
set ansplus="%1,%2,%3,%4,%5,%6,%7 %8 "
if "%ansplus:~12,1%"=="," (
if "%ansplus:~24,1%"=="," (
if "%ansplus:~36,1%"=="," (
if "%ansplus:~48,1%"=="," (
if "%ansplus:~60,1%"=="," (
if "%ansplus:~72,1%"=="," (
if trick==trick%8 (
set seven=7
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/shower_songs.html?thelist=%1,%2,%3,%4,%5,%6,%7"
goto :end
) else (
set seven=6
)
) else (
set seven=5
)
) else (
set seven=4
)
) else (
set seven=3
)
) else (
set seven=2
)
) else (
set seven=1
)
) else (
set seven=0
)
set passed=yes
if trick==trick%2 goto :loop
set ans="%ans%,%2"
if trick==trick%3 goto :loop
set ans="%ans%,%3"
if trick==trick%4 goto :loop
set ans="%ans%,%4"
if trick==trick%5 goto :loop
set ans="%ans%,%5"
if trick==trick%6 goto :loop
set ans="%ans%,%6"
if trick==trick%7 goto :loop
set ans="%ans%,%7"
if trick==trick%8 goto :loop
set ans="%ans%,%8"
if trick==trick%9 goto :loop
set ans="%ans%,%9"
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans:"=%"
:loop
if "%9"=="" (
@echo off
) else (
shift
set rest="%rest% %9"
goto :loop
)
set ans="%ans%%rest%"
set ans=%ans:"=%
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
if trick==trick%passed% (
set ans=%ans:"=%
if "%ans:,=%"=="%ans%" (
echo "Nothing to do."
) else (
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
)
rem exit
:end
… and involving, if you are on macOS or Windows implementing accordingly …
YouTube API Caller Radio Play Doctype Meta Tutorial
It took a session on this MacBook Air’s macOS Firefox web browser trying the Tabular Single Row Media Gallery web application to emphasise the importance of more consistency checking on …
doctype HTML tagdeclaration …
<!DOCTYPE html>
… and …
meta HTML display tagcharset attribute …
<meta charset="UTF-8">
… existence in web applications we create, to the point that not having the second one defined was stopping proper webpage display on Firefox. Was this a portent of what is to come soon on more web browsers?!
Let’s look at the purpose of these two HTML tagthingos …
What’s the scripting here? They are called batch files with extension *.bat we’re calling play.bat (going back to the DOS days of the ’70’s again). With *.bat you just need to plonk your play.bat anywhere within the Windows local system path, and the word (now command) “play” will do the rest anywhere in that user’s command line environment. And the batch file has …
@echo off
rem play.bat
rem RJM Programming
rem November, 2025
set passed=
set rest=
if trick==trick%1 (
set /p ans=Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Son,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go.
) else (
set ans="%1"
set passed=yes
if trick==trick%2 goto :loop
set ans="%ans%,%2"
if trick==trick%3 goto :loop
set ans="%ans%,%3"
if trick==trick%4 goto :loop
set ans="%ans%,%4"
if trick==trick%5 goto :loop
set ans="%ans%,%5"
if trick==trick%6 goto :loop
set ans="%ans%,%6"
if trick==trick%7 goto :loop
set ans="%ans%,%7"
if trick==trick%8 goto :loop
set ans="%ans%,%8"
if trick==trick%9 goto :loop
set ans="%ans%,%9"
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans:"=%"
:loop
if "%9"=="" (
@echo off
) else (
shift
set rest="%rest%,%9"
goto :loop
)
set ans="%ans%%rest%"
set ans=%ans:"=%
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
if trick==trick%passed% (
set ans=%ans:"=%
if "%ans:,=%"=="%ans%" (
echo "Nothing to do."
) else (
explorer.exe "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html %ans%"
)
)
rem exit
:end
… as your starting gambit, here, where the equivalent of macOS’s “open” is “explorer.exe” on Windows (ie. the File Explorer) … almost as cute!
YouTube API Caller Radio Play Playlist Local System Tutorial
The ..
command line
… of a laptop or notebook or personal computer can be an environment to relax from the GUI aspects of your modern operating systems and think about …
processes
batch driven tasks
task simplifications
… and in the category of that last one, on our local macOS operating system we envisaged a day we could slip back to the “quiet world” of the “command line” and type a command like …
play Tragedy,Imagine,Down Among the Dead Men PAN -
… and get somewhere playing those songs through a web browser accessing the YouTube API and our interfacings to it in webpage software form, playing in a continuous Radio Play style.
You see, with all the distractions, only having to remember …
play
… no matter where we were in “command line” woooorrrrllllddd seemed the ideal, and yes, it’s possible. However, we think explaining …
bash /Applications/MAMP/htdocs/play.ksh Tragedy,Imagine,Down Among the Dead Men PAN -
… is a necessary dividing line between two parts to the discussion. So what’s bash? It’s the shell we associate as your macOS default shell (we get to via the “out of the box” macOS desktop application called Terminal) … well, it used to be … anyway, the first line of (what started as play.ksh then play.sh and then eventually, just, play … as a filename that is) …
#!/bin/bash
rest=""
if [ -z "$1" ]; then
echo "Radio Play via comma separate YouTube 11 character IDs or search ideas for a playlist ... egs. Tragedy,Boogie Wonderland,Down Among the Dead Men ... random ... Tragedy ,Imagine*3,Breezin ... ordered 5 ... Tragedy ,Pina Colada Song,Fast Car ... audio ... Tragedy ,Galveston,Fix You ... audio ordered, and go."
read ans
else
ans="$1 $2 $3 $4 $5 $6 $7 $8 $9"
while [ ! -z "$9" ]; do
shift
rest="${rest} $9"
done
ans="$ans${rest}"
fi
if [ ! -z "$ans" ]; then
open "https://www.rjmprogramming.com.au/HTMLCSS/swipe_media.html $ans"
fi
exit
… tells the local system use the bash shell to interpret this what you might like to think of as an executable script (which we went chmod 777 play regarding to make it so).
Okay, so we wrote this script in /Applications/MAMP/htdocs/ and that …
bash /Applications/MAMP/htdocs/play Tragedy,Imagine,Down Among the Dead Men PAN -
… could swing it at this stage, or even being in /Applications/MAMP/htdocs/ and going …
./play Tragedy,Imagine,Down Among the Dead Men PAN -
… but (even in /Applications/MAMP/htdocs/) …
play Tragedy,Imagine,Down Among the Dead Men PAN -
… is most likely to reply something like …
zsh: no such command
As the programmer, perhaps you could leave it at that with your “insider knowledge”, or if “play” as a command already meant something (a test that would be good to do before any such proposed work), otherwise … do you really think you’ll remember next Wednesday? So …
enter into the wooooorrrrllllddd of aliases (thanks to this great advice, thanks) … eg.
alias play="/Applications/MAMP/htdocs/play"
placed into …
~/.bashrc
… via (in our case) …
vi ~/.bashrc
then …
source ~/.bashrc
… needs to be included into the login procedure of …
~/.profile
…via (in our case) …
vi ~/.profile
to make …
play
… as the interactively asking alternative to the argumentative example of …
play Tragedy,Imagine,Down Among the Dead Men PAN -
… mean something … and anywhere
… all of this possible because of the brilliantly useful macOS (not Linux nor unix) …
… opener of web browsers from the command line blowing of our tiny little rather still naive mind … mind you, VAX/VMS “phone” command from the ’70’s might have even been better?! And then there were those punch cards … in the hopper … and if you got a character wrong … back to the end of the queue.
By the way, this brought into play for us what your default web browser is. Ours is Safari yet we develop more on Google Chrome. Safari, for us, does more Popup Blocking, and it is a thing to look out for should a window not open when expected (and these command line methodologies don’t get past you still having to unmute and/or click/tap once before the Radio Play mode of play kicks off). To undo the Popup Block there will probably be a means to do this to the right of the web browser address bar.
But there is a point. Today represents an improvement on yesterday’s arrangements for dynamic playlist creation regarding our Tabular Single Row Media Gallery web application via the playlist emoji button 🔀 click/tap or on the web browser command line. With yesterday’s scenario, had you entered as your internal playlist comma separated string …
Born to Run,Born to Run,Born to Run,Born to Run
… without the …
Burp …
… that is you’d have ended up with the top find off a YouTube search repeated 4 times. Is this ideal? We asked Nala and Luna but, unfortunately they were busy, so they left me with the decision, and we came up with …
That’s kind of silly.
For these few reasons …
variety
album style Radio Play listening possibilities
perhaps getting around that …
This video requires payment to watch YouTube
… issue we talked about before … because you could uncheck it’s checkbox if the error appears
giving non-top search items a go
… we decided to “mix it up” regarding entries like …
Born to Run,Born to Run,Born to Run,Born to Run
… as well as the simpler …
Born to Run*4
… so that repeats don’t cause users indigestion … chortle, chortle.
Here’s the Javascript turning Born to Run*4 into Born to Run,Born to Run,Born to Run,Born to Run …
YouTube API Caller Radio Play Playlist Songname Search List Address Bar Tutorial
Don’t know if you are like me, but especially when on this MacBook Air we’re, forever, using a web browser address bar to type in, what we’ve set up as, a Google search engine webpage query. Rather than even going to Google webpage first, that is!
Most people don’t want to know about arcane web application argument arrangements … though we’re very fond of the 5 minute ones?!
What’s wrong with some of you? Who would not relish the thought of …
&or?andgo=y # will click the Radio button after all above (unless notgo is mentioned in the list somewhere), as relevant, with the programmatically determined derived YouTube ID list via YouTube search(es)
💬🦆 Come On!
… when, after a bit of thought and tweaks to our RJM Programming domain’s Apache Document Root residing 404.shtml webpage Javascript …
if (document.URL.indexOf('rjmprogramming.com.au/HTMLCSS/swipe_media.htm') != -1) {
if (decodeURIComponent(document.URL).indexOf(',') != -1) {
if (decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'')).toLowerCase().indexOf('notgo') != -1) {
location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?thelist=' + encodeURIComponent(decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace('notgo','').replace('NOTGO','').replace('Notgo','')));
} else {
location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?andgo=y&thelist=' + encodeURIComponent(decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'').replace(/^\%20/g,'')));
exit;
}
} else if (decodeURIComponent(document.URL.split('rjmprogramming.com.au/HTMLCSS/swipe_media.htm')[1].replace(/^l/g,'')).toLowerCase().indexOf('ask') != -1) {
location.href='//www.rjmprogramming.com.au/HTMLCSS/swipe_media.html?ask=y';
exit;
}
}
… now all you need to add after that link above, on the web browser address bar is …
[commaSeparatedList_decodeURIComponent_ized]
… ie. just type a comma separated YouTube song search basis link after the link wording above
YouTube API Caller Radio Play Playlist Songname Search List Dropdown Tutorial
Around here, regarding web application work, we really like dropdown (ie. HTML select element) work because a lot of information can be …
stored
displayed (often taking up minimal webpage space)
it’s option subelements can have an event life of their own, or be part of the select element event whole picture
dropdown multiple selection mode (as with today’s work) can …
still support your single choice scenario
we’ve coded today’s dropdown to support, as applicable, ordered single click choices … versus …
can allow for control key (sets of choices not necessarily adjacent) and shift key (blocks of choices)
can respond (as with today’s dropdown) to preset selections established at creation via dropdown (ie. select) innerHTML option subelement selected attribute setting
dropdown events onmousedown and ontouchdown (as for today’s dropdown) and onclick can be harnessed ahead of an onchange event … and in today’s case can help unset any preset option subelement selected attribute setting(s)
Just so flexible! Subelement option CSS styling can be less friendly, but even so, often background colouring is possible, and we do a bit of that with the work from yesterday’s YouTube API Caller Radio Play Playlist Songname Search List Tutorial and today’s better “shored up” work you can see a bit of below (where your starting point might be that we “wrap” this particular Javascript prompt window through the Javascript overprompt function below) …
var outplist='', kaconto=null, kacontoarr=[], rconeis=155, gconeis=255, bconeis=255;
function karlook(iois) {
var aconto=null;
aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
if (outplist.indexOf(',') != -1) {
kaconto=aconto;
setTimeout(function(){ kaconto.getElementById('ajaxs').style.cursor='progress'; }, 3000);
setTimeout(postkarlook, 7000);
} else if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
kaconto=aconto;
setTimeout(mpostkarlook, 7000);
}
}
}
}
function karlookagain(iois,idxn) {
var aconto=null;
aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.body != null) {
if (eval('' + kacontoarr.length) > eval('' + idxn)) {
kacontoarr[eval('' + idxn)]=aconto;
} else {
kacontoarr.push(aconto);
}
}
}
}
function mpostkarlook() {
if (kaconto.getElementById('ajaxs')) {
var kbuts=kaconto.getElementsByTagName('input');
for (var lbuts=0; lbuts<kbuts.length; lbuts++) {
if (('' + kbuts[lbuts].type) == 'button') {
if (('' + kbuts[lbuts].value).indexOf('Radio') == 0) {
kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', String.fromCharCode(10) + 'Radio');
}
}
}
} else {
setTimeout(mpostkarlook, 5000);
}
}
function postkarlook() {
var selectedones='', oktogo=true, hihi=0;
if (kaconto.getElementById('ajaxs')) {
//alert(kaconto.getElementById('ajaxs').innerHTML);
for (hihi=0; hihi<kacontoarr.length; hihi++) {
if (!kacontoarr[hihi]) {
oktogo=false;
//alert('hihi=' + hihi + ' NOT okay');
} else if (!kacontoarr[hihi].getElementById('ajaxs')) {
oktogo=false;
//alert('hihi=' + hihi + ' not okay');
}
}
if (!oktogo) {
setTimeout(postkarlook, 5000);
} else if (kaconto.getElementById('ajaxs').innerHTML.indexOf('... and then ...') == -1) {
kaconto.getElementById('ajaxs').style.cursor='pointer';
var otherps=baeisf();
if (otherps != '' || navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
var kbuts=kaconto.getElementsByTagName('input');
for (var lbuts=0; lbuts<kbuts.length; lbuts++) {
if (('' + kbuts[lbuts].type) == 'button') {
if (('' + kbuts[lbuts].value).indexOf('Radio') == 0) {
var wasvl=kbuts[lbuts].value;
if (otherps == ' ') {
kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Ordered ' + String.fromCharCode(10) + 'Audio ' + String.fromCharCode(10) + 'Radio');
} else if (otherps == ' ') {
kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Audio ' + String.fromCharCode(10) + 'Radio');
} else if (otherps == ' ') {
kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', 'Ordered ' + String.fromCharCode(10) + 'Radio');
} else {
kbuts[lbuts].value=kbuts[lbuts].value.replace('Radio', String.fromCharCode(10) + 'Radio');
}
}
}
}
}
selectedones=(kaconto.getElementById('ajaxs').innerHTML.split(kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].split('</option>')[0] + '</option>').replace('>', ' class=uptop selected>');
for (hihi=0; hihi<kacontoarr.length; hihi++) {
if (rconeis == gconeis && rconeis == bconeis) {
bconeis-=7;
if (bconeis < 0) { bconeis+=255; }
} else if (rconeis == gconeis) {
gconeis-=7;
if (gconeis < 0) { gconeis+=255; }
} else {
rconeis-=7;
if (rconeis < 0) { rconeis+=255; }
}
selectedones+=((kacontoarr[hihi].getElementById('ajaxs').innerHTML.split(kacontoarr[hihi].getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].split('</option>')[0] + '</option>').replace('>', ' class=uptop selected>')).replace(/option\ onclick\=/g, 'option style=background-color:rgb(' + rconeis + ',' + gconeis + ',' + bconeis + '); onclick=');
kaconto.getElementById('ajaxs').innerHTML+='<option value="">... and then ...</option>';
kaconto.getElementById('ajaxs').innerHTML+=kacontoarr[hihi].getElementById('ajaxs').innerHTML.split(kacontoarr[hihi].getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>')[1].replace(/option\ onclick\=/g, 'option style=background-color:rgb(' + rconeis + ',' + gconeis + ',' + bconeis + '); onclick=');
//alert(kacontoarr[hihi].getElementById('ajaxs').innerHTML);
}
//alert(selectedones);
kaconto.getElementById('ajaxs').innerHTML=kaconto.getElementById('ajaxs').innerHTML.replace(kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>', kaconto.getElementById('ajaxs').innerHTML.split('</option>')[0] + '</option>' + selectedones + (selectedones != '' ? '<option id=optclk value="">____ Selection above available (resettable via click here) as you click/tap button at right ____</option>' : ''));
if (selectedones != '') {
kaconto.getElementById('ajaxs').onmousedown=function(event){ if (event.target.parentNode.outerHTML.split('>')[0].indexOf(' data-flagged=') == -1) { event.target.parentNode.setAttribute('data-flagged','y'); event.target.parentNode.innerHTML=event.target.parentNode.innerHTML.replace(/\ selected/g, ' ').replace('____ Selection above available (resettable via click here) as you click/tap button at right ____','____ Please select choices in usual multiple choice dropdown ways ____'); } };
kaconto.getElementById('ajaxs').ontouchdown=function(event){ if (event.target.parentNode.outerHTML.split('>')[0].indexOf(' data-flagged=') == -1) { event.target.parentNode.setAttribute('data-flagged','y'); event.target.parentNode.innerHTML=event.target.parentNode.innerHTML.replace(/\ selected/g, ' ').replace('____ Selection above available (resettable via click here) as you click/tap button at right ____','____ Please select choices in usual multiple choice dropdown ways ____'); } };
}
}
}
}
function baeisf() {
var outarrp=outplist.split(',');
if (eval('' + outarrp.length) > 1) {
return outarrp[0].replace(outarrp[0].trim(), '');
}
return '';
}
And so, today …
we add onto the default random ordering mode of Radio Play via YouTube search comma separated list, the further choices ordered or audio or audio ordered, as per the relevant Javascript prompt blurb that is now going …
Enter YouTube 11 character code video (comma separated) or audio stream only of video (semicolon) list to Radio Play (and add ! to start in shuffle mode and/or # for the order you enter and/or & for whole list) … or a YouTube Search String basis for playlist via a Radio📻? button to activate, later. Comma separateds can be search ideas … egs. Tragedy,Boogie Wonderland,Down Among the Dead Men … random … Tragedy ,Imagine,Breezin … ordered … Tragedy ,Pina Colada Song,Fast Car … audio … Tragedy ,Galveston,Angel of the Morning … audio ordered. Double click on this cell for playlist redefinitions.
started allowing for dropdown events onmousedown and ontouchdown be able to reset the preset choices we programmatically select for the user should they be happy (but our motivation for this event work was the potential to run into a YouTube video that gives the error …
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);
}
… 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='';
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 …
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 ''; }
Because the theme of our current Editable Calendar web application revolves around time stamps and day names and month names regarding yesterday’s Editable Calendar Google Translate Tutorial that means, regarding language internationalization ideas …
as well as yesterday’s Google Translate ideas … also available is …
Yesterday’s Editable Calendar Primer Tutorial‘s start to our Editable Calendar project was a very anglo-centric exercise. Today, we want to use the great …
… to help translate our inhouse burgeoning Editable Calendar skeletal contents to some non English languages.
Why the skeletal here? Well, your own entries made before you select a dropdown non English language choice are stripped out in this changedsecond draftEditable Calendar you can try below, because we’re using the Google Translate “static URL” approach to the translations. But we will examine, down the track, if we can do better?! Again, stay tuned for more progression and internationalization over the days on this Editable Calendar project.
we’re channelling how in emails “word strings” starting with “http” become links … and so …
in our event in month “blurb” textarea elements we allow user highlighted text containing such “http” “word strings” be opened in popup windows showing the content of those URLs, as available
Here is the relevant Javascript we ended up with, for this …
Just briefly, delved into the wooooorrrrllllldddd of days of the week before 1582 debate … you had to be there … and in the words of Lleyton … Come on!!!! And we came out the other side. Good times! Anyway, thanks for all the interesting discussion, which we recommend you start at with this gem. Anyway, we now allow dates after 1582 (after this was previously set at 1970) in all respects and dates between 0000 and 1581 only via tweaks to the address bar URL you do yourself and we just hide the day of the week string. Otherwise … this could be needed?!
When doing our inhouse testing for Event Calendar Collaboration Tutorial the other day, it got us “peeved”, shall we say. We wanted a mechanism, with those “a” link “mailto:” emailing arrangements, of not having to fill out the email address in the “To:” field each time. First world problem alert! Still and all …
When it comes to procedures …
Aaaaaarrrrgggghhhh …
Nuances count … regarding …
Errrrrrr …
Saving time …
Saving frustration
… resulting in the “easy to remember” acronym WANESS … we rest our cases!
What can help here? Well, it is a personalization … so … anyone, anyone? Yes, Lou, back from holidays, a month late … yes, well, okay … we can see you’ve put some thought into this … HTTP Cookies could be used. Yes, Shwetank, you’ve had your hand up some time now. We agree, Web Storage window.localStorage allows for more data, so we’ll go with that, though either style of approach would work here.
Global variables initialization …
var defemail='', defsms='';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
Within document.body onload event logic …
if (document.getElementById('semail') && document.getElementById('ssms')) {
document.getElementById('semail').oncontextmenu=function(){ emailaskit(); };
document.getElementById('semail').ontouchmove=function(){ emailaskit(); };
document.getElementById('ssms').oncontextmenu=function(){ smsaskit(); };
document.getElementById('ssms').ontouchmove=function(){ smsaskit(); };
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('semail').title+=' Move gesture here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Move gesture here can ask for new default remembered SMS number for collaboration purposes';
} else {
document.getElementById('semail').title+=' Right click here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Right click here can ask for new default remembered SMS number for collaboration purposes';
}
}
Calling these two Javascript function helpers …
function emailaskit() {
if (defemail == defemail.trim()) {
defemail=defemail.trim() + ' ';
var emailm=prompt('Enter default email address.', defemail.trim());
if (emailm == null) { emailm=''; }
if (emailm.trim() != '' && emailm.trim().indexOf('@') != -1) {
defemail=emailm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', emailm.trim());
}
}
defemail=defemail.trim() + ' ';
}
function smsaskit() {
if (defsms == defsms.trim()) {
defsms=defsms.trim() + ' ';
var smsm=prompt('Enter default SMS number.', defsms.trim());
if (smsm == null) { smsm=''; }
if (smsm.trim() != '' && smsm.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
defsms=smsm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', smsm.trim());
}
}
defsms=defsms.trim() + ' ';
}
And allow control, as well, at the SMS prompt window logic …
function dosms() {
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
//alert('' + eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length));
if (eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length) >= 18000) {
snum=('' + prompt('Please enter SMS number to send to. We suspect message is too long for an SMS and if you enter an email address here instead, we will try to send an email instead. Append space(s) to remember, whatever you enter, for next time.', snum)).replace(/^null/g, (defemail.indexOf('@') != -1 ? defemail : (defsms != '' ? defsms : '')) );
} else {
snum=('' + prompt('Please enter SMS number to send to. Append space(s) to remember for next time.', snum)).replace(/^null/g, (defsms != '' ? defsms : (defemail.indexOf('@') != -1 ? defemail : '')));
}
if (snum == null) { snum=''; }
if (snum.indexOf('@') != -1) {
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', snum);
defemail=snum;
}
return doemail(snum);
} else if (snum.trim() != '' && snum.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
//alert('Snum=' + snum + '?');
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', snum);
defsms=snum;
}
var azx=top.document.getElementById('xas' + 'ms');
if (azx == null) { azx=top.document.createElement("a"); }
//if (1 == 1) {
// document.getElementById('divas').appendChild(azx);
//} else {
top.document.body.appendChild(azx);
// }
azx.id = 'xas' + 'ms';
azx.target = "_top";
azx.style = "display: none";
azx.href = 'sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()));
azx.click();
}
return '';
}
Also, today, we battled the logic to allow the textarea element onblur events also open the door to emailing and SMS “work in progress”. Believe it or not, this timing change was quite difficult in the changedevents_in_month.htm parent of the Events in Month web application. Never a dull moment in web application I.T. we’d say!
it did not have a fully fleshed out collaboration or sharing set of functionalities … at the time, probably, because …
each Monthly calendar filled out, and wanting to be saved, could involve much more than the 850 characters available to previous “mailto:” or “sms:” communication conduits, back to when we first tackled this project … but now …
hashtagging parts to the “mailto:” URLs (and maybe sometimes the “sms:” URL) might cover the data length needs
… so that this Event Calendar could be a web application at the center of a collaboration network of people working on that event organization. Much more useful, we figure!
Timing became really important with this integration of …
email
SMS
… communication conduit possibilities. With its design we have to wait until the point where the user is filling in textarea elements regarding a designated …
Month
Year
… of relevance, before we allow the email 📧 and SMS 📟 emoji buttons be shown. In the code …
Amended HTML h1 element static HTML to add, later shown, perhaps, email 📧 and SMS 📟 emoji buttons …
<h1>Events in Month <button style=display:none; title='Share via Email' id=semail onclick="doemail('');">📧</button> <button style=display:none; title='Share via SMS' id=ssms onclick=dosms();>📟</button> </h1>
New static HTML div element placed to the bottom of the body element …
<div id=divas></div>
New Javascript global variables (picking up hashtagging parts of the address bar URL, perhaps linked off an email or SMS link clicked) …
Client meets server today, allowing the PHP data storage talents in yesterday’s Event Calendar PHP Tutorial‘s work to meet a “clientside” way to …
Record to Remember via Bookmark
… use the web browser Bookmarks to help you recall an Events in Month report with long entries.
Involving a Bookmark still needs those “get” ? and & arguments, and we allow the PHP to lookup for us the data underscoring an address bar URL such as …
… that mapping being possible, now, making use of a pseudo hashtag arrangement … your Clayton‘s hashtag, if you will!
To start to use a hashtag suits, as your hashtag navigation only makes sense in the “clientside” woooorrrrrllllddd, and even there, really using one only tries to position a webpage where an element with an ID matching the hashtag sits (and we are never going to have this ID element in our work), and in the meantime we’ve passed across from the child PHP to the parent HTML a valuable piece of information helping the link to the Bookmark system be possible. The Javascript codeline (you may have noticed) …
var documentURL=document.URL;
… as stupid and simple looking as it is, is crucial for us. We get child webpage parts (like our PHP) to change document.URL to a far too long in normal circumstances address bar URL the rest of the code feeds off. It’s just that now, that far too long in normal circumstances address bar URL has a #[hashtag] appended such as …
#August__2023_00000__1
… uniquifying a Month, Year Events in Month identifier part with a version of the user’s IP address (so that they only see what is relevant to them).
Address bar URLs such as “https://www.rjmprogramming.com.au/HTMLCSS/events_in_month.php?exactlabel=August__2023_00000__1” are Bookmarkable, and so we allow for similar outcomes with less concern about how much data is being “recorded” and recallable (via that web browser’s Bookmark system).
Also, today, a lot of CSS tweaks, so that the CSS styling now looks like …
… form submit button (toggling) value to start involving PHP with those longer datasets of Event in Month descriptions, in our most recent project. What do we use as the data conduit? No, not a database. No, not a serverside flat file. No, not clientside window.localStorage nor window.sessionStorage nor HTTP Cookies. We store long Event in Month description data in our new events_in_month.php PHP itself. And this same PHP can populate options in a new dropdown element in the parent to facilitate the recalling of any relevant “Record to Remember” recordings.
The PHP is kind of short, so we will show it below, including one MAMP example of that “self storage” …
<?php
// events_in_month.php
// RJM Programming
// August, 2023
// Help out events_in_month.htm
But, there’s an inherent weakness with the design, we’ll go into more into the future.
… well … it’s a perennial for us, regarding how if you stick with clientside thinking, only, web applications, when the amount of data to remember starts adding up, the “get arguments approach” ( ie. use ? and & arguments at the address bar ) is restricted by length restrictions regarding URL lengths.
Rather than jump to PHP serverside ideas just yet, we wanted to show some more ideas, staying with “clientside only thinking”, today, as well as improving the UX (user experience) and small steps forward regarding styling.
Okay then, regarding the idea to remember an Event in Month form, when there is a lot of data, and staying “just clientside”, we’ve coded for a “New Window” idea, albeit not as memorable as the default “Remember in Bookmark” possible for your smaller datasets. However, in saying that, we found that within this new window, with our Google Chrome web browser, we could …
bring up Context Menu with a right click or two finger gesture within the popup window webpage content …
pick Inspect option …
be in Elements tab of your Web Inspector … and …
highlight top <html> tag …
Context Menu with a right click or two finger gesture …
pick Copy -> Copy outerHTML … so that …
your Event Calendar for your Events in Month choice is in a text buffer … ready for you to …
Paste into a Text Editor that Events in Month webpage to store (perhaps in a MAMP local Apache/PHP/mySql web server environment, where you can further look at and develop your own ideas)
The user is told when the switch to “New Window” compromise becomes active, decided upon by reconstructing the proposed address bar URL regularly and when too long …
function formanalyze() {
var fio=document.getElementsByTagName('form')[0];
var delm='?';
var fioih=fio.innerHTML;
var fions=fioih.split(' name="');
var testurl=documentURL.split('?')[0].split('#')[0];
for (var ijk=1; ijk<fions.length; ijk++) {
testurl+=delm + fions[ijk].split('"')[0] + '=' + encodeURIComponent(document.getElementById(fions[ijk].split('"')[0]).value);
delm='&';
}
setTimeout(formanalyze, 3000);
if (eval('' + testurl.length) >= 750) {
if (document.getElementById('remember')) { document.getElementById('remember').value='New window'; }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value='New window'; }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value='New window'; }
} else {
if (document.getElementById('remember')) { document.getElementById('remember').value=document.getElementById('remember').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value=document.getElementById('rememberme').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value=document.getElementById('remembermoi').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
}
return eval('' + testurl.length);
}
… the form submit buttons are reworded accordingly.
Another idea from this blog thread’s inspiration …
… we’ve now addressed in today’s “second draft” is allowing for an optional bold Event Day Blurb Title, available to the user via a new dropdown “Bold Title” option.
And, how can we do more with colour, to help the right bits stand out, and be consistent? We thought …
text shadow means by which the text of Event Calendar can be more impactive …
<div style="text-shadow:-1px 1px 1px #ff2d95;" id=eventcalendar></div>
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 …
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 ''; }
Because the theme of our current Editable Calendar web application revolves around time stamps and day names and month names regarding yesterday’s Editable Calendar Google Translate Tutorial that means, regarding language internationalization ideas …
as well as yesterday’s Google Translate ideas … also available is …
Yesterday’s Editable Calendar Primer Tutorial‘s start to our Editable Calendar project was a very anglo-centric exercise. Today, we want to use the great …
… to help translate our inhouse burgeoning Editable Calendar skeletal contents to some non English languages.
Why the skeletal here? Well, your own entries made before you select a dropdown non English language choice are stripped out in this changedsecond draftEditable Calendar you can try below, because we’re using the Google Translate “static URL” approach to the translations. But we will examine, down the track, if we can do better?! Again, stay tuned for more progression and internationalization over the days on this Editable Calendar project.
we’re channelling how in emails “word strings” starting with “http” become links … and so …
in our event in month “blurb” textarea elements we allow user highlighted text containing such “http” “word strings” be opened in popup windows showing the content of those URLs, as available
Here is the relevant Javascript we ended up with, for this …
Just briefly, delved into the wooooorrrrllllldddd of days of the week before 1582 debate … you had to be there … and in the words of Lleyton … Come on!!!! And we came out the other side. Good times! Anyway, thanks for all the interesting discussion, which we recommend you start at with this gem. Anyway, we now allow dates after 1582 (after this was previously set at 1970) in all respects and dates between 0000 and 1581 only via tweaks to the address bar URL you do yourself and we just hide the day of the week string. Otherwise … this could be needed?!
When doing our inhouse testing for Event Calendar Collaboration Tutorial the other day, it got us “peeved”, shall we say. We wanted a mechanism, with those “a” link “mailto:” emailing arrangements, of not having to fill out the email address in the “To:” field each time. First world problem alert! Still and all …
When it comes to procedures …
Aaaaaarrrrgggghhhh …
Nuances count … regarding …
Errrrrrr …
Saving time …
Saving frustration
… resulting in the “easy to remember” acronym WANESS … we rest our cases!
What can help here? Well, it is a personalization … so … anyone, anyone? Yes, Lou, back from holidays, a month late … yes, well, okay … we can see you’ve put some thought into this … HTTP Cookies could be used. Yes, Shwetank, you’ve had your hand up some time now. We agree, Web Storage window.localStorage allows for more data, so we’ll go with that, though either style of approach would work here.
Global variables initialization …
var defemail='', defsms='';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
Within document.body onload event logic …
if (document.getElementById('semail') && document.getElementById('ssms')) {
document.getElementById('semail').oncontextmenu=function(){ emailaskit(); };
document.getElementById('semail').ontouchmove=function(){ emailaskit(); };
document.getElementById('ssms').oncontextmenu=function(){ smsaskit(); };
document.getElementById('ssms').ontouchmove=function(){ smsaskit(); };
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
document.getElementById('semail').title+=' Move gesture here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Move gesture here can ask for new default remembered SMS number for collaboration purposes';
} else {
document.getElementById('semail').title+=' Right click here can ask for new default remembered email address for collaboration purposes';
document.getElementById('ssms').title+=' Right click here can ask for new default remembered SMS number for collaboration purposes';
}
}
Calling these two Javascript function helpers …
function emailaskit() {
if (defemail == defemail.trim()) {
defemail=defemail.trim() + ' ';
var emailm=prompt('Enter default email address.', defemail.trim());
if (emailm == null) { emailm=''; }
if (emailm.trim() != '' && emailm.trim().indexOf('@') != -1) {
defemail=emailm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', emailm.trim());
}
}
defemail=defemail.trim() + ' ';
}
function smsaskit() {
if (defsms == defsms.trim()) {
defsms=defsms.trim() + ' ';
var smsm=prompt('Enter default SMS number.', defsms.trim());
if (smsm == null) { smsm=''; }
if (smsm.trim() != '' && smsm.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
defsms=smsm.trim() + ' ';
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', smsm.trim());
}
}
defsms=defsms.trim() + ' ';
}
And allow control, as well, at the SMS prompt window logic …
function dosms() {
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defemail=window.localStorage.getItem('eventcollaboratoremailee');
}
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
defsms=window.localStorage.removeItem('eventcollaboratorsmsno');
}
//alert('' + eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length));
if (eval('' + ('sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()))).length) >= 18000) {
snum=('' + prompt('Please enter SMS number to send to. We suspect message is too long for an SMS and if you enter an email address here instead, we will try to send an email instead. Append space(s) to remember, whatever you enter, for next time.', snum)).replace(/^null/g, (defemail.indexOf('@') != -1 ? defemail : (defsms != '' ? defsms : '')) );
} else {
snum=('' + prompt('Please enter SMS number to send to. Append space(s) to remember for next time.', snum)).replace(/^null/g, (defsms != '' ? defsms : (defemail.indexOf('@') != -1 ? defemail : '')));
}
if (snum == null) { snum=''; }
if (snum.indexOf('@') != -1) {
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratoremailee')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratoremailee');
}
window.localStorage.setItem('eventcollaboratoremailee', snum);
defemail=snum;
}
return doemail(snum);
} else if (snum.trim() != '' && snum.trim().replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').trim() == '') {
//alert('Snum=' + snum + '?');
if (snum.trim() != snum) {
snum=snum.trim();
if (('' + window.localStorage.getItem('eventcollaboratorsmsno')).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
window.localStorage.removeItem('eventcollaboratorsmsno');
}
window.localStorage.setItem('eventcollaboratorsmsno', snum);
defsms=snum;
}
var azx=top.document.getElementById('xas' + 'ms');
if (azx == null) { azx=top.document.createElement("a"); }
//if (1 == 1) {
// document.getElementById('divas').appendChild(azx);
//} else {
top.document.body.appendChild(azx);
// }
azx.id = 'xas' + 'ms';
azx.target = "_top";
azx.style = "display: none";
azx.href = 'sms:' + snum + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#bih=' + encodeURIComponent(parent.hfanalyze()));
azx.click();
}
return '';
}
Also, today, we battled the logic to allow the textarea element onblur events also open the door to emailing and SMS “work in progress”. Believe it or not, this timing change was quite difficult in the changedevents_in_month.htm parent of the Events in Month web application. Never a dull moment in web application I.T. we’d say!
it did not have a fully fleshed out collaboration or sharing set of functionalities … at the time, probably, because …
each Monthly calendar filled out, and wanting to be saved, could involve much more than the 850 characters available to previous “mailto:” or “sms:” communication conduits, back to when we first tackled this project … but now …
hashtagging parts to the “mailto:” URLs (and maybe sometimes the “sms:” URL) might cover the data length needs
… so that this Event Calendar could be a web application at the center of a collaboration network of people working on that event organization. Much more useful, we figure!
Timing became really important with this integration of …
email
SMS
… communication conduit possibilities. With its design we have to wait until the point where the user is filling in textarea elements regarding a designated …
Month
Year
… of relevance, before we allow the email 📧 and SMS 📟 emoji buttons be shown. In the code …
Amended HTML h1 element static HTML to add, later shown, perhaps, email 📧 and SMS 📟 emoji buttons …
<h1>Events in Month <button style=display:none; title='Share via Email' id=semail onclick="doemail('');">📧</button> <button style=display:none; title='Share via SMS' id=ssms onclick=dosms();>📟</button> </h1>
New static HTML div element placed to the bottom of the body element …
<div id=divas></div>
New Javascript global variables (picking up hashtagging parts of the address bar URL, perhaps linked off an email or SMS link clicked) …
Client meets server today, allowing the PHP data storage talents in yesterday’s Event Calendar PHP Tutorial‘s work to meet a “clientside” way to …
Record to Remember via Bookmark
… use the web browser Bookmarks to help you recall an Events in Month report with long entries.
Involving a Bookmark still needs those “get” ? and & arguments, and we allow the PHP to lookup for us the data underscoring an address bar URL such as …
… that mapping being possible, now, making use of a pseudo hashtag arrangement … your Clayton‘s hashtag, if you will!
To start to use a hashtag suits, as your hashtag navigation only makes sense in the “clientside” woooorrrrrllllddd, and even there, really using one only tries to position a webpage where an element with an ID matching the hashtag sits (and we are never going to have this ID element in our work), and in the meantime we’ve passed across from the child PHP to the parent HTML a valuable piece of information helping the link to the Bookmark system be possible. The Javascript codeline (you may have noticed) …
var documentURL=document.URL;
… as stupid and simple looking as it is, is crucial for us. We get child webpage parts (like our PHP) to change document.URL to a far too long in normal circumstances address bar URL the rest of the code feeds off. It’s just that now, that far too long in normal circumstances address bar URL has a #[hashtag] appended such as …
#August__2023_00000__1
… uniquifying a Month, Year Events in Month identifier part with a version of the user’s IP address (so that they only see what is relevant to them).
Address bar URLs such as “https://www.rjmprogramming.com.au/HTMLCSS/events_in_month.php?exactlabel=August__2023_00000__1” are Bookmarkable, and so we allow for similar outcomes with less concern about how much data is being “recorded” and recallable (via that web browser’s Bookmark system).
Also, today, a lot of CSS tweaks, so that the CSS styling now looks like …
… form submit button (toggling) value to start involving PHP with those longer datasets of Event in Month descriptions, in our most recent project. What do we use as the data conduit? No, not a database. No, not a serverside flat file. No, not clientside window.localStorage nor window.sessionStorage nor HTTP Cookies. We store long Event in Month description data in our new events_in_month.php PHP itself. And this same PHP can populate options in a new dropdown element in the parent to facilitate the recalling of any relevant “Record to Remember” recordings.
The PHP is kind of short, so we will show it below, including one MAMP example of that “self storage” …
<?php
// events_in_month.php
// RJM Programming
// August, 2023
// Help out events_in_month.htm
But, there’s an inherent weakness with the design, we’ll go into more into the future.
… well … it’s a perennial for us, regarding how if you stick with clientside thinking, only, web applications, when the amount of data to remember starts adding up, the “get arguments approach” ( ie. use ? and & arguments at the address bar ) is restricted by length restrictions regarding URL lengths.
Rather than jump to PHP serverside ideas just yet, we wanted to show some more ideas, staying with “clientside only thinking”, today, as well as improving the UX (user experience) and small steps forward regarding styling.
Okay then, regarding the idea to remember an Event in Month form, when there is a lot of data, and staying “just clientside”, we’ve coded for a “New Window” idea, albeit not as memorable as the default “Remember in Bookmark” possible for your smaller datasets. However, in saying that, we found that within this new window, with our Google Chrome web browser, we could …
bring up Context Menu with a right click or two finger gesture within the popup window webpage content …
pick Inspect option …
be in Elements tab of your Web Inspector … and …
highlight top <html> tag …
Context Menu with a right click or two finger gesture …
pick Copy -> Copy outerHTML … so that …
your Event Calendar for your Events in Month choice is in a text buffer … ready for you to …
Paste into a Text Editor that Events in Month webpage to store (perhaps in a MAMP local Apache/PHP/mySql web server environment, where you can further look at and develop your own ideas)
The user is told when the switch to “New Window” compromise becomes active, decided upon by reconstructing the proposed address bar URL regularly and when too long …
function formanalyze() {
var fio=document.getElementsByTagName('form')[0];
var delm='?';
var fioih=fio.innerHTML;
var fions=fioih.split(' name="');
var testurl=documentURL.split('?')[0].split('#')[0];
for (var ijk=1; ijk<fions.length; ijk++) {
testurl+=delm + fions[ijk].split('"')[0] + '=' + encodeURIComponent(document.getElementById(fions[ijk].split('"')[0]).value);
delm='&';
}
setTimeout(formanalyze, 3000);
if (eval('' + testurl.length) >= 750) {
if (document.getElementById('remember')) { document.getElementById('remember').value='New window'; }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value='New window'; }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value='New window'; }
} else {
if (document.getElementById('remember')) { document.getElementById('remember').value=document.getElementById('remember').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('rememberme')) { document.getElementById('rememberme').value=document.getElementById('rememberme').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
if (document.getElementById('remembermoi')) { document.getElementById('remembermoi').value=document.getElementById('remembermoi').value.replace(/^Remember$/g, 'Remember via Bookmark'); }
}
return eval('' + testurl.length);
}
… the form submit buttons are reworded accordingly.
Another idea from this blog thread’s inspiration …
… we’ve now addressed in today’s “second draft” is allowing for an optional bold Event Day Blurb Title, available to the user via a new dropdown “Bold Title” option.
And, how can we do more with colour, to help the right bits stand out, and be consistent? We thought …
text shadow means by which the text of Event Calendar can be more impactive …
<div style="text-shadow:-1px 1px 1px #ff2d95;" id=eventcalendar></div>