Back to documentation

Stack based calculator

This page is written with "normal" django templates, not the pure python hypergen templates.

Add number to stack

Perform operation

Stack

  1. 2.0
  2. 3.0

Show sourcestemplates/djangotemplates/content.html
{% extends "djangotemplates/base.html"%}
{% load hypergen %}{% csrf_token %}

{% block content %}
  <h2>Add number to stack</h2>
  <input id="number" type="number" autofocus>
  {# The {% callback %} template tag works exactly like it's python cousin, except it requires an id and event. #}
  {# Also notice that you can reference other elements with "#id[.type]" magic strings. #}
  <button {% callback "djangotemplates:push" "#number.float" id="push" event="onclick" %}>Push</button>

  <h2>Perform operation</h2>
  <button {% callback "djangotemplates:add" id="add" event="onclick" %}>+</button>
  <button {% callback "djangotemplates:subtract" id="subtract" event="onclick" %}>-</button>
  <button {% callback "djangotemplates:multiply" id="multiply" event="onclick" %}>*</button>
  <button {% callback "djangotemplates:divide" id="divide" event="onclick" %}>/</button>
  <button {% callback "djangotemplates:reset" id="reset" event="onclick" %}>C</button>

  <h2>Stack</h2>
  <ol>
  {% for item in stack reversed %}
    <li>{{item}}</li>
  {% endfor %}
  </ol>
{% endblock %}
templates/djangotemplates/base.html
{% load hypergen %}{% load static %}<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    {# Due to technical reasons both header and footer media are needed #}
    {% hypergen_media_header %}
    <link rel="stylesheet" type="text/css" href="https://unpkg.com/simpledotcss/simple.min.css"></link>
    <link rel="stylesheet" type="text/css" href="{% static 'website/website.css' %}"></link>
  </head>
<body>
  <p><a href="{% url 'website:documentation' %}">Back to documentation</a></p>
  
  <h1>Stack based calculator</h1>
  <p>This page is written with "normal" django templates, not the pure python hypergen templates.</p>

  {# This matches the target_id keyword argument to the @actions #}
  <div id="content">
    {% block content %}
    {% endblock %}
  </div>
  
  <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/default.min.css"></link>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min.js"></script>
  <script src="{% static 'website/website.js' %}" defer></script>

  {{sources|safe}}
  
  {# Due to technical reasons both header and footer media are needed #}
  {% hypergen_media_footer %}
</body>
</html>
urls.py
from djangotemplates import views
from hypergen.hypergen import autourls
try:
    from django.conf.urls import url
except ImportError:
    from django.urls import re_path as url

app_name = 'djangotemplates'

urlpatterns = [
    url('^$', views.djangotemplates, name="djangotemplates"),] + autourls(views, app_name)
views.py
import operator

from hypergen.imports import *
from hypergen.context import context as c
from hypergen.templatetags.hypergen import render_to_hypergen

from django.shortcuts import render

from hypergen.incubation import SessionVar
from website.templates2 import show_sources

STACK = SessionVar("STACK", [])  # This variable lives in the session data.

# djangotemplates is a vanilla Django view, with it's route defined in urls.py.
# It's decorated with @liveview to enable liveview capabilities.
@liveview(perm=NO_PERM_REQUIRED, autourl=False)
def djangotemplates(request):
    return render(request, "djangotemplates/content.html", context=dict(stack=STACK.get(),
        sources=hypergen(show_sources, __file__)))

def render_content():
    # render_to_hypergen() works exactly as Djangos render_to_string except for two things:
    #     1. It writes the HTML directly to the page.
    #     2. It supports a "block" keyword argument so that only the content of that block is rendered.
    render_to_hypergen("djangotemplates/content.html", context=dict(stack=STACK.get(),
        sources=hypergen(show_sources, __file__)), block="content")

###  ACTIONS ###
# @actions works exactly like vanilla hypergen actions, so the hypergen template language is enabled.
# Here we choose to use render_context to partially render a Django html template.

@action(perm=NO_PERM_REQUIRED, target_id="content")
def push(request, number):
    if number is not None:
        assert type(number) is float
        STACK.append(number)

    render_content()

@action(perm=NO_PERM_REQUIRED, target_id="content")
def reset(request):
    STACK.set([])
    render_content()

@action(perm=NO_PERM_REQUIRED, target_id="content")
def add(request, *args):
    apply_operation(operator.add)

@action(perm=NO_PERM_REQUIRED, target_id="content")
def subtract(request, *args):
    apply_operation(operator.sub)

@action(perm=NO_PERM_REQUIRED, target_id="content")
def multiply(request, *args):
    apply_operation(operator.mul)

@action(perm=NO_PERM_REQUIRED, target_id="content")
def divide(request, *args):
    if len(STACK.get()) and STACK.get()[-1] == 0:
        command("alert", "Can't divide by zero")
        return

    apply_operation(operator.truediv)

def apply_operation(op):
    if len(STACK) < 2:
        command("alert", "Stack has too few elements")
        return

    b, a = STACK.pop(), STACK.pop()
    STACK.append(op(a, b))

    render_content()