Ticket #5472: olwidget_admin.diff
File olwidget_admin.diff, 79.3 KB (added by , 15 years ago) |
---|
-
contrib/gis/admin/options.py
1 from django.conf import settings 1 import copy 2 3 from django.utils.encoding import force_unicode 2 4 from django.contrib.admin import ModelAdmin 3 from django.contrib.gis.admin.widgets import OpenLayersWidget4 from django.contrib.gis.gdal import OGRGeomType5 5 from django.contrib.gis.db import models 6 from django.contrib.gis.widgets import EditableMap, InfoMap 6 7 7 8 class GeoModelAdmin(ModelAdmin): 8 """ 9 The administration options class for Geographic models. Map settings 10 may be overloaded from their defaults to create custom maps. 11 """ 12 # The default map settings that may be overloaded -- still subject 13 # to API changes. 14 default_lon = 0 15 default_lat = 0 16 default_zoom = 4 17 display_wkt = False 18 display_srid = False 19 extra_js = [] 20 num_zoom = 18 21 max_zoom = False 22 min_zoom = False 23 units = False 24 max_resolution = False 25 max_extent = False 26 modifiable = True 27 mouse_position = True 28 scale_text = True 29 layerswitcher = True 30 scrollable = True 31 map_width = 600 32 map_height = 400 33 map_srid = 4326 34 map_template = 'gis/admin/openlayers.html' 35 openlayers_url = 'http://openlayers.org/api/2.8/OpenLayers.js' 36 point_zoom = num_zoom - 6 37 wms_url = 'http://labs.metacarta.com/wms/vmap0' 38 wms_layer = 'basic' 39 wms_name = 'OpenLayers WMS' 40 debug = False 41 widget = OpenLayersWidget 9 options = {} 10 list_map = None 11 list_map_options = {} 12 change_list_template = "gis/admin/olwidget_change_list.html" 42 13 43 def _media(self):44 "Injects OpenLayers JavaScript into the admin."45 media = super(GeoModelAdmin, self)._media()46 media.add_js([self.openlayers_url])47 media.add_js(self.extra_js)48 return media49 media = property(_media)50 51 14 def formfield_for_dbfield(self, db_field, **kwargs): 52 15 """ 53 Overloaded from ModelAdmin so that an OpenLayersWidget is used 54 for viewing/editing GeometryFields. 16 Overloaded from ModelAdmin to use our map widget. 55 17 """ 56 18 if isinstance(db_field, models.GeometryField): 57 19 request = kwargs.pop('request', None) 58 # Setting the widget with the newly defined widget.59 20 kwargs['widget'] = self.get_map_widget(db_field) 60 21 return db_field.formfield(**kwargs) 61 22 else: 62 return super(GeoModelAdmin, self).formfield_for_dbfield(db_field, **kwargs) 23 return super(GeoModelAdmin, self).formfield_for_dbfield( 24 db_field, **kwargs) 63 25 64 26 def get_map_widget(self, db_field): 65 27 """ 66 Returns a subclass of the OpenLayersWidget (or whatever was specified 67 in the `widget` attribute) using the settings from the attributes set 68 in this class. 28 Returns an EditableMap subclass with options appropriate for the given 29 field. 69 30 """ 70 is_collection = db_field.geom_type in ('MULTIPOINT', 'MULTILINESTRING', 'MULTIPOLYGON', 'GEOMETRYCOLLECTION')71 if is_collection:72 if db_field.geom_type == 'GEOMETRYCOLLECTION': collection_type = 'Any'73 else: collection_type = OGRGeomType(db_field.geom_type.replace('MULTI', ''))31 is_collection = db_field.geom_type in ('MULTIPOINT', 'MULTILINESTRING', 32 'MULTIPOLYGON', 'GEOMETRYCOLLECTION') 33 if db_field.geom_type == 'GEOMETRYCOLLECTION': 34 geometry = ['polygon', 'point', 'linestring'] 74 35 else: 75 collection_type = 'None' 36 if db_field.geom_type in ('MULTIPOINT', 'POINT'): 37 geometry = 'point' 38 elif db_field.geom_type in ('POLYGON', 'MULTIPOLYGON'): 39 geometry = 'polygon' 40 elif db_field.geom_type in ('LINESTRING', 'MULTILINESTRING'): 41 geometry = 'linestring' 42 else: 43 # fallback: allow all types. 44 geometry = ['polygon', 'point', 'linestring'] 76 45 77 class OLMap(self.widget): 78 template = self.map_template 79 geom_type = db_field.geom_type 80 params = {'default_lon' : self.default_lon, 81 'default_lat' : self.default_lat, 82 'default_zoom' : self.default_zoom, 83 'display_wkt' : self.debug or self.display_wkt, 84 'geom_type' : OGRGeomType(db_field.geom_type), 85 'field_name' : db_field.name, 86 'is_collection' : is_collection, 87 'scrollable' : self.scrollable, 88 'layerswitcher' : self.layerswitcher, 89 'collection_type' : collection_type, 90 'is_linestring' : db_field.geom_type in ('LINESTRING', 'MULTILINESTRING'), 91 'is_polygon' : db_field.geom_type in ('POLYGON', 'MULTIPOLYGON'), 92 'is_point' : db_field.geom_type in ('POINT', 'MULTIPOINT'), 93 'num_zoom' : self.num_zoom, 94 'max_zoom' : self.max_zoom, 95 'min_zoom' : self.min_zoom, 96 'units' : self.units, #likely shoud get from object 97 'max_resolution' : self.max_resolution, 98 'max_extent' : self.max_extent, 99 'modifiable' : self.modifiable, 100 'mouse_position' : self.mouse_position, 101 'scale_text' : self.scale_text, 102 'map_width' : self.map_width, 103 'map_height' : self.map_height, 104 'point_zoom' : self.point_zoom, 105 'srid' : self.map_srid, 106 'display_srid' : self.display_srid, 107 'wms_url' : self.wms_url, 108 'wms_layer' : self.wms_layer, 109 'wms_name' : self.wms_name, 110 'debug' : self.debug, 111 } 112 return OLMap 46 options = copy.deepcopy(self.options) 47 options.update({ 48 'geometry': geometry, 49 'isCollection': is_collection, 50 'name': db_field.name, 51 }) 52 class Widget(EditableMap): 53 def __init__(self, *args, **kwargs): 54 kwargs['options'] = options 55 # OL rendering bug with floats requires this. 56 kwargs['template'] = "gis/admin/admin_editable_map.html" 57 super(Widget, self).__init__(*args, **kwargs) 113 58 114 # Using the Beta OSM in the admin requires the following: 115 # (1) The Google Maps Mercator projection needs to be added 116 # to your `spatial_ref_sys` table. You'll need at least GDAL 1.5: 117 # >>> from django.contrib.gis.gdal import SpatialReference 118 # >>> from django.contrib.gis.utils import add_postgis_srs 119 # >>> add_postgis_srs(SpatialReference(900913)) # Adding the Google Projection 120 from django.contrib.gis import gdal 121 if gdal.HAS_GDAL: 122 class OSMGeoAdmin(GeoModelAdmin): 123 map_template = 'gis/admin/osm.html' 124 extra_js = ['http://openstreetmap.org/openlayers/OpenStreetMap.js'] 125 num_zoom = 20 126 map_srid = 900913 127 max_extent = '-20037508,-20037508,20037508,20037508' 128 max_resolution = 156543.0339 129 point_zoom = num_zoom - 6 130 units = 'm' 59 return Widget 60 61 def get_changelist_map(self, cl): 62 """ 63 Display a map in the admin changelist, with info popups 64 """ 65 if self.list_map: 66 info = [] 67 for obj in cl.get_query_set(): 68 info.append(( 69 [getattr(obj, field) for field in self.list_map], 70 "<a href='%s'>%s</a>" % ( 71 cl.url_for_result(obj), 72 force_unicode(obj) 73 ) 74 )) 75 76 return InfoMap(info, options=self.list_map_options) 77 return None 78 79 def get_changelist_context(self, request): 80 """ 81 Add changelist map, if any, to the context. 82 """ 83 context = super(GeoModelAdmin, self).get_changelist_context(request) 84 map = self.get_changelist_map(context['cl']) 85 if map: 86 context['media'] += map.media 87 context['map'] = map 88 return context 89 -
contrib/gis/admin/__init__.py
1 1 # Getting the normal admin routines, classes, and `site` instance. 2 2 from django.contrib.admin import autodiscover, site, AdminSite, ModelAdmin, StackedInline, TabularInline, HORIZONTAL, VERTICAL 3 3 4 # Geographic admin options classes and widgets.4 # Geographic admin options classes 5 5 from django.contrib.gis.admin.options import GeoModelAdmin 6 from django.contrib.gis.admin.widgets import OpenLayersWidget7 8 try:9 from django.contrib.gis.admin.options import OSMGeoAdmin10 HAS_OSM = True11 except ImportError:12 HAS_OSM = False -
contrib/gis/admin/widgets.py
1 from django.conf import settings2 from django.contrib.gis.gdal import OGRException3 from django.contrib.gis.geos import GEOSGeometry, GEOSException4 from django.forms.widgets import Textarea5 from django.template import loader, Context6 from django.utils import translation7 8 # Creating a template context that contains Django settings9 # values needed by admin map templates.10 geo_context = Context({'ADMIN_MEDIA_PREFIX' : settings.ADMIN_MEDIA_PREFIX,11 'LANGUAGE_BIDI' : translation.get_language_bidi(),12 })13 14 class OpenLayersWidget(Textarea):15 """16 Renders an OpenLayers map using the WKT of the geometry.17 """18 def render(self, name, value, attrs=None):19 # Update the template parameters with any attributes passed in.20 if attrs: self.params.update(attrs)21 22 # Defaulting the WKT value to a blank string -- this23 # will be tested in the JavaScript and the appropriate24 # interface will be constructed.25 self.params['wkt'] = ''26 27 # If a string reaches here (via a validation error on another28 # field) then just reconstruct the Geometry.29 if isinstance(value, basestring):30 try:31 value = GEOSGeometry(value)32 except (GEOSException, ValueError):33 value = None34 35 if value and value.geom_type.upper() != self.geom_type:36 value = None37 38 # Constructing the dictionary of the map options.39 self.params['map_options'] = self.map_options()40 41 # Constructing the JavaScript module name using the name of42 # the GeometryField (passed in via the `attrs` keyword).43 # Use the 'name' attr for the field name (rather than 'field')44 self.params['name'] = name45 # note: we must switch out dashes for underscores since js46 # functions are created using the module variable47 js_safe_name = self.params['name'].replace('-','_')48 self.params['module'] = 'geodjango_%s' % js_safe_name49 50 if value:51 # Transforming the geometry to the projection used on the52 # OpenLayers map.53 srid = self.params['srid']54 if value.srid != srid:55 try:56 ogr = value.ogr57 ogr.transform(srid)58 wkt = ogr.wkt59 except OGRException:60 wkt = ''61 else:62 wkt = value.wkt63 64 # Setting the parameter WKT with that of the transformed65 # geometry.66 self.params['wkt'] = wkt67 68 return loader.render_to_string(self.template, self.params,69 context_instance=geo_context)70 71 def map_options(self):72 "Builds the map options hash for the OpenLayers template."73 74 # JavaScript construction utilities for the Bounds and Projection.75 def ol_bounds(extent):76 return 'new OpenLayers.Bounds(%s)' % str(extent)77 def ol_projection(srid):78 return 'new OpenLayers.Projection("EPSG:%s")' % srid79 80 # An array of the parameter name, the name of their OpenLayers81 # counterpart, and the type of variable they are.82 map_types = [('srid', 'projection', 'srid'),83 ('display_srid', 'displayProjection', 'srid'),84 ('units', 'units', str),85 ('max_resolution', 'maxResolution', float),86 ('max_extent', 'maxExtent', 'bounds'),87 ('num_zoom', 'numZoomLevels', int),88 ('max_zoom', 'maxZoomLevels', int),89 ('min_zoom', 'minZoomLevel', int),90 ]91 92 # Building the map options hash.93 map_options = {}94 for param_name, js_name, option_type in map_types:95 if self.params.get(param_name, False):96 if option_type == 'srid':97 value = ol_projection(self.params[param_name])98 elif option_type == 'bounds':99 value = ol_bounds(self.params[param_name])100 elif option_type in (float, int):101 value = self.params[param_name]102 elif option_type in (str,):103 value = '"%s"' % self.params[param_name]104 else:105 raise TypeError106 map_options[js_name] = value107 return map_options -
contrib/gis/widgets.py
1 from os.path import join 2 3 from django.contrib.gis.gdal import OGRException 4 from django.contrib.gis.geos import GEOSGeometry, GEOSException 5 from django.forms.widgets import Textarea 6 from django.template.loader import render_to_string 7 from django.utils import simplejson 8 from django.conf import settings 9 from django import forms 10 11 try: 12 GOOGLE_API_KEY = settings.GOOGLE_API_KEY 13 except AttributeError: 14 GOOGLE_API_KEY = "" 15 16 try: 17 YAHOO_APP_ID = settings.YAHOO_APP_ID 18 except AttributeError: 19 YAHOO_APP_ID = "" 20 21 22 GOOGLE_API = "http://maps.google.com/maps?file=api&v=2&key=%s" % GOOGLE_API_KEY 23 YAHOO_API = "http://api.maps.yahoo.com/ajaxymap?v=3.0&appid=%s" % YAHOO_APP_ID 24 MS_VE_API = "http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.1" 25 OSM_API = "http://openstreetmap.org/openlayers/OpenStreetMap.js" 26 OL_API = "http://openlayers.org/api/2.8/OpenLayers.js" 27 OLWIDGET_JS = join(settings.ADMIN_MEDIA_PREFIX, "js/olwidget.js") 28 OLWIDGET_CSS = join(settings.ADMIN_MEDIA_PREFIX, "css/olwidget.css") 29 30 DEFAULT_PROJ = "4326" 31 32 PEP8_OPTIONS_TRANSLATION = { 33 # map constructor options 34 'map_options': 'mapOptions', 35 'max_resolution': 'maxResolution', 36 'min_resolution': 'minResolution', 37 'max_extent': 'maxExtent', 38 'min_extent': 'minExtent', 39 'min_scale': 'minScale', 40 'max_scale': 'maxScale', 41 'display_projection': 'displayProjection', 42 'num_zoom_levels': 'numZoomLevels', 43 # olwidget options 44 'map_div_class': 'mapDivClass', 45 'map_div_style': 'mapDivStyle', 46 'default_lon': 'defaultLon', 47 'default_lat': 'defaultLat', 48 'default_zoom': 'defaultZoom', 49 'hide_textarea': 'hideTextarea', 50 'is_collection': 'isCollection', 51 'popups_outside': 'popupsOutside', 52 'popup_direction': 'popupDirection', 53 'popup_pagination_separator': 'popupPaginationSeparator', 54 'cluster_display': 'clusterDisplay', 55 'cluster_style': 'clusterStyle', 56 'font_size': 'fontSize', 57 'font_family': 'fontFamily', 58 'font_color': 'fontColor', 59 # overlay style options 60 'overlay_style': 'overlayStyle', 61 'fill_color': 'fillColor', 62 'fill_opacity': 'fillOpacity', 63 'stroke_color': 'strokeColor', 64 'stroke_width': 'strokeWidth', 65 'stroke_linecap': 'strokeLinecap', 66 'stroke_dash_style': 'strokeDashstyle', 67 'point_radius': 'pointRadius', 68 'external_graphic': 'externalGraphic', 69 'graphic_height': 'graphicHeight', 70 'graphic_x_offset': 'graphicXOffset', 71 'graphic_y_offset': 'graphicYOffset', 72 'graphic_opacity': 'graphicOpacity', 73 'graphic_name': 'graphicName', 74 } 75 76 def translate_options(options): 77 translated = {} 78 for key, value in options.iteritems(): 79 new_key = PEP8_OPTIONS_TRANSLATION.get(key, key) 80 # recurse 81 if isinstance(value, dict): 82 translated[new_key] = translate_options(value) 83 else: 84 translated[new_key] = value 85 return translated 86 87 class MapMixin(object): 88 def set_options(self, options, template): 89 self.options = options or {} 90 # Though this is the olwidget.js default, it must be explicitly set so 91 # form.media knows to include osm. 92 self.options['layers'] = self.options.get('layers', ['osm.mapnik']) 93 self.template = template or self.default_template 94 95 def _media(self): 96 js = set() 97 # collect scripts necessary for various layers 98 for layer in self.options['layers']: 99 if layer.startswith("osm."): 100 js.add(OSM_API) 101 elif layer.startswith("google."): 102 js.add(GOOGLE_API) 103 elif layer.startswith("yahoo."): 104 js.add(YAHOO_API) 105 elif layer.startswith("ve."): 106 js.add(MS_VE_API) 107 js = [OL_API, OLWIDGET_JS] + list(js) 108 return forms.Media(css={'all': (OLWIDGET_CSS,)}, js=js) 109 media = property(_media) 110 111 class EditableMap(forms.Textarea, MapMixin): 112 """ 113 An OpenLayers mapping widget for geographic data. 114 115 Example:: 116 117 from django import forms 118 from olwidget.widgets import OLWidget 119 120 class MyForm(forms.Form): 121 location = forms.CharField(widget=EditableMap( 122 options={'geometry': 'point'})) 123 """ 124 default_template = 'gis/editable_map.html' 125 126 def __init__(self, options=None, template=None): 127 self.set_options(options, template) 128 super(EditableMap, self).__init__() 129 130 def render(self, name, value, attrs=None): 131 if not attrs: 132 attrs = {} 133 # without an id, javascript fails 134 if attrs.has_key('id'): 135 element_id = attrs['id'] 136 else: 137 element_id = "id_%s" % id(self) 138 139 # Allow passing of wkt for MapDisplay subclass 140 if attrs.has_key('wkt'): 141 wkt = attrs['wkt'] 142 else: 143 # Use the default SRID's 144 wkt = add_srid(get_wkt(value)) 145 146 if name and not self.options.has_key('name'): 147 self.options['name'] = name 148 149 context = { 150 'id': element_id, 151 'name': name, 152 'wkt': wkt, 153 'map_opts': simplejson.dumps( 154 translate_options(self.options) 155 ), 156 } 157 return render_to_string(self.template, context) 158 159 class MapDisplay(EditableMap): 160 """ 161 Object for display of geometries on an OpenLayers map. Arguments (all are 162 optional): 163 164 * ``fields`` - a list of geometric fields or WKT strings to display on the 165 map. If none are given, the map will have no overlay. 166 * ``name`` - a name to use for display of the field data layer. 167 * ``options`` - a dict of options for map display. A complete list of 168 options is in the documentation for olwidget.js. 169 """ 170 171 def __init__(self, fields=None, options=None, template=None): 172 self.fields = fields 173 174 options = options or {} 175 if not options.has_key('editable'): 176 options['editable'] = False 177 178 if (self.fields and len(self.fields) > 1) or \ 179 (fields[0].geom_type.upper() == 'GEOMETRYCOLLECTION'): 180 options['isCollection'] = True 181 182 super(MapDisplay, self).__init__(options, template) 183 184 def __unicode__(self): 185 wkt = add_srid(collection_wkt(self.fields)) 186 name = self.options.get('name', 'data') 187 return self.render(name, None, attrs={'wkt': wkt}) 188 189 class InfoMap(forms.Widget, MapMixin): 190 """ 191 Widget for displaying maps with pop-up info boxes over geometries. 192 Arguments: 193 194 * ``info``: an array of [geometry, HTML] pairs that specify geometries, and 195 the popup contents associated with them. Geometries can be expressed as 196 geometry fields, or as WKT strings. Example:: 197 198 [ 199 [geomodel1.geofield, "<p>Model One</p>"], 200 [geomodel2.geofield, "<p>Model Two</p>"], 201 ... 202 ] 203 204 * ``options``: an optional dict of options for map display. 205 206 """ 207 default_template = 'gis/info_map.html' 208 209 def __init__(self, info=None, options=None, template=None): 210 self.info = info 211 self.set_options(options, template) 212 super(InfoMap, self).__init__() 213 214 def render(self, name, value, attrs=None): 215 if self.info is None: 216 info_json = '[]' 217 else: 218 # convert fields to wkt 219 for geom, html in self.info: 220 wkt_array = [[add_srid(collection_wkt(geom)), html] for geom, html in self.info] 221 info_json = simplejson.dumps(wkt_array) 222 223 # arbitrary unique id 224 div_id = "id_%s" % id(self) 225 226 context = { 227 'id': div_id, 228 'info_array': info_json, 229 'map_opts': simplejson.dumps( 230 translate_options(self.options) 231 ), 232 } 233 return render_to_string(self.template, context) 234 235 def __unicode__(self): 236 return self.render(None, None) 237 238 def get_wkt(value, srid=DEFAULT_PROJ): 239 """ 240 `value` is either a WKT string or a geometry field. Returns WKT in the 241 projection for the given SRID. 242 """ 243 if isinstance(value, basestring): 244 try: 245 value = GEOSGeometry(value) 246 except (GEOSException, ValueError): 247 value = None 248 249 wkt = '' 250 if value: 251 try: 252 ogr = value.ogr 253 ogr.transform(srid) 254 wkt = ogr.wkt 255 except OGRException: 256 pass 257 return wkt 258 259 def collection_wkt(fields): 260 """ Returns WKT for the given list of geometry fields. """ 261 262 if not fields: 263 return "" 264 265 if len(fields) == 1: 266 return get_wkt(fields[0]) 267 268 return "GEOMETRYCOLLECTION(%s)" % \ 269 ",".join(get_wkt(field) for field in fields) 270 271 def add_srid(wkt, srid=DEFAULT_PROJ): 272 """ 273 Returns EWKT (WKT with a specified SRID) for the given wkt and SRID 274 (default 4326). 275 """ 276 if wkt: 277 return "SRID=%s;%s" % (srid, wkt) 278 return "" 279 -
contrib/gis/templates/gis/admin/osm.html
1 {% extends "gis/admin/openlayers.html" %}2 {% block openlayers %}{% include "gis/admin/osm.js" %}{% endblock %}3 No newline at end of file -
contrib/gis/templates/gis/admin/admin_editable_map.html
1 <span style='float: left;'> 2 {% include "gis/editable_map.html" %} 3 </span> 4 <div style='clear: both;'></div> -
contrib/gis/templates/gis/admin/olwidget_change_list.html
1 {% extends "admin/change_list.html" %} 2 3 {% block content %} 4 {% if not is_popup %} 5 {{ map }} 6 {% endif %} 7 8 {{ block.super }} 9 {% endblock %} -
contrib/gis/templates/gis/admin/openlayers.html
1 {% block extrastyle %}2 <style type="text/css">3 #{{ id }}_map { width: {{ map_width }}px; height: {{ map_height }}px; }4 #{{ id }}_map .aligned label { float:inherit; }5 #{{ id }}_admin_map { position: relative; vertical-align: top; float: {{ LANGUAGE_BIDI|yesno:"right,left" }}; }6 {% if not display_wkt %}#{{ id }} { display: none; }{% endif %}7 .olControlEditingToolbar .olControlModifyFeatureItemActive {8 background-image: url("{{ ADMIN_MEDIA_PREFIX }}img/gis/move_vertex_on.png");9 background-repeat: no-repeat;10 }11 .olControlEditingToolbar .olControlModifyFeatureItemInactive {12 background-image: url("{{ ADMIN_MEDIA_PREFIX }}img/gis/move_vertex_off.png");13 background-repeat: no-repeat;14 }15 </style>16 <!--[if IE]>17 <style type="text/css">18 /* This fixes the mouse offset issues in IE. */19 #{{ id }}_admin_map { position: static; vertical-align: top; }20 /* `font-size: 0` fixes the 1px border between tiles, but borks LayerSwitcher.21 Thus, this is disabled until a better fix is found.22 #{{ id }}_map { width: {{ map_width }}px; height: {{ map_height }}px; font-size: 0; } */23 </style>24 <![endif]-->25 {% endblock %}26 <span id="{{ id }}_admin_map">27 <script type="text/javascript">28 //<![CDATA[29 {% block openlayers %}{% include "gis/admin/openlayers.js" %}{% endblock %}30 //]]>31 </script>32 <div id="{{ id }}_map"{% if LANGUAGE_BIDI %} dir="ltr"{% endif %}></div>33 <a href="javascript:{{ module }}.clearFeatures()">Delete all Features</a>34 {% if display_wkt %}<p> WKT debugging window:</p>{% endif %}35 <textarea id="{{ id }}" class="vWKTField required" cols="150" rows="10" name="{{ name }}">{{ wkt }}</textarea>36 <script type="text/javascript">{% block init_function %}{{ module }}.init();{% endblock %}</script>37 </span> -
contrib/gis/templates/gis/admin/osm.js
1 {% extends "gis/admin/openlayers.js" %}2 {% block base_layer %}new OpenLayers.Layer.OSM.Mapnik("OpenStreetMap (Mapnik)");{% endblock %} -
contrib/gis/templates/gis/admin/openlayers.js
1 {# Author: Justin Bronn, Travis Pinney & Dane Springmeyer #}2 {% block vars %}var {{ module }} = {};3 {{ module }}.map = null; {{ module }}.controls = null; {{ module }}.panel = null; {{ module }}.re = new RegExp("^SRID=\d+;(.+)", "i"); {{ module }}.layers = {};4 {{ module }}.wkt_f = new OpenLayers.Format.WKT();5 {{ module }}.is_collection = {{ is_collection|yesno:"true,false" }};6 {{ module }}.collection_type = '{{ collection_type }}';7 {{ module }}.is_linestring = {{ is_linestring|yesno:"true,false" }};8 {{ module }}.is_polygon = {{ is_polygon|yesno:"true,false" }};9 {{ module }}.is_point = {{ is_point|yesno:"true,false" }};10 {% endblock %}11 {{ module }}.get_ewkt = function(feat){return 'SRID={{ srid }};' + {{ module }}.wkt_f.write(feat);}12 {{ module }}.read_wkt = function(wkt){13 // OpenLayers cannot handle EWKT -- we make sure to strip it out.14 // EWKT is only exposed to OL if there's a validation error in the admin.15 var match = {{ module }}.re.exec(wkt);16 if (match){wkt = match[1];}17 return {{ module }}.wkt_f.read(wkt);18 }19 {{ module }}.write_wkt = function(feat){20 if ({{ module }}.is_collection){ {{ module }}.num_geom = feat.geometry.components.length;}21 else { {{ module }}.num_geom = 1;}22 document.getElementById('{{ id }}').value = {{ module }}.get_ewkt(feat);23 }24 {{ module }}.add_wkt = function(event){25 // This function will sync the contents of the `vector` layer with the26 // WKT in the text field.27 if ({{ module }}.is_collection){28 var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.{{ geom_type }}());29 for (var i = 0; i < {{ module }}.layers.vector.features.length; i++){30 feat.geometry.addComponents([{{ module }}.layers.vector.features[i].geometry]);31 }32 {{ module }}.write_wkt(feat);33 } else {34 // Make sure to remove any previously added features.35 if ({{ module }}.layers.vector.features.length > 1){36 old_feats = [{{ module }}.layers.vector.features[0]];37 {{ module }}.layers.vector.removeFeatures(old_feats);38 {{ module }}.layers.vector.destroyFeatures(old_feats);39 }40 {{ module }}.write_wkt(event.feature);41 }42 }43 {{ module }}.modify_wkt = function(event){44 if ({{ module }}.is_collection){45 if ({{ module }}.is_point){46 {{ module }}.add_wkt(event);47 return;48 } else {49 // When modifying the selected components are added to the50 // vector layer so we only increment to the `num_geom` value.51 var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.{{ geom_type }}());52 for (var i = 0; i < {{ module }}.num_geom; i++){53 feat.geometry.addComponents([{{ module }}.layers.vector.features[i].geometry]);54 }55 {{ module }}.write_wkt(feat);56 }57 } else {58 {{ module }}.write_wkt(event.feature);59 }60 }61 // Function to clear vector features and purge wkt from div62 {{ module }}.deleteFeatures = function(){63 {{ module }}.layers.vector.removeFeatures({{ module }}.layers.vector.features);64 {{ module }}.layers.vector.destroyFeatures();65 }66 {{ module }}.clearFeatures = function (){67 {{ module }}.deleteFeatures();68 document.getElementById('{{ id }}').value = '';69 {{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }});70 }71 // Add Select control72 {{ module }}.addSelectControl = function(){73 var select = new OpenLayers.Control.SelectFeature({{ module }}.layers.vector, {'toggle' : true, 'clickout' : true});74 {{ module }}.map.addControl(select);75 select.activate();76 }77 {{ module }}.enableDrawing = function(){ {{ module }}.map.getControlsByClass('OpenLayers.Control.DrawFeature')[0].activate();}78 {{ module }}.enableEditing = function(){ {{ module }}.map.getControlsByClass('OpenLayers.Control.ModifyFeature')[0].activate();}79 // Create an array of controls based on geometry type80 {{ module }}.getControls = function(lyr){81 {{ module }}.panel = new OpenLayers.Control.Panel({'displayClass': 'olControlEditingToolbar'});82 var nav = new OpenLayers.Control.Navigation();83 var draw_ctl;84 if ({{ module }}.is_linestring){85 draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Path, {'displayClass': 'olControlDrawFeaturePath'});86 } else if ({{ module }}.is_polygon){87 draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Polygon, {'displayClass': 'olControlDrawFeaturePolygon'});88 } else if ({{ module }}.is_point){89 draw_ctl = new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Point, {'displayClass': 'olControlDrawFeaturePoint'});90 }91 {% if modifiable %}92 var mod = new OpenLayers.Control.ModifyFeature(lyr, {'displayClass': 'olControlModifyFeature'});93 {{ module }}.controls = [nav, draw_ctl, mod];94 {% else %}95 {{ module }}.controls = [nav, darw_ctl];96 {% endif %}97 }98 {{ module }}.init = function(){99 {% block map_options %}// The options hash, w/ zoom, resolution, and projection settings.100 var options = {101 {% autoescape off %}{% for item in map_options.items %} '{{ item.0 }}' : {{ item.1 }}{% if not forloop.last %},{% endif %}102 {% endfor %}{% endautoescape %} };{% endblock %}103 // The admin map for this geometry field.104 {{ module }}.map = new OpenLayers.Map('{{ id }}_map', options);105 // Base Layer106 {{ module }}.layers.base = {% block base_layer %}new OpenLayers.Layer.WMS( "{{ wms_name }}", "{{ wms_url }}", {layers: '{{ wms_layer }}'} );{% endblock %}107 {{ module }}.map.addLayer({{ module }}.layers.base);108 {% block extra_layers %}{% endblock %}109 {% if is_linestring %}OpenLayers.Feature.Vector.style["default"]["strokeWidth"] = 3; // Default too thin for linestrings. {% endif %}110 {{ module }}.layers.vector = new OpenLayers.Layer.Vector(" {{ field_name }}");111 {{ module }}.map.addLayer({{ module }}.layers.vector);112 // Read WKT from the text field.113 var wkt = document.getElementById('{{ id }}').value;114 if (wkt){115 // After reading into geometry, immediately write back to116 // WKT <textarea> as EWKT (so that SRID is included).117 var admin_geom = {{ module }}.read_wkt(wkt);118 {{ module }}.write_wkt(admin_geom);119 if ({{ module }}.is_collection){120 // If geometry collection, add each component individually so they may be121 // edited individually.122 for (var i = 0; i < {{ module }}.num_geom; i++){123 {{ module }}.layers.vector.addFeatures([new OpenLayers.Feature.Vector(admin_geom.geometry.components[i].clone())]);124 }125 } else {126 {{ module }}.layers.vector.addFeatures([admin_geom]);127 }128 // Zooming to the bounds.129 {{ module }}.map.zoomToExtent(admin_geom.geometry.getBounds());130 if ({{ module }}.is_point){131 {{ module }}.map.zoomTo({{ point_zoom }});132 }133 } else {134 {{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }});135 }136 // This allows editing of the geographic fields -- the modified WKT is137 // written back to the content field (as EWKT, so that the ORM will know138 // to transform back to original SRID).139 {{ module }}.layers.vector.events.on({"featuremodified" : {{ module }}.modify_wkt});140 {{ module }}.layers.vector.events.on({"featureadded" : {{ module }}.add_wkt});141 {% block controls %}142 // Map controls:143 // Add geometry specific panel of toolbar controls144 {{ module }}.getControls({{ module }}.layers.vector);145 {{ module }}.panel.addControls({{ module }}.controls);146 {{ module }}.map.addControl({{ module }}.panel);147 {{ module }}.addSelectControl();148 // Then add optional visual controls149 {% if mouse_position %}{{ module }}.map.addControl(new OpenLayers.Control.MousePosition());{% endif %}150 {% if scale_text %}{{ module }}.map.addControl(new OpenLayers.Control.Scale());{% endif %}151 {% if layerswitcher %}{{ module }}.map.addControl(new OpenLayers.Control.LayerSwitcher());{% endif %}152 // Then add optional behavior controls153 {% if not scrollable %}{{ module }}.map.getControlsByClass('OpenLayers.Control.Navigation')[0].disableZoomWheel();{% endif %}154 {% endblock %}155 if (wkt){156 {{ module }}.enableEditing();157 } else {158 {{ module }}.enableDrawing();159 }160 } -
contrib/gis/templates/gis/editable_map.html
1 <textarea id="{{ id }}" name="{{ name }}">{{ wkt }}</textarea> 2 <script type='text/javascript'> 3 new olwidget.EditableMap("{{ id }}", {{map_opts|safe}}); 4 </script> -
contrib/gis/templates/gis/info_map.html
1 <div id="{{ id }}"></div> 2 <script type='text/javascript'> 3 new olwidget.InfoMap("{{ id }}", {{ info_array|safe }}, {{ map_opts|safe }}); 4 </script> -
contrib/admin/media/css/olwidget.css
1 /* 2 * Extra editing icons 3 */ 4 .olControlEditingToolbar .olControlModifyFeatureItemInactive { 5 background: url("../img/gis/extra_edit_icons.png") no-repeat scroll -48px 0px; 6 } 7 .olControlEditingToolbar .olControlModifyFeatureItemActive { 8 background: url("../img/gis/extra_edit_icons.png") no-repeat scroll -24px 0px; 9 } 10 .olControlEditingToolbar .olControlClearFeaturesItemInactive, 11 .olControlEditingToolbar .olControlClearFeaturesItemActive { 12 background: url("../img/gis/extra_edit_icons.png") no-repeat scroll -0px 0px; 13 } 14 div.olControlEditingToolbar { 15 width: 210px; 16 } 17 18 /* Override padding to avoid position computation errors */ 19 .olPopupContent { 20 padding: 0px !important; 21 overflow: visible !important; 22 } 23 /* Show popups over other controls */ 24 .olPopup { 25 z-index: 1005 !important; 26 } 27 28 /* Div containing all popup elements */ 29 .olwidgetPopupContent { 30 overflow: visible; 31 padding: 2px; 32 border: 2px solid #777; 33 background-color: #777; 34 } 35 36 .olwidgetPopupCloseBox { 37 cursor: pointer; 38 position: absolute; 39 right: 10px; 40 top: 10px; 41 background: #fff url("../img/gis/popup_icons.png") no-repeat scroll -80px 0px; 42 padding-top: 16px; 43 width: 16px; 44 height: 0px; 45 overflow: hidden; 46 } 47 .olwidgetPopupCloseBox:hover { 48 background-position: -64px 0px; 49 } 50 /* Div containing content user HTML */ 51 .olwidgetPopupPage { 52 overflow: auto; 53 background: #fff; 54 padding: 8px; 55 padding-top: 23px; 56 57 /* IE6 fix */ 58 zoom: 1; 59 } 60 61 .olwidgetPopupPagination { 62 clear: both; 63 float: right; 64 background: #fff; 65 padding-left: 5px; 66 padding-right: 5px; 67 } 68 .olwidgetPaginationPrevious { 69 float: left; 70 cursor: pointer; 71 /* Replace text with background image trick */ 72 background: url("../img/gis/popup_icons.png") no-repeat scroll -48px 0px; 73 padding-top: 16px; 74 width: 16px; 75 height: 0px; 76 overflow: hidden; 77 } 78 .olwidgetPaginationPrevious:hover { 79 background-position: -32px 0px; 80 } 81 82 /* Div containing page count, e.g. "1 of 5". */ 83 .olwidgetPaginationCount { 84 float: left; 85 margin-left: 0.5em; 86 margin-right: 0.5em; 87 } 88 .olwidgetPaginationNext { 89 float: left; 90 cursor: pointer; 91 /* Replace text with background image trick */ 92 background: url("../img/gis/popup_icons.png") no-repeat scroll -16px 0px; 93 padding-top: 16px; 94 width: 16px; 95 height: 0px; 96 overflow: hidden; 97 } 98 .olwidgetPaginationNext:hover { 99 background-position: 0px 0px; 100 } 101 .olwidgetClusterList { 102 margin: 0; 103 padding-left: 1em; 104 } 105 106 /* position blocks */ 107 .olwidgetPopupStemTL, .olwidgetPopupStemTR { 108 background: url("../img/gis/popup_icons.png") no-repeat scroll -124px 0px; 109 } 110 .olwidgetPopupStemBL, .olwidgetPopupStemBR { 111 background: url("../img/gis/popup_icons.png") no-repeat scroll -96px 0px; 112 } -
contrib/admin/media/img/gis/jquery_ui_license.txt
Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: contrib/admin/media/img/gis/popup_icons.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: contrib/admin/media/img/gis/extra_edit_icons.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream
1 The file "popup_icons.png" contain images taken from the jquery-ui library, 2 under the following license: 3 4 Copyright (c) 2009 Paul Bakaus, http://jqueryui.com/ 5 6 This software consists of voluntary contributions made by many 7 individuals (AUTHORS.txt, http://jqueryui.com/about) For exact 8 contribution history, see the revision history and logs, available 9 at http://jquery-ui.googlecode.com/svn/ 10 11 Permission is hereby granted, free of charge, to any person obtaining 12 a copy of this software and associated documentation files (the 13 "Software"), to deal in the Software without restriction, including 14 without limitation the rights to use, copy, modify, merge, publish, 15 distribute, sublicense, and/or sell copies of the Software, and to 16 permit persons to whom the Software is furnished to do so, subject to 17 the following conditions: 18 19 The above copyright notice and this permission notice shall be 20 included in all copies or substantial portions of the Software. 21 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 27 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 -
contrib/admin/media/js/olwidget.js
1 /* 2 * Simplified open layers mapping widgets. 3 * 4 * olwidget.EditableMap(textareaID, options) -- replace a textarea containing 5 * (E)WKT data with an editable map. 6 * 7 * olwidget.InfoMap(div_id, data, options) -- replace a div with a map which 8 * displays the data (an array of [WKT, html] pairs) in clickable popups. 9 * 10 */ 11 (function() { 12 13 /* 14 * Base namespace and utility functions 15 */ 16 var olwidget = { 17 /* 18 * WKT transformations 19 */ 20 wktFormat: new OpenLayers.Format.WKT(), 21 featureToEWKT: function(feature, proj) { 22 // convert "EPSG:" in projCode to 'SRID=' 23 var srid = 'SRID=' + proj.projCode.substring(5) + ';'; 24 return srid + this.wktFormat.write(feature); 25 }, 26 stripSRIDre: new RegExp("^SRID=\\d+;(.+)", "i"), 27 ewktToFeature: function(wkt) { 28 var match = this.stripSRIDre.exec(wkt); 29 if (match) { 30 wkt = match[1]; 31 } 32 return this.wktFormat.read(wkt); 33 }, 34 multiGeometryClasses: { 35 'linestring': OpenLayers.Geometry.MultiLineString, 36 'point': OpenLayers.Geometry.MultiPoint, 37 'polygon': OpenLayers.Geometry.MultiPolygon, 38 'collection': OpenLayers.Geometry.Collection 39 }, 40 /* 41 * Projection transformation 42 */ 43 transformVector: function(vector, fromProj, toProj) { 44 // Transform the projection of a feature vector or an array of feature 45 // vectors (as used in a collection) between the given projections. 46 if (fromProj.projCode == toProj.projCode) { 47 return vector; 48 } 49 var transformed; 50 if (vector.constructor == Array) { 51 transformed = []; 52 for (var i = 0; i < vector.length; i++) { 53 transformed.push(this.transformVector(vector[i], fromProj, toProj)); 54 } 55 } else { 56 var cloned = vector.geometry.clone(); 57 transformed = new OpenLayers.Feature.Vector(cloned.transform(fromProj, toProj)); 58 } 59 return transformed; 60 }, 61 /* 62 * Constructors for layers 63 */ 64 wms: { 65 map: function() { 66 return new OpenLayers.Layer.WMS( 67 "OpenLayers WMS", 68 "http://labs.metacarta.com/wms/vmap0", 69 {layers: 'basic'} 70 ); 71 }, 72 nasa: function() { 73 return new OpenLayers.Layer.WMS( 74 "NASA Global Mosaic", 75 "http://t1.hypercube.telascience.org/cgi-bin/landsat7", 76 {layers: "landsat7"} 77 ); 78 }, 79 blank: function() { 80 return new OpenLayers.Layer("", {isBaseLayer: true}); 81 } 82 }, 83 osm: { 84 mapnik: function() { 85 // Not using OpenLayers.Layer.OSM.Mapnik constructor because of 86 // an IE6 bug. This duplicates that constructor. 87 return new OpenLayers.Layer.OSM("OpenStreetMap (Mapnik)", 88 [ 89 "http://a.tile.openstreetmap.org/${z}/${x}/${y}.png", 90 "http://b.tile.openstreetmap.org/${z}/${x}/${y}.png", 91 "http://c.tile.openstreetmap.org/${z}/${x}/${y}.png" 92 ], 93 { numZoomLevels: 19 }); 94 }, 95 osmarender: function() { 96 return new OpenLayers.Layer.OSM.Osmarender( 97 'OpenStreetMap (Osmarender)'); 98 } 99 }, 100 google: { 101 streets: function() { 102 return new OpenLayers.Layer.Google("Google Streets", 103 {sphericalMercator: true, numZoomLevels: 20}); 104 }, 105 physical: function() { 106 return new OpenLayers.Layer.Google("Google Physical", 107 {sphericalMercator: true, type: G_PHYSICAL_MAP}); 108 }, 109 satellite: function() { 110 return new OpenLayers.Layer.Google("Google Satellite", 111 {sphericalMercator: true, type: G_SATELLITE_MAP}); 112 }, 113 hybrid: function() { 114 return new OpenLayers.Layer.Google("Google Hybrid", 115 {sphericalMercator: true, type: G_HYBRID_MAP, numZoomLevels: 20}); 116 } 117 }, 118 yahoo: { 119 map: function() { 120 return new OpenLayers.Layer.Yahoo("Yahoo", 121 {sphericalMercator: true, numZoomLevels: 20}); 122 } 123 }, 124 ve: { 125 map: function(type, typeName) { 126 /* 127 VE does not play nice with vector layers at zoom level 1. 128 Also, map may need "panMethod: OpenLayers.Easing.Linear.easeOut" 129 to avoid drift. See: 130 131 http://openlayers.com/dev/examples/ve-novibrate.html 132 133 */ 134 135 return new OpenLayers.Layer.VirtualEarth("Microsoft VE (" + typeName + ")", 136 {sphericalMercator: true, minZoomLevel: 2, type: type }); 137 }, 138 road: function() { return this.map(VEMapStyle.Road, "Road"); }, 139 shaded: function() { return this.map(VEMapStyle.Shaded, "Shaded"); }, 140 aerial: function() { return this.map(VEMapStyle.Aerial, "Aerial"); }, 141 hybrid: function() { return this.map(VEMapStyle.Hybrid, "Hybrid"); } 142 }, 143 144 145 /* 146 * Deep copies all attributes in 'source' object into 'destination' object. 147 * Useful for applying defaults in nested objects. 148 */ 149 deepJoinOptions: function(destination, source) { 150 if (destination == undefined) { 151 destination = {}; 152 } 153 for (var a in source) { 154 if (source[a] != undefined) { 155 if (typeof(source[a]) == 'object' && source[a].constructor != Array) { 156 destination[a] = this.deepJoinOptions(destination[a], source[a]); 157 } else { 158 destination[a] = source[a]; 159 } 160 } 161 } 162 return destination; 163 } 164 }; 165 166 /* 167 * Base olwidget map type. Extends OpenLayers.Map 168 */ 169 olwidget.BaseMap = OpenLayers.Class(OpenLayers.Map, { 170 initialize: function(mapDivID, options) { 171 this.opts = this.initOptions(options); 172 this.initMap(mapDivID, this.opts); 173 }, 174 /* 175 * Extend the passed in options with defaults, and create unserialized 176 * objects for serialized options (such as projections). 177 */ 178 initOptions: function(options) { 179 var defaults = { 180 mapOptions: { 181 units: 'm', 182 maxResolution: 156543.0339, 183 projection: "EPSG:900913", 184 displayProjection: "EPSG:4326", 185 maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34], 186 controls: ['LayerSwitcher', 'Navigation', 'PanZoom', 'Attribution'] 187 }, 188 mapDivClass: '', 189 mapDivStyle: { 190 width: '600px', 191 height: '400px' 192 }, 193 name: 'data', 194 layers: ['osm.mapnik'], 195 defaultLon: 0, 196 defaultLat: 0, 197 defaultZoom: 4, 198 overlayStyle: { 199 fillColor: '#ff00ff', 200 strokeColor: '#ff00ff', 201 pointRadius: 6, 202 fillOpacity: 0.5, 203 strokeWidth: 2 204 } 205 }; 206 var opts = olwidget.deepJoinOptions(defaults, options); 207 208 opts.overrideZoom = options.defaultZoom != undefined; 209 opts.overrideCenter = options.defaultLat != undefined && options.defaultLon != undefined; 210 211 // construct objects for serialized options 212 var me = opts.mapOptions.maxExtent; 213 opts.mapOptions.maxExtent = new OpenLayers.Bounds(me[0], me[1], me[2], me[3]); 214 opts.mapOptions.projection = new OpenLayers.Projection(opts.mapOptions.projection); 215 opts.mapOptions.displayProjection = new OpenLayers.Projection( 216 opts.mapOptions.displayProjection); 217 opts.default_center = new OpenLayers.LonLat(opts.defaultLon, opts.defaultLat); 218 opts.default_center.transform(opts.mapOptions.displayProjection, 219 opts.mapOptions.projection); 220 var controls = []; 221 for (var i = 0; i < opts.mapOptions.controls.length; i++) { 222 var control = opts.mapOptions.controls[i]; 223 controls.push(new OpenLayers.Control[control]()); 224 } 225 opts.mapOptions.controls = controls; 226 return opts; 227 }, 228 /* 229 * Initialize the OpenLayers Map instance and add layers. 230 */ 231 initMap: function(mapDivID, opts) { 232 var mapDiv = document.getElementById(mapDivID); 233 OpenLayers.Util.extend(mapDiv.style, opts.mapDivStyle); 234 mapDiv.className = opts.mapDivClass; 235 var layers = []; 236 for (var i = 0; i < opts.layers.length; i++) { 237 var parts = opts.layers[i].split("."); 238 layers.push(olwidget[parts[0]][parts[1]]()); 239 240 // workaround for problems with Micorsoft layers and vector layer drift 241 // (see http://openlayers.com/dev/examples/ve-novibrate.html) 242 if (parts[0] == "ve") { 243 if (opts.mapOptions.panMethod == undefined) { 244 opts.mapOptions.panMethod = OpenLayers.Easing.Linear.easeOut; 245 } 246 } 247 } 248 var styleMap = new OpenLayers.StyleMap({'default': new OpenLayers.Style(opts.overlayStyle)}); 249 250 // Super constructor 251 OpenLayers.Map.prototype.initialize.apply(this, [mapDiv.id, opts.mapOptions]); 252 this.vectorLayer = new OpenLayers.Layer.Vector(this.opts.name, { styleMap: styleMap }); 253 layers.push(this.vectorLayer); 254 this.addLayers(layers); 255 this.setDefaultCenter(); 256 }, 257 setDefaultCenter: function() { 258 this.setCenter(this.opts.default_center.clone(), this.opts.defaultZoom); 259 }, 260 clearFeatures: function() { 261 this.vectorLayer.removeFeatures(this.vectorLayer.features); 262 this.vectorLayer.destroyFeatures(); 263 } 264 }); 265 266 /* 267 * Map type that implements editable vectors. 268 */ 269 olwidget.EditableMap = OpenLayers.Class(olwidget.BaseMap, { 270 initialize: function(textareaID, options) { 271 var defaults = { 272 editable: true, 273 geometry: 'point', 274 hideTextarea: true, 275 isCollection: false 276 }; 277 options = olwidget.deepJoinOptions(defaults, options); 278 279 // set up map div 280 var mapDiv = document.createElement("div"); 281 mapDiv.id = textareaID + "_map"; 282 this.textarea = document.getElementById(textareaID); 283 this.textarea.parentNode.insertBefore(mapDiv, this.textarea); 284 285 // initialize map 286 olwidget.BaseMap.prototype.initialize.apply(this, [mapDiv.id, options]) 287 288 if (this.opts.hideTextarea) { 289 this.textarea.style.display = 'none'; 290 } 291 292 this.initWKTAndCenter() 293 this.initControls(); 294 }, 295 initWKTAndCenter: function() { 296 // Read any initial WKT from the text field. We assume that the 297 // WKT uses the projection given in "displayProjection", and ignore 298 // any initial SRID. 299 300 var wkt = this.textarea.value; 301 if (wkt) { 302 // After reading into geometry, immediately write back to 303 // WKT <textarea> as EWKT (so the SRID is included if it wasn't 304 // before). 305 var geom = olwidget.ewktToFeature(wkt); 306 geom = olwidget.transformVector(geom, this.displayProjection, this.projection); 307 if (this.opts.isCollection) { 308 this.vectorLayer.addFeatures(geom); 309 } else { 310 this.vectorLayer.addFeatures([geom]); 311 } 312 this.numGeom = this.vectorLayer.features.length; 313 314 // Set center 315 if (this.opts.geometry == 'point' && !this.opts.isCollection) { 316 this.setCenter(geom.geometry.getBounds().getCenterLonLat(), 317 this.opts.defaultZoom); 318 } else { 319 this.zoomToExtent(this.vectorLayer.getDataExtent()); 320 } 321 } 322 }, 323 initControls: function() { 324 // Initialize controls for editing geometries, navigating, and map data. 325 326 // This allows editing of the geographic fields -- the modified WKT is 327 // written back to the content field (as EWKT) 328 if (this.opts.editable) { 329 var closuredThis = this; 330 this.vectorLayer.events.on({ 331 "featuremodified" : function(event) { closuredThis.modifyWKT(event); }, 332 "featureadded": function(event) { closuredThis.addWKT(event); } 333 }); 334 335 // Map controls: 336 // Add geometry specific panel of toolbar controls 337 var panel = this.buildPanel(this.vectorLayer); 338 this.addControl(panel); 339 var select = new OpenLayers.Control.SelectFeature( this.vectorLayer, 340 {toggle: true, clickout: true, hover: false}); 341 this.addControl(select); 342 select.activate(); 343 } 344 }, 345 clearFeatures: function() { 346 olwidget.BaseMap.prototype.clearFeatures.apply(this); 347 this.textarea.value = ''; 348 }, 349 buildPanel: function(layer) { 350 var panel = new OpenLayers.Control.Panel({displayClass: 'olControlEditingToolbar'}); 351 var controls = []; 352 353 var nav = new OpenLayers.Control.Navigation(); 354 controls.push(nav); 355 356 // Drawing control(s) 357 var geometries; 358 if (this.opts.geometry.constructor == Array) { 359 geometries = this.opts.geometry; 360 } else { 361 geometries = [this.opts.geometry]; 362 } 363 for (var i = 0; i < geometries.length; i++) { 364 var drawControl; 365 if (geometries[i] == 'linestring') { 366 drawControl = new OpenLayers.Control.DrawFeature(layer, 367 OpenLayers.Handler.Path, 368 {'displayClass': 'olControlDrawFeaturePath'}); 369 } else if (geometries[i] == 'polygon') { 370 drawControl = new OpenLayers.Control.DrawFeature(layer, 371 OpenLayers.Handler.Polygon, 372 {'displayClass': 'olControlDrawFeaturePolygon'}); 373 } else if (geometries[i] == 'point') { 374 drawControl = new OpenLayers.Control.DrawFeature(layer, 375 OpenLayers.Handler.Point, 376 {'displayClass': 'olControlDrawFeaturePoint'}); 377 } 378 controls.push(drawControl); 379 } 380 381 // Modify feature control 382 var mod = new OpenLayers.Control.ModifyFeature(layer); 383 controls.push(mod); 384 385 // Clear all control 386 var closuredThis = this; 387 var del = new OpenLayers.Control.Button({ 388 displayClass: 'olControlClearFeatures', 389 trigger: function() { 390 closuredThis.clearFeatures(); 391 } 392 }); 393 394 controls.push(del); 395 panel.addControls(controls); 396 return panel; 397 }, 398 // Callback for openlayers "featureadded" 399 addWKT: function(event) { 400 // This function will sync the contents of the `vector` layer with the 401 // WKT in the text field. 402 if (this.opts.isCollection) { 403 this.featureToTextarea(this.vectorLayer.features); 404 } else { 405 // Make sure to remove any previously added features. 406 if (this.vectorLayer.features.length > 1) { 407 old_feats = [this.vectorLayer.features[0]]; 408 this.vectorLayer.removeFeatures(old_feats); 409 this.vectorLayer.destroyFeatures(old_feats); 410 } 411 this.featureToTextarea(event.feature); 412 } 413 }, 414 // Callback for openlayers "featuremodified" 415 modifyWKT: function(event) { 416 if (this.opts.isCollection){ 417 // OpenLayers adds points around the modified feature that we want to strip. 418 // So only take the features up to "numGeom", the number of features counted 419 // when we last added. 420 var feat = []; 421 for (var i = 0; i < this.numGeom; i++) { 422 feat.push(this.vectorLayer.features[i].clone()); 423 } 424 this.featureToTextarea(feat) 425 } else { 426 this.featureToTextarea(event.feature); 427 } 428 }, 429 featureToTextarea: function(feature) { 430 if (this.opts.isCollection) { 431 this.numGeom = feature.length; 432 } else { 433 this.numGeom = 1; 434 } 435 feature = olwidget.transformVector(feature, 436 this.projection, this.displayProjection); 437 if (this.opts.isCollection) { 438 // Convert to multi-geometry types if we are a collection. 439 // Passing arrays to the WKT formatter results in a 440 // "GEOMETRYCOLLECTION" type, but if we have only one geometry, 441 // we should use a "MULTI<geometry>" type. 442 if (this.opts.geometry.constructor != Array) { 443 var geoms = []; 444 for (var i = 0; i < feature.length; i++) { 445 geoms.push(feature[i].geometry); 446 } 447 var GeoClass = olwidget.multiGeometryClasses[this.opts.geometry]; 448 feature = new OpenLayers.Feature.Vector(new GeoClass(geoms)); 449 } 450 } 451 this.textarea.value = olwidget.featureToEWKT(feature, this.displayProjection); 452 } 453 }); 454 455 /* 456 * olwidget.InfoMap -- map type supporting clickable vectors that raise 457 * popups. The popups are displayed optionally inside or outside the map's 458 * viewport. 459 * 460 * Usage: olwidget.Infomap(mapDivID, infoArray, options) 461 * 462 * arguments: 463 * mapDivID: the DOM id of a div to replace with the map. 464 * infoArray: An array of the form: 465 * [ ["WKT", "html"], ... ] 466 * where "WKT" represents the well-known text form of the geometry, 467 * and "html" represents the HTML content for the popup. 468 * options: An options object. See distribution documentation for details. 469 */ 470 olwidget.InfoMap = OpenLayers.Class(olwidget.BaseMap, { 471 initialize: function(mapDivID, infoArray, options) { 472 var infomapDefaults = { 473 popupsOutside: false, 474 popupDirection: 'auto', 475 popupPaginationSeparator: ' of ', 476 cluster: false, 477 clusterDisplay: "paginate", 478 clusterStyle: { 479 pointRadius: "${radius}", 480 strokeWidth: "${width}", 481 label: "${label}", 482 labelSelect: true, 483 fontSize: "11px", 484 fontFamily: "Helvetica, sans-serif", 485 fontColor: "#ffffff" 486 } 487 }; 488 489 options = olwidget.deepJoinOptions(infomapDefaults, options); 490 olwidget.BaseMap.prototype.initialize.apply(this, [mapDivID, options]); 491 492 // Must have explicitly specified position for popups to work properly. 493 if (!this.div.style.position) { 494 this.div.style.position = 'relative'; 495 } 496 497 if (this.opts.cluster == true) { 498 this.addClusterStrategy(); 499 } 500 501 var features = []; 502 for (var i = 0; i < infoArray.length; i++) { 503 var feature = olwidget.ewktToFeature(infoArray[i][0]); 504 feature = olwidget.transformVector(feature, 505 this.displayProjection, this.projection); 506 507 if (feature.constructor != Array) { 508 feature = [feature]; 509 } 510 for (var k = 0; k < feature.length; k++) { 511 feature[k].attributes = { html: infoArray[i][1] }; 512 features.push(feature[k]); 513 } 514 } 515 this.vectorLayer.addFeatures(features); 516 517 this.select = new OpenLayers.Control.SelectFeature(this.vectorLayer, { clickout: true, hover: false }); 518 this.select.events.register("featurehighlighted", this, 519 function(evt) { this.createPopup(evt); }); 520 this.select.events.register("featureunhighlighted", this, 521 function(evt) { this.deletePopup() }); 522 523 // Zooming changes clusters, so we must delete popup if we zoom. 524 this.events.register("zoomend", this, function(event) { this.select.unselectAll(); }); 525 526 this.addControl(this.select); 527 this.select.activate(); 528 529 // Set zoom level 530 if (this.opts.overrideCenter) { 531 this.setCenter(this.opts.default_center); 532 } else { 533 this.setCenter(this.vectorLayer.getDataExtent().getCenterLonLat()); 534 } 535 if (this.opts.overrideZoom) { 536 this.zoomTo(this.opts.defaultZoom); 537 } else { 538 this.zoomToExtent(this.vectorLayer.getDataExtent()); 539 } 540 }, 541 addClusterStrategy: function() { 542 var style_context = { 543 width: function(feature) { 544 return (feature.cluster) ? 2 : 1; 545 }, 546 radius: function(feature) { 547 var n = feature.attributes.count; 548 var pix; 549 if (n == 1) { 550 pix = 6; 551 } else if (n <= 5) { 552 pix = 8; 553 } else if (n <= 25) { 554 pix = 10; 555 } else if (n <= 50) { 556 pix = 12; 557 } else { 558 pix = 14; 559 } 560 return pix; 561 }, 562 label: function(feature) { 563 return (feature.cluster && feature.cluster.length > 1) ? feature.cluster.length : ''; 564 } 565 }; 566 567 var defaultStyleOpts = OpenLayers.Util.applyDefaults( 568 OpenLayers.Util.applyDefaults({}, this.opts.clusterStyle), 569 this.vectorLayer.styleMap.styles['default'].defaultStyle); 570 var selectStyleOpts = OpenLayers.Util.applyDefaults( 571 OpenLayers.Util.applyDefaults({}, this.opts.clusterStyle), 572 this.vectorLayer.styleMap.styles['select'].defaultStyle); 573 574 var defaultStyle = new OpenLayers.Style(defaultStyleOpts, {context: style_context}); 575 var selectStyle = new OpenLayers.Style(selectStyleOpts, {context: style_context}); 576 this.removeLayer(this.vectorLayer); 577 this.vectorLayer = new OpenLayers.Layer.Vector(this.opts.name, { 578 styleMap: new OpenLayers.StyleMap({ 'default': defaultStyle, 'select': selectStyle }), 579 strategies: [new OpenLayers.Strategy.Cluster()] 580 }); 581 this.addLayer(this.vectorLayer); 582 }, 583 /** 584 * Override parent to allow placement of popups outside viewport 585 */ 586 addPopup: function(popup, exclusive) { 587 if (exclusive) { 588 //remove all other popups from screen 589 for (var i = this.popups.length - 1; i >= 0; --i) { 590 this.removePopup(this.popups[i]); 591 } 592 } 593 594 popup.map = this; 595 this.popups.push(popup); 596 var popupDiv = popup.draw(); 597 if (popupDiv) { 598 popupDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] + 599 this.popups.length; 600 //if (this.opts.popupsOutside) { 601 this.div.appendChild(popupDiv); 602 // store a reference to this function so we can unregister on removal 603 this.popupMoveFunc = function(event) { 604 var px = this.getPixelFromLonLat(this.popup.lonlat); 605 popup.moveTo(px); 606 } 607 this.events.register("move", this, this.popupMoveFunc); 608 this.popupMoveFunc(); 609 //} else { 610 // this.layerContainerDiv.appendChild(popupDiv); 611 //} 612 } 613 }, 614 /** 615 * Override parent to allow placement of popups outside viewport 616 */ 617 removePopup: function(popup) { 618 OpenLayers.Util.removeItem(this.popups, popup); 619 if (popup.div) { 620 try { 621 //if (this.opts.popupsOutside) { 622 this.div.removeChild(popup.div); 623 this.events.unregister("move", this, this.popupMoveFunc); 624 //} else { 625 // this.layerContainerDiv.removeChild(popup.div); 626 //} 627 } catch (e) { } 628 } 629 popup.map = null; 630 }, 631 632 /** 633 * Build a paginated popup 634 */ 635 createPopup: function(evt) { 636 var feature = evt.feature; 637 var lonlat; 638 if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { 639 lonlat = feature.geometry.getBounds().getCenterLonLat(); 640 } else { 641 lonlat = this.getLonLatFromViewPortPx(evt.object.handlers.feature.evt.xy); 642 } 643 644 var popupHTML = []; 645 if (feature.cluster) { 646 if (this.opts.clusterDisplay == 'list') { 647 if (feature.cluster.length > 1) { 648 var html = "<ul class='olwidgetClusterList'>"; 649 for (var i = 0; i < feature.cluster.length; i++) { 650 html += "<li>" + feature.cluster[i].attributes.html + "</li>"; 651 } 652 html += "</ul>"; 653 popupHTML.push(html); 654 } else { 655 popupHTML.push(feature.cluster[0].attributes.html); 656 } 657 } else { 658 for (var i = 0; i < feature.cluster.length; i++) { 659 popupHTML.push(feature.cluster[i].attributes.html); 660 } 661 } 662 } else { 663 popupHTML.push(feature.attributes.html); 664 } 665 var infomap = this; 666 this.popup = new olwidget.Popup(null, 667 lonlat, null, popupHTML, null, true, 668 function() { infomap.select.unselect(feature) }, 669 this.opts.popupDirection, 670 this.opts.popupPaginationSeparator); 671 if (this.opts.popupsOutside) { 672 this.popup.panMapIfOutOfView = false; 673 } 674 this.addPopup(this.popup); 675 }, 676 677 deletePopup: function() { 678 if (this.popup) { 679 this.popup.destroy(); 680 this.popup = null; 681 } 682 } 683 }); 684 685 /* 686 * Paginated, framed popup type, CSS stylable. 687 */ 688 olwidget.Popup = OpenLayers.Class(OpenLayers.Popup.Framed, { 689 autoSize: true, 690 panMapIfOutOfView: true, 691 fixedRelativePosition: false, 692 // Position blocks. Overriden to include additional "className" parameter, 693 // allowing image paths relative to css rather than relative to the html 694 // file (as paths included in a JS file are computed). 695 positionBlocks: { 696 "tl": { 697 'offset': new OpenLayers.Pixel(44, -6), 698 'padding': new OpenLayers.Bounds(5, 14, 5, 5), 699 'blocks': [ 700 { // stem 701 className: 'olwidgetPopupStemTL', 702 size: new OpenLayers.Size(24, 14), 703 anchor: new OpenLayers.Bounds(null, 0, 32, null), 704 position: new OpenLayers.Pixel(0, -28) 705 } 706 ] 707 }, 708 "tr": { 709 'offset': new OpenLayers.Pixel(-44, -6), 710 'padding': new OpenLayers.Bounds(5, 14, 5, 5), 711 'blocks': [ 712 { // stem 713 className: "olwidgetPopupStemTR", 714 size: new OpenLayers.Size(24, 14), 715 anchor: new OpenLayers.Bounds(32, 0, null, null), 716 position: new OpenLayers.Pixel(0, -28) 717 } 718 ] 719 }, 720 "bl": { 721 'offset': new OpenLayers.Pixel(44, 6), 722 'padding': new OpenLayers.Bounds(5, 5, 5, 14), 723 'blocks': [ 724 { // stem 725 className: "olwidgetPopupStemBL", 726 size: new OpenLayers.Size(24, 14), 727 anchor: new OpenLayers.Bounds(null, null, 32, 0), 728 position: new OpenLayers.Pixel(0, 0) 729 } 730 ] 731 }, 732 "br": { 733 'offset': new OpenLayers.Pixel(-44, 6), 734 'padding': new OpenLayers.Bounds(5, 5, 5, 14), 735 'blocks': [ 736 { // stem 737 className: "olwidgetPopupStemBR", 738 size: new OpenLayers.Size(24, 14), 739 anchor: new OpenLayers.Bounds(32, null, null, 0), 740 position: new OpenLayers.Pixel(0, 0) 741 } 742 ] 743 } 744 }, 745 746 initialize: function(id, lonlat, contentSize, contentHTML, anchor, closeBox, 747 closeBoxCallback, relativePosition, separator) { 748 if (relativePosition && relativePosition != 'auto') { 749 this.fixedRelativePosition = true; 750 this.relativePosition = relativePosition; 751 } 752 if (separator == undefined) { 753 this.separator = ' of '; 754 } else { 755 this.separator = separator; 756 } 757 // we don't use the default close box because we want it to appear in 758 // the content div for easier CSS control. 759 this.olwidgetCloseBox = closeBox; 760 this.olwidgetCloseBoxCallback = closeBoxCallback; 761 this.page = 0; 762 OpenLayers.Popup.Framed.prototype.initialize.apply(this, [id, lonlat, 763 contentSize, contentHTML, anchor, false, null]); 764 }, 765 766 /* 767 * Construct the interior of a popup. If contentHTML is an Array, display 768 * the array element specified by this.page. 769 */ 770 setContentHTML: function(contentHTML) { 771 if (contentHTML != null) { 772 this.contentHTML = contentHTML; 773 } 774 775 var pageHTML; 776 var showPagination; 777 if (this.contentHTML.constructor != Array) { 778 pageHTML = this.contentHTML; 779 showPagination = false; 780 } else { 781 pageHTML = this.contentHTML[this.page]; 782 showPagination = this.contentHTML.length > 1; 783 } 784 785 if ((this.contentDiv != null) && (pageHTML != null)) { 786 var popup = this; // for closures 787 788 // Clear old contents 789 this.contentDiv.innerHTML = ""; 790 791 // Build container div 792 var containerDiv = document.createElement("div"); 793 containerDiv.className = 'olwidgetPopupContent'; 794 this.contentDiv.appendChild(containerDiv); 795 796 // Build close box 797 if (this.olwidgetCloseBox) { 798 closeDiv = document.createElement("div"); 799 closeDiv.className = "olwidgetPopupCloseBox"; 800 closeDiv.innerHTML = "close"; 801 closeDiv.onclick = function(event) { 802 popup.olwidgetCloseBoxCallback.apply(popup, arguments); 803 } 804 containerDiv.appendChild(closeDiv); 805 } 806 807 var pageDiv = document.createElement("div"); 808 pageDiv.innerHTML = pageHTML; 809 pageDiv.className = "olwidgetPopupPage"; 810 containerDiv.appendChild(pageDiv); 811 812 if (showPagination) { 813 // Build pagination control 814 815 paginationDiv = document.createElement("div"); 816 paginationDiv.className = "olwidgetPopupPagination"; 817 var prev = document.createElement("div"); 818 prev.className = "olwidgetPaginationPrevious"; 819 prev.innerHTML = "prev"; 820 prev.onclick = function(event) { 821 popup.page = (popup.page - 1 + popup.contentHTML.length) % 822 popup.contentHTML.length; 823 popup.setContentHTML(); 824 popup.map.events.triggerEvent("move"); 825 } 826 827 var count = document.createElement("div"); 828 count.className = "olwidgetPaginationCount"; 829 count.innerHTML = (this.page + 1) + " of " + this.contentHTML.length; 830 var next = document.createElement("div"); 831 next.className = "olwidgetPaginationNext"; 832 next.innerHTML = "next"; 833 next.onclick = function(event) { 834 popup.page = (popup.page + 1) % popup.contentHTML.length; 835 popup.setContentHTML(); 836 popup.map.events.triggerEvent("move"); 837 } 838 839 paginationDiv.appendChild(prev); 840 paginationDiv.appendChild(count); 841 paginationDiv.appendChild(next); 842 containerDiv.appendChild(paginationDiv); 843 844 } 845 var clearFloat = document.createElement("div"); 846 clearFloat.style.clear = "both"; 847 containerDiv.appendChild(clearFloat); 848 849 if (this.autoSize) { 850 this.registerImageListeners(); 851 this.updateSize(); 852 } 853 } 854 }, 855 856 /* 857 * Override parent to make the popup more CSS-friendly. Rather than 858 * specifying img paths in javascript, give position blocks CSS classes 859 * that can be used to apply background images to the divs. 860 */ 861 createBlocks: function() { 862 this.blocks = []; 863 864 //since all positions contain the same number of blocks, we can 865 // just pick the first position and use its blocks array to create 866 // our blocks array 867 var firstPosition = null; 868 for(var key in this.positionBlocks) { 869 firstPosition = key; 870 break; 871 } 872 873 var position = this.positionBlocks[firstPosition]; 874 for (var i = 0; i < position.blocks.length; i++) { 875 876 var block = {}; 877 this.blocks.push(block); 878 879 var divId = this.id + '_FrameDecorationDiv_' + i; 880 block.div = OpenLayers.Util.createDiv(divId, 881 null, null, null, "absolute", null, "hidden", null 882 ); 883 this.groupDiv.appendChild(block.div); 884 } 885 }, 886 /* 887 * Override parent to make the popup more CSS-friendly, reflecting 888 * modifications to createBlocks. 889 */ 890 updateBlocks: function() { 891 if (!this.blocks) { 892 this.createBlocks(); 893 } 894 if (this.size && this.relativePosition) { 895 var position = this.positionBlocks[this.relativePosition]; 896 for (var i = 0; i < position.blocks.length; i++) { 897 898 var positionBlock = position.blocks[i]; 899 var block = this.blocks[i]; 900 901 // adjust sizes 902 var l = positionBlock.anchor.left; 903 var b = positionBlock.anchor.bottom; 904 var r = positionBlock.anchor.right; 905 var t = positionBlock.anchor.top; 906 907 //note that we use the isNaN() test here because if the 908 // size object is initialized with a "auto" parameter, the 909 // size constructor calls parseFloat() on the string, 910 // which will turn it into NaN 911 // 912 var w = (isNaN(positionBlock.size.w)) ? this.size.w - (r + l) 913 : positionBlock.size.w; 914 915 var h = (isNaN(positionBlock.size.h)) ? this.size.h - (b + t) 916 : positionBlock.size.h; 917 918 block.div.style.width = (w < 0 ? 0 : w) + 'px'; 919 block.div.style.height = (h < 0 ? 0 : h) + 'px'; 920 921 block.div.style.left = (l != null) ? l + 'px' : ''; 922 block.div.style.bottom = (b != null) ? b + 'px' : ''; 923 block.div.style.right = (r != null) ? r + 'px' : ''; 924 block.div.style.top = (t != null) ? t + 'px' : ''; 925 926 block.div.className = positionBlock.className; 927 } 928 929 this.contentDiv.style.left = this.padding.left + "px"; 930 this.contentDiv.style.top = this.padding.top + "px"; 931 } 932 }, 933 updateSize: function() { 934 if (this.map.opts.popupsOutside == true) { 935 var preparedHTML = "<div class='" + this.contentDisplayClass+ "'>" + 936 this.contentDiv.innerHTML + 937 "</div>"; 938 939 var containerElement = document.body; 940 var realSize = OpenLayers.Util.getRenderedDimensions( 941 preparedHTML, null, { 942 displayClass: this.displayClass, 943 containerElement: containerElement 944 } 945 ); 946 return this.setSize(realSize); 947 } else { 948 return OpenLayers.Popup.prototype.updateSize.apply(this, arguments); 949 } 950 }, 951 952 CLASS_NAME: "olwidget.Popup" 953 }); 954 955 // finish anonymous function. Add olwidget to 'window'. 956 this.olwidget = olwidget; 957 })(); -
contrib/admin/options.py
873 873 return self.render_change_form(request, context, change=True, obj=obj) 874 874 change_view = transaction.commit_on_success(change_view) 875 875 876 def changelist_view(self, request, extra_context=None):877 " The 'change list' admin view for this model."876 def get_changelist_context(self, request): 877 "Get the default context for the changelist view." 878 878 from django.contrib.admin.views.main import ChangeList, ERROR_FLAG 879 879 opts = self.model._meta 880 880 app_label = opts.app_label … … 977 977 'actions_on_top': self.actions_on_top, 978 978 'actions_on_bottom': self.actions_on_bottom, 979 979 } 980 return context 981 982 def changelist_view(self, request, extra_context=None): 983 "The 'change list' admin view for this model." 984 985 context = self.get_changelist_context(request) 980 986 context.update(extra_context or {}) 981 987 context_instance = template.RequestContext(request, current_app=self.admin_site.name) 982 988 return render_to_response(self.change_list_template or [