atlas import scripts tweaks

This commit is contained in:
Johnson Chetty 2012-06-07 08:25:58 +02:00
commit 4932e30cb3
85 changed files with 1988 additions and 192 deletions

6
README
View File

@ -2,6 +2,12 @@ Note: If running postgres 9.1 and Django < 1.4, you will probably need this patc
Don't forget to install python-psycopg2 and python-gdal for the sake of GeoDjango.
To install Trigram Search:
psql <database_name>
create extension pg_trgm;
\q
python manage.py trgmidx
chaloBEST
Get:

41
chaloBEST/feeds.py Normal file
View File

@ -0,0 +1,41 @@
#from django.contrib.syndication.views import Feed
#from django.contrib.gis.feeds import Feed
from django.contrib.gis.feeds import Feed
from mumbai.models import *
from django.shortcuts import get_object_or_404
class RouteFeed(Feed):
# description_template = 'feeds/route_description.html'
def get_object(self, request, alias):
return get_object_or_404(Route, alias=alias)
def title(self, obj):
return "ChaloBEST.in: Feed for Bus No.: %s" % obj.alias
def description(self, obj):
return "GeoRSS Route Feed"
def geometry(self, obj):
return obj.from_stop.point
def link(self, obj):
return obj.get_absolute_url()
def items(self, obj):
return Stop.objects.filter(routedetail__route=obj)
def item_title(self, obj):
return obj.display_name
def item_geometry(self, obj):
return obj.point
def item_link(self, obj):
return obj.get_absolute_url()
def item_description(self, obj):
return obj.display_name #FIXME

View File

@ -11,16 +11,16 @@ import datetime
Convert Atlas.csv file (obtained from BEST) into first stage Atlas.json
(step 1)
'''
atlasDict = {}
def csvToJSON():
atlasCSV = csv.reader(open(join(PROJECT_ROOT, "../db_csv_files/Atlas.csv"), "r"), delimiter="\t")
atlasDict = {}
previousRoute = None
for a in atlasCSV:
routeNo = a[1].strip()
routeNo = a[0].strip()
# print a
if routeNo != '':
if atlasDict.has_key(routeNo):
atlasDist[routeNo].append(a)
atlasDict[routeNo].append(a)
else:
atlasDict[routeNo] = [a]
previousRoute = routeNo
@ -40,34 +40,39 @@ def processJSON():
routeErrors = {'routes': [], 'others': []}
routeMapping = json.loads(open(join(PROJECT_ROOT, "../db_csv_files/routeMapping.json")).read())
routes = json.loads(open(join(PROJECT_ROOT, "../db_csv_files/Atlas.json")).read())
previousRow = []
outDict = {}
for key in routes.keys():
previousRow = []
print key
if key not in routeMapping: #make note of routeNames we dont have routeAlias for yet.
routeErrors['routes'].append(key)
else: #else, go ahead ..
routeAlias = routeMapping[key]
routeCode = routeMapping[key]
thisRoute = routes[key]
#handle copying over empty values from previous rows
outDict[key] = []
for row in thisRoute:
# pdb.set_trace()
for i in range(2,5): # AM, N, PM
if row[i].strip() == '':
for i in range(1,4): # AM, N, PM
if row[i].strip() == '' and previousRow:
row[i] = previousRow[i]
for i in [7,10]: # From, To
if row[i].strip() == '':
for i in [6,9]: # From, To
if row[i].strip() == '' and previousRow:
row[i] = previousRow[i]
try:
if row[-5].strip() == '': #FIXME: change this to a positive index
row[-5] = previousRow[-5] #-5 is Schedule Type
# Schedule Type
if row[24].strip() == '' and previousRow: #FIXME: change this to a positive index
row[24] = previousRow[24] #-5 is Schedule Type
# RouteAlias
if row[0].strip() == '' and previousRow: #FIXME: change this to a positive index
row[0] = previousRow[0]
except:
pdb.set_trace()
previousRow = row
outDict[key].append(row)
atlasRouteErrors = open("atlasRouteErrors.json", "w")
atlasRouteErrors = open(join(PROJECT_ROOT, "../db_csv_files/atlasRouteErrors.json"), "w")
atlasRouteErrors.write(json.dumps(routeErrors, indent=2))
atlasRouteErrors.close()
atlasCopied = open(join(PROJECT_ROOT, "../db_csv_files/atlasCopied.json"), "w")
@ -89,17 +94,17 @@ def groupUnique():
for row in routes[key]:
print key
d = {
'from': row[7],
'to': row[10],
'span': row[13], #FIXME: what are you doing if span is null?
'from': row[6],
'to': row[9],
'span': row[12], #FIXME: what are you doing if span is null?
'is_full': False,
# 'schedule': row[28],
# 'rows': {
# row[-5]: row
# }
'schedule': row[24],
'rows': {
#row[24]: row
}
}
matchedRow = isNotUnique(d, outDict[key])
schedule = row[-5]
schedule = row[24]
if matchedRow is not None:
if outDict[key][matchedRow]['rows'].has_key(schedule):
outDict[key][matchedRow]['rows'][schedule].append(row)
@ -110,8 +115,9 @@ def groupUnique():
if isLargestSpan(d, routes[key]):
d['is_full'] = True
outDict[key].append(d)
if not outDict[key][-1].has_key('rows'):
outDict[key][-1]['rows'] = {}
#
#if not outDict[key][-1].has_key('rows'):
# outDict[key][-1]['rows'] = {}
outDict[key][-1]['rows'][schedule] = [row]
outFile = open(join(PROJECT_ROOT, "../db_csv_files/uniqueRoutes.json"), "w")
@ -190,7 +196,11 @@ def importUniqueRoutes():
depot = None #FIXME!! Catch depot errors based on findings
#pdb.set_trace()
for row in rows:
routeScheduleObj = RouteSchedule(unique_route=obj, schedule_type=schedule, busesAM=noneInt(row[2]), busesN=noneInt(row[3]), busesPM=noneInt(row[4]), bus_type=row[5], depot_txt=row[6], depot=depot, first_from=formatTime(row[8]), last_from=formatTime(row[9]), first_to=formatTime(row[11]), last_to=formatTime(row[12]), runtime1=noneInt(row[14]), runtime2=noneInt(row[15]), runtime3=noneInt(row[16]), runtime4=noneInt(row[17]), headway1=noneInt(row[18]), headway2=noneInt(row[19]), headway3=noneInt(row[20]), headway4=noneInt(row[21]), headway5=noneInt(row[22]))
#routeScheduleObj = RouteSchedule(unique_route=obj, schedule_type=schedule, busesAM=noneInt(row[2]), busesN=noneInt(row[3]), busesPM=noneInt(row[4]), bus_type=row[5], depot_txt=row[6], depot=depot, first_from=formatTime(row[8]), last_from=formatTime(row[9]), first_to=formatTime(row[11]), last_to=formatTime(row[12]), runtime1=noneInt(row[14]), runtime2=noneInt(row[15]), runtime3=noneInt(row[16]), runtime4=noneInt(row[17]), headway1=noneInt(row[18]), headway2=noneInt(row[19]), headway3=noneInt(row[20]), headway4=noneInt(row[21]), headway5=noneInt(row[22]))
routeScheduleObj = RouteSchedule(unique_route=obj, schedule_type=schedule, busesAM=noneInt(row[1]), busesN=noneInt(row[2]), busesPM=noneInt(row[3]), bus_type=row[4], depot_txt=row[5], depot=depot, first_from=formatTime(row[7]), last_from=formatTime(row[8]), first_to=formatTime(row[10]), last_to=formatTime(row[11]), runtime1=noneInt(row[13]), runtime2=noneInt(row[14]), runtime3=noneInt(row[15]), runtime4=noneInt(row[16]), headway1=noneInt(row[17]), headway2=noneInt(row[18]), headway3=noneInt(row[19]), headway4=noneInt(row[20]), headway5=noneInt(row[21]))
routeScheduleObj.save()
#done saving things - write out error files:

View File

@ -67,9 +67,9 @@ def areas(request):
def stops(request):
q = request.GET.get("q", "")
if q != '':
qset = Stop.objects.find_approximate(q, TRIGRAM_THRESHOLD).select_related()
qset = Stop.objects.find_approximate(q, TRIGRAM_THRESHOLD)
else:
qset = Stop.objects.all().select_related()
qset = Stop.objects.all()
srid = int(request.GET.get("srid", 4326))
return render_to_json_response({
'type': 'FeatureCollection',

View File

@ -5,6 +5,7 @@ from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.db import connection
import json
from django.contrib.gis.measure import D
STOP_CHOICES = ( ('U','Up'),
('D', 'Down'),
@ -53,7 +54,7 @@ RUNTIMES = (
(20, 24)
)
class TrigramSearchManager(models.Manager):
class TrigramSearchManager(models.GeoManager):
def __init__(self, trigram_columns=[]):
super(TrigramSearchManager, self).__init__()
self.trigram_columns = trigram_columns
@ -94,7 +95,8 @@ class Area(models.Model):
'slug': self.slug,
'name': self.name,
'name_mr': self.name_mr,
'display_name': self.display_name
'display_name': self.display_name,
'url': self.get_absolute_url()
#FIXME add alt_names and geometry
}
@ -103,7 +105,20 @@ class Area(models.Model):
def __unicode__(self):
return self.name
#FIXME: ideally this would be done using the polygon of the area, but right now we take a random stop in the area, find all stops within x kms, and then return unique areas for those stops.
@property
def nearby_areas(self, distance=D(km=3)):
stop = self.stop_set.all()[0]
tup = (stop.point, distance,)
qset = Stop.objects.filter(point__distance_lte=tup).values('area').distinct()
area_ids = [val['area'] for val in qset]
return Area.objects.filter(pk__in=area_ids)
@property
def routes_passing(self):
return Route.objects.filter(routedetail__stop__area=self).distinct()
class Road(models.Model):
code = models.IntegerField()#primary_key=True)
slug = models.SlugField(null=True)
@ -158,7 +173,8 @@ class Stop(models.Model):
'name_mr': self.name_mr,
'direction': self.dbdirection,
'routes': ", ".join([r.alias for r in routes]),
'alternative_names': ", ".join([a.name for a in self.alt_names.all().filter(typ='common')])
'alternative_names': ", ".join([a.name for a in self.alt_names.all().filter(typ='common')]),
'url': self.get_absolute_url()
}
def get_geojson(self, srid=4326):
@ -197,6 +213,15 @@ class Stop(models.Model):
self.save()
return self.get_geojson(srid=srid)
@property
def nearby_stops(self, dist=D(km=1)):
tup = (self.point, dist,)
return Stop.objects.filter(point__distance_lte=tup)
@property
def routes(self):
return Route.objects.filter(routedetail__stop=self)
def __unicode__(self):
return self.name
@ -213,7 +238,7 @@ class Stop(models.Model):
has_point.boolean = True
def get_absolute_url(self):
return "/admin/mumbai/stop/%d/" % self.id
return "/stop/%s" % self.slug
class Route(models.Model):
@ -226,6 +251,7 @@ class Route(models.Model):
to_stop = models.ForeignKey(Stop, related_name='routes_to', default=None, null=True, blank=True)
distance = models.DecimalField(max_digits=3, decimal_places=1)
stages = models.IntegerField()
class Meta:
ordering = ['code']
@ -242,9 +268,13 @@ class Route(models.Model):
'code': self.code,
'alias': self.alias,
'slug': self.slug,
'distance': str(self.distance)
'distance': str(self.distance),
'url': self.get_absolute_url()
}
def areas_passed(self):
return Area.objects.filter(stop__routedetail__route=self).distinct()
class RouteDetail(models.Model):
route_code = models.TextField()
route = models.ForeignKey(Route, to_field="code", null=True, blank=True)

View File

@ -38,14 +38,24 @@ def area(request, name):
return render_to_response("area.html", context)
def stop(request, slug):
stop = get_object_or_404(Stop, slug=slug)
context = RequestContext(request, {
'stop': stop
})
return render_to_response("stop.html", context)
def editstops(request):
context = RequestContext(request, {})
return render_to_response("editstops.html", context)
def buseditor(request):
context = RequestContext(request, {})
return render_to_response("buseditor.html", context)
def stats(request):
total_stops_left = Stop.objects.filter(point=None).count()
total_stops = Stop.objects.count()

View File

View File

@ -0,0 +1,32 @@
from django.contrib.gis.db import models
LINE_CHOICES = (
('Western', 'Western'),
('Central', 'Central'),
('Harbour', 'Harbour'),
)
class Train(models.Model):
number = models.CharField(max_length=128)
line = models.CharField(max_length=128, choices=LINE_CHOICES, db_index=True)
stations = models.ManyToManyField("Station", through='TrainStation')
def __unicode__(self):
return self.number
class Station(models.Model):
name = models.CharField(max_length=128)
point = models.PointField(null=True, blank=True)
# line = models.CharField(choices=LINE_CHOICES, db_index=True)
def __unicode__(self):
return self.name
class TrainStation(models.Model):
train = models.ForeignKey(Train)
station = models.ForeignKey(Station)
serial = models.IntegerField()
time = models.TimeField()
# Create your models here.

View File

@ -0,0 +1,52 @@
from pyquery import PyQuery as pq
from models import *
import datetime
BASE_URL = 'http://mumbailifeline.com/'
'''
eg.:
>>>parseURL('http://mumbailifeline.com/timetable.php?sel_route=central&sfrom=Mumbai_CST&sto=Masjid&time1=4:00%20am&time2=11:59%20PM', Central')
'''
def parseURL(url, line):
d = pq(url=url)
table = d('#gradient-style')
trs = table.find('tr')
for i in range(1,len(trs)):
thisTr = trs[i]
td = thisTr.getchildren()[0]
a = td.find('a')
trainNo = a.text.strip()
print "Saving %s ... " % trainNo
trainURL = BASE_URL + a.get('href').strip()
saveTrain(trainURL, trainNo, line)
def saveTrain(url, no, line):
train, created = Train.objects.get_or_create(number=no, line=line)
if not created:
print "Train no %s already exists in db, skipping" % no
return
train.save()
d = pq(url=url)
table = d.find('table')[3]
serial = 0
for tr in table.iterfind('tr'):
children = tr.getchildren()
if len(tr.findall('td')) > 0:
td0 = children[0]
a = td0.find('a')
stationName = a.text.strip()
station, created = Station.objects.get_or_create(name=stationName)
timeString = children[1].find('strong').text
hour = int(timeString.split(":")[0].strip()) - 1
mins = int(timeString.split(":")[1][0:2])
ampm = timeString[-2:]
if ampm == 'pm':
hour = hour + 12
stationTime = datetime.time(hour,mins)
st = TrainStation(train=train, station=station, time=stationTime, serial=serial)
st.save()
serial += 1
print "Saved %s" % no

View File

@ -0,0 +1,16 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)

View File

@ -0,0 +1 @@
# Create your views here.

View File

@ -98,6 +98,7 @@ MIDDLEWARE_CLASSES = (
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware'
)
ROOT_URLCONF = 'chaloBEST.urls'
@ -120,7 +121,9 @@ INSTALLED_APPS = (
# Uncomment the next line to enable admin documentation:
'django.contrib.gis',
'django_extensions',
'debug_toolbar',
'mumbai',
'mumbaitrains',
# 'django.contrib.admindocs',
)

View File

@ -1,11 +1,14 @@
(function($) {
var API_BASE = 'http://chalobest.in/1.0/';
console.log(API_BASE);
//console.log(API_BASE);
var clickedName = 'stops';
var searchQuery = 'None';
var url1 = API_BASE + clickedName + '/' + '?q=';
var url2 = API_BASE + clickedName + '/';
var Features = Backbone.Model.extend({});
var Features = Backbone.Model.extend({
});
var apiCollection = Backbone.Collection.extend({
model: Features,
@ -15,126 +18,146 @@
}
});
var apiView = Backbone.View.extend({
//el: '#sideBar',
events: {
"click a": "stopDetails"
},
//el: '#content',
events: {
"click a": "clicked"
},
initialize: function() {
//this.render();
_.bindAll(this, "render");
this.collection.bind("all", this.render);
//this.render();
_.bindAll(this, "render", "clicked");
this.collection.bind("all", this.render, this.clicked);
//apiView.prototype.initialize.call(this);
},
render: function() {
//$(this.el).html(this.counter = this.collection.length);
console.log(this.collection.length);
//console.log(this.el);
this.collection.each( function(model){
$('#sideBar').append('<li> <a id=\''+model.cid+'\' href="#">' + model.get('properties').official_name + "</a></li>");
//console.log(model.cid);
//console.log(this.collection.length);
//console.log(this.el);
this.collection.each(function(model) {
$('#sideBar').append('<li> <a id=\'' + model.cid + '\' href="#">' + model.get('properties').official_name + "</a></li>");
//console.log(model.cid);
});
});
return this;
},
clicked: function(e) {
//e.preventDefaults();
//var name1 = this.model.get('properties').official_name;
console.log(e);
//alert("you clicked me"+ e.target.innerHTML);
},
return this;
},
clicked: function(e) {
//e.preventDefaults();
//var name1 = this.model.get('properties').official_name;
//console.log(e);
//alert("you clicked me"+ e.target.innerHTML);
events.trigger('stopdetailsEvent', e);
//return this;
},
//close: function() {
// $(this.el).unbind();
// $(this.el).remove();
//}
});
var stopView = Backbone.View.extend({
el: '#content',
initialize: function() {
_.bindAll(this, "stopDetails");
this.collection.bind("stopdetailsEvent", this.stopDetails);
},
stopDetails: function(e) {
var cid = $(e.target).attr('id');
//this.trigger
//console.log(cid);
this.values= this.collection.getByCid(cid);
//this.trigger('new-stage', this.collection.get)
this.stopName = e.target.innerHTML;
//var test = this.collection.where({official_name: this.stopName});
console.log(this.values.get('properties').road);
$('#sLug').append(this.values.get('properties').slug);
$('#rOads').append(this.values.get('properties').road);
$('#rOutes').append(this.values.get('properties').routes);
$('#dIrection').append(this.values.get('properties').direction);
//console.log(e.target);
$('#dIsplayName').append(this.values.get('properties').official_name);
$('#mArathiName').append(this.values.get('properties').name_mr);
$('#aLtName').append(this.values.get('properties').alternative_names);
},
close:function () {
$(this.el).unbind();
$(this.el).remove();
}
//console.log(e);
//alert("you clicked me"+ e.target.innerHTML);
var cid = $(e.target).attr('id');
//this.trigger
//console.log(cid);
this.values = this.collection.getByCid(cid);
//this.trigger('new-stage', this.collection.get)
this.stopName = e.target.innerHTML;
//var test = this.collection.where({official_name: this.stopName});
//console.log(this.values.get('properties').road);
//console.log(this.el);
$(this.el).find('input#sLug').val(this.values.get('properties').slug);
//$('#sLug').attr('id', 'sLug').value(this.values.get('properties').slug);
$(this.el).find('input#rOads').val(this.values.get('properties').road);
$(this.el).find('textarea#rOutes').html(this.values.get('properties').routes);
$(this.el).find('input#dIrection').val(this.values.get('properties').direction);
//console.log(e.target);
$(this.el).find('input#dIsplayName').val(this.values.get('properties').official_name);
$(this.el).find('input#mArathiName').val(this.values.get('properties').name_mr);
$(this.el).find('input#aLtName').val(this.values.get('properties').alternative_names);
},
});
}),
events = new apiCollection();
$(function() {
$(function() {
stopDetailsView = new stopView({
el: $("#content"),
collection: events
});
eventView = new apiView({
el: $("#sideBar"),
//el: $('#slug'),
//el:$('#displayName'),
el: $("#sideBar"),
//el: $('#slug'),
//el:$('#displayName'),
collection: events
});
events.fetch({
success: function() {
console.log(events.length);
//console.log(this.official_name);
//alert();
events.fetch({
success: function() {
console.log(events.length);
//console.log(this.official_name);
//alert();
}
});
});
var Map = Backbone.Model.extend({});
var MapView = Backbone.View.extend({
el: '#mapCol',
initialize: function() {
_.bindAll(this, 'initMap');
this.initMap();
},
initMap: function() {
// Initialize Basic Openlayers;
var center = new OpenLayers.LonLat(8110203.9998955, 2170000.4068373);
//alert("you are here");
map = new OpenLayers.Map(this.el, {
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326")
});
//alert(this.el);
var layers = [];
layers[0] = new OpenLayers.Layer.OSM(); //some more layer will go here
//$(this.el).html(map);
map.addLayers(layers);
map.setCenter(center, 12);
}
});
});
$(function() {
var map_view = new MapView();
//alert("I am here" + this.el);
});
var Map = Backbone.Model.extend({});
var MapView = Backbone.View.extend({
el: '#mapCol',
initialize: function() {
_.bindAll(this, 'initMap');
this.initMap();
},
initMap: function() {
// Initialize Basic Openlayers;
var center = new OpenLayers.LonLat(8110203.9998955, 2170000.4068373);
//alert("you are here");
map = new OpenLayers.Map(this.el, {
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326")
});
//alert(this.el);
var layers = [];
layers[0] = new OpenLayers.Layer.OSM(); //some more layer will go here
//$(this.el).html(map);
map.addLayers(layers);
map.setCenter(center, 12);
}
});
$(function() {
var map_view = new MapView();
//alert("I am here" + this.el);
});
//var router = Backbone.Router.extend({
//routes:{
//})
})(jQuery);
//var router = Backbone.Router.extend({
//routes:{
//})
})(jQuery);

View File

@ -1,33 +1,49 @@
{% extends 'base.html' %}
{% extends 'databrowse_base.html' %}
{% block title %} Area: {{ area.name }} {% endblock %}
{% block head %}
<style type="text/css">
.has_point {
color: #0f0;
}
.no_point {
color: #f00;
}
a:hover {
color: #00f;
}
</style>
{% block api_url %}
var API_BASE = "/1.0/";
var API_URL = API_BASE + 'area/' + "{{ area.slug }}";
{% endblock %}
{% block body %}
<ul id="stopList">
{% for s in stops %}
<li>
<a href="{{ s.get_absolute_url }}" class="{% if s.point %} has_point {% else %} no_point {% endif %}">{{ s.name }}</a>
</li>
<div id="stopListWrapper" class="listColumn">
<h4>Stops in {{ area.display_name }}:</h4>
<input class="listFilterInput" placeholder="Filter..." />
<ul id="stopList">
{% for stop in stops %}
<li>
<a href="{{ stop.get_absolute_url }}">{{ stop.display_name }}</a>
</li>
{% endfor %}
</ul>
</div>
<div id="routeListWrapper" class="listColumn">
<h4>Routes passing through {{ area.display_name }}:</h4>
<input class="listFilterInput" placeholder="Filter..." />
<ul id="routeList">
{% for route in area.routes_passing %}
<li>
<a href="{{ route.get_absolute_url }}">{{ route.alias }}</a>
</li>
{% endfor %}
{% endfor %}
</ul>
</div>
<div id="areaListWrapper" class="listColumn">
<h4>Nearby areas:</h4>
<input class="listFilterInput" placeholder="Filter..." />
<ul id="areaList">
{% for area in area.nearby_areas %}
<li>
<a href="{{ area.get_absolute_url }}">{{ area.display_name }}</a>
</li>
{% endfor %}
</ul>
</ul>
</div>
<div id="map"></div>
{% endblock %}

View File

@ -3,6 +3,35 @@
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="/static/js/jquery-1.7.1.min.js"></script>
<script type="text/javascript">
console.firebug=true;//fix the openlayer problem
</script>
<script type="text/javascript" src="http://openlayers.org/dev/OpenLayers.js"></script>
<style type="text/css">
body,html {
width: 100%;
}
* {
-moz-box-sizing:border-box;
-webkit-box-sizing:border-box;
box-sizing:border-box; /*vendor*/
}
#wrapper {
width: 100%;
}
.listColumn {
width: 15%;
float: left;
}
#map {
float: left;
width: 50%;
}
</style>
<title>ChaloBEST: {% block title %} {% endblock %}</title>
{% block head %}

View File

@ -6,9 +6,10 @@
{% block head %}
<link rel="stylesheet" href="/static/css/styles.css" ></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type = "text/javascript" src="/static/js/underscore-min.js"></script>
<script type ="text/javascript" src="/static/js/backbone-min.js"></script>
<script type="text/javascript" src="/static/js/buseditor.js"></script>
<script type="text/javascript" src="/static/js/thebus.js"></script>
<script type="text/javascript">
console.firebug=true;//fix the openlayer problem
</script>
@ -24,7 +25,7 @@
<input id="search" type="text" placeholder="Search for Areas and Stops">
<input id="stops" type="button" value="Stops">
<input id="areas" type="button" value="Areas">
<input id="routes" type="button" value="Routes">
<input id="login" type="button" value="Login to OSM" style="float: right;">
@ -37,14 +38,16 @@
This BEST Bus stop editor allows you to edit Stops and Areas.
</p>
<p>
<input id="sLug" type="text" placeholder="stop-slug" disabled>
<input id="sLug" type="text" placeholder="stop-slug" value = "" disabled>
<input id="rOads" type="text" placeholder="Road Name" disabled>
<input id="rOutes" type="text" placeholder="Routes" disabled>
<input id="dIrection" type="text" placeholder="Direction (u - up/d - Down)" disabled>
<input id="dIsplayName" type="text" placeholder="Display Name" >
<input id="mArathiName" type="text" placeholder="Marathi Name" >
<input id="aLtName" type="text" placeholder="Alternative Names" >
<!--<input id="rOutes" type="textarea" placeholder="Routes" disabled>-->
<textarea id="rOutes" rows="3" placeholder="Routes" ></textarea>
</p>
<p>
<input id="save" type="button" value="Save">

View File

@ -0,0 +1,114 @@
{% extends 'base.html' %}
{% block title %} {% endblock %}
{% block head %}
<style type="text/css">
.has_point {
color: #0f0;
}
.no_point {
color: #f00;
}
a:hover {
color: #00f;
}
#map {
float: left;
width: 600px;
height: 400px;
}
</style>
<script type="text/javascript">
{% block api_url %}
var API_BASE = "/1.0/";
var API_URL = API_BASE + 'route/' + "{{ route.alias }}";
{% endblock %}
$(document).ready(function() {
// initMap();
var url = API_URL;
$.getJSON(url, {'srid': 3857}, function(obj) {
initMap();
{% block geojson_callback %}
var stopsGeoJSON = obj.stops;
var stops = stopsGeoJSON.features;
var stopsWithGeom = [];
$.each(stops, function(i,v) {
if (!$.isEmptyObject(v.geometry)) {
stopsWithGeom.push(v);
}
});
stopsGeoJSON.features = stopsWithGeom;
//console.log(jsonLayer);
jsonLayer.addFeatures(geojson_format.read(stopsGeoJSON));
var maxExtent = jsonLayer.getDataExtent();
map.zoomToExtent(maxExtent);
{% endblock %}
});
});
function initMap() {
var center = new OpenLayers.LonLat(8110203.9998955, 2170000.4068373);
map = new OpenLayers.Map("map", {
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326")
});
var layers = [];
// layers[0] = new OpenLayers.Layer.OSM();
layers[0] = new OpenLayers.Layer.OSM();
layers[1] = new OpenLayers.Layer.Bing({
name: "Bing Aerial",
type: "Aerial",
key: "AqGpO7N9ioFw3YHoPV3C8crGfJqW5YST4gGKgIOnijrUbitLlgcAS2A0M9SJrUv9",
});
geojson_format = new OpenLayers.Format.GeoJSON();
//
//yes, jsonLayer is global. Yes, I know it's wrong.
jsonLayer = layers[2] = new OpenLayers.Layer.Vector("Bus Stops");
map.addLayers(layers);
jsonLayer.events.on({
'featureselected': onFeatureSelect,
'featureunselected': onFeatureUnselect
});
// Feature selection control
mapControl = new OpenLayers.Control.SelectFeature(jsonLayer, {
clickout: false,
toggle: true
});
//map.addControl(new OpenLayers.Control.ZoomPanel());
map.addControl(mapControl);
mapControl.activate();
// Add a LayerSwitcher since we now have Bing
map.addControl(new OpenLayers.Control.LayerSwitcher());
// Add a permalink that opens the relevant view in OSM.org in a different window
var permalink = new OpenLayers.Control.Permalink({base: "http://www.openstreetmap.org/"});
map.addControl(permalink);
}
function onFeatureSelect(obj) {
window.location = obj.feature.attributes.url;
}
function onFeatureUnselect(obj) {
$.noop();
}
</script>
{% endblock %}
{% block body %}
{% endblock %}

View File

@ -1,33 +1,37 @@
{% extends 'base.html' %}
{% extends 'databrowse_base.html' %}
{% block title %} Route {{ route.alias }} {% endblock %}
{% block head %}
<style type="text/css">
.has_point {
color: #0f0;
}
.no_point {
color: #f00;
}
a:hover {
color: #00f;
}
</style>
{% block api_url %}
var API_BASE = "/1.0/";
var API_URL = API_BASE + 'route/' + "{{ route.alias }}";
{% endblock %}
{% block body %}
<ul id="stopList">
{% for r in routeDetails %}
<li>
<a href="{{ r.stop.get_absolute_url }}" class="{% if r.stop.point %} has_point {% else %} no_point {% endif %}">{{ r.stop.name }}</a> - {{ r.stop.dbdirection }}
</li>
<div id="stopListWrapper" class="listColumn">
<h4>Stops on route:</h4>
<input class="listFilterInput" placeholder="Filter..." />
<ul id="stopList">
{% for r in routeDetails %}
<li>
<a href="{{ r.stop.get_absolute_url }}">{{ r.stop.name }}</a>
</li>
{% endfor %}
</ul>
</div>
{% endfor %}
<div id="areaListWrapper" class="listColumn">
<h4>Areas passed:</h4>
<input class="listFilterInput" placeholder="Filter..." />
<ul id="areaList">
{% for area in route.areas_passed %}
<li>
<a href="{{ area.get_absolute_url }}">{{ area.name }}</a>
</li>
{% endfor %}
</ul>
</ul>
</div>
<div id="map"></div>
{% endblock %}

View File

@ -0,0 +1,56 @@
{% extends 'databrowse_base.html' %}
{% block api_url %}
var API_BASE = "/1.0/";
var API_URL = API_BASE + 'stop/' + "{{ stop.slug }}";
{% endblock %}
{% block geojson_callback %}
jsonLayer.addFeatures(geojson_format.read(obj));
var maxExtent = jsonLayer.getDataExtent();
map.zoomToExtent(maxExtent);
{% endblock %}
{% block body %}
<div id="stopListWrapper" class="listColumn">
<h4>Nearby stops:</h4>
<input class="listFilterInput" placeholder="Filter..." />
<ul id="stopList">
{% for s in stop.nearby_stops %}
<li>
<a href="{{ s.get_absolute_url }}">{{ s.display_name }}</a>
</li>
{% endfor %}
</ul>
</div>
<div id="routeListWrapper" class="listColumn">
<h4>Routes at stop:</h4>
<input class="listFilterInput" placeholder="Filter..." />
<ul id="routeList">
{% for route in stop.routes %}
<li>
<a href="{{ route.get_absolute_url }}">{{ route.alias }}</a>
</li>
{% endfor %}
</ul>
</div>
<div id="areaListWrapper" class="listColumn">
<h4>Nearby areas:</h4>
<input class="listFilterInput" placeholder="Filter..." />
<ul id="areaList">
{% for area in stop.area.nearby_areas %}
<li>
<a href="{{ area.get_absolute_url }}">{{ area.display_name }}</a>
</li>
{% endfor %}
</ul>
</div>
<div id="map"></div>
{% endblock %}

View File

@ -4,6 +4,7 @@ from os.path import join
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
from feeds import RouteFeed
#import ox.django.api.urls
#import mumbai
@ -16,8 +17,12 @@ urlpatterns = patterns('',
url(r'^static/(?P<path>.*)$','django.views.static.serve', {'document_root':'./static'}),
(r'^routes/$', 'mumbai.views.routes'),
(r'^route/(?P<alias>[a-zA-Z0-9\s\-]*?)/$', 'mumbai.views.route'),
(r'^route/(?P<alias>[a-zA-Z0-9\s\-]*?)/georss/$', RouteFeed()),
(r'^areas/$', 'mumbai.views.areas'),
(r'^area/(?P<name>.*?)/$', 'mumbai.views.area'),
# (r'^area/(?P<name>.*?)/georss/$', AreaFeed()),
(r'^stop/(?P<slug>.*?)/$', 'mumbai.views.stop'),
# (r'^stop/(?P<slug>.*?)/georss/$', StopFeed()),
(r'^buseditor/$', 'mumbai.views.buseditor'),
(r'^editstops/$', 'mumbai.views.editstops'),
(r'^1.0/', include('mumbai.apiurls')),

2
fabfile.py vendored
View File

@ -42,5 +42,5 @@ def setup():
def deploy():
bzr_push()
bzr_update()
virtual_run('python %(project_name)s/manage.py syncdb;python %(project_name)s/manage.py migrate'%env)
# virtual_run('python %(project_name)s/manage.py syncdb;python %(project_name)s/manage.py migrate'%env)
run('touch %(project_root)s/wsgi/django.wsgi'%env)

View File

@ -0,0 +1,10 @@
Index: django/contrib/gis/feeds.py
===================================================================
--- django/contrib/gis/feeds.py (revision 17461)
+++ django/contrib/gis/feeds.py (working copy)
@@ -1,4 +1,4 @@
-from django.contrib.syndication.feeds import Feed as BaseFeed, FeedDoesNotExist
+from django.contrib.syndication.views import Feed as BaseFeed
from django.utils.feedgenerator import Atom1Feed, Rss201rev2Feed
class GeoFeedMixin(object):

View File

@ -5,7 +5,10 @@
# -------------------------------------------------------------------- #
# MAIN CONFIGURATION #
# -------------------------------------------------------------------- #
import os
from os.path import join
PROJECT_PATH = os.path.dirname(__file__)
# you should configure your database here before doing any real work.
# see: http://docs.djangoproject.com/en/dev/ref/settings/#databases
@ -16,7 +19,8 @@ DATABASES = {
}
}
MEDIA_ROOT = join(PROJECT_PATH, 'static')
LOCAL_DEVELOPMENT = True
# the rapidsms backend configuration is designed to resemble django's
# database configuration, as a nested dict of (name, configuration).
#
@ -162,6 +166,13 @@ TEMPLATE_LOADERS = (
'django.template.loaders.eggs.Loader'
)
TEMPLATE_DIRS = (
join(PROJECT_PATH, "templates"),
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
# -------------------------------------------------------------------- #
# HERE BE DRAGONS! #
# these settings are pure hackery, and will go away soon #

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 899 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 836 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,12 @@
/* vim:set et ts=4 sw=4 */
jQuery(function() {
/* allow module h2s with the 'collapsed' or 'expanded' classes to
* collapse or expand the module. (see modules.css for more.) */
jQuery("div.module.collapsed h2, div.module.expanded h2").each(function() {
jQuery('<span class="toggler"></span>').click(function() {
jQuery(this).parents("div.module").toggleClass("collapsed").toggleClass("expanded");
}).appendTo(this);
});
});

View File

@ -0,0 +1,29 @@
// vim: noet
jQuery(function() {
/* hide the help text for each module that contains
* it, and add a "show help" button to the toolbar */
jQuery(".module div.help").each(function() {
var help_box = jQuery(this);
help_box.hide();
var module = help_box.parent(".module");
var toolbar = jQuery("div.toolbar", module);
/* create a toolbar, if this module
* does not already have one */
if(!toolbar.length) {
toolbar = jQuery('<div class="toolbar"></div>')
module.append(toolbar);
}
/* add a tool button to show
* the div that we just hid */
toolbar.append(
jQuery('<span class="help">Show Help</span>').click(function(ev) {
help_box.slideToggle();
})
);
})
});

View File

@ -0,0 +1,63 @@
// vim: noet
jQuery(function() {
jQuery(document.body).click(function(e) {
/* ignore this click if it wasn't a link */
var link = $(e.target);
if(link.get(0).tagName.toLowerCase() != "a")
return true;
/* find the paginator that this link lives within. if there
* is none (ie, a link that isn't within a paginator was clicked),
* we're not interested in this event */
var paginator = link.parents("div.paginator");
if(!paginator.length)
return true;
/* as above, for the table that we will reload with the new
* page of data. a paginator shouldn't exist outside of a
* table, but let's not blow up if it does */
var table = paginator.parents("table");
if(!table.length)
return true;
/* this click was within a paginator link.
* we'll take it from here, so kill the event */
e.preventDefault();
/* wat */
jQuery.ajax({
dataType: "html",
url: link.attr("href"),
complete: function(res, status) {
/* if the request was successful... */
if(status == "success" || status == "notmodified") {
/* create a dummy div, and inject the results into it. since the
* page we just requested is the SAME PAGE that we're currently
* viewing, only with a different page of objects, we can find
* the new table the old paginator's DOM id.
* --
* NOTE: this is mostly ripped off from the jQuery.load
* function, which removes SCRIPT tags to avoid a
* permission error in internet exploder */
var new_table =
jQuery("<div />")
.append(res.responseText.replace(
/<script(.|\s)*?\/script>/g, ""))
.find("#" + paginator.attr("id")) // <-- new paginator
.closest("table");
/* replace the current table with the replacement
* from the new page. this will destroy any events
* currently attached, but will leave the rest of
* the page alone */
table.replaceWith(new_table);
}
}
});
});
});

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,146 @@
/* vim:set et ts=4 sw=4 */
form {
border: 1px solid #ddd;
padding: 0 1em;
}
/* recursive models can be displayed as a tree within a <select>, by
* ordering them cleverly and adding their "depth" to the class, to
* bump them to the right, indicating their ancestry */
form option.depth-1 { padding-left: 1em; }
form option.depth-2 { padding-left: 2em; }
form option.depth-3 { padding-left: 3em; }
form option.depth-4 { padding-left: 4em; }
form option.depth-5 { padding-left: 5em; }
form option.depth-6 { padding-left: 6em; }
form option.depth-7 { padding-left: 7em; }
form option.depth-8 { padding-left: 8em; }
/* some options are less interesting than others; like None, or
* Disabled, or Default; so mark them dull */
form option.na {
font-style: italic;
color: #aaa;
}
/* TODO: wtf is this? */
form .no-data {
display: inline-block;
background: #f8f8ff;
text-align: center;
padding: 2em;
color: #aaa;
}
form .no-data a.add {
display: block;
padding-top: 0.625em;
font-size: 80%;
}
/* each field is wrapped in a div.field, which bundles together
* everything related to it. in order:
*
* 1. text label
* 2. list of errors
* 3. the field itself
* 4. help text
*/
form div.field {
margin-top: 1em; }
form div.field label {
margin-bottom: 0.5em;
display: block;
color: #000;
}
/* for fields that need a longer description, help text can be
* added below. similar to django's models.Model.help_text */
form div.field p.help {
max-width: 30em;
font-size: 80%;
color: #aaa;
margin-top: 0;
padding-top: 2px;
margin-left: 0.625em;
padding-left: 0.3125em;
border-left: 0.625em solid #f8f8f8;
}
/* highlight examples (usually examples of text that should
* be sent over SMS, but could be anything) in help text */
form div.field p.help span.example {
font-family: monospace;
background: #f8f8f8;
color: #888;
}
form div.field.error { }
form div.field.error label {
font-weight: bold;
color: #f00;
}
form div.field.error ul.errors {
margin: 0 0 0.5em 0;
padding: 0;
}
form div.field.error ul.errors li {
background: #fff8f8 url("../icons/silk/exclamation.png") no-repeat 5px 50%;
padding: 0.25em 5px 0.25em 25px;
border: 1px solid #fdd;
margin-top: 0.25em;
min-height: 16px;
line-height: 1.4;
display: block;
color: #f44;
}
/* wrap submission and/or action buttons separately */
form div.submit {
background: #f8f8f8 url("../images/table-footer-bg.png") repeat-x 0 0;
border-top: 1px solid #eee;
margin: 1em -1em 0 -1em;
padding: 1em;
}
/* if the browser supports after (+) and :first-child...
*
* 1. do a bit of extra work to replace the usual `1em margin-top` of
* the first div.field with padding-top on the form itself, to remove
* the 1px border between the module h2 and the form
*
* 2. add some fancy rounded corners to the bottom of the form, and do
* some margin jiggery-pokery to ensure that the div.submit doesn't
* overlap and cause jagged edges. */
body:last-child h2 + form {
border-top: 0;
padding: 0;
background-color: #f8f8f8;
-webkit-border-bottom-right-radius: 5px;
-webkit-border-bottom-left-radius: 5px;
-moz-border-radius-bottomright: 5px;
-moz-border-radius-bottomleft: 5px;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
}
h2 + form div.field:first-child {
margin-top: 0; }
body:last-child form > div:first-child {
background-color: #fff;
padding: 1em;
}
body:last-child form div.submit {
background-color: transparent;
margin: 0;
}

View File

@ -0,0 +1,25 @@
/* vim:set et ts=4 sw=4 */
/* make the generated buttons look like tiny little icons. they're
* seldom used, so should stay well out of the way */
input.js-button {
cursor: pointer;
border: 0;
padding: 0;
width: 16px;
height: 16px;
overflow: hidden;
text-indent: -9999px;
background-color: transparent;
background-repeat: no-repeat;
background-position: 50% 50%;
}
/* from http://www.famfamfam.com/lab/icons/silk/
* (licensed under Creative Commons Attribution) */
input.js-button.add { background-image: url("../icons/silk/add.png"); }
input.js-button.del { background-image: url("../icons/silk/delete.png"); }
input.js-button.accept { background-image: url("../icons/silk/accept.png"); }
input.js-button.unaccept { background-image: url("../icons/silk/accept--dull.png"); }
input.js-button.clear { background-image: url("../icons/silk/decline.png"); }
input.js-button.reload { background-image: url("../icons/silk/reload.png"); }

View File

@ -0,0 +1,318 @@
/* vim:set et ts=4 sw=4 */
body {
background: #eee url("../images/body-bg.png");
font: 9pt "Lucida Grande", "Bitstream Vera Sans", Verdana, sans-serif;
line-height: 1;
color: #333;
padding: 0;
margin: 0;
}
a {
text-decoration: none;
color: #33a7d2;
}
a:hover {
text-decoration: underline; }
abbr {
cursor: help; }
p {
line-height: 1.4; }
/* this is not okay. but it is, unfortunately, the least error-prone way
* (that i know) of fixing broken floaty layouts in IE6 */
div.clear-hack {
overflow: hidden;
clear: both;
height: 0;
}
#wrapper {
width: 80em;
background: #fff;
margin: 0.5em auto 0 auto;
/* a little pretty for the 10/dec demo */
-moz-box-shadow: 4px 4px 8px #aaa;
box-shadow: 4px 4px 8px #aaa;
-moz-border-radius-bottomright: 1em;
-moz-border-radius-bottomleft: 1em;
}
/* no scaling for ie6 */
* html #wrapper {
width: 960px; }
/* the header is based roughly upon unicef.org, with rapidsms colors */
#header {
height:122px;
width:960px;
text-align:right;
position: relative;
color: #CCF;
background: #94997e; /* Old browsers */
background: -moz-linear-gradient(top, #94997e 0%, #d2dab3 10%, #d2dab3 80%, #94997e 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#94997e), color-stop(10%,#d2dab3), color-stop(80%,#d2dab3), color-stop(100%,#94997e)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #94997e 0%,#d2dab3 10%,#d2dab3 80%,#94997e 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #94997e 0%,#d2dab3 10%,#d2dab3 80%,#94997e 100%); /* Opera11.10+ */
background: -ms-linear-gradient(top, #94997e 0%,#d2dab3 10%,#d2dab3 80%,#94997e 100%); /* IE10+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#94997e', endColorstr='#94997e',GradientType=0 ); /* IE6-9 */
background: linear-gradient(top, #94997e 0%,#d2dab3 10%,#d2dab3 80%,#94997e 100%); /* W3C */}
}
/* hide the log in/out links in the top right. this doesn't need to
* be especially discoverable; when the user tries to do something
* requiring a login, they should be redirected automatically */
#header #auth {
font-size: 80%;
position: absolute;
line-height: 22px;
margin: 0 10px;
right: 0;
top: 0;;}
#header #auth a {
color: #000;
padding-right:6px;
font-size:80%;
position:relative;
z-index:1;
}
#branding {
padding: 2px 10px;
}
/* align in the middle of the unicef blue stripe of header bg, and
* display logo on the right. TODO: extract the unicef branding */
#branding h1 {
background: url(../images/bessms_header07d.png) no-repeat;
height: 108px;
color: #fff;
margin: 0;
width:960px;
position:absolute;
top:6px;
left:0px;
}
* html #branding h1 {
width: 940px; }
#branding h1 a {
height: 115px;
width: 960px;
display: block;
/*background: url("../images/rapidsms-logo.png") no-repeat 0 50%;*/
/* float the RapidSMS logo, in case any app would like to
* append anything to the light blue (empty) stripe */
float: left;
}
#branding h1 a span {
position: absolute;
left: -9999px;
}
#tabs,
#page-tabs {
position: absolute;
height: 28px;
bottom: 0;
padding: 0;
margin: 0;
}
/* global tabs sit on the right, page-specific tabs sit on the left.
* to draw more attention. TODO: maybe re-think this */
#tabs { right: 0; }
#page-tabs { left: 0; }
#tabs li,
#page-tabs li {
display: block;
float: left;
line-height: 28px;
}
/* 5px spacing between each tab, to match the top gap, since
* we're using pixel-positioned backgrounds there */
#tabs li { margin-right: 5px; }
#page-tabs li { margin-left: 5px; }
#tabs li a,
#page-tabs li a {
color: white;
display: block;
padding: 0 1em;
border-right: 1px solid #FE0000;
border-left: 1px solid #FE0000;
outline: none;
background-color:#CE0000;
text-shadow: 1px 2px 1px #000; }
/* there are unread messages in this tab! TODO: is this just
* for the training app? if so, move it there! */
#tabs li.unread a span {
display: block;
padding-right: 21px;
background: url("../icons/silk/email_open.png") no-repeat 100% 50%;
}
/* always highlight the active (in the navigation sense, not
* the css :active sense) tab, even when it's being hovered
* or focused, since clicking it again is mostly useless */
#tabs li.active a, #page-tabs li.active a,
#tabs li.active a:hover, #page-tabs li.active a:hover,
#tabs li.active a:focus, #page-tabs li.active a:focus {
background: #fff url("../images/tab-bg-active.png") repeat-x;
text-decoration: none;
text-shadow: #000 1px 1px 2px;
color: #000;
/* the same color as the strip in header-bg.png */
border: 1px solid #cef1f5;
border-bottom: 0;
/* nudge the active tab north by one pixel, to line it
* up with the tops of the other tabs */
margin-top: -1px;
}
/* brighten up inactive tabs when hovering or tab-focusing
* with the keyboard (we removed the outline, above) */
#tabs li a:hover, #page-tabs li a:hover,
#tabs li a:focus, #page-tabs li a:focus {
/*background-image: url("../images/tab-bg-hover.png");*/
text-shadow: #000 1px 1px 2px;
text-decoration: none;
}
#breadcrumbs {
color: #ccc;
font-size: 2em;
line-height: 1;
padding: 0.5em;
text-shadow: #eee 2px 2px 2px;
border-bottom: 1px dotted #eee;
}
#breadcrumbs a {
color: #000;
}
.module a
{color:#CE0000;}
#inner {
padding: 1em;
position: relative;
}
/* some parts of the page title are dynamic (or otherwise really
* important), like search terms. highlight them! */
#inner h1 span.highlight {
background: #ffa;
-moz-border-radius: 5px;
border: 2px solid #ff0;
padding: 0 4px;
margin-left: -4px;
}
/* when an app has something really important to say, it can use the
* apps/webui/templates/message.html template to display a huge blob
* of text. this should probably be replaced with flash messages */
#inner div.message {
text-align: center;
padding: 4em 25%;
}
#inner div.message p {
margin: 0 0 0.5em 0;
font-size: 2em;
}
/* some apps (erm, just the querylog, actually) add big triggers to the
* bottom of the page to show or perform some action. */
div.trigger {
font-size: 80%;
text-align: center;
padding: 0.625em;
background: #f8f8f8;
cursor: pointer;
color: #aaa;
}
div.trigger.warn {
background: #fdd;
color: #f00;
}
#footer {
border-top: 1px dotted #eee;
padding: 0.5em;
clear: both;
color: #ccc;
/* reserve space for at two lines of links @ LH=1.4 (for the
* copyright and licensing/download info) */
min-height: 2.8em;
}
/* bump the footer links down a line, to align them with the second
* line of legal junk on the right. reduce the opacity until hover,
* to keep them out of view until they're needed. */
#footer .footer-region {
margin-top: 1.4em;
line-height: 1.4;
opacity: 0.25;
float: left;
}
#footer .footer-region:hover {
opacity: 1; }
#footer .footer-region a { margin-right: 0.5em; }
#footer .footer-region a:last-child { margin-right: 0; }
#footer a
{color:#CE0000;}
#footer p.rights {
text-align: right;
float: right;
margin: 0;
}

View File

@ -0,0 +1,137 @@
/* vim:set et ts=4 sw=4 */
#instruction h2/*THE CSS FOR THE INSTRUCTIONS FROM WIKI*/
{font-weight:bold;}
div.module {
margin-top: 2em;
position: relative;
overflow:auto;
}
div.module div.module {
border: 1px solid #8fbcc9; }
div.module:first-child {
margin-top: 0; }
div.module.collapsed {
overflow-y: hidden;
height: 2.6em;
}
div.module.collapsed h2 {
background-image: url("../images/h2-bg-collapsed.png"); }
div.module.collapsed + div.module {
margin-top: 1px; }
div.module.collapsed h2 span.toggler,
div.module.expanded h2 span.toggler {
background: no-repeat 50% 50%;
text-indent: -9999px;
cursor: pointer;
width: 16px;
height: 2.6em;
overflow: hidden;
position: absolute;
padding: 0 0.5em;
right: 0;
top: 0;
}
div.module.collapsed h2 span.toggler { background-image: url("../icons/silk/section_collapsed--bright.png"); }
div.module.expanded h2 span.toggler { background-image: url("../icons/silk/section_expanded--bright.png"); }
/* module headers are mostly ripped off from django admin, although
* here, we never use <caption>, to keep things simple. (they have
* surprisingly confusing layout rules.) */
div.module h2,
div.module h3 {
margin: 0;
background-repeat: repeat-x;
background-position: 0 100%;
white-space: nowrap;
font-weight: normal;
line-height: 1;
color: #fff;
}
div.module h2 {
background-color: #000;
background-image: url("../images/h2-bg.png");
text-shadow: #000 2px 2px 1px;
padding: 0.3125em;
font-size: 160%;
}
/* less important info can be wrapped in a span to dull it */
div.module h2 span {
text-shadow: none;
font-size: 62.5%;
opacity: 0.8;
}
/* subheaders are almost the same. to dull things, i just made the
* h2-bg image 80% opaque and re-saved it. STILL TODO: ask meghana
* to make this pretty */
div.module h3 {
background-image: url("../images/h3-bg.png");
background-color: #333;
padding: 0.5em;
font-size: 100%;
}
/* modules can (optionally) include help text, to explain how they can
* be used. this is hidden by module-help.js, if it's available, but
* shouldn't be too verbose, in case it isn't */
div.module div.help,
div.module form.search {
border-right: 0.5em solid #ffb;
border-left: 0.5em solid #ffb;
background: #ffc;
padding: 1em;
}
div.module div.help p {
margin: 0; }
/* modules can optionally contain a small "toolbar", which hangs in the
* top right, overlapping the <h2>, if there is one */
div.module div.toolbar {
position: absolute;
top: 0;
right: 0;
line-height: 2.6em;
}
div.module div.toolbar a,
div.module div.toolbar span {
display: block;
float: right;
color: #eee;
margin-right: 0.625em;
padding-left: 21px;
background-repeat: no-repeat;
background-position: 0 50%;
font-size: 80%;
cursor: pointer;
}
/* various common toolbar icons. should be from the famfamfam
* silk set, to fit in with the rest of RapidSMS. this will
* probably grow (and be abstracted) as apps do more things */
div.module div.toolbar .add { background-image: url("../icons/silk/add.png"); }
div.module div.toolbar .help { background-image: url("../icons/silk/help.png"); }
div.module div.toolbar .search { background-image: url("../icons/silk/magnifier.png"); }

View File

@ -0,0 +1,52 @@
/* vim:set et ts=4 sw=4 */
.col-1, .col-2, .col-3, .col-4, .col-5, .col-6 {
margin-left: 1em;
min-height: 1px;
float: left;
}
.two-columns { padding-left: 1em; }
.two-columns .col-1 { margin-left: -1em; }
.two-columns .col-1
{
width: 34%; }
.two-columns .col-2
{
width: 66%;
overflow:auto; }
.three-columns { padding-left: 2em; }
.three-columns .col-1 { margin-left: -2em; }
.three-columns .col-2 {
width: 34%; }
.three-columns .col-1,
.three-columns .col-3 {
width: 33%; }
.four-columns { padding-left: 3em; }
.four-columns .col-1 { margin-left: -3em; }
.four-columns .col-1,
.four-columns .col-2,
.four-columns .col-3,
.four-columns .col-4 {
width: 25%; }
.five-columns { padding-left: 4em; }
.five-columns .col-1 { margin-left: -4em; }
.five-columns .col-1,
.five-columns .col-2,
.five-columns .col-3,
.five-columns .col-4,
.five-columns .col-5 {
width: 20%; }

View File

@ -0,0 +1,237 @@
/* vim:set et ts=4 sw=4 */
table {
border-collapse: collapse;
width:100%;}
col { }
/* highlight sorted columns just a little tiny bit. some people
* won't be able to see it, but the header should contain some
* kind of indication, too. darker colors interfere with the
* grid lines, which are also very light. */
col.sorted {
background: #fcfcff; }
tr{ }
td, th {
padding: 0.5em;
border: 1px solid #ddd;
/* reset the "look" of headers to match regular cells,
* since they can appear anywhere (col or row scope) */
font-weight: normal;
text-align: left;
}
/* if this table is directly following a header, we don't
* need a border top. it'd probably get lost, anyway */
h2 + table thead th {
border-top: none; }
thead th {
background: #e1e1e1 url(../images/table-header-bg.png) repeat-x 100% 0;
color: #888;
}
thead th a,
thead th span.unsortable {
color: #888;
outline: 0;
border-left: 1px solid #f8f8f8;
/* the padding/margin magic overlaps the padding
* of the th, to make it all clickable */
padding: 0.5em;
margin: -0.5em;
/* if a sort marker is within this link, it'll
* need to position absolutely within */
position: relative;
display: block;
}
/* highlight it when the th is hovered, a bit
* like (most) native controls. this is crappy,
* since the background image is sitting on top
* of the th bg, not replacing it */
thead th a:hover {
background-image: url(../images/table-header-bg-highlight.png);
color: #000;
}
thead th.sorted a {
padding-right: 26px;
color: #000;
}
/* unfortunately, an extra element (a span) is
* needed to display the sort marker. all of the
* other backgrounds are already busy. snap it
* to the right/middle of the th */
thead th.sorted a span {
display: block;
position: absolute;
right: 5px;
top: 50%;
width: 16px;
height: 16px;
margin-top: -8px;
overflow: hidden;
text-indent: -9999px;
}
thead th.asc a span { background-image: url("../icons/silk/sort_ascending.png"); }
thead th.desc a span { background-image: url("../icons/silk/sort_descending.png"); }
/* make the grid lighter within the tbody, since it's
* only a visual hint to distinguish the rows + cols */
tbody th, tbody td {
border-color: #f8f8f8; }
/* stripe the rows
tbody tr:nth-child(odd) {
background: #f8f8f8; }*/
/* restore the dark outer borders of the tbody */
tbody tr:first-child th, tbody tr:first-child td { border-top-color: #ddd; }
tbody th:last-child, tbody td:last-child { border-right-color: #ddd; }
tbody tr:last-child th, tbody tr:last-child td { border-bottom-color: #ddd; }
tbody th:first-child, tbody td:first-child { border-left-color: #ddd; }
/* some cells have nothing important to say, (like "none" or
* "never"), but are required none the less. make them dull,
* to highlight the rows which contain real data */
td.na, th.na, td span.na, th span.na {
font-style: italic;
color: #aaa;
}
/* when a row is "active" (eg. it is being viewed, edited, etc), it
* is dimly highlighted. the bgcolor is 10% of #33a7d2 (links)
* applied to the cells (not the row), to mask the stripes */
tr.active td, tr.active th {
background: #ebf6fa url(../images/table-row-bg-active.png) repeat-x 100% 0; }
tr.no-data { }
tr.no-data td {
text-align: center;
background: #f8f8ff no-repeat 50% 50%;
padding: 2em;
color: #aaa;
}
/* since no-data rows usually only have a single <td>, the
* last-child rule above breaks their huge padding. this is
* a hack to restore it. */
body:last-child tr.no-data td:last-child {
padding-right: 2em; }
tr.no-data td a.add {
display: block;
padding-top: 0.625em;
font-size: 80%;
}
/* since there is no data, it might be useful to point the
* user in the right direction. these arrows are very light,
* and displayed behind the "You haven't..." text. */
tr.no-data.look-up td { background-image: url("../images/big-arrows/up.png"); }
tr.no-data.look-right td { background-image: url("../images/big-arrows/right.png"); }
tr.no-data.look-down td { background-image: url("../images/big-arrows/down.png"); }
tr.no-data.look-left td { background-image: url("../images/big-arrows/left.png"); }
/* if there is no data because an error occurred, make the
* table obviously busted by highlighting it in red. */
tr.no-data.error td {
color: #f66;
background-color: #fff8f8;
background-image: url("../images/big-arrows/error.png");
}
tr.depth-1 td.indent { padding-left: 2em; }
tr.depth-2 td.indent { padding-left: 4em; }
tr.depth-3 td.indent { padding-left: 6em; }
tr.depth-4 td.indent { padding-left: 8em; }
tr.depth-5 td.indent { padding-left: 10em; }
tr.depth-6 td.indent { padding-left: 12em; }
tr.depth-7 td.indent { padding-left: 14em; }
tr.depth-8 td.indent { padding-left: 16em; }
tfoot {
background: #f8f8f8 url("../images/table-footer-bg.png") repeat-x 0 0;
font-size: 80%;
}
/* no padding in the footer cell; the links will float and pad
* themselves, so the clickable blocks are easier to hit */
tfoot td {
padding: 0; }
/* footer links are dull, because they're less important
* than the data. TODO: is this totally stupid? (i don't
* really care, it's pretty) */
tfoot a,
tfoot span {
display: block;
float: right;
padding: 0.625em;
color: #aaa;
}
/* footer links can be broken up with spans, which look
* the same, except super dull (for things like disabled
* pagination links */
tfoot span {
color: #ddd; }
/* highlight hover links brighter than usual, since
* they're harder to spot */
tfoot a:hover {
background: #fff; }
/* move all paginator links to the left, to separate from
* additional views and export, which lives on the right */
tfoot .paginator,
tfoot .paginator a,
tfoot .paginator span {
float: left; }
tfoot .paginator a.active {
background: #ddd;
color: #fff;
}
tfoot .paginator .first,
tfoot .paginator .prev,
tfoot .paginator .next,
tfoot .paginator .last {
background-repeat: no-repeat;
background-position: 0 50%;
text-indent: -9999px;
overflow: hidden;
padding-right: 0;
padding-left: 0;
width: 16px;
}
/* links look something like:
* << < 1 2 3 4 > >> */
tfoot .paginator .first { background-image: url("../icons/silk/resultset_first.png"); }
tfoot .paginator .prev { background-image: url("../icons/silk/resultset_previous.png"); }
tfoot .paginator .next { background-image: url("../icons/silk/resultset_next.png"); }
tfoot .paginator .last { background-image: url("../icons/silk/resultset_last.png"); }
/* when a link is disabled, move the background image
* over to reveal the transparent sprite to the left */
tfoot .paginator span.na {
background-position: -16px 50%; }
/* the ... to indicate that page links have been hidden
* (because there were too many) should be quite dull */
tfoot .paginator span.elipsis {
letter-spacing: 1px;
color: #888;
}

195
smsBEST/templates/dashboard.html Executable file
View File

@ -0,0 +1,195 @@
{% extends "layout.html" %}
{% block title %}Dashboard{% endblock %}
{% block stylesheets %}
{{ block.super }}
<style type="text/css">
#inner {
margin: 0px 25%;
}
div.module div {
border: 1px solid #ddd;
border-top-color: #636363;
margin-top: -1px;
}
div.module p {
padding-left: 1em;
padding-right: 1em;
}
code, pre {
background: #ffe;
}
pre {
padding: 1em;
margin: 0;
}
/* Start Our CSS */
#languageBtns {
position:absolute;
top:32px;
left:-205px;
}
#languageBtns span {
display:block;
font-size:18px;
cursor:pointer;
line-height:28px;
}
#selectedLanguage {
color:#CE0000;}
#instruction {
border:2px solid #ce0000;}
#instruction h2 /*THE CSS FOR THE INSTRUCTIONS FROM WIKI*/
{font-size:16px;
font-weight:normal;
margin-bottom:16px;
background: #ce0000; /* Old browsers */
background: -moz-linear-gradient(top, #ce0000 0%, #ce0000 44%, #ff4400 88%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ce0000), color-stop(44%,#ce0000), color-stop(88%,#ff4400)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #ce0000 0%,#ce0000 44%,#ff4400 88%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ce0000 0%,#ce0000 44%,#ff4400 88%); /* Opera11.10+ */
background: -ms-linear-gradient(top, #ce0000 0%,#ce0000 44%,#ff4400 88%); /* IE10+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ce0000', endColorstr='#ff4400',GradientType=0 ); /* IE6-9 */
background: linear-gradient(top, #ce0000 0%,#ce0000 44%,#ff4400 88%); /* W3C */
text-shadow: #000 1px 2px 1px;}
#instruction ul
{list-style:none;
margin-bottom:16px;
margin-right:20px;
font-size:16px;}
#instruction ul li
{margin-bottom:8px;}
#instruction p
{margin-bottom:8px;}
code {
font-weight:bold;
font-size:14px;
margin-left:17px;}
number {
font-weight:bold;
font-family:monospace;
font-size:14px;}
#footer p {
text-align:center;
color:#000;}
/* END Our CSS */
</style>
{% endblock %}
{% block javascripts %}
{{ block.super }}
<script type="text/javascript">
$(function() {
$('#languageBtns span').click(function() {
var langString = '.english, .marathi, .hindi, .gujarati';
$(langString).hide();
var lang = $(this).attr("data-lang");
$('.' + lang).show();
});
$('span[data-lang=english]').click();
});
</script>
{% endblock %}
{% block content %}
<div id="languageBtns">
<span data-lang="english">English</span> <span data-lang="marathi">मराठी</span> <span data-lang="hindi">हिन्दी</span> <span data-lang="gujarati">ગુજરાતી</span>
</div>
<div id="instruction" class="module">
<!-- <h1> Short Instructions</h1> -->
<h2> Welcome!</h2>
<ul><li class="english"> With this service, you can send and receive simple queries by SMS about bus stops, bus numbers and routing on BEST.<br><br>Send SMS to <number>9619524420</number> and you will receive a return SMS with the information you need.
</li><li class="marathi"> चलोबेस्टद्वारे आपल्याला वेगवेगळ्या बेस्ट बसस्थानकांची, बसक्रमांकाची तसेच बसमार्गांची माहिती SMS ने मिळू शकते. <br><br>आपला SMS <number>९६१९५२४४२०</number> या क्रमांकावर पाठवावा, आम्ही आपल्याला पाहिजे असलेली माहिती SMS द्वारे परत पाठवू.
</li><li class="hindi"> इस सुविधा से आप साधारण SMS के ज़रिये बेस्ट बस स्टॉप, बस क्रमांक और मार्गों की जानकारी पा सकते हैं| <br><br><number>9619524420</number> ईस नंबर पर SMS भेजनेपर आपको जवाबी SMS से जरुरी जानकारी मिलेगी।
</li><li class="gujarati"> આ સુવિધા થકી એક સામાન્ય SMS કરીને આપ કોઈ પણ બસ સ્ટોપ, નંબર અથવા માર્ગ ની માહિતી મેળવી શકો છો.<br><br> <number>9619524420</number> પર SMS કરવાથી તમને વળતા SMS દ્વારા પૂછાવેલી માહિતી મોકલવામાં આવશે.
</li></ul>
<h2> How-To Use </h2>
<ul><li class="english"> To see the route of any bus, send an SMS with "BUS " and any bus number. Example:
</li><li class="marathi"> कोणत्याही बेस्ट बसमार्गाची माहिती करून घेण्यासाठी, "BUS" व त्यानंतर बसक्रमांक लिहून वरील क्रमांकावर SMS पाठवावा। उदाहरणार्थ:
</li><li class="hindi"> किसी भी बस मार्ग के सभी स्टॉप जानने के लिए BUS और ऊसके बाद बस क्रमांक उपर दिए हुए नंबर पर SMS करें। उदहारण:
</li><li class="gujarati"> કોઈ પણ નંબર ની બસ નું માર્ગ જાણવા માટે BUS પછી એનું નંબર SMS કરો. દાખલો:
</li></ul>
<p><span>&#9656; </span><code> BUS 21</code>
</p>
<ul><li class="english"> To see all the bus routes served by a stop, send an SMS with "STOP " and the name of any bus stop or area. Example:
</li><li class="marathi"> एखाद्या बसस्थानकावर येणाऱ्या सर्व बसेसची माहिती मिळवण्यासाठी, "STOP" व त्यानंतर बसस्थानकाचे नाव किंवा विभागाचे नाव लिहून वरील क्रमांकावर SMS पाठवावा| उदाहरणार्थ:
</li><li class="hindi"> कोई भी स्टॉप पर रुकनेवाली सारी बसों की जानकारी के लिए STOP एवं उसका नाम या इलाके का नाम SMS करें| उदहारण:
</li><li class="gujarati"> કોઈ પણ સ્ટોપ પર પસાર થતી બસો ની માહિતી માટે STOP પછી બસ સ્ટોપ નું નામ અથવા વિસ્તાર નું નામ SMS કરો. દાખલો:
</li></ul>
<p><span>&#9656; </span><code>STOP MAHIM</code>
</p>
<ul><li class="english"> To find out how to go from one stop to another, send an SMS with "FROM " any stop name "TO " any stop name. Example:
</li><li class="marathi"> एका स्थानकावरून दुस-या स्थानकापर्यंत कोणत्या बसने जावे हे माहित करण्यासाठी, "FROM" (कुठून) "TO" (कुठपर्यंत) लिहून वरील क्रमांकावर SMS पाठवावा| उदाहरणार्थ:
</li><li class="hindi"> कोई भी स्टॉप से अन्य स्टॉप तक जानेवाली बसों की जानकारी के किये FROM एवं स्टॉप का नाम और TO एवं स्टॉप का नाम SMS करें| उदहारण:
</li><li class="gujarati"> * કોઈ પણ બસ સ્ટોપ થી બીજે જતી બસો ના નંબર જાણવા માટે "FROM" પછી સ્ટોપ નું નામ અને "TO" પછી બીજા સ્ટોપ નું નામ SMS કરો. દાખલો:
</li></ul>
<p><span>&#9656; </span><code>FROM COLABA TO MAHIM</code>
</p>
<h2> Feedback </span></h2>
<ul><li class="english"> ChaloBEST is still being tested, we plan to release a public beta soon. We welcome your feedback and comments via email to info@chalobest.in
</li><li class="marathi"> चलोबेस्टची सध्या तपासणी सुरु आहे. आम्ही लवकरच ही लोकसेवा पूर्णपणे सुरू करणार आहोत. चलोबेस्टविषयी आपल्या प्रतिक्रिया आणि विचार कळविल्यास आम्हाला आंनद होईल. आपण आम्हाला इमेलद्वारे info@chalobest.in या पत्त्यावर संपर्क साधु शकता.
</li><li class="hindi"> चलोबेस्ट सेवा की फिलहाल जाँच शुरु है। जल्दही हम ये सेवा पुरी तरह से शुरु करेंगे। ईस सेवा के बारे में आपके विचार और प्रतिक्रिया जानने पर हमें खुशी होगी। आप हमें info@chalobest.in ईस ईमेल पर अपनी राय दे सकते है।
</li><li class="gujarati"> ચલોબેસ્ટ હાલ પ્રાયોગિક ધોરણે દાખલ કરેલ છે. જાહેર ઉપયોગ માટે ટૂંક સમય માં એનું વિમોચન થશે. info@chalobest.in પર ઈ-મેઈલ દ્વારા તમારી પ્રતિક્રિયા તેમજ સૂચન નું આવકાર છે.
</li></ul>
</div>
<!--
<div class="module">
<h2>Installation Successful!</h2>
<div>
<p>
See <a href="http://docs.rapidsms.org/Installation">the RapidSMS wiki</a>
to learn how to install community apps or create your own.
</p>
<p>
To replace this message with a different view, add a pattern in app's
<code>urls</code> module with the pattern: <code>r'^$</code>.
</p>
<p>
For example:
</p>
<pre>from django.conf.urls.defaults import *
from myproject.myapp import views
urlpatterns = patterns('',
url(r'^$', views.dashboard)
)</pre>
</div>
</div>
-->
{% endblock %}
{% block footer %}
<div id="footer">
<p><a href="http://chalobest.in">ChaloBEST</a> is a collaboration of <a href="http://mesn.org">Mumbai Environmental Social Network (MESN)</a>, <a href="http://sparcsys.com">SPARC Systems</a>, <a href="http://camputer.org">CAMP</a>, and <br> <a href="http://www.hbcse.tifr.res.in">Homi Bhabha Centre for Science Education, TIFR</a>, with a little help from <a href="http://bestundertaking.com">our friends</a>.</p>
</div>
{% endblock %}

89
smsBEST/templates/layout.html Executable file
View File

@ -0,0 +1,89 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
{% load region_tags %}
{% load tabs_tags %}
{% load i18n %}
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>{% block title %}RapidSMS{% endblock %}</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
{% block stylesheets %}
<link type="text/css" rel="stylesheet" href="{{ MEDIA_URL }}rapidsms/stylesheets/layout.css" />
<link type="text/css" rel="stylesheet" href="{{ MEDIA_URL }}rapidsms/stylesheets/splits.css" />
<link type="text/css" rel="stylesheet" href="{{ MEDIA_URL }}rapidsms/stylesheets/modules.css" />
<link type="text/css" rel="stylesheet" href="{{ MEDIA_URL }}rapidsms/stylesheets/tables.css" />
<link type="text/css" rel="stylesheet" href="{{ MEDIA_URL }}rapidsms/stylesheets/forms.css" />
<link type="text/css" rel="stylesheet" href="{{ MEDIA_URL }}rapidsms/stylesheets/icons.css" />
{% endblock %}
{% block javascripts %}
<script type="text/javascript" src="{{ MEDIA_URL }}rapidsms/javascripts/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}rapidsms/javascripts/collapse.js"></script>
{% endblock %}
</head>
<body>
<div id="wrapper">
{% region "top" %}
{% block header %}
<div id="header">
<div id="branding">
<h1>
<a title="{% trans "Return to the Dashboard" %}" href="{% url rapidsms-dashboard %}">
<span>RapidSMS</span>
</a>
</h1>
</div>
{% block auth %}
<div id="auth">{% if user.is_authenticated %}
<a href="{% url rapidsms-logout %}">{% trans "Log out" %} {{ user.username }}</a>{% else %}
<a href="{% url rapidsms-login %}">{% trans "Log in" %}</a>{% endif %}
</div>
{% endblock %}
{% get_tabs as tabs %}
<ul id="tabs">{% for tab in tabs %}
<li class="app-{{ tab.name }}{% if tab.is_active %} active{% endif %}">
<a href="{{ tab.url }}"><span>{{ tab.caption }}</span></a>
</li>{% endfor %}
</ul>
{% block page_tabs %}
{% endblock %}
</div>
{% endblock %}
{% block breadcrumbs %}{% if breadcrumbs %}
<div id="breadcrumbs">{% for caption, url in breadcrumbs %}
<a href="{{ url }}">{{ caption }}</a>{% if not forloop.last %}
<span>&raquo;</span>{% endif %}{% endfor %}
</div>{% endif %}
{% endblock %}
<div id="inner">
{% block content %}{% endblock %}
</div>
{% block footer %}
<div id="footer">
<p class="rights">
Copyright &copy; 2008 &#8211; 2010
<a href="http://unicef.org">UNICEF</a> et al.<br />
<a href="http://github.com/rapidsms/rapidsms">RapidSMS</a> is available under
<a href="http://github.com/rapidsms/rapidsms/raw/master/LICENSE">the BSD license</a>.
</p>
{% region "footer" %}
</div>
{% endblock %}
{% region "bottom" %}
</div>
</body>
</html>

View File

@ -1,6 +1,8 @@
from django.conf.urls.defaults import *
from django.conf import settings
from django.contrib import admin
from os.path import join
admin.autodiscover()
@ -28,10 +30,10 @@ urlpatterns = patterns('',
(r'^scheduler/', include('rapidsms.contrib.scheduler.urls')),
)
if settings.DEBUG:
urlpatterns += patterns('',
# helper URLs file that automatically serves the 'static' folder in
# INSTALLED_APPS via the Django static media server (NOT for use in
# production)
(r'^', include('rapidsms.urls.static_media')),
)
if settings.LOCAL_DEVELOPMENT:
#
urlpatterns += patterns('',
#
(r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': join(settings.PROJECT_PATH, "static")}),
#
)