Okay, I never really liked the user interface for the app. So I decided to change a thing or two. Started with one change, then moved on to another one. I think they make things work a little better for the average user. I would like to get a loading icon working, but can’t find an easy way to do so. And, don’t particularly want to use Javascript.

Anyway, the first thing I wanted to do, was allow the user to display an image without going through the curve parameters form (from home and help pages). So, I decided I would use the text links in the image_links.html template to go to the form and the image links to just generate and display an image—no questions asked.

No Questions Asked

Unfortunately, there is no way to generate a post request other than through a form, or some additional packages (e.g. htmx). And, even then a form might still be required. So, I went with a form. For now I am duplicating a lot of the HTML. Should be possible to use a loop with some thinking and a logical design.

Some of the biggest headache was sorting out form and image position within the flex containers. I expect I made it harder than it likely was, but—

The basic form for each image type looks like the following. Using the basic spirograph type for this example. It will replace the anchor tag currently used around the image. Initially I had a lot of inline CSS until I could get things working. That is now in the app stylesheet.

    <form  method="post" action="{{ url_for('sp_basic') }}" class="img_btn">
      <input type="image" id="basic" src="{{url_for('static', filename='spiro_basic.png')}}"
       alt="basic spirograph image"
       style="margin:0; padding:0; width:100px; height:100px;">
    </form>

And, that didn’t quite work. An error was produced.

werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'shp_mlt'

Turns out my code in the function fini_curve_form() expected the shp_mlt field/key in the form’s returned post data. Bad design, which I may try to fix. But adding the following hidden field to the form did the trick.

      <input type="hidden" name="shp_mlt" value="">

As I said, I repeated (definitely not DRY here) the above for each spirograph image type.

I initially added a paragraph to the index page explaining how the two types of links worked differently. But in a later refactoring moved it to the image_links.html template. That template now looks like the following. Only the first few image types displayed here. I am sure you will get the idea.

<h3>Spirograph Image Types</h3>

<p>If you click on the textual link, you will taken to a form where you can specify some paramters with respect to the spirograph curve and its display. If you click on an image link a spirograph using default values (most of which are randomly generated) will be produced and displayed. And, if you reload the page (accepting the *resend* query), you will be shown another spirograph image. And, it should be different each time you reload. To switch image types you will need to select a new image type.</p>

<p>Do be patient, there is a fair bit of arithmetic going on for some of the image types.</p>

<div class="flex-container" style="margin:0;padding:0;">
  <div>
    <p><a href="{{ url_for('sp_basic') }}">Basic Spirograph</a><br>&nbsp;</p>
    <form  method="post" action="{{ url_for('sp_basic') }}" class="img_btn">
      <input type="hidden" name="shp_mlt" value="">
      <input type="image" id="basic" src="{{url_for('static', filename='spiro_basic.png')}}"
       alt="basic spirograph image"
       style="margin:0; padding:0; width:100px; height:100px;">
    </form>
  </div>
  <div>
    <p><a href="{{ url_for('sp_basic_t') }}">Basic Spirograph</a><br>with 2D Transforms</p>
    <form  method="post" action="{{ url_for('sp_basic_t') }}" class="img_btn">
      <input type="hidden" name="shp_mlt" value="">
      <input type="image" id="basic_t" src="{{url_for('static', filename='spiro_basic_transf.png')}}"
       alt="basic spirograph image with 2D transforms"
       style="margin:0; padding:0; width:100px; height:100px;">
    </form>
  </div>
  <div>&nbsp;</div>
... ...

I don’t believe I have shown a screenshot of the home page, so here it is.

screen shot of app home page

Choices on the Image Display Page

As it stands, all the links on the spirograph image display page take the user to the curve parameter form. I’d also like to give them choices on that page as well. So, I am going to generate a second image links template, no images, all text links. And, I am going to try doing so without all that duplicated HTML. So, some Jinja work going to be needed.

I started by creating a new template, text_links.html and copied the apprropriate content from the disp_image.html template to it. And, added a {% include 'text_links.html' %} to replace the HTML removed from the image display template. A quick test says it works just fine.

Now to refactor the new template. Basically what I want for each image type is a “tile” containing a title, a link saying “Draw it!” and a link saying “Give me choices!”. Or some such. So, I am going to need a list of titles, and a list of the related route function names for each title.

There is likely a better way to sort my variables, but…

{% set sp_basic = {"Basic<br>&nbsp;": "sp_basic", "Basic<br>2D Transforms": "sp_basic_t", "Blank": "n/a"} %}
{% set sp_clw = {"Cycling Line Width<br>using scatterplot": "sp_basic_clw",
    "Cycling Line Width<br>using fill_btween": "sp_basic_clw_btw",
    "Cycling Line Width<br>with 2D transform": "sp_clw_btw_t"}
 %}
 {% set sp_gnarly = {"Gnarly<br>&nbsp;": "sp_gnarly", "Gnarly<br>2D Transforms": "sp_gnarly_t",  "Blank": "n/a"} %}
 {% set sp_mosaic = {"Mosaic<br>&nbsp;": "sp_mosaic", "Mosiac<br>2D Transforms": "sp_mosaic_t",
                     "Mosiac<br>Transform to Transform": "sp_mosaic_t2t"}
%}
{% set sp_sects = [sp_basic, sp_clw, sp_gnarly, sp_mosaic] %}

I managed the code in the template fairly easily and relatively quickly using inline CSS. However, the <br> in the title strings just did not generate a line break. A little hunting showed that Jinja by default autoescapes any HTML in strings you print. So, I had to use the |safe filter to tell Jinja not to do so. I also needed to add <br>&nbsp; to the single line titles so that the items in image type tile displayed in the same postition. I.E. regardless of the title size.

<div class="flex-container">
  {% for sps in sp_sects %}
  {% for i_typ in sps %}
  <div class="tlnk">
  {% if i_typ == "Blank" %}
    &nbsp;
  {% else %}
    <p class="tlnk"><b>{{ i_typ|safe }}</b></p>
    <form  method="post" action="{{ url_for(sps[i_typ]) }}">
      <input type="hidden" name="shp_mlt" value="">
      <input type="submit" value="Draw it!" />
    </form>
    <p class="tlnk"><a href="{{ url_for(sps[i_typ]) }}">Give me choices!</a></p>
  {% endif %}  
  </div>
  {% endfor %}
  {% endfor %}

I won’t bother with the CSS styles. I am sure you can work out what you might need or want for your app.

Here’s a screenshot of the modified section of the image display page.

screen shot of links section of image display page

Now that is certainly is much tidier than my image_links.html template. Though the image display page is now a bit longer; i.e. more scrolling. Time for a refactor of the image_links.html template.

Refactor image_links.html

But going to take a bit of a rethink as I also need to deal with image links. Decided to replace the route with a tuple of route and image name. The whole now looks like this. At least 100 lines shorter than the previous version with all its repeated HTML.

{% set sp_basic = {
  "Basic Spirograph<br>&nbsp;": ("sp_basic", 'spiro_basic.png'),
  "Basic Spirograph<br>2D Transforms": ("sp_basic_t", "spiro_basic_transf.png"),
  "Blank": "n/a"} %}
{% set sp_clw = {
  "Cycling Line Width<br>using scatterplot": ("sp_basic_clw", "spiro_basic_clw.png"),
  "Cycling Line Width<br>using fill_btween": ("sp_basic_clw_btw", "spiro_basic_clw.png"),
  "Cycling Line Width<br>with 2D transform": ("sp_clw_btw_t", "spiro_basic_clw_btw_trf.png")}
%}
{% set sp_gnarly = {
  "Gnarly<br>&nbsp;": ("sp_gnarly", "spiro_gnarly.png"),
  "Gnarly<br>2D Transforms": ("sp_gnarly_t", "spiro_gnarly_transf.png"),
  "Blank": "n/a"} %}
{% set sp_mosaic = {
  "Mosaic<br>&nbsp;": ("sp_mosaic", "spiro_mosaic.png"),
  "Mosiac<br>2D Transforms": ("sp_mosaic_t", "spiro_mosaic_transf.png"),
  "Mosiac<br>Transform to Transform": ("sp_mosaic_t2t", "spiro_mosaic_t2t.png")}
%}
{% set sp_sects = [sp_basic, sp_clw, sp_gnarly, sp_mosaic] %}

<h3>Spirograph Image Types</h3>

<p>If you click on the textual link, you will taken to a form where you can specify some paramters with respect to the spirograph curve and its display. If you click on an image link a spirograph using default values (most of which are randomly generated) will be produced and displayed. And, if you reload the page (accepting the *resend* query), you will be shown another spirograph image. And, it should be different each time you reload. To switch image types you will need to select a new image type.</p>

<p>Do be patient, there is a fair bit of arithmetic going on for some of the image types.</p>

<div class="flex-container" style="margin:0;padding:0;">
  {% for sps in sp_sects %}
  {% for i_typ in sps %}
  <div>
    {% if i_typ == "Blank" %}
      &nbsp;
    {% else %}
      {% set sp_ttl = i_typ.split('<br>') %}
      <p><a href="{{ url_for(sps[i_typ][0]) }}">{{ sp_ttl[0] }}</a><br>{{ sp_ttl[1]|safe }}</p>
      <form  method="post" action="{{ url_for(sps[i_typ][0]) }}" class="img_btn">
        <input type="hidden" name="shp_mlt" value="">
        <input type="image" id="basic" src="{{url_for('static', filename=sps[i_typ][1])}}"
         alt="basic spirograph image"
         style="margin:0; padding:0; width:100px; height:100px;">
      </form>
    {% endif %}  
    </div>
    {% endfor %}
    {% endfor %}
</div>

Should probably figure out how to put these values in some sort of global variable available to any template. But, that will have to wait for for a later date.

Draw Another One Button

In the image above you may have noticed the “Draw Another One!” button. I was for a period of time just reloading the page and clicking the ok to resend pop-up from the browser. That got tiring.

So, I added code the image display page template, to add a form with that button text. It is basically the same form as the “Draw it!” buttons below. But, it does not specify a form action. As a result the form action used to generate the current image is used again. Much nicer that reload and approve. A little less mouse clicking is always good.

That section of the template is shown below.

    <div style="width:50%; margin-left: 3.25rem;">
      <form method="post" action="" class="dano">
        <input type="hidden" name="shp_mlt" value="">
        <input type="submit" value="Draw another one!">
      </form>
    </div>

Some decent progress I believe.

Done

Think that’s it for this one. Until the next time, remember it pays to spend some time making your code DRY.

Resources