Luke Plant avatar Luke Plant committed 89eebee Merge

Merged from default

Comments (0)

Files changed (199)

 - You need to create a settings_private.py file (should be obvious if you
   try to run it).  This file needs the various settings that I cannot
   release publically (database, passwords, secret key)
-- Additional dependencies:
-	p3.py
-	

cciw/cciwmain/common.py

 def standard_subs(value):
     """Standard substitutions made on HTML content"""
     return value.replace('{{thisyear}}', str(get_thisyear()))\
-                .replace('{{media}}', settings.CCIW_MEDIA_URL)
+                .replace('{{media}}', settings.MEDIA_URL)\
+                .replace('{{static}}', settings.STATIC_URL)
 standard_subs.is_safe = True # provided our substitutions don't introduce anything that must be escaped
 
 def get_order_option(order_options, request, default_order_by):
 
     context['menulinks'] = links
     context['current_member'] = threadlocals.get_current_member()
-    context['pagevars'] = {
-        'media_root_url': settings.CCIW_MEDIA_URL,
-        'style_sheet_url': settings.CCIW_MEDIA_URL + '/style.css',
-        'admin_media_root_url': settings.ADMIN_MEDIA_PREFIX,
-    }
 
     context.update(view_extras.get_view_extras_context(request))
 
     return context
-
-
-
-

cciw/cciwmain/decorators.py

 def json_response(view_func):
     def _inner(request, *args, **kwargs):
         data = view_func(request, *args, **kwargs)
-        return HttpResponse(python_to_json(data),
+        resp = HttpResponse(python_to_json(data),
                             mimetype="text/javascript")
+        resp['Cache-Control'] = "no-cache"
+        return resp
     return wraps(view_func)(_inner)

cciw/cciwmain/fixtures/basic.json

+[
+    {
+        "pk": "1", 
+        "model": "cciwmain.site", 
+        "fields": {
+            "info": "Site 1 info", 
+            "long_name": "Site 1 long name", 
+            "slug_name": "llys-andreas", 
+            "short_name": "Site 1"
+        }
+    }, 
+    {
+        "fields": {
+            "previous_camp": null, 
+            "leaders": [
+                1
+            ], 
+            "end_date": "2000-07-08", 
+            "online_applications": true, 
+            "number": 1, 
+            "site": 1, 
+            "age": "Jnr", 
+            "year": 2000, 
+            "start_date": "2000-07-01", 
+            "chaplain": null
+        }, 
+        "model": "cciwmain.camp", 
+        "pk": "1"
+    }, 
+    {
+        "fields": {
+            "previous_camp": 1, 
+            "leaders": [
+                1
+            ], 
+            "end_date": "2001-07-08", 
+            "online_applications": true, 
+            "number": 1, 
+            "site": 1, 
+            "age": "Jnr", 
+            "year": 2001, 
+            "start_date": "2001-07-01", 
+            "chaplain": null
+        }, 
+        "model": "cciwmain.camp", 
+        "pk": "2"
+    }, 
+    {
+        "fields": {
+            "visible": true, 
+            "extra_title": "", 
+            "parent_item": null, 
+            "title": "Home", 
+            "url": "/", 
+            "listorder": 0
+        }, 
+        "model": "cciwmain.menulink", 
+        "pk": "1"
+    }, 
+    {
+        "pk": 1, 
+        "model": "sites.site", 
+        "fields": {
+            "domain": "www.cciw.co.uk", 
+            "name": "www.cciw.co.uk"
+        }
+    }, 
+    {
+        "fields": {
+            "username": "davestott", 
+            "first_name": "Dave", 
+            "last_name": "Stott", 
+            "is_active": true, 
+            "is_superuser": false, 
+            "is_staff": true, 
+            "last_login": "2008-04-23 19:06:39", 
+            "groups": [
+                2
+            ], 
+            "user_permissions": [], 
+            "password": "sha1$1b3b9$a8a863f2f021582d972b6e50629c8f8588de7bba", 
+            "email": "leader@somewhere.com", 
+            "date_joined": "2007-05-20 23:22:40"
+        }, 
+        "model": "auth.user", 
+        "pk": 1
+    }, 
+    {
+        "fields": {
+            "info": "Dave and Rebecca are members of Grace Baptist Church, Southport.  Dave has been a leader or assistant leader on many camps (EMW, CCIW and church camps).", 
+            "name": "Dave & Rebecca Stott", 
+            "users": [
+                1
+            ]
+        }, 
+        "model": "cciwmain.person", 
+        "pk": 1
+    }
+]

cciw/cciwmain/fixtures/basic.yaml

-- model: cciwmain.site
-  pk: '1'
-  fields:
-    info: Site 1 info
-    long_name: Site 1 long name
-    short_name: Site 1
-    slug_name: llys-andreas
-
-- fields:
-    age: Jnr
-    chaplain: null
-    end_date: 2000-07-08
-    leaders: [1]
-    number: 1
-    online_applications: true
-    previous_camp: null
-    site: 1
-    start_date: 2000-07-01
-    year: 2000
-  model: cciwmain.camp
-  pk: '1'
-  
-- fields:
-    age: Jnr
-    chaplain: null
-    end_date: 2001-07-08
-    leaders: [1]
-    number: 1
-    online_applications: true
-    previous_camp: 1
-    site: 1
-    start_date: 2001-07-01
-    year: 2001
-  model: cciwmain.camp
-  pk: '2'
-
-- model: cciwmain.menulink
-  fields:
-    extra_title: ''
-    listorder: 0
-    parent_item: null
-    title: Home
-    url: /
-    visible: true
-  pk: '1'
-
-- model: sites.site
-  pk: 1
-  fields:
-    domain: www.cciw.co.uk
-    name: www.cciw.co.uk
-
-# We need User object to exist to create Person object fully
-
-- fields:
-    date_joined: 2007-05-20 23:22:40
-    email: leader@somewhere.com
-    first_name: Dave
-    groups: [2]
-    is_active: true
-    is_staff: true
-    is_superuser: false
-    last_login: 2008-04-23 19:06:39
-    last_name: Stott
-    # test_normaluser_password
-    password: sha1$1b3b9$a8a863f2f021582d972b6e50629c8f8588de7bba
-    user_permissions: []
-    username: davestott
-  model: auth.user
-  pk: 1
-
-- fields:
-    info: 'Dave and Rebecca are members of Grace Baptist Church, Southport.  Dave has been a leader or assistant leader on many camps (EMW, CCIW and church camps).'
-    name: Dave & Rebecca Stott
-    users: [1]
-  model: cciwmain.person
-  pk: 1

cciw/cciwmain/fixtures/basic_topic.json

+[
+    {
+        "pk": "1", 
+        "model": "cciwmain.forum", 
+        "fields": {
+            "open": true, 
+            "location": "camps/2000/1/forum/"
+        }
+    }, 
+    {
+        "pk": "1", 
+        "model": "cciwmain.topic", 
+        "fields": {
+            "poll": null, 
+            "forum": 1, 
+            "post_count": 1, 
+            "needs_approval": false, 
+            "created_at": "2006-09-03 12:16:57", 
+            "subject": "<Jill & Jane>", 
+            "started_by": "test_member_1", 
+            "last_post_by": "test_member_1", 
+            "news_item": null, 
+            "hidden": false, 
+            "last_post_at": "2006-09-03 12:16:57", 
+            "open": true, 
+            "approved": false, 
+            "checked_by": null
+        }
+    }, 
+    {
+        "pk": "1", 
+        "model": "cciwmain.post", 
+        "fields": {
+            "hidden": false, 
+            "needs_approval": false, 
+            "posted_by": "test_member_1", 
+            "approved": null, 
+            "topic": 1, 
+            "checked_by": null, 
+            "photo": null, 
+            "message": "A [b]unique message[/b] with some bbcode & <stuff> to be escaped", 
+            "posted_at": "2006-09-03 12:16:57", 
+            "subject": ""
+        }
+    }
+]

cciw/cciwmain/fixtures/basic_topic.yaml

-- model: cciwmain.forum
-  pk: '1'
-  fields:
-    open: true
-    location: camps/2000/1/forum/
-
-- model: cciwmain.topic
-  pk: '1'
-  fields:
-    subject: '<Jill & Jane>'
-    started_by: test_member_1
-    approved: false
-    checked_by: null
-    created_at: 2006-09-03 12:16:57
-    forum: 1
-    hidden: false
-    needs_approval: false
-    news_item: null
-    open: true
-    poll: null
-    post_count: 1
-    last_post_at: 2006-09-03 12:16:57
-    last_post_by: test_member_1
-
-- model: cciwmain.post
-  pk: '1'
-  fields:
-    posted_by: test_member_1
-    subject: ''
-    message: 'A [b]unique message[/b] with some bbcode & <stuff> to be escaped'
-    posted_at: 2006-09-03 12:16:57
-    hidden: false
-    approved: null
-    checked_by: null
-    needs_approval: false
-    photo: null
-    topic: 1
-

cciw/cciwmain/fixtures/contact.json

+[
+    {
+        "fields": {
+            "menu_link": null, 
+            "html": "\n<p>If you have an enquiry to make to the CCIW directors,\nplease use the form below and your message will be forwarded \nto the relevant person, who will reply by e-mail.</p>\n", 
+            "page_title": ""
+        }, 
+        "model": "cciwmain.htmlchunk", 
+        "pk": "feedback_intro"
+    }, 
+    {
+        "fields": {
+            "menu_link": null, 
+            "html": "", 
+            "page_title": ""
+        }, 
+        "model": "cciwmain.htmlchunk", 
+        "pk": "feedback_outro"
+    }
+]

cciw/cciwmain/fixtures/contact.yaml

-
-- fields: {html: "\n<p>If you have an enquiry to make to the CCIW directors,\nplease\
-      \ use the form below and your message will be forwarded \nto the relevant person,\
-      \ who will reply by e-mail.</p>\n", menu_link: null, page_title: ''}
-  model: cciwmain.htmlchunk
-  pk: feedback_intro
-
-- fields: {html: '', menu_link: null, page_title: ''}
-  model: cciwmain.htmlchunk
-  pk: feedback_outro

cciw/cciwmain/fixtures/htmlchunks.json

+[
+    {
+        "fields": {
+            "visible": true, 
+            "extra_title": "", 
+            "parent_item": null, 
+            "title": "Home", 
+            "url": "/", 
+            "listorder": 0
+        }, 
+        "model": "cciwmain.menulink", 
+        "pk": 1
+    }, 
+    {
+        "fields": {
+            "menu_link": 1, 
+            "html": "<p>CCIW is a charitable company that runs outdoor camps on a number of sites in Wales.\r\n The camps provide great outdoor fun with God and the Bible at the centre of each day.</p>\r\n<p>The detailed format of the day varies from camp to camp, but all of them \r\ninclude a morning service as a camp, activities in the afternoon and \r\nbible studies in the evening in tent groups.  The kind of activities we do \r\ninclude canoeing, raft-building, swimming, walking, rock-climbing, and gorge-walking, \r\nas well as football, rounders and other camp site games.  Below is \r\na list of other pages to find out more about the camps.</p>\r\n\r\n<h2>Contents:</h2>\r\n<ul>\r\n<li><a href=\"/news/\">News</a><br/>\r\nThe latest news, particularly about what is available on the website,\r\n is here, with the opportunity to add your own comments.\r\n\r\n<p>See also:</p>\r\n<ul><li><a href=\"/posts/\">Recent message board posts</a></li>\r\n<li><a href=\"/topics/\">Recently started topics</a></li>\r\n<li><a href=\"/tags/\">Recently created tags</a></li>\r\n</ul>\r\n<br/><br/>\r\n</li>\r\n<li><a href=\"/thisyear/\">Camps {{thisyear}}</a><br/>\r\nInformation for camps in {{thisyear}}, including dates, leadership teams,\r\n and how to book.<br/><br/>\r\n</li>\r\n\r\n<li><a href=\"/camps/\">Camp forums and photos</a><br/>\r\nHere you can find photos and messages boards from the CCIW camps that have run in the past.\r\nHopefully these will give you an idea of what we do, or help you stay in contact with\r\nfriends you met on camp. <br/><br/>\r\nThe leaders and committee members have also lead and organised camps with churches and\r\nother organisations (particularly <a href=\"http://www.emw.org.uk/\">The Evangelical Movement of Wales</a>) for many years, and some photos of these camps\r\ncan be found here. <br/><br/>\r\n</li>\r\n\r\n<li><a href=\"/sites/\">Camp sites</a><br/>\r\nInformation on the different sites we run camps at.<br/><br/>\r\n</li>\r\n\r\n\r\n<li><a href=\"/members/\">Members</a><br/>\r\nList of currently signed up members to the website.  Look for your friends here!<br/><br/>\r\n</li>\r\n\r\n<li><a href=\"/info/\">About CCIW</a><br/>\r\nCompany information, including the doctrinal basis of CCIW, legal information, and the names and addresses of the directors. \r\n<br/>\r\n<br/></li>\r\n\r\n\r\n<li><a href=\"/website/\">About website</a><br/>\r\nInformation about the website, including message boards about the different features.<br/><br/>\r\n</li>\r\n\r\n<li><a href=\"/contact/\">Contact us</a><br/>\r\nAny comments about camp, suggestions, or other reasons to get in contact with us - leave us a message.<br/>\r\n<br/>\r\n</li>\r\n\r\n</ul>\r\n<br/>\r\n<p>CCIW is a limited company (reg. No. 3900844), and a Registered Charity (No:1079713)</p>", 
+            "page_title": "Christian Camps in Wales"
+        }, 
+        "model": "cciwmain.htmlchunk", 
+        "pk": "home_page"
+    }
+]

cciw/cciwmain/fixtures/htmlchunks.yaml

-- fields: 
-    extra_title: ''
-    listorder: 0
-    parent_item: null
-    title: Home
-    url: /
-    visible: true
-  model: cciwmain.menulink
-  pk: 1
-
-- fields:
-    html: "<p>CCIW is a charitable company that runs outdoor camps on\
-      \ a number of sites in Wales.\r\n The camps provide great outdoor fun with God\
-      \ and the Bible at the centre of each day.</p>\r\n<p>The detailed format of\
-      \ the day varies from camp to camp, but all of them \r\ninclude a morning service\
-      \ as a camp, activities in the afternoon and \r\nbible studies in the evening\
-      \ in tent groups.  The kind of activities we do \r\ninclude canoeing, raft-building,\
-      \ swimming, walking, rock-climbing, and gorge-walking, \r\nas well as football,\
-      \ rounders and other camp site games.  Below is \r\na list of other pages to\
-      \ find out more about the camps.</p>\r\n\r\n<h2>Contents:</h2>\r\n<ul>\r\n<li><a\
-      \ href=\"/news/\">News</a><br/>\r\nThe latest news, particularly about what\
-      \ is available on the website,\r\n is here, with the opportunity to add your\
-      \ own comments.\r\n\r\n<p>See also:</p>\r\n<ul><li><a href=\"/posts/\">Recent\
-      \ message board posts</a></li>\r\n<li><a href=\"/topics/\">Recently started\
-      \ topics</a></li>\r\n<li><a href=\"/tags/\">Recently created tags</a></li>\r\
-      \n</ul>\r\n<br/><br/>\r\n</li>\r\n<li><a href=\"/thisyear/\">Camps {{thisyear}}</a><br/>\r\
-      \nInformation for camps in {{thisyear}}, including dates, leadership teams,\r\
-      \n and how to book.<br/><br/>\r\n</li>\r\n\r\n<li><a href=\"/camps/\">Camp forums\
-      \ and photos</a><br/>\r\nHere you can find photos and messages boards from the\
-      \ CCIW camps that have run in the past.\r\nHopefully these will give you an\
-      \ idea of what we do, or help you stay in contact with\r\nfriends you met on\
-      \ camp. <br/><br/>\r\nThe leaders and committee members have also lead and organised\
-      \ camps with churches and\r\nother organisations (particularly <a href=\"http://www.emw.org.uk/\"\
-      >The Evangelical Movement of Wales</a>) for many years, and some photos of these\
-      \ camps\r\ncan be found here. <br/><br/>\r\n</li>\r\n\r\n<li><a href=\"/sites/\"\
-      >Camp sites</a><br/>\r\nInformation on the different sites we run camps at.<br/><br/>\r\
-      \n</li>\r\n\r\n\r\n<li><a href=\"/members/\">Members</a><br/>\r\nList of currently\
-      \ signed up members to the website.  Look for your friends here!<br/><br/>\r\
-      \n</li>\r\n\r\n<li><a href=\"/info/\">About CCIW</a><br/>\r\nCompany information,\
-      \ including the doctrinal basis of CCIW, legal information, and the names and\
-      \ addresses of the directors. \r\n<br/>\r\n<br/></li>\r\n\r\n\r\n<li><a href=\"\
-      /website/\">About website</a><br/>\r\nInformation about the website, including\
-      \ message boards about the different features.<br/><br/>\r\n</li>\r\n\r\n<li><a\
-      \ href=\"/contact/\">Contact us</a><br/>\r\nAny comments about camp, suggestions,\
-      \ or other reasons to get in contact with us - leave us a message.<br/>\r\n\
-      <br/>\r\n</li>\r\n\r\n</ul>\r\n<br/>\r\n<p>CCIW is a limited company (reg. No.\
-      \ 3900844), and a Registered Charity (No:1079713)</p>"
-    menu_link: 1
-    page_title: Christian Camps in Wales
-  model: cciwmain.htmlchunk
-  pk: home_page

cciw/cciwmain/fixtures/news.json

+[
+    {
+        "pk": 1, 
+        "model": "cciwmain.forum", 
+        "fields": {
+            "open": true, 
+            "location": "news/"
+        }
+    }, 
+    {
+        "pk": 1, 
+        "model": "cciwmain.newsitem", 
+        "fields": {
+            "created_at": "2002-12-27 15:22:57", 
+            "subject": "Bits & Pieces", 
+            "created_by": "test_member_1", 
+            "full_item": "", 
+            "summary": "Summary [b]with bbcode[/b]"
+        }
+    }, 
+    {
+        "pk": 2, 
+        "model": "cciwmain.newsitem", 
+        "fields": {
+            "created_at": "2002-12-27 15:22:57", 
+            "subject": "Fish & Chips", 
+            "created_by": "test_member_1", 
+            "full_item": "<p>Full item with <i>html</i> and everything</p>", 
+            "summary": ""
+        }
+    }, 
+    {
+        "pk": 1, 
+        "model": "cciwmain.topic", 
+        "fields": {
+            "poll": null, 
+            "forum": 1, 
+            "post_count": 1, 
+            "needs_approval": false, 
+            "created_at": "2006-09-03 12:16:57", 
+            "subject": "Bits & Pieces", 
+            "started_by": "test_member_1", 
+            "last_post_by": "test_member_1", 
+            "news_item": 1, 
+            "hidden": false, 
+            "last_post_at": "2006-09-03 12:16:57", 
+            "open": true, 
+            "approved": false, 
+            "checked_by": null
+        }
+    }, 
+    {
+        "pk": 2, 
+        "model": "cciwmain.topic", 
+        "fields": {
+            "poll": null, 
+            "forum": 1, 
+            "post_count": 1, 
+            "needs_approval": false, 
+            "created_at": "2006-09-03 12:16:57", 
+            "subject": "Fish & Chips", 
+            "started_by": "test_member_1", 
+            "last_post_by": "test_member_1", 
+            "news_item": 2, 
+            "hidden": false, 
+            "last_post_at": "2006-09-03 12:16:57", 
+            "open": true, 
+            "approved": false, 
+            "checked_by": null
+        }
+    }, 
+    {
+        "pk": 1, 
+        "model": "cciwmain.post", 
+        "fields": {
+            "hidden": false, 
+            "needs_approval": false, 
+            "posted_by": "test_member_1", 
+            "approved": null, 
+            "topic": 1, 
+            "checked_by": null, 
+            "photo": null, 
+            "message": "A [b]unique message[/b] with some bbcode & <stuff> to be escaped", 
+            "posted_at": "2006-09-03 12:16:57", 
+            "subject": ""
+        }
+    }, 
+    {
+        "pk": 2, 
+        "model": "cciwmain.post", 
+        "fields": {
+            "hidden": false, 
+            "needs_approval": false, 
+            "posted_by": "test_member_1", 
+            "approved": null, 
+            "topic": 2, 
+            "checked_by": null, 
+            "photo": null, 
+            "message": "A [b]unique message[/b] with some bbcode & <stuff> to be escaped", 
+            "posted_at": "2006-09-03 12:16:57", 
+            "subject": ""
+        }
+    }
+]

cciw/cciwmain/fixtures/news.yaml

-- model: cciwmain.forum
-  pk: 1
-  fields:
-    open: true
-    location: news/
-
-- model: cciwmain.newsitem
-  pk: 1
-  fields: 
-    created_at: !!timestamp '2002-12-27 15:22:57'
-    created_by: test_member_1
-    full_item: ''
-    subject: Bits & Pieces
-    summary: 'Summary [b]with bbcode[/b]'
-
-
-- model: cciwmain.newsitem
-  pk: 2
-  fields: 
-    created_at: !!timestamp '2002-12-27 15:22:57'
-    created_by: test_member_1
-    full_item: '<p>Full item with <i>html</i> and everything</p>'
-    subject: Fish & Chips
-    summary: ''
-
-
-- model: cciwmain.topic
-  pk: 1
-  fields:
-    subject: Bits & Pieces
-    started_by: test_member_1
-    approved: false
-    checked_by: null
-    created_at: 2006-09-03 12:16:57
-    forum: 1
-    hidden: false
-    needs_approval: false
-    news_item: 1
-    open: true
-    poll: null
-    post_count: 1
-    last_post_at: 2006-09-03 12:16:57
-    last_post_by: test_member_1
-
-- model: cciwmain.topic
-  pk: 2
-  fields:
-    subject: Fish & Chips
-    started_by: test_member_1
-    approved: false
-    checked_by: null
-    created_at: 2006-09-03 12:16:57
-    forum: 1
-    hidden: false
-    needs_approval: false
-    news_item: 2
-    open: true
-    poll: null
-    post_count: 1
-    last_post_at: 2006-09-03 12:16:57
-    last_post_by: test_member_1
-
-
-- model: cciwmain.post
-  pk: 1
-  fields:
-    posted_by: test_member_1
-    subject: ''
-    message: 'A [b]unique message[/b] with some bbcode & <stuff> to be escaped'
-    posted_at: 2006-09-03 12:16:57
-    hidden: false
-    approved: null
-    checked_by: null
-    needs_approval: false
-    photo: null
-    topic: 1
-
-
-- model: cciwmain.post
-  pk: 2
-  fields:
-    posted_by: test_member_1
-    subject: ''
-    message: 'A [b]unique message[/b] with some bbcode & <stuff> to be escaped'
-    posted_at: 2006-09-03 12:16:57
-    hidden: false
-    approved: null
-    checked_by: null
-    needs_approval: false
-    photo: null
-    topic: 2
-

cciw/cciwmain/fixtures/people.json

+null
Add a comment to this file

cciw/cciwmain/fixtures/people.yaml

Empty file removed.

cciw/cciwmain/fixtures/sites.json

+[
+    {
+        "fields": {
+            "info": "     <address>Llys Andreas Camp Site,<br/>\r\nFfordd Tyddyn Felin<br/>\r\n Tal-y-bont<br/>\r\n Barmouth<br/>\r\n LL43 2AU<br/>\r\n Pay phone: 01341 247526<br/>\r\n </address>\r\n <p>This site in Tal-y-bont is a smaller site than Tywyn, but still has plenty of room for the 50 campers it can accomodate. It has a main marquee for services and campsite activities, and a good sized playing space including a volleyball area. There is also a picturesque river just on the edge of the campsite.</p>\r\n\r\n<p>There is a multi-purpose building which houses a kitchen and eating/games areas. The site also has a toilet and wash-block, (including showers) for both males and females.</p>\r\n\r\n<p>Llys Andreas is very accessible, just two minutes off the main road between Barmouth & Harlech and just 10 mins from Tal-y-bont railway station. Barmouth also has a leisure centre, which has a five-a-side football pitch, as well a beach, a fair and plenty of shops. There is also a very pleasant beach much closer to Llys Andreas, which is a great spot for barbeques, bathing or bivouacking!\r\n</p>\r\n\r\n<div class='sitephoto'>\r\n<img src=\"{{media}}photos/real/1999-la-volleyball.jpeg\" width=\"352\" height=\"288\"  alt=\"photo 5\" /><p><b>Volley Ball on site</b></p>\r\n</div>\r\n\r\n<div class='sitephoto'>\r\n<img src=\"{{media}}photos/real/1999-la-river_bank.jpeg\" width=\"352\" height=\"288\"  alt=\"photo 6\" />\r\n<p><b>River Bank near the site</b></p>\r\n</div>\r\n    ", 
+            "long_name": "Llys Andreas, Barmouth", 
+            "slug_name": "llys-andreas", 
+            "short_name": "Llys Andreas"
+        }, 
+        "model": "cciwmain.site", 
+        "pk": 1
+    }
+]

cciw/cciwmain/fixtures/sites.yaml

-- fields: {info: "     <address>Llys Andreas Camp Site,<br/>\r\nFfordd Tyddyn Felin<br/>\r\
-      \n Tal-y-bont<br/>\r\n Barmouth<br/>\r\n LL43 2AU<br/>\r\n Pay phone: 01341\
-      \ 247526<br/>\r\n </address>\r\n <p>This site in Tal-y-bont is a smaller site\
-      \ than Tywyn, but still has plenty of room for the 50 campers it can accomodate.\
-      \ It has a main marquee for services and campsite activities, and a good sized\
-      \ playing space including a volleyball area. There is also a picturesque river\
-      \ just on the edge of the campsite.</p>\r\n\r\n<p>There is a multi-purpose building\
-      \ which houses a kitchen and eating/games areas. The site also has a toilet\
-      \ and wash-block, (including showers) for both males and females.</p>\r\n\r\n\
-      <p>Llys Andreas is very accessible, just two minutes off the main road between\
-      \ Barmouth & Harlech and just 10 mins from Tal-y-bont railway station. Barmouth\
-      \ also has a leisure centre, which has a five-a-side football pitch, as well\
-      \ a beach, a fair and plenty of shops. There is also a very pleasant beach much\
-      \ closer to Llys Andreas, which is a great spot for barbeques, bathing or bivouacking!\r\
-      \n</p>\r\n\r\n<div class='sitephoto'>\r\n<img src=\"{{media}}photos/real/1999-la-volleyball.jpeg\"\
-      \ width=\"352\" height=\"288\"  alt=\"photo 5\" /><p><b>Volley Ball on site</b></p>\r\
-      \n</div>\r\n\r\n<div class='sitephoto'>\r\n<img src=\"{{media}}photos/real/1999-la-river_bank.jpeg\"\
-      \ width=\"352\" height=\"288\"  alt=\"photo 6\" />\r\n<p><b>River Bank near\
-      \ the site</b></p>\r\n</div>\r\n    ", long_name: 'Llys Andreas, Barmouth',
-    short_name: Llys Andreas, slug_name: llys-andreas}
-  model: cciwmain.site
-  pk: 1

cciw/cciwmain/fixtures/test_members.json

+[
+    {
+        "pk": "test_member_1", 
+        "model": "cciwmain.member", 
+        "fields": {
+            "dummy_member": false, 
+            "message_option": 1, 
+            "icon": "", 
+            "banned": false, 
+            "comments": "My comments", 
+            "real_name": "Test", 
+            "show_email": false, 
+            "email": "test@test.com", 
+            "moderated": 0, 
+            "date_joined": "2006-09-02 12:16:57", 
+            "last_seen": "2006-09-03 12:16:57", 
+            "password": "247SSw8klbYoU", 
+            "hidden": false, 
+            "permissions": []
+        }
+    }, 
+    {
+        "pk": 1, 
+        "model": "cciwmain.permission", 
+        "fields": {
+            "description": "Poll creator"
+        }
+    }, 
+    {
+        "pk": "test_poll_creator_1", 
+        "model": "cciwmain.member", 
+        "fields": {
+            "dummy_member": false, 
+            "message_option": 1, 
+            "icon": "", 
+            "banned": false, 
+            "comments": "My comments", 
+            "real_name": "Test Poll Creator", 
+            "show_email": false, 
+            "email": "test2@test.com", 
+            "moderated": 0, 
+            "date_joined": "2006-09-02 12:16:57", 
+            "last_seen": "2006-09-03 12:16:57", 
+            "password": "247SSw8klbYoU", 
+            "hidden": false, 
+            "permissions": [
+                1
+            ]
+        }
+    }
+]

cciw/cciwmain/fixtures/test_members.yaml

-- model: cciwmain.member
-  pk: test_member_1
-  fields:
-    banned: false
-    comments: 'My comments'
-    date_joined: 2006-09-02 12:16:57
-    dummy_member: false
-    email: 'test@test.com'
-    hidden: false
-    icon: ''
-    last_seen: 2006-09-03 12:16:57
-    message_option: 1
-    moderated: 0
-    password: '247SSw8klbYoU'
-    permissions: []
-    real_name: 'Test'
-    show_email: false
-
-
-- model: cciwmain.permission
-  pk: 1
-  fields: {description: Poll creator}
-
-- model: cciwmain.member
-  pk: test_poll_creator_1
-  fields:
-    banned: false
-    comments: 'My comments'
-    date_joined: 2006-09-02 12:16:57
-    dummy_member: false
-    email: 'test2@test.com'
-    hidden: false
-    icon: ''
-    last_seen: 2006-09-03 12:16:57
-    message_option: 1
-    moderated: 0
-    password: '247SSw8klbYoU'
-    permissions: [1]
-    real_name: 'Test Poll Creator'
-    show_email: false

cciw/cciwmain/fixtures/users.json

+[
+    {
+        "fields": {
+            "codename": "add_htmlchunk", 
+            "name": "Can add HTML chunk", 
+            "content_type": 21
+        }, 
+        "model": "auth.permission", 
+        "pk": 1
+    }, 
+    {
+        "fields": {
+            "codename": "change_htmlchunk", 
+            "name": "Can change HTML chunk", 
+            "content_type": 21
+        }, 
+        "model": "auth.permission", 
+        "pk": 2
+    }, 
+    {
+        "fields": {
+            "codename": "delete_htmlchunk", 
+            "name": "Can delete HTML chunk", 
+            "content_type": 21
+        }, 
+        "model": "auth.permission", 
+        "pk": 3
+    }, 
+    {
+        "fields": {
+            "username": "admin", 
+            "first_name": "Admin", 
+            "last_name": "", 
+            "is_active": true, 
+            "is_superuser": true, 
+            "is_staff": true, 
+            "last_login": "2007-12-17 18:49:13", 
+            "groups": [], 
+            "user_permissions": [], 
+            "password": "sha1$3b8d0$b5f6730d7bd13886ac2f7e6b5062c037b81e267c", 
+            "email": "someone@somewhere.com", 
+            "date_joined": "2007-12-17 18:49:13"
+        }, 
+        "model": "auth.user", 
+        "pk": 1
+    }, 
+    {
+        "fields": {
+            "username": "editor", 
+            "first_name": "Editor", 
+            "last_name": "", 
+            "is_active": true, 
+            "is_superuser": false, 
+            "is_staff": true, 
+            "last_login": "2007-12-17 18:49:13", 
+            "groups": [], 
+            "user_permissions": [
+                1, 
+                2, 
+                3
+            ], 
+            "password": "sha1$72713$4d655a356d9dfde29f74d04e8c40a6e412d26d0a", 
+            "email": "editor@somewhere.com", 
+            "date_joined": "2007-12-17 18:49:13"
+        }, 
+        "model": "auth.user", 
+        "pk": 2
+    }, 
+    {
+        "fields": {
+            "username": "normaluser", 
+            "first_name": "Some other user", 
+            "last_name": "", 
+            "is_active": true, 
+            "is_superuser": false, 
+            "is_staff": false, 
+            "last_login": "2007-12-17 18:49:13", 
+            "groups": [], 
+            "user_permissions": [], 
+            "password": "sha1$1b3b9$a8a863f2f021582d972b6e50629c8f8588de7bba", 
+            "email": "editor@somewhere.com", 
+            "date_joined": "2007-12-17 18:49:13"
+        }, 
+        "model": "auth.user", 
+        "pk": 3
+    }
+]

cciw/cciwmain/fixtures/users.yaml

-# This seems to be created automatically
-#- fields: {app_label: cciwmain, model: htmlchunk, name: HTML chunk}
-#  model: contenttypes.contenttype
-#  pk: 21
-
-- fields: {codename: add_htmlchunk, content_type: 21, name: Can add HTML chunk}
-  model: auth.permission
-  pk: 1
-- fields: {codename: change_htmlchunk, content_type: 21, name: Can change HTML chunk}
-  model: auth.permission
-  pk: 2
-- fields: {codename: delete_htmlchunk, content_type: 21, name: Can delete HTML chunk}
-  model: auth.permission
-  pk: 3
-
-
-- fields:
-    date_joined: 2007-12-17 18:49:13.010855
-    email: someone@somewhere.com
-    first_name: 'Admin'
-    groups: []
-    is_active: true
-    is_staff: true
-    is_superuser: true
-    last_login: 2007-12-17 18:49:13.010834
-    last_name: ''
-    # password: test_admin_password
-    password: sha1$3b8d0$b5f6730d7bd13886ac2f7e6b5062c037b81e267c
-    user_permissions: []
-    username: admin
-  model: auth.user
-  pk: 1
-
-- fields:
-    date_joined: 2007-12-17 18:49:13.010855
-    email: editor@somewhere.com
-    first_name: 'Editor'
-    groups: []
-    is_active: true
-    is_staff: true
-    is_superuser: false
-    last_login: 2007-12-17 18:49:13.010834
-    last_name: ''
-    # test_editor_password
-    password: sha1$72713$4d655a356d9dfde29f74d04e8c40a6e412d26d0a
-    user_permissions: [1, 2, 3]
-    username: editor
-  model: auth.user
-  pk: 2
-
-- fields:
-    date_joined: 2007-12-17 18:49:13.010855
-    email: editor@somewhere.com
-    first_name: 'Some other user'
-    groups: []
-    is_active: true
-    is_staff: false
-    is_superuser: false
-    last_login: 2007-12-17 18:49:13.010834
-    last_name: ''
-    # test_normaluser_password
-    password: sha1$1b3b9$a8a863f2f021582d972b6e50629c8f8588de7bba
-    user_permissions: []
-    username: normaluser
-  model: auth.user
-  pk: 3

cciw/cciwmain/imageutils.py

 # and it's easier than getting
 
 from django.conf import settings
-import shutil
 import os
 import ImageFile
-import glob
+import tempfile
 
 def parse_image(filename):
     fp = open(filename, "rb")
     except OSError:
         pass # don't care if we couldn't delete for some reason
 
-def write_file(filename, filedata):
-    destination = open(filename, 'wb')
+def write_file(fp, filedata):
     for chunk in filedata.chunks():
-        destination.write(chunk)
+        fp.write(chunk)
+    fp.close()
 
 def fix_member_icon(member, filedata):
-    filename = "%s/%s" % (settings.MEDIA_ROOT, member.icon)
-    write_file(filename, filedata)
+    fd, filename = tempfile.mkstemp()
+    write_file(os.fdopen(fd, "w"), filedata)
 
     try:
         img = parse_image(filename)
         safe_del(filename)
         raise ValidationError(u"The image was bigger than %s by %s." % \
             (settings.MEMBER_ICON_MAX_SIZE, settings.MEMBER_ICON_MAX_SIZE))
-
         # Ideally would have scale to fit
 
-    # Give the icon a predictable name, with the same extension it had before.
-    # We refer to it in views without its extension, and use content negotiation
-    # to get the right one.
-    # This means we can just we only need the primary key (the username) of
-    # the Member object to calculate this URL, saving on *lots* of db queries.
-
-    ext = filename.split('.')[-1]
-    # Remove existing variants
-    for f in glob.glob("%s/%s/%s" % (settings.MEDIA_ROOT, settings.MEMBER_ICON_PATH, member.user_name + ".*")):
-        os.unlink(f)
-
+    # Convert to destination format
+    ext = settings.DEFAULT_MEMBER_ICON.split('.')[-1]
     newrelpath = "%s/%s" % (settings.MEMBER_ICON_PATH, member.user_name + "." + ext)
     newfullpath = "%s/%s" % (settings.MEDIA_ROOT, newrelpath)
-    shutil.move(filename, newfullpath)
+
+    opts = {}
+    try:
+        opts['transparency'] = img.info['transparency']
+    except KeyError:
+        pass
+    img.save(newfullpath, **opts)
+
     os.chmod(newfullpath, 0777)
     member.icon = newrelpath
     member.save()

cciw/cciwmain/models/__init__.py

         (topic.get_absolute_url(), escape(topic.subject[0:30])))
 
 def render_photo(photo):
-     return mark_safe(u'<a href="%s"><img src="%s/photos/thumbnails/%s" alt="Photo %s" /></a>' % \
-         (photo.get_absolute_url(), settings.CCIW_MEDIA_URL, photo.filename, photo.id))
+     return mark_safe(u'<a href="%s"><img src="%sphotos/thumbnails/%s" alt="Photo %s" /></a>' % \
+         (photo.get_absolute_url(), settings.MEDIA_URL, photo.filename, photo.id))
 
 
 register_renderer(Member, Member.get_link)

cciw/cciwmain/models/members.py

         return str(self)
 
     def imageurl(self):
-        return os.path.join(settings.CCIW_MEDIA_URL, settings.AWARD_UPLOAD_PATH, self.image.name)
+        return self.image.url
 
     def get_absolute_url(self):
         from django.template.defaultfilters import slugify

cciw/cciwmain/static/adminextra.css

+#header2
+{
+	background-image: url('/static/images/header.png');
+}
+
+#headerlogo
+{
+	background-image: url('/static/images/headerlogo.png');
+}
+#header2
+{
+	height: 63px;
+	background-repeat: repeat-x;
+}
+
+#headerlogo
+{
+	background-repeat: no-repeat;
+	margin-left: 0px;
+	height: 63px;
+}
+
+#header	{ background:black; color:white; min-height:2.4em; overflow:auto; }
+#header a:link, #header a:visited { color:#00bb55; }
+#header a:hover { text-decoration:underline; }
+
+#helplink 
+{ 
+    font-size: 11px; 
+    text-align: right; 
+    padding: 2px 10px;
+}
+
+.removebtn,
+.editbtn,
+.emailbtn
+{
+    cursor: pointer;
+}
+
+.firstline,
+.refdetails
+{
+    cursor: pointer;
+}
+
+.firstline,
+.addrblock,
+.refdetails
+{
+    background: #d0d0d0;
+}
+
+.hidden
+{
+    display: none;
+}
+
+.refdetails
+{
+    border-top: 1px solid #808080;
+    border-bottom: 1px solid #808080;
+    margin-top: 2px;
+}
+
+.good
+{
+    color: green;
+}
+
+.ok
+{
+    color: darkorange;
+}
+
+.refrow td
+{
+    border-bottom: 1px solid black;
+}
+
+.refrow table td
+{
+    border-bottom: 0px;
+}
+
+.refrow table
+{
+    width: 100%;
+}
+
+tr.refrow td.nopadding
+{
+
+    padding: 0px;
+    margin: 0px;
+}
+
+/* References */
+
+.refcount 
+{ 
+    color: white; 
+    background: #8080ff;
+    padding-left: 2px;
+    padding-right: 2px;
+}
+
+.reference
+{
+    padding-left: 2em;
+    margin-bottom: 3em;
+}
+
+.referencestart
+{
+    border-top: 1px solid #888;
+    padding-top: 0.5em;
+}
+
+.referencebutton
+{
+    padding: 0.5em;
+}
+
+/* Admin overrides */
+
+#user-tools 
+{ 
+    top: 1.4em;
+    padding:0.2em 10px 1.2em 10px;
+}
+
+.actionnote {
+    background-color: #ff8;
+    padding: 0.3em;
+}
+
+/* Popups */
+
+.inlinepopup {
+    display:none;
+    position:fixed;
+    top:0px;
+    left:0px;
+    z-index: 2;
+}
+
+.inlinepopup .closebar {
+    padding: 3px;
+    background-color: black;
+    color: white;
+    text-align: right;
+}
+
+.inlinepopup .closebar a {
+    color: white;
+}
+
+.inlinepopup_background {
+    display:none;
+    position:fixed;
+    height:100%;
+    width:100%;
+    top:0;
+    left:0;
+    background:#000000;
+    z-index:1;
+    opacity: 0.7;
+}
Add a comment to this file

cciw/cciwmain/static/defaultmember.png

Added
New image

cciw/cciwmain/static/iegte6.css

+body
+{
+	font-size: small;
+}

cciw/cciwmain/static/ielt6.css

+table.sideheaders,
+table.topheaders,
+table.recenttags
+{
+	width: auto;
+}
Add a comment to this file

cciw/cciwmain/static/images/arrow-down.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/arrow-up.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/book.png

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/edit.png

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/email.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/angel.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/anvil.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/bandit.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/batman.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/behead.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/biggun.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/blowingup.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/bluekillsred.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/bluemad.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/bow.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/boxing.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/confused.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/cool.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/crying.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/eek.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/eyebrow.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/grim_reaper.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/grin.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/hanged.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/idea.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/lightsaber1.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/lol.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/mad.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/mallet1.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/rolleyes.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/rotfl.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/sad.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/santaclaus.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/saw.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/sheep.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/shifty.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/sleep.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/smile.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/thinking.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/tongue.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/unsure.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/wave.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/wink.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/emoticons/youarestupid.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/feed.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/header.png

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/header_inv.png

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/headerlogo.png

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/headerlogo_inv.png

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/headervline.png

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/headervline_inv.png

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/loading.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/sendemail.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/sortasc.png

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/sortdesc.png

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/wales2-th.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/wales2.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/wales3-th.gif

Added
New image
Add a comment to this file

cciw/cciwmain/static/images/wales3.gif

Added
New image

cciw/cciwmain/static/javascript/cciwutils.js

+// Misc extensions to jQuery and CCIW specific functions.
+
+(function($) {
+    $.fn.insertAtCaret = function(text) {
+        return this.each(function(){
+            if (document.selection) {
+                //IE support
+                this.focus();
+                var sel = document.selection.createRange();
+                sel.text = text;
+                this.focus();
+            }else if (this.selectionStart || this.selectionStart == '0') {
+                //MOZILLA/NETSCAPE support
+                var startPos = this.selectionStart;
+                var endPos = this.selectionEnd;
+                var scrollTop = this.scrollTop;
+                this.value = this.value.substring(0, startPos) + text + this.value.substring(endPos,this.value.length);
+                this.focus();
+                this.selectionStart = startPos + text.length;
+                this.selectionEnd = startPos + text.length;
+                this.scrollTop = scrollTop;
+            } else {
+                this.value += text;
+                this.focus();
+            }
+        });
+    };
+
+    $.fn.wrapAtCaret = function(startText, endText) {
+        return this.each(function(){
+            if (document.selection) {
+                //IE support
+                this.focus();
+                var sel = document.selection.createRange();
+                sel.text = startText + sel.text + endText;
+                this.focus();
+            } else if (this.selectionStart || this.selectionStart == '0') {
+                //MOZILLA/NETSCAPE support
+                var startPos = this.selectionStart;
+                var endPos = this.selectionEnd;
+                var scrollTop = this.scrollTop;
+                var origText = this.value.substring(startPos, endPos);
+                this.value = this.value.substring(0, startPos) + startText + origText + endText + this.value.substring(endPos,this.value.length);
+                this.focus();
+                if (origText.length == 0) {
+                    this.selectionStart = startPos + startText.length;
+                } else {
+                    this.selectionStart = startPos + startText.length + origText.length + endText.length;
+                }
+                this.selectionEnd = this.selectionStart;
+                this.scrollTop = scrollTop;
+            } else {
+                this.value += startText + endText;
+                this.focus();
+            }
+        });
+    };
+})(jQuery);
+
+var cciw = (function(pub, $) {
+
+    var submittableControl = function(node) {
+        var type = (node.type || "").toLowerCase();
+        var accept = false;
+        if (node.disabled || !node.name) {
+            accept = false;
+        } else {
+            // We don't know which button was 'clicked',
+            // so we can't include any as an element to submit
+            // Also can't submit files
+            accept = $.inArray(type, ["file", "submit", "reset", "button", "image"]) == -1;
+        }
+        return accept;
+    };
+
+    var addFormOnchangeHandlers = function(form_id, mk_input_change_handler) {
+        // Summary: Adds 'onchange' handlers to all inputs in a form
+        // form_id: id of the form in the DOM
+        // mk_input_change_handler: when called with one of the
+        //   form elements, returns a handler to be connected to
+        //   that element.
+        var form = $('#' + form_id);
+        if (form == null) {
+            return null;
+        }
+        var inputs = form.find('input,textarea,select');
+        inputs.each(function(i, elem) {
+            if (submittableControl(elem)) {
+                $(elem).change(mk_input_change_handler(elem));
+            }
+        });
+        return null;
+    };
+
+    var djangoNormaliseControlId = function(control_id) {
+        // Summary: returns the id/name that corresponds to
+        // the whole Django widget.  For MultiWidgets,
+        // this strips the trailing _0, _1 etc.
+        return control_id.replace(/^(.*)(_\d+)$/, "$1");
+    };
+
+    // standardform_* functions depend on the HTML in CciwFormMixin
+    var standardformDisplayError = function(control_id, errors) {
+        var row = $('#div_' + control_id);
+        if (row.size() == 0) {
+            return;
+        }
+        if (!row.hasClass("validationErrorBottom")) {
+            // insert <ul> before it
+            var content = $("<div class='validationErrorTop'><ul class='errorlist'></ul</div>");
+            $.each(errors, function(i, val) {
+                       content.find("ul").append("<li>").html(val);
+                   });
+            row.before(content);
+            row.addClass("validationErrorBottom");
+        }
+    };
+
+    var standardformClearError = function(control_id) {
+        var row = $('#div_' + control_id);
+        if (row.size() == 0) {
+            return;
+        }
+        if (row.hasClass("validationErrorBottom")) {
+            row.removeClass("validationErrorBottom");
+            // there will be a previous sibling
+            // which holds the error message
+            row.prev().remove();
+        }
+    };
+
+    var standardformGetValidatorCallback = function(control_name, control_id) {
+        // Summary: returns a callback that should be called when
+        // the AJAX validation request returns with data.
+        var control_name_n = djangoNormaliseControlId(control_name);
+        var control_id_n = djangoNormaliseControlId(control_id);
+        var handler = function(json) {
+            var errors = json[control_name_n];
+            if (errors != null && errors != undefined) {
+                standardformClearError(control_id_n);
+                standardformDisplayError(control_id_n, errors);
+            } else {
+                standardformClearError(control_id_n);
+            }
+        };
+        return handler;
+    };
+
+    var standardformGetInputChangeHandler = function(form_id, control_name, control_id) {
+        // Summary: returns an event handler to be added to a control,
+        // form_id: id of the form the control belongs to
+        // control_name: the name of the control
+        // control_id: id of the control
+        var on_input_change = function(ev) {
+            $.ajax({
+                type: "POST",
+                data: $('#' + form_id).serialize(),
+                url: "?format=json",
+                dataType: "json",
+                success: standardformGetValidatorCallback(control_name, control_id)
+            });
+        };
+        return on_input_change;
+    };
+
+    // Public interface:
+    pub.standardformAddOnchangeHandlers = function(form_id) {
+        addFormOnchangeHandlers(form_id, function(input) {
+            return standardformGetInputChangeHandler(form_id, input.name, input.id);
+        });
+    };
+
+    // To keep XHTML validation, we have to avoid
+    // 'target', so use this hack instead.
+    pub.externalLinks = function() {
+        $("a[href][rel=external]").each(function(i, elem) {
+                                            elem.target = "_blank";
+                                        });
+    };
+
+    return pub;
+})(cciw || {}, jQuery);

cciw/cciwmain/static/style.css

+/******************* COLOURS *******************/
+/* Include all borders here too */
+
+body {
+	background-color: black;
+	color: white;
+	font-size: small;
+}
+
+a:link {
+	color: #00bb55;
+}
+
+a:visited {
+	color: #ff7700;
+}
+a:hover {
+	color: #00ff55;
+}
+
+a img, a {
+	border-width: 0px;
+}
+
+
+/* Header */
+
+#header
+{
+	background-image: url('/static/images/header.png');
+}
+
+#headerlogo
+{
+	background-image: url('/static/images/headerlogo.png');
+}
+
+#mainbase
+{
+	background-color: #282828;
+}
+
+#mainstandard #contentBody, #mainstandard #pageTitle, #mainstandard #sidebar
+{
+	background-color: #181818;
+	border-top: 1px solid #666666;
+	border-bottom: 1px solid #666666;
+}
+
+
+/* Sidebar styles */
+#sidebar h1
+{
+	border-bottom: 1px solid #666666;
+}
+
+#sidebar a
+{
+	border-left: 2px solid #262626;
+	border-right: 2px solid #262626;
+}
+
+#sidebar a.currentSection,
+#sidebar a.currentPage
+{
+	background-color: #333333;
+	border-left: 2px solid #505050;
+	border-right: 2px solid #505050;
+	color: #ffffff;
+}
+
+#sidebar a:hover
+{
+	background-color: #441100;
+	border-left: 2px solid #662200;
+	border-right: 2px solid #662200;
+	color: white;
+}
+
+#footer
+{
+	background-image: url('/static/images/headervline.png');
+}
+
+
+/* Content styles */
+
+h2
+{
+	border-bottom: 2px solid #663300;
+}
+
+/* Tables */
+
+
+table.sideheaders td,
+table.simpleform td,
+table.topheaders td
+{
+	background-color: #000000;
+}
+
+table.sideheaders th,
+table.simpleform th,
+table.topheaders th
+{
+	background-color: #383838;
+}
+
+table.sideheaders th,
+table.sideheaders td,
+table.simpleform th,
+table.simpleform td,
+table.topheaders th,
+table.topheaders td
+{
+	border: solid 1px #336633;
+}
+
+td div.postSubject
+{
+	border-bottom: 1px solid #336633;
+}
+
+/* Sorting control */
+span.sortingControl img
+{
+	border-width: 0px;
+	border-bottom: 1px solid #808080;
+}
+span.sortingControl img.sortAscActive,
+span.sortingControl img.sortDescActive
+{
+	border-bottom: 2px solid #00ff00;
+
+}
+