Ce serveur Gitlab sera éteint le 30 juin 2020, pensez à migrer vos projets vers les serveurs gitlab-research.centralesupelec.fr et gitlab-student.centralesupelec.fr !

Commit 24a39e80 authored by Maël Kervella's avatar Maël Kervella Committed by Pierre Cadart

Templatag pour générer des form avec typeahead

Utilise les form django et la génération de bootstrap
parent f2a4f837
...@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %} {% endcomment %}
{% load bootstrap3 %} {% load bootstrap3 %}
{% load bootstrap_form_typeahead %}
{% block title %}Création et modification de machines{% endblock %} {% block title %}Création et modification de machines{% endblock %}
...@@ -38,39 +39,13 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -38,39 +39,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% bootstrap_form_errors domainform %} {% bootstrap_form_errors domainform %}
{% endif %} {% endif %}
{% if type_to_ipv4 %}
<script>
var type_to_ipv4 = {
type: [{% for type, iplist in type_to_ipv4.items %}"{{ type }}",{% endfor %}],
iplist: [{% for type, iplist in type_to_ipv4.items %}
[ {{ iplist | safe }} ], {% endfor %}
]
}
$(document).ready(function() {
$("#id_ipv4").html("<option value='' selected='selected'>Choisisez un type de machine d'abord</options>");
$("#id_type").change(function() {
var val = $(this).val();
var options = "<option value='' selected='selected'>Assignation automatique de l'ipv4</option>";
for (var i = 0; i < type_to_ipv4.type.length; i++) {
if (type_to_ipv4.type[i] == val) {
for (var j = 0; j < type_to_ipv4.iplist[i].length; j++) {
options += "<option value='"+type_to_ipv4.iplist[i][j].id+"'>"+type_to_ipv4.iplist[i][j].ip+"</option>";
}
}
}
$("#id_ipv4").html(options)
});
});
</script>
{% endif %}
<form class="form" method="post"> <form class="form" method="post">
{% csrf_token %} {% csrf_token %}
{% if machineform %} {% if machineform %}
{% bootstrap_form machineform %} {% bootstrap_form machineform %}
{% endif %} {% endif %}
{% if interfaceform %} {% if interfaceform %}
{% bootstrap_form interfaceform %} {% bootstrap_form_typeahead interfaceform 'ipv4,type' %}
{% endif %} {% endif %}
{% if domainform %} {% if domainform %}
{% bootstrap_form domainform %} {% bootstrap_form domainform %}
......
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2017 Maël Kervella
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2017 Maël Kervella
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from django import template
from django.utils.safestring import mark_safe
from bootstrap3.templatetags.bootstrap3 import bootstrap_form
from bootstrap3.utils import render_tag
from bootstrap3.forms import render_field
register = template.Library()
@register.simple_tag
def bootstrap_form_typeahead(django_form, typeahead_fields, *args, **kwargs):
"""
Render a form where some specific fields are rendered using Typeahead.
Using Typeahead really improves the performance, the speed and UX when
dealing with very large datasets (select with 50k+ elts for instance).
For convenience, it accepts the same parameters as a standard bootstrap
can accept.
**Tag name**::
bootstrap_form_typeahead
**Parameters**:
form
The form that is to be rendered
typeahead_fields
A list of field names (comma separated) that should be rendered
with typeahead instead of the default bootstrap renderer.
See boostrap_form_ for other arguments
**Usage**::
{% bootstrap_form_typeahead form ['field1[,field2[,...]]] %}
**Example**:
{% bootstrap_form_typeahead form 'ipv4' %}
"""
t_fields = typeahead_fields.split(',')
exclude = kwargs.get('exclude', None)
exclude = exclude.split(',') if exclude else []
form = ''
for f_name, f_value in django_form.fields.items() :
if not f_name in exclude :
if f_name in t_fields :
form += render_tag(
'div',
attrs = {'class': 'form-group'},
content = label_tag( f_name, f_value ) +
input_tag( f_name, f_value ) +
hidden_tag( f_name ) +
typeahead_full_script( f_name, f_value )
)
else:
form += render_field(
f_value.get_bound_field(django_form, f_name),
*args,
**kwargs
)
return mark_safe( form )
def input_id( f_name ):
return 'typeahead_input_'+f_name
def select_id( f_name ):
return 'typeahead_select_'+f_name
def hidden_tag( f_name ):
return render_tag(
'input',
attrs={
'id': select_id(f_name),
'name': f_name,
'type': 'hidden',
'value': ''
}
)
def label_tag( f_name, f_value ):
return render_tag(
'label',
attrs={
'class': 'control-label',
'for': input_id(f_name)
},
content=f_value.label
)
def input_tag( f_name, f_value ):
return render_tag(
'input',
attrs={
'class': 'form-control',
'id': input_id(f_name),
'type': 'text',
'placeholder': f_value.empty_label
},
)
def typeahead_full_script( f_name, f_value ) :
js_content = \
'$("#'+input_id(f_name)+'").ready( function() {\n' + \
typeahead_choices( f_value ) + '\n' + \
typeahead_engine () + '\n' + \
'$("#'+input_id(f_name) + '").typeahead(\n' + \
typeahead_datasets( f_name ) + \
').bind(\n' + \
'"typeahead:select", ' + \
typeahead_updater( f_name ) + '\n' + \
')\n' + \
'});\n'
return render_tag( 'script', content=mark_safe( js_content ) )
def typeahead_choices( f_value ) :
return 'var choices = [' + \
', '.join([ \
'{key: ' + (str(choice[0]) if choice[0] != '' else '""') + \
', value: "' + str(choice[1]) + '"}' \
for choice in f_value.choices \
]) + \
'];'
def typeahead_engine () :
return 'var choices = new Bloodhound({ ' \
'datumTokenizer: Bloodhound.tokenizers.obj.whitespace("value"), ' \
'queryTokenizer: Bloodhound.tokenizers.whitespace, ' \
'local: choices, ' \
'identify: function(obj) { return obj.value; } ' \
'});'
def typeahead_datasets( f_name ) :
return '{ ' \
'hint: true, ' \
'highlight: true, ' \
'minLength: 1 ' \
'}, ' \
'{ ' \
'templates: { ' \
'suggestion: Handlebars.compile("<div>{{value}}</div>") ' \
'}, ' \
'display: "value", ' \
'name: "'+f_name+'", ' \
'source: choices ' \
'}'
def typeahead_updater( f_name ):
return 'function(evt, item) { ' \
'$("#'+select_id(f_name)+'").val( item.key ); ' \
'return item; ' \
'}'
...@@ -117,11 +117,7 @@ def new_machine(request, userid): ...@@ -117,11 +117,7 @@ def new_machine(request, userid):
reversion.set_comment("Création") reversion.set_comment("Création")
messages.success(request, "La machine a été créée") messages.success(request, "La machine a été créée")
return redirect("/users/profil/" + str(user.id)) return redirect("/users/profil/" + str(user.id))
type_to_ipv4 = {} return form({'machineform': machine, 'interfaceform': interface, 'domainform': domain}, 'machines/machine.html', request)
for t in interface.fields['type'].queryset :
iplist = IpList.objects.filter(interface__isnull=True).filter(ip_type=t.ip_type)
type_to_ipv4[str(t.id)] = ','.join(['{id:"%s", ip:"%s"}' % (b.id, b.ipv4) for b in iplist])
return form({'machineform': machine, 'interfaceform': interface, 'domainform': domain, 'type_to_ipv4': type_to_ipv4}, 'machines/machine.html', request)
@login_required @login_required
def edit_interface(request, interfaceid): def edit_interface(request, interfaceid):
...@@ -158,11 +154,7 @@ def edit_interface(request, interfaceid): ...@@ -158,11 +154,7 @@ def edit_interface(request, interfaceid):
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in domain_form.changed_data)) reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in domain_form.changed_data))
messages.success(request, "La machine a été modifiée") messages.success(request, "La machine a été modifiée")
return redirect("/users/profil/" + str(interface.machine.user.id)) return redirect("/users/profil/" + str(interface.machine.user.id))
type_to_ipv4 = {} return form({'machineform': machine_form, 'interfaceform': interface_form, 'domainform': domain_form}, 'machines/machine.html', request)
for t in interface_form.fields['type'].queryset :
iplist = IpList.objects.filter(interface__isnull=True).filter(ip_type=t.ip_type)
type_to_ipv4[str(t.id)] = ','.join(['{id:"%s", ip:"%s"}' % (b.id, b.ipv4) for b in iplist])
return form({'machineform': machine_form, 'interfaceform': interface_form, 'domainform': domain_form, 'type_to_ipv4': type_to_ipv4}, 'machines/machine.html', request)
@login_required @login_required
def del_machine(request, machineid): def del_machine(request, machineid):
...@@ -218,11 +210,7 @@ def new_interface(request, machineid): ...@@ -218,11 +210,7 @@ def new_interface(request, machineid):
reversion.set_comment("Création") reversion.set_comment("Création")
messages.success(request, "L'interface a été ajoutée") messages.success(request, "L'interface a été ajoutée")
return redirect("/users/profil/" + str(machine.user.id)) return redirect("/users/profil/" + str(machine.user.id))
type_to_ipv4 = {} return form({'interfaceform': interface_form, 'domainform': domain_form}, 'machines/machine.html', request)
for t in interface_form.fields['type'].queryset :
iplist = IpList.objects.filter(interface__isnull=True).filter(ip_type=t.ip_type)
type_to_ipv4[str(t.id)] = ','.join(['{id:"%s", ip:"%s"}' % (b.id, b.ipv4) for b in iplist])
return form({'interfaceform': interface_form, 'domainform': domain_form, 'type_to_ipv4': type_to_ipv4}, 'machines/machine.html', request)
@login_required @login_required
def del_interface(request, interfaceid): def del_interface(request, interfaceid):
......
span.twitter-typeahead .tt-menu,
span.twitter-typeahead .tt-dropdown-menu {
position: absolute;
top: 100%;
left: 0;
z-index: 1000;
display: none;
float: left;
min-width: 160px;
padding: 5px 0;
margin: 2px 0 0;
list-style: none;
font-size: 14px;
text-align: left;
background-color: #ffffff;
border: 1px solid #cccccc;
border: 1px solid rgba(0, 0, 0, 0.15);
border-radius: 4px;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
background-clip: padding-box;
}
span.twitter-typeahead .tt-suggestion {
display: block;
padding: 3px 20px;
clear: both;
font-weight: normal;
line-height: 1.42857143;
color: #333333;
white-space: nowrap;
}
span.twitter-typeahead .tt-suggestion.tt-cursor,
span.twitter-typeahead .tt-suggestion:hover,
span.twitter-typeahead .tt-suggestion:focus {
color: #ffffff;
text-decoration: none;
outline: 0;
background-color: #337ab7;
}
.input-group.input-group-lg span.twitter-typeahead .form-control {
height: 46px;
padding: 10px 16px;
font-size: 18px;
line-height: 1.3333333;
border-radius: 6px;
}
.input-group.input-group-sm span.twitter-typeahead .form-control {
height: 30px;
padding: 5px 10px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
}
span.twitter-typeahead {
width: 100%;
}
.input-group span.twitter-typeahead {
display: block !important;
height: 34px;
}
.input-group span.twitter-typeahead .tt-menu,
.input-group span.twitter-typeahead .tt-dropdown-menu {
top: 32px !important;
}
.input-group span.twitter-typeahead:not(:first-child):not(:last-child) .form-control {
border-radius: 0;
}
.input-group span.twitter-typeahead:first-child .form-control {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group span.twitter-typeahead:last-child .form-control {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.input-group.input-group-sm span.twitter-typeahead {
height: 30px;
}
.input-group.input-group-sm span.twitter-typeahead .tt-menu,
.input-group.input-group-sm span.twitter-typeahead .tt-dropdown-menu {
top: 30px !important;
}
.input-group.input-group-lg span.twitter-typeahead {
height: 46px;
}
.input-group.input-group-lg span.twitter-typeahead .tt-menu,
.input-group.input-group-lg span.twitter-typeahead .tt-dropdown-menu {
top: 46px !important;
}
This diff is collapsed.
This diff is collapsed.
...@@ -32,8 +32,11 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -32,8 +32,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<head> <head>
{# Load CSS and JavaScript #} {# Load CSS and JavaScript #}
{% bootstrap_css %} {% bootstrap_css %}
<link href="/static/css/typeaheadjs.css" rel="stylesheet">
{% bootstrap_javascript %} {% bootstrap_javascript %}
<script src="/static/js/typeahead.js"></script>
<script src="/static/js/handlebars.js"></script>
<link rel="stylesheet" href="{% static "/css/base.css" %}"> <link rel="stylesheet" href="{% static "/css/base.css" %}">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ site_name }} : {% block title %}Accueil{% endblock %}</title> <title>{{ site_name }} : {% block title %}Accueil{% endblock %}</title>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment