diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2016-09-09 00:41:57 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2016-09-09 00:41:57 +0200 |
commit | 13790d69392535543991be2f9de453b6a2fe9493 (patch) | |
tree | 5df1cfe674759003b1599f7334448f9c7f00637d | |
parent | b9fad2cce5388c1f32a936521149cf2fa36e783e (diff) | |
download | Ishtar-13790d69392535543991be2f9de453b6a2fe9493.tar.bz2 Ishtar-13790d69392535543991be2f9de453b6a2fe9493.zip |
Shortcut menu: menu is now dynamic - selected items filter dependant items (refs #2996) - can now pin items from sheet (refs #3078)
-rw-r--r-- | archaeological_context_records/models.py | 10 | ||||
-rw-r--r-- | archaeological_context_records/templates/ishtar/sheet_contextrecord.html | 2 | ||||
-rw-r--r-- | archaeological_files/models.py | 3 | ||||
-rw-r--r-- | archaeological_files/templates/ishtar/sheet_file.html | 2 | ||||
-rw-r--r-- | archaeological_finds/models.py | 9 | ||||
-rw-r--r-- | archaeological_finds/templates/ishtar/sheet_find.html | 2 | ||||
-rw-r--r-- | archaeological_operations/models.py | 8 | ||||
-rw-r--r-- | archaeological_operations/templates/ishtar/sheet_operation.html | 2 | ||||
-rw-r--r-- | ishtar_common/context_processors.py | 35 | ||||
-rw-r--r-- | ishtar_common/models.py | 8 | ||||
-rw-r--r-- | ishtar_common/static/js/ishtar.js | 58 | ||||
-rw-r--r-- | ishtar_common/static/media/style.css | 34 | ||||
-rw-r--r-- | ishtar_common/templates/base.html | 35 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/blocks/shortcut_menu.html | 24 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/blocks/window_nav.html | 7 | ||||
-rw-r--r-- | ishtar_common/templatetags/window_header.py | 8 | ||||
-rw-r--r-- | ishtar_common/urls.py | 3 | ||||
-rw-r--r-- | ishtar_common/views.py | 123 |
18 files changed, 285 insertions, 88 deletions
diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py index a98f7792a..fa2d5b430 100644 --- a/archaeological_context_records/models.py +++ b/archaeological_context_records/models.py @@ -108,6 +108,7 @@ class IdentificationType(GeneralType): class ContextRecord(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): SHOW_URL = 'show-contextrecord' + SLUG = 'contextrecord' TABLE_COLS = ['parcel.town', 'operation.year', 'operation.operation_code', 'label', 'unit'] @@ -220,6 +221,15 @@ class ContextRecord(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): Q(operation__in_charge=user.ishtaruser.person) |\ Q(history_creator=user) + @classmethod + def get_owns(cls, user, menu_filtr=None): + extra_query = {} + if menu_filtr: + extra_query = {'operation': menu_filtr} + owns = super(ContextRecord, cls).get_owns(user, + extra_query=extra_query) + return sorted(owns, key=lambda x: x.cached_label) + def full_label(self): return unicode(self) if not self.operation: diff --git a/archaeological_context_records/templates/ishtar/sheet_contextrecord.html b/archaeological_context_records/templates/ishtar/sheet_contextrecord.html index 2c2bf98fe..bd883ac0b 100644 --- a/archaeological_context_records/templates/ishtar/sheet_contextrecord.html +++ b/archaeological_context_records/templates/ishtar/sheet_contextrecord.html @@ -4,7 +4,7 @@ {% block head_title %}{% trans "Context Record" %}{% endblock %} {% block content %} -{% window_nav item window_id 'show-contextrecord' 'record_modify' 'show-historized-contextrecord' 'revert-contextrecord' previous next %} +{% window_nav item window_id 'show-contextrecord' 'record_modify' 'show-historized-contextrecord' 'revert-contextrecord' previous next 1 %} {% if item.image %} <a href='{{item.image.url}}' rel="prettyPhoto" title="{{item.label}}" class='photo'><img src='{{item.thumbnail.url}}'/></a> diff --git a/archaeological_files/models.py b/archaeological_files/models.py index eaa9d832e..740ae9a71 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -74,6 +74,7 @@ class File(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, TABLE_COLS = ['numeric_reference', 'year', 'internal_reference', 'file_type', 'saisine_type', 'towns', ] SHOW_URL = 'show-file' + SLUG = 'file' year = models.IntegerField(_(u"Year"), default=lambda: datetime.datetime.now().year) numeric_reference = models.IntegerField( @@ -333,7 +334,7 @@ class File(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, return cls @classmethod - def get_owns(cls, user): + def get_owns(cls, user, menu_filtr=None): owns = super(File, cls).get_owns(user) return sorted(owns, key=lambda x: x.cached_label) diff --git a/archaeological_files/templates/ishtar/sheet_file.html b/archaeological_files/templates/ishtar/sheet_file.html index 5165a0425..211d2b181 100644 --- a/archaeological_files/templates/ishtar/sheet_file.html +++ b/archaeological_files/templates/ishtar/sheet_file.html @@ -8,7 +8,7 @@ {% if can_add_operation %} {% window_file_nav item window_id previous next %} {% else %} -{% window_nav item window_id 'show-file' 'file_modify' 'show-historized-file' 'revert-file' previous next %} +{% window_nav item window_id 'show-file' 'file_modify' 'show-historized-file' 'revert-file' previous next 1 %} {% endif %} <h3>{% trans "General"%}</h3> diff --git a/archaeological_finds/models.py b/archaeological_finds/models.py index 15ed32120..0f069e1d8 100644 --- a/archaeological_finds/models.py +++ b/archaeological_finds/models.py @@ -275,6 +275,7 @@ class FindBasket(Basket): class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): CHECK_DICT = dict(CHECK_CHOICES) SHOW_URL = 'show-find' + SLUG = 'find' TABLE_COLS = ['label', 'material_types', 'datings.period', 'base_finds.context_record.parcel.town', 'base_finds.context_record.operation.year', @@ -564,6 +565,14 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): ishtaruser.person) |\ Q(history_creator=user) + @classmethod + def get_owns(cls, user, menu_filtr=None): + extra_query = {} + if menu_filtr: + extra_query = {'base_finds__context_record': menu_filtr} + owns = super(Find, cls).get_owns(user, extra_query=extra_query) + return sorted(owns, key=lambda x: x.cached_label) + def save(self, *args, **kwargs): super(Find, self).save(*args, **kwargs) diff --git a/archaeological_finds/templates/ishtar/sheet_find.html b/archaeological_finds/templates/ishtar/sheet_find.html index c867b46ee..fbd7cec1a 100644 --- a/archaeological_finds/templates/ishtar/sheet_find.html +++ b/archaeological_finds/templates/ishtar/sheet_find.html @@ -4,7 +4,7 @@ {% block head_title %}{% trans "Find" %}{% endblock %} {% block content %} -{% window_nav item window_id 'show-find' 'find_modify' 'show-historized-find' 'revert-find' previous next %} +{% window_nav item window_id 'show-find' 'find_modify' 'show-historized-find' 'revert-find' previous next 1 %} {% if item.image %} <a href='{{item.image.url}}' rel="prettyPhoto" title="{{item.label}}" class='photo'><img src='{{item.thumbnail.url}}'/></a> diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index f5a1ca8b0..701ae4593 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -174,6 +174,7 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms, 'start_date', 'excavation_end_date'] TABLE_COLS.insert(4, 'associated_file_short_label') IMAGE_PREFIX = 'operations/' + SLUG = 'operation' creation_date = models.DateField(_(u"Creation date"), default=datetime.date.today) end_date = models.DateField(_(u"Closing date"), null=True, blank=True) @@ -298,8 +299,11 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms, ordering = ('cached_label',) @classmethod - def get_owns(cls, user): - owns = super(Operation, cls).get_owns(user) + def get_owns(cls, user, menu_filtr=None): + extra_query = {} + if menu_filtr: + extra_query = {'associated_file': menu_filtr} + owns = super(Operation, cls).get_owns(user, extra_query=extra_query) # owns = owns.annotate(null_count=Count('operation_code')) # return owns.order_by("common_name", "-year", "operation_code") return sorted(owns, key=lambda x: x.cached_label) diff --git a/archaeological_operations/templates/ishtar/sheet_operation.html b/archaeological_operations/templates/ishtar/sheet_operation.html index 2f6dbdf4c..6b2030f5e 100644 --- a/archaeological_operations/templates/ishtar/sheet_operation.html +++ b/archaeological_operations/templates/ishtar/sheet_operation.html @@ -4,7 +4,7 @@ {% block head_title %}{% trans "Operation" %}{% endblock %} {% block content %} -{% window_nav item window_id 'show-operation' 'operation_modify' 'show-historized-operation' 'revert-operation' previous next %} +{% window_nav item window_id 'show-operation' 'operation_modify' 'show-historized-operation' 'revert-operation' previous next 1 %} {% if item.image %} <a href='{{item.image.url}}' rel="prettyPhoto" title="{{item.label}}" class='photo'><img src='{{item.thumbnail.url}}'/></a> diff --git a/ishtar_common/context_processors.py b/ishtar_common/context_processors.py index f8a4a0f95..bb12a401d 100644 --- a/ishtar_common/context_processors.py +++ b/ishtar_common/context_processors.py @@ -19,29 +19,11 @@ from django.conf import settings from django.contrib.sites.models import Site -from django.utils.translation import ugettext_lazy as _ from ishtar_common.version import VERSION -from ishtar_common.utils import shortify from menus import Menu -from ishtar_common.models import get_current_profile -from archaeological_operations.models import Operation -from archaeological_files.models import File -from archaeological_context_records.models import ContextRecord -from archaeological_finds.models import Find - -profile = get_current_profile() -CURRENT_ITEMS = [] -if profile.files: - CURRENT_ITEMS.append((_(u"Archaeological file"), File)) -CURRENT_ITEMS.append((_(u"Operation"), Operation)) -if profile.context_record: - CURRENT_ITEMS.append((_(u"Context record"), ContextRecord)) -if profile.find: - CURRENT_ITEMS.append((_(u"Find"), Find)) - def get_base_context(request): dct = {'URL_PATH': settings.URL_PATH} @@ -74,21 +56,4 @@ def get_base_context(request): dct['VERSION'] = u".".join([unicode(n) for n in VERSION]) if settings.EXTRA_VERSION: dct['VERSION'] += unicode(settings.EXTRA_VERSION) - dct['current_menu'] = [] - for lbl, model in CURRENT_ITEMS: - model_name = model.__name__.lower() - cls = '' - current = model_name in request.session and request.session[model_name] - items = [] - for item in model.get_owns(request.user): - pk = unicode(item.pk) - if item.IS_BASKET: - pk = "basket-" + pk - selected = pk == current - if selected: - cls = item.get_short_menu_class() - items.append((pk, shortify(unicode(item), 60), - selected, item.get_short_menu_class())) - if items: - dct['current_menu'].append((lbl, model_name, cls, items)) return dct diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 6150ab0aa..9e48df8d2 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -235,7 +235,7 @@ class OwnPerms: return cls.objects.filter(query).count() @classmethod - def get_owns(cls, user): + def get_owns(cls, user, extra_query={}): """ Get Own items """ @@ -249,8 +249,10 @@ class OwnPerms: query = cls.get_query_owns(user) if not query: return cls.objects.filter(pk__isnull=True) - items += list( - cls.objects.filter(query).order_by(*cls._meta.ordering).all()) + q = cls.objects.filter(query) + if extra_query: + q = q.filter(**extra_query) + items += list(q.order_by(*cls._meta.ordering).all()) return items diff --git a/ishtar_common/static/js/ishtar.js b/ishtar_common/static/js/ishtar.js index 4d82cb238..fecefe0a9 100644 --- a/ishtar_common/static/js/ishtar.js +++ b/ishtar_common/static/js/ishtar.js @@ -1,5 +1,5 @@ - /* CSRFToken management */ + $.ajaxSetup({ beforeSend: function(xhr, settings) { function getCookie(name) { @@ -23,6 +23,8 @@ beforeSend: function(xhr, settings) { } }}); +var shortcut_url = ''; + function manage_async_link(event){ event.preventDefault(); var url = $(this).attr('href'); @@ -36,30 +38,66 @@ function manage_async_link(event){ function get_next_table_id(){} function get_previous_table_id(){} -$(document).ready(function(){ - $("#main_menu > ul > li > ul").hide(); - $("#main_menu ul ul .selected").parents().show(); - var items = new Array('file', 'operation'); +function init_shortcut_menu(html){ + $("#progress").hide(); + $("#context_menu").html(html); + $(".chosen-select").chosen(); $("#current_file").change(function(){ $.post('/' + url_path + 'update-current-item/', - {item:'file', value:$("#current_file").val()} + {item:'file', value:$("#current_file").val()}, + load_shortcut_menu ); }); $("#current_operation").change(function(){ $.post('/' + url_path + 'update-current-item/', - {item:'operation', value:$("#current_operation").val()} + {item:'operation', value:$("#current_operation").val()}, + load_shortcut_menu ); }); $("#current_contextrecord").change(function(){ $.post('/' + url_path + 'update-current-item/', - {item:'contextrecord', value:$("#current_contextrecord").val()} + {item:'contextrecord', value:$("#current_contextrecord").val()}, + load_shortcut_menu ); }); $("#current_find").change(function(){ $.post('/' + url_path + 'update-current-item/', - {item:'find', value:$("#current_find").val()} + {item:'find', value:$("#current_find").val()}, + load_shortcut_menu ); }); +} + +function display_info(msg){ + $('#message .information .content').html(msg); + $('#message').fadeIn('slow'); + $('#message .information').fadeIn('slow'); + setTimeout( + function(){ + $('#message .information').fadeOut('slow'); + $('#message').fadeOut('slow'); + }, 5000); +} + +function load_shortcut_menu(){ + if (!shortcut_url) return; + $("#progress").show(); + $.ajax({ + url: shortcut_url, + cache: false, + success:function(html){ + init_shortcut_menu(html); + }, + error:function(XMLHttpRequest, textStatus, errorThrows){ + $("#progress").hide(); + } + }); +} + +$(document).ready(function(){ + $("#main_menu > ul > li > ul").hide(); + $("#main_menu ul ul .selected").parents().show(); + var items = new Array('file', 'operation'); if ($(document).height() < 1.5*$(window).height()){ $('#to_bottom_arrow').hide(); $('#to_top_arrow').hide(); @@ -67,6 +105,7 @@ $(document).ready(function(){ $('#language_selector').change(function(){ $('#language_form').submit(); }); + load_shortcut_menu(); if ($.isFunction($(".prettyPhoto a").prettyPhoto)){ $(".prettyPhoto a").prettyPhoto({'social_tools':''}); } @@ -74,6 +113,7 @@ $(document).ready(function(){ $(this).attr('class', $(this).children("option:selected").attr('class')); }); $("a.async-link").click(manage_async_link); + $(".chosen-select").chosen(); }); $(document).on("click", '#to_bottom_arrow', function(){ diff --git a/ishtar_common/static/media/style.css b/ishtar_common/static/media/style.css index ebd13d4b7..bff3ef473 100644 --- a/ishtar_common/static/media/style.css +++ b/ishtar_common/static/media/style.css @@ -21,6 +21,8 @@ div.form, ul.form { } /* color */ + +.pin-action, #window hr, #context_menu .red, a, a.remove { @@ -46,6 +48,7 @@ a.add-button, color:#000; } +.chosen-container, #context_menu .green, #context_menu .red, #context_menu .orange, @@ -248,6 +251,13 @@ button.ui-widget-header:hover { z-index: 100 !important; } +.chosen-container-active.chosen-with-drop .chosen-single, +.chosen-container-single .chosen-single{ + background: none; + background-color: #fff; + border-radius:4px; +} + textarea, input[type=text], input[type=password], @@ -293,6 +303,26 @@ div.nav-button{ border: 0 solid transparent; } +#message, +#message div{ + display: none; +} + +#message { + z-index: 42200; + position: absolute; + top: 5px; + right: 5px; + background: #fff; + padding: 0.5em 1em; + border: 1px solid; + border-radius: 3px; +} + +#message span{ + padding: 0 1em; +} + #to_bottom_arrow{ bottom:80px; } @@ -731,6 +761,10 @@ ul.form .help_text{ font-style: normal; } +.pin-action:hover{ + cursor:pointer; +} + .autocomplete{ width:350px; } diff --git a/ishtar_common/templates/base.html b/ishtar_common/templates/base.html index 47ea61594..703644a35 100644 --- a/ishtar_common/templates/base.html +++ b/ishtar_common/templates/base.html @@ -14,12 +14,14 @@ <script language="javascript" type="text/javascript" src="{{JQUERY_URL}}?ver={{VERSION}}"></script> <script language="javascript" type="text/javascript" src="{{JQUERY_UI_URL}}jquery-ui.js?ver={{VERSION}}"></script> <script language="javascript" type="text/javascript" src="{{JQUERY_UI_URL}}ui/i18n/jquery.ui.datepicker-{{COUNTRY}}.js?ver={{VERSION}}"></script> + <script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/chosen/chosen.jquery.min.js?ver={{VERSION}}"></script> <script language="javascript" type="text/javascript" src="{{STATIC_URL}}/js/prettyPhoto/js/jquery.prettyPhoto.js?ver={{VERSION}}"></script> <script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/i18n/grid.locale-{{COUNTRY}}.js?ver={{VERSION}}"></script> <script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/jquery.jqGrid.min.js?ver={{VERSION}}"></script> <script language="javascript" type="text/javascript" src="{{STATIC_URL}}js/grid.tbltogrid.js?ver={{VERSION}}"></script> <script language="javascript" type="text/javascript" src="{{STATIC_URL}}/js/ishtar.js?ver={{VERSION}}"></script> <link type="text/css" href="{{JQUERY_UI_URL}}jquery-ui.css?ver={{VERSION}}" rel="stylesheet" /> + <link type="text/css" href="{{STATIC_URL}}js/chosen/chosen.min.css?ver={{VERSION}}" rel="stylesheet" /> <link rel="stylesheet" href="{{STATIC_URL}}/font-awesome/css/font-awesome.min.css?ver={{VERSION}}" /> <link rel="stylesheet" href="{{STATIC_URL}}/js/prettyPhoto/css/prettyPhoto.css?ver={{VERSION}}" /> <link rel="stylesheet" href="{{STATIC_URL}}media/ui.jqgrid.css?ver={{VERSION}}" /> @@ -28,6 +30,9 @@ {% include "blocks/extra_head.html" %} {% block extra_head %} {% endblock %} + <script type='text/javascript'> + var shortcut_url = '{% url "shortcut-menu" %}'; + </script> </head> <body{% if current_theme%} id='{{current_theme}}'{%endif%}> <div id="header"> @@ -64,31 +69,8 @@ <a href='{% url "start" %}' id="logo"> {% if APP_NAME %}<p id="app_name">{{APP_NAME}}</p>{%endif%} </a> - {% if not reminders %}<div id="context_menu"> - {% block context %}{% if current_menu %} - <form method="post" action="{% url 'update-current-item' %}"> - <fieldset> - <i class="icon fa fa-thumb-tack fa-2x" aria-hidden="true" title="{% trans 'Pin an item in order to constrain default searches with this item. New created and modified items are auto-pin.' %}"></i> - <table id='current_items'> - {% for lbl, model_name, main_cls, items in current_menu %} - <tr> - <td><label for="current_{{model_name}}">{{lbl}}</label></td> - <td> - <select class='{{main_cls}}' id='current_{{model_name}}'> - <option class='normal' value=''>--</option> - {% for val, label, selected, cls in items %}<option{% if cls %} class='{{cls}}'{% endif %} value='{{val}}'{% if selected %} selected="selected"{% endif %}>{% ifequal cls 'basket' %} {% endifequal %}{% ifequal cls 'green' %} {% endifequal %}{% ifequal cls 'orange' %} {% endifequal %}{% ifequal cls 'red' %} {% endifequal %}{{label}}</option> - {% endfor %}</select> - </td>{% with 'show-'|add:model_name as model_url%} - <td><a href='#' onclick='load_current_window("{% url model_url 0 %}", "{{model_name}}");' class='display_details'><i class="fa fa-info-circle" aria-hidden="true"></i></a></td> - {% endwith %} - </tr> - {% endfor %} - </table> - </fieldset> - </form> - {% endif %}{% endblock %} - </div>{% endif %} -{% if reminders %}<fieldset id='reminder'><legend>{% trans "Current items" %}</legend> + {% if not reminders %}<div id="context_menu"></div> + {% else %}<fieldset id='reminder'><legend>{% trans "Current items" %}</legend> {% for lbl, value in reminders %} <p><strong class='lbl'>{{lbl}}{% trans ":"%}</strong> <span class='value'>{{value}}</span></p> {% endfor %} @@ -128,6 +110,9 @@ <p class='progress-detail progress-4'>{% trans "Time to take another coffee?" %} <i class="fa fa-coffee" aria-hidden="true"></i></p> </div> </div> + <div id='message'> + <div class='information'><i class="fa fa-info-circle" aria-hidden="true"></i> <span class='content'></span></div> + </div> </body> </html> diff --git a/ishtar_common/templates/ishtar/blocks/shortcut_menu.html b/ishtar_common/templates/ishtar/blocks/shortcut_menu.html new file mode 100644 index 000000000..29c975e79 --- /dev/null +++ b/ishtar_common/templates/ishtar/blocks/shortcut_menu.html @@ -0,0 +1,24 @@ +{% load i18n %} +{% load url from future%} +{% if current_menu %} +<form method="post" action="{% url 'update-current-item' %}"> +<fieldset> +<i class="icon fa fa-thumb-tack fa-2x" aria-hidden="true" title="{% trans 'Pin an item in order to constrain default searches with this item. By default only your items are displayed. New created and modified items are auto-pin.' %}"></i> +<table id='current_items'> +{% for lbl, model_name, main_cls, items in current_menu %} +<tr> + <td><label for="current_{{model_name}}">{{lbl}}</label></td> + <td> + <select class='{{main_cls}} chosen-select' id='current_{{model_name}}'> + <option class='normal' value=''>--</option> + {% for val, label, selected, cls in items %}<option{% if cls %} class='{{cls}}'{% endif %} value='{{val}}'{% if selected %} selected="selected"{% endif %}>{% ifequal cls 'basket' %} {% endifequal %}{% ifequal cls 'green' %} {% endifequal %}{% ifequal cls 'orange' %} {% endifequal %}{% ifequal cls 'red' %} {% endifequal %}{{label}}</option> + {% endfor %}</select> + </td>{% with 'show-'|add:model_name as model_url%} + <td><a href='#' onclick='load_current_window("{% url model_url 0 %}", "{{model_name}}");' class='display_details'><i class="fa fa-info-circle" aria-hidden="true"></i></a></td> + {% endwith %} +</tr> +{% endfor %} +</table> +</fieldset> +</form> +{% endif %} diff --git a/ishtar_common/templates/ishtar/blocks/window_nav.html b/ishtar_common/templates/ishtar/blocks/window_nav.html index 13069b1eb..c0d1ba9fe 100644 --- a/ishtar_common/templates/ishtar/blocks/window_nav.html +++ b/ishtar_common/templates/ishtar/blocks/window_nav.html @@ -42,6 +42,13 @@ <i class="fa fa-pencil fa-stack-1x fa-inverse"></i> </span> </a>{% endif %} + {% if pin_action %} + <span class='pin-action' onclick='$.get("{% url 'pin' item.SLUG item.pk %}", function(){load_shortcut_menu(); display_info("{% trans 'Item pined in your shortcut menu.' %}")});' title="{% trans 'Pin' %}"> + <span class="fa-stack fa-lg"> + <i class="fa fa-circle fa-stack-2x"></i> + <i class="fa fa-thumb-tack fa-stack-1x fa-inverse"></i> + </span> + </span>{% endif %} <a class='badge' href='{% url show_url item.pk "odt" %}' title='{% trans "Export as OpenOffice.org file"%}'>ODT</a> <a class='badge' href='{% url show_url item.pk "pdf" %}' title='{% trans "Export as PDF file"%}'>PDF</a> </div> <hr class='clear'> diff --git a/ishtar_common/templatetags/window_header.py b/ishtar_common/templatetags/window_header.py index b137f24a5..5322c4478 100644 --- a/ishtar_common/templatetags/window_header.py +++ b/ishtar_common/templatetags/window_header.py @@ -6,7 +6,7 @@ register = template.Library() @register.inclusion_tag('ishtar/blocks/window_nav.html') def window_nav(item, window_id, show_url, modify_url='', histo_url='', - revert_url='', previous=None, nxt=None): + revert_url='', previous=None, nxt=None, pin_action=False): return { 'show_url': show_url, 'modify_url': modify_url, @@ -15,7 +15,8 @@ def window_nav(item, window_id, show_url, modify_url='', histo_url='', 'item': item, 'window_id': window_id, 'previous': previous, - 'next': nxt} + 'next': nxt, + 'pin_action': pin_action} @register.inclusion_tag('ishtar/blocks/window_file_nav.html') @@ -34,4 +35,5 @@ def window_file_nav(item, window_id, previous=None, nxt=None): 'extra_action': mark_safe(add_operation), 'window_id': window_id, 'previous': previous, - 'next': nxt} + 'next': nxt, + 'pin_action': True} diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py index a6f24beed..802e6ca0d 100644 --- a/ishtar_common/urls.py +++ b/ishtar_common/urls.py @@ -34,6 +34,7 @@ urlpatterns = patterns( # internationalization url(r'^i18n/', include('django.conf.urls.i18n')), # General + url(r'shortcut_menu/', views.shortcut_menu, name='shortcut-menu'), url(r'person_search/(?P<step>.+)?$', check_rights(['add_person'])( views.person_search_wizard), name='person_search'), @@ -129,6 +130,8 @@ urlpatterns += patterns( name='dashboard-main-detail'), url(r'update-current-item/$', 'update_current_item', name='update-current-item'), + url(r'pin/(?P<item_type>[a-z-]+)/(?P<pk>\d+)/$', 'update_current_item', + name='pin'), url(r'new-person/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$', 'new_person', name='new-person'), url(r'new-person-noorga/' diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 46a8ceb6a..5022aa08e 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -62,7 +62,7 @@ from archaeological_operations.forms import DashboardForm as DashboardFormOpe from archaeological_files.forms import DashboardForm as DashboardFormFile from ishtar_common.forms import FinalForm, FinalDeleteForm -from ishtar_common.utils import get_random_item_image_link +from ishtar_common.utils import get_random_item_image_link, shortify from ishtar_common import forms_common as forms from ishtar_common import wizards from ishtar_common.models import HistoryError, PRIVATE_FIELDS, \ @@ -198,11 +198,122 @@ def get_autocomplete_generic(model, extra={'available': True}): return func -def update_current_item(request): - if not request.is_ajax() and not request.method == 'POST': - raise Http404 - if 'value' in request.POST and 'item' in request.POST: - request.session[request.POST['item']] = request.POST['value'] +def shortcut_menu(request): + from archaeological_operations.models import Operation + from archaeological_files.models import File + from archaeological_context_records.models import ContextRecord + from archaeological_finds.models import Find + + profile = get_current_profile() + CURRENT_ITEMS = [] + if profile.files: + CURRENT_ITEMS.append((_(u"Archaeological file"), File)) + CURRENT_ITEMS.append((_(u"Operation"), Operation)) + if profile.context_record: + CURRENT_ITEMS.append((_(u"Context record"), ContextRecord)) + if profile.find: + CURRENT_ITEMS.append((_(u"Find"), Find)) + dct = {'current_menu': []} + current_selected_item = None + for lbl, model in CURRENT_ITEMS: + new_selected_item = None + model_name = model.SLUG + cls = '' + current = model_name in request.session and request.session[model_name] + items = [] + for item in model.get_owns(request.user, + menu_filtr=current_selected_item): + pk = unicode(item.pk) + if item.IS_BASKET: + pk = "basket-" + pk + selected = pk == current + if selected: + cls = item.get_short_menu_class() + new_selected_item = item + items.append((pk, shortify(unicode(item), 60), + selected, item.get_short_menu_class())) + # selected is not in owns - add it to the list + if not new_selected_item and current: + try: + item = model.objects.get(pk=int(current)) + items.append((item.pk, shortify(unicode(item), 60), + True, item.get_short_menu_class())) + except (model.DoesNotExist, ValueError): + pass + if items: + dct['current_menu'].append((lbl, model_name, cls, items)) + current_selected_item = new_selected_item + return render_to_response('ishtar/blocks/shortcut_menu.html', dct, + context_instance=RequestContext(request)) + + +def get_current_items(request): + from archaeological_files.models import File + from archaeological_operations.models import Operation + from archaeological_context_records.models import ContextRecord + from archaeological_finds.models import Find + currents = {} + for key, model in (('file', File), + ('operation', Operation), + ('contextrecord', ContextRecord), + ('find', Find)): + currents[key] = None + if key in request.session and request.session[key]: + try: + currents[key] = model.objects.get(pk=int(request.session[key])) + except (ValueError, File.DoesNotExist): + continue + return currents + + +def update_current_item(request, item_type=None, pk=None): + if not item_type or not pk: + if not request.is_ajax() and not request.method == 'POST': + raise Http404 + item_type = request.POST['item'] + if 'value' in request.POST and 'item' in request.POST: + request.session[item_type] = request.POST['value'] + else: + request.session[item_type] = str(pk) + + currents = get_current_items(request) + # reinit when descending item are not relevant + if item_type == 'file' and currents['file'] and currents['operation'] and \ + currents['operation'].associated_file != currents['file']: + request.session["operation"] = '' + currents['operation'] = None + if item_type in ('operation', 'file') and currents['contextrecord'] and \ + (not request.session["operation"] or + currents['contextrecord'].operation != currents['operation']): + request.session["contextrecord"] = '' + currents['contextrecord'] = None + from archaeological_finds.models import Find + if item_type in ('contextrecord', 'operation', 'file') and currents['find'] and\ + (not request.session["contextrecord"] or + not Find.objects.filter( + downstream_treatment__isnull=True, + base_finds__context_record__pk=request.session["contextrecord"], + pk=currents['find'].pk).count()): + request.session["find"] = '' + currents['find'] = None + + # re-init ascending item with relevant values + if item_type == "find" and currents['find']: + from archaeological_context_records.models import ContextRecord + q = ContextRecord.objects.filter( + base_finds__find__pk=currents['find'].pk) + if q.count(): + currents['contextrecord'] = q.all()[0] + request.session['contextrecord'] = str( + currents['contextrecord'].pk) + if item_type in ("find", 'contextrecord') and currents['contextrecord']: + currents['operation'] = currents['contextrecord'].operation + request.session['operation'] = str(currents['operation'].pk) + if item_type in ("find", 'contextrecord', 'operation') and \ + currents['operation']: + currents['file'] = currents['operation'].associated_file + request.session['file'] = str(currents['file'].pk) if currents['file'] \ + else None return HttpResponse('ok') |