From c5c3b01dfa3e84c969c284b15ba31f5b488df1b0 Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 30 Mar 2022 01:18:42 -0500 Subject: [PATCH] Use jQuery to allow users to like/unlike posts with dynamic updates - Only the pages that need jQuery and the likes.js script will load it --- routes.py | 25 +++++++++++++++++++++++-- static/likes.js | 19 +++++++++++++++++++ static/styles.css | 1 + static/styles.css.map | 2 +- static/styles.scss | 1 + templates/layouts/base.html | 19 +++++++++++++++++++ templates/pages/feed.html | 8 +++++--- 7 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 static/likes.js diff --git a/routes.py b/routes.py index 67f71fb..0d36540 100644 --- a/routes.py +++ b/routes.py @@ -1,7 +1,7 @@ -from flask import Blueprint, redirect, render_template, url_for, request +from flask import Blueprint, redirect, render_template, url_for, request, jsonify from flask_login import current_user, login_required -from models import User, Post, Comment +from models import User, Post, Comment, PostLike, CommentLike from forms import NewPostForm, NewCommentForm, EditProfileForm from database import db @@ -46,6 +46,27 @@ def view_post(post_id: int): return render_template('pages/post.html', form=NewCommentForm(), post=post) +@blueprint.route('/post//like', methods=['POST']) +@login_required +def like_post(post_id: int): + # Check that the relevant post exists + post = db.session.query(Post).get_or_404(post_id) + + # Acquire the relevant PostLike in question + post_like = db.session.query(PostLike).filter_by(post=post, user=current_user).first() + if post_like is None: + post_like = PostLike(post=post, user=current_user) + db.session.add(post_like) + else: + db.session.delete(post_like) + post_like = None + + db.session.commit() + + # post_like is only NOT None if the user had not liked it before, but has liked it now after db.commit(). + return jsonify({'liked': post_like is not None, 'status_text': post.get_like_text()}) + + @blueprint.route('/search') def search(): return render_template('pages/search.html') diff --git a/static/likes.js b/static/likes.js new file mode 100644 index 0000000..7fef968 --- /dev/null +++ b/static/likes.js @@ -0,0 +1,19 @@ +function like(id) { + $.ajax({url: `/post/${id}/like`, method: "POST", dataType: "json"}) + .done(function (data) { + let post_parent = $(`#post-${id}`) + let heart_icon = post_parent.find('.fa-heart') + let pre_liked = heart_icon.hasClass('liked') + + // Toggle if the current state no longer matches the database state. + if (pre_liked !== data.liked) { + if (pre_liked) + heart_icon.removeClass('liked') + else + heart_icon.addClass('liked') + } + + // Set new state of the like status text + post_parent.find('.post-like-status').html(data.status_text) + }) +} diff --git a/static/styles.css b/static/styles.css index e141901..60d333b 100644 --- a/static/styles.css +++ b/static/styles.css @@ -257,6 +257,7 @@ nav .links li:not(:last-child)::after, footer .links li:not(:last-child)::after top: 1em; right: 1em; color: #b0c9f3; + cursor: pointer; } .post-box .fa-heart.liked { color: #1b53a8; diff --git a/static/styles.css.map b/static/styles.css.map index 0731870..4112a86 100644 --- a/static/styles.css.map +++ b/static/styles.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["styles.scss"],"names":[],"mappings":"AAAA;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;AAEA;EAOE;;AALA;EAEE;;;AASJ;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;;;AAKJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAEA;EACE;EACA;;AAIJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;;;AAKN;EACE;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAIA;EACE;EACA;;AAEA;EACE;;AAEA;EACE;;;AAMR;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAIA;EACE;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;;;AAMF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;;AAKF;EACE;EACA;EACA;EACA;;;AAMR;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAEA;EACE;EACA;;AAIJ;EACE;EACA;;AAGF;EACE;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;;AACA;EACE;;AAIJ;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAIJ;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAEA;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAKN;EACE;EACA;;AAIJ;EAEE;EACA;EACA;;;AAMR;EACE;EACA;;AACA;EACE;;AAEA;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAKN;EACE;EACA;;;AAIJ;EACE;EACA;EACA;;AAEA;EACE;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EAME;EACA;EACA;EAEA;EACA;EACA;;AAXA;EACE;;;AAcN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;;AAGF;EACE","file":"styles.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["styles.scss"],"names":[],"mappings":"AAAA;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;AAEA;EAOE;;AALA;EAEE;;;AASJ;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;;;AAKJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAEA;EACE;EACA;;AAIJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;;;AAKN;EACE;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAIA;EACE;EACA;;AAEA;EACE;;AAEA;EACE;;;AAMR;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAIA;EACE;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;;;AAMF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;;AAKF;EACE;EACA;EACA;EACA;;;AAMR;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAEA;EACE;EACA;;AAIJ;EACE;EACA;;AAGF;EACE;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AACA;EACE;;AAIJ;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAIJ;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAEA;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAKN;EACE;EACA;;AAIJ;EAEE;EACA;EACA;;;AAMR;EACE;EACA;;AACA;EACE;;AAEA;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAKN;EACE;EACA;;;AAIJ;EACE;EACA;EACA;;AAEA;EACE;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EAME;EACA;EACA;EAEA;EACA;EACA;;AAXA;EACE;;;AAcN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;;AAGF;EACE","file":"styles.css"} \ No newline at end of file diff --git a/static/styles.scss b/static/styles.scss index 314d0b2..27cdbe9 100644 --- a/static/styles.scss +++ b/static/styles.scss @@ -303,6 +303,7 @@ nav, footer { top: 1em; right: 1em; color: #b0c9f3; + cursor: pointer; &.liked { color: #1b53a8; } diff --git a/templates/layouts/base.html b/templates/layouts/base.html index c30633e..b93188b 100644 --- a/templates/layouts/base.html +++ b/templates/layouts/base.html @@ -9,6 +9,25 @@ + {% if use_jquery %} + + + {% if use_likes %} + + {% endif %} + {% endif %} {% endblock %} diff --git a/templates/pages/feed.html b/templates/pages/feed.html index d37bf04..41e9382 100644 --- a/templates/pages/feed.html +++ b/templates/pages/feed.html @@ -1,5 +1,7 @@ {% extends 'layouts/index.html' %} {% from 'macros.html' import render_field %} +{% set use_jquery = true %} +{% set use_likes = true %} {% block content %} {% if current_user.is_authenticated %} @@ -13,15 +15,15 @@
{% for post in posts %} -
- +
+ {{ post.text }}