summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chimere/admin.py2
-rw-r--r--chimere/forms.py1
-rw-r--r--chimere/migrations/0009_auto__add_field_marker_keywords__add_field_route_keywords.py298
-rw-r--r--chimere/models.py63
-rw-r--r--chimere/search_indexes.py2
-rw-r--r--chimere/static/chimere/css/styles.css36
-rw-r--r--chimere/static/chimere/js/base.js6
-rw-r--r--chimere/static/chimere/js/jquery.chimere-ol.js48
-rw-r--r--chimere/static/chimere/js/search-autocomplete.js58
-rw-r--r--chimere/templates/chimere/edit.html6
-rw-r--r--chimere/templates/chimere/main_map_simple.html2
-rw-r--r--chimere/templates/search/indexes/chimere/marker_text.txt1
-rw-r--r--chimere/templates/search/indexes/chimere/route_text.txt1
-rw-r--r--chimere/templates/search/search.html27
-rw-r--r--chimere/templates/search/search_js.html24
-rw-r--r--chimere/urls.py2
-rw-r--r--chimere/views.py18
-rw-r--r--conf/solr/schema-fr.xml166
-rw-r--r--conf/solr/schema.xml168
19 files changed, 848 insertions, 81 deletions
diff --git a/chimere/admin.py b/chimere/admin.py
index d5af268..2672306 100644
--- a/chimere/admin.py
+++ b/chimere/admin.py
@@ -211,7 +211,7 @@ class MarkerAdmin(admin.ModelAdmin):
form = MarkerAdminForm
fieldsets = ((None, {
'fields': ['point', 'name', 'status', 'categories',
- 'description', 'weight', 'start_date', 'end_date']
+ 'description', 'weight', 'keywords', 'start_date', 'end_date']
}),
(_(u"Submitter"), {
'classes':('collapse',),
diff --git a/chimere/forms.py b/chimere/forms.py
index 8c512ae..d923963 100644
--- a/chimere/forms.py
+++ b/chimere/forms.py
@@ -310,6 +310,7 @@ class MarkerForm(MarkerBaseForm):
ref_pk = forms.IntegerField(label=u" ", widget=forms.HiddenInput(),
required=False)
description = forms.CharField(widget=TextareaWidget, required=False)
+ keywords = forms.CharField(max_length=200, required=False)
class Meta:
model = Marker
exclude = ('status',)
diff --git a/chimere/migrations/0009_auto__add_field_marker_keywords__add_field_route_keywords.py b/chimere/migrations/0009_auto__add_field_marker_keywords__add_field_route_keywords.py
new file mode 100644
index 0000000..daeb1be
--- /dev/null
+++ b/chimere/migrations/0009_auto__add_field_marker_keywords__add_field_route_keywords.py
@@ -0,0 +1,298 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Marker.keywords'
+ db.add_column('chimere_marker', 'keywords',
+ self.gf('django.db.models.fields.TextField')(max_length=200, null=True, blank=True),
+ keep_default=False)
+
+ # Adding field 'Route.keywords'
+ db.add_column('chimere_route', 'keywords',
+ self.gf('django.db.models.fields.TextField')(max_length=200, null=True, blank=True),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Marker.keywords'
+ db.delete_column('chimere_marker', 'keywords')
+
+ # Deleting field 'Route.keywords'
+ db.delete_column('chimere_route', 'keywords')
+
+
+ models = {
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '6'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'filtr': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'multimedia_files'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pictures'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/models.py b/chimere/models.py
index 4c77211..15d264b 100644
--- a/chimere/models.py
+++ b/chimere/models.py
@@ -20,7 +20,7 @@
"""
Models description
"""
-import os, datetime, pyexiv2, re, string
+import os, datetime, pyexiv2, re, string, copy
import simplejson as json
from lxml import etree
from PIL import Image
@@ -427,6 +427,8 @@ class GeographicItem(models.Model):
submiter_comment = models.TextField(_(u"Submitter comment"), max_length=200,
blank=True, null=True)
status = models.CharField(_(u"Status"), max_length=1, choices=STATUS)
+ keywords = models.TextField(_(u"Keywords"), max_length=200,
+ blank=True, null=True)
import_key = models.CharField(_(u"Import key"), max_length=200,
blank=True, null=True)
import_version = models.IntegerField(_(u"Import version"),
@@ -695,35 +697,45 @@ class Marker(GeographicItem):
'''Return a GeoJSON string
'''
jsons = []
+ json_tpl = {"type":"Feature", "properties":{}}
for cat in self.categories.all():
if categories_id and cat.id not in categories_id:
continue
- items = {'id':self.id, 'name':json.dumps(self.name),
- 'geometry':self.point.geojson,
- 'icon_path':cat.icon.image,
+ items = copy.deepcopy(json_tpl)
+ items['geometry'] = json.loads(self.point.geojson)
+ items['properties'].update({
+ 'pk':self.id,
+ 'name':self.name,
+ 'icon_path':unicode(cat.icon.image),
'icon_hover_path':cat.hover_icon.image \
if cat.hover_icon else '',
- 'icon_width':cat.icon.image.width,
- 'icon_height':cat.icon.image.height,
- 'category_name':json.dumps(cat.name),}
+ 'category_name':cat.name})
items['weight'] = ''
if cat.weighted:
if not self.weight:
continue
+ items['weight'] = self.weight
+ if cat.color_theme and cat.color_theme.colors.count():
+ items['colors'] += ["#%s"] % '", "#'.join(
+ [color.code for color in cat.color_theme.colors.\
+ order_by('order').all()])
+ try:
+ items['properties'].update({'icon_width':cat.icon.image.width,
+ 'icon_height':cat.icon.image.height,})
+ except IOError:
+ pass
+ if cat.weighted:
+ if not self.weight:
+ continue
items['weight'] = u', "weight":%d' % self.weight
if cat.color_theme and cat.color_theme.colors.count():
items['weight'] += u', "colors":["#%s"]' % '", "#'.join(
[color.code for color in cat.color_theme.colors.\
order_by('order').all()])
- jsons.append(u'{"type":"Feature", "geometry":%(geometry)s, '\
- u'"properties":{"pk": %(id)d, "name": %(name)s, '\
- u'"icon_path":"%(icon_path)s", '\
- u'"icon_hover_path":"%(icon_hover_path)s", '\
- u'"icon_width":%(icon_width)d, '\
- u'"icon_height":%(icon_height)d, '\
- u'"category_name":%(category_name)s'\
- u'%(weight)s}}' % items)
- return ",".join(jsons)
+
+ jsons.append(items)
+
+ return json.dumps(jsons)
@property
def default_category(self):
@@ -1196,11 +1208,11 @@ class Route(GeographicItem):
'''
if '#' not in color:
color = '#' + color
- attributes = {'id':self.id, 'name':json.dumps(self.name),
- 'color':color, 'geometry':self.route.geojson,}
- return u'{"type":"Feature", "geometry":%(geometry)s, '\
- u'"properties":{"pk": %(id)d, "name": %(name)s, '\
- u'"color":"%(color)s"}}' % attributes
+ attributes = {"type":"Feature",
+ "geometry":json.loads(self.route.geojson),
+ "properties":{"pk":self.id, "name":self.name,
+ "color":color}}
+ return json.dumps(attributes)
def getTinyUrl(self):
parameters = 'current_feature=%d&checked_categories=%s' % (self.id,
@@ -1295,11 +1307,10 @@ class AggregatedRoute(models.Model):
'''
if '#' not in color:
color = '#' + color
- attributes = {'id':self.id, 'name':json.dumps(u'Aggregated route'),
- 'color':color, 'geometry':self.route.geojson,}
- return u'{"type":"Feature", "geometry":%(geometry)s, '\
- u'"properties":{"pk": %(id)d, "name": %(name)s, '\
- u'"color":"%(color)s"}}' % attributes
+ attributes = {'color':color, 'geometry':json.loads(self.route.geojson),
+ 'type':"Feature", "properties":{"pk": self.id,
+ "name": u'Aggregated route',}}
+ return json.dumps(attributes)
class SimplePoint:
"""
diff --git a/chimere/search_indexes.py b/chimere/search_indexes.py
index 5e4a69a..edf9bd1 100644
--- a/chimere/search_indexes.py
+++ b/chimere/search_indexes.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-# Copyright (C) 2014 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+# Copyright (C) 2014-2015 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
#
# This program is free software: you can redistribute it and/or modify
diff --git a/chimere/static/chimere/css/styles.css b/chimere/static/chimere/css/styles.css
index c41442e..98bc7ab 100644
--- a/chimere/static/chimere/css/styles.css
+++ b/chimere/static/chimere/css/styles.css
@@ -69,7 +69,7 @@ fieldset, .action li, #content,
background-color:#FFF;
}
-div.warning, .errorlist{
+div.warning, .errorlist, .errorlist legend{
background-color:#ffca64;
}
@@ -81,24 +81,6 @@ div.warning, .errorlist{
border:1px solid #54c200;
}
-#no-content .alert,
-#layer_selection h4,
-#layer_selection #layer_list,
-#maps, #detail, #main-map,
-div.warning,
-#content,
-.action li.selected,
-#content .olControlLayerSwitcher .layersDiv,
-#panel, #map-footer, #chimere_itinerary_panel,
-#search-box, #utils-div{
- border:1px solid #327e04;
-}
-
-
-.errorlist{
- border:1px solid #ff3f3f;
-}
-
/* rounded */
/* entête */
@@ -201,6 +183,12 @@ fieldset{
display:block;
}
+a[disabled] {
+ pointer-events: none;
+ cursor: default;
+ color: gray;
+}
+
#page_title{
position:absolute;
top:6px;
@@ -815,6 +803,10 @@ table.inline-table td input[type=file]{
margin-right: auto;
}
+#haystack-search .action-label{
+ display:none;
+}
+
#search-box{
position:absolute;
z-index:200;
@@ -1016,6 +1008,12 @@ ul#multimedia_list_content li.multimedia{
min-height:50px;
}
+.errorlist legend{
+ margin:0;
+ padding:0 10px;
+ border:none;
+}
+
p.legend{
padding:0;
margin:0;
diff --git a/chimere/static/chimere/js/base.js b/chimere/static/chimere/js/base.js
index 641f94a..b26d9f3 100644
--- a/chimere/static/chimere/js/base.js
+++ b/chimere/static/chimere/js/base.js
@@ -141,3 +141,9 @@ function share_link_update(){
return false;
});
}
+
+$("a").on("click", function(event){
+ if ($(this).is("[disabled]")) {
+ event.preventDefault();
+ }
+});
diff --git a/chimere/static/chimere/js/jquery.chimere-ol.js b/chimere/static/chimere/js/jquery.chimere-ol.js
index 251c09c..ae3e340 100644
--- a/chimere/static/chimere/js/jquery.chimere-ol.js
+++ b/chimere/static/chimere/js/jquery.chimere-ol.js
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008-2014 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+/* Copyright (C) 2008-2015 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as
@@ -461,8 +461,36 @@ if (typeof(OpenLayers) != 'undefined'){
methods.routingAddStep();
}
}
+
+ // verify that the initial display_feature is displayed
+ if (settings.display_feature){
+ var is_displayed = false;
+ for(j=0; j<settings.layerMarkers.markers.length;j++){
+ var c_marker = settings.layerMarkers.markers[j];
+ if(c_marker.pk == settings.display_feature){
+ is_displayed = true;
+ }
+ }
+ if (!is_displayed){
+ methods.loadMarker(settings.display_feature);
+ }
+ }
+ methods.update_permalink_activation();
+
methods.preload_images();
}, // end of init
+ update_permalink_activation:function(){
+ if (settings.checked_categories.length ||
+ settings.current_feature ||
+ settings.routing_speed ||
+ settings.routing_transport ||
+ settings.routing_start ||
+ settings.routing_end){
+ $("#permalink a").removeAttr("disabled");
+ } else {
+ $("#permalink a").attr("disabled", "disabled");
+ }
+ },
/* Preload icons */
preload_images: function(){
if (typeof extra_url == 'undefined') return;
@@ -601,6 +629,15 @@ if (typeof(OpenLayers) != 'undefined'){
$('#chimere_map_menu').css('left', offsetX);
}
},
+ loadMarker: function(object_id) {
+ var uri = extra_url + "get-marker/" + object_id;
+ $.ajax({url: uri,
+ dataType: "json",
+ success: function (data) {
+ for (idx in data) methods.addMarker(data[idx]);
+ }
+ });
+ },
/*
* Load markers and route from DB
*/
@@ -646,6 +683,7 @@ if (typeof(OpenLayers) != 'undefined'){
},
complete: function () {
if($('#waiting').length){$('#waiting').hide();}
+ methods.update_permalink_activation();
}
});
},
@@ -725,6 +763,7 @@ if (typeof(OpenLayers) != 'undefined'){
settings.permalink.updateLink();
});
$('.subcategories li input').bind("click", function (e) {
+ $('#search-result').html('');
var c_name = $(this).attr('name');
c_name = c_name.substr(c_name.lastIndexOf("_")+1);
if($(this).is(':checked')){
@@ -875,6 +914,7 @@ if (typeof(OpenLayers) != 'undefined'){
settings.current_popup.groupDiv.onclick = methods.hidePopup;
}
settings.permalink.updateLink();
+ methods.update_permalink_activation();
}
var _repan_popup = function(){
/* re-pan manually */
@@ -1598,9 +1638,10 @@ if (typeof(OpenLayers) != 'undefined'){
var c_marker = settings.layerMarkers.markers[j];
if(c_marker.pk == feature_pk){
c_marker.events.triggerEvent('click');
- return
+ return true
}
}
+ return false;
//feature.markerClick();
//OpenLayers.Popup.popupSelect.clickFeature(feature);
/*
@@ -1618,6 +1659,7 @@ if (typeof(OpenLayers) != 'undefined'){
else { // Default behaviour
if (settings.current_popup)
{
+ settings.current_feature = null;
if (!settings.simple){
$('#detail').fadeOut();
}
@@ -1625,10 +1667,12 @@ if (typeof(OpenLayers) != 'undefined'){
settings.current_popup.hide();
if(evt)
settings.map.events.triggerEvent('click', evt);
+ methods.update_permalink_activation();
return true;
}
}
}
+ methods.update_permalink_activation();
return false;
},
saveExtent: function(){
diff --git a/chimere/static/chimere/js/search-autocomplete.js b/chimere/static/chimere/js/search-autocomplete.js
index cd1b0e1..5e8a85e 100644
--- a/chimere/static/chimere/js/search-autocomplete.js
+++ b/chimere/static/chimere/js/search-autocomplete.js
@@ -1,5 +1,6 @@
-var no_result_message = "No exact match.";
+var do_you_mean = "Do you mean: ";
+var end_do_you_mean = "?";
var Autocomplete = function(options) {
this.form_selector = options.form_selector;
@@ -30,14 +31,23 @@ Autocomplete.prototype.setup = function() {
}
self.fetch(query);
- })
+ });
// on selecting a result, populate the search field.
this.form_elem.on('click', '.ac-result', function(ev) {
self.query_box.val($(this).text());
$('.ac-results').remove();
+ $('#spelling').fadeOut();
return false;
- })
+ });
+
+ // on selecting a suggestion, populate the search field.
+ $('#search-box').on('click', '.spelling-item', function(ev) {
+ self.query_box.val($(this).text());
+ $('.ac-results').remove();
+ $('#spelling').fadeOut();
+ return false;
+ });
}
Autocomplete.prototype.fetch = function(query) {
@@ -47,11 +57,38 @@ Autocomplete.prototype.fetch = function(query) {
url: this.url,
data: { 'q': query },
success: function(data) {
- self.show_results(data);
+ if(data.results.length){
+ self.show_results(data);
+ } else {
+ $('.ac-results').remove();
+ }
+ if(data.spelling.length){
+ self.show_spelling(data.spelling)
+ } else {
+ $("#spelling").fadeOut();
+ }
+ return true;
}
})
}
+Autocomplete.prototype.show_spelling = function(spelling) {
+ var text = do_you_mean;
+ var base_elem = '<a href="#" class="spelling-item">'
+ var end_base_elem = '</a>';
+ for(var offset in spelling) {
+ if (offset > 0){
+ text += ", ";
+ }
+ text += base_elem;
+ text += spelling[offset];
+ text += end_base_elem;
+ }
+ text += end_do_you_mean;
+ $("#spelling").html(text);
+ $("#spelling").fadeIn();
+}
+
Autocomplete.prototype.show_results = function(data) {
// Remove any existing results.
$('.ac-results').remove();
@@ -60,17 +97,10 @@ Autocomplete.prototype.show_results = function(data) {
var results_wrapper = $('<div class="ac-results"></div>');
var base_elem = $('<div class="result-wrapper"><a href="#" class="ac-result"></a></div>');
- if(results.length > 0) {
- for(var res_offset in results) {
- var elem = base_elem.clone();
- // don't use .html(...) here, as it opens to XSS.
- elem.find('.ac-result').text(results[res_offset]);
- results_wrapper.append(elem);
- }
- }
- else {
+ for(var res_offset in results) {
var elem = base_elem.clone();
- elem.text(no_result_message);
+ // don't use .html(...) here, as it opens to XSS.
+ elem.find('.ac-result').text(results[res_offset]);
results_wrapper.append(elem);
}
diff --git a/chimere/templates/chimere/edit.html b/chimere/templates/chimere/edit.html
index 8322c50..be97606 100644
--- a/chimere/templates/chimere/edit.html
+++ b/chimere/templates/chimere/edit.html
@@ -56,6 +56,12 @@
{{ form.description }}
<p class="help">{{ form.description.help_text }}</p>
</div>
+ <div class="fieldWrapper">
+ <label for="id_keywords">{% trans "Keywords" %}</label>
+ {{ form.keywords.errors }}
+ {{ form.keywords }}
+ <p class="help">{{ form.keywords.help_text }}</p>
+ </div>
{% if dated %}
<div class="fieldWrapper dated_field">
<label for="id_start_date">{% trans "Start date" %}</label>
diff --git a/chimere/templates/chimere/main_map_simple.html b/chimere/templates/chimere/main_map_simple.html
index 4a1b603..4e93f8c 100644
--- a/chimere/templates/chimere/main_map_simple.html
+++ b/chimere/templates/chimere/main_map_simple.html
@@ -7,7 +7,7 @@
{% block sidebar %}
<div id='panel'>
<a href='#' onclick='showHide("categories")'>
- <h2>{% trans "Categories"%}</h2>
+ <h2 class='btn'>{% trans "Categories"%}</h2>
</a>
<form method='post' name='frm_categories' id='frm_categories'>
<div id='categories' name='categories'></div>
diff --git a/chimere/templates/search/indexes/chimere/marker_text.txt b/chimere/templates/search/indexes/chimere/marker_text.txt
index ad5bae1..7c7929d 100644
--- a/chimere/templates/search/indexes/chimere/marker_text.txt
+++ b/chimere/templates/search/indexes/chimere/marker_text.txt
@@ -1,3 +1,4 @@
{% load unescape %}
{{object.name}}
{{object.description|safe|striptags|unescape}}
+{{object.keywords}}
diff --git a/chimere/templates/search/indexes/chimere/route_text.txt b/chimere/templates/search/indexes/chimere/route_text.txt
index 2fad18d..5e612cd 100644
--- a/chimere/templates/search/indexes/chimere/route_text.txt
+++ b/chimere/templates/search/indexes/chimere/route_text.txt
@@ -1 +1,2 @@
{{object.name}}
+{{object.keywords}}
diff --git a/chimere/templates/search/search.html b/chimere/templates/search/search.html
index b40359a..95d3937 100644
--- a/chimere/templates/search/search.html
+++ b/chimere/templates/search/search.html
@@ -1,18 +1,10 @@
{% load url from future %}{% load i18n %}
-{% if query %}
<script type='text/javascript'>
-var geo_objects = [{% for result in page.object_list %}{{result.object.getGeoJSON|safe}}{% if not forloop.last %}, {% endif %}{% endfor %}];
-var geo_features = {};
-for (idx=0 ; idx < geo_objects.length ; idx++){
- var c_idx = geo_objects[idx].properties.pk;
- if (search_result.indexOf(c_idx) == -1){
- search_result.push(c_idx);
- geo_features[c_idx] = $('#main-map').chimere('addMarker',
- geo_objects[idx]);
- }
-}
-{% if page.object_list.count %}$("#main-map").chimere("zoomToMarkerExtent");{% endif %}
+var do_you_mean = "{% trans 'Do you mean: ' %}";
+var end_do_you_mean = "{% trans '?' %}";
</script>
+{% if query %}
+{% include "search/search_js.html" %}
<div id='search-listing'>
<ul>
{% for result in page.object_list %}
@@ -26,16 +18,21 @@ for (idx=0 ; idx < geo_objects.length ; idx++){
</div>
{% if page.has_previous or page.has_next %}
<div id='search-nav'>
- {% if page.has_previous %}<a href="#" onclick="haystack_search(this, {{ page.previous_page_number }});">{% trans "Previous" %}</a>{% endif %}
- {% if page.has_next %}<a href="#" onclick="haystack_search(this, {{ page.next_page_number }});">{% trans "More results..." %}</a>{% endif %}
+ <nav>
+ <ul class="pager">
+ {% if page.has_previous %}<li class="previous"><a href="#" onclick="haystack_search(this, {{ page.previous_page_number }});">&larr; {% trans "Previous" %}</a></li>{% endif %}
+ {% if page.has_next %}<li class="next"><a href="#" onclick="haystack_search(this, {{ page.next_page_number }});">{% trans "More results..." %} &rarr;</a></li>{% endif %}
+ </ul>
+ </nav>
</div>
{% endif %}
{% else %}
<form id='search-form' class='autocomplete-me'>
<input type="text" id="id_q" name="q" autocomplete="off"/>
- <button name='haystack-search' id='haystack-search' type='button' disabled='disabled' class="btn btn-default">{% trans "Search" %}</button>
+ <button name='haystack-search' id='haystack-search' type='button' disabled='disabled' class="btn btn-default"><span class='action-label'>{% trans "Search" %} </span><span class="glyphicon glyphicon-search"></span></button>
</form>
+<div id='spelling'></div>
<div id='search-result'></div>
<script type='text/javascript'>
no_result_message = "{% trans 'No exact match.' %}";
diff --git a/chimere/templates/search/search_js.html b/chimere/templates/search/search_js.html
new file mode 100644
index 0000000..c8d9812
--- /dev/null
+++ b/chimere/templates/search/search_js.html
@@ -0,0 +1,24 @@
+<script type='text/javascript'>
+$(function(){
+ // clean checked categories
+ $('.subcategory').each(function(){ $(this).removeClass('selected'); });
+ $('.subcategory input[type=checkbox]').attr('checked', false);
+
+ var geo_objects = [];
+ {% for result in page.object_list %}var c_lst ={{result.object.getGeoJSON|safe}};
+ for (idx in c_lst){
+ geo_objects.push(c_lst[idx]);
+ }{% endfor %}
+ var geo_features = {};
+ for (idx=0 ; idx < geo_objects.length ; idx++){
+ var c_idx = geo_objects[idx].properties.pk;
+ if (search_result.indexOf(c_idx) == -1){
+ search_result.push(c_idx);
+ geo_features[c_idx] = $('#main-map').chimere('addMarker',
+ geo_objects[idx]);
+ }
+ }
+ window.setTimeout(function(){$("#main-map").chimere("zoomToMarkerExtent")}, 500);
+});
+</script>
+
diff --git a/chimere/urls.py b/chimere/urls.py
index 30ca844..256c08f 100644
--- a/chimere/urls.py
+++ b/chimere/urls.py
@@ -106,6 +106,8 @@ urlpatterns += patterns('chimere.views',
name="getgeoobjects"),
url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?getAvailableCategories/$',
'get_available_categories', name="get_categories"),
+ url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?get-marker/'\
+ r'(?P<pk>[0-9]+)$', 'getMarker', name="get-marker"),
url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?getAllCategories/$',
'get_all_categories', name="get_all_categories"),
url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?getCategory/(?P<category_id>\d+)/?$',
diff --git a/chimere/views.py b/chimere/views.py
index 01179e4..4ca2498 100644
--- a/chimere/views.py
+++ b/chimere/views.py
@@ -28,6 +28,7 @@ import copy
import datetime
from itertools import groupby
import re
+import simplejson as json
from django.conf import settings
from django.contrib.auth import authenticate, login, logout
@@ -688,7 +689,14 @@ def getGeoObjects(request, map_name, category_ids, status):
data = {"type": "FeatureCollection", "features":jsons}
data = json.dumps(data)
- return HttpResponse(data)
+ return HttpResponse(data, content_type="application/json")
+
+def getMarker(request, map_name, pk):
+ q = Marker.objects.filter(pk=pk, status='A')
+ if not q.count():
+ return HttpResponse('{}')
+ data = q.all()[0].getGeoJSON()
+ return HttpResponse(data, content_type="application/json")
def get_all_categories(request, map_name=None):
'''
@@ -1023,9 +1031,15 @@ if hasattr(settings, 'CHIMERE_SEARCH_ENGINE') \
sqs = SearchQuerySet().autocomplete(
content_auto=request.GET.get('q', ''))[:5]
suggestions = [result.object.name for result in sqs if result.object]
+ spelling = []
+ if not suggestions:
+ spelling = SearchQuerySet().spelling_suggestion(
+ request.GET.get('q', '')) or []
+ # convert to list spelling...
# make sure it returns a JSON object, not a bare list.
# otherwise, it could be vulnerable to an XSS attack.
the_data = json.dumps({
- 'results': suggestions
+ 'results': suggestions,
+ 'spelling':spelling,
})
return HttpResponse(the_data, content_type='application/json')
diff --git a/conf/solr/schema-fr.xml b/conf/solr/schema-fr.xml
new file mode 100644
index 0000000..68605c8
--- /dev/null
+++ b/conf/solr/schema-fr.xml
@@ -0,0 +1,166 @@
+<?xml version="1.0" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<schema name="default" version="1.4">
+ <types>
+ <fieldtype name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
+ <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true" omitNorms="true"/>
+ <fieldtype name="binary" class="solr.BinaryField"/>
+
+ <!-- Numeric field types that manipulate the value into
+ a string value that isn't human-readable in its internal form,
+ but with a lexicographic ordering the same as the numeric ordering,
+ so that range queries work correctly. -->
+ <fieldType name="int" class="solr.TrieIntField" precisionStep="0" omitNorms="true" sortMissingLast="true" positionIncrementGap="0"/>
+ <fieldType name="float" class="solr.TrieFloatField" precisionStep="0" omitNorms="true" sortMissingLast="true" positionIncrementGap="0"/>
+ <fieldType name="long" class="solr.TrieLongField" precisionStep="0" omitNorms="true" sortMissingLast="true" positionIncrementGap="0"/>
+ <fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" omitNorms="true" sortMissingLast="true" positionIncrementGap="0"/>
+
+ <fieldType name="tint" class="solr.TrieIntField" precisionStep="8" omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="tfloat" class="solr.TrieFloatField" precisionStep="8" omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="tlong" class="solr.TrieLongField" precisionStep="8" omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="tdouble" class="solr.TrieDoubleField" precisionStep="8" omitNorms="true" positionIncrementGap="0"/>
+
+ <fieldType name="date" class="solr.TrieDateField" omitNorms="true" precisionStep="0" positionIncrementGap="0"/>
+ <!-- A Trie based date field for faster date range queries and date faceting. -->
+ <fieldType name="tdate" class="solr.TrieDateField" omitNorms="true" precisionStep="6" positionIncrementGap="0"/>
+
+ <fieldType name="point" class="solr.PointType" dimension="2" subFieldSuffix="_d"/>
+ <fieldType name="location" class="solr.LatLonType" subFieldSuffix="_coordinate"/>
+ <fieldtype name="geohash" class="solr.GeoHashField"/>
+
+ <fieldType name="text_general" class="solr.TextField" positionIncrementGap="100">
+ <analyzer type="index">
+ <tokenizer class="solr.StandardTokenizerFactory"/>
+ <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" enablePositionIncrements="true" />
+ <!-- in this example, we will only use synonyms at query time
+ <filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>
+ -->
+ <filter class="solr.LowerCaseFilterFactory"/>
+ </analyzer>
+ <analyzer type="query">
+ <tokenizer class="solr.StandardTokenizerFactory"/>
+ <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" enablePositionIncrements="true" />
+ <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
+ <filter class="solr.LowerCaseFilterFactory"/>
+ </analyzer>
+ </fieldType>
+
+ <fieldType name="text_fr" class="solr.TextField" positionIncrementGap="100">
+ <analyzer type="index">
+ <tokenizer class="solr.StandardTokenizerFactory"/>
+ <filter class="solr.StopFilterFactory"
+ ignoreCase="true"
+ words="lang/stopwords_fr.txt"
+ enablePositionIncrements="true"
+ />
+ <filter class="solr.LowerCaseFilterFactory"/>
+
+ <filter class="solr.ElisionFilterFactory" ignoreCase="true" articles="lang/contractions_fr.txt"/>
+ <filter class="solr.LowerCaseFilterFactory"/>
+ <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_fr.txt" format="snowball" enablePositionIncrements="true"/>
+ <filter class="solr.FrenchLightStemFilterFactory"/>
+ </analyzer>
+ <analyzer type="query">
+ <tokenizer class="solr.StandardTokenizerFactory"/>
+ <filter class="solr.StopFilterFactory"
+ ignoreCase="true"
+ words="lang/stopwords_fr.txt"
+ enablePositionIncrements="true"
+ />
+ <filter class="solr.LowerCaseFilterFactory"/>
+
+ <filter class="solr.ElisionFilterFactory" ignoreCase="true" articles="lang/contractions_fr.txt"/>
+ <filter class="solr.LowerCaseFilterFactory"/>
+ <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_fr.txt" format="snowball" enablePositionIncrements="true"/>
+ <filter class="solr.FrenchLightStemFilterFactory"/>
+ </analyzer>
+ </fieldType>
+
+ <fieldType name="text_ws" class="solr.TextField" positionIncrementGap="100">
+ <analyzer>
+ <tokenizer class="solr.WhitespaceTokenizerFactory"/>
+ </analyzer>
+ </fieldType>
+
+ <fieldType name="ngram" class="solr.TextField" >
+ <analyzer type="index">
+ <tokenizer class="solr.KeywordTokenizerFactory"/>
+ <filter class="solr.LowerCaseFilterFactory"/>
+ <filter class="solr.NGramFilterFactory" minGramSize="3" maxGramSize="15" />
+ </analyzer>
+ <analyzer type="query">
+ <tokenizer class="solr.KeywordTokenizerFactory"/>
+ <filter class="solr.LowerCaseFilterFactory"/>
+ </analyzer>
+ </fieldType>
+
+ <fieldType name="edge_ngram" class="solr.TextField" positionIncrementGap="1">
+ <analyzer type="index">
+ <tokenizer class="solr.WhitespaceTokenizerFactory" />
+ <filter class="solr.LowerCaseFilterFactory" />
+ <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/>
+ <filter class="solr.EdgeNGramFilterFactory" minGramSize="2" maxGramSize="15" side="front" />
+ </analyzer>
+ <analyzer type="query">
+ <tokenizer class="solr.WhitespaceTokenizerFactory" />
+ <filter class="solr.LowerCaseFilterFactory" />
+ <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/>
+ </analyzer>
+ </fieldType>
+ </types>
+
+ <fields>
+ <!-- general -->
+ <field name="id" type="string" indexed="true" stored="true" multiValued="false" required="true"/>
+ <field name="django_ct" type="string" indexed="true" stored="true" multiValued="false"/>
+ <field name="django_id" type="string" indexed="true" stored="true" multiValued="false"/>
+
+ <dynamicField name="*_i" type="int" indexed="true" stored="true"/>
+ <dynamicField name="*_s" type="string" indexed="true" stored="true"/>
+ <dynamicField name="*_l" type="long" indexed="true" stored="true"/>
+ <dynamicField name="*_t" type="text_fr" indexed="true" stored="true"/>
+ <dynamicField name="*_b" type="boolean" indexed="true" stored="true"/>
+ <dynamicField name="*_f" type="float" indexed="true" stored="true"/>
+ <dynamicField name="*_d" type="double" indexed="true" stored="true"/>
+ <dynamicField name="*_dt" type="date" indexed="true" stored="true"/>
+ <dynamicField name="*_p" type="location" indexed="true" stored="true"/>
+ <dynamicField name="*_coordinate" type="tdouble" indexed="true" stored="false"/>
+
+
+ <field name="text" type="text_fr" indexed="true" stored="true" multiValued="false" />
+
+ <field name="location" type="location" indexed="true" stored="true" multiValued="false" />
+
+ <field name="categories" type="text_fr" indexed="true" stored="true" multiValued="true" />
+
+ <field name="content_auto" type="edge_ngram" indexed="true" stored="true" multiValued="false" />
+
+ </fields>
+
+ <!-- field to use to determine and enforce document uniqueness. -->
+ <uniqueKey>id</uniqueKey>
+
+ <!-- field for the QueryParser to use when an explicit fieldname is absent -->
+ <defaultSearchField>text</defaultSearchField>
+
+ <!-- SolrQueryParser configuration: defaultOperator="AND|OR" -->
+ <solrQueryParser defaultOperator="AND"/>
+</schema>
+
+
diff --git a/conf/solr/schema.xml b/conf/solr/schema.xml
new file mode 100644
index 0000000..ba25e5c
--- /dev/null
+++ b/conf/solr/schema.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<schema name="default" version="1.4">
+ <types>
+ <fieldtype name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
+ <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true" omitNorms="true"/>
+ <fieldtype name="binary" class="solr.BinaryField"/>
+
+ <!-- Numeric field types that manipulate the value into
+ a string value that isn't human-readable in its internal form,
+ but with a lexicographic ordering the same as the numeric ordering,
+ so that range queries work correctly. -->
+ <fieldType name="int" class="solr.TrieIntField" precisionStep="0" omitNorms="true" sortMissingLast="true" positionIncrementGap="0"/>
+ <fieldType name="float" class="solr.TrieFloatField" precisionStep="0" omitNorms="true" sortMissingLast="true" positionIncrementGap="0"/>
+ <fieldType name="long" class="solr.TrieLongField" precisionStep="0" omitNorms="true" sortMissingLast="true" positionIncrementGap="0"/>
+ <fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" omitNorms="true" sortMissingLast="true" positionIncrementGap="0"/>
+
+ <fieldType name="tint" class="solr.TrieIntField" precisionStep="8" omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="tfloat" class="solr.TrieFloatField" precisionStep="8" omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="tlong" class="solr.TrieLongField" precisionStep="8" omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="tdouble" class="solr.TrieDoubleField" precisionStep="8" omitNorms="true" positionIncrementGap="0"/>
+
+ <fieldType name="date" class="solr.TrieDateField" omitNorms="true" precisionStep="0" positionIncrementGap="0"/>
+ <!-- A Trie based date field for faster date range queries and date faceting. -->
+ <fieldType name="tdate" class="solr.TrieDateField" omitNorms="true" precisionStep="6" positionIncrementGap="0"/>
+
+ <fieldType name="point" class="solr.PointType" dimension="2" subFieldSuffix="_d"/>
+ <fieldType name="location" class="solr.LatLonType" subFieldSuffix="_coordinate"/>
+ <fieldtype name="geohash" class="solr.GeoHashField"/>
+
+ <fieldType name="text_general" class="solr.TextField" positionIncrementGap="100">
+ <analyzer type="index">
+ <tokenizer class="solr.StandardTokenizerFactory"/>
+ <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" enablePositionIncrements="true" />
+ <!-- in this example, we will only use synonyms at query time
+ <filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>
+ -->
+ <filter class="solr.LowerCaseFilterFactory"/>
+ </analyzer>
+ <analyzer type="query">
+ <tokenizer class="solr.StandardTokenizerFactory"/>
+ <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" enablePositionIncrements="true" />
+ <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
+ <filter class="solr.LowerCaseFilterFactory"/>
+ </analyzer>
+ </fieldType>
+
+ <fieldType name="text_en" class="solr.TextField" positionIncrementGap="100">
+ <analyzer type="index">
+ <tokenizer class="solr.StandardTokenizerFactory"/>
+ <filter class="solr.StopFilterFactory"
+ ignoreCase="true"
+ words="stopwords_en.txt"
+ enablePositionIncrements="true"
+ />
+ <filter class="solr.LowerCaseFilterFactory"/>
+ <filter class="solr.EnglishPossessiveFilterFactory"/>
+ <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
+ <!-- Optionally you may want to use this less aggressive stemmer instead of PorterStemFilterFactory:
+ <filter class="solr.EnglishMinimalStemFilterFactory"/>
+ -->
+ <filter class="solr.PorterStemFilterFactory"/>
+ </analyzer>
+ <analyzer type="query">
+ <tokenizer class="solr.StandardTokenizerFactory"/>
+ <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
+ <filter class="solr.StopFilterFactory"
+ ignoreCase="true"
+ words="stopwords_en.txt"
+ enablePositionIncrements="true"
+ />
+ <filter class="solr.LowerCaseFilterFactory"/>
+ <filter class="solr.EnglishPossessiveFilterFactory"/>
+ <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
+ <!-- Optionally you may want to use this less aggressive stemmer instead of PorterStemFilterFactory:
+ <filter class="solr.EnglishMinimalStemFilterFactory"/>
+ -->
+ <filter class="solr.PorterStemFilterFactory"/>
+ </analyzer>
+ </fieldType>
+
+ <fieldType name="text_ws" class="solr.TextField" positionIncrementGap="100">
+ <analyzer>
+ <tokenizer class="solr.WhitespaceTokenizerFactory"/>
+ </analyzer>
+ </fieldType>
+
+ <fieldType name="ngram" class="solr.TextField" >
+ <analyzer type="index">
+ <tokenizer class="solr.KeywordTokenizerFactory"/>
+ <filter class="solr.LowerCaseFilterFactory"/>
+ <filter class="solr.NGramFilterFactory" minGramSize="3" maxGramSize="15" />
+ </analyzer>
+ <analyzer type="query">
+ <tokenizer class="solr.KeywordTokenizerFactory"/>
+ <filter class="solr.LowerCaseFilterFactory"/>
+ </analyzer>
+ </fieldType>
+
+ <fieldType name="edge_ngram" class="solr.TextField" positionIncrementGap="1">
+ <analyzer type="index">
+ <tokenizer class="solr.WhitespaceTokenizerFactory" />
+ <filter class="solr.LowerCaseFilterFactory" />
+ <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/>
+ <filter class="solr.EdgeNGramFilterFactory" minGramSize="2" maxGramSize="15" side="front" />
+ </analyzer>
+ <analyzer type="query">
+ <tokenizer class="solr.WhitespaceTokenizerFactory" />
+ <filter class="solr.LowerCaseFilterFactory" />
+ <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/>
+ </analyzer>
+ </fieldType>
+ </types>
+
+ <fields>
+ <!-- general -->
+ <field name="id" type="string" indexed="true" stored="true" multiValued="false" required="true"/>
+ <field name="django_ct" type="string" indexed="true" stored="true" multiValued="false"/>
+ <field name="django_id" type="string" indexed="true" stored="true" multiValued="false"/>
+
+ <dynamicField name="*_i" type="int" indexed="true" stored="true"/>
+ <dynamicField name="*_s" type="string" indexed="true" stored="true"/>
+ <dynamicField name="*_l" type="long" indexed="true" stored="true"/>
+ <dynamicField name="*_t" type="text_en" indexed="true" stored="true"/>
+ <dynamicField name="*_b" type="boolean" indexed="true" stored="true"/>
+ <dynamicField name="*_f" type="float" indexed="true" stored="true"/>
+ <dynamicField name="*_d" type="double" indexed="true" stored="true"/>
+ <dynamicField name="*_dt" type="date" indexed="true" stored="true"/>
+ <dynamicField name="*_p" type="location" indexed="true" stored="true"/>
+ <dynamicField name="*_coordinate" type="tdouble" indexed="true" stored="false"/>
+
+
+ <field name="text" type="text_en" indexed="true" stored="true" multiValued="false" />
+
+ <field name="location" type="location" indexed="true" stored="true" multiValued="false" />
+
+ <field name="categories" type="text_en" indexed="true" stored="true" multiValued="true" />
+
+ <field name="content_auto" type="edge_ngram" indexed="true" stored="true" multiValued="false" />
+
+ </fields>
+
+ <!-- field to use to determine and enforce document uniqueness. -->
+ <uniqueKey>id</uniqueKey>
+
+ <!-- field for the QueryParser to use when an explicit fieldname is absent -->
+ <defaultSearchField>text</defaultSearchField>
+
+ <!-- SolrQueryParser configuration: defaultOperator="AND|OR" -->
+ <solrQueryParser defaultOperator="AND"/>
+</schema>
+