Creating Wishlist2Text website – Part 3

Hello, this is the third post from a series how I build https://wishlist2text.appspot.com
You can read the previous post here and here. In this part, I will create jinja templates to render HTML.

Create templates folder if you haven’t created it yet inside of wishlist2text folder. I will need 3 html file. First one is base with general elements such as navbars, steamid with user form to enter steam id and wishlist to display the content of user wishlist. Let’s start from base.

<!doctype html>
<html lang="en">

<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <!-- Bootstrap CSS -->
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
    integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
  <link rel="stylesheet" href="static/css/wishlist2text.css">
  <!-- Optional JavaScript -->
  <!-- jQuery first, then Popper.js, then Bootstrap JS -->
  <script src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
    integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
    crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
    integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
    crossorigin="anonymous"></script>
  <title>Wishlist2Text</title>
</head>

<body>
  <!-- Image and text -->
  <nav class="navbar navbar-dark bg-primary">
    <a class="navbar-brand" href="{{ url_for('wishlist.scan_steam') }}">
      <img src="static/img/logo.png" width="30" height="30" class="d-inline-block align-top" alt="">
      Wishlist2Text
    </a>
  </nav>
  {% with messages = get_flashed_messages(with_categories=true) %}
  {% if messages %}
  {% for category, message in messages %}
  <div class="alert alert-{{ category }}" role="alert">
    {{ message }}
  </div>
  {% endfor %}
  {% endif %}
  {% endwith %}
  {% block content %}{% endblock %}
  <!-- Footer -->
  <footer class="footer">
    <div class="container text-center">Source Code:
      <a href="https://github.com/mpostument/Wishlist2Text">Github.com</a>
    </div>
  </footer>
</body>

</html>

This is a simple template which includes bootstrap. More information about bootstrap can be found here. What is interesting here is jinja2. 
with messages = get_flashed_messages(with_categories=true) – line take flash messages from scan_steam function from part 2. And include message category (flash(“Was not able to scan wishlist”, “danger”)). Then I am using jinja if condition to check if some messages received and display them using a loop. Next interesting line is {% block content %}{% endblock %}. Our rest of the templates will extend this base template and display content inside of this block. 
The second template is steamid.

{% extends "base.html" %}
{% block content %}
    <div class="container">
        <div class="row justify-content-center align-items-center" style="height:100vh">
            <div class="col-4">
                <div class="card">
                    <div class="card-body">
                        <form action="" method="post" novalidate>
                            {{ form.hidden_tag() }}
                            <div class="form-group">
                                {{ form.steam_id(class_='form-control', placeholder="Enter Steam ID or Username")}}
                                {% for error in form.steam_id.errors %}
                                    <span style="color: red;">[{{ error }}]</span>
                                {% endfor %}
                            </div>
                            {{ form.submit(class_='btn btn-success mb-2') }}
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
{% endblock %}

Again this is a regular HTML but with few jinja lines. First line is {{ form.hidden_tag() }} this line need to be included for all flask from. And then I am displaying form itself using bootstrap classes {{ form.steam_id(class_=’form-control’, placeholder=”Enter Steam ID or Username”)}} and submit button {{ form.submit(class_=’btn btn-success mb-2′) }}. Also when user press submits flask is doing form validation and I need to display errors if they exist. So I am looping through form errors and displaying error messages. Also, there is {% extends “base.html” %}. This line is used to extend the content of the base template. After rendering steamid template will look like base template + steamid template. There is the missing final part {% block content %}{% endblock %}. These two lines specify block in the base template where this content should be pasted. 
And our final template is wishlist.

{% extends "base.html" %}
{% block content %}
<div class="container">
    <div class="form-group">
        <textarea class="form-control" id="steamWishlistTextArea" readonly rows="25">
    {% for game in games -%}
        {{game}}
    {% endfor %}
    </textarea>
    </div>
    <button type="button" id="steamWishlistButton" class="btn btn-success">Copy</button>
</div>
<script>
    $("#steamWishlistButton").click(function () {
        $("textarea").select();
        document.execCommand("copy");
    });
</script>
{% endblock %}

Here is present the same extends and block as in the previous template. And here is only simple jinja code. This code is looping through all games received from API call to steam and display all these games as a text area. Also here is a little js script which allows a user to copy a game list with a single button. 

Now, wishlist2text is ready. You can run the website by executing 

python main.py

In the final part of this series if will explain how Travis can be used to deploy a website to google app engine.