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 | 5230a8e0a06a5d67d6c13f2359bc51be07b4fb5a (patch) | |
tree | 5df1cfe674759003b1599f7334448f9c7f00637d /ishtar_common | |
parent | 06f8d8f45d5c08ec9ed17cee4836f3311703e6df (diff) | |
download | Ishtar-5230a8e0a06a5d67d6c13f2359bc51be07b4fb5a.tar.bz2 Ishtar-5230a8e0a06a5d67d6c13f2359bc51be07b4fb5a.zip |
Shortcut menu: menu is now dynamic - selected items filter dependant items (refs #2996) - can now pin items from sheet (refs #3078)
Diffstat (limited to 'ishtar_common')
-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 |
10 files changed, 254 insertions, 81 deletions
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') |