mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-17 05:22:16 +00:00
Added calendar view
This commit is contained in:
@@ -33,6 +33,8 @@ class RigboardIndex(generic.TemplateView):
|
||||
context['events'] = models.Event.objects.current_events()
|
||||
return context
|
||||
|
||||
class WebCalendar(generic.TemplateView):
|
||||
template_name = 'RIGS/calendar.html'
|
||||
|
||||
class EventDetail(generic.DetailView):
|
||||
model = models.Event
|
||||
|
||||
1061
RIGS/static/css/fullcalendar.css
Executable file
1061
RIGS/static/css/fullcalendar.css
Executable file
File diff suppressed because it is too large
Load Diff
202
RIGS/static/css/fullcalendar.print.css
Executable file
202
RIGS/static/css/fullcalendar.print.css
Executable file
@@ -0,0 +1,202 @@
|
||||
/*!
|
||||
* FullCalendar v2.3.1 Print Stylesheet
|
||||
* Docs & License: http://fullcalendar.io/
|
||||
* (c) 2015 Adam Shaw
|
||||
*/
|
||||
|
||||
/*
|
||||
* Include this stylesheet on your page to get a more printer-friendly calendar.
|
||||
* When including this stylesheet, use the media='print' attribute of the <link> tag.
|
||||
* Make sure to include this stylesheet IN ADDITION to the regular fullcalendar.css.
|
||||
*/
|
||||
|
||||
.fc {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
|
||||
/* Global Event Restyling
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
.fc-event {
|
||||
background: #fff !important;
|
||||
color: #000 !important;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.fc-event .fc-resizer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/* Table & Day-Row Restyling
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
th,
|
||||
td,
|
||||
hr,
|
||||
thead,
|
||||
tbody,
|
||||
.fc-row {
|
||||
border-color: #ccc !important;
|
||||
background: #fff !important;
|
||||
}
|
||||
|
||||
/* kill the overlaid, absolutely-positioned common components */
|
||||
.fc-bg,
|
||||
.fc-bgevent-skeleton,
|
||||
.fc-highlight-skeleton,
|
||||
.fc-helper-skeleton {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* don't force a min-height on rows (for DayGrid) */
|
||||
.fc tbody .fc-row {
|
||||
height: auto !important; /* undo height that JS set in distributeHeight */
|
||||
min-height: 0 !important; /* undo the min-height from each view's specific stylesheet */
|
||||
}
|
||||
|
||||
.fc tbody .fc-row .fc-content-skeleton {
|
||||
position: static; /* undo .fc-rigid */
|
||||
padding-bottom: 0 !important; /* use a more border-friendly method for this... */
|
||||
}
|
||||
|
||||
.fc tbody .fc-row .fc-content-skeleton tbody tr:last-child td { /* only works in newer browsers */
|
||||
padding-bottom: 1em; /* ...gives space within the skeleton. also ensures min height in a way */
|
||||
}
|
||||
|
||||
.fc tbody .fc-row .fc-content-skeleton table {
|
||||
/* provides a min-height for the row, but only effective for IE, which exaggerates this value,
|
||||
making it look more like 3em. for other browers, it will already be this tall */
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* Undo month-view event limiting. Display all events and hide the "more" links
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
.fc-more-cell,
|
||||
.fc-more {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.fc tr.fc-limited {
|
||||
display: table-row !important;
|
||||
}
|
||||
|
||||
.fc td.fc-limited {
|
||||
display: table-cell !important;
|
||||
}
|
||||
|
||||
.fc-popover {
|
||||
display: none; /* never display the "more.." popover in print mode */
|
||||
}
|
||||
|
||||
|
||||
/* TimeGrid Restyling
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* undo the min-height 100% trick used to fill the container's height */
|
||||
.fc-time-grid {
|
||||
min-height: 0 !important;
|
||||
}
|
||||
|
||||
/* don't display the side axis at all ("all-day" and time cells) */
|
||||
.fc-agenda-view .fc-axis {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* don't display the horizontal lines */
|
||||
.fc-slats,
|
||||
.fc-time-grid hr { /* this hr is used when height is underused and needs to be filled */
|
||||
display: none !important; /* important overrides inline declaration */
|
||||
}
|
||||
|
||||
/* let the container that holds the events be naturally positioned and create real height */
|
||||
.fc-time-grid .fc-content-skeleton {
|
||||
position: static;
|
||||
}
|
||||
|
||||
/* in case there are no events, we still want some height */
|
||||
.fc-time-grid .fc-content-skeleton table {
|
||||
height: 4em;
|
||||
}
|
||||
|
||||
/* kill the horizontal spacing made by the event container. event margins will be done below */
|
||||
.fc-time-grid .fc-event-container {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
/* TimeGrid *Event* Restyling
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* naturally position events, vertically stacking them */
|
||||
.fc-time-grid .fc-event {
|
||||
position: static !important;
|
||||
margin: 3px 2px !important;
|
||||
}
|
||||
|
||||
/* for events that continue to a future day, give the bottom border back */
|
||||
.fc-time-grid .fc-event.fc-not-end {
|
||||
border-bottom-width: 1px !important;
|
||||
}
|
||||
|
||||
/* indicate the event continues via "..." text */
|
||||
.fc-time-grid .fc-event.fc-not-end:after {
|
||||
content: "...";
|
||||
}
|
||||
|
||||
/* for events that are continuations from previous days, give the top border back */
|
||||
.fc-time-grid .fc-event.fc-not-start {
|
||||
border-top-width: 1px !important;
|
||||
}
|
||||
|
||||
/* indicate the event is a continuation via "..." text */
|
||||
.fc-time-grid .fc-event.fc-not-start:before {
|
||||
content: "...";
|
||||
}
|
||||
|
||||
/* time */
|
||||
|
||||
/* undo a previous declaration and let the time text span to a second line */
|
||||
.fc-time-grid .fc-event .fc-time {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
/* hide the the time that is normally displayed... */
|
||||
.fc-time-grid .fc-event .fc-time span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ...replace it with a more verbose version (includes AM/PM) stored in an html attribute */
|
||||
.fc-time-grid .fc-event .fc-time:after {
|
||||
content: attr(data-full);
|
||||
}
|
||||
|
||||
|
||||
/* Vertical Scroller & Containers
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* kill the scrollbars and allow natural height */
|
||||
.fc-scroller,
|
||||
.fc-day-grid-container, /* these divs might be assigned height, which we need to cleared */
|
||||
.fc-time-grid-container { /* */
|
||||
overflow: visible !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
/* kill the horizontal border/padding used to compensate for scrollbars */
|
||||
.fc-row {
|
||||
border: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
/* Button Controls
|
||||
--------------------------------------------------------------------------------------------------*/
|
||||
|
||||
.fc-button-group,
|
||||
.fc button {
|
||||
display: none; /* don't display any button-related controls */
|
||||
}
|
||||
10789
RIGS/static/js/fullcalendar.js
Executable file
10789
RIGS/static/js/fullcalendar.js
Executable file
File diff suppressed because it is too large
Load Diff
7
RIGS/static/js/moment.min.js
vendored
Executable file
7
RIGS/static/js/moment.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
111
RIGS/templates/RIGS/calendar.html
Normal file
111
RIGS/templates/RIGS/calendar.html
Normal file
@@ -0,0 +1,111 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
|
||||
{% block title %}Calendar{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<link href="{% static "css/fullcalendar.css" %}" rel='stylesheet' />
|
||||
<link href="{% static "css/fullcalendar.print.css" %}" rel='stylesheet' media='print' />
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{# <script src="//code.jquery.com/jquery-latest.min.js"></script> #}
|
||||
<script src="{% static "js/moment.min.js" %}"></script>
|
||||
<script src="{% static "js/fullcalendar.js" %}"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
$('#calendar').fullCalendar({
|
||||
//defaultDate: '2015-02-12',
|
||||
editable: false,
|
||||
eventLimit: true, // allow "more" link when too many events
|
||||
firstDay: 1,
|
||||
aspectRatio: 1.5,
|
||||
timeFormat: 'HH:mm',
|
||||
views: {
|
||||
basic: {
|
||||
// options apply to basicWeek and basicDay views
|
||||
},
|
||||
agenda: {
|
||||
// options apply to agendaWeek and agendaDay views
|
||||
},
|
||||
week: {
|
||||
columnFormat:'ddd D/M'
|
||||
},
|
||||
day: {
|
||||
// options apply to basicDay and agendaDay views
|
||||
}
|
||||
},
|
||||
buttonText:{
|
||||
today: 'Today',
|
||||
month: 'Month',
|
||||
week: 'Week',
|
||||
day: 'Day'
|
||||
},
|
||||
header:{
|
||||
left: 'title',
|
||||
center: '',
|
||||
right: 'today prev,next month,agendaWeek,agendaDay'
|
||||
},
|
||||
events: function(start_moment, end_moment, timezone, callback) {
|
||||
|
||||
$.ajax({
|
||||
url: '/api/event',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
start: moment(start_moment).format("YYYY-MM-DD[T]HH:mm:ss[Z]"),
|
||||
end: moment(end_moment).format("YYYY-MM-DD[T]HH:mm:ss[Z]")
|
||||
},
|
||||
success: function(doc) {
|
||||
var events = [];
|
||||
var colours =
|
||||
$(doc).each(function() {
|
||||
thisEvent = [];
|
||||
colours = {'Provisional': 'orange',
|
||||
'Confirmed': 'green' ,
|
||||
'Booked': 'green' ,
|
||||
'Cancelled': 'grey'
|
||||
};
|
||||
|
||||
thisEvent['start'] = $(this).attr('start_date');
|
||||
if ($(this).attr('start_time')) {
|
||||
thisEvent['start'] += 'T' + $(this).attr('start_time');
|
||||
|
||||
}
|
||||
|
||||
if ($(this).attr('end_date')) {
|
||||
thisEvent['end'] = $(this).attr('end_date');
|
||||
if ($(this).attr('end_time')) {
|
||||
thisEvent['end'] += 'T' + $(this).attr('end_time');
|
||||
}
|
||||
}
|
||||
thisEvent['className'] = 'modal-href';
|
||||
|
||||
thisEvent['title'] = $(this).attr('title');
|
||||
|
||||
thisEvent['color'] = colours[$(this).attr('status')];
|
||||
|
||||
thisEvent['url'] = $(this).attr('url');
|
||||
|
||||
events.push(thisEvent);
|
||||
});
|
||||
callback(events);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div style="col-sm-12">
|
||||
<div id='calendar'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,13 +1,22 @@
|
||||
{% extends 'base.html' %}
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||
{% block title %}Event {% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}
|
||||
{% endif %}{% endblock %}
|
||||
|
||||
{% block buttons %}
|
||||
{% if not request.is_ajax %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
{% if not request.is_ajax %}
|
||||
<div class="col-sm-12">
|
||||
<div class="col-sm-8">
|
||||
<h1>Event {% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %}</h1>
|
||||
</div>
|
||||
<div class="col-sm-4 text-right">
|
||||
<div class="col-sm-12 text-right">
|
||||
<div class="btn-group btn-page">
|
||||
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
|
||||
class="glyphicon glyphicon-edit"></span></a>
|
||||
@@ -26,7 +35,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
{% if object.is_rig %}
|
||||
{# only need contact details for a rig #}
|
||||
<div class="col-sm-12 col-md-6 col-lg-5">
|
||||
@@ -154,6 +163,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if not request.is_ajax %}
|
||||
<div class="col-sm-12 text-right">
|
||||
<div class="btn-group btn-page">
|
||||
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
|
||||
@@ -172,6 +182,7 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if event.is_rig %}
|
||||
<div class="col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
@@ -185,22 +196,45 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if not request.is_ajax %}
|
||||
<div class="col-sm-12 text-right">
|
||||
<div class="btn-group btn-page">
|
||||
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
|
||||
class="glyphicon glyphicon-edit"></span></a>
|
||||
<a href="{% url 'event_print' event.pk %}" class="btn btn-default"><span
|
||||
class="glyphicon glyphicon-print"></span></a>
|
||||
{% if event.is_rig %}
|
||||
<a href="{% url 'event_print' event.pk %}" class="btn btn-default"><span
|
||||
class="glyphicon glyphicon-print"></span></a>
|
||||
{% endif %}
|
||||
<a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span
|
||||
class="glyphicon glyphicon-duplicate"></span></a>
|
||||
{% if perms.RIGS.add_invoice %}
|
||||
<a href="{% url 'invoice_event' event.pk %}" class="btn btn-default" title="Invoice Rig"><span
|
||||
class="glyphicon glyphicon-gbp"></span></a>
|
||||
{% if event.is_rig %}
|
||||
{% if perms.RIGS.add_invoice %}
|
||||
<a href="{% url 'invoice_event' event.pk %}" class="btn btn-default" title="Invoice Rig"><span
|
||||
class="glyphicon glyphicon-gbp"></span></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div>Last edited at {{ object.last_edited_at|date:"SHORT_DATETIME_FORMAT" }}
|
||||
by {{ object.last_edited_by.name }}.
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% if request.is_ajax %}
|
||||
{% block footer %}
|
||||
<div class="row">
|
||||
<div class="col-sm-10 align-left">
|
||||
Lasted edited at {{ object.last_edited_at|date:"SHORT_DATE_FORMAT" }} by {{ object.last_edited_by.name }}
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<div class="pull-right">
|
||||
<a href="{% url 'event_detail' object.pk %}" class="btn btn-primary">Open Event Page <span
|
||||
class="glyphicon glyphicon-eye"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
|
||||
@@ -57,6 +57,7 @@ urlpatterns = patterns('',
|
||||
|
||||
# Rigboard
|
||||
url(r'^rigboard/$', rigboard.RigboardIndex.as_view(), name='rigboard'),
|
||||
url(r'^rigboard/calendar/$', rigboard.WebCalendar.as_view(), name='web_calendar'),
|
||||
url(r'^rigboard/archive/$', RedirectView.as_view(pattern_name='event_archive')),
|
||||
|
||||
url(r'^event/(?P<pk>\d+)/$',
|
||||
@@ -122,8 +123,5 @@ urlpatterns = patterns('',
|
||||
url(r'^rig/show/(?P<pk>\d+)/$', RedirectView.as_view(pattern_name='event_detail')),
|
||||
url(r'^bookings/$', RedirectView.as_view(pattern_name='rigboard')),
|
||||
url(r'^bookings/past/$', RedirectView.as_view(pattern_name='event_archive')),
|
||||
# Calendar may have gone away, redirect to the archive for now
|
||||
url(r'^rigboard/calendar/$',
|
||||
RedirectView.as_view(pattern_name='event_archive', permanent=False)),
|
||||
)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ from django.shortcuts import get_object_or_404
|
||||
from django.core import serializers
|
||||
import simplejson
|
||||
from django.contrib import messages
|
||||
import datetime
|
||||
|
||||
from RIGS import models, forms
|
||||
|
||||
@@ -194,6 +195,7 @@ class SecureAPIRequest(generic.View):
|
||||
'person': models.Person,
|
||||
'organisation': models.Organisation,
|
||||
'profile': models.Profile,
|
||||
'event': models.Event,
|
||||
}
|
||||
|
||||
perms = {
|
||||
@@ -201,6 +203,7 @@ class SecureAPIRequest(generic.View):
|
||||
'person': 'RIGS.view_person',
|
||||
'organisation': 'RIGS.view_organisation',
|
||||
'profile': None,
|
||||
'event': 'RIGS.view_event',
|
||||
}
|
||||
|
||||
'''
|
||||
@@ -261,6 +264,71 @@ class SecureAPIRequest(generic.View):
|
||||
json = simplejson.dumps(results[:20])
|
||||
return HttpResponse(json, content_type="application/json") # Always json
|
||||
|
||||
start = request.GET.get('start', None)
|
||||
end = request.GET.get('end', None)
|
||||
|
||||
if model == "event" and start and end:
|
||||
# Probably a calendar request
|
||||
start_datetime = datetime.datetime.strptime( start, "%Y-%m-%dT%H:%M:%SZ" )
|
||||
end_datetime = datetime.datetime.strptime( end, "%Y-%m-%dT%H:%M:%SZ" )
|
||||
all_objects = self.models[model].objects
|
||||
results = []
|
||||
filter = Q(start_date__lte=end_datetime) & Q(start_date__gte=start_datetime)
|
||||
objects = all_objects.filter(filter).select_related('person', 'organisation', 'venue', 'mic').order_by('-start_date')
|
||||
for item in objects:
|
||||
data = {
|
||||
'pk': item.pk,
|
||||
'title': item.name
|
||||
}
|
||||
|
||||
data['is_rig'] = item.is_rig
|
||||
data['status'] = str(item.get_status_display())
|
||||
|
||||
if item.start_date:
|
||||
data['start_date'] = item.start_date.strftime('%Y-%m-%d')
|
||||
|
||||
if item.start_time:
|
||||
data['start_time'] = item.start_time.strftime('%H:%M:%SZ')
|
||||
|
||||
if item.end_date:
|
||||
data['end_date'] = item.end_date.strftime('%Y-%m-%d')
|
||||
|
||||
if item.end_time:
|
||||
data['end_time'] = item.end_time.strftime('%H:%M:%SZ')
|
||||
|
||||
if item.meet_at:
|
||||
data['meet_at'] = item.meet_at.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
|
||||
if item.access_at:
|
||||
data['access_at'] = item.access_at.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
|
||||
if item.venue:
|
||||
data['venue'] = item.venue.name
|
||||
|
||||
if item.person:
|
||||
data['person'] = item.person.name
|
||||
|
||||
if item.organisation:
|
||||
data['organisation'] = item.organisation.name
|
||||
|
||||
if item.mic:
|
||||
data['mic'] = {
|
||||
'name':item.mic.get_full_name(),
|
||||
'initials':item.mic.initials
|
||||
}
|
||||
|
||||
if item.description:
|
||||
data['description'] = item.description
|
||||
|
||||
if item.notes:
|
||||
data['notes'] = item.notes
|
||||
|
||||
data['url'] = str(reverse_lazy('event_detail',kwargs={'pk':item.pk}))
|
||||
|
||||
results.append(data)
|
||||
json = simplejson.dumps(results)
|
||||
return HttpResponse(json, content_type="application/json") # Always json
|
||||
|
||||
return HttpResponse(model)
|
||||
|
||||
class ProfileDetail(generic.DetailView):
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{% url 'rigboard' %}">Rigboard</a></li>
|
||||
<li><a href="{% url 'event_archive' %}">Archive</a></li>
|
||||
<li><a href="{% url 'web_calendar' %}">Calendar</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% if perms.RIGS.view_invoice %}
|
||||
|
||||
Reference in New Issue
Block a user