diff --git a/.env.example b/.env.example index 5aab1612b..9c4e015a5 100644 --- a/.env.example +++ b/.env.example @@ -110,8 +110,10 @@ LDAP_BASE_DN= USE_LOCAL_AUTH= # ReCaptcha -RECAPTCHA_SITE_KEY_V3= -RECAPTCHA_SECRET_KEY_V3= +RECAPTCHA_ENABLED= +RECAPTCHA_PUBLIC_KEY= +RECAPTCHA_PRIVATE_KEY= +RECAPTCHA_THRESHOLD= # Sentry SENTRY_DSN= diff --git a/app/agency/api/views.py b/app/agency/api/views.py index 9b3733b17..5379eb186 100644 --- a/app/agency/api/views.py +++ b/app/agency/api/views.py @@ -90,9 +90,7 @@ def get_custom_request_form_options(agency_ein): CustomRequestForms.repeatable, CustomRequestForms.category, CustomRequestForms.minimum_required).filter_by( - agency_ein=agency_ein).order_by(asc(CustomRequestForms.category), asc(CustomRequestForms.id)).all() - # Convert the results of with_entities back to tuple format so that jsonify can be used - custom_request_forms = [tuple(form) for form in custom_request_forms] + agency_ein=agency_ein, is_active=True).order_by(asc(CustomRequestForms.category), asc(CustomRequestForms.order)).all() return jsonify(custom_request_forms), 200 @@ -177,12 +175,19 @@ def get_request_types(agency_ein): if current_user.is_agency_active(agency_ein): agency = Agencies.query.filter_by(ein=agency_ein).one_or_none() if agency is not None and agency.agency_features['custom_request_forms']['enabled']: - request_types = [ + active_request_types = [ (custom_request_form.form_name, custom_request_form.form_name) for custom_request_form in CustomRequestForms.query.filter_by( - agency_ein=agency_ein - ).order_by(asc(CustomRequestForms.category), asc(CustomRequestForms.id)).all() + agency_ein=agency_ein, is_active=True + ).order_by(asc(CustomRequestForms.category), asc(CustomRequestForms.order)).all() ] + inactive_request_types = [ + (custom_request_form.form_name, "(Inactive) " + custom_request_form.form_name) + for custom_request_form in CustomRequestForms.query.filter_by( + agency_ein=agency_ein, is_active=False + ).order_by(asc(CustomRequestForms.category), asc(CustomRequestForms.order)).all() + ] + request_types = active_request_types + inactive_request_types request_types.insert(0, ("", "All")) return jsonify({"request_types": request_types}), 200 diff --git a/app/jobs.py b/app/jobs.py index f18bba0c2..7bcc6fb0e 100644 --- a/app/jobs.py +++ b/app/jobs.py @@ -7,13 +7,13 @@ from psycopg2 import OperationalError from sqlalchemy.exc import SQLAlchemyError -from app import calendar, db, store -from app.constants import OPENRECORDS_DL_EMAIL, request_status +from app import calendar, sentry, store, db +from app.constants import OPENRECORDS_DL_EMAIL, request_status, determination_type from app.constants.event_type import EMAIL_NOTIFICATION_SENT, REQ_STATUS_CHANGED from app.constants.response_privacy import PRIVATE from app.lib.db_utils import create_object, update_object from app.lib.email_utils import send_email -from app.models import Agencies, Emails, Events, Requests, Users +from app.models import Agencies, Emails, Events, Requests, Responses, Determinations, Users # NOTE: (For Future Reference) # If we find ourselves in need of a request context, app.test_request_context() might come in handy. @@ -45,81 +45,104 @@ def _update_request_statuses(): due_soon_date = calendar.addbusdays( now, current_app.config['DUE_SOON_DAYS_THRESHOLD'] ).replace(hour=23, minute=59, second=59) # the entire day + request_errors = [] agencies = Agencies.query.with_entities(Agencies.ein).filter_by(is_active=True).all() for agency_ein, in agencies: + # Overdue requests requests_overdue = Requests.query.filter( Requests.due_date < now, Requests.status != request_status.CLOSED, Requests.agency_ein == agency_ein ).order_by( - Requests.due_date.asc() + Requests.id.asc() ).all() + # Query for all acknowledged overdue requests + agency_requests_overdue = Requests.query.join(Responses, Determinations).filter( + Requests.due_date < now, + Requests.status != request_status.CLOSED, + Requests.agency_ein == agency_ein, + Determinations.dtype == determination_type.ACKNOWLEDGMENT + ).order_by( + Requests.id.asc() + ).all() + + # Get the difference for all unacknowledged overdue requests + agency_acknowledgments_overdue = list(set(requests_overdue) - set(agency_requests_overdue)) + agency_acknowledgments_overdue.sort(key=lambda x: x.id) + + # Due soon requests requests_due_soon = Requests.query.filter( Requests.due_date > now, Requests.due_date <= due_soon_date, Requests.status != request_status.CLOSED, Requests.agency_ein == agency_ein ).order_by( - Requests.due_date.asc() + Requests.id.asc() + ).all() + + # Query for all acknowledged due soon requests + agency_requests_due_soon = Requests.query.join(Responses, Determinations).filter( + Requests.due_date > now, + Requests.due_date <= due_soon_date, + Requests.status != request_status.CLOSED, + Requests.agency_ein == agency_ein, + Determinations.dtype == determination_type.ACKNOWLEDGMENT + ).order_by( + Requests.id.asc() ).all() + # Get the difference for all unacknowledged due soon requests + agency_acknowledgments_due_soon = list(set(requests_due_soon) - set(agency_requests_due_soon)) + agency_acknowledgments_due_soon.sort(key=lambda x: x.id) + if not requests_overdue and not requests_due_soon: continue - agency_requests_overdue = [] - agency_acknowledgments_overdue = [] - agency_requests_due_soon = [] - agency_acknowledgments_due_soon = [] - # OVERDUE for request in requests_overdue: - - if request.was_acknowledged: - agency_requests_overdue.append(request) - else: - agency_acknowledgments_overdue.append(request) - if request.status != request_status.OVERDUE: - create_object( - Events( - request.id, - user_guid=None, - type_=REQ_STATUS_CHANGED, - previous_value={"status": request.status}, - new_value={"status": request_status.OVERDUE}, - response_id=None, + try: + update_object( + {"status": request_status.OVERDUE}, + Requests, + request.id) + create_object( + Events( + request.id, + user_guid=None, + type_=REQ_STATUS_CHANGED, + previous_value={"status": request.status}, + new_value={"status": request_status.OVERDUE}, + response_id=None, + ) ) - ) - update_object( - {"status": request_status.OVERDUE}, - Requests, - request.id) + except Exception: + request_errors.append( + (request.id, traceback.format_exc().replace("\n", "
").replace(" ", " "))) # DUE SOON for request in requests_due_soon: - - if request.was_acknowledged: - agency_requests_due_soon.append(request) - else: - agency_acknowledgments_due_soon.append(request) - if request.status != request_status.DUE_SOON: - create_object( - Events( - request.id, - user_guid=None, - type_=REQ_STATUS_CHANGED, - previous_value={"status": request.status}, - new_value={"status": request_status.DUE_SOON}, - response_id=None, + try: + update_object( + {"status": request_status.DUE_SOON}, + Requests, + request.id) + create_object( + Events( + request.id, + user_guid=None, + type_=REQ_STATUS_CHANGED, + previous_value={"status": request.status}, + new_value={"status": request_status.DUE_SOON}, + response_id=None, + ) ) - ) - update_object( - {"status": request_status.DUE_SOON}, - Requests, - request.id) + except Exception: + request_errors.append( + (request.id, traceback.format_exc().replace("\n", "
").replace(" ", " "))) # mail to agency admins for each agency user_emails = list(set(admin.notification_email or admin.email for admin @@ -161,6 +184,13 @@ def _update_request_statuses(): timestamp=datetime.utcnow() ) ) + send_email( + 'Update Request Statuses Job Finished', + to=[OPENRECORDS_DL_EMAIL], + template='email_templates/email_update_request_statuses_job_finished', + timestamp=str(datetime.utcnow()), + request_errors=request_errors + ) @app.task(autoretry_for=(OperationalError, SQLAlchemyError,), retry_kwargs={'max_retries': 5}, retry_backoff=True) diff --git a/app/lib/__init__.py b/app/lib/__init__.py index 94f40ea89..1a7d50a6a 100644 --- a/app/lib/__init__.py +++ b/app/lib/__init__.py @@ -46,6 +46,15 @@ def _populate(self, year): elif year >= 1888: self[date(year, 5, 30)] = "Memorial Day" + # Juneteenth Day + if year > 2021: + name = "Juneteenth Day" + self[date(year, 6, 19)] = name + if self.observed and date(year, 6, 19).weekday() == 5: + self[date(year, 6, 19) + rd(days=-1)] = name + " (Observed)" + elif self.observed and date(year, 6, 19).weekday() == 6: + self[date(year, 6, 19) + rd(days=+1)] = name + " (Observed)" + # Independence Day if year > 1870: name = "Independence Day" diff --git a/app/lib/email_utils.py b/app/lib/email_utils.py index 5a97d56ad..7abe5ea5f 100644 --- a/app/lib/email_utils.py +++ b/app/lib/email_utils.py @@ -35,8 +35,8 @@ def send_async_email(msg): current_app.logger.exception("Failed to Send Email {} : {}".format(msg, e)) -def send_contact_email(subject, recipients, body, sender): - msg = Message(subject, recipients, body, sender=sender) +def send_contact_email(subject, recipients, body, sender, reply_to): + msg = Message(subject, recipients, body, sender=sender, reply_to=reply_to) send_async_email.delay(msg) diff --git a/app/lib/recaptcha_utils.py b/app/lib/recaptcha_utils.py deleted file mode 100644 index 37786dcff..000000000 --- a/app/lib/recaptcha_utils.py +++ /dev/null @@ -1,152 +0,0 @@ -import logging - -import requests -from flask import Markup, current_app, json, request -from wtforms import ValidationError -from wtforms.fields import HiddenField -from wtforms.widgets import HiddenInput - -logger = logging.getLogger(__name__) - -JSONEncoder = json.JSONEncoder - -RECAPTCHA_TEMPLATE = """ - - - -""" - -RECAPTCHA_TEMPLATE_MANUAL = """ - - - -""" - -RECAPTCHA_VERIFY_SERVER = "https://www.google.com/recaptcha/api/siteverify" -RECAPTCHA_ERROR_CODES = { - "missing-input-secret": "The secret parameter is missing.", - "invalid-input-secret": "The secret parameter is invalid or malformed.", - "missing-input-response": "The response parameter is missing.", - "invalid-input-response": "The response parameter is invalid or malformed.", -} - - -class Recaptcha3Validator(object): - """Validates a ReCaptcha.""" - - def __init__(self, message=None): - if message is None: - message = "Please verify that you are not a robot." - self.message = message - - def __call__(self, form, field): - if current_app.testing: - return True - - token = field.data - if not token: - logger.warning( - "Token is not ready or incorrect configuration (check JavaScript error log)." - ) - raise ValidationError(field.gettext(self.message)) - - remote_ip = request.remote_addr - if not Recaptcha3Validator._validate_recaptcha(field, token, remote_ip): - field.recaptcha_error = "incorrect-captcha-sol" - raise ValidationError(field.gettext(self.message)) - - @staticmethod - def _validate_recaptcha(field, response, remote_addr): - """Performs the actual validation.""" - try: - private_key = current_app.config["RECAPTCHA3_PRIVATE_KEY"] - except KeyError: - raise RuntimeError("RECAPTCHA3_PRIVATE_KEY is not set in app config.") - - data = {"secret": private_key, "remoteip": remote_addr, "response": response} - - http_response = requests.post(RECAPTCHA_VERIFY_SERVER, data) - if http_response.status_code != 200: - return False - - json_resp = http_response.json() - if ( - json_resp["success"] - and json_resp["action"] == field.action - and json_resp["score"] > field.score_threshold - ): - logger.info(json_resp) - return True - else: - logger.warning(json_resp) - - for error in json_resp.get("error-codes", []): - if error in RECAPTCHA_ERROR_CODES: - raise ValidationError(RECAPTCHA_ERROR_CODES[error]) - - return False - - -class Recaptcha3Widget(HiddenInput): - def __call__(self, field, **kwargs): - """Returns the recaptcha input HTML.""" - public_key_name = "RECAPTCHA3_PUBLIC_KEY" - try: - public_key = current_app.config[public_key_name] - except KeyError: - raise RuntimeError("{public_key_name} is not set in app config.") - - return Markup( - ( - RECAPTCHA_TEMPLATE - if field.execute_on_load - else RECAPTCHA_TEMPLATE_MANUAL - ).format(public_key=public_key, action=field.action, field_name=field.name) - ) - - -class Recaptcha3Field(HiddenField): - widget = Recaptcha3Widget() - - # error message if recaptcha validation fails - recaptcha_error = None - - def __init__( - self, - action, - score_threshold=0.5, - execute_on_load=True, - validators=None, - **kwargs - ): - """If execute_on_load is False, recaptcha.execute needs to be manually bound to an event to obtain token, - the JavaScript function to call is executeRecaptcha{action}, e.g. onsubmit="executeRecaptchaSignIn" """ - if not action: - # TODO: more validation on action, see https://developers.google.com/recaptcha/docs/v3#actions - # "actions may only contain alphanumeric characters and slashes, and must not be user-specific" - raise RuntimeError("action must not be none or empty.") - - self.action = action - self.execute_on_load = execute_on_load - self.score_threshold = score_threshold - validators = validators or [Recaptcha3Validator()] - super(Recaptcha3Field, self).__init__(validators=validators, **kwargs) diff --git a/app/main/views.py b/app/main/views.py index d9ec2e2b7..7a111f738 100644 --- a/app/main/views.py +++ b/app/main/views.py @@ -19,8 +19,8 @@ from app.lib.db_utils import create_object, update_object from app.lib.email_utils import send_contact_email from app.models import Emails, Users -from app.request.forms import TechnicalSupportForm from . import main +import requests @main.route('/', methods=['GET', 'POST']) @@ -55,9 +55,25 @@ def status(): @main.route('/contact', methods=['GET', 'POST']) @main.route('/technical-support', methods=['GET', 'POST']) def technical_support(): - form = TechnicalSupportForm() - if request.method == 'POST': + if current_app.config['RECAPTCHA_ENABLED'] and not current_user.is_agency: + try: + # Verify recaptcha token and return error if failed + recaptcha_response = requests.post( + url='https://www.google.com/recaptcha/api/siteverify?secret={}&response={}' + .format(current_app.config["RECAPTCHA_PRIVATE_KEY"], + request.form["g-recaptcha-response"])).json() + + if recaptcha_response['success'] is False or recaptcha_response['score'] < current_app.config[ + "RECAPTCHA_THRESHOLD"]: + current_app.logger.exception("Recaptcha failed to verify response.\n\n{}".format(recaptcha_response)) + flash('Recaptcha failed, please try again.', category='danger') + return render_template('main/contact.html') + except: + current_app.logger.exception("Recaptcha failed to get a response.") + flash('Recaptcha failed, please try again.', category='danger') + return render_template('main/contact.html') + name = request.form.get('name') email = request.form.get('email') subject = request.form.get('subject') @@ -78,14 +94,14 @@ def technical_support(): ) ) if current_user.is_agency: - send_contact_email(subject, [current_app.config['OPENRECORDS_AGENCY_SUPPORT_DL']], body, email) + send_contact_email(subject, [current_app.config['OPENRECORDS_AGENCY_SUPPORT_DL']], body, email, None) else: - send_contact_email(subject, [OPENRECORDS_DL_EMAIL], body, email) + send_contact_email(subject, [OPENRECORDS_DL_EMAIL], body, current_app.config['MAIL_SENDER'], email) flash('Your message has been sent. We will get back to you.', category='success') else: flash('Cannot send email.', category='danger') error_id = request.args.get('error_id', '') - return render_template('main/contact.html', error_id=error_id, form=form) + return render_template('main/contact.html', error_id=error_id) @main.route('/faq', methods=['GET']) diff --git a/app/models.py b/app/models.py index 5c99e4007..6cb176a28 100644 --- a/app/models.py +++ b/app/models.py @@ -980,6 +980,14 @@ def agency_request_summary_released(self): and self.agency_request_summary_release_date < datetime.utcnow() ) + @property + def requester_name(self): + try: + request_doc = es.get(index=current_app.config["ELASTICSEARCH_INDEX"], doc_type="request", id=self.id) + return request_doc['_source']['requester_name'] + except Exception as e: + print(e) + def es_update(self): if current_app.config["ELASTICSEARCH_ENABLED"]: if self.agency.is_active: @@ -1011,7 +1019,8 @@ def es_update(self): if self.privacy["title"] else self.title, "agency_name": self.agency.name, - "agency_acronym": self.agency.acronym + "agency_acronym": self.agency.acronym, + "request_type": [metadata["form_name"] for metadata in self.custom_metadata.values()] } }, # refresh='wait_for' @@ -2025,6 +2034,8 @@ class CustomRequestForms(db.Model): repeatable - an integer the determines if that form is repeatable. 0 = not repeatable, 1 = can be added twice, etc. category - an integer to separate different types of custom forms for an agency minimum_required - an integer to dictates the minimum amount of fields required for a successful submission + order - an integer to determine sorting order when displaying form options in the dropdown + is_active - a boolean to determine if the custom request form is actively being used by the agency or not """ __tablename__ = "custom_request_forms" @@ -2036,6 +2047,8 @@ class CustomRequestForms(db.Model): repeatable = db.Column(db.Integer, nullable=False) category = db.Column(db.Integer, nullable=True) minimum_required = db.Column(db.Integer, nullable=True) + order = db.Column(db.Integer, nullable=True) + is_active = db.Column(db.Boolean, nullable=True) @classmethod def populate(cls, json_name=None): diff --git a/app/report/utils.py b/app/report/utils.py index 81dd004ca..b3d05fbf3 100644 --- a/app/report/utils.py +++ b/app/report/utils.py @@ -534,7 +534,7 @@ def generate_open_data_report(agency_ein: str, date_from: datetime, date_to: dat Files.name, Responses.dataset_description).filter( Requests.agency_ein == agency_ein, - Requests.date_submitted.between(date_from, date_to), + Responses.date_modified.between(date_from, date_to), Responses.privacy != PRIVATE, Responses.is_dataset == True).all() @@ -557,7 +557,7 @@ def generate_open_data_report(agency_ein: str, date_from: datetime, date_to: dat Responses.dataset_description, Links.url).filter( Requests.agency_ein == agency_ein, - Requests.date_submitted.between(date_from, date_to), + Responses.date_modified.between(date_from, date_to), Responses.privacy != PRIVATE, Responses.is_dataset == True).all() diff --git a/app/request/forms.py b/app/request/forms.py index bce1106b5..5e47997e1 100644 --- a/app/request/forms.py +++ b/app/request/forms.py @@ -29,7 +29,6 @@ ) from app.lib.db_utils import get_agency_choices from app.models import Reasons, LetterTemplates, EnvelopeTemplates, CustomRequestForms -from app.lib.recaptcha_utils import Recaptcha3Field class PublicUserRequestForm(FlaskForm): @@ -54,8 +53,6 @@ class PublicUserRequestForm(FlaskForm): # File Upload request_file = FileField("Upload File (optional, must be less than 20 Mb)") - recaptcha = Recaptcha3Field(action="TestAction", execute_on_load=True) - # Submit Button submit = SubmitField("Submit Request") @@ -122,8 +119,6 @@ class AgencyUserRequestForm(FlaskForm): # File Upload request_file = FileField("Upload File (optional, must be less than 20 Mb)") - recaptcha = Recaptcha3Field(action="TestAction", execute_on_load=True) - # Submit Button submit = SubmitField("Submit Request") @@ -180,7 +175,6 @@ class AnonymousRequestForm(FlaskForm): # File Upload request_file = FileField("Upload File (optional, must be less than 20 Mb)") - recaptcha = Recaptcha3Field(action="TestAction", execute_on_load=True) submit = SubmitField("Submit Request") def __init__(self): @@ -495,12 +489,19 @@ def __init__(self): self.agency_user.default = current_user.get_id() if default_agency.agency_features["custom_request_forms"]["enabled"]: - self.request_type.choices = [ + active_forms = [ (custom_request_form.form_name, custom_request_form.form_name) for custom_request_form in CustomRequestForms.query.filter_by( - agency_ein=default_agency.ein - ).order_by(asc(CustomRequestForms.category), asc(CustomRequestForms.id)).all() + agency_ein=default_agency.ein, is_active=True + ).order_by(asc(CustomRequestForms.category), asc(CustomRequestForms.order)).all() + ] + inactive_forms = [ + (custom_request_form.form_name, "(Inactive) " + custom_request_form.form_name) + for custom_request_form in CustomRequestForms.query.filter_by( + agency_ein=default_agency.ein, is_active=False + ).order_by(asc(CustomRequestForms.category), asc(CustomRequestForms.order)).all() ] + self.request_type.choices = active_forms + inactive_forms self.request_type.choices.insert(0, ("", "All")) # process form for default values @@ -529,7 +530,3 @@ def __init__(self, request): request.requester.notification_email or request.requester.email ) self.subject.data = "Inquiry about {}".format(request.id) - - -class TechnicalSupportForm(FlaskForm): - recaptcha = Recaptcha3Field(action="TestAction", execute_on_load=True) \ No newline at end of file diff --git a/app/request/utils.py b/app/request/utils.py index 586b4c318..d7f6bda62 100644 --- a/app/request/utils.py +++ b/app/request/utils.py @@ -614,6 +614,7 @@ def create_contact_record(request, first_name, last_name, email, subject, messag send_contact_email( subject, agency_emails, - message, + body, + current_app.config['MAIL_SENDER'], email ) diff --git a/app/request/views.py b/app/request/views.py index 8dc785aa0..484eb8c91 100644 --- a/app/request/views.py +++ b/app/request/views.py @@ -60,6 +60,7 @@ from app.user_request.utils import get_current_point_of_contact from app import sentry import json +import requests @request.route("/new", methods=["GET", "POST"]) @@ -96,6 +97,38 @@ def new(): new_request_template = "request/new_request_" + template_suffix if flask_request.method == "POST": + if current_app.config['RECAPTCHA_ENABLED'] and not current_user.is_agency: + try: + # Verify recaptcha token and return error if failed + recaptcha_response = requests.post( + url='https://www.google.com/recaptcha/api/siteverify?secret={}&response={}' + .format(current_app.config["RECAPTCHA_PRIVATE_KEY"], + flask_request.form["g-recaptcha-response"])).json() + + if recaptcha_response['success'] is False or recaptcha_response['score'] < current_app.config[ + "RECAPTCHA_THRESHOLD"]: + current_app.logger.exception("Recaptcha failed to verify response.\n\n{}".format(recaptcha_response)) + flash('Recaptcha failed, please try again.', category='danger') + return render_template( + new_request_template, + form=form, + kiosk_mode=kiosk_mode, + category=category, + agency=agency, + title=title, + ) + except: + current_app.logger.exception("Recaptcha failed to get a response.") + flash('Recaptcha failed, please try again.', category='danger') + return render_template( + new_request_template, + form=form, + kiosk_mode=kiosk_mode, + category=category, + agency=agency, + title=title, + ) + # validate upload with no request id available upload_path = None if form.request_file.data: @@ -107,8 +140,23 @@ def new(): ) custom_metadata = json.loads( - flask_request.form.get("custom-request-forms-data", {}) + flask_request.form.get("custom-request-forms-data", '{}') ) + # validate that custom_metadata JSON has data if custom request forms are enabled for the agency + agency_ein = (form.request_agency.data + if form.request_agency.data != "None" + else current_user.default_agency_ein) + agency_object = Agencies.query.filter_by(ein=agency_ein).first() + if agency_object.agency_features["custom_request_forms"]["enabled"] and not custom_metadata: + flash('An unexpected error occurred. Please reload the page and try submitting your request again.', + category='danger') + return redirect(url_for("request.new")) + # validate that form_name exists in custom_metadata JSON + for key,value in custom_metadata.items(): + form_name = value.get('form_name', None) + if not form_name: + flash('An unexpected error occurred. Please try submitting your request again.', category='danger') + return redirect(url_for("request.new")) tz_name = ( escape(flask_request.form["tz-name"]) if flask_request.form["tz-name"] @@ -492,6 +540,7 @@ def contact_agency(request_id): ) flash("Your message has been sent.", category="success") else: + current_app.logger.exception("Contact the agency error: {}\n\n{}".format(current_request.id, form.errors)) flash( "There was a problem sending your message. Please try again.", category="danger", diff --git a/app/static/img/ui-icons_444444_256x240.png b/app/static/img/ui-icons_444444_256x240.png old mode 100755 new mode 100644 diff --git a/app/static/img/ui-icons_555555_256x240.png b/app/static/img/ui-icons_555555_256x240.png old mode 100755 new mode 100644 index e965f6d97..e69de29bb Binary files a/app/static/img/ui-icons_555555_256x240.png and b/app/static/img/ui-icons_555555_256x240.png differ diff --git a/app/static/img/ui-icons_777620_256x240.png b/app/static/img/ui-icons_777620_256x240.png old mode 100755 new mode 100644 index 9785948a2..e69de29bb Binary files a/app/static/img/ui-icons_777620_256x240.png and b/app/static/img/ui-icons_777620_256x240.png differ diff --git a/app/static/img/ui-icons_777777_256x240.png b/app/static/img/ui-icons_777777_256x240.png old mode 100755 new mode 100644 diff --git a/app/static/img/ui-icons_cc0000_256x240.png b/app/static/img/ui-icons_cc0000_256x240.png old mode 100755 new mode 100644 index 45ac7787c..e69de29bb Binary files a/app/static/img/ui-icons_cc0000_256x240.png and b/app/static/img/ui-icons_cc0000_256x240.png differ diff --git a/app/static/img/ui-icons_ffffff_256x240.png b/app/static/img/ui-icons_ffffff_256x240.png old mode 100755 new mode 100644 index fe41d2d0f..e69de29bb Binary files a/app/static/img/ui-icons_ffffff_256x240.png and b/app/static/img/ui-icons_ffffff_256x240.png differ diff --git a/app/static/js/admin/main.js b/app/static/js/admin/main.js index 2d1028065..860c9b130 100644 --- a/app/static/js/admin/main.js +++ b/app/static/js/admin/main.js @@ -42,11 +42,13 @@ $(function () { var row = $(this).parents(".row"); var id = row.find("input[name='user-id']").val(); var isSuperUser = $(this).is(":checked"); + var agencyEin = $("input[name='agency-ein']").val(); $.ajax({ url: "/user/" + id, type: "PATCH", data: { - is_super: isSuperUser + is_super: isSuperUser, + agency_ein: agencyEin } }); }); diff --git a/app/static/js/plugins/bootstrap.min.js b/app/static/js/plugins/bootstrap.min.js index e79c06513..eb0a8b410 100755 --- a/app/static/js/plugins/bootstrap.min.js +++ b/app/static/js/plugins/bootstrap.min.js @@ -1,7 +1,6 @@ /*! - * Bootstrap v3.3.6 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. + * Bootstrap v3.4.1 (https://getbootstrap.com/) + * Copyright 2011-2019 Twitter, Inc. * Licensed under the MIT license */ -if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.6",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.6",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.6",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.6",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.6",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.6",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.6",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");!function(t){"use strict";var e=jQuery.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1==e[0]&&9==e[1]&&e[2]<1||3this.$items.length-1||t<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){e.to(t)}):i==t?this.pause().cycle():this.slide(idocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&t?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!t?this.scrollbarWidth:""})},s.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},s.prototype.checkScrollbar=function(){var t=window.innerWidth;if(!t){var e=document.documentElement.getBoundingClientRect();t=e.right-Math.abs(e.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0},sanitize:!0,sanitizeFn:null,whiteList:t},m.prototype.init=function(t,e,i){if(this.enabled=!0,this.type=t,this.$element=g(e),this.options=this.getOptions(i),this.$viewport=this.options.viewport&&g(document).find(g.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var o=this.options.trigger.split(" "),n=o.length;n--;){var s=o[n];if("click"==s)this.$element.on("click."+this.type,this.options.selector,g.proxy(this.toggle,this));else if("manual"!=s){var a="hover"==s?"mouseenter":"focusin",r="hover"==s?"mouseleave":"focusout";this.$element.on(a+"."+this.type,this.options.selector,g.proxy(this.enter,this)),this.$element.on(r+"."+this.type,this.options.selector,g.proxy(this.leave,this))}}this.options.selector?this._options=g.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},m.prototype.getDefaults=function(){return m.DEFAULTS},m.prototype.getOptions=function(t){var e=this.$element.data();for(var i in e)e.hasOwnProperty(i)&&-1!==g.inArray(i,o)&&delete e[i];return(t=g.extend({},this.getDefaults(),e,t)).delay&&"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),t.sanitize&&(t.template=n(t.template,t.whiteList,t.sanitizeFn)),t},m.prototype.getDelegateOptions=function(){var i={},o=this.getDefaults();return this._options&&g.each(this._options,function(t,e){o[t]!=e&&(i[t]=e)}),i},m.prototype.enter=function(t){var e=t instanceof this.constructor?t:g(t.currentTarget).data("bs."+this.type);if(e||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e)),t instanceof g.Event&&(e.inState["focusin"==t.type?"focus":"hover"]=!0),e.tip().hasClass("in")||"in"==e.hoverState)e.hoverState="in";else{if(clearTimeout(e.timeout),e.hoverState="in",!e.options.delay||!e.options.delay.show)return e.show();e.timeout=setTimeout(function(){"in"==e.hoverState&&e.show()},e.options.delay.show)}},m.prototype.isInStateTrue=function(){for(var t in this.inState)if(this.inState[t])return!0;return!1},m.prototype.leave=function(t){var e=t instanceof this.constructor?t:g(t.currentTarget).data("bs."+this.type);if(e||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e)),t instanceof g.Event&&(e.inState["focusout"==t.type?"focus":"hover"]=!1),!e.isInStateTrue()){if(clearTimeout(e.timeout),e.hoverState="out",!e.options.delay||!e.options.delay.hide)return e.hide();e.timeout=setTimeout(function(){"out"==e.hoverState&&e.hide()},e.options.delay.hide)}},m.prototype.show=function(){var t=g.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(t);var e=g.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(t.isDefaultPrevented()||!e)return;var i=this,o=this.tip(),n=this.getUID(this.type);this.setContent(),o.attr("id",n),this.$element.attr("aria-describedby",n),this.options.animation&&o.addClass("fade");var s="function"==typeof this.options.placement?this.options.placement.call(this,o[0],this.$element[0]):this.options.placement,a=/\s?auto?\s?/i,r=a.test(s);r&&(s=s.replace(a,"")||"top"),o.detach().css({top:0,left:0,display:"block"}).addClass(s).data("bs."+this.type,this),this.options.container?o.appendTo(g(document).find(this.options.container)):o.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var l=this.getPosition(),h=o[0].offsetWidth,d=o[0].offsetHeight;if(r){var p=s,c=this.getPosition(this.$viewport);s="bottom"==s&&l.bottom+d>c.bottom?"top":"top"==s&&l.top-dc.width?"left":"left"==s&&l.left-ha.top+a.height&&(n.top=a.top+a.height-l)}else{var h=e.left-s,d=e.left+s+i;ha.right&&(n.left=a.left+a.width-d)}return n},m.prototype.getTitle=function(){var t=this.$element,e=this.options;return t.attr("data-original-title")||("function"==typeof e.title?e.title.call(t[0]):e.title)},m.prototype.getUID=function(t){for(;t+=~~(1e6*Math.random()),document.getElementById(t););return t},m.prototype.tip=function(){if(!this.$tip&&(this.$tip=g(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},m.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},m.prototype.enable=function(){this.enabled=!0},m.prototype.disable=function(){this.enabled=!1},m.prototype.toggleEnabled=function(){this.enabled=!this.enabled},m.prototype.toggle=function(t){var e=this;t&&((e=g(t.currentTarget).data("bs."+this.type))||(e=new this.constructor(t.currentTarget,this.getDelegateOptions()),g(t.currentTarget).data("bs."+this.type,e))),t?(e.inState.click=!e.inState.click,e.isInStateTrue()?e.enter(e):e.leave(e)):e.tip().hasClass("in")?e.leave(e):e.enter(e)},m.prototype.destroy=function(){var t=this;clearTimeout(this.timeout),this.hide(function(){t.$element.off("."+t.type).removeData("bs."+t.type),t.$tip&&t.$tip.detach(),t.$tip=null,t.$arrow=null,t.$viewport=null,t.$element=null})},m.prototype.sanitizeHtml=function(t){return n(t,this.options.whiteList,this.options.sanitizeFn)};var e=g.fn.tooltip;g.fn.tooltip=function i(o){return this.each(function(){var t=g(this),e=t.data("bs.tooltip"),i="object"==typeof o&&o;!e&&/destroy|hide/.test(o)||(e||t.data("bs.tooltip",e=new m(this,i)),"string"==typeof o&&e[o]())})},g.fn.tooltip.Constructor=m,g.fn.tooltip.noConflict=function(){return g.fn.tooltip=e,this}}(jQuery),function(n){"use strict";var s=function(t,e){this.init("popover",t,e)};if(!n.fn.tooltip)throw new Error("Popover requires tooltip.js");s.VERSION="3.4.1",s.DEFAULTS=n.extend({},n.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),((s.prototype=n.extend({},n.fn.tooltip.Constructor.prototype)).constructor=s).prototype.getDefaults=function(){return s.DEFAULTS},s.prototype.setContent=function(){var t=this.tip(),e=this.getTitle(),i=this.getContent();if(this.options.html){var o=typeof i;this.options.sanitize&&(e=this.sanitizeHtml(e),"string"===o&&(i=this.sanitizeHtml(i))),t.find(".popover-title").html(e),t.find(".popover-content").children().detach().end()["string"===o?"html":"append"](i)}else t.find(".popover-title").text(e),t.find(".popover-content").children().detach().end().text(i);t.removeClass("fade top bottom left right in"),t.find(".popover-title").html()||t.find(".popover-title").hide()},s.prototype.hasContent=function(){return this.getTitle()||this.getContent()},s.prototype.getContent=function(){var t=this.$element,e=this.options;return t.attr("data-content")||("function"==typeof e.content?e.content.call(t[0]):e.content)},s.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var t=n.fn.popover;n.fn.popover=function e(o){return this.each(function(){var t=n(this),e=t.data("bs.popover"),i="object"==typeof o&&o;!e&&/destroy|hide/.test(o)||(e||t.data("bs.popover",e=new s(this,i)),"string"==typeof o&&e[o]())})},n.fn.popover.Constructor=s,n.fn.popover.noConflict=function(){return n.fn.popover=t,this}}(jQuery),function(s){"use strict";function n(t,e){this.$body=s(document.body),this.$scrollElement=s(t).is(document.body)?s(window):s(t),this.options=s.extend({},n.DEFAULTS,e),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",s.proxy(this.process,this)),this.refresh(),this.process()}function e(o){return this.each(function(){var t=s(this),e=t.data("bs.scrollspy"),i="object"==typeof o&&o;e||t.data("bs.scrollspy",e=new n(this,i)),"string"==typeof o&&e[o]()})}n.VERSION="3.4.1",n.DEFAULTS={offset:10},n.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},n.prototype.refresh=function(){var t=this,o="offset",n=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),s.isWindow(this.$scrollElement[0])||(o="position",n=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var t=s(this),e=t.data("target")||t.attr("href"),i=/^#./.test(e)&&s(e);return i&&i.length&&i.is(":visible")&&[[i[o]().top+n,e]]||null}).sort(function(t,e){return t[0]-e[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},n.prototype.process=function(){var t,e=this.$scrollElement.scrollTop()+this.options.offset,i=this.getScrollHeight(),o=this.options.offset+i-this.$scrollElement.height(),n=this.offsets,s=this.targets,a=this.activeTarget;if(this.scrollHeight!=i&&this.refresh(),o<=e)return a!=(t=s[s.length-1])&&this.activate(t);if(a&&e=n[t]&&(n[t+1]===undefined||e .active"),n=i&&r.support.transition&&(o.length&&o.hasClass("fade")||!!e.find("> .fade").length);function s(){o.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),t.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),n?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu").length&&t.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),i&&i()}o.length&&n?o.one("bsTransitionEnd",s).emulateTransitionEnd(a.TRANSITION_DURATION):s(),o.removeClass("in")};var t=r.fn.tab;r.fn.tab=e,r.fn.tab.Constructor=a,r.fn.tab.noConflict=function(){return r.fn.tab=t,this};var i=function(t){t.preventDefault(),e.call(r(this),"show")};r(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',i).on("click.bs.tab.data-api",'[data-toggle="pill"]',i)}(jQuery),function(l){"use strict";var h=function(t,e){this.options=l.extend({},h.DEFAULTS,e);var i=this.options.target===h.DEFAULTS.target?l(this.options.target):l(document).find(this.options.target);this.$target=i.on("scroll.bs.affix.data-api",l.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",l.proxy(this.checkPositionWithEventLoop,this)),this.$element=l(t),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};function i(o){return this.each(function(){var t=l(this),e=t.data("bs.affix"),i="object"==typeof o&&o;e||t.data("bs.affix",e=new h(this,i)),"string"==typeof o&&e[o]()})}h.VERSION="3.4.1",h.RESET="affix affix-top affix-bottom",h.DEFAULTS={offset:0,target:window},h.prototype.getState=function(t,e,i,o){var n=this.$target.scrollTop(),s=this.$element.offset(),a=this.$target.height();if(null!=i&&"top"==this.affixed)return n>demos: http://jqueryui.com/widget/ - var widgetUuid = 0; +var widgetHasOwnProperty = Array.prototype.hasOwnProperty; var widgetSlice = Array.prototype.slice; $.cleanData = ( function( orig ) { return function( elems ) { var events, elem, i; for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { - try { - - // Only trigger remove when necessary to save time - events = $._data( elem, "events" ); - if ( events && events.remove ) { - $( elem ).triggerHandler( "remove" ); - } - // Http://bugs.jquery.com/ticket/8235 - } catch ( e ) {} + // Only trigger remove when necessary to save time + events = $._data( elem, "events" ); + if ( events && events.remove ) { + $( elem ).triggerHandler( "remove" ); + } } orig( elems ); }; @@ -75,12 +74,12 @@ $.widget = function( name, base, prototype ) { base = $.Widget; } - if ( $.isArray( prototype ) ) { + if ( Array.isArray( prototype ) ) { prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); } // Create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + $.expr.pseudos[ fullName.toLowerCase() ] = function( elem ) { return !!$.data( elem, fullName ); }; @@ -89,7 +88,7 @@ $.widget = function( name, base, prototype ) { constructor = $[ namespace ][ name ] = function( options, element ) { // Allow instantiation without "new" keyword - if ( !this._createWidget ) { + if ( !this || !this._createWidget ) { return new constructor( options, element ); } @@ -120,7 +119,7 @@ $.widget = function( name, base, prototype ) { // inheriting from basePrototype.options = $.widget.extend( {}, basePrototype.options ); $.each( prototype, function( prop, value ) { - if ( !$.isFunction( value ) ) { + if ( typeof value !== "function" ) { proxiedPrototype[ prop ] = value; return; } @@ -199,7 +198,7 @@ $.widget.extend = function( target ) { for ( ; inputIndex < inputLength; inputIndex++ ) { for ( key in input[ inputIndex ] ) { value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + if ( widgetHasOwnProperty.call( input[ inputIndex ], key ) && value !== undefined ) { // Clone objects if ( $.isPlainObject( value ) ) { @@ -248,7 +247,8 @@ $.widget.bridge = function( name, object ) { "attempted to call method '" + options + "'" ); } - if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) { + if ( typeof instance[ options ] !== "function" || + options.charAt( 0 ) === "_" ) { return $.error( "no such method '" + options + "' for " + name + " widget instance" ); } @@ -509,12 +509,34 @@ $.Widget.prototype = { classes: this.options.classes || {} }, options ); + function bindRemoveEvent() { + var nodesToBind = []; + + options.element.each( function( _, element ) { + var isTracked = $.map( that.classesElementLookup, function( elements ) { + return elements; + } ) + .some( function( elements ) { + return elements.is( element ); + } ); + + if ( !isTracked ) { + nodesToBind.push( element ); + } + } ); + + that._on( $( nodesToBind ), { + remove: "_untrackClassesElement" + } ); + } + function processClassString( classes, checkOption ) { var current, i; for ( i = 0; i < classes.length; i++ ) { current = that.classesElementLookup[ classes[ i ] ] || $(); if ( options.add ) { - current = $( $.unique( current.get().concat( options.element.get() ) ) ); + bindRemoveEvent(); + current = $( $.uniqueSort( current.get().concat( options.element.get() ) ) ); } else { current = $( current.not( options.element ).get() ); } @@ -526,10 +548,6 @@ $.Widget.prototype = { } } - this._on( options.element, { - "remove": "_untrackClassesElement" - } ); - if ( options.keys ) { processClassString( options.keys.match( /\S+/g ) || [], true ); } @@ -547,6 +565,8 @@ $.Widget.prototype = { that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); } } ); + + this._off( $( event.target ) ); }, _removeClass: function( element, keys, extra ) { @@ -627,7 +647,7 @@ $.Widget.prototype = { _off: function( element, eventName ) { eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.off( eventName ).off( eventName ); + element.off( eventName ); // Clear the stack to avoid memory leaks (#10056) this.bindings = $( this.bindings.not( element ).get() ); @@ -693,7 +713,7 @@ $.Widget.prototype = { } this.element.trigger( event, data ); - return !( $.isFunction( callback ) && + return !( typeof callback === "function" && callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || event.isDefaultPrevented() ); } @@ -715,6 +735,8 @@ $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { options = options || {}; if ( typeof options === "number" ) { options = { duration: options }; + } else if ( options === true ) { + options = {}; } hasOptions = !$.isEmptyObject( options ); @@ -744,7 +766,7 @@ var widget = $.widget; /*! - * jQuery UI Position 1.12.1 + * jQuery UI Position 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -783,6 +805,10 @@ function parseCss( element, property ) { return parseInt( $.css( element, property ), 10 ) || 0; } +function isWindow( obj ) { + return obj != null && obj === obj.window; +} + function getDimensions( elem ) { var raw = elem[ 0 ]; if ( raw.nodeType === 9 ) { @@ -792,7 +818,7 @@ function getDimensions( elem ) { offset: { top: 0, left: 0 } }; } - if ( $.isWindow( raw ) ) { + if ( isWindow( raw ) ) { return { width: elem.width(), height: elem.height(), @@ -819,9 +845,9 @@ $.position = { return cachedScrollbarWidth; } var w1, w2, - div = $( "
" + - "
" ), + div = $( "
" + + "
" ), innerDiv = div.children()[ 0 ]; $( "body" ).append( div ); @@ -854,12 +880,12 @@ $.position = { }, getWithinInfo: function( element ) { var withinElement = $( element || window ), - isWindow = $.isWindow( withinElement[ 0 ] ), + isElemWindow = isWindow( withinElement[ 0 ] ), isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9, - hasOffset = !isWindow && !isDocument; + hasOffset = !isElemWindow && !isDocument; return { element: withinElement, - isWindow: isWindow, + isWindow: isElemWindow, isDocument: isDocument, offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 }, scrollLeft: withinElement.scrollLeft(), @@ -879,7 +905,12 @@ $.fn.position = function( options ) { options = $.extend( {}, options ); var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, - target = $( options.of ), + + // Make sure string options are treated as CSS selectors + target = typeof options.of === "string" ? + $( document ).find( options.of ) : + $( options.of ), + within = $.position.getWithinInfo( options.within ), scrollInfo = $.position.getScrollInfo( within ), collision = ( options.collision || "flip" ).split( " " ), @@ -1232,7 +1263,7 @@ var position = $.ui.position; /*! - * jQuery UI :data 1.12.1 + * jQuery UI :data 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -1246,7 +1277,7 @@ var position = $.ui.position; //>>docs: http://api.jqueryui.com/data-selector/ -var data = $.extend( $.expr[ ":" ], { +var data = $.extend( $.expr.pseudos, { data: $.expr.createPseudo ? $.expr.createPseudo( function( dataName ) { return function( elem ) { @@ -1261,7 +1292,7 @@ var data = $.extend( $.expr[ ":" ], { } ); /*! - * jQuery UI Disable Selection 1.12.1 + * jQuery UI Disable Selection 1.13.2 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -1276,7 +1307,6 @@ var data = $.extend( $.expr[ ":" ], { // This file is deprecated - var disableSelection = $.fn.extend( { disableSelection: ( function() { var eventType = "onselectstart" in document.createElement( "div" ) ? @@ -1296,1952 +1326,2178 @@ var disableSelection = $.fn.extend( { } ); + +// Create a local jQuery because jQuery Color relies on it and the +// global may not exist with AMD and a custom build (#10199). +// This module is a noop if used as a regular AMD module. +// eslint-disable-next-line no-unused-vars +var jQuery = $; + + /*! - * jQuery UI Focusable 1.12.1 - * http://jqueryui.com + * jQuery Color Animations v2.2.0 + * https://github.com/jquery/jquery-color * - * Copyright jQuery Foundation and other contributors + * Copyright OpenJS Foundation and other contributors * Released under the MIT license. * http://jquery.org/license + * + * Date: Sun May 10 09:02:36 2020 +0200 */ -//>>label: :focusable Selector -//>>group: Core -//>>description: Selects elements which can be focused. -//>>docs: http://api.jqueryui.com/focusable-selector/ + var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " + + "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", -// Selectors -$.ui.focusable = function( element, hasTabindex ) { - var map, mapName, img, focusableIfVisible, fieldset, - nodeName = element.nodeName.toLowerCase(); + class2type = {}, + toString = class2type.toString, - if ( "area" === nodeName ) { - map = element.parentNode; - mapName = map.name; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap='#" + mapName + "']" ); - return img.length > 0 && img.is( ":visible" ); - } + // plusequals test for += 100 -= 100 + rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, - if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) { - focusableIfVisible = !element.disabled; + // a set of RE's that can match strings and generate color tuples. + stringParsers = [ { + re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ], + execResult[ 3 ], + execResult[ 4 ] + ]; + } + }, { + re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ] * 2.55, + execResult[ 2 ] * 2.55, + execResult[ 3 ] * 2.55, + execResult[ 4 ] + ]; + } + }, { - if ( focusableIfVisible ) { + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ], 16 ), + execResult[ 4 ] ? + ( parseInt( execResult[ 4 ], 16 ) / 255 ).toFixed( 2 ) : + 1 + ]; + } + }, { - // Form controls within a disabled fieldset are disabled. - // However, controls within the fieldset's legend do not get disabled. - // Since controls generally aren't placed inside legends, we skip - // this portion of the check. - fieldset = $( element ).closest( "fieldset" )[ 0 ]; - if ( fieldset ) { - focusableIfVisible = !fieldset.disabled; + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ), + execResult[ 4 ] ? + ( parseInt( execResult[ 4 ] + execResult[ 4 ], 16 ) / 255 ) + .toFixed( 2 ) : + 1 + ]; } - } - } else if ( "a" === nodeName ) { - focusableIfVisible = element.href || hasTabindex; - } else { - focusableIfVisible = hasTabindex; - } + }, { + re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + space: "hsla", + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ] / 100, + execResult[ 3 ] / 100, + execResult[ 4 ] + ]; + } + } ], - return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) ); -}; + // jQuery.Color( ) + color = jQuery.Color = function( color, green, blue, alpha ) { + return new jQuery.Color.fn.parse( color, green, blue, alpha ); + }, + spaces = { + rgba: { + props: { + red: { + idx: 0, + type: "byte" + }, + green: { + idx: 1, + type: "byte" + }, + blue: { + idx: 2, + type: "byte" + } + } + }, -// Support: IE 8 only -// IE 8 doesn't resolve inherit to visible/hidden for computed values -function visible( element ) { - var visibility = element.css( "visibility" ); - while ( visibility === "inherit" ) { - element = element.parent(); - visibility = element.css( "visibility" ); - } - return visibility !== "hidden"; -} + hsla: { + props: { + hue: { + idx: 0, + type: "degrees" + }, + saturation: { + idx: 1, + type: "percent" + }, + lightness: { + idx: 2, + type: "percent" + } + } + } + }, + propTypes = { + "byte": { + floor: true, + max: 255 + }, + "percent": { + max: 1 + }, + "degrees": { + mod: 360, + floor: true + } + }, + support = color.support = {}, -$.extend( $.expr[ ":" ], { - focusable: function( element ) { - return $.ui.focusable( element, $.attr( element, "tabindex" ) != null ); - } -} ); + // element for support tests + supportElem = jQuery( "

" )[ 0 ], -var focusable = $.ui.focusable; + // colors = jQuery.Color.names + colors, + // local aliases of functions called often + each = jQuery.each; +// determine rgba support immediately +supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; +support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; +// define cache name and alpha properties +// for rgba and hsla spaces +each( spaces, function( spaceName, space ) { + space.cache = "_" + spaceName; + space.props.alpha = { + idx: 3, + type: "percent", + def: 1 + }; +} ); -// Support: IE8 Only -// IE8 does not support the form attribute and when it is supplied. It overwrites the form prop -// with a string, so we need to find the proper form. -var form = $.fn.form = function() { - return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form ); -}; +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); +function getType( obj ) { + if ( obj == null ) { + return obj + ""; + } -/*! - * jQuery UI Form Reset Mixin 1.12.1 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - */ + return typeof obj === "object" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} -//>>label: Form Reset Mixin -//>>group: Core -//>>description: Refresh input widgets when their form is reset -//>>docs: http://api.jqueryui.com/form-reset-mixin/ +function clamp( value, prop, allowEmpty ) { + var type = propTypes[ prop.type ] || {}; + if ( value == null ) { + return ( allowEmpty || !prop.def ) ? null : prop.def; + } + // ~~ is an short way of doing floor for positive numbers + value = type.floor ? ~~value : parseFloat( value ); -var formResetMixin = $.ui.formResetMixin = { - _formResetHandler: function() { - var form = $( this ); + // IE will pass in empty strings as value for alpha, + // which will hit this case + if ( isNaN( value ) ) { + return prop.def; + } - // Wait for the form reset to actually happen before refreshing - setTimeout( function() { - var instances = form.data( "ui-form-reset-instances" ); - $.each( instances, function() { - this.refresh(); - } ); - } ); - }, + if ( type.mod ) { - _bindFormResetHandler: function() { - this.form = this.element.form(); - if ( !this.form.length ) { - return; - } + // we add mod before modding to make sure that negatives values + // get converted properly: -10 -> 350 + return ( value + type.mod ) % type.mod; + } - var instances = this.form.data( "ui-form-reset-instances" ) || []; - if ( !instances.length ) { + // for now all property types without mod have min and max + return Math.min( type.max, Math.max( 0, value ) ); +} - // We don't use _on() here because we use a single event handler per form - this.form.on( "reset.ui-form-reset", this._formResetHandler ); - } - instances.push( this ); - this.form.data( "ui-form-reset-instances", instances ); - }, +function stringParse( string ) { + var inst = color(), + rgba = inst._rgba = []; - _unbindFormResetHandler: function() { - if ( !this.form.length ) { - return; + string = string.toLowerCase(); + + each( stringParsers, function( _i, parser ) { + var parsed, + match = parser.re.exec( string ), + values = match && parser.parse( match ), + spaceName = parser.space || "rgba"; + + if ( values ) { + parsed = inst[ spaceName ]( values ); + + // if this was an rgba parse the assignment might happen twice + // oh well.... + inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; + rgba = inst._rgba = parsed._rgba; + + // exit each( stringParsers ) here because we matched + return false; } + } ); - var instances = this.form.data( "ui-form-reset-instances" ); - instances.splice( $.inArray( this, instances ), 1 ); - if ( instances.length ) { - this.form.data( "ui-form-reset-instances", instances ); - } else { - this.form - .removeData( "ui-form-reset-instances" ) - .off( "reset.ui-form-reset" ); + // Found a stringParser that handled it + if ( rgba.length ) { + + // if this came from a parsed string, force "transparent" when alpha is 0 + // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) + if ( rgba.join() === "0,0,0,0" ) { + jQuery.extend( rgba, colors.transparent ); } + return inst; } -}; + // named colors + return colors[ string ]; +} -/*! - * jQuery UI Support for jQuery core 1.7.x 1.12.1 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - */ +color.fn = jQuery.extend( color.prototype, { + parse: function( red, green, blue, alpha ) { + if ( red === undefined ) { + this._rgba = [ null, null, null, null ]; + return this; + } + if ( red.jquery || red.nodeType ) { + red = jQuery( red ).css( green ); + green = undefined; + } -//>>label: jQuery 1.7 Support -//>>group: Core -//>>description: Support version 1.7.x of jQuery core - - - -// Support: jQuery 1.7 only -// Not a great way to check versions, but since we only support 1.7+ and only -// need to detect <1.8, this is a simple check that should suffice. Checking -// for "1.7." would be a bit safer, but the version string is 1.7, not 1.7.0 -// and we'll never reach 1.70.0 (if we do, we certainly won't be supporting -// 1.7 anymore). See #11197 for why we're not using feature detection. -if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) { - - // Setters for .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight() - // Unlike jQuery Core 1.8+, these only support numeric values to set the - // dimensions in pixels - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; + var inst = this, + type = getType( red ), + rgba = this._rgba = []; - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; - if ( border ) { - size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; - } - } ); - return size; + // more than 1 argument specified - assume ( red, green, blue, alpha ) + if ( green !== undefined ) { + red = [ red, green, blue, alpha ]; + type = "array"; } - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } + if ( type === "string" ) { + return this.parse( stringParse( red ) || colors._default ); + } - return this.each( function() { - $( this ).css( type, reduce( this, size ) + "px" ); + if ( type === "array" ) { + each( spaces.rgba.props, function( _key, prop ) { + rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); } ); - }; + return this; + } - $.fn[ "outer" + name ] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } + if ( type === "object" ) { + if ( red instanceof color ) { + each( spaces, function( _spaceName, space ) { + if ( red[ space.cache ] ) { + inst[ space.cache ] = red[ space.cache ].slice(); + } + } ); + } else { + each( spaces, function( _spaceName, space ) { + var cache = space.cache; + each( space.props, function( key, prop ) { - return this.each( function() { - $( this ).css( type, reduce( this, size, true, margin ) + "px" ); - } ); - }; - } ); + // if the cache doesn't exist, and we know how to convert + if ( !inst[ cache ] && space.to ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} + // if the value was null, we don't need to copy it + // if the key was alpha, we don't need to copy it either + if ( key === "alpha" || red[ key ] == null ) { + return; + } + inst[ cache ] = space.to( inst._rgba ); + } -; -/*! - * jQuery UI Keycode 1.12.1 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - */ + // this is the only case where we allow nulls for ALL properties. + // call clamp with alwaysAllowEmpty + inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); + } ); -//>>label: Keycode -//>>group: Core -//>>description: Provide keycodes as keynames -//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/ + // everything defined but alpha? + if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { + // use the default of 1 + if ( inst[ cache ][ 3 ] == null ) { + inst[ cache ][ 3 ] = 1; + } -var keycode = $.ui.keyCode = { - BACKSPACE: 8, - COMMA: 188, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - LEFT: 37, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SPACE: 32, - TAB: 9, - UP: 38 -}; + if ( space.from ) { + inst._rgba = space.from( inst[ cache ] ); + } + } + } ); + } + return this; + } + }, + is: function( compare ) { + var is = color( compare ), + same = true, + inst = this; + each( spaces, function( _, space ) { + var localCache, + isCache = is[ space.cache ]; + if ( isCache ) { + localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; + each( space.props, function( _, prop ) { + if ( isCache[ prop.idx ] != null ) { + same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); + return same; + } + } ); + } + return same; + } ); + return same; + }, + _space: function() { + var used = [], + inst = this; + each( spaces, function( spaceName, space ) { + if ( inst[ space.cache ] ) { + used.push( spaceName ); + } + } ); + return used.pop(); + }, + transition: function( other, distance ) { + var end = color( other ), + spaceName = end._space(), + space = spaces[ spaceName ], + startColor = this.alpha() === 0 ? color( "transparent" ) : this, + start = startColor[ space.cache ] || space.to( startColor._rgba ), + result = start.slice(); + end = end[ space.cache ]; + each( space.props, function( _key, prop ) { + var index = prop.idx, + startValue = start[ index ], + endValue = end[ index ], + type = propTypes[ prop.type ] || {}; + // if null, don't override start value + if ( endValue === null ) { + return; + } -// Internal use only -var escapeSelector = $.ui.escapeSelector = ( function() { - var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g; - return function( selector ) { - return selector.replace( selectorEscape, "\\$1" ); - }; -} )(); + // if null - use end + if ( startValue === null ) { + result[ index ] = endValue; + } else { + if ( type.mod ) { + if ( endValue - startValue > type.mod / 2 ) { + startValue += type.mod; + } else if ( startValue - endValue > type.mod / 2 ) { + startValue -= type.mod; + } + } + result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); + } + } ); + return this[ spaceName ]( result ); + }, + blend: function( opaque ) { + // if we are already opaque - return ourself + if ( this._rgba[ 3 ] === 1 ) { + return this; + } -/*! - * jQuery UI Labels 1.12.1 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - */ + var rgb = this._rgba.slice(), + a = rgb.pop(), + blend = color( opaque )._rgba; -//>>label: labels -//>>group: Core -//>>description: Find all the labels associated with a given input -//>>docs: http://api.jqueryui.com/labels/ + return color( jQuery.map( rgb, function( v, i ) { + return ( 1 - a ) * blend[ i ] + a * v; + } ) ); + }, + toRgbaString: function() { + var prefix = "rgba(", + rgba = jQuery.map( this._rgba, function( v, i ) { + if ( v != null ) { + return v; + } + return i > 2 ? 1 : 0; + } ); + if ( rgba[ 3 ] === 1 ) { + rgba.pop(); + prefix = "rgb("; + } + return prefix + rgba.join() + ")"; + }, + toHslaString: function() { + var prefix = "hsla(", + hsla = jQuery.map( this.hsla(), function( v, i ) { + if ( v == null ) { + v = i > 2 ? 1 : 0; + } -var labels = $.fn.labels = function() { - var ancestor, selector, id, labels, ancestors; + // catch 1 and 2 + if ( i && i < 3 ) { + v = Math.round( v * 100 ) + "%"; + } + return v; + } ); - // Check control.labels first - if ( this[ 0 ].labels && this[ 0 ].labels.length ) { - return this.pushStack( this[ 0 ].labels ); - } + if ( hsla[ 3 ] === 1 ) { + hsla.pop(); + prefix = "hsl("; + } + return prefix + hsla.join() + ")"; + }, + toHexString: function( includeAlpha ) { + var rgba = this._rgba.slice(), + alpha = rgba.pop(); - // Support: IE <= 11, FF <= 37, Android <= 2.3 only - // Above browsers do not support control.labels. Everything below is to support them - // as well as document fragments. control.labels does not work on document fragments - labels = this.eq( 0 ).parents( "label" ); + if ( includeAlpha ) { + rgba.push( ~~( alpha * 255 ) ); + } - // Look for the label based on the id - id = this.attr( "id" ); - if ( id ) { + return "#" + jQuery.map( rgba, function( v ) { - // We don't search against the document in case the element - // is disconnected from the DOM - ancestor = this.eq( 0 ).parents().last(); + // default to 0 when nulls exist + v = ( v || 0 ).toString( 16 ); + return v.length === 1 ? "0" + v : v; + } ).join( "" ); + }, + toString: function() { + return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); + } +} ); +color.fn.parse.prototype = color.fn; - // Get a full set of top level ancestors - ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() ); +// hsla conversions adapted from: +// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 - // Create a selector for the label based on the id - selector = "label[for='" + $.ui.escapeSelector( id ) + "']"; +function hue2rgb( p, q, h ) { + h = ( h + 1 ) % 1; + if ( h * 6 < 1 ) { + return p + ( q - p ) * h * 6; + } + if ( h * 2 < 1 ) { + return q; + } + if ( h * 3 < 2 ) { + return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6; + } + return p; +} - labels = labels.add( ancestors.find( selector ).addBack( selector ) ); +spaces.hsla.to = function( rgba ) { + if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { + return [ null, null, null, rgba[ 3 ] ]; + } + var r = rgba[ 0 ] / 255, + g = rgba[ 1 ] / 255, + b = rgba[ 2 ] / 255, + a = rgba[ 3 ], + max = Math.max( r, g, b ), + min = Math.min( r, g, b ), + diff = max - min, + add = max + min, + l = add * 0.5, + h, s; + if ( min === max ) { + h = 0; + } else if ( r === max ) { + h = ( 60 * ( g - b ) / diff ) + 360; + } else if ( g === max ) { + h = ( 60 * ( b - r ) / diff ) + 120; + } else { + h = ( 60 * ( r - g ) / diff ) + 240; } - // Return whatever we have found for labels - return this.pushStack( labels ); + // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% + // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) + if ( diff === 0 ) { + s = 0; + } else if ( l <= 0.5 ) { + s = diff / add; + } else { + s = diff / ( 2 - add ); + } + return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ]; }; +spaces.hsla.from = function( hsla ) { + if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { + return [ null, null, null, hsla[ 3 ] ]; + } + var h = hsla[ 0 ] / 360, + s = hsla[ 1 ], + l = hsla[ 2 ], + a = hsla[ 3 ], + q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, + p = 2 * l - q; -/*! - * jQuery UI Scroll Parent 1.12.1 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - */ - -//>>label: scrollParent -//>>group: Core -//>>description: Get the closest ancestor element that is scrollable. -//>>docs: http://api.jqueryui.com/scrollParent/ - - - -var scrollParent = $.fn.scrollParent = function( includeHidden ) { - var position = this.css( "position" ), - excludeStaticParent = position === "absolute", - overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, - scrollParent = this.parents().filter( function() { - var parent = $( this ); - if ( excludeStaticParent && parent.css( "position" ) === "static" ) { - return false; - } - return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + - parent.css( "overflow-x" ) ); - } ).eq( 0 ); - - return position === "fixed" || !scrollParent.length ? - $( this[ 0 ].ownerDocument || document ) : - scrollParent; + return [ + Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), + Math.round( hue2rgb( p, q, h ) * 255 ), + Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), + a + ]; }; -/*! - * jQuery UI Tabbable 1.12.1 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - */ - -//>>label: :tabbable Selector -//>>group: Core -//>>description: Selects elements which can be tabbed to. -//>>docs: http://api.jqueryui.com/tabbable-selector/ +each( spaces, function( spaceName, space ) { + var props = space.props, + cache = space.cache, + to = space.to, + from = space.from; + // makes rgba() and hsla() + color.fn[ spaceName ] = function( value ) { + // generate a cache for this space if it doesn't exist + if ( to && !this[ cache ] ) { + this[ cache ] = to( this._rgba ); + } + if ( value === undefined ) { + return this[ cache ].slice(); + } -var tabbable = $.extend( $.expr[ ":" ], { - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - hasTabindex = tabIndex != null; - return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex ); - } -} ); + var ret, + type = getType( value ), + arr = ( type === "array" || type === "object" ) ? value : arguments, + local = this[ cache ].slice(); + each( props, function( key, prop ) { + var val = arr[ type === "object" ? key : prop.idx ]; + if ( val == null ) { + val = local[ prop.idx ]; + } + local[ prop.idx ] = clamp( val, prop ); + } ); -/*! - * jQuery UI Unique ID 1.12.1 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - */ + if ( from ) { + ret = color( from( local ) ); + ret[ cache ] = local; + return ret; + } else { + return color( local ); + } + }; -//>>label: uniqueId -//>>group: Core -//>>description: Functions to generate and remove uniqueId's -//>>docs: http://api.jqueryui.com/uniqueId/ + // makes red() green() blue() alpha() hue() saturation() lightness() + each( props, function( key, prop ) { + // alpha is included in more than one space + if ( color.fn[ key ] ) { + return; + } + color.fn[ key ] = function( value ) { + var local, cur, match, fn, + vtype = getType( value ); + if ( key === "alpha" ) { + fn = this._hsla ? "hsla" : "rgba"; + } else { + fn = spaceName; + } + local = this[ fn ](); + cur = local[ prop.idx ]; -var uniqueId = $.fn.extend( { - uniqueId: ( function() { - var uuid = 0; + if ( vtype === "undefined" ) { + return cur; + } - return function() { - return this.each( function() { - if ( !this.id ) { - this.id = "ui-id-" + ( ++uuid ); + if ( vtype === "function" ) { + value = value.call( this, cur ); + vtype = getType( value ); + } + if ( value == null && prop.empty ) { + return this; + } + if ( vtype === "string" ) { + match = rplusequals.exec( value ); + if ( match ) { + value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); } - } ); - }; - } )(), - - removeUniqueId: function() { - return this.each( function() { - if ( /^ui-id-\d+$/.test( this.id ) ) { - $( this ).removeAttr( "id" ); } - } ); - } + local[ prop.idx ] = value; + return this[ fn ]( local ); + }; + } ); } ); +// add cssHook and .fx.step function for each named hook. +// accept a space separated string of properties +color.hook = function( hook ) { + var hooks = hook.split( " " ); + each( hooks, function( _i, hook ) { + jQuery.cssHooks[ hook ] = { + set: function( elem, value ) { + var parsed, curElem, + backgroundColor = ""; + if ( value !== "transparent" && ( getType( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { + value = color( parsed || value ); + if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { + curElem = hook === "backgroundColor" ? elem.parentNode : elem; + while ( + ( backgroundColor === "" || backgroundColor === "transparent" ) && + curElem && curElem.style + ) { + try { + backgroundColor = jQuery.css( curElem, "backgroundColor" ); + curElem = curElem.parentNode; + } catch ( e ) { + } + } + value = value.blend( backgroundColor && backgroundColor !== "transparent" ? + backgroundColor : + "_default" ); + } -// This file is deprecated -var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); + value = value.toRgbaString(); + } + try { + elem.style[ hook ] = value; + } catch ( e ) { -/*! - * jQuery UI Mouse 1.12.1 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - */ + // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' + } + } + }; + jQuery.fx.step[ hook ] = function( fx ) { + if ( !fx.colorInit ) { + fx.start = color( fx.elem, hook ); + fx.end = color( fx.end ); + fx.colorInit = true; + } + jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); + }; + } ); -//>>label: Mouse -//>>group: Widgets -//>>description: Abstracts mouse-based interactions to assist in creating certain widgets. -//>>docs: http://api.jqueryui.com/mouse/ +}; +color.hook( stepHooks ); +jQuery.cssHooks.borderColor = { + expand: function( value ) { + var expanded = {}; -var mouseHandled = false; -$( document ).on( "mouseup", function() { - mouseHandled = false; -} ); + each( [ "Top", "Right", "Bottom", "Left" ], function( _i, part ) { + expanded[ "border" + part + "Color" ] = value; + } ); + return expanded; + } +}; -var widgetsMouse = $.widget( "ui.mouse", { - version: "1.12.1", - options: { - cancel: "input, textarea, button, select, option", - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var that = this; +// Basic color names only. +// Usage of any of the other color names requires adding yourself or including +// jquery.color.svg-names.js. +colors = jQuery.Color.names = { - this.element - .on( "mousedown." + this.widgetName, function( event ) { - return that._mouseDown( event ); - } ) - .on( "click." + this.widgetName, function( event ) { - if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) { - $.removeData( event.target, that.widgetName + ".preventClickEvent" ); - event.stopImmediatePropagation(); - return false; - } - } ); + // 4.1. Basic color keywords + aqua: "#00ffff", + black: "#000000", + blue: "#0000ff", + fuchsia: "#ff00ff", + gray: "#808080", + green: "#008000", + lime: "#00ff00", + maroon: "#800000", + navy: "#000080", + olive: "#808000", + purple: "#800080", + red: "#ff0000", + silver: "#c0c0c0", + teal: "#008080", + white: "#ffffff", + yellow: "#ffff00", - this.started = false; - }, + // 4.2.3. "transparent" color keyword + transparent: [ null, null, null, 0 ], - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.off( "." + this.widgetName ); - if ( this._mouseMoveDelegate ) { - this.document - .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) - .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); - } - }, + _default: "#ffffff" +}; - _mouseDown: function( event ) { - // don't let more than one widget handle mouseStart - if ( mouseHandled ) { - return; - } +/*! + * jQuery UI Effects 1.13.2 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ - this._mouseMoved = false; +//>>label: Effects Core +//>>group: Effects +/* eslint-disable max-len */ +//>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects. +/* eslint-enable max-len */ +//>>docs: http://api.jqueryui.com/category/effects-core/ +//>>demos: http://jqueryui.com/effect/ - // We may have missed mouseup (out of window) - ( this._mouseStarted && this._mouseUp( event ) ); - this._mouseDownEvent = event; +var dataSpace = "ui-effects-", + dataSpaceStyle = "ui-effects-style", + dataSpaceAnimated = "ui-effects-animated"; - var that = this, - btnIsLeft = ( event.which === 1 ), +$.effects = { + effect: {} +}; - // event.target.nodeName works around a bug in IE 8 with - // disabled inputs (#7620) - elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ? - $( event.target ).closest( this.options.cancel ).length : false ); - if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) { - return true; - } +/******************************************************************************/ +/****************************** CLASS ANIMATIONS ******************************/ +/******************************************************************************/ +( function() { - this.mouseDelayMet = !this.options.delay; - if ( !this.mouseDelayMet ) { - this._mouseDelayTimer = setTimeout( function() { - that.mouseDelayMet = true; - }, this.options.delay ); - } +var classAnimationActions = [ "add", "remove", "toggle" ], + shorthandStyles = { + border: 1, + borderBottom: 1, + borderColor: 1, + borderLeft: 1, + borderRight: 1, + borderTop: 1, + borderWidth: 1, + margin: 1, + padding: 1 + }; - if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { - this._mouseStarted = ( this._mouseStart( event ) !== false ); - if ( !this._mouseStarted ) { - event.preventDefault(); - return true; +$.each( + [ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], + function( _, prop ) { + $.fx.step[ prop ] = function( fx ) { + if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { + jQuery.style( fx.elem, prop, fx.end ); + fx.setAttr = true; } - } - - // Click event may never have fired (Gecko & Opera) - if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) { - $.removeData( event.target, this.widgetName + ".preventClickEvent" ); - } - - // These delegates are required to keep context - this._mouseMoveDelegate = function( event ) { - return that._mouseMove( event ); - }; - this._mouseUpDelegate = function( event ) { - return that._mouseUp( event ); }; + } +); - this.document - .on( "mousemove." + this.widgetName, this._mouseMoveDelegate ) - .on( "mouseup." + this.widgetName, this._mouseUpDelegate ); - - event.preventDefault(); +function camelCase( string ) { + return string.replace( /-([\da-z])/gi, function( all, letter ) { + return letter.toUpperCase(); + } ); +} - mouseHandled = true; - return true; - }, +function getElementStyles( elem ) { + var key, len, + style = elem.ownerDocument.defaultView ? + elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : + elem.currentStyle, + styles = {}; - _mouseMove: function( event ) { + if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { + len = style.length; + while ( len-- ) { + key = style[ len ]; + if ( typeof style[ key ] === "string" ) { + styles[ camelCase( key ) ] = style[ key ]; + } + } - // Only check for mouseups outside the document if you've moved inside the document - // at least once. This prevents the firing of mouseup in the case of IE<9, which will - // fire a mousemove event if content is placed under the cursor. See #7778 - // Support: IE <9 - if ( this._mouseMoved ) { + // Support: Opera, IE <9 + } else { + for ( key in style ) { + if ( typeof style[ key ] === "string" ) { + styles[ key ] = style[ key ]; + } + } + } - // IE mouseup check - mouseup happened when mouse was out of window - if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && - !event.button ) { - return this._mouseUp( event ); + return styles; +} - // Iframe mouseup check - mouseup occurred in another document - } else if ( !event.which ) { +function styleDifference( oldStyle, newStyle ) { + var diff = {}, + name, value; - // Support: Safari <=8 - 9 - // Safari sets which to 0 if you press any of the following keys - // during a drag (#14461) - if ( event.originalEvent.altKey || event.originalEvent.ctrlKey || - event.originalEvent.metaKey || event.originalEvent.shiftKey ) { - this.ignoreMissingWhich = true; - } else if ( !this.ignoreMissingWhich ) { - return this._mouseUp( event ); + for ( name in newStyle ) { + value = newStyle[ name ]; + if ( oldStyle[ name ] !== value ) { + if ( !shorthandStyles[ name ] ) { + if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { + diff[ name ] = value; } } } + } - if ( event.which || event.button ) { - this._mouseMoved = true; - } - - if ( this._mouseStarted ) { - this._mouseDrag( event ); - return event.preventDefault(); - } + return diff; +} - if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { - this._mouseStarted = - ( this._mouseStart( this._mouseDownEvent, event ) !== false ); - ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) ); - } +// Support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} - return !this._mouseStarted; - }, +$.effects.animateClass = function( value, duration, easing, callback ) { + var o = $.speed( duration, easing, callback ); - _mouseUp: function( event ) { - this.document - .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) - .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); + return this.queue( function() { + var animated = $( this ), + baseClass = animated.attr( "class" ) || "", + applyClassChange, + allAnimations = o.children ? animated.find( "*" ).addBack() : animated; - if ( this._mouseStarted ) { - this._mouseStarted = false; + // Map the animated objects to store the original styles. + allAnimations = allAnimations.map( function() { + var el = $( this ); + return { + el: el, + start: getElementStyles( this ) + }; + } ); - if ( event.target === this._mouseDownEvent.target ) { - $.data( event.target, this.widgetName + ".preventClickEvent", true ); - } + // Apply class change + applyClassChange = function() { + $.each( classAnimationActions, function( i, action ) { + if ( value[ action ] ) { + animated[ action + "Class" ]( value[ action ] ); + } + } ); + }; + applyClassChange(); - this._mouseStop( event ); - } + // Map all animated objects again - calculate new styles and diff + allAnimations = allAnimations.map( function() { + this.end = getElementStyles( this.el[ 0 ] ); + this.diff = styleDifference( this.start, this.end ); + return this; + } ); - if ( this._mouseDelayTimer ) { - clearTimeout( this._mouseDelayTimer ); - delete this._mouseDelayTimer; - } + // Apply original class + animated.attr( "class", baseClass ); - this.ignoreMissingWhich = false; - mouseHandled = false; - event.preventDefault(); - }, + // Map all animated objects again - this time collecting a promise + allAnimations = allAnimations.map( function() { + var styleInfo = this, + dfd = $.Deferred(), + opts = $.extend( {}, o, { + queue: false, + complete: function() { + dfd.resolve( styleInfo ); + } + } ); - _mouseDistanceMet: function( event ) { - return ( Math.max( - Math.abs( this._mouseDownEvent.pageX - event.pageX ), - Math.abs( this._mouseDownEvent.pageY - event.pageY ) - ) >= this.options.distance - ); - }, + this.el.animate( this.diff, opts ); + return dfd.promise(); + } ); - _mouseDelayMet: function( /* event */ ) { - return this.mouseDelayMet; - }, + // Once all animations have completed: + $.when.apply( $, allAnimations.get() ).done( function() { - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function( /* event */ ) {}, - _mouseDrag: function( /* event */ ) {}, - _mouseStop: function( /* event */ ) {}, - _mouseCapture: function( /* event */ ) { return true; } -} ); + // Set the final class + applyClassChange(); + // For each animated element, + // clear all css properties that were animated + $.each( arguments, function() { + var el = this.el; + $.each( this.diff, function( key ) { + el.css( key, "" ); + } ); + } ); + // This is guarnteed to be there if you use jQuery.speed() + // it also handles dequeuing the next anim... + o.complete.call( animated[ 0 ] ); + } ); + } ); +}; +$.fn.extend( { + addClass: ( function( orig ) { + return function( classNames, speed, easing, callback ) { + return speed ? + $.effects.animateClass.call( this, + { add: classNames }, speed, easing, callback ) : + orig.apply( this, arguments ); + }; + } )( $.fn.addClass ), -// $.ui.plugin is deprecated. Use $.widget() extensions instead. -var plugin = $.ui.plugin = { - add: function( module, option, set ) { - var i, - proto = $.ui[ module ].prototype; - for ( i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args, allowDisconnected ) { - var i, - set = instance.plugins[ name ]; + removeClass: ( function( orig ) { + return function( classNames, speed, easing, callback ) { + return arguments.length > 1 ? + $.effects.animateClass.call( this, + { remove: classNames }, speed, easing, callback ) : + orig.apply( this, arguments ); + }; + } )( $.fn.removeClass ), - if ( !set ) { - return; - } + toggleClass: ( function( orig ) { + return function( classNames, force, speed, easing, callback ) { + if ( typeof force === "boolean" || force === undefined ) { + if ( !speed ) { - if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || - instance.element[ 0 ].parentNode.nodeType === 11 ) ) { - return; - } + // Without speed parameter + return orig.apply( this, arguments ); + } else { + return $.effects.animateClass.call( this, + ( force ? { add: classNames } : { remove: classNames } ), + speed, easing, callback ); + } + } else { - for ( i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); + // Without force parameter + return $.effects.animateClass.call( this, + { toggle: classNames }, force, speed, easing ); } - } - } -}; - - - -var safeActiveElement = $.ui.safeActiveElement = function( document ) { - var activeElement; + }; + } )( $.fn.toggleClass ), - // Support: IE 9 only - // IE9 throws an "Unspecified error" accessing document.activeElement from an