diff options
author | Étienne Loks <etienne.loks@proxience.com> | 2015-02-22 21:04:43 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@proxience.com> | 2015-02-22 21:04:43 +0100 |
commit | 906a299b4c07d4e6f0a31cd6504926cf7ff7cc66 (patch) | |
tree | 6f05955d3b12933817813d02a1c7aaa856e3efe7 | |
parent | 49a981c28c1c47ee548859f0490fa157acf9b1ba (diff) | |
parent | ed6c1559c44bdc3214cd2dffb377359601b28a33 (diff) | |
download | Chimère-906a299b4c07d4e6f0a31cd6504926cf7ff7cc66.tar.bz2 Chimère-906a299b4c07d4e6f0a31cd6504926cf7ff7cc66.zip |
Merge branch 'v2.2'
Conflicts:
chimere/admin.py
chimere/models.py
chimere/static/chimere/css/styles.css
chimere/urls.py
chimere/views.py
-rw-r--r-- | chimere/admin.py | 2 | ||||
-rw-r--r-- | chimere/forms.py | 1 | ||||
-rw-r--r-- | chimere/migrations/0009_auto__add_field_marker_keywords__add_field_route_keywords.py | 298 | ||||
-rw-r--r-- | chimere/models.py | 63 | ||||
-rw-r--r-- | chimere/search_indexes.py | 2 | ||||
-rw-r--r-- | chimere/static/chimere/css/styles.css | 36 | ||||
-rw-r--r-- | chimere/static/chimere/js/base.js | 6 | ||||
-rw-r--r-- | chimere/static/chimere/js/jquery.chimere-ol.js | 48 | ||||
-rw-r--r-- | chimere/static/chimere/js/search-autocomplete.js | 58 | ||||
-rw-r--r-- | chimere/templates/chimere/edit.html | 6 | ||||
-rw-r--r-- | chimere/templates/chimere/main_map_simple.html | 2 | ||||
-rw-r--r-- | chimere/templates/search/indexes/chimere/marker_text.txt | 1 | ||||
-rw-r--r-- | chimere/templates/search/indexes/chimere/route_text.txt | 1 | ||||
-rw-r--r-- | chimere/templates/search/search.html | 27 | ||||
-rw-r--r-- | chimere/templates/search/search_js.html | 24 | ||||
-rw-r--r-- | chimere/urls.py | 2 | ||||
-rw-r--r-- | chimere/views.py | 18 | ||||
-rw-r--r-- | conf/solr/schema-fr.xml | 166 | ||||
-rw-r--r-- | conf/solr/schema.xml | 168 |
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 }});">← {% 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..." %} →</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> + |