diff --git a/countdown/forms.py b/countdown/forms.py index 64c3e11..a85bac2 100644 --- a/countdown/forms.py +++ b/countdown/forms.py @@ -4,9 +4,9 @@ from wtforms.fields import html5 from wtforms.validators import Optional class CountdownAdminForm(FlaskForm): - hours = html5.IntegerField("Hours", [Optional()], - render_kw = {"min":0, "max":999, "placeholder": "00"}) - minutes = html5.IntegerField("Minutes", [Optional()], - render_kw = {"min":0, "max":59, "placeholder": "00"}) - seconds = html5.IntegerField("Seconds", [Optional()], - render_kw = {"min":0, "max":59, "placeholder": "00"}) + hours = fields.IntegerField("Hours", [Optional()], + render_kw = {"min":0, "max":999, "placeholder": "00", "autocomplete": "off"}) + minutes = fields.IntegerField("Minutes", [Optional()], + render_kw = {"min":0, "max":59, "placeholder": "00", "autocomplete": "off"}) + seconds = fields.IntegerField("Seconds", [Optional()], + render_kw = {"min":0, "max":59, "placeholder": "00", "autocomplete": "off"}) diff --git a/countdown/templates/countdown/create.html b/countdown/templates/countdown/create.html index 8f50a4b..25b51c6 100644 --- a/countdown/templates/countdown/create.html +++ b/countdown/templates/countdown/create.html @@ -2,18 +2,29 @@ {% block title %}Countdown{% endblock title %} {% block body %} -
- {{ form.csrf_token }} - {{ form.hours.label }}: {{ form.hours }} - {{ form.minutes.label }}: {{ form.minutes }} - {{ form.seconds.label }}: {{ form.seconds }} - -
+
+
+ {{ form.csrf_token }} +
+
+
{{ form.hours }}
+
{{ form.hours.label }}
+
+
+
{{ form.minutes }}
+
{{ form.minutes.label }}
+
+
+
{{ form.seconds }}
+
{{ form.seconds.label }}
+
+
-{% if clock %} -Clock: http://localhost:5000/countdown/{{ clock }} -{% endif %} + +
+
{% endblock body %} {% block scripts %} + {% endblock scripts %} diff --git a/countdown/templates/countdown/create.js b/countdown/templates/countdown/create.js new file mode 100644 index 0000000..6b961ff --- /dev/null +++ b/countdown/templates/countdown/create.js @@ -0,0 +1 @@ +import './create.scss'; diff --git a/countdown/templates/countdown/create.scss b/countdown/templates/countdown/create.scss new file mode 100644 index 0000000..ea2b7b4 --- /dev/null +++ b/countdown/templates/countdown/create.scss @@ -0,0 +1,43 @@ +#btn-create { + margin-top: 2em; + margin-left: auto; + margin-right: auto; + font-size: 1.5em; + background-color: none; + border-style: solid; + border-width: 0px; + border-width: 1px; + border-right-width: 1px; + border-color: #7676ff; + display: block; + padding: 0.2em; + padding-left: 0.7em; + padding-right: 0.7em; + cursor: pointer; + color: #7676ff; + background-color: white; +} + +#time { + display: flex; +} + +.time-value { + margin-bottom: 0.3em; +} + +.time-label { + color: gray; + text-align: center; + font-size: 1.2em; +} + +#hours, #minutes, #seconds { + font-size: 3em; + font-style: bold; + border-style: none; + display: block; + width: 5em; + text-align: center; + color: blue; +} diff --git a/countdown/templates/countdown/created.html b/countdown/templates/countdown/created.html index 6ec72f9..0b7acdf 100644 --- a/countdown/templates/countdown/created.html +++ b/countdown/templates/countdown/created.html @@ -2,14 +2,29 @@ {% block title %}Countdown{% endblock title %} {% block body %} -{% for clock in clocks %} +
-
- Clock: http://localhost:5000/countdown/{{ clock }} +{% for countdown in countdowns %} +
+
+

Countdown {{ loop.index }}

+
+
+ +
+
+ + + +
-
{% endfor %} +
+ {% endblock body %} {% block scripts %} + {% endblock scripts %} diff --git a/countdown/templates/countdown/created.js b/countdown/templates/countdown/created.js new file mode 100644 index 0000000..8aa5db5 --- /dev/null +++ b/countdown/templates/countdown/created.js @@ -0,0 +1,101 @@ +// This file is packed by webpack into /static/dist/countdown_created.bundle.js +// Use with: `url_for('static', filename='dist/countdown_created.bundle.js')` +// See: webpack.common.js +import log from 'loglevel'; +import $ from 'jquery'; + +import {sleep} from '../../../js/netclock.js'; + +import './created.scss'; + +let api_base = "/countdown/api/v1/"; + +let padTime = (t) => { + let t_s = t.toString(); + // Pads to at least two digits filling with 0 + let leftPad = t_s.length < 2 ? + "0".repeat(2 - t.toString().length) : + ""; + + return `${leftPad+t_s}`; +}; + +let formatTime = (h, m, s) => { + let htext = padTime(h); + let mtext = padTime(m); + let stext = padTime(s); + + htext = htext !== "00" ? htext + ":" : ""; + mtext = mtext !== "00" || htext !== "00" ? mtext + ":" : ""; + + return htext + mtext + stext; +}; + +let splitTimestamp = (t) => { + // Timestamp as full seconds + let seconds = Math.floor(t); + + return { + "hours": ~~(seconds / 3600), + "minutes": ~~((seconds % 3600) / 60), + "seconds": ~~(seconds % 60), + "milliseconds": ~~((t % 1) * 1000) + }; +}; + +let fillCountdown = (el) => { + let x = el.attr("countdown-id"); + + $.getJSON({ + url: api_base + el.attr('countdown-id'), + success: function(resp) { + let header = el.children(".created-countdown-header"); + + let split = splitTimestamp(resp.total); + header.children(".created-countdown-time") + .text(formatTime(split.hours, split.minutes, split.seconds)); + + let countdownInfo = header.children(".created-countdown-info"); + if(resp.start === "-1") { + countdownInfo.text("Not started"); + } else if(resp.left <= 0) { + countdownInfo.text("Ended"); + } else { + countdownInfo.text("Running"); + } + } + }); +}; + +let startCountdown = (el) => { + $.ajax({ + url: api_base + "start/" + el.val(), + method: 'PATCH' + }).done(() => { + $(".created-countdown").each((idx, el) => fillCountdown($(el))); + }); + +}; + +let stopCountdown = (el) => { + $.ajax({ + url: api_base + "stop/" + el.val(), + method: 'PATCH' + }).done(() => { + $(".created-countdown").each((idx, el) => fillCountdown($(el))); + }); +}; + +let resetCountdown = (el) => { + $.ajax({ + url: api_base + "reset/" + el.val(), + method: 'PATCH' + }).done(() => { + $(".created-countdown").each((idx, el) => fillCountdown($(el))); + }); +}; + +$(".created-countdown").each((idx, el) => fillCountdown($(el))); +$(".created-countdown-start").each((idx, el) => $(el).click(() => startCountdown($(el)))); +$(".created-countdown-stop").each((idx, el) => $(el).click(() => stopCountdown($(el)))); +$(".created-countdown-reset").each((idx, el) => $(el).click(() => resetCountdown($(el)))); diff --git a/countdown/templates/countdown/created.scss b/countdown/templates/countdown/created.scss new file mode 100644 index 0000000..e69de29 diff --git a/countdown/templates/countdown/countdown.html b/countdown/templates/countdown/view.html similarity index 76% rename from countdown/templates/countdown/countdown.html rename to countdown/templates/countdown/view.html index 54fee78..aa9d409 100644 --- a/countdown/templates/countdown/countdown.html +++ b/countdown/templates/countdown/view.html @@ -12,5 +12,5 @@ - + {% endblock scripts %} diff --git a/countdown/countdown.js b/countdown/templates/countdown/view.js similarity index 89% rename from countdown/countdown.js rename to countdown/templates/countdown/view.js index c7a07f2..9ed096b 100644 --- a/countdown/countdown.js +++ b/countdown/templates/countdown/view.js @@ -1,12 +1,12 @@ -// This file is packed by webpack into /static/dist/countdown.bundle.js -// Use with: `url_for('static', filename='dist/countdown.bundle.js')` +// This file is packed by webpack into /static/dist/countdown_view.bundle.js +// Use with: `url_for('static', filename='dist/countdown_view.bundle.js')` // See: webpack.common.js import log from 'loglevel'; import $ from 'jquery'; -import {sleep} from '../js/netclock.js'; +import {sleep} from '../../../js/netclock.js'; -import './countdown.scss'; +import './view.scss'; let api_base = "/countdown/api/v1/"; @@ -75,7 +75,10 @@ let updateCountdown = () => { let text = formatTime(time.hours, time.minutes, time.seconds); sleep(time.milliseconds) - .then(() => $("#countdown").text(text)); + .then(() => { + $("#countdown").text(text); + $("#subtext").text(); + }); }; let unsyncTimer = undefined; diff --git a/countdown/countdown.scss b/countdown/templates/countdown/view.scss similarity index 100% rename from countdown/countdown.scss rename to countdown/templates/countdown/view.scss diff --git a/countdown/views.py b/countdown/views.py index 6b7486a..1b7b9f2 100644 --- a/countdown/views.py +++ b/countdown/views.py @@ -17,11 +17,8 @@ def create(): total += (form.minutes.data or 0) * 60 total += (form.hours.data or 0) * 60 * 60 - countdown_id = cache.add_countdown(total) - # user = User(form.username.data, form.email.data, - # form.password.data) - # db_session.add(user) - session['created_countdowns'].append(str(countdown_id)) + countdown = cache.add_countdown(total) + session['created_countdowns'].append(str(countdown['id'])) session.modified = True return redirect(url_for('countdown.created')) @@ -29,9 +26,9 @@ def create(): @app.route('/mine', methods=['GET']) def created(): - return render_template('countdown/created.html', clocks=session['created_countdowns']) + return render_template('countdown/created.html', countdowns=session.get('created_countdowns') or []) @app.route('/', methods=['GET']) def view(countdown_id): - return render_template('countdown/countdown.html', countdown_id=countdown_id) + return render_template('countdown/view.html', countdown_id=countdown_id) diff --git a/querysheet.http b/querysheet.http index a91cc2c..80cbd67 100644 --- a/querysheet.http +++ b/querysheet.http @@ -6,7 +6,7 @@ Content-Type: application/json {"total": "150"} # Set id -:id = cddabcb5-9da1-4ecb-ad36-2ca468da68e1 +:id = 224489a4-799d-4960-9dd1-56c4b81d1c2e # Start PATCH http://localhost:5000/countdown/api/v1/start/:id @@ -16,3 +16,6 @@ PATCH http://localhost:5000/countdown/api/v1/stop/:id # Reset PATCH http://localhost:5000/countdown/api/v1/reset/:id + +# GET +GET http://localhost:5000/countdown/api/v1/:id \ No newline at end of file diff --git a/webpack.common.js b/webpack.common.js index dee13bc..7c3ce0a 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -4,7 +4,9 @@ const path = require('path'); module.exports = { entry: { netclock: './js/netclock.js', - countdown: './countdown/countdown.js' + countdown_create: './countdown/templates/countdown/create.js', + countdown_view: './countdown/templates/countdown/view.js', + countdown_created: './countdown/templates/countdown/created.js' }, plugins: [ new CleanWebpackPlugin()