Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Improve the default widget #3

Merged
merged 2 commits into from

2 participants

@timheap

The default widget has numerous problems, including:

  • Unnecessary duplication of JavaScript code,
  • Failure to work without JavaScript, and
  • Bugs when multiple widgets are included on the same page

I fixed these issues by:

  • Turning the JavaScript code in to a jQuery plugin, removing most of the initialization code from the individual widget templates to a external JavaScript file, and adding a {% phileo_js %} tag to load this plugin.
  • Giving each like button a unique ID, so multiple like buttons can appear on a single page
  • Made the widget a plain old form. This way, it works without JavaScript. Additionally, the CSRF stuff is included in the form by default, so the ajax_csrf.js script is obsolete
@timheap timheap Reworked the widget form, including the JavaScript
- Turned the JavaScript code in to a jQuery plugin, removed most of the
  initialization code from the individual widget templates to a external
  JavaScript file, and added a {% phileo_js %} tag to load this plugin.
- Each like button gets a unique ID, so multiple like buttons can appear
  on a single page
- Made the widget a plain old form. This way, it works without
  JavaScript. Additionally, the CSRF stuff is included in the form by
  default, so the ajax_csrf.js script is obsolete
45b5c41
@timheap timheap Add a default value for widget_id
The widget_id when rendering a like widget defaulted to None, which
broke the widget when no id was supplied. This creates a default id for
widgets, which should be unique for that model instance.

Conflicts:

	phileo/templatetags/phileo_tags.py
012eab3
@paltman paltman merged commit 4a323a2 into pinax:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 28, 2011
  1. @timheap

    Reworked the widget form, including the JavaScript

    timheap authored
    - Turned the JavaScript code in to a jQuery plugin, removed most of the
      initialization code from the individual widget templates to a external
      JavaScript file, and added a {% phileo_js %} tag to load this plugin.
    - Each like button gets a unique ID, so multiple like buttons can appear
      on a single page
    - Made the widget a plain old form. This way, it works without
      JavaScript. Additionally, the CSRF stuff is included in the form by
      default, so the ajax_csrf.js script is obsolete
  2. @timheap

    Add a default value for widget_id

    timheap authored
    The widget_id when rendering a like widget defaulted to None, which
    broke the widget when no id was supplied. This creates a default id for
    widgets, which should be unique for that model instance.
    
    Conflicts:
    
    	phileo/templatetags/phileo_tags.py
This page is out of date. Refresh to see the latest.
View
9 docs/changelog.rst
@@ -3,6 +3,15 @@
ChangeLog
=========
+0.3
+---
+- Turned the JavaScript code in to a jQuery plugin, removed most of the initialization
+ code from the individual widget templates to a external JavaScript file, and added a
+ {% phileo_js %} tag to load this plugin.
+- Each like button gets a unique ID, so multiple like buttons can appear on a single
+ page
+- The like form works without JavaScript.
+
0.2
---
View
26 docs/templatetags.rst
@@ -23,6 +23,15 @@ This renders some css style sheets that will style the widget.::
It renders "phileo/_css.html" and can be overridden as desired.
+phileo_js
+---------
+
+This renders some script tags that are needed to make the widget work.::
+
+ {% phileo_js %}
+
+It renders "phileo/_js.html" and can be overridden as desired.
+
likes_widget
------------
@@ -31,26 +40,11 @@ This renders a fragement of html that will be what the user will click
on to unlike or like objects. It only has two required parameters, which
are the user and the object.::
- {% likes_widget user object [like_link_id="likes" like_span_total_class="phileo-count" toggle_class="phileo-liked"] %}
+ {% likes_widget user object [widget_id="unique_id" like_type="likes" toggle_class="phileo-liked"] %}
It renders "phileo/_widget.html" and can be overridden as desired.
-
-likes_js
---------
-
-This is a simple inclusion template tag that will render a bit
-of javascript for doing the ajax toggling of a user's like for
-a given object. The only two required parameters are the first
-two which are the user doing the liking and the object that is
-the subject of the liking.::
-
- {% likes_js user object [like_link="#likes" like_span_total="phileo-count" toggle_class="phileo-liked"] %}
-
-It renders "phileo/_script.html" and can be overriden as desired.
-
-
liked
-----
View
10 docs/usage.rst
@@ -17,14 +17,14 @@ Then in the <head> section of your template load the css::
{% likes_css %}
-In the body where you want the liking widget to go, add::
+Load the required JavaScript file, wherever you load your JavaScript libraries::
- {% likes_widget request.user post %}
+ {% phileo_js %}
-Then at the bottom of your page where include your javascript::
+In the body where you want the liking widget to go, add::
- {% likes_js request.user post %}
+ {% likes_widget request.user post %}
-That's all you need to do to get the basics working.
+That's all you need to do to get the basics working.
View
25 phileo/static/phileo/js/ajax_csrf.js
@@ -1,25 +0,0 @@
-(function($) {
- // from http://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#ajax
- $('html').ajaxSend(
- function(event, xhr, settings) {
- function getCookie(name) {
- var cookieValue = null;
- if (document.cookie && document.cookie != '') {
- var cookies = document.cookie.split(';');
- for (var i = 0; i < cookies.length; i++) {
- var cookie = $.trim(cookies[i]);
- // Does this cookie string begin with the name we want?
- if (cookie.substring(0, name.length + 1) == (name + '=')) {
- cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
- break;
- }
- }
- }
- return cookieValue;
- }
- if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
- // Only send the token to relative URLs i.e. locally.
- xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
- }
- });
- })(jQuery);
View
39 phileo/static/phileo/js/jquery.phileo.js
@@ -0,0 +1,39 @@
+jQuery(function($) {
+
+ var PhileoLikes = function(form, options) {
+ this.options = $.extend({}, $.fn.phileo.defaults, options);
+ this.$form = $(form);
+
+ this.$count = $(this.options.count);
+
+ var self = this;
+ this.$form.submit(function(event) {
+ event.preventDefault();
+
+ $.ajax({
+ url: self.$form.attr('action'),
+ type: "POST",
+ data: self.$form.serialize(),
+ statusCode: {
+ 200: function(data, textStatus, jqXHR) {
+ self.$count.text(data.likes_count);
+ self.$form[data.liked ? 'addClass' : 'removeClass'](self.options.toggle_class);
+ }
+ }
+ });
+ });
+ };
+
+ $.fn.phileo = function(options) {
+ $(this).each(function(i, el) {
+ var phileo = new PhileoLikes(el, options);
+ $(el).data('Phileo', {instance: phileo});
+ });
+ return this;
+ };
+
+ $.fn.phileo.defaults = {
+ toggle_class: 'phileo-liked',
+ count: false
+ };
+});
View
1  phileo/templates/phileo/_js.html
@@ -0,0 +1 @@
+<script src="{{ STATIC_URL }}phileo/js/jquery.phileo.js"></script>
View
23 phileo/templates/phileo/_script.html
@@ -1,23 +0,0 @@
-<script type="text/javascript" src="{{ STATIC_URL }}phileo/js/ajax_csrf.js"></script>
-<script type="text/javascript">
- $(function () {
- $("{{ like_link }}")
- .addClass("iconic")
- .addClass("check")
- .addClass("phileo")
- .addClass("{{ is_liked }}");
- $("{{ like_link }}").click(function() {
- $.ajax({
- url: "{{ like_url }}",
- type: "POST",
- data: {},
- statusCode: {
- 200: function(data, textStatus, jqXHR) {
- $("{{ like_span_total }}").text(data.likes_count);
- $("{{ like_link }}").toggleClass("{{ toggle_class }}");
- }
- }
- });
- });
- });
-</script>
View
27 phileo/templates/phileo/_widget.html
@@ -1,4 +1,23 @@
-<div class="phileo">
- <a class="{{ toggle_class }}" id="{{ like_link }}"></a>
- <span class="{{ like_span_total }}">{{ likes_count }}</span>
-</div>
+{% block phileo_widget_form %}
+ <form class="phileo {{ is_liked }} {{ like_type }}" action="{{ like_url }}" method="POST" id="{{ widget_id }}">{% csrf_token %}
+ {% block phileo_widget_button %}
+ <input type="submit" class="phileo-toggle" value="Like" />
+ {% endblock phileo_widget_button %}
+ {% block phileo_widget_count %}
+ <span class="phileo-count">
+ <span id="{{ like_count_id }}">{{ like_count }}</span>
+ {{ like_type }}{{ like_count|pluralize }}
+ </span>
+ {% endblock phileo_widget_count %}
+ </form>
+{% endblock phileo_widget_form %}
+{% block phileo_widget_js %}
+ <script type="text/javascript">
+ jQuery(function ($) {
+ $("#{{ widget_id }}").phileo({
+ count: "#{{ like_count_id }}",
+ toggle_class: "{{ toggle_class }}"
+ });
+ });
+ </script>
+{% endblock phileo_widget_js %}
View
50 phileo/templatetags/phileo_tags.py
@@ -7,7 +7,6 @@
from phileo.models import Like
-
register = template.Library()
@@ -65,52 +64,45 @@ def likes_count(obj):
def likes_css():
return {"STATIC_URL": settings.STATIC_URL}
+@register.inclusion_tag("phileo/_js.html")
+def phileo_js():
+ return {"STATIC_URL": settings.STATIC_URL}
+
@register.inclusion_tag("phileo/_widget.html")
-def likes_widget(user, obj, like_link_id="likes", like_span_total_class="phileo-count", toggle_class="phileo-liked"):
+def likes_widget(user, obj, widget_id=None, like_type="like", toggle_class="phileo-liked"):
ct = ContentType.objects.get_for_model(obj)
- likes_count = Like.objects.filter(
+
+ like_count = Like.objects.filter(
receiver_content_type = ct,
receiver_object_id = obj.pk
).count()
+
liked = user.liking.filter(
receiver_content_type = ct,
receiver_object_id = obj.pk
).exists()
- return {
- "like_link": like_link_id,
- "like_span_total": like_span_total_class,
- "likes_count": likes_count,
- "toggle_class": toggle_class if liked else ""
- }
+ if widget_id == None:
+ widget_id = "phileo_%s_%s_%s" % (like_type, ct.pk, obj.pk)
-@register.inclusion_tag("phileo/_script.html")
-def likes_js(user, obj, like_link="#likes", like_span_total=".phileo-count", toggle_class="phileo-liked"):
- ct = ContentType.objects.get_for_model(obj)
- url = reverse("phileo_like_toggle", kwargs={
- "content_type_id": ct.id,
+ like_count_id = "%s_count" % widget_id
+
+ like_url = reverse("phileo_like_toggle", kwargs={
+ "content_type_id": ct.pk,
"object_id": obj.pk
})
- liked = Like.objects.filter(
- sender = user,
- receiver_content_type = ContentType.objects.get_for_model(obj),
- receiver_object_id = obj.pk
- ).exists()
- if liked:
- is_liked = toggle_class
- else:
- is_liked = ""
+
return {
- "STATIC_URL": settings.STATIC_URL,
- "like_url": url,
- "like_link": like_link,
- "like_span_total": like_span_total,
+ "like_url": like_url,
+ "widget_id": widget_id,
+ "like_type": like_type,
+ "like_count": like_count,
+ "like_count_id": like_count_id,
"toggle_class": toggle_class,
- "is_liked": is_liked
+ "is_liked": toggle_class if liked else ""
}
-
class LikedObjectsNode(template.Node):
def __init__(self, objects, user, varname):
View
4 phileo/views.py
@@ -37,7 +37,9 @@ def like_toggle(request, content_type_id, object_id):
"likes_count": Like.objects.filter(
receiver_content_type = content_type,
receiver_object_id = object_id
- ).count()
+ ).count(),
+ "liked": created,
+
}), mimetype="application/json")
return redirect(request.META["HTTP_REFERER"])
Something went wrong with that request. Please try again.