\\n ' + content + '<\\/div>\\n';\n }\n\n $('body').append(template);\n $('body').addClass('has-modal u-body--overlay-open');\n };\n\n base.init();\n };\n\n\n})( jQuery );\n","\n\n\n//------------------------------------------------\\\\\n// Charlie Filter\n//------------------------------------------------\\\\\n\n\n;(function ( $ ) {\n if (!$.charlie) {\n $.charlie = {};\n }\n\n $.charlie.filter = function() {\n var colors = [\n 'opt-1',\n 'opt-2',\n 'opt-3',\n 'opt-4',\n 'opt-5',\n 'opt-6',\n 'opt-7',\n 'opt-8',\n 'opt-9',\n 'opt-10',\n 'opt-11',\n 'opt-12',\n 'opt-13',\n 'opt-14',\n 'opt-15'\n ];\n\n var arrayClean = function (array, deleteValue) {\n for (var i = 0; i < array.length; i++) {\n if (array[i] == deleteValue) {\n array.splice(i, 1);\n i--;\n }\n }\n return array;\n };\n\n var assign_input_to_value = function(input) {\n var arr = input.val().split(',');\n var arr = arrayClean(arr, \"\");\n\n return arr.map(function(v) {\n return parseInt(v);\n });\n }\n\n var filters = {\n company: assign_input_to_value($('#js_filter_input_company')),\n office: assign_input_to_value($('#js_filter_input_office')),\n team: assign_input_to_value($('#js_filter_input_team')),\n team_member: assign_input_to_value($('#js_filter_input_team_member')),\n };\n\n /// Color algo\n color_selector = function(direction) {\n switch (direction) {\n case 'ASC':\n first = colors.shift();\n colors.push(first);\n return first;\n case 'DESC':\n last = colors.pop();\n colors.unshift(last);\n return last;\n default:\n throw new Error(\"unsupported direction, try 'ASC' or 'DESC'.\");\n }\n }\n\n function Filter(tag) {\n var id = tag.data('id');\n var uuid = tag.data('uuid');\n var name = tag.data('name');\n var initials = tag.data('initials');\n var filter_type = tag.data('filter-type');\n var color = color_selector('ASC');\n var avatar = avatar_url(tag);\n var reference = '.js-filter-option-selected[data-uuid=\"' + tag.data('uuid') + '\"]';\n\n this.reference = function() {\n return reference;\n }\n\n this.render_to_card = function() {\n return render_to_card();\n };\n\n function avatar_url(tag) {\n return tag.data('avatar-url');\n }\n\n function render_to_card() {\n return [\n \"
\",\n render_icon(filter_type),\n \"
\" +\n name +\n remove_icon() +\n \"
\",\n \"
\",\n \"
\",\n ].join(\"\");\n }\n\n\n function render_icon(type) {\n return \"
\" + select_icon(type) + \"
\"\n }\n\n function select_icon(type) {\n switch (type) {\n case 'company':\n return company_icon();\n\n case 'office':\n return company_icon();\n\n case 'team':\n return team_icon();\n\n case 'team_member':\n return initials;\n\n default:\n throw new Error('Filter type is not allowed, try office, team or team member');\n }\n\n }\n\n function company_icon() {\n return [\n \"
\",\n \"Company Profile icon \",\n \" \",\n \" \"\n ].join(\"\");\n }\n\n function team_icon() {\n return [\n \"
\",\n \"Team Icon \",\n \" \",\n \" \",\n \" \",\n \" \",\n \" \"\n ].join(\"\");\n }\n\n function remove_icon() {\n return [\n \"
\",\n \"
\",\n \"Close icon \",\n \" \",\n \" \",\n \"
\"\n ].join(\"\");\n }\n }\n\n var bind_filter_tag_events_to = function(tag) {\n tag.on('click', function() {\n var id = $(this).data('id');\n var type = $(this).data('filter-type');\n\n remove_filter_from_hash(id, type, filters);\n update_filter_input_for_type(type, filters);\n\n remove_filter($(this));\n color_selector('DESC');\n toggle_suggestion_if(any_suggestions());\n });\n };\n\n var add_filter = function(filter_option) {\n var filter = new Filter(filter_option);\n var uuid = filter_option.data('uuid');\n var clone = $('.js-filter-option[data-uuid=\"' + uuid + '\"]');\n $('.js-filter-input').append(filter.render_to_card());\n bind_filter_tag_events_to($(filter.reference()));\n clone.addClass('is-hidden is-filter');\n filter_option.addClass('is-hidden is-filter');\n filter_btn_now_active();\n show_add_a_filter_tag(any_filters_applied(filters), $('.js-filter-empty-state'));\n }\n\n var remove_filter = function(filter) {\n var filter_option = filter.data('uuid');\n var reference = $('.js-filter-option[data-uuid=\"' + filter_option + '\"]');\n\n reference.removeClass('is-filter');\n if (reference.hasClass('is-matched')) {\n reference.removeClass('is-hidden');\n }\n\n filter_btn_now_active();\n show_add_a_filter_tag(any_filters_applied(filters), $('.js-filter-empty-state'));\n filter.remove();\n }\n\n var filter_btn_now_active = function() {\n $('.js-apply-filter-btn').addClass('c-cal__action-wrapper--primary');\n }\n\n var expand_filter_dropdown = function(filter_input) {\n var reference = filter_input.data('reference');\n var filter = $('.js-filter[data-reference=\"'+ reference +'\"]');\n var action = $('.js-dropdown-action[data-reference=\"' + reference + '\"]');\n var dropdown = $('.js-filter-dropdown[data-reference=\"'+ reference +'\"]');\n var is_open = dropdown.hasClass('is-open');\n var icon = action.find('.js-dropdown-icon')\n\n if (is_open) {\n filter.removeClass('is-open');\n dropdown.removeClass('is-open');\n action.removeClass('is-open');\n icon.removeClass('o-icon--270');\n icon.addClass('o-icon--90');\n\n\n } else {\n filter.addClass('is-open');\n dropdown.addClass('is-open');\n action.addClass('is-open');\n icon.removeClass('o-icon--90');\n icon.addClass('o-icon--270');\n $('.js-search').focus();\n }\n }\n\n var add_filter_color_to_events = function(filter) {\n var uuid = filter.data('uuid');\n var color = color_selector('ASC');\n\n filter.addClass(color);\n $('.js-cal-event[data-filter=\"' + uuid + '\"]').addClass(color);\n }\n\n var remove_filter_from_hash = function(id, type, filters) {\n switch (type) {\n case 'company':\n var arr = filters.company;\n remove_item_from_array(id, arr);\n return filters;\n\n case 'office':\n var arr = filters.office;\n remove_item_from_array(id, arr);\n return filters;\n\n case 'team':\n var arr = filters.team;\n remove_item_from_array(id, arr);\n return filters;\n\n case 'team_member':\n var arr = filters.team_member;\n remove_item_from_array(id, arr);\n return filters;\n\n default:\n throw new Error('Filter type is not allowed, try office, team or team member');\n }\n }\n\n var remove_item_from_array = function(id, array) {\n array.remove(id);\n }\n\n var add_filter_to_hash = function(id, type, filters) {\n switch (type) {\n case 'company':\n var arr = filters.company;\n add_item_to_array(id, arr);\n return filters;\n\n case 'office':\n var arr = filters.office;\n add_item_to_array(id, arr);\n return filters;\n\n case 'team':\n var arr = filters.team;\n add_item_to_array(id, arr);\n return filters;\n\n case 'team_member':\n var arr = filters.team_member;\n add_item_to_array(id, arr);\n return filters;\n\n default:\n throw new Error('Filter type is not allowed, try office, team or team member');\n }\n }\n\n var add_item_to_array = function(id, array) {\n array.push(id);\n }\n\n var update_filter_input_for_type = function(type, filters) {\n switch (type) {\n case 'company':\n var val = filters.company;\n var input = $('#js_filter_input_company');\n return update_hidden_input(input, val);\n\n case 'office':\n var val = filters.office;\n var input = $('#js_filter_input_office');\n return update_hidden_input(input, val);\n\n case 'team':\n var val = filters.team;\n var input = $('#js_filter_input_team');\n return update_hidden_input(input, val);\n\n case 'team_member':\n var val = filters.team_member;\n var input = $('#js_filter_input_team_member');\n return update_hidden_input(input, val);\n\n default:\n throw new Error('Filter type is not allowed, try office, team or team member');\n }\n }\n\n var update_hidden_input = function(input, val) {\n input.val(val);\n }\n\n var any_filters_applied = function(filters) {\n if (\n filters.team_member.length ||\n filters.company.length ||\n filters.office.length ||\n filters.team.length\n ) { return true; }\n\n return false;\n }\n\n var show_add_a_filter_tag = function(any_filters, filter) {\n if (any_filters) {\n filter.addClass('is-hidden');\n } else {\n filter.removeClass('is-hidden');\n }\n }\n\n var submit_filter_form = function(action) {\n action.addClass('is-loading');\n var form = action.attr('form');\n\n setTimeout(function() { $('#' + form ).submit(); }, 1);\n action.prop('disabled', 'true');\n }\n\n var toggle_suggestion_if = function(state) {\n if (state) {\n hide_suggestions_empty_state();\n } else {\n show_suggestions_empty_state();\n }\n }\n\n var any_suggestions = function() {\n var count = 0;\n\n $('.js-filter-suggestion').each(function() {\n var is_filter = $(this).hasClass('is-filter');\n if (is_filter) { count += 1; }\n\n return count;\n })\n\n if (count < 3 ) {\n return true;\n } else { return false; }\n }\n\n var show_suggestions_empty_state = function() {\n $('.js-when-no-suggestion').removeClass('is-hidden');\n }\n\n var hide_suggestions_empty_state = function() {\n $('.js-when-no-suggestion').addClass('is-hidden');\n }\n\n // User events\n $('.js-dropdown-action').on('click', function() {\n expand_filter_dropdown($(this));\n });\n\n $('.js-filter-input').on('click', function(e) {\n if ($(e.target).is('.js-tag-target')) {\n return;\n } else {\n expand_filter_dropdown($(this));\n }\n });\n\n $('.js-filter-option').on('click', function() {\n var id = $(this).data('id');\n var type = $(this).data('filter-type');\n\n add_filter_to_hash(id, type, filters);\n update_filter_input_for_type(type, filters);\n\n add_filter($(this));\n toggle_suggestion_if(any_suggestions());\n });\n\n $('.js-submit-filter').on('click', function(e) {\n e.preventDefault();\n console.log('prevented');\n filter_btn_now_active();\n submit_filter_form($(this));\n })\n\n $('.js-filter-option-selected').each(function() {\n add_filter_color_to_events($(this));\n })\n\n if ($('.js-filter-option-selected').length) {\n bind_filter_tag_events_to($('.js-filter-option-selected'));\n }\n\n toggle_suggestion_if(any_suggestions());\n show_add_a_filter_tag(any_filters_applied(filters), $('.js-filter-empty-state'));\n }\n\n})( jQuery );\n","\n\n\n//------------------------------------------------\\\\\n// Charlie Flow controller\n//------------------------------------------------\\\\\n\n\n;(function ( $ ) {\n if (!$.charlie) {\n $.charlie = {};\n }\n // Checklist specific variables\n $.charlie.flowController = function() {\n var base = $(this),\n $flow = $('.js-flow-controller'),\n $steps = $('.js-flow-step'),\n $btns = $('.js-flow-btns'),\n $footer = $('.js-flow-footer');\n\n // Create placeholder objects for extensibility\n base.helpers = {};\n base.consts = {};\n base.events = {};\n\n // Define changing variables\n var currentStep, currentStepIndex = 1;\n\n // Consts that get set on load\n base.consts.stepCount = 0;\n\n base.init = function() {\n base.helpers.countSteps();\n base.bindEvents();\n };\n\n base.bindEvents = function() {\n $steps.on('click', function() {\n var step = $(this);\n\n base.events.moveToStep(step);\n base.helpers.currentStep();\n base.helpers.setCurrentStep();\n });\n\n $btns.on('click', function() {\n var btn = $(this);\n\n base.events.traverseSteps(btn);\n base.helpers.currentStep();\n base.helpers.setCurrentStep();\n });\n };\n\n base.events.moveToStep = function(step) {\n if(step.hasClass('is-current')) {\n // Do nothing\n } else {\n $steps.not(step).removeClass('is-current').addClass('not-current');\n step.removeClass('not-current').addClass('is-current');\n }\n };\n\n base.events.traverseSteps = function(stepBtn) {\n base.helpers.setCurrentStep();\n var direction = stepBtn.data('direction').toLowerCase();\n var nextStep, nextStepIndex;\n\n switch (direction) {\n case 'next':\n nextStepIndex = currentStepIndex + 1;\n nextStep = $('.js-flow-step[data-step=' + nextStepIndex + ']');\n break;\n\n case 'previous':\n nextStepIndex = currentStepIndex - 1;\n nextStep = $('.js-flow-step[data-step=' + nextStepIndex + ']');\n break;\n\n default:\n // Do nothing\n }\n\n $steps.not(nextStep).removeClass('is-current').addClass('not-current');\n nextStep.removeClass('not-current').addClass('is-current');\n };\n\n base.helpers.countSteps = function() {\n $steps.each(function() {\n base.consts.stepCount += 1;\n });\n\n $('.js-flow-footer').data('total-steps', base.consts.stepCount);\n };\n\n base.helpers.currentStep = function() {\n currentStep = $('.js-flow-step.is-current');\n currentStepIndex = currentStep.data('step');\n };\n\n base.helpers.setCurrentStep = function() {\n var _currentStep = parseInt(currentStepIndex);\n\n if (_currentStep === 1) {\n $footer.removeClass('is-on-middle-step is-on-last-step');\n $footer.addClass('is-on-first-step');\n\n } else if (_currentStep > 1 && _currentStep < base.consts.stepCount) {\n $footer.removeClass('is-on-first-step is-on-last-step');\n $footer.addClass('is-on-middle-step');\n\n } else if (_currentStep === base.consts.stepCount){\n $footer.removeClass('is-on-first-step is-on-middle-step');\n $footer.addClass('is-on-last-step');\n\n } else {\n // Do nothing\n }\n };\n\n base.init();\n };\n\n})( jQuery );\n","\n;(function ( $ ) {\n if (!$.charlie) {\n $.charlie = {};\n }\n\n // Remove component from DOM\n $.charlie.removeComponent = function ( target ) {\n target.remove();\n };\n\n $.charlie.replaceComponent = function ( target, partial ) {\n target.replaceWith(partial);\n };\n\n $.charlie.hideComponent = function(target) {\n target.slideUp(300);\n };\n\n $.charlie.toggleSection = function(hide_content, target) {\n if ( hide_content ) {\n $(target).addClass('is-hidden');\n } else {\n $(target).removeClass('is-hidden');\n }\n }\n\n})( jQuery );\n","// ------------------------------------------------\\\\\n// Charlie modal dialogs, popups and alerts\n// ------------------------------------------------\\\\\n\n;(function( $ ) {\n if (!$.charlie) {\n $.charlie = {};\n }\n\n $.charlie.modal = function( el, options ) {\n var base = this;\n var modal, card;\n\n if ($('body').hasClass('has-modal') && typeof base.close !== 'undefined') {\n // If a modal is already open close it. This usually happens when a trigger\n // is double clicked so removing the original for the second should be OK.\n base.close();\n }\n\n base._rand = Math.round(Math.random() * 99999);\n base.$el = $(el);\n base.el = el;\n base.$el.data('charlie-modal', base); // reverse reference to DOM object\n\n base.init = function() {\n base.options = $.extend({}, $.charlie.modal.defaultOptions, options);\n\n base.buildHTML();\n base.bindEvents();\n base.isOpen = true;\n base.confirm = false;\n };\n\n base.buildHTML = function() {\n var modalClasses = [ 'modal-card js-modal-card', ];\n var headerClasses = [ 'modal-card__header', ];\n var template;\n\n if (base.options.type === 'primary') {\n headerClasses.push('cds-color--primary');\n } else if (base.options.type === 'secondary') {\n headerClasses.push('cds-color--primary');\n } else if (base.options.type === 'success') {\n headerClasses.push('cds-color--success');\n } else if (base.options.type === 'danger') {\n headerClasses.push('cds-color--danger');\n } else if (base.options.type === 'warning') {\n headerClasses.push('cds-color--warning');\n } else if (base.options.type === 'primary-action') {\n headerClasses.push('cds-color--primary-action')\n }\n\n if (base.options.animation === 'default') {\n modalClasses.push('anim--scale-in-now');\n } else {\n modalClasses.push(base.options.animation);\n }\n\n template = [\n '
',\n ' ',\n '
' + base.options.title + ' ',\n ' ',\n ' ',\n ];\n\n if (base.options.form === false) {\n template.splice(4, 0, '
');\n template.splice(5, 0, '
');\n }\n\n // Add overlay to body, and append the dialog box\n $.charlie.overlay(base.options.container_size, 'modal');\n\n modal = $('.js-modal');\n modal.find('.js-overlay-wrap').append(template.join('\\n'));\n card = modal.find('.js-modal-card');\n\n if (base.options.form !== false) {\n card.append(base.options.form);\n\n } else {\n if ( base.options.content !== false ) {\n base.addContent();\n }\n base.addActions();\n }\n\n $('body').trigger('modal:open');\n };\n\n base.addContent = function() {\n var cardContentWrap = card.find('.js-modal-content');\n var cardContent = '
' + base.options.content + '
';\n\n cardContentWrap.html(cardContent);\n };\n\n base.addActions = function() {\n var cardActionsWrap = card.find('.js-modal-actions');\n var modalActions = '
' + base.options.close_btn + ' ';\n var confirmBtnClasses;\n var confirmBtnAttributes = [];\n var confirmBtn;\n\n if ( base.options.href !== false ) {\n confirmBtnClasses = [\n 'c-button',\n 'js-confirm-btn js-close-btn',\n ];\n\n if (base.options.type === 'success') {\n confirmBtnClasses.push('cds-color-interaction--success');\n }\n\n if (base.options.type === 'warning') {\n confirmBtnClasses.push('cds-color-interaction--warning');\n }\n\n if (base.options.type === 'danger') {\n confirmBtnClasses.push('cds-color-interaction--danger');\n }\n\n if (base.options.loader !== false) {\n confirmBtnClasses.push('js-confirm-loader');\n }\n\n if (base.options.remote !== false) {\n confirmBtnAttributes.push('data-remote=\"' + base.options.remote + '\"');\n }\n\n if (base.options.method !== false) {\n confirmBtnAttributes.push('data-method=\"' + base.options.method + '\"');\n }\n\n confirmBtn = '
' + base.options.confirm_btn + ' ';\n\n modalActions += confirmBtn;\n }\n\n cardActionsWrap.html(modalActions);\n };\n\n base.bindEvents = function() {\n if (base.options.overlay_clickable === true) {\n var cardClicked = false;\n\n modal.on('mousedown', function() {\n if ( !cardClicked ) {\n base.close();\n }\n cardClicked = false;\n });\n\n card.on('mousedown', function() {\n cardClicked = true;\n });\n }\n\n modal.find('.js-close-btn').on('click', function() {\n if ( $(this).hasClass('js-confirm-loader') ) {\n base.$el.addClass('is-loading');\n }\n\n if ($(this).hasClass('js-confirm-btn')) {\n base.confirm = true;\n }\n\n base.close();\n });\n\n setTimeout(function() {\n $(window).on('keyup.' + base._rand, function(e) {\n if (e.keyCode === 27) {\n base.close();\n }\n });\n }, 500);\n };\n\n base.close = function(callback) {\n base.isOpen = false;\n $(window).unbind('keyup.' + base._rand);\n\n if (base.confirm) {\n base.$el.trigger('modal:confirming');\n } else {\n base.$el.trigger('modal:cancelling');\n }\n\n modal.removeClass('anim--opacity-in').addClass('anim--opacity-out');\n card.removeClass('anim--scale-in').addClass('anim--scale-out');\n\n setTimeout(function() {\n modal.remove();\n $('body').trigger('modal:close');\n $('body').removeClass('has-modal u-body--overlay-open');\n\n if (typeof callback !== 'undefined') {\n callback();\n }\n }, 1);\n\n return base;\n };\n\n base.init();\n };\n\n $.charlie.modal.defaultOptions = {\n title: 'missing title', // Title of alert box\n content: false, // Load in content with ajax\n form: false, // Load in content with ajax\n type: 'default', // Theme of alert box\n animation: 'default', // Load in animation\n href: false, // Where to go when you click ok\n close_btn: 'Cancel', // Text on close btn\n confirm_btn: 'Confirm action', // Text on confirm btn\n remote: false,\n method: false,\n loader: false,\n eventName: false,\n overlay_clickable: true,\n container_size: 'col-xs-12 col-md-8 offset-md-2 col-lg-6 offset-lg-3',\n };\n\n $.fn.charlieModal = function() {\n\n // Find each link\n // Disable default action if necessary\n // Pass href and options to charlie.modal\n return this.each(function() {\n var $link = $(this),\n loadingTarget;\n\n $link.off().on('click', function(e) {\n e.preventDefault();\n\n // Pass in override or undefined to modal\n var modalOptions = {\n title: $link.attr('data-modal-title'),\n content: $link.attr('data-modal-content'),\n form: $link.attr('data-modal-form'),\n type: $link.attr('data-modal-type'),\n animation: $link.attr('data-modal-animation'),\n loader: $link.attr('data-modal-loader'),\n remote: $link.attr('data-modal-remote'),\n method: $link.attr('data-modal-method'),\n overlay_clickable: $link.attr('data-modal-overlay-clickable'),\n eventName: $link.attr('data-modal-event-name'),\n container_size: $link.attr('data-modal-container-size'),\n close_btn: $link.attr('data-modal-close-btn'),\n confirm_btn: $link.attr('data-modal-confirm-btn'),\n };\n\n if ( $link.attr('href') ) {\n modalOptions.href = $link.attr('href');\n } else if ( $link.attr('data-modal-path') ) {\n modalOptions.href = $link.attr('data-modal-path');\n }\n\n if ( $link.attr('data-modal-loader-target') ) {\n loadingTarget = $link.attr('data-modal-loader-target');\n } else {\n loadingTarget = $link;\n }\n\n (new $.charlie.modal(loadingTarget, modalOptions));\n });\n });\n };\n\n})( jQuery );\n","\n\n//------------------------------------------------\\\\\n// Charlie Onboarding Menu\n//------------------------------------------------\\\\\n\n;(function( $ ) {\n if (!$.charlie) {\n $.charlie = {};\n }\n\n $.charlie.onboardingMenu = function(options) {\n var base = this;\n\n base.init = function() {\n base.options = $.extend({},\n $.charlie.onboardingMenu.defaultOptions, options);\n\n base.$navbar = $(base.options.navbar);\n base.$navMobile = $(base.options.navMobile);\n base.$menuBtnMobile = $(base.options.menuBtnMobile);\n\n if ( base.$navbar.length ) {\n // Setup useful references for later use\n base.navbar = base.options.navbar;\n base.$navbar.data(\"charlie-onboardingMenu\", base);\n\n base.$stepCounter = $(base.options.stepCounter);\n base.completedSteps = base.$stepCounter.data('completed-steps');\n base.currentStep = base.$stepCounter.data('current-step');\n\n // Put your initialization code here\n // console.log('charlie onboardingMenu init');\n base.buildStates();\n base.bindEvents();\n\n } else {\n console.log(\"Couldn't find navbar with class: \" + navbar);\n }\n };\n\n base.buildStates = function() {\n // Get links and reset classes on ajaxComplete\n base.navArray = base.$navbar.find(base.options.navItems);\n base.navArray.removeClass('is-disabled is-complete is-current is-available');\n base.setStates(base.navArray);\n\n if ( base.$navMobile.length ) {\n base.mobileArray = base.$navMobile.find(base.options.navItems);\n base.mobileArray.removeClass('is-disabled is-complete is-current is-available');\n base.setStates(base.mobileArray, -1);\n }\n\n // console.log(base.currentStep);\n // console.log('charlie onboardingMenu built states for all nav items');\n };\n\n base.setStates = function(navArray, offset) {\n offset = offset || 0;\n // Add styling to all links\n navArray.each( function(i) {\n var this_step = $(this);\n\n if ( i > base.completedSteps + offset ) { this_step.addClass('is-disabled'); }\n if ( i < base.completedSteps + offset ) { this_step.addClass('is-complete'); }\n if ( i == base.completedSteps + offset ) { this_step.addClass('is-available'); }\n if ( i == base.currentStep + offset ) { this_step.addClass('is-current'); }\n });\n };\n\n base.bindEvents = function() {\n //// Add events related to this particular navbar\n $(document).on('onboardingStepChange', function() {\n base.$stepCounter = $(base.options.stepCounter);\n base.completedSteps = base.$stepCounter.data('completed-steps');\n base.currentStep = base.$stepCounter.data('current-step');\n base.buildStates();\n });\n };\n\n // Initialize the onboarding navbar\n base.init();\n };\n\n $.charlie.onboardingMenu.defaultOptions = {\n navbar: '.js-onboarding-nav', // Class of item\n navMobile: '.js-onboarding-mobile-nav', // Class of item\n menuBtnMobile: '.js-onboarding-mobile-nav-btn',\n stepCounter: '.js-onboarding-steps',\n navItems: '.js-onboarding-nav__item', // Class of item\n };\n\n $.fn.charlieInitOnboardingMenu = function(options) {\n (new $.charlie.onboardingMenu(options));\n };\n\n $.fn.charlieReloadOnboardingMenu = function() {\n $(document).trigger('onboardingStepChange');\n };\n\n\n})( jQuery );\n","\n\n//------------------------------------------------\\\\\n// Charlie permission helpers\n//------------------------------------------------\\\\\n\n;(function ( $ ) {\n if (!$.charlie) {\n $.charlie = {};\n }\n\n // $.fn.charlieShowPermissions = function() {\n // var base = $(this);\n //\n // base.on('mouseenter', function() {\n // $(this).next().addClass('go');\n // });\n // base.on('mouseleave', function() {\n // $(this).next().removeClass('go');\n // });\n // };\n\n})( jQuery );\n\n\n$(document).on('ready ajaxComplete', function() {\n var permissionHovers = $('.js-permission-hover');\n\n permissionHovers.on('mouseenter', function() {\n $(this).next().addClass('has-info');\n });\n\n permissionHovers.on('mouseleave', function() {\n $(this).next().removeClass('has-info');\n });\n})\n","\"use strict\";\n\n(function ($) {\n if (!$.charlie) {\n $.charlie = {};\n }\n\n $.charlie.pollForJobStatus = {\n path: null,\n init: function init(path, jobIdPlaceholder) {\n this.path = path;\n this.jobIdPlaceholder = jobIdPlaceholder;\n },\n call: function call() {\n var _this = this;\n\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n _ref$jobId = _ref.jobId,\n jobId = _ref$jobId === void 0 ? requiredArgument('jobId') : _ref$jobId,\n _ref$onComplete = _ref.onComplete,\n onComplete = _ref$onComplete === void 0 ? requiredArgument('onComplete') : _ref$onComplete,\n _ref$delay = _ref.delay,\n delay = _ref$delay === void 0 ? 3000 : _ref$delay,\n _ref$timeout = _ref.timeout,\n timeout = _ref$timeout === void 0 ? 300000 : _ref$timeout,\n onSuccess = _ref.onSuccess,\n onFail = _ref.onFail,\n onProblem = _ref.onProblem;\n\n var interval = setInterval(function () {\n $.ajax({\n type: 'GET',\n url: _this.path.replace(_this.jobIdPlaceholder, jobId),\n dataType: 'json',\n success: function success(response) {\n // A jobId from an enqueued job defined in a sidekiq worker\n // that includes the module Sidekiq::Status::Worker can be\n // used to poll the sidekiq controller for job status. The\n // status column will return one of these values:\n // :queued, :working, :complete, :failed or :interrupted.\n // It will be nil after expiry (30 minutes).\n if (typeof onSuccess !== 'undefined') {\n onSuccess(response);\n }\n\n switch (response.status) {\n case 'complete':\n clearInterval(interval);\n onComplete();\n break;\n\n case 'failed':\n clearInterval(interval);\n if (typeof onFail !== 'undefined') {\n onFail();\n }\n\n break;\n\n default:\n if (response.status !== 'queued' && response.status !== 'working') {\n clearInterval(interval);\n\n if (typeof onProblem !== 'undefined') {\n onProblem();\n } else {\n var unhandledSidekiqStatusError = new Error(\"Unhandled sidekiq response status: '\".concat(response.status, \"'\"));\n appsignal.sendError(unhandledSidekiqStatusError);\n }\n }\n }\n },\n error: function error(response) {\n clearInterval(interval);\n\n if (typeof onProblem !== 'undefined') {\n onProblem();\n }\n }\n });\n }, delay);\n setTimeout(function () {\n clearInterval(interval);\n }, timeout);\n }\n };\n})(jQuery);\n","(function ( $ ) {\n if (!$.charlie) {\n $.charlie = {};\n }\n\n $.charlie.requiredArgument = function(argName) {\n appsignal.sendError(new Error(argName + 'is required'));\n };\n\n})( jQuery );\n","\n\n\n//------------------------------------------------\\\\\n// Charlie Search\n//------------------------------------------------\\\\\n\n\n;(function ( $ ) {\n if (!$.charlie) {\n $.charlie = {};\n }\n // Checklist specific variables\n $.charlie.search = function(options) {\n var base = $(this),\n defaults = {};\n\n base.init = function () {\n base.options = $.extend(defaults.options, options);\n base.search( base.options );\n };\n\n base.search = function(options) {\n var matched_types = {\n company: 0,\n office: 0,\n team: 0,\n team_member: 0,\n };\n\n base.hide_filter_types();\n\n $(options.searchable).each(function(){\n var query = options.query.toString().toLowerCase();\n var terms = $(this).data( options.terms ).toString().toLowerCase();\n var matched = new RegExp( query ).test( terms );\n var is_filter = $(this).hasClass('is-filter');\n\n // If query has any input\n if (query.length) {\n\n // And we find a matched query term\n if (matched) {\n var type = $(this).data('filter-type');\n $(this).addClass('is-matched');\n\n // But the matched term is already a filter\n if (is_filter) {\n // Do nothing\n\n // Or it is not an applied filter\n } else {\n $(this).removeClass('is-hidden');\n base.increment_matched_types(type, matched_types);\n\n }\n\n // If we don't find a matched query\n } else {\n $(this).addClass('is-hidden');\n $(this).removeClass('is-matched');\n }\n\n base.show_filter_types(matched_types);\n\n // There is nothing currently being queried\n } else {\n $(this).addClass('is-hidden');\n $(this).removeClass('is-matched');\n }\n })\n\n if (base.any_matches(matched_types)) {\n base.hide_suggestions();\n } else {\n base.show_suggestions();\n }\n }\n\n base.increment_matched_types = function(type, types) {\n switch (type) {\n case 'company':\n return types.company += 1;\n case 'office':\n return types.office += 1;\n case 'team':\n return types.team += 1;\n case 'team_member':\n return types.team_member += 1;\n default:\n throw new Error('filter type is not one of the permitted options: company, office, team or team_member')\n }\n }\n\n base.hide_filter_types = function() {\n $('.js-filter-types').addClass('is-hidden');\n }\n\n base.show_filter_types = function(types) {\n if (types.company > 0) {\n $('.js-filter-types[data-filter-type=\"company\"]').removeClass('is-hidden');\n }\n\n if (types.office > 0) {\n $('.js-filter-types[data-filter-type=\"office\"]').removeClass('is-hidden');\n }\n\n if (types.team > 0) {\n $('.js-filter-types[data-filter-type=\"team\"]').removeClass('is-hidden');\n }\n\n if (types.team_member > 0) {\n $('.js-filter-types[data-filter-type=\"team_member\"]').removeClass('is-hidden');\n }\n }\n\n base.show_suggestions = function() {\n $('.js-filter-suggestions').removeClass('is-hidden');\n }\n\n base.hide_suggestions = function() {\n $('.js-filter-suggestions').addClass('is-hidden');\n }\n\n base.any_matches = function(types) {\n if (\n types.company > 0 ||\n types.office > 0 ||\n types.team > 0 ||\n types.team_member > 0\n ) {\n return true;\n } else { return false; }\n }\n\n defaults.options = {\n query: '',\n terms: 'searchable-terms',\n searchable: '.js-searchable'\n };\n\n base.init();\n };\n\n})( jQuery );\n","\n\n//------------------------------------------------\\\\\n// Charlie State controller\n//------------------------------------------------\\\\\n\n;(function ( $ ) {\n if (!$.charlie) {\n $.charlie = {};\n }\n\n $.charlie.stateController = (function(_state_controller) {\n var all_states = 'is-showing is-hidden is-active is-disabled is-editing is-collapsed';\n _state_controller.public = {};\n _state_controller.private = {}; // Returns a testable object that is globally available\n\n // Public Method\n _state_controller.public.set_state = function(origin) {\n var options = $.charlie.stateController.private.construct(origin);\n $.charlie.stateController.private.init(options);\n };\n\n // Private (only by name) on $.charlie.stateController function, this patterns allows us to test methods\n _state_controller.private.init = function(options) {\n _state_controller.private.update_states({\n state: options.state,\n reset_state: options.reset_state,\n receivers: options.receivers,\n listeners: options.listeners,\n });\n $(document).trigger('charlieLayoutUpdated'); // Layout updated\n }\n\n _state_controller.private.construct = function(origin) {\n // This method constructs the core options that\n // inform the state handling process\n\n var sender = origin.data('set-state-of'), // Assigns a reference to where state should be set\n resetter = origin.data('reset-state-of') || null; // Assigns a reference to where reset_state should be set\n\n var options = {\n state: origin.data('set-state'), // The state that should be applied\n reset_state: origin.data('reset-state') || null, // The reset_state that should be applied\n receivers: $('.js-receive-state[data-receive-state=\"' + sender + '\"]'), // The receivers of state\n listeners: $('.js-receive-state[data-receive-state=\"' + resetter + '\"]'), // The listeners of reset_state\n };\n\n return options;\n }\n\n _state_controller.private.update_states = function(options) {\n // This method resets state according to what has been defined\n // And then apply's state the appropriate destination\n\n _state_controller.private.reset_states(options.reset_state, options.listeners, options.receivers);\n _state_controller.private.set_states(options.state, options.receivers);\n }\n\n _state_controller.private.reset_states = function(reset_state, listeners, receivers) {\n // This method resets state either by resetting state back to neutral (cleaning the target of any state)\n // Or listens to the reset state that has been sent from a resetter\n\n _state_controller.private.reset_all_states(receivers);\n if (reset_state && listeners) { _state_controller.private.set_states(reset_state, listeners); }\n }\n\n _state_controller.private.set_states = function(state, target) {\n // Dependent on the state that has been supplied, apply's the appropriate state to the target\n switch (state) {\n case 'activate':\n return _state_controller.private.change_state_to('is-active', target);\n case 'show':\n return _state_controller.private.change_state_to('is-showing', target);\n case 'hide':\n return _state_controller.private.change_state_to('is-hidden', target);\n case 'edit':\n return _state_controller.private.change_state_to('is-editing', target);\n case 'disable':\n return _state_controller.private.change_state_to('is-disabled', target);\n case 'collapse':\n return _state_controller.private.change_state_to('is-collapsed', target);\n default:\n throw new Error('Can not set this state on targets');\n }\n }\n\n _state_controller.private.change_state_to = function(state, receivers) { receivers.addClass(state); }\n _state_controller.private.reset_all_states = function(receivers) { receivers.removeClass(all_states); }\n\n return _state_controller;\n })($.charlie.stateController || {});\n\n\n $.fn.charlieContentState = function() {\n var base = $(this),\n type = base.data('type'),\n show = $('.js-content-module[data-show-if~=\"' + type + '\"]'),\n hide = $('.js-content-module[data-hide-if~=\"' + type + '\"]');\n\n if ( base.is(\":checked\") ) {\n show.removeClass('not-visible');\n hide.addClass('not-visible');\n } else {\n show.addClass('not-visible');\n hide.removeClass('not-visible');\n }\n };\n\n})( jQuery );\n","export default class Expand {\n init() {\n this.hideAll();\n this.events();\n this.toggleIcons().removeClass('permission-roles__toggle--hidden');\n }\n\n events() {\n this.expandAllButton().click(() => this.showAll());\n this.collapseAllButton().click(() => this.hideAll());\n\n this.headerCells().click((e) => {\n $(e.target)\n .closest('.permission-roles__head-row')\n .toggleClass('permission-roles__head-row--open');\n $(e.target)\n .closest('.permission-roles__body')\n .find(`.${this.bodyRowClass()}`)\n .toggleClass(this.hiddenClass());\n $(e.target)\n .find(`.${this.toggleIconClass()}`)\n .toggleClass(this.toggleIconOpenClass());\n });\n }\n\n hideAll() {\n this.toggleableHeaders().removeClass('permission-roles__head-row--open');\n this.toggleableRows().addClass(this.hiddenClass());\n this.toggleIcons().removeClass(this.toggleIconOpenClass());\n }\n\n showAll() {\n this.toggleableHeaders().addClass('permission-roles__head-row--open');\n this.toggleableRows().removeClass(this.hiddenClass());\n this.toggleIcons().addClass(this.toggleIconOpenClass());\n }\n\n /**\n * Classes.\n */\n hiddenClass() {\n return 'permission-roles__body-row--hidden';\n }\n\n toggleIconClass() {\n return 'permission-roles__toggle';\n }\n\n toggleIconOpenClass() {\n return 'permission-roles__toggle--open';\n }\n\n bodyRowClass() {\n return 'permission-roles__body-row';\n }\n\n /**\n * Selectors.\n */\n toggleableRows() {\n return $('.permission-roles__table .permission-roles__body .permission-roles__body-row');\n }\n\n toggleableHeaders() {\n return $('.permission-roles__table .permission-roles__head-row');\n }\n\n expandAllButton() {\n return $('.js-permission-roles__expand-all-btn');\n }\n\n collapseAllButton() {\n return $('.js-permission-roles__collapse-all-btn');\n }\n\n headerCells() {\n return $('.permission-roles__head-row');\n }\n\n toggleIcons() {\n return $(`.${this.toggleIconClass()}`);\n }\n}\n","/* global charlie */\n\nimport Expand from './expand';\n\ncharlie.on('ready', () => new Expand().init());\n","require('./jquery');\n","// Ensure that the charlie object exists in jQuery before we start adding things\n// to it.\nif (!$.charlie) {\n $.charlie = {};\n}\n","/**\n * Handles the reviewee exclusions selector, specifically updating visible\n * avatars as the selection changes.\n */\nexport default class Exclusions {\n init() {\n if ($('.js-review-avatars').length > 0) {\n this.initExcludedAvatars();\n }\n\n if ($('.js-exclusion-toggle').length > 0) {\n this.initToggle();\n }\n }\n\n /**\n * Hide avatars when they are excluded from a review.\n */\n initExcludedAvatars() {\n // Handle when the option is selected on the first pass through. This will\n // force only a specific number of avatars to be shown when the option is\n // first displayed.\n $('.js-radio-group').change(() => this.handleChange());\n\n // Note! Deliberately not setting the initialized data attribute here as\n // doing so can cause the component's JS not to add it's events, rendering\n // the Multi Select broken.\n $('.js-exclusion-selector .js-checkbox-input').change(() => this.handleChange());\n\n // Handle when the user returns to the step and has previously selected\n // options. As the option will already be open the change event above won't\n // get fired so we need to do it manually.\n //\n // We also need to use a timeout to force this to happen after the\n // component's JS. If left to it's own devices this will run before the\n // select component has done what it's need to and so avatars won't be\n // hidden. Forcing this to wait ensures it's finished working and the page\n // will be in an expected state.\n //\n // This is seriously hacky :( when everything is moved over we should be\n // able to do away with it, though.\n setTimeout(() => this.handleChange(), 100);\n }\n\n /**\n * Handle selection changes in the exclusions selector. This will hide avatars\n * from Team Members that have been selected and update the count of Team\n * Members included in the review.\n */\n handleChange() {\n const $avatarGroup = $('.js-review-avatars');\n const selected = [];\n\n // Show all so any previously hidden avatars are available if necessary.\n $avatarGroup.find('.is-hidden').removeClass('is-hidden');\n\n // Build an array of selected team members who are being excluded.\n $('.js-exclusions .js-ms-selected-options .e-tag')\n .each((_, element) => selected.push($(element).data('value')));\n\n // Hide exclusions, update the total reviewees and hide avatars so that the\n // limit of avatars displayed isn't exceeded.\n this.hideAvatarsById($avatarGroup, selected);\n\n $('.js-avatar_group-text')\n .html(`${$avatarGroup.find('.js-avatar').not('.is-hidden').length} total`);\n\n this.limitAvatars($avatarGroup);\n }\n\n /**\n * Receives an array of IDs and hides avatars if they match.\n *\n * @param {Object} $avatarGroup Containing object to search for matches in.\n * @param {Array} IDs\n */\n hideAvatarsById($avatarGroup, IDs) {\n const selectors = [];\n IDs.forEach(ID => selectors.push(`.js-avatar[data-member=\"${ID}\"]`));\n $avatarGroup.find(selectors.join(',')).addClass('is-hidden');\n }\n\n /**\n * Hide avatars so that the limit isn't passed.\n *\n * @param {Object} $avatarGroup\n */\n limitAvatars($avatarGroup) {\n const $visibleAvatars = $avatarGroup.find('.js-avatar').not('.is-hidden');\n const limit = $avatarGroup.data('limit');\n const selectors = [];\n\n if ($visibleAvatars.length > limit) {\n $visibleAvatars.slice(limit)\n .each((_, element) => {\n selectors.push(`.js-avatar[data-member=\"${$(element).data('member')}\"]`);\n });\n\n $avatarGroup.find(selectors.join(',')).addClass('is-hidden');\n }\n }\n\n /**\n * Shows the exclusion selector on the reviewee step of the launch flow.\n */\n initToggle() {\n $('.js-exclusion-selector').hide();\n\n $('.js-exclusion-toggle').click((event) => {\n event.preventDefault();\n\n if ($('.js-exclusion-selector').is(':hidden')) {\n $('.js-exclusion-selector').addClass('u-padding--t-25').show();\n } else {\n $('.js-exclusion-selector').hide();\n }\n });\n }\n}\n","/**\n * Handle the reminder switch on the reminders launch step.\n */\nexport default class Reminders {\n /**\n * Initialise the object.\n */\n init() {\n if ($('.js-future-reminder').length > 0) {\n this.initToggle();\n }\n }\n\n /**\n * Show or hide the future reminder date model.\n */\n initToggle() {\n this.toggleLogic();\n\n $('#run_again_reminder_enabled')\n .parent('.js-switch')\n .click(() => this.toggleLogic());\n }\n\n /**\n * Define the logic that determines if the date box should be shown or not.\n */\n toggleLogic() {\n const reminderContainer = $('.js-future-reminder');\n const toggle = $('#run_again_reminder_enabled');\n\n reminderContainer.hide();\n if (toggle.is(':checked')) {\n reminderContainer.show();\n }\n }\n}\n","/**\n * Handle the Schema preview link interactions in the launch flow.\n */\nexport default class SchemaLink {\n init() {\n if ($('.js-schema-preview-link').length > 0) {\n this.initPreviewLink();\n }\n\n if ($('.js-schema-link').length > 0) {\n this.initQuoteLink();\n }\n }\n\n /**\n * Builds the preview template link on the second step of the creation flow.\n *\n * When the select input changes the final character of the href attribute on\n * the preview link is changed to the ID in the select.\n */\n initPreviewLink() {\n $('.js-schema-preview-link').click((event) => {\n const $element = $(event.currentTarget);\n\n // Lowercase \"l\" in \"previewlink\" is deliberate - jQuery will change the\n // data attributes name to this.\n const linkTarget = $('.js-schema-select .js-select__input-field')\n .find(':selected').data('previewlink');\n\n $element.attr('href', linkTarget);\n }).data('initialized', true);\n }\n\n /**\n * Select a template in the drop down when a link is clicked in the quote\n * on the template selection page of the launch flow.\n */\n initQuoteLink() {\n $('.js-schema-link').click((event) => {\n event.preventDefault();\n\n const $element = $(event.currentTarget);\n $('#reviews_launch_steps_schema_form_schema')\n .find(`option[value = \"${$element.data('schemaid')}\"]`)\n .prop('selected', true);\n });\n }\n}\n","export default class SortableQuestions {\n init($container) {\n if ($container.length < 1) {\n return;\n }\n\n // Use jQuery UI's Sortable interaction.\n $container.sortable({\n // When the order changes a hidden form element containing the position\n // for each question is updated behind the scenes. When the step is then\n // navigated away from the new positions are saved.\n update: (event) => {\n const $updatedContainer = $(event.target);\n let position = 0;\n\n $updatedContainer.children('li').each((_, element) => {\n $(element).find('.js-question-position').val(position);\n position += 1;\n });\n },\n });\n }\n}\n","/* global charlie */\n\nimport Exclusions from './exclusions';\nimport Reminders from './reminders';\nimport SchemaLink from './schema-link';\nimport SortableQuestions from './sortable-questions';\n\nexport default class Reviews {\n /**\n * Set-up events. This will need to be called after every step progression to\n * ensure events are set up properly.\n */\n init() {\n this.schemaLink = this.schemaLink || new SchemaLink();\n this.schemaLink.init();\n\n this.exclusions = this.exclusions || new Exclusions();\n this.exclusions.init();\n\n this.reminders = this.reminders || new Reminders();\n this.reminders.init();\n\n this.sortableQuestions = this.sortableQuestions || new SortableQuestions();\n this.sortableQuestions.init($('.js-reviewee-questions-list'));\n this.sortableQuestions.init($('.js-reviewer-questions-list'));\n }\n}\n\nconst reviews = new Reviews();\n\n// When the onboardingStepChange event gets fired we need to bind events to\n// elements on the new step. onReady won't be triggered as it's only a partial\n// DOM change, not a full page reload.\ncharlie.on('ready charlie:flow-step-change', () => reviews.init());\n","function submitFormWithPaymentMethod(payment_method) {\n var form = document.getElementById('credit-card-form');\n var hiddenInput = document.createElement('input');\n hiddenInput.setAttribute('type', 'hidden');\n hiddenInput.setAttribute('name', 'payment_credentials_credit_card[stripe_payment_method]');\n hiddenInput.setAttribute('value', payment_method);\n form.appendChild(hiddenInput);\n $billing_page = $('.js-billing-overview')\n\n\n if ($billing_page.length) {\n var valuesToSubmit = new FormData(form);\n\n $.ajax({\n url: '/billing/credentials',\n type: \"POST\",\n data: valuesToSubmit,\n processData: false,\n contentType: false,\n dataType: 'script',\n })\n } else {\n form.submit();\n }\n\n}\n\nfunction cardholderName() {\n var $cardholderName = $('#js-cardholder-name');\n return $cardholderName.val();\n}\n\nfunction validateCardholderName() {\n var name = cardholderName();\n\n var $cardholderName = $('#js-cardholder-name');\n var $button = $('#credit-card-form').find('.js-submit-btn');\n\n if (name) {\n $cardholderName.data('input').removeError();\n $button.data('button').enable();\n } else {\n $cardholderName.data('input').setError('Your cardholder name is required.');\n $button.data('button').disable();\n }\n}\n\nfunction setupStripeElements(stripe, form) {\n var appearance = {\n fonts: [{\n cssSrc: 'https://use.typekit.net/spq0fsn.css'\n }]\n };\n\n clientSecret = $(form).data('client-secret');\n\n var elements = stripe.elements(appearance, clientSecret);\n\n var style = {\n base: {\n color: '#2e424d', // charcoal\n fontFamily: '\"futura-pt\", sans-serif',\n fontSize: '18px',\n '::placeholder': {\n color: '#b1c4cd', // coolgray\n fontStyle: 'italic'\n }\n },\n invalid: {\n color: '#e1542d', // danger\n iconColor: '#e1542d' // danger\n }\n };\n\n var cardElement = elements.create('card', {\n hidePostalCode: true,\n style: style\n });\n cardElement.mount('#card-element');\n\n // Create a token when the form is submitted.\n form.addEventListener('submit', function(e) {\n e.preventDefault();\n confirmCardSetup(stripe, clientSecret, cardElement);\n });\n\n cardElement.addEventListener('change', function(event) {\n var $button = $(form).find('.js-submit-btn');\n var displayError = document.getElementById('card-errors');\n\n if (event.error) {\n displayError.textContent = event.error.message;\n $button.data('button').disable();\n } else {\n displayError.textContent = '';\n $button.data('button').enable();\n }\n });\n\n $('#js-cardholder-name').on('change', validateCardholderName);\n $(form).data('initialized', true);\n}\n\nfunction confirmCardSetup(stripe, clientSecret, cardElement) {\n stripe.confirmCardSetup(clientSecret, {\n payment_method: {\n card: cardElement,\n billing_details: {\n name: cardholderName(),\n },\n },\n })\n .then(function(result) {\n if (result.error) {\n var errorElement = document.getElementById('card-errors');\n errorElement.textContent = result.error.message;\n $('.js-submit-btn').data('button').removeLoader();\n } else {\n submitFormWithPaymentMethod(result.setupIntent.payment_method);\n }\n });\n}\n\n$(document).on('ready ajaxComplete', function() {\n if ($('#card-element').length == 0) {\n return;\n }\n\n var form = document.getElementById('credit-card-form');\n\n if (!$(form).data('initialized')) {\n var stripe = Stripe(form.getAttribute('data-stripe-publishable-key'));\n setupStripeElements(stripe, form);\n }\n});\n","/* global $ */\n\nclass DesignSystemAccordion {\n constructor ($accordion) {\n this.$accordion = $accordion\n }\n\n events () {\n this.$accordion.children('.js-accordion-bar').on('click', (e) => {\n const clickableChildren = this.$accordion.find('.c-button, .js-avatar')\n\n // Prevent opening of the accordion if you click on a button inside the accordion bar.\n if (!clickableChildren.is(e.target) && !clickableChildren.has(e.target).length) {\n e.preventDefault()\n\n if (this.$accordion.hasClass('is-open')) this.close()\n else this.open()\n }\n })\n }\n\n open () {\n if (this.$accordion.data('openable')) {\n this.$accordion.addClass('is-open')\n this.$accordion.removeClass('is-closed')\n\n this.$accordion.attr('aria-expanded', true)\n\n this.$accordion.children('.js-accordion-content').slideDown(100, () => {\n this.$accordion.trigger('accordionOpen')\n })\n\n if (this.$accordion.attr('remote-link') && !this.$accordion.attr('remote-loaded')) {\n this.handleRemote()\n }\n }\n }\n\n close () {\n this.$accordion.removeClass('is-open')\n\n this.$accordion.attr('aria-expanded', false)\n\n if (this.$accordion.data('openable')) {\n this.$accordion.addClass('is-closed')\n }\n\n this.$accordion.children('.js-accordion-content').slideUp(100)\n }\n\n handleRemote () {\n $.ajax({\n type: 'GET',\n dataType: 'html',\n url: this.$accordion.data('remote-link'),\n beforeSend: () => {\n $('.js-accordion-loader', this.$accordion).addClass('is-loading')\n },\n complete: () => {\n $('.js-accordion-loader', this.$accordion).removeClass('is-loading')\n },\n success: (data) => {\n this.$accordion.attr('remote-loaded', true)\n $('.js-accordion-content-drop', this.$accordion).replaceWith(data)\n },\n error: () => {\n $('.js-accordion-content-error').removeClass('is-hidden')\n }\n })\n }\n}\n\n$(document).on('ready ajaxComplete turbo:frame-render', () => {\n $('.js-accordion').each((index, target) => {\n const $accordion = $(target)\n if (!$accordion.data('initialized')) {\n const klass = new DesignSystemAccordion($accordion)\n klass.events()\n $accordion.data('initialized', true)\n\n if ($accordion.data('pre-open')) klass.open()\n $accordion.data('instance', klass)\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemAvatar {\n constructor ($avatar) {\n this.$avatar = $avatar\n this.$imageTarget = this.$avatar.find('.js-avatar-uploader-image')\n }\n\n init () {\n this.$avatar.dropzone({\n url: this.$avatar.data('url'),\n acceptedFiles: 'image/jpg, image/jpeg, image/png',\n maxFilesize: 20,\n thumbnailWidth: 360,\n thumbnailHeight: 360,\n previewTemplate: `
\n
\n
\n
\n
\n
\n
`,\n sending: (file, xhr) => {\n xhr.setRequestHeader('X-CSRF-Token', $('meta[name=\"csrf-token\"]').attr('content'))\n xhr.timeout = 25000\n xhr.ontimeout = () => {\n window.alert('Your request timed out. Try a smaller file or a faster internet connection.')\n }\n this.$avatar.addClass('is-loading')\n },\n processing: () => {\n this.$avatar.removeClass('has-error has-success')\n this.$avatar.addClass('is-loading')\n },\n dragleave: () => {\n this.$avatar.removeClass('is-dragging')\n },\n dragover: () => {\n this.$avatar.addClass('is-dragging')\n },\n drop: () => {\n this.$avatar.removeClass('is-dragging')\n },\n complete: () => {\n this.$avatar.removeClass('is-loading is-empty')\n },\n success: () => {\n this.$avatar.addClass('has-success')\n },\n error: () => {\n this.$avatar.addClass('has-error')\n },\n thumbnail: (file, dataUrl) => {\n if (file.accepted) {\n this.$avatar.find('[data-dz-thumbnail]').attr('alt', file.name)\n this.$avatar.find('[data-dz-thumbnail]').attr('src', dataUrl)\n this.$imageTarget.attr('style', `background-image: url(${dataUrl});`)\n }\n }\n })\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-avatar-uploader').each((index, target) => {\n const identifier = $(target).data('identifier')\n const $target = $(`.js-avatar-uploader[data-identifier=${identifier}]`)\n\n if ($target.length > 0) {\n new DesignSystemAvatar($target).init()\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemAvatarGroup {\n constructor ($wrapper) {\n this.wrapper = $wrapper\n this.limit = $wrapper.data('limit')\n this.overflowSingular = $wrapper.data('overflow-singular')\n this.overflowPlural = $wrapper.data('overflow-plural')\n this.overflowText = $wrapper.find('.js-avatar_group-text')\n this.count = $wrapper.data('count')\n this.overflowCount = 0\n this.visibleAvatarsCount = 0\n this.replaceVisibleAvatar = false\n\n const avatarGroup = {\n addAvatar: (id, url) => {\n this.addAvatar(id, url)\n },\n removeAvatar: (id) => {\n this.removeAvatar(id)\n },\n removeAllAvatars: () => {\n this.removeAllAvatars()\n },\n getCount: () => {\n this.getCount()\n }\n }\n\n this.wrapper[0].data = {'avatar-group': avatarGroup}\n }\n\n overflowCopy () {\n let word = this.overflowPlural\n\n if (this.count === 1 || this.overflowCount === 1) {\n word = this.overflowSingular\n }\n\n if (this.count <= this.limit) {\n return [\n this.count,\n word\n ].join(' ')\n } else {\n return [\n '+',\n this.overflowCount,\n 'more',\n word\n ].join(' ')\n }\n }\n\n updateCounts ($wrapper) {\n this.count = $wrapper.find('.js-avatar').length\n this.visibleAvatarsCount = $wrapper.find('.js-avatar').not('.is-hidden').length\n this.replaceVisibleAvatar = (this.visibleAvatarsCount < this.limit)\n\n if (this.count <= this.limit) {\n this.overflowCount = 0\n } else {\n this.overflowCount = this.count - this.limit\n }\n }\n\n getCount () {\n return this.wrapper.find('.js-avatar').length\n }\n\n avatarAsHTML (id, url) {\n return `
`\n }\n\n addAvatar (id, url) {\n if (!this.wrapper.find(`.js-avatar[data-id=\"${id}\"]`).length) {\n this.wrapper.find('.js-avatar_group__content').prepend(this.avatarAsHTML(id, url))\n\n this.updateCounts(this.wrapper)\n this.overflowText.removeClass('is-hidden').text(this.overflowCopy())\n\n if (this.count <= this.limit) {\n $(`.js-avatar[data-id=\"${id}\"]`).removeClass('is-hidden')\n }\n }\n }\n\n removeAvatar (id) {\n this.wrapper.find(`.js-avatar[data-id=\"${id}\"]`).remove()\n this.wrapper.find(`[data-member=\"${id}\"]`).remove()\n\n this.updateCounts(this.wrapper)\n\n if (this.replaceVisibleAvatar) {\n this.wrapper.find('.js-avatar.is-hidden').first().removeClass('is-hidden')\n }\n\n this.overflowText.removeClass('is-hidden').text(this.overflowCopy())\n }\n\n removeAllAvatars () {\n this.wrapper.find('.js-avatar').remove()\n\n this.updateCounts(this.wrapper)\n this.overflowText.addClass('is-hidden')\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-avatar_group').each((_, target) => {\n const $avatarGroup = $(target)\n\n if (!$avatarGroup.data('initialized')) {\n $avatarGroup.data('instance', new DesignSystemAvatarGroup($avatarGroup))\n $avatarGroup.data('initialized', true)\n }\n })\n})\n","// /* global $ */\n\nclass DesignSystemBulkActions {\n constructor ($wrapper) {\n this.wrapper = $wrapper[0]\n\n const bulkActions = {\n fixBulkActions: function() {\n $wrapper[0].classList.add('is-fixed')\n },\n unfixBulkActions: function() {\n $wrapper[0].classList.remove('is-fixed')\n },\n activateBulkActions: function() {\n $wrapper[0].classList.add('is-active')\n $wrapper[0].classList.remove('is-inactive')\n },\n deactivateBulkActions: function() {\n $wrapper[0].classList.remove('is-active')\n $wrapper[0].classList.add('is-inactive')\n const avatarGroupData = $wrapper[0].querySelector('.js-avatar_group').data\n avatarGroupData && avatarGroupData['avatar-group'].removeAllAvatars()\n },\n updateTitle: function(title) {\n const target = $wrapper[0].querySelector('.js-bulk-actions-title')\n target.innerHTML = title\n },\n };\n\n this.wrapper.data = {'bulk-actions': bulkActions}\n\n charlie.onScrolledPast( // eslint-disable-line no-undef\n this.wrapper.offsetTop,\n bulkActions.fixBulkActions,\n bulkActions.unfixBulkActions\n );\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-bulk-actions').each((_, target) => {\n const $bulkActions = $(target)\n if (!$bulkActions.data('initialized')) {\n $bulkActions.data('instance', new DesignSystemBulkActions($bulkActions))\n $bulkActions.data('initialized', true)\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemButton {\n constructor ($button) {\n this.$button = $button\n this.classes = ''\n this.loader = this.$button.hasClass('js-button--loader')\n this.loading = false\n this.disabled = this.$button.hasClass('c-button--disabled')\n }\n\n init () {\n if (!this.$button.data('initialized')) {\n const classes = this.$button.attr('class') || ''\n this.classes = classes.replace(/(^|\\s)js-\\S+/g, '')\n\n if (this.$button.hasClass('js-remove-component')) {\n this.$button.on('click', (e) => {\n e.preventDefault()\n this.$button.closest('section').remove()\n this.enableButtonLink()\n })\n }\n\n if (this.$button.hasClass('js-create-btn')) {\n this.$button.on('click', (e) => {\n this.enableButtonLink()\n })\n }\n\n if (this.loader) {\n this.$button.on('click', () => { this.toggleLoader() })\n $('body').on('modal:open modal:close', () => { this.removeLoader() })\n }\n\n if (this.$button.hasClass('js-toggle-collapse')) {\n this.$button.on('click', (e) => {\n e.preventDefault()\n this.toggleRelatedContainerState()\n })\n }\n\n this.$button.data('initialized', true)\n this.$button.data('button', this)\n }\n }\n\n addLoader () {\n if (this.loading) return\n\n const width = this.$button.css('width')\n this.$button.before(this.loaderHTML(this.classes, width))\n this.$button.addClass('is-hidden')\n this.loading = true\n }\n\n removeLoader () {\n if (!this.loading) return\n\n this.$button.prev('.js-button-loader-dummy').remove()\n this.$button.removeClass('is-hidden')\n this.loading = false\n }\n\n toggleLoader () {\n if (!this.loading) {\n this.addLoader()\n } else {\n this.removeLoader()\n }\n }\n\n disable () {\n if (this.disabled) return\n\n this.$button.addClass('c-button--disabled')\n this.$button.attr('disabled', true)\n this.disabled = true\n }\n\n enable () {\n if (!this.disabled) return\n\n this.$button.removeClass('c-button--disabled')\n this.$button.attr('disabled', false)\n this.disabled = false\n }\n\n toggleDisabled () {\n if (this.disabled) {\n this.enable()\n } else {\n this.disable()\n }\n }\n\n enableButtonLink () {\n this.$newButton = $('.js-new-button')\n this.$newButton.removeClass('c-button--disabled')\n this.$newButton.attr('disabled', false)\n this.$newButton = false\n }\n\n disableButtonLink () {\n this.removeLoader()\n this.disabled = false\n this.disable()\n\n this.$button.off()\n this.$button.on('click', function (e) {\n e.preventDefault()\n })\n }\n\n toggleRelatedContainerState () {\n if (this.$button.hasClass('js-toggle-collapse')) {\n // eslint-disable-next-line vars-on-top\n const $target = $(this.$button.attr('href'))\n // eslint-disable-next-line vars-on-top\n const $buttonState = (this.$button.attr('aria-expanded') === 'true')\n\n // Set the new state for button and container\n if ($buttonState) {\n $target.addClass('is-collapsed')\n this.$button.addClass('is-collapsing')\n } else {\n $target.removeClass('is-collapsed')\n this.$button.removeClass('is-collapsing')\n }\n\n // Update button ARIA state\n this.$button.attr('aria-expanded', !$buttonState)\n $(document).trigger('charlieLayoutUpdated')\n }\n }\n\n loaderHTML (classes, width) {\n return `
`\n }\n}\n\n$(document).on('ready ajaxComplete', function () {\n $('.js-button--loader, .js-toggle-collapse, .js-button').each(function () {\n if ($(this).hasClass('e-button')) { return }\n\n if (!$(this).data('initialized')) {\n new DesignSystemButton($(this)).init()\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemButtonGroup {\n constructor ($button) {\n this.button = $button\n this.id = $button.data('id')\n this.$dropdown = $(`.js-dropdown[data-id=\"${this.id}\"]`)\n }\n\n init () {\n $(document).on('click', (event) => {\n const isDropdownOpen = this.$dropdown.hasClass('is-open')\n const clickedOutsideButton = !$(event.target).closest(this.button).length\n const clickedOutsideDropwdown = !$(event.target).closest(this.$dropdown).length\n\n if (clickedOutsideButton && clickedOutsideDropwdown) {\n if (isDropdownOpen) {\n this.closeDropdown()\n }\n }\n })\n\n this.button.on('click', () => {\n this.toggleDropdown()\n })\n }\n\n closeDropdown () {\n this.$dropdown.removeClass('is-open')\n this.button.removeClass('is-open')\n }\n\n openDropdown () {\n this.$dropdown.addClass('is-open')\n this.button.addClass('is-open')\n };\n\n toggleDropdown () {\n const isOpen = this.$dropdown.hasClass('is-open')\n\n if (isOpen) {\n this.closeDropdown()\n } else {\n this.openDropdown()\n }\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-open-dropdown').each((_, target) => {\n if (!$(target).data('initialized')) {\n $(target).data('initialized', true)\n new DesignSystemButtonGroup($(target)).init()\n }\n })\n})\n","// /* global $ */\n\nclass DesignSystemCabinet {\n constructor ($wrapper) {\n this.wrapper = $wrapper[0]\n }\n\n init () {\n this.handleCabinetPreOpens()\n\n const cabinetCase = this.wrapper.querySelector('.js-cabinet-case')\n cabinetCase.addEventListener('click', () => {\n this.handleCabinet()\n })\n }\n\n handleCabinetPreOpens () {\n $('.js-cabinet').each(() => {\n if (this.wrapper.getAttribute('data-pre-open') == 'true') {\n this.openCabinet()\n }\n })\n }\n\n handleCabinet () {\n if (this.wrapper.classList.contains('is-open')) {\n this.closeCabinet()\n } else {\n this.openCabinet()\n }\n }\n\n openCabinet() {\n if (this.wrapper.getAttribute('data-openable') == 'true') {\n this.wrapper.classList.add('is-open')\n }\n }\n\n closeCabinet() {\n this.wrapper.classList.remove('is-open');\n }\n\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-cabinet').each((_, target) => {\n const $cabinet = $(target)\n if (!$cabinet.data('initialized')) {\n $cabinet.data('instance', new DesignSystemCabinet($cabinet))\n $cabinet.data('instance').init()\n $cabinet.data('initialized', true)\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemCheckbox {\n constructor ($checkbox) {\n this.$checkbox = $checkbox\n }\n\n bindEvents () {\n this.$checkbox.on('click', () => {\n const $toggleControl = $(this.$checkbox.data('control'))\n const state = this.$checkbox.data('state')\n\n $toggleControl.toggleClass(state)\n $(document).trigger('charlieLayoutUpdated')\n })\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-checkbox-input').each((index, checkbox) => {\n const $checkbox = $(checkbox)\n const toggle = ($checkbox.data('control') && $checkbox.data('state'))\n if (typeof $checkbox.data('initialized') === 'undefined') {\n if (toggle) new DesignSystemCheckbox($checkbox).bindEvents()\n $checkbox.data('initialized', true)\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemCheckboxGroup {\n constructor ($checkboxGroup) {\n this.$checkboxGroup = $checkboxGroup[0]\n this.$selectAll = this.$checkboxGroup.querySelectorAll('.js-checkbox-group__select-all')[0]\n this.$clearAll = this.$checkboxGroup.querySelector('.js-checkbox-group__clear-all')\n }\n\n events () {\n const inputWrappers = this.$checkboxGroup.querySelectorAll('.js-checkbox-group__input-wrapper')\n inputWrappers.forEach(inputWrapper => {\n inputWrapper.addEventListener('click', (event) => {\n event.preventDefault()\n const $input = inputWrapper.querySelector('.c-checkbox__input')\n this.toggleInputValue($input)\n })\n })\n\n this.$selectAll.addEventListener('click', (event) => {\n event.preventDefault()\n\n this.handleSelectAll()\n })\n\n this.$clearAll.addEventListener('click', (event) => {\n this.handleClearAll()\n })\n }\n\n toggleInputValue ($input) {\n if(!$input.getAttribute('disabled')){\n if ($input.getAttribute('checked') != null) {\n $input.removeAttribute('checked')\n } else {\n $input.setAttribute('checked', true)\n }\n this.checkFormInputs()\n }\n }\n\n checkFormInputs () {\n const isChecked = this.$checkboxGroup.querySelectorAll('input:checked').length > 0\n if (isChecked) {\n this.enableClearAllButton()\n } else {\n this.disableClearAllButton()\n }\n\n const countChecked = this.$checkboxGroup.querySelectorAll('input:checked').length\n const countInputs = this.$checkboxGroup.querySelectorAll('input').length\n if (countChecked === countInputs) {\n this.disableSelectAllButton()\n } else {\n this.enableSelectAllButton()\n }\n }\n\n handleSelectAll () {\n const inputWrappers = this.$checkboxGroup.querySelectorAll('.js-checkbox-group__input-wrapper')\n\n inputWrappers.forEach(inputWrapper => {\n const $input = inputWrapper.querySelector('.c-checkbox__input')\n $input.setAttribute('checked', true)\n })\n\n this.disableSelectAllButton()\n this.enableClearAllButton()\n }\n\n handleClearAll () {\n const inputWrappers = this.$checkboxGroup.querySelectorAll('.js-checkbox-group__input-wrapper')\n\n inputWrappers.forEach(inputWrapper => {\n const $input = inputWrapper.querySelector('.c-checkbox__input')\n\n $input.removeAttribute('checked')\n })\n\n this.$checkboxGroup.querySelectorAll('.js-checkbox-group__select-all').forEach(selectAll => {\n selectAll.classList.remove('c-checkbox-group__select-all-selected')\n })\n\n this.enableSelectAllButton()\n this.disableClearAllButton()\n }\n\n disableSelectAllButton () {\n this.$selectAll.classList.add('c-checkbox-group__select-all-disabled', 'c-button--disabled')\n this.$selectAll.setAttribute('disabled', 'disabled')\n }\n\n enableSelectAllButton () {\n this.$selectAll.classList.remove('c-checkbox-group__select-all-disabled', 'c-button--disabled')\n this.$selectAll.removeAttribute('disabled')\n }\n\n disableClearAllButton () {\n this.$clearAll.classList.add('c-checkbox-group__clear-all-disabled', 'c-button--disabled')\n this.$clearAll.setAttribute('disabled', 'disabled')\n }\n\n enableClearAllButton () {\n this.$clearAll.classList.remove('c-checkbox-group__clear-all-disabled', 'c-button--disabled')\n this.$clearAll.removeAttribute('disabled')\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-checkbox-group').each((index, target) => {\n const $checkboxGroup = $(target)\n if (!$checkboxGroup.data('initialized')) {\n const klass = new DesignSystemCheckboxGroup($checkboxGroup)\n klass.events()\n $checkboxGroup.data('initialized', true)\n }\n })\n})\n","class DesignSystemChecklistTask {\n constructor (checklistTask) {\n this.checklistTask = checklistTask[0]\n this.checklistInput = this.checklistTask.querySelector('.js-checklist-task__check')\n }\n\n init() {\n this.checklistInput && this.checklistInput.addEventListener('click', () => {\n this.updateChecklistTask()\n })\n }\n\n updateChecklistTask() {\n const task_checked = this.checklistTask.dataset.checked === 'false' ? true : false\n const action_url = this.checklistTask.dataset.actionUrl\n\n this.checklistTask.classList.toggle(\"c-checklist_task--checked\")\n this.checklistTask.dataset.checked = task_checked\n this.updateChecklistGraph()\n\n if (action_url) {\n $.ajax({\n type: \"PATCH\",\n dataType: \"script\",\n url: action_url,\n data: {\n checklist_item: {\n checked: task_checked\n },\n ui_updated: true\n }\n })\n } else {\n console.warn('Could not create update path')\n }\n }\n\n updateChecklistGraph() {\n // Figure out new checklist completeness\n const checklistTaskGroup = this.checklistTask.closest('.js-checklist_task_group')\n if (checklistTaskGroup) {\n const all_tasks = checklistTaskGroup.querySelectorAll('.js-checklist-task').length\n const all_completed_tasks = checklistTaskGroup.querySelectorAll('.js-checklist-task.c-checklist_task--checked').length\n const skippable_tasks = checklistTaskGroup.querySelectorAll('.js-checklist-task.js-skip-counter').length\n const skippable_completed_tasks = checklistTaskGroup.querySelectorAll('.js-checklist-task.c-checklist_task--checked.js-skip-counter').length\n\n const number_of_completed_tasks = (all_completed_tasks - skippable_completed_tasks)\n const number_of_tasks = (all_tasks - skippable_tasks)\n\n const percentage = number_of_completed_tasks / number_of_tasks * 100\n const percentage_as_text = number_of_completed_tasks + '/' + number_of_tasks\n\n // Setup new chart data\n const chart = checklistTaskGroup.querySelector('.js-doughnut_chart').data.chart\n const style = percentage > 70 ? '#50e2c3' : '#e1542d'\n\n chart.data.datasets[0]['data'] = [percentage, 100 - percentage]\n chart.data.datasets[0]['backgroundColor'] = [style, \"#f2f2f2\"]\n chart.data.datasets[0]['hoverBackgroundColor'] = [style, \"#f2f2f2\"]\n\n chart.options.animation.duration = 200\n\n // Update DOM\n checklistTaskGroup.querySelector('.js-doughnut_chart__label').textContent = percentage_as_text\n chart.update()\n }\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n if ($('.js-checklist-task').length) {\n $('.js-checklist-task').each((_, target) => {\n const $checklistTask = $(target)\n\n if (!$checklistTask.data(\"initialized\")) {\n $checklistTask.data('instance', new DesignSystemChecklistTask($checklistTask))\n $checklistTask.data('instance').init()\n $checklistTask.data(\"initialized\", true)\n }\n })\n }\n})\n","/* global $ */\n\nclass DesignSystemChecklistTaskGroup {\n constructor (checklistTaskGroup) {\n this.checklistTaskGroupNode = checklistTaskGroup\n this.checklistTaskGroup = checklistTaskGroup[0]\n }\n\n init () {\n this.activateShowCompletedTasksButton()\n this.activateEditButtonOnMobile()\n this.reorderTasks()\n }\n\n updateChecklistTaskPosition (task) {\n const actionUrl = this.checklistTaskGroup.getAttribute('data-action-url')\n if ( actionUrl ) {\n const itemsToSort = task.closest('.js-checklist_task_group__tasks--reorderable')\n const array_of_items = itemsToSort.sortable().sortable('toArray', { attribute: 'data-id' });\n $.ajax({\n type: \"PATCH\",\n dataType: \"script\",\n url: actionUrl,\n data: {\n checklist: {\n order: array_of_items\n }\n }\n });\n } else {\n console.warn('Could not create update path');\n }\n }\n\n activateShowCompletedTasksButton () {\n const showTaskButton = this.checklistTaskGroup.querySelector('.js-show-tasks')\n if(showTaskButton) {\n if ( !showTaskButton.data || !showTaskButton.data.initialized ) { // Don't initialize events for buttons that have events\n showTaskButton.addEventListener('click', () => {\n this.checklistTaskGroup.classList.remove('has-success')\n })\n showTaskButton.data = { initialized: true }\n }\n }\n }\n\n activateEditButtonOnMobile () {\n const editButton = this.checklistTaskGroup.querySelector('.js-checklist_task_group-edit-on-mobile')\n if (editButton) {\n if ( !editButton.data || !editButton.data.initialized ) { // Don't initialize events for buttons that have events\n editButton.addEventListener('click', () => {\n if(this.checklistTaskGroup.classList.contains('is-editing')){\n this.checklistTaskGroup.querySelectorAll('.c-checklist_task__actions').forEach((actions) => {\n actions.style.display = 'none'\n })\n this.checklistTaskGroup.classList.remove('is-editing')\n } else {\n this.checklistTaskGroup.querySelectorAll('.c-checklist_task__actions').forEach((actions) => {\n actions.style.display = 'block'\n })\n this.checklistTaskGroup.classList.add('is-editing')\n }\n })\n editButton.data = { initialized: true }\n }\n }\n }\n\n reorderTasks () {\n const tasks = this.checklistTaskGroup.querySelectorAll('.js-checklist-task')\n let time_out_id\n\n if ( tasks.length > 0 ) {\n this.checklistTaskGroupNode.sortable({\n items: \".js-checklist-task\",\n opacity: 0.6,\n update: (event, ui) => {\n // Ignore the previous request if you trigger a new one\n if ( time_out_id != 0 ) { clearTimeout(time_out_id); }\n\n time_out_id = setTimeout(() => {\n time_out_id = 0;\n this.updateChecklistTaskPosition( $(ui.item) );\n }, 2000);\n }\n })\n }\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-checklist_task_group').each((index, target) => {\n const $checklistTaskGroup = $(target)\n if (!$checklistTaskGroup.data('initialized')) {\n new DesignSystemChecklistTaskGroup($checklistTaskGroup)\n new DesignSystemChecklistTaskGroup($checklistTaskGroup).init()\n $checklistTaskGroup.data('initialized', true)\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemCounter {\n constructor ($counter) {\n this.$counter = $counter\n this.$stateClasses = {\n complete: 'is-complete',\n 'in-progress': 'is-in-progress',\n incomplete: 'is-incomplete'\n }\n }\n\n changeState (state) {\n this.$counter.removeClass('is-complete is-in-progress is-incomplete')\n this.$counter.addClass(this.$stateClasses[state])\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-counter').each((_, target) => {\n if (!$(target).data('initialized')) {\n $(target).data('instance', new DesignSystemCounter($(target)))\n $(target).data('initialized', true)\n }\n })\n})\n","/* global $, AirDatepicker */\n\nimport 'air-datepicker/air-datepicker.css'\nimport localeEn from 'air-datepicker/locale/en'\n\n// ! without an id, the air-datepicker js file will not work correctly !\nclass DesignSystemDatepicker {\n constructor ($datepicker) {\n this.$datepicker = $datepicker\n this.$input = $datepicker.find('.js-datepicker__input-field')\n\n this.$toggleDisabled = function () {\n this.$input.attr('disabled', !this.$input.attr('disabled'))\n }\n }\n\n init () {\n const inputValue = this.$input[0].value\n const input = this.$input[0]\n const parent = this.$input[0].parentElement\n const maxDateValue = this.$input.data('date-options-maxdate')\n const minDateValue = this.$input.data('date-options-mindate')\n const minPicker = this.$input.data('date-options-minpicker') ? true : false\n const maxPicker = this.$input.data('date-options-maxpicker') ? true : false\n\n const airDpInstance = new AirDatepicker(input, {\n locale: localeEn,\n view: this.$input.data('date-options-viewmode'),\n dateFormat: this.$input.data('date-options-format'),\n container: parent,\n autoClose: true,\n firstDay: 1,\n startDate: inputValue ? [inputValue] : [new Date()],\n selectedDates: inputValue ? [inputValue] : false,\n maxDate: maxDateValue,\n minDate: minDateValue,\n onSelect: function onSelect(date) {\n var evt = new CustomEvent('datepickerclick', { detail: { date: date } });\n input.dispatchEvent(evt);\n if (minPicker) {\n var setMinDate = new CustomEvent(\"setMinDate\", {\n detail: date.date.setDate(date.date.getDate()+1) // +1 because we dont want the same date to be pickable, just the one after\n })\n document.dispatchEvent(setMinDate);\n } else if (maxPicker) {\n var setMaxDate = new CustomEvent(\"setMaxDate\", {\n detail: date.date.setDate(date.date.getDate()-1) // -1 because we dont want the same date to be pickable, just the one before\n })\n document.dispatchEvent(setMaxDate);\n }\n },\n onRenderCell: function onRenderCell(date) {\n if (airDpInstance.minDate || airDpInstance.maxDate) {\n var maxSelectableDate = airDpInstance.maxDate ? new Date(airDpInstance.maxDate).setDate(airDpInstance.maxDate.getDate()+1) : \"\"\n var minSelectableDate = airDpInstance.minDate ? new Date(airDpInstance.minDate).setDate(airDpInstance.minDate.getDate()) : \"\"\n\n if (date.date.toString() == new Date(minSelectableDate).toString() || date.date.toString() == new Date(maxSelectableDate).toString()) {\n return {\n classes: '-range-'\n }\n }\n }\n },\n })\n if (maxPicker) {\n document.addEventListener(\"setMinDate\", (event) => {\n airDpInstance.update({\n minDate: event.detail, // update new minimum date\n selectedDates: airDpInstance.selectedDates, // keep existing date selected\n }, { silent: true })\n })\n }\n if (minPicker) {\n document.addEventListener(\"setMaxDate\", (event) => {\n airDpInstance.update({\n maxDate: event.detail, // update new maximum date\n selectedDates: airDpInstance.selectedDates, // keep existing date selected\n }, { silent: true })\n })\n }\n }\n\n handleToggleClick (airDpInstance) {\n airDpInstance.visible ? airDpInstance.hide() : airDpInstance.show()\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-datepicker').each((_, target) => {\n const $datepicker = $(target)\n\n if (!$datepicker.data('initialized')) {\n $datepicker.data('instance', new DesignSystemDatepicker($datepicker))\n $datepicker.data('instance').init()\n $datepicker.data('initialized', true)\n }\n })\n})\n\nexport { DesignSystemDatepicker }\n","/* global $, chart */\n\nclass DesignSystemDoughnutChart {\n\n constructor(doughnutChart) {\n this.doughnutChart = doughnutChart[0]\n\n if ( !this.doughnutChart.data || !this.doughnutChart.data['chart'] ) {\n const ctx = this.doughnutChart.getContext(\"2d\")\n const data = this.doughnutChart.dataset.chartData ? JSON.parse(this.doughnutChart.dataset.chartData) : []\n const labels = this.doughnutChart.dataset.chartLabels ? JSON.parse(this.doughnutChart.dataset.chartLabels) : []\n const colors = this.doughnutChart.dataset.chartColors ? JSON.parse(this.doughnutChart.dataset.chartColors) : []\n const cutout = this.doughnutChart.dataset.chartCutout\n\n const checklistGraph = new Chart(ctx, {\n type: 'doughnut',\n data: {\n labels: labels,\n datasets: [{\n data: data,\n backgroundColor: colors,\n hoverBackgroundColor: colors\n }],\n },\n options: {\n animateRotate: data[0] == 100,\n cutout: cutout,\n plugins: {\n legend: {\n display: false\n },\n tooltip: {\n enabled: labels.length > 2,\n titleFont: { weight: 'normal' }\n }\n }\n }\n })\n\n this.doughnutChart.data = { 'chart': checklistGraph }\n }\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n\n $('.js-doughnut_chart').each((_, target) => {\n const $doughnutChart = $(target)\n\n if (!$doughnutChart.data('doughnut-chart')) {\n $doughnutChart.data('doughnut-chart', new DesignSystemDoughnutChart($doughnutChart))\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemGroupCard {\n constructor ($groupCard) {\n this.$groupCard = $groupCard\n }\n\n events () {\n this.setup()\n }\n\n setup () {\n const instance = {\n card: this.$groupCard,\n header: this.$groupCard.find('.js-group_card__header'),\n editToggles: this.$groupCard.find('.js-group_card__toggle-edit'),\n toggleEditState: function () {\n this.header.toggleClass('is-editing')\n }\n }\n\n instance.editToggles.on('click', function () {\n instance.toggleEditState()\n })\n\n this.$groupCard.data('initialized', true)\n\n return instance\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-group_card').each((index, target) => {\n const $groupCard = $(target)\n if (!$groupCard.data('initialized')) {\n new DesignSystemGroupCard($groupCard).events()\n }\n })\n})\n","const context = require.context('.', true, /index.js$/)\ncontext.keys().forEach(context)\n","export default class DesignSystemShowPassword {\n constructor ($button) {\n this.$button = $button\n this.$input = $button.prev().find('.js-input')\n this.originalText = $button.text()\n }\n\n bindEvents () {\n this.$button.on('click', (e) => {\n e.preventDefault()\n\n if (this.$input.attr('type') === 'password') {\n this.$input.attr('type', 'text')\n this.$button.text('Hide password')\n } else {\n this.$input.attr('type', 'password')\n this.$button.text(this.originalText)\n }\n })\n }\n}\n","export default class DesignSystemInputState {\n constructor ($input) {\n this.$input = $input\n this.disabled = $input.hasClass('c-input--disabled')\n }\n\n disable () {\n if (this.disabled) return\n\n this.$input.addClass('c-input--disabled')\n this.$input.attr('disabled', true)\n this.disabled = true\n }\n\n enable () {\n if (!this.disabled) return\n\n this.$input.removeClass('c-input--disabled')\n this.$input.attr('disabled', false)\n this.disabled = false\n }\n\n toggleDisabled () {\n if (this.disabled) {\n this.enable()\n } else {\n this.disable()\n }\n }\n}\n","/* global $, ClipboardJS */\n\nimport DesignSystemInputErrors from './js/input-errors'\nimport DesignSystemShowPassword from './js/show-password'\nimport DesignSystemInputState from './js/input-state'\n\nclass DesignSystemInput {\n constructor (input) {\n // this.input = input[0]\n }\n\n init () {\n this.copyToClipBoard()\n this.showPassword()\n }\n\n copyToClipBoard () {\n if ($('.js-copy-to-clipboard').length > 0) {\n new ClipboardJS('.js-copy-to-clipboard')\n }\n }\n\n showPassword () {\n $('.js-show-password-button').each((index, button) => {\n const $button = $(button)\n if (!$button.data('instance')) {\n $button.data('instance', new DesignSystemShowPassword($button))\n $button.data('instance').bindEvents()\n }\n })\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n\n $('.js-input').each((index, target) => {\n const $input = $(target)\n if (!$input.data('initialized')) {\n new DesignSystemInput($input)\n new DesignSystemInput($input).init()\n\n // JS error handling.\n $input.data('input', new DesignSystemInputErrors($input))\n $input.data('state', new DesignSystemInputState($input))\n\n $input.data('initialized', true)\n }\n })\n})\n","export default class DesignSystemInputErrors {\n constructor ($input) {\n this.$input = $input\n this.id = this.$input[0].getAttribute('id')\n this.$wrapper = this.$input[0].parentElement\n }\n\n removeError () {\n const errorElement = this.$wrapper.getElementsByClassName('js-input__error-message')[0]\n errorElement && errorElement.remove()\n\n this.$wrapper.getElementsByClassName('js-input')[0].classList.remove('has-error')\n this.$wrapper.getElementsByClassName('js-input')[0].removeAttribute('aria-required')\n }\n\n errorAsHTML (message) {\n const paragraph = document.createElement('p')\n paragraph.setAttribute('class', 'c-input__error-message js-input__error-message')\n paragraph.innerHTML = message\n return paragraph\n }\n\n setError (message) {\n this.removeError(this.$wrapper)\n\n this.$wrapper.getElementsByClassName('js-input')[0].classList.add('has-error')\n this.$wrapper.getElementsByClassName('js-input')[0].setAttribute('aria-required', 'true')\n this.$wrapper.getElementsByClassName('js-input__info')[0].append(this.errorAsHTML(message))\n }\n}\n","/* global $, clickedInsideOf */\n\nclass DesignSystemMultipleSelect {\n constructor (ms) {\n this.ms = ms\n }\n\n init () {\n this.bindEventsToMultipleSelect()\n }\n\n bindEventsToMultipleSelect () {\n const base = {}\n const $ms = $('#' + this.ms.prop('id')) // Select scoped multiple select from unique ID\n\n // Scoped selectors\n const $input = $ms.find('.js-ms-input')\n const $dropdown = $ms.find('.js-ms-dropdown')\n const $dropdownControl = $ms.find('.js-ms-dropdown-control')\n const $search = $ms.find('.js-ms-search')\n const $checkboxWrappers = $ms.find('.js-checkbox-wrapper')\n const $checkboxes = $ms.find('.js-checkbox-input')\n const $options = $ms.find('.js-ms-options')\n const $selectedOptions = $ms.find('.js-ms-selected-options')\n const $actions = $ms.find('.js-ms-actions')\n const $tags = $ms.find('.js-ms-tag')\n const $resultCount = $ms.find('.js-ms-results-count')\n const $groups = $ms.find('.js-md-grouped-options')\n const $limit = $search.data('limit')\n const $limit_error = $ms.find('#limit-error')\n\n base.setResultCount = function (number) {\n if (number === 1) {\n $resultCount.html(number + ' result')\n } else {\n $resultCount.html(number + ' results')\n }\n }\n\n base.focus = function () {\n base.handleTransition('focused')\n }\n\n base.unfocus = function () {\n base.handleTransition('unfocused')\n }\n\n base.handleTransition = function (direction) {\n switch (direction) {\n case 'focused':\n if (!$ms.hasClass('is-focused')) {\n $ms.addClass('is-focused')\n $dropdown.addClass('is-open')\n if (!$search.is(':focus')) {\n $search.focus()\n }\n }\n break\n\n case 'unfocused':\n if ($ms.hasClass('is-focused')) {\n $ms.removeClass('is-focused')\n $dropdown.removeClass('is-open')\n $search.blur()\n if (base.onDone) { base.onDone($ms) }\n }\n break\n\n default:\n throw new Error('Unsupported transition for multiple select:' + direction)\n }\n }\n\n base.showOrHideGroupLabels = function () {\n $groups.each(function () {\n const group = $(this).data('group')\n const checkboxes = $ms.find('.js-checkbox-input.is-visible[data-group=\"' + group + '\"]')\n\n if (checkboxes.length) {\n $(this).removeClass('is-hidden')\n } else {\n $(this).addClass('is-hidden')\n }\n })\n }\n\n base.queryMatchesTerm = function (query, term) {\n return new RegExp(query).test(term)\n }\n\n base.showCheckboxesThatMatchQuery = function (query) {\n if (!query) {\n base.changeAllCheckboxes('show')\n $checkboxes.removeClass('is-focused')\n } else {\n $checkboxWrappers.each(function () {\n const term = $(this).data('term').toLowerCase()\n\n if (base.queryMatchesTerm(query, term)) {\n $(this).removeClass('is-hidden')\n $(this).find('.js-checkbox-input').addClass('is-visible')\n }\n })\n }\n\n // Set the visible checkboxes for global manipulation.\n base.visibleCheckboxes = $dropdown.find('.js-checkbox-input.is-visible')\n base.numberOfResults = base.visibleCheckboxes.length\n base.firstCheckbox = base.visibleCheckboxes.first()\n base.showOrHideGroupLabels()\n base.setResultCount(base.numberOfResults)\n\n if (query && base.firstCheckbox.length) {\n base.firstCheckbox.addClass('is-focused')\n }\n }\n\n base.findTag = function (value) {\n return $ms.find(\".js-ms-tag[data-value='\" + value + \"']\")\n }\n\n base.findCheckbox = function (value) {\n return $ms.find(\".js-checkbox-input[value='\" + value + \"']\")\n }\n\n base.handleSearch = function (event, query) {\n const escape = (event.keyCode === 27)\n const backspace = (event.keyCode === 8)\n const enter = (event.keyCode === 13)\n\n // Selectors\n const $lastSelectedTag = $selectedOptions.find('.js-ms-tag').last()\n\n $checkboxes.removeClass('is-focused')\n base.changeAllCheckboxes('hide')\n base.showCheckboxesThatMatchQuery(query)\n\n if (escape) {\n base.handleTransition('unfocused')\n }\n\n if (backspace) {\n if (base.keydownSearchLength === 0) {\n if ($lastSelectedTag.length) {\n base.transitionCheckbox(base.findCheckbox($lastSelectedTag.data('value')), false)\n }\n }\n }\n\n if (enter) {\n if (base.keyupSearchLength > 0) {\n base.transitionCheckbox(base.firstCheckbox, !base.firstCheckbox.prop('checked'))\n query = $search.val('')\n base.showCheckboxesThatMatchQuery(query)\n $checkboxes.removeClass('is-focused')\n }\n }\n }\n\n base.preventDefaultOnCertainKeys = function (event) {\n const enter = (event.keyCode === 13)\n const escape = (event.keyCode === 27)\n\n // This function does two things:\n // 1) Prevents escaping modals when escaping the multi-select\n // 2) Prevents submitting the form when checking checkboxes with enter\n\n if (enter || escape) {\n event.preventDefault()\n event.stopPropagation()\n return false\n }\n }\n\n base.transitionCheckboxByValue = function (value, checked) {\n const checkbox = base.findCheckbox(value)\n base.transitionCheckbox(checkbox, checked)\n }\n\n base.transitionCheckbox = function (checkbox, state) {\n const value = checkbox.val()\n const checked = checkbox.prop('checked')\n const stateDefined = typeof state !== 'undefined'\n const $tag = base.findTag(value)\n\n if (stateDefined) {\n if (state) {\n $search.before($tag)\n checkbox.prop('checked', true)\n } else {\n $options.append($tag)\n checkbox.prop('checked', false)\n }\n } else {\n if (checked) {\n $search.before($tag)\n // Clears the search input value when selecting a team member\n const query = $search.val('')\n base.showCheckboxesThatMatchQuery(query) // shows all team members by default\n $checkboxes.removeClass('is-focused')\n } else {\n $options.append($tag)\n }\n }\n\n if ($limit) { base.handleCheckBoxLimit() }\n\n $ms.trigger('choice')\n }\n\n base.handleCheckBoxLimit = function () {\n let checked_options = $ms.find('.js-checkbox-input:checked')\n let unchecked_options = $ms.find('.js-checkbox-input:not(:checked)')\n\n if ($limit <= checked_options.length) {\n unchecked_options.attr('disabled','true');\n $limit_error.removeClass('is-hidden');\n } else {\n unchecked_options.removeAttr('disabled');\n $limit_error.addClass('is-hidden');\n }\n }\n\n base.changeAllCheckboxes = function (visibility) {\n switch (visibility) {\n case 'hide':\n $checkboxWrappers.addClass('is-hidden')\n $checkboxes.removeClass('is-visible')\n break\n\n case 'show':\n $checkboxWrappers.removeClass('is-hidden')\n $checkboxes.addClass('is-visible')\n break\n\n default:\n throw new Error('Unsupported visibility state for checkboxes:' + visibility)\n }\n }\n\n base.controlAllCheckboxes = function (action) {\n switch (action) {\n case 'select-all':\n base.visibleCheckboxes.each(function () { base.transitionCheckbox($(this), true) })\n break\n\n case 'deselect-all':\n base.visibleCheckboxes.each(function () { base.transitionCheckbox($(this), false) })\n break\n\n case 'done':\n base.handleTransition('unfocused')\n break\n\n default:\n throw new Error('Unsupported action for multiple select:' + action)\n }\n }\n\n base.selectedValues = function () {\n return $.makeArray(\n $ms.find('.js-checkbox-input:checked').map(function (i, el) {\n return $(el).prop('value')\n })\n )\n }\n\n base.setDoneCallback = function (cb) {\n base.onDone = cb\n }\n\n const handleClickOutside = function (event) {\n if (!clickedInsideOf(event.target, $ms)) {\n base.handleTransition('unfocused')\n }\n }\n\n base.destroy = function () {\n $(document).unbind('click', handleClickOutside)\n }\n\n base.init = function () {\n // Show all tags that are preselected\n $checkboxes.each(function () { base.transitionCheckbox($(this)) })\n\n $input.on('click', function () {\n base.handleTransition('focused')\n })\n\n $dropdownControl.on('click', function (e) {\n e.stopPropagation()\n if ($ms.hasClass('is-focused')) {\n base.handleTransition('unfocused')\n } else {\n base.handleTransition('focused')\n }\n })\n\n $search.on('focus', function () {\n base.handleTransition('focused')\n })\n\n $search.on('keydown', function (event) {\n base.keydownSearchLength = $(this).val().length\n base.preventDefaultOnCertainKeys(event)\n })\n\n $search.on('keyup', function (event) {\n base.keyupSearchLength = $(this).val().length\n base.handleSearch(event, $(this).val().toLowerCase())\n base.preventDefaultOnCertainKeys(event)\n })\n\n $search.on('blur', function () {\n if (base.firstCheckbox.length) {\n base.firstCheckbox.removeClass('is-focused')\n }\n })\n\n $checkboxes.on('change', function () {\n base.transitionCheckbox($(this))\n })\n\n $actions.on('click', function () {\n base.controlAllCheckboxes($(this).data('action'))\n })\n\n $(document).bind('click', handleClickOutside)\n\n $tags.on('click', function () {\n base.transitionCheckbox(base.findCheckbox($(this).data('value')), false)\n })\n }\n\n base.visibleCheckboxes = $dropdown.find('.js-checkbox-input.is-visible')\n base.numberOfResults = base.visibleCheckboxes.length\n base.setResultCount(base.numberOfResults)\n base.firstCheckbox = ''\n $ms[0].actions = {\n focus: base.focus,\n unfocus: base.unfocus,\n selectedValues: base.selectedValues,\n transitionCheckboxByValue: base.transitionCheckboxByValue,\n setDoneCallback: base.setDoneCallback,\n destroy: base.destroy\n }\n base.init()\n }\n}\n\n$(document).on('ready ajaxComplete turbo:load', () => {\n $('.js-ms').each((index, target) => {\n const $ms = $(target)\n\n if (!$ms.data('initialized')) {\n new DesignSystemMultipleSelect($ms)\n new DesignSystemMultipleSelect($ms).init()\n $ms.data('initialized', true)\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemNavbar {\n constructor (navbar) {\n this.navbar = navbar[0]\n this.dropdownTriggers = this.navbar.querySelectorAll('.js-navbar__dropdown-trigger')\n this.dropdowns = this.navbar.querySelectorAll('.js-navbar__dropdown')\n }\n\n init () {\n this.initDropdownTrigger()\n }\n\n hideNavbarDropdowns () {\n this.dropdown.forEach((dropdown) => {\n dropdown.classList.remove('is-open')\n })\n }\n\n openNavbarDropdown (dropdown) {\n dropdown.classList.add('is-open')\n }\n\n initDropdownTrigger () {\n this.dropdownTriggers.forEach((trigger) => {\n trigger.addEventListener('mousedown', () => {\n const dropdownParent = trigger.parentElement\n if ( trigger.classList.contains('is-open') ) {\n this.hideNavbarDropdown();\n } else {\n this.hideNavbarDropdown();\n this.openNavbarDropdown(dropdownParent);\n }\n })\n\n trigger.addEventListener('mouseenter focusin', () => {\n const dropdownParent = trigger.parentElement\n this.hideNavbarDropdown()\n this.openNavbarDropdown(dropdownParent)\n })\n\n trigger.addEventListener('mouseleave focusout', (e) => {\n const dropdownParent = trigger.parentElement\n if(e.target !== dropdownParent && e.target.parentElement === dropdownParent){\n this.hideNavbarDropdown()\n }\n })\n })\n\n this.dropdowns.forEach((dropdown) => {\n dropdown.addEventListener('mouseleave', () => {\n this.hideNavbarDropdown()\n })\n })\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-navbar').each((_, target) => {\n const $navbar = $(target)\n\n if (!$navbar.data('initialized')) {\n $navbar.data('instance', new DesignSystemNavbar($navbar))\n $navbar.data('instance', new DesignSystemNavbar($navbar).init())\n $navbar.data('initialized', true)\n }\n })\n});\n","/* global $ */\n\nclass DesignSystemPanel {\n constructor ($panel) {\n this.$panel = $panel[0]\n }\n\n init () {\n $('.js-panel__show').on('click', () => {\n this.$panel.setAttribute('data-show', '')\n this.$panel.style.visibility = \"visible\"\n })\n\n $('.js-panel__show').on('keyup', (e) => {\n if (e.which == 13) {\n this.$panel.setAttribute('data-show', '')\n this.$panel.style.visibility = \"visible\"\n }\n })\n\n $('.js-panel__controls').on('click', () => {\n this.closePanel()\n })\n\n $('.js-c-panel__controls-close').on('click', () => {\n this.closePanel()\n })\n\n $(document).on('keyup', (e) => {\n if (e.which == 27) {\n this.closePanel()\n }\n })\n\n // clicking outside the panel to close it breaks in Lookbook\n if (!(window.location.pathname.indexOf('lookbook') > -1)) {\n $(document).on('click', (e) => {\n if (!this.isPanelTrigger(e.target) && !this.isInPanel(e.target)) {\n this.closePanel()\n }\n })\n }\n }\n\n closePanel () {\n if ($(this.$panel).attr('data-show') === '') {\n this.$panel.removeAttribute('data-show')\n this.$panel.style.visibility = \"hidden\"\n }\n }\n\n isPanelTrigger (element) {\n if ($('.js-panel__show').length > 1) { // for date button as link in report metric filters\n return $('.js-panel__show')[0] === $(element).closest('.c-button')[0] || $('.js-panel__show')[1] === $(element).closest('.c-button--as-link')[0]\n } else {\n return $('.js-panel__show')[0] === $(element).closest('.c-button')[0]\n }\n }\n\n isInPanel (element) {\n if ($(this.$panel).attr('data-show') === '') {\n return ($(element).closest('.js-panel').length > 0)\n }\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-panel').each((_, target) => {\n const $panel = $(target)\n\n if (!$panel.data('initialized')) {\n $panel.data('instance', new DesignSystemPanel($panel))\n $panel.data('instance').init()\n $panel.data('initialized', true)\n }\n })\n})\n","// /* global $ */\n\nclass DesignSystemProgressNavbar {\n constructor ($progressNavbar) {\n this.progressNavbar = $progressNavbar[0]\n this.steps = this.progressNavbar.querySelectorAll('.js-progress-navbar__step')\n this.completedUpToStep = this.progressNavbar.getAttribute('completed-up-to')\n this.stateNames = [\n 'is-current',\n 'is-progressing-to',\n 'is-completing',\n 'is-incomplete',\n 'is-in-progress',\n 'is-complete',\n 'is-complete-current',\n 'is-complete-future',\n ]\n }\n\n init () {\n this.loadCurrentStep()\n }\n\n currentStep () {\n return this.progressNavbar.querySelector('.js-progress-navbar__step.is-current')\n }\n\n loadCurrentStep () {\n this.currentStep().classList.add('is-progressing-to')\n }\n\n enableLink (step) {\n const href = step.getAttribute('href')\n const dataHref = step.getAttribute('data-href')\n if (href) {\n step.classList.add('is-link')\n step.setAttribute('href', href)\n step.setAttribute('data-href', '')\n }\n\n if(dataHref) {\n step.classList.add('is-link')\n step.setAttribute('href', dataHref)\n step.setAttribute('data-href', dataHref)\n }\n\n if (step.getAttribute('step-index') > this.completedUpToStep) {\n this.completedUpToStep = step.getAttribute('step-index')\n }\n }\n\n changeStepState (step, newState) {\n const counter = step.querySelector('.js-progress-navbar__step-counter')\n const counterInstance = $(counter).data('instance')\n\n step.classList.remove(...this.stateNames)\n step.classList.add(...newState.split(' '))\n\n if (typeof counterInstance !== 'undefined') {\n if (step.classList.contains('is-complete') ||\n step.classList.contains('is-complete-current') ||\n step.classList.contains('is-complete-future')\n ) {\n step.getAttribute('complete', true)\n counterInstance.changeState('complete')\n this.enableLink(step)\n } else if (step.classList.contains('is-current')) {\n counterInstance.changeState('in-progress')\n this.enableLink(step)\n } else {\n counterInstance.changeState('incomplete')\n }\n }\n }\n\n finishCurrentStep () {\n this.changeStepState(this.currentStep(), 'is-complete is-completing')\n }\n\n changeCurrentStep (newStep) {\n this.steps.forEach((step, index ) => {\n const thisStep = step\n if (index === newStep) {\n if (thisStep.getAttribute('complete')) {\n this.changeStepState(thisStep, 'is-complete-current is-current');\n } else {\n this.changeStepState(thisStep, 'is-in-progress is-current');\n }\n } else if (index > newStep) {\n if (thisStep.getAttribute('complete')) {\n this.changeStepState(thisStep, 'is-complete-future');\n } else {\n this.changeStepState(thisStep, 'is-incomplete');\n }\n } else {\n this.changeStepState(thisStep, 'is-complete');\n }\n });\n\n this.loadCurrentStep();\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-progress-navbar').each((_, target) => {\n const $progressNavbar = $(target)\n if (!$progressNavbar.data('initialized')) {\n $progressNavbar.data('instance', new DesignSystemProgressNavbar($progressNavbar))\n $progressNavbar.data('instance').init()\n $progressNavbar.data('initialized', true)\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemRadioButton {\n constructor ($radioButton) {\n this.$radioButton = $radioButton[0]\n this.$input = this.$radioButton.querySelector('.js-radio-button__input')\n this.$radioGroup = this.$radioButton.closest('.js-radio-group')\n this.$drawer = this.$radioButton.querySelector('.js-radio_button__drawer')\n }\n\n init () {\n if (this.$input) {\n this.$input.addEventListener('click', () => {\n if (this.$drawer) {\n this.handleDrawers()\n }\n\n if (this.$input.dataset.addControl || this.$input.dataset.removeControl) {\n this.handleVisibilityToggling()\n }\n })\n }\n }\n\n handleDrawers () {\n // Hide all content drawers for the parent radio group\n if (this.$radioGroup) {\n this.$radioGroup.querySelectorAll('.js-radio_button__drawer').forEach((drawer) => {\n drawer.classList.remove('is-open')\n })\n }\n\n // Show this radio buttons content drawer\n this.$drawer.classList.add('is-open')\n }\n\n handleVisibilityToggling() {\n const inputData = this.$input.dataset\n const $addControl = document.querySelector(inputData.addControl)\n const $removeControl = document.querySelector(inputData.removeControl)\n\n if ($addControl) {\n $addControl.classList.add(inputData.addState)\n }\n\n if ($removeControl) {\n $removeControl.classList.remove(inputData.removeState)\n }\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-radio-button').each((index, radioButton) => {\n const $radioButton = $(radioButton)\n\n if (!$radioButton.data('initialized')) {\n $radioButton.data('instance', new DesignSystemRadioButton($radioButton))\n $radioButton.data('instance').init()\n $radioButton.data('initialized', true)\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemSelect {\n constructor ($select) {\n this.$select = $select\n this.$wrapper = $select.closest('.js-select__wrapper')\n\n if (this.$wrapper.hasClass('js-select-toggle-content')) {\n this.$select.on('change', () => {\n this.toggleContent()\n })\n }\n }\n\n addValue (value, name) {\n this.$select.append(`
${name} `)\n this.setValue(value)\n }\n\n setValue (value) {\n this.$select.val(value)\n }\n\n toggleDisabled () {\n const currentStatus = this.$select.prop('disabled')\n\n this.$select.prop('disabled', !currentStatus)\n this.$wrapper.toggleClass('is-disabled')\n }\n\n toggleContent () {\n const selectedOption = this.$select.val()\n\n $('.js-select-toggle-target').addClass('is-hidden')\n\n $(`.js-select-toggle-target[data-option=${selectedOption}]`).removeClass('is-hidden')\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-select__input-field').each((_, target) => {\n if (!$(target).data('initialized')) {\n $(target).data('select', new DesignSystemSelect($(target)))\n $(target).data('initialized', true)\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemSwitch {\n constructor ($switch) {\n this.$switch = $switch\n }\n\n events () {\n this.$switch.on('change', () => {\n this.handleChange()\n })\n }\n\n handleChange () {\n const initialState = !this.$switch.prop('checked')\n\n $.charlie.modal('.js-switch-modal', {\n title: this.$switch.data('modal-title'),\n content: this.$switch.data('modal-content'),\n form: this.$switch.data('modal-form'),\n type: this.$switch.data('modal-type'),\n animation: this.$switch.data('modal-animation'),\n href: this.$switch.data('modal-href'),\n close_btn: this.$switch.data('modal-close-btn'),\n confirm_btn: this.$switch.data('modal-confirm-btn'),\n remote: this.$switch.data('modal-remote'),\n method: this.$switch.data('modal-method'),\n loader: this.$switch.data('modal-loader'),\n eventName: this.$switch.data('modal-eventName')\n })\n\n this.$switch.data('charlie-modal').$el.on('modal:cancelling', function () {\n $('.js-switch-modal').each((index, target) => {\n const $switch = $(target)\n $switch.prop('checked', initialState)\n $switch.off('modal:cancelling')\n })\n })\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-switch-modal').each((index, target) => {\n const $switch = $(target)\n if (!$switch.data('initialized')) {\n new DesignSystemSwitch($switch).events()\n $switch.data('initialized', true)\n }\n })\n})\n","/* global $ */\nclass DesignSystemTabbedContent {\n constructor ($tabbedContent) {\n this.$tabbedContent = $tabbedContent\n }\n\n events () {\n this.$tabbedContent.find('.c-tabbed_content__tab a').each((index, tab) => {\n tab.addEventListener('click', (e) => {\n this.handleClick(e, tab)\n })\n })\n }\n\n handleClick (e, $tab) {\n e.preventDefault()\n\n // Get elements we'll be manipulating. Remember to scope to the closest\n // .js-tab-container as there could be multiple Tabbed Content components\n // on a single page.\n const target = $tab.getAttribute('data-target')\n const targetedTab = $tab.closest('.c-tabbed_content__tab')\n const tabbedContent = $tab.closest('.js-tabbed-content')\n const targetedContent = tabbedContent.querySelector(`[id=\"${target}\"]`)\n const currentTab = tabbedContent.querySelector('.c-tabbed_content__tab--active')\n const currentContent = tabbedContent.querySelector('.c-tabbed_content__content--active')\n\n // Make the current active elements inactive.\n currentTab.classList.remove('c-tabbed_content__tab--active')\n currentTab.removeAttribute('aria-selected')\n currentTab.querySelector('[tabindex=\"-1\"]')\n\n currentContent.classList.remove('c-tabbed_content__content--active')\n currentContent.setAttribute('hidden', true)\n\n // Make the selected elements active.\n targetedTab.classList.add('c-tabbed_content__tab--active')\n currentTab.setAttribute('aria-selected', true)\n currentTab.querySelector('a').setAttribute('tabindex', '0')\n\n targetedContent.classList.add('c-tabbed_content__content--active')\n targetedContent.removeAttribute('hidden')\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-tabbed-content').each((index, target) => {\n const $tabbedContent = $(target)\n if (!$tabbedContent.data('initialized')) {\n new DesignSystemTabbedContent($tabbedContent).events()\n $tabbedContent.data('initialized', true)\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemTable {\n constructor (table) {\n this.table = table[0]\n\n const selectableRows = this.table.querySelector(\".js-selectable-rows\")\n if(selectableRows){\n this.setCheckboxes()\n this.totalNumberOfCheckboxes = this.checkboxes.length\n this.bulkActions = document.querySelector('.js-bulk-actions')\n this.avatarGroup = this.bulkActions.querySelector('.js-avatar_group')\n\n const tableObj = {\n updateTable: (rowId) => {\n this.updateTable(rowId)\n }\n }\n\n this.table.data = {'table': tableObj}\n\n this.bindSelectAllEvents()\n this.setSelectAllCheckboxState()\n }\n }\n\n // sets checkboxes on page load and on any row(s) updated\n setCheckboxes () {\n this.selectAllCheckbox = this.table.querySelector('.js-checkbox-input-select-all')\n this.checkboxes = Array.from(this.table.querySelectorAll('.js-checkbox-input')).filter((checkbox) => {\n return checkbox !== this.selectAllCheckbox\n })\n }\n\n // Adds the event listener for click on the checkbox(es) of the row(s) that was/were just changed (line manager changed or office changed or added to team or removed from team etc) or deleted\n updateTable (rowId) {\n this.setCheckboxes()\n this.selectAllUnSelected()\n\n // if row was updated and not deleted\n if(rowId) {\n const row = document.getElementById(rowId)\n const checkbox = row.querySelector('.js-checkbox-input')\n this.handleCheckboxListener(checkbox)\n }\n }\n\n // sets the event listener both on page load and on any row(s) updated\n handleCheckboxListener (checkbox) {\n checkbox.removeEventListener('click', null)\n checkbox.addEventListener('click', () => {\n this.setSelectAllCheckboxState()\n this.storeSelectedTableRowIds(checkbox)\n })\n }\n\n bindSelectAllEvents () {\n this.table.setAttribute('selected-rows', '[]')\n\n this.selectAllCheckbox.removeEventListener('click', null)\n this.selectAllCheckbox.addEventListener('click', () => {\n if ( this.selectAllCheckbox.checked ) {\n this.checkAllCheckboxes()\n } else {\n this.uncheckAllCheckboxes()\n }\n })\n\n this.checkboxes.map((checkbox) => {\n this.handleCheckboxListener(checkbox)\n })\n }\n\n howManyCheckboxesAreChecked() {\n let totalNumberOfCheckedCheckboxes = 0\n\n this.checkboxes.map((checkbox) => {\n if (checkbox.checked) {\n totalNumberOfCheckedCheckboxes += 1\n }\n })\n\n if (totalNumberOfCheckedCheckboxes === 0) {\n return 'none'\n } else {\n if (this.totalNumberOfCheckboxes === totalNumberOfCheckedCheckboxes) {\n return 'all'\n } else if (totalNumberOfCheckedCheckboxes > 0) {\n return 'some'\n } else {\n return 'none'\n }\n }\n }\n\n selectAllUnSelected () {\n this.selectAllCheckbox.checked = false\n this.selectAllCheckbox.indeterminate = false\n }\n\n setSelectAllCheckboxState() {\n const howManySelected = this.howManyCheckboxesAreChecked()\n\n switch (howManySelected) {\n case 'all':\n this.selectAllCheckbox.checked = true\n this.selectAllCheckbox.indeterminate = false\n this.selectAllSelected()\n break\n case 'some':\n this.selectAllCheckbox.checked = true\n this.selectAllCheckbox.indeterminate = true\n break\n case 'none':\n this.selectAllUnSelected()\n break\n default:\n this.selectAllUnSelected()\n break\n }\n }\n\n checkAllCheckboxes() {\n this.checkboxes.map((checkbox) => {\n checkbox.checked = true\n this.storeSelectedTableRowIds(checkbox)\n })\n }\n\n uncheckAllCheckboxes() {\n this.checkboxes.map((checkbox) => {\n checkbox.checked = false\n this.storeSelectedTableRowIds(checkbox)\n })\n }\n\n getTableRowId(checkbox) {\n return checkbox.closest('.js-table-row').getAttribute('id')\n }\n\n getTableRowAvatarUrl(checkbox) {\n return checkbox.closest('.js-table-row').querySelector('.js-avatar').style.backgroundImage\n }\n\n storeSelectedTableRowIds(checkbox) {\n const ID = this.getTableRowId(checkbox)\n const avatarURL = this.getTableRowAvatarUrl(checkbox)\n let storedIds = JSON.parse(this.table.getAttribute('selected-rows'))\n\n if (checkbox.checked) {\n if (!storedIds.includes(ID)) {\n storedIds.push(ID)\n }\n this.avatarGroup.data['avatar-group'].addAvatar(ID, avatarURL)\n this.bulkActions.data['bulk-actions'].activateBulkActions()\n } else {\n storedIds = storedIds.filter( id => {\n if(id !== ID){\n return id\n }\n })\n\n this.avatarGroup.data['avatar-group'].removeAvatar(ID)\n if (this.avatarGroup.data['avatar-group'].getCount() === 0) {\n bulkActionsWrapper.data['bulk-actions'].deactivateBulkActions()\n }\n }\n this.table.setAttribute('selected-rows', JSON.stringify(storedIds))\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-table').each((_, target) => {\n const $table = $(target)\n\n $table.tablesorter({\n cssDesc: 'c-table_cell--sorted-desc'\n })\n\n if (!$table.data('initialized')) {\n $table.data('instance', new DesignSystemTable($table))\n $table.data('initialized', true)\n }\n })\n})\n","/* global $ */\n\nclass DesignSystemTableRow {\n constructor ($tableRow) {\n this.$tableRow = $tableRow[0]\n\n this.initializeCharlieFunctions()\n }\n\n init () {\n // Suspect this deleteButton is no longer used - have placed Tombstone to test\n const deleteButton = this.$tableRow.querySelector('.js-delete-table-row')\n if (deleteButton) {\n deleteButton.addEventListener('click', () => {\n $.charlie.removeTableRow(this.$tableRow)\n });\n }\n }\n\n initializeCharlieFunctions () {\n if (!$.charlie) {\n $.charlie = {};\n }\n\n if (!$.charlie.replaceTableRow) {\n\n // used by bulk_actions.js.erb when updating row(s) from table\n $.charlie.replaceTableRow = ($target, $row) => {\n var $table = $target.closest('.js-table')[0]\n var id = $target.attr('id')\n $target.replaceWith($row)\n\n $('#' + id).addClass('is-changing')\n\n setTimeout(function () {\n $('#' + id).removeClass('is-changing')\n $table.data['table'].updateTable(id)\n }, 1500)\n }\n }\n\n // used when removing item from table\n if (!$.charlie.removeTableRow) {\n $.charlie.removeTableRow = ($row) => {\n var $table = $row.closest('.js-table')[0]\n $row.remove()\n $table.data['table'].updateTable(null)\n }\n }\n\n // Suspect this is no longer used - have placed Tombstones:\n if (!$.charlie.newTableRow) {\n $.charlie.newTableRow = ($table, $row) => {\n var $tableBody = $table.find('.js-table-body')\n $tableBody.prepend($row)\n $table.data('table').updateTable()\n }\n }\n }\n}\n\n$(document).on('ready ajaxComplete', () => {\n $('.js-table-row').each((_, target) => {\n const $tableRow = $(target)\n\n if (!$tableRow.data('initialized')) {\n $tableRow.data('instance', new DesignSystemTableRow($tableRow))\n // $tableRow.data('instance').init()\n $tableRow.data('initialized', true)\n }\n })\n});\n","/* global $, charlie */\n\nclass DesignSystemTooltip {\n constructor (tooltip, control) {\n this.tooltip = tooltip[0]\n this.control = control\n this.visibleOnLoad = this.tooltip.classList.contains('js-visible-on-load')\n }\n\n init () {\n this.initialisePopper()\n }\n\n initialisePopper () {\n new Popper(this.tooltip, this.visibleOnLoad, this.control).init()\n }\n}\n\ncharlie.onReady(() => {\n $(document).on('ready ajaxComplete', () => {\n $('.js-tooltip').each((index, target) => {\n const $tooltip = $(target)\n if (!$tooltip.data('initialized')) {\n new DesignSystemTooltip($tooltip).init()\n $tooltip.data('initialized', true)\n }\n })\n })\n})\n\nexport { DesignSystemTooltip }\n","/*!\n * Bootstrap Colorpicker v2.3.3\n * http://mjolnic.github.io/bootstrap-colorpicker/\n *\n * Originally written by (c) 2012 Stefan Petre\n * Licensed under the Apache License v2.0\n * http://www.apache.org/licenses/LICENSE-2.0.txt\n *\n */\n\n(function(factory) {\n \"use strict\";\n if (typeof exports === 'object') {\n module.exports = factory(window.jQuery);\n } else if (typeof define === 'function' && define.amd) {\n define(['jquery'], factory);\n } else if (window.jQuery && !window.jQuery.fn.colorpicker) {\n factory(window.jQuery);\n }\n}(function($) {\n 'use strict';\n\n /**\n * Color manipulation helper class\n *\n * @param {Object|String} val\n * @param {Object} predefinedColors\n * @constructor\n */\n var Color = function(val, predefinedColors) {\n this.value = {\n h: 0,\n s: 0,\n b: 0,\n a: 1\n };\n this.origFormat = null; // original string format\n if (predefinedColors) {\n $.extend(this.colors, predefinedColors);\n }\n if (val) {\n if (val.toLowerCase !== undefined) {\n // cast to string\n val = val + '';\n this.setColor(val);\n } else if (val.h !== undefined) {\n this.value = val;\n }\n }\n };\n\n Color.prototype = {\n constructor: Color,\n // 140 predefined colors from the HTML Colors spec\n colors: {\n \"aliceblue\": \"#f0f8ff\",\n \"antiquewhite\": \"#faebd7\",\n \"aqua\": \"#00ffff\",\n \"aquamarine\": \"#7fffd4\",\n \"azure\": \"#f0ffff\",\n \"beige\": \"#f5f5dc\",\n \"bisque\": \"#ffe4c4\",\n \"black\": \"#000000\",\n \"blanchedalmond\": \"#ffebcd\",\n \"blue\": \"#0000ff\",\n \"blueviolet\": \"#8a2be2\",\n \"brown\": \"#a52a2a\",\n \"burlywood\": \"#deb887\",\n \"cadetblue\": \"#5f9ea0\",\n \"chartreuse\": \"#7fff00\",\n \"chocolate\": \"#d2691e\",\n \"coral\": \"#ff7f50\",\n \"cornflowerblue\": \"#6495ed\",\n \"cornsilk\": \"#fff8dc\",\n \"crimson\": \"#dc143c\",\n \"cyan\": \"#00ffff\",\n \"darkblue\": \"#00008b\",\n \"darkcyan\": \"#008b8b\",\n \"darkgoldenrod\": \"#b8860b\",\n \"darkgray\": \"#a9a9a9\",\n \"darkgreen\": \"#006400\",\n \"darkkhaki\": \"#bdb76b\",\n \"darkmagenta\": \"#8b008b\",\n \"darkolivegreen\": \"#556b2f\",\n \"darkorange\": \"#ff8c00\",\n \"darkorchid\": \"#9932cc\",\n \"darkred\": \"#8b0000\",\n \"darksalmon\": \"#e9967a\",\n \"darkseagreen\": \"#8fbc8f\",\n \"darkslateblue\": \"#483d8b\",\n \"darkslategray\": \"#2f4f4f\",\n \"darkturquoise\": \"#00ced1\",\n \"darkviolet\": \"#9400d3\",\n \"deeppink\": \"#ff1493\",\n \"deepskyblue\": \"#00bfff\",\n \"dimgray\": \"#696969\",\n \"dodgerblue\": \"#1e90ff\",\n \"firebrick\": \"#b22222\",\n \"floralwhite\": \"#fffaf0\",\n \"forestgreen\": \"#228b22\",\n \"fuchsia\": \"#ff00ff\",\n \"gainsboro\": \"#dcdcdc\",\n \"ghostwhite\": \"#f8f8ff\",\n \"gold\": \"#ffd700\",\n \"goldenrod\": \"#daa520\",\n \"gray\": \"#808080\",\n \"green\": \"#008000\",\n \"greenyellow\": \"#adff2f\",\n \"honeydew\": \"#f0fff0\",\n \"hotpink\": \"#ff69b4\",\n \"indianred\": \"#cd5c5c\",\n \"indigo\": \"#4b0082\",\n \"ivory\": \"#fffff0\",\n \"khaki\": \"#f0e68c\",\n \"lavender\": \"#e6e6fa\",\n \"lavenderblush\": \"#fff0f5\",\n \"lawngreen\": \"#7cfc00\",\n \"lemonchiffon\": \"#fffacd\",\n \"lightblue\": \"#add8e6\",\n \"lightcoral\": \"#f08080\",\n \"lightcyan\": \"#e0ffff\",\n \"lightgoldenrodyellow\": \"#fafad2\",\n \"lightgrey\": \"#d3d3d3\",\n \"lightgreen\": \"#90ee90\",\n \"lightpink\": \"#ffb6c1\",\n \"lightsalmon\": \"#ffa07a\",\n \"lightseagreen\": \"#20b2aa\",\n \"lightskyblue\": \"#87cefa\",\n \"lightslategray\": \"#778899\",\n \"lightsteelblue\": \"#b0c4de\",\n \"lightyellow\": \"#ffffe0\",\n \"lime\": \"#00ff00\",\n \"limegreen\": \"#32cd32\",\n \"linen\": \"#faf0e6\",\n \"magenta\": \"#ff00ff\",\n \"maroon\": \"#800000\",\n \"mediumaquamarine\": \"#66cdaa\",\n \"mediumblue\": \"#0000cd\",\n \"mediumorchid\": \"#ba55d3\",\n \"mediumpurple\": \"#9370d8\",\n \"mediumseagreen\": \"#3cb371\",\n \"mediumslateblue\": \"#7b68ee\",\n \"mediumspringgreen\": \"#00fa9a\",\n \"mediumturquoise\": \"#48d1cc\",\n \"mediumvioletred\": \"#c71585\",\n \"midnightblue\": \"#191970\",\n \"mintcream\": \"#f5fffa\",\n \"mistyrose\": \"#ffe4e1\",\n \"moccasin\": \"#ffe4b5\",\n \"navajowhite\": \"#ffdead\",\n \"navy\": \"#000080\",\n \"oldlace\": \"#fdf5e6\",\n \"olive\": \"#808000\",\n \"olivedrab\": \"#6b8e23\",\n \"orange\": \"#ffa500\",\n \"orangered\": \"#ff4500\",\n \"orchid\": \"#da70d6\",\n \"palegoldenrod\": \"#eee8aa\",\n \"palegreen\": \"#98fb98\",\n \"paleturquoise\": \"#afeeee\",\n \"palevioletred\": \"#d87093\",\n \"papayawhip\": \"#ffefd5\",\n \"peachpuff\": \"#ffdab9\",\n \"peru\": \"#cd853f\",\n \"pink\": \"#ffc0cb\",\n \"plum\": \"#dda0dd\",\n \"powderblue\": \"#b0e0e6\",\n \"purple\": \"#800080\",\n \"red\": \"#ff0000\",\n \"rosybrown\": \"#bc8f8f\",\n \"royalblue\": \"#4169e1\",\n \"saddlebrown\": \"#8b4513\",\n \"salmon\": \"#fa8072\",\n \"sandybrown\": \"#f4a460\",\n \"seagreen\": \"#2e8b57\",\n \"seashell\": \"#fff5ee\",\n \"sienna\": \"#a0522d\",\n \"silver\": \"#c0c0c0\",\n \"skyblue\": \"#87ceeb\",\n \"slateblue\": \"#6a5acd\",\n \"slategray\": \"#708090\",\n \"snow\": \"#fffafa\",\n \"springgreen\": \"#00ff7f\",\n \"steelblue\": \"#4682b4\",\n \"tan\": \"#d2b48c\",\n \"teal\": \"#008080\",\n \"thistle\": \"#d8bfd8\",\n \"tomato\": \"#ff6347\",\n \"turquoise\": \"#40e0d0\",\n \"violet\": \"#ee82ee\",\n \"wheat\": \"#f5deb3\",\n \"white\": \"#ffffff\",\n \"whitesmoke\": \"#f5f5f5\",\n \"yellow\": \"#ffff00\",\n \"yellowgreen\": \"#9acd32\",\n \"transparent\": \"transparent\"\n },\n _sanitizeNumber: function(val) {\n if (typeof val === 'number') {\n return val;\n }\n if (isNaN(val) || (val === null) || (val === '') || (val === undefined)) {\n return 1;\n }\n if (val === '') {\n return 0;\n }\n if (val.toLowerCase !== undefined) {\n if (val.match(/^\\./)) {\n val = \"0\" + val;\n }\n return Math.ceil(parseFloat(val) * 100) / 100;\n }\n return 1;\n },\n isTransparent: function(strVal) {\n if (!strVal) {\n return false;\n }\n strVal = strVal.toLowerCase().trim();\n return (strVal === 'transparent') || (strVal.match(/#?00000000/)) || (strVal.match(/(rgba|hsla)\\(0,0,0,0?\\.?0\\)/));\n },\n rgbaIsTransparent: function(rgba) {\n return ((rgba.r === 0) && (rgba.g === 0) && (rgba.b === 0) && (rgba.a === 0));\n },\n //parse a string to HSB\n setColor: function(strVal) {\n strVal = strVal.toLowerCase().trim();\n if (strVal) {\n if (this.isTransparent(strVal)) {\n this.value = {\n h: 0,\n s: 0,\n b: 0,\n a: 0\n };\n } else {\n this.value = this.stringToHSB(strVal) || {\n h: 0,\n s: 0,\n b: 0,\n a: 1\n }; // if parser fails, defaults to black\n }\n }\n },\n stringToHSB: function(strVal) {\n strVal = strVal.toLowerCase();\n var alias;\n if (typeof this.colors[strVal] !== 'undefined') {\n strVal = this.colors[strVal];\n alias = 'alias';\n }\n var that = this,\n result = false;\n $.each(this.stringParsers, function(i, parser) {\n var match = parser.re.exec(strVal),\n values = match && parser.parse.apply(that, [match]),\n format = alias || parser.format || 'rgba';\n if (values) {\n if (format.match(/hsla?/)) {\n result = that.RGBtoHSB.apply(that, that.HSLtoRGB.apply(that, values));\n } else {\n result = that.RGBtoHSB.apply(that, values);\n }\n that.origFormat = format;\n return false;\n }\n return true;\n });\n return result;\n },\n setHue: function(h) {\n this.value.h = 1 - h;\n },\n setSaturation: function(s) {\n this.value.s = s;\n },\n setBrightness: function(b) {\n this.value.b = 1 - b;\n },\n setAlpha: function(a) {\n this.value.a = Math.round((parseInt((1 - a) * 100, 10) / 100) * 100) / 100;\n },\n toRGB: function(h, s, b, a) {\n if (!h) {\n h = this.value.h;\n s = this.value.s;\n b = this.value.b;\n }\n h *= 360;\n var R, G, B, X, C;\n h = (h % 360) / 60;\n C = b * s;\n X = C * (1 - Math.abs(h % 2 - 1));\n R = G = B = b - C;\n\n h = ~~h;\n R += [C, X, 0, 0, X, C][h];\n G += [X, C, C, X, 0, 0][h];\n B += [0, 0, X, C, C, X][h];\n return {\n r: Math.round(R * 255),\n g: Math.round(G * 255),\n b: Math.round(B * 255),\n a: a || this.value.a\n };\n },\n toHex: function(h, s, b, a) {\n var rgb = this.toRGB(h, s, b, a);\n if (this.rgbaIsTransparent(rgb)) {\n return 'transparent';\n }\n return '#' + ((1 << 24) | (parseInt(rgb.r) << 16) | (parseInt(rgb.g) << 8) | parseInt(rgb.b)).toString(16).substr(1);\n },\n toHSL: function(h, s, b, a) {\n h = h || this.value.h;\n s = s || this.value.s;\n b = b || this.value.b;\n a = a || this.value.a;\n\n var H = h,\n L = (2 - s) * b,\n S = s * b;\n if (L > 0 && L <= 1) {\n S /= L;\n } else {\n S /= 2 - L;\n }\n L /= 2;\n if (S > 1) {\n S = 1;\n }\n return {\n h: isNaN(H) ? 0 : H,\n s: isNaN(S) ? 0 : S,\n l: isNaN(L) ? 0 : L,\n a: isNaN(a) ? 0 : a\n };\n },\n toAlias: function(r, g, b, a) {\n var rgb = this.toHex(r, g, b, a);\n for (var alias in this.colors) {\n if (this.colors[alias] === rgb) {\n return alias;\n }\n }\n return false;\n },\n RGBtoHSB: function(r, g, b, a) {\n r /= 255;\n g /= 255;\n b /= 255;\n\n var H, S, V, C;\n V = Math.max(r, g, b);\n C = V - Math.min(r, g, b);\n H = (C === 0 ? null :\n V === r ? (g - b) / C :\n V === g ? (b - r) / C + 2 :\n (r - g) / C + 4\n );\n H = ((H + 360) % 6) * 60 / 360;\n S = C === 0 ? 0 : C / V;\n return {\n h: this._sanitizeNumber(H),\n s: S,\n b: V,\n a: this._sanitizeNumber(a)\n };\n },\n HueToRGB: function(p, q, h) {\n if (h < 0) {\n h += 1;\n } else if (h > 1) {\n h -= 1;\n }\n if ((h * 6) < 1) {\n return p + (q - p) * h * 6;\n } else if ((h * 2) < 1) {\n return q;\n } else if ((h * 3) < 2) {\n return p + (q - p) * ((2 / 3) - h) * 6;\n } else {\n return p;\n }\n },\n HSLtoRGB: function(h, s, l, a) {\n if (s < 0) {\n s = 0;\n }\n var q;\n if (l <= 0.5) {\n q = l * (1 + s);\n } else {\n q = l + s - (l * s);\n }\n\n var p = 2 * l - q;\n\n var tr = h + (1 / 3);\n var tg = h;\n var tb = h - (1 / 3);\n\n var r = Math.round(this.HueToRGB(p, q, tr) * 255);\n var g = Math.round(this.HueToRGB(p, q, tg) * 255);\n var b = Math.round(this.HueToRGB(p, q, tb) * 255);\n return [r, g, b, this._sanitizeNumber(a)];\n },\n toString: function(format) {\n format = format || 'rgba';\n var c = false;\n switch (format) {\n case 'rgb':\n {\n c = this.toRGB();\n if (this.rgbaIsTransparent(c)) {\n return 'transparent';\n }\n return 'rgb(' + c.r + ',' + c.g + ',' + c.b + ')';\n }\n break;\n case 'rgba':\n {\n c = this.toRGB();\n return 'rgba(' + c.r + ',' + c.g + ',' + c.b + ',' + c.a + ')';\n }\n break;\n case 'hsl':\n {\n c = this.toHSL();\n return 'hsl(' + Math.round(c.h * 360) + ',' + Math.round(c.s * 100) + '%,' + Math.round(c.l * 100) + '%)';\n }\n break;\n case 'hsla':\n {\n c = this.toHSL();\n return 'hsla(' + Math.round(c.h * 360) + ',' + Math.round(c.s * 100) + '%,' + Math.round(c.l * 100) + '%,' + c.a + ')';\n }\n break;\n case 'hex':\n {\n return this.toHex();\n }\n break;\n case 'alias':\n return this.toAlias() || this.toHex();\n default:\n {\n return c;\n }\n break;\n }\n },\n // a set of RE's that can match strings and generate color tuples.\n // from John Resig color plugin\n // https://github.com/jquery/jquery-color/\n stringParsers: [{\n re: /rgb\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*?\\)/,\n format: 'rgb',\n parse: function(execResult) {\n return [\n execResult[1],\n execResult[2],\n execResult[3],\n 1\n ];\n }\n }, {\n re: /rgb\\(\\s*(\\d*(?:\\.\\d+)?)\\%\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*?\\)/,\n format: 'rgb',\n parse: function(execResult) {\n return [\n 2.55 * execResult[1],\n 2.55 * execResult[2],\n 2.55 * execResult[3],\n 1\n ];\n }\n }, {\n re: /rgba\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*(?:,\\s*(\\d*(?:\\.\\d+)?)\\s*)?\\)/,\n format: 'rgba',\n parse: function(execResult) {\n return [\n execResult[1],\n execResult[2],\n execResult[3],\n execResult[4]\n ];\n }\n }, {\n re: /rgba\\(\\s*(\\d*(?:\\.\\d+)?)\\%\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*(?:,\\s*(\\d*(?:\\.\\d+)?)\\s*)?\\)/,\n format: 'rgba',\n parse: function(execResult) {\n return [\n 2.55 * execResult[1],\n 2.55 * execResult[2],\n 2.55 * execResult[3],\n execResult[4]\n ];\n }\n }, {\n re: /hsl\\(\\s*(\\d*(?:\\.\\d+)?)\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*?\\)/,\n format: 'hsl',\n parse: function(execResult) {\n return [\n execResult[1] / 360,\n execResult[2] / 100,\n execResult[3] / 100,\n execResult[4]\n ];\n }\n }, {\n re: /hsla\\(\\s*(\\d*(?:\\.\\d+)?)\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*(?:,\\s*(\\d*(?:\\.\\d+)?)\\s*)?\\)/,\n format: 'hsla',\n parse: function(execResult) {\n return [\n execResult[1] / 360,\n execResult[2] / 100,\n execResult[3] / 100,\n execResult[4]\n ];\n }\n }, {\n re: /#?([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/,\n format: 'hex',\n parse: function(execResult) {\n return [\n parseInt(execResult[1], 16),\n parseInt(execResult[2], 16),\n parseInt(execResult[3], 16),\n 1\n ];\n }\n }, {\n re: /#?([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/,\n format: 'hex',\n parse: function(execResult) {\n return [\n parseInt(execResult[1] + execResult[1], 16),\n parseInt(execResult[2] + execResult[2], 16),\n parseInt(execResult[3] + execResult[3], 16),\n 1\n ];\n }\n }],\n colorNameToHex: function(name) {\n if (typeof this.colors[name.toLowerCase()] !== 'undefined') {\n return this.colors[name.toLowerCase()];\n }\n return false;\n }\n };\n\n /*\n * Default plugin options\n */\n var defaults = {\n horizontal: false, // horizontal mode layout ?\n inline: false, //forces to show the colorpicker as an inline element\n color: false, //forces a color\n format: false, //forces a format\n input: 'input', // children input selector\n container: false, // container selector\n component: '.add-on, .input-group-addon', // children component selector\n sliders: {\n saturation: {\n maxLeft: 100,\n maxTop: 100,\n callLeft: 'setSaturation',\n callTop: 'setBrightness'\n },\n hue: {\n maxLeft: 0,\n maxTop: 100,\n callLeft: false,\n callTop: 'setHue'\n },\n alpha: {\n maxLeft: 0,\n maxTop: 100,\n callLeft: false,\n callTop: 'setAlpha'\n }\n },\n slidersHorz: {\n saturation: {\n maxLeft: 100,\n maxTop: 100,\n callLeft: 'setSaturation',\n callTop: 'setBrightness'\n },\n hue: {\n maxLeft: 100,\n maxTop: 0,\n callLeft: 'setHue',\n callTop: false\n },\n alpha: {\n maxLeft: 100,\n maxTop: 0,\n callLeft: 'setAlpha',\n callTop: false\n }\n },\n template: '
' +\n '
' +\n '
' +\n '
' +\n '
' +\n '
' +\n '
',\n align: 'right',\n customClass: null,\n colorSelectors: null\n };\n\n /**\n * Colorpicker component class\n *\n * @param {Object|String} element\n * @param {Object} options\n * @constructor\n */\n var Colorpicker = function(element, options) {\n this.element = $(element).addClass('colorpicker-element');\n this.options = $.extend(true, {}, defaults, this.element.data(), options);\n this.component = this.options.component;\n this.component = (this.component !== false) ? this.element.find(this.component) : false;\n if (this.component && (this.component.length === 0)) {\n this.component = false;\n }\n this.container = (this.options.container === true) ? this.element : this.options.container;\n this.container = (this.container !== false) ? $(this.container) : false;\n\n // Is the element an input? Should we search inside for any input?\n this.input = this.element.is('input') ? this.element : (this.options.input ?\n this.element.find(this.options.input) : false);\n if (this.input && (this.input.length === 0)) {\n this.input = false;\n }\n // Set HSB color\n this.color = new Color(this.options.color !== false ? this.options.color : this.getValue(), this.options.colorSelectors);\n this.format = this.options.format !== false ? this.options.format : this.color.origFormat;\n\n if (this.options.color !== false) {\n this.updateInput(this.color);\n this.updateData(this.color);\n }\n\n // Setup picker\n this.picker = $(this.options.template);\n if (this.options.customClass) {\n this.picker.addClass(this.options.customClass);\n }\n if (this.options.inline) {\n this.picker.addClass('colorpicker-inline colorpicker-visible');\n } else {\n this.picker.addClass('colorpicker-hidden');\n }\n if (this.options.horizontal) {\n this.picker.addClass('colorpicker-horizontal');\n }\n if (this.format === 'rgba' || this.format === 'hsla' || this.options.format === false) {\n this.picker.addClass('colorpicker-with-alpha');\n }\n if (this.options.align === 'right') {\n this.picker.addClass('colorpicker-right');\n }\n if (this.options.inline === true) {\n this.picker.addClass('colorpicker-no-arrow');\n }\n if (this.options.colorSelectors) {\n var colorpicker = this;\n $.each(this.options.colorSelectors, function(name, color) {\n var $btn = $('
').css('background-color', color).data('class', name);\n $btn.click(function() {\n colorpicker.setValue($(this).css('background-color'));\n });\n colorpicker.picker.find('.colorpicker-selectors').append($btn);\n });\n this.picker.find('.colorpicker-selectors').show();\n }\n this.picker.on('mousedown.colorpicker touchstart.colorpicker', $.proxy(this.mousedown, this));\n this.picker.appendTo(this.container ? this.container : $('body'));\n\n // Bind events\n if (this.input !== false) {\n this.input.on({\n 'keyup.colorpicker': $.proxy(this.keyup, this)\n });\n this.input.on({\n 'change.colorpicker': $.proxy(this.change, this)\n });\n if (this.component === false) {\n this.element.on({\n 'focus.colorpicker': $.proxy(this.show, this)\n });\n }\n if (this.options.inline === false) {\n this.element.on({\n 'focusout.colorpicker': $.proxy(this.hide, this)\n });\n }\n }\n\n if (this.component !== false) {\n this.component.on({\n 'click.colorpicker': $.proxy(this.show, this)\n });\n }\n\n if ((this.input === false) && (this.component === false)) {\n this.element.on({\n 'click.colorpicker': $.proxy(this.show, this)\n });\n }\n\n // for HTML5 input[type='color']\n if ((this.input !== false) && (this.component !== false) && (this.input.attr('type') === 'color')) {\n\n this.input.on({\n 'click.colorpicker': $.proxy(this.show, this),\n 'focus.colorpicker': $.proxy(this.show, this)\n });\n }\n this.update();\n\n $($.proxy(function() {\n this.element.trigger('create');\n }, this));\n };\n\n Colorpicker.Color = Color;\n\n Colorpicker.prototype = {\n constructor: Colorpicker,\n destroy: function() {\n this.picker.remove();\n this.element.removeData('colorpicker', 'color').off('.colorpicker');\n if (this.input !== false) {\n this.input.off('.colorpicker');\n }\n if (this.component !== false) {\n this.component.off('.colorpicker');\n }\n this.element.removeClass('colorpicker-element');\n this.element.trigger({\n type: 'destroy'\n });\n },\n reposition: function() {\n if (this.options.inline !== false || this.options.container) {\n return false;\n }\n var type = this.container && this.container[0] !== document.body ? 'position' : 'offset';\n var element = this.component || this.element;\n var offset = element[type]();\n if (this.options.align === 'right') {\n offset.left -= this.picker.outerWidth() - element.outerWidth();\n }\n this.picker.css({\n top: offset.top + element.outerHeight(),\n left: offset.left\n });\n },\n show: function(e) {\n if (this.isDisabled()) {\n return false;\n }\n this.picker.addClass('colorpicker-visible').removeClass('colorpicker-hidden');\n this.reposition();\n $(window).on('resize.colorpicker', $.proxy(this.reposition, this));\n if (e && (!this.hasInput() || this.input.attr('type') === 'color')) {\n if (e.stopPropagation && e.preventDefault) {\n e.stopPropagation();\n e.preventDefault();\n }\n }\n if ((this.component || !this.input) && (this.options.inline === false)) {\n $(window.document).on({\n 'mousedown.colorpicker': $.proxy(this.hide, this)\n });\n }\n this.element.trigger({\n type: 'showPicker',\n color: this.color\n });\n },\n hide: function() {\n this.picker.addClass('colorpicker-hidden').removeClass('colorpicker-visible');\n $(window).off('resize.colorpicker', this.reposition);\n $(document).off({\n 'mousedown.colorpicker': this.hide\n });\n this.update();\n this.element.trigger({\n type: 'hidePicker',\n color: this.color\n });\n },\n updateData: function(val) {\n val = val || this.color.toString(this.format);\n this.element.data('color', val);\n return val;\n },\n updateInput: function(val) {\n val = val || this.color.toString(this.format);\n if (this.input !== false) {\n if (this.options.colorSelectors) {\n var color = new Color(val, this.options.colorSelectors);\n var alias = color.toAlias();\n if (typeof this.options.colorSelectors[alias] !== 'undefined') {\n val = alias;\n }\n }\n this.input.prop('value', val);\n }\n return val;\n },\n updatePicker: function(val) {\n if (val !== undefined) {\n this.color = new Color(val, this.options.colorSelectors);\n }\n var sl = (this.options.horizontal === false) ? this.options.sliders : this.options.slidersHorz;\n var icns = this.picker.find('i');\n if (icns.length === 0) {\n return;\n }\n if (this.options.horizontal === false) {\n sl = this.options.sliders;\n icns.eq(1).css('top', sl.hue.maxTop * (1 - this.color.value.h)).end()\n .eq(2).css('top', sl.alpha.maxTop * (1 - this.color.value.a));\n } else {\n sl = this.options.slidersHorz;\n icns.eq(1).css('left', sl.hue.maxLeft * (1 - this.color.value.h)).end()\n .eq(2).css('left', sl.alpha.maxLeft * (1 - this.color.value.a));\n }\n icns.eq(0).css({\n 'top': sl.saturation.maxTop - this.color.value.b * sl.saturation.maxTop,\n 'left': this.color.value.s * sl.saturation.maxLeft\n });\n this.picker.find('.colorpicker-saturation').css('backgroundColor', this.color.toHex(this.color.value.h, 1, 1, 1));\n this.picker.find('.colorpicker-alpha').css('backgroundColor', this.color.toHex());\n this.picker.find('.colorpicker-color, .colorpicker-color div').css('backgroundColor', this.color.toString(this.format));\n return val;\n },\n updateComponent: function(val) {\n val = val || this.color.toString(this.format);\n if (this.component !== false) {\n var icn = this.component.find('i').eq(0);\n if (icn.length > 0) {\n icn.css({\n 'backgroundColor': val\n });\n } else {\n this.component.css({\n 'backgroundColor': val\n });\n }\n }\n return val;\n },\n update: function(force) {\n var val;\n if ((this.getValue(false) !== false) || (force === true)) {\n // Update input/data only if the current value is not empty\n val = this.updateComponent();\n this.updateInput(val);\n this.updateData(val);\n this.updatePicker(); // only update picker if value is not empty\n }\n return val;\n\n },\n setValue: function(val) { // set color manually\n this.color = new Color(val, this.options.colorSelectors);\n this.update(true);\n this.element.trigger({\n type: 'changeColor',\n color: this.color,\n value: val\n });\n },\n getValue: function(defaultValue) {\n defaultValue = (defaultValue === undefined) ? '#000000' : defaultValue;\n var val;\n if (this.hasInput()) {\n val = this.input.val();\n } else {\n val = this.element.data('color');\n }\n if ((val === undefined) || (val === '') || (val === null)) {\n // if not defined or empty, return default\n val = defaultValue;\n }\n return val;\n },\n hasInput: function() {\n return (this.input !== false);\n },\n isDisabled: function() {\n if (this.hasInput()) {\n return (this.input.prop('disabled') === true);\n }\n return false;\n },\n disable: function() {\n if (this.hasInput()) {\n this.input.prop('disabled', true);\n this.element.trigger({\n type: 'disable',\n color: this.color,\n value: this.getValue()\n });\n return true;\n }\n return false;\n },\n enable: function() {\n if (this.hasInput()) {\n this.input.prop('disabled', false);\n this.element.trigger({\n type: 'enable',\n color: this.color,\n value: this.getValue()\n });\n return true;\n }\n return false;\n },\n currentSlider: null,\n mousePointer: {\n left: 0,\n top: 0\n },\n mousedown: function(e) {\n if (!e.pageX && !e.pageY && e.originalEvent && e.originalEvent.touches) {\n e.pageX = e.originalEvent.touches[0].pageX;\n e.pageY = e.originalEvent.touches[0].pageY;\n }\n e.stopPropagation();\n e.preventDefault();\n\n var target = $(e.target);\n\n //detect the slider and set the limits and callbacks\n var zone = target.closest('div');\n var sl = this.options.horizontal ? this.options.slidersHorz : this.options.sliders;\n if (!zone.is('.colorpicker')) {\n if (zone.is('.colorpicker-saturation')) {\n this.currentSlider = $.extend({}, sl.saturation);\n } else if (zone.is('.colorpicker-hue')) {\n this.currentSlider = $.extend({}, sl.hue);\n } else if (zone.is('.colorpicker-alpha')) {\n this.currentSlider = $.extend({}, sl.alpha);\n } else {\n return false;\n }\n var offset = zone.offset();\n //reference to guide's style\n this.currentSlider.guide = zone.find('i')[0].style;\n this.currentSlider.left = e.pageX - offset.left;\n this.currentSlider.top = e.pageY - offset.top;\n this.mousePointer = {\n left: e.pageX,\n top: e.pageY\n };\n //trigger mousemove to move the guide to the current position\n $(document).on({\n 'mousemove.colorpicker': $.proxy(this.mousemove, this),\n 'touchmove.colorpicker': $.proxy(this.mousemove, this),\n 'mouseup.colorpicker': $.proxy(this.mouseup, this),\n 'touchend.colorpicker': $.proxy(this.mouseup, this)\n }).trigger('mousemove');\n }\n return false;\n },\n mousemove: function(e) {\n if (!e.pageX && !e.pageY && e.originalEvent && e.originalEvent.touches) {\n e.pageX = e.originalEvent.touches[0].pageX;\n e.pageY = e.originalEvent.touches[0].pageY;\n }\n e.stopPropagation();\n e.preventDefault();\n var left = Math.max(\n 0,\n Math.min(\n this.currentSlider.maxLeft,\n this.currentSlider.left + ((e.pageX || this.mousePointer.left) - this.mousePointer.left)\n )\n );\n var top = Math.max(\n 0,\n Math.min(\n this.currentSlider.maxTop,\n this.currentSlider.top + ((e.pageY || this.mousePointer.top) - this.mousePointer.top)\n )\n );\n this.currentSlider.guide.left = left + 'px';\n this.currentSlider.guide.top = top + 'px';\n if (this.currentSlider.callLeft) {\n this.color[this.currentSlider.callLeft].call(this.color, left / this.currentSlider.maxLeft);\n }\n if (this.currentSlider.callTop) {\n this.color[this.currentSlider.callTop].call(this.color, top / this.currentSlider.maxTop);\n }\n // Change format dynamically\n // Only occurs if user choose the dynamic format by\n // setting option format to false\n if (this.currentSlider.callTop === 'setAlpha' && this.options.format === false) {\n\n // Converting from hex / rgb to rgba\n if (this.color.value.a !== 1) {\n this.format = 'rgba';\n this.color.origFormat = 'rgba';\n }\n\n // Converting from rgba to hex\n else {\n this.format = 'hex';\n this.color.origFormat = 'hex';\n }\n }\n this.update(true);\n\n this.element.trigger({\n type: 'changeColor',\n color: this.color\n });\n return false;\n },\n mouseup: function(e) {\n e.stopPropagation();\n e.preventDefault();\n $(document).off({\n 'mousemove.colorpicker': this.mousemove,\n 'touchmove.colorpicker': this.mousemove,\n 'mouseup.colorpicker': this.mouseup,\n 'touchend.colorpicker': this.mouseup\n });\n return false;\n },\n change: function(e) {\n this.keyup(e);\n },\n keyup: function(e) {\n if ((e.keyCode === 38)) {\n if (this.color.value.a < 1) {\n this.color.value.a = Math.round((this.color.value.a + 0.01) * 100) / 100;\n }\n this.update(true);\n } else if ((e.keyCode === 40)) {\n if (this.color.value.a > 0) {\n this.color.value.a = Math.round((this.color.value.a - 0.01) * 100) / 100;\n }\n this.update(true);\n } else {\n this.color = new Color(this.input.val(), this.options.colorSelectors);\n // Change format dynamically\n // Only occurs if user choose the dynamic format by\n // setting option format to false\n if (this.color.origFormat && this.options.format === false) {\n this.format = this.color.origFormat;\n }\n if (this.getValue(false) !== false) {\n this.updateData();\n this.updateComponent();\n this.updatePicker();\n }\n }\n this.element.trigger({\n type: 'changeColor',\n color: this.color,\n value: this.input.val()\n });\n }\n };\n\n $.colorpicker = Colorpicker;\n\n $.fn.colorpicker = function(option) {\n var pickerArgs = arguments,\n rv = null;\n\n var $returnValue = this.each(function() {\n var $this = $(this),\n inst = $this.data('colorpicker'),\n options = ((typeof option === 'object') ? option : {});\n if ((!inst) && (typeof option !== 'string')) {\n $this.data('colorpicker', new Colorpicker(this, options));\n } else {\n if (typeof option === 'string') {\n rv = inst[option].apply(inst, Array.prototype.slice.call(pickerArgs, 1));\n }\n }\n });\n if (option === 'getValue') {\n return rv;\n }\n return $returnValue;\n };\n\n $.fn.colorpicker.constructor = Colorpicker;\n\n}));\n","/*\n\n\tcountUp.js\n\tby @inorganik\n\n*/\n\n// target = id of html element or var of previously selected html element where counting occurs\n// startVal = the value you want to begin at\n// endVal = the value you want to arrive at\n// decimals = number of decimal places, default 0\n// duration = duration of animation in seconds, default 2\n// options = optional object of options (see below)\n\nvar CountUp = function(target, startVal, endVal, decimals, duration, options) {\n var self = this;\n self.version = function () { return '1.9.3'; };\n\n // default options\n self.options = {\n useEasing: true, // toggle easing\n useGrouping: true, // 1,000,000 vs 1000000\n separator: ',', // character to use as a separator\n decimal: '.', // character to use as a decimal\n easingFn: easeOutExpo, // optional custom easing function, default is Robert Penner's easeOutExpo\n formattingFn: formatNumber, // optional custom formatting function, default is formatNumber above\n prefix: '', // optional text before the result\n suffix: '', // optional text after the result\n numerals: [] // optionally pass an array of custom numerals for 0-9\n };\n\n // extend default options with passed options object\n if (options && typeof options === 'object') {\n for (var key in self.options) {\n if (options.hasOwnProperty(key) && options[key] !== null) {\n self.options[key] = options[key];\n }\n }\n }\n\n if (self.options.separator === '') {\n self.options.useGrouping = false;\n }\n else {\n // ensure the separator is a string (formatNumber assumes this)\n self.options.separator = '' + self.options.separator;\n }\n\n // make sure requestAnimationFrame and cancelAnimationFrame are defined\n // polyfill for browsers without native support\n // by Opera engineer Erik Möller\n var lastTime = 0;\n var vendors = ['webkit', 'moz', 'ms', 'o'];\n for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {\n window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];\n window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];\n }\n if (!window.requestAnimationFrame) {\n window.requestAnimationFrame = function(callback, element) {\n var currTime = new Date().getTime();\n var timeToCall = Math.max(0, 16 - (currTime - lastTime));\n var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);\n lastTime = currTime + timeToCall;\n return id;\n };\n }\n if (!window.cancelAnimationFrame) {\n window.cancelAnimationFrame = function(id) {\n clearTimeout(id);\n };\n }\n\n function formatNumber(num) {\n var neg = (num < 0),\n x, x1, x2, x3, i, len;\n num = Math.abs(num).toFixed(self.decimals);\n num += '';\n x = num.split('.');\n x1 = x[0];\n x2 = x.length > 1 ? self.options.decimal + x[1] : '';\n if (self.options.useGrouping) {\n x3 = '';\n for (i = 0, len = x1.length; i < len; ++i) {\n if (i !== 0 && ((i % 3) === 0)) {\n x3 = self.options.separator + x3;\n }\n x3 = x1[len - i - 1] + x3;\n }\n x1 = x3;\n }\n // optional numeral substitution\n if (self.options.numerals.length) {\n x1 = x1.replace(/[0-9]/g, function(w) {\n return self.options.numerals[+w];\n })\n x2 = x2.replace(/[0-9]/g, function(w) {\n return self.options.numerals[+w];\n })\n }\n return (neg ? '-' : '') + self.options.prefix + x1 + x2 + self.options.suffix;\n }\n // Robert Penner's easeOutExpo\n function easeOutExpo(t, b, c, d) {\n return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;\n }\n function ensureNumber(n) {\n return (typeof n === 'number' && !isNaN(n));\n }\n\n self.initialize = function() { \n if (self.initialized) return true;\n \n self.error = '';\n self.d = (typeof target === 'string') ? document.getElementById(target) : target;\n if (!self.d) { \n self.error = '[CountUp] target is null or undefined'\n return false;\n }\n self.startVal = Number(startVal);\n self.endVal = Number(endVal);\n // error checks\n if (ensureNumber(self.startVal) && ensureNumber(self.endVal)) {\n self.decimals = Math.max(0, decimals || 0);\n self.dec = Math.pow(10, self.decimals);\n self.duration = Number(duration) * 1000 || 2000;\n self.countDown = (self.startVal > self.endVal);\n self.frameVal = self.startVal;\n self.initialized = true;\n return true;\n }\n else {\n self.error = '[CountUp] startVal ('+startVal+') or endVal ('+endVal+') is not a number';\n return false;\n }\n };\n\n // Print value to target\n self.printValue = function(value) {\n var result = self.options.formattingFn(value);\n\n if (self.d.tagName === 'INPUT') {\n this.d.value = result;\n }\n else if (self.d.tagName === 'text' || self.d.tagName === 'tspan') {\n this.d.textContent = result;\n }\n else {\n this.d.innerHTML = result;\n }\n };\n\n self.count = function(timestamp) {\n\n if (!self.startTime) { self.startTime = timestamp; }\n\n self.timestamp = timestamp;\n var progress = timestamp - self.startTime;\n self.remaining = self.duration - progress;\n\n // to ease or not to ease\n if (self.options.useEasing) {\n if (self.countDown) {\n self.frameVal = self.startVal - self.options.easingFn(progress, 0, self.startVal - self.endVal, self.duration);\n } else {\n self.frameVal = self.options.easingFn(progress, self.startVal, self.endVal - self.startVal, self.duration);\n }\n } else {\n if (self.countDown) {\n self.frameVal = self.startVal - ((self.startVal - self.endVal) * (progress / self.duration));\n } else {\n self.frameVal = self.startVal + (self.endVal - self.startVal) * (progress / self.duration);\n }\n }\n\n // don't go past endVal since progress can exceed duration in the last frame\n if (self.countDown) {\n self.frameVal = (self.frameVal < self.endVal) ? self.endVal : self.frameVal;\n } else {\n self.frameVal = (self.frameVal > self.endVal) ? self.endVal : self.frameVal;\n }\n\n // decimal\n self.frameVal = Math.round(self.frameVal*self.dec)/self.dec;\n\n // format and print value\n self.printValue(self.frameVal);\n\n // whether to continue\n if (progress < self.duration) {\n self.rAF = requestAnimationFrame(self.count);\n } else {\n if (self.callback) self.callback();\n }\n };\n // start your animation\n self.start = function(callback) {\n if (!self.initialize()) return;\n self.callback = callback;\n self.rAF = requestAnimationFrame(self.count);\n };\n // toggles pause/resume animation\n self.pauseResume = function() {\n if (!self.paused) {\n self.paused = true;\n cancelAnimationFrame(self.rAF);\n } else {\n self.paused = false;\n delete self.startTime;\n self.duration = self.remaining;\n self.startVal = self.frameVal;\n requestAnimationFrame(self.count);\n }\n };\n // reset to startVal so animation can be run again\n self.reset = function() {\n self.paused = false;\n delete self.startTime;\n self.initialized = false;\n if (self.initialize()) {\n cancelAnimationFrame(self.rAF);\n self.printValue(self.startVal);\n }\n };\n // pass a new endVal and start animation\n self.update = function (newEndVal) {\n if (!self.initialize()) return;\n newEndVal = Number(newEndVal);\n if (!ensureNumber(newEndVal)) {\n self.error = '[CountUp] update() - new endVal is not a number: '+newEndVal;\n return;\n }\n self.error = '';\n if (newEndVal === self.frameVal) return;\n cancelAnimationFrame(self.rAF);\n self.paused = false;\n delete self.startTime;\n self.startVal = self.frameVal;\n self.endVal = newEndVal;\n self.countDown = (self.startVal > self.endVal);\n self.rAF = requestAnimationFrame(self.count);\n };\n\n // format startVal on initialization\n if (self.initialize()) self.printValue(self.startVal);\n};\n\n(function($) {\n $.fn.countup = function(params) {\n // make sure dependency is present\n if (typeof CountUp !== 'function') {\n console.error('countUp.js is a required dependency of countUp-jquery.js.');\n return;\n }\n\n var defaults = {\n startVal: 0,\n decimals: 0,\n duration: 2,\n };\n\n if (typeof params === 'number') {\n defaults.endVal = params;\n }\n else if (typeof params === 'object') {\n $.extend(defaults, params);\n }\n else {\n console.error('countUp-jquery requires its argument to be either an object or number');\n return;\n }\n\n this.each(function(i, elem) {\n var countUp = new CountUp(elem, defaults.startVal, defaults.endVal, defaults.decimals, defaults.duration, defaults.options);\n\n countUp.start();\n });\n\n\n\n return this;\n\n };\n\n}(jQuery));\n","//===========================//\n// MODIFIED FOR CHARLIE!\n//===========================//\n///////\n/////// Changed (this.element.dropzone) from throw error to if/else\n///////\n/*\n *\n * More info at [www.dropzonejs.com](http://www.dropzonejs.com)\n *\n * Copyright (c) 2012, Matias Meno\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n */\n\n(function() {\n var Dropzone, Emitter, camelize, contentLoaded, detectVerticalSquash, drawImageIOSFix, noop, without,\n __slice = [].slice,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n noop = function() {};\n\n Emitter = (function() {\n function Emitter() {}\n\n Emitter.prototype.addEventListener = Emitter.prototype.on;\n\n Emitter.prototype.on = function(event, fn) {\n this._callbacks = this._callbacks || {};\n if (!this._callbacks[event]) {\n this._callbacks[event] = [];\n }\n this._callbacks[event].push(fn);\n return this;\n };\n\n Emitter.prototype.emit = function() {\n var args, callback, callbacks, event, _i, _len;\n event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];\n this._callbacks = this._callbacks || {};\n callbacks = this._callbacks[event];\n if (callbacks) {\n for (_i = 0, _len = callbacks.length; _i < _len; _i++) {\n callback = callbacks[_i];\n callback.apply(this, args);\n }\n }\n return this;\n };\n\n Emitter.prototype.removeListener = Emitter.prototype.off;\n\n Emitter.prototype.removeAllListeners = Emitter.prototype.off;\n\n Emitter.prototype.removeEventListener = Emitter.prototype.off;\n\n Emitter.prototype.off = function(event, fn) {\n var callback, callbacks, i, _i, _len;\n if (!this._callbacks || arguments.length === 0) {\n this._callbacks = {};\n return this;\n }\n callbacks = this._callbacks[event];\n if (!callbacks) {\n return this;\n }\n if (arguments.length === 1) {\n delete this._callbacks[event];\n return this;\n }\n for (i = _i = 0, _len = callbacks.length; _i < _len; i = ++_i) {\n callback = callbacks[i];\n if (callback === fn) {\n callbacks.splice(i, 1);\n break;\n }\n }\n return this;\n };\n\n return Emitter;\n\n })();\n\n Dropzone = (function(_super) {\n var extend, resolveOption;\n\n __extends(Dropzone, _super);\n\n Dropzone.prototype.Emitter = Emitter;\n\n\n /*\n This is a list of all available events you can register on a dropzone object.\n\n You can register an event handler like this:\n\n dropzone.on(\"dragEnter\", function() { });\n */\n\n Dropzone.prototype.events = [\"drop\", \"dragstart\", \"dragend\", \"dragenter\", \"dragover\", \"dragleave\", \"addedfile\", \"addedfiles\", \"removedfile\", \"thumbnail\", \"error\", \"errormultiple\", \"processing\", \"processingmultiple\", \"uploadprogress\", \"totaluploadprogress\", \"sending\", \"sendingmultiple\", \"success\", \"successmultiple\", \"canceled\", \"canceledmultiple\", \"complete\", \"completemultiple\", \"reset\", \"maxfilesexceeded\", \"maxfilesreached\", \"queuecomplete\"];\n\n Dropzone.prototype.defaultOptions = {\n url: null,\n method: \"post\",\n withCredentials: false,\n parallelUploads: 2,\n uploadMultiple: false,\n maxFilesize: 256,\n paramName: \"file\",\n createImageThumbnails: true,\n maxThumbnailFilesize: 10,\n thumbnailWidth: 120,\n thumbnailHeight: 120,\n filesizeBase: 1000,\n maxFiles: null,\n params: {},\n clickable: true,\n ignoreHiddenFiles: true,\n acceptedFiles: null,\n acceptedMimeTypes: null,\n autoProcessQueue: true,\n autoQueue: true,\n addRemoveLinks: false,\n previewsContainer: null,\n hiddenInputContainer: \"body\",\n capture: null,\n dictDefaultMessage: \"Drop files here to upload\",\n dictFallbackMessage: \"Your browser does not support drag'n'drop file uploads.\",\n dictFallbackText: \"Please use the fallback form below to upload your files like in the olden days.\",\n dictFileTooBig: \"File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.\",\n dictInvalidFileType: \"You can't upload files of this type.\",\n dictResponseError: \"Server responded with {{statusCode}} code.\",\n dictCancelUpload: \"Cancel upload\",\n dictCancelUploadConfirmation: \"Are you sure you want to cancel this upload?\",\n dictRemoveFile: \"Remove file\",\n dictRemoveFileConfirmation: null,\n dictMaxFilesExceeded: \"You can not upload any more files.\",\n accept: function(file, done) {\n return done();\n },\n init: function() {\n return noop;\n },\n forceFallback: false,\n fallback: function() {\n var child, messageElement, span, _i, _len, _ref;\n this.element.className = \"\" + this.element.className + \" dz-browser-not-supported\";\n _ref = this.element.getElementsByTagName(\"div\");\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n child = _ref[_i];\n if (/(^| )dz-message($| )/.test(child.className)) {\n messageElement = child;\n child.className = \"dz-message\";\n continue;\n }\n }\n if (!messageElement) {\n messageElement = Dropzone.createElement(\"
\");\n this.element.appendChild(messageElement);\n }\n span = messageElement.getElementsByTagName(\"span\")[0];\n if (span) {\n if (span.textContent != null) {\n span.textContent = this.options.dictFallbackMessage;\n } else if (span.innerText != null) {\n span.innerText = this.options.dictFallbackMessage;\n }\n }\n return this.element.appendChild(this.getFallbackForm());\n },\n resize: function(file) {\n var info, srcRatio, trgRatio;\n info = {\n srcX: 0,\n srcY: 0,\n srcWidth: file.width,\n srcHeight: file.height\n };\n srcRatio = file.width / file.height;\n info.optWidth = this.options.thumbnailWidth;\n info.optHeight = this.options.thumbnailHeight;\n if ((info.optWidth == null) && (info.optHeight == null)) {\n info.optWidth = info.srcWidth;\n info.optHeight = info.srcHeight;\n } else if (info.optWidth == null) {\n info.optWidth = srcRatio * info.optHeight;\n } else if (info.optHeight == null) {\n info.optHeight = (1 / srcRatio) * info.optWidth;\n }\n trgRatio = info.optWidth / info.optHeight;\n if (file.height < info.optHeight || file.width < info.optWidth) {\n info.trgHeight = info.srcHeight;\n info.trgWidth = info.srcWidth;\n } else {\n if (srcRatio > trgRatio) {\n info.srcHeight = file.height;\n info.srcWidth = info.srcHeight * trgRatio;\n } else {\n info.srcWidth = file.width;\n info.srcHeight = info.srcWidth / trgRatio;\n }\n }\n info.srcX = (file.width - info.srcWidth) / 2;\n info.srcY = (file.height - info.srcHeight) / 2;\n return info;\n },\n\n /*\n Those functions register themselves to the events on init and handle all\n the user interface specific stuff. Overwriting them won't break the upload\n but can break the way it's displayed.\n You can overwrite them if you don't like the default behavior. If you just\n want to add an additional event handler, register it on the dropzone object\n and don't overwrite those options.\n */\n drop: function(e) {\n return this.element.classList.remove(\"dz-drag-hover\");\n },\n dragstart: noop,\n dragend: function(e) {\n return this.element.classList.remove(\"dz-drag-hover\");\n },\n dragenter: function(e) {\n return this.element.classList.add(\"dz-drag-hover\");\n },\n dragover: function(e) {\n return this.element.classList.add(\"dz-drag-hover\");\n },\n dragleave: function(e) {\n return this.element.classList.remove(\"dz-drag-hover\");\n },\n paste: noop,\n reset: function() {\n return this.element.classList.remove(\"dz-started\");\n },\n addedfile: function(file) {\n var node, removeFileEvent, removeLink, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results;\n if (this.element === this.previewsContainer) {\n this.element.classList.add(\"dz-started\");\n }\n if (this.previewsContainer) {\n file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim());\n file.previewTemplate = file.previewElement;\n this.previewsContainer.appendChild(file.previewElement);\n _ref = file.previewElement.querySelectorAll(\"[data-dz-name]\");\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n node = _ref[_i];\n node.textContent = file.name;\n }\n _ref1 = file.previewElement.querySelectorAll(\"[data-dz-size]\");\n for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {\n node = _ref1[_j];\n node.innerHTML = this.filesize(file.size);\n }\n if (this.options.addRemoveLinks) {\n file._removeLink = Dropzone.createElement(\"
\" + this.options.dictRemoveFile + \" \");\n file.previewElement.appendChild(file._removeLink);\n }\n removeFileEvent = (function(_this) {\n return function(e) {\n e.preventDefault();\n e.stopPropagation();\n if (file.status === Dropzone.UPLOADING) {\n return Dropzone.confirm(_this.options.dictCancelUploadConfirmation, function() {\n return _this.removeFile(file);\n });\n } else {\n if (_this.options.dictRemoveFileConfirmation) {\n return Dropzone.confirm(_this.options.dictRemoveFileConfirmation, function() {\n return _this.removeFile(file);\n });\n } else {\n return _this.removeFile(file);\n }\n }\n };\n })(this);\n _ref2 = file.previewElement.querySelectorAll(\"[data-dz-remove]\");\n _results = [];\n for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {\n removeLink = _ref2[_k];\n _results.push(removeLink.addEventListener(\"click\", removeFileEvent));\n }\n return _results;\n }\n },\n removedfile: function(file) {\n var _ref;\n if (file.previewElement) {\n if ((_ref = file.previewElement) != null) {\n _ref.parentNode.removeChild(file.previewElement);\n }\n }\n return this._updateMaxFilesReachedClass();\n },\n thumbnail: function(file, dataUrl) {\n var thumbnailElement, _i, _len, _ref;\n if (file.previewElement) {\n file.previewElement.classList.remove(\"dz-file-preview\");\n _ref = file.previewElement.querySelectorAll(\"[data-dz-thumbnail]\");\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n thumbnailElement = _ref[_i];\n thumbnailElement.alt = file.name;\n thumbnailElement.src = dataUrl;\n }\n return setTimeout(((function(_this) {\n return function() {\n return file.previewElement.classList.add(\"dz-image-preview\");\n };\n })(this)), 1);\n }\n },\n error: function(file, message) {\n var node, _i, _len, _ref, _results;\n if (file.previewElement) {\n file.previewElement.classList.add(\"dz-error\");\n if (typeof message !== \"String\" && message.error) {\n message = message.error;\n }\n _ref = file.previewElement.querySelectorAll(\"[data-dz-errormessage]\");\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n node = _ref[_i];\n _results.push(node.textContent = message);\n }\n return _results;\n }\n },\n errormultiple: noop,\n processing: function(file) {\n if (file.previewElement) {\n file.previewElement.classList.add(\"dz-processing\");\n if (file._removeLink) {\n return file._removeLink.textContent = this.options.dictCancelUpload;\n }\n }\n },\n processingmultiple: noop,\n uploadprogress: function(file, progress, bytesSent) {\n var node, _i, _len, _ref, _results;\n if (file.previewElement) {\n _ref = file.previewElement.querySelectorAll(\"[data-dz-uploadprogress]\");\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n node = _ref[_i];\n if (node.nodeName === 'PROGRESS') {\n _results.push(node.value = progress);\n } else {\n _results.push(node.style.width = \"\" + progress + \"%\");\n }\n }\n return _results;\n }\n },\n totaluploadprogress: noop,\n sending: noop,\n sendingmultiple: noop,\n success: function(file) {\n if (file.previewElement) {\n return file.previewElement.classList.add(\"dz-success\");\n }\n },\n successmultiple: noop,\n canceled: function(file) {\n return this.emit(\"error\", file, \"Upload canceled.\");\n },\n canceledmultiple: noop,\n complete: function(file) {\n if (file._removeLink) {\n file._removeLink.textContent = this.options.dictRemoveFile;\n }\n if (file.previewElement) {\n return file.previewElement.classList.add(\"dz-complete\");\n }\n },\n completemultiple: noop,\n maxfilesexceeded: noop,\n maxfilesreached: noop,\n queuecomplete: noop,\n addedfiles: noop,\n previewTemplate: \"
\\n
\\n
\\n
\\n
\\n
\\n
\\n Check \\n \\n \\n \\n \\n \\n
\\n
\\n
\\n Error \\n \\n \\n \\n \\n \\n \\n \\n
\\n
\"\n };\n\n extend = function() {\n var key, object, objects, target, val, _i, _len;\n target = arguments[0], objects = 2 <= arguments.length ? __slice.call(arguments, 1) : [];\n for (_i = 0, _len = objects.length; _i < _len; _i++) {\n object = objects[_i];\n for (key in object) {\n val = object[key];\n target[key] = val;\n }\n }\n return target;\n };\n\n function Dropzone(element, options) {\n var elementOptions, fallback, _ref;\n this.element = element;\n this.version = Dropzone.version;\n this.defaultOptions.previewTemplate = this.defaultOptions.previewTemplate.replace(/\\n*/g, \"\");\n this.clickableElements = [];\n this.listeners = [];\n this.files = [];\n if (typeof this.element === \"string\") {\n this.element = document.querySelector(this.element);\n }\n if (!(this.element && (this.element.nodeType != null))) {\n\n throw new Error(\"Invalid dropzone element.\");\n }\n if (this.element.dropzone) {\n //throw new Error(\"Dropzone already attached.\");\n // console.log('Dropzone is already attached.'); REVIEW: dropzone error\n } else {\n //if dropzone is not already attatched add it!\n Dropzone.instances.push(this);\n this.element.dropzone = this;\n elementOptions = (_ref = Dropzone.optionsForElement(this.element)) != null ? _ref : {};\n this.options = extend({}, this.defaultOptions, elementOptions, options != null ? options : {});\n if (this.options.forceFallback || !Dropzone.isBrowserSupported()) {\n return this.options.fallback.call(this);\n }\n if (this.options.url == null) {\n this.options.url = this.element.getAttribute(\"action\");\n }\n if (!this.options.url) {\n throw new Error(\"No URL provided.\");\n }\n if (this.options.acceptedFiles && this.options.acceptedMimeTypes) {\n throw new Error(\"You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.\");\n }\n if (this.options.acceptedMimeTypes) {\n this.options.acceptedFiles = this.options.acceptedMimeTypes;\n delete this.options.acceptedMimeTypes;\n }\n this.options.method = this.options.method.toUpperCase();\n if ((fallback = this.getExistingFallback()) && fallback.parentNode) {\n fallback.parentNode.removeChild(fallback);\n }\n if (this.options.previewsContainer !== false) {\n if (this.options.previewsContainer) {\n this.previewsContainer = Dropzone.getElement(this.options.previewsContainer, \"previewsContainer\");\n } else {\n this.previewsContainer = this.element;\n }\n }\n if (this.options.clickable) {\n if (this.options.clickable === true) {\n this.clickableElements = [this.element];\n } else {\n this.clickableElements = Dropzone.getElements(this.options.clickable, \"clickable\");\n }\n }\n this.init();\n }\n }\n\n Dropzone.prototype.getAcceptedFiles = function() {\n var file, _i, _len, _ref, _results;\n _ref = this.files;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n file = _ref[_i];\n if (file.accepted) {\n _results.push(file);\n }\n }\n return _results;\n };\n\n Dropzone.prototype.getRejectedFiles = function() {\n var file, _i, _len, _ref, _results;\n _ref = this.files;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n file = _ref[_i];\n if (!file.accepted) {\n _results.push(file);\n }\n }\n return _results;\n };\n\n Dropzone.prototype.getFilesWithStatus = function(status) {\n var file, _i, _len, _ref, _results;\n _ref = this.files;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n file = _ref[_i];\n if (file.status === status) {\n _results.push(file);\n }\n }\n return _results;\n };\n\n Dropzone.prototype.getQueuedFiles = function() {\n return this.getFilesWithStatus(Dropzone.QUEUED);\n };\n\n Dropzone.prototype.getUploadingFiles = function() {\n return this.getFilesWithStatus(Dropzone.UPLOADING);\n };\n\n Dropzone.prototype.getAddedFiles = function() {\n return this.getFilesWithStatus(Dropzone.ADDED);\n };\n\n Dropzone.prototype.getActiveFiles = function() {\n var file, _i, _len, _ref, _results;\n _ref = this.files;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n file = _ref[_i];\n if (file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED) {\n _results.push(file);\n }\n }\n return _results;\n };\n\n Dropzone.prototype.init = function() {\n var eventName, noPropagation, setupHiddenFileInput, _i, _len, _ref, _ref1;\n if (this.element.tagName === \"form\") {\n this.element.setAttribute(\"enctype\", \"multipart/form-data\");\n }\n if (this.element.classList.contains(\"dropzone\") && !this.element.querySelector(\".dz-message\")) {\n this.element.appendChild(Dropzone.createElement(\"
\" + this.options.dictDefaultMessage + \"
\"));\n }\n if (this.clickableElements.length) {\n setupHiddenFileInput = (function(_this) {\n return function() {\n if (_this.hiddenFileInput) {\n _this.hiddenFileInput.parentNode.removeChild(_this.hiddenFileInput);\n }\n _this.hiddenFileInput = document.createElement(\"input\");\n _this.hiddenFileInput.setAttribute(\"type\", \"file\");\n if ((_this.options.maxFiles == null) || _this.options.maxFiles > 1) {\n _this.hiddenFileInput.setAttribute(\"multiple\", \"multiple\");\n }\n _this.hiddenFileInput.className = \"dz-hidden-input\";\n if (_this.options.acceptedFiles != null) {\n _this.hiddenFileInput.setAttribute(\"accept\", _this.options.acceptedFiles);\n }\n if (_this.options.capture != null) {\n _this.hiddenFileInput.setAttribute(\"capture\", _this.options.capture);\n }\n _this.hiddenFileInput.style.visibility = \"hidden\";\n _this.hiddenFileInput.style.position = \"absolute\";\n _this.hiddenFileInput.style.top = \"0\";\n _this.hiddenFileInput.style.left = \"0\";\n _this.hiddenFileInput.style.height = \"0\";\n _this.hiddenFileInput.style.width = \"0\";\n document.querySelector(_this.options.hiddenInputContainer).appendChild(_this.hiddenFileInput);\n return _this.hiddenFileInput.addEventListener(\"change\", function() {\n var file, files, _i, _len;\n files = _this.hiddenFileInput.files;\n if (files.length) {\n for (_i = 0, _len = files.length; _i < _len; _i++) {\n file = files[_i];\n _this.addFile(file);\n }\n }\n _this.emit(\"addedfiles\", files);\n return setupHiddenFileInput();\n });\n };\n })(this);\n setupHiddenFileInput();\n }\n this.URL = (_ref = window.URL) != null ? _ref : window.webkitURL;\n _ref1 = this.events;\n for (_i = 0, _len = _ref1.length; _i < _len; _i++) {\n eventName = _ref1[_i];\n this.on(eventName, this.options[eventName]);\n }\n this.on(\"uploadprogress\", (function(_this) {\n return function() {\n return _this.updateTotalUploadProgress();\n };\n })(this));\n this.on(\"removedfile\", (function(_this) {\n return function() {\n return _this.updateTotalUploadProgress();\n };\n })(this));\n this.on(\"canceled\", (function(_this) {\n return function(file) {\n return _this.emit(\"complete\", file);\n };\n })(this));\n this.on(\"complete\", (function(_this) {\n return function(file) {\n if (_this.getAddedFiles().length === 0 && _this.getUploadingFiles().length === 0 && _this.getQueuedFiles().length === 0) {\n return setTimeout((function() {\n return _this.emit(\"queuecomplete\");\n }), 0);\n }\n };\n })(this));\n noPropagation = function(e) {\n e.stopPropagation();\n if (e.preventDefault) {\n return e.preventDefault();\n } else {\n return e.returnValue = false;\n }\n };\n this.listeners = [\n {\n element: this.element,\n events: {\n \"dragstart\": (function(_this) {\n return function(e) {\n return _this.emit(\"dragstart\", e);\n };\n })(this),\n \"dragenter\": (function(_this) {\n return function(e) {\n noPropagation(e);\n return _this.emit(\"dragenter\", e);\n };\n })(this),\n \"dragover\": (function(_this) {\n return function(e) {\n var efct;\n try {\n efct = e.dataTransfer.effectAllowed;\n } catch (_error) {}\n e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy';\n noPropagation(e);\n return _this.emit(\"dragover\", e);\n };\n })(this),\n \"dragleave\": (function(_this) {\n return function(e) {\n return _this.emit(\"dragleave\", e);\n };\n })(this),\n \"drop\": (function(_this) {\n return function(e) {\n noPropagation(e);\n return _this.drop(e);\n };\n })(this),\n \"dragend\": (function(_this) {\n return function(e) {\n return _this.emit(\"dragend\", e);\n };\n })(this)\n }\n }\n ];\n this.clickableElements.forEach((function(_this) {\n return function(clickableElement) {\n return _this.listeners.push({\n element: clickableElement,\n events: {\n \"click\": function(evt) {\n if ((clickableElement !== _this.element) || (evt.target === _this.element || Dropzone.elementInside(evt.target, _this.element.querySelector(\".dz-message\")))) {\n _this.hiddenFileInput.click();\n }\n return true;\n }\n }\n });\n };\n })(this));\n this.enable();\n return this.options.init.call(this);\n };\n\n Dropzone.prototype.destroy = function() {\n var _ref;\n this.disable();\n this.removeAllFiles(true);\n if ((_ref = this.hiddenFileInput) != null ? _ref.parentNode : void 0) {\n this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput);\n this.hiddenFileInput = null;\n }\n delete this.element.dropzone;\n return Dropzone.instances.splice(Dropzone.instances.indexOf(this), 1);\n };\n\n Dropzone.prototype.updateTotalUploadProgress = function() {\n var activeFiles, file, totalBytes, totalBytesSent, totalUploadProgress, _i, _len, _ref;\n totalBytesSent = 0;\n totalBytes = 0;\n activeFiles = this.getActiveFiles();\n if (activeFiles.length) {\n _ref = this.getActiveFiles();\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n file = _ref[_i];\n totalBytesSent += file.upload.bytesSent;\n totalBytes += file.upload.total;\n }\n totalUploadProgress = 100 * totalBytesSent / totalBytes;\n } else {\n totalUploadProgress = 100;\n }\n return this.emit(\"totaluploadprogress\", totalUploadProgress, totalBytes, totalBytesSent);\n };\n\n Dropzone.prototype._getParamName = function(n) {\n if (typeof this.options.paramName === \"function\") {\n return this.options.paramName(n);\n } else {\n return \"\" + this.options.paramName + (this.options.uploadMultiple ? \"[\" + n + \"]\" : \"\");\n }\n };\n\n Dropzone.prototype.getFallbackForm = function() {\n var existingFallback, fields, fieldsString, form;\n if (existingFallback = this.getExistingFallback()) {\n return existingFallback;\n }\n fieldsString = \"
\";\n fields = Dropzone.createElement(fieldsString);\n if (this.element.tagName !== \"FORM\") {\n form = Dropzone.createElement(\"
\");\n form.appendChild(fields);\n } else {\n this.element.setAttribute(\"enctype\", \"multipart/form-data\");\n this.element.setAttribute(\"method\", this.options.method);\n }\n return form != null ? form : fields;\n };\n\n Dropzone.prototype.getExistingFallback = function() {\n var fallback, getFallback, tagName, _i, _len, _ref;\n getFallback = function(elements) {\n var el, _i, _len;\n for (_i = 0, _len = elements.length; _i < _len; _i++) {\n el = elements[_i];\n if (/(^| )fallback($| )/.test(el.className)) {\n return el;\n }\n }\n };\n _ref = [\"div\", \"form\"];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n tagName = _ref[_i];\n if (fallback = getFallback(this.element.getElementsByTagName(tagName))) {\n return fallback;\n }\n }\n };\n\n Dropzone.prototype.setupEventListeners = function() {\n var elementListeners, event, listener, _i, _len, _ref, _results;\n _ref = this.listeners;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n elementListeners = _ref[_i];\n _results.push((function() {\n var _ref1, _results1;\n _ref1 = elementListeners.events;\n _results1 = [];\n for (event in _ref1) {\n listener = _ref1[event];\n _results1.push(elementListeners.element.addEventListener(event, listener, false));\n }\n return _results1;\n })());\n }\n return _results;\n };\n\n Dropzone.prototype.removeEventListeners = function() {\n var elementListeners, event, listener, _i, _len, _ref, _results;\n _ref = this.listeners;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n elementListeners = _ref[_i];\n _results.push((function() {\n var _ref1, _results1;\n _ref1 = elementListeners.events;\n _results1 = [];\n for (event in _ref1) {\n listener = _ref1[event];\n _results1.push(elementListeners.element.removeEventListener(event, listener, false));\n }\n return _results1;\n })());\n }\n return _results;\n };\n\n Dropzone.prototype.disable = function() {\n var file, _i, _len, _ref, _results;\n this.clickableElements.forEach(function(element) {\n return element.classList.remove(\"dz-clickable\");\n });\n this.removeEventListeners();\n _ref = this.files;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n file = _ref[_i];\n _results.push(this.cancelUpload(file));\n }\n return _results;\n };\n\n Dropzone.prototype.enable = function() {\n this.clickableElements.forEach(function(element) {\n return element.classList.add(\"dz-clickable\");\n });\n return this.setupEventListeners();\n };\n\n Dropzone.prototype.filesize = function(size) {\n var cutoff, i, selectedSize, selectedUnit, unit, units, _i, _len;\n selectedSize = 0;\n selectedUnit = \"b\";\n if (size > 0) {\n units = ['TB', 'GB', 'MB', 'KB', 'b'];\n for (i = _i = 0, _len = units.length; _i < _len; i = ++_i) {\n unit = units[i];\n cutoff = Math.pow(this.options.filesizeBase, 4 - i) / 10;\n if (size >= cutoff) {\n selectedSize = size / Math.pow(this.options.filesizeBase, 4 - i);\n selectedUnit = unit;\n break;\n }\n }\n selectedSize = Math.round(10 * selectedSize) / 10;\n }\n return \"
\" + selectedSize + \" \" + selectedUnit;\n };\n\n Dropzone.prototype._updateMaxFilesReachedClass = function() {\n if ((this.options.maxFiles != null) && this.getAcceptedFiles().length >= this.options.maxFiles) {\n if (this.getAcceptedFiles().length === this.options.maxFiles) {\n this.emit('maxfilesreached', this.files);\n }\n return this.element.classList.add(\"dz-max-files-reached\");\n } else {\n return this.element.classList.remove(\"dz-max-files-reached\");\n }\n };\n\n Dropzone.prototype.drop = function(e) {\n var files, items;\n if (!e.dataTransfer) {\n return;\n }\n this.emit(\"drop\", e);\n files = e.dataTransfer.files;\n this.emit(\"addedfiles\", files);\n if (files.length) {\n items = e.dataTransfer.items;\n if (items && items.length && (items[0].webkitGetAsEntry != null)) {\n this._addFilesFromItems(items);\n } else {\n this.handleFiles(files);\n }\n }\n };\n\n Dropzone.prototype.paste = function(e) {\n var items, _ref;\n if ((e != null ? (_ref = e.clipboardData) != null ? _ref.items : void 0 : void 0) == null) {\n return;\n }\n this.emit(\"paste\", e);\n items = e.clipboardData.items;\n if (items.length) {\n return this._addFilesFromItems(items);\n }\n };\n\n Dropzone.prototype.handleFiles = function(files) {\n var file, _i, _len, _results;\n _results = [];\n for (_i = 0, _len = files.length; _i < _len; _i++) {\n file = files[_i];\n _results.push(this.addFile(file));\n }\n return _results;\n };\n\n Dropzone.prototype._addFilesFromItems = function(items) {\n var entry, item, _i, _len, _results;\n _results = [];\n for (_i = 0, _len = items.length; _i < _len; _i++) {\n item = items[_i];\n if ((item.webkitGetAsEntry != null) && (entry = item.webkitGetAsEntry())) {\n if (entry.isFile) {\n _results.push(this.addFile(item.getAsFile()));\n } else if (entry.isDirectory) {\n _results.push(this._addFilesFromDirectory(entry, entry.name));\n } else {\n _results.push(void 0);\n }\n } else if (item.getAsFile != null) {\n if ((item.kind == null) || item.kind === \"file\") {\n _results.push(this.addFile(item.getAsFile()));\n } else {\n _results.push(void 0);\n }\n } else {\n _results.push(void 0);\n }\n }\n return _results;\n };\n\n Dropzone.prototype._addFilesFromDirectory = function(directory, path) {\n var dirReader, entriesReader;\n dirReader = directory.createReader();\n entriesReader = (function(_this) {\n return function(entries) {\n var entry, _i, _len;\n for (_i = 0, _len = entries.length; _i < _len; _i++) {\n entry = entries[_i];\n if (entry.isFile) {\n entry.file(function(file) {\n if (_this.options.ignoreHiddenFiles && file.name.substring(0, 1) === '.') {\n return;\n }\n file.fullPath = \"\" + path + \"/\" + file.name;\n return _this.addFile(file);\n });\n } else if (entry.isDirectory) {\n _this._addFilesFromDirectory(entry, \"\" + path + \"/\" + entry.name);\n }\n }\n };\n })(this);\n return dirReader.readEntries(entriesReader, function(error) {\n return typeof console !== \"undefined\" && console !== null ? typeof console.log === \"function\" ? console.log(error) : void 0 : void 0;\n });\n };\n\n Dropzone.prototype.accept = function(file, done) {\n if (file.size > this.options.maxFilesize * 1024 * 1024) {\n return done(this.options.dictFileTooBig.replace(\"{{filesize}}\", Math.round(file.size / 1024 / 10.24) / 100).replace(\"{{maxFilesize}}\", this.options.maxFilesize));\n } else if (!Dropzone.isValidFile(file, this.options.acceptedFiles)) {\n return done(this.options.dictInvalidFileType);\n } else if ((this.options.maxFiles != null) && this.getAcceptedFiles().length >= this.options.maxFiles) {\n done(this.options.dictMaxFilesExceeded.replace(\"{{maxFiles}}\", this.options.maxFiles));\n return this.emit(\"maxfilesexceeded\", file);\n } else {\n return this.options.accept.call(this, file, done);\n }\n };\n\n Dropzone.prototype.addFile = function(file) {\n file.upload = {\n progress: 0,\n total: file.size,\n bytesSent: 0\n };\n this.files.push(file);\n file.status = Dropzone.ADDED;\n this.emit(\"addedfile\", file);\n this._enqueueThumbnail(file);\n return this.accept(file, (function(_this) {\n return function(error) {\n if (error) {\n file.accepted = false;\n _this._errorProcessing([file], error);\n } else {\n file.accepted = true;\n if (_this.options.autoQueue) {\n _this.enqueueFile(file);\n }\n }\n return _this._updateMaxFilesReachedClass();\n };\n })(this));\n };\n\n Dropzone.prototype.enqueueFiles = function(files) {\n var file, _i, _len;\n for (_i = 0, _len = files.length; _i < _len; _i++) {\n file = files[_i];\n this.enqueueFile(file);\n }\n return null;\n };\n\n Dropzone.prototype.enqueueFile = function(file) {\n if (file.status === Dropzone.ADDED && file.accepted === true) {\n file.status = Dropzone.QUEUED;\n if (this.options.autoProcessQueue) {\n return setTimeout(((function(_this) {\n return function() {\n return _this.processQueue();\n };\n })(this)), 0);\n }\n } else {\n throw new Error(\"This file can't be queued because it has already been processed or was rejected.\");\n }\n };\n\n Dropzone.prototype._thumbnailQueue = [];\n\n Dropzone.prototype._processingThumbnail = false;\n\n Dropzone.prototype._enqueueThumbnail = function(file) {\n if (this.options.createImageThumbnails && file.type.match(/image.*/) && file.size <= this.options.maxThumbnailFilesize * 1024 * 1024) {\n this._thumbnailQueue.push(file);\n return setTimeout(((function(_this) {\n return function() {\n return _this._processThumbnailQueue();\n };\n })(this)), 0);\n }\n };\n\n Dropzone.prototype._processThumbnailQueue = function() {\n if (this._processingThumbnail || this._thumbnailQueue.length === 0) {\n return;\n }\n this._processingThumbnail = true;\n return this.createThumbnail(this._thumbnailQueue.shift(), (function(_this) {\n return function() {\n _this._processingThumbnail = false;\n return _this._processThumbnailQueue();\n };\n })(this));\n };\n\n Dropzone.prototype.removeFile = function(file) {\n if (file.status === Dropzone.UPLOADING) {\n this.cancelUpload(file);\n }\n this.files = without(this.files, file);\n this.emit(\"removedfile\", file);\n if (this.files.length === 0) {\n return this.emit(\"reset\");\n }\n };\n\n Dropzone.prototype.removeAllFiles = function(cancelIfNecessary) {\n var file, _i, _len, _ref;\n if (cancelIfNecessary == null) {\n cancelIfNecessary = false;\n }\n _ref = this.files.slice();\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n file = _ref[_i];\n if (file.status !== Dropzone.UPLOADING || cancelIfNecessary) {\n this.removeFile(file);\n }\n }\n return null;\n };\n\n Dropzone.prototype.createThumbnail = function(file, callback) {\n var fileReader;\n fileReader = new FileReader;\n fileReader.onload = (function(_this) {\n return function() {\n if (file.type === \"image/svg+xml\") {\n _this.emit(\"thumbnail\", file, fileReader.result);\n if (callback != null) {\n callback();\n }\n return;\n }\n return _this.createThumbnailFromUrl(file, fileReader.result, callback);\n };\n })(this);\n return fileReader.readAsDataURL(file);\n };\n\n Dropzone.prototype.createThumbnailFromUrl = function(file, imageUrl, callback, crossOrigin) {\n var img;\n img = document.createElement(\"img\");\n if (crossOrigin) {\n img.crossOrigin = crossOrigin;\n }\n img.onload = (function(_this) {\n return function() {\n var canvas, ctx, resizeInfo, thumbnail, _ref, _ref1, _ref2, _ref3;\n file.width = img.width;\n file.height = img.height;\n resizeInfo = _this.options.resize.call(_this, file);\n if (resizeInfo.trgWidth == null) {\n resizeInfo.trgWidth = resizeInfo.optWidth;\n }\n if (resizeInfo.trgHeight == null) {\n resizeInfo.trgHeight = resizeInfo.optHeight;\n }\n canvas = document.createElement(\"canvas\");\n ctx = canvas.getContext(\"2d\");\n canvas.width = resizeInfo.trgWidth;\n canvas.height = resizeInfo.trgHeight;\n drawImageIOSFix(ctx, img, (_ref = resizeInfo.srcX) != null ? _ref : 0, (_ref1 = resizeInfo.srcY) != null ? _ref1 : 0, resizeInfo.srcWidth, resizeInfo.srcHeight, (_ref2 = resizeInfo.trgX) != null ? _ref2 : 0, (_ref3 = resizeInfo.trgY) != null ? _ref3 : 0, resizeInfo.trgWidth, resizeInfo.trgHeight);\n thumbnail = canvas.toDataURL(\"image/png\");\n _this.emit(\"thumbnail\", file, thumbnail);\n if (callback != null) {\n return callback();\n }\n };\n })(this);\n if (callback != null) {\n img.onerror = callback;\n }\n return img.src = imageUrl;\n };\n\n Dropzone.prototype.processQueue = function() {\n var i, parallelUploads, processingLength, queuedFiles;\n parallelUploads = this.options.parallelUploads;\n processingLength = this.getUploadingFiles().length;\n i = processingLength;\n if (processingLength >= parallelUploads) {\n return;\n }\n queuedFiles = this.getQueuedFiles();\n if (!(queuedFiles.length > 0)) {\n return;\n }\n if (this.options.uploadMultiple) {\n return this.processFiles(queuedFiles.slice(0, parallelUploads - processingLength));\n } else {\n while (i < parallelUploads) {\n if (!queuedFiles.length) {\n return;\n }\n this.processFile(queuedFiles.shift());\n i++;\n }\n }\n };\n\n Dropzone.prototype.processFile = function(file) {\n return this.processFiles([file]);\n };\n\n Dropzone.prototype.processFiles = function(files) {\n var file, _i, _len;\n for (_i = 0, _len = files.length; _i < _len; _i++) {\n file = files[_i];\n file.processing = true;\n file.status = Dropzone.UPLOADING;\n this.emit(\"processing\", file);\n }\n if (this.options.uploadMultiple) {\n this.emit(\"processingmultiple\", files);\n }\n return this.uploadFiles(files);\n };\n\n Dropzone.prototype._getFilesWithXhr = function(xhr) {\n var file, files;\n return files = (function() {\n var _i, _len, _ref, _results;\n _ref = this.files;\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n file = _ref[_i];\n if (file.xhr === xhr) {\n _results.push(file);\n }\n }\n return _results;\n }).call(this);\n };\n\n Dropzone.prototype.cancelUpload = function(file) {\n var groupedFile, groupedFiles, _i, _j, _len, _len1, _ref;\n if (file.status === Dropzone.UPLOADING) {\n groupedFiles = this._getFilesWithXhr(file.xhr);\n for (_i = 0, _len = groupedFiles.length; _i < _len; _i++) {\n groupedFile = groupedFiles[_i];\n groupedFile.status = Dropzone.CANCELED;\n }\n file.xhr.abort();\n for (_j = 0, _len1 = groupedFiles.length; _j < _len1; _j++) {\n groupedFile = groupedFiles[_j];\n this.emit(\"canceled\", groupedFile);\n }\n if (this.options.uploadMultiple) {\n this.emit(\"canceledmultiple\", groupedFiles);\n }\n } else if ((_ref = file.status) === Dropzone.ADDED || _ref === Dropzone.QUEUED) {\n file.status = Dropzone.CANCELED;\n this.emit(\"canceled\", file);\n if (this.options.uploadMultiple) {\n this.emit(\"canceledmultiple\", [file]);\n }\n }\n if (this.options.autoProcessQueue) {\n return this.processQueue();\n }\n };\n\n resolveOption = function() {\n var args, option;\n option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];\n if (typeof option === 'function') {\n return option.apply(this, args);\n }\n return option;\n };\n\n Dropzone.prototype.uploadFile = function(file) {\n return this.uploadFiles([file]);\n };\n\n Dropzone.prototype.uploadFiles = function(files) {\n var file, formData, handleError, headerName, headerValue, headers, i, input, inputName, inputType, key, method, option, progressObj, response, updateProgress, url, value, xhr, _i, _j, _k, _l, _len, _len1, _len2, _len3, _m, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;\n xhr = new XMLHttpRequest();\n for (_i = 0, _len = files.length; _i < _len; _i++) {\n file = files[_i];\n file.xhr = xhr;\n }\n method = resolveOption(this.options.method, files);\n url = resolveOption(this.options.url, files);\n xhr.open(method, url, true);\n xhr.withCredentials = !!this.options.withCredentials;\n response = null;\n handleError = (function(_this) {\n return function() {\n var _j, _len1, _results;\n _results = [];\n for (_j = 0, _len1 = files.length; _j < _len1; _j++) {\n file = files[_j];\n _results.push(_this._errorProcessing(files, response || _this.options.dictResponseError.replace(\"{{statusCode}}\", xhr.status), xhr));\n }\n return _results;\n };\n })(this);\n updateProgress = (function(_this) {\n return function(e) {\n var allFilesFinished, progress, _j, _k, _l, _len1, _len2, _len3, _results;\n if (e != null) {\n progress = 100 * e.loaded / e.total;\n for (_j = 0, _len1 = files.length; _j < _len1; _j++) {\n file = files[_j];\n file.upload = {\n progress: progress,\n total: e.total,\n bytesSent: e.loaded\n };\n }\n } else {\n allFilesFinished = true;\n progress = 100;\n for (_k = 0, _len2 = files.length; _k < _len2; _k++) {\n file = files[_k];\n if (!(file.upload.progress === 100 && file.upload.bytesSent === file.upload.total)) {\n allFilesFinished = false;\n }\n file.upload.progress = progress;\n file.upload.bytesSent = file.upload.total;\n }\n if (allFilesFinished) {\n return;\n }\n }\n _results = [];\n for (_l = 0, _len3 = files.length; _l < _len3; _l++) {\n file = files[_l];\n _results.push(_this.emit(\"uploadprogress\", file, progress, file.upload.bytesSent));\n }\n return _results;\n };\n })(this);\n xhr.onload = (function(_this) {\n return function(e) {\n var _ref;\n if (files[0].status === Dropzone.CANCELED) {\n return;\n }\n if (xhr.readyState !== 4) {\n return;\n }\n response = xhr.responseText;\n if (xhr.getResponseHeader(\"content-type\") && ~xhr.getResponseHeader(\"content-type\").indexOf(\"application/json\")) {\n try {\n response = JSON.parse(response);\n } catch (_error) {\n e = _error;\n response = \"Invalid JSON response from server.\";\n }\n }\n updateProgress();\n if (!((200 <= (_ref = xhr.status) && _ref < 300))) {\n return handleError();\n } else {\n return _this._finished(files, response, e);\n }\n };\n })(this);\n xhr.onerror = (function(_this) {\n return function() {\n if (files[0].status === Dropzone.CANCELED) {\n return;\n }\n return handleError();\n };\n })(this);\n progressObj = (_ref = xhr.upload) != null ? _ref : xhr;\n progressObj.onprogress = updateProgress;\n headers = {\n \"Accept\": \"application/json\",\n \"Cache-Control\": \"no-cache\",\n \"X-Requested-With\": \"XMLHttpRequest\"\n };\n if (this.options.headers) {\n extend(headers, this.options.headers);\n }\n for (headerName in headers) {\n headerValue = headers[headerName];\n if (headerValue) {\n xhr.setRequestHeader(headerName, headerValue);\n }\n }\n formData = new FormData();\n if (this.options.params) {\n _ref1 = this.options.params;\n for (key in _ref1) {\n value = _ref1[key];\n formData.append(key, value);\n }\n }\n for (_j = 0, _len1 = files.length; _j < _len1; _j++) {\n file = files[_j];\n this.emit(\"sending\", file, xhr, formData);\n }\n if (this.options.uploadMultiple) {\n this.emit(\"sendingmultiple\", files, xhr, formData);\n }\n if (this.element.tagName === \"FORM\") {\n _ref2 = this.element.querySelectorAll(\"input, textarea, select, button\");\n for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {\n input = _ref2[_k];\n inputName = input.getAttribute(\"name\");\n inputType = input.getAttribute(\"type\");\n if (input.tagName === \"SELECT\" && input.hasAttribute(\"multiple\")) {\n _ref3 = input.options;\n for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {\n option = _ref3[_l];\n if (option.selected) {\n formData.append(inputName, option.value);\n }\n }\n } else if (!inputType || ((_ref4 = inputType.toLowerCase()) !== \"checkbox\" && _ref4 !== \"radio\") || input.checked) {\n formData.append(inputName, input.value);\n }\n }\n }\n for (i = _m = 0, _ref5 = files.length - 1; 0 <= _ref5 ? _m <= _ref5 : _m >= _ref5; i = 0 <= _ref5 ? ++_m : --_m) {\n formData.append(this._getParamName(i), files[i], files[i].name);\n }\n return this.submitRequest(xhr, formData, files);\n };\n\n Dropzone.prototype.submitRequest = function(xhr, formData, files) {\n return xhr.send(formData);\n };\n\n Dropzone.prototype._finished = function(files, responseText, e) {\n var file, _i, _len;\n for (_i = 0, _len = files.length; _i < _len; _i++) {\n file = files[_i];\n file.status = Dropzone.SUCCESS;\n this.emit(\"success\", file, responseText, e);\n this.emit(\"complete\", file);\n }\n if (this.options.uploadMultiple) {\n this.emit(\"successmultiple\", files, responseText, e);\n this.emit(\"completemultiple\", files);\n }\n if (this.options.autoProcessQueue) {\n return this.processQueue();\n }\n };\n\n Dropzone.prototype._errorProcessing = function(files, message, xhr) {\n var file, _i, _len;\n for (_i = 0, _len = files.length; _i < _len; _i++) {\n file = files[_i];\n file.status = Dropzone.ERROR;\n this.emit(\"error\", file, message, xhr);\n this.emit(\"complete\", file);\n }\n if (this.options.uploadMultiple) {\n this.emit(\"errormultiple\", files, message, xhr);\n this.emit(\"completemultiple\", files);\n }\n if (this.options.autoProcessQueue) {\n return this.processQueue();\n }\n };\n\n return Dropzone;\n\n })(Emitter);\n\n Dropzone.version = \"4.2.0\";\n\n Dropzone.options = {};\n\n Dropzone.optionsForElement = function(element) {\n if (element.getAttribute(\"id\")) {\n return Dropzone.options[camelize(element.getAttribute(\"id\"))];\n } else {\n return void 0;\n }\n };\n\n Dropzone.instances = [];\n\n Dropzone.forElement = function(element) {\n if (typeof element === \"string\") {\n element = document.querySelector(element);\n }\n if ((element != null ? element.dropzone : void 0) == null) {\n throw new Error(\"No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone.\");\n }\n return element.dropzone;\n };\n\n Dropzone.autoDiscover = true;\n\n Dropzone.discover = function() {\n var checkElements, dropzone, dropzones, _i, _len, _results;\n if (document.querySelectorAll) {\n dropzones = document.querySelectorAll(\".dropzone\");\n } else {\n dropzones = [];\n checkElements = function(elements) {\n var el, _i, _len, _results;\n _results = [];\n for (_i = 0, _len = elements.length; _i < _len; _i++) {\n el = elements[_i];\n if (/(^| )dropzone($| )/.test(el.className)) {\n _results.push(dropzones.push(el));\n } else {\n _results.push(void 0);\n }\n }\n return _results;\n };\n checkElements(document.getElementsByTagName(\"div\"));\n checkElements(document.getElementsByTagName(\"form\"));\n }\n _results = [];\n for (_i = 0, _len = dropzones.length; _i < _len; _i++) {\n dropzone = dropzones[_i];\n if (Dropzone.optionsForElement(dropzone) !== false) {\n _results.push(new Dropzone(dropzone));\n } else {\n _results.push(void 0);\n }\n }\n return _results;\n };\n\n // We would not use the word \"blacklist\", but this is part of Dropzone\n Dropzone.blacklistedBrowsers = [/opera.*Macintosh.*version\\/12/i];\n\n Dropzone.isBrowserSupported = function() {\n var capableBrowser, regex, _i, _len, _ref;\n capableBrowser = true;\n if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) {\n if (!(\"classList\" in document.createElement(\"a\"))) {\n capableBrowser = false;\n } else {\n _ref = Dropzone.blacklistedBrowsers;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n regex = _ref[_i];\n if (regex.test(navigator.userAgent)) {\n capableBrowser = false;\n continue;\n }\n }\n }\n } else {\n capableBrowser = false;\n }\n return capableBrowser;\n };\n\n without = function(list, rejectedItem) {\n var item, _i, _len, _results;\n _results = [];\n for (_i = 0, _len = list.length; _i < _len; _i++) {\n item = list[_i];\n if (item !== rejectedItem) {\n _results.push(item);\n }\n }\n return _results;\n };\n\n camelize = function(str) {\n return str.replace(/[\\-_](\\w)/g, function(match) {\n return match.charAt(1).toUpperCase();\n });\n };\n\n Dropzone.createElement = function(string) {\n var div;\n div = document.createElement(\"div\");\n div.innerHTML = string;\n return div.childNodes[0];\n };\n\n Dropzone.elementInside = function(element, container) {\n if (element === container) {\n return true;\n }\n while (element = element.parentNode) {\n if (element === container) {\n return true;\n }\n }\n return false;\n };\n\n Dropzone.getElement = function(el, name) {\n var element;\n if (typeof el === \"string\") {\n element = document.querySelector(el);\n } else if (el.nodeType != null) {\n element = el;\n }\n if (element == null) {\n throw new Error(\"Invalid `\" + name + \"` option provided. Please provide a CSS selector or a plain HTML element.\");\n }\n return element;\n };\n\n Dropzone.getElements = function(els, name) {\n var e, el, elements, _i, _j, _len, _len1, _ref;\n if (els instanceof Array) {\n elements = [];\n try {\n for (_i = 0, _len = els.length; _i < _len; _i++) {\n el = els[_i];\n elements.push(this.getElement(el, name));\n }\n } catch (_error) {\n e = _error;\n elements = null;\n }\n } else if (typeof els === \"string\") {\n elements = [];\n _ref = document.querySelectorAll(els);\n for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {\n el = _ref[_j];\n elements.push(el);\n }\n } else if (els.nodeType != null) {\n elements = [els];\n }\n if (!((elements != null) && elements.length)) {\n throw new Error(\"Invalid `\" + name + \"` option provided. Please provide a CSS selector, a plain HTML element or a list of those.\");\n }\n return elements;\n };\n\n Dropzone.confirm = function(question, accepted, rejected) {\n if (window.confirm(question)) {\n return accepted();\n } else if (rejected != null) {\n return rejected();\n }\n };\n\n Dropzone.isValidFile = function(file, acceptedFiles) {\n var baseMimeType, mimeType, validType, _i, _len;\n if (!acceptedFiles) {\n return true;\n }\n acceptedFiles = acceptedFiles.split(\",\");\n mimeType = file.type;\n baseMimeType = mimeType.replace(/\\/.*$/, \"\");\n for (_i = 0, _len = acceptedFiles.length; _i < _len; _i++) {\n validType = acceptedFiles[_i];\n validType = validType.trim();\n if (validType.charAt(0) === \".\") {\n if (file.name.toLowerCase().indexOf(validType.toLowerCase(), file.name.length - validType.length) !== -1) {\n return true;\n }\n } else if (/\\/\\*$/.test(validType)) {\n if (baseMimeType === validType.replace(/\\/.*$/, \"\")) {\n return true;\n }\n } else {\n if (mimeType === validType) {\n return true;\n }\n }\n }\n return false;\n };\n\n if (typeof jQuery !== \"undefined\" && jQuery !== null) {\n jQuery.fn.dropzone = function(options) {\n return this.each(function() {\n return new Dropzone(this, options);\n });\n };\n }\n\n if (typeof module !== \"undefined\" && module !== null) {\n module.exports = Dropzone;\n } else {\n window.Dropzone = Dropzone;\n }\n\n Dropzone.ADDED = \"added\";\n\n Dropzone.QUEUED = \"queued\";\n\n Dropzone.ACCEPTED = Dropzone.QUEUED;\n\n Dropzone.UPLOADING = \"uploading\";\n\n Dropzone.PROCESSING = Dropzone.UPLOADING;\n\n Dropzone.CANCELED = \"canceled\";\n\n Dropzone.ERROR = \"error\";\n\n Dropzone.SUCCESS = \"success\";\n\n\n /*\n\n Bugfix for iOS 6 and 7\n Source: http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios\n based on the work of https://github.com/stomita/ios-imagefile-megapixel\n */\n\n detectVerticalSquash = function(img) {\n var alpha, canvas, ctx, data, ey, ih, iw, py, ratio, sy;\n iw = img.naturalWidth;\n ih = img.naturalHeight;\n canvas = document.createElement(\"canvas\");\n canvas.width = 1;\n canvas.height = ih;\n ctx = canvas.getContext(\"2d\");\n ctx.drawImage(img, 0, 0);\n data = ctx.getImageData(0, 0, 1, ih).data;\n sy = 0;\n ey = ih;\n py = ih;\n while (py > sy) {\n alpha = data[(py - 1) * 4 + 3];\n if (alpha === 0) {\n ey = py;\n } else {\n sy = py;\n }\n py = (ey + sy) >> 1;\n }\n ratio = py / ih;\n if (ratio === 0) {\n return 1;\n } else {\n return ratio;\n }\n };\n\n drawImageIOSFix = function(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) {\n var vertSquashRatio;\n vertSquashRatio = detectVerticalSquash(img);\n return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio);\n };\n\n\n /*\n * contentloaded.js\n *\n * Author: Diego Perini (diego.perini at gmail.com)\n * Summary: cross-browser wrapper for DOMContentLoaded\n * Updated: 20101020\n * License: MIT\n * Version: 1.2\n *\n * URL:\n * http://javascript.nwbox.com/ContentLoaded/\n * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE\n */\n\n contentLoaded = function(win, fn) {\n var add, doc, done, init, poll, pre, rem, root, top;\n done = false;\n top = true;\n doc = win.document;\n root = doc.documentElement;\n add = (doc.addEventListener ? \"addEventListener\" : \"attachEvent\");\n rem = (doc.addEventListener ? \"removeEventListener\" : \"detachEvent\");\n pre = (doc.addEventListener ? \"\" : \"on\");\n init = function(e) {\n if (e.type === \"readystatechange\" && doc.readyState !== \"complete\") {\n return;\n }\n (e.type === \"load\" ? win : doc)[rem](pre + e.type, init, false);\n if (!done && (done = true)) {\n return fn.call(win, e.type || e);\n }\n };\n poll = function() {\n var e;\n try {\n root.doScroll(\"left\");\n } catch (_error) {\n e = _error;\n setTimeout(poll, 50);\n return;\n }\n return init(\"poll\");\n };\n if (doc.readyState !== \"complete\") {\n if (doc.createEventObject && root.doScroll) {\n try {\n top = !win.frameElement;\n } catch (_error) {}\n if (top) {\n poll();\n }\n }\n doc[add](pre + \"DOMContentLoaded\", init, false);\n doc[add](pre + \"readystatechange\", init, false);\n return win[add](pre + \"load\", init, false);\n }\n };\n\n Dropzone._autoDiscoverFunction = function() {\n if (Dropzone.autoDiscover) {\n return Dropzone.discover();\n }\n };\n\n contentLoaded(window, Dropzone._autoDiscoverFunction);\n\n}).call(this);\n","/*\n * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/\n *\n * Uses the built in easing capabilities added In jQuery 1.1\n * to offer multiple easing options\n *\n * TERMS OF USE - jQuery Easing\n * \n * Open source under the BSD License. \n * \n * Copyright В© 2008 George McGinley Smith\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n * \n * Redistributions of source code must retain the above copyright notice, this list of \n * conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, this list \n * of conditions and the following disclaimer in the documentation and/or other materials \n * provided with the distribution.\n * \n * Neither the name of the author nor the names of contributors may be used to endorse \n * or promote products derived from this software without specific prior written permission.\n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY \n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED \n * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED \n * OF THE POSSIBILITY OF SUCH DAMAGE. \n *\n*/\n\n// t: current time, b: begInnIng value, c: change In value, d: duration\njQuery.easing['jswing'] = jQuery.easing['swing'];\n\njQuery.extend( jQuery.easing,\n{\n\tdef: 'easeOutQuad',\n\tswing: function (x, t, b, c, d) {\n\t\t//alert(jQuery.easing.default);\n\t\treturn jQuery.easing[jQuery.easing.def](x, t, b, c, d);\n\t},\n\teaseInQuad: function (x, t, b, c, d) {\n\t\treturn c*(t/=d)*t + b;\n\t},\n\teaseOutQuad: function (x, t, b, c, d) {\n\t\treturn -c *(t/=d)*(t-2) + b;\n\t},\n\teaseInOutQuad: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return c/2*t*t + b;\n\t\treturn -c/2 * ((--t)*(t-2) - 1) + b;\n\t},\n\teaseInCubic: function (x, t, b, c, d) {\n\t\treturn c*(t/=d)*t*t + b;\n\t},\n\teaseOutCubic: function (x, t, b, c, d) {\n\t\treturn c*((t=t/d-1)*t*t + 1) + b;\n\t},\n\teaseInOutCubic: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return c/2*t*t*t + b;\n\t\treturn c/2*((t-=2)*t*t + 2) + b;\n\t},\n\teaseInQuart: function (x, t, b, c, d) {\n\t\treturn c*(t/=d)*t*t*t + b;\n\t},\n\teaseOutQuart: function (x, t, b, c, d) {\n\t\treturn -c * ((t=t/d-1)*t*t*t - 1) + b;\n\t},\n\teaseInOutQuart: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return c/2*t*t*t*t + b;\n\t\treturn -c/2 * ((t-=2)*t*t*t - 2) + b;\n\t},\n\teaseInQuint: function (x, t, b, c, d) {\n\t\treturn c*(t/=d)*t*t*t*t + b;\n\t},\n\teaseOutQuint: function (x, t, b, c, d) {\n\t\treturn c*((t=t/d-1)*t*t*t*t + 1) + b;\n\t},\n\teaseInOutQuint: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;\n\t\treturn c/2*((t-=2)*t*t*t*t + 2) + b;\n\t},\n\teaseInSine: function (x, t, b, c, d) {\n\t\treturn -c * Math.cos(t/d * (Math.PI/2)) + c + b;\n\t},\n\teaseOutSine: function (x, t, b, c, d) {\n\t\treturn c * Math.sin(t/d * (Math.PI/2)) + b;\n\t},\n\teaseInOutSine: function (x, t, b, c, d) {\n\t\treturn -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;\n\t},\n\teaseInExpo: function (x, t, b, c, d) {\n\t\treturn (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;\n\t},\n\teaseOutExpo: function (x, t, b, c, d) {\n\t\treturn (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;\n\t},\n\teaseInOutExpo: function (x, t, b, c, d) {\n\t\tif (t==0) return b;\n\t\tif (t==d) return b+c;\n\t\tif ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;\n\t\treturn c/2 * (-Math.pow(2, -10 * --t) + 2) + b;\n\t},\n\teaseInCirc: function (x, t, b, c, d) {\n\t\treturn -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;\n\t},\n\teaseOutCirc: function (x, t, b, c, d) {\n\t\treturn c * Math.sqrt(1 - (t=t/d-1)*t) + b;\n\t},\n\teaseInOutCirc: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;\n\t\treturn c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;\n\t},\n\teaseInElastic: function (x, t, b, c, d) {\n\t\tvar s=1.70158;var p=0;var a=c;\n\t\tif (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;\n\t\tif (a < Math.abs(c)) { a=c; var s=p/4; }\n\t\telse var s = p/(2*Math.PI) * Math.asin (c/a);\n\t\treturn -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;\n\t},\n\teaseOutElastic: function (x, t, b, c, d) {\n\t\tvar s=1.70158;var p=0;var a=c;\n\t\tif (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;\n\t\tif (a < Math.abs(c)) { a=c; var s=p/4; }\n\t\telse var s = p/(2*Math.PI) * Math.asin (c/a);\n\t\treturn a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;\n\t},\n\teaseInOutElastic: function (x, t, b, c, d) {\n\t\tvar s=1.70158;var p=0;var a=c;\n\t\tif (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);\n\t\tif (a < Math.abs(c)) { a=c; var s=p/4; }\n\t\telse var s = p/(2*Math.PI) * Math.asin (c/a);\n\t\tif (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;\n\t\treturn a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;\n\t},\n\teaseInBack: function (x, t, b, c, d, s) {\n\t\tif (s == undefined) s = 1.70158;\n\t\treturn c*(t/=d)*t*((s+1)*t - s) + b;\n\t},\n\teaseOutBack: function (x, t, b, c, d, s) {\n\t\tif (s == undefined) s = 1.70158;\n\t\treturn c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;\n\t},\n\teaseInOutBack: function (x, t, b, c, d, s) {\n\t\tif (s == undefined) s = 1.70158; \n\t\tif ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;\n\t\treturn c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;\n\t},\n\teaseInBounce: function (x, t, b, c, d) {\n\t\treturn c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;\n\t},\n\teaseOutBounce: function (x, t, b, c, d) {\n\t\tif ((t/=d) < (1/2.75)) {\n\t\t\treturn c*(7.5625*t*t) + b;\n\t\t} else if (t < (2/2.75)) {\n\t\t\treturn c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;\n\t\t} else if (t < (2.5/2.75)) {\n\t\t\treturn c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;\n\t\t} else {\n\t\t\treturn c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;\n\t\t}\n\t},\n\teaseInOutBounce: function (x, t, b, c, d) {\n\t\tif (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;\n\t\treturn jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;\n\t}\n});\n\n/*\n *\n * TERMS OF USE - EASING EQUATIONS\n * \n * Open source under the BSD License. \n * \n * Copyright В© 2001 Robert Penner\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n * \n * Redistributions of source code must retain the above copyright notice, this list of \n * conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, this list \n * of conditions and the following disclaimer in the documentation and/or other materials \n * provided with the distribution.\n * \n * Neither the name of the author nor the names of contributors may be used to endorse \n * or promote products derived from this software without specific prior written permission.\n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY \n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED \n * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED \n * OF THE POSSIBILITY OF SUCH DAMAGE. \n *\n */","// prettier-ignore\n// version 2.31.1\n(function (factory) { if (typeof define === 'function' && define.amd) { define(['jquery'], factory); } else if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = factory(require('jquery')); } else { factory(jQuery); } }(function (jQuery) {\n\n /*! Parser: date ranges -updated 11/22/2015 (v2.24.6) */\n !function (e) {\n \"use strict\"; var u, f = e.tablesorter, i = /(\\d{1,2}[-\\s]\\d{1,2}[-\\s]\\d{4}(\\s+\\d{1,2}:\\d{2}(:\\d{2})?(\\s+[AP]M)?)?)/gi, d = /(\\d{1,2}[-\\s]\\d{1,2}[-\\s]\\d{4}(\\s+\\d{1,2}:\\d{2}(:\\d{2})?(\\s+[AP]M)?)?)/gi, o = /(\\d{1,2})[-\\s](\\d{1,2})[-\\s](\\d{4})/, c = /(\\d{4}[-\\s]\\d{1,2}[-\\s]\\d{1,2}(\\s+\\d{1,2}:\\d{2}(:\\d{2})?(\\s+[AP]M)?)?)/gi, g = /(\\d{4})[-\\s](\\d{1,2})[-\\s](\\d{1,2})/, l = /(\\d{1,2}\\s+\\w+\\s+\\d{4}(\\s+\\d{1,2}:\\d{2}(:\\d{2})?(\\s\\w+)?)?)/g, p = /(\\d{1,2})\\s+(\\w+)\\s+(\\d{4})/;\n/*! date-range MMDDYYYY */e.tablesorter.addParser({ id: \"date-range-mdy\", is: function () { return !1 }, format: function (e) { var t, r, a, n, s = []; if (n = (r = e.replace(/\\s+/g, \" \").replace(/[\\/\\-.,]/g, \"-\").match(i)) && r.length) { for (a = 0; a < n; a++)t = new Date(r[a]), s.push(t instanceof Date && isFinite(t) ? t.getTime() : r[a]); return s.sort().join(\" - \") } return e }, type: \"text\" }),\n /*! date-range DDMMYYYY */\n e.tablesorter.addParser({ id: \"date-range-dmy\", is: function () { return !1 }, format: function (e) { var t, r, a, n, s = []; if (n = (r = e.replace(/\\s+/g, \" \").replace(/[\\/\\-.,]/g, \"-\").match(d)) && r.length) { for (a = 0; a < n; a++)t = new Date((\"\" + r[a]).replace(o, \"$2/$1/$3\")), s.push(t instanceof Date && isFinite(t) ? t.getTime() : r[a]); return s.sort().join(\" - \") } return e }, type: \"text\" }),\n /*! date-range DDMMYYYY */\n e.tablesorter.addParser({ id: \"date-range-ymd\", is: function () { return !1 }, format: function (e) { var t, r, a, n, s = []; if (n = (r = e.replace(/\\s+/g, \" \").replace(/[\\/\\-.,]/g, \"-\").match(c)) && r.length) { for (a = 0; a < n; a++)t = new Date((\"\" + r[a]).replace(g, \"$2/$3/$1\")), s.push(t instanceof Date && isFinite(t) ? t.getTime() : r[a]); return s.sort().join(\" - \") } return e }, type: \"text\" }), f.dates || (f.dates = {}), f.dates.months || (f.dates.months = {}), f.dates.months.en = { 1: \"Jan\", 2: \"Feb\", 3: \"Mar\", 4: \"Apr\", 5: \"May\", 6: \"Jun\", 7: \"Jul\", 8: \"Aug\", 9: \"Sep\", 10: \"Oct\", 11: \"Nov\", 12: \"Dec\" }, u = function (e, t, r) { var a, n, s = t.globalize && (t.globalize[r] || t.globalize) || {}, i = f.dates.months[s.lang || \"en\"]; for (n in t.ignoreCase && (e = e.toLowerCase()), i) if (\"string\" == typeof n && (a = i[n], t.ignoreCase && (a = a.toLowerCase()), e.match(a))) return parseInt(n, 10); return e },\n /*! date-range \"dd MMM yyyy - dd MMM yyyy\" */\n f.addParser({ id: \"date-range-dMMMyyyy\", is: function () { return !1 }, format: function (e, t, r, a) { var n, s, i, d, o = [], c = e.replace(/\\s+/g, \" \").match(l), g = c && c.length; if (g) { for (d = 0; d < g; d++)n = \"\", (i = c[d].match(p)) && 4 <= i.length && (i.shift(), s = u(i[1], t.config, a), isNaN(s) || (c[d] = c[d].replace(i[1], s)), n = new Date((\"\" + c[d]).replace(f.regex.shortDateXXY, \"$3/$2/$1\"))), o.push(n instanceof Date && isFinite(n) ? n.getTime() : c[d]); return o.sort().join(\" - \") } return e }, type: \"text\" })\n }(jQuery); return jQuery;\n}));\n","// require('./jquery.iframe-transport.js')\n// This [jQuery](https://jquery.com/) plugin implements an `
\");var m=a.ns,k=function(b,c,d,e,f){a._j1=b+c+m;a._k1=b+d+m;a._l1=b+e+m;f&&(a._m1=b+f+m)};c=e.pointerEnabled;a.pointerEnabled=c||e.msPointerEnabled;a.pointerEnabled?(a.hasTouch=!1,a._n1=.2,a.pointerMultitouch=Boolean(1