瀏覽代碼

Events fixes and refinements (#51)

* Bug fixes and docs/updates to event feature. Adding additional content_panel layout options in CoderedPage. Tweaking css and content_panel layouts

* Fixing bug when generating ical

* Removing `get_description` from events because it does not exist

* Additional sorting/occurrence madness and bug fixes. Changing calendar ajax call to GET so it can benefit from caching
Vince Salvino 6 年之前
父節點
當前提交
2d71fa58cc

File diff suppressed because it is too large
+ 22 - 0
coderedcms/migrations/0006_auto_20181213_1753.py


+ 63 - 39
coderedcms/models/page_models.py

@@ -335,10 +335,15 @@ class CoderedPage(Page, metaclass=CoderedPageMeta):
         Page.content_panels +
         [
             ImageChooserPanel('cover_image'),
-            FieldPanel('tags'),
         ]
     )
 
+    body_content_panels = []
+
+    bottom_content_panels = [
+        FieldPanel('tags'),
+    ]
+
     layout_panels = [
         MultiFieldPanel(
             [
@@ -427,7 +432,7 @@ class CoderedPage(Page, metaclass=CoderedPageMeta):
         Override to "lazy load" the panels overriden by subclasses.
         """
         return TabbedInterface([
-            ObjectList(cls.content_panels, heading='Content'),
+            ObjectList(cls.content_panels + cls.body_content_panels + cls.bottom_content_panels, heading='Content'),
             ObjectList(cls.layout_panels, heading='Layout'),
             ObjectList(cls.promote_panels, heading='SEO', classname="seo"),
             ObjectList(cls.settings_panels, heading='Settings', classname="settings"),
@@ -514,6 +519,9 @@ class CoderedPage(Page, metaclass=CoderedPageMeta):
         context['content_walls'] = self.get_content_walls(check_child_setting=False)
         return context
 
+
+
+
 ###############################################################################
 # Abstract pages providing pre-built common website functionality, suitable for subclassing.
 # These are abstract so subclasses can override fields if desired.
@@ -542,10 +550,9 @@ class CoderedWebPage(CoderedPage):
     )
 
     # Panels
-    content_panels = (
-        CoderedPage.content_panels +
-        [StreamFieldPanel('body'),]
-    )
+    body_content_panels = [
+        StreamFieldPanel('body'),
+    ]
 
     @property
     def body_preview(self):
@@ -569,7 +576,7 @@ class CoderedWebPage(CoderedPage):
 
     @page_ptr.setter
     def page_ptr(self, value):
-        self.base_page_ptr = value    
+        self.base_page_ptr = value
 
 
 class CoderedArticlePage(CoderedWebPage):
@@ -654,12 +661,7 @@ class CoderedArticlePage(CoderedWebPage):
     content_panels = (
         CoderedWebPage.content_panels +
         [
-            MultiFieldPanel(
-                [
-                    FieldPanel('caption'),
-                ],
-                _('Additional Content')
-            ),
+            FieldPanel('caption'),
             MultiFieldPanel(
                 [
                     FieldPanel('author'),
@@ -739,13 +741,14 @@ class CoderedEventPage(CoderedWebPage, BaseEvent):
             MultiFieldPanel(
                 [
                     FieldPanel('calendar_color'),
+                    FieldPanel('address'),
                 ],
                 heading=_('Event information')
             ),
-            FieldPanel('address'),
             InlinePanel(
                 'occurrences',
-                heading="Occurrences",
+                min_num=1,
+                heading=_("Dates and times"),
             ),
         ]
     )
@@ -754,11 +757,26 @@ class CoderedEventPage(CoderedWebPage, BaseEvent):
     def upcoming_occurrences(self):
         """
         Returns the next x occurrences for this event.
-
         By default, it returns 10.
         """
         return self.query_occurrences(num_of_instances_to_return=10)
 
+    @property
+    def most_recent_occurrence(self):
+        """
+        Gets the next upcoming, or last occurrence if the event has no more occurrences.
+        """
+        noc = self.next_occurrence()
+        if noc:
+            return noc
+        else:
+            aoc = []
+            for occurrence in self.occurrences.all():
+                aoc += [instance for instance in occurrence.all_occurrences()]
+            if len(aoc) > 0:
+                return aoc[-1] # last one in the list
+            return None
+
     def query_occurrences(self, num_of_instances_to_return=None, **kwargs):
         """
         Returns a list of all upcoming event instances for the specified query.
@@ -790,6 +808,9 @@ class CoderedEventPage(CoderedWebPage, BaseEvent):
     def convert_to_ical_format(self, dt_start=None, dt_end=None, occurrence=None):
         ical_event = ICalEvent()
         ical_event.add('summary', self.title)
+        if self.address:
+            ical_event.add('location', self.address)
+
         if dt_start:
             ical_event.add('dtstart', dt_start)
 
@@ -829,10 +850,11 @@ class DefaultCalendarViewChoices():
     LIST_MONTH = 'listMonth'
 
     CHOICES = (
-            (MONTH, 'Monthly Calendar'),
-            (AGENDA_WEEK, 'Weekly Calendar'),
-            (AGENDA_DAY, 'Daily Calendar'),
-            (LIST_MONTH, 'Monthly List'),
+            ('', _('No calendar')),
+            (MONTH, _('Monthly Calendar')),
+            (AGENDA_WEEK, _('Weekly Calendar')),
+            (AGENDA_DAY, _('Daily Calendar')),
+            (LIST_MONTH, _('Calendar List View')),
         )
 
 class CoderedEventIndexPage(CoderedWebPage):
@@ -857,7 +879,7 @@ class CoderedEventIndexPage(CoderedWebPage):
         blank=True,
         choices=DefaultCalendarViewChoices.CHOICES,
         max_length=255,
-        verbose_name=_('Default Calendar View'),
+        verbose_name=_('Calendar Style'),
         help_text=_('The default look of the calendar on this page.')
     )
 
@@ -872,19 +894,22 @@ class CoderedEventIndexPage(CoderedWebPage):
         if self.index_query_pagemodel and self.index_order_by == 'next_occurrence':
             querymodel = resolve_model_string(self.index_query_pagemodel, self._meta.app_label)
             qs = querymodel.objects.child_of(self).live()
-            qs = sorted(qs.all(), key=lambda e: e.next_occurrence())
-            return qs
+            # filter out events that don't have a next_occurrence
+            upcoming = []
+            for event in qs.all():
+                if event.next_occurrence():
+                    upcoming.append(event)
+            # sort the events by next_occurrence
+            return sorted(upcoming, key=lambda e: e.next_occurrence())
 
         return super().get_index_children()
 
     def get_calendar_events(self, start, end):
-        events = set()
-
-        for event_page in self.get_index_children():
-            events.add(event_page)
-
+        # start with all child events, regardless of get_index_children rules.
+        querymodel = resolve_model_string(self.index_query_pagemodel, self._meta.app_label)
+        qs = querymodel.objects.child_of(self).live()
         event_instances = []
-        for event in events:
+        for event in qs:
             occurrences = event.query_occurrences(limit=None, from_date=start, to_date=end)
             for occurrence in occurrences:
                 event_data = {
@@ -1002,8 +1027,8 @@ class CoderedFormPage(CoderedWebPage):
         help_text=_('Date and time when the FORM will no longer be available on the page.'),
     )
 
-    content_panels = (
-        CoderedWebPage.content_panels +
+    body_content_panels = (
+        CoderedWebPage.body_content_panels +
         [
             FormSubmissionsPanel(),
             InlinePanel('form_fields', label="Form fields"),
@@ -1328,13 +1353,12 @@ class CoderedLocationPage(CoderedWebPage):
     )
 
     content_panels = (
-        CoderedWebPage.content_panels[:1] + 
+        CoderedWebPage.content_panels +
         [
             FieldPanel('address'),
             FieldPanel('website'),
             FieldPanel('phone_number'),
-        ] +
-        CoderedWebPage.content_panels[1:]
+        ]
     )
 
     layout_panels = (
@@ -1351,7 +1375,7 @@ class CoderedLocationPage(CoderedWebPage):
     )
 
     settings_panels = (
-        CoderedWebPage.settings_panels + 
+        CoderedWebPage.settings_panels +
         [
             MultiFieldPanel(
                 [
@@ -1389,7 +1413,7 @@ class CoderedLocationPage(CoderedWebPage):
                 'page': self
             }
         )
-    
+
     def to_geojson(self):
         return {
             "type": "Feature",
@@ -1436,13 +1460,13 @@ class CoderedLocationIndexPage(CoderedWebPage):
 
     center_latitude = models.FloatField(
         null=True,
-        blank=True, 
+        blank=True,
         help_text=_('The default latitude you want the map set to.'),
         default=0
     )
     center_longitude = models.FloatField(
         null=True,
-        blank=True, 
+        blank=True,
         help_text=_('The default longitude you want the map set to.'),
         default=0
     )
@@ -1468,7 +1492,7 @@ class CoderedLocationIndexPage(CoderedWebPage):
             ),
         ]
     )
-        
+
     def geojson_data(self, viewport=None):
         """
         function that will return all locations under this index as geoJSON compliant data.

+ 6 - 1
coderedcms/project_template/project_name/settings/base.py

@@ -187,4 +187,9 @@ BOOTSTRAP4 = {
     'base_url': '',
     # remove green highlight on inputs
     'success_css_class': ''
-}
+}
+
+
+# Tags
+
+TAGGIT_CASE_INSENSITIVE = True

File diff suppressed because it is too large
+ 22 - 0
coderedcms/project_template/website/migrations/0005_auto_20181213_1753.py


+ 4 - 3
coderedcms/static/css/codered-admin.css

@@ -52,7 +52,7 @@ body.ready input[type='checkbox'], body.ready input[type='radio'] {
 
 .halloeditor, .tagit, input, select, textarea {
     background-color:#eee;
-    border:1px solid #eee;
+    border:1.5px solid #ddd;
     padding-top:0.5em;
     padding-bottom:0.5em;
     font-weight:normal;
@@ -60,7 +60,7 @@ body.ready input[type='checkbox'], body.ready input[type='radio'] {
 
 .halloeditor:hover, .tagit:hover, input:hover, select:hover, textarea:hover {
     background-color:#eee;
-    border:1px solid #eee;
+    border:1.5px solid #ddd;
 }
 
 input[type='checkbox'], input[type='radio'] {
@@ -78,7 +78,8 @@ input[type='checkbox']::before, input[type='radio']::before {
 .full input {
     background-color:white;
 }
-.full input:focus, .halloeditor:focus, .tagit:focus, input:focus, select:focus, textarea:focus {
+.full input:focus, .halloeditor:focus, .tagit:focus, input:focus, select:focus, textarea:focus,
+.tag_field.focused .tagit {
     border-color:#00b0b1;
     background-color:#f2fcfc;
 }

+ 3 - 2
coderedcms/static/css/codered-editor.css

@@ -35,7 +35,7 @@ label,
 .sequence-member .richtext,
 .sequence-member .tagit {
     background-color:white;
-    border:1px solid #ddd;
+    border:1.5px solid #ddd;
 }
 
 .sequence-member input:focus,
@@ -67,6 +67,7 @@ label,
 }
 .input input[type='color']{
     height: 40px;
+    padding: 5px;
 }
 
 
@@ -215,7 +216,7 @@ li.sequence-member li > .field .Draftail-Editor,
 li.sequence-member li.sequence-member .Draftail-Editor {
     background-color: #fff !important;
     border-radius:5px;
-    border:1px solid #ddd !important;
+    border:1.5px solid #ddd !important;
     padding: 0.5em 1em;
 }
 li.sequence-member li.sequence-member .Draftail-Editor {

+ 2 - 2
coderedcms/static/js/codered-front.js

@@ -166,9 +166,9 @@ $(document).ready(function()
                                 fixedWeekCount: false,
                                 events: {
                                     url: '/ajax/calendar/events/',
-                                    type: 'POST',
+                                    type: 'GET',
                                     data: {
-                                        'page_id': pageId
+                                        'pid': pageId
                                     }
                                 }
                             });

+ 1 - 1
coderedcms/templates/coderedcms/includes/ical/calendar_ical_button.html

@@ -1,5 +1,5 @@
 <form data-attribute="calendar-ical-form" class="calendar-ical-form" action="{% url 'event_generate_ical_for_calendar' %}" method="POST">
         <input name="page_id" type="number" hidden value="{{ page.id }}" />
         {% csrf_token %}
-    <button class="btn btn-primary" type="submit">{% block button_text %}Download Calendar{% endblock %}</button>
+    <button class="btn btn-primary" title="Download calendar in .ical format" type="submit">{% block button_text %}Download Calendar{% endblock %}</button>
 </form>

+ 1 - 1
coderedcms/templates/coderedcms/includes/ical/recurring_ical_button.html

@@ -1,5 +1,5 @@
 <form data-attribute="recurring-ical-form-{{event.pk}}" class="recurring-ical-form" action="{% url 'event_generate_recurring_ical' %}" method="POST">
     {% csrf_token %}
     <input name="event_pk" type="number" hidden value="{{event.pk}}" />
-    <button class="btn btn-primary" type="submit">{% block button_text %}Add All Events To Calendar{% endblock %}</button>
+    <button class="btn btn-primary" title="Download events in .ical format" type="submit">{% block button_text %}Add All Events To Calendar{% endblock %}</button>
 </form>

+ 4 - 4
coderedcms/templates/coderedcms/includes/ical/single_ical_button.html

@@ -1,7 +1,7 @@
-<form data-attribute="single-ical-form-{{event.pk}}-{{datetime_start}}" class="single-ical-form" action="{% url 'event_generate_single_ical' %}" method="POST">
+<form data-attribute="single-ical-form-{{event.pk}}-{{datetime_start}}" class="single-ical-form d-inline" action="{% url 'event_generate_single_ical' %}" method="POST">
     {% csrf_token %}
     <input name="event_pk" type="number" hidden value="{{event.pk}}" />
-    <input name="datetime_start" type="text" hidden value="{{datetime_start}}" />
-    <input name="datetime_end" type="text" hidden value="{{datetime_end}}" />
-    <button class="btn btn-primary" type="submit">{% block button_text %}Add to Calendar{% endblock %}</button>
+    <input name="datetime_start" type="text" hidden value="{{start|date:"c"}}" />
+    <input name="datetime_end" type="text" hidden value="{{end|date:"c"}}" />
+    <button class="btn btn-primary btn-sm" title="Download event in .ical format" type="submit">{% block button_text %}Add to Calendar{% endblock %}</button>
 </form>

+ 1 - 1
coderedcms/templates/coderedcms/includes/iframe_gmap.html

@@ -1,5 +1,5 @@
 {% if address %}
-<div class="row mb-2 mt-2">
+<div class="my-2">
     <div class="embed-responsive embed-responsive-16by9 mb-5">
         <iframe class="embed-responsive-item" width="100%" style="border:0" src="https://maps.google.com/maps?q={{ address }}&output=embed" allowfullscreen></iframe>
     </div>

+ 14 - 5
coderedcms/templates/coderedcms/includes/struct_data_event.json

@@ -2,11 +2,14 @@
 
 {
   "@context": "http://schema.org",
- "mainEntityOfPage": {
+  "mainEntityOfPage": {
     "@type": "WebPage",
     "@id": "{{page.get_full_url}}"
   },
-  "description": "{{page.get_description}}",
+
+  {% if page.search_description %}
+  "description": "{{page.search_description}}",
+  {% endif %}
 
   {# Get different aspect ratios. Use huge numbers because wagtail will not upscale, #}
   {# but will max out at the image's original resultion using the specified aspect ratio. #}
@@ -31,6 +34,7 @@
     ],
   {% endif %}
 
+  {% if self.address %}
   "location":{
     "@type": "Place",
     "name": "{{self.title}}",
@@ -39,11 +43,16 @@
       "streetAddress": "{{self.address}}",
     }
   },
+  {% endif %}
+
   "name": "{{self.title}}",
-  "startDate": "{{self.next_occurrence.0|structured_data_datetime}}",
-  {% if self.next_occurrence.1 != '' %}
-  "endDate": "{{self.next_occurrence.1|structured_data_datetime}}",
+
+  {% with self.most_recent_occurrence as nextup %}
+  "startDate": "{{nextup.0|structured_data_datetime}}",
+  {% if nextup.1 %}
+  "endDate": "{{nextup.1|structured_data_datetime}}",
   {% endif %}
+  {% endwith %}
 
   "@type": "Event"
 }

+ 0 - 8
coderedcms/templates/coderedcms/pages/article_page.html

@@ -15,14 +15,6 @@
 {% if settings.coderedcms.SeoSettings.og_meta %}
     {% block og_description %}{{self.get_description}}{% endblock %}
     {% block og_type %}article{% endblock %}
-    {% block og_image %}
-        {% if self.cover_image %}
-            {% image self.cover_image fill-2000x1000 as cover_image %}
-            {{self.get_site.root_url}}{{cover_image.url}}
-        {% else %}
-            {{block.super}}
-        {% endif %}
-    {% endblock %}
     {% block og_seo_extra %}
         <meta property="og:article:published_time" content="{{self.get_pub_date}}" />
         <meta property="og:article:modified_time" content="{{self.last_published_at}}" />

+ 3 - 0
coderedcms/templates/coderedcms/pages/base.html

@@ -42,6 +42,9 @@
                 {% if self.og_image %}
                     {% image self.og_image original as og_logo %}
                     {{og_logo.url}}
+                {% elif self.cover_image %}
+                    {% image self.cover_image original as og_logo %}
+                    {{og_logo.url}}
                 {% elif settings.coderedcms.LayoutSettings.logo %}
                     {% image settings.coderedcms.LayoutSettings.logo original as og_logo %}
                     {{og_logo.url}}

+ 3 - 1
coderedcms/templates/coderedcms/pages/event_index_page.html

@@ -3,6 +3,7 @@
 {% load wagtailcore_tags wagtailimages_tags coderedcms_tags %}
 
 {% block content_post_body %}
+{% if self.default_calendar_view %}
     <div class="container">
         <div class="row">
             <div class="col pt-5 pb-5">
@@ -17,6 +18,7 @@
             </div>
         </div>
     </div>
+{% endif %}
 {% endblock %}
 
 {% block index_content %}
@@ -34,7 +36,7 @@
                 {% block event_body_preview %}
                     <div class="col-md">
                         <h3><a href="{{ event.url }}">{{ event.title }}</a></h3>
-                        <p>{{ event.next_occurrence.0 }}</p>
+                        <p>{{ event.most_recent_occurrence.0 }}</p>
                         <p>{{ event.body_preview }}</p>
                     </div>
                 {% endblock %}

+ 35 - 46
coderedcms/templates/coderedcms/pages/event_page.html

@@ -1,27 +1,26 @@
 {% extends "coderedcms/pages/web_page.html" %}
-
 {% load wagtailadmin_tags wagtailcore_tags wagtailimages_tags coderedcms_tags %}
 
-{% block description %}{{self.get_description}}{% endblock %}
-
-
-{% if settings.coderedcms.SeoSettings.og_meta %}
-    {% block og_description %}{{self.get_description}}{% endblock %}
-    {% block og_image %}
-        {% if self.cover_image %}
-            {% image self.cover_image fill-2000x1000 as cover_image %}
-            {{self.get_site.root_url}}{{cover_image.url}}
-        {% else %}
-            {{block.super}}
-        {% endif %}
-    {% endblock %}
-{% endif %}
-
 {% if settings.coderedcms.SeoSettings.twitter_meta %}
     {% block twitter_card %}{% if self.cover_image %}summary_large_image{% else %}{{block.super}}{% endif %}{% endblock %}
 {% endif %}
 
+{% block content_pre_body %}
+    {{ block.super }}
+    {% with self.most_recent_occurrence as nextup %}
+    <div class="container my-5">
+        <p class="d-md-inline-block mr-4"><b>When:</b> {{nextup.0}}</p>
+        {% if self.address %}
+        <p class="d-md-inline-block mr-4"><b>Where:</b> {{self.address}}</p>
+        {% endif %}
+        <div class="float-lg-right">{% include "coderedcms/includes/ical/single_ical_button.html" with event=self start=nextup.0 end=nextup.1 %}</div>
+        <hr>
+    </div>
+    {% endwith %}
+{% endblock %}
+
 {% block content_post_body %}
+
     {% block map %}
         <div class="container">
             {% include 'coderedcms/includes/iframe_gmap.html' with address=page.address %}
@@ -29,42 +28,32 @@
     {% endblock %}
 
     {% block upcoming_dates %}
-        {% if self.upcoming_occurrences %}
+        {% if self.upcoming_occurrences|length > 1 %}
             <div class="container">
-                <div class="row">
-                    <div class="col">
-                        <h3 style="display:inline-block;">Upcoming Dates</h3>
-                        <div class="table-responsive">
-                            <table class="table table-striped">
-                                <tr>
-                                    <th>Starting Time</th>
-                                    <th>Ending Time</th>
-                                    <th>Actions</th>
-                                </tr>
-                                {% for date in self.upcoming_occurrences %}
-                                <tr>
-                                    <td>{{date.0}}</td>
-                                    <td>{% if date.0 != date.1 %}{{date.1}}{% endif %}</td>
-                                    <td>{% include "coderedcms/includes/ical/single_ical_button.html" with event=self datetime_start=date.0|date:"c" datetime_end=date.1|date:"c" %}</td>
-                                </tr>
-                                {% endfor %}
-                            </table>
-                        </div>
-                    </div>
+                <h2>Upcoming Dates</h2>
+                <div class="table-responsive">
+                    <table class="table table-striped">
+                        <tr>
+                            <th>Start Time</th>
+                            <th>End Time</th>
+                            <th>Actions</th>
+                        </tr>
+                        {% for date in self.upcoming_occurrences %}
+                        <tr>
+                            <td>{{date.0}}</td>
+                            <td>{% if date.0 != date.1 %}{{date.1}}{% endif %}</td>
+                            <td>{% include "coderedcms/includes/ical/single_ical_button.html" with event=self start=date.0 end=date.1 %}</td>
+                        </tr>
+                        {% endfor %}
+                    </table>
                 </div>
+                {% block ical %}
+                    {% include "coderedcms/includes/ical/recurring_ical_button.html" with event=self %}
+                {% endblock %}
             </div>
         {% endif %}
     {% endblock %}
 
-    {% block ical %}
-        <div class="container">
-            <div class="row">
-                <div class="col">
-                    {% include "coderedcms/includes/ical/recurring_ical_button.html" with event=self %}
-                </div>
-            </div>
-        </div>
-    {% endblock %}
 {% endblock %}
 
 {% if settings.coderedcms.SeoSettings.struct_meta %}

+ 12 - 3
coderedcms/views.py

@@ -17,6 +17,7 @@ from wagtail.core.models import Page
 from wagtail.search.backends import db, get_search_backend
 from wagtail.search.models import Query
 
+from coderedcms import utils
 from coderedcms.forms import SearchForm
 from coderedcms.models import CoderedPage, CoderedEventPage, get_page_models, GeneralSettings
 from coderedcms.importexport import convert_csv_to_json, import_pages, ImportPagesFromCSVFileForm
@@ -24,6 +25,7 @@ from coderedcms.settings import cr_settings
 
 
 
+
 def search(request):
     """
     Searches pages across the entire site.
@@ -99,6 +101,7 @@ def search(request):
         'results_paginated': results_paginated
     })
 
+
 @login_required
 def serve_protected_file(request, path):
     """
@@ -115,6 +118,7 @@ def serve_protected_file(request, path):
         return response
     raise Http404()
 
+
 def robots(request):
     robots = GeneralSettings.for_site(request.site).robots
     return render(
@@ -124,6 +128,7 @@ def robots(request):
         content_type='text/plain'
     )
 
+
 def event_generate_single_ical_for_event(request):
     if request.method == "POST":
         event_pk = request.POST['event_pk']
@@ -147,6 +152,7 @@ def event_generate_single_ical_for_event(request):
         return response
     raise Http404()
 
+
 def event_generate_recurring_ical_for_event(request):
     if request.method == "POST":
         event_pk = request.POST['event_pk']
@@ -166,6 +172,7 @@ def event_generate_recurring_ical_for_event(request):
         return response
     raise Http404()
 
+
 def event_generate_ical_for_calendar(request):
     if request.method == "POST":
         try:
@@ -184,19 +191,21 @@ def event_generate_ical_for_calendar(request):
         return response
     raise Http404()
 
+
 def event_get_calendar_events(request):
     if request.is_ajax():
         try:
-            page = CoderedPage.objects.get(id=request.POST.get('page_id')).specific
+            page = CoderedPage.objects.get(id=request.GET.get('pid')).specific
         except ValueError:
             raise Http404
-        start_str = request.POST.get('start')
+        start_str = request.GET.get('start')
         start = datetime.strptime(start_str[:10], "%Y-%m-%d") if start_str else None
-        end_str = request.POST.get('end')
+        end_str = request.GET.get('end')
         end = datetime.strptime(end_str[:10], "%Y-%m-%d") if end_str else None
         return JsonResponse(page.get_calendar_events(start=start, end=end), safe=False)
     raise Http404()
 
+
 @login_required
 def import_pages_from_csv_file(request):
     """

+ 33 - 8
docs/features/events.rst

@@ -1,15 +1,40 @@
 Events
 =============
 
-Event pages allow users to create a calendar or list of events.  These lists/calendars allow
-users to download ical invitations to their own calendars.
+Create a calendar or list of events. Visitors can download ical invitations to their own calendars
+for each event, recurring events, or all events.
 
-There are two abstract pages when dealing with events.  The first ``CoderedEventPage`` holds 
-the information regarding the event.  Dates, location, etc all will fall under this page.  The
-``CoderedEventIndexPage`` will aggregate its children ``CoderedEventPage`` and display them in a calendar.  
 
-The event functionality is built-in to Codered CMS but it is not enabled by default.  To implement,
-add the following to your ``website/models.py``::
+Usage
+-----
+
+If events are implemented on your site (see instructions below), first start by creating an
+"Event Landing Page" (may be named differently on your specific website). Add content to this
+page as usual. Under the **Layout** tab, you can choose a few options:
+
+* Show list of child pages: Check this box to show a list of all events.
+* Calendar style: There are several options here. Choose one that fits your needs.
+
+Next, save the Event Landing Page. Now create a child page. Each child page here represents
+an individual event. Events can be one time, or recurring, similar to Outlook or other
+calendar software.
+
+When creating an event page, fill out the relevant information, and click the **+** icon next
+to "Dates and times" to add an event occurrence. You can create multiple occurrences, or set
+an occurrence to repeat.
+
+
+Implementation
+--------------
+
+The event functionality is built-in to CodeRed CMS but it is not enabled by default.
+
+There are two abstract pages when dealing with events.  The first ``CoderedEventPage`` holds
+the information regarding the event.  Dates, location, etc. all will fall under this page.  The
+``CoderedEventIndexPage`` will aggregate its children ``CoderedEventPage`` and display them in a
+calendar or list.
+
+To implement, add the following to your ``website/models.py``::
 
     from modelcluster.fields import ParentalKey
     from coderedcms.models import (
@@ -49,4 +74,4 @@ add the following to your ``website/models.py``::
 Next run ``python manage.py makemigrations`` and ``python manage.py migrate`` to create the new pages
 in your project.
 
-Now when going to the wagtail admin, you can create an EventIndexPage, and child EventPages.
+Now when going to the wagtail admin, you can create an Event Landing Page, and child Event Pages.

Some files were not shown because too many files changed in this diff