+ ...
+
+Take a look at the right side of the navbar:
+
+.. figure:: ../img/custom_right_menu.png
+
+The custom menus seen so far are based on a fixed html template, the :file:`base/templates/menu.html`, hooked to the **render_nav_menu** tag. Feel free to create new placeholders and menus through this powerful template tag, it makes the menus creation very fast in the top navbar but it's not flexible enough to allow to choose a different position.
+So more generic tags has been implemented in GeoNode to have more customization power.
+
+The **get_menu** assignment tag, included in the `base_tags`, lets you decide how to render the menus returning only their data in a dictionary like this:
+
+.. code-block:: html
+
+ {
+
: , ]>,
+ : , ]>,
+ ...
+ }
+
+You can easily use those data to build `Bootstrap `_ dropdowns or an accordion panels and put them wherever you want.
+
+Styling options
+---------------
+
You are able to change any specific piece of your GeoNode project's style by adding CSS rules to :file:`site_base.css`, but since GeoNode is based on Bootstrap, there are many pre-defined themes that you can simply drop into your project to get a whole new look. This is very similar to `WordPress `_ themes and is a powerful and easy way to change the look of your site without much effort.
Bootswatch
diff --git a/docs/tutorials/admin/customize_lookfeel/img/admin_base_section.png b/docs/tutorials/admin/customize_lookfeel/img/admin_base_section.png
new file mode 100644
index 00000000000..687ab70987e
Binary files /dev/null and b/docs/tutorials/admin/customize_lookfeel/img/admin_base_section.png differ
diff --git a/docs/tutorials/admin/customize_lookfeel/img/admin_menu.png b/docs/tutorials/admin/customize_lookfeel/img/admin_menu.png
new file mode 100644
index 00000000000..61769d64231
Binary files /dev/null and b/docs/tutorials/admin/customize_lookfeel/img/admin_menu.png differ
diff --git a/docs/tutorials/admin/customize_lookfeel/img/admin_menu_2.png b/docs/tutorials/admin/customize_lookfeel/img/admin_menu_2.png
new file mode 100644
index 00000000000..e78667d633d
Binary files /dev/null and b/docs/tutorials/admin/customize_lookfeel/img/admin_menu_2.png differ
diff --git a/docs/tutorials/admin/customize_lookfeel/img/admin_menu_item_1_1.png b/docs/tutorials/admin/customize_lookfeel/img/admin_menu_item_1_1.png
new file mode 100644
index 00000000000..4b6b5a95383
Binary files /dev/null and b/docs/tutorials/admin/customize_lookfeel/img/admin_menu_item_1_1.png differ
diff --git a/docs/tutorials/admin/customize_lookfeel/img/admin_menu_item_1_2.png b/docs/tutorials/admin/customize_lookfeel/img/admin_menu_item_1_2.png
new file mode 100644
index 00000000000..c22de52cc76
Binary files /dev/null and b/docs/tutorials/admin/customize_lookfeel/img/admin_menu_item_1_2.png differ
diff --git a/docs/tutorials/admin/customize_lookfeel/img/admin_menu_item_2_1.png b/docs/tutorials/admin/customize_lookfeel/img/admin_menu_item_2_1.png
new file mode 100644
index 00000000000..b962ec40ac4
Binary files /dev/null and b/docs/tutorials/admin/customize_lookfeel/img/admin_menu_item_2_1.png differ
diff --git a/docs/tutorials/admin/customize_lookfeel/img/admin_menu_placeholder_initial_data.png b/docs/tutorials/admin/customize_lookfeel/img/admin_menu_placeholder_initial_data.png
new file mode 100644
index 00000000000..b81e998f60b
Binary files /dev/null and b/docs/tutorials/admin/customize_lookfeel/img/admin_menu_placeholder_initial_data.png differ
diff --git a/docs/tutorials/admin/customize_lookfeel/img/admin_menu_placeholders.png b/docs/tutorials/admin/customize_lookfeel/img/admin_menu_placeholders.png
new file mode 100644
index 00000000000..0cad15a1d5d
Binary files /dev/null and b/docs/tutorials/admin/customize_lookfeel/img/admin_menu_placeholders.png differ
diff --git a/docs/tutorials/admin/customize_lookfeel/img/custom_menu_1.png b/docs/tutorials/admin/customize_lookfeel/img/custom_menu_1.png
new file mode 100644
index 00000000000..395cda5f4ec
Binary files /dev/null and b/docs/tutorials/admin/customize_lookfeel/img/custom_menu_1.png differ
diff --git a/docs/tutorials/admin/customize_lookfeel/img/custom_menu_2.png b/docs/tutorials/admin/customize_lookfeel/img/custom_menu_2.png
new file mode 100644
index 00000000000..9fc19c4af3c
Binary files /dev/null and b/docs/tutorials/admin/customize_lookfeel/img/custom_menu_2.png differ
diff --git a/docs/tutorials/admin/customize_lookfeel/img/custom_right_menu.png b/docs/tutorials/admin/customize_lookfeel/img/custom_right_menu.png
new file mode 100644
index 00000000000..ab0fe49cbc2
Binary files /dev/null and b/docs/tutorials/admin/customize_lookfeel/img/custom_right_menu.png differ
diff --git a/geonode/base/admin.py b/geonode/base/admin.py
index 91e1454819d..d3314d79234 100755
--- a/geonode/base/admin.py
+++ b/geonode/base/admin.py
@@ -43,7 +43,11 @@
Link,
Backup,
License,
- HierarchicalKeyword)
+ HierarchicalKeyword,
+ MenuPlaceholder,
+ Menu,
+ MenuItem
+)
from django.http import HttpResponseRedirect
@@ -249,6 +253,21 @@ class HierarchicalKeywordAdmin(TreeAdmin):
form = movenodeform_factory(HierarchicalKeyword)
+class MenuPlaceholderAdmin(admin.ModelAdmin):
+ model = MenuPlaceholder
+ list_display = ('name', )
+
+
+class MenuAdmin(admin.ModelAdmin):
+ model = Menu
+ list_display = ('title', 'placeholder', 'order')
+
+
+class MenuItemAdmin(admin.ModelAdmin):
+ model = MenuItem
+ list_display = ('title', 'menu', 'order', 'blank_target', 'url')
+
+
admin.site.register(TopicCategory, TopicCategoryAdmin)
admin.site.register(Region, RegionAdmin)
admin.site.register(SpatialRepresentationType, SpatialRepresentationTypeAdmin)
@@ -258,6 +277,9 @@ class HierarchicalKeywordAdmin(TreeAdmin):
admin.site.register(Backup, BackupAdmin)
admin.site.register(License, LicenseAdmin)
admin.site.register(HierarchicalKeyword, HierarchicalKeywordAdmin)
+admin.site.register(MenuPlaceholder, MenuPlaceholderAdmin)
+admin.site.register(Menu, MenuAdmin)
+admin.site.register(MenuItem, MenuItemAdmin)
class ResourceBaseAdminForm(ModelForm):
diff --git a/geonode/base/fixtures/initial_data.json b/geonode/base/fixtures/initial_data.json
index baa048ede48..03c684f43de 100644
--- a/geonode/base/fixtures/initial_data.json
+++ b/geonode/base/fixtures/initial_data.json
@@ -4845,5 +4845,12 @@
"bbox_y0": 3.48639,
"bbox_y1": 12.21558
}
+ },
+ {
+ "model": "base.menuplaceholder",
+ "pk": 1,
+ "fields": {
+ "name": "TOPBAR_MENU"
+ }
}
]
diff --git a/geonode/base/migrations/0036_auto_20190129_1433.py b/geonode/base/migrations/0036_auto_20190129_1433.py
new file mode 100644
index 00000000000..2a58bcaa859
--- /dev/null
+++ b/geonode/base/migrations/0036_auto_20190129_1433.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.16 on 2019-01-29 14:33
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('base', '0035_resourcebase_dirty_state'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Menu',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=255)),
+ ('order', models.IntegerField()),
+ ],
+ options={
+ 'ordering': ['order'],
+ },
+ ),
+ migrations.CreateModel(
+ name='MenuItem',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=255)),
+ ('order', models.IntegerField()),
+ ('blank_target', models.BooleanField()),
+ ('url', models.CharField(max_length=2000)),
+ ('menu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='base.Menu')),
+ ],
+ options={
+ 'ordering': ['order'],
+ },
+ ),
+ migrations.CreateModel(
+ name='MenuPlaceholder',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=255, unique=True)),
+ ],
+ ),
+ migrations.AddField(
+ model_name='menu',
+ name='placeholder',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='base.MenuPlaceholder'),
+ ),
+ migrations.AlterUniqueTogether(
+ name='menuitem',
+ unique_together=set([('menu', 'order'), ('menu', 'title')]),
+ ),
+ migrations.AlterUniqueTogether(
+ name='menu',
+ unique_together=set([('placeholder', 'order'), ('placeholder', 'title')]),
+ ),
+ ]
diff --git a/geonode/base/migrations/0037_auto_20190222_1347.py b/geonode/base/migrations/0037_auto_20190222_1347.py
new file mode 100644
index 00000000000..50d650a3124
--- /dev/null
+++ b/geonode/base/migrations/0037_auto_20190222_1347.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-02-22 13:47
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('base', '0036_auto_20190129_1433'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='resourcebase',
+ name='language',
+ field=models.CharField(choices=[(b'abk', b'Abkhazian'), (b'aar', b'Afar'), (b'afr', b'Afrikaans'), (b'amh', b'Amharic'), (b'ara', b'Arabic'), (b'asm', b'Assamese'), (b'aym', b'Aymara'), (b'aze', b'Azerbaijani'), (b'bak', b'Bashkir'), (b'ben', b'Bengali'), (b'bih', b'Bihari'), (b'bis', b'Bislama'), (b'bre', b'Breton'), (b'bul', b'Bulgarian'), (b'bel', b'Byelorussian'), (b'cat', b'Catalan'), (b'chi', b'Chinese'), (b'cos', b'Corsican'), (b'dan', b'Danish'), (b'dzo', b'Dzongkha'), (b'eng', b'English'), (b'fra', b'French'), (b'epo', b'Esperanto'), (b'est', b'Estonian'), (b'fao', b'Faroese'), (b'fij', b'Fijian'), (b'fin', b'Finnish'), (b'fry', b'Frisian'), (b'glg', b'Gallegan'), (b'ger', b'German'), (b'gre', b'Greek'), (b'kal', b'Greenlandic'), (b'grn', b'Guarani'), (b'guj', b'Gujarati'), (b'hau', b'Hausa'), (b'heb', b'Hebrew'), (b'hin', b'Hindi'), (b'hun', b'Hungarian'), (b'ind', b'Indonesian'), (b'ina', b'Interlingua (International Auxiliary language Association)'), (b'iku', b'Inuktitut'), (b'ipk', b'Inupiak'), (b'ita', b'Italian'), (b'jpn', b'Japanese'), (b'kan', b'Kannada'), (b'kas', b'Kashmiri'), (b'kaz', b'Kazakh'), (b'khm', b'Khmer'), (b'kin', b'Kinyarwanda'), (b'kir', b'Kirghiz'), (b'kor', b'Korean'), (b'kur', b'Kurdish'), (b'oci', b"Langue d 'Oc (post 1500)"), (b'lao', b'Lao'), (b'lat', b'Latin'), (b'lav', b'Latvian'), (b'lin', b'Lingala'), (b'lit', b'Lithuanian'), (b'mlg', b'Malagasy'), (b'mlt', b'Maltese'), (b'mar', b'Marathi'), (b'mol', b'Moldavian'), (b'mon', b'Mongolian'), (b'nau', b'Nauru'), (b'nep', b'Nepali'), (b'nor', b'Norwegian'), (b'ori', b'Oriya'), (b'orm', b'Oromo'), (b'pan', b'Panjabi'), (b'pol', b'Polish'), (b'por', b'Portuguese'), (b'pus', b'Pushto'), (b'que', b'Quechua'), (b'roh', b'Rhaeto-Romance'), (b'run', b'Rundi'), (b'rus', b'Russian'), (b'smo', b'Samoan'), (b'sag', b'Sango'), (b'san', b'Sanskrit'), (b'scr', b'Serbo-Croatian'), (b'sna', b'Shona'), (b'snd', b'Sindhi'), (b'sin', b'Singhalese'), (b'ssw', b'Siswant'), (b'slv', b'Slovenian'), (b'som', b'Somali'), (b'sot', b'Sotho'), (b'spa', b'Spanish'), (b'sun', b'Sudanese'), (b'swa', b'Swahili'), (b'tgl', b'Tagalog'), (b'tgk', b'Tajik'), (b'tam', b'Tamil'), (b'tat', b'Tatar'), (b'tel', b'Telugu'), (b'tha', b'Thai'), (b'tir', b'Tigrinya'), (b'tog', b'Tonga (Nyasa)'), (b'tso', b'Tsonga'), (b'tsn', b'Tswana'), (b'tur', b'Turkish'), (b'tuk', b'Turkmen'), (b'twi', b'Twi'), (b'uig', b'Uighur'), (b'ukr', b'Ukrainian'), (b'urd', b'Urdu'), (b'uzb', b'Uzbek'), (b'vie', b'Vietnamese'), (b'vol', b'Volap\xc3\xbck'), (b'wol', b'Wolof'), (b'xho', b'Xhosa'), (b'yid', b'Yiddish'), (b'yor', b'Yoruba'), (b'zha', b'Zhuang'), (b'zul', b'Zulu')], default=b'eng', help_text='language used within the dataset', max_length=3, verbose_name='language'),
+ ),
+ ]
diff --git a/geonode/base/models.py b/geonode/base/models.py
index 91dccbdf1c6..09f70d9b67c 100644
--- a/geonode/base/models.py
+++ b/geonode/base/models.py
@@ -1336,6 +1336,79 @@ def __unicode__(self):
return u"{0} link".format(self.link_type)
+class MenuPlaceholder(models.Model):
+
+ name = models.CharField(
+ max_length=255,
+ null=False,
+ blank=False,
+ unique=True
+ )
+
+ def __str__(self):
+ return self.name
+
+
+class Menu(models.Model):
+
+ title = models.CharField(
+ max_length=255,
+ null=False,
+ blank=False
+ )
+ placeholder = models.ForeignKey(
+ to='MenuPlaceholder',
+ on_delete=models.CASCADE,
+ null=False
+ )
+ order = models.IntegerField(
+ null=False,
+ )
+
+ def __str__(self):
+ return self.title
+
+ class Meta:
+ unique_together = (
+ ('placeholder', 'order'),
+ ('placeholder', 'title'),
+ )
+ ordering = ['order']
+
+
+class MenuItem(models.Model):
+
+ title = models.CharField(
+ max_length=255,
+ null=False,
+ blank=False
+ )
+ menu = models.ForeignKey(
+ to='Menu',
+ on_delete=models.CASCADE,
+ null=False
+ )
+ order = models.IntegerField(
+ null=False
+ )
+ blank_target = models.BooleanField()
+ url = models.CharField(
+ max_length=2000,
+ null=False,
+ blank=False
+ )
+
+ def __str__(self):
+ return self.title
+
+ class Meta:
+ unique_together = (
+ ('menu', 'order'),
+ ('menu', 'title'),
+ )
+ ordering = ['order']
+
+
def resourcebase_post_save(instance, *args, **kwargs):
"""
Used to fill any additional fields after the save.
diff --git a/geonode/base/templates/base/menu.html b/geonode/base/templates/base/menu.html
new file mode 100644
index 00000000000..e1df7b348c4
--- /dev/null
+++ b/geonode/base/templates/base/menu.html
@@ -0,0 +1,50 @@
+
+
+{% for menu, menu_items in menus.items %}
+
+ {% if menu_items|length > 0 %}
+
+
+
+
+ {{ menu.title }}
+ {% if menu_items|length > 0 %}
+
+ {% endif %}
+
+
+
+
+
+ {% endif %}
+
+{% endfor %}
+
+
diff --git a/geonode/base/templatetags/base_tags.py b/geonode/base/templatetags/base_tags.py
index d2f796f8aaf..51d518d32aa 100644
--- a/geonode/base/templatetags/base_tags.py
+++ b/geonode/base/templatetags/base_tags.py
@@ -33,8 +33,11 @@
from geonode.maps.models import Map
from geonode.documents.models import Document
from geonode.groups.models import GroupProfile
-from geonode.base.models import HierarchicalKeyword
+from geonode.base.models import (
+ HierarchicalKeyword, Menu, MenuItem
+)
from geonode.security.utils import get_visible_resources
+from collections import OrderedDict
register = template.Library()
@@ -306,3 +309,21 @@ def fullurl(context, url):
return ''
r = context['request']
return r.build_absolute_uri(url)
+
+
+@register.assignment_tag
+def get_menu(placeholder_name):
+ menus = {
+ m: MenuItem.objects.filter(menu=m)
+ for m in Menu.objects.filter(placeholder__name=placeholder_name)
+ }
+ return OrderedDict(sorted(menus.items(), key=lambda(k, v): (v, k)))
+
+
+@register.inclusion_tag(filename='base/menu.html')
+def render_nav_menu(placeholder_name):
+ menus = {
+ m: MenuItem.objects.filter(menu=m)
+ for m in Menu.objects.filter(placeholder__name=placeholder_name)
+ }
+ return {'menus': OrderedDict(sorted(menus.items(), key=lambda(k, v): (v, k)))}
diff --git a/geonode/base/tests.py b/geonode/base/tests.py
index 18c3d4f553b..85c829c25f9 100644
--- a/geonode/base/tests.py
+++ b/geonode/base/tests.py
@@ -19,8 +19,10 @@
#########################################################################
from geonode.tests.base import GeoNodeBaseTestSupport
-
-from geonode.base.models import ResourceBase
+from geonode.base.models import (
+ ResourceBase, MenuPlaceholder, Menu, MenuItem
+)
+from django.template import Template, Context
class ThumbnailTests(GeoNodeBaseTestSupport):
@@ -33,3 +35,409 @@ def test_initial_behavior(self):
self.assertFalse(self.rb.has_thumbnail())
missing = self.rb.get_thumbnail_url()
self.assertEquals('/static/geonode/img/missing_thumb.png', missing)
+
+
+class RenderMenuTagTest(GeoNodeBaseTestSupport):
+ """
+ Test class for render_menu and render_top_menu custom tags of base_tags
+ """
+
+ def setUp(self):
+ super(RenderMenuTagTest, self).setUp()
+ self.placeholder_0 = MenuPlaceholder.objects.create(
+ name='test_menu_placeholder_0'
+ )
+ self.placeholder_1 = MenuPlaceholder.objects.create(
+ name='test_menu_placeholder_1'
+ )
+ self.menu_0_0 = Menu.objects.create(
+ title='test_menu_0_0',
+ order=0,
+ placeholder=self.placeholder_0
+
+ )
+ self.menu_0_1 = Menu.objects.create(
+ title='test_menu_0_1',
+ order=1,
+ placeholder=self.placeholder_0
+
+ )
+ self.menu_1_0 = Menu.objects.create(
+ title='test_menu_1_0',
+ order=0,
+ placeholder=self.placeholder_1
+
+ )
+ self.menu_item_0_0_0 = MenuItem.objects.create(
+ title='test_menu_item_0_0_0',
+ order=0,
+ blank_target=False,
+ url='/about',
+ menu=self.menu_0_0
+ )
+ self.menu_item_0_0_1 = MenuItem.objects.create(
+ title='test_menu_item_0_0_1',
+ order=1,
+ blank_target=False,
+ url='/about',
+ menu=self.menu_0_0
+ )
+ self.menu_item_0_1_0 = MenuItem.objects.create(
+ title='test_menu_item_0_1_0',
+ order=0,
+ blank_target=False,
+ url='/about',
+ menu=self.menu_0_1
+ )
+ self.menu_item_0_1_1 = MenuItem.objects.create(
+ title='test_menu_item_0_1_1',
+ order=1,
+ blank_target=False,
+ url='/about',
+ menu=self.menu_0_1
+ )
+ self.menu_item_0_1_2 = MenuItem.objects.create(
+ title='test_menu_item_0_1_2',
+ order=2,
+ blank_target=False,
+ url='/about',
+ menu=self.menu_0_1
+ )
+ self.menu_item_1_0_0 = MenuItem.objects.create(
+ title='test_menu_item_1_0_0',
+ order=0,
+ blank_target=False,
+ url='/about',
+ menu=self.menu_1_0
+ )
+ self.menu_item_1_0_1 = MenuItem.objects.create(
+ title='test_menu_item_1_0_1',
+ order=1,
+ blank_target=False,
+ url='/about',
+ menu=self.menu_1_0
+ )
+
+ def test_get_menu_placeholder_0(self):
+ template = Template(
+ "{% load base_tags %} {% get_menu 'test_menu_placeholder_0' %}"
+ )
+ rendered = template.render(Context({}))
+ # menu_placeholder_0
+ # first menu
+ self.assertIn(
+ self.menu_0_0.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_0_0.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_0_0_0.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_0_0_0.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_0_0_1.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_0_0_1.title
+ )
+ )
+ # second menu
+ self.assertIn(
+ self.menu_0_1.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_0_1.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_0_1_0.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_0_1_0.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_0_1_1.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_0_1_1.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_0_1_2.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_0_1_2.title
+ )
+ )
+ # menu_placeholder_1
+ # first menu
+ self.assertNotIn(
+ self.menu_1_0.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_1_0.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_1_0_0.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_1_0_0.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_1_0_1.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_1_0_1.title
+ )
+ )
+
+ def test_get_menu_placeholder_1(self):
+ template = Template(
+ "{% load base_tags %} {% get_menu 'test_menu_placeholder_1' %}"
+ )
+ rendered = template.render(Context({}))
+ # menu_placeholder_0
+ # first menu
+ self.assertNotIn(
+ self.menu_0_0.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_0_0.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_0_0_0.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_0_0_0.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_0_0_1.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_0_0_1.title
+ )
+ )
+ # second menu
+ self.assertNotIn(
+ self.menu_0_1.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_0_1.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_0_1_0.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_0_1_0.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_0_1_1.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_0_1_1.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_0_1_2.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_0_1_2.title
+ )
+ )
+ # menu_placeholder_1
+ # first menu
+ self.assertIn(
+ self.menu_1_0.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_1_0.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_1_0_0.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_1_0_0.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_1_0_1.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_1_0_1.title
+ )
+ )
+
+ def test_render_nav_menu_placeholder_0(self):
+ template = Template(
+ "{% load base_tags %} {% render_nav_menu 'test_menu_placeholder_0' %}"
+ )
+ rendered = template.render(Context({}))
+ # menu_placeholder_0
+ # first menu
+ self.assertIn(
+ self.menu_0_0.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_0_0.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_0_0_0.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_0_0_0.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_0_0_1.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_0_0_1.title
+ )
+ )
+ # second menu
+ self.assertIn(
+ self.menu_0_1.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_0_1.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_0_1_0.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_0_1_0.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_0_1_1.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_0_1_1.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_0_1_2.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_0_1_2.title
+ )
+ )
+ # menu_placeholder_1
+ # first menu
+ self.assertNotIn(
+ self.menu_1_0.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_1_0.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_1_0_0.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_1_0_0.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_1_0_1.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_1_0_1.title
+ )
+ )
+
+ def test_render_nav_menu_placeholder_1(self):
+ template = Template(
+ "{% load base_tags %} {% render_nav_menu 'test_menu_placeholder_1' %}"
+ )
+ rendered = template.render(Context({}))
+ # menu_placeholder_0
+ # first menu
+ self.assertNotIn(
+ self.menu_0_0.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_0_0.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_0_0_0.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_0_0_0.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_0_0_1.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_0_0_1.title
+ )
+ )
+ # second menu
+ self.assertNotIn(
+ self.menu_0_1.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_0_1.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_0_1_0.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_0_1_0.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_0_1_1.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_0_1_1.title
+ )
+ )
+ self.assertNotIn(
+ self.menu_item_0_1_2.title,
+ rendered,
+ 'No "{}" string expected in the rendered template'.format(
+ self.menu_item_0_1_2.title
+ )
+ )
+ # menu_placeholder_1
+ # first menu
+ self.assertIn(
+ self.menu_1_0.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_1_0.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_1_0_0.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_1_0_0.title
+ )
+ )
+ self.assertIn(
+ self.menu_item_1_0_1.title,
+ rendered,
+ 'Expected "{}" string in the rendered template'.format(
+ self.menu_item_1_0_1.title
+ )
+ )
diff --git a/geonode/templates/base.html b/geonode/templates/base.html
index c47162c5633..607aa971e89 100644
--- a/geonode/templates/base.html
+++ b/geonode/templates/base.html
@@ -1,6 +1,26 @@
+
+
{% load i18n avatar_tags %}
{% load static from staticfiles %}
{% load account socialaccount %}
+{% load base_tags %}
@@ -127,7 +147,9 @@