Animated GIF Slide AlmaLinux Ffmpeg Video Tutorial

Animated GIF Slide AlmaLinux Ffmpeg Video Tutorial

Animated GIF Slide AlmaLinux Ffmpeg Video Tutorial

Further to yesterday’s Animated GIF Slide GIFEncoder AlmaLinux Tweaks Tutorial‘s inhouse Animated GIF Creator web application improvements, today we channel how with going from …

  • CentOS Apache PHP version starting with a 5 … to …
  • AlmaLinux Apache PHP version starting with an 8

… recently, we got the opportunity to install the great ffmpeg on our AlmaLinux web server, you might recall when we presented Ffmpeg Install and Public Face Tutorial, which means we can now offer Video creation … via …

<?php

if (strpos($_SERVER['SERVER_NAME'], 'rjmprogramming.com.au') !== false) {
if (!isset($_POST['video']) && isset($_POST['slideshow'])) {
$_POST['video']='y';
} else if (!isset($_GET['video']) && isset($_GET['slideshow'])) {
$_GET['video']='y';
}
}

?>

… alongside Animated GIF creation with this web application, when it is performed on our AlmaLinux web server in the video enabled PHP tutorial_to_animated_gif.php inhouse animated GIF (and now video) creator web application.


Previous relevant Animated GIF Slide GIFEncoder AlmaLinux Tweaks Tutorial is shown below.

Animated GIF Slide GIFEncoder AlmaLinux Tweaks Tutorial

Animated GIF Slide GIFEncoder AlmaLinux Tweaks Tutorial

Around here, we’re so used to using PHP local web server Apache/PHP/MySql MAMP (for PHP version starting with a 7) for our Animated GIF creations, and we recommend the (downloading PHP code to a) local web server approach here (but read on), that we forgot to suss out whether there were any issues with the brilliant László Zsidi GIFEncoder.class.php PHP class making it all happen.

Discombobulated we were to find there were issues going from …

  • CentOS Apache PHP version starting with a 5 … to …
  • AlmaLinux Apache PHP version starting with an 8

The major issue was that …

  • curly brace PHP syntax, in a lot of data array index and string offset related guises, is deprecated in PHP8 … but still okay in PHP7 … (thanks to this great link for advice)
  • class constructors cannot use the Class name any more, but rather use __constructor as the function name in the PHP code (thanks to this great link for advice)

And so we feel obligated to share with you better for PHP8 GIFEncoder.class.php to go along with a curly brace tweaked PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application you should have more success with, unless there is too much data, hosted on the RJM Programming domain.


Previous relevant Animated GIF Slide Extraction Applied CSS Styling Tutorial is shown below.

Animated GIF Slide Extraction Applied CSS Styling Tutorial

Animated GIF Slide Extraction Applied CSS Styling Tutorial

We dedicate today’s blog posting to the English phrase (that maybe works in other languages) …

Same, same but different

… as it is about the pros and cons of HTML iframe integration, especially as it applies to CSS styling. Off the top of our heads we see a Pros and Cons table looking like …

Pros and Cons of HTML Iframe Based Web Application Software Integration
Pros Cons
Become tools Difficulty with styling integration especially regarding time of coding differences
Become modularised Focus within iframe can cause problems
Ability to begin again at (0,0) regarding positioning Hashtag navigation within iframe can cause problems
Sharing the coding and execution load
Software organizational advantages
Can glean information off parent and vice versa
New chance for synchronizations
Multitasking
Coding language mixing
Parent child interactions

… and, as you can see, we are mainly fans of what it can bring to the table (mild chuckle, followed by a chortle).

But that first Con can grate, that “Difficulty with styling integration especially regarding time of coding differences”, and today, we thought we’d “apply” to relevant (there was one we found we should not “apply” the thinking to) HTML iframe “child” styling using yesterday’s Animated GIF Slide Extraction CSS Styling Tutorial‘s CSS styling idea in the “parent” (“applied” to these children).

We used a “suck it and see” approach whereby we just, where applicable, appended the CSS <style></style> styling logic of yesterday (plus a bit) to the document.body “body” innerHTML attribute of the iframe called, to see whether it felt more integrated. And we thought it did, perhaps because that styling was one of the more generic feeling ones we can remember (by that we’re meaning that the selectors were often just HTML tag names rather than too much “class” or “id” aspects to those selectors). Also, sometimes it won’t work because adding to the document.body innerHTML can sometimes “muck up” logic (but not today).

And what allows for “deploying” such an idea? Inhouse, we call what we do here “Client Pre-emptive Iframe” ideas, where the relevant iframe element’s “onload” (or on rare occasions, “onerror”) events are used to add logic at a slightly later time to any HTML iframe document.body element’s “onload” logic would be applied. This is a powerful mechanism open to you if you are dealing with same domain parent/child URLs, that is the case for us with this work today.

It’s as easy to do as (showing you one iframe “onload” function example below, and with inline CSS usage, rather than an external CSS file usage (where it would be even easier)) …


var paconto=null;

function pcheckit(iois) {
paconto = (iois.contentWindow || iois.contentDocument);
if (paconto != null) {
if (paconto.document) { paconto = paconto.document; }
if (paconto.body != null) {
setTimeout(function(){
if (document.getElementById('pmyifthree')) {
document.getElementById('pmyifthree').scrolling='no';
}
document.getElementById('myifthree').scrolling='no';
paconto.body.innerHTML+='<st' + 'yle> ' + document.head.innerHTML.split('<st' + 'yle>')[1].split('</st' + 'yle>')[0] + ' </st' + 'yle>';
paconto.getElementsByTagName('select')[0].style.display='none';
paconto.getElementById('image').style.display='none';
paconto.getElementById('isub').style.display='none';
paconto.getElementsByTagName('div')[0].style.opacity='0.0';
paconto.getElementsByTagName('select')[1].style.display='none';
paconto.getElementsByTagName('h1')[0].style.opacity='0.0';
if (1 == 1) { paconto.getElementsByTagName('h4')[0].style.opacity='0.0'; }
if (1 == 1) { paconto.getElementsByTagName('h3')[0].style.opacity='0.0'; }
}, 12000);
}
}
}

… to make this idea come, above. We don’t go overboard with precise integration, that is not our point. Just a …

Same, same but different

… feel in the changed tenth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version, or now, the Animated GIF Slide Extraction via User Interaction web application hashtag speed test version), which you can try below.


Previous relevant Animated GIF Slide Extraction CSS Styling Tutorial is shown below.

Animated GIF Slide Extraction CSS Styling Tutorial

Animated GIF Slide Extraction CSS Styling Tutorial

Another aesthetic plus on top of …

… which we flesh out more of today, further to yesterday’s Animated GIF Slide Extraction Speed Test Tutorial.

What was new to us with today’s work? The linear gradient effect (called text gradient) applied to text was new, thanks, in amongst …

<style>

#agmode { background-color: #98FB98; }
#agmodetwo { background-color: #AFEEEE; }

hr {
border: 5px solid green;
border-radius: 5px;
}

hr.one {
border: 5px solid red;
border-radius: 5px;
}

hr.two {
border: 5px solid orange;
border-radius: 5px;
}

hr.three {
border: 5px solid green;
border-radius: 5px;
}

body {
background: linear-gradient(to right, rgba(173,216,230,0.5) 0%, rgba(255,255,127,0.5) 100%);
}

img {
background: linear-gradient(to right, transparent 0%, transparent 100%);
border-radius: 9px;
}

h3 {
text-shadow: -1px 1px 1px #952dff;
}

input {
text-shadow: -0.4px 0.4px 0.4px #2d952d;
border-radius: 200px;
}

input::placeholder {
text-shadow: -1px 1px 1px #2d95ff;
}

summary {
text-shadow: -1px 1px 1px #ff952d;
}

h1 {
/* font-size: 72px; */
background: -webkit-linear-gradient(rgb(188, 12, 241), rgb(212, 64, 104), rgb(104, 212, 64));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}


iframe {
border-radius: 9px;
}

a {
border-radius: 9px;
}

</style>

… in the changed ninth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version, or now, the Animated GIF Slide Extraction via User Interaction web application hashtag speed test version), which you can try below.


Previous relevant Animated GIF Slide Extraction Speed Test Tutorial is shown below.

Animated GIF Slide Extraction Speed Test Tutorial

Animated GIF Slide Extraction Speed Test Tutorial

Yesterday’s Animated GIF Slide Extraction User Experience Tutorial sparked our interest in that …

  • we wondered whether hashtag components appended to ($_GET) address bar URLs perhaps consisting of ? and & argument parts slowed things down … and after first considering some standalone arrangement …
  • we realized we have quite good conditions with our current Animated GIF Extraction web application project predilections to adapt it

Getting into the coding of this we realized we were touching on another unknown to us. Is a hashtag call such as …


./agtoslides.php?slidenumber=1&random=56476858765876&delay=400&title=%2E%2Fuser_of_ss.gif&numfillin=3#agname=%2E%2Fuser_of_ss.gif

… to PHP going to register the hashtagging? Well, certainly not with PHP functionality but a client facing document.body onload event logic can see it …

<?php

// agtoslides.php
// RJM Programming
// May, 2024
// Animated GIF to a slide via ... ksh agtoslides.ksh [animatedGIFfilename] [slideNumber]
ini_set('max_execution_time', 60000);

$outp='';
$infl='';
$infill='';
$preoutp='';
$postoutp='';

if (file_exists('/tmp/agtoslides')) {
if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh')) {
if (isset($argc) && !isset($_GET['agname']) && !isset($_POST['agname'])) {
$infl=str_replace('+',' ',$argv[1]);
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($argv[1]));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
} else if (!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
}
if ($argc > 2) {
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($argv[2]))) . ' ' . $infill;
} else {
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else {
if (isset($_GET['random']) && !isset($_GET['agname'])) {
echo "<html>
<head>
<scrip" . "t type=text/javascript>
var jjjxhr=null, jjjform=null, astr='', stats=0;

function joneslidedu() {
if (jjjxhr.readyState == 4) {
if (jjjxhr.status == 200) {
parent.window.opener.timingshashpush((new Date()).getTime()); // document.body.innerHTML=jjjxhr.responseText.split(jjjxhr.responseText.substring(1).split('>')[0])[1].split('</body>')[0];
stats=jjjxhr.status;
}
}
}

function ajaxit() {
if (1 == 1) {
parent.setstats(1);
jjjform = new FormData();
jjjxhr = new XMLHttpRequest();
jjjform.append('agname', decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]));
jjjform.append('random', decodeURIComponent('" . $_GET['random'] . "'));
jjjform.append('slidenumber', decodeURIComponent('" . $_GET['slidenumber'] . "'));
jjjxhr.open('post', './agtoslides.php', true);
jjjxhr.onreadystatechange = joneslidedu;
jjjxhr.send(jjjform);
if (parent.window.opener.setstats) {
parent.window.opener.setstats(1);
}
parent.window.opener.document.getElementById('spareagname').value=decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]);
//alert(parent.window.opener.document.getElementById('sparemyform').outerHTML.length);
if (eval('' + parent.window.opener.document.getElementById('sparemyform').outerHTML.length) < 1000) {
parent.window.opener.document.getElementById('sparemyform').method='GET';
} else {
parent.window.opener.document.getElementById('sparemyform').method='POST';
}
parent.window.opener.document.getElementById('sparemyform').action=('' + parent.document.getElementById('sparemyform').action).split('#')[0];
parent.window.opener.document.getElementById('sparemysub').click();
if (1 == 11) {
//parent.getto().document.title='yes';
while (('' + parent.getto().getstats()) != '200') {
if (astr == '' || eval('' + astr.length) > 800) {
astr=' ';
} else {
astr+=' ';
}
}
}
} else {
jjjform = new FormData();
jjjxhr = new XMLHttpRequest();
jjjform.append('agname', decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]));
jjjform.append('random', decodeURIComponent('" . $_GET['random'] . "'));
jjjform.append('slidenumber', decodeURIComponent('" . $_GET['slidenumber'] . "'));
jjjxhr.open('post', './agtoslides.php', true);
jjjxhr.onreadystatechange = joneslidedu;
jjjxhr.send(jjjform);
while (stats != 200) {
if (astr == '' || eval('' + astr.length) > 800) {
astr=' ';
} else {
astr+=' ';
}
}
}
return true;
}

</scr" . "ipt>
</head>
<body onload='return ajaxit();' id=xbody></body></html>
";
exit;
}
if (isset($_GET['agname'])) {
if (isset($_GET['random'])) {
$infill=trim(str_replace('+',' ',urldecode($_GET['random']))) . ' tidyhere';
}
$infl=str_replace(' ','+',urldecode($_GET['agname']));
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($_GET['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
} else if (strpos($infl, $_SERVER['SERVER_NAME']) === false && strpos($infl, 'http') !== false) {
$infl=str_replace(' ','+',urldecode($_GET['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), file_get_contents(str_replace('https:','http:',$infl)) );
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
}
if ((!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) && strpos($infl, 'data:image/') === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
}
if (isset($_GET['slidenumber'])) {
//echo 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber']));
//exit;
//file_put_contents('xget.xxx', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
//echo ' --- ' . $outp;
//exit;
} else {
//file_put_contents('xget.zzz', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else if (isset($_POST['agname'])) {
if (isset($_POST['random'])) {
$infill=trim(str_replace('+',' ',urldecode($_POST['random']))) . ' tidyhere';
}
$infl=str_replace(' ','+',urldecode($_POST['agname']));
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($_POST['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
//if (strlen($infl) != 0) {
//file_put_contents('x.xx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
} else if (strpos($infl, $_SERVER['SERVER_NAME']) === false && strpos($infl, 'http') !== false) {
$infl=str_replace(' ','+',urldecode($_POST['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), file_get_contents(str_replace('https:','http:',$infl)) );
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
//if (strlen($infl) != 0) {
//file_put_contents('x.xxxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
// } else {
//file_put_contents('x.xxxxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
}
if ((!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) && strpos($infl, 'data:image/') === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
//if (strlen($infl) != 0) {
//file_put_contents('x.xxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
}
if (isset($_POST['slidenumber'])) {
//file_put_contents('xpost.xxx', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_POST['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_POST['slidenumber'])) . ' ' . $infill);
} else {
//file_put_contents('xpost.zzz', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
if (strpos($post, "agname=") !== false && strpos($post, "random=") !== false && strpos($post, "slidenumber=") !== false) {
$infill=explode('&', explode('random=', $post)[1])[0] . ' tidyhere';
$sn=explode('&', explode('slidenumber=', $post)[1])[0];
$infl=str_replace(' ','+',urldecode(explode('&', explode('agname=', $post)[1])[0]));
if (strpos($infl, 'data:image/') !== false) {
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
}
//file_put_contents('x.xxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . $sn . ' ' . $infill);
}
}
}
}
}
$inn=0;
$ij=0;
$otherstuff="";
if (isset($_GET['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_GET['delay'])) . '&';
}
if (isset($_POST['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_POST['delay'])) . '&';
}
if (isset($_GET['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_GET['title'])) . '&';
}
if (isset($_POST['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_POST['title'])) . '&';
}
if (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
$ij++;
$inn++;
}
}
$inn=0;
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
if ($postoutp == '') {
$postoutp='</body></html>';
$preoutp="<html><body onload=\" parent.agslideshow('slideshow','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
if ($postoutp != '') {
if ($inn > 0) {
$preoutp.=" parent.agslideshow('slideshow" . ('' . (1 + $inn)) . "','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
}
unlink('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png');
$inn++;
}
if ($postoutp != '') { $preoutp.=" parent.preagslideshow('/PHP/animegif/tutorial_to_animated_gif.php?" . $otherstuff . "numfillin=" . ('' . $ij) . "'); \">"; }
//file_put_contents('x.x', $preoutp . $outp . $postoutp);
echo $preoutp . $outp . $postoutp;
exit;

?>

… we found, to our relief! And though the synchronization is not exact, we simulate “apples for apples” via that Ajax asynchronicity timing for a hashtag call for the “window.open” window, versus the “window.opener” window non-hashtag call of that default animated GIF (like a splash page example) as you enter the web application.

Codewise we have …


Previous relevant Animated GIF Slide Extraction User Experience Tutorial is shown below.

Animated GIF Slide Extraction User Experience Tutorial

Animated GIF Slide Extraction User Experience Tutorial

We often equate the term “user experience” with “niceties”, in that we often find we deal with “user experience” issues well into a project, but you can put more effort into forward design planning so that you deal with it better throughout the project. We found with the Animated GIF Slide Extraction project of yesterday’s Animated GIF Creation Canvas Integration via Slide Extraction Tutorial that issues that had annoyed us for several days past, but which did not stop the web application working, turned into a day where we felt that we were improving the “user experience” by “fixing annoyances” and “adding niceties”, today. As you might imagine, this can be subjective, because just because we think an idea is an improvement does not mean every user out there will think so, and this is where time set aside for real users to try a product (ie. user acceptance testing) ahead of “going live” can be a great idea.

Anyway, there was …

  • an annoyance, on non-mobile, we first introduced when we integrated Animated GIF Creation in with Animated GIF Slide Extraction a couple of days ago … too much cursor:progress; usage … and in fixing we were astonished that cursor:wait; displays the same graphics … anyway, we think it helps when a cursor can help a user get used to identifying wherein the workflow they are situated at any given time …
    <?php echo ”

    function cursorcheck(defisidea) {
    if (window.parent) { if (parent.document.getElementById('cursorchoice')) { if (parent.document.getElementById('cursorchoice').value != '') { return parent.document.getElementById('cursorchoice').value; } } }
    return defisidea;
    }

    “; ?>
    … looking to parent …

    <input data-choice='' type=hidden value='help' id='cursorchoice'></input>
  • we felt better adding <hr> horizontal rule elements above and below the middle HTML iframe we set aside for client browsing functionality … and also …
  • made that iframe less wide enabling us to place to the right of it a hashtag navigational “a” link back up to the top …

    <hr>
    <iframe onload=pcheckit(this); style='display:inline-block;width:80%;height:160px;' id=myifthree src='/PHP/read_exif_off_image_rotate.php#itwo'></iframe> <a id=atotop style='display:inline-block;vertical-align:top;width:15%;text-shadow: -1px 1px 1px #952dff;' onclick="window.scrollTo(0,0);" href='#mydet'>&#11014; Top</a>
    <hr>

    … and …
  • given a background indicative of the goings on with the extracted animated GIF slide …

    function ob(tv) {
    if (tv == '' && intc != '') {
    tv=intc;
    document.getElementById('agname').value=intc;
    document.getElementById('mygimage').src=intc;
    document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    document.getElementById('atotop').style.backgroundSize='contain';
    document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    if (window.parent) {
    if (window.parent != window.self) {
    parent.document.getElementById('myta').setAttribute('data-img', document.getElementById('myta').getAttribute('data-img'));
    parent.document.getElementById('myta').title=document.getElementById('myta').title;
    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').src=intc;
    parent.document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    parent.document.getElementById('atotop').style.backgroundSize='contain';
    parent.document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').title='Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...';
    parent.document.getElementById('mysum').innerHTML=appbut('Animated GIF Slide Extraction Display ... RJM Programming - May, 2024 ... Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...');
    parent.document.getElementById('slidenumber').value='' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij));
    parent.unsetit();
    }
    }
    //tv=gifurl;
    ij=0;
    setTimeout(function(){ intc=''; }, 27000);
    }
    if (tv.trim() != '') {
    if (tv.indexOf('data') != 0 && tv.indexOf('//') != -1 && document.URL.indexOf('//') != -1) {
    if (tv.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'') != document.URL.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'')) {
    document.getElementById('myiffour').src='/getex.php?dodu=y&url=' + encodeURIComponent(tv); //window.open('/getex.php?dodu=y&url=' + encodeURIComponent(tv), '_blank');
    } else {
    prefetch(tv);
    }
    } else {
    prefetch(tv);
    }
    }
    }

    … and …
  • should the user click one (of the now two, and colour coded, as below) Animated GIF Creation action buttons now presented in our “reveal” details/summary the scrolling now lands

    function appittwo(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'rcmysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'rcmysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    function appit(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'mysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'mysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    … at the top of that middle iframe which is short enough so it and the Animated GIF Creation iframe are viewable on many platforms, those button presses created personalized animated GIFs there and then (at least on non-mobile), the user there to see that happening … where …
  • the user clicking the buttons up the top or down the bottom regarding Animate GIF Creation work for the two “submit” button modes can see which one was pressed via new border:5px dotted yellow; styling …
    <?php

    $indone="youllneverfindthis";
    $outdone="youllneverfindthis";


    if (isset($_POST['followthrough']) || isset($_GET['followthrough'])) {
    if (isset($_POST['followthrough'])) {
    if (strlen($_POST['followthrough']) > 0) {
    $indone='#' . $_POST['followthrough'] . " { ba";
    $outdone='#' . $_POST['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_POST['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_POST['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    } else if (isset($_GET['followthrough'])) {
    if (strlen($_GET['followthrough']) > 0) {
    $indone='#' . $_GET['followthrough'] . " { ba";
    $outdone='#' . $_GET['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_GET['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_GET['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    }
    }

    ?>
    applied

    <?php echo ”

    <style>
    input[type=submit]:active {
    border: 5px dotted yellow;
    }
    a { padding: 5px 5px 5px 5px; margin: 5px 5px 5px 5px; border: 1px solid red; background-color: #f0f0f0; }
    ::placeholder {
    font-size: 9px;
    }
    ::-webkit-input-placeholder { /* Chrome/Opera/Safari */
    font-size: 9px;
    }
    ::-moz-placeholder { /* Firefox 19+ */
    font-size: 9px;
    }
    :-ms-input-placeholder { /* IE 10+ */
    font-size: 9px;
    }
    :-moz-placeholder { /* Firefox 18- */
    font-size: 9px;
    }" . str_replace($indone, $outdone, "
    #mysubmit { background-color: #98FB98; }
    #rcmysubmit { background-color: #AFEEEE; }
    #overlayit { background-color: #FADADD; }
    #imsel { background-color: cyan; }
    #jmsel { background-color: magenta; }
    #watermarkmode { background-color: olive; }
    #selwhs { background-color: teal; }
    #sfilteris { background-color: lightgreen; } ") . "
    </style>

    “; ?>
    to the relevant bottom button

Codewise we have …


Previous relevant Animated GIF Creation Canvas Integration via Slide Extraction Tutorial is shown below.

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Thinking about yesterday’s Animated GIF Creation Data Limits via Slide Extraction Tutorial‘s progress …

What about if the user is happy to use those filled in animated GIF slide textboxes (with delay and title) to create a user created (and downloadable) animated GIF there and then?

Well, we know that user could click their own presented button, but we wanted to flag it up at the parent ahead of time too, in terms of clarity in the changed seventh draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below.

So, what’s all this got to do with an HTML canvas element (in case we have readers who take notice of the nuances of blog posting titles, that is)? Well, once you reach the stage with our inhouse Animated GIF Creator web application, where it has created your own animated GIF image, there is an “onclick” subsection of functionality that, in our new scenario, suffered from an error 404 (Bad Request) because the codeline ran as …

<?php echo ”

canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));

“; ?>

… but got that error because variable useyourwords contains an animated GIF “first slide” data-URI (useful in that a [canvasContext].drawImage() call of it would do what “drawImage” does with animated GIFs anyway (going back to the original point regarding this whole thread of blog postings)) which caused an overshoot of data size limits on conventional ($_GET style) address bar URLs (perhaps involving ? and & arguments (whether they be five minute or ten minute ones)). But regular readers will know, for a happy couple of months now, we recognize we do not always have to call into play serverside PHP and its $_POST mechanisms here, because we can also call on our life changing hashtagging (ie. #) (clientside approach for HTML/Javascript/CSS webpage) ideas now! Yay!!!!! And so, it came to pass, that … yes … there was light on yonder hilland vale … whatever that is … as “we broke bread” … shall we say … let’s … with some new hashtagging code in the changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application

<?php echo ”

if (eval('' + ('' + '/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords).length) <= 800) {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
} else {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords.replace('&','#'), '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
}


“; ?>

… as above and with the changed user_of_signature_signature.htm User of Signature Signature inhouse canvas graphic data web application “canvas hoster” …


var thewords=(location.search + location.hash).split('thewords=')[1] ? decodeURIComponent((location.search + location.hash).split('thewords=')[1].split('&')[0]) : "";
if (thewords.indexOf('data') == 0) { thewords=thewords.replace(/\ /g,'+'); }

… to bring “canvas integration” into the mix.


Previous relevant Animated GIF Creation Data Limits via Slide Extraction Tutorial is shown below.

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Even PHP’s $_POST[] approach to HTML form navigation data sharing has it’s limits, and that can be challenged when considering a whole set of data-URI defined animated GIF slide images.

But, behind the scenes, when $_POST[] does not get filled out with regard to the data limits of the Apache/PHP/MySql (in our case) web server involved, there is still php://input

PHP provides a number of miscellaneous I/O streams that allow access to PHP’s own input and output streams, the standard input, output and error file descriptors, in-memory and disk-backed temporary file streams, and filters that can manipulate other file resources as they are read from and written to.

php://stdin, php://stdout and php://stderr ¶
php://stdin, php://stdout and php://stderr allow direct access to the corresponding input or output stream of the PHP process. The stream references a duplicate file descriptor, so if you open php://stdin and later close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected. It is recommended that you simply use the constants STDIN, STDOUT and STDERR instead of manually opening streams using these wrappers.

php://stdin is read-only, whereas php://stdout and php://stderr are write-only.

… we can turn to (thanks, PHP), that can save the day in a lot of these scenarios.

The thing is, which our parent HTML and Javascript can help with, we want to be flagging the scenario where we should be checking that php://input usage might be coming into play. Well, even for an HTML form method=POST action=[ourRelevantPHP] scenario, the PHP global $_SERVER[‘QUERY_STRING’] is honoured, shall we say (separate to any $_GET[] ideas, is what we are getting at here). So we can, at the client HTML and Javascript parent (and client) end, set a unique $_SERVER[‘QUERY_STRING’] condition to test for in a changed sixth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below, nuancing yesterday’s Animated GIF Creation Interfacing via Slide Extraction Tutorial


<form id=agf style=display:none; method=POST data-target=ifconto action='/PHP/animegif/tutorial_to_animated_gif.php?theword=numfillin'>
</form>

… and then, up at that “[ourRelevantPHP]” changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application we can test as per

<?php

if (strpos(('' . $_SERVER['QUERY_STRING']), '=numfillin') !== false && !isset($_POST['numfillin']) && !isset($_GET['numfillin'])) {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
$prefdelim='?';
$pairings=[];
//file_put_contents('yes.yes', substr($post,0,300));
if (strpos($post, '=') !== false && strpos($post, '?') === false) {
$pairings=explode('=', ('?' . $post));
} else if (strpos($post, '=') !== false) {
$pairings=explode('=', ('' . $post));
}
if (strpos($post, '=') !== false) { // && strpos($post, '?') !== false) {
$post='';
//file_put_contents('yesagain.yes', '' . sizeof($pairings));
for ($ipairings=1; $ipairings<sizeof($pairings); $ipairings++) {
$thisval=explode('&', $pairings[$ipairings])[0];
$thisname=explode($prefdelim, $pairings[-1 + $ipairings])[1];
if (strpos(('~' . $thisval), '~data') !== false) {
$_POST[$thisname]=$thisval;
} else {
$_POST[$thisname]=$thisval;
}
if (strpos($thisname, 'slideshow') !== false) {
//file_put_contents('yes_yet_again.yes', '' . $thisname . ' ' . strlen($thisval));
}
//file_put_contents('yes_again.yes', '' . $thisname . ' ' . strlen($thisval));
$prefdelim='&';
}
$pairings=[];
}
}
$post='';

if (isset($_GET['numfillin'])) { $numfillin=$_GET['numfillin']; }
if (isset($_POST['numfillin'])) { $numfillin=$_POST['numfillin']; }

$nonplus=' ';
$theplus='+';
if ($numfillin >= 2) {
if (isset($_GET['numfillin'])) {
$numfillin=$_GET['numfillin'];
if (isset($_GET['slideshow'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_GET['slideshow']));
}
$nonplus=' ';
$theplus='+';
if (isset($_GET['slideshow2'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
} else if (isset($_POST['numfillin'])) {
$numfillin=$_POST['numfillin'];
if (isset($_POST['slideshow'])) {
//file_put_contents('yes_slideshow_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_POST['slideshow']));
}
if (isset($_POST['slideshow2'])) {
//file_put_contents('yes_slideshow2_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
}
$nonplus=' ';
$theplus='+';
for ($ijh=3; $ijh<=$numfillin; $ijh++) {
$pretwopattern='<div id="fdiv' . $ijh . '">';
if (isset($_GET['slideshow' . $ijh])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else if (isset($_POST['slideshow' . $ijh])) {
//file_put_contents('yes_slideshow' . $ijh . '_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else {
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
$nonplus=' ';
$theplus='+';
if ($ijh == $numfillin) {
$ijh++;
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
}
}

?>

… to cater for more scenarios, we’re hoping!


Previous relevant Animated GIF Creation Interfacing via Slide Extraction Tutorial is shown below.

Animated GIF Creation Interfacing via Slide Extraction Tutorial

Animated GIF Creation Interfacing via Slide Extraction Tutorial

The work of today combines …

… to add the chance for a user to use what ImageMagick produces as an Animated GIF slide and fill this out into the textboxes of the Animated GIF Creator “child” iframe hosted incarnation “quietly” filled out probably “below the fold”, but scrollable toable.

There are data limits to what the Animated GIF Creator can handle, but perhaps it can help a user create their own Animated GIFs, for their own purposes, via other sources.

Sources for courses

… we’d say. But we would say that, wouldn’t we?!

To make this happen, amongst the …

  1. PHP … and …
  2. Korn Shell

… helper components (to get to ImageMagick) we swap the “tidying up of interim files” role Korn Shell used to do, quite successfully (and still does for any interim “whole Animated GIF” files created), passing the responsibilities to the PHP to do (via passing over to the Korn Shell a new extra argument, to tell it this is the new arrangement). And at the changed third draft agtoslides.php PHP (working with the changed third draft agtoslides.ksh), before the “outputting command line” is executed, a whole lot of “child asks stuff of the parent” “programming talk and action” happens (and works, because our Client Pre-emptive Iframe Onload Event logic looks for that iframe document’s document.body.innerHTML as the representation of the extracted slide (of the animated GIF) of interest) …

<?php

$preoutp='';
$postoutp='';

$inn=0;
$ij=0;
$otherstuff="";
if (isset($_GET['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_GET['delay'])) . '&';
}
if (isset($_POST['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_POST['delay'])) . '&';
}
if (isset($_GET['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_GET['title'])) . '&';
}
if (isset($_POST['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_POST['title'])) . '&';
}
if (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
$ij++;
$inn++;
}
}
$inn=0;
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
if ($postoutp == '') {
$postoutp='</body></html>';
$preoutp="<html><body onload=\" parent.agslideshow('slideshow','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
if ($postoutp != '') {
if ($inn > 0) {
$preoutp.=" parent.agslideshow('slideshow" . ('' . (1 + $inn)) . "','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
}
unlink('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png');
$inn++;
}
if ($postoutp != '') { $preoutp.=" parent.preagslideshow('/PHP/animegif/tutorial_to_animated_gif.php?" . $otherstuff . "numfillin=" . ('' . $ij) . "'); \">"; }
//file_put_contents('x.x', $preoutp . $outp . $postoutp);
echo $preoutp . $outp . $postoutp;
exit;

?>

… to have the new parent Javascript functions …


function preagslideshow(theurl) {
if (theurl.indexOf('delay=') != -1) {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=delay value="' + decodeURIComponent(theurl.split('delay=')[1].split('&')[0]) + '"></input>';
} else {
jjform.append('delay', decodeURIComponent(theurl.split('delay=')[1].split('&')[0]));
}
}
if (theurl.indexOf('title=') != -1) {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=title value="' + decodeURIComponent(theurl.split('title=')[1].split('&')[0]) + '"></input>';
} else {
jjform.append('title', decodeURIComponent(theurl.split('title=')[1].split('&')[0]));
}
}
if (theurl.indexOf('numfillin=') != -1) {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=numfillin value="' + decodeURIComponent(theurl.split('numfillin=')[1].split('&')[0]) + '"></input>';
} else {
jjform.append('numfillin', decodeURIComponent(theurl.split('numfillin=')[1].split('&')[0]));
}
}
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=submit style=display:none; id=mysubag value=Submit></input>';
//alert(document.getElementById('agf').outerHTML);
document.getElementById('mysubag').click();
} else {
jjxhr.onreadystatechange = twoslidedu;
//jjxhr.responseType = "Document";
jjxhr.open('post', theurl.split('?')[0], true);
//document.getElementById('ifconto').src=theurl;
}
}

function agslideshow(thename, thevalue) {
if (1 == 1) {
if (thename == 'slideshow') {
if (9 == 9) {
//alert(thevalue);
document.getElementById('agf').innerHTML='<input type=hidden name=slideshow value="' + thevalue + '"></input>';
} else {
jjform = new FormData();
jjxhr = new XMLHttpRequest();
jjform.append('slideshow', thevalue);
}
} else {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=' + thename + ' value="' + thevalue + '"></input>';
} else {
jjform.append(thename, thevalue);
}
}
} else {
agconto.getElementById(thename).value=thevalue;
}
}

… working with the new static HTML …


<form id=agf style=display:none; method=POST data-target=ifconto action='/PHP/animegif/tutorial_to_animated_gif.php'>
</form>

… be able to assist with this new Animated GIF Creator interfacing to happen for the user, should they be interested, in a changed fifth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below.


Previous relevant Animated GIF Slide Extraction Reveal Tutorial is shown below.

Animated GIF Slide Extraction Reveal Tutorial

Animated GIF Slide Extraction Reveal Tutorial

Around here, we’re not ashamed to simplify 90% of web design issues into two categories …

  1. an “overlay” issue … or …
  2. a “reveal” issue

… and today’s improvements, pitted against the progress up until yesterday’s Animated GIF Slide Extraction Absolute URL Tutorial, pitted these two “colossuses” (at least in our mind) against each other as concept ideas towards today’s work’s solution. Which wins? We opted for a “reveal” solution, where the initial position is “reveal”.

We could have “overlayed” but we went for the KISS (“keep it simple simpleton”) principle, where, what you see at the top of a webpage takes prominence for the user. The thing is, though, in this alternate input section, we are not fussed that it stays around, hence the details/summary “reveal” way a user can make it disappear at any given point in time.

Here’s the thing, though, a details/summary “reveal” pairing has that “summary” innerHTML content part that can remain, no matter what, as a status informer mechanism we’re hoping helps out the “formerly obtuse” web application ways of our Animated GIF Extraction web application, in a changed fourth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below.


Previous relevant Animated GIF Slide Extraction Absolute URL Tutorial is shown below.

Animated GIF Slide Extraction Absolute URL Tutorial

Animated GIF Slide Extraction Absolute URL Tutorial

The other user entry the user might do using the Animated GIF Slide Extraction web application of yesterday’s Animated GIF Slide Extraction Browsing Tutorial onto …

  • relative animated GIF URL (within the address bar domain of use or an absolute URL serving similar purposes) … and yesterday’s …
  • browsed for local animated GIF file of interest … is today’s …
  • absolute URL pointing to a domain not the same as the address bar domain of use

As you might guess this last option for the user may not work for a domain with very high security, but being as hotlinking images makes the Internet woooorrrrllllddd go around perhaps the user can try this underlying curl based logic out, to see with a changed third draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), try below.

You may have noticed in our first draft we were not concerned with two incarnations of the web application being executed at once. Back then, one might interfere with the next if interrupted during the serverside ImageMagick phase of creating the png slides off the input animated GIF. Recently, we have started using …


uniquifier

… based logic (but in non-SQL realms) for that ImageMagick work. By and large the internal use only interim file naming in this ImageMagick phase is 99.9999999% sure to be unique to your session, and so not interfering, or accidentally picking up, other sessional data. You might want to look out for a textbox named “random”, in the code, regarding how we make that happen …


user@Users-Air htdocs % fgrep -n "'random'" extract_ag_slide_huh_of.html
157: jjform.append('random', document.getElementById('random').value);
165: document.getElementById('myif').src='./agtoslides.php?agname=' + encodeURIComponent(document.getElementById('agname').value) + '&slidenumber=' + encodeURIComponent(document.getElementById('slidenumber').value) + '&random=' + encodeURIComponent(document.getElementById('random').value);
167: //window.open('//www.rjmprogramming.com.au/Mac/extract_ag_slide_huh_of.html?slide=' + encodeURIComponent(document.getElementById('slidenumber').value) + '&random=' + encodeURIComponent(document.getElementById('random').value) + '#url=' + encodeURIComponent(document.getElementById('agname').value), '_blank', 'top=10,left=10,width=600,height=600');
173: document.getElementById('random').value='' + Math.floor(Math.random() * 198786753);
293: document.getElementById('random').value='' + Math.floor(Math.random() * 198786753);
376:<body onload="document.getElementById('random').value='' + Math.floor(Math.random() * 19878675); setTimeout(askaway,8000); ob(gifurl);">
user@Users-Air htdocs %


Previous relevant Animated GIF Slide Extraction Browsing Tutorial is shown below.

Animated GIF Slide Extraction Browsing Tutorial

Animated GIF Slide Extraction Browsing Tutorial

As of the recent Animated GIF Slide Extraction Primer Tutorial‘s progress with an Extraction of a User Nominated Animated GIF Slide web application’s …

  • input animated GIF URL modus operandi … today we add …
  • local operating system file browsing method of user animated GIF entry

… approach to our web application’s functionality abilities in a changed second draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version) helped out, especially via PHP’s acceptance of HTML form method=POST data, by …

… or via arrangements below.


Previous relevant Animated GIF Slide Extraction Primer Tutorial is shown below.

Animated GIF Slide Extraction Primer Tutorial

Animated GIF Slide Extraction Primer Tutorial

Would you believe …

  • the extraction of an HTML video element still is not too hard using that HTML video element object as the first parameter to a [canvasContext].drawImage method call (as you might recall reading the recent Canvas DrawImage First Parameter Primer Tutorial) … whereas …
  • the extraction of an HTML animated GIF image (ie. img) element still is a lot harder, regarding only the clientside Javascript side of web applications because using that animated GIF img object as that first parameter to a [canvasContext].drawImage method call results only in the first still (or slide) of that animated GIF

? And so, to proceed with our “Animated GIF Slide Extraction” web application where a user can ask for the still (or slide) to be honed in on, needed us to design it so that a …

… looking arrangement could fulfil our requirements, so far, where the user can supply …

  1. [animatedGIFimageFileName] … and …
  2. slide number to extract (which can be entered as a percentage, being as our “HTML and Javascript parent (clientside) web application” logics are capable of determining an animated GIF’s …

    • number of slides (PHP extracts) … and, albeit not needed so far, with this project …
    • duration of an animated GIF “run through”

    )

… in …


var ij=0;

/** @param {Uint8Array} uint8 */
function isGifAnimated(uint8) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if (origgifloc == '') { origgifloc=gifloc; }
pbefore='';
//ij=0;
let duration = 0;
for (let i = 0, len = uint8.length; i < len; i++) {
if (uint8[i] == 0x21
&& uint8[i + 1] == 0xF9
&& uint8[i + 2] == 0x04
&& uint8[i + 7] == 0x00)
{
const delay = (uint8[i + 5] << 8) | (uint8[i + 4] & 0xFF);
duration += delay < 2 ? 10 : delay;



if (doit || gifloc.indexOf('%') != -1 || 1 == 1) {
ij++;
doit=true;
gifloc=origgifloc;
pbefore='' + ('gifloc=' + gifloc + ' and duration=' + eval(duration / 100) + ' and ij=' + ij + ' ');
if (origgifloc.indexOf('%') != -1) { gifloc='' + Math.round(eval(eval(gifloc.replace('%','')) * eval('' + ij) / 100.0)); }
//document.title='' + pbefore + ' ... ' + gifloc;
}
}
}
if (eval(duration / 100) <= 0.11) {
return 0;
}
//if (gifloc.indexOf('%') != -1) {
// alert('' + eval(duration / 100) + ' vs ' + delay);
// gifloc=gifloc.replace('%','');
//}
if (1 == 5 && canextract > 0) {
alert('' + eval(duration / 100));
} else {

var newimg=new Image();
newimg.onload = function(){
ih=newimg.height;
iw=newimg.width;
document.getElementById('dimg').style.width='' + eval(1 * newimg.width) + 'px';
document.getElementById('dimg').style.height='' + eval(1 * newimg.height) + 'px';
document.getElementById('dimg').style.background='linear-gradient(rgba(255,255,255,0.9),rgba(255,255,255,0.9)),url(' + gifurl + ')';
//document.getElementById('dimg').style.backgroundPosition='' + iw + 'px ' + ih + 'px';
document.getElementById('dimg').style.backgroundPosition='0px 0px';
document.getElementById('dimg').style.backgroundSize='' + newimg.width + 'px ' + newimg.height + 'px';
document.getElementById('dimg').style.backgroundRepeat='no-repeat';
document.getElementById('dimg').src='#';
document.getElementById('dimg').src=gifurl;
document.getElementById('mygimage').style.opacity='0.1';
};

newimg.src=gifurl;
goi=document.getElementById('mygimage');
goisrc=gifurl;
document.getElementById('mygimage').src=gifurl;
//newimg.src=gifurl;
setTimeout(function(){
jjform = new FormData();
jjxhr = new XMLHttpRequest();
document.getElementById('agname').value=gifurl;
document.getElementById('mygimage').title='Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...';
document.getElementById('slidenumber').value='' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij));
jjform.append('agname', gifurl);
jjform.append('slidenumber', '' + eval(1 + eval( eval(-1 + eval('' + gifloc.replace('%',''))) % ij)));
jjxhr.onreadystatechange = oneslidedu;
//jjxhr.responseType = "Document";
jjxhr.open('post', './agtoslides.php', true);
if (1 == 1) {
if (eval('' + document.getElementById('agname').value.length) < 400) {
//document.getElementById('dimg').style.opacity='0.1';
document.body.style.cursor='progress';
document.getElementById('myif').src='./agtoslides.php?agname=' + encodeURIComponent(document.getElementById('agname').value) + '&slidenumber=' + encodeURIComponent(document.getElementById('slidenumber').value);
} else {
//document.getElementById('dimg').style.opacity='0.1';
document.body.style.cursor='progress';
document.getElementById('mysub').click();
}
} else {
jjxhr.send(jjform);
}
}, 5000);
}
return duration / 100; // if 0.1 is not an animated GIF
}

… and to try this out you can turn the iframe below into a user interaction one via a click below

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


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


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


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


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


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


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


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


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


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


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


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


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


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

Posted in eLearning, Operating System, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Animated GIF Slide GIFEncoder AlmaLinux Tweaks Tutorial

Animated GIF Slide GIFEncoder AlmaLinux Tweaks Tutorial

Animated GIF Slide GIFEncoder AlmaLinux Tweaks Tutorial

Around here, we’re so used to using PHP local web server Apache/PHP/MySql MAMP (for PHP version starting with a 7) for our Animated GIF creations, and we recommend the (downloading PHP code to a) local web server approach here (but read on), that we forgot to suss out whether there were any issues with the brilliant László Zsidi GIFEncoder.class.php PHP class making it all happen.

Discombobulated we were to find there were issues going from …

  • CentOS Apache PHP version starting with a 5 … to …
  • AlmaLinux Apache PHP version starting with an 8

The major issue was that …

  • curly brace PHP syntax, in a lot of data array index and string offset related guises, is deprecated in PHP8 … but still okay in PHP7 … (thanks to this great link for advice)
  • class constructors cannot use the Class name any more, but rather use __constructor as the function name in the PHP code (thanks to this great link for advice)

And so we feel obligated to share with you better for PHP8 GIFEncoder.class.php to go along with a curly brace tweaked PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application you should have more success with, unless there is too much data, hosted on the RJM Programming domain.


Previous relevant Animated GIF Slide Extraction Applied CSS Styling Tutorial is shown below.

Animated GIF Slide Extraction Applied CSS Styling Tutorial

Animated GIF Slide Extraction Applied CSS Styling Tutorial

We dedicate today’s blog posting to the English phrase (that maybe works in other languages) …

Same, same but different

… as it is about the pros and cons of HTML iframe integration, especially as it applies to CSS styling. Off the top of our heads we see a Pros and Cons table looking like …

Pros and Cons of HTML Iframe Based Web Application Software Integration
Pros Cons
Become tools Difficulty with styling integration especially regarding time of coding differences
Become modularised Focus within iframe can cause problems
Ability to begin again at (0,0) regarding positioning Hashtag navigation within iframe can cause problems
Sharing the coding and execution load
Software organizational advantages
Can glean information off parent and vice versa
New chance for synchronizations
Multitasking
Coding language mixing
Parent child interactions

… and, as you can see, we are mainly fans of what it can bring to the table (mild chuckle, followed by a chortle).

But that first Con can grate, that “Difficulty with styling integration especially regarding time of coding differences”, and today, we thought we’d “apply” to relevant (there was one we found we should not “apply” the thinking to) HTML iframe “child” styling using yesterday’s Animated GIF Slide Extraction CSS Styling Tutorial‘s CSS styling idea in the “parent” (“applied” to these children).

We used a “suck it and see” approach whereby we just, where applicable, appended the CSS <style></style> styling logic of yesterday (plus a bit) to the document.body “body” innerHTML attribute of the iframe called, to see whether it felt more integrated. And we thought it did, perhaps because that styling was one of the more generic feeling ones we can remember (by that we’re meaning that the selectors were often just HTML tag names rather than too much “class” or “id” aspects to those selectors). Also, sometimes it won’t work because adding to the document.body innerHTML can sometimes “muck up” logic (but not today).

And what allows for “deploying” such an idea? Inhouse, we call what we do here “Client Pre-emptive Iframe” ideas, where the relevant iframe element’s “onload” (or on rare occasions, “onerror”) events are used to add logic at a slightly later time to any HTML iframe document.body element’s “onload” logic would be applied. This is a powerful mechanism open to you if you are dealing with same domain parent/child URLs, that is the case for us with this work today.

It’s as easy to do as (showing you one iframe “onload” function example below, and with inline CSS usage, rather than an external CSS file usage (where it would be even easier)) …


var paconto=null;

function pcheckit(iois) {
paconto = (iois.contentWindow || iois.contentDocument);
if (paconto != null) {
if (paconto.document) { paconto = paconto.document; }
if (paconto.body != null) {
setTimeout(function(){
if (document.getElementById('pmyifthree')) {
document.getElementById('pmyifthree').scrolling='no';
}
document.getElementById('myifthree').scrolling='no';
paconto.body.innerHTML+='<st' + 'yle> ' + document.head.innerHTML.split('<st' + 'yle>')[1].split('</st' + 'yle>')[0] + ' </st' + 'yle>';
paconto.getElementsByTagName('select')[0].style.display='none';
paconto.getElementById('image').style.display='none';
paconto.getElementById('isub').style.display='none';
paconto.getElementsByTagName('div')[0].style.opacity='0.0';
paconto.getElementsByTagName('select')[1].style.display='none';
paconto.getElementsByTagName('h1')[0].style.opacity='0.0';
if (1 == 1) { paconto.getElementsByTagName('h4')[0].style.opacity='0.0'; }
if (1 == 1) { paconto.getElementsByTagName('h3')[0].style.opacity='0.0'; }
}, 12000);
}
}
}

… to make this idea come, above. We don’t go overboard with precise integration, that is not our point. Just a …

Same, same but different

… feel in the changed tenth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version, or now, the Animated GIF Slide Extraction via User Interaction web application hashtag speed test version), which you can try below.


Previous relevant Animated GIF Slide Extraction CSS Styling Tutorial is shown below.

Animated GIF Slide Extraction CSS Styling Tutorial

Animated GIF Slide Extraction CSS Styling Tutorial

Another aesthetic plus on top of …

… which we flesh out more of today, further to yesterday’s Animated GIF Slide Extraction Speed Test Tutorial.

What was new to us with today’s work? The linear gradient effect (called text gradient) applied to text was new, thanks, in amongst …

<style>

#agmode { background-color: #98FB98; }
#agmodetwo { background-color: #AFEEEE; }

hr {
border: 5px solid green;
border-radius: 5px;
}

hr.one {
border: 5px solid red;
border-radius: 5px;
}

hr.two {
border: 5px solid orange;
border-radius: 5px;
}

hr.three {
border: 5px solid green;
border-radius: 5px;
}

body {
background: linear-gradient(to right, rgba(173,216,230,0.5) 0%, rgba(255,255,127,0.5) 100%);
}

img {
background: linear-gradient(to right, transparent 0%, transparent 100%);
border-radius: 9px;
}

h3 {
text-shadow: -1px 1px 1px #952dff;
}

input {
text-shadow: -0.4px 0.4px 0.4px #2d952d;
border-radius: 200px;
}

input::placeholder {
text-shadow: -1px 1px 1px #2d95ff;
}

summary {
text-shadow: -1px 1px 1px #ff952d;
}

h1 {
/* font-size: 72px; */
background: -webkit-linear-gradient(rgb(188, 12, 241), rgb(212, 64, 104), rgb(104, 212, 64));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}


iframe {
border-radius: 9px;
}

a {
border-radius: 9px;
}

</style>

… in the changed ninth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version, or now, the Animated GIF Slide Extraction via User Interaction web application hashtag speed test version), which you can try below.


Previous relevant Animated GIF Slide Extraction Speed Test Tutorial is shown below.

Animated GIF Slide Extraction Speed Test Tutorial

Animated GIF Slide Extraction Speed Test Tutorial

Yesterday’s Animated GIF Slide Extraction User Experience Tutorial sparked our interest in that …

  • we wondered whether hashtag components appended to ($_GET) address bar URLs perhaps consisting of ? and & argument parts slowed things down … and after first considering some standalone arrangement …
  • we realized we have quite good conditions with our current Animated GIF Extraction web application project predilections to adapt it

Getting into the coding of this we realized we were touching on another unknown to us. Is a hashtag call such as …


./agtoslides.php?slidenumber=1&random=56476858765876&delay=400&title=%2E%2Fuser_of_ss.gif&numfillin=3#agname=%2E%2Fuser_of_ss.gif

… to PHP going to register the hashtagging? Well, certainly not with PHP functionality but a client facing document.body onload event logic can see it …

<?php

// agtoslides.php
// RJM Programming
// May, 2024
// Animated GIF to a slide via ... ksh agtoslides.ksh [animatedGIFfilename] [slideNumber]
ini_set('max_execution_time', 60000);

$outp='';
$infl='';
$infill='';
$preoutp='';
$postoutp='';

if (file_exists('/tmp/agtoslides')) {
if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh')) {
if (isset($argc) && !isset($_GET['agname']) && !isset($_POST['agname'])) {
$infl=str_replace('+',' ',$argv[1]);
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($argv[1]));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
} else if (!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
}
if ($argc > 2) {
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($argv[2]))) . ' ' . $infill;
} else {
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else {
if (isset($_GET['random']) && !isset($_GET['agname'])) {
echo "<html>
<head>
<scrip" . "t type=text/javascript>
var jjjxhr=null, jjjform=null, astr='', stats=0;

function joneslidedu() {
if (jjjxhr.readyState == 4) {
if (jjjxhr.status == 200) {
parent.window.opener.timingshashpush((new Date()).getTime()); // document.body.innerHTML=jjjxhr.responseText.split(jjjxhr.responseText.substring(1).split('>')[0])[1].split('</body>')[0];
stats=jjjxhr.status;
}
}
}

function ajaxit() {
if (1 == 1) {
parent.setstats(1);
jjjform = new FormData();
jjjxhr = new XMLHttpRequest();
jjjform.append('agname', decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]));
jjjform.append('random', decodeURIComponent('" . $_GET['random'] . "'));
jjjform.append('slidenumber', decodeURIComponent('" . $_GET['slidenumber'] . "'));
jjjxhr.open('post', './agtoslides.php', true);
jjjxhr.onreadystatechange = joneslidedu;
jjjxhr.send(jjjform);
if (parent.window.opener.setstats) {
parent.window.opener.setstats(1);
}
parent.window.opener.document.getElementById('spareagname').value=decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]);
//alert(parent.window.opener.document.getElementById('sparemyform').outerHTML.length);
if (eval('' + parent.window.opener.document.getElementById('sparemyform').outerHTML.length) < 1000) {
parent.window.opener.document.getElementById('sparemyform').method='GET';
} else {
parent.window.opener.document.getElementById('sparemyform').method='POST';
}
parent.window.opener.document.getElementById('sparemyform').action=('' + parent.document.getElementById('sparemyform').action).split('#')[0];
parent.window.opener.document.getElementById('sparemysub').click();
if (1 == 11) {
//parent.getto().document.title='yes';
while (('' + parent.getto().getstats()) != '200') {
if (astr == '' || eval('' + astr.length) > 800) {
astr=' ';
} else {
astr+=' ';
}
}
}
} else {
jjjform = new FormData();
jjjxhr = new XMLHttpRequest();
jjjform.append('agname', decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]));
jjjform.append('random', decodeURIComponent('" . $_GET['random'] . "'));
jjjform.append('slidenumber', decodeURIComponent('" . $_GET['slidenumber'] . "'));
jjjxhr.open('post', './agtoslides.php', true);
jjjxhr.onreadystatechange = joneslidedu;
jjjxhr.send(jjjform);
while (stats != 200) {
if (astr == '' || eval('' + astr.length) > 800) {
astr=' ';
} else {
astr+=' ';
}
}
}
return true;
}

</scr" . "ipt>
</head>
<body onload='return ajaxit();' id=xbody></body></html>
";
exit;
}
if (isset($_GET['agname'])) {
if (isset($_GET['random'])) {
$infill=trim(str_replace('+',' ',urldecode($_GET['random']))) . ' tidyhere';
}
$infl=str_replace(' ','+',urldecode($_GET['agname']));
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($_GET['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
} else if (strpos($infl, $_SERVER['SERVER_NAME']) === false && strpos($infl, 'http') !== false) {
$infl=str_replace(' ','+',urldecode($_GET['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), file_get_contents(str_replace('https:','http:',$infl)) );
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
}
if ((!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) && strpos($infl, 'data:image/') === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
}
if (isset($_GET['slidenumber'])) {
//echo 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber']));
//exit;
//file_put_contents('xget.xxx', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
//echo ' --- ' . $outp;
//exit;
} else {
//file_put_contents('xget.zzz', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else if (isset($_POST['agname'])) {
if (isset($_POST['random'])) {
$infill=trim(str_replace('+',' ',urldecode($_POST['random']))) . ' tidyhere';
}
$infl=str_replace(' ','+',urldecode($_POST['agname']));
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($_POST['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
//if (strlen($infl) != 0) {
//file_put_contents('x.xx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
} else if (strpos($infl, $_SERVER['SERVER_NAME']) === false && strpos($infl, 'http') !== false) {
$infl=str_replace(' ','+',urldecode($_POST['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), file_get_contents(str_replace('https:','http:',$infl)) );
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
//if (strlen($infl) != 0) {
//file_put_contents('x.xxxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
// } else {
//file_put_contents('x.xxxxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
}
if ((!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) && strpos($infl, 'data:image/') === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
//if (strlen($infl) != 0) {
//file_put_contents('x.xxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
}
if (isset($_POST['slidenumber'])) {
//file_put_contents('xpost.xxx', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_POST['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_POST['slidenumber'])) . ' ' . $infill);
} else {
//file_put_contents('xpost.zzz', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
if (strpos($post, "agname=") !== false && strpos($post, "random=") !== false && strpos($post, "slidenumber=") !== false) {
$infill=explode('&', explode('random=', $post)[1])[0] . ' tidyhere';
$sn=explode('&', explode('slidenumber=', $post)[1])[0];
$infl=str_replace(' ','+',urldecode(explode('&', explode('agname=', $post)[1])[0]));
if (strpos($infl, 'data:image/') !== false) {
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
}
//file_put_contents('x.xxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . $sn . ' ' . $infill);
}
}
}
}
}
$inn=0;
$ij=0;
$otherstuff="";
if (isset($_GET['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_GET['delay'])) . '&';
}
if (isset($_POST['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_POST['delay'])) . '&';
}
if (isset($_GET['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_GET['title'])) . '&';
}
if (isset($_POST['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_POST['title'])) . '&';
}
if (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
$ij++;
$inn++;
}
}
$inn=0;
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
if ($postoutp == '') {
$postoutp='</body></html>';
$preoutp="<html><body onload=\" parent.agslideshow('slideshow','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
if ($postoutp != '') {
if ($inn > 0) {
$preoutp.=" parent.agslideshow('slideshow" . ('' . (1 + $inn)) . "','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
}
unlink('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png');
$inn++;
}
if ($postoutp != '') { $preoutp.=" parent.preagslideshow('/PHP/animegif/tutorial_to_animated_gif.php?" . $otherstuff . "numfillin=" . ('' . $ij) . "'); \">"; }
//file_put_contents('x.x', $preoutp . $outp . $postoutp);
echo $preoutp . $outp . $postoutp;
exit;

?>

… we found, to our relief! And though the synchronization is not exact, we simulate “apples for apples” via that Ajax asynchronicity timing for a hashtag call for the “window.open” window, versus the “window.opener” window non-hashtag call of that default animated GIF (like a splash page example) as you enter the web application.

Codewise we have …


Previous relevant Animated GIF Slide Extraction User Experience Tutorial is shown below.

Animated GIF Slide Extraction User Experience Tutorial

Animated GIF Slide Extraction User Experience Tutorial

We often equate the term “user experience” with “niceties”, in that we often find we deal with “user experience” issues well into a project, but you can put more effort into forward design planning so that you deal with it better throughout the project. We found with the Animated GIF Slide Extraction project of yesterday’s Animated GIF Creation Canvas Integration via Slide Extraction Tutorial that issues that had annoyed us for several days past, but which did not stop the web application working, turned into a day where we felt that we were improving the “user experience” by “fixing annoyances” and “adding niceties”, today. As you might imagine, this can be subjective, because just because we think an idea is an improvement does not mean every user out there will think so, and this is where time set aside for real users to try a product (ie. user acceptance testing) ahead of “going live” can be a great idea.

Anyway, there was …

  • an annoyance, on non-mobile, we first introduced when we integrated Animated GIF Creation in with Animated GIF Slide Extraction a couple of days ago … too much cursor:progress; usage … and in fixing we were astonished that cursor:wait; displays the same graphics … anyway, we think it helps when a cursor can help a user get used to identifying wherein the workflow they are situated at any given time …
    <?php echo ”

    function cursorcheck(defisidea) {
    if (window.parent) { if (parent.document.getElementById('cursorchoice')) { if (parent.document.getElementById('cursorchoice').value != '') { return parent.document.getElementById('cursorchoice').value; } } }
    return defisidea;
    }

    “; ?>
    … looking to parent …

    <input data-choice='' type=hidden value='help' id='cursorchoice'></input>
  • we felt better adding <hr> horizontal rule elements above and below the middle HTML iframe we set aside for client browsing functionality … and also …
  • made that iframe less wide enabling us to place to the right of it a hashtag navigational “a” link back up to the top …

    <hr>
    <iframe onload=pcheckit(this); style='display:inline-block;width:80%;height:160px;' id=myifthree src='/PHP/read_exif_off_image_rotate.php#itwo'></iframe> <a id=atotop style='display:inline-block;vertical-align:top;width:15%;text-shadow: -1px 1px 1px #952dff;' onclick="window.scrollTo(0,0);" href='#mydet'>&#11014; Top</a>
    <hr>

    … and …
  • given a background indicative of the goings on with the extracted animated GIF slide …

    function ob(tv) {
    if (tv == '' && intc != '') {
    tv=intc;
    document.getElementById('agname').value=intc;
    document.getElementById('mygimage').src=intc;
    document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    document.getElementById('atotop').style.backgroundSize='contain';
    document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    if (window.parent) {
    if (window.parent != window.self) {
    parent.document.getElementById('myta').setAttribute('data-img', document.getElementById('myta').getAttribute('data-img'));
    parent.document.getElementById('myta').title=document.getElementById('myta').title;
    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').src=intc;
    parent.document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    parent.document.getElementById('atotop').style.backgroundSize='contain';
    parent.document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').title='Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...';
    parent.document.getElementById('mysum').innerHTML=appbut('Animated GIF Slide Extraction Display ... RJM Programming - May, 2024 ... Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...');
    parent.document.getElementById('slidenumber').value='' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij));
    parent.unsetit();
    }
    }
    //tv=gifurl;
    ij=0;
    setTimeout(function(){ intc=''; }, 27000);
    }
    if (tv.trim() != '') {
    if (tv.indexOf('data') != 0 && tv.indexOf('//') != -1 && document.URL.indexOf('//') != -1) {
    if (tv.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'') != document.URL.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'')) {
    document.getElementById('myiffour').src='/getex.php?dodu=y&url=' + encodeURIComponent(tv); //window.open('/getex.php?dodu=y&url=' + encodeURIComponent(tv), '_blank');
    } else {
    prefetch(tv);
    }
    } else {
    prefetch(tv);
    }
    }
    }

    … and …
  • should the user click one (of the now two, and colour coded, as below) Animated GIF Creation action buttons now presented in our “reveal” details/summary the scrolling now lands

    function appittwo(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'rcmysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'rcmysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    function appit(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'mysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'mysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    … at the top of that middle iframe which is short enough so it and the Animated GIF Creation iframe are viewable on many platforms, those button presses created personalized animated GIFs there and then (at least on non-mobile), the user there to see that happening … where …
  • the user clicking the buttons up the top or down the bottom regarding Animate GIF Creation work for the two “submit” button modes can see which one was pressed via new border:5px dotted yellow; styling …
    <?php

    $indone="youllneverfindthis";
    $outdone="youllneverfindthis";


    if (isset($_POST['followthrough']) || isset($_GET['followthrough'])) {
    if (isset($_POST['followthrough'])) {
    if (strlen($_POST['followthrough']) > 0) {
    $indone='#' . $_POST['followthrough'] . " { ba";
    $outdone='#' . $_POST['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_POST['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_POST['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    } else if (isset($_GET['followthrough'])) {
    if (strlen($_GET['followthrough']) > 0) {
    $indone='#' . $_GET['followthrough'] . " { ba";
    $outdone='#' . $_GET['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_GET['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_GET['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    }
    }

    ?>
    applied

    <?php echo ”

    <style>
    input[type=submit]:active {
    border: 5px dotted yellow;
    }
    a { padding: 5px 5px 5px 5px; margin: 5px 5px 5px 5px; border: 1px solid red; background-color: #f0f0f0; }
    ::placeholder {
    font-size: 9px;
    }
    ::-webkit-input-placeholder { /* Chrome/Opera/Safari */
    font-size: 9px;
    }
    ::-moz-placeholder { /* Firefox 19+ */
    font-size: 9px;
    }
    :-ms-input-placeholder { /* IE 10+ */
    font-size: 9px;
    }
    :-moz-placeholder { /* Firefox 18- */
    font-size: 9px;
    }" . str_replace($indone, $outdone, "
    #mysubmit { background-color: #98FB98; }
    #rcmysubmit { background-color: #AFEEEE; }
    #overlayit { background-color: #FADADD; }
    #imsel { background-color: cyan; }
    #jmsel { background-color: magenta; }
    #watermarkmode { background-color: olive; }
    #selwhs { background-color: teal; }
    #sfilteris { background-color: lightgreen; } ") . "
    </style>

    “; ?>
    to the relevant bottom button

Codewise we have …


Previous relevant Animated GIF Creation Canvas Integration via Slide Extraction Tutorial is shown below.

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Thinking about yesterday’s Animated GIF Creation Data Limits via Slide Extraction Tutorial‘s progress …

What about if the user is happy to use those filled in animated GIF slide textboxes (with delay and title) to create a user created (and downloadable) animated GIF there and then?

Well, we know that user could click their own presented button, but we wanted to flag it up at the parent ahead of time too, in terms of clarity in the changed seventh draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below.

So, what’s all this got to do with an HTML canvas element (in case we have readers who take notice of the nuances of blog posting titles, that is)? Well, once you reach the stage with our inhouse Animated GIF Creator web application, where it has created your own animated GIF image, there is an “onclick” subsection of functionality that, in our new scenario, suffered from an error 404 (Bad Request) because the codeline ran as …

<?php echo ”

canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));

“; ?>

… but got that error because variable useyourwords contains an animated GIF “first slide” data-URI (useful in that a [canvasContext].drawImage() call of it would do what “drawImage” does with animated GIFs anyway (going back to the original point regarding this whole thread of blog postings)) which caused an overshoot of data size limits on conventional ($_GET style) address bar URLs (perhaps involving ? and & arguments (whether they be five minute or ten minute ones)). But regular readers will know, for a happy couple of months now, we recognize we do not always have to call into play serverside PHP and its $_POST mechanisms here, because we can also call on our life changing hashtagging (ie. #) (clientside approach for HTML/Javascript/CSS webpage) ideas now! Yay!!!!! And so, it came to pass, that … yes … there was light on yonder hilland vale … whatever that is … as “we broke bread” … shall we say … let’s … with some new hashtagging code in the changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application

<?php echo ”

if (eval('' + ('' + '/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords).length) <= 800) {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
} else {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords.replace('&','#'), '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
}


“; ?>

… as above and with the changed user_of_signature_signature.htm User of Signature Signature inhouse canvas graphic data web application “canvas hoster” …


var thewords=(location.search + location.hash).split('thewords=')[1] ? decodeURIComponent((location.search + location.hash).split('thewords=')[1].split('&')[0]) : "";
if (thewords.indexOf('data') == 0) { thewords=thewords.replace(/\ /g,'+'); }

… to bring “canvas integration” into the mix.


Previous relevant Animated GIF Creation Data Limits via Slide Extraction Tutorial is shown below.

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Even PHP’s $_POST[] approach to HTML form navigation data sharing has it’s limits, and that can be challenged when considering a whole set of data-URI defined animated GIF slide images.

But, behind the scenes, when $_POST[] does not get filled out with regard to the data limits of the Apache/PHP/MySql (in our case) web server involved, there is still php://input

PHP provides a number of miscellaneous I/O streams that allow access to PHP’s own input and output streams, the standard input, output and error file descriptors, in-memory and disk-backed temporary file streams, and filters that can manipulate other file resources as they are read from and written to.

php://stdin, php://stdout and php://stderr ¶
php://stdin, php://stdout and php://stderr allow direct access to the corresponding input or output stream of the PHP process. The stream references a duplicate file descriptor, so if you open php://stdin and later close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected. It is recommended that you simply use the constants STDIN, STDOUT and STDERR instead of manually opening streams using these wrappers.

php://stdin is read-only, whereas php://stdout and php://stderr are write-only.

… we can turn to (thanks, PHP), that can save the day in a lot of these scenarios.

The thing is, which our parent HTML and Javascript can help with, we want to be flagging the scenario where we should be checking that php://input usage might be coming into play. Well, even for an HTML form method=POST action=[ourRelevantPHP] scenario, the PHP global $_SERVER[‘QUERY_STRING’] is honoured, shall we say (separate to any $_GET[] ideas, is what we are getting at here). So we can, at the client HTML and Javascript parent (and client) end, set a unique $_SERVER[‘QUERY_STRING’] condition to test for in a changed sixth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below, nuancing yesterday’s Animated GIF Creation Interfacing via Slide Extraction Tutorial


<form id=agf style=display:none; method=POST data-target=ifconto action='/PHP/animegif/tutorial_to_animated_gif.php?theword=numfillin'>
</form>

… and then, up at that “[ourRelevantPHP]” changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application we can test as per

<?php

if (strpos(('' . $_SERVER['QUERY_STRING']), '=numfillin') !== false && !isset($_POST['numfillin']) && !isset($_GET['numfillin'])) {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
$prefdelim='?';
$pairings=[];
//file_put_contents('yes.yes', substr($post,0,300));
if (strpos($post, '=') !== false && strpos($post, '?') === false) {
$pairings=explode('=', ('?' . $post));
} else if (strpos($post, '=') !== false) {
$pairings=explode('=', ('' . $post));
}
if (strpos($post, '=') !== false) { // && strpos($post, '?') !== false) {
$post='';
//file_put_contents('yesagain.yes', '' . sizeof($pairings));
for ($ipairings=1; $ipairings<sizeof($pairings); $ipairings++) {
$thisval=explode('&', $pairings[$ipairings])[0];
$thisname=explode($prefdelim, $pairings[-1 + $ipairings])[1];
if (strpos(('~' . $thisval), '~data') !== false) {
$_POST[$thisname]=$thisval;
} else {
$_POST[$thisname]=$thisval;
}
if (strpos($thisname, 'slideshow') !== false) {
//file_put_contents('yes_yet_again.yes', '' . $thisname . ' ' . strlen($thisval));
}
//file_put_contents('yes_again.yes', '' . $thisname . ' ' . strlen($thisval));
$prefdelim='&';
}
$pairings=[];
}
}
$post='';

if (isset($_GET['numfillin'])) { $numfillin=$_GET['numfillin']; }
if (isset($_POST['numfillin'])) { $numfillin=$_POST['numfillin']; }

$nonplus=' ';
$theplus='+';
if ($numfillin >= 2) {
if (isset($_GET['numfillin'])) {
$numfillin=$_GET['numfillin'];
if (isset($_GET['slideshow'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_GET['slideshow']));
}
$nonplus=' ';
$theplus='+';
if (isset($_GET['slideshow2'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
} else if (isset($_POST['numfillin'])) {
$numfillin=$_POST['numfillin'];
if (isset($_POST['slideshow'])) {
//file_put_contents('yes_slideshow_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_POST['slideshow']));
}
if (isset($_POST['slideshow2'])) {
//file_put_contents('yes_slideshow2_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
}
$nonplus=' ';
$theplus='+';
for ($ijh=3; $ijh<=$numfillin; $ijh++) {
$pretwopattern='<div id="fdiv' . $ijh . '">';
if (isset($_GET['slideshow' . $ijh])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else if (isset($_POST['slideshow' . $ijh])) {
//file_put_contents('yes_slideshow' . $ijh . '_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else {
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
$nonplus=' ';
$theplus='+';
if ($ijh == $numfillin) {
$ijh++;
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
}
}

?>

… to cater for more scenarios, we’re hoping!


Previous relevant Animated GIF Creation Interfacing via Slide Extraction Tutorial is shown below.

Animated GIF Creation Interfacing via Slide Extraction Tutorial

Animated GIF Creation Interfacing via Slide Extraction Tutorial

The work of today combines …

… to add the chance for a user to use what ImageMagick produces as an Animated GIF slide and fill this out into the textboxes of the Animated GIF Creator “child” iframe hosted incarnation “quietly” filled out probably “below the fold”, but scrollable toable.

There are data limits to what the Animated GIF Creator can handle, but perhaps it can help a user create their own Animated GIFs, for their own purposes, via other sources.

Sources for courses

… we’d say. But we would say that, wouldn’t we?!

To make this happen, amongst the …

  1. PHP … and …
  2. Korn Shell

… helper components (to get to ImageMagick) we swap the “tidying up of interim files” role Korn Shell used to do, quite successfully (and still does for any interim “whole Animated GIF” files created), passing the responsibilities to the PHP to do (via passing over to the Korn Shell a new extra argument, to tell it this is the new arrangement). And at the changed third draft agtoslides.php PHP (working with the changed third draft agtoslides.ksh), before the “outputting command line” is executed, a whole lot of “child asks stuff of the parent” “programming talk and action” happens (and works, because our Client Pre-emptive Iframe Onload Event logic looks for that iframe document’s document.body.innerHTML as the representation of the extracted slide (of the animated GIF) of interest) …

<?php

$preoutp='';
$postoutp='';

$inn=0;
$ij=0;
$otherstuff="";
if (isset($_GET['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_GET['delay'])) . '&';
}
if (isset($_POST['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_POST['delay'])) . '&';
}
if (isset($_GET['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_GET['title'])) . '&';
}
if (isset($_POST['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_POST['title'])) . '&';
}
if (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
$ij++;
$inn++;
}
}
$inn=0;
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
if ($postoutp == '') {
$postoutp='</body></html>';
$preoutp="<html><body onload=\" parent.agslideshow('slideshow','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
if ($postoutp != '') {
if ($inn > 0) {
$preoutp.=" parent.agslideshow('slideshow" . ('' . (1 + $inn)) . "','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
}
unlink('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png');
$inn++;
}
if ($postoutp != '') { $preoutp.=" parent.preagslideshow('/PHP/animegif/tutorial_to_animated_gif.php?" . $otherstuff . "numfillin=" . ('' . $ij) . "'); \">"; }
//file_put_contents('x.x', $preoutp . $outp . $postoutp);
echo $preoutp . $outp . $postoutp;
exit;

?>

… to have the new parent Javascript functions …


function preagslideshow(theurl) {
if (theurl.indexOf('delay=') != -1) {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=delay value="' + decodeURIComponent(theurl.split('delay=')[1].split('&')[0]) + '"></input>';
} else {
jjform.append('delay', decodeURIComponent(theurl.split('delay=')[1].split('&')[0]));
}
}
if (theurl.indexOf('title=') != -1) {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=title value="' + decodeURIComponent(theurl.split('title=')[1].split('&')[0]) + '"></input>';
} else {
jjform.append('title', decodeURIComponent(theurl.split('title=')[1].split('&')[0]));
}
}
if (theurl.indexOf('numfillin=') != -1) {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=numfillin value="' + decodeURIComponent(theurl.split('numfillin=')[1].split('&')[0]) + '"></input>';
} else {
jjform.append('numfillin', decodeURIComponent(theurl.split('numfillin=')[1].split('&')[0]));
}
}
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=submit style=display:none; id=mysubag value=Submit></input>';
//alert(document.getElementById('agf').outerHTML);
document.getElementById('mysubag').click();
} else {
jjxhr.onreadystatechange = twoslidedu;
//jjxhr.responseType = "Document";
jjxhr.open('post', theurl.split('?')[0], true);
//document.getElementById('ifconto').src=theurl;
}
}

function agslideshow(thename, thevalue) {
if (1 == 1) {
if (thename == 'slideshow') {
if (9 == 9) {
//alert(thevalue);
document.getElementById('agf').innerHTML='<input type=hidden name=slideshow value="' + thevalue + '"></input>';
} else {
jjform = new FormData();
jjxhr = new XMLHttpRequest();
jjform.append('slideshow', thevalue);
}
} else {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=' + thename + ' value="' + thevalue + '"></input>';
} else {
jjform.append(thename, thevalue);
}
}
} else {
agconto.getElementById(thename).value=thevalue;
}
}

… working with the new static HTML …


<form id=agf style=display:none; method=POST data-target=ifconto action='/PHP/animegif/tutorial_to_animated_gif.php'>
</form>

… be able to assist with this new Animated GIF Creator interfacing to happen for the user, should they be interested, in a changed fifth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below.


Previous relevant Animated GIF Slide Extraction Reveal Tutorial is shown below.

Animated GIF Slide Extraction Reveal Tutorial

Animated GIF Slide Extraction Reveal Tutorial

Around here, we’re not ashamed to simplify 90% of web design issues into two categories …

  1. an “overlay” issue … or …
  2. a “reveal” issue

… and today’s improvements, pitted against the progress up until yesterday’s Animated GIF Slide Extraction Absolute URL Tutorial, pitted these two “colossuses” (at least in our mind) against each other as concept ideas towards today’s work’s solution. Which wins? We opted for a “reveal” solution, where the initial position is “reveal”.

We could have “overlayed” but we went for the KISS (“keep it simple simpleton”) principle, where, what you see at the top of a webpage takes prominence for the user. The thing is, though, in this alternate input section, we are not fussed that it stays around, hence the details/summary “reveal” way a user can make it disappear at any given point in time.

Here’s the thing, though, a details/summary “reveal” pairing has that “summary” innerHTML content part that can remain, no matter what, as a status informer mechanism we’re hoping helps out the “formerly obtuse” web application ways of our Animated GIF Extraction web application, in a changed fourth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below.


Previous relevant Animated GIF Slide Extraction Absolute URL Tutorial is shown below.

Animated GIF Slide Extraction Absolute URL Tutorial

Animated GIF Slide Extraction Absolute URL Tutorial

The other user entry the user might do using the Animated GIF Slide Extraction web application of yesterday’s Animated GIF Slide Extraction Browsing Tutorial onto …

  • relative animated GIF URL (within the address bar domain of use or an absolute URL serving similar purposes) … and yesterday’s …
  • browsed for local animated GIF file of interest … is today’s …
  • absolute URL pointing to a domain not the same as the address bar domain of use

As you might guess this last option for the user may not work for a domain with very high security, but being as hotlinking images makes the Internet woooorrrrllllddd go around perhaps the user can try this underlying curl based logic out, to see with a changed third draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), try below.

You may have noticed in our first draft we were not concerned with two incarnations of the web application being executed at once. Back then, one might interfere with the next if interrupted during the serverside ImageMagick phase of creating the png slides off the input animated GIF. Recently, we have started using …


uniquifier

… based logic (but in non-SQL realms) for that ImageMagick work. By and large the internal use only interim file naming in this ImageMagick phase is 99.9999999% sure to be unique to your session, and so not interfering, or accidentally picking up, other sessional data. You might want to look out for a textbox named “random”, in the code, regarding how we make that happen …


user@Users-Air htdocs % fgrep -n "'random'" extract_ag_slide_huh_of.html
157: jjform.append('random', document.getElementById('random').value);
165: document.getElementById('myif').src='./agtoslides.php?agname=' + encodeURIComponent(document.getElementById('agname').value) + '&slidenumber=' + encodeURIComponent(document.getElementById('slidenumber').value) + '&random=' + encodeURIComponent(document.getElementById('random').value);
167: //window.open('//www.rjmprogramming.com.au/Mac/extract_ag_slide_huh_of.html?slide=' + encodeURIComponent(document.getElementById('slidenumber').value) + '&random=' + encodeURIComponent(document.getElementById('random').value) + '#url=' + encodeURIComponent(document.getElementById('agname').value), '_blank', 'top=10,left=10,width=600,height=600');
173: document.getElementById('random').value='' + Math.floor(Math.random() * 198786753);
293: document.getElementById('random').value='' + Math.floor(Math.random() * 198786753);
376:<body onload="document.getElementById('random').value='' + Math.floor(Math.random() * 19878675); setTimeout(askaway,8000); ob(gifurl);">
user@Users-Air htdocs %


Previous relevant Animated GIF Slide Extraction Browsing Tutorial is shown below.

Animated GIF Slide Extraction Browsing Tutorial

Animated GIF Slide Extraction Browsing Tutorial

As of the recent Animated GIF Slide Extraction Primer Tutorial‘s progress with an Extraction of a User Nominated Animated GIF Slide web application’s …

  • input animated GIF URL modus operandi … today we add …
  • local operating system file browsing method of user animated GIF entry

… approach to our web application’s functionality abilities in a changed second draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version) helped out, especially via PHP’s acceptance of HTML form method=POST data, by …

… or via arrangements below.


Previous relevant Animated GIF Slide Extraction Primer Tutorial is shown below.

Animated GIF Slide Extraction Primer Tutorial

Animated GIF Slide Extraction Primer Tutorial

Would you believe …

  • the extraction of an HTML video element still is not too hard using that HTML video element object as the first parameter to a [canvasContext].drawImage method call (as you might recall reading the recent Canvas DrawImage First Parameter Primer Tutorial) … whereas …
  • the extraction of an HTML animated GIF image (ie. img) element still is a lot harder, regarding only the clientside Javascript side of web applications because using that animated GIF img object as that first parameter to a [canvasContext].drawImage method call results only in the first still (or slide) of that animated GIF

? And so, to proceed with our “Animated GIF Slide Extraction” web application where a user can ask for the still (or slide) to be honed in on, needed us to design it so that a …

… looking arrangement could fulfil our requirements, so far, where the user can supply …

  1. [animatedGIFimageFileName] … and …
  2. slide number to extract (which can be entered as a percentage, being as our “HTML and Javascript parent (clientside) web application” logics are capable of determining an animated GIF’s …

    • number of slides (PHP extracts) … and, albeit not needed so far, with this project …
    • duration of an animated GIF “run through”

    )

… in …


var ij=0;

/** @param {Uint8Array} uint8 */
function isGifAnimated(uint8) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if (origgifloc == '') { origgifloc=gifloc; }
pbefore='';
//ij=0;
let duration = 0;
for (let i = 0, len = uint8.length; i < len; i++) {
if (uint8[i] == 0x21
&& uint8[i + 1] == 0xF9
&& uint8[i + 2] == 0x04
&& uint8[i + 7] == 0x00)
{
const delay = (uint8[i + 5] << 8) | (uint8[i + 4] & 0xFF);
duration += delay < 2 ? 10 : delay;



if (doit || gifloc.indexOf('%') != -1 || 1 == 1) {
ij++;
doit=true;
gifloc=origgifloc;
pbefore='' + ('gifloc=' + gifloc + ' and duration=' + eval(duration / 100) + ' and ij=' + ij + ' ');
if (origgifloc.indexOf('%') != -1) { gifloc='' + Math.round(eval(eval(gifloc.replace('%','')) * eval('' + ij) / 100.0)); }
//document.title='' + pbefore + ' ... ' + gifloc;
}
}
}
if (eval(duration / 100) <= 0.11) {
return 0;
}
//if (gifloc.indexOf('%') != -1) {
// alert('' + eval(duration / 100) + ' vs ' + delay);
// gifloc=gifloc.replace('%','');
//}
if (1 == 5 && canextract > 0) {
alert('' + eval(duration / 100));
} else {

var newimg=new Image();
newimg.onload = function(){
ih=newimg.height;
iw=newimg.width;
document.getElementById('dimg').style.width='' + eval(1 * newimg.width) + 'px';
document.getElementById('dimg').style.height='' + eval(1 * newimg.height) + 'px';
document.getElementById('dimg').style.background='linear-gradient(rgba(255,255,255,0.9),rgba(255,255,255,0.9)),url(' + gifurl + ')';
//document.getElementById('dimg').style.backgroundPosition='' + iw + 'px ' + ih + 'px';
document.getElementById('dimg').style.backgroundPosition='0px 0px';
document.getElementById('dimg').style.backgroundSize='' + newimg.width + 'px ' + newimg.height + 'px';
document.getElementById('dimg').style.backgroundRepeat='no-repeat';
document.getElementById('dimg').src='#';
document.getElementById('dimg').src=gifurl;
document.getElementById('mygimage').style.opacity='0.1';
};

newimg.src=gifurl;
goi=document.getElementById('mygimage');
goisrc=gifurl;
document.getElementById('mygimage').src=gifurl;
//newimg.src=gifurl;
setTimeout(function(){
jjform = new FormData();
jjxhr = new XMLHttpRequest();
document.getElementById('agname').value=gifurl;
document.getElementById('mygimage').title='Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...';
document.getElementById('slidenumber').value='' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij));
jjform.append('agname', gifurl);
jjform.append('slidenumber', '' + eval(1 + eval( eval(-1 + eval('' + gifloc.replace('%',''))) % ij)));
jjxhr.onreadystatechange = oneslidedu;
//jjxhr.responseType = "Document";
jjxhr.open('post', './agtoslides.php', true);
if (1 == 1) {
if (eval('' + document.getElementById('agname').value.length) < 400) {
//document.getElementById('dimg').style.opacity='0.1';
document.body.style.cursor='progress';
document.getElementById('myif').src='./agtoslides.php?agname=' + encodeURIComponent(document.getElementById('agname').value) + '&slidenumber=' + encodeURIComponent(document.getElementById('slidenumber').value);
} else {
//document.getElementById('dimg').style.opacity='0.1';
document.body.style.cursor='progress';
document.getElementById('mysub').click();
}
} else {
jjxhr.send(jjform);
}
}, 5000);
}
return duration / 100; // if 0.1 is not an animated GIF
}

… and to try this out you can turn the iframe below into a user interaction one via a click below

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


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


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


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


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


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


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


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


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


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


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


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


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

Posted in eLearning, Software, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Animated GIF Slide Set and Forget Dimensioning Tutorial

Animated GIF Slide Set and Forget Dimensioning Tutorial

Animated GIF Slide Set and Forget Dimensioning Tutorial

When you have a fairly large web application project you are coding, it’s pretty inevitable that you “know where the bodies are buried” (if you’ll pardon our amateur dramatics). We’ve known about one for years with our inhouse Animated GIF Creator project (we last talked about at Animated GIF Slide Extraction Applied CSS Styling Tutorial), chipping away at it, but not cracking it to our satisfaction, concerning …

  • when a user creates an animated GIF …
  • derived of image slide sources of differing dimensions …
  • up to today, we were allowing for this in a user selectable dropdown but not doing a good job of flagging that to the user … it occurred to us …
  • today, on non-mobile, we’ll make the size attribute of that dropdown be the number of subelement option elements it has so that a non-mobile user can see all this happening … sorry, mobile users … and …
  • append four more options, as required, namely …
    1. Always Pick Maximal Dimensions
    2. Always Pick Minimal Dimensions
    3. Always Pick Maximal Width+Height
    4. Always Pick Minimal Width+Height

    … as a “set and forget” way a user can strategize their animated GIF output dimensioning no matter what else goes into the “slide mix”

At least for non-mobile we feel that this changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application is worth retrying regarding these Javascript modifications

<?php echo ”

function owoh(thisselis) {
var askwh='', askend=',[numSlides]', atwo=2;
owvisited=true;
if (('' + thisselis.value).trim() == '' && ('' + thisselis.value) != '') {
document.getElementById('defselwhs').innerHTML=document.getElementById('defselwhs').innerHTML.replace(' (' + document.getElementById('defselwhs').innerHTML.split(' (')[1].split(')')[0] + ')', ' (' + thisselis.innerHTML.split(' value=\"' + thisselis.value + '\">')[1].split('<')[0].replace('Always ','') + thisselis.value + ')');
return '';
} else if (('' + thisselis.value) == '' && document.getElementById('defselwhs').innerHTML.indexOf(' (Always Pick') != -1) {
document.getElementById('defselwhs').innerHTML=document.getElementById('defselwhs').innerHTML.replace(' (' + document.getElementById('defselwhs').innerHTML.split(' (')[1].split(')')[0] + ')', ' (or as below)');
return '';
} else if (('' + thisselis.value) == '' && document.getElementById('defselwhs').innerHTML.indexOf(' (Pick') != -1) {
document.getElementById('defselwhs').innerHTML=document.getElementById('defselwhs').innerHTML.replace(' (' + document.getElementById('defselwhs').innerHTML.split(' (')[1].split(')')[0] + ')', ' (or as below)');
return '';
} else if (('' + thisselis.value) == '?' && document.getElementById('defselwhs').innerHTML.indexOf(' (Always Pick') != -1) {
document.getElementById('defselwhs').innerHTML=document.getElementById('defselwhs').innerHTML.replace(' (' + document.getElementById('defselwhs').innerHTML.split(' (')[1].split(')')[0] + ')', ' (or as below)');
} else if (('' + thisselis.value) == '?' && document.getElementById('defselwhs').innerHTML.indexOf(' (Pick') != -1) {
document.getElementById('defselwhs').innerHTML=document.getElementById('defselwhs').innerHTML.replace(' (' + document.getElementById('defselwhs').innerHTML.split(' (')[1].split(')')[0] + ')', ' (or as below)');
}

if (thisselis.value.indexOf(',') != -1) {
document.getElementById('ow').value='' + thisselis.value.split(',')[0];
document.getElementById('oh').value='' + thisselis.value.split(',')[1];
} else if (thisselis.value='?') {
if (document.getElementById('slideshow2')) {
if (document.getElementById('slideshow2').value != '') {
atwo=1;
while (document.getElementById('slideshow' + eval(1 + atwo)) && ('' + document.getElementById('slideshow' + eval(1 + atwo)).value) != '') {
atwo++;
askend=',[numSlides=' + atwo + ']';
}
}
}
askwh=prompt('Please comma separate width,height[,widthEnd,heightEnd' + askend + '] (eg. 750,1334) where a -1 for one lets it be proportional', '');
if (askwh == null) { askwh=''; } else { askwh=askwh.replace(/\ /g,''); }
if (askwh.indexOf(',') != -1 && eval('' + askwh.split('-').length) <= 2) {
if (eval('' + askwh.split(',').length) >= 4) {
document.getElementById('owend').value='' + askwh.split(',')[2];
document.getElementById('ohend').value='' + askwh.split(',')[3];
//alert('yes');
} else {
document.getElementById('owend').value='';
document.getElementById('ohend').value='';
//alert('no');
}
if (eval('' + askwh.split(',').length) >= 5) {
document.getElementById('endnumber').value='' + askwh.split(',')[4];
} else {
document.getElementById('endnumber').value='';
}
if (askwh.indexOf('-1,') == 0) {
document.getElementById('ow').value='' + Math.round(eval('' + thisselis.outerHTML.split(' x ')[0].split('>')[eval(-1 + thisselis.outerHTML.split(' x ')[0].split('>').length)]) * eval('' + askwh.split(',')[1]) / eval('' + thisselis.outerHTML.split(',')[1].split('\"')[0].split(\"'\")[0]));
askwh=askwh.replace('-1,', document.getElementById('ow').value + ',');
document.getElementById('oh').value='' + askwh.split(',')[1];
if (eval('' + askwh.split(',').length) >= 4) {
if (askwh.split(',')[2] == '-1') {
document.getElementById('owend').value='' + Math.round(eval(document.getElementById('ow').value) * eval('' + askwh.split(',')[3]) / eval('' + askwh.split(',')[1]));
askwh=askwh.replace(',-1', ',' + document.getElementById('owend').value);
}
}
} else if ((askwh + '~').indexOf(',-1~') != -1 || (askwh + '~').indexOf(askwh.split(',')[0] + ',-1,') != -1) {
document.getElementById('ow').value='' + askwh.split(',')[0];
document.getElementById('oh').value='' + Math.round(eval('' + thisselis.outerHTML.split(' x ')[1].split('<')[0]) * eval('' + askwh.split(',')[0]) / eval('' + thisselis.outerHTML.split(',')[0].split('>')[eval(-1 + thisselis.outerHTML.split(',')[0].split('>').length)]));
askwh=askwh.replace(askwh.split(',')[0] + ',-1', askwh.split(',')[0] + ',' + document.getElementById('oh').value);
if (eval('' + askwh.split(',').length) >= 4) {
if (askwh.split(',')[3] == '-1') {
document.getElementById('ohend').value='' + Math.round(eval(document.getElementById('oh').value) * eval('' + askwh.split(',')[2]) / eval('' + askwh.split(',')[0]));
askwh=askwh.replace(',-1', ',' + document.getElementById('ohend').value);
}
}
} else {
document.getElementById('ow').value='' + askwh.split(',')[0];
document.getElementById('oh').value='' + askwh.split(',')[1];
}
if (thisselis.outerHTML.indexOf(askwh) == -1) {
thisselis.style.display='inline-block';
thisselis.innerHTML+='<option value=\"' + askwh + '\">' + askwh.replace(',',' x ') + '</option>';
}
} else {
askwh='';
document.getElementById('ow').value='-1';
document.getElementById('oh').value='-1';
}
thisselis.value=askwh;
} else {
document.getElementById('ow').value='-1';
document.getElementById('oh').value='-1';
}
}

function selw() {
var rework=false, ws=[], hs=[], ida=0, dimarr=[], maxis=0, minis=0, jda=0, maxwis=0, maxhis=0, minwis=0, minhis=0, cmaxis='', cminis='';
if (document.getElementById('selwhs')) {
if (eval('' + document.getElementById('selwhs').innerHTML.length) != selwhsl) {
selwhsl=document.getElementById('selwhs').innerHTML.length;
if (document.getElementById('selwhs').value.trim() == '' && document.getElementById('selwhs').value != '') {
rework=true;
}
var ijk=eval(-1 + eval('' + document.getElementById('selwhs').innerHTML.split(' x ').length));
document.title='' + ijk;
if (ijk >= 2 && document.getElementById('selwhs').innerHTML.indexOf('Always Pick ') == -1) {
//alert('yes');
document.getElementById('selwhs').innerHTML+='<option value=\" \">Always Pick Maximal Dimensions</option><option value=\" \">Always Pick Minimal Dimensions</option><option value=\" \">Always Pick Maximum Width+Height</option><option value=\" \">Always Pick Minimal Width+Height</option>';
//alert('Yes');
} //else if (ijk > 2) {
//alert('huh ' + document.getElementById('selwhs').innerHTML);
//}
if (rework) {
dimarr=document.getElementById('selwhs').innerHTML.split(' x ');
for (ida=1; ida<dimarr.length; ida++) {
ws.push(eval(dimarr[eval(-1 + ida)].split('>')[eval(-1 + dimarr[eval(-1 + ida)].split('>').length)]));
hs.push(eval(dimarr[eval(0 + ida)].split('<')[0]));
jda=eval(eval(dimarr[eval(-1 + ida)].split('>')[eval(-1 + dimarr[eval(-1 + ida)].split('>').length)]) + eval(dimarr[eval(0 + ida)].split('<')[0]));
if (ida <= 1) {
maxis=jda;
minis=jda;
cmaxis='' + eval(dimarr[eval(-1 + ida)].split('>')[eval(-1 + dimarr[eval(-1 + ida)].split('>').length)]) + ',' + eval(dimarr[eval(0 + ida)].split('<')[0]);
cminis='' + eval(dimarr[eval(-1 + ida)].split('>')[eval(-1 + dimarr[eval(-1 + ida)].split('>').length)]) + ',' + eval(dimarr[eval(0 + ida)].split('<')[0]);
maxwis=ws[0];
maxhis=hs[0];
minwis=ws[0];
minhis=hs[0];
} else {
if (ws[eval(-1 + ws.length)] > maxwis) {
maxwis=ws[eval(-1 + ws.length)];
}
if (ws[eval(-1 + ws.length)] < minwis) {
minwis=ws[eval(-1 + ws.length)];
}
if (hs[eval(-1 + hs.length)] > maxhis) {
maxhis=hs[eval(-1 + hs.length)];
}
if (hs[eval(-1 + hs.length)] < minhis) {
minhis=hs[eval(-1 + hs.length)];
}
}
if (jda > maxis) {
maxis=jda;
cmaxis='' + eval(dimarr[eval(-1 + ida)].split('>')[eval(-1 + dimarr[eval(-1 + ida)].split('>').length)]) + ',' + eval(dimarr[eval(0 + ida)].split('<')[0]);
}
if (jda < minis) {
minis=jda;
cminis='' + eval(dimarr[eval(-1 + ida)].split('>')[eval(-1 + dimarr[eval(-1 + ida)].split('>').length)]) + ',' + eval(dimarr[eval(0 + ida)].split('<')[0]);
}
}
if (document.getElementById('selwhs').value == ' ') {
if (document.getElementById('selwhs').innerHTML.indexOf(' value=\"' + maxwis + ',' + maxhis + '\"') != -1) {
document.getElementById('selwhs').value=maxwis + ',' + maxhis;
} else {
document.getElementById('selwhs').innerHTML+='<option value=\"' + maxwis + ',' + maxhis + '\">' + maxwis + ' x ' + maxhis + '</option>'
}
}
if (document.getElementById('selwhs').value == ' ') {
if (document.getElementById('selwhs').innerHTML.indexOf(' value=\"' + minwis + ',' + minhis + '\"') != -1) {
document.getElementById('selwhs').value=minwis + ',' + minhis;
} else {
document.getElementById('selwhs').innerHTML+='<option value=\"' + minwis + ',' + minhis + '\">' + minwis + ' x ' + minhis + '</option>'
}
}
if (document.getElementById('selwhs').value == ' ') {
document.getElementById('selwhs').value=cmaxis;
}
if (document.getElementById('selwhs').value == ' ') {
document.getElementById('selwhs').value=cminis;
}
}
var ijh=eval(-1 + eval('' + document.getElementById('selwhs').innerHTML.split('</optio').length));
if (ijh > 1) {
document.getElementById('selwhs').style.maxWidth='300px';
document.getElementById('selwhs').style.width='300px';
document.getElementById('selwhs').style.backgroundColor='lightgreen';
}
document.getElementById('selwhs').size=ijh;
}
}
}


setInterval(selw, 1000);

?>


Previous relevant Animated GIF Slide Extraction Applied CSS Styling Tutorial is shown below.

Animated GIF Slide Extraction Applied CSS Styling Tutorial

Animated GIF Slide Extraction Applied CSS Styling Tutorial

We dedicate today’s blog posting to the English phrase (that maybe works in other languages) …

Same, same but different

… as it is about the pros and cons of HTML iframe integration, especially as it applies to CSS styling. Off the top of our heads we see a Pros and Cons table looking like …

Pros and Cons of HTML Iframe Based Web Application Software Integration
Pros Cons
Become tools Difficulty with styling integration especially regarding time of coding differences
Become modularised Focus within iframe can cause problems
Ability to begin again at (0,0) regarding positioning Hashtag navigation within iframe can cause problems
Sharing the coding and execution load
Software organizational advantages
Can glean information off parent and vice versa
New chance for synchronizations
Multitasking
Coding language mixing
Parent child interactions

… and, as you can see, we are mainly fans of what it can bring to the table (mild chuckle, followed by a chortle).

But that first Con can grate, that “Difficulty with styling integration especially regarding time of coding differences”, and today, we thought we’d “apply” to relevant (there was one we found we should not “apply” the thinking to) HTML iframe “child” styling using yesterday’s Animated GIF Slide Extraction CSS Styling Tutorial‘s CSS styling idea in the “parent” (“applied” to these children).

We used a “suck it and see” approach whereby we just, where applicable, appended the CSS <style></style> styling logic of yesterday (plus a bit) to the document.body “body” innerHTML attribute of the iframe called, to see whether it felt more integrated. And we thought it did, perhaps because that styling was one of the more generic feeling ones we can remember (by that we’re meaning that the selectors were often just HTML tag names rather than too much “class” or “id” aspects to those selectors). Also, sometimes it won’t work because adding to the document.body innerHTML can sometimes “muck up” logic (but not today).

And what allows for “deploying” such an idea? Inhouse, we call what we do here “Client Pre-emptive Iframe” ideas, where the relevant iframe element’s “onload” (or on rare occasions, “onerror”) events are used to add logic at a slightly later time to any HTML iframe document.body element’s “onload” logic would be applied. This is a powerful mechanism open to you if you are dealing with same domain parent/child URLs, that is the case for us with this work today.

It’s as easy to do as (showing you one iframe “onload” function example below, and with inline CSS usage, rather than an external CSS file usage (where it would be even easier)) …


var paconto=null;

function pcheckit(iois) {
paconto = (iois.contentWindow || iois.contentDocument);
if (paconto != null) {
if (paconto.document) { paconto = paconto.document; }
if (paconto.body != null) {
setTimeout(function(){
if (document.getElementById('pmyifthree')) {
document.getElementById('pmyifthree').scrolling='no';
}
document.getElementById('myifthree').scrolling='no';
paconto.body.innerHTML+='<st' + 'yle> ' + document.head.innerHTML.split('<st' + 'yle>')[1].split('</st' + 'yle>')[0] + ' </st' + 'yle>';
paconto.getElementsByTagName('select')[0].style.display='none';
paconto.getElementById('image').style.display='none';
paconto.getElementById('isub').style.display='none';
paconto.getElementsByTagName('div')[0].style.opacity='0.0';
paconto.getElementsByTagName('select')[1].style.display='none';
paconto.getElementsByTagName('h1')[0].style.opacity='0.0';
if (1 == 1) { paconto.getElementsByTagName('h4')[0].style.opacity='0.0'; }
if (1 == 1) { paconto.getElementsByTagName('h3')[0].style.opacity='0.0'; }
}, 12000);
}
}
}

… to make this idea come, above. We don’t go overboard with precise integration, that is not our point. Just a …

Same, same but different

… feel in the changed tenth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version, or now, the Animated GIF Slide Extraction via User Interaction web application hashtag speed test version), which you can try below.


Previous relevant Animated GIF Slide Extraction CSS Styling Tutorial is shown below.

Animated GIF Slide Extraction CSS Styling Tutorial

Animated GIF Slide Extraction CSS Styling Tutorial

Another aesthetic plus on top of …

… which we flesh out more of today, further to yesterday’s Animated GIF Slide Extraction Speed Test Tutorial.

What was new to us with today’s work? The linear gradient effect (called text gradient) applied to text was new, thanks, in amongst …

<style>

#agmode { background-color: #98FB98; }
#agmodetwo { background-color: #AFEEEE; }

hr {
border: 5px solid green;
border-radius: 5px;
}

hr.one {
border: 5px solid red;
border-radius: 5px;
}

hr.two {
border: 5px solid orange;
border-radius: 5px;
}

hr.three {
border: 5px solid green;
border-radius: 5px;
}

body {
background: linear-gradient(to right, rgba(173,216,230,0.5) 0%, rgba(255,255,127,0.5) 100%);
}

img {
background: linear-gradient(to right, transparent 0%, transparent 100%);
border-radius: 9px;
}

h3 {
text-shadow: -1px 1px 1px #952dff;
}

input {
text-shadow: -0.4px 0.4px 0.4px #2d952d;
border-radius: 200px;
}

input::placeholder {
text-shadow: -1px 1px 1px #2d95ff;
}

summary {
text-shadow: -1px 1px 1px #ff952d;
}

h1 {
/* font-size: 72px; */
background: -webkit-linear-gradient(rgb(188, 12, 241), rgb(212, 64, 104), rgb(104, 212, 64));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}


iframe {
border-radius: 9px;
}

a {
border-radius: 9px;
}

</style>

… in the changed ninth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version, or now, the Animated GIF Slide Extraction via User Interaction web application hashtag speed test version), which you can try below.


Previous relevant Animated GIF Slide Extraction Speed Test Tutorial is shown below.

Animated GIF Slide Extraction Speed Test Tutorial

Animated GIF Slide Extraction Speed Test Tutorial

Yesterday’s Animated GIF Slide Extraction User Experience Tutorial sparked our interest in that …

  • we wondered whether hashtag components appended to ($_GET) address bar URLs perhaps consisting of ? and & argument parts slowed things down … and after first considering some standalone arrangement …
  • we realized we have quite good conditions with our current Animated GIF Extraction web application project predilections to adapt it

Getting into the coding of this we realized we were touching on another unknown to us. Is a hashtag call such as …


./agtoslides.php?slidenumber=1&random=56476858765876&delay=400&title=%2E%2Fuser_of_ss.gif&numfillin=3#agname=%2E%2Fuser_of_ss.gif

… to PHP going to register the hashtagging? Well, certainly not with PHP functionality but a client facing document.body onload event logic can see it …

<?php

// agtoslides.php
// RJM Programming
// May, 2024
// Animated GIF to a slide via ... ksh agtoslides.ksh [animatedGIFfilename] [slideNumber]
ini_set('max_execution_time', 60000);

$outp='';
$infl='';
$infill='';
$preoutp='';
$postoutp='';

if (file_exists('/tmp/agtoslides')) {
if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh')) {
if (isset($argc) && !isset($_GET['agname']) && !isset($_POST['agname'])) {
$infl=str_replace('+',' ',$argv[1]);
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($argv[1]));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
} else if (!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
}
if ($argc > 2) {
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($argv[2]))) . ' ' . $infill;
} else {
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else {
if (isset($_GET['random']) && !isset($_GET['agname'])) {
echo "<html>
<head>
<scrip" . "t type=text/javascript>
var jjjxhr=null, jjjform=null, astr='', stats=0;

function joneslidedu() {
if (jjjxhr.readyState == 4) {
if (jjjxhr.status == 200) {
parent.window.opener.timingshashpush((new Date()).getTime()); // document.body.innerHTML=jjjxhr.responseText.split(jjjxhr.responseText.substring(1).split('>')[0])[1].split('</body>')[0];
stats=jjjxhr.status;
}
}
}

function ajaxit() {
if (1 == 1) {
parent.setstats(1);
jjjform = new FormData();
jjjxhr = new XMLHttpRequest();
jjjform.append('agname', decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]));
jjjform.append('random', decodeURIComponent('" . $_GET['random'] . "'));
jjjform.append('slidenumber', decodeURIComponent('" . $_GET['slidenumber'] . "'));
jjjxhr.open('post', './agtoslides.php', true);
jjjxhr.onreadystatechange = joneslidedu;
jjjxhr.send(jjjform);
if (parent.window.opener.setstats) {
parent.window.opener.setstats(1);
}
parent.window.opener.document.getElementById('spareagname').value=decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]);
//alert(parent.window.opener.document.getElementById('sparemyform').outerHTML.length);
if (eval('' + parent.window.opener.document.getElementById('sparemyform').outerHTML.length) < 1000) {
parent.window.opener.document.getElementById('sparemyform').method='GET';
} else {
parent.window.opener.document.getElementById('sparemyform').method='POST';
}
parent.window.opener.document.getElementById('sparemyform').action=('' + parent.document.getElementById('sparemyform').action).split('#')[0];
parent.window.opener.document.getElementById('sparemysub').click();
if (1 == 11) {
//parent.getto().document.title='yes';
while (('' + parent.getto().getstats()) != '200') {
if (astr == '' || eval('' + astr.length) > 800) {
astr=' ';
} else {
astr+=' ';
}
}
}
} else {
jjjform = new FormData();
jjjxhr = new XMLHttpRequest();
jjjform.append('agname', decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]));
jjjform.append('random', decodeURIComponent('" . $_GET['random'] . "'));
jjjform.append('slidenumber', decodeURIComponent('" . $_GET['slidenumber'] . "'));
jjjxhr.open('post', './agtoslides.php', true);
jjjxhr.onreadystatechange = joneslidedu;
jjjxhr.send(jjjform);
while (stats != 200) {
if (astr == '' || eval('' + astr.length) > 800) {
astr=' ';
} else {
astr+=' ';
}
}
}
return true;
}

</scr" . "ipt>
</head>
<body onload='return ajaxit();' id=xbody></body></html>
";
exit;
}
if (isset($_GET['agname'])) {
if (isset($_GET['random'])) {
$infill=trim(str_replace('+',' ',urldecode($_GET['random']))) . ' tidyhere';
}
$infl=str_replace(' ','+',urldecode($_GET['agname']));
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($_GET['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
} else if (strpos($infl, $_SERVER['SERVER_NAME']) === false && strpos($infl, 'http') !== false) {
$infl=str_replace(' ','+',urldecode($_GET['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), file_get_contents(str_replace('https:','http:',$infl)) );
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
}
if ((!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) && strpos($infl, 'data:image/') === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
}
if (isset($_GET['slidenumber'])) {
//echo 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber']));
//exit;
//file_put_contents('xget.xxx', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
//echo ' --- ' . $outp;
//exit;
} else {
//file_put_contents('xget.zzz', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else if (isset($_POST['agname'])) {
if (isset($_POST['random'])) {
$infill=trim(str_replace('+',' ',urldecode($_POST['random']))) . ' tidyhere';
}
$infl=str_replace(' ','+',urldecode($_POST['agname']));
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($_POST['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
//if (strlen($infl) != 0) {
//file_put_contents('x.xx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
} else if (strpos($infl, $_SERVER['SERVER_NAME']) === false && strpos($infl, 'http') !== false) {
$infl=str_replace(' ','+',urldecode($_POST['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), file_get_contents(str_replace('https:','http:',$infl)) );
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
//if (strlen($infl) != 0) {
//file_put_contents('x.xxxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
// } else {
//file_put_contents('x.xxxxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
}
if ((!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) && strpos($infl, 'data:image/') === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
//if (strlen($infl) != 0) {
//file_put_contents('x.xxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
}
if (isset($_POST['slidenumber'])) {
//file_put_contents('xpost.xxx', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_POST['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_POST['slidenumber'])) . ' ' . $infill);
} else {
//file_put_contents('xpost.zzz', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
if (strpos($post, "agname=") !== false && strpos($post, "random=") !== false && strpos($post, "slidenumber=") !== false) {
$infill=explode('&', explode('random=', $post)[1])[0] . ' tidyhere';
$sn=explode('&', explode('slidenumber=', $post)[1])[0];
$infl=str_replace(' ','+',urldecode(explode('&', explode('agname=', $post)[1])[0]));
if (strpos($infl, 'data:image/') !== false) {
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
}
//file_put_contents('x.xxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . $sn . ' ' . $infill);
}
}
}
}
}
$inn=0;
$ij=0;
$otherstuff="";
if (isset($_GET['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_GET['delay'])) . '&';
}
if (isset($_POST['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_POST['delay'])) . '&';
}
if (isset($_GET['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_GET['title'])) . '&';
}
if (isset($_POST['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_POST['title'])) . '&';
}
if (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
$ij++;
$inn++;
}
}
$inn=0;
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
if ($postoutp == '') {
$postoutp='</body></html>';
$preoutp="<html><body onload=\" parent.agslideshow('slideshow','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
if ($postoutp != '') {
if ($inn > 0) {
$preoutp.=" parent.agslideshow('slideshow" . ('' . (1 + $inn)) . "','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
}
unlink('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png');
$inn++;
}
if ($postoutp != '') { $preoutp.=" parent.preagslideshow('/PHP/animegif/tutorial_to_animated_gif.php?" . $otherstuff . "numfillin=" . ('' . $ij) . "'); \">"; }
//file_put_contents('x.x', $preoutp . $outp . $postoutp);
echo $preoutp . $outp . $postoutp;
exit;

?>

… we found, to our relief! And though the synchronization is not exact, we simulate “apples for apples” via that Ajax asynchronicity timing for a hashtag call for the “window.open” window, versus the “window.opener” window non-hashtag call of that default animated GIF (like a splash page example) as you enter the web application.

Codewise we have …


Previous relevant Animated GIF Slide Extraction User Experience Tutorial is shown below.

Animated GIF Slide Extraction User Experience Tutorial

Animated GIF Slide Extraction User Experience Tutorial

We often equate the term “user experience” with “niceties”, in that we often find we deal with “user experience” issues well into a project, but you can put more effort into forward design planning so that you deal with it better throughout the project. We found with the Animated GIF Slide Extraction project of yesterday’s Animated GIF Creation Canvas Integration via Slide Extraction Tutorial that issues that had annoyed us for several days past, but which did not stop the web application working, turned into a day where we felt that we were improving the “user experience” by “fixing annoyances” and “adding niceties”, today. As you might imagine, this can be subjective, because just because we think an idea is an improvement does not mean every user out there will think so, and this is where time set aside for real users to try a product (ie. user acceptance testing) ahead of “going live” can be a great idea.

Anyway, there was …

  • an annoyance, on non-mobile, we first introduced when we integrated Animated GIF Creation in with Animated GIF Slide Extraction a couple of days ago … too much cursor:progress; usage … and in fixing we were astonished that cursor:wait; displays the same graphics … anyway, we think it helps when a cursor can help a user get used to identifying wherein the workflow they are situated at any given time …
    <?php echo ”

    function cursorcheck(defisidea) {
    if (window.parent) { if (parent.document.getElementById('cursorchoice')) { if (parent.document.getElementById('cursorchoice').value != '') { return parent.document.getElementById('cursorchoice').value; } } }
    return defisidea;
    }

    “; ?>
    … looking to parent …

    <input data-choice='' type=hidden value='help' id='cursorchoice'></input>
  • we felt better adding <hr> horizontal rule elements above and below the middle HTML iframe we set aside for client browsing functionality … and also …
  • made that iframe less wide enabling us to place to the right of it a hashtag navigational “a” link back up to the top …

    <hr>
    <iframe onload=pcheckit(this); style='display:inline-block;width:80%;height:160px;' id=myifthree src='/PHP/read_exif_off_image_rotate.php#itwo'></iframe> <a id=atotop style='display:inline-block;vertical-align:top;width:15%;text-shadow: -1px 1px 1px #952dff;' onclick="window.scrollTo(0,0);" href='#mydet'>&#11014; Top</a>
    <hr>

    … and …
  • given a background indicative of the goings on with the extracted animated GIF slide …

    function ob(tv) {
    if (tv == '' && intc != '') {
    tv=intc;
    document.getElementById('agname').value=intc;
    document.getElementById('mygimage').src=intc;
    document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    document.getElementById('atotop').style.backgroundSize='contain';
    document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    if (window.parent) {
    if (window.parent != window.self) {
    parent.document.getElementById('myta').setAttribute('data-img', document.getElementById('myta').getAttribute('data-img'));
    parent.document.getElementById('myta').title=document.getElementById('myta').title;
    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').src=intc;
    parent.document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    parent.document.getElementById('atotop').style.backgroundSize='contain';
    parent.document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').title='Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...';
    parent.document.getElementById('mysum').innerHTML=appbut('Animated GIF Slide Extraction Display ... RJM Programming - May, 2024 ... Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...');
    parent.document.getElementById('slidenumber').value='' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij));
    parent.unsetit();
    }
    }
    //tv=gifurl;
    ij=0;
    setTimeout(function(){ intc=''; }, 27000);
    }
    if (tv.trim() != '') {
    if (tv.indexOf('data') != 0 && tv.indexOf('//') != -1 && document.URL.indexOf('//') != -1) {
    if (tv.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'') != document.URL.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'')) {
    document.getElementById('myiffour').src='/getex.php?dodu=y&url=' + encodeURIComponent(tv); //window.open('/getex.php?dodu=y&url=' + encodeURIComponent(tv), '_blank');
    } else {
    prefetch(tv);
    }
    } else {
    prefetch(tv);
    }
    }
    }

    … and …
  • should the user click one (of the now two, and colour coded, as below) Animated GIF Creation action buttons now presented in our “reveal” details/summary the scrolling now lands

    function appittwo(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'rcmysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'rcmysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    function appit(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'mysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'mysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    … at the top of that middle iframe which is short enough so it and the Animated GIF Creation iframe are viewable on many platforms, those button presses created personalized animated GIFs there and then (at least on non-mobile), the user there to see that happening … where …
  • the user clicking the buttons up the top or down the bottom regarding Animate GIF Creation work for the two “submit” button modes can see which one was pressed via new border:5px dotted yellow; styling …
    <?php

    $indone="youllneverfindthis";
    $outdone="youllneverfindthis";


    if (isset($_POST['followthrough']) || isset($_GET['followthrough'])) {
    if (isset($_POST['followthrough'])) {
    if (strlen($_POST['followthrough']) > 0) {
    $indone='#' . $_POST['followthrough'] . " { ba";
    $outdone='#' . $_POST['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_POST['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_POST['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    } else if (isset($_GET['followthrough'])) {
    if (strlen($_GET['followthrough']) > 0) {
    $indone='#' . $_GET['followthrough'] . " { ba";
    $outdone='#' . $_GET['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_GET['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_GET['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    }
    }

    ?>
    applied

    <?php echo ”

    <style>
    input[type=submit]:active {
    border: 5px dotted yellow;
    }
    a { padding: 5px 5px 5px 5px; margin: 5px 5px 5px 5px; border: 1px solid red; background-color: #f0f0f0; }
    ::placeholder {
    font-size: 9px;
    }
    ::-webkit-input-placeholder { /* Chrome/Opera/Safari */
    font-size: 9px;
    }
    ::-moz-placeholder { /* Firefox 19+ */
    font-size: 9px;
    }
    :-ms-input-placeholder { /* IE 10+ */
    font-size: 9px;
    }
    :-moz-placeholder { /* Firefox 18- */
    font-size: 9px;
    }" . str_replace($indone, $outdone, "
    #mysubmit { background-color: #98FB98; }
    #rcmysubmit { background-color: #AFEEEE; }
    #overlayit { background-color: #FADADD; }
    #imsel { background-color: cyan; }
    #jmsel { background-color: magenta; }
    #watermarkmode { background-color: olive; }
    #selwhs { background-color: teal; }
    #sfilteris { background-color: lightgreen; } ") . "
    </style>

    “; ?>
    to the relevant bottom button

Codewise we have …


Previous relevant Animated GIF Creation Canvas Integration via Slide Extraction Tutorial is shown below.

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Thinking about yesterday’s Animated GIF Creation Data Limits via Slide Extraction Tutorial‘s progress …

What about if the user is happy to use those filled in animated GIF slide textboxes (with delay and title) to create a user created (and downloadable) animated GIF there and then?

Well, we know that user could click their own presented button, but we wanted to flag it up at the parent ahead of time too, in terms of clarity in the changed seventh draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below.

So, what’s all this got to do with an HTML canvas element (in case we have readers who take notice of the nuances of blog posting titles, that is)? Well, once you reach the stage with our inhouse Animated GIF Creator web application, where it has created your own animated GIF image, there is an “onclick” subsection of functionality that, in our new scenario, suffered from an error 404 (Bad Request) because the codeline ran as …

<?php echo ”

canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));

“; ?>

… but got that error because variable useyourwords contains an animated GIF “first slide” data-URI (useful in that a [canvasContext].drawImage() call of it would do what “drawImage” does with animated GIFs anyway (going back to the original point regarding this whole thread of blog postings)) which caused an overshoot of data size limits on conventional ($_GET style) address bar URLs (perhaps involving ? and & arguments (whether they be five minute or ten minute ones)). But regular readers will know, for a happy couple of months now, we recognize we do not always have to call into play serverside PHP and its $_POST mechanisms here, because we can also call on our life changing hashtagging (ie. #) (clientside approach for HTML/Javascript/CSS webpage) ideas now! Yay!!!!! And so, it came to pass, that … yes … there was light on yonder hilland vale … whatever that is … as “we broke bread” … shall we say … let’s … with some new hashtagging code in the changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application

<?php echo ”

if (eval('' + ('' + '/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords).length) <= 800) {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
} else {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords.replace('&','#'), '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
}


“; ?>

… as above and with the changed user_of_signature_signature.htm User of Signature Signature inhouse canvas graphic data web application “canvas hoster” …


var thewords=(location.search + location.hash).split('thewords=')[1] ? decodeURIComponent((location.search + location.hash).split('thewords=')[1].split('&')[0]) : "";
if (thewords.indexOf('data') == 0) { thewords=thewords.replace(/\ /g,'+'); }

… to bring “canvas integration” into the mix.


Previous relevant Animated GIF Creation Data Limits via Slide Extraction Tutorial is shown below.

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Even PHP’s $_POST[] approach to HTML form navigation data sharing has it’s limits, and that can be challenged when considering a whole set of data-URI defined animated GIF slide images.

But, behind the scenes, when $_POST[] does not get filled out with regard to the data limits of the Apache/PHP/MySql (in our case) web server involved, there is still php://input

PHP provides a number of miscellaneous I/O streams that allow access to PHP’s own input and output streams, the standard input, output and error file descriptors, in-memory and disk-backed temporary file streams, and filters that can manipulate other file resources as they are read from and written to.

php://stdin, php://stdout and php://stderr ¶
php://stdin, php://stdout and php://stderr allow direct access to the corresponding input or output stream of the PHP process. The stream references a duplicate file descriptor, so if you open php://stdin and later close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected. It is recommended that you simply use the constants STDIN, STDOUT and STDERR instead of manually opening streams using these wrappers.

php://stdin is read-only, whereas php://stdout and php://stderr are write-only.

… we can turn to (thanks, PHP), that can save the day in a lot of these scenarios.

The thing is, which our parent HTML and Javascript can help with, we want to be flagging the scenario where we should be checking that php://input usage might be coming into play. Well, even for an HTML form method=POST action=[ourRelevantPHP] scenario, the PHP global $_SERVER[‘QUERY_STRING’] is honoured, shall we say (separate to any $_GET[] ideas, is what we are getting at here). So we can, at the client HTML and Javascript parent (and client) end, set a unique $_SERVER[‘QUERY_STRING’] condition to test for in a changed sixth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below, nuancing yesterday’s Animated GIF Creation Interfacing via Slide Extraction Tutorial


<form id=agf style=display:none; method=POST data-target=ifconto action='/PHP/animegif/tutorial_to_animated_gif.php?theword=numfillin'>
</form>

… and then, up at that “[ourRelevantPHP]” changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application we can test as per

<?php

if (strpos(('' . $_SERVER['QUERY_STRING']), '=numfillin') !== false && !isset($_POST['numfillin']) && !isset($_GET['numfillin'])) {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
$prefdelim='?';
$pairings=[];
//file_put_contents('yes.yes', substr($post,0,300));
if (strpos($post, '=') !== false && strpos($post, '?') === false) {
$pairings=explode('=', ('?' . $post));
} else if (strpos($post, '=') !== false) {
$pairings=explode('=', ('' . $post));
}
if (strpos($post, '=') !== false) { // && strpos($post, '?') !== false) {
$post='';
//file_put_contents('yesagain.yes', '' . sizeof($pairings));
for ($ipairings=1; $ipairings<sizeof($pairings); $ipairings++) {
$thisval=explode('&', $pairings[$ipairings])[0];
$thisname=explode($prefdelim, $pairings[-1 + $ipairings])[1];
if (strpos(('~' . $thisval), '~data') !== false) {
$_POST[$thisname]=$thisval;
} else {
$_POST[$thisname]=$thisval;
}
if (strpos($thisname, 'slideshow') !== false) {
//file_put_contents('yes_yet_again.yes', '' . $thisname . ' ' . strlen($thisval));
}
//file_put_contents('yes_again.yes', '' . $thisname . ' ' . strlen($thisval));
$prefdelim='&';
}
$pairings=[];
}
}
$post='';

if (isset($_GET['numfillin'])) { $numfillin=$_GET['numfillin']; }
if (isset($_POST['numfillin'])) { $numfillin=$_POST['numfillin']; }

$nonplus=' ';
$theplus='+';
if ($numfillin >= 2) {
if (isset($_GET['numfillin'])) {
$numfillin=$_GET['numfillin'];
if (isset($_GET['slideshow'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_GET['slideshow']));
}
$nonplus=' ';
$theplus='+';
if (isset($_GET['slideshow2'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
} else if (isset($_POST['numfillin'])) {
$numfillin=$_POST['numfillin'];
if (isset($_POST['slideshow'])) {
//file_put_contents('yes_slideshow_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_POST['slideshow']));
}
if (isset($_POST['slideshow2'])) {
//file_put_contents('yes_slideshow2_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
}
$nonplus=' ';
$theplus='+';
for ($ijh=3; $ijh<=$numfillin; $ijh++) {
$pretwopattern='<div id="fdiv' . $ijh . '">';
if (isset($_GET['slideshow' . $ijh])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else if (isset($_POST['slideshow' . $ijh])) {
//file_put_contents('yes_slideshow' . $ijh . '_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else {
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
$nonplus=' ';
$theplus='+';
if ($ijh == $numfillin) {
$ijh++;
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
}
}

?>

… to cater for more scenarios, we’re hoping!


Previous relevant Animated GIF Creation Interfacing via Slide Extraction Tutorial is shown below.

Animated GIF Creation Interfacing via Slide Extraction Tutorial

Animated GIF Creation Interfacing via Slide Extraction Tutorial

The work of today combines …

… to add the chance for a user to use what ImageMagick produces as an Animated GIF slide and fill this out into the textboxes of the Animated GIF Creator “child” iframe hosted incarnation “quietly” filled out probably “below the fold”, but scrollable toable.

There are data limits to what the Animated GIF Creator can handle, but perhaps it can help a user create their own Animated GIFs, for their own purposes, via other sources.

Sources for courses

… we’d say. But we would say that, wouldn’t we?!

To make this happen, amongst the …

  1. PHP … and …
  2. Korn Shell

… helper components (to get to ImageMagick) we swap the “tidying up of interim files” role Korn Shell used to do, quite successfully (and still does for any interim “whole Animated GIF” files created), passing the responsibilities to the PHP to do (via passing over to the Korn Shell a new extra argument, to tell it this is the new arrangement). And at the changed third draft agtoslides.php PHP (working with the changed third draft agtoslides.ksh), before the “outputting command line” is executed, a whole lot of “child asks stuff of the parent” “programming talk and action” happens (and works, because our Client Pre-emptive Iframe Onload Event logic looks for that iframe document’s document.body.innerHTML as the representation of the extracted slide (of the animated GIF) of interest) …

<?php

$preoutp='';
$postoutp='';

$inn=0;
$ij=0;
$otherstuff="";
if (isset($_GET['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_GET['delay'])) . '&';
}
if (isset($_POST['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_POST['delay'])) . '&';
}
if (isset($_GET['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_GET['title'])) . '&';
}
if (isset($_POST['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_POST['title'])) . '&';
}
if (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
$ij++;
$inn++;
}
}
$inn=0;
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
if ($postoutp == '') {
$postoutp='</body></html>';
$preoutp="<html><body onload=\" parent.agslideshow('slideshow','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
if ($postoutp != '') {
if ($inn > 0) {
$preoutp.=" parent.agslideshow('slideshow" . ('' . (1 + $inn)) . "','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
}
unlink('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png');
$inn++;
}
if ($postoutp != '') { $preoutp.=" parent.preagslideshow('/PHP/animegif/tutorial_to_animated_gif.php?" . $otherstuff . "numfillin=" . ('' . $ij) . "'); \">"; }
//file_put_contents('x.x', $preoutp . $outp . $postoutp);
echo $preoutp . $outp . $postoutp;
exit;

?>

… to have the new parent Javascript functions …


function preagslideshow(theurl) {
if (theurl.indexOf('delay=') != -1) {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=delay value="' + decodeURIComponent(theurl.split('delay=')[1].split('&')[0]) + '"></input>';
} else {
jjform.append('delay', decodeURIComponent(theurl.split('delay=')[1].split('&')[0]));
}
}
if (theurl.indexOf('title=') != -1) {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=title value="' + decodeURIComponent(theurl.split('title=')[1].split('&')[0]) + '"></input>';
} else {
jjform.append('title', decodeURIComponent(theurl.split('title=')[1].split('&')[0]));
}
}
if (theurl.indexOf('numfillin=') != -1) {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=numfillin value="' + decodeURIComponent(theurl.split('numfillin=')[1].split('&')[0]) + '"></input>';
} else {
jjform.append('numfillin', decodeURIComponent(theurl.split('numfillin=')[1].split('&')[0]));
}
}
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=submit style=display:none; id=mysubag value=Submit></input>';
//alert(document.getElementById('agf').outerHTML);
document.getElementById('mysubag').click();
} else {
jjxhr.onreadystatechange = twoslidedu;
//jjxhr.responseType = "Document";
jjxhr.open('post', theurl.split('?')[0], true);
//document.getElementById('ifconto').src=theurl;
}
}

function agslideshow(thename, thevalue) {
if (1 == 1) {
if (thename == 'slideshow') {
if (9 == 9) {
//alert(thevalue);
document.getElementById('agf').innerHTML='<input type=hidden name=slideshow value="' + thevalue + '"></input>';
} else {
jjform = new FormData();
jjxhr = new XMLHttpRequest();
jjform.append('slideshow', thevalue);
}
} else {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=' + thename + ' value="' + thevalue + '"></input>';
} else {
jjform.append(thename, thevalue);
}
}
} else {
agconto.getElementById(thename).value=thevalue;
}
}

… working with the new static HTML …


<form id=agf style=display:none; method=POST data-target=ifconto action='/PHP/animegif/tutorial_to_animated_gif.php'>
</form>

… be able to assist with this new Animated GIF Creator interfacing to happen for the user, should they be interested, in a changed fifth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below.


Previous relevant Animated GIF Slide Extraction Reveal Tutorial is shown below.

Animated GIF Slide Extraction Reveal Tutorial

Animated GIF Slide Extraction Reveal Tutorial

Around here, we’re not ashamed to simplify 90% of web design issues into two categories …

  1. an “overlay” issue … or …
  2. a “reveal” issue

… and today’s improvements, pitted against the progress up until yesterday’s Animated GIF Slide Extraction Absolute URL Tutorial, pitted these two “colossuses” (at least in our mind) against each other as concept ideas towards today’s work’s solution. Which wins? We opted for a “reveal” solution, where the initial position is “reveal”.

We could have “overlayed” but we went for the KISS (“keep it simple simpleton”) principle, where, what you see at the top of a webpage takes prominence for the user. The thing is, though, in this alternate input section, we are not fussed that it stays around, hence the details/summary “reveal” way a user can make it disappear at any given point in time.

Here’s the thing, though, a details/summary “reveal” pairing has that “summary” innerHTML content part that can remain, no matter what, as a status informer mechanism we’re hoping helps out the “formerly obtuse” web application ways of our Animated GIF Extraction web application, in a changed fourth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below.


Previous relevant Animated GIF Slide Extraction Absolute URL Tutorial is shown below.

Animated GIF Slide Extraction Absolute URL Tutorial

Animated GIF Slide Extraction Absolute URL Tutorial

The other user entry the user might do using the Animated GIF Slide Extraction web application of yesterday’s Animated GIF Slide Extraction Browsing Tutorial onto …

  • relative animated GIF URL (within the address bar domain of use or an absolute URL serving similar purposes) … and yesterday’s …
  • browsed for local animated GIF file of interest … is today’s …
  • absolute URL pointing to a domain not the same as the address bar domain of use

As you might guess this last option for the user may not work for a domain with very high security, but being as hotlinking images makes the Internet woooorrrrllllddd go around perhaps the user can try this underlying curl based logic out, to see with a changed third draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), try below.

You may have noticed in our first draft we were not concerned with two incarnations of the web application being executed at once. Back then, one might interfere with the next if interrupted during the serverside ImageMagick phase of creating the png slides off the input animated GIF. Recently, we have started using …


uniquifier

… based logic (but in non-SQL realms) for that ImageMagick work. By and large the internal use only interim file naming in this ImageMagick phase is 99.9999999% sure to be unique to your session, and so not interfering, or accidentally picking up, other sessional data. You might want to look out for a textbox named “random”, in the code, regarding how we make that happen …


user@Users-Air htdocs % fgrep -n "'random'" extract_ag_slide_huh_of.html
157: jjform.append('random', document.getElementById('random').value);
165: document.getElementById('myif').src='./agtoslides.php?agname=' + encodeURIComponent(document.getElementById('agname').value) + '&slidenumber=' + encodeURIComponent(document.getElementById('slidenumber').value) + '&random=' + encodeURIComponent(document.getElementById('random').value);
167: //window.open('//www.rjmprogramming.com.au/Mac/extract_ag_slide_huh_of.html?slide=' + encodeURIComponent(document.getElementById('slidenumber').value) + '&random=' + encodeURIComponent(document.getElementById('random').value) + '#url=' + encodeURIComponent(document.getElementById('agname').value), '_blank', 'top=10,left=10,width=600,height=600');
173: document.getElementById('random').value='' + Math.floor(Math.random() * 198786753);
293: document.getElementById('random').value='' + Math.floor(Math.random() * 198786753);
376:<body onload="document.getElementById('random').value='' + Math.floor(Math.random() * 19878675); setTimeout(askaway,8000); ob(gifurl);">
user@Users-Air htdocs %


Previous relevant Animated GIF Slide Extraction Browsing Tutorial is shown below.

Animated GIF Slide Extraction Browsing Tutorial

Animated GIF Slide Extraction Browsing Tutorial

As of the recent Animated GIF Slide Extraction Primer Tutorial‘s progress with an Extraction of a User Nominated Animated GIF Slide web application’s …

  • input animated GIF URL modus operandi … today we add …
  • local operating system file browsing method of user animated GIF entry

… approach to our web application’s functionality abilities in a changed second draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version) helped out, especially via PHP’s acceptance of HTML form method=POST data, by …

… or via arrangements below.


Previous relevant Animated GIF Slide Extraction Primer Tutorial is shown below.

Animated GIF Slide Extraction Primer Tutorial

Animated GIF Slide Extraction Primer Tutorial

Would you believe …

  • the extraction of an HTML video element still is not too hard using that HTML video element object as the first parameter to a [canvasContext].drawImage method call (as you might recall reading the recent Canvas DrawImage First Parameter Primer Tutorial) … whereas …
  • the extraction of an HTML animated GIF image (ie. img) element still is a lot harder, regarding only the clientside Javascript side of web applications because using that animated GIF img object as that first parameter to a [canvasContext].drawImage method call results only in the first still (or slide) of that animated GIF

? And so, to proceed with our “Animated GIF Slide Extraction” web application where a user can ask for the still (or slide) to be honed in on, needed us to design it so that a …

… looking arrangement could fulfil our requirements, so far, where the user can supply …

  1. [animatedGIFimageFileName] … and …
  2. slide number to extract (which can be entered as a percentage, being as our “HTML and Javascript parent (clientside) web application” logics are capable of determining an animated GIF’s …

    • number of slides (PHP extracts) … and, albeit not needed so far, with this project …
    • duration of an animated GIF “run through”

    )

… in …


var ij=0;

/** @param {Uint8Array} uint8 */
function isGifAnimated(uint8) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if (origgifloc == '') { origgifloc=gifloc; }
pbefore='';
//ij=0;
let duration = 0;
for (let i = 0, len = uint8.length; i < len; i++) {
if (uint8[i] == 0x21
&& uint8[i + 1] == 0xF9
&& uint8[i + 2] == 0x04
&& uint8[i + 7] == 0x00)
{
const delay = (uint8[i + 5] << 8) | (uint8[i + 4] & 0xFF);
duration += delay < 2 ? 10 : delay;



if (doit || gifloc.indexOf('%') != -1 || 1 == 1) {
ij++;
doit=true;
gifloc=origgifloc;
pbefore='' + ('gifloc=' + gifloc + ' and duration=' + eval(duration / 100) + ' and ij=' + ij + ' ');
if (origgifloc.indexOf('%') != -1) { gifloc='' + Math.round(eval(eval(gifloc.replace('%','')) * eval('' + ij) / 100.0)); }
//document.title='' + pbefore + ' ... ' + gifloc;
}
}
}
if (eval(duration / 100) <= 0.11) {
return 0;
}
//if (gifloc.indexOf('%') != -1) {
// alert('' + eval(duration / 100) + ' vs ' + delay);
// gifloc=gifloc.replace('%','');
//}
if (1 == 5 && canextract > 0) {
alert('' + eval(duration / 100));
} else {

var newimg=new Image();
newimg.onload = function(){
ih=newimg.height;
iw=newimg.width;
document.getElementById('dimg').style.width='' + eval(1 * newimg.width) + 'px';
document.getElementById('dimg').style.height='' + eval(1 * newimg.height) + 'px';
document.getElementById('dimg').style.background='linear-gradient(rgba(255,255,255,0.9),rgba(255,255,255,0.9)),url(' + gifurl + ')';
//document.getElementById('dimg').style.backgroundPosition='' + iw + 'px ' + ih + 'px';
document.getElementById('dimg').style.backgroundPosition='0px 0px';
document.getElementById('dimg').style.backgroundSize='' + newimg.width + 'px ' + newimg.height + 'px';
document.getElementById('dimg').style.backgroundRepeat='no-repeat';
document.getElementById('dimg').src='#';
document.getElementById('dimg').src=gifurl;
document.getElementById('mygimage').style.opacity='0.1';
};

newimg.src=gifurl;
goi=document.getElementById('mygimage');
goisrc=gifurl;
document.getElementById('mygimage').src=gifurl;
//newimg.src=gifurl;
setTimeout(function(){
jjform = new FormData();
jjxhr = new XMLHttpRequest();
document.getElementById('agname').value=gifurl;
document.getElementById('mygimage').title='Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...';
document.getElementById('slidenumber').value='' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij));
jjform.append('agname', gifurl);
jjform.append('slidenumber', '' + eval(1 + eval( eval(-1 + eval('' + gifloc.replace('%',''))) % ij)));
jjxhr.onreadystatechange = oneslidedu;
//jjxhr.responseType = "Document";
jjxhr.open('post', './agtoslides.php', true);
if (1 == 1) {
if (eval('' + document.getElementById('agname').value.length) < 400) {
//document.getElementById('dimg').style.opacity='0.1';
document.body.style.cursor='progress';
document.getElementById('myif').src='./agtoslides.php?agname=' + encodeURIComponent(document.getElementById('agname').value) + '&slidenumber=' + encodeURIComponent(document.getElementById('slidenumber').value);
} else {
//document.getElementById('dimg').style.opacity='0.1';
document.body.style.cursor='progress';
document.getElementById('mysub').click();
}
} else {
jjxhr.send(jjform);
}
}, 5000);
}
return duration / 100; // if 0.1 is not an animated GIF
}

… and to try this out you can turn the iframe below into a user interaction one via a click below

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


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


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


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


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


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


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


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


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


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


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


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

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

Mister Ed Mathematics Collaboration Tutorial

Mister Ed Mathematics Collaboration Tutorial

Mister Ed Mathematics Collaboration Tutorial

Onto the previous Mister Ed Mathematics Primer Tutorial, if we are talking collaboration today, you might expect an emoji button or two to send an email or SMS, but we’ve intertwined …

  • ideas of collaboration and sharing … with …
  • window.localStorage (ie. like HTTP Cookie) web browser intersessional and intrasessional approaches to recalling …
  • a user’s own defined YouTube … identifier,duration,start,end … inhouse argument definitions … which can …
  • be slotted (for yourself, as a user, or derivable by an email or SMS recipient) into the mix of (perhaps, now, not) Mister Ed video snippets that get played as a user answers correctly, in the Mister Ed Mathematics quiz

… and we access that just with “behind the scenes” links a savvy user can click to access (but explained in “blurb land”)


function ask() {
var advice='', kpstr='';
var xem=prompt('Enter arguments such as ... ' + String.fromCharCode(10) + String.fromCharCode(10) + "?mr_ed_ideas=REC2gi-Hu2M,REC2gi-Hu2M&mr_ed_ideasdur=299.0,299.0&mr_ed_ideasizero=60,168&mr_ed_ideasjzero=70,237&keep=y" + String.fromCharCode(10) + String.fromCharCode(10) + " ... where your entry must start with ? and the keep=y is there to remember for next session and email= or sms= can be used.", "keep=y&mr_ed_ideas=REC2gi-Hu2M,REC2gi-Hu2M&mr_ed_ideasdur=299.0,299.0&mr_ed_ideasizero=60,168&mr_ed_ideasjzero=70,237");
if (xem == null) { xem=''; } else if (('' + xem + '!').substring(0,1) != '?') { xem=''; }
var wasxem=xem;
if (xem.indexOf('mr_ed_ideas=') != -1 && xem.indexOf('mr_ed_ideasdur=') != -1 && xem.indexOf('mr_ed_ideasizero=') != -1 && xem.indexOf('mr_ed_ideasjzero=') != -1) {
if (xem.indexOf('?') == 0 && xem.indexOf('=') != -1) {
var recip='';
if (xem.indexOf('email=') != -1) {
if (inbideas != '' && inbideasdur != '' && inbideasizero != '' && inbideasjzero != '' && xem.indexOf('mr_ed_ideas') == -1) {
wasxem+='&mr_ed_ideas=' + encodeURIComponent(inbideas);
wasxem+='&mr_ed_ideasdur=' + encodeURIComponent(inbideasdur);
wasxem+='&mr_ed_ideasizero=' + encodeURIComponent(inbideasizero);
wasxem+='&mr_ed_ideasjzero=' + encodeURIComponent(inbideasjzero);
}
if (xem.indexOf('keep=') != -1) {
wasxem=wasxem.replace(/keep\=/g,'keNOep=');
kpstr='?keNOep=y';
advice=encodeURIComponent(' ... if you like Mister Ed (YouTube video) ideas, to remember for the next time, reissue URL below with keNOep changed to keep ...');
}
recip=(xem + '&').split('email=')[1].split('&')[0];
if (recip.trim().indexOf('@') != -1) {
document.getElementById('ems').href='mailto:' + recip + '?subject=Mister%20Ed%20Mathematics' + advice + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + kpstr + '#' + wasxem.replace(/^\?/g,'').replace('email=','emJail=').replace('sms=','sJms='));
setTimeout(function(){ document.getElementById('ems').click(); }, 2000);
}
} else if (xem.indexOf('sms=') != -1) {
if (inbideas != '' && inbideasdur != '' && inbideasizero != '' && inbideasjzero != '' && xem.indexOf('mr_ed_ideas') == -1) {
wasxem+='&mr_ed_ideas=' + encodeURIComponent(inbideas);
wasxem+='&mr_ed_ideasdur=' + encodeURIComponent(inbideasdur);
wasxem+='&mr_ed_ideasizero=' + encodeURIComponent(inbideasizero);
wasxem+='&mr_ed_ideasjzero=' + encodeURIComponent(inbideasjzero);
}
if (xem.indexOf('keep=') != -1) {
wasxem=wasxem.replace(/keep\=/g,'keNOep=');
kpstr='?keNOep=y';
advice=encodeURIComponent(' ... if you like Mister Ed (YouTube video) ideas, to remember for the next time, reissue URL below with keNOep changed to keep ...');
}
recip=(xem + '&').split('sms=')[1].split('&')[0];
if (recip.trim() != '' && recip.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,'') == '') {
document.getElementById('ems').href='sms:' + recip + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + kpstr + '#' + wasxem.replace(/^\?/g,'').replace('sms=','sJms=').replace('email=','emJail='));
setTimeout(function(){ document.getElementById('ems').click(); }, 2000);
}
}
location.hash='#' + xem.replace(/^\?/g,'');
var jnbideas=(('' + location.hash + '&' + location.search).split('mr_ed_ideas=')[1] ? ',' + decodeURIComponent(('' + location.hash + '&' + location.search).split('mr_ed_ideas=')[1].split('&')[0]) + ',' : (',' + decodeURIComponent(('' + window.localStorage.getItem('mr_ed_ideas')).replace(/^null/g,'').replace(/^undefined/g,'')).replace(/\'/g,'').replace(/\"/g,'').replace(/^\,/g,"'").replace(/\,/g,"','").replace(/\,\'$/g,",")).replace(/^\,$/g,'') );
var jnbideasdur=(('' + location.hash + '&' + location.search).split('mr_ed_ideasdur=')[1] ? ',' + decodeURIComponent(('' + location.hash + '&' + location.search).split('mr_ed_ideasdur=')[1].split('&')[0]) + ',' : (',' + decodeURIComponent(('' + window.localStorage.getItem('mr_ed_ideasdur')).replace(/^null/g,'').replace(/^undefined/g,'')).replace(/\'/g,'').replace(/\"/g,'').replace(/^\,/g,"'").replace(/\,/g,"','").replace(/\,\'$/g,",")).replace(/^\,$/g,'') );
var jnbideasizero=(('' + location.hash + '&' + location.search).split('mr_ed_ideasizero=')[1] ? ',' + decodeURIComponent(('' + location.hash + '&' + location.search).split('mr_ed_ideasizero=')[1].split('&')[0]) + ',' : (',' + decodeURIComponent(('' + window.localStorage.getItem('mr_ed_ideasizero')).replace(/^null/g,'').replace(/^undefined/g,'')).replace(/\'/g,'').replace(/\"/g,'').replace(/^\,/g,"'").replace(/\,/g,"','").replace(/\,\'$/g,",")).replace(/^\,$/g,'') );
var jnbideasjzero=(('' + location.hash + '&' + location.search).split('mr_ed_ideasjzero=')[1] ? ',' + decodeURIComponent(('' + location.hash + '&' + location.search).split('mr_ed_ideasjzero=')[1].split('&')[0]) + ',' : (',' + decodeURIComponent(('' + window.localStorage.getItem('mr_ed_ideasjzero')).replace(/^null/g,'').replace(/^undefined/g,'')).replace(/\'/g,'').replace(/\"/g,'').replace(/^\,/g,"'").replace(/\,/g,"','").replace(/\,\'$/g,",")).replace(/^\,$/g,'') );
if ((xem + '&').indexOf('mr_ed_ideas=&') != -1 && xem.indexOf('keep=') != -1) {
try {
window.localStorage.removeItem('mr_ed_ideas');
} catch { }
} else if (jnbideas != '' && jnbideas != inbideas) {
//alert('0:' + jnbideas);
//document.write(String.fromCharCode(10) + '<scr' + "ipt> ideas=['hMPbipfgQ2c'," + jnbideas.replace(/\'/g,'').replace(/\"/g,'').replace(/^\,/g,"'").replace(/\,/g,"','").replace(/\,\'$/g,",") + "'hMPbipfgQ2c','B5eRMaBMOTs','B5eRMaBMOTs','B5eRMaBMOTs','PDJQwyB81vg','PDJQwyB81vg','PDJQwyB81vg','PDJQwyB81vg','-AK1aeKTGDg']; </scr" + "ipt> " + String.fromCharCode(10));
eval(" ideas=['hMPbipfgQ2c'," + jnbideas.replace(/\'/g,'').replace(/\"/g,'').replace(/^\,/g,"'").replace(/\,/g,"','").replace(/\,\'$/g,",") + "'hMPbipfgQ2c','B5eRMaBMOTs','B5eRMaBMOTs','B5eRMaBMOTs','PDJQwyB81vg','PDJQwyB81vg','PDJQwyB81vg','PDJQwyB81vg','-AK1aeKTGDg']");
//alert('1:' + jnbideas);
if (xem.indexOf('keep=') != -1) {
try {
window.localStorage.removeItem('mr_ed_ideas');
} catch { }
//alert('2:' + jnbideas);
window.localStorage.setItem('mr_ed_ideas', encodeURIComponent(jnbideas));
//alert('3:' + jnbideas);
}
} else if ((xem + '&').indexOf('mr_ed_ideas=&') != -1 && xem.indexOf('keep=') != -1) {
try {
window.localStorage.removeItem('mr_ed_ideas');
} catch { }
}
if ((xem + '&').indexOf('mr_ed_ideasdur=&') != -1 && xem.indexOf('keep=') != -1) {
try {
window.localStorage.removeItem('mr_ed_ideasdur');
} catch { }
} else if (jnbideasdur != '' && jnbideasdur != inbideasdur) {
//alert(3);
//document.write(String.fromCharCode(10) + '<scr' + "ipt> ideasdur=['41.808'," + jnbideasdur.replace(/\'/g,'').replace(/\"/g,'').replace(/^\,/g,"'").replace(/\,/g,"','").replace(/\,\'$/g,",") + "'41.808','1753.0','1753.0','1753.0','876.0','876.0','876.0','876.0','942.0']; </scr" + "ipt> " + String.fromCharCode(10));
eval(" ideasdur=['41.808'," + jnbideasdur.replace(/\'/g,'').replace(/\"/g,'').replace(/^\,/g,"'").replace(/\,/g,"','").replace(/\,\'$/g,",") + "'41.808','1753.0','1753.0','1753.0','876.0','876.0','876.0','876.0','942.0']");
if (xem.indexOf('keep=') != -1) {
try {
window.localStorage.removeItem('mr_ed_ideasdur');
} catch { }
window.localStorage.setItem('mr_ed_ideasdur', encodeURIComponent(jnbideasdur));
}
} else if ((xem + '&').indexOf('mr_ed_ideasdur=&') != -1 && xem.indexOf('keep=') != -1) {
try {
window.localStorage.removeItem('mr_ed_ideasdur');
} catch { }
}
if ((xem + '&').indexOf('mr_ed_ideasizero=&') != -1 && xem.indexOf('keep=') != -1) {
try {
window.localStorage.removeItem('mr_ed_ideasizero');
} catch { }
} else if (jnbideasizero != '' && jnbideasizero != inbideasizero) {
//alert(4);
//document.write(String.fromCharCode(10) + '<scr' + "ipt> ideasizero=['9'," + jnbideasizero.replace(/\'/g,'').replace(/\"/g,'').replace(/^\,/g,"'").replace(/\,/g,"','").replace(/\,\'$/g,",") + "'23','127','697','742','0','97','175','155','720']; </scr" + "ipt> " + String.fromCharCode(10));
eval(" ideasizero=['9'," + jnbideasizero.replace(/\'/g,'').replace(/\"/g,'').replace(/^\,/g,"'").replace(/\,/g,"','").replace(/\,\'$/g,",") + "'23','127','697','742','0','97','175','155','720']");
if (xem.indexOf('keep=') != -1) {
try {
window.localStorage.removeItem('mr_ed_ideasizero');
} catch { }
window.localStorage.setItem('mr_ed_ideasizero', encodeURIComponent(jnbideasizero));
}
} else if ((xem + '&').indexOf('mr_ed_ideasizero=&') != -1 && xem.indexOf('keep=') != -1) {
try {
window.localStorage.removeItem('mr_ed_ideasizero');
} catch { }
}
if ((xem + '&').indexOf('mr_ed_ideasjzero=&') != -1 && xem.indexOf('keep=') != -1) {
try {
window.localStorage.removeItem('mr_ed_ideasjzero');
} catch { }
} else if (jnbideasjzero != '' && jnbideasjzero != inbideasjzero) {
//alert(5);
//document.write(String.fromCharCode(10) + '<scr' + "ipt> ideasjzero=['11'," + jnbideasjzero.replace(/\'/g,'').replace(/\"/g,'').replace(/^\,/g,"'").replace(/\,/g,"','").replace(/\,\'$/g,",") + "'25','139','742','762','4','150','204','161','785']; </scr" + "ipt> " + String.fromCharCode(10));
eval(" ideasjzero=['11'," + jnbideasjzero.replace(/\'/g,'').replace(/\"/g,'').replace(/^\,/g,"'").replace(/\,/g,"','").replace(/\,\'$/g,",") + "'25','139','742','762','4','150','204','161','785']");
if (xem.indexOf('keep=') != -1) {
try {
window.localStorage.removeItem('mr_ed_ideasjzero');
} catch { }
window.localStorage.setItem('mr_ed_ideasjzero', encodeURIComponent(jnbideasjzero));
}
} else if ((xem + '&').indexOf('mr_ed_ideasjzero=&') != -1 && xem.indexOf('keep=') != -1) {
try {
window.localStorage.removeItem('mr_ed_ideasjzero');
} catch { }
}
//alert(33);
}
}
}

You may have noticed another feature of this changed mr_ed_maths.html Mister Ed Maths web application (you can also try below) continuing on into “day two”. The mathematics test answers, at least ours inspired by Mister Ed, are all one character (albeit numerical) long. And, what does that mean? Anyone? Anyone? Yes, Larry you think it’s …

Hot in Largo

… is that code for “It’s Slowly Getting Hot” … or … yes, Douglas

Flor-ID-a … ErGO?

Yes, well, okay then. Ummm. Think you’re both onto something there. We were thinking, ourselves, like, just in the realms of the everyday, like, that, being as we live in a free society, like, it could be that, given things being the way they were, we could accept user input as if … yes … Amy

As if?!

… it is a Hotkey … phew!!!! Yes, because one key is needed to answer we can introduce a new textbox …


<input onkeydown="return okd(event);" id=ians onblur=checkans(this); style=display:inline-block;width:500px; type=text placeholder='Mobile users can gesture with correct number of fingers involved, for extra score.' value=''></input>

… directed “onkeydown” keyboard event calling …


function okd(evt) {
if (evt.altKey) {
return false;
} else if (evt.ctrlKey) {
return false;
} else if (evt.shiftKey) {
return false;
}
var ichar = evt.which || evt.keyCode;
if (ichar > 48 && ichar <= 57) { setTimeout(function(){ checkans(document.getElementById('ians')); }, 10); } else { evt.target.value=''; return false; }
return true;
}

… Javascript event function, streamlining matters considerably.

And regarding “above the fold” meets “focus” meets “scrolling position” matters, we make more use of that textbox’s placeholder attribute, after it’s initial guise, filling it out with …

  • current score
  • wrong answer explanations … counterintuitively then being able to …
  • shorten it’s width

… for some more improvement, we think, because parts above become “just for show” should they be up the top out of view.


Previous relevant Mister Ed Mathematics Primer Tutorial is shown below.

Mister Ed Mathematics Primer Tutorial

Mister Ed Mathematics Primer Tutorial

Well, we all know …

A horse is a horse, of course, of course …

… and it’s become apparent to Nala that …

No one can talk to a horse, of course …

… but as Luna would tell you …

That is, of course, unless the horse is the famous Mister Ed!

And we wanted to harness these mathematical skills to write a new web application rewarding those eager beaver budding mathematicians (and, presumably, giving short shrift to people) with … well, see for yourself with the “how we got there” mr_ed_maths.html Mister Ed Maths web application …

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


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

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

HTML/Javascript Music Chord Game Revisit Tutorial

HTML/Javascript Music Chord Game Revisit Tutorial

HTML/Javascript Music Chord Game Revisit Tutorial

Unsurprisingly, even for non-mobile usage, the 2015 HTML/Javascript Music Chord Game Tutorial Name Those Notes and Name Those Chords game playing of audio before a click usage instigated by the user ways does not pass muster in the web browser rules of 2024.

We decided to start showing the HTML iframe hosted middle player helper, so that the user gets a chance to click/tap a Web Audio (API) means by which to …

  • supply that click/tap required before playing audio
  • use Web Audio API to play sound
  • stop navigating away from the URL for the window.top webpage …
  • in favour of using faux hashtag URLs up at the parent looked out for by the child iframe window … so that this click/tap above can last longer

… for what we see as an improved …

… set of HTML and Javascript codesets.

Notwithstanding, the code still relies on …

… thanks!


Previous relevant HTML/Javascript Music Chord Game Tutorial is shown below.

HTML/Javascript Music Chord Game Tutorial

HTML/Javascript Music Chord Game Tutorial

Yesterday we wrote a musical pitch game for one note at a time and today we extend that functionality to allow the user to guess the characteristics of musical chords and intervals played for them by this MIDI music web application (as you can review with HTML/Javascript Music Pitch Game Tutorial).

We used the HTML iframe element yesterday, and today we further nest these elements to have an iframe within an iframe, all at the same domain. The reason to do this is that we think the logic for examination of the musical chord guesses by the user is quite different because we need to …

  • cater for HTML select tags with multiple selections
  • add a new guessable concept … the type of chord played

As we mentioned yesterday, if you write lots of your own web applications, and they are all sitting in the same domain, then the HTML iframe element is a great tool for web application code modularisation and the iframe can see what its parent contains content-wise as well as the other way around. This can be a very useful attribute of these HTML elements.

Try the live run today supervising yesterday’s old functionality and today’s new functionality, at the one place, thanks to the HTML iframe element.

So, here we are with …

  • See the downloadable supervisory HTML and Javascript source code you could call name_those_notes_chords.html (or try its live run)
  • See today’s downloadable supervised (optionally via iframe) HTML and Javascript source code you could call name_those_chords.html (or try its live run)
  • See yesterday’s downloadable supervised (optionally via iframe) HTML and Javascript source code you could call name_those_notes.html (or try its live run or see the differences to this code from yesterday with name_those_notes.html)
  • See the doubly supervised downloadable iframe HTML and Javascript source code MyScale.html
  • See the doubly supervised downloadable iframe HTML and Javascript source code differences from a day ago via MyScale.html

The code is based on the wonderful software ideas (with thanks) from …

Hope you enjoy the extended difficulty of our musical game. It’s getting very challenging!


Previous relevant HTML/Javascript Music Pitch Game Tutorial is shown below.

HTML/Javascript Music Pitch Game Tutorial

HTML/Javascript Music Pitch Game Tutorial

Yesterday we continued on with the MIDI music web application (as you can see below with HTML/Javascript/PHP Compose Music Tutorial) we’ve been working on almost to the point of it being useful to be called upon within an HTML iframe element to be useful in other ways.

If you write lots of your own web applications, and they are all sitting in the same domain, then the HTML iframe element is a great tool for web application code modularisation, rather than rewriting the cart, the horse and the wheel all while still trying to perfect that breakfast in bed with coffee made via thought transference, and sending drones to active robots to do your office work (project) … that can wait.

If you see people critical of the iframe element it is usually due to security concerns, and cross-domain use of the HTML iframe element does not always work. You can do things in your code to restrict misuse.

End of rave … today we test your “Perfect Pitch” … well, maybe?!

Try the live run today and maybe it is enlightening or maybe not. After all, many musical instruments are really sensitive to the environment around them, and whether they are in tune. All we can say here, is that the computer approximates what it thinks is the sound frequency required to produce a certain note, and maybe that is what you see it as too … if so, it is likely you have perfect pitch, but maybe if you are always, like, a semitone off the same way each time, it could be something else going on.

So, here we are with …

  • See the downloadable supervisory HTML and Javascript source code you could call name_those_notes.html (or try its live run)
  • See the downloadable iframe HTML and Javascript source code MyScale.html
  • See the downloadable iframe HTML and Javascript source code differences from a day ago via MyScale.html

The code is based on the wonderful software ideas (with thanks) from …

Hope you enjoy the game where you score one point for a match of note in a generic sense, and five points for an exact match of a note, in its correct octave (where middle C (in a piano) is known as C4. Try it out.


Previous HTML/Javascript/PHP Compose Music Tutorial is shown below.

HTML/Javascript/PHP Compose Music Tutorial

HTML/Javascript/PHP Compose Music Tutorial

Yesterday we set up the MIDI music web application we’ve been working on to take the first steps with composing, with HTML/Javascript Music Follow Up Tutorial as shown below, and as you may recall from this the idea that the GET method would cause URLs that are too long for the web browser with any length to your musical composition, and that we’d have to involve the POST method on an HTML form element, perhaps feeding this through to a server-side language like PHP … well, it panned out this involvement of PHP and HTML forms was overkill for “playing” these long pieces … for that we could resort to “hidden” input text fields … but … yes, there’s always a but … when we got to wanting to be able to save our compositions, and come back to them for playing or tweaking, or both, we could not avoid the use of a server-side language (for us, this is PHP) and the interface to that server-side language, an HTML form element … basically because how else are you going to be able to save the composition to a file, and then reread that file? You need a language like PHP.

So, here we are, still needing to calibrate the Italian speed words methinks, but otherwise, now, we can (on laptops only, it looks like) …

  • play a note
  • play scales and arpeggios
  • play a small tune … and as of today …
  • play a longer tune
  • compose a tune you can play (but you’ll need earplugs for our “Rhapsody in Puce”)
  • save a composed tune and recall it for playing (where PHP needed)

… but still no match for the complex scenarios sheet music can handle … still, we’re getting there … speaking of which …

Hope you enjoy the ideas. We got ours (with thanks) from …


Previous relevant HTML/Javascript Music Follow Up Tutorial is shown below.

HTML/Javascript Music Follow Up Tutorial

HTML/Javascript Music Follow Up Tutorial

We follow up on our HTML/Javascript Music Primer Tutorial as shown below, today, by setting our minds to a “first draft” of a method to construct a tune in MIDI … say “first draft” because, it is often easier on a “first draft” to involve GET parameters with a URL, for ease of testing. This idea is a “first draft” because there are limits with URL lengths allowable this way, and in order to get around more involved examples than today’s first few bars of Für Elise (by Beethoven), we’ll need a subsequent draft that caters for POST parameters involving, perhaps, an HTML form and maybe calling on server-side PHP work … we’ll have to see.

So what can get sorted out with this “first draft” idea? How about sorting out an internal protocol of communication of data? This type of decision is a hugely important part of the design phases of a project. We’ve opted for …

  • comma separated word list
  • special rules for the user regarding these, with respect to …
    1. one “+” sign at start or end signifies two notes are playing at once (during any and all ideas of below)
    2. rests … via “0”
    3. volume … via leading “0” value
    4. note (or rest) length … via negative number (loosely) based on -1 = crotchet
    5. MIDI note (ie. sound frequency) … via number as the MIDI note code or decimal frequency
    6. speed … Italian words Largo or Larghetto or Adagio or Andante or Moderato or Allegro or Presto or slowx? or slowby? or fastx? or fastby?

… eg. first few bars of Für Elise … URL …

http://www.rjmprogramming.com.au/HTMLCSS/MIDI.js-master/examples/MyScale.html?sheetmusic=largo,slowby3,64,-0.50,63,-0.50,64,-0.50,63,-0.50,64,-0.50,59,-0.50,62,-0.50,60,-0.50,+57,-1.0+,+33,-0.50+,+40,-0.50+,45,-0.50,48,-0.50,52,-0.50,57,-0.50

… and, yes, realize sheet music can cater for much more functionality than above … today is just a start, but feel free to …

Hopefully more to come, but, “consider this”.


Previous relevant HTML/Javascript Music Primer Tutorial is shown below.

HTML/Javascript Music Primer Tutorial

HTML/Javascript Music Primer Tutorial

We discovered some great HTML and Javascript code to help make music with a web application, and for this we want to thank and congratulate mudcube for some really great software.

In addition to that we found at The Glass Armonica a wonderfully useful table to use as a basis for the user to “make music”.

If you’ve learnt a musical instrument, you may have self-taught yourself by playing songs, maybe on a guitar, by working out the basic chords, but, here, today, we start the “music” ball rolling with some scales and arpeggios. If it was good enough for J.S. Bach, who are we mere mortals, to complain … whinge, maybe … but never complain. Learning the piano was given this book we just called “Hanon” which did a thorough job of making scale type practice more interesting, but personally, couldn’t wait to get to more melodic music.

Anyway, how do you feel about synthesised music? Guess a lot of people are okay with it, but there’ll be others who “try” to avoid it … but think it might be pretty hard to completely avoid it now with so much involvement with computers and such. Maybe we should do some research with the excellent article Best Synthesizer | Beginner Guitar HQ, and see some of this history according to Wikipedia, and what it has written regarding synthesiser (and while you are there, read about MIDI).

So the software, in its “innards” will be concerned with calculating sound frequencies … because it’s all about waves man person. If the music is long lasting, maybe a bit like a permanent wave, man person.

If you like, take a look at the HTML and Javascript code you could call MyScale.html or execute a live run.

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


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


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


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


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


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

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

Mister Ed Mathematics Primer Tutorial

Mister Ed Mathematics Primer Tutorial

Mister Ed Mathematics Primer Tutorial

Well, we all know …

A horse is a horse, of course, of course …

… and it’s become apparent to Nala that …

No one can talk to a horse, of course …

… but as Luna would tell you …

That is, of course, unless the horse is the famous Mister Ed!

And we wanted to harness these mathematical skills to write a new web application rewarding those eager beaver budding mathematicians (and, presumably, giving short shrift to people) with … well, see for yourself with the “how we got there” mr_ed_maths.html Mister Ed Maths web application …

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

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

Code Difference AlmaLinux HTML Issue Followup Tutorial

Code Difference AlmaLinux HTML Issue Followup Tutorial

Code Difference AlmaLinux HTML Issue Followup Tutorial

Web application solutions, looking at them the next day, can often throw up …

There’s more to it than that.

… ideas, especially if you’ve been beavering away at the one code source (section), and the overall solution might involve more than that. And it may be …

  • your own followup testing … or …
  • your own followup usage (somewhere else, that annoys) … or …
  • someone else’s observations

… which gets you to realize you’ve only addressed one part of several parts to an overall solution. This occurred regarding Code Difference AlmaLinux HTML Issue Tutorial from a couple of days ago, and us happening upon a link like the https://www.rjmprogramming.com.au/HTMLCSS/body_cavities.html-GETME (and we’re only worrying about .html and GETME style URLs here) of …


https://www.rjmprogramming.com.au/HTMLCSS/body_cavities.html-GETME
https://www.rjmprogramming.com.au/HTMLCSS/body_cavities.html-GETME

… is like one we’d use at this blog but want it to display code, and in this scenario we often display …

  1. a code differences link … the problems of which we addressed in part one of the solution a few days ago …
  2. a link like above that is meant to display HTML code …
  3. as applicable, a link to the web application involved

So, as of a couple of days ago, that middle one would do something, for HTML code links, but not what we were expecting. But because we have that access to the WordPress blog TwentyTen theme header.php PHP codex code, we can amend as per (working off the structure of a previous modification you can read about at WordPress Table Cell Nests Code Element Overflow Issue Tutorial) …

<?php

function calendar_pass() {
var thisc='', thiscc='', thist='', jiicp=0, thisdate='', thistime='', nexttime='', thishour=0, nexthour=0, thisminute='', thissecond='00', thisurl='';
var h1cps=docgetclass('entry-title','*'); //document.getElementsByTagName('h2');
var tdzs=document.getElementsByTagName('td'), itdzs=0;
var cps=document.getElementsByTagName('a');
var cdes=document.getElementsByTagName('code');
var mfnd=false, washref='';
for (var ijcal=0; ijcal<cps.length; ijcal++) { // new calendar links background image
// Check for GETME links for .htm and no diff.php mention
if (('' + cps[ijcal].href).toLowerCase().indexOf('.htm') != -1 && ('' + cps[ijcal].href).indexOf('GETME') != -1 && ('' + cps[ijcal].href).indexOf('diff.php') == -1) {
washref=('' + cps[ijcal].href);
cps[ijcal].href='//www.rjmprogramming.com.au/PHP/Geographicals/diff.php?zero=' + encodeURIComponent(washref) + '#seehtmllook=n';
}

if (eval('' + ('' + cps[ijcal].href).split('/').length) == 8) {
if (eval('' + ('' + cps[ijcal].href).split('/')[4].length) == 4) {
mfnd=false;
for (itdzs=0; itdzs<tdzs.length; itdzs++) {

if (tdzs[itdzs].innerHTML.replace(String.fromCharCode(10),'').indexOf('<code') == 0 && navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
if (tdzs[itdzs].outerHTML.indexOf('-webkit-overflow-scrolling') == -1) {
if (1 == 1) {
tdzs[itdzs].innerHTML=tdzs[itdzs].innerHTML.replace('<code>','<code style="-webkit-overflow-scrolling:touch;overflow:scroll;">').replace('<code style="','<code style="-webkit-overflow-scrolling:touch;overflow:scroll;');
} else {
tdzs[itdzs].WebkitOverflowScrolling='touch';
tdzs[itdzs].Overflow='scroll';
}
}
}

if (tdzs[itdzs].innerHTML == cps[ijcal].outerHTML) {
tdzs[itdzs].className=cps[ijcal].title.replace(/\ /g,'_');
tdzs[itdzs].onclick=function(evt){ window.open('//www.rjmprogramming.com.au/ITblog/' + evt.target.innerHTML.split(' title="')[1].split('"')[0].toLowerCase().replace(String.fromCharCode(35), "").replace(".", "").replace(".", "").replace(".", "").replace("+", "").replace("+", "").replace("'", "").replace('%27','').replace(/\//g, "-").replace(/,/g, "").replace("---","-").replace("---","-").replace(/--/g,"-").replace(" ","-").replace(" ","-").replace(" ","-").replace(" ","-").replace(" ","-").replace(" ","-").replace(" ","-").replace(" ","-").replace(" ","-").replace(" ","-").replace(" ","-").replace(" ","-").replace(" ","-").replace(" ","-"), '_blank', 'top=50,left=50,width=1200,height=900'); };
mfnd=true;
}
}
if (!mfnd) {
cps[ijcal].onmouseover=function(evt){ var pbs=('' + evt.target.href).split('/'); if (document.head.innerHTML.indexOf('[title=' + "'" + evt.target.title + "'" + ']') == -1) { document.head.innerHTML+=' <style> [title=' + "'" + evt.target.title + "'" + '] { ' + ' background:url(//www.rjmprogramming.com.au/ITblog/500/500/?random=178654345&mustbedated=' + pbs[4] + pbs[5] + pbs[6] + ') center center no-repeat; background-size:cover; } </style> '; } };
} else {
cps[ijcal].onmouseover=function(evt){ var pbs=('' + evt.target.href).split('/'); if (document.head.innerHTML.indexOf(' .' + evt.target.title.replace(/\ /g,'_') + ' {') == -1) { document.head.innerHTML+=' <style> .' + evt.target.title.replace(/\ /g,'_') + ' { ' + ' background:url(//www.rjmprogramming.com.au/ITblog/500/500/?random=178654345&mustbedated=' + pbs[4] + pbs[5] + pbs[6] + ') center center no-repeat !important; background-size:cover; } </style> '; } };
}
}
}
}
//for (itdzs=0; itdzs<cdes.length; itdzs++) {
// cdes[itdzs].className='notranslate';
// cdes[itdzs].translation='no';
//}
for (var iicp=0; iicp<h1cps.length; iicp++) {
thist=h1cps[iicp].innerHTML.split(' <')[0].split('<')[0];
thisurl='';
if (h1cps[iicp].innerHTML.indexOf(' id="d') != -1) {
thisurl="//www.rjmprogramming.com.au/ITblog/" + h1cps[iicp].innerHTML.split(' id="d')[1].split('"')[0];
}
if (jiicp < cps.length) {
while (jiicp < cps.length && (cps[jiicp].innerHTML.indexOf(' content="') == -1 || cps[jiicp].innerHTML.indexOf('&#') != -1)) {
jiicp++;
}
if (jiicp < cps.length) {
if (cps[jiicp].title.indexOf(':') != -1) {
thisdate=cps[jiicp].innerHTML.split(' content="')[1].split('"')[0].replace('-','').replace('-','');
thishour=eval(cps[jiicp].title.split(':')[0]);
nexthour=thishour;
if (cps[jiicp].title.indexOf(' pm') != -1 && thishour < 12) thishour+=12;
if (thishour < 12) {
nexthour+=12;
} else if (nexthour < 23) {
nexthour=23;
}
thisminute=cps[jiicp].title.split(':')[1].split(' ')[0];
thistime=':' + ('0' + thishour).slice(-2) + thisminute + thissecond;
nexttime=':' + ('0' + nexthour).slice(-2) + thisminute + thissecond;
//alert(thist + ' ' + thisurl + ' ' + thisdate + thistime);
//alert("//www.rjmprogramming.com.au/PHP/ics_attachment.php?id=0&inhouse_ynft=y&eventwords=test&title=" + encodeURIComponent(thist) + '&stage=' + encodeURIComponent(h1cps[iicp].innerHTML.split(' id="d')[1].split('"')[0]) + '&datestart=' + encodeURIComponent(thisdate + thistime) + '&dateend=' + encodeURIComponent(thisdate + thistime) + '&emode=Address&address=Address&description=Description&url=' + encodeURIComponent(thisurl));
//window.open("//www.rjmprogramming.com.au/PHP/ics_attachment.php?id=0&tz=" + encodeURIComponent("Australia/Perth,Australia/Perth") + "&inhouse_ynft=y&eventwords=test&title=" + encodeURIComponent(thist) + '&stage=' + encodeURIComponent(h1cps[iicp].innerHTML.split(' id="d')[1].split('"')[0]) + '&datestart=' + encodeURIComponent(thisdate + thistime) + '&dateend=' + encodeURIComponent(thisdate + nexttime) + '&emode=AndTo&address=' + encodeURIComponent('rmetcalfe15@gmail.com') + '&description=Description&url=' + encodeURIComponent(thisurl), '_blank', 'top=45,left=55,width=600,height=600');
thisc="//www.rjmprogramming.com.au/PHP/ics_attachment.php?id=0&tz=" + encodeURIComponent("Australia/Perth,Australia/Perth") + "&inhouse_ynft=y&eventwords=test&title=" + encodeURIComponent(thist) + '&stage=' + encodeURIComponent(h1cps[iicp].innerHTML.split(' id="d')[1].split('"')[0]) + '&datestart=' + encodeURIComponent(thisdate + thistime) + '&dateend=' + encodeURIComponent(thisdate + nexttime) + '&emode=To&address=emailAddress&description=Description&url=' + encodeURIComponent(thisurl);
thiscc="//www.rjmprogramming.com.au/PHP/ics_attachment.php?id=0&tz=" + encodeURIComponent("Australia/Perth,Australia/Perth") + "&inhouse_ynft=y&eventwords=test&title=" + encodeURIComponent(thist) + '&stage=' + encodeURIComponent(h1cps[iicp].innerHTML.split(' id="d')[1].split('"')[0]) + '&datestart=' + encodeURIComponent(thisdate + thistime) + '&dateend=' + encodeURIComponent(thisdate + nexttime) + '&emode=Address&address=&description=Description&url=' + encodeURIComponent(thisurl);

cps[jiicp].innerHTML+=' <a id="oe' + h1cps[iicp].innerHTML.split(' id="d')[1].split('"')[0] + '" title="Change order of blog posts (now newest to oldest) to oldest through to newest (like a book)" target=_blank style="text-decoration:none;cursor:pointer;" onclick="hrrearrange(this);">&#128256;</a>';

cps[jiicp].innerHTML+=' <a id="ce' + h1cps[iicp].innerHTML.split(' id="d')[1].split('"')[0] + '" title="Create iCal Calendar Event ' + thist + '" target=_blank href="' + "//www.rjmprogramming.com.au/PHP/ics_attachment.php?id=0&tz=" + encodeURIComponent("Australia/Perth,Australia/Perth") + "&inhouse_ynft=y&eventwords=test&title=" + encodeURIComponent(thist) + '&stage=' + encodeURIComponent(h1cps[iicp].innerHTML.split(' id="d')[1].split('"')[0]) + '&datestart=' + encodeURIComponent(thisdate + thistime) + '&dateend=' + encodeURIComponent(thisdate + nexttime) + '&emode=AndTo&address=' + encodeURIComponent('rmetcalfe15@gmail.com') + '&description=Description&url=' + encodeURIComponent(thisurl) + '">&#128197;</a>';
cps[jiicp].innerHTML+=' <iframe id="ice' + h1cps[iicp].innerHTML.split(' id="d')[1].split('"')[0] + '" src="about:blank" style="display:none;width:1px;height:1px;"></iframe><a title="Email and Create iCal Calendar Event ' + thist + '" target=_blank href="#" onclick=" var emtwo=prompt(' + "'" + 'Who do we email to?' + "','fillin@email.in'); document.getElementById('ice" + h1cps[iicp].innerHTML.split(' id="d')[1].split('"')[0] + "').src='" + thisc + "'.replace(/emailAddress/g, encodeURIComponent(emtwo)); window.open('" + thiscc + "','_blank'); \">&#10133;</a>";
cps[jiicp].innerHTML+=' <a id="ee' + h1cps[iicp].innerHTML.split(' id="d')[1].split('"')[0] + '" title="Email iCal Calendar Event ' + thist + '" target=_blank href="#" onclick=" var em=prompt(' + "'" + 'Who do we email to?' + "','fillin@email.in'); window.open('" + thisc + "'.replace(/emailAddress/g, encodeURIComponent(em)),'_blank'); \">&#128231;</a>";
jiicp+=3;
cps=document.getElementsByTagName('a');
}
}
}
}
}

?>

… coupled with changes to diff.php inhouse PHP code that go

<?php

$seehtml=isset($_GET['seehtmllook']);
if (!$seehtml) { $seehtml=isset($_POST['seehtmllook']); }

if (isset($_GET['zero'])) {
if (strlen($_GET['zero']) > 0 && strpos(strtolower(str_replace('+',' ',urldecode($_GET['zero']))), '.htm') !== false) {
if (strpos(str_replace('+',' ',urldecode($_GET['zero'])), 'rjmprogramming.com.au') !== false || strpos(str_replace('+',' ',urldecode($_GET['zero'])), '/') !== false || $seehtml) {
if ($seehtml) {
header('Location: ' . str_replace('+',' ',urldecode($_GET['zero'])));
exit;
} else if (strpos(str_replace('+',' ',urldecode($_GET['zero'])), 'rjmprogramming.com.au') !== false) {
$zcont=str_replace("\n","<br>",str_replace(' ','&nbsp;',str_replace('&#','&#',str_replace('>','>',str_replace('<','<', file_get_contents($_SERVER['DOCUMENT_ROOT'] . explode('rjmprogramming.com.au',str_replace('+',' ',urldecode($_GET['zero'])))[1]) ) ))));
echo '<html><body title="Double click toggles between file and look modes for ' . str_replace('+',' ',urldecode($_GET['zero'])) . '" ondblclick="if (top.document.URL.indexOf(' . "'&seehtmllook='" . ') != -1) { top.location.href=top.document.URL.replace(' . "'seehtmllook','seeXhtmllook'" . '); } else { top.location.href=top.document.URL.split(' . "'#'" . ')[0] + ' . "'&seehtmllook=y'" . '; }">' . $zcont . '</body></html>';
exit;
} else if (strpos(str_replace('+',' ',urldecode($_GET['zero'])), '/') !== false) {
$zcont=str_replace("\n","<br>",str_replace(' ','&nbsp;',str_replace('&#','&#',str_replace('>','>',str_replace('<','<', file_get_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . str_replace('+',' ',urldecode($_GET['zero'])))) ))));
echo '<html><body title="Double click toggles between file and look modes for ' . str_replace('+',' ',urldecode($_GET['zero'])) . '" ondblclick="if (top.document.URL.indexOf(' . "'&seehtmllook='" . ') != -1) { top.location.href=top.document.URL.replace(' . "'seehtmllook','seeXhtmllook'" . '); } else { top.location.href=top.document.URL.split(' . "'#'" . ')[0] + ' . "'&seehtmllook=y'" . '; }">' . $zcont . '</body></html>';
//echo $zcont;
exit;
}
}
}
} else if (isset($_POST['zero'])) {
if (strlen($_POST['zero']) > 0 && strpos(strtolower(str_replace('+',' ',urldecode($_POST['zero']))), '.htm') !== false) {
if (strpos(str_replace('+',' ',urldecode($_POST['zero'])), 'rjmprogramming.com.au') !== false || strpos(str_replace('+',' ',urldecode($_POST['zero'])), '/') !== false || $seehtml) {
if ($seehtml) {
header('Location: ' . str_replace('+',' ',urldecode($_POST['zero'])));
exit;
} else if (strpos(str_replace('+',' ',urldecode($_POST['zero'])), 'rjmprogramming.com.au') !== false) {
$zcont=str_replace("\n","<br>",str_replace(' ','&nbsp;',str_replace('&#','&#',str_replace('>','>',str_replace('<','<', file_get_contents($_SERVER['DOCUMENT_ROOT'] . explode('rjmprogramming.com.au',str_replace('+',' ',urldecode($_POST['zero'])))[1]) ) ))));
echo '<html><body title="Double click toggles between file and look modes for ' . str_replace('+',' ',urldecode($_POST['zero'])) . '" ondblclick="if (top.document.URL.indexOf(' . "'&seehtmllook='" . ') != -1) { top.location.href=top.document.URL.replace(' . "'seehtmllook','seeXhtmllook'" . '); } else { top.location.href=top.document.URL.split(' . "'#'" . ')[0] + ' . "'&seehtmllook=y'" . '; }">' . $zcont . '</body></html>';
//echo $zcont;
exit;
} else if (strpos(str_replace('+',' ',urldecode($_POST['zero'])), '/') !== false) {
$zcont=str_replace("\n","<br>",str_replace(' ','&nbsp;',str_replace('&#','&#',str_replace('>','>',str_replace('<','<', file_get_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . str_replace('+',' ',urldecode($_POST['zero'])))) ))));
echo '<html><body title="Double click toggles between file and look modes for ' . str_replace('+',' ',urldecode($_POST['zero'])) . '" ondblclick="if (top.document.URL.indexOf(' . "'&seehtmllook='" . ') != -1) { top.location.href=top.document.URL.replace(' . "'seehtmllook','seeXhtmllook'" . '); } else { top.location.href=top.document.URL.split(' . "'#'" . ')[0] + ' . "'&seehtmllook=y'" . '; }">' . $zcont . '</body></html>';
//echo $zcont;
exit;
}
}
}
}


?>


Previous relevant Code Difference AlmaLinux HTML Issue Tutorial is shown below.

Code Difference AlmaLinux HTML Issue Tutorial

Code Difference AlmaLinux HTML Issue Tutorial

We’re pretty sure we have an Apache PHP arrangement difference affecting our Code Difference Reporting of HTML Based Code (since Code Difference Report Mixed Content Issue Tutorial) between moving from …

  • CentOS Apache PHP version starting with a 5 … to …
  • AlmaLinux Apache PHP version starting with an 8

… whereby our GETME suffix code versioning inhouse arrangements are affected, because it seems on AlmaLinux, unlike with CentOS a URL such as …


https://www.rjmprogramming.com.au/HTMLCSS/body_cavities.html-GETME
https://www.rjmprogramming.com.au/HTMLCSS/body_cavities.html-GETME

… shows the content as an HTML webpage, whereas we’re used to seeing this display the HTML code contained within that file.

Our code difference reporting system worked that way, ideally. Other extensions like *.php* based ones act the same way between CentOS and AlmaLinux, but we’ve decided to live with this “new woooorrrrllldddd order”, and turn it, in a mild way, to our advantage, offering code difference report readers of *.html* code the chance now to …

  • see the content as the HTML text within … now that we intervene with PHP code such as

    <?php

    // initially ...
    $seehtml=isset($_GET['seehtmllook']);
    $latestfile="Latest file ";

    // ... and then later, within PHP mapit function ... PHP code snippets like ...
    if (!$seehtml) {
    $oneis=str_replace('+',' ',urldecode($_GET['two']));
    if (strpos(strtolower(str_replace('.html_getme','.html-GETME',$oneis)), '.html-') !== false && strpos(strtolower(str_replace('.html_getme','.html-GETME',$oneis)), '-getme') !== false) {
    $latestfile="Latest <select onchange=\" top.location.href=top.document.URL.replace('?','?seehtmllook=y&');\"><option value=''>file</option><option value='look'>look</option></select> ";
    file_put_contents($_SERVER['DOCUMENT_ROOT'] . '/two.html', str_replace("~!@#","
    ",str_replace('<','&gt;',str_replace('<','&lt;',str_replace("\n","~!@#",file_get_contents($_SERVER['DOCUMENT_ROOT'] . explode('rjmprogramming.com.au',$oneis)[1]))))));
    return '/two.html';
    }
    } else if (strpos(strtolower(str_replace('.html_getme','.html-GETME',str_replace('+',' ',urldecode($_GET['two'])))), '.html-') !== false && strpos(strtolower(str_replace('.html_getme','.html-GETME',str_replace('+',' ',urldecode($_GET['two'])))), '-getme') !== false) {
    $latestfile="Latest <select onchange=\" top.location.href=top.document.URL.replace('seehtmllook=','seehtmlXlook=');\"><option value='look'>look</option><option value=''>file</option></select> ";
    }

    return str_replace('+',' ',urldecode($_GET['two']));

    ?>

    … gotten to in this different way

    <?php

    $mapitoneone=mapit('one.one');
    $mapittwotwo=mapit('two.two');

    $iframebits="<h1 id=latest_file" . $suffid . ">" . $latestfile . postmapit('...') . " <a href=#differences" . $suffid . " title=Differences>Differences</a> below this ... " . hit($_GET['one']) . "</h1><br><details open><summary></summary><iframe onload=mayberework(this); style='" . $bciy . "width:100%;height:300px;' height=300 src=" . $mapitoneone . "?randone=" . rand(0,564533) . " title='" . $_GET['one'] . "'></iframe></details><br>";
    $iframebits.="<h1 id=differences" . $suffid . ">Differences" . $haskbit . " <a href=#latest_file" . $suffid . " title=Latest>^</a> <a href=#older_file" . $suffid . " title=Older>v</a>" . $legend . "</h1><br><details open><summary></summary><iframe onload=mayberework(this); style='background-color:pink;width:100%;height:300px;' height=300 id=ifhuh src='huh" . server_remote_addr() . ".huh?rand=" . rand(0,5645342) . "' title='Differences between " . $_GET['one'] . " and " . str_replace("--GETME", "-GETME", $_GET['one']) . "'></iframe></details><br>";
    $iframebits.="<h1 id=older_file" . $suffid . ">Older file ... <a href=#differences" . $suffid . " title=Differences>Differences</a> just above ... " . hit(str_replace("--GETME", "-GETME", $_GET['one'])) . "</h1><br><details open><summary></summary><iframe onload=mayberework(this); style='background-color:lightgreen;width:100%;height:300px;' height=300 src=" . $mapittwotwo . "?randtwo=" . rand(0,564533) . " title='" . str_replace("--GETME", "-GETME", $_GET['one']) . "'></iframe></details><br>";

    ?>

    … or …

  • see the content as the HTML look … via an option on a newly presented dropdown … as per


    … toggleable to see it like

… to give a CMS (Content Management System) feel to this report in a changed diff.php PHP code basis, for this.


Previous relevant Code Difference Report Mixed Content Issue Tutorial is shown below.

Code Difference Report Mixed Content Issue Tutorial

Code Difference Report Mixed Content Issue Tutorial

It took us a long time, but we now feel we’re better across, writing web applications, and dealing with URLs, that …

  • not mentioning protocols http: nor https: specifically is preferable …
  • As time goes on, more and more we see the benefits of URLs that start with “/” (but not HTTP:// nor HTTPS:// absolute URL designations), especially when it comes to pointing at a “tool” (eg. external Javascript). It has
    the benefits of …

    • is programmer controlled, so they can place the tool in Document Root folder (in the case of an Apache web server) … and, in so doing …
    • it’s irrelevant where the “parent” (calling) web application is placed … and …
    • mixed content issues are avoided by not using an absolute URL, though it kind of, is!

… both ideals above related to Mixed Content (ie. involving “competing protocols” within a webpage).

Sometimes, however, you can’t help but have to deal with explicit http: and/or https: protocol syntax. It is that way calling our Differences Reporting PHP web application. And we figure, we opened a small can of worms performing the work of the recent Code Difference Highlighting User Interface Tutorial, and in so doing, we hope, sincerely …

  • really improved those middle HTML iframe Linux diff based Difference Reports … but may have opened us up to …
  • upper and lower HTML iframes, containing new and old code versions respectively, sometimes had Mixed Content issues that stopped them displaying

Consider a URL such as …


https://www.rjmprogramming.com.au/PHP/Geographicals/diff.php?one=HTTP://www.rjmprogramming.com.au/PHP/australia_place_crowfly_distances.php-------GETME&f0=&f1=&f2=&f3=&f4=&f5=&f6=

… or …


http://www.rjmprogramming.com.au/PHP/Geographicals/diff.php?one=HTTPS://www.rjmprogramming.com.au/PHP/australia_place_crowfly_distances.php-------GETME&f0=&f1=&f2=&f3=&f4=&f5=&f6=

… and we suspect either of these two URLs might have caused this upper and lower HTML iframes issue up until today. How did we approach the remedy? We could have …

  • detected the Mixed Content potential of the incoming URL and in the PHP reissued the address bar call, effectively, via a header(‘Location: [newUrlFixedForNiMixedContent]’); style of recall … or, what we ended up doing, being (some readers may find the following “a little bit kludgy , this kludgy inside 🎵, am not one of those, who easily 🎶 kludgifies (at least in public)“)
  • stayed on the same PHP execution call via …
    <?php

    if (isset($_GET['one'])) { // && !isset($_GET['two'])) {
    if (strpos(('' .$_SERVER['SERVER_PORT']), '443') !== false && strpos(strtoupper($_GET['one']), 'HTTP') !== false && strpos(strtoupper($_GET['one']), 'HTTPS') === false) {
    $_GET['one']='HTTPS' . substr($_GET['one'], 4);
    } else if (strpos(('' .$_SERVER['SERVER_PORT']), '443') === false && strpos(strtoupper($_GET['one']), 'HTTPS') !== false) {
    $_GET['one']='HTTP' . substr($_GET['one'], 5);
    }
    if (isset($_GET['two'])) {
    if (strpos(('' .$_SERVER['SERVER_PORT']), '443') !== false && strpos(strtoupper($_GET['two']), 'HTTP') !== false && strpos(strtoupper($_GET['two']), 'HTTPS') === false) {
    $_GET['two']='HTTPS' . substr($_GET['two'], 4);
    } else if (strpos(('' .$_SERVER['SERVER_PORT']), '443') === false && strpos(strtoupper($_GET['two']), 'HTTPS') !== false) {
    $_GET['two']='HTTP' . substr($_GET['two'], 5);
    }
    }

    // more PHP
    }

    ?>

… to not mix any of the apples with any of the pears!


Previous relevant Code Difference Highlighting User Interface Tutorial is shown below.

Code Difference Highlighting User Interface Tutorial

Code Difference Highlighting User Interface Tutorial

Unless a piece of your web application functionality is categorized as “internal use only” you, as a programmer, will want to offer functionality that does not ask the user to remember some arcane URL (GET ? and &) arrangement at the address bar of a web browser. And so, onto yesterday’s Code Difference Highlighting Tutorial, talking about our inhouse PHP Code Difference Reporting functionality, we wanted to offer …



… which is, in raw HTML, at initialization …


<input onchange=doprehs(this.value,0); title="Highlight colour" style=display:inline-block;width:2%; type=color id=mcol value="#000000"><input style="width:18%;background-color:yellow;" onblur="if (this.value.length > 0) { location.href=(document.URL.replace('highlight=','hl=').split(String.fromCharCode(35))[0] + '&highlight=' + encodeURIComponent(prehs + this.value.replace(/\;/g,'U+0003B'))).replace('.php&','.php?');; }" id="myhl" value="" title="Highlight optionally entered string." placeholder="Highlight optionally entered string."></input><input onchange=doprehs(this.value,1); title="Highlight background colour" style=display:inline-block;width:2%; type=color id=mbcol value="#ffff00"></input>

… those two HTML input type=color “textboxes”, respectively, addressing how the HTML mark highlighting element is coloured, via …

  • color (default black)
  • background-color (default yellow)

… as a new highlight functionality feature introduced today in diff.php code or try it yourself here.

Stop Press

The PHP diff.php code got changed so that a user entered comma separated list will be scrutinised for whether it represents a single string to find, or if highlighting should happen for each list member in the comma separated list.


Previous relevant Code Difference Highlighting Tutorial is shown below.

Code Difference Highlighting Tutorial

Code Difference Highlighting Tutorial

We last mentioned our inhouse PHP code difference mechanism with …

It meant, in that scenario yesterday, when a single variable usage “tells a story” in the code, this code difference highlighting might be more effective at explaining the issues rather than showing the code in a code element (even with inhouse colour coding), because there is also the “before” and “after” scenarios there on the screen for the reader to contextualize. See the newly changed PHP diff.php code or try it yourself here.


Previous relevant Code Difference Saved User Settings Tutorial is shown below.

Code Difference Saved User Settings Tutorial

Code Difference Saved User Settings Tutorial

As a PHP programmer it is easy to admire …

  • the server side file and database and operating system smarts of the great serverside language PHP is … all while …
  • PHP writing out HTML (with its CSS and Javascript) has a web application able to access all that clientside intelligence

… and with this in mind, we allow for saved CSS styling user settings, as of today, with our Difference Report web application arrangements.

Don’t we need a database for this? Well, that is possible, and with serverside PHP, could be done, but we opt for clientside window.localStorage usage to …

  • Save user CSS styling settings
  • Recall user CSS styling settings

… so that a user might opt to “set and forget” their preferred set of …

  • New additional
  • Changed single line
  • New block of lines
  • Deleted lines
  • Changed multiple lines

… (CSS Selector) sensitive “categories” of Difference Report data type settings.

As a result, building on yesterday’s Code Difference User Settings Tutorial, the deployment of CSS selector logic, in PHP, now changes to …

<?php

$style="<style> font { text-shadow: -1px 1px 1px #ff2d95; } </style>";
$legend="";
$mx="";
$onecommand=" function nocaret(invx) { var outvx=decodeURIComponent(invx); while (outvx.indexOf('<') > outvx.indexOf('>')) { outvx=outvx.replace('>' + outvx.split('>')[1].split('<')[0] + '<',''); } return encodeURIComponent(outvx); } function onb(event) { var othis=event.target, cih=''; if (('' + othis.id + ' ').substring(0,1) == 'f') { cih=('' + window.localStorage.getItem('diff_' + othis.id)).replace(/^undefined$/g,''.replace(/^null$/g,'')); if (('' + othis.innerHTML.replace(/\ \;/g,' ') + '~~').indexOf(' ~~') != -1) { if (cih == '') { window.localStorage.setItem('diff_' + othis.id, encodeURIComponent('14 >' + othis.innerText + '<')); } else { window.localStorage.removeItem('diff_' + othis.id); window.localStorage.setItem('diff_' + othis.id, nocaret(cih) + encodeURIComponent(' >' + othis.innerText + '<')); } } } } function blurize(othis) { if (1 == 2) { othis.onblur=function(event) { onb(event); }; } return othis; } function perhapsih(insg,ofo) { if (insg.indexOf('<') > insg.indexOf('<') && insg.indexOf('<') != -1) { ofo.innerHTML=insg.split('>')[1].split('>')[0]; ofo.setAttribute('data-ih', insg.split('>')[1].split('>')[0]); return insg.replace('>' + insg.split('>')[1].split('>')[0] + '<', ''); } } function givef(idn,cssis) { if (('' + document.getElementById('f' + idn).title).indexOf(' ' + decodeURIComponent(cssis) + ' ') == -1) { document.getElementById('f' + idn).title=document.getElementById('lspan').title + ' You have user CSS styling friendly one off setting of ' + decodeURIComponent(cssis) + ' for this category of Difference Reporting'; } } function getmaybe(foin,defis) { var mgs=document.URL.split(foin.id + '='); thatget=('' + window.localStorage.getItem('diff_' + foin.id)).replace(/^undefined$/g,'').replace(/^null$/g,''); if (thatget != '') { if (eval('' + mgs.length) == 1) { return decodeURIComponent(thatget); } else if (mgs[1].split('&')[0].split('#')[0] == '') { return decodeURIComponent(thatget); } } if (eval('' + mgs.length) > 1) { if (mgs[1].split('&')[0].split('#')[0] != '') { return decodeURIComponent(mgs[1].split('&')[0].split('#')[0]); } } return defis; } function getany() { var mgs=[],addget='',thisget=''; if (document.URL.replace('?','&').indexOf('&f') == -1 || 1 == 1) { for (var iig=0; iig<=6; iig++) { mgs=document.URL.split('f' + iig + '='); thisget=('' + window.localStorage.getItem('diff_f' + iig)).replace(/^undefined$/g,'').replace(/^null$/g,''); if (thisget != '') { document.getElementById('f' + iig).title=document.getElementById('lspan').title + ' You have user CSS styling friendly setting of ' + decodeURIComponent(thisget) + ' for this category of Difference Reporting'; } if (eval('' + mgs.length) > 1) { if (mgs[1].split('&')[0].split('#')[0] != '') { document.getElementById('f' + iig).title=document.getElementById('lspan').title + ' You have user CSS styling friendly setting of ' + decodeURIComponent(mgs[1].split('&')[0].split('#')[0]) + ' for this category of Difference Reporting'; } } if (document.URL.replace('?','&').indexOf('&f' + iig + '=') == -1) { addget+='&f' + iig + '=' + thisget; } } } if (addget != '') { location.href=(document.URL.split('#')[0] + addget).replace('.php&','.php?'); } } setTimeout(getany,2000); function removeany(newfo) { window.localStorage.removeItem('diff_' + newfo.id); } function addany(newishfo,newwhat) { removeany(newishfo); window.localStorage.setItem('diff_' + newishfo.id, newwhat); } function askabout(fo) { var defd='14', ccol='black', ccols=fo.outerHTML.split(' color=' + String.fromCharCode(34)), psizes=fo.outerHTML.split('px'); if (eval('' + ccols.length) > 1) { ccol=ccols[1].split(String.fromCharCode(34))[0]; } if (eval('' + psizes.length) > 1) { defd=psizes[0].split(':')[eval(-1 + psizes[0].split(':').length)].trim(); } var numis=prompt('How many px (ie. pixels) do you want for the font size of these ' + fo.innerHTML + ' parts of report? Optionally append after a space a colour that is not the default colour ' + ccol + ' for this category of difference report. Optionally append after a space any other styling you want ( eg. text-shadow: -1px 1px 1px #ff2d95; ). Append spaces to save for other Coding Difference Report sessions into the future. Prefix with minus ( ie. - ) to forget any remembered setting. An entry can be > followed by a new wording for this category followed by <', getmaybe(fo,defd)); if (numis != null) { if ((perhapsih(numis,fo) + 'x').trim().substring(0,1) == '-') { removeany(fo); numis=numis.replace('-',''); } if (('' + numis).trim() != '') { if (numis.replace(/\ $/g,'') != numis) { addany(fo,encodeURIComponent(numis.trim())); } location.href=(document.URL.split('#')[0] + '&' + fo.id + '=' + encodeURIComponent(numis.trim())).replace('.php&','.php?'); } } } ";
if (isset($_GET['f0']) || isset($_GET['f1']) || isset($_GET['f2']) || isset($_GET['f3']) || isset($_GET['f4']) || isset($_GET['f5']) || isset($_GET['f6'])) {
$onecommand.=" function sizefonts() { } setTimeout(sizefonts, 3000); ";
for ($ij=0; $ij<=6; $ij++) {
if (isset($_GET['f' . $ij])) {
$ihbit="";
$words=str_replace('+',' ',urldecode($_GET['f' . $ij]));
if (strpos($words, '<') !== false && strpos($words, '>') !== false) {
if (strpos($words, '<') > strpos($words, '>')) {
$ihbit=" document.getElementById('f" . $ij . "').innerHTML='" . str_replace("'", "' + String.fromCharCode(39) + '", explode('<',explode('>',$words)[1])[0]) . "'; ";
}
}
if (trim($words) != '') { $onecommand=str_replace("} ", " givef(" . $ij . ",'" . $_GET['f' . $ij] . "'); } ", $onecommand); }
$wordsa=explode(' ', trim($words));
if (sizeof($wordsa) > 1) {
$words=substr($words,(1 + strlen($wordsa[0])));
for ($ijj=1; $ijj<sizeof($wordsa); $ijj++) {
if (strpos($wordsa[$ijj], ':') === false && $ijj == 1) {
$words=trim(substr($words,(0 + strlen($wordsa[$ijj]))));
$style.='<style> .f' . $ij . " { font-color: " . trim($wordsa[$ijj]) . '; } </style>';
$onecommand=str_replace("} ", " document.getElementById('f" . $ij . "').color='' + '" . trim($wordsa[$ijj]) . "'; document.getElementById('f" . $ij . "').style.fontColor='' + '" . trim($wordsa[$ijj]) . "'; } ", $onecommand);
}
}
if (trim($words) != '') {
if (strpos($words, "{") !== false && strpos($words, "}") !== false) {
$style.='<style> ' . $words . ' </style>';
$onecommand=str_replace("} ", " document.getElementById('dstyle').innerHTML+='<style> ' + '" . $words . " </style>'; } ", $onecommand);
} else {
$style.='<style> .f' . $ij . " { " . $words . ' } </style>';
$onecommand=str_replace("} ", " document.getElementById('dstyle').innerHTML+='<style> .f" . $ij . " { ' + '" . $words . " } </style>'; } ", $onecommand);
}
}
}
$onecommand=str_replace("} ", $ihbit . " document.getElementById('f" . $ij . "').style.fontSize='' + '" . trim($wordsa[0]) . "px'; } ", $onecommand);
$style.='<style> .f' . $ij . " { font-size: " . trim($wordsa[0]) . 'px; } </style>';
}
}
}

?>

… to start making this happen (including being able to change our “inhouse category” names, if you like) in our changed diff.php‘s more colourful Code Differences helper.


Previous relevant Code Difference User Settings Tutorial is shown below.

Code Difference User Settings Tutorial

Code Difference User Settings Tutorial

Yesterday’s Code Difference Privacy Tutorial represented too much of an echo chamber for our liking. Where possible, we prefer functionality that the users out there can tweak themselves.

In thinking about this, those 5 categories (involving 2 subcategories) …

  • New additional
  • Changed single line
  • New block of lines
  • Deleted lines
  • Changed multiple lines

… were what occurred to us could be the CSS Selector basis for us to improve the Code Difference reporting via CSS styling functionality.

Up to today the deployment of that CSS selector logic would have had to be more complex than necessary, but today’s …

  • giving new id and class attributes to the “legend” span id=lspan elements … and …
  • equivalent class attribute to report matching element data

… makes the deployment of CSS selector logic really easy, in PHP, as per …

<?php

$style="<style> font { text-shadow: -1px 1px 1px #ff2d95; } </style>";
$legend="";
$mx="";
$onecommand=" function askabout(fo) { var defd='14', ccol='black', ccols=fo.outerHTML.split(' color=' + String.fromCharCode(34)), psizes=fo.outerHTML.split('px'); if (eval('' + ccols.length) > 1) { ccol=ccols[1].split(String.fromCharCode(34))[0]; } if (eval('' + psizes.length) > 1) { defd=psizes[0].split(':')[eval(-1 + psizes[0].split(':').length)].trim(); } var numis=prompt('How many px (ie. pixels) do you want for the font size of these ' + fo.innerHTML + ' parts of report? Optionally append after a space a colour that is not the default colour ' + ccol + ' for this category of difference report. Optionally append after a space any other styling you want ( eg. text-shadow: -1px 1px 1px #ff2d95; )', defd); if (numis != null) { if (('' + numis).trim() != '') { location.href=(document.URL.split('#')[0] + '&' + fo.id + '=' + encodeURIComponent(numis.trim())).replace('.php&','.php?'); } } } ";
if (isset($_GET['f0']) || isset($_GET['f1']) || isset($_GET['f2']) || isset($_GET['f3']) || isset($_GET['f4']) || isset($_GET['f5']) || isset($_GET['f6'])) {
$onecommand.=" function sizefonts() { } setTimeout(sizefonts, 3000); ";
for ($ij=0; $ij<=6; $ij++) {
if (isset($_GET['f' . $ij])) {
$words=str_replace('+',' ',urldecode($_GET['f' . $ij]));
$wordsa=explode(' ', trim($words));
if (sizeof($wordsa) > 1) {
$words=substr($words,(1 + strlen($wordsa[0])));
for ($ijj=1; $ijj<sizeof($wordsa); $ijj++) {
if (strpos($wordsa[$ijj], ':') === false && $ijj == 1) {
$words=trim(substr($words,(0 + strlen($wordsa[$ijj]))));
$style.='<style> .f' . $ij . " { font-color: " . trim($wordsa[$ijj]) . '; } </style>';
$onecommand=str_replace("} ", " document.getElementById('f" . $ij . "').color='' + '" . trim($wordsa[$ijj]) . "'; document.getElementById('f" . $ij . "').style.fontColor='' + '" . trim($wordsa[$ijj]) . "'; } ", $onecommand);
}
}
if (trim($words) != '') {
if (strpos($words, "{") !== false && strpos($words, "}") !== false) {
$style.='<style> ' . $words . ' </style>';
$onecommand=str_replace("} ", " document.getElementById('dstyle').innerHTML+='<style> ' + '" . $words . " </style>'; } ", $onecommand);
} else {
$style.='<style> .f' . $ij . " { " . $words . ' } </style>';
$onecommand=str_replace("} ", " document.getElementById('dstyle').innerHTML+='<style> .f" . $ij . " { ' + '" . $words . " } </style>'; } ", $onecommand);
}
}
}
$onecommand=str_replace("} ", " document.getElementById('f" . $ij . "').style.fontSize='' + '" . trim($wordsa[0]) . "px'; } ", $onecommand);
$style.='<style> .f' . $ij . " { font-size: " . trim($wordsa[0]) . 'px; } </style>';
}
}
}

?>

… user tweakable (using window.prompt interactive entry) via clickable “legend” elements in our changed diff.php‘s more colourful Code Differences helper.


Previous relevant Code Difference Privacy Tutorial is shown below.

Code Difference Privacy Tutorial

Code Difference Privacy Tutorial

Yesterday’s Code Difference Colour Coding Tutorial Difference Report modifications (still) had the inherent weakness …

  • it was possible, but unlikely, for users to see other user generated reports, if they happened to be asking for reports at exactly the same time … because …
  • we had not catered for busy traffic here … but, today …
  • we cater, better, for busy online traffic … and at the same time …
  • improve the privacy of the reporting on an IP address basis

The downside, at least for us managing this, is that we do not want a build up of files belonging to difference reports long gone. We arrange it, then, that as soon as the report is created, a window.open scenario is coded for …

<?php

$legend=' <span id=lspan><span><font size=2 color=purple>New additional</font></span> <span><font size=2 color=magenta>Changed single </font><font size=2 color=indigo> line</font></span> <span><font size=2 color=blue>New block of lines</font></span> <span><font size=2 color=orange>Deleted lines</font></span> <span><font size=2 color=darkgreen>Changed multiple </font><font size=2 color=olive>lines</font> <a id=myaa onclick="var wod=window.open(' . "'','_blank','left=100,top=100,width=600,height=600'" . '); wod.document.write(' . "'<textarea title=' + document.URL + ' cols=120 rows=40 style=background-color:pink;>' + " . 'window.atob(' . "'" . trim(base64_encode(file_get_contents("huh" . server_remote_addr() . ".huh"))) . "'" . ') + ' . "'</textarea>'" . '); wod.document.title=document.URL; " style=text-decoration:underline;cursor:pointer;>Original ...</a></span></span>';

$onecommand=" function muchl() { if (document.getElementById('lspan').innerHTML.indexOf(\".atob('')\") != -1) { document.getElementById('lspan').innerHTML=document.getElementById('lspan').innerHTML.replace(\".atob('')\", \".atob('" . trim(base64_encode(file_get_contents("huh" . server_remote_addr() . ".huh"))) . "')\"); } } setTimeout(muchl,8000); ";

?>

… leaving the door open for us to tidy up straight away in our changed diff.php‘s more colourful Code Differences helper.


Previous relevant Code Difference Colour Coding Tutorial is shown below.

Code Difference Colour Coding Tutorial

Code Difference Colour Coding Tutorial

It’s coming up to a few years now, since we looked at the code differences reporting we offer the reader, as a way to scrutinize code changes, around here, when we presented Code Download Table Difference Functional Hover Tutorial. Well, we thought we might try some colour coding to perhaps lift the fog on the cryptic nature of Linux diff (difference) command based reports. They can be cryptic because they can feed into the automation feeding of the report into other Linux commands to facilitate ongoing editing endeavours, but we do not want to go into that here, at least today.

But on examining the reports we came up with the following difference report “categories” if you will …

  • New additional
  • Changed single line
  • New block of lines
  • Deleted lines
  • Changed multiple lines

… the header (of a block of interest) the dead give away, depending on the existence of “a” or “c” or “d” and/or “,” for a common sense reinterpretation by us not visiting “man diff” ourselves, yet, regarding this work.

Feel free to take a look at our changed diff.php‘s more colourful Code Differences helper.


Previous relevant Code Download Table Difference Functional Hover Tutorial is shown below.

Code Download Table Multiple Row Email Hover Tutorial

Code Download Table Difference Functional Hover Tutorial

Is it worth adding “onmouseover” event logic onto yesterday’s Code Download Table Difference Functional Linking Tutorial? You bet it is! Just because “onmouseover” has no relevance to mobile platforms, so, obversely, developing software with version control systems is irrelevant to mobile platforms.

a place for everything and everything in its place

… we figure. But this is of relevance to the programmer. Sometimes, rather than cater for all the platforms, settling on a subset (of those platforms) can be apt because …

  • one of mobile or non-mobile subsets of platforms is irrelevant to the scenario … as for today … or …
  • you try to reinvent the wheel on the pretext that you are waiting for a particular web browser or platform to allow the functionality in, into the future … you could be waiting a while, with the complexity of app arrangements going on around the net these days

Anyway, back to the “onmouseover” event on non-mobile platforms … it was the case that this event was a favourite for the conduit towards Ajax (client) functionality. And thinking on what we do today to nuance our Code Differences PHP web application, we were thinking …

What would Ajax (like to) do?

… and we decided Ajax would really like to …

  • populate a “div” style=display:inline-block; element adjacent to the functional detail to inform about … but this was not possible … so, instead, we …
  • populate a popup window near to the functional detail to inform about

… for a non-mobile “hover” (ie. “onmouseover”) event.

Along the way we add some more hashtag navigations and set up more colour coding to the output of (the optional) “functional links” Code Difference reporting.

So take a look at our changed diff.php Code Differences helper applied to itself below …


Previous relevant Code Download Table Multiple Row Email Report Tutorial is shown below.

Code Download Table Multiple Row Email Report Tutorial

Code Download Table Multiple Row Email Report Tutorial

Before leaving yesterday’s Download and Copy or Move Code Download Table Tutorial extensions to our Code Download Table functionality …

  • add copy onto a download functionality to the Code Download Table … today, we …
  • add a Multiple Row selection basis for a personalized Email Report for the user

… as we saw that there was scope for this as a sharing mechanism for project discussions and ideas, we hope.

Today’s tutorial picture tries to show the steps to emailing off a report of interest to a user …

  1. User clicks the “Allow Multiple Row Clicks” checkbox …

    prefixask=prefixask.replace('</div>', '<div id=divawrc style=display:inline-block;>  Allow Multiple Row Clicks <input onchange="domrows();" id=awrc style=inline-block; type=checkbox></input> <div id=dawrc style=display:inline-block;></div></div></div>');

    … which causes …
  2. “Report” button shows to its right …

    function domrows() {
    document.getElementById('dawrc').innerHTML='<input style=inline-block; type=button onclick=treportdo(); value=Report></input>';
    var trsis=document.getElementsByTagName('tr');
    for (var itrsis=0; itrsis<trsis.length; itrsis++) {
    trsis[itrsis].onclick = function(e) { if (e.target.innerHTML != '') { var trs=document.getElementsByTagName('tr'); for (var itrs=0; itrs<trs.length; itrs++) { if (trs[itrs].outerHTML.indexOf(e.target.innerHTML) != -1) { trs[itrs].style.border='2px dotted red'; } } } };
    }
    }

    … and table row onclick logic is dynamically applied to those “tr” elements
  3. User clicks somewhere within rows they are interested in seeing be included in a report (which is a snippet of the whole Code Download Table, perhaps to do with a project of interest, or a learning topic of interest)
  4. User optionally clicks the “Report” button …

    function treportdo() {
    var trsis=document.getElementsByTagName('tr');
    webc='<html><head><script type="text/javascript"> function emailto(eto) { window.opener.parentemailto(eto); } function xemailto(eto) { if (eto.indexOf("@") != -1) { var zhr=new XMLHttpRequest(); var zform=new FormData(); zform.append("inline",""); zform.append("to",eto); zform.append("subj","Code Download Table part"); zform.append("body",document.getElementById("mytable").outerHTML); zhr.open("post", "//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php", true); zhr.send(zform); alert("Email sent to " + eto); } } </script></head><body><table id=mytable></table><br><br><br><input onblur=emailto(this.value); placeholder="Email to" type=email></input></body></html>';
    for (var itrsis=0; itrsis<trsis.length; itrsis++) {
    if (itrsis == 0) {
    webc=webc.replace('</table>', trsis[itrsis].outerHTML + '</table>');
    }
    if (trsis[itrsis].outerHTML.indexOf('>') > trsis[itrsis].outerHTML.indexOf('border:')) {
    if (trsis[itrsis].outerHTML.indexOf('dotted') > trsis[itrsis].outerHTML.indexOf('border:')) {
    webc=webc.replace('</table>', trsis[itrsis].outerHTML + '</table>');
    }
    }
    }
    var woois=window.open('','_blank','top=20,left=20,width=600,height=600');
    woois.document.write(webc);
    }

    … which causes a …
  5. New popup window opens showing the relevant snippet of Code Download Table of interest to the user … including …
  6. Textbox for an optional emailee entry that can be filled in … to …
  7. Set off Ajax/FormData methodology means …

    function parentemailto(eto) {
    if (eto.indexOf("@") != -1) {
    var zhr=new XMLHttpRequest();
    var zform=new FormData();
    zform.append("inline","");
    zform.append("to",eto);
    zform.append("subj","RJM Programming Code Download Table part");
    zform.append("body", reltoabs('<table' + webc.split('</table>')[0].split('<table')[1] + '</table>'));
    zhr.open("post", "//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php", true);
    zhr.send(zform);
    alert("Email sent to " + eto);
    }
    }

    … to send off an Inline HTML Email report to the emailee … including …
  8. Links of email can be clicked to get back to source code and other links back at the RJM Programming domain web server

… in our changed getmelist.js external Javascript code file (that you can try out for yourself at this live run link).


Previous relevant Download and Copy or Move Code Download Table Tutorial is shown below.

Download and Copy or Move Code Download Table Tutorial

Download and Copy or Move Code Download Table Tutorial

After the “goings on” with the relatively recent PHP Blog Summary Fixed Title Events Tutorial we thought we were finished with “Code Download Table” functionality … but then …

along came Jones yesterday’s Download and Copy or Move Server Tutorial

… and … lo and behold … we saw a good use for the idea of …

  1. download from “the net” to a Downloads folder on your computer or device … and more often than not …
  2. you, the user, copies or renames this data to another location on your computer or device with command line or with operating system GUI

… and allowing for that second step above be programmatical with the most apt functionality that had ever passed our cotton pickin’ mind … our Code Download Table … wi’ all tho’ GETME’s!

But we don’t want to interfere too much with the Code Download Table “flow” here, so create up the top left 20 seconds worth of time (extendable by their actions) available to the user to create “download” attributes on all …

  • “a” links … with …
  • “href” attribute containing “GETME” …
  • but not “diff.php” … and …
  • “download” attribute (the attribute necessary to “download” rather than our default displaying of source code in a new webpage)

… plus no href attribute containing “?s=” either, for today’s purposes with a changed getmelist.js external Javascript code file (that you can try out for yourself at this live run link) … via its new …


var dnprefix=decodeURIComponent(('' + localStorage.getItem('download_copy_to_folder')).replace(/^null$/g,'')); //.replace(/\+/g,' ').replace(/\\\\/g, '_').replace(/\//g, '_').replace(/\:/g, '_');
var delaymore=0;
var prefixask='<div id=firstask style="position:absolute;top:0px;left:0px;"> Download GETME? <input id=dpccb style=inline-block; type=checkbox onchange="dogetmes(document.getElementById(' + "'" + 'dpcis' + "'" + ').value);"></input> <input style=inline-block;width:300px; onclick="delaymore+=20000;" onblur="if (document.getElementById(' + "'" + 'dpccb' + "'" + ').checked) { dogetmes(document.getElementById(this.value); }" type=text id=dpcis placeholder="Optional Download Folder Later Copy to Place via Listener" value="' + dnprefix + '"></input></div>';

function dogetmes(dpprefix) {
delaymore+=20000;
var asis=document.getElementsByTagName('a');
if (dpprefix != dnprefix && 1 == 7) {
localStorage.setItem('download_copy_to_folder', dpprefix);
}
for (var iasis=0; iasis<asis.length; iasis++) {
if (asis[iasis].href.indexOf('diff.php') == -1 && asis[iasis].href.indexOf('?s=') == -1 && asis[iasis].href.indexOf('GETME') != -1) {
asis[iasis].download=dpprefix.replace(/\//g,'_').replace(/\\\\/g,'_').replace(/\:/g,'_') + asis[iasis].href.split('/')[eval(-1 + asis[iasis].href.split('/').length)];
}
}
}

function nomorepa() {
if (eval('' + delaymore) == 0) {
if (document.getElementById('firstask')) {
document.getElementById('firstask').innerHTML='';
}
} else {
setTimeout(nomorepa, eval('' + delaymore));
delaymore=0;
}
}

function lastdivpop() {
var wasih='';
if (document.getElementById('lastdiv')) {
if (document.getElementById('lastdiv').innerHTML == '') {
wasih=wasih;
setTimeout(lastdivpop, 3000);
} else if (document.getElementById('lastdiv').innerHTML.indexOf('firstask') == -1) {
wasih=document.getElementById('lastdiv').innerHTML;
document.getElementById('lastdiv').innerHTML=prefixask + wasih;
prefixask='';
setTimeout(nomorepa, 20000);
} else {
setTimeout(lastdivpop, 3000);
}
}
}

setTimeout(lastdivpop, 8000);


Previous relevant Download and Copy or Move Server Tutorial is shown below.

Download and Copy or Move Server Tutorial

Download and Copy or Move Server Tutorial

Yesterday’s Download and Copy or Move Primer Tutorial was all about the “client side” of …

… and we’ve just “tweaked” (albeit, very importantly, in our books (… but the pamphlettes are still not playing ball)) to ensure no “file clobbering” takes place so that the Korn Shell now does …


suf=""
isuf=-1
while [ -f "${dpath}/${brest}${suf}" ]; do
((isuf=isuf+1))
suf="_${isuf}"
done
if [ ! -z "$suf" ]; then
echo "mv ${dpath}/${brest} ${dpath}/${brest}${suf} # `date`" >> download_to_place.out
mv ${dpath}/${brest} ${dpath}/${brest}${suf} >> download_to_place.out 2>> download_to_place.err
fi

… in download_copier.ksh download_copier.ksh Korn Shell scripting on our macOS operating system “client”.

But today is mainly about filling in the missing bits on the “server” side. This (need for a) “conduit” we referred to yesterday is because we accept no folder paths can be mentioned at the “server” end. Suppose, though, that the “non-pathed” filename we supply to an “a” link’s “download” attribute can be prefixed by a mildly mashed up version of that path we copy to from the Downloads folder of your “client” computer or device, as you perform a “download” via the clicking of an “a” link.

Well, at this blog we’d already started functionality to toggle the use or not of …

  • “a” links … with …
  • “href” attribute containing “GETME” …
  • but not “diff.php” … and …
  • “download” attribute (the attribute necessary to “download” rather than our default displaying of source code in a new webpage)

Were you here, then, when we published WordPress Blog Download Mode Toggler Primer Tutorial (or were you indisposed again?!) There we established an “All Posts” menu “Toggle Download Mode from GETME” option piece of functionality to toggle between …

  • displaying of source code in a new webpage for GETME “a” links … versus …
  • use the changed PHP toggle_download.php in conjunction with a changed good ‘ol TwentyTen Theme header.php as below …
    <?php

    if (outs == null) {
    var dnprefix=decodeURIComponent(('' + localStorage.getItem('download_copy_to_folder')).replace(/^null$/g,'')).replace(/\+/g,' ').replace(/\\\\/g, '_').replace(/\//g, '_').replace(/\:/g, '_');
    for (idmjk=0; idmjk<admjk.length; idmjk++) {
    if (admjk[idmjk].href.indexOf('GETME') != -1 && admjk[idmjk].href.indexOf('diff.php') == -1) {

    if (origcafd < 0) { //!cafd) {
    xp=admjk[idmjk].href.split("GETME");
    prexp=xp[0].split("/");
    postprexp=prexp[-1 + prexp.length].split(".");
    extis = postprexp[-1 + postprexp.length].replace(/_/g,"").replace(/-/g,"").replace(/GETME/g,"");
    outs="//www.rjmprogramming.com.au/getmelist.htm?topoff=150&tsp=" + (Math.floor(Math.random() * 1999900) + 100) + "#" + postprexp[0] + "." + postprexp[-1 + postprexp.length].replace(extis,"").replace(extis,"").replace(extis,"") + "GETME" + extis;
    aorig=admjk[idmjk].innerHTML;
    admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(".","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Code Download Table\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=500,height=500'); } return false; \">⚫</span>");
    if (aorig == admjk[idmjk].innerHTML && admjk[idmjk].innerHTML.indexOf('er posts') == -1) admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(" ","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Code Download Table\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=500,height=500'); } return false; \">⚪</span>");
    cafd++;
    } else {
    prestuffs = admjk[idmjk].href.split('/');
    newaspare = admjk[idmjk].href.replace('_-GETME', '').replace('__GETME', '').replace('_GETME', '').replace(big, '');

    while (big.indexOf('-') != -1) {

    big = big.replace('-', '');

    newaspare = newaspare.replace(big, '');

    }

    big = '----------------------GETME';
    stuffs = newaspare.split('/');
    if (dnprefix != '') {
    admjk[idmjk].download = dnprefix + prestuffs[stuffs.length - 1];
    } else {

    admjk[idmjk].download = dnprefix + stuffs[stuffs.length - 1];
    }
    admjk[idmjk].title = "(Really download) " + admjk[idmjk].title + ' ... welcome to the long hover functionality that shows allows for a Download Mode for the blog that can be toggled';
    admjk[idmjk].onmouseover = " getDownloadMode(); ";
    admjk[idmjk].onmouseout = " yehBut(); ";
    admjk[idmjk].ontouchstart = " getDownloadMode(); ";
    admjk[idmjk].ontouchend = " yehBut(); ";
    }
    } else if (admjk[idmjk].href.indexOf('GETME') != -1 && origcafd < 0) { //!cafd) {
    xp=admjk[idmjk].href.split("GETME");
    prexp=xp[0].split("/");
    postprexp=prexp[-1 + prexp.length].split(".");
    extis = postprexp[-1 + postprexp.length].replace(/_/g,"").replace(/-/g,"").replace(/GETME/g,"");
    outs="//www.rjmprogramming.com.au/getmelist.htm?topoff=150&tsp=" + (Math.floor(Math.random() * 1999900) + 100) + "#" + postprexp[0] + "." + postprexp[-1 + postprexp.length].replace(extis,"").replace(extis,"").replace(extis,"") + "GETME" + extis;
    aorig=admjk[idmjk].innerHTML;
    selbitis=allthecombos((admjk[idmjk].href + '=').split('=')[1].split('&')[0]);
    admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(".","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Code Download Table\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=500,height=500'); } return false; \"><select onchange=\" if (this.value.length > 0) { window.open(this.value,'_blank'); } return false; \" style='margin-bottom:0px;width:40px;' id='sel" + cafd + "'><option value=>⚫</option>" + selbitis + "</select></span>");
    if (aorig == admjk[idmjk].innerHTML && admjk[idmjk].innerHTML.indexOf('er posts') == -1) admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(" ","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Code Download Table\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=500,height=500'); } return false; \"><select onchange=\" if (this.value.length > 0) { window.open(this.value,'_blank'); } return false; \" style='margin-bottom:0px;width:40px;' id='sel" + cafd + "'><option value=>⚪</option>" + selbitis + "</select></span>");
    cafd++;
    } else if ((admjk[idmjk].innerHTML.indexOf('live run') != -1 || admjk[idmjk].title.toLowerCase().indexOf('click picture') != -1) && origcafd < 0) { //!cafd) {
    outs="//www.rjmprogramming.com.au/slideshow.html#tuts";
    admjk[idmjk].innerHTML=admjk[idmjk].innerHTML.replace(" ","<span data-alt='" + outs + "' id='spn" + cafd + "' title=\" + Cut to the Chase ... see the blog post list related to live runs and slideshows ... ie. the main point of the blog posting\" onclick=\"if (cafd == cafd) { cafd=" + cafd + "; changeasfordownload(); } else { window.open('" + outs + "','_blank','top=100,left=100,width=650,height=100'); } return false; \">✂</span>");
    cafd++;
    }
    }
    }

    ?>
    … to, depending on whether the user specifies in the “All Posts” toggling’s Javascript prompt window presented, specifies a new comma separated “client folder of interest to copy to” place (stored in window.localStorage), will …

    1. download with the GETME to the Downloads folder and copy off to the specified folder of interest (backing up as necessary) … versus …
    2. the default download mode downloads to the Downloads folder without the GETME parts

See these changes in action below, contextualizing “server” and “client” codes in the full picture of assisted Downloads (copied on to a folder of the user’s interest) …


Previous relevant Download and Copy or Move Primer Tutorial is shown below.

Download and Copy or Move Primer Tutorial

Download and Copy or Move Primer Tutorial

Downloading from “the net” (“server land”) to your computer or device (“client land”) is a big part of the online experience and the sharing of data over the world wide web. But have you ever wondered about the two step design of …

  1. download from “the net” to a Downloads folder on your computer or device … and more often than not …
  2. you, the user, copies or renames this data to another location on your computer or device with command line or with operating system GUI

… ? Why not allow the “server” side define where it can download to on the “client”? Well, that would be a security nightmare, allowing a highjacking of mission critical files on your computer or device. So, I get it, that is a “no no”. But could we have a controlled “arrangement” between …

… ? We think that sounds reasonable and so, today, we start our (two parts or more) mini-project (making step 2 above be considered to be programmatically handled, sometimes) designing a Korn Shell (“client” side) listener to suit our macOS “client” computer, executed as a background process via …


ksh download_copier.ksh &

But what is the conduit, if the “server” web applications/pages cannot define a destination folder other than the macOS Downloads folder for the user involved? Well, that is where we need either …

… to define a “client land” folder to copy to (from the user’s Download folder (receiving the downloaded data).

That first Korn Shell read command interactive input was interesting to us for a command backgrounded via the “&” command suffix. But if stdin and stdout are not mentioned in the command you can answer this interactive input and then the processing the Korn Shell performs proceeds in the background. Exactly what we were hoping for, but weren’t sure that this was the case!

The picture is filled in better tomorrow as we discuss the conduit in more detail tomorrow.

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


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


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


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


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


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


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


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


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


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


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


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


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


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


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

Posted in eLearning, Operating System, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , | Leave a comment