Mercurial > public > sg101
changeset 1094:110bbc78a482
GCalendar V3 conversion in progress.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Sun, 29 May 2016 23:09:23 -0500 |
parents | 1ac847818aea |
children | 74d7e56a9cfb |
files | comments/urls.py comments/views.py gcalendar/forms.py gcalendar/static/js/gcalendar.js gcalendar/static/js/gcalendar_edit.js gcalendar/views.py sg101/templates/gcalendar/edit.html sg101/templates/gcalendar/event.html sg101/templates/gcalendar/index.html |
diffstat | 9 files changed, 391 insertions(+), 90 deletions(-) [+] |
line wrap: on
line diff
--- a/comments/urls.py Wed May 11 22:00:44 2016 -0500 +++ b/comments/urls.py Sun May 29 23:09:23 2016 -0500 @@ -8,7 +8,10 @@ urlpatterns = [ url(r'^flag/$', comments.views.flag_comment, name='comments-flag'), - url(r'^markdown/$', comments.views.markdown_preview, name='comments-markdown_preview'), + url(r'^markdown/$', comments.views.markdown_preview, + name='comments-markdown_preview'), + url(r'^markdown/v3/$', comments.views.markdown_preview_v3, + name='comments-markdown_preview_v3'), url(r'^post/$', comments.views.post_comment, name='comments-post'), url(r'^cr/(\d+)/(\d+)/$', django.contrib.contenttypes.views.shortcut,
--- a/comments/views.py Wed May 11 22:00:44 2016 -0500 +++ b/comments/views.py Sun May 29 23:09:23 2016 -0500 @@ -140,7 +140,7 @@ function for a javascript editor such as markItUp. """ if not request.user.is_authenticated(): - return HttpResponseForbidden('This service is only available to logged in users.') + return HttpResponseForbidden('This service is only available to logged-in users.') data = request.POST.get('data', None) if data is None: @@ -156,3 +156,20 @@ return render(request, 'comments/markdown_preview.html', { 'data': html, }) + + +@require_POST +def markdown_preview_v3(request): + if not request.user.is_authenticated(): + return HttpResponseForbidden( + 'This service is only available to logged-in users.') + + data = request.POST.get('data', None) + html = site_markup(data) if data else '' + if html: + try: + image_check(html) + except ImageCheckError as ex: + html = PREVIEW_UNAVAILABLE.format(ex) + + return HttpResponse(html)
--- a/gcalendar/forms.py Wed May 11 22:00:44 2016 -0500 +++ b/gcalendar/forms.py Sun May 29 23:09:23 2016 -0500 @@ -64,17 +64,22 @@ class EventEntryForm(forms.ModelForm): - what = forms.CharField(widget=forms.TextInput(attrs={'size': 60})) - start_date = forms.DateField(widget=forms.TextInput(attrs={'size': 10})) - start_time = forms.TimeField(required=False, widget=forms.Select(choices=TIME_CHOICES)) - end_date = forms.DateField(widget=forms.TextInput(attrs={'size': 10})) - end_time = forms.TimeField(required=False, widget=forms.Select(choices=TIME_CHOICES)) + what = forms.CharField(label='Event Title') + start_date = forms.DateField(label='Start Date') + start_time = forms.TimeField(label='Start Time', required=False, + widget=forms.Select(choices=TIME_CHOICES)) + end_date = forms.DateField(label='End Date') + end_time = forms.TimeField(label='End Time', required=False, + widget=forms.Select(choices=TIME_CHOICES)) time_zone = forms.CharField(required=False, widget=forms.HiddenInput()) - where = forms.CharField(required=False, widget=forms.TextInput(attrs={'size': 60})) + where = forms.CharField( + label='Event Location', + required=False, + help_text='If applicable, please fill this out for an accurate Google map') description = forms.CharField( + label='Event Details', required=False, widget=forms.Textarea(attrs={ - 'class': 'markItUp smileyTarget', 'id': 'id_body', # needed for image related js }))
--- a/gcalendar/static/js/gcalendar.js Wed May 11 22:00:44 2016 -0500 +++ b/gcalendar/static/js/gcalendar.js Sun May 29 23:09:23 2016 -0500 @@ -1,3 +1,46 @@ +function editorReplaceText(textArea, i, j, newText) { + textArea.value = textArea.value.substring(0, i) + newText + + textArea.value.substring(j); +} + +function editorWrapSelection(textArea, wrapText) { + if (wrapText.length == 0) return; + var i = textArea.selectionStart; + var j = textArea.selectionEnd; + if (i == j) return; + var selection = textArea.value.substring(i, j); + var newText = wrapText + selection + wrapText; + editorReplaceText(textArea, i, j, newText); + textArea.focus(); + textArea.setSelectionRange(i, j + 2 * wrapText.length); +} + +function editorPrependLines(textArea, s) { + if (s.length == 0) return; + var i = textArea.selectionStart; + var j = textArea.selectionEnd; + var newText = s; + var selection = textArea.value.substring(i, j); + newText += selection.replace(/\n/gm, '\n' + s); + editorReplaceText(textArea, i, j, newText); +} + +function editorLink(textArea) { + var i = textArea.selectionStart; + var j = textArea.selectionEnd; + var url = window.prompt("Please enter a URL:", "http://"); + if (!url) return; + var link; + if (i == j) { + link = '[Link](' + url + ')'; + } else { + var selection = textArea.value.substring(i, j); + link = '[' + selection + '](' + url + ')'; + } + editorReplaceText(textArea, i, j, link); + textArea.focus(); +} + $(document).ready(function() { $('#id_start_date').datepicker({constrainInput: true, dateFormat: 'mm/dd/yy', @@ -19,15 +62,73 @@ } } }); - if ($('#id_all_day:checked').length) - { - $('#id_start_time').hide(); - $('#id_end_time').hide(); - $('#id_tz_stuff').hide(); + if ($('#id_all_day:checked').length) { + $('.all-day-hide').hide(); } $('#id_all_day').click(function () { - $('#id_start_time').toggle(); - $('#id_end_time').toggle(); - $('#id_tz_stuff').toggle(); - }); + $('.all-day-hide').toggle(); + }); + + var editorPanel = $('#editor-panel textarea'); + var previewPanel = $('#preview-panel'); + previewPanel.css('height', editorPanel.css('height')); + var observer = new MutationObserver(function(mutations) { + if (previewPanel.is(':visible')) { + alert(editorPanel[0].value); + $.ajax({ + url: '/comments/markdown/v3/', + method: 'POST', + data: {'data': editorPanel[0].value}, + dataType: 'html', + success: function(data, textStatus) { + alert(data); + previewPanel.html(data); + }, + error: function (xhr, textStatus, ex) { + alert('Oops, an error occurred: ' + xhr.statusText + ' - ' + + xhr.responseText); + } + }); + } + }); + var target = document.getElementById('preview-panel'); + observer.observe(target, {attributes: true}); + + // Editor stuff + $('.v3-editor').each(function (index) { + var $this = $(this); + var textArea = $this.find('textarea')[0]; + $this.find('.editor-bold').click(function () { + editorWrapSelection(textArea, '**'); + return false; + }); + $this.find('.editor-italic').click(function () { + editorWrapSelection(textArea, '_'); + return false; + }); + $this.find('.editor-strike').click(function () { + editorWrapSelection(textArea, '---'); + return false; + }); + $this.find('.editor-link').click(function () { + editorLink(textArea); + return false; + }); + $this.find('.editor-quote').click(function () { + editorPrependLines(textArea, '> '); + return false; + }); + $this.find('.editor-code').click(function () { + editorPrependLines(textArea, ' '); + return false; + }); + $this.find('.editor-bullet').click(function () { + editorPrependLines(textArea, '* '); + return false; + }); + $this.find('.editor-number').click(function () { + editorPrependLines(textArea, '1. '); + return false; + }); + }); });
--- a/gcalendar/static/js/gcalendar_edit.js Wed May 11 22:00:44 2016 -0500 +++ b/gcalendar/static/js/gcalendar_edit.js Sun May 29 23:09:23 2016 -0500 @@ -9,8 +9,8 @@ data: { id : RegExp.$1 }, dataType: 'text', success: function (id) { - var id = '#gcal-' + id; - $(id).parents('li').hide('normal'); + var rowId = '#gcal-row-' + id; + $(rowId).fadeOut(800); }, error: function (xhr, textStatus, ex) { alert('Oops, an error occurred. ' + xhr.statusText + ' - ' +
--- a/gcalendar/views.py Wed May 11 22:00:44 2016 -0500 +++ b/gcalendar/views.py Sun May 29 23:09:23 2016 -0500 @@ -3,8 +3,9 @@ """ from django.contrib.auth.decorators import login_required +from django.core.exceptions import PermissionDenied +from django.core.paginator import InvalidPage from django.core.urlresolvers import reverse -from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage from django.http import HttpResponse from django.http import HttpResponseBadRequest from django.http import HttpResponseForbidden @@ -13,6 +14,8 @@ from django.shortcuts import get_object_or_404 from django.shortcuts import render +from core.functions import get_page +from core.paginator import DiggPaginator from gcalendar.forms import EventEntryForm from gcalendar.models import Event @@ -26,6 +29,7 @@ return render(request, 'gcalendar/index.html', { 'tz': tz, + 'V3_DESIGN': True, }) @@ -45,6 +49,7 @@ return render(request, 'gcalendar/event.html', { 'title': 'Add Calendar Event', 'form': form, + 'V3_DESIGN': True, }) @@ -58,17 +63,16 @@ def edit_events(request): events = Event.objects.filter(user=request.user, status=Event.ON_CAL).\ order_by('-start_date') - paginator = Paginator(events, 25) - num = request.GET.get('page') + paginator = DiggPaginator(events, 25, body=5, tail=2, margin=3, padding=2) + num = get_page(request.GET) try: page = paginator.page(num) - except PageNotAnInteger: - page = paginator.page(1) - except EmptyPage: - page = paginator.page(paginator.num_pages) + except InvalidPage: + raise Http404 return render(request, 'gcalendar/edit.html', { 'page': page, + 'V3_DESIGN': True, }) @@ -76,7 +80,7 @@ def edit_event(request, event_id): event = get_object_or_404(Event, pk=event_id) if event.user != request.user: - raise Http404 + raise PermissionDenied if request.method == 'POST': form = EventEntryForm(request.POST, instance=event) @@ -105,11 +109,11 @@ def delete_event(request): """This view marks an event for deletion. It is called via AJAX.""" if request.user.is_authenticated(): - id = request.POST.get('id', None) - if id is None or not id.isdigit(): + event_id = request.POST.get('id') + if event_id is None or not event_id.isdigit(): return HttpResponseBadRequest() try: - event = Event.objects.get(pk=id) + event = Event.objects.get(pk=event_id) except Event.DoesNotExist: return HttpResponseBadRequest() if request.user != event.user: @@ -117,6 +121,6 @@ event.status = Event.DEL_REQ event.save() - return HttpResponse(id) + return HttpResponse(event_id, content_type="text/plain") return HttpResponseForbidden()
--- a/sg101/templates/gcalendar/edit.html Wed May 11 22:00:44 2016 -0500 +++ b/sg101/templates/gcalendar/edit.html Sun May 29 23:09:23 2016 -0500 @@ -1,30 +1,58 @@ -{% extends 'base.html' %} +{% extends 'v3/base.html' %} {% load static from staticfiles %} {% block title %}Edit Calendar Events{% endblock %} +{% block content %} + +<nav aria-label="You are here:" role="navigation"> + <ul class="breadcrumbs"> + <li><a href="{% url 'gcalendar-index' %}">Calendar</a></li> + <li> + <span class="show-for-sr">Current: </span> Edit Events + </li> + </ul> +</nav> + +<h2>Edit Calendar Events</h2> +{% if page.object_list %} +<p> +You have the following events on our calendar. Click on the event title to edit +it, or click the <i class="fi-x size-16"></i> to delete it. Your changes will +be submitted to the site staff for approval, and won't be reflected on the +Google calendar until then. The approval process usually takes less than 12 +hours. Thanks for helping to keep our calendar up to date! +</p> +<table class="stack"> + <thead> + <th>Date</th> + <th>Event Title</th> + <th>Actions</th> + </thead> + <tbody> + {% for event in page.object_list %} + <tr id="gcal-row-{{ event.id }}"> + <td>{{ event.start_date|date:"M d, Y"}}</td> + <td><a href="{% url 'gcalendar-edit_event' event.id %}" + title="Edit Event">{{ event.what }}</a></td> + <td> + <a class="gcal-del" id="gcal-{{ event.id }}" + title="Delete Event"><i class="fi-x size-16"></i></a> + </td> + </tr> + {% endfor %} + </tbody> +</table> +<div class="secondary callout"> + Please don't worry about deleting old events. It's nice to have + a historical record of events on the calendar. +</div> +{% include 'core/v3/pagination.html' %} +{% else %} +<div class="callout"> +You either have no events on our calendar, or all your events have pending +changes that require admin review. +</div> +{% endif %} +{% endblock %} {% block custom_js %} <script type="text/javascript" src="{% static "js/gcalendar_edit.js" %}"></script> {% endblock %} -{% block content %} -<div class="breadcrumbs"><a href="{% url 'gcalendar-index' %}">Calendar</a> » Edit Events</div> -<h2>Edit Calendar Events</h2> -{% if page.object_list %} -<p>You have the following events on our calendar. Click on the event title to edit it, or click the -<img src="{% static "icons/cross.png" %}" alt="Cross" /> to delete it. -Your changes will be submitted to the site staff for approval, and won't be reflected on the Google -calendar until then. The approval process usually takes less than 12 hours. Thanks for helping to -keep our calendar up to date! -</p> -<ul> -{% for event in page.object_list %} -<li>{{ event.start_date|date:"M d, Y"}} • -<a href="{% url 'gcalendar-edit_event' event.id %}" title="Edit Event">{{ event.what }}</a> -<a class="gcal-del" id="gcal-{{ event.id }}" href="#"><img src="{% static "icons/cross.png" %}" alt="Delete Event" title="Delete Event" /></a> -</li> -{% endfor %} -</ul> -{% include 'core/django_pagination.html' with page_obj=page %} -{% else %} -<p>You either have no events on our calendar, or all your events have pending changes -that require admin review.</p> -{% endif %} -{% endblock %}
--- a/sg101/templates/gcalendar/event.html Wed May 11 22:00:44 2016 -0500 +++ b/sg101/templates/gcalendar/event.html Sun May 29 23:09:23 2016 -0500 @@ -1,19 +1,21 @@ -{% extends 'base.html' %} +{% extends 'v3/base.html' %} {% load core_tags %} {% load script_tags %} {% load static from staticfiles %} {% block title %}{{ title }}{% endblock %} {% block custom_css %} +{% css_tags 'jquery-ui markitup' %} <link rel="stylesheet" href="{% static "css/gcalendar.css" %}" /> {% endblock %} -{% block custom_js %} -{% script_tags 'jquery-ui markitup' %} -<script src="{% static "js/timezone.js" %}"></script> -<script src="{% static "js/gcalendar.js" %}"></script> -<script src="{% static "js/jquery.form.min.js" %}"></script> -{% endblock %} + {% block content %} -<div class="breadcrumbs"><a href="{% url 'gcalendar-index' %}">Calendar</a> » {{ title }}</div> +<nav aria-label="You are here:" role="navigation"> + <ul class="breadcrumbs"> + <li><a href="{% url 'gcalendar-index' %}">Calendar</a></li> + <li><span class="show-for-sr">Current: </span>{{ title }}</li> + </ul> +</nav> + <h2>{{ title }}</h2> <p>Use this form to add or change an event on our calendar. Please note the following:</p> <ul> @@ -22,6 +24,134 @@ <li>Once submitted, your event will be reviewed by the site staff for approval. Normally it will appear on the calendar within 24 hours.</li> </ul> + +<form id="id_gcal_event_form" action="." method="post">{% csrf_token %} + {{ form.non_field_errors }} + {{ form.what.errors }} + <div class="row"> + <div class="columns"> + <label for="{{ form.what.id_for_label }}">{{ form.what.label }} + {{ form.what }} + </label> + </div> + </div> + {{ form.start_date.errors }} + {{ form.start_time.errors }} + <div class="row medium-unstack"> + <div class="medium-3 columns"> + <label for="{{ form.start_date.id_for_label }}">{{ form.start_date.label }} + {{ form.start_date }} + </label> + </div> + <div class="medium-3 columns all-day-hide"> + <label for="{{ form.start_time.id_for_label }}">{{ form.start_time.label }} + {{ form.start_time }} + </label> + </div> + </div> + {{ form.end_date.errors }} + {{ form.end_time.errors }} + <div class="row medium-unstack"> + <div class="medium-3 columns"> + <label for="{{ form.end_date.id_for_label }}">{{ form.end_date.label }} + {{ form.end_date }} + </label> + </div> + <div class="medium-3 columns all-day-hide"> + <label for="{{ form.end_time.id_for_label }}">{{ form.end_time.label }} + {{ form.end_time }} + </label> + </div> + </div> + {{ form.all_day.errors }} + <div class="row"> + <div class="columns"> + {{ form.all_day }} + <label for="{{ form.all_day.id_for_label }}"> + {{ form.all_day.label }} + </label> + </div> + </div> + <fieldset class="all-day-hide"> + <legend>Time Zone</legend> + {{ form.time_zone.errors }} + <div class="row medium-unstack"> + <div class="medium-3 columns"> + <select id="id_tz_area"></select> + </div> + <div class="medium-3 columns"> + <select id="id_tz_location"></select> + </div> + </div> + {{ form.time_zome }} + </fieldset> + {{ form.where.errors }} + <div class="row"> + <div class="columns"> + <label for="{{ form.where.id_for_label }}">{{ form.where.label }} + {{ form.where }} + </label> + <p class="help-text" id="where-help-text"> + {{ form.where.help_text }} + </p> + </div> + </div> + {{ form.description.errors }} + <div class="row"> + <div class="columns"> + <label for="{{ form.description.id_for_label }}">{{ form.description.label }}</label> + <ul class="tabs" data-tabs id="editor-tabs"> + <li class="tabs-title is-active"><a href="#editor-panel" + aria-selected="true"><i class="fi-pencil size-21" title="Edit"></i></a></li> + <li class="tabs-title"><a href="#preview-panel"> + <i class="fi-eye size-21" title="Preview"></i></a></li> + </ul> + <div class="tabs-content" data-tabs-content="editor-tabs"> + <div class="tabs-panel is-active v3-editor" id="editor-panel"> + + <ul class="menu"> + <li><a class="editor-bold" href="#"><i class="fi-bold size-21" title="Bold"></i></a></li> + <li><a class="editor-italic" href="#"><i class="fi-italic size-21" title="Italic"></i></a></li> + <li><a class="editor-strike" href="#"><i class="fi-strikethrough size-21" title="Strike"></i></a></li> + <li><a class="editor-link" href="#"><i class="fi-link size-21" title="Link"></i></a></li> + <li><a class="editor-quote" href="#"><i class="fi-quote size-21" title="Quote"></i></a></li> + <li><a class="editor-code" href="#"><i class="fi-music size-21" title="Format Tablature"></i></a></li> + <li><a class="editor-bullet" href="#"><i class="fi-list-bullet size-21" title="Bullet List"></i></a></li> + <li><a class="editor-number" href="#"><i class="fi-list-number size-21" title="Numbered List"></i></a></li> + <li><a class="editor-hot-link" href="#"> + <i class="fi-photo size-21" title="Hot-Link Image"></i></a></li> + <li><a class="editor-upload" href="#"> + <i class="fi-upload size-21" title="Upload Image"></i></a></li> + </ul> + + <!-- + <textarea name="description" placeholder="Event Details" rows="10"></textarea> + --> + {{ form.description }} + </div> + <div class="tabs-panel" id="preview-panel"> + <p>Suspendisse dictum feugiat nisl ut dapibus. Vivamus hendrerit arcu sed erat molestie vehicula. Ut in nulla enim. Phasellus molestie magna non est bibendum non venenatis nisl tempor. Sed auctor neque eu tellus rhoncus ut eleifend nibh porttitor.</p> + </div> + </div> + </div> + </div> + {% if form.create_forum_thread %} + {{ form.create_forum_thread.errors }} + <div class="row"> + <div class="columns"> + {{ form.create_forum_thread }} + <label class="middle" for="{{ form.create_forum_thread.id_for_label }}"> + {{ form.create_forum_thread.label }} + </label> + </div> + </div> + {% endif %} + {{ form.time_zone }} + <input type="submit" name="submit_button" value="Add Event" class="primary button" /> +</form> +<hr> + +<!-- <form id="id_gcal_event_form" action="." method="post">{% csrf_token %} <table> {% if form.non_field_errors %} @@ -50,4 +180,13 @@ </form> {% include 'user_photos/image_forms.html' %} <p><a href="{% url 'gcalendar-index' %}">« Back to the Event Calendar</a></p> +--> + {% endblock %} + +{% block custom_js %} +{% js_tags 'jquery-ui markitup' %} +<script src="{% static "js/timezone.js" %}"></script> +<script src="{% static "js/gcalendar.js" %}"></script> +<script src="{% static "js/jquery.form.min.js" %}"></script> +{% endblock %}
--- a/sg101/templates/gcalendar/index.html Wed May 11 22:00:44 2016 -0500 +++ b/sg101/templates/gcalendar/index.html Sun May 29 23:09:23 2016 -0500 @@ -1,18 +1,29 @@ -{% extends 'base.html' %} +{% extends 'v3/base.html' %} {% load static from staticfiles %} {% block title %}Event Calendar{% endblock %} {% block content %} <h2>SurfGuitar101 Event Calendar</h2> <p> -<strong>Welcome to the SG101 event calendar!</strong> Our users can add events to this -calendar. Please see the links below the calendar to add, modify, or delete events. +<strong>Welcome to the SG101 event calendar!</strong> +Our users can add events to this calendar. +{% if user.is_authenticated %} + Please click the buttons below to add, modify, or delete events. +{% else %} + Please <a href="{% url 'accounts-login' %}?next={% url 'gcalendar-index' %}">login</a> + to add, modify, or delete events. +{% endif %} </p> -<div class="info"> - <p> - This calendar is now aggregating several Google calendars, both from - SurfGuitar101 and other friends in the surf music world. This allows us to give you - more information without duplicating efforts in the community. - </p> +<div class="primary callout"> + <div class="media-object"> + <div class="media-object-section"> + <i class="fi-info size-36"></i> + </div> + <div class="media-object-section"> + This calendar is now aggregating several Google calendars, both from + SurfGuitar101 and other friends in the surf music world. This allows us to give you + more information without duplicating efforts in the community. + </div> + </div> <p> By default we show you all events from all calendars. Too much information? No problem, just use the pull-down menu in the upper right corner of the @@ -26,23 +37,16 @@ </p> {% else %} <p><strong>Please note:</strong> all times shown are in the <strong>{{ tz }}</strong> time zone. Please -<a href="{% url 'accounts-login' %}">login</a> to view the times based on the time zone set in your profile.</p> +<a href="{% url 'accounts-login' %}?next={% url 'gcalendar-index' %}">login</a> to view the times based on the time zone set in your profile.</p> {% endif %} +<div class="flex-video"> <iframe src="https://www.google.com/calendar/embed?showTitle=0&mode=AGENDA&height=640&wkst=1&bgcolor=%23FFFFFF&src=cn1s9ucnemr669g0cc80mfl4s8%40group.calendar.google.com&color=%238C500B&src=b4gjo175fvn4mvbeipr65nc3gg%40group.calendar.google.com&color=%23691426&src=i81lu3fkh57sgqqenogefd9v78%40group.calendar.google.com&color=%231B887A&src=qrihvvsqabp3i3uv8gj4i5lfik%40group.calendar.google.com&color=%23AB8B00&ctz={{ tz|urlencode:"" }}" style="border:solid 1px #777" width="750" height="640" frameborder="0" scrolling="no"></iframe> - -<ul> -{% if user.is_authenticated %} - <li><a href="{% url 'gcalendar-add' %}"><img src="{% static "icons/calendar_add.png" %}" alt="Add" /></a> - <a href="{% url 'gcalendar-add' %}">Add an event to our calendar</a></li> - <li><a href="{% url 'gcalendar-edit_events' %}"><img src="{% static "icons/calendar_edit.png" %}" alt="Edit" /></a> - <a href="{% url 'gcalendar-edit_events' %}">Change or delete an event you previously added</a></li> -{% endif %} - <li> -<a href="http://www.google.com/calendar/feeds/i81lu3fkh57sgqqenogefd9v78%40group.calendar.google.com/public/basic"> -<img src="{% static "icons/feed.png" %}" alt="feed" /></a> -<a href="http://www.google.com/calendar/feeds/i81lu3fkh57sgqqenogefd9v78%40group.calendar.google.com/public/basic"> -RSS Feed</a> -</li> -</ul> +</div> +<div class="button-group"> + <a class="button" href="{% url 'gcalendar-add' %}"><i class="fi-plus size-16"></i> + Add New Event</a> + <a class="secondary button" href="{% url 'gcalendar-edit_events' %}"> + <i class="fi-wrench size-16"></i> Change or Delete Events</a> +</div> {% endblock %}