diff --git a/app/assets/javascripts/app/controllers/_application_controller/_base.coffee b/app/assets/javascripts/app/controllers/_application_controller/_base.coffee index c7a189014..153830caa 100644 --- a/app/assets/javascripts/app/controllers/_application_controller/_base.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller/_base.coffee @@ -77,8 +77,7 @@ class App.Controller extends Spine.Controller # release bindings if @el - @el.undelegate() - @el.unbind() + @el.off() @el.empty() # release spine bindings (see release() of spine.coffee) @@ -220,7 +219,7 @@ class App.Controller extends Spine.Controller userInfo: (data) -> el = data.el || $('[data-id="customer_info"]') - el.unbind() + el.off() # start customer info controller new App.WidgetUser( diff --git a/app/assets/javascripts/app/controllers/_application_controller/_modal.coffee b/app/assets/javascripts/app/controllers/_application_controller/_modal.coffee index d12ba79cf..28bbc692a 100644 --- a/app/assets/javascripts/app/controllers/_application_controller/_modal.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller/_modal.coffee @@ -181,7 +181,7 @@ class App.ControllerModal extends App.Controller form = @el # focus first input, select or textarea - form.find('input:not([disabled]):not([type="hidden"]):not(".btn"), select:not([disabled]), textarea:not([disabled])').first().focus() + form.find('input:not([disabled]):not([type="hidden"]):not(".btn"), select:not([disabled]), textarea:not([disabled])').first().trigger('focus') @initalFormParams = @formParams() diff --git a/app/assets/javascripts/app/controllers/_application_controller/_modal_generic_history.coffee b/app/assets/javascripts/app/controllers/_application_controller/_modal_generic_history.coffee index f603d77c6..228190c1f 100644 --- a/app/assets/javascripts/app/controllers/_application_controller/_modal_generic_history.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller/_modal_generic_history.coffee @@ -18,7 +18,7 @@ class App.GenericHistory extends App.ControllerModal content = $ App.view('generic/history')( items: localItem ) - content.find('a[data-type="sortorder"]').bind('click', (e) => + content.find('a[data-type="sortorder"]').on('click', (e) => e.preventDefault() @sortorder() ) diff --git a/app/assets/javascripts/app/controllers/_application_controller/form.coffee b/app/assets/javascripts/app/controllers/_application_controller/form.coffee index 01e1ec987..926ca719e 100644 --- a/app/assets/javascripts/app/controllers/_application_controller/form.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller/form.coffee @@ -34,11 +34,8 @@ class App.ControllerForm extends App.Controller @form.prepend('') @form.prepend('') - # Fix for Issue #2510 - Zammad Customers shown as Agents in IE - # Previously the handlers are called directly, before the DOM elements are ready, thereby causing a race condition under IE11. - # Now we only dispatch the handlers after the DOM is ready. if @handlers.length - $(@dispatchHandlers) + @dispatchHandlers() # if element is given, prepend form to it if @el @@ -160,7 +157,7 @@ class App.ControllerForm extends App.Controller for eventSelector, callback of @events do (eventSelector, callback) -> evs = eventSelector.split(' ') - fieldset.find(evs[1]).bind(evs[0], (e) -> callback(e)) + fieldset.find(evs[1]).on(evs[0], (e) -> callback(e)) # bind tool tips fieldset.find('.js-helpMessage').tooltip() @@ -316,7 +313,7 @@ class App.ControllerForm extends App.Controller item_bind = item.find('.richtext-content') item_event = 'blur' - item_bind.bind(item_event, (e) => + item_bind.on(item_event, (e) => @lastChangedAttribute = attribute.name params = App.ControllerForm.params(@form) for handler in @handlers @@ -787,7 +784,7 @@ class App.ControllerForm extends App.Controller # set autofocus by delay to make validation testable App.Delay.set( -> - lookupForm.find('.has-error').find('input, textarea, select').first().focus() + lookupForm.find('.has-error').find('input, textarea, select').first().trigger('focus') 200 'validate' ) diff --git a/app/assets/javascripts/app/controllers/_application_controller/reorder_modal.coffee b/app/assets/javascripts/app/controllers/_application_controller/reorder_modal.coffee index 0419c69eb..e18ee2f25 100644 --- a/app/assets/javascripts/app/controllers/_application_controller/reorder_modal.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller/reorder_modal.coffee @@ -21,7 +21,7 @@ class App.ControllerReorderModal extends App.ControllerModal onShown: -> super - @$('.js-submit').focus() + @$('.js-submit').trigger('focus') save: -> ids = @$('tr.item').toArray().map (el) -> parseInt(el.dataset.id) diff --git a/app/assets/javascripts/app/controllers/_application_controller/table.coffee b/app/assets/javascripts/app/controllers/_application_controller/table.coffee index a1d9db8d7..6144ec66b 100644 --- a/app/assets/javascripts/app/controllers/_application_controller/table.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller/table.coffee @@ -406,7 +406,7 @@ class App.ControllerTable extends App.Controller if @bindCheckbox.events for event, callback of @bindCheckbox.events do (table, event, callback) -> - table.delegate('input[name="bulk"]', event, (e) -> + table.on(event, 'input[name="bulk"]', (e) -> e.stopPropagation() id = $(e.currentTarget).parents('tr').data('id') checked = $(e.currentTarget).prop('checked') @@ -424,12 +424,12 @@ class App.ControllerTable extends App.Controller if @checkbox # click first tr>td, catch click - table.delegate('tr > td:nth-child(1)', 'click', (e) -> + table.on('click', 'tr > td:nth-child(1)', (e) -> e.stopPropagation() ) # bind on full bulk click - table.delegate('input[name="bulk_all"]', 'change', (e) => + table.on('change', 'input[name="bulk_all"]', (e) => e.stopPropagation() clicks = [] if $(e.currentTarget).prop('checked') diff --git a/app/assets/javascripts/app/controllers/_application_controller/wizard_modal.coffee b/app/assets/javascripts/app/controllers/_application_controller/wizard_modal.coffee index 846f77c42..07dc8574f 100644 --- a/app/assets/javascripts/app/controllers/_application_controller/wizard_modal.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller/wizard_modal.coffee @@ -20,7 +20,7 @@ class App.ControllerWizardModal extends App.ControllerFullPage @hideAlert(name) @$('.setup.wizard').addClass('hide') @$(".setup.wizard.#{name}").removeClass('hide') - @$(".setup.wizard.#{name} input, .setup.wizard.#{name} select").first().focus() + @$(".setup.wizard.#{name} input, .setup.wizard.#{name} select").first().trigger('focus') showAlert: (screen, message) => @$(".#{screen}").find('.alert').first().removeClass('hide').text(App.i18n.translatePlain(message)) diff --git a/app/assets/javascripts/app/controllers/_channel/chat.coffee b/app/assets/javascripts/app/controllers/_channel/chat.coffee index 5c38a54d5..323faa559 100644 --- a/app/assets/javascripts/app/controllers/_channel/chat.coffee +++ b/app/assets/javascripts/app/controllers/_channel/chat.coffee @@ -204,7 +204,7 @@ class ChannelChat extends App.ControllerSubContent onUrlSubmit: (event) -> event.preventDefault() if event - @urlInput.focus() + @urlInput.trigger('focus') @changeDemoWebsite() changeDemoWebsite: -> diff --git a/app/assets/javascripts/app/controllers/_channel/email.coffee b/app/assets/javascripts/app/controllers/_channel/email.coffee index 995148038..a7ada3b61 100644 --- a/app/assets/javascripts/app/controllers/_channel/email.coffee +++ b/app/assets/javascripts/app/controllers/_channel/email.coffee @@ -610,11 +610,11 @@ class ChannelEmailAccountWizard extends App.ControllerWizardModal if !verify @$('.js-inbound-acknowledge .js-back').attr('data-slide', 'js-inbound') - @$('.js-inbound-acknowledge .js-next').unbind('click.verify') + @$('.js-inbound-acknowledge .js-next').off('click.verify') else @$('.js-inbound-acknowledge .js-back').attr('data-slide', 'js-intro') @$('.js-inbound-acknowledge .js-next').attr('data-slide', '') - @$('.js-inbound-acknowledge .js-next').unbind('click.verify').bind('click.verify', (e) => + @$('.js-inbound-acknowledge .js-next').off('click.verify').on('click.verify', (e) => e.preventDefault() @verify(@account) ) diff --git a/app/assets/javascripts/app/controllers/_channel/sms.coffee b/app/assets/javascripts/app/controllers/_channel/sms.coffee index 50b5364a4..6628ef3eb 100644 --- a/app/assets/javascripts/app/controllers/_channel/sms.coffee +++ b/app/assets/javascripts/app/controllers/_channel/sms.coffee @@ -170,7 +170,7 @@ class ChannelSmsAccount extends App.ControllerModal params: @channel ) @renderAdapterOptions(@channel.options?.adapter, el) - el.find('[name="options::adapter"]').bind('change', (e) => + el.find('[name="options::adapter"]').on('change', (e) => @renderAdapterOptions(e.target.value, el) ) el @@ -309,7 +309,7 @@ class ChannelSmsNotification extends App.ControllerModal params: @channel ) @renderAdapterOptions(@channel.options?.adapter, el) - el.find('[name="options::adapter"]').bind('change', (e) => + el.find('[name="options::adapter"]').on('change', (e) => @renderAdapterOptions(e.target.value, el) ) el diff --git a/app/assets/javascripts/app/controllers/_channel/twitter.coffee b/app/assets/javascripts/app/controllers/_channel/twitter.coffee index 756462846..f50141315 100644 --- a/app/assets/javascripts/app/controllers/_channel/twitter.coffee +++ b/app/assets/javascripts/app/controllers/_channel/twitter.coffee @@ -219,7 +219,7 @@ class AccountEdit extends App.ControllerModal term: '' group_id: '' renderSearchTerms() - content.find('.js-searchTermList [name="search::term"]').last().focus() + content.find('.js-searchTermList [name="search::term"]').last().trigger('focus') removeSearchTerm = (event) => index = $(event.currentTarget).attr('data-index') @@ -248,7 +248,7 @@ class AccountEdit extends App.ControllerModal renderSearchTerms() - content.find('.js-searchTermAdd').click(addSearchTerm) + content.find('.js-searchTermAdd').on('click', addSearchTerm) content.find('.js-searchTermList').on('click', '.js-searchTermRemove', removeSearchTerm) content.find('.js-mentionsGroup').replaceWith createGroupSelection(@channel.options.sync.mentions.group_id, 'mentions') diff --git a/app/assets/javascripts/app/controllers/_plugin/global_search.coffee b/app/assets/javascripts/app/controllers/_plugin/global_search.coffee index 655d39661..8fdb74b62 100644 --- a/app/assets/javascripts/app/controllers/_plugin/global_search.coffee +++ b/app/assets/javascripts/app/controllers/_plugin/global_search.coffee @@ -27,7 +27,7 @@ class App.GlobalSearchWidget extends App.Controller $('#global-search').val(currentValue) delay = -> - $('#global-search').focus() + $('#global-search').trigger('focus') App.Delay.set(delay, 20, 'global-search-delay') ) diff --git a/app/assets/javascripts/app/controllers/_plugin/keyboard_shortcuts.coffee b/app/assets/javascripts/app/controllers/_plugin/keyboard_shortcuts.coffee index 7dcf18c4a..022ae6a75 100644 --- a/app/assets/javascripts/app/controllers/_plugin/keyboard_shortcuts.coffee +++ b/app/assets/javascripts/app/controllers/_plugin/keyboard_shortcuts.coffee @@ -33,13 +33,13 @@ class App.KeyboardShortcutWidget extends App.Controller @observerKeys() @lastKey = undefined - $(document).keyup((e) => + $(document).on('keyup', (e) => return if e.keyCode isnt 27 @lastKey = undefined ) observerKeys: => - $(document).unbind('keydown.shortcuts') + $(document).off('keydown.shortcuts') navigationHotkeys = App.Browser.hotkeys() areas = App.Config.get('keyboard_shortcuts') @@ -56,7 +56,7 @@ class App.KeyboardShortcutWidget extends App.Controller modifier += shortcut.key if shortcut.callback @log 'debug', 'bind for', modifier - $(document).bind('keydown.shortcuts', modifier, (e) => + $(document).on('keydown.shortcuts', {keys: modifier}, (e) => e.preventDefault() if @lastKey && @lastKey.modifier is modifier && @lastKey.time + 5500 > new Date().getTime() @lastKey.count += 1 @@ -94,7 +94,7 @@ App.Config.set( description: __('Dashboard') globalEvent: 'dashboard' callback: -> - $('#global-search').blur() + $('#global-search').trigger('blur') App.Event.trigger('keyboard_shortcuts_close') window.location.hash = '#dashboard' } @@ -104,7 +104,7 @@ App.Config.set( description: __('Overviews') globalEvent: 'overview' callback: -> - $('#global-search').blur() + $('#global-search').trigger('blur') App.Event.trigger('keyboard_shortcuts_close') window.location.hash = '#ticket/view' } @@ -115,7 +115,7 @@ App.Config.set( globalEvent: 'search' callback: -> App.Event.trigger('keyboard_shortcuts_close') - $('#global-search').focus() + $('#global-search').trigger('focus') } { key: 'a' @@ -123,9 +123,9 @@ App.Config.set( description: __('Notifications') globalEvent: 'notification' callback: -> - $('#global-search').blur() + $('#global-search').trigger('blur') App.Event.trigger('keyboard_shortcuts_close') - $('#navigation .js-toggleNotifications').click() + $('#navigation .js-toggleNotifications').trigger('click') } { key: 'n' @@ -133,7 +133,7 @@ App.Config.set( description: __('New Ticket') globalEvent: 'new-ticket' callback: -> - $('#global-search').blur() + $('#global-search').trigger('blur') App.Event.trigger('keyboard_shortcuts_close') window.location.hash = '#ticket/create' } @@ -168,7 +168,7 @@ App.Config.set( globalEvent: 'close-current-tab' callback: -> App.Event.trigger('keyboard_shortcuts_close') - $('#navigation .tasks .is-active .js-close').click() + $('#navigation .tasks .is-active .js-close').trigger('click') } { key: 'tab' @@ -185,12 +185,12 @@ App.Config.set( if current.get(0) next = current.next() if next.get(0) - next.find('div').first().click() + next.find('div').first().trigger('click') scollIfNeeded(next) return prev = $('#navigation .tasks .task').first() if prev.get(0) - prev.find('div').first().click() + prev.find('div').first().trigger('click') scollIfNeeded(prev) } { @@ -208,12 +208,12 @@ App.Config.set( if current.get(0) prev = current.prev() if prev.get(0) - prev.find('div').first().click() + prev.find('div').first().trigger('click') scollIfNeeded(prev) return last = $('#navigation .tasks .task').last() if last.get(0) - last.find('div').first().click() + last.find('div').first().trigger('click') scollIfNeeded(last) } { @@ -227,24 +227,24 @@ App.Config.set( # check of primary modal exists dialog = $('body > div.modal') if dialog.get(0) - dialog.find('.js-submit').click() + dialog.find('.js-submit').trigger('click') return # check of local modal exists dialog = $('.active.content > div.modal') if dialog.get(0) - dialog.find('.js-submit').click() + dialog.find('.js-submit').trigger('click') return # check ticket edit dialog = $('.active.content .js-attributeBar .js-submit') if dialog.get(0) - dialog.first().click() + dialog.first().trigger('click') return dialog = $('.active.content .js-submit') if dialog.get(0) - dialog.first().click() + dialog.first().trigger('click') return } ] @@ -342,8 +342,8 @@ App.Config.set( globalEvent: 'article-note-open' callback: -> App.Event.trigger('keyboard_shortcuts_close') - $('.active.content .editControls .js-articleTypes [data-value="note"]').click() - $('.active.content .article-new .articleNewEdit-body').first().focus() + $('.active.content .editControls .js-articleTypes [data-value="note"]').trigger('click') + $('.active.content .article-new .articleNewEdit-body').first().trigger('focus') } { key: 'g' @@ -355,9 +355,9 @@ App.Config.set( lastArticleWithReply = $('.active.content .ticket-article .icon-reply').last() lastArticleWithReplyAll = lastArticleWithReply.parent().find('.icon-reply-all') if lastArticleWithReplyAll.get(0) - lastArticleWithReplyAll.click() + lastArticleWithReplyAll.trigger('click') return - lastArticleWithReply.click() + lastArticleWithReply.trigger('click') } { key: 'j' @@ -366,7 +366,7 @@ App.Config.set( globalEvent: 'article-internal-public' callback: -> App.Event.trigger('keyboard_shortcuts_close') - $('.active.content .editControls .js-selectInternalPublic').click() + $('.active.content .editControls .js-selectInternalPublic').trigger('click') } #{ # key: 'm' @@ -385,7 +385,7 @@ App.Config.set( App.Event.trigger('keyboard_shortcuts_close') return if !$('.active.content .edit').get(0) $('.active.content .edit [name="state_id"]').val(4) - $('.active.content .js-attributeBar .js-submit').first().click() + $('.active.content .js-attributeBar .js-submit').first().trigger('click') } { key: ['◀', '▶'] diff --git a/app/assets/javascripts/app/controllers/_plugin/navigation.coffee b/app/assets/javascripts/app/controllers/_plugin/navigation.coffee index 24f359acf..fbd75c22d 100644 --- a/app/assets/javascripts/app/controllers/_plugin/navigation.coffee +++ b/app/assets/javascripts/app/controllers/_plugin/navigation.coffee @@ -256,7 +256,7 @@ class Navigation extends App.Controller @nudge(e, 1) return else if e.keyCode is 13 # enter - @searchInput.blur() + @searchInput.trigger('blur') href = @$('.global-search-result .nav-tab.is-hover').attr('href') if href @navigate(href) diff --git a/app/assets/javascripts/app/controllers/_plugin/notify.coffee b/app/assets/javascripts/app/controllers/_plugin/notify.coffee index 3637edd7f..bdfe86deb 100644 --- a/app/assets/javascripts/app/controllers/_plugin/notify.coffee +++ b/app/assets/javascripts/app/controllers/_plugin/notify.coffee @@ -54,7 +54,8 @@ class App.Notify extends App.Controller if App.Session.get() isnt undefined && window.Notification window.Notification.requestPermission() - $(window).focus( + $(window).on( + 'focus', => for counter, notification of @desktopNotify notification.close() diff --git a/app/assets/javascripts/app/controllers/_ui_element/_application_selector.coffee b/app/assets/javascripts/app/controllers/_ui_element/_application_selector.coffee index b0cfa7f4d..e0b6d95e6 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/_application_selector.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/_application_selector.coffee @@ -162,7 +162,7 @@ class App.UiElement.ApplicationSelector item = $( App.view('generic/application_selector')(attribute: attribute) ) # add filter - item.delegate('.js-add', 'click', (e) => + item.on('click', '.js-add', (e) => element = $(e.target).closest('.js-filterElement') # add first available attribute @@ -191,7 +191,7 @@ class App.UiElement.ApplicationSelector ) # remove filter - item.delegate('.js-remove', 'click', (e) => + item.on('click', '.js-remove', (e) => return if $(e.currentTarget).hasClass('is-disabled') if @hasEmptySelectorAtStart() @@ -229,7 +229,7 @@ class App.UiElement.ApplicationSelector item.filter('.js-filter').append(row) # change attribute selector - item.delegate('.js-attributeSelector select', 'change', (e) => + item.on('change', '.js-attributeSelector select', (e) => elementRow = $(e.target).closest('.js-filterElement') groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value') return if !groupAndAttribute @@ -238,7 +238,7 @@ class App.UiElement.ApplicationSelector ) # change operator selector - item.delegate('.js-operator select', 'change', (e) => + item.on('change', '.js-operator select', (e) => elementRow = $(e.target).closest('.js-filterElement') groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value') return if !groupAndAttribute @@ -335,7 +335,7 @@ class App.UiElement.ApplicationSelector if !@hasDuplicateSelector() # enable all - elementFull.find('.js-attributeSelector select option').removeAttr('disabled') + elementFull.find('.js-attributeSelector select option').prop('disabled', false) # disable all used attributes elementFull.find('.js-attributeSelector select').each(-> @@ -460,7 +460,7 @@ class App.UiElement.ApplicationSelector elementRow.find('.js-preCondition').closest('.controls').removeClass('hide') elementRow.find('.js-preCondition select').replaceWith(selection) - elementRow.find('.js-preCondition select').bind('change', (e) -> + elementRow.find('.js-preCondition select').on('change', (e) -> toggleValue() ) diff --git a/app/assets/javascripts/app/controllers/_ui_element/basedate.coffee b/app/assets/javascripts/app/controllers/_ui_element/basedate.coffee index 5796a2345..9abbd84cd 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/basedate.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/basedate.coffee @@ -47,14 +47,14 @@ class App.UiElement.basedate @bindEvents: (item, attribute) -> item .find('input') - .bind('focus', (e) -> + .on('focus', (e) -> item.find('.js-datepicker').datepicker('rerender') - ).bind('keyup blur change', (e) => + ).on('keyup blur change', (e) => @setNewTime(item, attribute, 0) @validation(item, attribute, true) ) - item.bind('validate', (e) => + item.on('validate', (e) => @validation(item, attribute) ) diff --git a/app/assets/javascripts/app/controllers/_ui_element/holiday_selector.coffee b/app/assets/javascripts/app/controllers/_ui_element/holiday_selector.coffee index b2fcc24f3..9542abc8d 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/holiday_selector.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/holiday_selector.coffee @@ -24,7 +24,7 @@ class App.UiElement.holiday_selector item.find('.js-datePicker').html(datePicker) # set active/inactive of date - item.delegate('.js-active', 'click', (e) -> + item.on('click', '.js-active', (e) -> active = $(e.target).prop('checked') row = $(e.target).closest('tr') input = $(e.target).closest('tr').find('.js-summary') @@ -39,19 +39,19 @@ class App.UiElement.holiday_selector ) # remove date - item.delegate('.js-remove', 'click', (e) -> + item.on('click', '.js-remove', (e) -> $(e.target).closest('tr').remove() ) # catch enter / apply add - item.find('.js-summary').bind( 'keydown', (e) -> + item.find('.js-summary').on( 'keydown', (e) -> return if e.which isnt 13 e.preventDefault() - item.find('.js-add').click() + item.find('.js-add').trigger('click') ) # add date - item.find('.js-add').bind('click', (e) -> + item.find('.js-add').on('click', (e) -> date = $(e.target).closest('tr').find('[name="{date}public_holidays_date"]').val() return if !date summary = $(e.target).closest('tr').find('.js-summary').val() diff --git a/app/assets/javascripts/app/controllers/_ui_element/ical_feed.coffee b/app/assets/javascripts/app/controllers/_ui_element/ical_feed.coffee index 45ae04d2e..d1c527147 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/ical_feed.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/ical_feed.coffee @@ -34,16 +34,16 @@ class App.UiElement.ical_feed extends App.UiElement.ApplicationUiElement updateCheckManual() item.find('.js-manual').val(attribute.value) - item.find('.js-check').bind('change', -> + item.find('.js-check').on('change', -> updateShadow() ) - item.find('.js-list').bind('click change', -> + item.find('.js-list').on('click change', -> updateCheckList() updateShadow('list') ) - item.find('.js-manual').bind('keyup focus blur', -> + item.find('.js-manual').on('keyup focus blur', -> updateCheckManual() updateShadow('manual') ) diff --git a/app/assets/javascripts/app/controllers/_ui_element/permission.coffee b/app/assets/javascripts/app/controllers/_ui_element/permission.coffee index a268a9f65..95cdff830 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/permission.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/permission.coffee @@ -26,7 +26,7 @@ class App.UiElement.permission extends App.UiElement.ApplicationUiElement ) ) # show/hide trees - item.find('[name=permission_ids]').bind('change', (e) => + item.find('[name=permission_ids]').on('change', (e) => @checkUncheck($(e.currentTarget), permissions, item) ) item.find('[name=permission_ids]').trigger('change') diff --git a/app/assets/javascripts/app/controllers/_ui_element/postmaster_match.coffee b/app/assets/javascripts/app/controllers/_ui_element/postmaster_match.coffee index 00841ee91..c9763fde5 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/postmaster_match.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/postmaster_match.coffee @@ -146,7 +146,7 @@ class App.UiElement.postmaster_match item.find('.js-attributeSelector').prepend(selector) # add filter - item.find('.js-add').bind('click', (e) -> + item.find('.js-add').on('click', (e) -> element = $(e.target).closest('.js-filterElement') elementClone = element.clone(true) element.after(elementClone) @@ -154,14 +154,14 @@ class App.UiElement.postmaster_match ) # remove filter - item.find('.js-remove').bind('click', (e) => + item.find('.js-remove').on('click', (e) => return if $(e.currentTarget).hasClass('is-disabled') $(e.target).closest('.js-filterElement').remove() @rebuildAttributeSelectors(item) ) # change attribute selector - item.find('.js-attributeSelector select').bind('change', (e) => + item.find('.js-attributeSelector select').on('change', (e) => key = $(e.target).find('option:selected').attr('value') elementRow = $(e.target).closest('.js-filterElement') @rebuildAttributeSelectors(item, elementRow, key, attribute) @@ -170,7 +170,7 @@ class App.UiElement.postmaster_match ) # change operator - item.find('.js-operator select').bind('change', (e) => + item.find('.js-operator select').on('change', (e) => key = $(e.target).find('.js-attributeSelector option:selected').attr('value') operator = $(e.target).find('option:selected').attr('value') elementRow = $(e.target).closest('.js-filterElement') @@ -233,7 +233,7 @@ class App.UiElement.postmaster_match @rebuildAttributeSelectors: (elementFull, elementRow, key, attribute) -> # enable all - elementFull.find('.js-attributeSelector select option').removeAttr('disabled') + elementFull.find('.js-attributeSelector select option').prop('disabled', false) # disable all used attributes elementFull.find('.js-attributeSelector select').each(-> diff --git a/app/assets/javascripts/app/controllers/_ui_element/postmaster_set.coffee b/app/assets/javascripts/app/controllers/_ui_element/postmaster_set.coffee index fa58e019f..ccf44043a 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/postmaster_set.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/postmaster_set.coffee @@ -198,7 +198,10 @@ class App.UiElement.postmaster_set config['tag'] = 'input' config['type'] = 'text' config['name'] = name - config['value'] = value + if !value && attribute.value && attribute.value[key] + config['value'] = attribute.value[key].value + else + config['value'] = value item = App.UiElement[config.tag].render(config, {}) elementRow.find('.js-value').html(item) @@ -227,7 +230,7 @@ class App.UiElement.postmaster_set @rebuildAttributeSelectors: (elementFull, elementRow, key, attribute) -> # enable all - elementFull.find('.js-attributeSelector select option').removeAttr('disabled') + elementFull.find('.js-attributeSelector select option').prop('disabled', false) # disable all used attributes elementFull.find('.js-attributeSelector select').each(-> diff --git a/app/assets/javascripts/app/controllers/_ui_element/richtext.coffee b/app/assets/javascripts/app/controllers/_ui_element/richtext.coffee index 757ebaa03..aafeb949c 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/richtext.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/richtext.coffee @@ -12,7 +12,7 @@ class App.UiElement.richtext buttons: attribute.buttons ) - item.find('a.btn--action[data-action]').click (event) => @toolButtonClicked(event, form) + item.find('a.btn--action[data-action]').on 'click', (event) => @toolButtonClicked(event, form) if attribute.plugins for plugin in attribute.plugins diff --git a/app/assets/javascripts/app/controllers/_ui_element/select.coffee b/app/assets/javascripts/app/controllers/_ui_element/select.coffee index a7996c125..86d470416 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/select.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/select.coffee @@ -45,7 +45,7 @@ class App.UiElement.select extends App.UiElement.ApplicationUiElement @bindEventListeners: (item, attribute, params) -> if attribute.display_warn - item.bind('change', (e) => + item.on('change', (e) => @bindWarnDisplayListener(e.target.value, attribute, params, item) ) diff --git a/app/assets/javascripts/app/controllers/_ui_element/sla_times.coffee b/app/assets/javascripts/app/controllers/_ui_element/sla_times.coffee index 2bf72247d..77a8daa28 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/sla_times.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/sla_times.coffee @@ -23,7 +23,7 @@ class App.UiElement.sla_times ) # disable/enable rows - item.find('.js-activateRow').bind('change', (e) -> + item.find('.js-activateRow').on('change', (e) -> element = $(e.target) row = element.closest('tr') if element.prop('checked') @@ -43,7 +43,7 @@ class App.UiElement.sla_times ) # convert hours into minutes - item.find('.js-timeConvertFrom').bind('keyup focus blur', (e) => + item.find('.js-timeConvertFrom').on('keyup focus blur', (e) => element = $(e.target) inText = element.val() @@ -62,12 +62,12 @@ class App.UiElement.sla_times ) # toggle row on clicking name cell - item.find('.js-forward-click').bind('click', (e) -> - $(e.currentTarget).closest('tr').find('.checkbox-replacement').click() + item.find('.js-forward-click').on('click', (e) -> + $(e.currentTarget).closest('tr').find('.checkbox-replacement').trigger('click') ) # toggle update type on clicking around the element - item.find('.js-forward-radio').bind('click', (e) -> + item.find('.js-forward-radio').on('click', (e) -> elem = $(e.currentTarget).closest('p').find('.js-updateTypeSelector') elem.prop('checked', true) @@ -75,20 +75,20 @@ class App.UiElement.sla_times ) # focus time input on clicking surrounding cell - item.find('.js-focus-input').bind('click', (e) -> + item.find('.js-focus-input').on('click', (e) -> $(e.currentTarget) .find('.form-control:visible') - .focus() + .trigger('focus') ) # show placeholder instead of 00:00 - item.find('.js-timeConvertFrom').bind('changeTime.timepicker', (e) -> + item.find('.js-timeConvertFrom').on('changeTime.timepicker', (e) -> if $(e.currentTarget).val() == '00:00' $(e.currentTarget).val('') ) # switch update/response times when type is selected accordingly - item.find('.js-updateTypeSelector').bind('change', (e) -> + item.find('.js-updateTypeSelector').on('change', (e) -> element = $(e.target) row = element.closest('tr') row.find('.js-activateRow').prop('checked', true) diff --git a/app/assets/javascripts/app/controllers/_ui_element/textarea.coffee b/app/assets/javascripts/app/controllers/_ui_element/textarea.coffee index 4ed6e555f..eca0d9e69 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/textarea.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/textarea.coffee @@ -12,7 +12,7 @@ class App.UiElement.textarea $( item[0] ).on('focus', -> visible = $( item[0] ).is(':visible') if visible && !$( item[0] ).expanding('active') - $( item[0] ).expanding().focus() + $( item[0] ).expanding().trigger('focus') ) App.Delay.set(a, 80) diff --git a/app/assets/javascripts/app/controllers/_ui_element/ticket_perform_action.coffee b/app/assets/javascripts/app/controllers/_ui_element/ticket_perform_action.coffee index 341fcd5d7..93f185047 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/ticket_perform_action.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/ticket_perform_action.coffee @@ -163,7 +163,7 @@ class App.UiElement.ticket_perform_action @updateAttributeSelectors: (elementFull) -> # enable all - elementFull.find('.js-attributeSelector select option').removeAttr('disabled') + elementFull.find('.js-attributeSelector select option').prop('disabled', false) # disable all used attributes elementFull.find('.js-attributeSelector select').each(-> @@ -292,7 +292,7 @@ class App.UiElement.ticket_perform_action elementRow.find('.js-preCondition').closest('.controls').removeClass('hide') elementRow.find('.js-preCondition select').replaceWith(selection) - elementRow.find('.js-preCondition select').bind('change', (e) -> + elementRow.find('.js-preCondition select').on('change', (e) -> toggleValue() ) diff --git a/app/assets/javascripts/app/controllers/_ui_element/timer.coffee b/app/assets/javascripts/app/controllers/_ui_element/timer.coffee index 24971f15e..cc6a4a7e6 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/timer.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/timer.coffee @@ -81,7 +81,7 @@ class App.UiElement.timer timer = $( App.view('generic/timer')( attribute: attribute, days: days, hours: hours, minutes: minutes ) ) timer.find('.js-boolean').data('field-type', 'boolean') - timer.find('.select-value').bind('click', (e) => + timer.find('.select-value').on('click', (e) => @select(e) ) @createOutputString(timer) @@ -93,7 +93,7 @@ class App.UiElement.timer if target.hasClass('is-selected') # prevent zero selections - if target.siblings('.is-selected').size() > 0 + if target.siblings('.is-selected').length > 0 target.removeClass('is-selected') target.next().val('false') else diff --git a/app/assets/javascripts/app/controllers/_ui_element/user_permission.coffee b/app/assets/javascripts/app/controllers/_ui_element/user_permission.coffee index 877dce2db..16509e0d3 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/user_permission.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/user_permission.coffee @@ -88,7 +88,7 @@ class App.UiElement.user_permission item.on('click', '.checkbox-replacement', throttled) # if customer, remove admin and agent - item.find('[name=role_ids]').bind('change', (e) => + item.find('[name=role_ids]').on('change', (e) => @checkUncheck($(e.currentTarget), rolesWithGroupPlugin, item) ) item.find('[name=role_ids]').trigger('change') diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create.coffee index ab954efdb..ecc02de68 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_create.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_create.coffee @@ -129,7 +129,7 @@ class App.TicketCreate extends App.Controller @$('[name="group_id"]').trigger('change') # add observer to change options - @$('[name="cc"], [name="group_id"], [name="customer_id"]').bind('change', => + @$('[name="cc"], [name="group_id"], [name="customer_id"]').on('change', => @updateSecurityOptions() ) @updateSecurityOptions() diff --git a/app/assets/javascripts/app/controllers/agent_ticket_merge.coffee b/app/assets/javascripts/app/controllers/agent_ticket_merge.coffee index e1d589779..e9d3fb63c 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_merge.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_merge.coffee @@ -49,11 +49,11 @@ class App.TicketMerge extends App.ControllerModal radio: true ) - content.delegate('[name="target_ticket_number"]', 'focus', (e) -> + content.on('focus', '[name="target_ticket_number"]', (e) -> $(e.target).parents().find('[name="radio"]').prop('checked', false) ) - content.delegate('[name="radio"]', 'click', (e) -> + content.on('click', '[name="radio"]', (e) -> if $(e.target).prop('checked') ticket_id = $(e.target).val() ticket = App.Ticket.fullLocal(ticket_id) diff --git a/app/assets/javascripts/app/controllers/chat.coffee b/app/assets/javascripts/app/controllers/chat.coffee index b334215ab..bf13e31df 100644 --- a/app/assets/javascripts/app/controllers/chat.coffee +++ b/app/assets/javascripts/app/controllers/chat.coffee @@ -508,7 +508,7 @@ class ChatWindow extends App.Controller ) @el.one('transitionend', @onTransitionend) - @scrollHolder.scroll(@detectScrolledtoBottom) + @scrollHolder.on('scroll', @detectScrolledtoBottom) # force repaint @el.prop('offsetHeight') @@ -568,7 +568,7 @@ class ChatWindow extends App.Controller ) focus: => - @input.focus() + @input.trigger('focus') onTransitionend: (event) => # chat window is done with animation - adjust scroll-bars @@ -628,7 +628,7 @@ class ChatWindow extends App.Controller switch event.keyCode when TABKEY allChatInputs = @input.not('[disabled="disabled"]') - chatCount = allChatInputs.size() + chatCount = allChatInputs.length index = allChatInputs.index(@input) if chatCount > 1 diff --git a/app/assets/javascripts/app/controllers/cti.coffee b/app/assets/javascripts/app/controllers/cti.coffee index 21d2af3de..d08a559d6 100644 --- a/app/assets/javascripts/app/controllers/cti.coffee +++ b/app/assets/javascripts/app/controllers/cti.coffee @@ -43,10 +43,10 @@ class App.CTI extends App.Controller item: @ringingCalls() ) $('.js-phoneMenuItem').after(localHtml) - $('.call-widget').find('.js-newUser').bind('click', (e) => + $('.call-widget').find('.js-newUser').on('click', (e) => @newUser(e) ) - $('.call-widget').find('.js-newTicket').bind('click', (e) => + $('.call-widget').find('.js-newTicket').on('click', (e) => user = undefined user_id = $(e.currentTarget).data('user-id') if user_id diff --git a/app/assets/javascripts/app/controllers/getting_started/base.coffee b/app/assets/javascripts/app/controllers/getting_started/base.coffee index 7737168ed..79088abfe 100644 --- a/app/assets/javascripts/app/controllers/getting_started/base.coffee +++ b/app/assets/javascripts/app/controllers/getting_started/base.coffee @@ -58,7 +58,7 @@ class GettingStartedBase extends App.ControllerWizardFullScreen logoUrl: @logoUrl() organization: organization ) - @$('input, select').first().focus() + @$('input, select').first().trigger('focus') onLogoPick: (event) => reader = new FileReader() diff --git a/app/assets/javascripts/app/controllers/getting_started/channel_email.coffee b/app/assets/javascripts/app/controllers/getting_started/channel_email.coffee index 98ff307fd..48548d553 100644 --- a/app/assets/javascripts/app/controllers/getting_started/channel_email.coffee +++ b/app/assets/javascripts/app/controllers/getting_started/channel_email.coffee @@ -243,11 +243,11 @@ class GettingStartedChannelEmail extends App.ControllerWizardFullScreen if !verify @$('.js-inbound-acknowledge .js-back').attr('data-slide', 'js-inbound') - @$('.js-inbound-acknowledge .js-next').unbind('click.verify') + @$('.js-inbound-acknowledge .js-next').off('click.verify') else @$('.js-inbound-acknowledge .js-back').attr('data-slide', 'js-intro') @$('.js-inbound-acknowledge .js-next').attr('data-slide', '') - @$('.js-inbound-acknowledge .js-next').unbind('click.verify').bind('click.verify', (e) => + @$('.js-inbound-acknowledge .js-next').off('click.verify').on('click.verify', (e) => e.preventDefault() @verify(@account) ) diff --git a/app/assets/javascripts/app/controllers/idoit_object_selector.coffee b/app/assets/javascripts/app/controllers/idoit_object_selector.coffee index 026e6cea2..4be75fa2a 100644 --- a/app/assets/javascripts/app/controllers/idoit_object_selector.coffee +++ b/app/assets/javascripts/app/controllers/idoit_object_selector.coffee @@ -31,7 +31,7 @@ class App.IdoitObjectSelector extends App.ControllerModal @search(params) ) @render() - @$('.js-input').focus() + @$('.js-input').trigger('focus') error: (xhr, status, error) => diff --git a/app/assets/javascripts/app/controllers/knowledge_base/reader_controller.coffee b/app/assets/javascripts/app/controllers/knowledge_base/reader_controller.coffee index c7d22496b..29134002f 100644 --- a/app/assets/javascripts/app/controllers/knowledge_base/reader_controller.coffee +++ b/app/assets/javascripts/app/controllers/knowledge_base/reader_controller.coffee @@ -96,7 +96,7 @@ class App.KnowledgeBaseReaderController extends App.Controller prepareLinks: (input) -> input = $($.parseHTML(input)) - for linkDom in input.find('a').andSelf('a').toArray() + for linkDom in input.find('a').addBack('a').toArray() switch $(linkDom).attr('data-target-type') when 'knowledge-base-answer' if object = App.KnowledgeBaseAnswerTranslation.find $(linkDom).attr('data-target-id') diff --git a/app/assets/javascripts/app/controllers/knowledge_base/search_field_widget.coffee b/app/assets/javascripts/app/controllers/knowledge_base/search_field_widget.coffee index dc97bffd8..1e10470fe 100644 --- a/app/assets/javascripts/app/controllers/knowledge_base/search_field_widget.coffee +++ b/app/assets/javascripts/app/controllers/knowledge_base/search_field_widget.coffee @@ -109,7 +109,7 @@ class App.KnowledgeBaseSearchFieldWidget extends App.Controller @renderResults?(data, originalQuery) focus: -> - @searchField.focus() + @searchField.trigger('focus') startSearch: (query) -> @searchField diff --git a/app/assets/javascripts/app/controllers/layout_ref.coffee b/app/assets/javascripts/app/controllers/layout_ref.coffee index 9c9995542..12a204fad 100644 --- a/app/assets/javascripts/app/controllers/layout_ref.coffee +++ b/app/assets/javascripts/app/controllers/layout_ref.coffee @@ -652,7 +652,7 @@ class ReferenceSetupWizard extends App.ControllerWizard } @agentEmail.add(@agentFirstName).add(@agentLastName).val('') - @agentFirstName.focus() + @agentFirstName.trigger('focus') App.Config.set( 'layout_ref/setup', ReferenceSetupWizard, 'Routes' ) @@ -709,7 +709,7 @@ class RichText extends App.ControllerAppContent App.Utils.htmlCleanup(textarea) # remove marker for cursor - textarea.find('[data-cursor=1]').focus() + textarea.find('[data-cursor=1]').trigger('focus') textarea.find('[data-cursor=1]').remove() @delay( execute, 1) @@ -953,11 +953,11 @@ class TicketZoomRef extends App.ControllerAppContent @closeDropdown() else @buttonDropdown.addClass 'is-open' - $(document).bind 'click.buttonDropdown', @closeDropdown + $(document).on 'click.buttonDropdown', @closeDropdown closeDropdown: => @buttonDropdown.removeClass 'is-open' - $(document).unbind 'click.buttonDropdown' + $(document).off 'click.buttonDropdown' performTicketMacro: (event) => console.log 'perform action', @$(event.currentTarget).text() @@ -1414,7 +1414,7 @@ class SchedulersRef extends App.ControllerAppContent if target.hasClass('is-selected') # prevent zero selections - if target.siblings('.is-selected').size() > 0 + if target.siblings('.is-selected').length > 0 target.removeClass('is-selected') else target.addClass('is-selected') @@ -2053,7 +2053,7 @@ class ChatWindowRef extends Spine.Controller switch event.keyCode when TABKEY allChatInputs = $('.js-customerChatInput').not('[disabled="disabled"]') - chatCount = allChatInputs.size() + chatCount = allChatInputs.length index = allChatInputs.index(@input) if chatCount > 1 @@ -2333,7 +2333,7 @@ class KnowledgeBaseAgentReaderRef extends App.ControllerAppContent if $(event.currentTarget).is('.btn--primary') @el.find('.main[data-level]').addClass('hidden') @el.find('[data-level~="search"]').removeClass('hidden') - @searchInput.focus() + @searchInput.trigger('focus') else @el.find("[data-level~=\"#{@currentLevel}\"]").removeClass('hidden') @el.find('[data-level~="search"]').addClass('hidden') diff --git a/app/assets/javascripts/app/controllers/login.coffee b/app/assets/javascripts/app/controllers/login.coffee index 633340e12..4d6021ed5 100644 --- a/app/assets/javascripts/app/controllers/login.coffee +++ b/app/assets/javascripts/app/controllers/login.coffee @@ -58,9 +58,9 @@ class Login extends App.ControllerFullPage # set focus to username or password if !@$('[name="username"]').val() - @$('[name="username"]').focus() + @$('[name="username"]').trigger('focus') else - @$('[name="password"]').focus() + @$('[name="password"]').trigger('focus') # scroll to top @scrollTo() diff --git a/app/assets/javascripts/app/controllers/report.coffee b/app/assets/javascripts/app/controllers/report.coffee index de1fe139e..fd9390e95 100644 --- a/app/assets/javascripts/app/controllers/report.coffee +++ b/app/assets/javascripts/app/controllers/report.coffee @@ -235,7 +235,7 @@ class Download extends App.Controller constructor: (data) -> # unbind existing click binds - data.el.unbind('click .js-dataDownloadBackendSelector') + data.el.off('click .js-dataDownloadBackendSelector') super @render() diff --git a/app/assets/javascripts/app/controllers/search.coffee b/app/assets/javascripts/app/controllers/search.coffee index ac17d6930..68056952a 100644 --- a/app/assets/javascripts/app/controllers/search.coffee +++ b/app/assets/javascripts/app/controllers/search.coffee @@ -245,7 +245,7 @@ class App.Search extends App.Controller @bulkForm.show() # show/hide bulk action - localElement.delegate('input[name="bulk"], input[name="bulk_all"]', 'change', (e) => + localElement.on('change', 'input[name="bulk"], input[name="bulk_all"]', (e) => if @shouldShowBulkForm() @bulkForm.show() else @@ -254,7 +254,7 @@ class App.Search extends App.Controller ) # deselect bulk_all if one item is uncheck observ - localElement.delegate('[name="bulk"]', 'change', (e) -> + localElement.on('change', '[name="bulk"]', (e) -> bulkAll = localElement.find('[name="bulk_all"]') checkedCount = localElement.find('input[name="bulk"]:checked').length checkboxCount = localElement.find('input[name="bulk"]').length diff --git a/app/assets/javascripts/app/controllers/ticket_link_add.coffee b/app/assets/javascripts/app/controllers/ticket_link_add.coffee index 15a380ae9..1ada76262 100644 --- a/app/assets/javascripts/app/controllers/ticket_link_add.coffee +++ b/app/assets/javascripts/app/controllers/ticket_link_add.coffee @@ -45,11 +45,11 @@ class App.TicketLinkAdd extends App.ControllerModal if @ticketIdsRecentViewed @buildContentTable(content, @ticketIdsRecentViewed, 'ticket-merge-recent-tickets') - content.delegate('[name="ticket_number"]', 'focus', (e) -> + content.on('focus', '[name="ticket_number"]', (e) -> $(e.target).parents().find('[name="radio"]').prop('checked', false) ) - content.delegate('[name="radio"]', 'click', (e) -> + content.on('click', '[name="radio"]', (e) -> if $(e.target).prop('checked') ticket_id = $(e.target).val() ticket = App.Ticket.fullLocal( ticket_id ) diff --git a/app/assets/javascripts/app/controllers/ticket_overview.coffee b/app/assets/javascripts/app/controllers/ticket_overview.coffee index a5d1beada..92098fe62 100644 --- a/app/assets/javascripts/app/controllers/ticket_overview.coffee +++ b/app/assets/javascripts/app/controllers/ticket_overview.coffee @@ -706,7 +706,7 @@ class App.TicketOverview extends App.Controller else if e.keyCode is 32 # space e.preventDefault() if @activeFocus is 'overview' - @$('.table-overview table tbody tr.is-hover td.js-checkbox-field label input').first().click() + @$('.table-overview table tbody tr.is-hover td.js-checkbox-field label input').first().trigger('click') else if e.keyCode is 9 # tab e.preventDefault() if @activeFocus is 'nav' @@ -726,18 +726,18 @@ class App.TicketOverview extends App.Controller items = @$('.table-overview table tbody') current = items.find('tr.is-hover') - if !current.size() + if !current.length items.find('tr').first().addClass('is-hover') return if position is 1 next = current.next('tr') - if next.size() + if next.length current.removeClass('is-hover') next.addClass('is-hover') else prev = current.prev('tr') - if prev.size() + if prev.length current.removeClass('is-hover') prev.addClass('is-hover') @@ -751,7 +751,7 @@ class App.TicketOverview extends App.Controller items = @$('.sidebar') current = items.find('li.active') - if !current.size() + if !current.length location = items.find('li a').first().attr('href') if location @navigate location @@ -759,11 +759,11 @@ class App.TicketOverview extends App.Controller if position is 1 next = current.next('li') - if next.size() + if next.length @navigate next.find('a').attr('href') else prev = current.prev('li') - if prev.size() + if prev.length @navigate prev.find('a').attr('href') if next @@ -831,7 +831,7 @@ class Navbar extends App.Controller # if all tabs are visible # remove dropdown and dropdown button - if @dropdownItem.not('.hide').size() is 0 + if @dropdownItem.not('.hide').length is 0 @dropdown.remove() @dropdownToggle.remove() @@ -1031,7 +1031,7 @@ class Table extends App.Controller checkbox: checkbox ) table = $(table) - table.delegate('[name="bulk_all"]', 'change', (e) -> + table.on('change', '[name="bulk_all"]', (e) -> if $(e.currentTarget).prop('checked') $(e.currentTarget).closest('table').find('[name="bulk"]').prop('checked', true) else @@ -1224,7 +1224,7 @@ class Table extends App.Controller @bulkForm.show() # show/hide bulk action - localElement.delegate('input[name="bulk"], input[name="bulk_all"]', 'change', (e) => + localElement.on('change', 'input[name="bulk"], input[name="bulk_all"]', (e) => if @shouldShowBulkForm() @bulkForm.show() else @@ -1233,7 +1233,7 @@ class Table extends App.Controller ) # deselect bulk_all if one item is uncheck observ - localElement.delegate('[name="bulk"]', 'change', (e) -> + localElement.on('change', '[name="bulk"]', (e) -> bulkAll = localElement.find('[name="bulk_all"]') checkedCount = localElement.find('input[name="bulk"]:checked').length checkboxCount = localElement.find('input[name="bulk"]').length diff --git a/app/assets/javascripts/app/controllers/ticket_zoom.coffee b/app/assets/javascripts/app/controllers/ticket_zoom.coffee index 362dc38d7..4e5312175 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom.coffee @@ -359,16 +359,16 @@ class App.TicketZoom extends App.Controller article_id: undefined modifier = 'alt+ctrl+left' - $(document).bind("keydown.ticket_zoom#{@ticket_id}", modifier, (e) => + $(document).on("keydown.ticket_zoom#{@ticket_id}", modifier, (e) => @articleNavigate('up') ) modifier = 'alt+ctrl+right' - $(document).bind("keydown.ticket_zoom#{@ticket_id}", modifier, (e) => + $(document).on("keydown.ticket_zoom#{@ticket_id}", modifier, (e) => @articleNavigate('down') ) shortcutNavigationstop: => - $(document).unbind("keydown.ticket_zoom#{@ticket_id}") + $(document).off("keydown.ticket_zoom#{@ticket_id}") articleNavigate: (direction) => articleStates = [] @@ -404,13 +404,13 @@ class App.TicketZoom extends App.Controller @positionPageHeaderUpdate() # scroll is also fired on window resize, if element scroll is changed - @main.bind( + @main.on( 'scroll' @positionPageHeaderUpdate ) positionPageHeaderStop: => - @main.unbind('scroll', @positionPageHeaderUpdate) + @main.off('scroll', @positionPageHeaderUpdate) @scrollHeaderPos: undefined diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_image_view.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_image_view.coffee index 243a8d0b0..43932abff 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom/article_image_view.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_image_view.coffee @@ -14,17 +14,17 @@ class App.TicketZoomArticleImageView extends App.ControllerModal constructor: -> super @unbindAll() - $(document).bind('keydown.image_preview', 'right', (e) => + $(document).on('keydown.image_preview', 'right', (e) => nextElement = @parentElement.closest('.attachment').next('.attachment.attachment--preview') return if nextElement.length is 0 @close() - nextElement.find('img').click() + nextElement.find('img').trigger('click') ) - $(document).bind('keydown.image_preview', 'left', (e) => + $(document).on('keydown.image_preview', 'left', (e) => prevElement = @parentElement.closest('.attachment').prev('.attachment.attachment--preview') return if prevElement.length is 0 @close() - prevElement.find('img').click() + prevElement.find('img').trigger('click') ) content: -> @@ -40,4 +40,4 @@ class App.TicketZoomArticleImageView extends App.ControllerModal @unbindAll() unbindAll: -> - $(document).unbind('keydown.image_preview') + $(document).off('keydown.image_preview') diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_new.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_new.coffee index a05680034..d70d4b2a8 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom/article_new.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_new.coffee @@ -64,7 +64,7 @@ class App.TicketZoomArticleNew extends App.Controller # set focus into field if data.focus - @$("[name=\"#{data.focus}\"], [data-name=\"#{data.focus}\"]").focus().parent().find('.token-input').focus() + @$("[name=\"#{data.focus}\"], [data-name=\"#{data.focus}\"]").trigger('focus').parent().find('.token-input').trigger('focus') return # set focus at end of field @@ -422,7 +422,7 @@ class App.TicketZoomArticleNew extends App.Controller @securityOptionsShow() # add observer to change options - @$('.js-to, .js-cc').bind('change', => + @$('.js-to, .js-cc').on('change', => @updateSecurityOptions() ) @updateSecurityOptions() @@ -459,7 +459,7 @@ class App.TicketZoomArticleNew extends App.Controller propagateOpenTextarea: (event) -> event.stopPropagation() - @textarea.focus() + @textarea.trigger('focus') updateLetterCount: => return if !@maxTextLength @@ -505,7 +505,7 @@ class App.TicketZoomArticleNew extends App.Controller easing: 'easeOutQuad' complete: => $(window).on('click.ticket-zoom-textarea', @closeTextarea) - @textarea.focus() if focus + @textarea.trigger('focus') if focus @textBubble.velocity properties: diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/attribute_bar.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/attribute_bar.coffee index 0ccebd823..f2bc4ab0c 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom/attribute_bar.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom/attribute_bar.coffee @@ -96,11 +96,11 @@ class App.TicketZoomAttributeBar extends App.Controller openMacroMenu: => @buttonDropdown.addClass 'is-open' - $(document).bind 'click.buttonDropdown', @closeMacroMenu + $(document).on 'click.buttonDropdown', @closeMacroMenu closeMacroMenu: => @buttonDropdown.removeClass 'is-open' - $(document).unbind 'click.buttonDropdown' + $(document).off 'click.buttonDropdown' performTicketMacro: (e) => macroId = $(e.currentTarget).data('id') diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/form_handler_core_workflow.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/form_handler_core_workflow.coffee index 75c6768dc..6dbcbb007 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom/form_handler_core_workflow.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom/form_handler_core_workflow.coffee @@ -56,7 +56,7 @@ class App.FormHandlerCoreWorkflow if $(target).get(0).tagName == 'FORM' target = $(target).find('button[type=submit]').first() - $(target).click() + $(target).trigger('click') # checks if the controller has a running Core Workflow request @requestsRunning: (controllerForm) -> @@ -170,7 +170,7 @@ class App.FormHandlerCoreWorkflow eventToBind = event.type + '.' + event.namespace target = newElement.find("[name='" + target_name + "']") if target.length > 0 - target.bind(eventToBind, event.data, event.handler) + target.on(eventToBind, event.data, event.handler) ) ) ) diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_article_attachments.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_article_attachments.coffee index 409f8290d..728cc00fb 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_article_attachments.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_article_attachments.coffee @@ -24,7 +24,7 @@ class SidebarArticleAttachments extends App.Controller if !_.isEmpty(attachments) html += App.view('ticket_zoom/sidebar_article_attachment')(article: article, attachments: attachments) @el.html(html) - @el.delegate('.js-attachments img', 'click', (e) => + @el.on('click', '.js-attachments img', (e) => @imageView(e) ) diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_git_issue.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_git_issue.coffee index 46625cea3..5cbda7f3e 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_git_issue.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_git_issue.coffee @@ -105,7 +105,7 @@ class App.SidebarGitIssue extends App.Controller list = $(App.view('ticket_zoom/sidebar_git_issue')( issues: @issueLinkData )) - list.delegate('.js-delete', 'click', (e) => + list.on('click', '.js-delete', (e) => e.preventDefault() issueLink = $(e.currentTarget).attr 'data-issue-id' @deleteIssue(issueLink) diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_idoit.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_idoit.coffee index d2fca7b2e..8b05d7a64 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_idoit.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_idoit.coffee @@ -82,7 +82,7 @@ class SidebarIdoit extends App.Controller list = $(App.view('ticket_zoom/sidebar_idoit')( objects: objects )) - list.delegate('.js-delete', 'click', (e) => + list.on('click', '.js-delete', (e) => e.preventDefault() objectId = $(e.currentTarget).attr 'data-object-id' @delete(objectId) diff --git a/app/assets/javascripts/app/controllers/user.coffee b/app/assets/javascripts/app/controllers/user.coffee index abb83b9f3..54935948c 100644 --- a/app/assets/javascripts/app/controllers/user.coffee +++ b/app/assets/javascripts/app/controllers/user.coffee @@ -43,7 +43,7 @@ class User extends App.ControllerSubContent ) # start search - @searchInput.bind( 'keyup', (e) => + @searchInput.on( 'keyup', (e) => query = @searchInput.val().trim() return if query is @query @query = query diff --git a/app/assets/javascripts/app/controllers/widget/button_with_dropdown.coffee b/app/assets/javascripts/app/controllers/widget/button_with_dropdown.coffee index 0c1bc5e01..01a4c1039 100644 --- a/app/assets/javascripts/app/controllers/widget/button_with_dropdown.coffee +++ b/app/assets/javascripts/app/controllers/widget/button_with_dropdown.coffee @@ -28,4 +28,4 @@ class App.WidgetButtonWithDropdown extends App.Controller @preventDefaultAndStopPropagation(e) return - @accessoriesContainer.blur() + @accessoriesContainer.trigger('blur') diff --git a/app/assets/javascripts/app/controllers/widget/link/kb_answer.coffee b/app/assets/javascripts/app/controllers/widget/link/kb_answer.coffee index 2e4ffb346..be93dca6b 100644 --- a/app/assets/javascripts/app/controllers/widget/link/kb_answer.coffee +++ b/app/assets/javascripts/app/controllers/widget/link/kb_answer.coffee @@ -74,7 +74,7 @@ class App.WidgetLinkKbAnswer extends App.WidgetLink @inputField.attr('disabled', false).val('') @setInputVisible(true) - @inputField.focus() + @inputField.trigger('focus') setInputVisible: (setInputVisible) -> @searchableSelect.toggleClass('hidden', !setInputVisible) diff --git a/app/assets/javascripts/app/controllers/widget/online_notification.coffee b/app/assets/javascripts/app/controllers/widget/online_notification.coffee index d41337d8d..eeacf9f45 100644 --- a/app/assets/javascripts/app/controllers/widget/online_notification.coffee +++ b/app/assets/javascripts/app/controllers/widget/online_notification.coffee @@ -81,25 +81,25 @@ class App.OnlineNotificationWidget extends App.Controller @nudge(e, 1) return else if e.keyCode is 13 # enter - @$('.js-item').filter('.is-hover').find('.js-locationVerify').click() + @$('.js-item').filter('.is-hover').find('.js-locationVerify').trigger('click') nudge: (e, position) -> # get current items = @$('.js-item') current = items.filter('.is-hover') - if !current.size() + if !current.length items.first().addClass('is-hover') return if position is 1 next = current.next('.js-item') - if next.size() + if next.length current.removeClass('is-hover') next.addClass('is-hover') else prev = current.prev('.js-item') - if prev.size() + if prev.length current.removeClass('is-hover') prev.addClass('is-hover') diff --git a/app/assets/javascripts/app/controllers/widget/tag.coffee b/app/assets/javascripts/app/controllers/widget/tag.coffee index 128d9e37c..38d1f39d6 100644 --- a/app/assets/javascripts/app/controllers/widget/tag.coffee +++ b/app/assets/javascripts/app/controllers/widget/tag.coffee @@ -68,7 +68,7 @@ class App.WidgetTag extends App.Controller showInput: (e) => e.preventDefault() @newTagLabel.addClass('hide') - @newTagInput.removeClass('hide').focus() + @newTagInput.removeClass('hide').trigger('focus') @newTagInput.trigger(jQuery.Event('keydown')) @editMode = true diff --git a/app/assets/javascripts/app/controllers/widget/ticket_bulk_form.coffee b/app/assets/javascripts/app/controllers/widget/ticket_bulk_form.coffee index c46dc9d5f..04eba61f0 100644 --- a/app/assets/javascripts/app/controllers/widget/ticket_bulk_form.coffee +++ b/app/assets/javascripts/app/controllers/widget/ticket_bulk_form.coffee @@ -107,7 +107,7 @@ class App.TicketBulkForm extends App.Controller @makeSpaceForTableRows() # need a delay because of the click event - setTimeout ( => @$('.textarea.form-group textarea').focus() ), 0 + setTimeout ( => @$('.textarea.form-group textarea').trigger('focus') ), 0 reset: => @cancel() diff --git a/app/assets/javascripts/app/lib/app_init/track.coffee b/app/assets/javascripts/app/lib/app_init/track.coffee index e4434e9a9..b4cd19bd9 100644 --- a/app/assets/javascripts/app/lib/app_init/track.coffee +++ b/app/assets/javascripts/app/lib/app_init/track.coffee @@ -46,7 +46,7 @@ class _trackSingleton # log clicks if @logClick - $(document).bind( + $(document).on( 'click' (e) => w = window.screen.width @@ -70,7 +70,7 @@ class _trackSingleton # log ajax calls if @logAjax - $(document).bind( 'ajaxComplete', ( e, request, settings ) => + $(document).on( 'ajaxComplete', ( e, request, settings ) => # do not log ui requests if settings.url && settings.url.substr(settings.url.length-3,3) isnt '/ui' @@ -105,7 +105,7 @@ class _trackSingleton ) ) - $(window).bind( + $(window).on( 'beforeunload' => @log('good bye', 'notice', {}) diff --git a/app/assets/javascripts/app/lib/app_post/_object_organization_autocompletion.coffee b/app/assets/javascripts/app/lib/app_post/_object_organization_autocompletion.coffee index e7d424c52..8fa959087 100644 --- a/app/assets/javascripts/app/lib/app_post/_object_organization_autocompletion.coffee +++ b/app/assets/javascripts/app/lib/app_post/_object_organization_autocompletion.coffee @@ -76,7 +76,7 @@ class App.ObjectOrganizationAutocompletion extends App.Controller @open() focusInput: => - @objectSelect.focus() if not @formControl.hasClass('focus') + @objectSelect.trigger('focus') if not @formControl.hasClass('focus') onBlur: => selectObject = @objectSelect.val() @@ -141,7 +141,7 @@ class App.ObjectOrganizationAutocompletion extends App.Controller switch which when 'last' token = @$('.token').last() - return if not token.size() + return if not token.length else token = which diff --git a/app/assets/javascripts/app/lib/app_post/ajax.coffee b/app/assets/javascripts/app/lib/app_post/ajax.coffee index db117d066..61a5780ca 100644 --- a/app/assets/javascripts/app/lib/app_post/ajax.coffee +++ b/app/assets/javascripts/app/lib/app_post/ajax.coffee @@ -67,9 +67,9 @@ class _ajaxSingleton @runNextInQueue() # bindings - $(document).bind('ajaxSend', => + $(document).on('ajaxSend', => @_show_spinner() - ).bind('ajaxComplete', (request, xhr, settings) => + ).on('ajaxComplete', (request, xhr, settings) => @_hide_spinner() # remeber XSRF-TOKEN for later @@ -81,7 +81,7 @@ class _ajaxSingleton ) # show error messages - $(document).bind('ajaxError', (e, jqxhr, settings, exception) -> + $(document).on('ajaxError', (e, jqxhr, settings, exception) -> if settings.failResponseNoTrigger return diff --git a/app/assets/javascripts/app/lib/app_post/clipboard.coffee b/app/assets/javascripts/app/lib/app_post/clipboard.coffee index 004c37c4e..3d97b78b4 100644 --- a/app/assets/javascripts/app/lib/app_post/clipboard.coffee +++ b/app/assets/javascripts/app/lib/app_post/clipboard.coffee @@ -10,7 +10,7 @@ class App.ClipBoard if _instance == undefined _instance ?= new _Singleton _instance.manuallyUpdateSelection(type) - + @getSelected: (type) -> if _instance == undefined _instance ?= new _Singleton @@ -56,10 +56,10 @@ class _Singleton bind: (el) -> # check selection on mouse up - $(el).bind('mouseup', => + $(el).on('mouseup', => @_updateSelection() ) - $(el).bind('keyup', (e) => + $(el).on('keyup', (e) => # check selection on sonder key if e.keyCode == 91 @@ -90,7 +90,7 @@ class _Singleton sel = document.selection.createRange() text = sel.text if type is 'text' - return $.trim(text.toString()) if text + return (text.toString()).trim() if text return '' if sel && sel.rangeCount @@ -98,7 +98,7 @@ class _Singleton for i in [1..sel.rangeCount] container.appendChild(sel.getRangeAt(i-1).cloneContents()) html = container.innerHTML - + if type != 'sel' html else diff --git a/app/assets/javascripts/app/lib/app_post/column_select.coffee b/app/assets/javascripts/app/lib/app_post/column_select.coffee index 3cd4e1a2a..9970e3d01 100644 --- a/app/assets/javascripts/app/lib/app_post/column_select.coffee +++ b/app/assets/javascripts/app/lib/app_post/column_select.coffee @@ -100,7 +100,7 @@ class App.ColumnSelect extends Spine.Controller @placeholder.addClass('is-hidden') - if @search.val() and @poolOptions.not('.is-filtered').not('.is-hidden').size() is 0 + if @search.val() and @poolOptions.not('.is-filtered').not('.is-hidden').length is 0 @clear() onRemove: (event) -> diff --git a/app/assets/javascripts/app/lib/app_post/icon_picker.coffee b/app/assets/javascripts/app/lib/app_post/icon_picker.coffee index 20791ff84..be50c88b4 100644 --- a/app/assets/javascripts/app/lib/app_post/icon_picker.coffee +++ b/app/assets/javascripts/app/lib/app_post/icon_picker.coffee @@ -81,10 +81,10 @@ class App.IconPicker extends Spine.Controller # propergate focus to our visible input onShadowFocus: -> - @input.focus() + @input.trigger('focus') onPickerOpen: -> - @filter.focus() + @filter.trigger('focus') @isOpen = true onPickerClose: -> diff --git a/app/assets/javascripts/app/lib/app_post/popover_provider/_single_object_popover_provider.coffee b/app/assets/javascripts/app/lib/app_post/popover_provider/_single_object_popover_provider.coffee index b8df9112d..ca00166b3 100644 --- a/app/assets/javascripts/app/lib/app_post/popover_provider/_single_object_popover_provider.coffee +++ b/app/assets/javascripts/app/lib/app_post/popover_provider/_single_object_popover_provider.coffee @@ -8,7 +8,7 @@ class App.SingleObjectPopoverProvider extends App.PopoverProvider "div.#{@cssClass()}, span.#{@cssClass()}" bind: -> - @params.parentController.$(@fullCssSelector()).bind('click', (e) => + @params.parentController.$(@fullCssSelector()).on('click', (e) => id = @objectIdFor(e.target) return if !id object = @constructor.klass.find(id) diff --git a/app/assets/javascripts/app/lib/app_post/searchable_select.coffee b/app/assets/javascripts/app/lib/app_post/searchable_select.coffee index d4d54fa92..9307739d9 100644 --- a/app/assets/javascripts/app/lib/app_post/searchable_select.coffee +++ b/app/assets/javascripts/app/lib/app_post/searchable_select.coffee @@ -211,7 +211,7 @@ class App.SearchableSelect extends Spine.Controller currentPosition += direction return if currentPosition < 0 - return if currentPosition > visibleOptions.size() - 1 + return if currentPosition > visibleOptions.length - 1 @unhighlightCurrentItem() @currentItem = visibleOptions.eq(currentPosition) @@ -419,7 +419,7 @@ class App.SearchableSelect extends Spine.Controller # propergate focus to our visible input onShadowFocus: -> - @input.focus() + @input.trigger('focus') onShadowChange: -> value = @shadowInput.val() @@ -446,7 +446,7 @@ class App.SearchableSelect extends Spine.Controller switch which when 'last' token = @$('.token').last() - return if not token.size() + return if not token.length else token = which diff --git a/app/assets/javascripts/app/lib/app_post/utils.coffee b/app/assets/javascripts/app/lib/app_post/utils.coffee index 04a7fbac4..a5b953dd5 100644 --- a/app/assets/javascripts/app/lib/app_post/utils.coffee +++ b/app/assets/javascripts/app/lib/app_post/utils.coffee @@ -176,7 +176,9 @@ class App.Utils # textCleand = App.Utils.textCleanup(rawText) @textCleanup: (ascii) -> - $.trim( ascii ) + return '' if !ascii + + ascii.trim() .replace(/(\r\n|\n\r)/g, "\n") # cleanup .replace(/\r/g, "\n") # cleanup .replace(/[ ]\n/g, "\n") # remove tailing spaces @@ -274,7 +276,7 @@ class App.Utils @quote: (ascii, max = 82) -> ascii = @textCleanup(ascii) ascii = @wrap(ascii, max) - $.trim(ascii) + ascii.trim() .replace /^(.*)$/mg, (match) -> if match '> ' + match @@ -1008,7 +1010,7 @@ class App.Utils valueTmp = value.toString().toLowerCase() byNames.push valueTmp byNamesWithValue[valueTmp] = [i, value] - + # sort() by default doesn't compare non-ascii characters such as ['é', 'a', 'ú', 'c'] # hence using localecompare in sorting for translated strings byNames = byNames.sort((a, b) -> a.localeCompare(b)) diff --git a/app/assets/javascripts/app/lib/app_post/websocket.coffee b/app/assets/javascripts/app/lib/app_post/websocket.coffee index dabd316d1..87e72c37a 100644 --- a/app/assets/javascripts/app/lib/app_post/websocket.coffee +++ b/app/assets/javascripts/app/lib/app_post/websocket.coffee @@ -104,7 +104,7 @@ class _webSocketSingleton extends App.Controller @connect() # send ping after visibilitychange to check if connection is open again after wakeup - $(document).bind('visibilitychange', => + $(document).on('visibilitychange', => @log 'debug', 'visibilitychange' return if document.hidden return if !@connectionEstablished diff --git a/app/assets/javascripts/app/lib/base/bootstrap-tokenfield.js b/app/assets/javascripts/app/lib/base/bootstrap-tokenfield.js index 73d95b996..3549a701c 100644 --- a/app/assets/javascripts/app/lib/base/bootstrap-tokenfield.js +++ b/app/assets/javascripts/app/lib/base/bootstrap-tokenfield.js @@ -194,7 +194,7 @@ , defaults = { minLength: this.options.showAutocompleteOnFocus ? 0 : null } - , args = $.isArray( typeaheadOptions ) ? typeaheadOptions : [typeaheadOptions, typeaheadOptions] + , args = Array.isArray( typeaheadOptions ) ? typeaheadOptions : [typeaheadOptions, typeaheadOptions] args[0] = $.extend( {}, defaults, args[0] ) @@ -222,8 +222,8 @@ } // Normalize label and value - attrs.value = $.trim(attrs.value.toString()); - attrs.label = attrs.label && attrs.label.length ? $.trim(attrs.label) : attrs.value + attrs.value = (attrs.value.toString()).trim(); + attrs.label = attrs.label && attrs.label.length ? (attrs.label).trim() : attrs.value // Bail out if has no value or label, or label is too short if (!attrs.value.length || !attrs.label.length || attrs.label.length <= this.options.minLength) return @@ -310,11 +310,11 @@ } , updateTokensOnEditDiscard: function(triggerChange) { - // if the field is being edited, update original field's value + // if the field is being edited, update original field's value if(this.$input.data('edit') && triggerChange) { // Trigger change event on the original field this.$element.val( this.getTokensList() ).trigger( $.Event('change', { initiator: 'tokenfield' }) ) - } + } } , setTokens: function (tokens, add, triggerChange) { @@ -382,7 +382,7 @@ , getInput: function() { return this.$input.val() } - + , setInput: function (val) { if (this.$input.hasClass('tt-input')) { // Typeahead acts weird when simply setting input value to empty, @@ -897,7 +897,7 @@ else { //temporary reset width to minimal value to get proper results this.$input.width(this.options.minWidth); - + var w = (this.textDirection === 'rtl') ? this.$input.offset().left + this.$input.outerWidth() - this.$wrapper.offset().left - parseInt(this.$wrapper.css('padding-left'), 10) - inputPadding - 1 : this.$wrapper.offset().left + this.$wrapper.width() + parseInt(this.$wrapper.css('padding-left'), 10) - this.$input.offset().left - inputPadding; diff --git a/app/assets/javascripts/app/lib/base/cropper.js b/app/assets/javascripts/app/lib/base/cropper.js index 30b8e2f61..ac1593482 100644 --- a/app/assets/javascripts/app/lib/base/cropper.js +++ b/app/assets/javascripts/app/lib/base/cropper.js @@ -77,8 +77,13 @@ var ACTION_ZOOM = 'zoom'; var ACTION_NONE = 'none'; + // Function check + function _isFunction(obj){ + return ((typeof obj) === 'function') + } + // Supports - var SUPPORT_CANVAS = $.isFunction($('')[0].getContext); + var SUPPORT_CANVAS = _isFunction($('')[0].getContext); // Maths var sqrt = Math.sqrt; @@ -485,7 +490,7 @@ // Clear `cropBox` is necessary when replace this.cropBox = null; - this.unbind(); + this.off(); this.resetPreview(); this.$preview = null; @@ -977,23 +982,23 @@ var $this = this.$element; var $cropper = this.$cropper; - if ($.isFunction(options.cropstart)) { + if (_isFunction(options.cropstart)) { $this.on(EVENT_CROP_START, options.cropstart); } - if ($.isFunction(options.cropmove)) { + if (_isFunction(options.cropmove)) { $this.on(EVENT_CROP_MOVE, options.cropmove); } - if ($.isFunction(options.cropend)) { + if (_isFunction(options.cropend)) { $this.on(EVENT_CROP_END, options.cropend); } - if ($.isFunction(options.crop)) { + if (_isFunction(options.crop)) { $this.on(EVENT_CROP, options.crop); } - if ($.isFunction(options.zoom)) { + if (_isFunction(options.zoom)) { $this.on(EVENT_ZOOM, options.zoom); } @@ -1021,23 +1026,23 @@ var $this = this.$element; var $cropper = this.$cropper; - if ($.isFunction(options.cropstart)) { + if (_isFunction(options.cropstart)) { $this.off(EVENT_CROP_START, options.cropstart); } - if ($.isFunction(options.cropmove)) { + if (_isFunction(options.cropmove)) { $this.off(EVENT_CROP_MOVE, options.cropmove); } - if ($.isFunction(options.cropend)) { + if (_isFunction(options.cropend)) { $this.off(EVENT_CROP_END, options.cropend); } - if ($.isFunction(options.crop)) { + if (_isFunction(options.crop)) { $this.off(EVENT_CROP, options.crop); } - if ($.isFunction(options.zoom)) { + if (_isFunction(options.zoom)) { $this.off(EVENT_ZOOM, options.zoom); } @@ -1947,7 +1952,7 @@ var cropBoxData = {}; var ratio; - if ($.isFunction(data)) { + if (_isFunction(data)) { data = data.call(this.$element); } @@ -2030,7 +2035,7 @@ var canvas = this.canvas; var aspectRatio = canvas.aspectRatio; - if ($.isFunction(data)) { + if (_isFunction(data)) { data = data.call(this.$element); } @@ -2087,7 +2092,7 @@ var widthChanged; var heightChanged; - if ($.isFunction(data)) { + if (_isFunction(data)) { data = data.call(this.$element); } @@ -2443,7 +2448,7 @@ $this.data(NAMESPACE, (data = new Cropper(this, options))); } - if (typeof options === 'string' && $.isFunction(fn = data[options])) { + if (typeof options === 'string' && _isFunction(fn = data[options])) { result = fn.apply(data, args); } }); diff --git a/app/assets/javascripts/app/lib/base/expanding.js b/app/assets/javascripts/app/lib/base/expanding.js index e2efb50cd..70a39bb52 100644 --- a/app/assets/javascripts/app/lib/base/expanding.js +++ b/app/assets/javascripts/app/lib/base/expanding.js @@ -29,7 +29,7 @@ this.attach(); this.update(); - if (opts.update) $textarea.bind("update.expanding", opts.update); + if (opts.update) $textarea.on("update.expanding", opts.update); }; // Stores (active) `Expanding` instances @@ -74,7 +74,7 @@ var events = 'input.expanding change.expanding', _this = this; if(!inputSupported) events += ' keyup.expanding'; - this.$textarea.bind(events, function() { _this.update(); }); + this.$textarea.on(events, function() { _this.update(); }); }, // Updates the clone with the textarea value @@ -96,7 +96,7 @@ delete this._oldTextareaStyles; var index = $.inArray(this, Expanding._registry); if (index > -1) Expanding._registry.splice(index, 1); - this.$textarea.unbind( + this.$textarea.off( 'input.expanding change.expanding keyup.expanding update.expanding'); }, diff --git a/app/assets/javascripts/app/lib/base/jquery.enableObjectResizingShim.js b/app/assets/javascripts/app/lib/base/jquery.enableObjectResizingShim.js index 9ac886e1e..60a639b95 100644 --- a/app/assets/javascripts/app/lib/base/jquery.enableObjectResizingShim.js +++ b/app/assets/javascripts/app/lib/base/jquery.enableObjectResizingShim.js @@ -104,7 +104,7 @@ document.getSelection().addRange(range) } - elem.focus() + elem.trigger('focus') break default: diff --git a/app/assets/javascripts/app/lib/base/jquery.fineuploader-3.0.js b/app/assets/javascripts/app/lib/base/jquery.fineuploader-3.0.js index 5a5c70ece..767a12794 100644 --- a/app/assets/javascripts/app/lib/base/jquery.fineuploader-3.0.js +++ b/app/assets/javascripts/app/lib/base/jquery.fineuploader-3.0.js @@ -2076,7 +2076,7 @@ qq.extend(qq.UploadHandlerXhr.prototype, { xformed[prop] = {}; transformOptions(val, xformed[prop]); } - else if ($.isArray(val)) { + else if (Array.isArray(val)) { arrayVals = []; $.each(val, function(idx, arrayVal) { if (arrayVal instanceof $) { diff --git a/app/assets/javascripts/app/lib/base/jquery.noty.js b/app/assets/javascripts/app/lib/base/jquery.noty.js index 0c00f422e..fe647231a 100644 --- a/app/assets/javascripts/app/lib/base/jquery.noty.js +++ b/app/assets/javascripts/app/lib/base/jquery.noty.js @@ -86,7 +86,7 @@ .attr('title', button.title) .appendTo(self.$bar.find('.noty_buttons')) .on('click', function(event) { - if($.isFunction(button.onClick)) { + if((typeof button.onClick) === 'function') { button.onClick.call($button, self, event); } }); diff --git a/app/assets/javascripts/app/lib/base/jquery.textmodule.js b/app/assets/javascripts/app/lib/base/jquery.textmodule.js index 45fcd955a..d158cddd2 100644 --- a/app/assets/javascripts/app/lib/base/jquery.textmodule.js +++ b/app/assets/javascripts/app/lib/base/jquery.textmodule.js @@ -102,10 +102,10 @@ var active = this.$widget.find('.dropdown-menu li.is-active') active.removeClass('is-active') - if (e.keyCode == 38 && active.prev().size()) { + if (e.keyCode == 38 && active.prev().length) { active = active.prev() } - else if (e.keyCode == 40 && active.next().size()) { + else if (e.keyCode == 40 && active.next().length) { active = active.next() } diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-datepicker.js b/app/assets/javascripts/app/lib/bootstrap/bootstrap-datepicker.js index c188d8560..ae73bf635 100755 --- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-datepicker.js +++ b/app/assets/javascripts/app/lib/bootstrap/bootstrap-datepicker.js @@ -84,7 +84,7 @@ replace: function(new_array){ if (!new_array) return; - if (!$.isArray(new_array)) + if (!Array.isArray(new_array)) new_array = [new_array]; this.clear(); this.push.apply(this, new_array); @@ -266,21 +266,21 @@ } o.daysOfWeekDisabled = o.daysOfWeekDisabled||[]; - if (!$.isArray(o.daysOfWeekDisabled)) + if (!Array.isArray(o.daysOfWeekDisabled)) o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/); o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function(d){ return parseInt(d, 10); }); o.daysOfWeekHighlighted = o.daysOfWeekHighlighted||[]; - if (!$.isArray(o.daysOfWeekHighlighted)) + if (!Array.isArray(o.daysOfWeekHighlighted)) o.daysOfWeekHighlighted = o.daysOfWeekHighlighted.split(/[,\s]*/); o.daysOfWeekHighlighted = $.map(o.daysOfWeekHighlighted, function(d){ return parseInt(d, 10); }); o.datesDisabled = o.datesDisabled||[]; - if (!$.isArray(o.datesDisabled)) { + if (!Array.isArray(o.datesDisabled)) { var datesDisabled = []; datesDisabled.push(DPGlobal.parseDate(o.datesDisabled, format, o.language)); o.datesDisabled = datesDisabled; @@ -494,7 +494,7 @@ this._attachSecondaryEvents(); this._trigger('show'); if ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) { - $(this.element).blur(); + $(this.element).trigger('blur'); } return this; }, @@ -609,7 +609,7 @@ } }, setDates: function(){ - var args = $.isArray(arguments[0]) ? arguments[0] : arguments; + var args = Array.isArray(arguments[0]) ? arguments[0] : arguments; this.update.apply(this, args); this._trigger('changeDate'); this.setValue(); @@ -617,7 +617,7 @@ }, setUTCDates: function(){ - var args = $.isArray(arguments[0]) ? arguments[0] : arguments; + var args = Array.isArray(arguments[0]) ? arguments[0] : arguments; this.update.apply(this, $.map(args, this._utc_to_local)); this._trigger('changeDate'); this.setValue(); @@ -785,7 +785,7 @@ _allow_update: true, rerender: function(){ this.fill(); - this.element.change(); + this.element.trigger('change'); return this; }, update: function(){ @@ -848,7 +848,7 @@ this._trigger('clearDate'); this.fill(); - this.element.change(); + this.element.trigger('change'); return this; }, @@ -1017,7 +1017,7 @@ tooltip = before.tooltip; } - clsName = $.unique(clsName); + clsName = $.uniqueSort(clsName); html.push(''+prevMonth.getUTCDate() + ''); tooltip = null; if (prevMonth.getUTCDay() === this.o.weekEnd){ @@ -1295,7 +1295,7 @@ element = this.element.find('input'); } if (element){ - element.change(); + element.trigger('change'); } if (this.o.autoclose && (!which || which === 'date')){ this.hide(); @@ -1487,7 +1487,7 @@ element = this.element.find('input'); } if (element){ - element.change(); + element.trigger('change'); } } }, @@ -1968,4 +1968,4 @@ datepickerPlugin.call($('[data-provide="datepicker-inline"]')); }); -})); \ No newline at end of file +})); diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-timepicker.js b/app/assets/javascripts/app/lib/bootstrap/bootstrap-timepicker.js index 828e7a228..79aa5a441 100644 --- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-timepicker.js +++ b/app/assets/javascripts/app/lib/bootstrap/bootstrap-timepicker.js @@ -1008,7 +1008,7 @@ }, updateElement: function() { - this.$element.val(this.getTime()).change(); + this.$element.val(this.getTime()).trigger('change'); }, updateFromElementVal: function(silent) { diff --git a/app/assets/javascripts/app/lib/core/jquery-2.2.1.js b/app/assets/javascripts/app/lib/core/jquery-3.6.0.js similarity index 66% rename from app/assets/javascripts/app/lib/core/jquery-2.2.1.js rename to app/assets/javascripts/app/lib/core/jquery-3.6.0.js index ac74e6a73..fc6c299b7 100644 --- a/app/assets/javascripts/app/lib/core/jquery-2.2.1.js +++ b/app/assets/javascripts/app/lib/core/jquery-3.6.0.js @@ -1,22 +1,22 @@ /*! - * jQuery JavaScript Library v2.2.1 - * http://jquery.com/ + * jQuery JavaScript Library v3.6.0 + * https://jquery.com/ * * Includes Sizzle.js - * http://sizzlejs.com/ + * https://sizzlejs.com/ * - * Copyright jQuery Foundation and other contributors + * Copyright OpenJS Foundation and other contributors * Released under the MIT license - * http://jquery.org/license + * https://jquery.org/license * - * Date: 2016-02-22T19:11Z + * Date: 2021-03-02T17:08Z */ +( function( global, factory ) { -(function( global, factory ) { + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { - // if electron is used, go back to non CommonJS - //if ( typeof module === "object" && typeof module.exports === "object" ) { - if ( typeof module === "object" && typeof module.exports === "object" && !(window.process && window.process.version && window.process.versions.electron)) { // For CommonJS and CommonJS-like environments where a proper `window` // is present, execute the factory and get jQuery. // For environments that do not have a `window` with a `document` @@ -37,20 +37,26 @@ } // Pass this if window is not defined yet -}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; -// Support: Firefox 18+ -// Can't be in strict mode, several libs including ASP.NET trace -// the stack via arguments.caller.callee and Firefox dies if -// you try to trace through "use strict" call chains. (#13335) -//"use strict"; var arr = []; -var document = window.document; +var getProto = Object.getPrototypeOf; var slice = arr.slice; -var concat = arr.concat; +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + var push = arr.push; @@ -62,12 +68,90 @@ var toString = class2type.toString; var hasOwn = class2type.hasOwnProperty; +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + var support = {}; +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + var - version = "2.2.1", + version = "3.6.0", // Define a local copy of jQuery jQuery = function( selector, context ) { @@ -75,19 +159,6 @@ var // The jQuery object is actually just the init constructor 'enhanced' // Need init if jQuery is called (just allow error to be thrown if not included) return new jQuery.fn.init( selector, context ); - }, - - // Support: Android<4.1 - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); }; jQuery.fn = jQuery.prototype = { @@ -97,9 +168,6 @@ jQuery.fn = jQuery.prototype = { constructor: jQuery, - // Start with an empty selector - selector: "", - // The default length of a jQuery object is 0 length: 0, @@ -110,13 +178,14 @@ jQuery.fn = jQuery.prototype = { // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { - return num != null ? - // Return just the one element from the set - ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } - // Return all the elements in a clean array - slice.call( this ); + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; }, // Take an array of elements and push it onto the stack @@ -128,7 +197,6 @@ jQuery.fn = jQuery.prototype = { // Add the old object onto the stack (as a reference) ret.prevObject = this; - ret.context = this.context; // Return the newly-formed element set return ret; @@ -157,6 +225,18 @@ jQuery.fn = jQuery.prototype = { return this.eq( -1 ); }, + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + eq: function( i ) { var len = this.length, j = +i + ( i < 0 ? len : 0 ); @@ -191,7 +271,7 @@ jQuery.extend = jQuery.fn.extend = function() { } // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + if ( typeof target !== "object" && !isFunction( target ) ) { target = {}; } @@ -208,25 +288,28 @@ jQuery.extend = jQuery.fn.extend = function() { // Extend the base object for ( name in options ) { - src = target[ name ]; copy = options[ name ]; + // Prevent Object.prototype pollution // Prevent never-ending loop - if ( target === copy ) { + if ( name === "__proto__" || target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = jQuery.isArray( copy ) ) ) ) { - - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray( src ) ? src : []; + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; } else { - clone = src && jQuery.isPlainObject( src ) ? src : {}; + clone = src; } + copyIsArray = false; // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); @@ -257,100 +340,40 @@ jQuery.extend( { noop: function() {}, - isFunction: function( obj ) { - return jQuery.type( obj ) === "function"; - }, - - isArray: Array.isArray, - - isWindow: function( obj ) { - return obj != null && obj === obj.window; - }, - - isNumeric: function( obj ) { - - // parseFloat NaNs numeric-cast false positives (null|true|false|"") - // ...but misinterprets leading-number strings, particularly hex literals ("0x...") - // subtraction forces infinities to NaN - // adding 1 corrects loss of precision from parseFloat (#15100) - var realStringObj = obj && obj.toString(); - return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0; - }, - isPlainObject: function( obj ) { + var proto, Ctor; - // Not plain objects: - // - Any object or value whose internal [[Class]] property is not "[object Object]" - // - DOM nodes - // - window - if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { return false; } - if ( obj.constructor && - !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) { - return false; + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; } - // If the function hasn't returned already, we're confident that - // |obj| is a plain object, created by {} or constructed with new Object - return true; + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; }, isEmptyObject: function( obj ) { var name; + for ( name in obj ) { return false; } return true; }, - type: function( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android<4.0, iOS<6 (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; - }, - - // Evaluates a script in a global context - globalEval: function( code ) { - var script, - indirect = eval; - - code = jQuery.trim( code ); - - if ( code ) { - - // If the code includes a valid, prologue position - // strict mode pragma, execute code by injecting a - // script tag into the document. - if ( code.indexOf( "use strict" ) === 1 ) { - script = document.createElement( "script" ); - script.text = code; - document.head.appendChild( script ).parentNode.removeChild( script ); - } else { - - // Otherwise, avoid the DOM node creation, insertion - // and removal by using an indirect global eval - - indirect( code ); - } - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Support: IE9-11+ - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); }, each: function( obj, callback ) { @@ -374,13 +397,6 @@ jQuery.extend( { return obj; }, - // Support: Android<4.1 - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - // results is for internal usage only makeArray: function( arr, results ) { var ret = results || []; @@ -389,7 +405,7 @@ jQuery.extend( { if ( isArrayLike( Object( arr ) ) ) { jQuery.merge( ret, typeof arr === "string" ? - [ arr ] : arr + [ arr ] : arr ); } else { push.call( ret, arr ); @@ -403,6 +419,8 @@ jQuery.extend( { return arr == null ? -1 : indexOf.call( arr, elem, i ); }, + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit merge: function( first, second ) { var len = +second.length, j = 0, @@ -465,74 +483,37 @@ jQuery.extend( { } // Flatten any nested arrays - return concat.apply( [], ret ); + return flat( ret ); }, // A global GUID counter for objects guid: 1, - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - now: Date.now, - // jQuery.support is not used in Core but other projects attach their // properties to it so it needs to exist. support: support } ); -// JSHint would error on this code due to the Symbol not being defined in ES5. -// Defining this global in .jshintrc would create a danger of using the global -// unguarded in another place, it seems safer to just disable JSHint for these -// three lines. -/* jshint ignore: start */ if ( typeof Symbol === "function" ) { jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; } -/* jshint ignore: end */ // Populate the class2type map jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); function isArrayLike( obj ) { - // Support: iOS 8.2 (not reproducible in simulator) + // Support: real iOS 8.2 only (not reproducible in simulator) // `in` check used to prevent JIT error (gh-2145) // hasOwn isn't used here due to false negatives // regarding Nodelist length in IE var length = !!obj && "length" in obj && obj.length, - type = jQuery.type( obj ); + type = toType( obj ); - if ( type === "function" || jQuery.isWindow( obj ) ) { + if ( isFunction( obj ) || isWindow( obj ) ) { return false; } @@ -541,17 +522,16 @@ function isArrayLike( obj ) { } var Sizzle = /*! - * Sizzle CSS Selector Engine v2.2.1 - * http://sizzlejs.com/ + * Sizzle CSS Selector Engine v2.3.6 + * https://sizzlejs.com/ * - * Copyright jQuery Foundation and other contributors + * Copyright JS Foundation and other contributors * Released under the MIT license - * http://jquery.org/license + * https://js.foundation/ * - * Date: 2015-10-17 + * Date: 2021-02-16 */ -(function( window ) { - +( function( window ) { var i, support, Expr, @@ -582,6 +562,7 @@ var i, classCache = createCache(), tokenCache = createCache(), compilerCache = createCache(), + nonnativeSelectorCache = createCache(), sortOrder = function( a, b ) { if ( a === b ) { hasDuplicate = true; @@ -589,65 +570,72 @@ var i, return 0; }, - // General-purpose constants - MAX_NEGATIVE = 1 << 31, - // Instance methods - hasOwn = ({}).hasOwnProperty, + hasOwn = ( {} ).hasOwnProperty, arr = [], pop = arr.pop, - push_native = arr.push, + pushNative = arr.push, push = arr.push, slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native - // http://jsperf.com/thor-indexof-vs-for/5 + // https://jsperf.com/thor-indexof-vs-for/5 indexOf = function( list, elem ) { var i = 0, len = list.length; for ( ; i < len; i++ ) { - if ( list[i] === elem ) { + if ( list[ i ] === elem ) { return i; } } return -1; }, - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", // Regular expressions // http://www.w3.org/TR/css3-selectors/#whitespace whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: // 1. quoted (capture 3; capture 4 or capture 5) "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) ".*" + ")\\)|)", // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), rpseudo = new RegExp( pseudos ), ridentifier = new RegExp( "^" + identifier + "$" ), @@ -658,16 +646,19 @@ var i, "TAG": new RegExp( "^(" + identifier + "|[*])" ), "ATTR": new RegExp( "^" + attributes ), "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) }, + rhtml = /HTML$/i, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, @@ -677,47 +668,79 @@ var i, rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, rsibling = /[+~]/, - rescape = /'|\\/g, - // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair high < 0 ? - // BMP codepoint String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); }, + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + // Used for iframes // See setDocument() // Removing the function wrapper causes a "Permission Denied" // error in IE unloadHandler = function() { setDocument(); - }; + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); // Optimize for push.apply( _, NodeList ) try { push.apply( - (arr = slice.call( preferredDoc.childNodes )), + ( arr = slice.call( preferredDoc.childNodes ) ), preferredDoc.childNodes ); + // Support: Android<4.0 // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions arr[ preferredDoc.childNodes.length ].nodeType; } catch ( e ) { push = { apply: arr.length ? // Leverage slice if possible function( target, els ) { - push_native.apply( target, slice.call(els) ); + pushNative.apply( target, slice.call( els ) ); } : // Support: IE<9 @@ -725,15 +748,16 @@ try { function( target, els ) { var j = target.length, i = 0; + // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} + while ( ( target[ j++ ] = els[ i++ ] ) ) {} target.length = j - 1; } }; } function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, nidselect, match, groups, newSelector, + var m, i, elem, nid, match, groups, newSelector, newContext = context && context.ownerDocument, // nodeType defaults to 9, since context defaults to document @@ -750,24 +774,21 @@ function Sizzle( selector, context, results, seed ) { // Try to shortcut find operations (as opposed to filters) in HTML documents if ( !seed ) { - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } + setDocument( context ); context = context || document; if ( documentIsHTML ) { // If the selector is sufficiently simple, try using a "get*By*" DOM method // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { // ID selector - if ( (m = match[1]) ) { + if ( ( m = match[ 1 ] ) ) { // Document context if ( nodeType === 9 ) { - if ( (elem = context.getElementById( m )) ) { + if ( ( elem = context.getElementById( m ) ) ) { // Support: IE, Opera, Webkit // TODO: identify versions @@ -786,7 +807,7 @@ function Sizzle( selector, context, results, seed ) { // Support: IE, Opera, Webkit // TODO: identify versions // getElementById can match elements by name instead of ID - if ( newContext && (elem = newContext.getElementById( m )) && + if ( newContext && ( elem = newContext.getElementById( m ) ) && contains( context, elem ) && elem.id === m ) { @@ -796,12 +817,12 @@ function Sizzle( selector, context, results, seed ) { } // Type selector - } else if ( match[2] ) { + } else if ( match[ 2 ] ) { push.apply( results, context.getElementsByTagName( selector ) ); return results; // Class selector - } else if ( (m = match[3]) && support.getElementsByClassName && + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && context.getElementsByClassName ) { push.apply( results, context.getElementsByClassName( m ) ); @@ -811,51 +832,62 @@ function Sizzle( selector, context, results, seed ) { // Take advantage of querySelectorAll if ( support.qsa && - !compilerCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && - if ( nodeType !== 1 ) { - newContext = context; - newSelector = selector; - - // qSA looks outside Element context, which is not what we want - // Thanks to Andrew Dupont for this workaround technique - // Support: IE <=8 + // Support: IE 8 only // Exclude object elements - } else if ( context.nodeName.toLowerCase() !== "object" ) { + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { - // Capture the context ID, setting it first if necessary - if ( (nid = context.getAttribute( "id" )) ) { - nid = nid.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", (nid = expando) ); + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } } // Prefix every selector in the list groups = tokenize( selector ); i = groups.length; - nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']"; while ( i-- ) { - groups[i] = nidselect + " " + toSelector( groups[i] ); + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); } newSelector = groups.join( "," ); - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; } - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); } } } @@ -876,12 +908,14 @@ function createCache() { var keys = []; function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries delete cache[ keys.shift() ]; } - return (cache[ key + " " ] = value); + return ( cache[ key + " " ] = value ); } return cache; } @@ -897,22 +931,24 @@ function markFunction( fn ) { /** * Support testing using an element - * @param {Function} fn Passed the created div and expects a boolean result + * @param {Function} fn Passed the created element and returns a boolean result */ function assert( fn ) { - var div = document.createElement("div"); + var el = document.createElement( "fieldset" ); try { - return !!fn( div ); - } catch (e) { + return !!fn( el ); + } catch ( e ) { return false; } finally { + // Remove from its parent by default - if ( div.parentNode ) { - div.parentNode.removeChild( div ); + if ( el.parentNode ) { + el.parentNode.removeChild( el ); } + // release memory in IE - div = null; + el = null; } } @@ -922,11 +958,11 @@ function assert( fn ) { * @param {Function} handler The method that will be applied */ function addHandle( attrs, handler ) { - var arr = attrs.split("|"), + var arr = attrs.split( "|" ), i = arr.length; while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; + Expr.attrHandle[ arr[ i ] ] = handler; } } @@ -939,8 +975,7 @@ function addHandle( attrs, handler ) { function siblingCheck( a, b ) { var cur = b && a, diff = cur && a.nodeType === 1 && b.nodeType === 1 && - ( ~b.sourceIndex || MAX_NEGATIVE ) - - ( ~a.sourceIndex || MAX_NEGATIVE ); + a.sourceIndex - b.sourceIndex; // Use IE sourceIndex if available on both nodes if ( diff ) { @@ -949,7 +984,7 @@ function siblingCheck( a, b ) { // Check if b follows a if ( cur ) { - while ( (cur = cur.nextSibling) ) { + while ( ( cur = cur.nextSibling ) ) { if ( cur === b ) { return -1; } @@ -977,7 +1012,63 @@ function createInputPseudo( type ) { function createButtonPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; }; } @@ -986,21 +1077,21 @@ function createButtonPseudo( type ) { * @param {Function} fn */ function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { + return markFunction( function( argument ) { argument = +argument; - return markFunction(function( seed, matches ) { + return markFunction( function( seed, matches ) { var j, matchIndexes = fn( [], seed.length, argument ), i = matchIndexes.length; // Match elements found at the specified indexes while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); } } - }); - }); + } ); + } ); } /** @@ -1021,10 +1112,13 @@ support = Sizzle.support = {}; * @returns {Boolean} True iff elem is a non-HTML XML node */ isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); }; /** @@ -1033,11 +1127,15 @@ isXML = Sizzle.isXML = function( elem ) { * @returns {Object} Returns the current document */ setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, parent, + var hasCompare, subWindow, doc = node ? node.ownerDocument || node : preferredDoc; // Return early if doc is invalid or already selected - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { return document; } @@ -1046,82 +1144,125 @@ setDocument = Sizzle.setDocument = function( node ) { docElem = document.documentElement; documentIsHTML = !isXML( document ); - // Support: IE 9-11, Edge + // Support: IE 9 - 11+, Edge 12 - 18+ // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - if ( (parent = document.defaultView) && parent.top !== parent ) { - // Support: IE 11 - if ( parent.addEventListener ) { - parent.addEventListener( "unload", unloadHandler, false ); + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); // Support: IE 9 - 10 only - } else if ( parent.attachEvent ) { - parent.attachEvent( "onunload", unloadHandler ); + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); } } + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + /* Attributes ---------------------------------------------------------------------- */ // Support: IE<8 // Verify that getAttribute really returns attributes and not properties // (excepting IE8 booleans) - support.attributes = assert(function( div ) { - div.className = "i"; - return !div.getAttribute("className"); - }); + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); /* getElement(s)By* ---------------------------------------------------------------------- */ // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( div ) { - div.appendChild( document.createComment("") ); - return !div.getElementsByTagName("*").length; - }); + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); // Support: IE<9 support.getElementsByClassName = rnative.test( document.getElementsByClassName ); // Support: IE<10 // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programatically-set names, + // The broken getElementById methods don't pick up programmatically-set names, // so use a roundabout getElementsByName test - support.getById = assert(function( div ) { - docElem.appendChild( div ).id = expando; + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; return !document.getElementsByName || !document.getElementsByName( expando ).length; - }); + } ); - // ID find and filter + // ID filter and find if ( support.getById ) { - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var m = context.getElementById( id ); - return m ? [ m ] : []; - } - }; - Expr.filter["ID"] = function( id ) { + Expr.filter[ "ID" ] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { - return elem.getAttribute("id") === attrId; + return elem.getAttribute( "id" ) === attrId; }; }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; } else { - // Support: IE6/7 - // getElementById is not reliable as a find shortcut - delete Expr.find["ID"]; - - Expr.filter["ID"] = function( id ) { + Expr.filter[ "ID" ] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode("id"); + elem.getAttributeNode( "id" ); return node && node.value === attrId; }; }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; } // Tag - Expr.find["TAG"] = support.getElementsByTagName ? + Expr.find[ "TAG" ] = support.getElementsByTagName ? function( tag, context ) { if ( typeof context.getElementsByTagName !== "undefined" ) { return context.getElementsByTagName( tag ); @@ -1136,12 +1277,13 @@ setDocument = Sizzle.setDocument = function( node ) { var elem, tmp = [], i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too results = context.getElementsByTagName( tag ); // Filter out possible comments if ( tag === "*" ) { - while ( (elem = results[i++]) ) { + while ( ( elem = results[ i++ ] ) ) { if ( elem.nodeType === 1 ) { tmp.push( elem ); } @@ -1153,7 +1295,7 @@ setDocument = Sizzle.setDocument = function( node ) { }; // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { return context.getElementsByClassName( className ); } @@ -1171,101 +1313,135 @@ setDocument = Sizzle.setDocument = function( node ) { // We allow this because of a bug in IE8/9 that throws an error // whenever `document.activeElement` is accessed on an iframe // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See http://bugs.jquery.com/ticket/13378 + // See https://bugs.jquery.com/ticket/13378 rbuggyQSA = []; - if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + // Build QSA regex // Regex strategy adopted from Diego Perini - assert(function( div ) { + assert( function( el ) { + + var input; + // Select is set to empty string on purpose // This is to test IE's treatment of not explicitly // setting a boolean content attribute, // since its presence should be enough - // http://bugs.jquery.com/ticket/12359 - docElem.appendChild( div ).innerHTML = "" + + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + ""; // Support: IE8, Opera 11-12.16 // Nothing should be selected when empty strings follow ^= or $= or *= // The test attribute must be unknown in Opera but "safe" for WinRT - // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( div.querySelectorAll("[msallowcapture^='']").length ) { + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); } // Support: IE8 // Boolean attributes and "value" are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { + if ( !el.querySelectorAll( "[selected]" ).length ) { rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); } // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push("~="); + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); } // Webkit/Opera - :checked should return selected option elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); } // Support: Safari 8+, iOS 8+ // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibing-combinator selector` fails - if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push(".#.+[+~]"); + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); } - }); - assert(function( div ) { + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + // Support: Windows 8 Native Apps // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement("input"); + var input = document.createElement( "input" ); input.setAttribute( "type", "hidden" ); - div.appendChild( input ).setAttribute( "name", "D" ); + el.appendChild( input ).setAttribute( "name", "D" ); // Support: IE8 // Enforce case-sensitivity of name attribute - if ( div.querySelectorAll("[name=d]").length ) { + if ( el.querySelectorAll( "[name=d]" ).length ) { rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); } // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":enabled").length ) { + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { rbuggyQSA.push( ":enabled", ":disabled" ); } + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only // Opera 10-11 does not throw on post-comma invalid pseudos - div.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); } - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { - assert(function( div ) { // Check to see if it's possible to do matchesSelector // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( div, "div" ); + support.disconnectedMatch = matches.call( el, "*" ); // This should fail with an exception // Gecko does not error, returns false instead - matches.call( div, "[s!='']:x" ); + matches.call( el, "[s!='']:x" ); rbuggyMatches.push( "!=", pseudos ); - }); + } ); } - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); /* Contains ---------------------------------------------------------------------- */ @@ -1282,11 +1458,11 @@ setDocument = Sizzle.setDocument = function( node ) { adown.contains ? adown.contains( bup ) : a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); + ) ); } : function( a, b ) { if ( b ) { - while ( (b = b.parentNode) ) { + while ( ( b = b.parentNode ) ) { if ( b === a ) { return true; } @@ -1315,7 +1491,11 @@ setDocument = Sizzle.setDocument = function( node ) { } // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? a.compareDocumentPosition( b ) : // Otherwise we know they are disconnected @@ -1323,13 +1503,24 @@ setDocument = Sizzle.setDocument = function( node ) { // Disconnected nodes if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { // Choose the first element that is related to our preferred document - if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { return -1; } - if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { return 1; } @@ -1342,6 +1533,7 @@ setDocument = Sizzle.setDocument = function( node ) { return compare & 4 ? -1 : 1; } : function( a, b ) { + // Exit early if the nodes are identical if ( a === b ) { hasDuplicate = true; @@ -1357,8 +1549,14 @@ setDocument = Sizzle.setDocument = function( node ) { // Parentless nodes are either documents or disconnected if ( !aup || !bup ) { - return a === document ? -1 : - b === document ? 1 : + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ aup ? -1 : bup ? 1 : sortInput ? @@ -1372,26 +1570,32 @@ setDocument = Sizzle.setDocument = function( node ) { // Otherwise we need full lists of their ancestors for comparison cur = a; - while ( (cur = cur.parentNode) ) { + while ( ( cur = cur.parentNode ) ) { ap.unshift( cur ); } cur = b; - while ( (cur = cur.parentNode) ) { + while ( ( cur = cur.parentNode ) ) { bp.unshift( cur ); } // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { + while ( ap[ i ] === bp[ i ] ) { i++; } return i ? + // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : + siblingCheck( ap[ i ], bp[ i ] ) : // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ 0; }; @@ -1403,16 +1607,10 @@ Sizzle.matches = function( expr, elements ) { }; Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); + setDocument( elem ); if ( support.matchesSelector && documentIsHTML && - !compilerCache[ expr + " " ] && + !nonnativeSelectorCache[ expr + " " ] && ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { @@ -1421,32 +1619,46 @@ Sizzle.matchesSelector = function( elem, expr ) { // IE 9's matchesSelector returns false on disconnected nodes if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { return ret; } - } catch (e) {} + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } } return Sizzle( expr, document, null, [ elem ] ).length > 0; }; Sizzle.contains = function( context, elem ) { + // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { setDocument( context ); } return contains( context, elem ); }; Sizzle.attr = function( elem, name ) { + // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { setDocument( elem ); } var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? fn( elem, name, !documentIsHTML ) : @@ -1456,11 +1668,15 @@ Sizzle.attr = function( elem, name ) { val : support.attributes || !documentIsHTML ? elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? + ( val = elem.getAttributeNode( name ) ) && val.specified ? val.value : null; }; +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + Sizzle.error = function( msg ) { throw new Error( "Syntax error, unrecognized expression: " + msg ); }; @@ -1481,7 +1697,7 @@ Sizzle.uniqueSort = function( results ) { results.sort( sortOrder ); if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { + while ( ( elem = results[ i++ ] ) ) { if ( elem === results[ i ] ) { j = duplicates.push( i ); } @@ -1509,17 +1725,21 @@ getText = Sizzle.getText = function( elem ) { nodeType = elem.nodeType; if ( !nodeType ) { + // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { + while ( ( node = elem[ i++ ] ) ) { + // Do not traverse comment nodes ret += getText( node ); } } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements // innerText usage removed for consistency of new lines (jQuery #11153) if ( typeof elem.textContent === "string" ) { return elem.textContent; } else { + // Traverse its children for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { ret += getText( elem ); @@ -1528,6 +1748,7 @@ getText = Sizzle.getText = function( elem ) { } else if ( nodeType === 3 || nodeType === 4 ) { return elem.nodeValue; } + // Do not include comment or processing instruction nodes return ret; @@ -1555,19 +1776,21 @@ Expr = Sizzle.selectors = { preFilter: { "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; } return match.slice( 0, 4 ); }, "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] 1 type (only|nth|...) 2 what (child|of-type) @@ -1578,22 +1801,25 @@ Expr = Sizzle.selectors = { 7 sign of y-component 8 y of y-component */ - match[1] = match[1].toLowerCase(); + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { - if ( match[1].slice( 0, 3 ) === "nth" ) { // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); } // numeric x and y parameters for Expr.filter.CHILD // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); } return match; @@ -1601,26 +1827,28 @@ Expr = Sizzle.selectors = { "PSEUDO": function( match ) { var excess, - unquoted = !match[6] && match[2]; + unquoted = !match[ 6 ] && match[ 2 ]; - if ( matchExpr["CHILD"].test( match[0] ) ) { + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { return null; } // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; // Strip excess characters from unquoted arguments } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && + ( excess = tokenize( unquoted, true ) ) && + // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); } // Return only captures needed by the pseudo filter method (type and argument) @@ -1633,7 +1861,9 @@ Expr = Sizzle.selectors = { "TAG": function( nodeNameSelector ) { var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); return nodeNameSelector === "*" ? - function() { return true; } : + function() { + return true; + } : function( elem ) { return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; }; @@ -1643,10 +1873,16 @@ Expr = Sizzle.selectors = { var pattern = classCache[ className + " " ]; return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); - }); + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); }, "ATTR": function( name, operator, check ) { @@ -1662,6 +1898,8 @@ Expr = Sizzle.selectors = { result += ""; + /* eslint-disable max-len */ + return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf( check ) === 0 : @@ -1670,10 +1908,12 @@ Expr = Sizzle.selectors = { operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : false; + /* eslint-enable max-len */ + }; }, - "CHILD": function( type, what, argument, first, last ) { + "CHILD": function( type, what, _argument, first, last ) { var simple = type.slice( 0, 3 ) !== "nth", forward = type.slice( -4 ) !== "last", ofType = what === "of-type"; @@ -1685,7 +1925,7 @@ Expr = Sizzle.selectors = { return !!elem.parentNode; } : - function( elem, context, xml ) { + function( elem, _context, xml ) { var cache, uniqueCache, outerCache, node, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, @@ -1699,7 +1939,7 @@ Expr = Sizzle.selectors = { if ( simple ) { while ( dir ) { node = elem; - while ( (node = node[ dir ]) ) { + while ( ( node = node[ dir ] ) ) { if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { @@ -1707,6 +1947,7 @@ Expr = Sizzle.selectors = { return false; } } + // Reverse direction for :only-* (if we haven't yet done so) start = dir = type === "only" && !start && "nextSibling"; } @@ -1722,22 +1963,22 @@ Expr = Sizzle.selectors = { // ...in a gzip-friendly way node = parent; - outerCache = node[ expando ] || (node[ expando ] = {}); + outerCache = node[ expando ] || ( node[ expando ] = {} ); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); + ( outerCache[ node.uniqueID ] = {} ); cache = uniqueCache[ type ] || []; nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; diff = nodeIndex && cache[ 2 ]; node = nodeIndex && parent.childNodes[ nodeIndex ]; - while ( (node = ++nodeIndex && node && node[ dir ] || + while ( ( node = ++nodeIndex && node && node[ dir ] || // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { + ( diff = nodeIndex = 0 ) || start.pop() ) ) { // When found, cache indexes on `parent` and break if ( node.nodeType === 1 && ++diff && node === elem ) { @@ -1747,16 +1988,18 @@ Expr = Sizzle.selectors = { } } else { + // Use previously-cached element index if available if ( useCache ) { + // ...in a gzip-friendly way node = elem; - outerCache = node[ expando ] || (node[ expando ] = {}); + outerCache = node[ expando ] || ( node[ expando ] = {} ); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); + ( outerCache[ node.uniqueID ] = {} ); cache = uniqueCache[ type ] || []; nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; @@ -1766,9 +2009,10 @@ Expr = Sizzle.selectors = { // xml :nth-child(...) // or :nth-last-child(...) or :nth(-last)?-of-type(...) if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { if ( ( ofType ? node.nodeName.toLowerCase() === name : @@ -1777,12 +2021,13 @@ Expr = Sizzle.selectors = { // Cache the index of each encountered element if ( useCache ) { - outerCache = node[ expando ] || (node[ expando ] = {}); + outerCache = node[ expando ] || + ( node[ expando ] = {} ); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); + ( outerCache[ node.uniqueID ] = {} ); uniqueCache[ type ] = [ dirruns, diff ]; } @@ -1803,6 +2048,7 @@ Expr = Sizzle.selectors = { }, "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive // http://www.w3.org/TR/selectors/#pseudo-classes // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters @@ -1822,15 +2068,15 @@ Expr = Sizzle.selectors = { if ( fn.length > 1 ) { args = [ pseudo, pseudo, "", argument ]; return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { + markFunction( function( seed, matches ) { var idx, matched = fn( seed, argument ), i = matched.length; while ( i-- ) { - idx = indexOf( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); } - }) : + } ) : function( elem ) { return fn( elem, 0, args ); }; @@ -1841,8 +2087,10 @@ Expr = Sizzle.selectors = { }, pseudos: { + // Potentially complex pseudos - "not": markFunction(function( selector ) { + "not": markFunction( function( selector ) { + // Trim the selector passed to compile // to avoid treating leading and trailing // spaces as combinators @@ -1851,39 +2099,40 @@ Expr = Sizzle.selectors = { matcher = compile( selector.replace( rtrim, "$1" ) ); return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { + markFunction( function( seed, matches, _context, xml ) { var elem, unmatched = matcher( seed, null, xml, [] ), i = seed.length; // Match elements unmatched by `matcher` while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); } } - }) : - function( elem, context, xml ) { - input[0] = elem; + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; matcher( input, null, xml, results ); + // Don't keep the element (issue #299) - input[0] = null; + input[ 0 ] = null; return !results.pop(); }; - }), + } ), - "has": markFunction(function( selector ) { + "has": markFunction( function( selector ) { return function( elem ) { return Sizzle( selector, elem ).length > 0; }; - }), + } ), - "contains": markFunction(function( text ) { + "contains": markFunction( function( text ) { text = text.replace( runescape, funescape ); return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; }; - }), + } ), // "Whether an element is represented by a :lang() selector // is based solely on the element's language value @@ -1893,25 +2142,26 @@ Expr = Sizzle.selectors = { // The identifier C does not have to be a valid language name." // http://www.w3.org/TR/selectors/#lang-pseudo "lang": markFunction( function( lang ) { + // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { + if ( !ridentifier.test( lang || "" ) ) { Sizzle.error( "unsupported lang: " + lang ); } lang = lang.replace( runescape, funescape ).toLowerCase(); return function( elem ) { var elemLang; do { - if ( (elemLang = documentIsHTML ? + if ( ( elemLang = documentIsHTML ? elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { elemLang = elemLang.toLowerCase(); return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); return false; }; - }), + } ), // Miscellaneous "target": function( elem ) { @@ -1924,29 +2174,30 @@ Expr = Sizzle.selectors = { }, "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); }, // Boolean properties - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); }, "selected": function( elem ) { + // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions elem.parentNode.selectedIndex; } @@ -1955,6 +2206,7 @@ Expr = Sizzle.selectors = { // Contents "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), // but not by others (comment: 8; processing instruction: 7; etc.) @@ -1968,7 +2220,7 @@ Expr = Sizzle.selectors = { }, "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); + return !Expr.pseudos[ "empty" ]( elem ); }, // Element/input types @@ -1992,57 +2244,62 @@ Expr = Sizzle.selectors = { // Support: IE<8 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); }, // Position-in-collection - "first": createPositionalPseudo(function() { + "first": createPositionalPseudo( function() { return [ 0 ]; - }), + } ), - "last": createPositionalPseudo(function( matchIndexes, length ) { + "last": createPositionalPseudo( function( _matchIndexes, length ) { return [ length - 1 ]; - }), + } ), - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { return [ argument < 0 ? argument + length : argument ]; - }), + } ), - "even": createPositionalPseudo(function( matchIndexes, length ) { + "even": createPositionalPseudo( function( matchIndexes, length ) { var i = 0; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; - }), + } ), - "odd": createPositionalPseudo(function( matchIndexes, length ) { + "odd": createPositionalPseudo( function( matchIndexes, length ) { var i = 1; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; - }), + } ), - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; for ( ; --i >= 0; ) { matchIndexes.push( i ); } return matchIndexes; - }), + } ), - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; ++i < length; ) { matchIndexes.push( i ); } return matchIndexes; - }) + } ) } }; -Expr.pseudos["nth"] = Expr.pseudos["eq"]; +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; // Add button/input type pseudos for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { @@ -2073,37 +2330,39 @@ tokenize = Sizzle.tokenize = function( selector, parseOnly ) { while ( soFar ) { // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { if ( match ) { + // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; + soFar = soFar.slice( match[ 0 ].length ) || soFar; } - groups.push( (tokens = []) ); + groups.push( ( tokens = [] ) ); } matched = false; // Combinators - if ( (match = rcombinators.exec( soFar )) ) { + if ( ( match = rcombinators.exec( soFar ) ) ) { matched = match.shift(); - tokens.push({ + tokens.push( { value: matched, + // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); + type: match[ 0 ].replace( rtrim, " " ) + } ); soFar = soFar.slice( matched.length ); } // Filters for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { matched = match.shift(); - tokens.push({ + tokens.push( { value: matched, type: type, matches: match - }); + } ); soFar = soFar.slice( matched.length ); } } @@ -2120,6 +2379,7 @@ tokenize = Sizzle.tokenize = function( selector, parseOnly ) { soFar.length : soFar ? Sizzle.error( selector ) : + // Cache the tokens tokenCache( selector, groups ).slice( 0 ); }; @@ -2129,24 +2389,28 @@ function toSelector( tokens ) { len = tokens.length, selector = ""; for ( ; i < len; i++ ) { - selector += tokens[i].value; + selector += tokens[ i ].value; } return selector; } function addCombinator( matcher, combinator, base ) { var dir = combinator.dir, - checkNonElements = base && dir === "parentNode", + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", doneName = done++; return combinator.first ? + // Check against closest ancestor/preceding element function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { + while ( ( elem = elem[ dir ] ) ) { if ( elem.nodeType === 1 || checkNonElements ) { return matcher( elem, context, xml ); } } + return false; } : // Check against all ancestor/preceding elements @@ -2156,7 +2420,7 @@ function addCombinator( matcher, combinator, base ) { // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching if ( xml ) { - while ( (elem = elem[ dir ]) ) { + while ( ( elem = elem[ dir ] ) ) { if ( elem.nodeType === 1 || checkNonElements ) { if ( matcher( elem, context, xml ) ) { return true; @@ -2164,31 +2428,36 @@ function addCombinator( matcher, combinator, base ) { } } } else { - while ( (elem = elem[ dir ]) ) { + while ( ( elem = elem[ dir ] ) ) { if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); // Support: IE <9 only // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); - if ( (oldCache = uniqueCache[ dir ]) && + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { // Assign to newCache so results back-propagate to previous elements - return (newCache[ 2 ] = oldCache[ 2 ]); + return ( newCache[ 2 ] = oldCache[ 2 ] ); } else { + // Reuse newcache so results back-propagate to previous elements - uniqueCache[ dir ] = newCache; + uniqueCache[ key ] = newCache; // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { return true; } } } } } + return false; }; } @@ -2197,20 +2466,20 @@ function elementMatcher( matchers ) { function( elem, context, xml ) { var i = matchers.length; while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { + if ( !matchers[ i ]( elem, context, xml ) ) { return false; } } return true; } : - matchers[0]; + matchers[ 0 ]; } function multipleContexts( selector, contexts, results ) { var i = 0, len = contexts.length; for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); + Sizzle( selector, contexts[ i ], results ); } return results; } @@ -2223,7 +2492,7 @@ function condense( unmatched, map, filter, context, xml ) { mapped = map != null; for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { + if ( ( elem = unmatched[ i ] ) ) { if ( !filter || filter( elem, context, xml ) ) { newUnmatched.push( elem ); if ( mapped ) { @@ -2243,14 +2512,18 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS if ( postFinder && !postFinder[ expando ] ) { postFinder = setMatcher( postFinder, postSelector ); } - return markFunction(function( seed, results, context, xml ) { + return markFunction( function( seed, results, context, xml ) { var temp, i, elem, preMap = [], postMap = [], preexisting = results.length, // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), // Prefilter to get matcher input, preserving a map for seed-results synchronization matcherIn = preFilter && ( seed || !selector ) ? @@ -2258,6 +2531,7 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS elems, matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, postFinder || ( seed ? preFilter : preexisting || postFilter ) ? @@ -2281,8 +2555,8 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS // Un-match failing elements by moving them back to matcherIn i = temp.length; while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); } } } @@ -2290,25 +2564,27 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS if ( seed ) { if ( postFinder || preFilter ) { if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts temp = []; i = matcherOut.length; while ( i-- ) { - if ( (elem = matcherOut[i]) ) { + if ( ( elem = matcherOut[ i ] ) ) { + // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); + temp.push( ( matcherIn[ i ] = elem ) ); } } - postFinder( null, (matcherOut = []), temp, xml ); + postFinder( null, ( matcherOut = [] ), temp, xml ); } // Move matched elements from seed to results to keep them synchronized i = matcherOut.length; while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { - seed[temp] = !(results[temp] = elem); + seed[ temp ] = !( results[ temp ] = elem ); } } } @@ -2326,14 +2602,14 @@ function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postS push.apply( results, matcherOut ); } } - }); + } ); } function matcherFromTokens( tokens ) { var checkContext, matcher, j, len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], i = leadingRelative ? 1 : 0, // The foundational matcher ensures that elements are reachable from top-level context(s) @@ -2345,38 +2621,43 @@ function matcherFromTokens( tokens ) { }, implicitRelative, true ), matchers = [ function( elem, context, xml ) { var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? + ( checkContext = context ).nodeType ? matchContext( elem, context, xml ) : matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) checkContext = null; return ret; } ]; for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); // Return special upon seeing a positional matcher if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling j = ++i; for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { + if ( Expr.relative[ tokens[ j ].type ] ) { break; } } return setMatcher( i > 1 && elementMatcher( matchers ), i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) ).replace( rtrim, "$1" ), matcher, i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), j < len && toSelector( tokens ) ); } @@ -2397,28 +2678,40 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { unmatched = seed && [], setMatched = [], contextBackup = outermostContext, + // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), len = elems.length; if ( outermost ) { - outermostContext = context === document || context || outermost; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; } // Add elements passing elementMatchers directly to results // Support: IE<9, Safari // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { if ( byElement && elem ) { j = 0; - if ( !context && elem.ownerDocument !== document ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { setDocument( elem ); xml = !documentIsHTML; } - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context || document, xml) ) { + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { results.push( elem ); break; } @@ -2430,8 +2723,9 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { // Track unmatched elements for set filters if ( bySet ) { + // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { + if ( ( elem = !matcher && elem ) ) { matchedCount--; } @@ -2455,16 +2749,17 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { // numerically zero. if ( bySet && i !== matchedCount ) { j = 0; - while ( (matcher = setMatchers[j++]) ) { + while ( ( matcher = setMatchers[ j++ ] ) ) { matcher( unmatched, setMatched, context, xml ); } if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting if ( matchedCount > 0 ) { while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); } } } @@ -2505,13 +2800,14 @@ compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { cached = compilerCache[ selector + " " ]; if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element if ( !match ) { match = tokenize( selector ); } i = match.length; while ( i-- ) { - cached = matcherFromTokens( match[i] ); + cached = matcherFromTokens( match[ i ] ); if ( cached[ expando ] ) { setMatchers.push( cached ); } else { @@ -2520,7 +2816,10 @@ compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { } // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); // Save selector and tokenization cached.selector = selector; @@ -2540,7 +2839,7 @@ compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { select = Sizzle.select = function( selector, context, results, seed ) { var i, tokens, token, type, find, compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); results = results || []; @@ -2549,12 +2848,12 @@ select = Sizzle.select = function( selector, context, results, seed ) { if ( match.length === 1 ) { // Reduce context if the leading compound selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - support.getById && context.nodeType === 9 && documentIsHTML && - Expr.relative[ tokens[1].type ] ) { + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; if ( !context ) { return results; @@ -2567,20 +2866,22 @@ select = Sizzle.select = function( selector, context, results, seed ) { } // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; while ( i-- ) { - token = tokens[i]; + token = tokens[ i ]; // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { + if ( Expr.relative[ ( type = token.type ) ] ) { break; } - if ( (find = Expr.find[ type ]) ) { + if ( ( find = Expr.find[ type ] ) ) { + // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { // If seed is empty or no tokens remain, we can return early tokens.splice( i, 1 ); @@ -2611,7 +2912,7 @@ select = Sizzle.select = function( selector, context, results, seed ) { // One-time assignments // Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; // Support: Chrome 14-35+ // Always assume duplicates if they aren't passed to the comparison function @@ -2622,68 +2923,73 @@ setDocument(); // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) // Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( div1 ) { +support.sortDetached = assert( function( el ) { + // Should return 1, but returns 4 (following) - return div1.compareDocumentPosition( document.createElement("div") ) & 1; -}); + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); // Support: IE<8 // Prevent attribute/property "interpolation" -// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( div ) { - div.innerHTML = ""; - return div.firstChild.getAttribute("href") === "#" ; -}) ) { +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { addHandle( "type|href|height|width", function( elem, name, isXML ) { if ( !isXML ) { return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); } - }); + } ); } // Support: IE<9 // Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( div ) { - div.innerHTML = ""; - div.firstChild.setAttribute( "value", "" ); - return div.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { return elem.defaultValue; } - }); + } ); } // Support: IE<9 // Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( div ) { - return div.getAttribute("disabled") == null; -}) ) { +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { addHandle( booleans, function( elem, name, isXML ) { var val; if ( !isXML ) { return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? + ( val = elem.getAttributeNode( name ) ) && val.specified ? val.value : - null; + null; } - }); + } ); } return Sizzle; -})( window ); +} )( window ); jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; + +// Deprecated jQuery.expr[ ":" ] = jQuery.expr.pseudos; jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; jQuery.text = Sizzle.getText; jQuery.isXMLDoc = Sizzle.isXML; jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + @@ -2718,40 +3024,41 @@ var siblings = function( n, elem ) { var rneedsContext = jQuery.expr.match.needsContext; -var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ ); +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + -var risSimple = /^.[^:#\[\.,]*$/; // Implement the identical functionality for filter and not function winnow( elements, qualifier, not ) { - if ( jQuery.isFunction( qualifier ) ) { + if ( isFunction( qualifier ) ) { return jQuery.grep( elements, function( elem, i ) { - /* jshint -W018 */ return !!qualifier.call( elem, i, elem ) !== not; } ); - } + // Single element if ( qualifier.nodeType ) { return jQuery.grep( elements, function( elem ) { return ( elem === qualifier ) !== not; } ); - } - if ( typeof qualifier === "string" ) { - if ( risSimple.test( qualifier ) ) { - return jQuery.filter( qualifier, elements, not ); - } - - qualifier = jQuery.filter( qualifier, elements ); + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); } - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); } jQuery.filter = function( expr, elems, not ) { @@ -2761,18 +3068,19 @@ jQuery.filter = function( expr, elems, not ) { expr = ":not(" + expr + ")"; } - return elems.length === 1 && elem.nodeType === 1 ? - jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : - jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); }; jQuery.fn.extend( { find: function( selector ) { - var i, + var i, ret, len = this.length, - ret = [], self = this; if ( typeof selector !== "string" ) { @@ -2785,14 +3093,13 @@ jQuery.fn.extend( { } ) ); } + ret = this.pushStack( [] ); + for ( i = 0; i < len; i++ ) { jQuery.find( selector, self[ i ], ret ); } - // Needed because $( selector, context ) becomes $( context ).find( selector ) - ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); - ret.selector = this.selector ? this.selector + " " + selector : selector; - return ret; + return len > 1 ? jQuery.uniqueSort( ret ) : ret; }, filter: function( selector ) { return this.pushStack( winnow( this, selector || [], false ) ); @@ -2824,7 +3131,8 @@ var rootjQuery, // A simple way to check for HTML strings // Prioritize #id over to avoid XSS via location.hash (#9521) // Strict HTML recognition (#11290: must start with <) - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, init = jQuery.fn.init = function( selector, context, root ) { var match, elem; @@ -2871,7 +3179,7 @@ var rootjQuery, for ( match in context ) { // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { + if ( isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); // ...and otherwise set as attributes @@ -2887,17 +3195,12 @@ var rootjQuery, } else { elem = document.getElementById( match[ 2 ] ); - // Support: Blackberry 4.6 - // gEBID returns nodes no longer in the document (#6963) - if ( elem && elem.parentNode ) { + if ( elem ) { // Inject the element directly into the jQuery object - this.length = 1; this[ 0 ] = elem; + this.length = 1; } - - this.context = document; - this.selector = selector; return this; } @@ -2913,13 +3216,13 @@ var rootjQuery, // HANDLE: $(DOMElement) } else if ( selector.nodeType ) { - this.context = this[ 0 ] = selector; + this[ 0 ] = selector; this.length = 1; return this; // HANDLE: $(function) // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { + } else if ( isFunction( selector ) ) { return root.ready !== undefined ? root.ready( selector ) : @@ -2927,11 +3230,6 @@ var rootjQuery, selector( jQuery ); } - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - return jQuery.makeArray( selector, this ); }; @@ -2972,23 +3270,24 @@ jQuery.fn.extend( { i = 0, l = this.length, matched = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; + targets = typeof selectors !== "string" && jQuery( selectors ); - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - // Always skip document fragments - if ( cur.nodeType < 11 && ( pos ? - pos.index( cur ) > -1 : + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { - matched.push( cur ); - break; + matched.push( cur ); + break; + } } } } @@ -3045,7 +3344,7 @@ jQuery.each( { parents: function( elem ) { return dir( elem, "parentNode" ); }, - parentsUntil: function( elem, i, until ) { + parentsUntil: function( elem, _i, until ) { return dir( elem, "parentNode", until ); }, next: function( elem ) { @@ -3060,10 +3359,10 @@ jQuery.each( { prevAll: function( elem ) { return dir( elem, "previousSibling" ); }, - nextUntil: function( elem, i, until ) { + nextUntil: function( elem, _i, until ) { return dir( elem, "nextSibling", until ); }, - prevUntil: function( elem, i, until ) { + prevUntil: function( elem, _i, until ) { return dir( elem, "previousSibling", until ); }, siblings: function( elem ) { @@ -3073,7 +3372,24 @@ jQuery.each( { return siblings( elem.firstChild ); }, contents: function( elem ) { - return elem.contentDocument || jQuery.merge( [], elem.childNodes ); + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { @@ -3103,14 +3419,14 @@ jQuery.each( { return this.pushStack( matched ); }; } ); -var rnotwhite = ( /\S+/g ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); // Convert String-formatted options into Object-formatted ones function createOptions( options ) { var object = {}; - jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { object[ flag ] = true; } ); return object; @@ -3171,7 +3487,7 @@ jQuery.Callbacks = function( options ) { fire = function() { // Enforce single-firing - locked = options.once; + locked = locked || options.once; // Execute callbacks for all pending executions, // respecting firingIndex overrides and runtime changes @@ -3227,11 +3543,11 @@ jQuery.Callbacks = function( options ) { ( function add( args ) { jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) ) { + if ( isFunction( arg ) ) { if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } - } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + } else if ( arg && arg.length && toType( arg ) !== "string" ) { // Inspect recursively add( arg ); @@ -3295,7 +3611,7 @@ jQuery.Callbacks = function( options ) { // Abort any pending executions lock: function() { locked = queue = []; - if ( !memory ) { + if ( !memory && !firing ) { list = memory = ""; } return this; @@ -3333,15 +3649,59 @@ jQuery.Callbacks = function( options ) { }; +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + jQuery.extend( { Deferred: function( func ) { var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ], - [ "notify", "progress", jQuery.Callbacks( "memory" ) ] + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] ], state = "pending", promise = { @@ -3352,23 +3712,33 @@ jQuery.extend( { deferred.done( arguments ).fail( arguments ); return this; }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + "catch": function( fn ) { + return promise.then( null, fn ); + }, - // deferred[ done | fail | progress ] for forwarding actions to newDefer + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) deferred[ tuple[ 1 ] ]( function() { var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { + if ( returned && isFunction( returned.promise ) ) { returned.promise() .progress( newDefer.notify ) .done( newDefer.resolve ) .fail( newDefer.reject ); } else { newDefer[ tuple[ 0 ] + "With" ]( - this === promise ? newDefer.promise() : this, + this, fn ? [ returned ] : arguments ); } @@ -3377,6 +3747,170 @@ jQuery.extend( { fns = null; } ).promise(); }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object @@ -3386,33 +3920,58 @@ jQuery.extend( { }, deferred = {}; - // Keep pipe for back-compat - promise.pipe = promise.then; - // Add list-specific methods jQuery.each( tuples, function( i, tuple ) { var list = tuple[ 2 ], - stateString = tuple[ 3 ]; + stateString = tuple[ 5 ]; - // promise[ done | fail | progress ] = list.add + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add promise[ tuple[ 1 ] ] = list.add; // Handle state if ( stateString ) { - list.add( function() { + list.add( + function() { - // state = [ resolved | rejected ] - state = stateString; + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); } - // deferred[ resolve | reject | notify ] + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments ); + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); return this; }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith deferred[ tuple[ 0 ] + "With" ] = list.fireWith; } ); @@ -3429,68 +3988,95 @@ jQuery.extend( { }, // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), resolveValues = slice.call( arguments ), - length = resolveValues.length, - // the count of uncompleted subordinates - remaining = length !== 1 || - ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + // the primary Deferred + primary = jQuery.Deferred(), - // the master Deferred. - // If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { + // subordinate callback factory + updateFunc = function( i ) { return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( values === progressValues ) { - deferred.notifyWith( contexts, values ); - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + primary.resolveWith( resolveContexts, resolveValues ); } }; - }, + }; - progressValues, progressContexts, resolveContexts; + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, + !remaining ); - // Add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .progress( updateFunc( i, progressContexts, progressValues ) ) - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ); - } else { - --remaining; - } + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( primary.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return primary.then(); } } - // If we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); } - return deferred.promise(); + return primary.promise(); } } ); +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + // The deferred used on DOM ready -var readyList; +var readyList = jQuery.Deferred(); jQuery.fn.ready = function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); return this; }; @@ -3504,15 +4090,6 @@ jQuery.extend( { // the ready event fires. See #6781 readyWait: 1, - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - // Handle when the DOM is ready ready: function( wait ) { @@ -3531,53 +4108,36 @@ jQuery.extend( { // If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.triggerHandler ) { - jQuery( document ).triggerHandler( "ready" ); - jQuery( document ).off( "ready" ); - } } } ); -/** - * The ready event handler and self cleanup method - */ +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method function completed() { document.removeEventListener( "DOMContentLoaded", completed ); window.removeEventListener( "load", completed ); jQuery.ready(); } -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - readyList = jQuery.Deferred(); + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); - // Catch cases where $(document).ready() is called - // after the browser event has already occurred. - // Support: IE9-10 only - // Older IE sometimes signals "interactive" too soon - if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { +} else { - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); - } else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); - } - } - return readyList.promise( obj ); -}; - -// Kick off the DOM ready check even if the user does not -jQuery.ready.promise(); + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} @@ -3590,7 +4150,7 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { bulk = key == null; // Sets many values - if ( jQuery.type( key ) === "object" ) { + if ( toType( key ) === "object" ) { chainable = true; for ( i in key ) { access( elems, fn, i, key[ i ], true, emptyGet, raw ); @@ -3600,7 +4160,7 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { } else if ( value !== undefined ) { chainable = true; - if ( !jQuery.isFunction( value ) ) { + if ( !isFunction( value ) ) { raw = true; } @@ -3614,7 +4174,7 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { // ...except when executing function values } else { bulk = fn; - fn = function( elem, key, value ) { + fn = function( elem, _key, value ) { return bulk.call( jQuery( elem ), value ); }; } @@ -3624,21 +4184,41 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { for ( ; i < len; i++ ) { fn( elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) ); } } } - return chainable ? - elems : + if ( chainable ) { + return elems; + } - // Gets - bulk ? - fn.call( elems ) : - len ? fn( elems[ 0 ], key ) : emptyGet; + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; }; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} var acceptData = function( owner ) { // Accepts only: @@ -3647,7 +4227,6 @@ var acceptData = function( owner ) { // - Node.DOCUMENT_NODE // - Object // - Any - /* jshint -W018 */ return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); }; @@ -3662,35 +4241,8 @@ Data.uid = 1; Data.prototype = { - register: function( owner, initial ) { - var value = initial || {}; - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable, non-writable property - // configurability must be true to allow the property to be - // deleted with the delete operator - } else { - Object.defineProperty( owner, this.expando, { - value: value, - writable: true, - configurable: true - } ); - } - return owner[ this.expando ]; - }, cache: function( owner ) { - // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. - // Always return an empty object. - if ( !acceptData( owner ) ) { - return {}; - } - // Check if the owner object already has a cache var value = owner[ this.expando ]; @@ -3727,15 +4279,16 @@ Data.prototype = { cache = this.cache( owner ); // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) if ( typeof data === "string" ) { - cache[ data ] = value; + cache[ camelCase( data ) ] = value; // Handle: [ owner, { properties } ] args } else { // Copy the properties one-by-one to the cache object for ( prop in data ) { - cache[ prop ] = data[ prop ]; + cache[ camelCase( prop ) ] = data[ prop ]; } } return cache; @@ -3743,10 +4296,11 @@ Data.prototype = { get: function( owner, key ) { return key === undefined ? this.cache( owner ) : - owner[ this.expando ] && owner[ this.expando ][ key ]; + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; }, access: function( owner, key, value ) { - var stored; // In cases where either: // @@ -3762,10 +4316,7 @@ Data.prototype = { if ( key === undefined || ( ( key && typeof key === "string" ) && value === undefined ) ) { - stored = this.get( owner, key ); - - return stored !== undefined ? - stored : this.get( owner, jQuery.camelCase( key ) ); + return this.get( owner, key ); } // When the key is not a string, or both a key and value @@ -3781,58 +4332,45 @@ Data.prototype = { return value !== undefined ? value : key; }, remove: function( owner, key ) { - var i, name, camel, + var i, cache = owner[ this.expando ]; if ( cache === undefined ) { return; } - if ( key === undefined ) { - this.register( owner ); - - } else { + if ( key !== undefined ) { // Support array or space separated string of keys - if ( jQuery.isArray( key ) ) { + if ( Array.isArray( key ) ) { - // If "name" is an array of keys... - // When data is initially created, via ("key", "val") signature, - // keys will be converted to camelCase. - // Since there is no way to tell _how_ a key was added, remove - // both plain key and camelCase key. #12786 - // This will only penalize the array argument path. - name = key.concat( key.map( jQuery.camelCase ) ); + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); } else { - camel = jQuery.camelCase( key ); + key = camelCase( key ); - // Try the string as a key before any manipulation - if ( key in cache ) { - name = [ key, camel ]; - } else { - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - name = camel; - name = name in cache ? - [ name ] : ( name.match( rnotwhite ) || [] ); - } + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); } - i = name.length; + i = key.length; while ( i-- ) { - delete cache[ name[ i ] ]; + delete cache[ key[ i ] ]; } } // Remove the expando if there's no more data if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - // Support: Chrome <= 35-45+ + // Support: Chrome <=35 - 45 // Webkit & Blink performance suffers when deleting properties // from DOM nodes, so set to undefined instead - // https://code.google.com/p/chromium/issues/detail?id=378607 + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) if ( owner.nodeType ) { owner[ this.expando ] = undefined; } else { @@ -3864,6 +4402,31 @@ var dataUser = new Data(); var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, rmultiDash = /[A-Z]/g; +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + function dataAttr( elem, key, data ) { var name; @@ -3875,14 +4438,7 @@ function dataAttr( elem, key, data ) { if ( typeof data === "string" ) { try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; + data = getData( data ); } catch ( e ) {} // Make sure we set the data so it isn't changed later @@ -3933,12 +4489,12 @@ jQuery.fn.extend( { i = attrs.length; while ( i-- ) { - // Support: IE11+ + // Support: IE 11 only // The attrs elements can be null (#14894) if ( attrs[ i ] ) { name = attrs[ i ].name; if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.slice( 5 ) ); + name = camelCase( name.slice( 5 ) ); dataAttr( elem, name, data[ name ] ); } } @@ -3958,7 +4514,7 @@ jQuery.fn.extend( { } return access( this, function( value ) { - var data, camelKey; + var data; // The calling jQuery object (element matches) is not empty // (and therefore has an element appears at this[ 0 ]) and the @@ -3968,29 +4524,15 @@ jQuery.fn.extend( { if ( elem && value === undefined ) { // Attempt to get data from the cache - // with the key as-is - data = dataUser.get( elem, key ) || - - // Try to find dashed key if it exists (gh-2779) - // This is for 2.2.x only - dataUser.get( elem, key.replace( rmultiDash, "-$&" ).toLowerCase() ); - - if ( data !== undefined ) { - return data; - } - - camelKey = jQuery.camelCase( key ); - - // Attempt to get data from the cache - // with the key camelized - data = dataUser.get( elem, camelKey ); + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); if ( data !== undefined ) { return data; } // Attempt to "discover" the data in // HTML5 custom data-* attrs - data = dataAttr( elem, camelKey, undefined ); + data = dataAttr( elem, key ); if ( data !== undefined ) { return data; } @@ -4000,24 +4542,10 @@ jQuery.fn.extend( { } // Set the data... - camelKey = jQuery.camelCase( key ); this.each( function() { - // First, attempt to store a copy or reference of any - // data that might've been store with a camelCased key. - var data = dataUser.get( this, camelKey ); - - // For HTML5 data-* attribute interop, we have to - // store property names with dashes in a camelCase form. - // This might not apply to all properties...* - dataUser.set( this, camelKey, value ); - - // *... In the case of properties that might _actually_ - // have dashes, we need to also store a copy of that - // unchanged property. - if ( key.indexOf( "-" ) > -1 && data !== undefined ) { - dataUser.set( this, key, value ); - } + // We always store the camelCased key + dataUser.set( this, key, value ); } ); }, null, value, arguments.length > 1, null, true ); }, @@ -4040,7 +4568,7 @@ jQuery.extend( { // Speed up dequeue by getting out quickly if this is just a lookup if ( data ) { - if ( !queue || jQuery.isArray( data ) ) { + if ( !queue || Array.isArray( data ) ) { queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); } else { queue.push( data ); @@ -4170,57 +4698,94 @@ var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; -var isHidden = function( elem, el ) { +var documentElement = document.documentElement; - // isHidden might be called from jQuery#filter function; + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; // in that case, element will be second argument elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || - !jQuery.contains( elem.ownerDocument, elem ); + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; }; function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, - scale = 1, + var adjusted, scale, maxIterations = 20, currentValue = tween ? - function() { return tween.cur(); } : - function() { return jQuery.css( elem, prop, "" ); }, + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, initial = currentValue(), unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), // Starting value computation is required for potential unit mismatches - initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && rcssNum.exec( jQuery.css( elem, prop ) ); if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + // Trust units reported by jQuery.css unit = unit || initialInUnit[ 3 ]; - // Make sure we update the tween properties later on - valueParts = valueParts || []; - // Iteratively approximate from a nonzero starting point initialInUnit = +initial || 1; - do { + while ( maxIterations-- ) { - // If previous iteration zeroed out, double until we get *something*. - // Use string for doubling so we don't accidentally see scale as unchanged below - scale = scale || ".5"; - - // Adjust and apply - initialInUnit = initialInUnit / scale; + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; - // Update scale, tolerating zero or NaN from tween.cur() - // Break the loop if scale is unchanged or perfect, or if we've just had enough. - } while ( - scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations - ); + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; } if ( valueParts ) { @@ -4238,20 +4803,145 @@ function adjustCSS( elem, prop, valueParts, tween ) { } return adjusted; } + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); var rcheckableType = ( /^(?:checkbox|radio)$/i ); -var rtagName = ( /<([\w:-]+)/ ); +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); -var rscriptType = ( /^$|\/(?:java|ecma)script/i ); +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + // We have to close these tags to support XHTML (#13200) var wrapMap = { - // Support: IE9 - option: [ 1, "" ], - // XHTML parsers do not magically insert elements in the // same way that tag soup parsers do. So we cannot shorten // this by omitting or other required elements. @@ -4263,26 +4953,36 @@ var wrapMap = { _default: [ 0, "", "" ] }; -// Support: IE9 -wrapMap.optgroup = wrapMap.option; - wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + function getAll( context, tag ) { - // Support: IE9-11+ + // Support: IE <=9 - 11 only // Use typeof to avoid zero-argument method invocation on host objects (#15151) - var ret = typeof context.getElementsByTagName !== "undefined" ? - context.getElementsByTagName( tag || "*" ) : - typeof context.querySelectorAll !== "undefined" ? - context.querySelectorAll( tag || "*" ) : - []; + var ret; - return tag === undefined || tag && jQuery.nodeName( context, tag ) ? - jQuery.merge( [ context ], ret ) : - ret; + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; } @@ -4304,7 +5004,7 @@ function setGlobalEval( elems, refElements ) { var rhtml = /<|&#?\w+;/; function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, contains, j, + var elem, tmp, tag, wrap, attached, j, fragment = context.createDocumentFragment(), nodes = [], i = 0, @@ -4316,9 +5016,9 @@ function buildFragment( elems, context, scripts, selection, ignored ) { if ( elem || elem === 0 ) { // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { + if ( toType( elem ) === "object" ) { - // Support: Android<4.1, PhantomJS<2 + // Support: Android <=4.0 only, PhantomJS 1 only // push.apply(_, arraylike) throws on ancient WebKit jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); @@ -4341,7 +5041,7 @@ function buildFragment( elems, context, scripts, selection, ignored ) { tmp = tmp.lastChild; } - // Support: Android<4.1, PhantomJS<2 + // Support: Android <=4.0 only, PhantomJS 1 only // push.apply(_, arraylike) throws on ancient WebKit jQuery.merge( nodes, tmp.childNodes ); @@ -4368,13 +5068,13 @@ function buildFragment( elems, context, scripts, selection, ignored ) { continue; } - contains = jQuery.contains( elem.ownerDocument, elem ); + attached = isAttached( elem ); // Append to fragment tmp = getAll( fragment.appendChild( elem ), "script" ); // Preserve script evaluation history - if ( contains ) { + if ( attached ) { setGlobalEval( tmp ); } @@ -4393,36 +5093,7 @@ function buildFragment( elems, context, scripts, selection, ignored ) { } -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0-4.3, Safari<=5.1 - // Check state lost if the name is set (#11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Safari<=5.1, Android<4.2 - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE<=11+ - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; -} )(); - - -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; function returnTrue() { return true; @@ -4432,8 +5103,19 @@ function returnFalse() { return false; } -// Support: IE9 -// See #13393 for more info +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 function safeActiveElement() { try { return document.activeElement; @@ -4516,8 +5198,8 @@ jQuery.event = { special, handlers, type, namespaces, origType, elemData = dataPriv.get( elem ); - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { return; } @@ -4528,6 +5210,12 @@ jQuery.event = { selector = handleObjIn.selector; } + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + // Make sure that the handler has a unique ID, used to find/remove it later if ( !handler.guid ) { handler.guid = jQuery.guid++; @@ -4535,7 +5223,7 @@ jQuery.event = { // Init the element's event structure and main handler, if this is the first if ( !( events = elemData.events ) ) { - events = elemData.events = {}; + events = elemData.events = Object.create( null ); } if ( !( eventHandle = elemData.handle ) ) { eventHandle = elemData.handle = function( e ) { @@ -4548,7 +5236,7 @@ jQuery.event = { } // Handle multiple events separated by a space - types = ( types || "" ).match( rnotwhite ) || [ "" ]; + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[ t ] ) || []; @@ -4630,7 +5318,7 @@ jQuery.event = { } // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnotwhite ) || [ "" ]; + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[ t ] ) || []; @@ -4691,19 +5379,26 @@ jQuery.event = { } }, - dispatch: function( event ) { + dispatch: function( nativeEvent ) { - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event ); + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), - var i, j, ret, matched, handleObj, - handlerQueue = [], - args = slice.call( arguments ), - handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], special = jQuery.event.special[ event.type ] || {}; // Use the fix-ed jQuery.Event rather than the (read-only) native event args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + event.delegateTarget = this; // Call the preDispatch hook for the mapped type, and let it bail if desired @@ -4723,9 +5418,10 @@ jQuery.event = { while ( ( handleObj = matched.handlers[ j++ ] ) && !event.isImmediatePropagationStopped() ) { - // Triggered event must either 1) have no namespace, or 2) have namespace(s) - // a subset or equal to those in the bound event (both can have no namespace). - if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { event.handleObj = handleObj; event.data = handleObj.data; @@ -4752,146 +5448,95 @@ jQuery.event = { }, handlers: function( event, handlers ) { - var i, matches, sel, handleObj, + var i, handleObj, sel, matchedHandlers, matchedSelectors, handlerQueue = [], delegateCount = handlers.delegateCount, cur = event.target; - // Support (at least): Chrome, IE9 // Find delegate handlers - // Black-hole SVG instance trees (#13180) - // - // Support: Firefox<=42+ - // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343) - if ( delegateCount && cur.nodeType && - ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) { + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { for ( ; cur !== this; cur = cur.parentNode || this ) { // Don't check non-elements (#13208) // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) { - matches = []; + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; // Don't conflict with Object.prototype properties (#13203) sel = handleObj.selector + " "; - if ( matches[ sel ] === undefined ) { - matches[ sel ] = handleObj.needsContext ? + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? jQuery( sel, this ).index( cur ) > -1 : jQuery.find( sel, this, null, [ cur ] ).length; } - if ( matches[ sel ] ) { - matches.push( handleObj ); + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); } } - if ( matches.length ) { - handlerQueue.push( { elem: cur, handlers: matches } ); + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); } } } } // Add the remaining (directly-bound) handlers + cur = this; if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } ); + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); } return handlerQueue; }, - // Includes some event props shared by KeyEvent and MouseEvent - props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " + - "metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ), + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, - fixHooks: {}, + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, - keyHooks: { - props: "char charCode key keyCode".split( " " ), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); } - - return event; - } + } ); }, - mouseHooks: { - props: ( "button buttons clientX clientY offsetX offsetY pageX pageY " + - "screenX screenY toElement" ).split( " " ), - filter: function( event, original ) { - var eventDoc, doc, body, - button = original.button; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + - ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + - ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, copy, - type = event.type, - originalEvent = event, - fixHook = this.fixHooks[ type ]; - - if ( !fixHook ) { - this.fixHooks[ type ] = fixHook = - rmouseEvent.test( type ) ? this.mouseHooks : - rkeyEvent.test( type ) ? this.keyHooks : - {}; - } - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = new jQuery.Event( originalEvent ); - - i = copy.length; - while ( i-- ) { - prop = copy[ i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Support: Cordova 2.5 (WebKit) (#13255) - // All events should have a target; Cordova deviceready doesn't - if ( !event.target ) { - event.target = document; - } - - // Support: Safari 6.0+, Chrome<28 - // Target should not be a text node (#504, #13143) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); }, special: { @@ -4900,39 +5545,51 @@ jQuery.event = { // Prevent triggered image.load events from bubbling to window.load noBubble: true }, - focus: { - - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - this.focus(); - return false; - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, click: { - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) { - this.click(); - return false; + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; }, - // For cross-browser consistency, don't fire native .click() on links + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack _default: function( event ) { - return jQuery.nodeName( event.target, "a" ); + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); } }, @@ -4949,6 +5606,99 @@ jQuery.event = { } }; +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + + // Support: Chrome 86+ + // In Chrome, if an element having a focusout handler is blurred by + // clicking outside of it, it invokes the handler synchronously. If + // that handler calls `.remove()` on the element, the data is cleared, + // leaving `result` undefined. We need to guard against this. + return result && result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + jQuery.removeEvent = function( elem, type, handle ) { // This "if" is needed for plain objects @@ -4974,11 +5724,21 @@ jQuery.Event = function( src, props ) { this.isDefaultPrevented = src.defaultPrevented || src.defaultPrevented === undefined && - // Support: Android<4.0 + // Support: Android <=2.3 only src.returnValue === false ? returnTrue : returnFalse; + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + // Event type } else { this.type = src; @@ -4990,26 +5750,27 @@ jQuery.Event = function( src, props ) { } // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); + this.timeStamp = src && src.timeStamp || Date.now(); // Mark it as fixed this[ jQuery.expando ] = true; }; // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html jQuery.Event.prototype = { constructor: jQuery.Event, isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse, + isSimulated: false, preventDefault: function() { var e = this.originalEvent; this.isDefaultPrevented = returnTrue; - if ( e ) { + if ( e && !this.isSimulated ) { e.preventDefault(); } }, @@ -5018,7 +5779,7 @@ jQuery.Event.prototype = { this.isPropagationStopped = returnTrue; - if ( e ) { + if ( e && !this.isSimulated ) { e.stopPropagation(); } }, @@ -5027,7 +5788,7 @@ jQuery.Event.prototype = { this.isImmediatePropagationStopped = returnTrue; - if ( e ) { + if ( e && !this.isSimulated ) { e.stopImmediatePropagation(); } @@ -5035,13 +5796,81 @@ jQuery.Event.prototype = { } }; +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + // Suppress native focus or blur as it's already being fired + // in leverageNative. + _default: function() { + return true; + }, + + delegateType: delegateType + }; +} ); + // Create mouseenter/leave events using mouseover/out and event-time checks // so that event delegation works in jQuery. // Do the same for pointerenter/pointerleave and pointerover/pointerout // // Support: Safari 7 only // Safari sends mouseenter too often; see: -// https://code.google.com/p/chromium/issues/detail?id=470258 +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 // for the description of the bug (it existed in older Chrome versions as well). jQuery.each( { mouseenter: "mouseover", @@ -5072,6 +5901,7 @@ jQuery.each( { } ); jQuery.fn.extend( { + on: function( types, selector, data, fn ) { return on( this, types, selector, data, fn ); }, @@ -5118,26 +5948,25 @@ jQuery.fn.extend( { var - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, - // Support: IE 10-11, Edge 10240+ + // Support: IE <=10 - 11, Edge 12 - 13 only // In IE/Edge using regex groups here causes severe slowdowns. // See https://connect.microsoft.com/IE/feedback/details/1736512/ rnoInnerhtml = /\s*$/g; -// Manipulating tables requires a tbody +// Prefer a tbody over its parent table for containing new rows function manipulationTarget( elem, content ) { - return jQuery.nodeName( elem, "table" ) && - jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - elem.getElementsByTagName( "tbody" )[ 0 ] || - elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) : - elem; + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; } // Replace/restore the type attribute of script elements for safe DOM manipulation @@ -5146,10 +5975,8 @@ function disableScript( elem ) { return elem; } function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - - if ( match ) { - elem.type = match[ 1 ]; + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); } else { elem.removeAttribute( "type" ); } @@ -5158,7 +5985,7 @@ function restoreScript( elem ) { } function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + var i, l, type, pdataOld, udataOld, udataCur, events; if ( dest.nodeType !== 1 ) { return; @@ -5166,13 +5993,11 @@ function cloneCopyEvent( src, dest ) { // 1. Copy private data: events, handlers, etc. if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.access( src ); - pdataCur = dataPriv.set( dest, pdataOld ); + pdataOld = dataPriv.get( src ); events = pdataOld.events; if ( events ) { - delete pdataCur.handle; - pdataCur.events = {}; + dataPriv.remove( dest, "handle events" ); for ( type in events ) { for ( i = 0, l = events[ type ].length; i < l; i++ ) { @@ -5208,22 +6033,22 @@ function fixInput( src, dest ) { function domManip( collection, args, callback, ignored ) { // Flatten any nested arrays - args = concat.apply( [], args ); + args = flat( args ); var fragment, first, scripts, hasScripts, node, doc, i = 0, l = collection.length, iNoClone = l - 1, value = args[ 0 ], - isFunction = jQuery.isFunction( value ); + valueIsFunction = isFunction( value ); // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || + if ( valueIsFunction || ( l > 1 && typeof value === "string" && !support.checkClone && rchecked.test( value ) ) ) { return collection.each( function( index ) { var self = collection.eq( index ); - if ( isFunction ) { + if ( valueIsFunction ) { args[ 0 ] = value.call( this, index, self.html() ); } domManip( self, args, callback, ignored ); @@ -5255,7 +6080,7 @@ function domManip( collection, args, callback, ignored ) { // Keep references to cloned scripts for later restoration if ( hasScripts ) { - // Support: Android<4.1, PhantomJS<2 + // Support: Android <=4.0 only, PhantomJS 1 only // push.apply(_, arraylike) throws on ancient WebKit jQuery.merge( scripts, getAll( node, "script" ) ); } @@ -5277,14 +6102,16 @@ function domManip( collection, args, callback, ignored ) { !dataPriv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) { - if ( node.src ) { + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl ) { - jQuery._evalUrl( node.src ); + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); } } else { - jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) ); + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); } } } @@ -5306,7 +6133,7 @@ function remove( elem, selector, keepData ) { } if ( node.parentNode ) { - if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + if ( keepData && isAttached( node ) ) { setGlobalEval( getAll( node, "script" ) ); } node.parentNode.removeChild( node ); @@ -5318,19 +6145,19 @@ function remove( elem, selector, keepData ) { jQuery.extend( { htmlPrefilter: function( html ) { - return html.replace( rxhtmlTag, "<$1>" ); + return html; }, clone: function( elem, dataAndEvents, deepDataAndEvents ) { var i, l, srcElements, destElements, clone = elem.cloneNode( true ), - inPage = jQuery.contains( elem.ownerDocument, elem ); + inPage = isAttached( elem ); // Fix IE cloning issues if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) { - // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 destElements = getAll( clone ); srcElements = getAll( elem ); @@ -5383,13 +6210,13 @@ jQuery.extend( { } } - // Support: Chrome <= 35-45+ + // Support: Chrome <=35 - 45+ // Assign undefined instead of using delete, see Data#remove elem[ dataPriv.expando ] = undefined; } if ( elem[ dataUser.expando ] ) { - // Support: Chrome <= 35-45+ + // Support: Chrome <=35 - 45+ // Assign undefined instead of using delete, see Data#remove elem[ dataUser.expando ] = undefined; } @@ -5399,10 +6226,6 @@ jQuery.extend( { } ); jQuery.fn.extend( { - - // Keep domManip exposed until 3.0 (gh-2225) - domManip: domManip, - detach: function( selector ) { return remove( this, selector, true ); }, @@ -5560,86 +6383,19 @@ jQuery.each( { elems = i === last ? this : this.clone( true ); jQuery( insert[ i ] )[ original ]( elems ); - // Support: QtWebKit - // .get() because push.apply(_, arraylike) throws + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit push.apply( ret, elems.get() ); } return this.pushStack( ret ); }; } ); - - -var iframe, - elemdisplay = { - - // Support: Firefox - // We have to pre-define these values for FF (#10227) - HTML: "block", - BODY: "block" - }; - -/** - * Retrieve the actual display of a element - * @param {String} name nodeName of the element - * @param {Object} doc Document object - */ - -// Called only from within defaultDisplay -function actualDisplay( name, doc ) { - var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), - - display = jQuery.css( elem[ 0 ], "display" ); - - // We don't have any data stored on the element, - // so use "detach" method as fast way to get rid of the element - elem.detach(); - - return display; -} - -/** - * Try to determine the default display value of an element - * @param {String} nodeName - */ -function defaultDisplay( nodeName ) { - var doc = document, - display = elemdisplay[ nodeName ]; - - if ( !display ) { - display = actualDisplay( nodeName, doc ); - - // If the simple way fails, read from inside an iframe - if ( display === "none" || !display ) { - - // Use the already-created iframe if possible - iframe = ( iframe || jQuery( "