From cebc979282c80ace1b2d4bb1388d32543f5f4961 Mon Sep 17 00:00:00 2001
From: Ole Laursen
Date: Tue, 25 Nov 2014 16:47:48 +0000
Subject: [PATCH] Summary: Resolve person/email/document multiselect issue by
importing select2 and switching the widgets over to using that. Port the
milestones editing page to Bootstrap. - Legacy-Id: 8713
---
ietf/doc/fields.py | 47 +-
ietf/doc/tests.py | 4 +-
ietf/doc/tests_draft.py | 12 +-
ietf/doc/urls.py | 2 +-
ietf/doc/views_draft.py | 35 +-
ietf/doc/views_search.py | 6 +-
ietf/group/edit.py | 12 +-
ietf/group/info.py | 2 +-
ietf/group/milestones.py | 130 ++--
ietf/group/tests_info.py | 28 +-
ietf/group/views_stream.py | 4 +-
ietf/nomcom/forms.py | 4 +-
ietf/person/fields.py | 60 +-
ietf/person/tests.py | 2 +-
ietf/person/urls.py | 2 +-
ietf/person/views.py | 13 +-
ietf/secr/drafts/forms.py | 4 +-
ietf/secr/sreq/forms.py | 4 +-
ietf/secr/templates/drafts/edit.html | 55 +-
ietf/secr/templates/sreq/edit.html | 55 +-
ietf/secr/templates/sreq/new.html | 55 +-
ietf/templates/doc/change_shepherd.html | 9 +-
ietf/templates/doc/draft/change_replaces.html | 17 +-
ietf/templates/doc/draft/edit_info.html | 2 +-
ietf/templates/group/edit.html | 31 +-
ietf/templates/group/edit_milestones.html | 136 ++--
ietf/templates/group/milestone_form.html | 47 +-
ietf/templates/group/stream_edit.html | 11 +-
ietf/templates/nomcom/edit_position.html | 7 +-
static/facelift/css/ietf.css | 14 +
static/facelift/css/lib/select2-bootstrap.css | 497 +++++++++++++
static/facelift/css/lib/select2-spinner.gif | Bin 0 -> 1849 bytes
static/facelift/css/lib/select2.css | 704 ++++++++++++++++++
static/facelift/css/lib/select2.png | Bin 0 -> 613 bytes
static/facelift/js/edit-milestones.js | 140 ++++
static/facelift/js/ietf.js | 195 ++---
static/facelift/js/lib/select2-3.5.2.min.js | 23 +
37 files changed, 1853 insertions(+), 516 deletions(-)
create mode 100644 static/facelift/css/lib/select2-bootstrap.css
create mode 100644 static/facelift/css/lib/select2-spinner.gif
create mode 100644 static/facelift/css/lib/select2.css
create mode 100644 static/facelift/css/lib/select2.png
create mode 100644 static/facelift/js/edit-milestones.js
create mode 100644 static/facelift/js/lib/select2-3.5.2.min.js
diff --git a/ietf/doc/fields.py b/ietf/doc/fields.py
index 264beb08e..275f77dc4 100644
--- a/ietf/doc/fields.py
+++ b/ietf/doc/fields.py
@@ -8,17 +8,16 @@ import debug # pyflakes:ignore
from ietf.doc.models import Document, DocAlias
-def tokeninput_id_doc_name_json(objs):
- return json.dumps([{ "id": o.pk, "name": escape(o.name) } for o in objs])
+def select2_id_doc_name_json(objs):
+ return json.dumps([{ "id": o.pk, "text": escape(o.name) } for o in objs])
-class AutocompletedDocumentsField(forms.CharField):
- """Tokenizing autocompleted multi-select field for choosing
- documents using jquery.tokeninput.js.
+class SearchableDocumentsField(forms.CharField):
+ """Server-based multi-select field for choosing documents using
+ select2.js.
The field uses a comma-separated list of primary keys in a
- CharField element as its API, the tokeninput Javascript adds some
- selection magic on top of this so we have to pass it a JSON
- representation of ids and user-understandable labels."""
+ CharField element as its API with some extra attributes used by
+ the Javascript part."""
def __init__(self,
max_entries=None, # max number of selected objs
@@ -31,39 +30,45 @@ class AutocompletedDocumentsField(forms.CharField):
self.doc_type = doc_type
self.model = model
- super(AutocompletedDocumentsField, self).__init__(*args, **kwargs)
+ super(SearchableDocumentsField, self).__init__(*args, **kwargs)
- self.widget.attrs["class"] = "tokenized-field"
- self.widget.attrs["data-hint-text"] = hint_text
+ self.widget.attrs["class"] = "select2-field"
+ self.widget.attrs["data-placeholder"] = hint_text
if self.max_entries != None:
self.widget.attrs["data-max-entries"] = self.max_entries
- def parse_tokenized_value(self, value):
+ def parse_select2_value(self, value):
return [x.strip() for x in value.split(",") if x.strip()]
def prepare_value(self, value):
if not value:
value = ""
if isinstance(value, basestring):
- pks = self.parse_tokenized_value(value)
- value = self.model.objects.filter(pk__in=pks, type=self.doc_type)
+ pks = self.parse_select2_value(value)
+ value = self.model.objects.filter(pk__in=pks)
+ filter_args = {}
+ if self.model == DocAlias:
+ filter_args["document__type"] = self.doc_type
+ else:
+ filter_args["type"] = self.doc_type
+ value = value.filter(**filter_args)
if isinstance(value, self.model):
value = [value]
- self.widget.attrs["data-pre"] = tokeninput_id_doc_name_json(value)
+ self.widget.attrs["data-pre"] = select2_id_doc_name_json(value)
# doing this in the constructor is difficult because the URL
# patterns may not have been fully constructed there yet
- self.widget.attrs["data-ajax-url"] = urlreverse("ajax_tokeninput_search_docs", kwargs={
+ self.widget.attrs["data-ajax-url"] = urlreverse("ajax_select2_search_docs", kwargs={
"doc_type": self.doc_type,
"model_name": self.model.__name__.lower()
})
- return ",".join(o.pk for o in value)
+ return u",".join(unicode(o.pk) for o in value)
def clean(self, value):
- value = super(AutocompletedDocumentsField, self).clean(value)
- pks = self.parse_tokenized_value(value)
+ value = super(SearchableDocumentsField, self).clean(value)
+ pks = self.parse_select2_value(value)
objs = self.model.objects.filter(pk__in=pks)
@@ -77,7 +82,7 @@ class AutocompletedDocumentsField(forms.CharField):
return objs
-class AutocompletedDocAliasField(AutocompletedDocumentsField):
+class SearchableDocAliasesField(SearchableDocumentsField):
def __init__(self, model=DocAlias, *args, **kwargs):
- super(AutocompletedDocAliasField, self).__init__(model=model, *args, **kwargs)
+ super(SearchableDocAliasesField, self).__init__(model=model, *args, **kwargs)
diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py
index ab7169c0c..a8a9a16f5 100644
--- a/ietf/doc/tests.py
+++ b/ietf/doc/tests.py
@@ -127,7 +127,7 @@ class SearchTestCase(TestCase):
draft = make_test_data()
# Document
- url = urlreverse("ajax_tokeninput_search_docs", kwargs={
+ url = urlreverse("ajax_select2_search_docs", kwargs={
"model_name": "document",
"doc_type": "draft",
})
@@ -139,7 +139,7 @@ class SearchTestCase(TestCase):
# DocAlias
doc_alias = draft.docalias_set.get()
- url = urlreverse("ajax_tokeninput_search_docs", kwargs={
+ url = urlreverse("ajax_select2_search_docs", kwargs={
"model_name": "docalias",
"doc_type": "draft",
})
diff --git a/ietf/doc/tests_draft.py b/ietf/doc/tests_draft.py
index eefe9b6ef..f76a81e55 100644
--- a/ietf/doc/tests_draft.py
+++ b/ietf/doc/tests_draft.py
@@ -1227,8 +1227,7 @@ class ChangeReplacesTests(TestCase):
# Post that says replacea replaces base a
self.assertEqual(self.basea.get_state().slug,'active')
- repljson='{"%d":"%s"}'%(DocAlias.objects.get(name=self.basea.name).id,self.basea.name)
- r = self.client.post(url, dict(replaces=repljson))
+ r = self.client.post(url, dict(replaces=str(DocAlias.objects.get(name=self.basea.name).id)))
self.assertEqual(r.status_code, 302)
self.assertEqual(RelatedDocument.objects.filter(relationship__slug='replaces',source=self.replacea).count(),1)
self.assertEqual(Document.objects.get(name='draft-test-base-a').get_state().slug,'repl')
@@ -1236,23 +1235,20 @@ class ChangeReplacesTests(TestCase):
# Post that says replaceboth replaces both base a and base b
url = urlreverse('doc_change_replaces', kwargs=dict(name=self.replaceboth.name))
self.assertEqual(self.baseb.get_state().slug,'expired')
- repljson='{"%d":"%s","%d":"%s"}'%(DocAlias.objects.get(name=self.basea.name).id,self.basea.name,
- DocAlias.objects.get(name=self.baseb.name).id,self.baseb.name)
- r = self.client.post(url, dict(replaces=repljson))
+ r = self.client.post(url, dict(replaces=str(DocAlias.objects.get(name=self.basea.name).id) + "," + str(DocAlias.objects.get(name=self.baseb.name).id)))
self.assertEqual(r.status_code, 302)
self.assertEqual(Document.objects.get(name='draft-test-base-a').get_state().slug,'repl')
self.assertEqual(Document.objects.get(name='draft-test-base-b').get_state().slug,'repl')
# Post that undoes replaceboth
- repljson='{}'
- r = self.client.post(url, dict(replaces=repljson))
+ r = self.client.post(url, dict(replaces=""))
self.assertEqual(r.status_code, 302)
self.assertEqual(Document.objects.get(name='draft-test-base-a').get_state().slug,'repl') # Because A is still also replaced by replacea
self.assertEqual(Document.objects.get(name='draft-test-base-b').get_state().slug,'expired')
# Post that undoes replacea
url = urlreverse('doc_change_replaces', kwargs=dict(name=self.replacea.name))
- r = self.client.post(url, dict(replaces=repljson))
+ r = self.client.post(url, dict(replaces=""))
self.assertEqual(r.status_code, 302)
self.assertEqual(Document.objects.get(name='draft-test-base-a').get_state().slug,'active')
diff --git a/ietf/doc/urls.py b/ietf/doc/urls.py
index e669d16b0..4a76ded78 100644
--- a/ietf/doc/urls.py
+++ b/ietf/doc/urls.py
@@ -49,7 +49,7 @@ urlpatterns = patterns('',
url(r'^all/$', views_search.index_all_drafts, name="index_all_drafts"),
url(r'^active/$', views_search.index_active_drafts, name="index_active_drafts"),
- url(r'^tokeninputsearch/(?P(document|docalias))/(?Pdraft)/$', views_search.ajax_tokeninput_search_docs, name="ajax_tokeninput_search_docs"),
+ url(r'^select2search/(?P(document|docalias))/(?Pdraft)/$', views_search.ajax_select2_search_docs, name="ajax_select2_search_docs"),
url(r'^(?P[A-Za-z0-9._+-]+)/(?:(?P[0-9-]+)/)?$', views_doc.document_main, name="doc_view"),
url(r'^(?P[A-Za-z0-9._+-]+)/history/$', views_doc.document_history, name="doc_history"),
diff --git a/ietf/doc/views_draft.py b/ietf/doc/views_draft.py
index c2a08f708..70ec3ed06 100644
--- a/ietf/doc/views_draft.py
+++ b/ietf/doc/views_draft.py
@@ -1,6 +1,6 @@
# changing state and metadata on Internet Drafts
-import datetime, json
+import datetime
from django import forms
from django.http import HttpResponseRedirect, HttpResponseForbidden, Http404
@@ -24,13 +24,14 @@ from ietf.doc.utils import ( add_state_change_event, can_adopt_draft,
get_tags_for_stream_id, nice_consensus,
update_reminder, update_telechat, make_notify_changed_event, get_initial_notify )
from ietf.doc.lastcall import request_last_call
+from ietf.doc.fields import SearchableDocAliasesField
from ietf.group.models import Group, Role
from ietf.iesg.models import TelechatDate
from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, user_is_person
from ietf.ietfauth.utils import role_required
from ietf.message.models import Message
from ietf.name.models import IntendedStdLevelName, DocTagName, StreamName
-from ietf.person.fields import AutocompletedEmailField
+from ietf.person.fields import SearchableEmailField
from ietf.person.models import Person, Email
from ietf.secr.lib.template import jsonapi
from ietf.utils.mail import send_mail, send_mail_message
@@ -307,35 +308,21 @@ def collect_email_addresses(emails, doc):
return emails
class ReplacesForm(forms.Form):
- replaces = forms.CharField(max_length=512,widget=forms.HiddenInput)
+ replaces = SearchableDocAliasesField(required=False)
comment = forms.CharField(widget=forms.Textarea, required=False)
def __init__(self, *args, **kwargs):
self.doc = kwargs.pop('doc')
super(ReplacesForm, self).__init__(*args, **kwargs)
- drafts = {}
- for d in self.doc.related_that_doc("replaces"):
- drafts[d.id] = d.document.name
- self.initial['replaces'] = json.dumps(drafts)
+ self.initial['replaces'] = self.doc.related_that_doc("replaces")
def clean_replaces(self):
- data = self.cleaned_data['replaces'].strip()
- if data:
- ids = [int(x) for x in json.loads(data)]
- else:
- return []
- objects = []
- for id in ids:
- try:
- d = DocAlias.objects.get(pk=id)
- except DocAlias.DoesNotExist:
- raise forms.ValidationError("ERROR: %s not found for id %d" % DocAlias._meta.verbos_name, id)
+ for d in self.cleaned_data['replaces']:
if d.document == self.doc:
- raise forms.ValidationError("ERROR: A draft can't replace itself")
+ raise forms.ValidationError("A draft can't replace itself")
if d.document.type_id == "draft" and d.document.get_state_slug() == "rfc":
- raise forms.ValidationError("ERROR: A draft can't replace an RFC")
- objects.append(d)
- return objects
+ raise forms.ValidationError("A draft can't replace an RFC")
+ return self.cleaned_data['replaces']
def replaces(request, name):
"""Change 'replaces' set of a Document of type 'draft' , notifying parties
@@ -942,7 +929,7 @@ def edit_shepherd_writeup(request, name):
context_instance=RequestContext(request))
class ShepherdForm(forms.Form):
- shepherd = AutocompletedEmailField(required=False, only_users=True)
+ shepherd = SearchableEmailField(required=False, only_users=True)
def edit_shepherd(request, name):
"""Change the shepherd for a Document"""
@@ -968,7 +955,7 @@ def edit_shepherd(request, name):
c.desc = "Document shepherd changed to "+ (doc.shepherd.person.name if doc.shepherd else "(None)")
c.save()
- if doc.shepherd.formatted_email() not in doc.notify:
+ if doc.shepherd and doc.shepherd.formatted_email() not in doc.notify:
login = request.user.person
addrs = doc.notify
if addrs:
diff --git a/ietf/doc/views_search.py b/ietf/doc/views_search.py
index 1d0af9636..d75200d8c 100644
--- a/ietf/doc/views_search.py
+++ b/ietf/doc/views_search.py
@@ -45,7 +45,7 @@ from ietf.community.models import CommunityList
from ietf.doc.models import ( Document, DocAlias, State, RelatedDocument, DocEvent,
LastCallDocEvent, TelechatDocEvent, IESG_SUBSTATE_TAGS )
from ietf.doc.expire import expirable_draft
-from ietf.doc.fields import tokeninput_id_doc_name_json
+from ietf.doc.fields import select2_id_doc_name_json
from ietf.group.models import Group
from ietf.idindex.index import active_drafts_index_by_group
from ietf.ipr.models import IprDocAlias
@@ -629,7 +629,7 @@ def index_active_drafts(request):
return render_to_response("doc/index_active_drafts.html", { 'groups': groups }, context_instance=RequestContext(request))
-def ajax_tokeninput_search_docs(request, model_name, doc_type):
+def ajax_select2_search_docs(request, model_name, doc_type):
if model_name == "docalias":
model = DocAlias
else:
@@ -652,4 +652,4 @@ def ajax_tokeninput_search_docs(request, model_name, doc_type):
objs = qs.distinct().order_by("name")[:20]
- return HttpResponse(tokeninput_id_doc_name_json(objs), content_type='application/json')
+ return HttpResponse(select2_id_doc_name_json(objs), content_type='application/json')
diff --git a/ietf/group/edit.py b/ietf/group/edit.py
index c3b99a236..9b585c675 100644
--- a/ietf/group/edit.py
+++ b/ietf/group/edit.py
@@ -19,7 +19,7 @@ from ietf.group.models import ( Group, Role, GroupEvent, GroupHistory, GroupStat
from ietf.group.utils import save_group_in_history, can_manage_group_type
from ietf.group.utils import get_group_or_404
from ietf.ietfauth.utils import has_role
-from ietf.person.fields import AutocompletedEmailsField
+from ietf.person.fields import SearchableEmailsField
from ietf.person.models import Person, Email
from ietf.group.mails import email_iesg_secretary_re_charter
@@ -29,11 +29,11 @@ class GroupForm(forms.Form):
name = forms.CharField(max_length=255, label="Name", required=True)
acronym = forms.CharField(max_length=10, label="Acronym", required=True)
state = forms.ModelChoiceField(GroupStateName.objects.all(), label="State", required=True)
- chairs = AutocompletedEmailsField(label="Chairs", required=False, only_users=True)
- secretaries = AutocompletedEmailsField(label="Secretarias", required=False, only_users=True)
- techadv = AutocompletedEmailsField(label="Technical Advisors", required=False, only_users=True)
- delegates = AutocompletedEmailsField(label="Delegates", required=False, only_users=True, max_entries=MAX_GROUP_DELEGATES,
- help_text=mark_safe("Chairs can delegate the authority to update the state of group documents - at most %s persons at a given time." % MAX_GROUP_DELEGATES))
+ chairs = SearchableEmailsField(label="Chairs", required=False, only_users=True)
+ secretaries = SearchableEmailsField(label="Secretarias", required=False, only_users=True)
+ techadv = SearchableEmailsField(label="Technical Advisors", required=False, only_users=True)
+ delegates = SearchableEmailsField(label="Delegates", required=False, only_users=True, max_entries=MAX_GROUP_DELEGATES,
+ help_text=mark_safe("Chairs can delegate the authority to update the state of group documents - at most %s persons at a given time." % MAX_GROUP_DELEGATES))
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active").order_by('name'), label="Shepherding AD", empty_label="(None)", required=False)
parent = forms.ModelChoiceField(Group.objects.filter(state="active").order_by('name'), empty_label="(None)", required=False)
list_email = forms.CharField(max_length=64, required=False)
diff --git a/ietf/group/info.py b/ietf/group/info.py
index 54ccd7401..be445f7c5 100644
--- a/ietf/group/info.py
+++ b/ietf/group/info.py
@@ -303,7 +303,7 @@ def construct_group_menu_context(request, group, selected, group_type, others):
if group.features.has_milestones:
if group.state_id != "proposed" and (is_chair or can_manage):
- actions.append((u"Add or edit milestones", urlreverse("group_edit_milestones", kwargs=kwargs)))
+ actions.append((u"Edit milestones", urlreverse("group_edit_milestones", kwargs=kwargs)))
if group.features.has_materials and can_manage_materials(request.user, group):
actions.append((u"Upload material", urlreverse("ietf.doc.views_material.choose_material_type", kwargs=kwargs)))
diff --git a/ietf/group/milestones.py b/ietf/group/milestones.py
index 0be402508..0815fc88b 100644
--- a/ietf/group/milestones.py
+++ b/ietf/group/milestones.py
@@ -2,99 +2,72 @@
import datetime
import calendar
-import json
from django import forms
-from django.http import HttpResponse, HttpResponseForbidden, HttpResponseBadRequest, HttpResponseRedirect, Http404
+from django.http import HttpResponseForbidden, HttpResponseBadRequest, HttpResponseRedirect, Http404
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
-from ietf.doc.models import Document, DocEvent
+from ietf.doc.models import DocEvent
from ietf.doc.utils import get_chartering_type
-from ietf.doc.fields import AutocompletedDocumentsField
+from ietf.doc.fields import SearchableDocumentsField
from ietf.group.models import GroupMilestone, MilestoneGroupEvent
from ietf.group.utils import (save_milestone_in_history, can_manage_group_type, milestone_reviewer_for_group_type,
get_group_or_404)
from ietf.name.models import GroupMilestoneStateName
from ietf.group.mails import email_milestones_changed
-
-def json_doc_names(docs):
- return json.dumps([{"id": doc.pk, "name": doc.name } for doc in docs])
-
-def parse_doc_names(s):
- return Document.objects.filter(pk__in=[x.strip() for x in s.split(",") if x.strip()], type="draft")
+from ietf.utils.fields import DatepickerDateField
class MilestoneForm(forms.Form):
id = forms.IntegerField(required=True, widget=forms.HiddenInput)
- desc = forms.CharField(max_length=500, label="Milestone:", required=True)
- due_month = forms.TypedChoiceField(choices=(), required=True, coerce=int)
- due_year = forms.TypedChoiceField(choices=(), required=True, coerce=int)
+ desc = forms.CharField(max_length=500, label="Milestone", required=True)
+ due = DatepickerDateField(date_format="MM yyyy", picker_settings={"min-view-mode": "months", "autoclose": "1", "view-mode": "years" }, required=True)
+ docs = SearchableDocumentsField(label="Drafts", required=False, help_text="Any drafts that the milestone concerns.")
resolved_checkbox = forms.BooleanField(required=False, label="Resolved")
- resolved = forms.CharField(max_length=50, required=False)
+ resolved = forms.CharField(label="Resolved as", max_length=50, required=False)
delete = forms.BooleanField(required=False, initial=False)
- docs = AutocompletedDocumentsField(required=False)
-
- accept = forms.ChoiceField(choices=(("accept", "Accept"), ("reject", "Reject and delete"), ("noaction", "No action")),
+ review = forms.ChoiceField(label="Review action", help_text="Choose whether to accept or reject the proposed changes.",
+ choices=(("accept", "Accept"), ("reject", "Reject and delete"), ("noaction", "No action")),
required=False, initial="noaction", widget=forms.RadioSelect)
- def __init__(self, *args, **kwargs):
- kwargs["label_suffix"] = ""
-
+ def __init__(self, needs_review, reviewer, *args, **kwargs):
m = self.milestone = kwargs.pop("instance", None)
- self.needs_review = kwargs.pop("needs_review", False)
- can_review = not self.needs_review
+ can_review = not needs_review
if m:
- self.needs_review = m.state_id == "review"
+ needs_review = m.state_id == "review"
if not "initial" in kwargs:
kwargs["initial"] = {}
kwargs["initial"].update(dict(id=m.pk,
desc=m.desc,
- due_month=m.due.month,
- due_year=m.due.year,
+ due=m.due,
resolved_checkbox=bool(m.resolved),
resolved=m.resolved,
- docs=",".join(m.docs.values_list("pk", flat=True)),
+ docs=m.docs.all(),
delete=False,
- accept="noaction" if can_review and self.needs_review else None,
+ review="noaction" if can_review and needs_review else "",
))
kwargs["prefix"] = "m%s" % m.pk
super(MilestoneForm, self).__init__(*args, **kwargs)
- # set choices for due date
- this_year = datetime.date.today().year
+ self.fields["resolved"].widget.attrs["data-default"] = "Done"
- self.fields["due_month"].choices = [(month, datetime.date(this_year, month, 1).strftime("%B")) for month in range(1, 13)]
+ if needs_review and self.milestone and self.milestone.state_id != "review":
+ self.fields["desc"].widget.attrs["readonly"] = True
- years = [ y for y in range(this_year, this_year + 10)]
+ self.changed = False
- initial = self.initial.get("due_year")
- if initial and initial not in years:
- years.insert(0, initial)
+ if not (needs_review and can_review):
+ self.fields["review"].widget = forms.HiddenInput()
- self.fields["due_year"].choices = zip(years, map(str, years))
-
- # figure out what to prepopulate many-to-many field with
- pre = ""
- if not self.is_bound:
- pre = self.initial.get("docs", "")
- else:
- pre = self["docs"].data or ""
-
- # this is ugly, but putting it on self["docs"] is buggy with a
- # bound/unbound form in Django 1.2
- self.docs_names = parse_doc_names(pre)
- self.docs_prepopulate = json_doc_names(self.docs_names)
-
- # calculate whether we've changed
- self.changed = self.is_bound and (not self.milestone or any(unicode(self[f].data) != unicode(self.initial[f]) for f in self.fields.iterkeys()))
+ self.needs_review = needs_review
def clean_resolved(self):
r = self.cleaned_data["resolved"].strip()
@@ -134,14 +107,17 @@ def edit_milestones(request, acronym, group_type=None, milestone_set="current"):
title = "Edit charter milestones for %s %s" % (group.acronym, group.type.name)
milestones = group.groupmilestone_set.filter(state="charter")
+ reviewer = milestone_reviewer_for_group_type(group_type)
+
forms = []
milestones_dict = dict((str(m.id), m) for m in milestones)
def due_month_year_to_date(c):
- y = c["due_year"]
- m = c["due_month"]
- return datetime.date(y, m, calendar.monthrange(y, m)[1])
+ y = c["due"].year
+ m = c["due"].month
+ first_day, last_day = calendar.monthrange(y, m)
+ return datetime.date(y, m, last_day)
def set_attributes_from_form(f, m):
c = f.cleaned_data
@@ -153,10 +129,24 @@ def edit_milestones(request, acronym, group_type=None, milestone_set="current"):
m.state = GroupMilestoneStateName.objects.get(slug="active")
elif milestone_set == "charter":
m.state = GroupMilestoneStateName.objects.get(slug="charter")
+
m.desc = c["desc"]
m.due = due_month_year_to_date(c)
m.resolved = c["resolved"]
+ def milestone_changed(f, m):
+ # we assume that validation has run
+ if not m or not f.is_valid():
+ return True
+
+ c = f.cleaned_data
+ return (c["desc"] != m.desc or
+ due_month_year_to_date(c) != m.due or
+ c["resolved"] != m.resolved or
+ set(c["docs"]) != set(m.docs.all()) or
+ c.get("review") in ("accept", "reject")
+ )
+
def save_milestone_form(f):
c = f.cleaned_data
@@ -180,14 +170,14 @@ def edit_milestones(request, acronym, group_type=None, milestone_set="current"):
changes = ['Changed %s' % named_milestone]
- if m.state_id == "review" and not needs_review and c["accept"] != "noaction":
+ if m.state_id == "review" and not needs_review and c["review"] != "noaction":
if not history:
history = save_milestone_in_history(m)
- if c["accept"] == "accept":
+ if c["review"] == "accept":
m.state_id = "active"
changes.append("set state to active from review, accepting new milestone")
- elif c["accept"] == "reject":
+ elif c["review"] == "reject":
m.state_id = "deleted"
changes.append("set state to deleted from review, rejecting new milestone")
@@ -257,8 +247,6 @@ def edit_milestones(request, acronym, group_type=None, milestone_set="current"):
elif m.state_id == "review":
return 'Added %s for review, due %s' % (named_milestone, m.due.strftime("%B %Y"))
- finished_milestone_text = "Done"
-
form_errors = False
if request.method == 'POST':
@@ -269,22 +257,23 @@ def edit_milestones(request, acronym, group_type=None, milestone_set="current"):
# new milestones have non-existing ids so instance end up as None
instance = milestones_dict.get(request.POST.get(prefix + "-id", ""), None)
- f = MilestoneForm(request.POST, prefix=prefix, instance=instance,
- needs_review=needs_review)
+ f = MilestoneForm(needs_review, reviewer, request.POST, prefix=prefix, instance=instance)
forms.append(f)
form_errors = form_errors or not f.is_valid()
+ f.changed = milestone_changed(f, f.milestone)
+ if f.is_valid() and f.cleaned_data.get("review") in ("accept", "reject"):
+ f.needs_review = False
+
action = request.POST.get("action", "review")
if action == "review":
for f in forms:
- if not f.is_valid():
- continue
-
- # let's fill in the form milestone so we can output it in the template
- if not f.milestone:
- f.milestone = GroupMilestone()
- set_attributes_from_form(f, f.milestone)
+ if f.is_valid():
+ # let's fill in the form milestone so we can output it in the template
+ if not f.milestone:
+ f.milestone = GroupMilestone()
+ set_attributes_from_form(f, f.milestone)
elif action == "save" and not form_errors:
changes = []
for f in forms:
@@ -311,11 +300,11 @@ def edit_milestones(request, acronym, group_type=None, milestone_set="current"):
return HttpResponseRedirect(group.about_url())
else:
for m in milestones:
- forms.append(MilestoneForm(instance=m, needs_review=needs_review))
+ forms.append(MilestoneForm(needs_review, reviewer, instance=m))
can_reset = milestone_set == "charter" and get_chartering_type(group.charter) == "rechartering"
- empty_form = MilestoneForm(needs_review=needs_review)
+ empty_form = MilestoneForm(needs_review, reviewer)
forms.sort(key=lambda f: f.milestone.due if f.milestone else datetime.date.max)
@@ -326,9 +315,8 @@ def edit_milestones(request, acronym, group_type=None, milestone_set="current"):
form_errors=form_errors,
empty_form=empty_form,
milestone_set=milestone_set,
- finished_milestone_text=finished_milestone_text,
needs_review=needs_review,
- reviewer=milestone_reviewer_for_group_type(group_type),
+ reviewer=reviewer,
can_reset=can_reset))
@login_required
diff --git a/ietf/group/tests_info.py b/ietf/group/tests_info.py
index 83526dd39..e3dc8bf54 100644
--- a/ietf/group/tests_info.py
+++ b/ietf/group/tests_info.py
@@ -1,7 +1,6 @@
import os
import shutil
import calendar
-import json
import datetime
from pyquery import PyQuery
@@ -530,23 +529,21 @@ class MilestoneTests(TestCase):
r = self.client.post(url, { 'prefix': "m-1",
'm-1-id': "-1",
'm-1-desc': "", # no description
- 'm-1-due_month': str(due.month),
- 'm-1-due_year': str(due.year),
+ 'm-1-due': due.strftime("%B %Y"),
'm-1-resolved': "",
'm-1-docs': ",".join(docs),
'action': "save",
})
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
- self.assertTrue(len(q('form ul.errorlist')) > 0)
+ self.assertTrue(len(q('form .has-error')) > 0)
self.assertEqual(GroupMilestone.objects.count(), milestones_before)
# add
r = self.client.post(url, { 'prefix': "m-1",
'm-1-id': "-1",
'm-1-desc': "Test 3",
- 'm-1-due_month': str(due.month),
- 'm-1-due_year': str(due.year),
+ 'm-1-due': due.strftime("%B %Y"),
'm-1-resolved': "",
'm-1-docs': ",".join(docs),
'action': "save",
@@ -580,8 +577,7 @@ class MilestoneTests(TestCase):
r = self.client.post(url, { 'prefix': "m-1",
'm-1-id': -1,
'm-1-desc': "Test 3",
- 'm-1-due_month': str(due.month),
- 'm-1-due_year': str(due.year),
+ 'm-1-due': due.strftime("%B %Y"),
'm-1-resolved': "",
'm-1-docs': "",
'action': "save",
@@ -612,11 +608,10 @@ class MilestoneTests(TestCase):
r = self.client.post(url, { 'prefix': "m1",
'm1-id': m1.id,
'm1-desc': m1.desc,
- 'm1-due_month': str(m1.due.month),
- 'm1-due_year': str(m1.due.year),
+ 'm1-due': m1.due.strftime("%B %Y"),
'm1-resolved': m1.resolved,
'm1-docs': ",".join(m1.docs.values_list("name", flat=True)),
- 'm1-accept': "accept",
+ 'm1-review': "accept",
'action': "save",
})
self.assertEqual(r.status_code, 302)
@@ -639,8 +634,7 @@ class MilestoneTests(TestCase):
r = self.client.post(url, { 'prefix': "m1",
'm1-id': m1.id,
'm1-desc': m1.desc,
- 'm1-due_month': str(m1.due.month),
- 'm1-due_year': str(m1.due.year),
+ 'm1-due': m1.due.strftime("%B %Y"),
'm1-resolved': "",
'm1-docs': ",".join(m1.docs.values_list("name", flat=True)),
'm1-delete': "checked",
@@ -670,15 +664,14 @@ class MilestoneTests(TestCase):
r = self.client.post(url, { 'prefix': "m1",
'm1-id': m1.id,
'm1-desc': "", # no description
- 'm1-due_month': str(due.month),
- 'm1-due_year': str(due.year),
+ 'm1-due': due.strftime("%B %Y"),
'm1-resolved': "",
'm1-docs': ",".join(docs),
'action': "save",
})
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
- self.assertTrue(len(q('form ul.errorlist')) > 0)
+ self.assertTrue(len(q('form .has-error')) > 0)
m = GroupMilestone.objects.get(pk=m1.pk)
self.assertEqual(GroupMilestone.objects.count(), milestones_before)
self.assertEqual(m.due, m1.due)
@@ -688,8 +681,7 @@ class MilestoneTests(TestCase):
r = self.client.post(url, { 'prefix': "m1",
'm1-id': m1.id,
'm1-desc': "Test 2 - changed",
- 'm1-due_month': str(due.month),
- 'm1-due_year': str(due.year),
+ 'm1-due': due.strftime("%B %Y"),
'm1-resolved': "Done",
'm1-resolved_checkbox': "checked",
'm1-docs': ",".join(docs),
diff --git a/ietf/group/views_stream.py b/ietf/group/views_stream.py
index 6fe223703..6ec34702c 100644
--- a/ietf/group/views_stream.py
+++ b/ietf/group/views_stream.py
@@ -10,7 +10,7 @@ from ietf.group.models import Group, GroupEvent, Role
from ietf.group.utils import save_group_in_history
from ietf.ietfauth.utils import has_role
from ietf.name.models import StreamName
-from ietf.person.fields import AutocompletedEmailsField
+from ietf.person.fields import SearchableEmailsField
from ietf.person.models import Email
import debug # pyflakes:ignore
@@ -33,7 +33,7 @@ def stream_documents(request, acronym):
return render_to_response('group/stream_documents.html', {'stream':stream, 'docs':docs, 'meta':meta, 'editable':editable }, context_instance=RequestContext(request))
class StreamEditForm(forms.Form):
- delegates = AutocompletedEmailsField(required=False, only_users=True)
+ delegates = SearchableEmailsField(required=False, only_users=True)
def stream_edit(request, acronym):
group = get_object_or_404(Group, acronym=acronym)
diff --git a/ietf/nomcom/forms.py b/ietf/nomcom/forms.py
index 7fba3b598..0aee2d491 100644
--- a/ietf/nomcom/forms.py
+++ b/ietf/nomcom/forms.py
@@ -17,7 +17,7 @@ from ietf.nomcom.utils import (NOMINATION_RECEIPT_TEMPLATE, FEEDBACK_RECEIPT_TEM
get_user_email, validate_private_key, validate_public_key,
get_or_create_nominee, create_feedback_email)
from ietf.person.models import Email
-from ietf.person.fields import AutocompletedEmailField
+from ietf.person.fields import SearchableEmailField
from ietf.utils.fields import MultiEmailField
from ietf.utils.mail import send_mail
@@ -657,7 +657,7 @@ class PositionForm(BaseNomcomForm, forms.ModelForm):
fieldsets = [('Position', ('name', 'description',
'is_open', 'incumbent'))]
- incumbent = AutocompletedEmailField(required=False)
+ incumbent = SearchableEmailField(required=False)
class Meta:
model = Position
diff --git a/ietf/person/fields.py b/ietf/person/fields.py
index 25ed5b889..031bb80cf 100644
--- a/ietf/person/fields.py
+++ b/ietf/person/fields.py
@@ -8,7 +8,7 @@ import debug # pyflakes:ignore
from ietf.person.models import Email, Person
-def tokeninput_id_name_json(objs):
+def select2_id_name_json(objs):
def format_email(e):
return escape(u"%s <%s>" % (e.person.name, e.address))
def format_person(p):
@@ -16,19 +16,19 @@ def tokeninput_id_name_json(objs):
formatter = format_email if objs and isinstance(objs[0], Email) else format_person
- return json.dumps([{ "id": o.pk, "name": formatter(o) } for o in objs])
+ return json.dumps([{ "id": o.pk, "text": formatter(o) } for o in objs])
-class AutocompletedPersonsField(forms.CharField):
- """Tokenizing autocompleted multi-select field for choosing
- persons/emails or just persons using jquery.tokeninput.js.
+class SearchablePersonsField(forms.CharField):
+ """Server-based multi-select field for choosing
+ persons/emails or just persons using select2.js.
The field operates on either Email or Person models. In the case
- of Email models, the person name is shown next to the email address.
+ of Email models, the person name is shown next to the email
+ address.
The field uses a comma-separated list of primary keys in a
- CharField element as its API, the tokeninput Javascript adds some
- selection magic on top of this so we have to pass it a JSON
- representation of ids and user-understandable labels."""
+ CharField element as its API with some extra attributes used by
+ the Javascript part."""
def __init__(self,
max_entries=None, # max number of selected objs
@@ -41,38 +41,38 @@ class AutocompletedPersonsField(forms.CharField):
self.only_users = only_users
self.model = model
- super(AutocompletedPersonsField, self).__init__(*args, **kwargs)
+ super(SearchablePersonsField, self).__init__(*args, **kwargs)
- self.widget.attrs["class"] = "tokenized-field"
- self.widget.attrs["data-hint-text"] = hint_text
+ self.widget.attrs["class"] = "select2-field"
+ self.widget.attrs["data-placeholder"] = hint_text
if self.max_entries != None:
self.widget.attrs["data-max-entries"] = self.max_entries
- def parse_tokenized_value(self, value):
+ def parse_select2_value(self, value):
return [x.strip() for x in value.split(",") if x.strip()]
def prepare_value(self, value):
if not value:
value = ""
if isinstance(value, basestring):
- pks = self.parse_tokenized_value(value)
+ pks = self.parse_select2_value(value)
value = self.model.objects.filter(pk__in=pks).select_related("person")
if isinstance(value, self.model):
value = [value]
- self.widget.attrs["data-pre"] = tokeninput_id_name_json(value)
+ self.widget.attrs["data-pre"] = select2_id_name_json(value)
# doing this in the constructor is difficult because the URL
# patterns may not have been fully constructed there yet
- self.widget.attrs["data-ajax-url"] = urlreverse("ajax_tokeninput_search", kwargs={ "model_name": self.model.__name__.lower() })
+ self.widget.attrs["data-ajax-url"] = urlreverse("ajax_select2_search_person_email", kwargs={ "model_name": self.model.__name__.lower() })
if self.only_users:
self.widget.attrs["data-ajax-url"] += "?user=1" # require a Datatracker account
- return ",".join(e.address for e in value)
+ return u",".join(e.address for e in value)
def clean(self, value):
- value = super(AutocompletedPersonsField, self).clean(value)
- pks = self.parse_tokenized_value(value)
+ value = super(SearchablePersonsField, self).clean(value)
+ pks = self.parse_select2_value(value)
objs = self.model.objects.filter(pk__in=pks)
if self.model == Email:
@@ -92,32 +92,32 @@ class AutocompletedPersonsField(forms.CharField):
return objs
-class AutocompletedPersonField(AutocompletedPersonsField):
- """Version of AutocompletedPersonsField specialized to a single object."""
+class SearchablePersonField(SearchablePersonsField):
+ """Version of SearchablePersonsField specialized to a single object."""
def __init__(self, *args, **kwargs):
kwargs["max_entries"] = 1
- super(AutocompletedPersonField, self).__init__(*args, **kwargs)
+ super(SearchablePersonField, self).__init__(*args, **kwargs)
def clean(self, value):
- return super(AutocompletedPersonField, self).clean(value).first()
+ return super(SearchablePersonField, self).clean(value).first()
-class AutocompletedEmailsField(AutocompletedPersonsField):
- """Version of AutocompletedPersonsField with the defaults right for Emails."""
+class SearchableEmailsField(SearchablePersonsField):
+ """Version of SearchablePersonsField with the defaults right for Emails."""
def __init__(self, model=Email, hint_text="Type in name or email to search for person and email address.",
*args, **kwargs):
- super(AutocompletedEmailsField, self).__init__(model=model, hint_text=hint_text, *args, **kwargs)
+ super(SearchableEmailsField, self).__init__(model=model, hint_text=hint_text, *args, **kwargs)
-class AutocompletedEmailField(AutocompletedEmailsField):
- """Version of AutocompletedEmailsField specialized to a single object."""
+class SearchableEmailField(SearchableEmailsField):
+ """Version of SearchableEmailsField specialized to a single object."""
def __init__(self, *args, **kwargs):
kwargs["max_entries"] = 1
- super(AutocompletedEmailField, self).__init__(*args, **kwargs)
+ super(SearchableEmailField, self).__init__(*args, **kwargs)
def clean(self, value):
- return super(AutocompletedEmailField, self).clean(value).first()
+ return super(SearchableEmailField, self).clean(value).first()
diff --git a/ietf/person/tests.py b/ietf/person/tests.py
index d044d45f5..80c239d98 100644
--- a/ietf/person/tests.py
+++ b/ietf/person/tests.py
@@ -11,7 +11,7 @@ class PersonTests(TestCase):
draft = make_test_data()
person = draft.ad
- r = self.client.get(urlreverse("ietf.person.views.ajax_tokeninput_search", kwargs={ "model_name": "email"}), dict(q=person.name))
+ r = self.client.get(urlreverse("ietf.person.views.ajax_select2_search", kwargs={ "model_name": "email"}), dict(q=person.name))
self.assertEqual(r.status_code, 200)
data = json.loads(r.content)
self.assertEqual(data[0]["id"], person.email_address())
diff --git a/ietf/person/urls.py b/ietf/person/urls.py
index 8392fb51d..ce76d9f69 100644
--- a/ietf/person/urls.py
+++ b/ietf/person/urls.py
@@ -2,6 +2,6 @@ from django.conf.urls import patterns
from ietf.person import ajax
urlpatterns = patterns('',
- (r'^search/(?P(person|email))/$', "ietf.person.views.ajax_tokeninput_search", None, 'ajax_tokeninput_search'),
+ (r'^search/(?P(person|email))/$', "ietf.person.views.ajax_select2_search", None, 'ajax_select2_search_person_email'),
(r'^(?P[a-z0-9]+).json$', ajax.person_json),
)
diff --git a/ietf/person/views.py b/ietf/person/views.py
index 7e61e727a..8d3627c75 100644
--- a/ietf/person/views.py
+++ b/ietf/person/views.py
@@ -2,9 +2,9 @@ from django.http import HttpResponse
from django.db.models import Q
from ietf.person.models import Email, Person
-from ietf.person.fields import tokeninput_id_name_json
+from ietf.person.fields import select2_id_name_json
-def ajax_tokeninput_search(request, model_name):
+def ajax_select2_search(request, model_name):
if model_name == "email":
model = Email
else:
@@ -39,6 +39,11 @@ def ajax_tokeninput_search(request, model_name):
if only_users:
objs = objs.exclude(user=None)
- objs = objs.distinct()[:10]
+ try:
+ page = int(request.GET.get("p", 1)) - 1
+ except ValueError:
+ page = 0
- return HttpResponse(tokeninput_id_name_json(objs), content_type='application/json')
+ objs = objs.distinct()[page:page + 10]
+
+ return HttpResponse(select2_id_name_json(objs), content_type='application/json')
diff --git a/ietf/secr/drafts/forms.py b/ietf/secr/drafts/forms.py
index 58d5a6ed6..c841668e3 100644
--- a/ietf/secr/drafts/forms.py
+++ b/ietf/secr/drafts/forms.py
@@ -8,7 +8,7 @@ from ietf.doc.models import Document, DocAlias, State
from ietf.name.models import IntendedStdLevelName, DocRelationshipName
from ietf.group.models import Group
from ietf.person.models import Person, Email
-from ietf.person.fields import AutocompletedEmailField
+from ietf.person.fields import SearchableEmailField
from ietf.secr.groups.forms import get_person
@@ -132,7 +132,7 @@ class EditModelForm(forms.ModelForm):
iesg_state = forms.ModelChoiceField(queryset=State.objects.filter(type='draft-iesg'),required=False)
group = GroupModelChoiceField(required=True)
review_by_rfc_editor = forms.BooleanField(required=False)
- shepherd = AutocompletedEmailField(required=False, only_users=True)
+ shepherd = SearchableEmailField(required=False, only_users=True)
class Meta:
model = Document
diff --git a/ietf/secr/sreq/forms.py b/ietf/secr/sreq/forms.py
index 20cf544c3..02c6b9859 100644
--- a/ietf/secr/sreq/forms.py
+++ b/ietf/secr/sreq/forms.py
@@ -2,7 +2,7 @@ from django import forms
from ietf.group.models import Group
from ietf.meeting.models import ResourceAssociation
-from ietf.person.fields import AutocompletedPersonsField
+from ietf.person.fields import SearchablePersonsField
# -------------------------------------------------
@@ -67,7 +67,7 @@ class SessionForm(forms.Form):
wg_selector3 = forms.ChoiceField(choices=WG_CHOICES,required=False)
third_session = forms.BooleanField(required=False)
resources = forms.MultipleChoiceField(choices=[(x.pk,x.desc) for x in ResourceAssociation.objects.all()], widget=forms.CheckboxSelectMultiple,required=False)
- bethere = AutocompletedPersonsField(label="Must be present", required=False)
+ bethere = SearchablePersonsField(label="Must be present", required=False)
def __init__(self, *args, **kwargs):
super(SessionForm, self).__init__(*args, **kwargs)
diff --git a/ietf/secr/templates/drafts/edit.html b/ietf/secr/templates/drafts/edit.html
index 1c29810f0..31d29d6e1 100644
--- a/ietf/secr/templates/drafts/edit.html
+++ b/ietf/secr/templates/drafts/edit.html
@@ -7,9 +7,58 @@
-
-
-
+
+
+
+
+
{% endblock %}
{% block breadcrumbs %}{{ block.super }}
diff --git a/ietf/secr/templates/sreq/edit.html b/ietf/secr/templates/sreq/edit.html
index 1c80339fd..372e4f368 100755
--- a/ietf/secr/templates/sreq/edit.html
+++ b/ietf/secr/templates/sreq/edit.html
@@ -5,9 +5,58 @@
{% block extrahead %}{{ block.super }}
-
-
-
+
+
+
+
+
{% endblock %}
{% block breadcrumbs %}{{ block.super }}
diff --git a/ietf/secr/templates/sreq/new.html b/ietf/secr/templates/sreq/new.html
index c7af96eb0..450fa8f27 100755
--- a/ietf/secr/templates/sreq/new.html
+++ b/ietf/secr/templates/sreq/new.html
@@ -5,9 +5,58 @@
{% block extrahead %}{{ block.super }}
-
-
-
+
+
+
+
+
{% endblock %}
{% block breadcrumbs %}{{ block.super }}
diff --git a/ietf/templates/doc/change_shepherd.html b/ietf/templates/doc/change_shepherd.html
index 1f8b856b6..67b81b10b 100644
--- a/ietf/templates/doc/change_shepherd.html
+++ b/ietf/templates/doc/change_shepherd.html
@@ -7,8 +7,8 @@ Change document shepherd for {{ doc.name }}-{{ doc.rev }}
{% endblock %}
{% block pagehead %}
-
-
+
+
{% endblock %}
{% block content %}
@@ -19,7 +19,7 @@ Change document shepherd for {{ doc.name }}-{{ doc.rev }}
{% bootstrap_messages %}
-
-
{% endblock %}
{% block js %}
-
-
+
{% endblock %}
diff --git a/ietf/templates/group/edit_milestones.html b/ietf/templates/group/edit_milestones.html
index 80397bdaf..769f895ab 100644
--- a/ietf/templates/group/edit_milestones.html
+++ b/ietf/templates/group/edit_milestones.html
@@ -1,111 +1,99 @@
-{% extends "base.html" %}
+{% extends "ietf.html" %}
+
+{% load bootstrap3 %}
+
+{% block pagehead %}
+
+
+
+{% endblock %}
{% block title %}{{ title }}{% endblock %}
-{% block morecss %}
-tr.milestone td { padding: 0.2em 0; cursor: pointer; vertical-align: top; }
-tr.milestone:hover { background-color: #e8f0fa; }
-td.due { width: 5em; }
-.milestone.changed { font-weight: bold; }
-.milestone .note { font-style: italic; display: inline-block; margin-left: 0.5em; color: #2647a0; }
-.milestone .doc { display: block; padding-left: 1em; }
-.edit-milestone { display: none; }
-.milestone.delete, .edit-milestone.delete, .edit-milestone.delete input { color: #aaa !important; }
-.edit-milestone table { margin: 1em 0; }
-.edit-milestone table td { padding: 0.1em; }
-.edit-milestone .desc input { width: 50em; }
-.edit-milestone .due input { width: 6em; }
-.edit-milestone input[type=checkbox] { vertical-align: middle; margin: 0 0.2em 0 0.8em;}
-.edit-milestone .resolved label { vertical-align: middle; }
-.edit-milestone .delete label { vertical-align: middle; }
-.edit-milestone .accept ul { display: inline-block; margin: 0; padding: 0; }
-.edit-milestone .accept ul li { list-style: none; display: inline-block; margin: 0; padding: 0; padding-left: 0.4em; }
-.edit-milestone .accept ul li label { vertical-align: middle; }
-.edit-milestone .accept ul li input { margin: 0; padding: 0; vertical-align: middle; }
-.edit-milestone .docs td { vertical-align: top; }
-
-ul.errorlist { border-width: 0px; padding: 0px; margin: 0px; display: inline-block; }
-ul.errorlist li { color: #a00; margin: 0px; padding: 0px; list-style: none; }
-p.help { font-style: italic; }
-p.error { color: #a00; font-size: larger; }
-tr.milestone.add { font-style: italic; }
-{% endblock %}
-
-{% block pagehead %}
-
-{% endblock %}
+{% bootstrap_messages %}
{% block content %}
-{% load ietf_filters %}
{{ title }}
This page depends on Javascript being enabled to work properly.
Links:
- {{ group.acronym }} {{ group.type.name }}
+ {{ group.acronym }} {{ group.type.name }}
{% if group.charter %}
- {{ group.charter.canonical_name }}
{% endif %}
-{% if forms %}Click a milestone to edit it.{% endif %}
+
+ {% if forms %}Click a milestone to edit it.{% endif %}
-{% if needs_review %}
-Note that as {{ group.type.name }} Chair you cannot edit descriptions of existing
-milestones and milestones you add are subject to review by the {{ reviewer }}.
-{% endif %}
+ {% if needs_review %}
+ Note that as {{ group.type.name }} Chair you cannot edit descriptions of existing
+ milestones and milestones you add are subject to review by the {{ reviewer }}.
+ {% endif %}
{% if can_reset %}
-You can reset
-this list to the milestones currently in use for the {{ group.acronym }} {{ group.type.name }}.
+ You can reset
+ this list to the milestones currently in use for the {{ group.acronym }} {{ group.type.name }}.
{% endif %}
{% if form_errors %}
-There were errors, see below.
+ There were errors, see below.
{% endif %}
-
{% endblock %}
-{% block content_end %}
-
-
-
-
-
+{% block js %}
+
+
+
{% endblock %}
diff --git a/ietf/templates/group/milestone_form.html b/ietf/templates/group/milestone_form.html
index 0a1a271fc..666c6d6a0 100644
--- a/ietf/templates/group/milestone_form.html
+++ b/ietf/templates/group/milestone_form.html
@@ -1,42 +1,9 @@
{# assumes group, form, needs_review, reviewer are in the context #}
-
-{{ form.id }}
-
-
- {{ form.desc.label_tag }}
-
-
- {% if needs_review and form.milestone and form.milestone.state_id != "review" %}
- {{ form.milestone.desc }} {{ form.desc.as_hidden }}
- {% else %}
- {{ form.desc }}
- {% endif %}
-
- {{ form.delete }} {{ form.delete.label_tag }}
-
-
- {% if form.desc.errors %}{{ form.desc.errors }} {% endif %}
-
- Due date:
- {{ form.due_month }} {{ form.due_year }} {{ form.due_month.errors }} {{ form.due_year.errors }}
- {{ form.resolved_checkbox }} {{ form.resolved_checkbox.label_tag }} {{ form.resolved }}
- {{ form.resolved.errors }}
-
-
-
- Drafts:
- {{ form.docs }}
- {{ form.docs.errors }}
-
-
- {% if form.needs_review %}
-
- Review:
-
- This milestone is not active yet, awaiting
- {{ reviewer }} acceptance{% if needs_review %}.{% else %}: {{ form.accept }}{% endif %}
-
-
- {% endif %}
-
+{% load bootstrap3 %}
+
+
+
+
+ {% bootstrap_form form layout='horizontal' %}
+
diff --git a/ietf/templates/group/stream_edit.html b/ietf/templates/group/stream_edit.html
index 275810475..0d9e00af8 100644
--- a/ietf/templates/group/stream_edit.html
+++ b/ietf/templates/group/stream_edit.html
@@ -6,8 +6,8 @@
{% block title %}Manage {{ group.name }} RFC stream{% endblock %}
{% block pagehead %}
-
-
+
+
{% endblock %}
{% block content %}
@@ -29,12 +29,12 @@
datatracker account. New accounts can be created here .
-
+
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
-
+ Save
Back
{% endbuttons %}
@@ -42,6 +42,5 @@
{% endblock %}
{% block js %}
-
-
+
{% endblock %}
diff --git a/ietf/templates/nomcom/edit_position.html b/ietf/templates/nomcom/edit_position.html
index 72421c573..d536a39f6 100644
--- a/ietf/templates/nomcom/edit_position.html
+++ b/ietf/templates/nomcom/edit_position.html
@@ -1,8 +1,8 @@
{% extends "nomcom/nomcom_private_base.html" %}
{% block pagehead %}
-
-
+
+
{% endblock %}
{% load bootstrap3 %}
@@ -27,6 +27,5 @@
{% endblock %}
{% block content_end %}
-
-
+
{% endblock %}
diff --git a/static/facelift/css/ietf.css b/static/facelift/css/ietf.css
index be24540b3..6c0f4751a 100644
--- a/static/facelift/css/ietf.css
+++ b/static/facelift/css/ietf.css
@@ -206,3 +206,17 @@ pre { line-height: 1.214; }
.navbar-dev .navbar-link:hover {
color: #ecdbff;
}
+
+/* milestone editing */
+#milestones-form .milestone {
+ cursor: pointer;
+}
+#milestones-form .milestone:hover {
+ background-color: #f5f5f5;
+}
+#milestones-form .edit-milestone {
+ display: none;
+}
+#milestones-form .milestone.delete, #milestones-form .edit-milestone.delete, #milestones-form .edit-milestone.delete input {
+ color: #aaa !important;
+}
diff --git a/static/facelift/css/lib/select2-bootstrap.css b/static/facelift/css/lib/select2-bootstrap.css
new file mode 100644
index 000000000..90a1063a2
--- /dev/null
+++ b/static/facelift/css/lib/select2-bootstrap.css
@@ -0,0 +1,497 @@
+/**
+ * Select2 Bootstrap 3 CSS v1.4.1
+ * Tested with Bootstrap v3.2.0 and Select2 v3.3.2, v3.4.1-v3.4.5, v3.5.1, master
+ * in latest Chrome, Safari, Firefox, Opera (Mac) and IE8-IE11
+ * MIT License
+ */
+/**
+ * Reset Bootstrap 3 .form-control styles which - if applied to the
+ * original -element the Select2-plugin may be run against -
+ * are copied to the .select2-container.
+ *
+ * 1. Overwrite .select2-container's original display:inline-block
+ * with Bootstrap 3's default for .form-control, display:block;
+ * courtesy of @juristr (@see https://github.com/fk/select2-bootstrap-css/pull/1)
+ */
+.select2-container.form-control {
+ background: transparent;
+ border: none;
+ display: block;
+ /* 1 */
+ margin: 0;
+ padding: 0;
+}
+
+/**
+ * Adjust Select2 inputs to fit Bootstrap 3 default .form-control appearance.
+ */
+.select2-container .select2-choices .select2-search-field input,
+.select2-container .select2-choice,
+.select2-container .select2-choices {
+ background: none;
+ padding: 0;
+ border-color: #cccccc;
+ border-radius: 4px;
+ color: #555555;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ background-color: white;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+
+.select2-search input {
+ border-color: #cccccc;
+ border-radius: 4px;
+ color: #555555;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ background-color: white;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+
+.select2-container .select2-choices .select2-search-field input {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+/**
+ * Adjust Select2 input heights to match the Bootstrap default.
+ */
+.select2-container .select2-choice {
+ height: 34px;
+ line-height: 1.42857;
+}
+
+/**
+ * Address Multi Select2's height which - depending on how many elements have been selected -
+ * may grown higher than their initial size.
+ */
+.select2-container.select2-container-multi.form-control {
+ height: auto;
+}
+
+/**
+ * Address Bootstrap 3 control sizing classes
+ * @see http://getbootstrap.com/css/#forms-control-sizes
+ */
+.select2-container.input-sm .select2-choice,
+.input-group-sm .select2-container .select2-choice {
+ height: 30px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+
+.select2-container.input-lg .select2-choice,
+.input-group-lg .select2-container .select2-choice {
+ height: 46px;
+ line-height: 1.33;
+ border-radius: 6px;
+}
+
+.select2-container-multi .select2-choices .select2-search-field input {
+ height: 32px;
+}
+
+.select2-container-multi.input-sm .select2-choices .select2-search-field input,
+.input-group-sm .select2-container-multi .select2-choices .select2-search-field input {
+ height: 28px;
+}
+
+.select2-container-multi.input-lg .select2-choices .select2-search-field input,
+.input-group-lg .select2-container-multi .select2-choices .select2-search-field input {
+ height: 44px;
+}
+
+/**
+ * Adjust height and line-height for .select2-search-field amd multi-select Select2 widgets.
+ *
+ * 1. Class repetition to address missing .select2-chosen in Select2 < 3.3.2.
+ */
+.select2-container-multi .select2-choices .select2-search-field input {
+ margin: 0;
+}
+
+.select2-chosen,
+.select2-choice > span:first-child,
+.select2-container .select2-choices .select2-search-field input {
+ padding: 6px 12px;
+}
+
+.input-sm .select2-chosen,
+.input-group-sm .select2-chosen,
+.input-sm .select2-choice > span:first-child,
+.input-group-sm .select2-choice > span:first-child,
+.input-sm .select2-choices .select2-search-field input,
+.input-group-sm .select2-choices .select2-search-field input {
+ padding: 5px 10px;
+}
+
+.input-lg .select2-chosen,
+.input-group-lg .select2-chosen,
+.input-lg .select2-choice > span:first-child,
+.input-group-lg .select2-choice > span:first-child,
+.input-lg .select2-choices .select2-search-field input,
+.input-group-lg .select2-choices .select2-search-field input {
+ padding: 10px 16px;
+}
+
+.select2-container-multi .select2-choices .select2-search-choice {
+ margin-top: 5px;
+ margin-bottom: 3px;
+}
+
+.select2-container-multi.input-sm .select2-choices .select2-search-choice,
+.input-group-sm .select2-container-multi .select2-choices .select2-search-choice {
+ margin-top: 3px;
+ margin-bottom: 2px;
+}
+
+.select2-container-multi.input-lg .select2-choices .select2-search-choice,
+.input-group-lg .select2-container-multi .select2-choices .select2-search-choice {
+ line-height: 24px;
+}
+
+/**
+ * Adjust the single Select2's dropdown arrow button appearance.
+ *
+ * 1. For Select2 v.3.3.2.
+ */
+.select2-container .select2-choice .select2-arrow,
+.select2-container .select2-choice div {
+ border-left: 1px solid #cccccc;
+ background: none;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+
+.select2-dropdown-open .select2-choice .select2-arrow,
+.select2-dropdown-open .select2-choice div {
+ border-left-color: transparent;
+ background: none;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+
+/**
+ * Adjust the dropdown arrow button icon position for the single-select Select2 elements
+ * to make it line up vertically now that we increased the height of .select2-container.
+ *
+ * 1. Class repetition to address missing .select2-chosen in Select2 v.3.3.2.
+ */
+.select2-container .select2-choice .select2-arrow b,
+.select2-container .select2-choice div b {
+ background-position: 0 3px;
+}
+
+.select2-dropdown-open .select2-choice .select2-arrow b,
+.select2-dropdown-open .select2-choice div b {
+ background-position: -18px 3px;
+}
+
+.select2-container.input-sm .select2-choice .select2-arrow b,
+.input-group-sm .select2-container .select2-choice .select2-arrow b,
+.select2-container.input-sm .select2-choice div b,
+.input-group-sm .select2-container .select2-choice div b {
+ background-position: 0 1px;
+}
+
+.select2-dropdown-open.input-sm .select2-choice .select2-arrow b,
+.input-group-sm .select2-dropdown-open .select2-choice .select2-arrow b,
+.select2-dropdown-open.input-sm .select2-choice div b,
+.input-group-sm .select2-dropdown-open .select2-choice div b {
+ background-position: -18px 1px;
+}
+
+.select2-container.input-lg .select2-choice .select2-arrow b,
+.input-group-lg .select2-container .select2-choice .select2-arrow b,
+.select2-container.input-lg .select2-choice div b,
+.input-group-lg .select2-container .select2-choice div b {
+ background-position: 0 9px;
+}
+
+.select2-dropdown-open.input-lg .select2-choice .select2-arrow b,
+.input-group-lg .select2-dropdown-open .select2-choice .select2-arrow b,
+.select2-dropdown-open.input-lg .select2-choice div b,
+.input-group-lg .select2-dropdown-open .select2-choice div b {
+ background-position: -18px 9px;
+}
+
+/**
+ * Address Bootstrap's validation states and change Select2's border colors and focus states.
+ * Apply .has-warning, .has-danger or .has-succes to #select2-drop to match Bootstraps' colors.
+ */
+.has-warning .select2-choice,
+.has-warning .select2-choices {
+ border-color: #8a6d3b;
+}
+.has-warning .select2-container-active .select2-choice,
+.has-warning .select2-container-multi.select2-container-active .select2-choices {
+ 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-warning.select2-drop-active {
+ border-color: #66512c;
+}
+.has-warning.select2-drop-active.select2-drop.select2-drop-above {
+ border-top-color: #66512c;
+}
+
+.has-error .select2-choice,
+.has-error .select2-choices {
+ border-color: #a94442;
+}
+.has-error .select2-container-active .select2-choice,
+.has-error .select2-container-multi.select2-container-active .select2-choices {
+ 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-error.select2-drop-active {
+ border-color: #843534;
+}
+.has-error.select2-drop-active.select2-drop.select2-drop-above {
+ border-top-color: #843534;
+}
+
+.has-success .select2-choice,
+.has-success .select2-choices {
+ border-color: #3c763d;
+}
+.has-success .select2-container-active .select2-choice,
+.has-success .select2-container-multi.select2-container-active .select2-choices {
+ 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;
+}
+.has-success.select2-drop-active {
+ border-color: #2b542c;
+}
+.has-success.select2-drop-active.select2-drop.select2-drop-above {
+ border-top-color: #2b542c;
+}
+
+/**
+ * Make Select2's active-styles - applied to .select2-container when the widget receives focus -
+ * fit Bootstrap 3's .form-element:focus appearance.
+ */
+.select2-container-active .select2-choice,
+.select2-container-multi.select2-container-active .select2-choices {
+ border-color: #66afe9;
+ outline: none;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+ -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
+ -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
+ transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
+}
+
+.select2-drop-active {
+ border-color: #66afe9;
+}
+
+.select2-drop-auto-width,
+.select2-drop.select2-drop-above.select2-drop-active {
+ border-top-color: #66afe9;
+}
+
+/**
+ * Select2 widgets in Bootstrap Input Groups
+ *
+ * When Select2 widgets are combined with other elements using Bootstrap 3's
+ * "Input Group" component, we don't want specific edges of the Select2 container
+ * to have a border-radius.
+ *
+ * In Bootstrap 2, input groups required a markup where these style adjustments
+ * could be bound to a CSS-class identifying if the additional elements are appended,
+ * prepended or both.
+ *
+ * Bootstrap 3 doesn't rely on these classes anymore, so we have to use our own.
+ * Use .select2-bootstrap-prepend and .select2-bootstrap-append on a Bootstrap 3 .input-group
+ * to let the contained Select2 widget know which edges should not be rounded as they are
+ * directly followed by another element.
+ *
+ * @see http://getbootstrap.com/components/#input-groups
+ */
+.input-group.select2-bootstrap-prepend [class^="select2-choice"] {
+ border-bottom-left-radius: 0 !important;
+ border-top-left-radius: 0 !important;
+}
+
+.input-group.select2-bootstrap-append [class^="select2-choice"] {
+ border-bottom-right-radius: 0 !important;
+ border-top-right-radius: 0 !important;
+}
+
+.select2-dropdown-open [class^="select2-choice"] {
+ border-bottom-right-radius: 0 !important;
+ border-bottom-left-radius: 0 !important;
+}
+
+.select2-dropdown-open.select2-drop-above [class^="select2-choice"] {
+ border-top-right-radius: 0 !important;
+ border-top-left-radius: 0 !important;
+ border-bottom-right-radius: 4px !important;
+ border-bottom-left-radius: 4px !important;
+}
+.input-group.select2-bootstrap-prepend .select2-dropdown-open.select2-drop-above [class^="select2-choice"] {
+ border-bottom-left-radius: 0 !important;
+ border-top-left-radius: 0 !important;
+}
+.input-group.select2-bootstrap-append .select2-dropdown-open.select2-drop-above [class^="select2-choice"] {
+ border-bottom-right-radius: 0 !important;
+ border-top-right-radius: 0 !important;
+}
+.input-group.input-group-sm.select2-bootstrap-prepend .select2-dropdown-open.select2-drop-above [class^="select2-choice"] {
+ border-bottom-right-radius: 3px !important;
+}
+.input-group.input-group-lg.select2-bootstrap-prepend .select2-dropdown-open.select2-drop-above [class^="select2-choice"] {
+ border-bottom-right-radius: 6px !important;
+}
+.input-group.input-group-sm.select2-bootstrap-append .select2-dropdown-open.select2-drop-above [class^="select2-choice"] {
+ border-bottom-left-radius: 3px !important;
+}
+.input-group.input-group-lg.select2-bootstrap-append .select2-dropdown-open.select2-drop-above [class^="select2-choice"] {
+ border-bottom-left-radius: 6px !important;
+}
+
+/**
+ * Adjust Select2's choices hover and selected styles to match Bootstrap 3's default dropdown styles.
+ */
+.select2-results .select2-highlighted {
+ color: white;
+ background-color: #428bca;
+}
+
+/**
+ * Adjust alignment of Bootstrap 3 buttons in Bootstrap 3 Input Groups to address
+ * Multi Select2's height which - depending on how many elements have been selected -
+ * may grown higher than their initial size.
+ */
+.select2-bootstrap-append .select2-container-multiple,
+.select2-bootstrap-append .input-group-btn,
+.select2-bootstrap-append .input-group-btn .btn,
+.select2-bootstrap-prepend .select2-container-multiple,
+.select2-bootstrap-prepend .input-group-btn,
+.select2-bootstrap-prepend .input-group-btn .btn {
+ vertical-align: top;
+}
+
+/**
+ * Make Multi Select2's choices match Bootstrap 3's default button styles.
+ */
+.select2-container-multi .select2-choices .select2-search-choice {
+ color: #555555;
+ background: white;
+ border-color: #cccccc;
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+.select2-container-multi .select2-choices .select2-search-choice-focus {
+ background: #ebebeb;
+ border-color: #adadad;
+ color: #333333;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+/**
+ * Address Multi Select2's choice close-button vertical alignment.
+ */
+.select2-search-choice-close {
+ margin-top: -7px;
+ top: 50%;
+}
+
+/**
+ * Adjust the single Select2's clear button position (used to reset the select box
+ * back to the placeholder value and visible once a selection is made
+ * activated by Select2's "allowClear" option).
+ */
+.select2-container .select2-choice abbr {
+ top: 50%;
+}
+
+/**
+ * Adjust "no results" and "selection limit" messages to make use
+ * of Bootstrap 3's default "Alert" style.
+ *
+ * @see http://getbootstrap.com/components/#alerts-default
+ */
+.select2-results .select2-no-results,
+.select2-results .select2-searching,
+.select2-results .select2-selection-limit {
+ background-color: #fcf8e3;
+ color: #8a6d3b;
+}
+
+/**
+ * Address disabled Select2 styles.
+ *
+ * 1. For Select2 v.3.3.2.
+ * 2. Revert border-left:0 inherited from Select2's CSS to prevent the arrow
+ * from jumping when switching from disabled to enabled state and vice versa.
+ */
+.select2-container.select2-container-disabled .select2-choice,
+.select2-container.select2-container-disabled .select2-choices {
+ cursor: not-allowed;
+ background-color: #eeeeee;
+ border-color: #cccccc;
+}
+.select2-container.select2-container-disabled .select2-choice .select2-arrow,
+.select2-container.select2-container-disabled .select2-choice div,
+.select2-container.select2-container-disabled .select2-choices .select2-arrow,
+.select2-container.select2-container-disabled .select2-choices div {
+ background-color: transparent;
+ border-left: 1px solid transparent;
+ /* 2 */
+}
+
+/**
+ * Address Select2's loading indicator position - which should not stick
+ * to the right edge of Select2's search input.
+ *
+ * 1. in .select2-search input
+ * 2. in Multi Select2's .select2-search-field input
+ * 3. in the status-message of infinite-scroll with remote data (@see http://ivaynberg.github.io/select2/#infinite)
+ *
+ * These styles alter Select2's default background-position of 100%
+ * and supply the new background-position syntax to browsers which support it:
+ *
+ * 1. Android, Safari < 6/Mobile, IE<9: change to a relative background-position of 99%
+ * 2. Chrome 25+, Firefox 13+, IE 9+, Opera 10.5+: use the new CSS3-background-position syntax
+ *
+ * @see http://www.w3.org/TR/css3-background/#background-position
+ *
+ * @todo Since both Select2 and Bootstrap 3 only support IE8 and above,
+ * we could use the :after-pseudo-element to display the loading indicator.
+ * Alternatively, we could supply an altered loading indicator image which already
+ * contains an offset to the right.
+ */
+.select2-search input.select2-active,
+.select2-container-multi .select2-choices .select2-search-field input.select2-active,
+.select2-more-results.select2-active {
+ background-position: 99%;
+ /* 4 */
+ background-position: right 4px center;
+ /* 5 */
+}
+
+/**
+ * To support Select2 pre v3.4.2 in combination with Bootstrap v3.2.0,
+ * ensure that .select2-offscreen width, height and position can not be overwritten.
+ *
+ * This adresses changes in Bootstrap somewhere after the initial v3.0.0 which -
+ * in combination with Select2's pre-v3.4.2 CSS missing the "!important" after
+ * the following rules - allow Bootstrap to overwrite the latter, which results in
+ * the original element Select2 is replacing not be properly being hidden
+ * when used in a "Bootstrap Input Group with Addon".
+ **/
+.select2-offscreen,
+.select2-offscreen:focus {
+ width: 1px !important;
+ height: 1px !important;
+ position: absolute !important;
+}
diff --git a/static/facelift/css/lib/select2-spinner.gif b/static/facelift/css/lib/select2-spinner.gif
new file mode 100644
index 0000000000000000000000000000000000000000..5b33f7e54f4e55b6b8774d86d96895db9af044b4
GIT binary patch
literal 1849
zcma*odr(tX9tZI2z31lM+(&YVk%mZ}5P~KlG2s=WSbGzm0!x7^P##Mnh7t-jP!X0Q
zk_SQ}Po-L1tlDK;6l?(>v)e5ZBQx4|Y-Q?nr@Px3?9h(3ZWr3^tj=`TP57gKr87N$
zp2wWee1GRRCwo_xahnw)5cxNPJbCg2L6DV|6`#+yw6v6!mDS$f9-JvFD^n;GQ&UrZ
zzh5jCkByB101O60U0q#p_1BM>Cv-vP?&s4@g_((4_1L=L$(a91)0=J91Gas#R{McE
znYG^9*0A5YZ>#;~+Wkn(W5B0^yELIYLP!K}mB~<)AM@1&nqekynuaEGqPrzoH|KodRXJy)%+w_fu3nE5>@Bd_b
zqC$EQ;{c`T&?EsNO|igL9gC7Ygxv?aQUEXMq?~>wg{EyW;VcJ37CUF#HjrT=KQO_*
zS>M9yydXk18D(+QDJ1>r);Lav_uYKp$T?4vr{Q$lTo&pKv^?(>L-)G2*lwH!Ah7k?
z7oH<8h-(KTKt5V6$8gF)C7Io&P5=SjTh)=zV=E2EUhQZP##L8S{d%UK>>+y82>+FV+#^BzW7u3F)Bb>=lYQ%%j`F>ASe
zo*cw@V#u6T`A2He;70mR(V&iV&-7{qP~=SRf&jm9-T{*ZeZ}$rd0#6c&fLG^xJcf5
z+p<`wJYgW+_s*V{uI$nMB;%8`S_3>PfGOj3Rq}@Cx^+j?rk92fANSFDBYnOqQ>Vdj
z)(|$AhP4t&Lb=Gvo2#3Gl%9<=Gv`Mz?Po@P4iLF!x}GUWJICDlFk-hS^Whyh7x~VH
z@0vD1>HYD4&e+~yzS*-sFR{9`{QEEZO1zg7>R&7cHts-6j!xHVdA8eI+ZlVzd%`es
zJT@$#GX(gvCJ1oJN%yLBK}{V=V;seo;!w|Yte!W1%5qLNFWqvZW>h&IiH+oPT=b@E
zPhGzv5=(Un*X>v`>%8h_nj^NdYcE6NHS_ifkCV$*D)Tqrbu`s;<=t<4
zAHNqNV?6(g<1PY-w@#I-WYFViz?9TrkMr)u0g`O`u|>T;k|2sV*YF^punvT;$SuTy{j3Gv)yqD!R_CF>yR)MzmmYS5v+~R
zXAdD%ng9?df;wd8GxR#%3O+gz};Vo;)sK%Bj-q>Oq%R7JU-KD?vYu>#2UjaDo
z&8$>5xW~?KPD_#XFToU1hIb*VOMidUr6iYiO0N|i-7s`T8!cFT`rN!^1Pt78J93i6
z5HI1wIM$94m{3SLDvISDe6$ZG1;eq_D9RTaaC>=cO{@Bs>$IlPCPJJ$h$)-3vzNUQ6OsN#_zWxey!_9%hxwH2_dEJi=yY|1c7nDm2_Lm!Cof8-R_+9UkS
zcBE(o47yE)oMR(Q=dp1a2wTX5KvvGyLqlWTa7V&!A*|w|)ax~1_~aJ0=_Lilg*0iQk7#ZD
EAHN$8j{pDw
literal 0
HcmV?d00001
diff --git a/static/facelift/css/lib/select2.css b/static/facelift/css/lib/select2.css
new file mode 100644
index 000000000..2d07a0343
--- /dev/null
+++ b/static/facelift/css/lib/select2.css
@@ -0,0 +1,704 @@
+/*
+Version: 3.5.2 Timestamp: Sat Nov 1 14:43:36 EDT 2014
+*/
+.select2-container {
+ margin: 0;
+ position: relative;
+ display: inline-block;
+ /* inline-block for ie7 */
+ zoom: 1;
+ *display: inline;
+ vertical-align: middle;
+}
+
+.select2-container,
+.select2-drop,
+.select2-search,
+.select2-search input {
+ /*
+ Force border-box so that % widths fit the parent
+ container without overlap because of margin/padding.
+ More Info : http://www.quirksmode.org/css/box.html
+ */
+ -webkit-box-sizing: border-box; /* webkit */
+ -moz-box-sizing: border-box; /* firefox */
+ box-sizing: border-box; /* css3 */
+}
+
+.select2-container .select2-choice {
+ display: block;
+ height: 26px;
+ padding: 0 0 0 8px;
+ overflow: hidden;
+ position: relative;
+
+ border: 1px solid #aaa;
+ white-space: nowrap;
+ line-height: 26px;
+ color: #444;
+ text-decoration: none;
+
+ border-radius: 4px;
+
+ background-clip: padding-box;
+
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ background-color: #fff;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff));
+ background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%);
+ background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0);
+ background-image: linear-gradient(to top, #eee 0%, #fff 50%);
+}
+
+html[dir="rtl"] .select2-container .select2-choice {
+ padding: 0 8px 0 0;
+}
+
+.select2-container.select2-drop-above .select2-choice {
+ border-bottom-color: #aaa;
+
+ border-radius: 0 0 4px 4px;
+
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff));
+ background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%);
+ background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
+ background-image: linear-gradient(to bottom, #eee 0%, #fff 90%);
+}
+
+.select2-container.select2-allowclear .select2-choice .select2-chosen {
+ margin-right: 42px;
+}
+
+.select2-container .select2-choice > .select2-chosen {
+ margin-right: 26px;
+ display: block;
+ overflow: hidden;
+
+ white-space: nowrap;
+
+ text-overflow: ellipsis;
+ float: none;
+ width: auto;
+}
+
+html[dir="rtl"] .select2-container .select2-choice > .select2-chosen {
+ margin-left: 26px;
+ margin-right: 0;
+}
+
+.select2-container .select2-choice abbr {
+ display: none;
+ width: 12px;
+ height: 12px;
+ position: absolute;
+ right: 24px;
+ top: 8px;
+
+ font-size: 1px;
+ text-decoration: none;
+
+ border: 0;
+ background: url('select2.png') right top no-repeat;
+ cursor: pointer;
+ outline: 0;
+}
+
+.select2-container.select2-allowclear .select2-choice abbr {
+ display: inline-block;
+}
+
+.select2-container .select2-choice abbr:hover {
+ background-position: right -11px;
+ cursor: pointer;
+}
+
+.select2-drop-mask {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ position: fixed;
+ left: 0;
+ top: 0;
+ min-height: 100%;
+ min-width: 100%;
+ height: auto;
+ width: auto;
+ opacity: 0;
+ z-index: 9998;
+ /* styles required for IE to work */
+ background-color: #fff;
+ filter: alpha(opacity=0);
+}
+
+.select2-drop {
+ width: 100%;
+ margin-top: -1px;
+ position: absolute;
+ z-index: 9999;
+ top: 100%;
+
+ background: #fff;
+ color: #000;
+ border: 1px solid #aaa;
+ border-top: 0;
+
+ border-radius: 0 0 4px 4px;
+
+ -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
+ box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
+}
+
+.select2-drop.select2-drop-above {
+ margin-top: 1px;
+ border-top: 1px solid #aaa;
+ border-bottom: 0;
+
+ border-radius: 4px 4px 0 0;
+
+ -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
+ box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
+}
+
+.select2-drop-active {
+ border: 1px solid #5897fb;
+ border-top: none;
+}
+
+.select2-drop.select2-drop-above.select2-drop-active {
+ border-top: 1px solid #5897fb;
+}
+
+.select2-drop-auto-width {
+ border-top: 1px solid #aaa;
+ width: auto;
+}
+
+.select2-drop-auto-width .select2-search {
+ padding-top: 4px;
+}
+
+.select2-container .select2-choice .select2-arrow {
+ display: inline-block;
+ width: 18px;
+ height: 100%;
+ position: absolute;
+ right: 0;
+ top: 0;
+
+ border-left: 1px solid #aaa;
+ border-radius: 0 4px 4px 0;
+
+ background-clip: padding-box;
+
+ background: #ccc;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee));
+ background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%);
+ background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0);
+ background-image: linear-gradient(to top, #ccc 0%, #eee 60%);
+}
+
+html[dir="rtl"] .select2-container .select2-choice .select2-arrow {
+ left: 0;
+ right: auto;
+
+ border-left: none;
+ border-right: 1px solid #aaa;
+ border-radius: 4px 0 0 4px;
+}
+
+.select2-container .select2-choice .select2-arrow b {
+ display: block;
+ width: 100%;
+ height: 100%;
+ background: url('select2.png') no-repeat 0 1px;
+}
+
+html[dir="rtl"] .select2-container .select2-choice .select2-arrow b {
+ background-position: 2px 1px;
+}
+
+.select2-search {
+ display: inline-block;
+ width: 100%;
+ min-height: 26px;
+ margin: 0;
+ padding-left: 4px;
+ padding-right: 4px;
+
+ position: relative;
+ z-index: 10000;
+
+ white-space: nowrap;
+}
+
+.select2-search input {
+ width: 100%;
+ height: auto !important;
+ min-height: 26px;
+ padding: 4px 20px 4px 5px;
+ margin: 0;
+
+ outline: 0;
+ font-family: sans-serif;
+ font-size: 1em;
+
+ border: 1px solid #aaa;
+ border-radius: 0;
+
+ -webkit-box-shadow: none;
+ box-shadow: none;
+
+ background: #fff url('select2.png') no-repeat 100% -22px;
+ background: url('select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
+ background: url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
+ background: url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
+ background: url('select2.png') no-repeat 100% -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
+}
+
+html[dir="rtl"] .select2-search input {
+ padding: 4px 5px 4px 20px;
+
+ background: #fff url('select2.png') no-repeat -37px -22px;
+ background: url('select2.png') no-repeat -37px -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
+ background: url('select2.png') no-repeat -37px -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
+ background: url('select2.png') no-repeat -37px -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
+ background: url('select2.png') no-repeat -37px -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
+}
+
+.select2-drop.select2-drop-above .select2-search input {
+ margin-top: 4px;
+}
+
+.select2-search input.select2-active {
+ background: #fff url('select2-spinner.gif') no-repeat 100%;
+ background: url('select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
+ background: url('select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
+ background: url('select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
+ background: url('select2-spinner.gif') no-repeat 100%, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
+}
+
+.select2-container-active .select2-choice,
+.select2-container-active .select2-choices {
+ border: 1px solid #5897fb;
+ outline: none;
+
+ -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
+ box-shadow: 0 0 5px rgba(0, 0, 0, .3);
+}
+
+.select2-dropdown-open .select2-choice {
+ border-bottom-color: transparent;
+ -webkit-box-shadow: 0 1px 0 #fff inset;
+ box-shadow: 0 1px 0 #fff inset;
+
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+
+ background-color: #eee;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee));
+ background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%);
+ background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
+ background-image: linear-gradient(to top, #fff 0%, #eee 50%);
+}
+
+.select2-dropdown-open.select2-drop-above .select2-choice,
+.select2-dropdown-open.select2-drop-above .select2-choices {
+ border: 1px solid #5897fb;
+ border-top-color: transparent;
+
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee));
+ background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%);
+ background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
+ background-image: linear-gradient(to bottom, #fff 0%, #eee 50%);
+}
+
+.select2-dropdown-open .select2-choice .select2-arrow {
+ background: transparent;
+ border-left: none;
+ filter: none;
+}
+html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow {
+ border-right: none;
+}
+
+.select2-dropdown-open .select2-choice .select2-arrow b {
+ background-position: -18px 1px;
+}
+
+html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow b {
+ background-position: -16px 1px;
+}
+
+.select2-hidden-accessible {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+
+/* results */
+.select2-results {
+ max-height: 200px;
+ padding: 0 0 0 4px;
+ margin: 4px 4px 4px 0;
+ position: relative;
+ overflow-x: hidden;
+ overflow-y: auto;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+
+html[dir="rtl"] .select2-results {
+ padding: 0 4px 0 0;
+ margin: 4px 0 4px 4px;
+}
+
+.select2-results ul.select2-result-sub {
+ margin: 0;
+ padding-left: 0;
+}
+
+.select2-results li {
+ list-style: none;
+ display: list-item;
+ background-image: none;
+}
+
+.select2-results li.select2-result-with-children > .select2-result-label {
+ font-weight: bold;
+}
+
+.select2-results .select2-result-label {
+ padding: 3px 7px 4px;
+ margin: 0;
+ cursor: pointer;
+
+ min-height: 1em;
+
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.select2-results-dept-1 .select2-result-label { padding-left: 20px }
+.select2-results-dept-2 .select2-result-label { padding-left: 40px }
+.select2-results-dept-3 .select2-result-label { padding-left: 60px }
+.select2-results-dept-4 .select2-result-label { padding-left: 80px }
+.select2-results-dept-5 .select2-result-label { padding-left: 100px }
+.select2-results-dept-6 .select2-result-label { padding-left: 110px }
+.select2-results-dept-7 .select2-result-label { padding-left: 120px }
+
+.select2-results .select2-highlighted {
+ background: #3875d7;
+ color: #fff;
+}
+
+.select2-results li em {
+ background: #feffde;
+ font-style: normal;
+}
+
+.select2-results .select2-highlighted em {
+ background: transparent;
+}
+
+.select2-results .select2-highlighted ul {
+ background: #fff;
+ color: #000;
+}
+
+.select2-results .select2-no-results,
+.select2-results .select2-searching,
+.select2-results .select2-ajax-error,
+.select2-results .select2-selection-limit {
+ background: #f4f4f4;
+ display: list-item;
+ padding-left: 5px;
+}
+
+/*
+disabled look for disabled choices in the results dropdown
+*/
+.select2-results .select2-disabled.select2-highlighted {
+ color: #666;
+ background: #f4f4f4;
+ display: list-item;
+ cursor: default;
+}
+.select2-results .select2-disabled {
+ background: #f4f4f4;
+ display: list-item;
+ cursor: default;
+}
+
+.select2-results .select2-selected {
+ display: none;
+}
+
+.select2-more-results.select2-active {
+ background: #f4f4f4 url('select2-spinner.gif') no-repeat 100%;
+}
+
+.select2-results .select2-ajax-error {
+ background: rgba(255, 50, 50, .2);
+}
+
+.select2-more-results {
+ background: #f4f4f4;
+ display: list-item;
+}
+
+/* disabled styles */
+
+.select2-container.select2-container-disabled .select2-choice {
+ background-color: #f4f4f4;
+ background-image: none;
+ border: 1px solid #ddd;
+ cursor: default;
+}
+
+.select2-container.select2-container-disabled .select2-choice .select2-arrow {
+ background-color: #f4f4f4;
+ background-image: none;
+ border-left: 0;
+}
+
+.select2-container.select2-container-disabled .select2-choice abbr {
+ display: none;
+}
+
+
+/* multiselect */
+
+.select2-container-multi .select2-choices {
+ height: auto !important;
+ height: 1%;
+ margin: 0;
+ padding: 0 5px 0 0;
+ position: relative;
+
+ border: 1px solid #aaa;
+ cursor: text;
+ overflow: hidden;
+
+ background-color: #fff;
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff));
+ background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%);
+ background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%);
+ background-image: linear-gradient(to bottom, #eee 1%, #fff 15%);
+}
+
+html[dir="rtl"] .select2-container-multi .select2-choices {
+ padding: 0 0 0 5px;
+}
+
+.select2-locked {
+ padding: 3px 5px 3px 5px !important;
+}
+
+.select2-container-multi .select2-choices {
+ min-height: 26px;
+}
+
+.select2-container-multi.select2-container-active .select2-choices {
+ border: 1px solid #5897fb;
+ outline: none;
+
+ -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
+ box-shadow: 0 0 5px rgba(0, 0, 0, .3);
+}
+.select2-container-multi .select2-choices li {
+ float: left;
+ list-style: none;
+}
+html[dir="rtl"] .select2-container-multi .select2-choices li
+{
+ float: right;
+}
+.select2-container-multi .select2-choices .select2-search-field {
+ margin: 0;
+ padding: 0;
+ white-space: nowrap;
+}
+
+.select2-container-multi .select2-choices .select2-search-field input {
+ padding: 5px;
+ margin: 1px 0;
+
+ font-family: sans-serif;
+ font-size: 100%;
+ color: #666;
+ outline: 0;
+ border: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ background: transparent !important;
+}
+
+.select2-container-multi .select2-choices .select2-search-field input.select2-active {
+ background: #fff url('select2-spinner.gif') no-repeat 100% !important;
+}
+
+.select2-default {
+ color: #999 !important;
+}
+
+.select2-container-multi .select2-choices .select2-search-choice {
+ padding: 3px 5px 3px 18px;
+ margin: 3px 0 3px 5px;
+ position: relative;
+
+ line-height: 13px;
+ color: #333;
+ cursor: default;
+ border: 1px solid #aaaaaa;
+
+ border-radius: 3px;
+
+ -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
+ box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
+
+ background-clip: padding-box;
+
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ background-color: #e4e4e4;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0);
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee));
+ background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
+ background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
+ background-image: linear-gradient(to bottom, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
+}
+html[dir="rtl"] .select2-container-multi .select2-choices .select2-search-choice
+{
+ margin: 3px 5px 3px 0;
+ padding: 3px 18px 3px 5px;
+}
+.select2-container-multi .select2-choices .select2-search-choice .select2-chosen {
+ cursor: default;
+}
+.select2-container-multi .select2-choices .select2-search-choice-focus {
+ background: #d4d4d4;
+}
+
+.select2-search-choice-close {
+ display: block;
+ width: 12px;
+ height: 13px;
+ position: absolute;
+ right: 3px;
+ top: 4px;
+
+ font-size: 1px;
+ outline: none;
+ background: url('select2.png') right top no-repeat;
+}
+html[dir="rtl"] .select2-search-choice-close {
+ right: auto;
+ left: 3px;
+}
+
+.select2-container-multi .select2-search-choice-close {
+ left: 3px;
+}
+
+html[dir="rtl"] .select2-container-multi .select2-search-choice-close {
+ left: auto;
+ right: 2px;
+}
+
+.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover {
+ background-position: right -11px;
+}
+.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close {
+ background-position: right -11px;
+}
+
+/* disabled styles */
+.select2-container-multi.select2-container-disabled .select2-choices {
+ background-color: #f4f4f4;
+ background-image: none;
+ border: 1px solid #ddd;
+ cursor: default;
+}
+
+.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice {
+ padding: 3px 5px 3px 5px;
+ border: 1px solid #ddd;
+ background-image: none;
+ background-color: #f4f4f4;
+}
+
+.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none;
+ background: none;
+}
+/* end multiselect */
+
+
+.select2-result-selectable .select2-match,
+.select2-result-unselectable .select2-match {
+ text-decoration: underline;
+}
+
+.select2-offscreen, .select2-offscreen:focus {
+ clip: rect(0 0 0 0) !important;
+ width: 1px !important;
+ height: 1px !important;
+ border: 0 !important;
+ margin: 0 !important;
+ padding: 0 !important;
+ overflow: hidden !important;
+ position: absolute !important;
+ outline: 0 !important;
+ left: 0px !important;
+ top: 0px !important;
+}
+
+.select2-display-none {
+ display: none;
+}
+
+.select2-measure-scrollbar {
+ position: absolute;
+ top: -10000px;
+ left: -10000px;
+ width: 100px;
+ height: 100px;
+ overflow: scroll;
+}
+
+/* Retina-ize icons */
+
+@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 2dppx) {
+ .select2-search input,
+ .select2-search-choice-close,
+ .select2-container .select2-choice abbr,
+ .select2-container .select2-choice .select2-arrow b {
+ background-image: url('select2x2.png') !important;
+ background-repeat: no-repeat !important;
+ background-size: 60px 40px !important;
+ }
+
+ .select2-search input {
+ background-position: 100% -21px !important;
+ }
+}
diff --git a/static/facelift/css/lib/select2.png b/static/facelift/css/lib/select2.png
new file mode 100644
index 0000000000000000000000000000000000000000..1d804ffb99699b9e030f1010314de0970b5a000d
GIT binary patch
literal 613
zcmV-r0-F7aP)#WY!I$JQV$)A5aAS1BM||2XVJl=+L1^1S1H%
zM-&lx?NZpUrHhn>fk<>POqf2sh40}xxGZfc+t+#Eb(qHy9_3*1(U%t9t)QDnI#YAL(|ACV(>)>6WD-t!8tutHkdb^#3`HzoJG3A2@T`%
zA|K@o*b!`R#(7)PWrMFn2))Ca3MR4(zaT`Zr61*kZK5NPnZwQszxh$fyv3?&4c>$q
z2m=+yc0dRXRAsPDxF6sD;@rK4JGdR_``1S~o6Xi@2&aR6hcSrEp9HVRzEqVDqBn<1%hR=D4e1f^ra^A|34Cjc=Gny{F(o#MrvPYgZuTJOz(n)-F<|
zj()qR;C={)N<0RRvDZ^@6ND+W*}gh-Lip(MDt!(zMSO)!j2j+*hxgzC-e3$@(O2p*
zu;+gddm(cZwXTCLx*Ky4THOa*^b^F`woveIeCK^0aR|TJ00000NkvXXu0mjfA#WC6
literal 0
HcmV?d00001
diff --git a/static/facelift/js/edit-milestones.js b/static/facelift/js/edit-milestones.js
new file mode 100644
index 000000000..c73a5d4c2
--- /dev/null
+++ b/static/facelift/js/edit-milestones.js
@@ -0,0 +1,140 @@
+$(document).ready(function () {
+ var idCounter = -1;
+ var milestonesForm = $('#milestones-form');
+
+ // make sure we got the lowest number for idCounter
+ milestonesForm.find('.edit-milestone input[name$="-id"]').each(function () {
+ var v = +this.value;
+ if (!isNaN(v) && v < idCounter)
+ idCounter = v - 1;
+ });
+
+ function setChanged() {
+ $(this).closest(".edit-milestone").addClass("changed");
+ setSubmitButtonState();
+ }
+
+ milestonesForm.on("change", '.edit-milestone select,.edit-milestone input,.edit-milestone textarea', setChanged);
+ milestonesForm.on("click", '.edit-milestone .select2 input', setChanged);
+
+ // the required stuff seems to trip up many browsers with dynamic forms
+ milestonesForm.find("input").prop("required", false);
+
+
+ function setSubmitButtonState() {
+ var action, label;
+ if (milestonesForm.find("input[name$=delete]:visible").length > 0)
+ action = "review";
+ else
+ action = "save";
+
+ milestonesForm.find("input[name=action]").val(action);
+
+ var submit = milestonesForm.find("[type=submit]");
+ submit.text(submit.data("label" + action));
+ if (milestonesForm.find(".edit-milestone.changed").length > 0 || action == "review")
+ submit.show();
+ else
+ submit.hide();
+ }
+
+ milestonesForm.find(".milestone").click(function () {
+ var row = $(this), editRow = row.next(".edit-milestone");
+ row.hide();
+ editRow.show();
+
+ editRow.find('input[name$="desc"]').focus();
+
+ setSubmitButtonState();
+
+ // collapse unchanged rows
+ milestonesForm.find(".milestone").not(this).each(function () {
+ var e = $(this).next('.edit-milestone');
+ if (e.is(":visible") && !e.hasClass("changed")) {
+ $(this).show();
+ e.hide();
+ }
+ });
+ });
+
+ milestonesForm.find(".add-milestone").click(function() {
+ // move Add milestone row and duplicate hidden template
+ var row = $(this).closest("tr"), editRow = row.next(".edit-milestone");
+ row.closest("table").append(row).append(editRow.clone());
+
+ // fixup template
+ var newId = idCounter;
+ --idCounter;
+
+ var prefix = "m" + newId;
+ editRow.find('input[name="prefix"]').val(prefix);
+
+ editRow.find("input,select,textarea").each(function () {
+ if (this.name == "prefix")
+ return;
+
+ if (this.name == "id")
+ this.value = "" + idCounter;
+
+ this.name = prefix + "-" + this.name;
+ this.id = prefix + "-" + this.id;
+ });
+ editRow.find("label").each(function () {
+ if (this.htmlFor)
+ this.htmlFor = prefix + "-" + this.htmlFor;
+ });
+
+ editRow.removeClass("template");
+ editRow.show();
+
+ editRow.find(".select2-field").each(function () {
+ window.setupSelect2Field($(this)); // from ietf.js
+ });
+ });
+
+ function setResolvedState() {
+ var resolved = $(this).is(":checked");
+ var label = $(this).closest(".edit-milestone").find("label[for=" + this.id + "]");
+ var reason = $(this).closest(".edit-milestone").find("[name$=resolved]");
+ if (resolved) {
+ reason.closest(".form-group").show();
+ if (!reason.val())
+ reason.val(reason.data("default"));
+ }
+ else {
+ reason.closest(".form-group").hide();
+ reason.val("");
+ }
+ }
+
+ milestonesForm.find(".edit-milestone [name$=resolved_checkbox]").each(setResolvedState);
+ milestonesForm.on("change", ".edit-milestone [name$=resolved_checkbox]", setResolvedState);
+
+ function setDeleteState() {
+ var edit = $(this).closest(".edit-milestone"), row = edit.prev(".milestone");
+
+ if ($(this).is(":checked")) {
+ if (+edit.find('input[name$="id"]').val() < 0) {
+ edit.remove();
+ setSubmitButtonState();
+ }
+ else {
+ row.addClass("delete");
+ edit.addClass("delete");
+ }
+ }
+ else {
+ row.removeClass("delete");
+ edit.removeClass("delete");
+ }
+ }
+
+ milestonesForm.find(".edit-milestone [name$=delete]").each(setDeleteState);
+ milestonesForm.on("change", ".edit-milestone input[name$=delete]", setDeleteState);
+
+ milestonesForm.find('.edit-milestone .has-error').each(function () {
+ $(this).closest(".edit-milestone").prev().click();
+ });
+
+ setSubmitButtonState();
+});
diff --git a/static/facelift/js/ietf.js b/static/facelift/js/ietf.js
index bc956b126..4b261703d 100644
--- a/static/facelift/js/ietf.js
+++ b/static/facelift/js/ietf.js
@@ -192,160 +192,59 @@ $(".snippet .show-all").click(function () {
// }
// });
+function setupSelect2Field(e) {
+ var url = e.data("ajax-url");
+ if (!url)
+ return;
-function to_disp(t) {
- // typehead/tokenfield don't fully deal with HTML entities
- return $('
').html(t).text().replace(/[<>"]/g, function (m) {
- return {
- '<': '(',
- '>': ')',
- '"': ''
- }[m];
- });
+ var maxEntries = e.data("max-entries");
+ var multiple = maxEntries != 1;
+ var prefetched = e.data("pre");
+ e.select2({
+ multiple: multiple,
+ minimumInputLength: 2,
+ width: "off",
+ allowClear: true,
+ maximumSelectionSize: maxEntries,
+ ajax: {
+ url: url,
+ dataType: "json",
+ quietMillis: 250,
+ data: function (term, page) {
+ return {
+ q: term,
+ p: page
+ };
+ },
+ results: function (results) {
+ return {
+ results: results,
+ more: results.length == 10
+ };
+ }
+ },
+ escapeMarkup: function (m) {
+ return m;
+ },
+ initSelection: function (element, cb) {
+ if (!multiple && prefetched.length > 0)
+ cb(prefetched[0]);
+ else
+ cb(prefetched);
+
+ },
+ dropdownCssClass: "bigdrop"
+ });
}
+$(document).ready(function () {
+ $(".select2-field").each(function () {
+ if ($(this).closest(".template").length > 0)
+ return;
-$(".tokenized-form").submit(function (e) {
- $(this).find(".tokenized-field").each(function () {
- var f = $(this);
- var io = f.data("io");
- var format = f.data("format");
- var t = f.tokenfield("getTokens");
-
- var v = $.map(t, function(o) { return o["value"]; });
- if (format === "json") {
- v = JSON.stringify(v);
- } else if (format === "csv") {
- v = v.join(", ");
- } else {
- console.log(io, "unknown format");
- v = v.join(" ");
- }
- f.val(v);
- if (io) {
- $(io).val(v);
- }
- });
-});
-
-
-$(".tokenized-field").each(function () {
- // autocomplete interferes with the token popup
- $(this).attr("autocomplete", "off");
-
- // in which field ID are we expected to place the result
- // (we also read the prefill information from there)
- var io = $(this).data("io");
- var raw = "";
- if (io) {
- raw = $(io).val();
- } else {
- io = "#" + this.id;
- raw = $(this).val();
- }
- console.log("io: ", io);
- console.log(io, "raw", raw);
- $(this).data("io", io);
-
- // which field of the JSON are we supposed to display
- var display = $(this).data("display");
- if (!display) {
- display = "name";
- }
- console.log(io, "display", display);
- $(this).data("display", display);
-
- // which field of the JSON are we supposed to return
- var result = $(this).data("result");
- if (!result) {
- result = "id";
- }
- console.log(io, "result", result);
- $(this).data("result", result);
-
- // what kind of data are we returning (json or csv)
- var format = $(this).data("format");
- if (!format) {
- format = "csv";
- }
- console.log(io, "format", format);
- $(this).data("format", format);
-
- // make tokens to prefill the input
- if (raw) {
- raw = $.parseJSON(raw);
- var pre = [];
- if (!raw[0] || !raw[0][display]) {
- $.each(raw, function(k, v) {
- var obj = {};
- obj["value"] = k;
- obj["label"] = to_disp(v);
- pre.push(obj);
- });
- } else {
- for (var i in raw) {
- var obj = {};
- obj["value"] = raw[i][result];
- obj["label"] = to_disp(raw[i][display]);
- pre.push(obj);
- }
- }
- $(this).val(pre);
- }
- console.log(io, "pre", pre);
-
- // check if the ajax-url contains a query parameter, add one if not
- var url = $(this).data("ajax-url");
- if (url.indexOf("?") === -1) {
- url += "?q=";
- }
- $(this).data("ajax-url", url);
- console.log(io, "ajax-url", url);
-
- var bh = new Bloodhound({
- datumTokenizer: function (d) {
- return Bloodhound.tokenizers.nonword(d[display]);
- },
- queryTokenizer: Bloodhound.tokenizers.nonword,
- limit: 20,
- remote: {
- url: url + "%QUERY",
- filter: function (data) {
- return $.map($.grep(data, function (n, i) {
- return true;
- }), function (n, i) {
- n["label"] = to_disp(n[display]);
- n["value"] = n[result];
- return n;
- });
- }
- }
- });
- bh.initialize();
- $(this).tokenfield({
- typeahead: [{
- highlight: true,
- minLength: 3,
- hint: true
- }, {
- source: bh.ttAdapter(),
- displayKey: "label"
- }],
- beautify: true,
- delimiter: [',', ';']
- }).tokenfield("setTokens", pre);
-
- // only allow tokens from the popup to be added to the field, no free text
- $(this).on('tokenfield:createtoken', function (event) {
- var existingTokens = $(this).tokenfield('getTokens');
- $.each(existingTokens, function(index, token) {
- if (event.attrs.id === undefined) {
- event.preventDefault();
- }
- });
+ setupSelect2Field($(this));
});
});
-
// Use the Bootstrap3 tooltip plugin for all elements with a title attribute
$('[title][title!=""]').tooltip();
diff --git a/static/facelift/js/lib/select2-3.5.2.min.js b/static/facelift/js/lib/select2-3.5.2.min.js
new file mode 100644
index 000000000..b56419e2e
--- /dev/null
+++ b/static/facelift/js/lib/select2-3.5.2.min.js
@@ -0,0 +1,23 @@
+/*
+Copyright 2014 Igor Vaynberg
+
+Version: 3.5.2 Timestamp: Sat Nov 1 14:43:36 EDT 2014
+
+This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
+General Public License version 2 (the "GPL License"). You may choose either license to govern your
+use of this software only upon the condition that you accept all of the terms of either the Apache
+License or the GPL License.
+
+You may obtain a copy of the Apache License and the GPL License at:
+
+http://www.apache.org/licenses/LICENSE-2.0
+http://www.gnu.org/licenses/gpl-2.0.html
+
+Unless required by applicable law or agreed to in writing, software distributed under the Apache License
+or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+either express or implied. See the Apache License and the GPL License for the specific language governing
+permissions and limitations under the Apache License and the GPL License.
+*/
+!function(a){"undefined"==typeof a.fn.each2&&a.extend(a.fn,{each2:function(b){for(var c=a([0]),d=-1,e=this.length;++dc;c+=1)if(r(a,b[c]))return c;return-1}function q(){var b=a(l);b.appendTo(document.body);var c={width:b.width()-b[0].clientWidth,height:b.height()-b[0].clientHeight};return b.remove(),c}function r(a,c){return a===c?!0:a===b||c===b?!1:null===a||null===c?!1:a.constructor===String?a+""==c+"":c.constructor===String?c+""==a+"":!1}function s(a,b,c){var d,e,f;if(null===a||a.length<1)return[];for(d=a.split(b),e=0,f=d.length;f>e;e+=1)d[e]=c(d[e]);return d}function t(a){return a.outerWidth(!1)-a.width()}function u(c){var d="keyup-change-value";c.on("keydown",function(){a.data(c,d)===b&&a.data(c,d,c.val())}),c.on("keyup",function(){var e=a.data(c,d);e!==b&&c.val()!==e&&(a.removeData(c,d),c.trigger("keyup-change"))})}function v(c){c.on("mousemove",function(c){var d=h;(d===b||d.x!==c.pageX||d.y!==c.pageY)&&a(c.target).trigger("mousemove-filtered",c)})}function w(a,c,d){d=d||b;var e;return function(){var b=arguments;window.clearTimeout(e),e=window.setTimeout(function(){c.apply(d,b)},a)}}function x(a,b){var c=w(a,function(a){b.trigger("scroll-debounced",a)});b.on("scroll",function(a){p(a.target,b.get())>=0&&c(a)})}function y(a){a[0]!==document.activeElement&&window.setTimeout(function(){var d,b=a[0],c=a.val().length;a.focus();var e=b.offsetWidth>0||b.offsetHeight>0;e&&b===document.activeElement&&(b.setSelectionRange?b.setSelectionRange(c,c):b.createTextRange&&(d=b.createTextRange(),d.collapse(!1),d.select()))},0)}function z(b){b=a(b)[0];var c=0,d=0;if("selectionStart"in b)c=b.selectionStart,d=b.selectionEnd-c;else if("selection"in document){b.focus();var e=document.selection.createRange();d=document.selection.createRange().text.length,e.moveStart("character",-b.value.length),c=e.text.length-d}return{offset:c,length:d}}function A(a){a.preventDefault(),a.stopPropagation()}function B(a){a.preventDefault(),a.stopImmediatePropagation()}function C(b){if(!g){var c=b[0].currentStyle||window.getComputedStyle(b[0],null);g=a(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:c.fontSize,fontFamily:c.fontFamily,fontStyle:c.fontStyle,fontWeight:c.fontWeight,letterSpacing:c.letterSpacing,textTransform:c.textTransform,whiteSpace:"nowrap"}),g.attr("class","select2-sizer"),a(document.body).append(g)}return g.text(b.val()),g.width()}function D(b,c,d){var e,g,f=[];e=a.trim(b.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each2(function(){0===this.indexOf("select2-")&&f.push(this)})),e=a.trim(c.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each2(function(){0!==this.indexOf("select2-")&&(g=d(this),g&&f.push(g))})),b.attr("class",f.join(" "))}function E(a,b,c,d){var e=o(a.toUpperCase()).indexOf(o(b.toUpperCase())),f=b.length;return 0>e?(c.push(d(a)),void 0):(c.push(d(a.substring(0,e))),c.push(""),c.push(d(a.substring(e,e+f))),c.push(" "),c.push(d(a.substring(e+f,a.length))),void 0)}function F(a){var b={"\\":"\","&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};return String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})}function G(c){var d,e=null,f=c.quietMillis||100,g=c.url,h=this;return function(i){window.clearTimeout(d),d=window.setTimeout(function(){var d=c.data,f=g,j=c.transport||a.fn.select2.ajaxDefaults.transport,k={type:c.type||"GET",cache:c.cache||!1,jsonpCallback:c.jsonpCallback||b,dataType:c.dataType||"json"},l=a.extend({},a.fn.select2.ajaxDefaults.params,k);d=d?d.call(h,i.term,i.page,i.context):null,f="function"==typeof f?f.call(h,i.term,i.page,i.context):f,e&&"function"==typeof e.abort&&e.abort(),c.params&&(a.isFunction(c.params)?a.extend(l,c.params.call(h)):a.extend(l,c.params)),a.extend(l,{url:f,dataType:c.dataType,data:d,success:function(a){var b=c.results(a,i.page,i);i.callback(b)},error:function(a,b,c){var d={hasError:!0,jqXHR:a,textStatus:b,errorThrown:c};i.callback(d)}}),e=j.call(h,l)},f)}}function H(b){var d,e,c=b,f=function(a){return""+a.text};a.isArray(c)&&(e=c,c={results:e}),a.isFunction(c)===!1&&(e=c,c=function(){return e});var g=c();return g.text&&(f=g.text,a.isFunction(f)||(d=g.text,f=function(a){return a[d]})),function(b){var g,d=b.term,e={results:[]};return""===d?(b.callback(c()),void 0):(g=function(c,e){var h,i;if(c=c[0],c.children){h={};for(i in c)c.hasOwnProperty(i)&&(h[i]=c[i]);h.children=[],a(c.children).each2(function(a,b){g(b,h.children)}),(h.children.length||b.matcher(d,f(h),c))&&e.push(h)}else b.matcher(d,f(c),c)&&e.push(c)},a(c().results).each2(function(a,b){g(b,e.results)}),b.callback(e),void 0)}}function I(c){var d=a.isFunction(c);return function(e){var f=e.term,g={results:[]},h=d?c(e):c;a.isArray(h)&&(a(h).each(function(){var a=this.text!==b,c=a?this.text:this;(""===f||e.matcher(f,c))&&g.results.push(a?this:{id:this,text:this})}),e.callback(g))}}function J(b,c){if(a.isFunction(b))return!0;if(!b)return!1;if("string"==typeof b)return!0;throw new Error(c+" must be a string, function, or falsy value")}function K(b,c){if(a.isFunction(b)){var d=Array.prototype.slice.call(arguments,2);return b.apply(c,d)}return b}function L(b){var c=0;return a.each(b,function(a,b){b.children?c+=L(b.children):c++}),c}function M(a,c,d,e){var h,i,j,k,l,f=a,g=!1;if(!e.createSearchChoice||!e.tokenSeparators||e.tokenSeparators.length<1)return b;for(;;){for(i=-1,j=0,k=e.tokenSeparators.length;k>j&&(l=e.tokenSeparators[j],i=a.indexOf(l),!(i>=0));j++);if(0>i)break;if(h=a.substring(0,i),a=a.substring(i+l.length),h.length>0&&(h=e.createSearchChoice.call(this,h,c),h!==b&&null!==h&&e.id(h)!==b&&null!==e.id(h))){for(g=!1,j=0,k=c.length;k>j;j++)if(r(e.id(h),e.id(c[j]))){g=!0;break}g||d(h)}}return f!==a?a:void 0}function N(){var b=this;a.each(arguments,function(a,c){b[c].remove(),b[c]=null})}function O(b,c){var d=function(){};return d.prototype=new b,d.prototype.constructor=d,d.prototype.parent=b.prototype,d.prototype=a.extend(d.prototype,c),d}if(window.Select2===b){var c,d,e,f,g,i,j,h={x:0,y:0},k={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(a){switch(a=a.which?a.which:a){case k.LEFT:case k.RIGHT:case k.UP:case k.DOWN:return!0}return!1},isControl:function(a){var b=a.which;switch(b){case k.SHIFT:case k.CTRL:case k.ALT:return!0}return a.metaKey?!0:!1},isFunctionKey:function(a){return a=a.which?a.which:a,a>=112&&123>=a}},l="
",m={"\u24b6":"A","\uff21":"A","\xc0":"A","\xc1":"A","\xc2":"A","\u1ea6":"A","\u1ea4":"A","\u1eaa":"A","\u1ea8":"A","\xc3":"A","\u0100":"A","\u0102":"A","\u1eb0":"A","\u1eae":"A","\u1eb4":"A","\u1eb2":"A","\u0226":"A","\u01e0":"A","\xc4":"A","\u01de":"A","\u1ea2":"A","\xc5":"A","\u01fa":"A","\u01cd":"A","\u0200":"A","\u0202":"A","\u1ea0":"A","\u1eac":"A","\u1eb6":"A","\u1e00":"A","\u0104":"A","\u023a":"A","\u2c6f":"A","\ua732":"AA","\xc6":"AE","\u01fc":"AE","\u01e2":"AE","\ua734":"AO","\ua736":"AU","\ua738":"AV","\ua73a":"AV","\ua73c":"AY","\u24b7":"B","\uff22":"B","\u1e02":"B","\u1e04":"B","\u1e06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24b8":"C","\uff23":"C","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\xc7":"C","\u1e08":"C","\u0187":"C","\u023b":"C","\ua73e":"C","\u24b9":"D","\uff24":"D","\u1e0a":"D","\u010e":"D","\u1e0c":"D","\u1e10":"D","\u1e12":"D","\u1e0e":"D","\u0110":"D","\u018b":"D","\u018a":"D","\u0189":"D","\ua779":"D","\u01f1":"DZ","\u01c4":"DZ","\u01f2":"Dz","\u01c5":"Dz","\u24ba":"E","\uff25":"E","\xc8":"E","\xc9":"E","\xca":"E","\u1ec0":"E","\u1ebe":"E","\u1ec4":"E","\u1ec2":"E","\u1ebc":"E","\u0112":"E","\u1e14":"E","\u1e16":"E","\u0114":"E","\u0116":"E","\xcb":"E","\u1eba":"E","\u011a":"E","\u0204":"E","\u0206":"E","\u1eb8":"E","\u1ec6":"E","\u0228":"E","\u1e1c":"E","\u0118":"E","\u1e18":"E","\u1e1a":"E","\u0190":"E","\u018e":"E","\u24bb":"F","\uff26":"F","\u1e1e":"F","\u0191":"F","\ua77b":"F","\u24bc":"G","\uff27":"G","\u01f4":"G","\u011c":"G","\u1e20":"G","\u011e":"G","\u0120":"G","\u01e6":"G","\u0122":"G","\u01e4":"G","\u0193":"G","\ua7a0":"G","\ua77d":"G","\ua77e":"G","\u24bd":"H","\uff28":"H","\u0124":"H","\u1e22":"H","\u1e26":"H","\u021e":"H","\u1e24":"H","\u1e28":"H","\u1e2a":"H","\u0126":"H","\u2c67":"H","\u2c75":"H","\ua78d":"H","\u24be":"I","\uff29":"I","\xcc":"I","\xcd":"I","\xce":"I","\u0128":"I","\u012a":"I","\u012c":"I","\u0130":"I","\xcf":"I","\u1e2e":"I","\u1ec8":"I","\u01cf":"I","\u0208":"I","\u020a":"I","\u1eca":"I","\u012e":"I","\u1e2c":"I","\u0197":"I","\u24bf":"J","\uff2a":"J","\u0134":"J","\u0248":"J","\u24c0":"K","\uff2b":"K","\u1e30":"K","\u01e8":"K","\u1e32":"K","\u0136":"K","\u1e34":"K","\u0198":"K","\u2c69":"K","\ua740":"K","\ua742":"K","\ua744":"K","\ua7a2":"K","\u24c1":"L","\uff2c":"L","\u013f":"L","\u0139":"L","\u013d":"L","\u1e36":"L","\u1e38":"L","\u013b":"L","\u1e3c":"L","\u1e3a":"L","\u0141":"L","\u023d":"L","\u2c62":"L","\u2c60":"L","\ua748":"L","\ua746":"L","\ua780":"L","\u01c7":"LJ","\u01c8":"Lj","\u24c2":"M","\uff2d":"M","\u1e3e":"M","\u1e40":"M","\u1e42":"M","\u2c6e":"M","\u019c":"M","\u24c3":"N","\uff2e":"N","\u01f8":"N","\u0143":"N","\xd1":"N","\u1e44":"N","\u0147":"N","\u1e46":"N","\u0145":"N","\u1e4a":"N","\u1e48":"N","\u0220":"N","\u019d":"N","\ua790":"N","\ua7a4":"N","\u01ca":"NJ","\u01cb":"Nj","\u24c4":"O","\uff2f":"O","\xd2":"O","\xd3":"O","\xd4":"O","\u1ed2":"O","\u1ed0":"O","\u1ed6":"O","\u1ed4":"O","\xd5":"O","\u1e4c":"O","\u022c":"O","\u1e4e":"O","\u014c":"O","\u1e50":"O","\u1e52":"O","\u014e":"O","\u022e":"O","\u0230":"O","\xd6":"O","\u022a":"O","\u1ece":"O","\u0150":"O","\u01d1":"O","\u020c":"O","\u020e":"O","\u01a0":"O","\u1edc":"O","\u1eda":"O","\u1ee0":"O","\u1ede":"O","\u1ee2":"O","\u1ecc":"O","\u1ed8":"O","\u01ea":"O","\u01ec":"O","\xd8":"O","\u01fe":"O","\u0186":"O","\u019f":"O","\ua74a":"O","\ua74c":"O","\u01a2":"OI","\ua74e":"OO","\u0222":"OU","\u24c5":"P","\uff30":"P","\u1e54":"P","\u1e56":"P","\u01a4":"P","\u2c63":"P","\ua750":"P","\ua752":"P","\ua754":"P","\u24c6":"Q","\uff31":"Q","\ua756":"Q","\ua758":"Q","\u024a":"Q","\u24c7":"R","\uff32":"R","\u0154":"R","\u1e58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1e5a":"R","\u1e5c":"R","\u0156":"R","\u1e5e":"R","\u024c":"R","\u2c64":"R","\ua75a":"R","\ua7a6":"R","\ua782":"R","\u24c8":"S","\uff33":"S","\u1e9e":"S","\u015a":"S","\u1e64":"S","\u015c":"S","\u1e60":"S","\u0160":"S","\u1e66":"S","\u1e62":"S","\u1e68":"S","\u0218":"S","\u015e":"S","\u2c7e":"S","\ua7a8":"S","\ua784":"S","\u24c9":"T","\uff34":"T","\u1e6a":"T","\u0164":"T","\u1e6c":"T","\u021a":"T","\u0162":"T","\u1e70":"T","\u1e6e":"T","\u0166":"T","\u01ac":"T","\u01ae":"T","\u023e":"T","\ua786":"T","\ua728":"TZ","\u24ca":"U","\uff35":"U","\xd9":"U","\xda":"U","\xdb":"U","\u0168":"U","\u1e78":"U","\u016a":"U","\u1e7a":"U","\u016c":"U","\xdc":"U","\u01db":"U","\u01d7":"U","\u01d5":"U","\u01d9":"U","\u1ee6":"U","\u016e":"U","\u0170":"U","\u01d3":"U","\u0214":"U","\u0216":"U","\u01af":"U","\u1eea":"U","\u1ee8":"U","\u1eee":"U","\u1eec":"U","\u1ef0":"U","\u1ee4":"U","\u1e72":"U","\u0172":"U","\u1e76":"U","\u1e74":"U","\u0244":"U","\u24cb":"V","\uff36":"V","\u1e7c":"V","\u1e7e":"V","\u01b2":"V","\ua75e":"V","\u0245":"V","\ua760":"VY","\u24cc":"W","\uff37":"W","\u1e80":"W","\u1e82":"W","\u0174":"W","\u1e86":"W","\u1e84":"W","\u1e88":"W","\u2c72":"W","\u24cd":"X","\uff38":"X","\u1e8a":"X","\u1e8c":"X","\u24ce":"Y","\uff39":"Y","\u1ef2":"Y","\xdd":"Y","\u0176":"Y","\u1ef8":"Y","\u0232":"Y","\u1e8e":"Y","\u0178":"Y","\u1ef6":"Y","\u1ef4":"Y","\u01b3":"Y","\u024e":"Y","\u1efe":"Y","\u24cf":"Z","\uff3a":"Z","\u0179":"Z","\u1e90":"Z","\u017b":"Z","\u017d":"Z","\u1e92":"Z","\u1e94":"Z","\u01b5":"Z","\u0224":"Z","\u2c7f":"Z","\u2c6b":"Z","\ua762":"Z","\u24d0":"a","\uff41":"a","\u1e9a":"a","\xe0":"a","\xe1":"a","\xe2":"a","\u1ea7":"a","\u1ea5":"a","\u1eab":"a","\u1ea9":"a","\xe3":"a","\u0101":"a","\u0103":"a","\u1eb1":"a","\u1eaf":"a","\u1eb5":"a","\u1eb3":"a","\u0227":"a","\u01e1":"a","\xe4":"a","\u01df":"a","\u1ea3":"a","\xe5":"a","\u01fb":"a","\u01ce":"a","\u0201":"a","\u0203":"a","\u1ea1":"a","\u1ead":"a","\u1eb7":"a","\u1e01":"a","\u0105":"a","\u2c65":"a","\u0250":"a","\ua733":"aa","\xe6":"ae","\u01fd":"ae","\u01e3":"ae","\ua735":"ao","\ua737":"au","\ua739":"av","\ua73b":"av","\ua73d":"ay","\u24d1":"b","\uff42":"b","\u1e03":"b","\u1e05":"b","\u1e07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24d2":"c","\uff43":"c","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\xe7":"c","\u1e09":"c","\u0188":"c","\u023c":"c","\ua73f":"c","\u2184":"c","\u24d3":"d","\uff44":"d","\u1e0b":"d","\u010f":"d","\u1e0d":"d","\u1e11":"d","\u1e13":"d","\u1e0f":"d","\u0111":"d","\u018c":"d","\u0256":"d","\u0257":"d","\ua77a":"d","\u01f3":"dz","\u01c6":"dz","\u24d4":"e","\uff45":"e","\xe8":"e","\xe9":"e","\xea":"e","\u1ec1":"e","\u1ebf":"e","\u1ec5":"e","\u1ec3":"e","\u1ebd":"e","\u0113":"e","\u1e15":"e","\u1e17":"e","\u0115":"e","\u0117":"e","\xeb":"e","\u1ebb":"e","\u011b":"e","\u0205":"e","\u0207":"e","\u1eb9":"e","\u1ec7":"e","\u0229":"e","\u1e1d":"e","\u0119":"e","\u1e19":"e","\u1e1b":"e","\u0247":"e","\u025b":"e","\u01dd":"e","\u24d5":"f","\uff46":"f","\u1e1f":"f","\u0192":"f","\ua77c":"f","\u24d6":"g","\uff47":"g","\u01f5":"g","\u011d":"g","\u1e21":"g","\u011f":"g","\u0121":"g","\u01e7":"g","\u0123":"g","\u01e5":"g","\u0260":"g","\ua7a1":"g","\u1d79":"g","\ua77f":"g","\u24d7":"h","\uff48":"h","\u0125":"h","\u1e23":"h","\u1e27":"h","\u021f":"h","\u1e25":"h","\u1e29":"h","\u1e2b":"h","\u1e96":"h","\u0127":"h","\u2c68":"h","\u2c76":"h","\u0265":"h","\u0195":"hv","\u24d8":"i","\uff49":"i","\xec":"i","\xed":"i","\xee":"i","\u0129":"i","\u012b":"i","\u012d":"i","\xef":"i","\u1e2f":"i","\u1ec9":"i","\u01d0":"i","\u0209":"i","\u020b":"i","\u1ecb":"i","\u012f":"i","\u1e2d":"i","\u0268":"i","\u0131":"i","\u24d9":"j","\uff4a":"j","\u0135":"j","\u01f0":"j","\u0249":"j","\u24da":"k","\uff4b":"k","\u1e31":"k","\u01e9":"k","\u1e33":"k","\u0137":"k","\u1e35":"k","\u0199":"k","\u2c6a":"k","\ua741":"k","\ua743":"k","\ua745":"k","\ua7a3":"k","\u24db":"l","\uff4c":"l","\u0140":"l","\u013a":"l","\u013e":"l","\u1e37":"l","\u1e39":"l","\u013c":"l","\u1e3d":"l","\u1e3b":"l","\u017f":"l","\u0142":"l","\u019a":"l","\u026b":"l","\u2c61":"l","\ua749":"l","\ua781":"l","\ua747":"l","\u01c9":"lj","\u24dc":"m","\uff4d":"m","\u1e3f":"m","\u1e41":"m","\u1e43":"m","\u0271":"m","\u026f":"m","\u24dd":"n","\uff4e":"n","\u01f9":"n","\u0144":"n","\xf1":"n","\u1e45":"n","\u0148":"n","\u1e47":"n","\u0146":"n","\u1e4b":"n","\u1e49":"n","\u019e":"n","\u0272":"n","\u0149":"n","\ua791":"n","\ua7a5":"n","\u01cc":"nj","\u24de":"o","\uff4f":"o","\xf2":"o","\xf3":"o","\xf4":"o","\u1ed3":"o","\u1ed1":"o","\u1ed7":"o","\u1ed5":"o","\xf5":"o","\u1e4d":"o","\u022d":"o","\u1e4f":"o","\u014d":"o","\u1e51":"o","\u1e53":"o","\u014f":"o","\u022f":"o","\u0231":"o","\xf6":"o","\u022b":"o","\u1ecf":"o","\u0151":"o","\u01d2":"o","\u020d":"o","\u020f":"o","\u01a1":"o","\u1edd":"o","\u1edb":"o","\u1ee1":"o","\u1edf":"o","\u1ee3":"o","\u1ecd":"o","\u1ed9":"o","\u01eb":"o","\u01ed":"o","\xf8":"o","\u01ff":"o","\u0254":"o","\ua74b":"o","\ua74d":"o","\u0275":"o","\u01a3":"oi","\u0223":"ou","\ua74f":"oo","\u24df":"p","\uff50":"p","\u1e55":"p","\u1e57":"p","\u01a5":"p","\u1d7d":"p","\ua751":"p","\ua753":"p","\ua755":"p","\u24e0":"q","\uff51":"q","\u024b":"q","\ua757":"q","\ua759":"q","\u24e1":"r","\uff52":"r","\u0155":"r","\u1e59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1e5b":"r","\u1e5d":"r","\u0157":"r","\u1e5f":"r","\u024d":"r","\u027d":"r","\ua75b":"r","\ua7a7":"r","\ua783":"r","\u24e2":"s","\uff53":"s","\xdf":"s","\u015b":"s","\u1e65":"s","\u015d":"s","\u1e61":"s","\u0161":"s","\u1e67":"s","\u1e63":"s","\u1e69":"s","\u0219":"s","\u015f":"s","\u023f":"s","\ua7a9":"s","\ua785":"s","\u1e9b":"s","\u24e3":"t","\uff54":"t","\u1e6b":"t","\u1e97":"t","\u0165":"t","\u1e6d":"t","\u021b":"t","\u0163":"t","\u1e71":"t","\u1e6f":"t","\u0167":"t","\u01ad":"t","\u0288":"t","\u2c66":"t","\ua787":"t","\ua729":"tz","\u24e4":"u","\uff55":"u","\xf9":"u","\xfa":"u","\xfb":"u","\u0169":"u","\u1e79":"u","\u016b":"u","\u1e7b":"u","\u016d":"u","\xfc":"u","\u01dc":"u","\u01d8":"u","\u01d6":"u","\u01da":"u","\u1ee7":"u","\u016f":"u","\u0171":"u","\u01d4":"u","\u0215":"u","\u0217":"u","\u01b0":"u","\u1eeb":"u","\u1ee9":"u","\u1eef":"u","\u1eed":"u","\u1ef1":"u","\u1ee5":"u","\u1e73":"u","\u0173":"u","\u1e77":"u","\u1e75":"u","\u0289":"u","\u24e5":"v","\uff56":"v","\u1e7d":"v","\u1e7f":"v","\u028b":"v","\ua75f":"v","\u028c":"v","\ua761":"vy","\u24e6":"w","\uff57":"w","\u1e81":"w","\u1e83":"w","\u0175":"w","\u1e87":"w","\u1e85":"w","\u1e98":"w","\u1e89":"w","\u2c73":"w","\u24e7":"x","\uff58":"x","\u1e8b":"x","\u1e8d":"x","\u24e8":"y","\uff59":"y","\u1ef3":"y","\xfd":"y","\u0177":"y","\u1ef9":"y","\u0233":"y","\u1e8f":"y","\xff":"y","\u1ef7":"y","\u1e99":"y","\u1ef5":"y","\u01b4":"y","\u024f":"y","\u1eff":"y","\u24e9":"z","\uff5a":"z","\u017a":"z","\u1e91":"z","\u017c":"z","\u017e":"z","\u1e93":"z","\u1e95":"z","\u01b6":"z","\u0225":"z","\u0240":"z","\u2c6c":"z","\ua763":"z","\u0386":"\u0391","\u0388":"\u0395","\u0389":"\u0397","\u038a":"\u0399","\u03aa":"\u0399","\u038c":"\u039f","\u038e":"\u03a5","\u03ab":"\u03a5","\u038f":"\u03a9","\u03ac":"\u03b1","\u03ad":"\u03b5","\u03ae":"\u03b7","\u03af":"\u03b9","\u03ca":"\u03b9","\u0390":"\u03b9","\u03cc":"\u03bf","\u03cd":"\u03c5","\u03cb":"\u03c5","\u03b0":"\u03c5","\u03c9":"\u03c9","\u03c2":"\u03c3"};i=a(document),f=function(){var a=1;return function(){return a++}}(),c=O(Object,{bind:function(a){var b=this;return function(){a.apply(b,arguments)}},init:function(c){var d,e,g=".select2-results";this.opts=c=this.prepareOpts(c),this.id=c.id,c.element.data("select2")!==b&&null!==c.element.data("select2")&&c.element.data("select2").destroy(),this.container=this.createContainer(),this.liveRegion=a(".select2-hidden-accessible"),0==this.liveRegion.length&&(this.liveRegion=a("",{role:"status","aria-live":"polite"}).addClass("select2-hidden-accessible").appendTo(document.body)),this.containerId="s2id_"+(c.element.attr("id")||"autogen"+f()),this.containerEventName=this.containerId.replace(/([.])/g,"_").replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1"),this.container.attr("id",this.containerId),this.container.attr("title",c.element.attr("title")),this.body=a(document.body),D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.attr("style",c.element.attr("style")),this.container.css(K(c.containerCss,this.opts.element)),this.container.addClass(K(c.containerCssClass,this.opts.element)),this.elementTabIndex=this.opts.element.attr("tabindex"),this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container).on("click.select2",A),this.container.data("select2",this),this.dropdown=this.container.find(".select2-drop"),D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(c.dropdownCssClass,this.opts.element)),this.dropdown.data("select2",this),this.dropdown.on("click",A),this.results=d=this.container.find(g),this.search=e=this.container.find("input.select2-input"),this.queryCount=0,this.resultsPage=0,this.context=null,this.initContainer(),this.container.on("click",A),v(this.results),this.dropdown.on("mousemove-filtered",g,this.bind(this.highlightUnderEvent)),this.dropdown.on("touchstart touchmove touchend",g,this.bind(function(a){this._touchEvent=!0,this.highlightUnderEvent(a)})),this.dropdown.on("touchmove",g,this.bind(this.touchMoved)),this.dropdown.on("touchstart touchend",g,this.bind(this.clearTouchMoved)),this.dropdown.on("click",this.bind(function(){this._touchEvent&&(this._touchEvent=!1,this.selectHighlighted())})),x(80,this.results),this.dropdown.on("scroll-debounced",g,this.bind(this.loadMoreIfNeeded)),a(this.container).on("change",".select2-input",function(a){a.stopPropagation()}),a(this.dropdown).on("change",".select2-input",function(a){a.stopPropagation()}),a.fn.mousewheel&&d.mousewheel(function(a,b,c,e){var f=d.scrollTop();e>0&&0>=f-e?(d.scrollTop(0),A(a)):0>e&&d.get(0).scrollHeight-d.scrollTop()+e<=d.height()&&(d.scrollTop(d.get(0).scrollHeight-d.height()),A(a))}),u(e),e.on("keyup-change input paste",this.bind(this.updateResults)),e.on("focus",function(){e.addClass("select2-focused")}),e.on("blur",function(){e.removeClass("select2-focused")}),this.dropdown.on("mouseup",g,this.bind(function(b){a(b.target).closest(".select2-result-selectable").length>0&&(this.highlightUnderEvent(b),this.selectHighlighted(b))})),this.dropdown.on("click mouseup mousedown touchstart touchend focusin",function(a){a.stopPropagation()}),this.nextSearchTerm=b,a.isFunction(this.opts.initSelection)&&(this.initSelection(),this.monitorSource()),null!==c.maximumInputLength&&this.search.attr("maxlength",c.maximumInputLength);var h=c.element.prop("disabled");h===b&&(h=!1),this.enable(!h);var i=c.element.prop("readonly");i===b&&(i=!1),this.readonly(i),j=j||q(),this.autofocus=c.element.prop("autofocus"),c.element.prop("autofocus",!1),this.autofocus&&this.focus(),this.search.attr("placeholder",c.searchInputPlaceholder)},destroy:function(){var a=this.opts.element,c=a.data("select2"),d=this;this.close(),a.length&&a[0].detachEvent&&d._sync&&a.each(function(){d._sync&&this.detachEvent("onpropertychange",d._sync)}),this.propertyObserver&&(this.propertyObserver.disconnect(),this.propertyObserver=null),this._sync=null,c!==b&&(c.container.remove(),c.liveRegion.remove(),c.dropdown.remove(),a.show().removeData("select2").off(".select2").prop("autofocus",this.autofocus||!1),this.elementTabIndex?a.attr({tabindex:this.elementTabIndex}):a.removeAttr("tabindex"),a.show()),N.call(this,"container","liveRegion","dropdown","results","search")},optionToData:function(a){return a.is("option")?{id:a.prop("value"),text:a.text(),element:a.get(),css:a.attr("class"),disabled:a.prop("disabled"),locked:r(a.attr("locked"),"locked")||r(a.data("locked"),!0)}:a.is("optgroup")?{text:a.attr("label"),children:[],element:a.get(),css:a.attr("class")}:void 0},prepareOpts:function(c){var d,e,g,h,i=this;if(d=c.element,"select"===d.get(0).tagName.toLowerCase()&&(this.select=e=c.element),e&&a.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in c)throw new Error("Option '"+this+"' is not allowed for Select2 when attached to a element.")}),c=a.extend({},{populateResults:function(d,e,g){var h,j=this.opts.id,k=this.liveRegion;h=function(d,e,l){var m,n,o,p,q,r,s,t,u,v;d=c.sortResults(d,e,g);var w=[];for(m=0,n=d.length;n>m;m+=1)o=d[m],q=o.disabled===!0,p=!q&&j(o)!==b,r=o.children&&o.children.length>0,s=a(" "),s.addClass("select2-results-dept-"+l),s.addClass("select2-result"),s.addClass(p?"select2-result-selectable":"select2-result-unselectable"),q&&s.addClass("select2-disabled"),r&&s.addClass("select2-result-with-children"),s.addClass(i.opts.formatResultCssClass(o)),s.attr("role","presentation"),t=a(document.createElement("div")),t.addClass("select2-result-label"),t.attr("id","select2-result-label-"+f()),t.attr("role","option"),v=c.formatResult(o,t,g,i.opts.escapeMarkup),v!==b&&(t.html(v),s.append(t)),r&&(u=a(""),u.addClass("select2-result-sub"),h(o.children,u,l+1),s.append(u)),s.data("select2-data",o),w.push(s[0]);e.append(w),k.text(c.formatMatches(d.length))},h(e,d,0)}},a.fn.select2.defaults,c),"function"!=typeof c.id&&(g=c.id,c.id=function(a){return a[g]}),a.isArray(c.element.data("select2Tags"))){if("tags"in c)throw"tags specified as both an attribute 'data-select2-tags' and in options of Select2 "+c.element.attr("id");c.tags=c.element.data("select2Tags")}if(e?(c.query=this.bind(function(a){var f,g,h,c={results:[],more:!1},e=a.term;h=function(b,c){var d;b.is("option")?a.matcher(e,b.text(),b)&&c.push(i.optionToData(b)):b.is("optgroup")&&(d=i.optionToData(b),b.children().each2(function(a,b){h(b,d.children)}),d.children.length>0&&c.push(d))},f=d.children(),this.getPlaceholder()!==b&&f.length>0&&(g=this.getPlaceholderOption(),g&&(f=f.not(g))),f.each2(function(a,b){h(b,c.results)}),a.callback(c)}),c.id=function(a){return a.id}):"query"in c||("ajax"in c?(h=c.element.data("ajax-url"),h&&h.length>0&&(c.ajax.url=h),c.query=G.call(c.element,c.ajax)):"data"in c?c.query=H(c.data):"tags"in c&&(c.query=I(c.tags),c.createSearchChoice===b&&(c.createSearchChoice=function(b){return{id:a.trim(b),text:a.trim(b)}}),c.initSelection===b&&(c.initSelection=function(b,d){var e=[];a(s(b.val(),c.separator,c.transformVal)).each(function(){var b={id:this,text:this},d=c.tags;a.isFunction(d)&&(d=d()),a(d).each(function(){return r(this.id,b.id)?(b=this,!1):void 0}),e.push(b)}),d(e)}))),"function"!=typeof c.query)throw"query function not defined for Select2 "+c.element.attr("id");if("top"===c.createSearchChoicePosition)c.createSearchChoicePosition=function(a,b){a.unshift(b)};else if("bottom"===c.createSearchChoicePosition)c.createSearchChoicePosition=function(a,b){a.push(b)};else if("function"!=typeof c.createSearchChoicePosition)throw"invalid createSearchChoicePosition option must be 'top', 'bottom' or a custom function";return c},monitorSource:function(){var d,c=this.opts.element,e=this;c.on("change.select2",this.bind(function(){this.opts.element.data("select2-change-triggered")!==!0&&this.initSelection()})),this._sync=this.bind(function(){var a=c.prop("disabled");a===b&&(a=!1),this.enable(!a);var d=c.prop("readonly");d===b&&(d=!1),this.readonly(d),this.container&&(D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.addClass(K(this.opts.containerCssClass,this.opts.element))),this.dropdown&&(D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(this.opts.dropdownCssClass,this.opts.element)))}),c.length&&c[0].attachEvent&&c.each(function(){this.attachEvent("onpropertychange",e._sync)}),d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver,d!==b&&(this.propertyObserver&&(delete this.propertyObserver,this.propertyObserver=null),this.propertyObserver=new d(function(b){a.each(b,e._sync)}),this.propertyObserver.observe(c.get(0),{attributes:!0,subtree:!1}))},triggerSelect:function(b){var c=a.Event("select2-selecting",{val:this.id(b),object:b,choice:b});return this.opts.element.trigger(c),!c.isDefaultPrevented()},triggerChange:function(b){b=b||{},b=a.extend({},b,{type:"change",val:this.val()}),this.opts.element.data("select2-change-triggered",!0),this.opts.element.trigger(b),this.opts.element.data("select2-change-triggered",!1),this.opts.element.click(),this.opts.blurOnChange&&this.opts.element.blur()},isInterfaceEnabled:function(){return this.enabledInterface===!0},enableInterface:function(){var a=this._enabled&&!this._readonly,b=!a;return a===this.enabledInterface?!1:(this.container.toggleClass("select2-container-disabled",b),this.close(),this.enabledInterface=a,!0)},enable:function(a){a===b&&(a=!0),this._enabled!==a&&(this._enabled=a,this.opts.element.prop("disabled",!a),this.enableInterface())},disable:function(){this.enable(!1)},readonly:function(a){a===b&&(a=!1),this._readonly!==a&&(this._readonly=a,this.opts.element.prop("readonly",a),this.enableInterface())},opened:function(){return this.container?this.container.hasClass("select2-dropdown-open"):!1},positionDropdown:function(){var v,w,x,y,z,b=this.dropdown,c=this.container,d=c.offset(),e=c.outerHeight(!1),f=c.outerWidth(!1),g=b.outerHeight(!1),h=a(window),i=h.width(),k=h.height(),l=h.scrollLeft()+i,m=h.scrollTop()+k,n=d.top+e,o=d.left,p=m>=n+g,q=d.top-g>=h.scrollTop(),r=b.outerWidth(!1),s=function(){return l>=o+r},t=function(){return d.left+l+c.outerWidth(!1)>r},u=b.hasClass("select2-drop-above");u?(w=!0,!q&&p&&(x=!0,w=!1)):(w=!1,!p&&q&&(x=!0,w=!0)),x&&(b.hide(),d=this.container.offset(),e=this.container.outerHeight(!1),f=this.container.outerWidth(!1),g=b.outerHeight(!1),l=h.scrollLeft()+i,m=h.scrollTop()+k,n=d.top+e,o=d.left,r=b.outerWidth(!1),b.show(),this.focusSearch()),this.opts.dropdownAutoWidth?(z=a(".select2-results",b)[0],b.addClass("select2-drop-auto-width"),b.css("width",""),r=b.outerWidth(!1)+(z.scrollHeight===z.clientHeight?0:j.width),r>f?f=r:r=f,g=b.outerHeight(!1)):this.container.removeClass("select2-drop-auto-width"),"static"!==this.body.css("position")&&(v=this.body.offset(),n-=v.top,o-=v.left),!s()&&t()&&(o=d.left+this.container.outerWidth(!1)-r),y={left:o,width:f},w?(y.top=d.top-g,y.bottom="auto",this.container.addClass("select2-drop-above"),b.addClass("select2-drop-above")):(y.top=n,y.bottom="auto",this.container.removeClass("select2-drop-above"),b.removeClass("select2-drop-above")),y=a.extend(y,K(this.opts.dropdownCss,this.opts.element)),b.css(y)},shouldOpen:function(){var b;return this.opened()?!1:this._enabled===!1||this._readonly===!0?!1:(b=a.Event("select2-opening"),this.opts.element.trigger(b),!b.isDefaultPrevented())},clearDropdownAlignmentPreference:function(){this.container.removeClass("select2-drop-above"),this.dropdown.removeClass("select2-drop-above")},open:function(){return this.shouldOpen()?(this.opening(),i.on("mousemove.select2Event",function(a){h.x=a.pageX,h.y=a.pageY}),!0):!1},opening:function(){var f,b=this.containerEventName,c="scroll."+b,d="resize."+b,e="orientationchange."+b;this.container.addClass("select2-dropdown-open").addClass("select2-container-active"),this.clearDropdownAlignmentPreference(),this.dropdown[0]!==this.body.children().last()[0]&&this.dropdown.detach().appendTo(this.body),f=a("#select2-drop-mask"),0===f.length&&(f=a(document.createElement("div")),f.attr("id","select2-drop-mask").attr("class","select2-drop-mask"),f.hide(),f.appendTo(this.body),f.on("mousedown touchstart click",function(b){n(f);var d,c=a("#select2-drop");c.length>0&&(d=c.data("select2"),d.opts.selectOnBlur&&d.selectHighlighted({noFocus:!0}),d.close(),b.preventDefault(),b.stopPropagation())})),this.dropdown.prev()[0]!==f[0]&&this.dropdown.before(f),a("#select2-drop").removeAttr("id"),this.dropdown.attr("id","select2-drop"),f.show(),this.positionDropdown(),this.dropdown.show(),this.positionDropdown(),this.dropdown.addClass("select2-drop-active");var g=this;this.container.parents().add(window).each(function(){a(this).on(d+" "+c+" "+e,function(){g.opened()&&g.positionDropdown()})})},close:function(){if(this.opened()){var b=this.containerEventName,c="scroll."+b,d="resize."+b,e="orientationchange."+b;this.container.parents().add(window).each(function(){a(this).off(c).off(d).off(e)}),this.clearDropdownAlignmentPreference(),a("#select2-drop-mask").hide(),this.dropdown.removeAttr("id"),this.dropdown.hide(),this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"),this.results.empty(),i.off("mousemove.select2Event"),this.clearSearch(),this.search.removeClass("select2-active"),this.opts.element.trigger(a.Event("select2-close"))}},externalSearch:function(a){this.open(),this.search.val(a),this.updateResults(!1)},clearSearch:function(){},getMaximumSelectionSize:function(){return K(this.opts.maximumSelectionSize,this.opts.element)},ensureHighlightVisible:function(){var c,d,e,f,g,h,i,j,b=this.results;if(d=this.highlight(),!(0>d)){if(0==d)return b.scrollTop(0),void 0;c=this.findHighlightableChoices().find(".select2-result-label"),e=a(c[d]),j=(e.offset()||{}).top||0,f=j+e.outerHeight(!0),d===c.length-1&&(i=b.find("li.select2-more-results"),i.length>0&&(f=i.offset().top+i.outerHeight(!0))),g=b.offset().top+b.outerHeight(!1),f>g&&b.scrollTop(b.scrollTop()+(f-g)),h=j-b.offset().top,0>h&&"none"!=e.css("display")&&b.scrollTop(b.scrollTop()+h)}},findHighlightableChoices:function(){return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)")},moveHighlight:function(b){for(var c=this.findHighlightableChoices(),d=this.highlight();d>-1&&d=c.length&&(b=c.length-1),0>b&&(b=0),this.removeHighlight(),d=a(c[b]),d.addClass("select2-highlighted"),this.search.attr("aria-activedescendant",d.find(".select2-result-label").attr("id")),this.ensureHighlightVisible(),this.liveRegion.text(d.text()),e=d.data("select2-data"),e&&this.opts.element.trigger({type:"select2-highlight",val:this.id(e),choice:e}),void 0)},removeHighlight:function(){this.results.find(".select2-highlighted").removeClass("select2-highlighted")},touchMoved:function(){this._touchMoved=!0},clearTouchMoved:function(){this._touchMoved=!1},countSelectableResults:function(){return this.findHighlightableChoices().length},highlightUnderEvent:function(b){var c=a(b.target).closest(".select2-result-selectable");if(c.length>0&&!c.is(".select2-highlighted")){var d=this.findHighlightableChoices();this.highlight(d.index(c))}else 0==c.length&&this.removeHighlight()},loadMoreIfNeeded:function(){var c,a=this.results,b=a.find("li.select2-more-results"),d=this.resultsPage+1,e=this,f=this.search.val(),g=this.context;0!==b.length&&(c=b.offset().top-a.offset().top-a.height(),c<=this.opts.loadMorePadding&&(b.addClass("select2-active"),this.opts.query({element:this.opts.element,term:f,page:d,context:g,matcher:this.opts.matcher,callback:this.bind(function(c){e.opened()&&(e.opts.populateResults.call(this,a,c.results,{term:f,page:d,context:g}),e.postprocessResults(c,!1,!1),c.more===!0?(b.detach().appendTo(a).html(e.opts.escapeMarkup(K(e.opts.formatLoadMore,e.opts.element,d+1))),window.setTimeout(function(){e.loadMoreIfNeeded()},10)):b.remove(),e.positionDropdown(),e.resultsPage=d,e.context=c.context,this.opts.element.trigger({type:"select2-loaded",items:c}))})})))},tokenize:function(){},updateResults:function(c){function m(){d.removeClass("select2-active"),h.positionDropdown(),e.find(".select2-no-results,.select2-selection-limit,.select2-searching").length?h.liveRegion.text(e.text()):h.liveRegion.text(h.opts.formatMatches(e.find('.select2-result-selectable:not(".select2-selected")').length))}function n(a){e.html(a),m()}var g,i,l,d=this.search,e=this.results,f=this.opts,h=this,j=d.val(),k=a.data(this.container,"select2-last-term");if((c===!0||!k||!r(j,k))&&(a.data(this.container,"select2-last-term",j),c===!0||this.showSearchInput!==!1&&this.opened())){l=++this.queryCount;var o=this.getMaximumSelectionSize();if(o>=1&&(g=this.data(),a.isArray(g)&&g.length>=o&&J(f.formatSelectionTooBig,"formatSelectionTooBig")))return n(""+K(f.formatSelectionTooBig,f.element,o)+" "),void 0;if(d.val().length"+K(f.formatInputTooShort,f.element,d.val(),f.minimumInputLength)+""):n(""),c&&this.showSearch&&this.showSearch(!0),void 0;if(f.maximumInputLength&&d.val().length>f.maximumInputLength)return J(f.formatInputTooLong,"formatInputTooLong")?n(""+K(f.formatInputTooLong,f.element,d.val(),f.maximumInputLength)+" "):n(""),void 0;f.formatSearching&&0===this.findHighlightableChoices().length&&n(""+K(f.formatSearching,f.element)+" "),d.addClass("select2-active"),this.removeHighlight(),i=this.tokenize(),i!=b&&null!=i&&d.val(i),this.resultsPage=1,f.query({element:f.element,term:d.val(),page:this.resultsPage,context:null,matcher:f.matcher,callback:this.bind(function(g){var i;if(l==this.queryCount){if(!this.opened())return this.search.removeClass("select2-active"),void 0;if(g.hasError!==b&&J(f.formatAjaxError,"formatAjaxError"))return n(""+K(f.formatAjaxError,f.element,g.jqXHR,g.textStatus,g.errorThrown)+" "),void 0;if(this.context=g.context===b?null:g.context,this.opts.createSearchChoice&&""!==d.val()&&(i=this.opts.createSearchChoice.call(h,d.val(),g.results),i!==b&&null!==i&&h.id(i)!==b&&null!==h.id(i)&&0===a(g.results).filter(function(){return r(h.id(this),h.id(i))}).length&&this.opts.createSearchChoicePosition(g.results,i)),0===g.results.length&&J(f.formatNoMatches,"formatNoMatches"))return n(""+K(f.formatNoMatches,f.element,d.val())+" "),void 0;e.empty(),h.opts.populateResults.call(this,e,g.results,{term:d.val(),page:this.resultsPage,context:null}),g.more===!0&&J(f.formatLoadMore,"formatLoadMore")&&(e.append(""+f.escapeMarkup(K(f.formatLoadMore,f.element,this.resultsPage))+" "),window.setTimeout(function(){h.loadMoreIfNeeded()},10)),this.postprocessResults(g,c),m(),this.opts.element.trigger({type:"select2-loaded",items:g})}})})}},cancel:function(){this.close()},blur:function(){this.opts.selectOnBlur&&this.selectHighlighted({noFocus:!0}),this.close(),this.container.removeClass("select2-container-active"),this.search[0]===document.activeElement&&this.search.blur(),this.clearSearch(),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus")},focusSearch:function(){y(this.search)},selectHighlighted:function(a){if(this._touchMoved)return this.clearTouchMoved(),void 0;var b=this.highlight(),c=this.results.find(".select2-highlighted"),d=c.closest(".select2-result").data("select2-data");d?(this.highlight(b),this.onSelect(d,a)):a&&a.noFocus&&this.close()},getPlaceholder:function(){var a;return this.opts.element.attr("placeholder")||this.opts.element.attr("data-placeholder")||this.opts.element.data("placeholder")||this.opts.placeholder||((a=this.getPlaceholderOption())!==b?a.text():b)},getPlaceholderOption:function(){if(this.select){var c=this.select.children("option").first();if(this.opts.placeholderOption!==b)return"first"===this.opts.placeholderOption&&c||"function"==typeof this.opts.placeholderOption&&this.opts.placeholderOption(this.select);if(""===a.trim(c.text())&&""===c.val())return c}},initContainerWidth:function(){function c(){var c,d,e,f,g,h;if("off"===this.opts.width)return null;if("element"===this.opts.width)return 0===this.opts.element.outerWidth(!1)?"auto":this.opts.element.outerWidth(!1)+"px";if("copy"===this.opts.width||"resolve"===this.opts.width){if(c=this.opts.element.attr("style"),c!==b)for(d=c.split(";"),f=0,g=d.length;g>f;f+=1)if(h=d[f].replace(/\s/g,""),e=h.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i),null!==e&&e.length>=1)return e[1];return"resolve"===this.opts.width?(c=this.opts.element.css("width"),c.indexOf("%")>0?c:0===this.opts.element.outerWidth(!1)?"auto":this.opts.element.outerWidth(!1)+"px"):null}return a.isFunction(this.opts.width)?this.opts.width():this.opts.width}var d=c.call(this);null!==d&&this.container.css("width",d)}}),d=O(c,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container"}).html([""," "," "," "," "," ",""].join(""));return b},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.focusser.prop("disabled",!this.isInterfaceEnabled())},opening:function(){var c,d,e;this.opts.minimumResultsForSearch>=0&&this.showSearch(!0),this.parent.opening.apply(this,arguments),this.showSearchInput!==!1&&this.search.val(this.focusser.val()),this.opts.shouldFocusInput(this)&&(this.search.focus(),c=this.search.get(0),c.createTextRange?(d=c.createTextRange(),d.collapse(!1),d.select()):c.setSelectionRange&&(e=this.search.val().length,c.setSelectionRange(e,e))),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.focusser.prop("disabled",!0).val(""),this.updateResults(!0),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&(this.parent.close.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},focus:function(){this.opened()?this.close():(this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus()},destroy:function(){a("label[for='"+this.focusser.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments),N.call(this,"selection","focusser")},initContainer:function(){var b,g,c=this.container,d=this.dropdown,e=f();this.opts.minimumResultsForSearch<0?this.showSearch(!1):this.showSearch(!0),this.selection=b=c.find(".select2-choice"),this.focusser=c.find(".select2-focusser"),b.find(".select2-chosen").attr("id","select2-chosen-"+e),this.focusser.attr("aria-labelledby","select2-chosen-"+e),this.results.attr("id","select2-results-"+e),this.search.attr("aria-owns","select2-results-"+e),this.focusser.attr("id","s2id_autogen"+e),g=a("label[for='"+this.opts.element.attr("id")+"']"),this.opts.element.focus(this.bind(function(){this.focus()})),this.focusser.prev().text(g.text()).attr("for",this.focusser.attr("id"));var h=this.opts.element.attr("title");this.opts.element.attr("title",h||g.text()),this.focusser.attr("tabindex",this.elementTabIndex),this.search.attr("id",this.focusser.attr("id")+"_search"),this.search.prev().text(a("label[for='"+this.focusser.attr("id")+"']").text()).attr("for",this.search.attr("id")),this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&229!=a.keyCode){if(a.which===k.PAGE_UP||a.which===k.PAGE_DOWN)return A(a),void 0;switch(a.which){case k.UP:case k.DOWN:return this.moveHighlight(a.which===k.UP?-1:1),A(a),void 0;case k.ENTER:return this.selectHighlighted(),A(a),void 0;case k.TAB:return this.selectHighlighted({noFocus:!0}),void 0;case k.ESC:return this.cancel(a),A(a),void 0}}})),this.search.on("blur",this.bind(function(){document.activeElement===this.body.get(0)&&window.setTimeout(this.bind(function(){this.opened()&&this.search.focus()}),0)})),this.focusser.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&a.which!==k.TAB&&!k.isControl(a)&&!k.isFunctionKey(a)&&a.which!==k.ESC){if(this.opts.openOnEnter===!1&&a.which===k.ENTER)return A(a),void 0;if(a.which==k.DOWN||a.which==k.UP||a.which==k.ENTER&&this.opts.openOnEnter){if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return;return this.open(),A(a),void 0}return a.which==k.DELETE||a.which==k.BACKSPACE?(this.opts.allowClear&&this.clear(),A(a),void 0):void 0}})),u(this.focusser),this.focusser.on("keyup-change input",this.bind(function(a){if(this.opts.minimumResultsForSearch>=0){if(a.stopPropagation(),this.opened())return;this.open()}})),b.on("mousedown touchstart","abbr",this.bind(function(a){this.isInterfaceEnabled()&&(this.clear(),B(a),this.close(),this.selection&&this.selection.focus())})),b.on("mousedown touchstart",this.bind(function(c){n(b),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.opened()?this.close():this.isInterfaceEnabled()&&this.open(),A(c)})),d.on("mousedown touchstart",this.bind(function(){this.opts.shouldFocusInput(this)&&this.search.focus()})),b.on("focus",this.bind(function(a){A(a)})),this.focusser.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){this.opened()||(this.container.removeClass("select2-container-active"),this.opts.element.trigger(a.Event("select2-blur")))})),this.search.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})),this.initContainerWidth(),this.opts.element.hide(),this.setPlaceholder()},clear:function(b){var c=this.selection.data("select2-data");if(c){var d=a.Event("select2-clearing");if(this.opts.element.trigger(d),d.isDefaultPrevented())return;var e=this.getPlaceholderOption();this.opts.element.val(e?e.val():""),this.selection.find(".select2-chosen").empty(),this.selection.removeData("select2-data"),this.setPlaceholder(),b!==!1&&(this.opts.element.trigger({type:"select2-removed",val:this.id(c),choice:c}),this.triggerChange({removed:c}))}},initSelection:function(){if(this.isPlaceholderOptionSelected())this.updateSelection(null),this.close(),this.setPlaceholder();else{var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.setPlaceholder(),c.nextSearchTerm=c.opts.nextSearchTerm(a,c.search.val()))})}},isPlaceholderOptionSelected:function(){var a;return this.getPlaceholder()===b?!1:(a=this.getPlaceholderOption())!==b&&a.prop("selected")||""===this.opts.element.val()||this.opts.element.val()===b||null===this.opts.element.val()},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=a.find("option").filter(function(){return this.selected&&!this.disabled});b(c.optionToData(d))}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=c.val(),f=null;b.query({matcher:function(a,c,d){var g=r(e,b.id(d));return g&&(f=d),g},callback:a.isFunction(d)?function(){d(f)}:a.noop})}),b},getPlaceholder:function(){return this.select&&this.getPlaceholderOption()===b?b:this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var a=this.getPlaceholder();if(this.isPlaceholderOptionSelected()&&a!==b){if(this.select&&this.getPlaceholderOption()===b)return;this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(a)),this.selection.addClass("select2-default"),this.container.removeClass("select2-allowclear")}},postprocessResults:function(a,b,c){var d=0,e=this;if(this.findHighlightableChoices().each2(function(a,b){return r(e.id(b.data("select2-data")),e.opts.element.val())?(d=a,!1):void 0}),c!==!1&&(b===!0&&d>=0?this.highlight(d):this.highlight(0)),b===!0){var g=this.opts.minimumResultsForSearch;g>=0&&this.showSearch(L(a.results)>=g)}},showSearch:function(b){this.showSearchInput!==b&&(this.showSearchInput=b,this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!b),this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!b),a(this.dropdown,this.container).toggleClass("select2-with-searchbox",b))},onSelect:function(a,b){if(this.triggerSelect(a)){var c=this.opts.element.val(),d=this.data();this.opts.element.val(this.id(a)),this.updateSelection(a),this.opts.element.trigger({type:"select2-selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.close(),b&&b.noFocus||!this.opts.shouldFocusInput(this)||this.focusser.focus(),r(c,this.id(a))||this.triggerChange({added:a,removed:d})}},updateSelection:function(a){var d,e,c=this.selection.find(".select2-chosen");this.selection.data("select2-data",a),c.empty(),null!==a&&(d=this.opts.formatSelection(a,c,this.opts.escapeMarkup)),d!==b&&c.append(d),e=this.opts.formatSelectionCssClass(a,c),e!==b&&c.addClass(e),this.selection.removeClass("select2-default"),this.opts.allowClear&&this.getPlaceholder()!==b&&this.container.addClass("select2-allowclear")},val:function(){var a,c=!1,d=null,e=this,f=this.data();if(0===arguments.length)return this.opts.element.val();if(a=arguments[0],arguments.length>1&&(c=arguments[1]),this.select)this.select.val(a).find("option").filter(function(){return this.selected}).each2(function(a,b){return d=e.optionToData(b),!1}),this.updateSelection(d),this.setPlaceholder(),c&&this.triggerChange({added:d,removed:f});else{if(!a&&0!==a)return this.clear(c),void 0;if(this.opts.initSelection===b)throw new Error("cannot call val() if initSelection() is not defined");this.opts.element.val(a),this.opts.initSelection(this.opts.element,function(a){e.opts.element.val(a?e.id(a):""),e.updateSelection(a),e.setPlaceholder(),c&&e.triggerChange({added:a,removed:f})})}},clearSearch:function(){this.search.val(""),this.focusser.val("")},data:function(a){var c,d=!1;return 0===arguments.length?(c=this.selection.data("select2-data"),c==b&&(c=null),c):(arguments.length>1&&(d=arguments[1]),a?(c=this.data(),this.opts.element.val(a?this.id(a):""),this.updateSelection(a),d&&this.triggerChange({added:a,removed:c})):this.clear(d),void 0)}}),e=O(c,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container select2-container-multi"}).html(["",""].join(""));return b},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=[];a.find("option").filter(function(){return this.selected&&!this.disabled}).each2(function(a,b){d.push(c.optionToData(b))}),b(d)}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=s(c.val(),b.separator,b.transformVal),f=[];b.query({matcher:function(c,d,g){var h=a.grep(e,function(a){return r(a,b.id(g))}).length;return h&&f.push(g),h},callback:a.isFunction(d)?function(){for(var a=[],c=0;c0||(this.selectChoice(null),this.clearPlaceholder(),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.open(),this.focusSearch(),b.preventDefault()))})),this.container.on("focus",b,this.bind(function(){this.isInterfaceEnabled()&&(this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"),this.clearPlaceholder())})),this.initContainerWidth(),this.opts.element.hide(),this.clearSearch()},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.search.prop("disabled",!this.isInterfaceEnabled())},initSelection:function(){if(""===this.opts.element.val()&&""===this.opts.element.text()&&(this.updateSelection([]),this.close(),this.clearSearch()),this.select||""!==this.opts.element.val()){var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.clearSearch())})}},clearSearch:function(){var a=this.getPlaceholder(),c=this.getMaxSearchWidth();a!==b&&0===this.getVal().length&&this.search.hasClass("select2-focused")===!1?(this.search.val(a).addClass("select2-default"),this.search.width(c>0?c:this.container.css("width"))):this.search.val("").width(10)},clearPlaceholder:function(){this.search.hasClass("select2-default")&&this.search.val("").removeClass("select2-default")},opening:function(){this.clearPlaceholder(),this.resizeSearch(),this.parent.opening.apply(this,arguments),this.focusSearch(),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.updateResults(!0),this.opts.shouldFocusInput(this)&&this.search.focus(),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&this.parent.close.apply(this,arguments)},focus:function(){this.close(),this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(b){var c=[],d=[],e=this;a(b).each(function(){p(e.id(this),c)<0&&(c.push(e.id(this)),d.push(this))}),b=d,this.selection.find(".select2-search-choice").remove(),a(b).each(function(){e.addSelectedChoice(this)}),e.postprocessResults()},tokenize:function(){var a=this.search.val();a=this.opts.tokenizer.call(this,a,this.data(),this.bind(this.onSelect),this.opts),null!=a&&a!=b&&(this.search.val(a),a.length>0&&this.open())},onSelect:function(a,c){this.triggerSelect(a)&&""!==a.text&&(this.addSelectedChoice(a),this.opts.element.trigger({type:"selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.clearSearch(),this.updateResults(),(this.select||!this.opts.closeOnSelect)&&this.postprocessResults(a,!1,this.opts.closeOnSelect===!0),this.opts.closeOnSelect?(this.close(),this.search.width(10)):this.countSelectableResults()>0?(this.search.width(10),this.resizeSearch(),this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()?this.updateResults(!0):this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.updateResults(),this.search.select()),this.positionDropdown()):(this.close(),this.search.width(10)),this.triggerChange({added:a}),c&&c.noFocus||this.focusSearch())},cancel:function(){this.close(),this.focusSearch()},addSelectedChoice:function(c){var j,k,d=!c.locked,e=a("
"),f=a("
"),g=d?e:f,h=this.id(c),i=this.getVal();j=this.opts.formatSelection(c,g.find("div"),this.opts.escapeMarkup),j!=b&&g.find("div").replaceWith(a("
").html(j)),k=this.opts.formatSelectionCssClass(c,g.find("div")),k!=b&&g.addClass(k),d&&g.find(".select2-search-choice-close").on("mousedown",A).on("click dblclick",this.bind(function(b){this.isInterfaceEnabled()&&(this.unselect(a(b.target)),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"),A(b),this.close(),this.focusSearch())})).on("focus",this.bind(function(){this.isInterfaceEnabled()&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"))})),g.data("select2-data",c),g.insertBefore(this.searchContainer),i.push(h),this.setVal(i)},unselect:function(b){var d,e,c=this.getVal();if(b=b.closest(".select2-search-choice"),0===b.length)throw"Invalid argument: "+b+". Must be .select2-search-choice";if(d=b.data("select2-data")){var f=a.Event("select2-removing");if(f.val=this.id(d),f.choice=d,this.opts.element.trigger(f),f.isDefaultPrevented())return!1;for(;(e=p(this.id(d),c))>=0;)c.splice(e,1),this.setVal(c),this.select&&this.postprocessResults();return b.remove(),this.opts.element.trigger({type:"select2-removed",val:this.id(d),choice:d}),this.triggerChange({removed:d}),!0}},postprocessResults:function(a,b,c){var d=this.getVal(),e=this.results.find(".select2-result"),f=this.results.find(".select2-result-with-children"),g=this;e.each2(function(a,b){var c=g.id(b.data("select2-data"));p(c,d)>=0&&(b.addClass("select2-selected"),b.find(".select2-result-selectable").addClass("select2-selected"))}),f.each2(function(a,b){b.is(".select2-result-selectable")||0!==b.find(".select2-result-selectable:not(.select2-selected)").length||b.addClass("select2-selected")}),-1==this.highlight()&&c!==!1&&this.opts.closeOnSelect===!0&&g.highlight(0),!this.opts.createSearchChoice&&!e.filter(".select2-result:not(.select2-selected)").length>0&&(!a||a&&!a.more&&0===this.results.find(".select2-no-results").length)&&J(g.opts.formatNoMatches,"formatNoMatches")&&this.results.append(""+K(g.opts.formatNoMatches,g.opts.element,g.search.val())+" ")},getMaxSearchWidth:function(){return this.selection.width()-t(this.search)},resizeSearch:function(){var a,b,c,d,e,f=t(this.search);a=C(this.search)+10,b=this.search.offset().left,c=this.selection.width(),d=this.selection.offset().left,e=c-(b-d)-f,a>e&&(e=c-f),40>e&&(e=c-f),0>=e&&(e=a),this.search.width(Math.floor(e))},getVal:function(){var a;return this.select?(a=this.select.val(),null===a?[]:a):(a=this.opts.element.val(),s(a,this.opts.separator,this.opts.transformVal))},setVal:function(b){var c;this.select?this.select.val(b):(c=[],a(b).each(function(){p(this,c)<0&&c.push(this)}),this.opts.element.val(0===c.length?"":c.join(this.opts.separator)))},buildChangeDetails:function(a,b){for(var b=b.slice(0),a=a.slice(0),c=0;c0&&c--,a.splice(d,1),d--);return{added:b,removed:a}},val:function(c,d){var e,f=this;if(0===arguments.length)return this.getVal();if(e=this.data(),e.length||(e=[]),!c&&0!==c)return this.opts.element.val(""),this.updateSelection([]),this.clearSearch(),d&&this.triggerChange({added:this.data(),removed:e}),void 0;if(this.setVal(c),this.select)this.opts.initSelection(this.select,this.bind(this.updateSelection)),d&&this.triggerChange(this.buildChangeDetails(e,this.data()));else{if(this.opts.initSelection===b)throw new Error("val() cannot be called if initSelection() is not defined");this.opts.initSelection(this.opts.element,function(b){var c=a.map(b,f.id);f.setVal(c),f.updateSelection(b),f.clearSearch(),d&&f.triggerChange(f.buildChangeDetails(e,f.data()))})}this.clearSearch()},onSortStart:function(){if(this.select)throw new Error("Sorting of elements is not supported when attached to . Attach to instead.");this.search.width(0),this.searchContainer.hide()},onSortEnd:function(){var b=[],c=this;this.searchContainer.show(),this.searchContainer.appendTo(this.searchContainer.parent()),this.resizeSearch(),this.selection.find(".select2-search-choice").each(function(){b.push(c.opts.id(a(this).data("select2-data")))}),this.setVal(b),this.triggerChange()},data:function(b,c){var e,f,d=this;return 0===arguments.length?this.selection.children(".select2-search-choice").map(function(){return a(this).data("select2-data")}).get():(f=this.data(),b||(b=[]),e=a.map(b,function(a){return d.opts.id(a)}),this.setVal(e),this.updateSelection(b),this.clearSearch(),c&&this.triggerChange(this.buildChangeDetails(f,this.data())),void 0)}}),a.fn.select2=function(){var d,e,f,g,h,c=Array.prototype.slice.call(arguments,0),i=["val","destroy","opened","open","close","focus","isFocused","container","dropdown","onSortStart","onSortEnd","enable","disable","readonly","positionDropdown","data","search"],j=["opened","isFocused","container","dropdown"],k=["val","data"],l={search:"externalSearch"};return this.each(function(){if(0===c.length||"object"==typeof c[0])d=0===c.length?{}:a.extend({},c[0]),d.element=a(this),"select"===d.element.get(0).tagName.toLowerCase()?h=d.element.prop("multiple"):(h=d.multiple||!1,"tags"in d&&(d.multiple=h=!0)),e=h?new window.Select2["class"].multi:new window.Select2["class"].single,e.init(d);else{if("string"!=typeof c[0])throw"Invalid arguments to select2 plugin: "+c;if(p(c[0],i)<0)throw"Unknown method: "+c[0];if(g=b,e=a(this).data("select2"),e===b)return;if(f=c[0],"container"===f?g=e.container:"dropdown"===f?g=e.dropdown:(l[f]&&(f=l[f]),g=e[f].apply(e,c.slice(1))),p(c[0],j)>=0||p(c[0],k)>=0&&1==c.length)return!1}}),g===b?this:g},a.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:!0,openOnEnter:!0,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(a,b,c,d){var e=[];return E(this.text(a),c.term,e,d),e.join("")},transformVal:function(b){return a.trim(b)},formatSelection:function(a,c,d){return a?d(this.text(a)):b},sortResults:function(a){return a},formatResultCssClass:function(a){return a.css},formatSelectionCssClass:function(){return b},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(a){return a==b?null:a.id},text:function(b){return b&&this.data&&this.data.text?a.isFunction(this.data.text)?this.data.text(b):b[this.data.text]:b.text
+},matcher:function(a,b){return o(""+b).toUpperCase().indexOf(o(""+a).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:M,escapeMarkup:F,blurOnChange:!1,selectOnBlur:!1,adaptContainerCssClass:function(a){return a},adaptDropdownCssClass:function(){return null},nextSearchTerm:function(){return b},searchInputPlaceholder:"",createSearchChoicePosition:"top",shouldFocusInput:function(a){var b="ontouchstart"in window||navigator.msMaxTouchPoints>0;return b?a.opts.minimumResultsForSearch<0?!1:!0:!0}},a.fn.select2.locales=[],a.fn.select2.locales.en={formatMatches:function(a){return 1===a?"One result is available, press enter to select it.":a+" results are available, use up and down arrow keys to navigate."},formatNoMatches:function(){return"No matches found"},formatAjaxError:function(){return"Loading failed"},formatInputTooShort:function(a,b){var c=b-a.length;return"Please enter "+c+" or more character"+(1==c?"":"s")},formatInputTooLong:function(a,b){var c=a.length-b;return"Please delete "+c+" character"+(1==c?"":"s")},formatSelectionTooBig:function(a){return"You can only select "+a+" item"+(1==a?"":"s")},formatLoadMore:function(){return"Loading more results\u2026"},formatSearching:function(){return"Searching\u2026"}},a.extend(a.fn.select2.defaults,a.fn.select2.locales.en),a.fn.select2.ajaxDefaults={transport:a.ajax,params:{type:"GET",cache:!1,dataType:"json"}},window.Select2={query:{ajax:G,local:H,tags:I},util:{debounce:w,markMatch:E,escapeMarkup:F,stripDiacritics:o},"class":{"abstract":c,single:d,multi:e}}}}(jQuery);
\ No newline at end of file