Merged in ^/personal/henrik/6.25.2-floorplans@11546, which provides basic meeting venue floorplan and room location support, including JSON API access to floorplan images and room location. Floorplan data for IETF 96 in Berlin is also provided in a data migration. Not part of this release, but planned for a later release, is support for arrows pointing out rooms, and secretariat support for room location input.
- Legacy-Id: 11547
This commit is contained in:
commit
ca36d50484
|
@ -575,7 +575,7 @@ class DocHistory(DocumentInfo):
|
|||
def save_document_in_history(doc):
|
||||
"""This should be called before saving changes to a Document instance,
|
||||
so that the DocHistory entries contain all previous states, while
|
||||
the Group entry contain the current state. XXX TODO: Call this
|
||||
the Document entry contain the current state. XXX TODO: Call this
|
||||
directly from Document.save(), and add event listeners for save()
|
||||
on related objects so we can save as needed when they change, too.
|
||||
"""
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Autogenerated by the makeresources management command 2015-10-19 12:29 PDT
|
||||
from tastypie.resources import ModelResource
|
||||
from ietf.api import ToOneField
|
||||
from tastypie.fields import ToManyField, CharField # pyflakes:ignore
|
||||
from tastypie.fields import ToManyField, CharField
|
||||
from tastypie.constants import ALL, ALL_WITH_RELATIONS # pyflakes:ignore
|
||||
from tastypie.cache import SimpleCache
|
||||
|
||||
|
|
|
@ -616,3 +616,7 @@ def format_timedelta(timedelta):
|
|||
hours, remainder = divmod(s, 3600)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
return '{hours:02d}:{minutes:02d}'.format(hours=hours,minutes=minutes)
|
||||
|
||||
@register.filter()
|
||||
def nbsp(value):
|
||||
return mark_safe(" ".join(value.split(' ')))
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from ietf.meeting.models import Meeting, Room, Session, TimeSlot, Constraint, Schedule, SchedTimeSessAssignment, ResourceAssociation
|
||||
from ietf.meeting.models import (Meeting, Room, Session, TimeSlot, Constraint, Schedule,
|
||||
SchedTimeSessAssignment, ResourceAssociation, FloorPlan)
|
||||
|
||||
class RoomAdmin(admin.ModelAdmin):
|
||||
list_display = ["id", "meeting", "name", "capacity", ]
|
||||
list_display = ["id", "meeting", "name", "capacity", "x1", "y1", "x2", "y2", ]
|
||||
list_filter = ["meeting"]
|
||||
ordering = ["-meeting"]
|
||||
|
||||
|
@ -98,3 +99,8 @@ admin.site.register(SchedTimeSessAssignment, SchedTimeSessAssignmentAdmin)
|
|||
class ResourceAssociationAdmin(admin.ModelAdmin):
|
||||
list_display = ["desc", "icon", "desc", ]
|
||||
admin.site.register(ResourceAssociation, ResourceAssociationAdmin)
|
||||
|
||||
class FloorPlanAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'meeting', 'name', 'order', 'image', ]
|
||||
raw_id_fields = ['meeting', ]
|
||||
admin.site.register(FloorPlan, FloorPlanAdmin)
|
||||
|
|
|
@ -3,8 +3,9 @@ import random
|
|||
import datetime
|
||||
|
||||
from django.db.models import Max
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
from ietf.meeting.models import Meeting, Session, Schedule, TimeSlot, SessionPresentation
|
||||
from ietf.meeting.models import Meeting, Session, Schedule, TimeSlot, SessionPresentation, FloorPlan
|
||||
from ietf.group.factories import GroupFactory
|
||||
from ietf.person.factories import PersonFactory
|
||||
|
||||
|
@ -106,3 +107,18 @@ class SessionPresentationFactory(factory.DjangoModelFactory):
|
|||
def rev(self):
|
||||
return self.document.rev
|
||||
|
||||
class FloorPlanFactory(factory.DjangoModelFactory):
|
||||
class Meta:
|
||||
model = FloorPlan
|
||||
|
||||
name = factory.Sequence(lambda n: u'Venue Floor %d' % n)
|
||||
meeting = factory.SubFactory(MeetingFactory)
|
||||
order = factory.Sequence(lambda n: n)
|
||||
image = factory.LazyAttribute(
|
||||
lambda _: ContentFile(
|
||||
factory.django.ImageField()._make_data(
|
||||
{'width': 1024, 'height': 768}
|
||||
), 'floorplan.jpg'
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import ietf.utils.storage
|
||||
import ietf.meeting.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('meeting', '0024_migrate_interim_meetings'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='FloorPlan',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('order', models.SmallIntegerField()),
|
||||
('image', models.ImageField(default=None, storage=ietf.utils.storage.NoLocationMigrationFileSystemStorage(location=None), upload_to=ietf.meeting.models.floorplan_path, blank=True)),
|
||||
('meeting', models.ForeignKey(to='meeting.Meeting')),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='room',
|
||||
name='floorplan',
|
||||
field=models.ForeignKey(default=None, blank=True, to='meeting.FloorPlan', null=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='room',
|
||||
name='x1',
|
||||
field=models.SmallIntegerField(default=None, null=True, blank=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='room',
|
||||
name='x2',
|
||||
field=models.SmallIntegerField(default=None, null=True, blank=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='room',
|
||||
name='y1',
|
||||
field=models.SmallIntegerField(default=None, null=True, blank=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='room',
|
||||
name='y2',
|
||||
field=models.SmallIntegerField(default=None, null=True, blank=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
65
ietf/meeting/migrations/0026_add_floorplan_data.py
Normal file
65
ietf/meeting/migrations/0026_add_floorplan_data.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
floors = [
|
||||
(1, "Berlin Intercontinental Floor 1", 1, 'floor/floorplan-96-berlin-intercontinental-floor-1.jpg'),
|
||||
(2, "Berlin Intercontinental Floor 1", 2, 'floor/floorplan-96-berlin-intercontinental-floor-2.jpg'),
|
||||
(3, "Berlin Intercontinental Floor 1", 14, 'floor/floorplan-96-berlin-intercontinental-floor-14.jpg'),
|
||||
]
|
||||
|
||||
rooms = [
|
||||
("Bellevue", 1, 176, 1348, 324, 1526),
|
||||
("Kaminzimmer", 1, 696, 820, 812, 1038),
|
||||
("Charlottenburg I", 1, 374, 320, 528, 400),
|
||||
("Charlottenburg II/III", 1, 374, 172, 528, 316),
|
||||
("Chess", 2, 238, 614, 336, 782),
|
||||
("Glienicke", 1, 228, 1251, 324, 1310),
|
||||
("Hugos 360", 3, 801, 1346, 976, 1509),
|
||||
("King", 2, 802, 1389, 890, 1508),
|
||||
("Koepenick I/II", 1, 370, 453, 458, 602),
|
||||
("Lincke", 2, 40, 99, 532, 166),
|
||||
("Potsdam I", 1, 1228, 790, 1550, 994),
|
||||
("Potsdam I/III", 1, 1017, 792, 1550, 994),
|
||||
("Potsdam II", 1, 1311, 1036, 1536, 1142),
|
||||
("Potsdam III", 1, 1017, 792, 1228, 987),
|
||||
("Rook", 2, 915, 1150, 1004, 1269),
|
||||
("Schoeneberg", 1, 369, 42, 534, 126),
|
||||
("Tegel", 1, 201, 1088, 326, 1184),
|
||||
("Tiergarten", 1, 240, 612, 334, 780),
|
||||
("Wintergarten/Pavillion", 1, 466, 1038, 711, 1504),
|
||||
]
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
FloorPlan = apps.get_model('meeting','FloorPlan')
|
||||
Room = apps.get_model('meeting','Room')
|
||||
Meeting = apps.get_model('meeting','Meeting')
|
||||
meeting = Meeting.objects.get(number='96')
|
||||
for item in floors:
|
||||
id, name, order, image = item
|
||||
f = FloorPlan(id=id, name=name, meeting=meeting, order=order, image=image)
|
||||
f.save()
|
||||
|
||||
for item in rooms:
|
||||
name, floor_id, x1, y1, x2, y2 = item
|
||||
room = Room.objects.get(name=name, meeting=meeting)
|
||||
room.floorplan_id = floor_id
|
||||
room.x1 = x1
|
||||
room.y1 = y1
|
||||
room.x2 = x2
|
||||
room.y2 = y2
|
||||
room.save()
|
||||
|
||||
def backward(apps, schema_editor):
|
||||
pass
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('meeting', '0025_add_floorplan_and_room_coordinates'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward,backward)
|
||||
]
|
|
@ -25,6 +25,7 @@ from ietf.group.models import Group
|
|||
from ietf.group.utils import can_manage_materials
|
||||
from ietf.name.models import MeetingTypeName, TimeSlotTypeName, SessionStatusName, ConstraintName, RoomResourceName
|
||||
from ietf.person.models import Person
|
||||
from ietf.utils.storage import NoLocationMigrationFileSystemStorage
|
||||
|
||||
countries = pytz.country_names.items()
|
||||
countries.sort(lambda x,y: cmp(x[1], y[1]))
|
||||
|
@ -274,6 +275,8 @@ class Meeting(models.Model):
|
|||
class Meta:
|
||||
ordering = ["-date", "id"]
|
||||
|
||||
# === Rooms, Resources, Floorplans =============================================
|
||||
|
||||
class ResourceAssociation(models.Model):
|
||||
name = models.ForeignKey(RoomResourceName)
|
||||
#url = models.UrlField() # not sure what this was for.
|
||||
|
@ -298,6 +301,15 @@ class Room(models.Model):
|
|||
capacity = models.IntegerField(null=True, blank=True)
|
||||
resources = models.ManyToManyField(ResourceAssociation, blank = True)
|
||||
session_types = models.ManyToManyField(TimeSlotTypeName, blank = True)
|
||||
# floorplan-related properties
|
||||
floorplan = models.ForeignKey('FloorPlan', null=True, blank=True, default=None)
|
||||
# floorplan: room pixel position : (0,0) is top left of image, (xd, yd)
|
||||
# is room width, height.
|
||||
x1 = models.SmallIntegerField(null=True, blank=True, default=None)
|
||||
y1 = models.SmallIntegerField(null=True, blank=True, default=None)
|
||||
x2 = models.SmallIntegerField(null=True, blank=True, default=None)
|
||||
y2 = models.SmallIntegerField(null=True, blank=True, default=None)
|
||||
# end floorplan-related stuff
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s size: %s" % (self.name, self.capacity)
|
||||
|
@ -332,6 +344,36 @@ class Room(models.Model):
|
|||
'capacity': self.capacity,
|
||||
}
|
||||
|
||||
def left(self):
|
||||
return min(self.x1, self.x2) if (self.x1 and self.x2) else 0
|
||||
def top(self):
|
||||
return min(self.y1, self.y2) if (self.y1 and self.y2) else 0
|
||||
def right(self):
|
||||
return max(self.x1, self.x2) if (self.x1 and self.x2) else 0
|
||||
def bottom(self):
|
||||
return max(self.y1, self.y2) if (self.y1 and self.y2) else 0
|
||||
def functional_display_name(self):
|
||||
if not self.functional_name:
|
||||
return ""
|
||||
if self.functional_name.lower().startswith('breakout'):
|
||||
return ""
|
||||
if self.functional_name[0].isdigit():
|
||||
return ""
|
||||
return self.functional_name
|
||||
class Meta:
|
||||
ordering = ["-meeting", "name"]
|
||||
|
||||
def floorplan_path(instance, filename):
|
||||
root, ext = os.path.splitext(filename)
|
||||
return u"%s/floorplan-%s-%s%s" % (settings.FLOORPLAN_MEDIA_DIR, instance.meeting.number, slugify(instance.name), ext)
|
||||
|
||||
class FloorPlan(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
meeting = models.ForeignKey(Meeting)
|
||||
order = models.SmallIntegerField()
|
||||
image = models.ImageField(storage=NoLocationMigrationFileSystemStorage(), upload_to=floorplan_path, blank=True, default=None)
|
||||
|
||||
# === Schedules, Sessions, Timeslots and Assignments ===========================
|
||||
|
||||
class TimeSlot(models.Model):
|
||||
"""
|
||||
|
@ -1307,3 +1349,4 @@ class Session(models.Model):
|
|||
if self.badness_test(1):
|
||||
self.badness_log(1, "badgroup: %s badness = %u\n" % (self.group.acronym, badness))
|
||||
return badness
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ from tastypie.cache import SimpleCache
|
|||
from ietf import api
|
||||
|
||||
from ietf.meeting.models import ( Meeting, ResourceAssociation, Constraint, Room, Schedule, Session,
|
||||
TimeSlot, SchedTimeSessAssignment, SessionPresentation )
|
||||
TimeSlot, SchedTimeSessAssignment, SessionPresentation, FloorPlan )
|
||||
|
||||
from ietf.name.resources import MeetingTypeNameResource
|
||||
class MeetingResource(ModelResource):
|
||||
|
@ -83,11 +83,28 @@ class ConstraintResource(ModelResource):
|
|||
}
|
||||
api.meeting.register(ConstraintResource())
|
||||
|
||||
class FloorPlanResource(ModelResource):
|
||||
meeting = ToOneField(MeetingResource, 'meeting')
|
||||
class Meta:
|
||||
queryset = FloorPlan.objects.all()
|
||||
serializer = api.Serializer()
|
||||
cache = SimpleCache()
|
||||
#resource_name = 'floorplan'
|
||||
filtering = {
|
||||
"id": ALL,
|
||||
"name": ALL,
|
||||
"order": ALL,
|
||||
"image": ALL,
|
||||
"meeting": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.meeting.register(FloorPlanResource())
|
||||
|
||||
from ietf.name.resources import TimeSlotTypeNameResource
|
||||
class RoomResource(ModelResource):
|
||||
meeting = ToOneField(MeetingResource, 'meeting')
|
||||
resources = ToManyField(ResourceAssociationResource, 'resources', null=True)
|
||||
session_types = ToManyField(TimeSlotTypeNameResource, 'session_types', null=True)
|
||||
floorplan = ToOneField(FloorPlanResource, 'floorplan', null=True)
|
||||
class Meta:
|
||||
cache = SimpleCache()
|
||||
queryset = Room.objects.all()
|
||||
|
@ -101,6 +118,7 @@ class RoomResource(ModelResource):
|
|||
"meeting": ALL_WITH_RELATIONS,
|
||||
"resources": ALL_WITH_RELATIONS,
|
||||
"session_types": ALL_WITH_RELATIONS,
|
||||
"floorplan": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.meeting.register(RoomResource())
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ def make_meeting_test_data():
|
|||
unofficial_schedule = Schedule.objects.create(meeting=meeting, owner=plainman, name="test-unofficial-agenda", visible=True, public=True)
|
||||
pname = RoomResourceName.objects.create(name='projector',slug='proj')
|
||||
projector = ResourceAssociation.objects.create(name=pname,icon="notfound.png",desc="Basic projector")
|
||||
room = Room.objects.create(meeting=meeting, name="Test Room", capacity=123)
|
||||
room = Room.objects.create(meeting=meeting, name="Test Room", capacity=123, functional_name="Testing Ground")
|
||||
breakfast_room = Room.objects.create(meeting=meeting, name="Breakfast Room", capacity=40)
|
||||
room.session_types.add("session")
|
||||
breakfast_room.session_types.add("lead")
|
||||
|
|
|
@ -46,7 +46,7 @@ class ScheduleEditTests(StaticLiveServerTestCase):
|
|||
def setUp(self):
|
||||
set_coverage_checking(False)
|
||||
condition_data()
|
||||
self.driver = webdriver.PhantomJS(service_log_path=settings.TEST_GHOSTDRIVER_LOG_PATH)
|
||||
self.driver = webdriver.PhantomJS(port=0, service_log_path=settings.TEST_GHOSTDRIVER_LOG_PATH)
|
||||
self.driver.set_window_size(1024,768)
|
||||
|
||||
def tearDown(self):
|
||||
|
|
|
@ -26,7 +26,8 @@ from ietf.utils.mail import outbox
|
|||
|
||||
from ietf.person.factories import PersonFactory
|
||||
from ietf.group.factories import GroupFactory
|
||||
from ietf.meeting.factories import SessionFactory, SessionPresentationFactory, ScheduleFactory, MeetingFactory
|
||||
from ietf.meeting.factories import ( SessionFactory, SessionPresentationFactory, ScheduleFactory,
|
||||
MeetingFactory, FloorPlanFactory )
|
||||
from ietf.doc.factories import DocumentFactory
|
||||
|
||||
class MeetingTests(TestCase):
|
||||
|
@ -1092,3 +1093,20 @@ class AjaxTests(TestCase):
|
|||
self.assertTrue('utc' in data)
|
||||
self.assertTrue('error' not in data)
|
||||
self.assertEqual(data['utc'], '20:00')
|
||||
|
||||
class FloorPlanTests(TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_floor_plan_page(self):
|
||||
make_meeting_test_data()
|
||||
meeting = Meeting.objects.filter(type_id='ietf').order_by('id').last()
|
||||
FloorPlanFactory.create(meeting=meeting)
|
||||
|
||||
url = urlreverse('ietf.meeting.views.floor_plan')
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ type_ietf_only_patterns = [
|
|||
]
|
||||
|
||||
type_ietf_only_patterns_id_optional = [
|
||||
url(r'^agenda(-utc)?(?P<ext>.html)?/?$', views.agenda),
|
||||
url(r'^agenda(?P<utc>-utc)?(?P<ext>.html)?/?$', views.agenda),
|
||||
url(r'^agenda(?P<ext>.txt)$', views.agenda),
|
||||
url(r'^agenda(?P<ext>.csv)$', views.agenda),
|
||||
url(r'^agenda/edit$', views.edit_agenda),
|
||||
|
@ -61,6 +61,8 @@ type_ietf_only_patterns_id_optional = [
|
|||
url(r'^agenda.ics$', views.ical_agenda),
|
||||
url(r'^agenda/week-view(?:.html)?/?$', views.week_view),
|
||||
url(r'^agenda/room-view(?:.html)?/?$', views.room_view),
|
||||
url(r'^agenda/floor-plan/?$', views.floor_plan),
|
||||
url(r'^agenda/floor-plan/(?P<floor>[-a-z0-9_]+)/?$', views.floor_plan),
|
||||
url(r'^week-view(?:.html)?/?$', views.week_view),
|
||||
url(r'^room-view(?:.html)?/$', views.room_view),
|
||||
url(r'^materials(?:.html)?/$', views.materials),
|
||||
|
|
|
@ -32,7 +32,7 @@ from ietf.doc.models import Document, State, DocEvent
|
|||
from ietf.group.models import Group
|
||||
from ietf.group.utils import can_manage_materials
|
||||
from ietf.ietfauth.utils import role_required, has_role
|
||||
from ietf.meeting.models import Meeting, Session, Schedule, Room
|
||||
from ietf.meeting.models import Meeting, Session, Schedule, Room, FloorPlan
|
||||
from ietf.meeting.helpers import get_areas, get_person_by_email, get_schedule_by_name
|
||||
from ietf.meeting.helpers import build_all_agenda_slices, get_wg_name_list
|
||||
from ietf.meeting.helpers import get_all_assignments_from_schedule
|
||||
|
@ -393,7 +393,7 @@ def list_agendas(request, num=None ):
|
|||
})
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def agenda(request, num=None, name=None, base=None, ext=None, owner=None):
|
||||
def agenda(request, num=None, name=None, base=None, ext=None, owner=None, utc=""):
|
||||
base = base if base else 'agenda'
|
||||
ext = ext if ext else '.html'
|
||||
mimetype = {
|
||||
|
@ -1424,3 +1424,15 @@ def upcoming_ical(request):
|
|||
response['Content-Disposition'] = 'attachment; filename="upcoming.ics"'
|
||||
return response
|
||||
|
||||
|
||||
def floor_plan(request, num=None, floor=None, ):
|
||||
meeting = get_meetings(num).first()
|
||||
schedule = meeting.agenda
|
||||
floors = FloorPlan.objects.filter(meeting=meeting).order_by('order')
|
||||
if floor:
|
||||
floors = floors.filter(name=floor)
|
||||
return render(request, 'meeting/floor-plan.html', {
|
||||
"schedule": schedule,
|
||||
"number": num,
|
||||
"floors": floors,
|
||||
})
|
||||
|
|
|
@ -29,8 +29,8 @@ class PersonInfo(models.Model):
|
|||
affiliation = models.CharField(max_length=255, blank=True, help_text="Employer, university, sponsor, etc.")
|
||||
address = models.TextField(max_length=255, blank=True, help_text="Postal mailing address.")
|
||||
biography = models.TextField(blank=True, help_text="Short biography for use on leadership pages. Use plain text or reStructuredText markup.")
|
||||
photo = models.ImageField(storage=NoLocationMigrationFileSystemStorage(location=settings.PHOTOS_DIR),upload_to=settings.PHOTOS_DIRNAME,blank=True, default=None)
|
||||
photo_thumb = models.ImageField(storage=NoLocationMigrationFileSystemStorage(location=settings.PHOTOS_DIR),upload_to=settings.PHOTOS_DIRNAME,blank=True, default=None)
|
||||
photo = models.ImageField(storage=NoLocationMigrationFileSystemStorage(), upload_to=settings.PHOTOS_DIRNAME, blank=True, default=None)
|
||||
photo_thumb = models.ImageField(storage=NoLocationMigrationFileSystemStorage(), upload_to=settings.PHOTOS_DIRNAME, blank=True, default=None)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.plain_name()
|
||||
|
|
|
@ -556,12 +556,18 @@ YANG_INVAL_MODEL_DIR = '/a/www/ietf-ftp/yang/invalmod/'
|
|||
|
||||
XML_LIBRARY = "/www/tools.ietf.org/tools/xml2rfc/web/public/rfc/"
|
||||
|
||||
# === Meeting Related Settings =================================================
|
||||
|
||||
MEETING_MATERIALS_SUBMISSION_START_DAYS = -90
|
||||
MEETING_MATERIALS_SUBMISSION_CUTOFF_DAYS = 26
|
||||
MEETING_MATERIALS_SUBMISSION_CORRECTION_DAYS = 50
|
||||
|
||||
INTERNET_DRAFT_DAYS_TO_EXPIRE = 185
|
||||
|
||||
FLOORPLAN_MEDIA_DIR = 'floor'
|
||||
|
||||
# ==============================================================================
|
||||
|
||||
DOT_BINARY = '/usr/bin/dot'
|
||||
UNFLATTEN_BINARY= '/usr/bin/unflatten'
|
||||
RSYNC_BINARY = '/usr/bin/rsync'
|
||||
|
|
|
@ -110,6 +110,7 @@ div.anchor-target:before {
|
|||
height: 65px;
|
||||
margin-top: -65px;
|
||||
}
|
||||
div.anchor-target { z-index: 0; }
|
||||
|
||||
/* Make the panel title font normally large */
|
||||
.panel-title { font-size: 14px }
|
||||
|
@ -124,6 +125,7 @@ label.required:after { content: "\2217"; color: #a94442; font-weight: bold; }
|
|||
|
||||
/* Add some margin to tabs */
|
||||
.nav-tabs[role=tablist] { margin-bottom: 0.7em; }
|
||||
.nav a { z-index: 100; }
|
||||
|
||||
/* Styles needed for the ballot table */
|
||||
/*
|
||||
|
|
BIN
ietf/static/ietf/images/arrow-ani.gif
Normal file
BIN
ietf/static/ietf/images/arrow-ani.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
173
ietf/static/ietf/js/room_params.js
Normal file
173
ietf/static/ietf/js/room_params.js
Normal file
|
@ -0,0 +1,173 @@
|
|||
var verbose = 0;
|
||||
|
||||
function suffixmap(nm)
|
||||
// Given a name like "foo-ab" or "foo-X-and-Y", change it to the "list-of-room-names" format, "foo-a/foo-b".
|
||||
{
|
||||
var andsuffix = /^(.*-)([^-]+)-and-(.*)$/;
|
||||
var andMatch = andsuffix.exec(nm);
|
||||
if (andMatch && andMatch[0] != '') {
|
||||
nm = andMatch[1] + andMatch[2] + "-" + andMatch[3];
|
||||
}
|
||||
// xyz-a/b/c => xyz-a/xyz-b/xyz-c
|
||||
var abcsuffix = /^(.*)-([a-h0-9]+)[-\/]([a-h0-9]+)([-\/][a-h0-9]+)?$/;
|
||||
var suffixMatch = abcsuffix.exec(nm);
|
||||
if (verbose) alert("nm=" + nm);
|
||||
if (suffixMatch && suffixMatch[0] != '') {
|
||||
if (verbose) alert("matched");
|
||||
nm = suffixMatch[1] + "-" + suffixMatch[2] + "/" +
|
||||
suffixMatch[1] + "-" + suffixMatch[3];
|
||||
if (verbose) alert("nm=>" + nm);
|
||||
if (suffixMatch[4] && suffixMatch[4] != '')
|
||||
nm += "/" + suffixMatch[1] + "-" + suffixMatch[4];
|
||||
if (verbose) alert("nm=>" + nm);
|
||||
}
|
||||
// xyz-abc => xyz-a/xyz-b/xyz-c
|
||||
abcsuffix = /^(.*)-([a-h])([a-h]+)([a-h])?$/;
|
||||
var suffixMatch = abcsuffix.exec(nm);
|
||||
if (suffixMatch && suffixMatch[0] != '') {
|
||||
nm = suffixMatch[1] + "-" + suffixMatch[2] + "/" +
|
||||
suffixMatch[1] + "-" + suffixMatch[3];
|
||||
if (suffixMatch[4] && suffixMatch[4] != '')
|
||||
nm += "/" + suffixMatch[1] + "-" + suffixMatch[4];
|
||||
}
|
||||
if (verbose) alert("suffixmap returning: " + nm);
|
||||
return nm;
|
||||
}
|
||||
|
||||
function roomcoords(nm)
|
||||
// Find the coordinates of a room or list of room names separated by "/".
|
||||
// Calls the function findroom() to get the coordinates for a specific room.
|
||||
{
|
||||
if (!nm) return null;
|
||||
|
||||
if (nm.match("/")) {
|
||||
var nms = nm.split("/");
|
||||
var nm0 = findroom(nms[0]);
|
||||
if (!nm0) return null;
|
||||
for (var i = 1; i < nms.length; i++) {
|
||||
var nmi = roomcoords(nms[i]);
|
||||
if (!nmi) return null;
|
||||
if (nmi[0] < nm0[0]) nm0[0] = nmi[0];
|
||||
if (nmi[1] < nm0[1]) nm0[1] = nmi[1];
|
||||
if (nmi[2] > nm0[2]) nm0[2] = nmi[2];
|
||||
if (nmi[3] > nm0[3]) nm0[3] = nmi[3];
|
||||
}
|
||||
return [nm0[0], nm0[1], nm0[2], nm0[3]];
|
||||
} else {
|
||||
return findroom(nm);
|
||||
}
|
||||
}
|
||||
|
||||
function setarrow(nm, fl)
|
||||
// Place an arrow at the center of a given room name (or list of room names separated by "/").
|
||||
{
|
||||
for (var i = 0; i < arrowsuffixlist.length; i++) {
|
||||
removearrow(arrowsuffixlist[i], fl);
|
||||
}
|
||||
for (var i = 0; i < arguments.length; i+=2) {
|
||||
nm = roommap(arguments[i]);
|
||||
if (verbose) alert("nm=" + nm);
|
||||
var rooms = nm.split(/[|]/);
|
||||
for (var j = 0; j < rooms.length; j++) {
|
||||
var room = rooms[j];
|
||||
var ret = roomcoords(room);
|
||||
if (verbose) alert("roomcoords returned: " + ret);
|
||||
if (!ret) continue;
|
||||
|
||||
var left = ret[0], top = ret[1], right = ret[2], bottom = ret[3], offsetleft = -25, offsettop = -25;
|
||||
if (verbose) alert("left=" + left + ", top=" + top + ", right=" + right + ", bottom=" + bottom);
|
||||
//alert("left=" + left + ", top=" + top + ", right=" + right + ", bottom=" + bottom);
|
||||
var arrowdiv = fl+'-arrowdiv' + (j > 0 ? j : "");
|
||||
//if (verbose) alert("arrowdiv: " + arrowdiv);
|
||||
var adiv = document.getElementById(arrowdiv);
|
||||
// if (verbose) alert("looking for 'arrowdiv'+" + j);
|
||||
if (adiv) {
|
||||
//if (verbose) alert("adiv found");
|
||||
adiv.style.left = left + (right - left) / 2 + offsetleft;
|
||||
adiv.style.top = top + (bottom - top) / 2 + offsettop;
|
||||
adiv.style.visibility = "visible";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function removearrow(which, fl)
|
||||
{
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var which = arguments[i];
|
||||
var arrowdiv = fl+'-arrowdiv' + (which ? which : "");
|
||||
var adiv = document.getElementById(arrowdiv);
|
||||
// if (verbose) alert("looking for '" + arrowdiv + "'");
|
||||
if (adiv) {
|
||||
// if (verbose) alert("adiv found");
|
||||
adiv.style.left = -500;
|
||||
adiv.style.top = -500;
|
||||
adiv.style.visibility = "hidden";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setarrowlist(which, names)
|
||||
{
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
setarrow(arguments[i], which);
|
||||
}
|
||||
}
|
||||
|
||||
function QueryString()
|
||||
// Create a QueryString object
|
||||
{
|
||||
// get the query string, ignore the ? at the front.
|
||||
var querystring = location.search.substring(1);
|
||||
|
||||
// parse out name/value pairs separated via &
|
||||
var args = querystring.split('&');
|
||||
|
||||
// split out each name = value pair
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var pair = args[i].split('=');
|
||||
|
||||
// Fix broken unescaping
|
||||
var temp = unescape(pair[0]).split('+');
|
||||
var name_ = temp.join(' ');
|
||||
|
||||
var value_ = '';
|
||||
if (typeof pair[1] == 'string') {
|
||||
temp = unescape(pair[1]).split('+');
|
||||
value_ = temp.join(' ');
|
||||
}
|
||||
|
||||
this[name_] = value_;
|
||||
}
|
||||
|
||||
this.get = function(nm, def) {
|
||||
var value_ = this[nm];
|
||||
if (value_ == null) return def;
|
||||
else return value_;
|
||||
};
|
||||
}
|
||||
|
||||
function checkParams()
|
||||
// Check the parameters for one named "room". If found, call setarrow(room).
|
||||
{
|
||||
var querystring = new QueryString();
|
||||
var room = querystring.get("room");
|
||||
if (room && room != "") setarrow(room);
|
||||
}
|
||||
|
||||
// new functions
|
||||
function located(loc)
|
||||
{
|
||||
if (loc.civic && loc.civic.ROOM) {
|
||||
// map from "TerminalRoom" to "terminal-room" as necessary.
|
||||
setarrow(loc.civic.ROOM.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(), "-green");
|
||||
}
|
||||
}
|
||||
|
||||
// this needs to be called onload
|
||||
function automaticarrow()
|
||||
{
|
||||
// if (navigator.geolocation) {
|
||||
// navigator.geolocation.getCurrentPosition(located);
|
||||
// }
|
||||
}
|
|
@ -546,6 +546,7 @@ class SubmitTests(TestCase):
|
|||
|
||||
# edit
|
||||
mailbox_before = len(outbox)
|
||||
# FIXME If this test is started before midnight, and ends after, it will fail
|
||||
document_date = datetime.date.today() - datetime.timedelta(days=-3)
|
||||
r = self.client.post(edit_url, {
|
||||
"edit-title": "some title",
|
||||
|
|
|
@ -31,33 +31,17 @@
|
|||
{% origin %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
|
||||
{% include "meeting/meeting_heading.html" with meeting=schedule.meeting updated=updated %}
|
||||
|
||||
<p class="noprint h6 text-center panel panel-heading ">
|
||||
{% if "-utc" in request.path %}
|
||||
<a href="{% url 'ietf.meeting.views.agenda' num=schedule.meeting.number %}">Agenda in local timezone</a> |
|
||||
{% else %}
|
||||
{% comment %}<a href="{% url 'ietf.meeting.views.agenda' base='agenda-utc' %}">Agenda in UTC timezone</a> | {% endcomment %}
|
||||
<a href="/meeting/agenda-utc">Agenda in UTC timezone</a> |
|
||||
{% endif %}
|
||||
<a href="{% url 'ietf.meeting.views.agenda' num=schedule.meeting.number ext='.txt' %}">Plaintext agenda</a> |
|
||||
<a href="https://tools.ietf.org/agenda/{{schedule.meeting.number}}/">Tools-style agenda</a>
|
||||
{% if user|has_role:"Secretariat,Area Director,IAB" %}
|
||||
|
|
||||
{% if schedule != meeting.agenda %}
|
||||
<a href="{% url 'ietf.meeting.views.agenda_by_room' num=schedule.meeting.number name=schedule.name owner=schedule.owner.email %}">List by Room</a> |
|
||||
<a href="{% url 'ietf.meeting.views.agenda_by_type' num=schedule.meeting.number name=schedule.name owner=schedule.owner.email %}">List by Type</a> |
|
||||
<a href="{% url 'ietf.meeting.views.room_view' num=schedule.meeting.number name=schedule.name owner=schedule.owner.email %}">Room Grid</a>
|
||||
{% else %}
|
||||
<a href="{% url 'ietf.meeting.views.agenda_by_room' num=schedule.meeting.number%}">List by Room</a> |
|
||||
<a href="{% url 'ietf.meeting.views.agenda_by_type' num=schedule.meeting.number%}">List by Type</a> |
|
||||
<a href="{% url 'ietf.meeting.views.room_view' num=schedule.meeting.number%}">Room Grid</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</p>
|
||||
<div class="col-md-12">
|
||||
{% if "-utc" in request.path %}
|
||||
{% include "meeting/meeting_heading.html" with meeting=schedule.meeting updated=updated selected="agenda-utc" title_extra="(UTC)" %}
|
||||
{% else %}
|
||||
{% include "meeting/meeting_heading.html" with meeting=schedule.meeting updated=updated selected="agenda" title_extra="" %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
{# cache this part for 5 minutes -- it takes 3-6 seconds to generate #}
|
||||
{% load cache %}
|
||||
{% cache 300 ietf_meeting_agenda_utc schedule.meeting.number request.path %}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{% extends "base.html" %}
|
||||
{% block morecss %}
|
||||
ul.daylist { list-style:none; padding-left:0; }
|
||||
li.daylistentry { font-size:162%; font-weight:700; }
|
||||
li h2 { font-weight: 600; margin-top: 0.5em; }
|
||||
li h3 { font-weight: 400; margin-top: 0.5em; }
|
||||
li.even { background-color:#EDF5FF; }
|
||||
li.odd { background-color:white; }
|
||||
ul.roomlist {list-style:none; padding-left:0; margin-bottom:20px;}
|
||||
ul.roomlist {list-style:none; margin-top: 0.5em; }
|
||||
li.roomlistentry { font-weight: 400; }
|
||||
ul.sessionlist { list-style:none; padding-left:2em; margin-bottom:10px;}
|
||||
li.sessionlistentry { font-size:62%; }
|
||||
|
||||
.type-lead:after { content: " (DO NOT POST)"; color:red; }
|
||||
.type-offagenda:after { content:" (not published on agenda)"; }
|
||||
|
@ -17,25 +17,26 @@ li.sessionlistentry { font-size:62%; }
|
|||
{% block title %}Agenda for {{meeting}} by Room{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "meeting/meeting_heading.html" with meeting=schedule.meeting updated=meeting.updated %}
|
||||
<h1>Agenda for {{meeting}} by Room</h1>
|
||||
<ul class="daylist">
|
||||
{% for day,sessions in ss_by_day.items %}
|
||||
<li class="daylistentry {% cycle 'even' 'odd' %}">{{day|date:'l, j F Y'}}
|
||||
{% regroup sessions by timeslot.get_functional_location as room_list %}
|
||||
<ul class="roomlist">
|
||||
{% for room in room_list %}
|
||||
<li class="roomlistentry">{{room.grouper|default:"Location Unavailable"}}
|
||||
<ul class="sessionlist">
|
||||
{% for ss in room.list %}
|
||||
<li class="sessionlistentry type-{{ss.timeslot.type.slug}}">{{ss.timeslot.time|date:"H:i"}}-{{ss.timeslot.end_time|date:"H:i"}} {{ss.session.short_name}}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% include "meeting/meeting_heading.html" with meeting=schedule.meeting updated=meeting.updated selected="by-room" title_extra="by Room" %}
|
||||
|
||||
<ul class="daylist">
|
||||
{% for day,sessions in ss_by_day.items %}
|
||||
<li class="daylistentry {% cycle 'even' 'odd' %}"><h2>{{day|date:'l, j F Y'}}</h2>
|
||||
{% regroup sessions by timeslot.get_functional_location as room_list %}
|
||||
<ul class="roomlist">
|
||||
{% for room in room_list %}
|
||||
<li class="roomlistentry"><h3>{{room.grouper|default:"Location Unavailable"}}</h3>
|
||||
<ul class="sessionlist">
|
||||
{% for ss in room.list %}
|
||||
<li class="sessionlistentry type-{{ss.timeslot.type.slug}}">{{ss.timeslot.time|date:"H:i"}}-{{ss.timeslot.end_time|date:"H:i"}} {{ss.session.short_name}}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
{% block morecss %}
|
||||
|
||||
ul.typelist { list-style:none; padding-left:0; }
|
||||
li.typelistentry { font-size:162%; font-weight:700; }
|
||||
li h2 { font-weight: 600; margin-top: 0.5em; }
|
||||
li h3 { font-weight: 400; margin-top: 0.5em; }
|
||||
li.even { background-color:#EDF5FF; }
|
||||
li.odd { background-color:white; }
|
||||
ul.daylist {list-style:none; padding-left:0; margin-bottom:20px;}
|
||||
li.daylistentry { margin-left:2em; font-weight: 400; }
|
||||
|
||||
.sessiontable {margin-left:2em; font-size:62%;}
|
||||
|
||||
.sessiontable {margin-left: 2em; }
|
||||
.sessiontable td {padding-right: 1em;}
|
||||
|
||||
.typelabel { font-size:162%; font-weight:700; }
|
||||
|
@ -25,18 +27,18 @@ li.daylistentry { margin-left:2em; font-weight: 400; }
|
|||
{% block title %}Agenda for {{meeting}} by Session Type{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "meeting/meeting_heading.html" with meeting=schedule.meeting updated=meeting.updated %}
|
||||
<h1>Agenda for {{meeting}} by Session Type</h1>
|
||||
{% include "meeting/meeting_heading.html" with meeting=schedule.meeting updated=meeting.updated selected="by-type" title_extra="by Session Type" %}
|
||||
|
||||
{% regroup assignments by session.type.slug as type_list %}
|
||||
<ul class="typelist">
|
||||
{% for type in type_list %}
|
||||
<li class="typelistentry {% cycle 'even' 'odd' %}">
|
||||
{{type.grouper}} {% if schedule == meeting.agenda %}<a id="ical-link" class="btn btn-primary" href="{% url "ietf.meeting.views.agenda_by_type_ics" num=meeting.number type=type.grouper %}">Download to Calendar</a>{% endif %}
|
||||
<h2>{{type.grouper|title}}</h2> {% if schedule == meeting.agenda %}<a id="ical-link" class="btn btn-primary" href="{% url "ietf.meeting.views.agenda_by_type_ics" num=meeting.number type=type.grouper %}">Download to Calendar</a>{% endif %}
|
||||
<ul class="daylist">
|
||||
{% regroup type.list by timeslot.time|date:"l Y-M-d" as daylist %}
|
||||
{% for day in daylist %}
|
||||
<li class="daylistentry">
|
||||
{{ day.grouper }}
|
||||
<h3>{{ day.grouper }}</h3>
|
||||
<table class="sessiontable">
|
||||
{% for ss in day.list %}
|
||||
<tr>
|
||||
|
|
106
ietf/templates/meeting/floor-plan.html
Normal file
106
ietf/templates/meeting/floor-plan.html
Normal file
|
@ -0,0 +1,106 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
|
||||
{% load ietf_filters %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block title %}
|
||||
IETF {{ schedule.meeting.number }} meeting agenda
|
||||
{% if "-utc" in request.path %}
|
||||
(UTC)
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
.floor-plan {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
.rooms a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
{% block bodyAttrs %}data-spy="scroll" data-target="#affix"{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12" >
|
||||
|
||||
{% include "meeting/meeting_heading.html" with meeting=schedule.meeting selected="floor-plan" title_extra="Floor Plan" %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
{% for floor in floors %}
|
||||
<div class="anchor-target" id="{{floor.name|slugify}}"></div>
|
||||
<h3>{{ floor.name }}</h3>
|
||||
<div class="floor-plan">
|
||||
<img class="col-md-12" src="{{ floor.image.url }}" >
|
||||
<!-- We need as many of these as we can have individual rooms combining into one -->
|
||||
<div id="{{floor.name|slugify}}-arrowdiv" style="position: absolute; left: 0; top: 67.5px; visibility: hidden;"><img id="arrow" src="{% static 'ietf/images/arrow-ani.gif' %}"></div>
|
||||
<div id="{{floor.name|slugify}}-arrowdiv1" style="position: absolute; left: 0; top: 67.5px; visibility: hidden;"><img id="arrow" src="{% static 'ietf/images/arrow-ani.gif' %}"></div>
|
||||
<div id="{{floor.name|slugify}}-arrowdiv2" style="position: absolute; left: 0; top: 67.5px; visibility: hidden;"><img id="arrow" src="{% static 'ietf/images/arrow-ani.gif' %}"></div>
|
||||
<div id="{{floor.name|slugify}}-arrowdiv3" style="position: absolute; left: 0; top: 67.5px; visibility: hidden;"><img id="arrow" src="{% static 'ietf/images/arrow-ani.gif' %}"></div>
|
||||
</div>
|
||||
<div class="rooms">
|
||||
{% for room in floor.room_set.all %}
|
||||
{#<a href="javascript: setarrow('{{room.name|slugify}}','{{floor.name|slugify}}')">{{ room.name|nbsp }}</a>#}
|
||||
{{ room.name|nbsp }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="row"></div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="col-md-2 hidden-print bs-docs-sidebar" id="affix">
|
||||
<ul class="nav nav-pills nav-stacked small" data-spy="affix">
|
||||
{% for floor in floors %}
|
||||
<li><a href="#{{floor.name|slugify}}">{{ floor.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{% with meeting=schedule.meeting %}
|
||||
<script src="{% static 'ietf/js/room_params.js' %}"></script>
|
||||
<script>
|
||||
// These must match the 'arrowdiv' divs above
|
||||
var arrowsuffixlist = [ '', '1', '2', '3' ];
|
||||
|
||||
function roommap(nm)
|
||||
{
|
||||
var c = findroom(nm);
|
||||
if (c) return nm;
|
||||
var m = suffixmap(nm);
|
||||
// alert("m=" + m);
|
||||
return m;
|
||||
}
|
||||
|
||||
function findroom(nm)
|
||||
{
|
||||
var left = 0, top = 0, right = 0, bottom = 0;
|
||||
|
||||
if (0) { }
|
||||
{% for room in meeting.room_set.all %}
|
||||
else if (nm == '{{room.name|slugify}}') { left = {{room.left}}; top = {{room.top}}; right = {{room.right}}; bottom = {{room.bottom}}; }{% endfor %}
|
||||
|
||||
{% for room in meeting.room_set.all %}{% if room.functional_display_name %}
|
||||
else if (nm == '{{room.functional_name|slugify}}') { left = {{room.left}}; top = {{room.top}}; right = {{room.right}}; bottom = {{room.bottom}}; }{% endif %}{% endfor %}
|
||||
|
||||
else return null;
|
||||
|
||||
// alert("nm=" + nm + ",left=" + left + ",top=" + top + ",r=" + right + ",b=" + bottom);
|
||||
return [left, top, right, bottom];
|
||||
}
|
||||
</script>
|
||||
{% endwith %}
|
||||
{% endblock %}
|
|
@ -1,24 +1,57 @@
|
|||
{# Copyright The IETF Trust 2015, All Rights Reserved #}{% load origin %}{% origin %}
|
||||
{# assumes meeting is in context #}
|
||||
{% if schedule != meeting.agenda %}
|
||||
<h3 class="alert alert-danger text-center">
|
||||
This is schedule {{schedule.owner.email}}/{{ schedule.name }}, not the official schedule.
|
||||
</h3>
|
||||
{% endif %}
|
||||
{% load origin %}
|
||||
{% load ietf_filters %}
|
||||
|
||||
<h1>
|
||||
IETF {{ meeting.number }} Meeting Agenda
|
||||
<br>
|
||||
<small>
|
||||
{{ meeting.city }}, {{ meeting.date|date:"F j" }} -
|
||||
{% if meeting.date.month != meeting.end_date.month %}
|
||||
{{ meeting.end_date|date:"F " }}
|
||||
{% endif %}
|
||||
{{ meeting.end_date|date:"j, Y" }}
|
||||
<span class="pull-right">
|
||||
Updated {{ updated|date:"Y-m-d \a\t G:i:s (T)" }}
|
||||
</span>
|
||||
{% origin %}
|
||||
|
||||
</small>
|
||||
{% if schedule != meeting.agenda %}
|
||||
<h3 class="alert alert-danger text-center">
|
||||
This is schedule {{schedule.owner.email}}/{{ schedule.name }}, not the official schedule.
|
||||
</h3>
|
||||
{% endif %}
|
||||
|
||||
</h1>
|
||||
<h1>
|
||||
IETF {{ meeting.number }} Meeting Agenda {{ title_extra }}
|
||||
<br>
|
||||
<small>
|
||||
{{ meeting.city }}, {{ meeting.date|date:"F j" }} -
|
||||
{% if meeting.date.month != meeting.end_date.month %}
|
||||
{{ meeting.end_date|date:"F " }}
|
||||
{% endif %}
|
||||
{{ meeting.end_date|date:"j, Y" }}
|
||||
{% if updated %}
|
||||
<span class="pull-right">
|
||||
Updated {{ updated|date:"Y-m-d \a\t G:i:s (T)" }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</small>
|
||||
</h1>
|
||||
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li {% if selected == "agenda" %}class="active"{% endif %}>
|
||||
<a href="{% url 'ietf.meeting.views.agenda' num=schedule.meeting.number %}">Agenda</a></li>
|
||||
<li {% if selected == "agenda-utc" %}class="active"{% endif %}>
|
||||
<a href="{% url 'ietf.meeting.views.agenda' num=schedule.meeting.number utc='-utc' %}">UTC Agenda</a></li>
|
||||
{% if user|has_role:"Secretariat,Area Director,IAB" %}
|
||||
{% if schedule != meeting.agenda %}
|
||||
<li {% if selected == "by-room" %}class="active"{% endif %}>
|
||||
<a href="{% url 'ietf.meeting.views.agenda_by_room' num=schedule.meeting.number name=schedule.name owner=schedule.owner.email %}">by Room</a></li>
|
||||
<li {% if selected == "by-type" %}class="active"{% endif %}>
|
||||
<a href="{% url 'ietf.meeting.views.agenda_by_type' num=schedule.meeting.number name=schedule.name owner=schedule.owner.email %}">by Type</a></li>
|
||||
<li {% if selected == "room-view" %}class="active"{% endif %}>
|
||||
<a href="{% url 'ietf.meeting.views.room_view' num=schedule.meeting.number name=schedule.name owner=schedule.owner.email %}">Room grid</a></li>
|
||||
{% else %}
|
||||
<li {% if selected == "by-room" %}class="active"{% endif %}>
|
||||
<a href="{% url 'ietf.meeting.views.agenda_by_room' num=schedule.meeting.number %}">by Room</a></li>
|
||||
<li {% if selected == "by-type" %}class="active"{% endif %}>
|
||||
<a href="{% url 'ietf.meeting.views.agenda_by_type' num=schedule.meeting.number %}">by Type</a></li>
|
||||
<li {% if selected == "room-view" %}class="active"{% endif %}>
|
||||
<a href="{% url 'ietf.meeting.views.room_view' num=schedule.meeting.number %}">Room grid</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<li {% if selected == "floor-plan" %}class="active"{% endif %}>
|
||||
<a href="{% url 'ietf.meeting.views.floor_plan' num=schedule.meeting.number %}">Floor plan</a></li>
|
||||
<li><a href="{% url 'ietf.meeting.views.agenda' num=schedule.meeting.number ext='.txt' %}">Plaintext</a></li>
|
||||
<li><a href="https://tools.ietf.org/agenda/{{schedule.meeting.number}}/">Tools-style »</a></li>
|
||||
</ul>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
{% include "meeting/meeting_heading.html" %}
|
||||
{% include "meeting/meeting_heading.html" with title_extra="" selected="" %}
|
||||
|
||||
<div class="jumbotron">
|
||||
<p>There is no agenda available yet.</p>
|
||||
|
|
|
@ -582,7 +582,7 @@
|
|||
</script>
|
||||
</head>
|
||||
<body onload="draw_calendar()" onresize="draw_calendar()" id="body">
|
||||
<div id="mtgheader" style="overflow:auto">{% include "meeting/meeting_heading.html" with meeting=schedule.meeting updated=schedule.meeting.updated %}</div>
|
||||
<div id="mtgheader" style="overflow:auto">{% include "meeting/meeting_heading.html" with meeting=schedule.meeting updated=schedule.meeting.updated selected="room-view" title_extra="Room Grid" %}</div>
|
||||
<div id="daycontainer" role="tabpanel">
|
||||
<ul id="daytabs" class="nav nav-tabs" role="tablist">
|
||||
{% for day in days %}
|
||||
|
|
Loading…
Reference in a new issue