Service Under Maintenance

North American PoPs Operational
Ashburn, VA (IAD) Operational
Atlanta, GA (ATL) Operational
Chicago 1, IL (ORD) Operational
Chicago 2, IL (CHI) Operational
Dallas, TX (DFW) Operational
Denver, CO (DEN) Operational
Detroit, MI (DET) Operational
Houston, TX (HOU) Operational
Los Angeles, CA (LAX) Operational
Miami, FL (MIA) Operational
Montreal, Canada (YUL) Operational
New York 1, NY (NYC) Operational
New York 2, NY (EWR) Operational
San Jose, CA (SJC) Operational
Seattle, WA (SEA) Operational
Toronto, Canada (TOR) Operational
Vancouver, Canada (VAN) Operational
EMEA PoPs Operational
Amsterdam, Netherlands (AMS) Operational
Barcelona, Spain (BCN) Operational
Cape Town, South Africa (CPT) Operational
Copenhagen, Denmark (CPH) Operational
Dubai, UAE (DWC) Operational
Dublin, Ireland (DUB) Operational
Dusseldorf, Germany (DUS) Operational
Frankfurt, Germany (FRA) Operational
Istanbul, Turkey (SAW) Operational
Johannesburg, South Africa (QRA) Operational
London 1, UK (LON) Operational
London 2, UK (LHR) Operational
Madrid, Spain (MAD) Operational
Milan, Italy (MXP) Operational
Paris, France (CDG) Operational
Paris, France (PAR) Operational
Stockholm, Sweden (STO) Operational
Tel Aviv, Israel (MED) Operational
Vienna, Austria (GRZ) Operational
Warsaw, Poland (WAR) Operational
Zurich, Switzerland (ZRH) Operational
LATAM PoPs Operational
Bogota, Colombia (BOG) Operational
Buenos Aires, Argentina (EZE) Operational
Lima, Peru (LIM) Operational
Queretaro, Mexico (QRO) Operational
Rio de Janeiro, Brazil (RIO) Operational
Santiago, Chile (STC) Operational
Sao Paulo, Brazil (SAO) Operational
APAC PoPs Operational
Auckland, New Zealand (AKL) Operational
Bangkok, Thailand (DMK) Operational
Hanoi, Vietnam (HAN) Operational
Hong Kong (HKG) Operational
Jakarta, Indonesia (JKT) Operational
Kuala Lumpur, Malaysia (KUL) Operational
Melbourne, Australia (MEB) Operational
Melbourne, Australia (MEL) Operational
Manila, Philippines (MNL) Operational
Mumbai, India (BOM) Operational
New Delhi, India (NDL) Operational
Osaka, Japan (OSK) Operational
Seoul, South Korea (KOR) Operational
Singapore (SIN) Operational
Sydney, Australia (SYD) Operational
Taipei, Taiwan (TSA) Operational
Tokyo, Japan (TKO) Operational
Services Operational
Imperva Management Portal UI Operational
Imperva Management Portal API Operational
Imperva Management Portal- Configuration Changes Operational
Cloud WAF Network Operational
IP Protection Operational
Advanced Bot Protection Operational
Account Take Over Operational
DNS Protection Operational
JSONAR Operational
Client-Side Protection Operational
Cloud WAF GDPR Operational
Cloud WAF SIEM Operational
Cloud WAF Events & Statistics Operational
Attack Analytics Operational
Cloud Data Security Operational
Runtime Application Self Protection Operational
API Security Operational
Imperva Support - Ticketing and Phone Systems Operational
Weblogs Operational
Third Party Services Operational
Third Party Services Operational
Coming Soon Under Maintenance
Hong Kong (HHK) - August 2025 Under Maintenance
London (LCY) - September 2025 Under Maintenance
Los Angeles (SNA) - September 2025 Under Maintenance
Mumbai (NAG) - August 2025 Under Maintenance
San Jose (SFO) - September 2025 Under Maintenance
Zurich (GVA) - September 2025 Under Maintenance
Operational
Degraded Performance
Partial Outage
Major Outage
Maintenance

Scheduled Maintenance

[ICM-3747] CDG PoP Migration to PAR -Paris, France Aug 5, 2025 21:00 - Aug 6, 2025 07:00 UTC

As part of our commitment to building a future-facing network, Imperva recently launched our Next Generation Architecture in the PAR - Paris, France PoP with improved capacity, connectivity, and services. This PoP is replacing our currently operational PoP in CDG – Paris, France. Imperva will be migrating all services and customer traffic from our CDG PoP to our PAR PoP, and decommissioning our CDG PoP during a scheduled maintenance window which will begin August 5 21:00 UTC, completing by August 6 07:00 UTC.
For Cloud WAF customers, Imperva will reroute traffic to an unaffected PoP in the region for the duration of the maintenance, with no expected interruption to Cloud WAF services. At the end of the maintenance, traffic will be serviced by the new PoP. DDoS Protection for Networks customers must ensure that the advertisement of their ranges via an alternate connection such as GRE tunnels or Cross-Connects is in place prior to the start of maintenance to avoid interruption of service. At the end of the maintenance, DDoS Protection traffic will be serviced by the new PoP. If Performance Monitoring is enabled on the connections, you will notice a change in the IP address of the PM servers that are sending ICMP echo messages. This might require you to modify ACL/firewall configurations to allow ICMP traffic from the new IPs. To learn more, see https://docs.imperva.com/bundle/cloud-application-security/page/network-ddos/performance-monitoring.html

Posted on Jul 28, 2025 - 15:44 UTC

[ICM-3871/ICM-3872] HKG to HHK PoP Migration - Hong Kong, Hong Kong Aug 6, 2025 16:00 - Aug 7, 2025 02:00 UTC

As part of our commitment to building a future-facing network, Imperva recently launched our Next Generation Architecture in the HHK - Hong Kong PoP with improved capacity, connectivity, and services. This PoP is replacing our currently operational PoP in HKG – Hong Kong. Imperva will be migrating all services and customer traffic from our HKG PoP to our HHK PoP, and decommissioning our HKG PoP during a scheduled maintenance window which will begin August 6th, 2025 16:00 UTC, completing by August 7th, 2025 02:00 UTC.

For Cloud WAF customers, Imperva will reroute traffic to an unaffected PoP in the region for the duration of the maintenance, with no expected interruption to Cloud WAF services. At the end of the maintenance, traffic will be serviced by the new PoP.

DDoS Protection for Networks customers must ensure that the advertisement of their ranges via an alternate connection such as GRE tunnels or Cross-Connects is in place prior to the start of maintenance to avoid interruption of service. At the end of the maintenance, DDoS Protection traffic will be serviced by the new PoP. If Performance Monitoring is enabled on the connections, you will notice a change in the IP address of the PM servers that are sending ICMP echo messages. This might require you to modify ACL/firewall configurations to allow ICMP traffic from the new IPs. To learn more, see https://docs.imperva.com/bundle/cloud-application-security/page/network-ddos/performance-monitoring.htm

Posted on Jul 30, 2025 - 19:56 UTC

[ICM-3929] Planned Maintenance on the Imperva data center in New Delhi, India Aug 7, 2025 18:00 - Aug 8, 2025 02:00 UTC

Update - Maintenance on the New Delhi, India data center will be performed on Thursday, August 7th, 2025 at 18:00 UTC. We expect to complete the maintenance by Friday, August 8th, 2025 at 02:00 UTC.
For Cloud WAF customers, Imperva will reroute traffic to the closest data center for the duration of the maintenance, with no expected interruption of Cloud WAF services.
DDoS Protection for Networks customers must ensure that the advertisement of their ranges via alternate connection such as GRE tunnels and Cross-Connects is in place prior to the start of maintenance to avoid interruption of service.
The link to Imperva's documentation can be found here: https://docs.imperva.com/bundle/cloud-application-security/page/network-ddos/maintenance-prep.htm

Jul 30, 2025 - 21:27 UTC
Scheduled - Maintenance on the New Delhi, India data center will be performed on Wednesday, August 6th, 2025 at 18:00 UTC. We expect to complete the maintenance by Thursday, August 7th, 2025 at 02:00 UTC.
For Cloud WAF customers, Imperva will reroute traffic to the closest data center for the duration of the maintenance, with no expected interruption of Cloud WAF services.
DDoS Protection for Networks customers must ensure that the advertisement of their ranges via alternate connection such as GRE tunnels and Cross-Connects is in place prior to the start of maintenance to avoid interruption of service.
The link to Imperva's documentation can be found here: https://docs.imperva.com/bundle/cloud-application-security/page/network-ddos/maintenance-prep.htm

Jul 28, 2025 - 19:51 UTC
Aug 4, 2025
Completed - The scheduled maintenance has been completed.
Aug 4, 02:54 UTC
In progress - Scheduled maintenance is currently in progress. We will provide updates as necessary.
Aug 3, 23:00 UTC
Scheduled - Maintenance on the Warsaw, Poland data center will be performed on Sunday, August 3rd, 2025 at 23:00 UTC. We expect to complete the maintenance by Monday, August 4th, 2025 at 05:00 UTC.
For Cloud WAF customers, Imperva will reroute traffic to the closest data center for the duration of the maintenance, with no expected interruption of Cloud WAF services.
DDoS Protection for Networks customers must ensure that the advertisement of their ranges via alternate connection such as GRE tunnels and Cross-Connects is in place prior to the start of maintenance to avoid interruption of service.
The link to Imperva's documentation can be found here: https://docs.imperva.com/bundle/cloud-application-security/page/network-ddos/maintenance-prep.htm

Jul 21, 14:46 UTC
Aug 3, 2025
Aug 2, 2025
Resolved - A fix has been implemented, and services have returned to normal. Monitoring confirms stability.
Aug 2, 01:00 UTC
Monitoring - A fix has been implemented, and services are gradually returning to normal. We are currently monitoring to ensure stability.
Aug 2, 00:28 UTC
Update - We are continuing to investigate this issue.
Aug 1, 23:54 UTC
Investigating - We have identified a service degradation impacting customers using Account Takeover (ATO) and Client Side Protection (CSP). The ATO and CSP dashboards on the Management Portal are currently not loading. Our technical teams are actively investigating the issue. Further updates to follow.

The status updates are an integral part of proactive monitoring and transparent communication about the status of our cloud services. Imperva investigates and attributes a status to all detected events that may or may not affect availability of the service.

In the event of a service disruption, the update will include potential impacts to any affected region.

Aug 1, 23:08 UTC
Aug 1, 2025
Jul 31, 2025

No incidents reported.

Jul 30, 2025
Resolved - The incident has been resolved and normal service levels have been restored for the Imperva Management Portal.

The status updates are an integral part of proactive monitoring and transparent communication about the status of our cloud services. Imperva investigates and attributes a status to all detected events that may or may not affect availability of the service.

In the event of a service disruption, the update will include potential impacts to any affected region.

Jul 30, 02:04 UTC
Monitoring - Technical teams have performed remedial actions and the Imperva Management Portal is returning to normal service levels. Technical teams will continue monitoring the system. Further updates to follow.

The status updates are an integral part of proactive monitoring and transparent communication about the status of our cloud services. Imperva investigates and attributes a status to all detected events that may or may not affect availability of the service.

In the event of a service disruption, the update will include potential impacts to any affected region.

Jul 30, 01:54 UTC
Identified - We have identified the source of the service degradation affecting customers ability to access the Imperva Management Portal. Technical teams are investigating. Further updates to follow.

The status updates are an integral part of proactive monitoring and transparent communication about the status of our cloud services. Imperva investigates and attributes a status to all detected events that may or may not affect availability of the service.

In the event of a service disruption, the update will include potential impacts to any affected region.

Jul 30, 01:38 UTC
Update - We are continuing to investigate this issue.
Jul 30, 01:07 UTC
Investigating - We have discovered a potential service degradation, affecting customers ability to log in to the Imperva Management Portal. Technical teams are investigating. Further updates to follow.

The status updates are an integral part of proactive monitoring and transparent communication about the status of our cloud services. Imperva investigates and attributes a status to all detected events that may or may not affect availability of the service.

In the event of a service disruption, the update will include potential impacts to any affected region.

Jul 30, 00:50 UTC
Jul 29, 2025
Completed - The scheduled maintenance has been completed.
Jul 29, 10:39 UTC
In progress - Scheduled maintenance is currently in progress. We will provide updates as necessary.
Jul 29, 04:00 UTC
Scheduled - Maintenance on the Bogota, Colombia data center will be performed on Tuesday, July 29th, 2025 at 04:00 UTC. We expect to complete the maintenance by Tuesday, July 29th, 2025 at 12:00 UTC.
For Cloud WAF customers, Imperva will reroute traffic to the closest data center for the duration of the maintenance, with no expected interruption of Cloud WAF services.
DDoS Protection for Networks customers must ensure that the advertisement of their ranges via alternate connection such as GRE tunnels and Cross-Connects is in place prior to the start of maintenance to avoid interruption of service.
The link to Imperva's documentation can be found here: https://docs.imperva.com/bundle/cloud-application-security/page/network-ddos/maintenance-prep.htm

Jul 17, 12:45 UTC
Jul 28, 2025

No incidents reported.

Jul 27, 2025

No incidents reported.

Jul 26, 2025
Completed - The scheduled maintenance has been completed.
Jul 26, 23:00 UTC
Verifying - Verification is currently underway for the maintenance items.
Jul 26, 22:56 UTC
Update - Maintenance on the (MEL to MEB PoP Migration - Melbourne, Australia) data center has been extended 1 hour to 27-Jul-2025 00:00 UTC.
Jul 26, 22:25 UTC
In progress - Scheduled maintenance is currently in progress. We will provide updates as necessary.
Jul 26, 13:00 UTC
Scheduled - As part of our commitment to building a future-facing network, Imperva recently launched our Next Generation Architecture in the MEB- Melbourne, Australia PoP with improved capacity, connectivity, and services. This PoP is replacing our currently operational PoP in MEL – Melbourne, Australia . Imperva will be migrating all services and customer traffic from our MEL Pop to our MEB PoP, and decommissioning our MEL PoP during a scheduled maintenance window which will begin July 26th at 13:00 UTC, completing by July 26th at 23:00 UTC.

For Cloud WAF customers, Imperva will reroute traffic to an unaffected PoP in the region for the duration of the maintenance, with no expected interruption to Cloud WAF services. At the end of the maintenance, traffic will be serviced by the new PoP.

DDoS Protection for Networks customers must ensure that the advertisement of their ranges via an alternate connection such as GRE tunnels or Cross-Connects is in place prior to the start of maintenance to avoid interruption of service. At the end of the maintenance, DDoS Protection traffic will be serviced by the new PoP. If Performance Monitoring is enabled on the connections, you will notice a change in the IP address of the PM servers that are sending ICMP echo messages. This might require you to modify ACL/firewall configurations to allow ICMP traffic from the new IPs. To learn more, see https://docs.imperva.com/bundle/cloud-application-security/page/network-ddos/performance-monitoring.html

Jul 18, 15:47 UTC
Jul 25, 2025

No incidents reported.

Jul 24, 2025
Completed - The scheduled maintenance has been completed.
Jul 24, 20:07 UTC
Verifying - Verification is currently underway for the maintenance items.
Jul 24, 19:50 UTC
In progress - Scheduled maintenance is currently in progress. We will provide updates as necessary.
Jul 24, 15:00 UTC
Scheduled - Maintenance on the Tokyo, Japan data center will be performed on Thursday, July 24th, 2025 at 15:00 UTC. We expect to complete the maintenance by Thursday, July 24th, 2025 at 23:00 UTC.
For Cloud WAF customers, Imperva will reroute traffic to the closest data center for the duration of the maintenance, with no expected interruption of Cloud WAF services.
DDoS Protection for Networks customers must ensure that the advertisement of their ranges via alternate connection such as GRE tunnels and Cross-Connects is in place prior to the start of maintenance to avoid interruption of service.
The link to Imperva's documentation can be found here: https://docs.imperva.com/bundle/cloud-application-security/page/network-ddos/maintenance-prep.htm

Jul 16, 21:57 UTC
Jul 23, 2025
Resolved - This incident has been fixed.
Jul 23, 22:09 UTC
Monitoring - A fix has been implemented and we are monitoring the result.
Jul 23, 21:56 UTC
Update - Due to an issue in the data center, traffic continues to be rerouted through an alternate data center in the region. Our teams are actively working to resolve the issue and restore normal service.

The status updates are an integral part of proactive monitoring and transparent communication about the status of our cloud services. Imperva investigates and attributes a status to all detected events that may or may not affect availability of the service.

In the event of a service disruption, the update will include potential impacts to any affected region.

Jul 23, 20:02 UTC
Identified - We have identified an issue in the Singapore data center. Traffic is being rerouted through an alternate data center in the region. Customers may encounter some latency for the duration of time that the reroute is in place.

The status updates are an integral part of proactive monitoring and transparent communication about the status of our cloud services. Imperva investigates and attributes a status to all detected events that may or may not affect availability of the service.

In the event of a service disruption, the update will include potential impacts to any affected region.

Jul 23, 18:52 UTC
Completed - The scheduled maintenance has been completed.
Jul 23, 08:49 UTC
In progress - Scheduled maintenance is currently in progress. We will provide updates as necessary.
Jul 23, 03:00 UTC
Scheduled - Maintenance on the Buenos Aires, Argentina data center will be performed on Wednesday, July 23rd, 2025 at 03:00 UTC. We expect to complete the maintenance by Wednesday, July 23rd, 2025 at 11:00 UTC.
For Cloud WAF customers, Imperva will reroute traffic to the closest data center for the duration of the maintenance, with no expected interruption of Cloud WAF services.
DDoS Protection for Networks customers must ensure that the advertisement of their ranges via alternate connection such as GRE tunnels and Cross-Connects is in place prior to the start of maintenance to avoid interruption of service.
The link to Imperva's documentation can be found here: https://docs.imperva.com/bundle/cloud-application-security/page/network-ddos/maintenance-prep.htm

Jul 8, 02:13 UTC
Jul 22, 2025
Completed - The scheduled maintenance has been completed.
Jul 22, 12:33 UTC
Update - Maintenance on the Ashburn, VA data center has been extended to Tuesday, July 22nd, 2025 at 13:00 UTC
Jul 22, 10:41 UTC
In progress - Scheduled maintenance is currently in progress. We will provide updates as necessary.
Jul 22, 03:00 UTC
Scheduled - Maintenance on the Ashburn, VA data center will be performed on Tuesday, July 22nd, 2025 at 03:00 UTC. We expect to complete the maintenance by Tuesday, July 22nd, 2025 at 11:00 UTC.
For Cloud WAF customers, Imperva will reroute traffic to the closest data center for the duration of the maintenance, with no expected interruption of Cloud WAF services.
DDoS Protection for Networks customers must ensure that the advertisement of their ranges via alternate connection such as GRE tunnels and Cross-Connects is in place prior to the start of maintenance to avoid interruption of service.
The link to Imperva's documentation can be found here: https://docs.imperva.com/bundle/cloud-application-security/page/network-ddos/maintenance-prep.htm

Jul 7, 07:23 UTC
Jul 21, 2025

No incidents reported.

', tooltipSelector: '.icon-tooltip-content', positionTypeX: 'center', positionTypeY: 'top', attribute:'data-title', extraOffsetX: 0, extraOffsetY: 10, showOnTouchDevice: false }); } //pops filtration on status page function initPopsFiltration() { var win = jQuery(window), page = jQuery('html,body'); jQuery('.components-section').each(function() { var filterHolder = jQuery(this), filterRowsHolder = filterHolder.find('.components-container.one-column'), filterRows = filterHolder.find('.component-container.is-group '), filterItemContainer = filterRows.find('.child-components-container'), filterItems = filterItemContainer.find('.component-inner-container'), filterBtnsContainer = filterHolder.find('.component-statuses-legend'), filterBtns = filterBtnsContainer.find('.legend-item'), filteredItemClass = 'filtered-item', visibleItemClass = 'visible-item', filteredRowClass = 'filtered-row', emptyRowClass = 'empty-row', filteredSectionClass = 'filtered-section', activeClass = 'active', filterHolderOffsetTop = filterHolder.closest('.container').offset().top, scrollTop, timer; //create holder for message var filterMsgHold = jQuery('
'); filterMsgHold.addClass('filter-msg-holder') .appendTo(filterRowsHolder); filterBtns.each(function(){ var btn = jQuery(this); findFilterClass(btn); if(btn.hasClass(activeClass)) { filterItemsFn(btn); checkRowClass(); checkFilteredRows(); } }); filterBtns.on('click', function(e) { var target = jQuery(e.target); if (!target.hasClass('legend-item')) { target = target.closest('legend-item'); } filterItemsFn(target); scrollToTop(); }); function findFilterClass(item) { var classes = item.attr('class').split(' '), classPartName = 'status'; for (var i = 0; i < classes.length; i++) { var matches = /^status\-(.+)/.exec(classes[i]); if (matches != null) { var statusclass = matches[1]; } } item.attr('data-filter', classPartName + '-' + statusclass); } function filterItemsFn(filterBtn) { if(filterBtn.hasClass(activeClass)) { filterBtn.removeClass(activeClass); removeFilterClassFn(filterBtn); checkRowClass(); checkActiveFilter(); checkFilteredRows(); } else { addFilterClassFn(filterBtn); checkRowClass(); checkFilteredRows(); } } function addFilterClassFn(filterBtn) { var filterClass = filterBtn.data('filter'); filterBtn.addClass(activeClass); filterItems.addClass(filteredItemClass); filterItems.filter('.' + filterBtn.data('filter')).addClass(visibleItemClass); filterHolder.addClass(filteredSectionClass); } function removeFilterClassFn(filterBtn) { filterItems.filter('.' + filterBtn.data('filter')).removeClass(visibleItemClass); } function checkRowClass() { filterRows .removeClass(emptyRowClass) .removeClass(filteredRowClass) .each(function(){ var row = jQuery(this); if (row.find('.' + visibleItemClass).length !==0 ) { row.addClass(filteredRowClass); } else { row.addClass(emptyRowClass); } }); } function checkActiveFilter() { if(filterBtns.filter('.' + activeClass).length === 0) { filterHolder.removeClass(filteredSectionClass); filterRows.removeClass(filteredRowClass); filterRows.removeClass(emptyRowClass); filterItems.removeClass(filteredItemClass).removeClass(visibleItemClass); } } function checkFilteredRows() { var filteredRowsLength = filterRows.filter('.' + filteredRowClass).length, activeBtns = filterBtns.filter('.' + activeClass), activeBtnsLength = activeBtns.length; var btnsTextArr = []; if(filteredRowsLength === 0 && activeBtnsLength !== 0) { filterMsgHold.addClass(visibleItemClass); activeBtns.each(function() { btnsTextArr.push('"' + jQuery(this).text().trim() + '"'); filterMsgHold.html('No ' + btnsTextArr.join(', ') + ' results.'); }); } else { filterMsgHold.removeClass(visibleItemClass); filterMsgHold.html(''); } } win.on('load scroll', function(){ scrollTop = win.scrollTop(); }); jQuery(window).on('resize orientationchange', function() { clearTimeout(timer); timer = setTimeout(function() { filterHolderOffsetTop = filterHolder.closest('.container').offset().top }, 50); }); function scrollToTop() { // start scrolling animation if(scrollTop > filterHolderOffsetTop) { page.stop().animate({ scrollTop: 0 }, 400); } } }); } //change text in filter btn on history page function initRenameFilterBtn() { jQuery('.history-backpage').each(function() { var holder = jQuery(this), filterBtn = holder.find('.show-filter'); var filterTextSpan = jQuery(''), arrowIcon = jQuery(''); filterBtn.html(''); filterTextSpan.text('Select Data Centers'); filterTextSpan.appendTo(filterBtn); arrowIcon .addClass('fa') .addClass('fa-chevron-down') .appendTo(filterBtn); }); } //init of range filtration on history page function initFilterRangePicker() { jQuery('.status-full-history').filterRangePicker(); } /* jQuery Tabs plugin */ ;(function($, $win) { 'use strict'; function Tabset($holder, options) { this.$holder = $holder; this.options = options; this.init(); } Tabset.prototype = { init: function() { this.$tabLinks = this.$holder.find(this.options.tabLinks); this.setStartActiveIndex(); this.setActiveTab(); if (this.options.autoHeight) { this.$tabHolder = $(this.$tabLinks.eq(0).attr(this.options.attrib)).parent(); } this.makeCallback('onInit', this); }, setStartActiveIndex: function() { var $classTargets = this.getClassTarget(this.$tabLinks); var $activeLink = $classTargets.filter('.' + this.options.activeClass); var $hashLink = this.$tabLinks.filter('[' + this.options.attrib + '="' + location.hash + '"]'); var activeIndex; if (this.options.checkHash && $hashLink.length) { $activeLink = $hashLink; } activeIndex = $classTargets.index($activeLink); this.activeTabIndex = this.prevTabIndex = (activeIndex === -1 ? (this.options.defaultTab ? 0 : null) : activeIndex); }, setActiveTab: function() { var self = this; this.$tabLinks.each(function(i, link) { var $link = $(link); var $classTarget = self.getClassTarget($link); var $tab = $($link.attr(self.options.attrib)); if (i !== self.activeTabIndex) { $classTarget.removeClass(self.options.activeClass); $tab.addClass(self.options.tabHiddenClass).removeClass(self.options.activeClass); } else { $classTarget.addClass(self.options.activeClass); $tab.removeClass(self.options.tabHiddenClass).addClass(self.options.activeClass); } self.attachTabLink($link, i); }); }, attachTabLink: function($link, i) { var self = this; $link.on(this.options.event + '.tabset', function(e) { e.preventDefault(); if (self.activeTabIndex === self.prevTabIndex && self.activeTabIndex !== i) { self.activeTabIndex = i; self.switchTabs(); } if (self.options.checkHash) { location.hash = jQuery(this).attr('href').split('#')[1] } }); }, resizeHolder: function(height) { var self = this; if (height) { this.$tabHolder.height(height); setTimeout(function() { self.$tabHolder.addClass('transition'); }, 10); } else { self.$tabHolder.removeClass('transition').height(''); } }, switchTabs: function() { var self = this; var $prevLink = this.$tabLinks.eq(this.prevTabIndex); var $nextLink = this.$tabLinks.eq(this.activeTabIndex); var $prevTab = this.getTab($prevLink); var $nextTab = this.getTab($nextLink); $prevTab.removeClass(this.options.activeClass); if (self.haveTabHolder()) { this.resizeHolder($prevTab.outerHeight()); } setTimeout(function() { self.getClassTarget($prevLink).removeClass(self.options.activeClass); $prevTab.addClass(self.options.tabHiddenClass); $nextTab.removeClass(self.options.tabHiddenClass).addClass(self.options.activeClass); self.getClassTarget($nextLink).addClass(self.options.activeClass); if (self.haveTabHolder()) { self.resizeHolder($nextTab.outerHeight()); setTimeout(function() { self.resizeHolder(); self.prevTabIndex = self.activeTabIndex; self.makeCallback('onChange', self); }, self.options.animSpeed); } else { self.prevTabIndex = self.activeTabIndex; } }, this.options.autoHeight ? this.options.animSpeed : 1); }, getClassTarget: function($link) { return this.options.addToParent ? $link.parent() : $link; }, getActiveTab: function() { return this.getTab(this.$tabLinks.eq(this.activeTabIndex)); }, getTab: function($link) { return $($link.attr(this.options.attrib)); }, haveTabHolder: function() { return this.$tabHolder && this.$tabHolder.length; }, destroy: function() { var self = this; this.$tabLinks.off('.tabset').each(function() { var $link = $(this); self.getClassTarget($link).removeClass(self.options.activeClass); $($link.attr(self.options.attrib)).removeClass(self.options.activeClass + ' ' + self.options.tabHiddenClass); }); this.$holder.removeData('Tabset'); }, makeCallback: function(name) { if (typeof this.options[name] === 'function') { var args = Array.prototype.slice.call(arguments); args.shift(); this.options[name].apply(this, args); } } }; $.fn.tabset = function(opt) { var args = Array.prototype.slice.call(arguments); var method = args[0]; var options = $.extend({ activeClass: 'active', addToParent: false, autoHeight: false, checkHash: false, defaultTab: true, animSpeed: 500, tabLinks: 'a', attrib: 'href', event: 'click', tabHiddenClass: 'js-tab-hidden' }, opt); options.autoHeight = options.autoHeight; return this.each(function() { var $holder = jQuery(this); var instance = $holder.data('Tabset'); if (typeof opt === 'object' || typeof opt === 'undefined') { $holder.data('Tabset', new Tabset($holder, options)); } else if (typeof method === 'string' && instance) { if (typeof instance[method] === 'function') { args.shift(); instance[method].apply(instance, args); } } }); }; }(jQuery, jQuery(window))); /* * jQuery Tooltip plugin */ ;(function($){ $.fn.hoverTooltip = function(o) { var options = $.extend({ tooltipStructure: '
', tooltipSelector: '.tooltip-text', positionTypeX: 'right', positionTypeY: 'top', attribute:'title', extraOffsetX: 10, extraOffsetY: 10, showOnTouchDevice: true },o); // create tooltip var tooltip = $('
').html(options.tooltipStructure).children().css({position:'absolute'}); var tooltipTextBox = tooltip.find(options.tooltipSelector); var tooltipWidth, tooltipHeight; // tooltip logic function initTooltip(item) { var tooltipText = item.attr(options.attribute); item.removeAttr(options.attribute); if(!tooltipText) return; if(isTouchDevice) { if(options.showOnTouchDevice) { item.bind('touchstart', function(e) { showTooltip(item, tooltipText, getEvent(e)); jQuery(document).one('touchend', hideTooltip); }); } } else { item.bind('mouseenter', function(e) { showTooltip(item, tooltipText, e); }).bind('mouseleave', hideTooltip); } } function showTooltip(item, text, e) { tooltipTextBox.html(text); tooltip.appendTo(document.body).show(); itemWidth = item.outerWidth(); tooltipWidth = tooltip.outerWidth(true); tooltipHeight = tooltip.outerHeight(true); var top, left, x = item.offset().left, y = item.offset().top; switch(options.positionTypeY) { case 'top': top = y - tooltipHeight - options.extraOffsetY; break; case 'center': top = y - tooltipHeight / 2; break; case 'bottom': top = y + options.extraOffsetY; break; } switch(options.positionTypeX) { case 'left': left = x - tooltipWidth - options.extraOffsetX; break; case 'center': left = x - tooltipWidth / 2 + itemWidth / 2; break; case 'right': left = x + options.extraOffsetX; break; } tooltip.css({ top: top, left: left }); } function hideTooltip() { tooltip.remove(); } // add handlers return this.each(function(){ initTooltip($(this)); }); }; // parse event function getEvent(e) { return e.originalEvent.changedTouches ? e.originalEvent.changedTouches[0] : e; } // detect device type var isTouchDevice = (function() { try { return ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch; } catch (e) { return false; } }()); }(jQuery)); /* * jQuery Open/Close plugin */ ;(function($) { function OpenClose(options) { this.options = $.extend({ addClassBeforeAnimation: true, hideOnClickOutside: false, activeClass: 'active', opener: '.opener', slider: '.slide', animSpeed: 400, effect: 'fade', event: 'click' }, options); this.init(); } OpenClose.prototype = { init: function() { if (this.options.holder) { this.findElements(); this.attachEvents(); this.makeCallback('onInit', this); } }, findElements: function() { this.holder = $(this.options.holder); this.opener = this.holder.find(this.options.opener); this.slider = this.holder.find(this.options.slider); }, attachEvents: function() { // add handler var self = this; this.eventHandler = function(e) { e.preventDefault(); if (self.slider.hasClass(slideHiddenClass)) { self.showSlide(); } else { self.hideSlide(); } }; self.opener.on(self.options.event, this.eventHandler); // hover mode handler if (self.options.event === 'hover') { self.opener.on('mouseenter', function() { if (!self.holder.hasClass(self.options.activeClass)) { self.showSlide(); } }); self.holder.on('mouseleave', function() { self.hideSlide(); }); } // outside click handler self.outsideClickHandler = function(e) { if (self.options.hideOnClickOutside) { var target = $(e.target); if (!target.is(self.holder) && !target.closest(self.holder).length) { self.hideSlide(); } } }; // set initial styles if (this.holder.hasClass(this.options.activeClass)) { $(document).on('click touchstart', self.outsideClickHandler); } else { this.slider.addClass(slideHiddenClass); } }, showSlide: function() { var self = this; if (self.options.addClassBeforeAnimation) { self.holder.addClass(self.options.activeClass); } self.slider.removeClass(slideHiddenClass); $(document).on('click touchstart', self.outsideClickHandler); self.makeCallback('animStart', true); toggleEffects[self.options.effect].show({ box: self.slider, speed: self.options.animSpeed, complete: function() { if (!self.options.addClassBeforeAnimation) { self.holder.addClass(self.options.activeClass); } self.makeCallback('animEnd', true); } }); }, hideSlide: function() { var self = this; if (self.options.addClassBeforeAnimation) { self.holder.removeClass(self.options.activeClass); } $(document).off('click touchstart', self.outsideClickHandler); self.makeCallback('animStart', false); toggleEffects[self.options.effect].hide({ box: self.slider, speed: self.options.animSpeed, complete: function() { if (!self.options.addClassBeforeAnimation) { self.holder.removeClass(self.options.activeClass); } self.slider.addClass(slideHiddenClass); self.makeCallback('animEnd', false); } }); }, destroy: function() { this.slider.removeClass(slideHiddenClass).css({ display: '' }); this.opener.off(this.options.event, this.eventHandler); this.holder.removeClass(this.options.activeClass).removeData('OpenClose'); $(document).off('click touchstart', this.outsideClickHandler); }, makeCallback: function(name) { if (typeof this.options[name] === 'function') { var args = Array.prototype.slice.call(arguments); args.shift(); this.options[name].apply(this, args); } } }; // add stylesheet for slide on DOMReady var slideHiddenClass = 'js-slide-hidden'; (function() { var tabStyleSheet = $('
')); } else { list.append($('
No ' + this.options.inicidentAttr + ' or ' + this.options.maintenanceAttr + ' reported for this ' + key + '.
')); } }, btnsFilterFn: function(row) { var filterList = row.find(this.options.inicidentsList), items, visibleItems; items = row.find(this.options.incidentContainer); this.removeMessage(filterList); // remove alert message if(items && items.length) { items.removeAttr(this.options.filtationHiddenAttr); //set hidden attributes on inactive elements after filtration from buttos this.filterItemsByIncident(items); visibleItems = items.not('[' + this.options.filtationHiddenAttr + ']'); // if ragne is selected run function checkRange, else run createOpenClose and checkItemsLength functions this.checkIsRangeSelected(row, filterList, visibleItems); if (!visibleItems.length) { //create message if no incidents in selected range or month this.createMessage(filterList); } } else { //create message if no incidents in selected range or month this.createMessage(filterList); } }, removeHiddenAttr: function(item) { item.removeAttr(this.options.hiddenAttr); }, findIncidentElements: function() { var self = this; //refind parent blocks after React rebuild the page this.monthContainer = this.holder.find(this.options.monthContainer); this.monthRows = this.monthContainer.find(this.options.monthRow); this.monthRows.each(function() { var monthRow = jQuery(this), filterList = monthRow.find(self.options.inicidentsList), btnExpand = monthRow.find('.expand-incidents'), filterItems = monthRow.find(self.options.incidentContainer); self.removeOpenClose(monthRow); //remove openClose from html self.removeHiddenAttr.bind(self)(filterItems); //remove "data-hidden-element" from all items self.removeMessage.bind(self)(filterList); // remove alert message if(btnExpand.length) { //find all incidents in row if(!btnExpand.text().includes('Collapse')) { btnExpand.trigger('click'); filterItems = monthRow.find(self.options.incidentContainer); } //hide React btn exapand btnExpand.attr(self.options.hiddenAttr, ''); } filterItems.each(function() { var filterItem = $(this); self.setFilterAttrOnIncident(filterItem); }); //set hidden attributes on inactive elements after filtration from buttos self.filterItemsByIncident(filterItems); filterItems = filterItems.not('[' + self.options.filtationHiddenAttr + ']'); // if ragne is selected run function checkRange, else run createOpenClose and checkItemsLength functions self.checkIsRangeSelected.bind(self)(monthRow, filterList, filterItems); if(!filterItems.length) { //create message if no incidents in selected range self.createMessage.bind(self)(filterList); } }); }, removeAlert: function(holder) { holder.find('.alert-message, .alert-filter-message').remove(); }, checkRange: function(row) { var self = this; //chake if incident was in current selected range var itemsList = row.find(this.options.inicidentsList), items = itemsList.find(this.options.incidentContainer), visibleItems, rowMonthTitle = row.find('.month-title'), eventTitle = rowMonthTitle.text().trim(), month = eventTitle.substr(0, eventTitle.length - 5), monthNumber = this.getMonthNumber(month, this.options.fullMonthArr), year = parseInt(eventTitle.substr(eventTitle.length - 4)) || (new Date()).getFullYear(), firstDayOfMonth = '01', lastDayOfMonth = this.daysInMonth(month, year), rowMonthTitleStart = new Date(year , monthNumber, firstDayOfMonth), rowMonthTitleEnd = new Date(year , monthNumber, lastDayOfMonth); this.removeHiddenAttr(row); //remove "data-hidden-element" from all rows this.removeMessage(itemsList); // remove alert message if(items && items.length) { //remove hiddinig attributes for all elements in whole list this.removeOpenClose(row); this.removeAlert(itemsList); this.removeHiddenAttr(items); //remove "data-hidden-element" from all items self.filterItemsByIncident(items); //set "Incident" or "Maintenance" attr for items items = items.not('[' + this.options.filtationHiddenAttr + ']'); // hide items for inactive filtration buttons items.each(function(){ var filterItem = jQuery(this), filterDatesHold = filterItem.find('.secondary.font-small.color-secondary'), filterDateContent = filterDatesHold.html(), eventRange = [], datesRange = [], eventMinDate, eventMaxDate; eventRange = filterDatesHold.text().split('-'); $(eventRange).each(function(i, elem){ var tempArr = elem.split(','); if(tempArr.length > 1) { datesRange.push(tempArr[0].trim()); } }); $(datesRange).each(function(i, elem){ var temp = elem.split(' '); if(i === 0) { eventMinDate = new Date(year , self.getMonthNumber(temp[0], self.options.shortMonthArr), temp[1]); } else { eventMaxDate = new Date(year , self.getMonthNumber(temp[0], self.options.shortMonthArr), temp[1]); } }); // check if incident was more than 1 day if((eventMinDate !== undefined && eventMaxDate !== undefined)) { if(!(self.startDate <= eventMinDate && self.endDate > eventMinDate) && !(self.startDate <= eventMaxDate && self.endDate > eventMaxDate)){ filterItem.attr(self.options.hiddenAttr, ''); } } else { if(!(self.startDate <= eventMinDate && self.endDate >= eventMinDate)) { filterItem.attr(self.options.hiddenAttr, ''); } } }); visibleItems = items.not('[' + this.options.hiddenAttr + ']').not('[' + this.options.filtationHiddenAttr + ']'); this.createOpenCloseStructure(itemsList, visibleItems); this.checkItemsLength(row, visibleItems); if (!visibleItems.length) { //create message if no incidents in selected range this.createMessage(itemsList); } // hide month row if it doesn't fit to range if ((self.startDate <= rowMonthTitleStart && self.endDate <= rowMonthTitleStart && !visibleItems.length) && (self.startDate <= rowMonthTitleEnd && self.endDate <= rowMonthTitleEnd && !visibleItems.length) || (self.startDate > rowMonthTitleStart && self.endDate > rowMonthTitleStart && !visibleItems.length) && (self.startDate > rowMonthTitleEnd && self.endDate > rowMonthTitleEnd && !visibleItems.length)) { rowMonthTitle.closest('.month').attr(this.options.hiddenAttr, ''); } } else { // hide month row if it doesn't fit to range if ((self.startDate <= rowMonthTitleStart && self.endDate <= rowMonthTitleStart) && (self.startDate <= rowMonthTitleEnd && self.endDate <= rowMonthTitleEnd) || (self.startDate > rowMonthTitleStart && self.endDate > rowMonthTitleStart) && (self.startDate > rowMonthTitleEnd && self.endDate > rowMonthTitleEnd)) { rowMonthTitle.closest('.month').attr(this.options.hiddenAttr, ''); } else { this.createMessage(itemsList); } } }, startObserveContent: function() { // Mutation Observer setup var self = this; // Select the node that will be observed for mutations this.targetNode = document.getElementById(this.options.holderId); // Options for the observer (which mutations to observe) this.config = { attributes: true, childList: true, subtree: true, characterData : true }; // Callback function to execute when mutations are observed this.observingCallback = function(mutationsList, observer) { if(self.btnFlag) { //set preloader class self.body.addClass(self.options.notLoadedClass); setTimeout(function(){ self.getDates(self.paginationDatesHold); self.setDates(self.datepicker); self.removeAlert(self.holder); self.holder.find('.' + self.options.openCloseClass).remove(); self.findIncidentElements(); //remove preloader class self.body.removeClass(self.options.notLoadedClass); }, 2000); } self.btnFlag = false; }; // Create an observer instance linked to the callback function this.observer = new MutationObserver(this.observingCallback); // Start observing the target node for configured mutations this.observer.observe(this.targetNode, this.config); }, makeCallback: function(name) { if (typeof this.options[name] === 'function') { var args = Array.prototype.slice.call(arguments); args.shift(); this.options[name].apply(this, args); } } }; $.fn.filterRangePicker = function(options) { return this.each(function() { $(this).data('FilterRangePicker', new FilterRangePicker($.extend(options, { holder:this }))); }); }; }(jQuery)); /* moment min js */ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.moment=t()}(this,function(){"use strict";var e,i;function c(){return e.apply(null,arguments)}function o(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function u(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function l(e){return void 0===e}function h(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function d(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function f(e,t){var n,s=[];for(n=0;n>>0,s=0;sSe(e)?(r=e+1,o-Se(e)):(r=e,o),{year:r,dayOfYear:a}}function Ie(e,t,n){var s,i,r=Ve(e.year(),t,n),a=Math.floor((e.dayOfYear()-r-1)/7)+1;return a<1?s=a+Ae(i=e.year()-1,t,n):a>Ae(e.year(),t,n)?(s=a-Ae(e.year(),t,n),i=e.year()+1):(i=e.year(),s=a),{week:s,year:i}}function Ae(e,t,n){var s=Ve(e,t,n),i=Ve(e+1,t,n);return(Se(e)-s+i)/7}I("w",["ww",2],"wo","week"),I("W",["WW",2],"Wo","isoWeek"),C("week","w"),C("isoWeek","W"),F("week",5),F("isoWeek",5),ue("w",B),ue("ww",B,z),ue("W",B),ue("WW",B,z),fe(["w","ww","W","WW"],function(e,t,n,s){t[s.substr(0,1)]=D(e)});function je(e,t){return e.slice(t,7).concat(e.slice(0,t))}I("d",0,"do","day"),I("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),I("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),I("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),I("e",0,0,"weekday"),I("E",0,0,"isoWeekday"),C("day","d"),C("weekday","e"),C("isoWeekday","E"),F("day",11),F("weekday",11),F("isoWeekday",11),ue("d",B),ue("e",B),ue("E",B),ue("dd",function(e,t){return t.weekdaysMinRegex(e)}),ue("ddd",function(e,t){return t.weekdaysShortRegex(e)}),ue("dddd",function(e,t){return t.weekdaysRegex(e)}),fe(["dd","ddd","dddd"],function(e,t,n,s){var i=n._locale.weekdaysParse(e,s,n._strict);null!=i?t.d=i:g(n).invalidWeekday=e}),fe(["d","e","E"],function(e,t,n,s){t[s]=D(e)});var Ze="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_");var ze="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_");var $e="Su_Mo_Tu_We_Th_Fr_Sa".split("_");var qe=ae;var Je=ae;var Be=ae;function Qe(){function e(e,t){return t.length-e.length}var t,n,s,i,r,a=[],o=[],u=[],l=[];for(t=0;t<7;t++)n=y([2e3,1]).day(t),s=this.weekdaysMin(n,""),i=this.weekdaysShort(n,""),r=this.weekdays(n,""),a.push(s),o.push(i),u.push(r),l.push(s),l.push(i),l.push(r);for(a.sort(e),o.sort(e),u.sort(e),l.sort(e),t=0;t<7;t++)o[t]=he(o[t]),u[t]=he(u[t]),l[t]=he(l[t]);this._weekdaysRegex=new RegExp("^("+l.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+u.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+o.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+a.join("|")+")","i")}function Xe(){return this.hours()%12||12}function Ke(e,t){I(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function et(e,t){return t._meridiemParse}I("H",["HH",2],0,"hour"),I("h",["hh",2],0,Xe),I("k",["kk",2],0,function(){return this.hours()||24}),I("hmm",0,0,function(){return""+Xe.apply(this)+L(this.minutes(),2)}),I("hmmss",0,0,function(){return""+Xe.apply(this)+L(this.minutes(),2)+L(this.seconds(),2)}),I("Hmm",0,0,function(){return""+this.hours()+L(this.minutes(),2)}),I("Hmmss",0,0,function(){return""+this.hours()+L(this.minutes(),2)+L(this.seconds(),2)}),Ke("a",!0),Ke("A",!1),C("hour","h"),F("hour",13),ue("a",et),ue("A",et),ue("H",B),ue("h",B),ue("k",B),ue("HH",B,z),ue("hh",B,z),ue("kk",B,z),ue("hmm",Q),ue("hmmss",X),ue("Hmm",Q),ue("Hmmss",X),ce(["H","HH"],ge),ce(["k","kk"],function(e,t,n){var s=D(e);t[ge]=24===s?0:s}),ce(["a","A"],function(e,t,n){n._isPm=n._locale.isPM(e),n._meridiem=e}),ce(["h","hh"],function(e,t,n){t[ge]=D(e),g(n).bigHour=!0}),ce("hmm",function(e,t,n){var s=e.length-2;t[ge]=D(e.substr(0,s)),t[ve]=D(e.substr(s)),g(n).bigHour=!0}),ce("hmmss",function(e,t,n){var s=e.length-4,i=e.length-2;t[ge]=D(e.substr(0,s)),t[ve]=D(e.substr(s,2)),t[pe]=D(e.substr(i)),g(n).bigHour=!0}),ce("Hmm",function(e,t,n){var s=e.length-2;t[ge]=D(e.substr(0,s)),t[ve]=D(e.substr(s))}),ce("Hmmss",function(e,t,n){var s=e.length-4,i=e.length-2;t[ge]=D(e.substr(0,s)),t[ve]=D(e.substr(s,2)),t[pe]=D(e.substr(i))});var tt,nt=Te("Hours",!0),st={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:Ce,monthsShort:He,week:{dow:0,doy:6},weekdays:Ze,weekdaysMin:$e,weekdaysShort:ze,meridiemParse:/[ap]\.?m?\.?/i},it={},rt={};function at(e){return e?e.toLowerCase().replace("_","-"):e}function ot(e){var t=null;if(!it[e]&&"undefined"!=typeof module&&module&&module.exports)try{t=tt._abbr,require("./locale/"+e),ut(t)}catch(e){}return it[e]}function ut(e,t){var n;return e&&((n=l(t)?ht(e):lt(e,t))?tt=n:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+e+" not found. Did you forget to load it?")),tt._abbr}function lt(e,t){if(null===t)return delete it[e],null;var n,s=st;if(t.abbr=e,null!=it[e])T("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),s=it[e]._config;else if(null!=t.parentLocale)if(null!=it[t.parentLocale])s=it[t.parentLocale]._config;else{if(null==(n=ot(t.parentLocale)))return rt[t.parentLocale]||(rt[t.parentLocale]=[]),rt[t.parentLocale].push({name:e,config:t}),null;s=n._config}return it[e]=new P(x(s,t)),rt[e]&&rt[e].forEach(function(e){lt(e.name,e.config)}),ut(e),it[e]}function ht(e){var t;if(e&&e._locale&&e._locale._abbr&&(e=e._locale._abbr),!e)return tt;if(!o(e)){if(t=ot(e))return t;e=[e]}return function(e){for(var t,n,s,i,r=0;r=t&&a(i,n,!0)>=t-1)break;t--}r++}return tt}(e)}function dt(e){var t,n=e._a;return n&&-2===g(e).overflow&&(t=n[_e]<0||11Pe(n[me],n[_e])?ye:n[ge]<0||24Ae(n,r,a)?g(e)._overflowWeeks=!0:null!=u?g(e)._overflowWeekday=!0:(o=Ee(n,s,i,r,a),e._a[me]=o.year,e._dayOfYear=o.dayOfYear)}(e),null!=e._dayOfYear&&(r=ct(e._a[me],s[me]),(e._dayOfYear>Se(r)||0===e._dayOfYear)&&(g(e)._overflowDayOfYear=!0),n=Ge(r,0,e._dayOfYear),e._a[_e]=n.getUTCMonth(),e._a[ye]=n.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=a[t]=s[t];for(;t<7;t++)e._a[t]=a[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[ge]&&0===e._a[ve]&&0===e._a[pe]&&0===e._a[we]&&(e._nextDay=!0,e._a[ge]=0),e._d=(e._useUTC?Ge:function(e,t,n,s,i,r,a){var o;return e<100&&0<=e?(o=new Date(e+400,t,n,s,i,r,a),isFinite(o.getFullYear())&&o.setFullYear(e)):o=new Date(e,t,n,s,i,r,a),o}).apply(null,a),i=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[ge]=24),e._w&&void 0!==e._w.d&&e._w.d!==i&&(g(e).weekdayMismatch=!0)}}var mt=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,_t=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,yt=/Z|[+-]\d\d(?::?\d\d)?/,gt=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],vt=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],pt=/^\/?Date\((\-?\d+)/i;function wt(e){var t,n,s,i,r,a,o=e._i,u=mt.exec(o)||_t.exec(o);if(u){for(g(e).iso=!0,t=0,n=gt.length;tn.valueOf():n.valueOf()this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},mn.isLocal=function(){return!!this.isValid()&&!this._isUTC},mn.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},mn.isUtc=Et,mn.isUTC=Et,mn.zoneAbbr=function(){return this._isUTC?"UTC":""},mn.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},mn.dates=n("dates accessor is deprecated. Use date instead.",un),mn.months=n("months accessor is deprecated. Use month instead",Ue),mn.years=n("years accessor is deprecated. Use year instead",Oe),mn.zone=n("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function(e,t){return null!=e?("string"!=typeof e&&(e=-e),this.utcOffset(e,t),this):-this.utcOffset()}),mn.isDSTShifted=n("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function(){if(!l(this._isDSTShifted))return this._isDSTShifted;var e={};if(w(e,this),(e=Ot(e))._a){var t=e._isUTC?y(e._a):bt(e._a);this._isDSTShifted=this.isValid()&&0
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
' + '' + '' + ' ' + '
' + ''; this.parentEl = (options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl); this.container = $(options.template).appendTo(this.parentEl); // // handle all the possible options overriding defaults // if (typeof options.locale === 'object') { if (typeof options.locale.direction === 'string') this.locale.direction = options.locale.direction; if (typeof options.locale.format === 'string') this.locale.format = options.locale.format; if (typeof options.locale.separator === 'string') this.locale.separator = options.locale.separator; if (typeof options.locale.daysOfWeek === 'object') this.locale.daysOfWeek = options.locale.daysOfWeek.slice(); if (typeof options.locale.monthNames === 'object') this.locale.monthNames = options.locale.monthNames.slice(); if (typeof options.locale.firstDay === 'number') this.locale.firstDay = options.locale.firstDay; if (typeof options.locale.applyLabel === 'string') this.locale.applyLabel = options.locale.applyLabel; if (typeof options.locale.cancelLabel === 'string') this.locale.cancelLabel = options.locale.cancelLabel; if (typeof options.locale.weekLabel === 'string') this.locale.weekLabel = options.locale.weekLabel; if (typeof options.locale.customRangeLabel === 'string'){ //Support unicode chars in the custom range name. var elem = document.createElement('textarea'); elem.innerHTML = options.locale.customRangeLabel; var rangeHtml = elem.value; this.locale.customRangeLabel = rangeHtml; } } this.container.addClass(this.locale.direction); if (typeof options.startDate === 'string') this.startDate = moment(options.startDate, this.locale.format); if (typeof options.endDate === 'string') this.endDate = moment(options.endDate, this.locale.format); if (typeof options.minDate === 'string') this.minDate = moment(options.minDate, this.locale.format); if (typeof options.maxDate === 'string') this.maxDate = moment(options.maxDate, this.locale.format); if (typeof options.startDate === 'object') this.startDate = moment(options.startDate); if (typeof options.endDate === 'object') this.endDate = moment(options.endDate); if (typeof options.minDate === 'object') this.minDate = moment(options.minDate); if (typeof options.maxDate === 'object') this.maxDate = moment(options.maxDate); // sanity check for bad options if (this.minDate && this.startDate.isBefore(this.minDate)) this.startDate = this.minDate.clone(); // sanity check for bad options if (this.maxDate && this.endDate.isAfter(this.maxDate)) this.endDate = this.maxDate.clone(); if (typeof options.applyButtonClasses === 'string') this.applyButtonClasses = options.applyButtonClasses; if (typeof options.applyClass === 'string') //backwards compat this.applyButtonClasses = options.applyClass; if (typeof options.cancelButtonClasses === 'string') this.cancelButtonClasses = options.cancelButtonClasses; if (typeof options.cancelClass === 'string') //backwards compat this.cancelButtonClasses = options.cancelClass; if (typeof options.maxSpan === 'object') this.maxSpan = options.maxSpan; if (typeof options.dateLimit === 'object') //backwards compat this.maxSpan = options.dateLimit; if (typeof options.opens === 'string') this.opens = options.opens; if (typeof options.drops === 'string') this.drops = options.drops; if (typeof options.showWeekNumbers === 'boolean') this.showWeekNumbers = options.showWeekNumbers; if (typeof options.showISOWeekNumbers === 'boolean') this.showISOWeekNumbers = options.showISOWeekNumbers; if (typeof options.buttonClasses === 'string') this.buttonClasses = options.buttonClasses; if (typeof options.buttonClasses === 'object') this.buttonClasses = options.buttonClasses.join(' '); if (typeof options.showDropdowns === 'boolean') this.showDropdowns = options.showDropdowns; if (typeof options.minYear === 'number') this.minYear = options.minYear; if (typeof options.maxYear === 'number') this.maxYear = options.maxYear; if (typeof options.showCustomRangeLabel === 'boolean') this.showCustomRangeLabel = options.showCustomRangeLabel; if (typeof options.singleDatePicker === 'boolean') { this.singleDatePicker = options.singleDatePicker; // if (this.singleDatePicker) // this.endDate = this.maxDate.clone(); } if (typeof options.timePicker === 'boolean') this.timePicker = options.timePicker; if (typeof options.timePickerSeconds === 'boolean') this.timePickerSeconds = options.timePickerSeconds; if (typeof options.timePickerIncrement === 'number') this.timePickerIncrement = options.timePickerIncrement; if (typeof options.timePicker24Hour === 'boolean') this.timePicker24Hour = options.timePicker24Hour; if (typeof options.autoApply === 'boolean') this.autoApply = options.autoApply; if (typeof options.autoUpdateInput === 'boolean') this.autoUpdateInput = options.autoUpdateInput; if (typeof options.linkedCalendars === 'boolean') this.linkedCalendars = options.linkedCalendars; if (typeof options.isInvalidDate === 'function') this.isInvalidDate = options.isInvalidDate; if (typeof options.isCustomDate === 'function') this.isCustomDate = options.isCustomDate; if (typeof options.alwaysShowCalendars === 'boolean') this.alwaysShowCalendars = options.alwaysShowCalendars; // update day names order to firstDay if (this.locale.firstDay != 0) { var iterator = this.locale.firstDay; while (iterator > 0) { this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift()); iterator--; } } var start, end, range; //if no start/end dates set, check if an input element contains initial values if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') { if ($(this.element).is(':text')) { var val = $(this.element).val(), split = val.split(this.locale.separator); start = end = null; if (split.length == 2) { start = moment(split[0], this.locale.format); end = moment(split[1], this.locale.format); } else if (this.singleDatePicker && val !== "") { start = moment(val, this.locale.format); end = moment(val, this.locale.format); } if (start !== null && end !== null) { this.setStartDate(start); this.setEndDate(end); } } } if (typeof options.ranges === 'object') { for (range in options.ranges) { if (typeof options.ranges[range][0] === 'string') start = moment(options.ranges[range][0], this.locale.format); else start = moment(options.ranges[range][0]); if (typeof options.ranges[range][1] === 'string') end = moment(options.ranges[range][1], this.locale.format); else end = moment(options.ranges[range][1]); // If the start or end date exceed those allowed by the minDate or maxSpan // options, shorten the range to the allowable period. if (this.minDate && start.isBefore(this.minDate)) start = this.minDate.clone(); var maxDate = this.maxDate; if (this.maxSpan && maxDate && start.clone().add(this.maxSpan).isAfter(maxDate)) maxDate = start.clone().add(this.maxSpan); if (maxDate && end.isAfter(maxDate)) end = maxDate.clone(); // If the end of the range is before the minimum or the start of the range is // after the maximum, don't display this range option at all. if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day')) || (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day'))) continue; //Support unicode chars in the range names. var elem = document.createElement('textarea'); elem.innerHTML = range; var rangeHtml = elem.value; this.ranges[rangeHtml] = [start, end]; } var list = ''; this.container.find('.ranges').prepend(list); } if (typeof cb === 'function') { this.callback = cb; } if (!this.timePicker) { this.startDate = this.startDate.startOf('day'); this.endDate = this.endDate.endOf('day'); this.container.find('.calendar-time').hide(); } //can't be used together for now if (this.timePicker && this.autoApply) this.autoApply = false; if (this.autoApply) { this.container.addClass('auto-apply'); } if (typeof options.ranges === 'object') this.container.addClass('show-ranges'); if (this.singleDatePicker) { this.container.addClass('single'); this.container.find('.drp-calendar.left').addClass('single'); this.container.find('.drp-calendar.left').show(); this.container.find('.drp-calendar.right').hide(); if (!this.timePicker && this.autoApply) { this.container.addClass('auto-apply'); } } if ((typeof options.ranges === 'undefined' && !this.singleDatePicker) || this.alwaysShowCalendars) { this.container.addClass('show-calendar'); } this.container.addClass('opens' + this.opens); //apply CSS classes and labels to buttons this.container.find('.applyBtn, .cancelBtn').addClass(this.buttonClasses); if (this.applyButtonClasses.length) this.container.find('.applyBtn').addClass(this.applyButtonClasses); if (this.cancelButtonClasses.length) this.container.find('.cancelBtn').addClass(this.cancelButtonClasses); this.container.find('.applyBtn').html(this.locale.applyLabel); this.container.find('.cancelBtn').html(this.locale.cancelLabel); // // event listeners // this.container.find('.drp-calendar') .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this)) .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this)) .on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this)) .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this)) .on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this)) .on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this)) .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this)); this.container.find('.ranges') .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this)); this.container.find('.drp-buttons') .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this)) .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this)); if (this.element.is('input') || this.element.is('button')) { this.element.on({ 'click.daterangepicker': $.proxy(this.show, this), 'focus.daterangepicker': $.proxy(this.show, this), 'keyup.daterangepicker': $.proxy(this.elementChanged, this), 'keydown.daterangepicker': $.proxy(this.keydown, this) //IE 11 compatibility }); } else { this.element.on('click.daterangepicker', $.proxy(this.toggle, this)); this.element.on('keydown.daterangepicker', $.proxy(this.toggle, this)); } // // if attached to a text input, set the initial value // this.updateElement(); }; DateRangePicker.prototype = { constructor: DateRangePicker, setStartDate: function(startDate) { if (typeof startDate === 'string') this.startDate = moment(startDate, this.locale.format); if (typeof startDate === 'object') this.startDate = moment(startDate); if (!this.timePicker) this.startDate = this.startDate.startOf('day'); if (this.timePicker && this.timePickerIncrement) this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); if (this.minDate && this.startDate.isBefore(this.minDate)) { this.startDate = this.minDate.clone(); if (this.timePicker && this.timePickerIncrement) this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); } if (this.maxDate && this.startDate.isAfter(this.maxDate)) { this.startDate = this.maxDate.clone(); if (this.timePicker && this.timePickerIncrement) this.startDate.minute(Math.floor(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); } if (!this.isShowing) this.updateElement(); this.updateMonthsInView(); }, setEndDate: function(endDate) { if (typeof endDate === 'string') this.endDate = moment(endDate, this.locale.format); if (typeof endDate === 'object') this.endDate = moment(endDate); if (!this.timePicker) this.endDate = this.endDate.endOf('day'); if (this.timePicker && this.timePickerIncrement) this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); if (this.endDate.isBefore(this.startDate)) this.endDate = this.startDate.clone(); if (this.maxDate && this.endDate.isAfter(this.maxDate)) this.endDate = this.maxDate.clone(); if (this.maxSpan && this.startDate.clone().add(this.maxSpan).isBefore(this.endDate)) this.endDate = this.startDate.clone().add(this.maxSpan); this.previousRightTime = this.endDate.clone(); this.container.find('.drp-selected').html(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format)); if (!this.isShowing) this.updateElement(); this.updateMonthsInView(); }, isInvalidDate: function() { return false; }, isCustomDate: function() { return false; }, updateView: function() { if (this.timePicker) { this.renderTimePicker('left'); this.renderTimePicker('right'); if (!this.endDate) { this.container.find('.right .calendar-time select').prop('disabled', true).addClass('disabled'); } else { this.container.find('.right .calendar-time select').prop('disabled', false).removeClass('disabled'); } } if (this.endDate) this.container.find('.drp-selected').html(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format)); this.updateMonthsInView(); this.updateCalendars(); this.updateFormInputs(); }, updateMonthsInView: function() { if (this.endDate) { //if both dates are visible already, do nothing if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month && (this.startDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM')) && (this.endDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM')) ) { return; } this.leftCalendar.month = this.startDate.clone().date(2); if (!this.linkedCalendars && (this.endDate.month() != this.startDate.month() || this.endDate.year() != this.startDate.year())) { this.rightCalendar.month = this.endDate.clone().date(2); } else { this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month'); } } else { if (this.leftCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM')) { this.leftCalendar.month = this.startDate.clone().date(2); this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month'); } } if (this.maxDate && this.linkedCalendars && !this.singleDatePicker && this.rightCalendar.month > this.maxDate) { this.rightCalendar.month = this.maxDate.clone().date(2); this.leftCalendar.month = this.maxDate.clone().date(2).subtract(1, 'month'); } }, updateCalendars: function() { if (this.timePicker) { var hour, minute, second; if (this.endDate) { hour = parseInt(this.container.find('.left .hourselect').val(), 10); minute = parseInt(this.container.find('.left .minuteselect').val(), 10); if (isNaN(minute)) { minute = parseInt(this.container.find('.left .minuteselect option:last').val(), 10); } second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0; if (!this.timePicker24Hour) { var ampm = this.container.find('.left .ampmselect').val(); if (ampm === 'PM' && hour < 12) hour += 12; if (ampm === 'AM' && hour === 12) hour = 0; } } else { hour = parseInt(this.container.find('.right .hourselect').val(), 10); minute = parseInt(this.container.find('.right .minuteselect').val(), 10); if (isNaN(minute)) { minute = parseInt(this.container.find('.right .minuteselect option:last').val(), 10); } second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0; if (!this.timePicker24Hour) { var ampm = this.container.find('.right .ampmselect').val(); if (ampm === 'PM' && hour < 12) hour += 12; if (ampm === 'AM' && hour === 12) hour = 0; } } this.leftCalendar.month.hour(hour).minute(minute).second(second); this.rightCalendar.month.hour(hour).minute(minute).second(second); } this.renderCalendar('left'); this.renderCalendar('right'); //highlight any predefined range matching the current start and end dates this.container.find('.ranges li').removeClass('active'); if (this.endDate == null) return; this.calculateChosenLabel(); }, renderCalendar: function(side) { // // Build the matrix of dates that will populate the calendar // var calendar = side == 'left' ? this.leftCalendar : this.rightCalendar; var month = calendar.month.month(); var year = calendar.month.year(); var hour = calendar.month.hour(); var minute = calendar.month.minute(); var second = calendar.month.second(); var daysInMonth = moment([year, month]).daysInMonth(); var firstDay = moment([year, month, 1]); var lastDay = moment([year, month, daysInMonth]); var lastMonth = moment(firstDay).subtract(1, 'month').month(); var lastYear = moment(firstDay).subtract(1, 'month').year(); var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth(); var dayOfWeek = firstDay.day(); //initialize a 6 rows x 7 columns array for the calendar var calendar = []; calendar.firstDay = firstDay; calendar.lastDay = lastDay; for (var i = 0; i < 6; i++) { calendar[i] = []; } //populate the calendar with date objects var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1; if (startDay > daysInLastMonth) startDay -= 7; if (dayOfWeek == this.locale.firstDay) startDay = daysInLastMonth - 6; var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]); var col, row; for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) { if (i > 0 && col % 7 === 0) { col = 0; row++; } calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second); curDate.hour(12); if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') { calendar[row][col] = this.minDate.clone(); } if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') { calendar[row][col] = this.maxDate.clone(); } } //make the calendar object available to hoverDate/clickDate if (side == 'left') { this.leftCalendar.calendar = calendar; } else { this.rightCalendar.calendar = calendar; } // // Display the calendar // var minDate = side == 'left' ? this.minDate : this.startDate; var maxDate = this.maxDate; var selected = side == 'left' ? this.startDate : this.endDate; var arrow = this.locale.direction == 'ltr' ? {left: 'chevron-left', right: 'chevron-right'} : {left: 'chevron-right', right: 'chevron-left'}; var html = ''; html += ''; html += ''; // add empty cell for week number if (this.showWeekNumbers || this.showISOWeekNumbers) html += ''; if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.linkedCalendars || side == 'left')) { html += ''; } else { html += ''; } var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY"); if (this.showDropdowns) { var currentMonth = calendar[1][1].month(); var currentYear = calendar[1][1].year(); var maxYear = (maxDate && maxDate.year()) || (this.maxYear); var minYear = (minDate && minDate.year()) || (this.minYear); var inMinYear = currentYear == minYear; var inMaxYear = currentYear == maxYear; var monthHtml = '"; var yearHtml = ''; dateHtml = monthHtml + yearHtml; } html += ''; if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.linkedCalendars || side == 'right' || this.singleDatePicker)) { html += ''; } else { html += ''; } html += ''; html += ''; // add week number label if (this.showWeekNumbers || this.showISOWeekNumbers) html += ''; $.each(this.locale.daysOfWeek, function(index, dayOfWeek) { html += ''; }); html += ''; html += ''; html += ''; //adjust maxDate to reflect the maxSpan setting in order to //grey out end dates beyond the maxSpan if (this.endDate == null && this.maxSpan) { var maxLimit = this.startDate.clone().add(this.maxSpan).endOf('day'); if (!maxDate || maxLimit.isBefore(maxDate)) { maxDate = maxLimit; } } for (var row = 0; row < 6; row++) { html += ''; // add week number if (this.showWeekNumbers) html += ''; else if (this.showISOWeekNumbers) html += ''; for (var col = 0; col < 7; col++) { var classes = []; //highlight today's date if (calendar[row][col].isSame(new Date(), "day")) classes.push('today'); //highlight weekends if (calendar[row][col].isoWeekday() > 5) classes.push('weekend'); //grey out the dates in other months displayed at beginning and end of this calendar if (calendar[row][col].month() != calendar[1][1].month()) classes.push('off', 'ends'); //don't allow selection of dates before the minimum date if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day')) classes.push('off', 'disabled'); //don't allow selection of dates after the maximum date if (maxDate && calendar[row][col].isAfter(maxDate, 'day')) classes.push('off', 'disabled'); //don't allow selection of date if a custom function decides it's invalid if (this.isInvalidDate(calendar[row][col])) classes.push('off', 'disabled'); //highlight the currently selected start date if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) classes.push('active', 'start-date'); //highlight the currently selected end date if (this.endDate != null && calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) classes.push('active', 'end-date'); //highlight dates in-between the selected dates if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate) classes.push('in-range'); //apply custom classes for this date var isCustom = this.isCustomDate(calendar[row][col]); if (isCustom !== false) { if (typeof isCustom === 'string') classes.push(isCustom); else Array.prototype.push.apply(classes, isCustom); } var cname = '', disabled = false; for (var i = 0; i < classes.length; i++) { cname += classes[i] + ' '; if (classes[i] == 'disabled') disabled = true; } if (!disabled) cname += 'available'; html += ''; } html += ''; } html += ''; html += '
' + dateHtml + '
' + this.locale.weekLabel + '' + dayOfWeek + '
' + calendar[row][0].week() + '' + calendar[row][0].isoWeek() + '' + calendar[row][col].date() + '
'; this.container.find('.drp-calendar.' + side + ' .calendar-table').html(html); }, renderTimePicker: function(side) { // Don't bother updating the time picker if it's currently disabled // because an end date hasn't been clicked yet if (side == 'right' && !this.endDate) return; var html, selected, minDate, maxDate = this.maxDate; if (this.maxSpan && (!this.maxDate || this.startDate.clone().add(this.maxSpan).isBefore(this.maxDate))) maxDate = this.startDate.clone().add(this.maxSpan); if (side == 'left') { selected = this.startDate.clone(); minDate = this.minDate; } else if (side == 'right') { selected = this.endDate.clone(); minDate = this.startDate; //Preserve the time already selected var timeSelector = this.container.find('.drp-calendar.right .calendar-time'); if (timeSelector.html() != '') { selected.hour(!isNaN(selected.hour()) ? selected.hour() : timeSelector.find('.hourselect option:selected').val()); selected.minute(!isNaN(selected.minute()) ? selected.minute() : timeSelector.find('.minuteselect option:selected').val()); selected.second(!isNaN(selected.second()) ? selected.second() : timeSelector.find('.secondselect option:selected').val()); if (!this.timePicker24Hour) { var ampm = timeSelector.find('.ampmselect option:selected').val(); if (ampm === 'PM' && selected.hour() < 12) selected.hour(selected.hour() + 12); if (ampm === 'AM' && selected.hour() === 12) selected.hour(0); } } if (selected.isBefore(this.startDate)) selected = this.startDate.clone(); if (maxDate && selected.isAfter(maxDate)) selected = maxDate.clone(); } // // hours // html = ' '; // // minutes // html += ': '; // // seconds // if (this.timePickerSeconds) { html += ': '; } // // AM/PM // if (!this.timePicker24Hour) { html += ''; } this.container.find('.drp-calendar.' + side + ' .calendar-time').html(html); }, updateFormInputs: function() { if ((this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) { this.container.find('button.applyBtn').prop('disabled', false); } else { this.container.find('button.applyBtn').prop('disabled', true); } }, move: function() { var parentOffset = { top: 0, left: 0 }, containerTop, drops = this.drops; var parentRightEdge = $(window).width(); if (!this.parentEl.is('body')) { parentOffset = { top: this.parentEl.offset().top - this.parentEl.scrollTop(), left: this.parentEl.offset().left - this.parentEl.scrollLeft() }; parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left; } switch (drops) { case 'auto': containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top; if (containerTop + this.container.outerHeight() >= this.parentEl[0].scrollHeight) { containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top; drops = 'up'; } break; case 'up': containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top; break; default: containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top; break; } // Force the container to it's actual width this.container.css({ top: 0, left: 0, right: 'auto' }); var containerWidth = this.container.outerWidth(); this.container.toggleClass('drop-up', drops == 'up'); if (this.opens == 'left') { var containerRight = parentRightEdge - this.element.offset().left - this.element.outerWidth(); if (containerWidth + containerRight > $(window).width()) { this.container.css({ top: containerTop, right: 'auto', left: 9 }); } else { this.container.css({ top: containerTop, right: containerRight, left: 'auto' }); } } else if (this.opens == 'center') { var containerLeft = this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2 - containerWidth / 2; if (containerLeft < 0) { this.container.css({ top: containerTop, right: 'auto', left: 9 }); } else if (containerLeft + containerWidth > $(window).width()) { this.container.css({ top: containerTop, left: 'auto', right: 0 }); } else { this.container.css({ top: containerTop, left: containerLeft, right: 'auto' }); } } else { var containerLeft = this.element.offset().left - parentOffset.left; if (containerLeft + containerWidth > $(window).width()) { this.container.css({ top: containerTop, left: 'auto', right: 0 }); } else { this.container.css({ top: containerTop, left: containerLeft, right: 'auto' }); } } }, show: function(e) { if (this.isShowing) return; // Create a click proxy that is private to this instance of datepicker, for unbinding this._outsideClickProxy = $.proxy(function(e) { this.outsideClick(e); }, this); // Bind global datepicker mousedown for hiding and $(document) .on('mousedown.daterangepicker', this._outsideClickProxy) // also support mobile devices .on('touchend.daterangepicker', this._outsideClickProxy) // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy) // and also close when focus changes to outside the picker (eg. tabbing between controls) .on('focusin.daterangepicker', this._outsideClickProxy); // Reposition the picker if the window is resized while it's open $(window).on('resize.daterangepicker', $.proxy(function(e) { this.move(e); }, this)); this.oldStartDate = this.startDate.clone(); this.oldEndDate = this.endDate.clone(); this.previousRightTime = this.endDate.clone(); this.updateView(); this.container.show(); this.move(); this.element.trigger('show.daterangepicker', this); this.isShowing = true; }, hide: function(e) { if (!this.isShowing) return; //incomplete date selection, revert to last values if (!this.endDate) { this.startDate = this.oldStartDate.clone(); this.endDate = this.oldEndDate.clone(); } //if a new date range was selected, invoke the user callback function if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) this.callback(this.startDate.clone(), this.endDate.clone(), this.chosenLabel); //if picker is attached to a text input, update it this.updateElement(); $(document).off('.daterangepicker'); $(window).off('.daterangepicker'); this.container.hide(); this.element.trigger('hide.daterangepicker', this); this.isShowing = false; }, toggle: function(e) { if (this.isShowing) { this.hide(); } else { this.show(); } }, outsideClick: function(e) { var target = $(e.target); // if the page is clicked anywhere except within the daterangerpicker/button // itself then call this.hide() if ( // ie modal dialog fix e.type == "focusin" || target.closest(this.element).length || target.closest(this.container).length || target.closest('.calendar-table').length ) return; this.hide(); this.element.trigger('outsideClick.daterangepicker', this); }, showCalendars: function() { this.container.addClass('show-calendar'); this.move(); this.element.trigger('showCalendar.daterangepicker', this); }, hideCalendars: function() { this.container.removeClass('show-calendar'); this.element.trigger('hideCalendar.daterangepicker', this); }, clickRange: function(e) { var label = e.target.getAttribute('data-range-key'); this.chosenLabel = label; if (label == this.locale.customRangeLabel) { this.showCalendars(); } else { var dates = this.ranges[label]; this.startDate = dates[0]; this.endDate = dates[1]; if (!this.timePicker) { this.startDate.startOf('day'); this.endDate.endOf('day'); } if (!this.alwaysShowCalendars) this.hideCalendars(); this.clickApply(); } }, clickPrev: function(e) { var cal = $(e.target).parents('.drp-calendar'); if (cal.hasClass('left')) { this.leftCalendar.month.subtract(1, 'month'); if (this.linkedCalendars) this.rightCalendar.month.subtract(1, 'month'); } else { this.rightCalendar.month.subtract(1, 'month'); } this.updateCalendars(); }, clickNext: function(e) { var cal = $(e.target).parents('.drp-calendar'); if (cal.hasClass('left')) { this.leftCalendar.month.add(1, 'month'); } else { this.rightCalendar.month.add(1, 'month'); if (this.linkedCalendars) this.leftCalendar.month.add(1, 'month'); } this.updateCalendars(); }, hoverDate: function(e) { //ignore dates that can't be selected if (!$(e.target).hasClass('available')) return; var title = $(e.target).attr('data-title'); var row = title.substr(1, 1); var col = title.substr(3, 1); var cal = $(e.target).parents('.drp-calendar'); var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; //highlight the dates between the start date and the date being hovered as a potential end date var leftCalendar = this.leftCalendar; var rightCalendar = this.rightCalendar; var startDate = this.startDate; if (!this.endDate) { this.container.find('.drp-calendar tbody td').each(function(index, el) { //skip week numbers, only look at dates if ($(el).hasClass('week')) return; var title = $(el).attr('data-title'); var row = title.substr(1, 1); var col = title.substr(3, 1); var cal = $(el).parents('.drp-calendar'); var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col]; if ((dt.isAfter(startDate) && dt.isBefore(date)) || dt.isSame(date, 'day')) { $(el).addClass('in-range'); } else { $(el).removeClass('in-range'); } }); } }, clickDate: function(e) { if (!$(e.target).hasClass('available')) return; var title = $(e.target).attr('data-title'); var row = title.substr(1, 1); var col = title.substr(3, 1); var cal = $(e.target).parents('.drp-calendar'); var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; // // this function needs to do a few things: // * alternate between selecting a start and end date for the range, // * if the time picker is enabled, apply the hour/minute/second from the select boxes to the clicked date // * if autoapply is enabled, and an end date was chosen, apply the selection // * if single date picker mode, and time picker isn't enabled, apply the selection immediately // * if one of the inputs above the calendars was focused, cancel that manual input // if (this.endDate || date.isBefore(this.startDate, 'day')) { //picking start if (this.timePicker) { var hour = parseInt(this.container.find('.left .hourselect').val(), 10); if (!this.timePicker24Hour) { var ampm = this.container.find('.left .ampmselect').val(); if (ampm === 'PM' && hour < 12) hour += 12; if (ampm === 'AM' && hour === 12) hour = 0; } var minute = parseInt(this.container.find('.left .minuteselect').val(), 10); if (isNaN(minute)) { minute = parseInt(this.container.find('.left .minuteselect option:last').val(), 10); } var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0; date = date.clone().hour(hour).minute(minute).second(second); } this.endDate = null; this.setStartDate(date.clone()); } else if (!this.endDate && date.isBefore(this.startDate)) { //special case: clicking the same date for start/end, //but the time of the end date is before the start date this.setEndDate(this.startDate.clone()); } else { // picking end if (this.timePicker) { var hour = parseInt(this.container.find('.right .hourselect').val(), 10); if (!this.timePicker24Hour) { var ampm = this.container.find('.right .ampmselect').val(); if (ampm === 'PM' && hour < 12) hour += 12; if (ampm === 'AM' && hour === 12) hour = 0; } var minute = parseInt(this.container.find('.right .minuteselect').val(), 10); if (isNaN(minute)) { minute = parseInt(this.container.find('.right .minuteselect option:last').val(), 10); } var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0; date = date.clone().hour(hour).minute(minute).second(second); } this.setEndDate(date.clone()); if (this.autoApply) { this.calculateChosenLabel(); this.clickApply(); } } // if (this.singleDatePicker) { // this.setEndDate(this.startDate); // if (!this.timePicker && this.autoApply) // this.clickApply(); // } this.updateView(); //This is to cancel the blur event handler if the mouse was in one of the inputs e.stopPropagation(); }, calculateChosenLabel: function () { var customRange = true; var i = 0; for (var range in this.ranges) { if (this.timePicker) { var format = this.timePickerSeconds ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD HH:mm"; //ignore times when comparing dates if time picker seconds is not enabled if (this.startDate.format(format) == this.ranges[range][0].format(format) && this.endDate.format(format) == this.ranges[range][1].format(format)) { customRange = false; this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').attr('data-range-key'); break; } } else { //ignore times when comparing dates if time picker is not enabled if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) { customRange = false; this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').attr('data-range-key'); break; } } i++; } if (customRange) { if (this.showCustomRangeLabel) { this.chosenLabel = this.container.find('.ranges li:last').addClass('active').attr('data-range-key'); } else { this.chosenLabel = null; } this.showCalendars(); } }, clickApply: function(e) { this.hide(); this.element.trigger('apply.daterangepicker', this); }, clickCancel: function(e) { this.startDate = this.oldStartDate; this.endDate = this.oldEndDate; this.hide(); this.element.trigger('cancel.daterangepicker', this); }, monthOrYearChanged: function(e) { var isLeft = $(e.target).closest('.drp-calendar').hasClass('left'), leftOrRight = isLeft ? 'left' : 'right', cal = this.container.find('.drp-calendar.'+leftOrRight); // Month must be Number for new moment versions var month = parseInt(cal.find('.monthselect').val(), 10); var year = cal.find('.yearselect').val(); if (!isLeft) { if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) { month = this.startDate.month(); year = this.startDate.year(); } } if (this.minDate) { if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) { month = this.minDate.month(); year = this.minDate.year(); } } if (this.maxDate) { if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) { month = this.maxDate.month(); year = this.maxDate.year(); } } if (isLeft) { this.leftCalendar.month.month(month).year(year); if (this.linkedCalendars) this.rightCalendar.month = this.leftCalendar.month.clone().add(1, 'month'); } else { this.rightCalendar.month.month(month).year(year); if (this.linkedCalendars) this.leftCalendar.month = this.rightCalendar.month.clone().subtract(1, 'month'); } this.updateCalendars(); }, timeChanged: function(e) { var cal = $(e.target).closest('.drp-calendar'), isLeft = cal.hasClass('left'); var hour = parseInt(cal.find('.hourselect').val(), 10); var minute = parseInt(cal.find('.minuteselect').val(), 10); if (isNaN(minute)) { minute = parseInt(cal.find('.minuteselect option:last').val(), 10); } var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0; if (!this.timePicker24Hour) { var ampm = cal.find('.ampmselect').val(); if (ampm === 'PM' && hour < 12) hour += 12; if (ampm === 'AM' && hour === 12) hour = 0; } if (isLeft) { var start = this.startDate.clone(); start.hour(hour); start.minute(minute); start.second(second); this.setStartDate(start); // if (this.singleDatePicker) { // this.endDate = this.startDate.clone(); // } else if (this.endDate && this.endDate.format('YYYY-MM-DD') == start.format('YYYY-MM-DD') && this.endDate.isBefore(start)) { this.setEndDate(start.clone()); } } else if (this.endDate) { var end = this.endDate.clone(); end.hour(hour); end.minute(minute); end.second(second); this.setEndDate(end); } //update the calendars so all clickable dates reflect the new time component this.updateCalendars(); //update the form inputs above the calendars with the new time this.updateFormInputs(); //re-render the time pickers because changing one selection can affect what's enabled in another this.renderTimePicker('left'); this.renderTimePicker('right'); }, elementChanged: function() { if (!this.element.is('input')) return; if (!this.element.val().length) return; var dateString = this.element.val().split(this.locale.separator), start = null, end = null; if (dateString.length === 2) { start = moment(dateString[0], this.locale.format); end = moment(dateString[1], this.locale.format); } // if (this.singleDatePicker || start === null || end === null) { if (start === null || end === null) { start = moment(this.element.val(), this.locale.format); end = start; } if (!start.isValid() || !end.isValid()) return; this.setStartDate(start); this.setEndDate(end); this.updateView(); }, keydown: function(e) { //hide on tab or enter if ((e.keyCode === 9) || (e.keyCode === 13)) { this.hide(); } //hide on esc and prevent propagation if (e.keyCode === 27) { e.preventDefault(); e.stopPropagation(); this.hide(); } }, updateElement: function() { if (this.element.is('input') && this.autoUpdateInput) { var newValue = this.startDate.format(this.locale.format); newValue += this.locale.separator + this.endDate.format(this.locale.format); // if (!this.singleDatePicker) { // newValue += this.locale.separator + this.endDate.format(this.locale.format); // } if (newValue !== this.element.val()) { this.element.val(newValue).trigger('change'); } } }, remove: function() { this.container.remove(); this.element.off('.daterangepicker'); this.element.removeData(); } }; $.fn.daterangepicker = function(options, callback) { var implementOptions = $.extend(true, {}, $.fn.daterangepicker.defaultOptions, options); this.each(function() { var el = $(this); if (el.data('daterangepicker')) el.data('daterangepicker').remove(); el.data('daterangepicker', new DateRangePicker(el, implementOptions, callback)); }); return this; }; return DateRangePicker; }));