mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-27 07:02:26 +00:00
Support de typeahead pour les select multiples avec tokenfield
This commit is contained in:
parent
a92eaae633
commit
1083f8d199
6 changed files with 1499 additions and 71 deletions
|
@ -118,7 +118,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if serviceform %}
|
{% if serviceform %}
|
||||||
<h3>Service</h3>
|
<h3>Service</h3>
|
||||||
{% bootstrap_form serviceform %}
|
{% massive_bootstrap_form serviceform 'servers' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if vlanform %}
|
{% if vlanform %}
|
||||||
<h3>Vlan</h3>
|
<h3>Vlan</h3>
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
from django import template
|
from django import template
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.forms import TextInput
|
from django.forms import TextInput
|
||||||
|
from django.forms.widgets import Select
|
||||||
from bootstrap3.templatetags.bootstrap3 import bootstrap_form
|
from bootstrap3.templatetags.bootstrap3 import bootstrap_form
|
||||||
from bootstrap3.utils import render_tag
|
from bootstrap3.utils import render_tag
|
||||||
from bootstrap3.forms import render_field
|
from bootstrap3.forms import render_field
|
||||||
|
@ -165,34 +166,64 @@ def massive_bootstrap_form(form, mbf_fields, *args, **kwargs):
|
||||||
hidden_fields = [h.name for h in form.hidden_fields()]
|
hidden_fields = [h.name for h in form.hidden_fields()]
|
||||||
|
|
||||||
html = ''
|
html = ''
|
||||||
|
|
||||||
for f_name, f_value in form.fields.items() :
|
for f_name, f_value in form.fields.items() :
|
||||||
if not f_name in exclude :
|
if not f_name in exclude :
|
||||||
if f_name in fields and not f_name in hidden_fields :
|
if f_name in fields and not f_name in hidden_fields :
|
||||||
f_bound = f_value.get_bound_field( form, f_name )
|
|
||||||
f_value.widget = TextInput(
|
if not isinstance(f_value.widget, Select) :
|
||||||
attrs={
|
raise ValueError(
|
||||||
'name': 'mbf_'+f_name,
|
('Field named {f_name} from {form} is not a Select and'
|
||||||
'placeholder': f_value.empty_label
|
'can\'t be rendered with massive_bootstrap_form.'
|
||||||
}
|
).format(
|
||||||
)
|
f_name=f_name,
|
||||||
html += render_field(
|
form=form
|
||||||
f_value.get_bound_field( form, f_name ),
|
|
||||||
*args,
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
html += render_tag(
|
|
||||||
'div',
|
|
||||||
content = hidden_tag( f_bound, f_name ) +
|
|
||||||
mbf_js(
|
|
||||||
f_name,
|
|
||||||
f_value,
|
|
||||||
f_bound,
|
|
||||||
choices,
|
|
||||||
engine,
|
|
||||||
match_func,
|
|
||||||
update_on
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
multiple = f_value.widget.allow_multiple_selected
|
||||||
|
f_bound = f_value.get_bound_field( form, f_name )
|
||||||
|
|
||||||
|
f_value.widget = TextInput(
|
||||||
|
attrs = {
|
||||||
|
'name': 'mbf_'+f_name,
|
||||||
|
'placeholder': f_value.empty_label
|
||||||
|
}
|
||||||
|
)
|
||||||
|
html += render_field(
|
||||||
|
f_value.get_bound_field( form, f_name ),
|
||||||
|
*args,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
if multiple :
|
||||||
|
content = mbf_js(
|
||||||
|
f_name,
|
||||||
|
f_value,
|
||||||
|
f_bound,
|
||||||
|
multiple,
|
||||||
|
choices,
|
||||||
|
engine,
|
||||||
|
match_func,
|
||||||
|
update_on
|
||||||
|
)
|
||||||
|
else :
|
||||||
|
content = hidden_tag( f_bound, f_name ) + mbf_js(
|
||||||
|
f_name,
|
||||||
|
f_value,
|
||||||
|
f_bound,
|
||||||
|
multiple,
|
||||||
|
choices,
|
||||||
|
engine,
|
||||||
|
match_func,
|
||||||
|
update_on
|
||||||
|
)
|
||||||
|
html += render_tag(
|
||||||
|
'div',
|
||||||
|
content = content,
|
||||||
|
attrs = { 'id': custom_div_id( f_bound ) }
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
html += render_field(
|
html += render_field(
|
||||||
f_value.get_bound_field( form, f_name ),
|
f_value.get_bound_field( form, f_name ),
|
||||||
|
@ -208,7 +239,11 @@ def input_id( f_bound ) :
|
||||||
|
|
||||||
def hidden_id( f_bound ):
|
def hidden_id( f_bound ):
|
||||||
""" The id of the HTML hidden input element """
|
""" The id of the HTML hidden input element """
|
||||||
return input_id( f_bound ) +'_hidden'
|
return input_id( f_bound ) + '_hidden'
|
||||||
|
|
||||||
|
def custom_div_id( f_bound ):
|
||||||
|
""" The id of the HTML div element containing values and script """
|
||||||
|
return input_id( f_bound ) + '_div'
|
||||||
|
|
||||||
def hidden_tag( f_bound, f_name ):
|
def hidden_tag( f_bound, f_name ):
|
||||||
""" The HTML hidden input element """
|
""" The HTML hidden input element """
|
||||||
|
@ -222,61 +257,101 @@ def hidden_tag( f_bound, f_name ):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def mbf_js( f_name, f_value, f_bound,
|
def mbf_js( f_name, f_value, f_bound, multiple,
|
||||||
choices_, engine_, match_func_, update_on_ ) :
|
choices_, engine_, match_func_, update_on_ ) :
|
||||||
""" The whole script to use """
|
""" The whole script to use """
|
||||||
|
|
||||||
choices = mark_safe( choices_[f_name] ) if f_name in choices_.keys() \
|
choices = ( mark_safe( choices_[f_name] ) if f_name in choices_.keys()
|
||||||
else default_choices( f_value )
|
else default_choices( f_value ) )
|
||||||
|
|
||||||
engine = mark_safe( engine_[f_name] ) if f_name in engine_.keys() \
|
engine = ( mark_safe( engine_[f_name] ) if f_name in engine_.keys()
|
||||||
else default_engine ( f_name )
|
else default_engine ( f_name ) )
|
||||||
|
|
||||||
match_func = mark_safe( match_func_[f_name] ) \
|
match_func = ( mark_safe( match_func_[f_name] )
|
||||||
if f_name in match_func_.keys() else default_match_func( f_name )
|
if f_name in match_func_.keys() else default_match_func( f_name ) )
|
||||||
|
|
||||||
update_on = update_on_[f_name] if f_name in update_on_.keys() else []
|
update_on = update_on_[f_name] if f_name in update_on_.keys() else []
|
||||||
|
|
||||||
js_content = (
|
if multiple :
|
||||||
'var choices_{f_name} = {choices};'
|
js_content = (
|
||||||
'var engine_{f_name};'
|
'var choices_{f_name} = {choices};'
|
||||||
'var setup_{f_name} = function() {{'
|
'var engine_{f_name};'
|
||||||
'engine_{f_name} = {engine};'
|
'var setup_{f_name} = function() {{'
|
||||||
'$( "#{input_id}" ).typeahead( "destroy" );'
|
'engine_{f_name} = {engine};'
|
||||||
'$( "#{input_id}" ).typeahead( {datasets} );'
|
'$( "#{input_id}" ).tokenfield( "destroy" );'
|
||||||
'}};'
|
'$( "#{input_id}" ).tokenfield({{typeahead: [ {datasets} ] }});'
|
||||||
'$( "#{input_id}" ).bind( "typeahead:select", {updater} );'
|
'}};'
|
||||||
'$( "#{input_id}" ).bind( "typeahead:change", {change} );'
|
'$( "#{input_id}" ).bind( "tokenfield:createtoken", {create} );'
|
||||||
'{updates}'
|
'$( "#{input_id}" ).bind( "tokenfield:edittoken", {edit} );'
|
||||||
'$( "#{input_id}" ).ready( function() {{'
|
'$( "#{input_id}" ).bind( "tokenfield:removetoken", {remove} );'
|
||||||
'setup_{f_name}();'
|
'{updates}'
|
||||||
'{init_input}'
|
'$( "#{input_id}" ).ready( function() {{'
|
||||||
'}} );'
|
'setup_{f_name}();'
|
||||||
).format(
|
'{init_input}'
|
||||||
f_name = f_name,
|
'}} );'
|
||||||
choices = choices,
|
).format(
|
||||||
engine = engine,
|
f_name = f_name,
|
||||||
input_id = input_id( f_bound ),
|
choices = choices,
|
||||||
datasets = default_datasets( f_name, match_func ),
|
engine = engine,
|
||||||
updater = typeahead_updater( f_bound ),
|
input_id = input_id( f_bound ),
|
||||||
change = typeahead_change( f_bound ),
|
datasets = default_datasets( f_name, match_func ),
|
||||||
updates = ''.join( [ (
|
create = tokenfield_create( f_name, f_bound ),
|
||||||
'$( "#{u_id}" ).change( function() {{'
|
edit = tokenfield_edit( f_bound ),
|
||||||
'setup_{f_name}();'
|
remove = tokenfield_remove( f_bound ),
|
||||||
'{reset_input}'
|
updates = ''.join( [ (
|
||||||
'}} );'
|
'$( "#{u_id}" ).change( function() {{'
|
||||||
).format(
|
'setup_{f_name}();'
|
||||||
u_id = u_id,
|
'{reset_input}'
|
||||||
reset_input = reset_input( f_bound ),
|
'}} );'
|
||||||
f_name = f_name
|
).format(
|
||||||
) for u_id in update_on ]
|
u_id = u_id,
|
||||||
),
|
reset_input = tokenfield_reset_input( f_bound ),
|
||||||
init_input = init_input( f_name, f_bound ),
|
f_name = f_name
|
||||||
)
|
) for u_id in update_on ]
|
||||||
|
),
|
||||||
|
init_input = tokenfield_init_input( f_name, f_bound ),
|
||||||
|
)
|
||||||
|
else :
|
||||||
|
js_content = (
|
||||||
|
'var choices_{f_name} = {choices};'
|
||||||
|
'var engine_{f_name};'
|
||||||
|
'var setup_{f_name} = function() {{'
|
||||||
|
'engine_{f_name} = {engine};'
|
||||||
|
'$( "#{input_id}" ).typeahead( "destroy" );'
|
||||||
|
'$( "#{input_id}" ).typeahead( {datasets} );'
|
||||||
|
'}};'
|
||||||
|
'$( "#{input_id}" ).bind( "typeahead:select", {select} );'
|
||||||
|
'$( "#{input_id}" ).bind( "typeahead:change", {change} );'
|
||||||
|
'{updates}'
|
||||||
|
'$( "#{input_id}" ).ready( function() {{'
|
||||||
|
'setup_{f_name}();'
|
||||||
|
'{init_input}'
|
||||||
|
'}} );'
|
||||||
|
).format(
|
||||||
|
f_name = f_name,
|
||||||
|
choices = choices,
|
||||||
|
engine = engine,
|
||||||
|
input_id = input_id( f_bound ),
|
||||||
|
datasets = default_datasets( f_name, match_func ),
|
||||||
|
select = typeahead_select( f_bound ),
|
||||||
|
change = typeahead_change( f_bound ),
|
||||||
|
updates = ''.join( [ (
|
||||||
|
'$( "#{u_id}" ).change( function() {{'
|
||||||
|
'setup_{f_name}();'
|
||||||
|
'{reset_input}'
|
||||||
|
'}} );'
|
||||||
|
).format(
|
||||||
|
u_id = u_id,
|
||||||
|
reset_input = typeahead_reset_input( f_bound ),
|
||||||
|
f_name = f_name
|
||||||
|
) for u_id in update_on ]
|
||||||
|
),
|
||||||
|
init_input = typeahead_init_input( f_name, f_bound ),
|
||||||
|
)
|
||||||
|
|
||||||
return render_tag( 'script', content=mark_safe( js_content ) )
|
return render_tag( 'script', content=mark_safe( js_content ) )
|
||||||
|
|
||||||
def init_input( f_name, f_bound ) :
|
def typeahead_init_input( f_name, f_bound ) :
|
||||||
""" The JS script to init the fields values """
|
""" The JS script to init the fields values """
|
||||||
init_key = f_bound.value() or '""'
|
init_key = f_bound.value() or '""'
|
||||||
return (
|
return (
|
||||||
|
@ -293,7 +368,7 @@ def init_input( f_name, f_bound ) :
|
||||||
hidden_id = hidden_id( f_bound )
|
hidden_id = hidden_id( f_bound )
|
||||||
)
|
)
|
||||||
|
|
||||||
def reset_input( f_bound ) :
|
def typeahead_reset_input( f_bound ) :
|
||||||
""" The JS script to reset the fields values """
|
""" The JS script to reset the fields values """
|
||||||
return (
|
return (
|
||||||
'$( "#{input_id}" ).typeahead("val", "");'
|
'$( "#{input_id}" ).typeahead("val", "");'
|
||||||
|
@ -303,6 +378,31 @@ def reset_input( f_bound ) :
|
||||||
hidden_id = hidden_id( f_bound )
|
hidden_id = hidden_id( f_bound )
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def tokenfield_init_input( f_name, f_bound ) :
|
||||||
|
""" The JS script to init the fields values """
|
||||||
|
init_key = f_bound.value() or '""'
|
||||||
|
return (
|
||||||
|
'$( "#{input_id}" ).tokenfield("setTokens", {init_val});'
|
||||||
|
).format(
|
||||||
|
input_id = input_id( f_bound ),
|
||||||
|
init_val = '""' if init_key == '""' else (
|
||||||
|
'engine_{f_name}.get( {init_key} ).map('
|
||||||
|
'function(o) {{ return o.value; }}'
|
||||||
|
')').format(
|
||||||
|
f_name = f_name,
|
||||||
|
init_key = init_key
|
||||||
|
),
|
||||||
|
init_key = init_key,
|
||||||
|
)
|
||||||
|
|
||||||
|
def tokenfield_reset_input( f_bound ) :
|
||||||
|
""" The JS script to reset the fields values """
|
||||||
|
return (
|
||||||
|
'$( "#{input_id}" ).tokenfield("setTokens", "");'
|
||||||
|
).format(
|
||||||
|
input_id = input_id( f_bound ),
|
||||||
|
)
|
||||||
|
|
||||||
def default_choices( f_value ) :
|
def default_choices( f_value ) :
|
||||||
""" The JS script creating the variable choices_<fieldname> """
|
""" The JS script creating the variable choices_<fieldname> """
|
||||||
return '[{objects}]'.format(
|
return '[{objects}]'.format(
|
||||||
|
@ -362,7 +462,7 @@ def default_match_func ( f_name ) :
|
||||||
f_name = f_name
|
f_name = f_name
|
||||||
)
|
)
|
||||||
|
|
||||||
def typeahead_updater( f_bound ):
|
def typeahead_select( f_bound ):
|
||||||
""" The JS script creating the function triggered when an item is
|
""" The JS script creating the function triggered when an item is
|
||||||
selected through typeahead """
|
selected through typeahead """
|
||||||
return (
|
return (
|
||||||
|
@ -391,3 +491,52 @@ def typeahead_change( f_bound ):
|
||||||
hidden_id = hidden_id( f_bound )
|
hidden_id = hidden_id( f_bound )
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def tokenfield_create( f_name, f_bound ):
|
||||||
|
""" The JS script triggered when a new token is created in tokenfield. """
|
||||||
|
return (
|
||||||
|
'function(evt) {{'
|
||||||
|
'var data = evt.attrs.value;'
|
||||||
|
'var i = 0;'
|
||||||
|
'while ( i<choices_{f_name}.length &&'
|
||||||
|
'choices_{f_name}[i].value !== data ) {{'
|
||||||
|
'i++;'
|
||||||
|
'}}'
|
||||||
|
'if ( i === choices_{f_name}.length ) {{ return false; }}'
|
||||||
|
'var new_input = document.createElement("input");'
|
||||||
|
'new_input.type = "hidden";'
|
||||||
|
'new_input.id = "{hidden_id}_"+data;'
|
||||||
|
'new_input.value = choices_{f_name}[i].key.toString();'
|
||||||
|
'new_input.name = "{name}";'
|
||||||
|
'$( "#{div_id}" ).append(new_input);'
|
||||||
|
'}}'
|
||||||
|
).format(
|
||||||
|
f_name = f_name,
|
||||||
|
hidden_id = hidden_id( f_bound ),
|
||||||
|
name = f_bound.html_name,
|
||||||
|
div_id = custom_div_id( f_bound )
|
||||||
|
)
|
||||||
|
|
||||||
|
def tokenfield_edit( f_bound ):
|
||||||
|
""" The JS script triggered when a token is edited in tokenfield. """
|
||||||
|
return (
|
||||||
|
'function(evt) {{'
|
||||||
|
'var data = evt.attrs.value;'
|
||||||
|
'var old_input = document.getElementById( "{hidden_id}_"+data );'
|
||||||
|
'old_input.parentNode.removeChild(old_input);'
|
||||||
|
'}}'
|
||||||
|
).format(
|
||||||
|
hidden_id = hidden_id( f_bound )
|
||||||
|
)
|
||||||
|
|
||||||
|
def tokenfield_remove( f_bound ):
|
||||||
|
""" The JS script trigggered when a token is removed from tokenfield. """
|
||||||
|
return (
|
||||||
|
'function(evt) {{'
|
||||||
|
'var data = evt.attrs.value;'
|
||||||
|
'var old_input = document.getElementById( "{hidden_id}_"+data );'
|
||||||
|
'old_input.parentNode.removeChild(old_input);'
|
||||||
|
'}}'
|
||||||
|
).format(
|
||||||
|
hidden_id = hidden_id( f_bound )
|
||||||
|
)
|
||||||
|
|
||||||
|
|
210
static/css/bootstrap-tokenfield.css
vendored
Normal file
210
static/css/bootstrap-tokenfield.css
vendored
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
/*!
|
||||||
|
* bootstrap-tokenfield
|
||||||
|
* https://github.com/sliptree/bootstrap-tokenfield
|
||||||
|
* Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
|
||||||
|
*/
|
||||||
|
@-webkit-keyframes blink {
|
||||||
|
0% {
|
||||||
|
border-color: #ededed;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
border-color: #b94a48;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes blink {
|
||||||
|
0% {
|
||||||
|
border-color: #ededed;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
border-color: #b94a48;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes blink {
|
||||||
|
0% {
|
||||||
|
border-color: #ededed;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
border-color: #b94a48;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tokenfield {
|
||||||
|
height: auto;
|
||||||
|
min-height: 34px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
}
|
||||||
|
.tokenfield.focus {
|
||||||
|
border-color: #66afe9;
|
||||||
|
outline: 0;
|
||||||
|
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);
|
||||||
|
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);
|
||||||
|
}
|
||||||
|
.tokenfield .token {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
background-color: #ededed;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin: -1px 5px 5px 0;
|
||||||
|
height: 22px;
|
||||||
|
vertical-align: top;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.tokenfield .token:hover {
|
||||||
|
border-color: #b9b9b9;
|
||||||
|
}
|
||||||
|
.tokenfield .token.active {
|
||||||
|
border-color: #52a8ec;
|
||||||
|
border-color: rgba(82, 168, 236, 0.8);
|
||||||
|
}
|
||||||
|
.tokenfield .token.duplicate {
|
||||||
|
border-color: #ebccd1;
|
||||||
|
-webkit-animation-name: blink;
|
||||||
|
animation-name: blink;
|
||||||
|
-webkit-animation-duration: 0.1s;
|
||||||
|
animation-duration: 0.1s;
|
||||||
|
-webkit-animation-direction: normal;
|
||||||
|
animation-direction: normal;
|
||||||
|
-webkit-animation-timing-function: ease;
|
||||||
|
animation-timing-function: ease;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
.tokenfield .token.invalid {
|
||||||
|
background: none;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
-webkit-border-radius: 0;
|
||||||
|
-moz-border-radius: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
border-bottom: 1px dotted #d9534f;
|
||||||
|
}
|
||||||
|
.tokenfield .token.invalid.active {
|
||||||
|
background: #ededed;
|
||||||
|
border: 1px solid #ededed;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.tokenfield .token .token-label {
|
||||||
|
display: inline-block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
padding-left: 4px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.tokenfield .token .close {
|
||||||
|
font-family: Arial;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 100%;
|
||||||
|
font-size: 1.1em;
|
||||||
|
line-height: 1.49em;
|
||||||
|
margin-left: 5px;
|
||||||
|
float: none;
|
||||||
|
height: 100%;
|
||||||
|
vertical-align: top;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
.tokenfield .token-input {
|
||||||
|
background: none;
|
||||||
|
width: 60px;
|
||||||
|
min-width: 60px;
|
||||||
|
border: 0;
|
||||||
|
height: 20px;
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.tokenfield .token-input:focus {
|
||||||
|
border-color: transparent;
|
||||||
|
outline: 0;
|
||||||
|
/* IE6-9 */
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.tokenfield.disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
background-color: #eeeeee;
|
||||||
|
}
|
||||||
|
.tokenfield.disabled .token-input {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.tokenfield.disabled .token:hover {
|
||||||
|
cursor: not-allowed;
|
||||||
|
border-color: #d9d9d9;
|
||||||
|
}
|
||||||
|
.tokenfield.disabled .token:hover .close {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.2;
|
||||||
|
filter: alpha(opacity=20);
|
||||||
|
}
|
||||||
|
.has-warning .tokenfield.focus {
|
||||||
|
border-color: #66512c;
|
||||||
|
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
|
||||||
|
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
|
||||||
|
}
|
||||||
|
.has-error .tokenfield.focus {
|
||||||
|
border-color: #843534;
|
||||||
|
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
|
||||||
|
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
|
||||||
|
}
|
||||||
|
.has-success .tokenfield.focus {
|
||||||
|
border-color: #2b542c;
|
||||||
|
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
|
||||||
|
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
|
||||||
|
}
|
||||||
|
.tokenfield.input-sm,
|
||||||
|
.input-group-sm .tokenfield {
|
||||||
|
min-height: 30px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
}
|
||||||
|
.input-group-sm .token,
|
||||||
|
.tokenfield.input-sm .token {
|
||||||
|
height: 20px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.input-group-sm .token-input,
|
||||||
|
.tokenfield.input-sm .token-input {
|
||||||
|
height: 18px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.tokenfield.input-lg,
|
||||||
|
.input-group-lg .tokenfield {
|
||||||
|
height: auto;
|
||||||
|
min-height: 45px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
.input-group-lg .token,
|
||||||
|
.tokenfield.input-lg .token {
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
.input-group-lg .token-label,
|
||||||
|
.tokenfield.input-lg .token-label {
|
||||||
|
line-height: 23px;
|
||||||
|
}
|
||||||
|
.input-group-lg .token .close,
|
||||||
|
.tokenfield.input-lg .token .close {
|
||||||
|
line-height: 1.3em;
|
||||||
|
}
|
||||||
|
.input-group-lg .token-input,
|
||||||
|
.tokenfield.input-lg .token-input {
|
||||||
|
height: 23px;
|
||||||
|
line-height: 23px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.tokenfield.rtl {
|
||||||
|
direction: rtl;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.tokenfield.rtl .token {
|
||||||
|
margin: -1px 0 5px 5px;
|
||||||
|
}
|
||||||
|
.tokenfield.rtl .token .token-label {
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
23
static/js/bootstrap-tokenfield/LICENSE.md
Normal file
23
static/js/bootstrap-tokenfield/LICENSE.md
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#### Sliptree
|
||||||
|
- by Illimar Tambek for [Sliptree](http://sliptree.com)
|
||||||
|
- Copyright (c) 2013 by Sliptree
|
||||||
|
|
||||||
|
Available for use under the [MIT License](http://en.wikipedia.org/wiki/MIT_License)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
1042
static/js/bootstrap-tokenfield/bootstrap-tokenfield.js
vendored
Normal file
1042
static/js/bootstrap-tokenfield/bootstrap-tokenfield.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -33,12 +33,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
{# Load CSS and JavaScript #}
|
{# Load CSS and JavaScript #}
|
||||||
{% bootstrap_css %}
|
{% bootstrap_css %}
|
||||||
<link href="/static/css/typeaheadjs.css" rel="stylesheet">
|
<link href="/static/css/typeaheadjs.css" rel="stylesheet">
|
||||||
|
<link href="/static/css/bootstrap-tokenfield.css" rel="stylesheet">
|
||||||
|
{% comment %}<link href="/static/css/jquery-ui.css" rel="stylesheet">{% endcomment %}
|
||||||
|
|
||||||
{% bootstrap_javascript %}
|
{% bootstrap_javascript %}
|
||||||
<script src="/static/js/typeahead/typeahead.js"></script>
|
<script src="/static/js/typeahead/typeahead.js"></script>
|
||||||
<script src="/static/js/handlebars/handlebars.js"></script>
|
<script src="/static/js/handlebars/handlebars.js"></script>
|
||||||
<script src="/static/js/konami/konami.js"></script>
|
<script src="/static/js/konami/konami.js"></script>
|
||||||
<script src="/static/js/sapphire.js"> var s=Sapphire(); Konami(s.activate); </script>
|
<script src="/static/js/sapphire.js"> var s=Sapphire(); Konami(s.activate); </script>
|
||||||
|
<script src="/static/js/bootstrap-tokenfield/bootstrap-tokenfield.js"></script>
|
||||||
|
{% comment %}<script src="/static/js/jquery-ui.js"></script>{% endcomment %}
|
||||||
<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>
|
||||||
|
|
Loading…
Reference in a new issue