作者 zhangFan

机场口岸通关物流辅助管理系统

运行版
  1 +/*!
  2 + * Stylesheet for the Date Range Picker, for use with Bootstrap 3.x
  3 + *
  4 + * Copyright 2013 Dan Grossman ( http://www.dangrossman.info )
  5 + * Licensed under the Apache License v2.0
  6 + * http://www.apache.org/licenses/LICENSE-2.0
  7 + *
  8 + * Built for http://www.improvely.com
  9 + */
  10 +
  11 +.daterangepicker.dropdown-menu {
  12 + max-width: none;
  13 + z-index: 3000;
  14 +}
  15 +
  16 +.daterangepicker.opensleft .ranges, .daterangepicker.opensleft .calendar {
  17 + float: left;
  18 + margin: 4px;
  19 +}
  20 +
  21 +.daterangepicker.opensright .ranges, .daterangepicker.opensright .calendar {
  22 + float: right;
  23 + margin: 4px;
  24 +}
  25 +
  26 +.daterangepicker .ranges {
  27 + width: 160px;
  28 + text-align: left;
  29 +}
  30 +
  31 +.daterangepicker .ranges .range_inputs>div {
  32 + float: left;
  33 +}
  34 +
  35 +.daterangepicker .ranges .range_inputs>div:nth-child(2) {
  36 + padding-left: 11px;
  37 +}
  38 +
  39 +.daterangepicker .calendar {
  40 + display: none;
  41 + max-width: 270px;
  42 +}
  43 +
  44 +.daterangepicker.show-calendar .calendar {
  45 + display: block;
  46 +}
  47 +
  48 +.daterangepicker .calendar.single .calendar-date {
  49 + border: none;
  50 +}
  51 +
  52 +.daterangepicker .calendar th, .daterangepicker .calendar td {
  53 + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  54 + white-space: nowrap;
  55 + text-align: center;
  56 + min-width: 32px;
  57 +}
  58 +
  59 +.daterangepicker .daterangepicker_start_input label,
  60 +.daterangepicker .daterangepicker_end_input label {
  61 + color: #333;
  62 + display: block;
  63 + font-size: 11px;
  64 + font-weight: normal;
  65 + height: 20px;
  66 + line-height: 20px;
  67 + margin-bottom: 2px;
  68 + text-shadow: #fff 1px 1px 0px;
  69 + text-transform: uppercase;
  70 + width: 74px;
  71 +}
  72 +
  73 +.daterangepicker .ranges input {
  74 + font-size: 11px;
  75 +}
  76 +
  77 +.daterangepicker .ranges .input-mini {
  78 + background-color: #eee;
  79 + border: 1px solid #ccc;
  80 + border-radius: 4px;
  81 + color: #555;
  82 + display: block;
  83 + font-size: 11px;
  84 + height: 30px;
  85 + line-height: 30px;
  86 + vertical-align: middle;
  87 + margin: 0 0 10px 0;
  88 + padding: 0 6px;
  89 + width: 74px;
  90 +}
  91 +
  92 +.daterangepicker .ranges ul {
  93 + list-style: none;
  94 + margin: 0;
  95 + padding: 0;
  96 +}
  97 +
  98 +.daterangepicker .ranges li {
  99 + font-size: 13px;
  100 + background: #f5f5f5;
  101 + border: 1px solid #f5f5f5;
  102 + color: #08c;
  103 + padding: 3px 12px;
  104 + margin-bottom: 8px;
  105 + -webkit-border-radius: 5px;
  106 + -moz-border-radius: 5px;
  107 + border-radius: 5px;
  108 + cursor: pointer;
  109 +}
  110 +
  111 +.daterangepicker .ranges li.active, .daterangepicker .ranges li:hover {
  112 + background: #08c;
  113 + border: 1px solid #08c;
  114 + color: #fff;
  115 +}
  116 +
  117 +.daterangepicker .calendar-date {
  118 + border: 1px solid #ddd;
  119 + padding: 4px;
  120 + border-radius: 4px;
  121 + background: #fff;
  122 +}
  123 +
  124 +.daterangepicker .calendar-time {
  125 + text-align: center;
  126 + margin: 8px auto 0 auto;
  127 + line-height: 30px;
  128 +}
  129 +
  130 +.daterangepicker {
  131 + position: absolute;
  132 + background: #fff;
  133 + top: 100px;
  134 + left: 20px;
  135 + padding: 4px;
  136 + margin-top: 1px;
  137 + -webkit-border-radius: 4px;
  138 + -moz-border-radius: 4px;
  139 + border-radius: 4px;
  140 +}
  141 +
  142 +.daterangepicker.opensleft:before {
  143 + position: absolute;
  144 + top: -7px;
  145 + right: 9px;
  146 + display: inline-block;
  147 + border-right: 7px solid transparent;
  148 + border-bottom: 7px solid #ccc;
  149 + border-left: 7px solid transparent;
  150 + border-bottom-color: rgba(0, 0, 0, 0.2);
  151 + content: '';
  152 +}
  153 +
  154 +.daterangepicker.opensleft:after {
  155 + position: absolute;
  156 + top: -6px;
  157 + right: 10px;
  158 + display: inline-block;
  159 + border-right: 6px solid transparent;
  160 + border-bottom: 6px solid #fff;
  161 + border-left: 6px solid transparent;
  162 + content: '';
  163 +}
  164 +
  165 +.daterangepicker.opensright:before {
  166 + position: absolute;
  167 + top: -7px;
  168 + left: 9px;
  169 + display: inline-block;
  170 + border-right: 7px solid transparent;
  171 + border-bottom: 7px solid #ccc;
  172 + border-left: 7px solid transparent;
  173 + border-bottom-color: rgba(0, 0, 0, 0.2);
  174 + content: '';
  175 +}
  176 +
  177 +.daterangepicker.opensright:after {
  178 + position: absolute;
  179 + top: -6px;
  180 + left: 10px;
  181 + display: inline-block;
  182 + border-right: 6px solid transparent;
  183 + border-bottom: 6px solid #fff;
  184 + border-left: 6px solid transparent;
  185 + content: '';
  186 +}
  187 +
  188 +.daterangepicker table {
  189 + width: 100%;
  190 + margin: 0;
  191 +}
  192 +
  193 +.daterangepicker td, .daterangepicker th {
  194 + text-align: center;
  195 + width: 20px;
  196 + height: 20px;
  197 + -webkit-border-radius: 4px;
  198 + -moz-border-radius: 4px;
  199 + border-radius: 4px;
  200 + cursor: pointer;
  201 + white-space: nowrap;
  202 +}
  203 +
  204 +.daterangepicker td.off {
  205 + color: #999;
  206 +}
  207 +
  208 +.daterangepicker td.disabled {
  209 + color: #999;
  210 +}
  211 +
  212 +.daterangepicker td.available:hover, .daterangepicker th.available:hover {
  213 + background: #eee;
  214 +}
  215 +
  216 +.daterangepicker td.in-range {
  217 + background: #ebf4f8;
  218 + -webkit-border-radius: 0;
  219 + -moz-border-radius: 0;
  220 + border-radius: 0;
  221 +}
  222 +
  223 +.daterangepicker td.active, .daterangepicker td.active:hover {
  224 + background-color: #357ebd;
  225 + border-color: #3071a9;
  226 + color: #fff;
  227 +}
  228 +
  229 +.daterangepicker td.week, .daterangepicker th.week {
  230 + font-size: 80%;
  231 + color: #ccc;
  232 +}
  233 +
  234 +.daterangepicker select.monthselect, .daterangepicker select.yearselect {
  235 + font-size: 12px;
  236 + padding: 1px;
  237 + height: auto;
  238 + margin: 0;
  239 + cursor: default;
  240 +}
  241 +
  242 +.daterangepicker select.monthselect {
  243 + margin-right: 2%;
  244 + width: 56%;
  245 +}
  246 +
  247 +.daterangepicker select.yearselect {
  248 + width: 40%;
  249 +}
  250 +
  251 +.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.ampmselect {
  252 + width: 50px;
  253 + margin-bottom: 0;
  254 +}
  255 +
  256 +.daterangepicker_start_input {
  257 + float: left;
  258 +}
  259 +
  260 +.daterangepicker_end_input {
  261 + float: left;
  262 + padding-left: 11px
  263 +}
  264 +
  265 +.daterangepicker th.month {
  266 + width: auto;
  267 +}
  1 +/**
  2 + * @version: 1.3.7
  3 + * @author: Dan Grossman http://www.dangrossman.info/
  4 + * @date: 2014-04-29
  5 + * @copyright: Copyright (c) 2012-2014 Dan Grossman. All rights reserved.
  6 + * @license: Licensed under Apache License v2.0. See http://www.apache.org/licenses/LICENSE-2.0
  7 + * @website: http://www.improvely.com/
  8 + */
  9 +!function ($, moment) {
  10 +
  11 + var DateRangePicker = function (element, options, cb) {
  12 +
  13 + // by default, the daterangepicker element is placed at the bottom of HTML body
  14 + this.parentEl = 'body';
  15 +
  16 + //element that triggered the date range picker
  17 + this.element = $(element);
  18 +
  19 + //create the picker HTML object
  20 + var DRPTemplate = '<div class="daterangepicker dropdown-menu">' +
  21 + '<div class="calendar left"></div>' +
  22 + '<div class="calendar right"></div>' +
  23 + '<div class="ranges">' +
  24 + '<div class="range_inputs">' +
  25 + '<div class="daterangepicker_start_input">' +
  26 + '<label for="daterangepicker_start"></label>' +
  27 + '<input class="input-mini" type="text" name="daterangepicker_start" value="" disabled="disabled" />' +
  28 + '</div>' +
  29 + '<div class="daterangepicker_end_input">' +
  30 + '<label for="daterangepicker_end"></label>' +
  31 + '<input class="input-mini" type="text" name="daterangepicker_end" value="" disabled="disabled" />' +
  32 + '</div>' +
  33 + '<button class="applyBtn" disabled="disabled"></button>&nbsp;' +
  34 + '<button class="cancelBtn"></button>' +
  35 + '</div>' +
  36 + '</div>' +
  37 + '</div>';
  38 +
  39 + //custom options
  40 + if (typeof options !== 'object' || options === null)
  41 + options = {};
  42 +
  43 + this.parentEl = (typeof options === 'object' && options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl);
  44 + this.container = $(DRPTemplate).appendTo(this.parentEl);
  45 +
  46 + this.setOptions(options, cb);
  47 +
  48 + //apply CSS classes and labels to buttons
  49 + var c = this.container;
  50 + $.each(this.buttonClasses, function (idx, val) {
  51 + c.find('button').addClass(val);
  52 + });
  53 + this.container.find('.daterangepicker_start_input label').html(this.locale.fromLabel);
  54 + this.container.find('.daterangepicker_end_input label').html(this.locale.toLabel);
  55 + if (this.applyClass.length)
  56 + this.container.find('.applyBtn').addClass(this.applyClass);
  57 + if (this.cancelClass.length)
  58 + this.container.find('.cancelBtn').addClass(this.cancelClass);
  59 + this.container.find('.applyBtn').html(this.locale.applyLabel);
  60 + this.container.find('.cancelBtn').html(this.locale.cancelLabel);
  61 +
  62 + //event listeners
  63 +
  64 + this.container.find('.calendar')
  65 + .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
  66 + .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
  67 + .on('click.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
  68 + .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.enterDate, this))
  69 + .on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this))
  70 + .on('change.daterangepicker', 'select.yearselect', $.proxy(this.updateMonthYear, this))
  71 + .on('change.daterangepicker', 'select.monthselect', $.proxy(this.updateMonthYear, this))
  72 + .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.ampmselect', $.proxy(this.updateTime, this));
  73 +
  74 + this.container.find('.ranges')
  75 + .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))
  76 + .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))
  77 + .on('click.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.showCalendars, this))
  78 + .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))
  79 + .on('mouseenter.daterangepicker', 'li', $.proxy(this.enterRange, this))
  80 + .on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this));
  81 +
  82 + if (this.element.is('input')) {
  83 + this.element.on({
  84 + 'click.daterangepicker': $.proxy(this.show, this),
  85 + 'focus.daterangepicker': $.proxy(this.show, this),
  86 + 'keyup.daterangepicker': $.proxy(this.updateFromControl, this)
  87 + });
  88 + } else {
  89 + this.element.on('click.daterangepicker', $.proxy(this.toggle, this));
  90 + }
  91 +
  92 + };
  93 +
  94 + DateRangePicker.prototype = {
  95 +
  96 + constructor: DateRangePicker,
  97 +
  98 + setOptions: function(options, callback) {
  99 +
  100 + this.startDate = moment().startOf('day');
  101 + this.endDate = moment().endOf('day');
  102 + this.minDate = false;
  103 + this.maxDate = false;
  104 + this.dateLimit = false;
  105 +
  106 + this.showDropdowns = false;
  107 + this.showWeekNumbers = false;
  108 + this.timePicker = false;
  109 + this.timePickerIncrement = 30;
  110 + this.timePicker12Hour = true;
  111 + this.singleDatePicker = false;
  112 + this.ranges = {};
  113 +
  114 + this.opens = 'right';
  115 + if (this.element.hasClass('pull-right'))
  116 + this.opens = 'left';
  117 +
  118 + this.buttonClasses = ['btn', 'btn-small'];
  119 + this.applyClass = 'btn-success';
  120 + this.cancelClass = 'btn-default';
  121 +
  122 + this.format = 'MM/DD/YYYY';
  123 + this.separator = ' - ';
  124 +
  125 + this.locale = {
  126 + applyLabel: 'Apply',
  127 + cancelLabel: 'Cancel',
  128 + fromLabel: 'From',
  129 + toLabel: 'To',
  130 + weekLabel: 'W',
  131 + customRangeLabel: 'Custom Range',
  132 + daysOfWeek: moment()._lang._weekdaysMin.slice(),
  133 + monthNames: moment()._lang._monthsShort.slice(),
  134 + firstDay: 0
  135 + };
  136 +
  137 + this.cb = function () { };
  138 +
  139 + if (typeof options.format === 'string')
  140 + this.format = options.format;
  141 +
  142 + if (typeof options.separator === 'string')
  143 + this.separator = options.separator;
  144 +
  145 + if (typeof options.startDate === 'string')
  146 + this.startDate = moment(options.startDate, this.format);
  147 +
  148 + if (typeof options.endDate === 'string')
  149 + this.endDate = moment(options.endDate, this.format);
  150 +
  151 + if (typeof options.minDate === 'string')
  152 + this.minDate = moment(options.minDate, this.format);
  153 +
  154 + if (typeof options.maxDate === 'string')
  155 + this.maxDate = moment(options.maxDate, this.format);
  156 +
  157 + if (typeof options.startDate === 'object')
  158 + this.startDate = moment(options.startDate);
  159 +
  160 + if (typeof options.endDate === 'object')
  161 + this.endDate = moment(options.endDate);
  162 +
  163 + if (typeof options.minDate === 'object')
  164 + this.minDate = moment(options.minDate);
  165 +
  166 + if (typeof options.maxDate === 'object')
  167 + this.maxDate = moment(options.maxDate);
  168 +
  169 + if (typeof options.applyClass === 'string')
  170 + this.applyClass = options.applyClass;
  171 +
  172 + if (typeof options.cancelClass === 'string')
  173 + this.cancelClass = options.cancelClass;
  174 +
  175 + if (typeof options.dateLimit === 'object')
  176 + this.dateLimit = options.dateLimit;
  177 +
  178 + // update day names order to firstDay
  179 + if (typeof options.locale === 'object') {
  180 +
  181 + if (typeof options.locale.daysOfWeek === 'object') {
  182 + // Create a copy of daysOfWeek to avoid modification of original
  183 + // options object for reusability in multiple daterangepicker instances
  184 + this.locale.daysOfWeek = options.locale.daysOfWeek.slice();
  185 + }
  186 +
  187 + if (typeof options.locale.monthNames === 'object') {
  188 + this.locale.monthNames = options.locale.monthNames.slice();
  189 + }
  190 +
  191 + if (typeof options.locale.firstDay === 'number') {
  192 + this.locale.firstDay = options.locale.firstDay;
  193 + var iterator = options.locale.firstDay;
  194 + while (iterator > 0) {
  195 + this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift());
  196 + iterator--;
  197 + }
  198 + }
  199 +
  200 + if (typeof options.locale.applyLabel === 'string') {
  201 + this.locale.applyLabel = options.locale.applyLabel;
  202 + }
  203 +
  204 + if (typeof options.locale.cancelLabel === 'string') {
  205 + this.locale.cancelLabel = options.locale.cancelLabel;
  206 + }
  207 +
  208 + if (typeof options.locale.fromLabel === 'string') {
  209 + this.locale.fromLabel = options.locale.fromLabel;
  210 + }
  211 +
  212 + if (typeof options.locale.toLabel === 'string') {
  213 + this.locale.toLabel = options.locale.toLabel;
  214 + }
  215 +
  216 + if (typeof options.locale.weekLabel === 'string') {
  217 + this.locale.weekLabel = options.locale.weekLabel;
  218 + }
  219 +
  220 + if (typeof options.locale.customRangeLabel === 'string') {
  221 + this.locale.customRangeLabel = options.locale.customRangeLabel;
  222 + }
  223 + }
  224 +
  225 + if (typeof options.opens === 'string')
  226 + this.opens = options.opens;
  227 +
  228 + if (typeof options.showWeekNumbers === 'boolean') {
  229 + this.showWeekNumbers = options.showWeekNumbers;
  230 + }
  231 +
  232 + if (typeof options.buttonClasses === 'string') {
  233 + this.buttonClasses = [options.buttonClasses];
  234 + }
  235 +
  236 + if (typeof options.buttonClasses === 'object') {
  237 + this.buttonClasses = options.buttonClasses;
  238 + }
  239 +
  240 + if (typeof options.showDropdowns === 'boolean') {
  241 + this.showDropdowns = options.showDropdowns;
  242 + }
  243 +
  244 + if (typeof options.singleDatePicker === 'boolean') {
  245 + this.singleDatePicker = options.singleDatePicker;
  246 + }
  247 +
  248 + if (typeof options.timePicker === 'boolean') {
  249 + this.timePicker = options.timePicker;
  250 + }
  251 +
  252 + if (typeof options.timePickerIncrement === 'number') {
  253 + this.timePickerIncrement = options.timePickerIncrement;
  254 + }
  255 +
  256 + if (typeof options.timePicker12Hour === 'boolean') {
  257 + this.timePicker12Hour = options.timePicker12Hour;
  258 + }
  259 +
  260 + var start, end, range;
  261 +
  262 + //if no start/end dates set, check if an input element contains initial values
  263 + if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {
  264 + if ($(this.element).is('input[type=text]')) {
  265 + var val = $(this.element).val();
  266 + var split = val.split(this.separator);
  267 + start = end = null;
  268 + if (split.length == 2) {
  269 + start = moment(split[0], this.format);
  270 + end = moment(split[1], this.format);
  271 + } else if (this.singleDatePicker) {
  272 + start = moment(val, this.format);
  273 + end = moment(val, this.format);
  274 + }
  275 + if (start !== null && end !== null) {
  276 + this.startDate = start;
  277 + this.endDate = end;
  278 + }
  279 + }
  280 + }
  281 +
  282 + if (typeof options.ranges === 'object') {
  283 + for (range in options.ranges) {
  284 +
  285 + start = moment(options.ranges[range][0]);
  286 + end = moment(options.ranges[range][1]);
  287 +
  288 + // If we have a min/max date set, bound this range
  289 + // to it, but only if it would otherwise fall
  290 + // outside of the min/max.
  291 + if (this.minDate && start.isBefore(this.minDate))
  292 + start = moment(this.minDate);
  293 +
  294 + if (this.maxDate && end.isAfter(this.maxDate))
  295 + end = moment(this.maxDate);
  296 +
  297 + // If the end of the range is before the minimum (if min is set) OR
  298 + // the start of the range is after the max (also if set) don't display this
  299 + // range option.
  300 + if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) {
  301 + continue;
  302 + }
  303 +
  304 + this.ranges[range] = [start, end];
  305 + }
  306 +
  307 + var list = '<ul>';
  308 + for (range in this.ranges) {
  309 + list += '<li>' + range + '</li>';
  310 + }
  311 + list += '<li>' + this.locale.customRangeLabel + '</li>';
  312 + list += '</ul>';
  313 + this.container.find('.ranges ul').remove();
  314 + this.container.find('.ranges').prepend(list);
  315 + }
  316 +
  317 + if (typeof callback === 'function') {
  318 + this.cb = callback;
  319 + }
  320 +
  321 + if (!this.timePicker) {
  322 + this.startDate = this.startDate.startOf('day');
  323 + this.endDate = this.endDate.endOf('day');
  324 + }
  325 +
  326 + if (this.singleDatePicker) {
  327 + this.opens = 'right';
  328 + this.container.find('.calendar.right').show();
  329 + this.container.find('.calendar.left').hide();
  330 + this.container.find('.ranges').hide();
  331 + if (!this.container.find('.calendar.right').hasClass('single'))
  332 + this.container.find('.calendar.right').addClass('single');
  333 + } else {
  334 + this.container.find('.calendar.right').removeClass('single');
  335 + this.container.find('.ranges').show();
  336 + }
  337 +
  338 + this.oldStartDate = this.startDate.clone();
  339 + this.oldEndDate = this.endDate.clone();
  340 + this.oldChosenLabel = this.chosenLabel;
  341 +
  342 + this.leftCalendar = {
  343 + month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute()]),
  344 + calendar: []
  345 + };
  346 +
  347 + this.rightCalendar = {
  348 + month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute()]),
  349 + calendar: []
  350 + };
  351 +
  352 + if (this.opens == 'right') {
  353 + //swap calendar positions
  354 + var left = this.container.find('.calendar.left');
  355 + var right = this.container.find('.calendar.right');
  356 + left.removeClass('left').addClass('right');
  357 + right.removeClass('right').addClass('left');
  358 + }
  359 +
  360 + if (typeof options.ranges === 'undefined' && !this.singleDatePicker) {
  361 + this.container.addClass('show-calendar');
  362 + }
  363 +
  364 + this.container.addClass('opens' + this.opens);
  365 +
  366 + this.updateView();
  367 + this.updateCalendars();
  368 +
  369 + },
  370 +
  371 + setStartDate: function(startDate) {
  372 + if (typeof startDate === 'string')
  373 + this.startDate = moment(startDate, this.format);
  374 +
  375 + if (typeof startDate === 'object')
  376 + this.startDate = moment(startDate);
  377 +
  378 + if (!this.timePicker)
  379 + this.startDate = this.startDate.startOf('day');
  380 +
  381 + this.oldStartDate = this.startDate.clone();
  382 +
  383 + this.updateView();
  384 + this.updateCalendars();
  385 + },
  386 +
  387 + setEndDate: function(endDate) {
  388 + if (typeof endDate === 'string')
  389 + this.endDate = moment(endDate, this.format);
  390 +
  391 + if (typeof endDate === 'object')
  392 + this.endDate = moment(endDate);
  393 +
  394 + if (!this.timePicker)
  395 + this.endDate = this.endDate.endOf('day');
  396 +
  397 + this.oldEndDate = this.endDate.clone();
  398 +
  399 + this.updateView();
  400 + this.updateCalendars();
  401 + },
  402 +
  403 + updateView: function () {
  404 + this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year());
  405 + this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year());
  406 + this.updateFormInputs();
  407 + },
  408 +
  409 + updateFormInputs: function () {
  410 + this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.format));
  411 + this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.format));
  412 +
  413 + if (this.startDate.isSame(this.endDate) || this.startDate.isBefore(this.endDate)) {
  414 + this.container.find('button.applyBtn').removeAttr('disabled');
  415 + } else {
  416 + this.container.find('button.applyBtn').attr('disabled', 'disabled');
  417 + }
  418 + },
  419 +
  420 + updateFromControl: function () {
  421 + if (!this.element.is('input')) return;
  422 + if (!this.element.val().length) return;
  423 +
  424 + var dateString = this.element.val().split(this.separator),
  425 + start = null,
  426 + end = null;
  427 +
  428 + if(dateString.length === 2) {
  429 + start = moment(dateString[0], this.format);
  430 + end = moment(dateString[1], this.format);
  431 + }
  432 +
  433 + if (this.singleDatePicker || start === null || end === null) {
  434 + start = moment(this.element.val(), this.format);
  435 + end = start;
  436 + }
  437 +
  438 + if (end.isBefore(start)) return;
  439 +
  440 + this.oldStartDate = this.startDate.clone();
  441 + this.oldEndDate = this.endDate.clone();
  442 +
  443 + this.startDate = start;
  444 + this.endDate = end;
  445 +
  446 + if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
  447 + this.notify();
  448 +
  449 + this.updateCalendars();
  450 + },
  451 +
  452 + notify: function () {
  453 + this.updateView();
  454 + this.cb(this.startDate, this.endDate, this.chosenLabel);
  455 + },
  456 +
  457 + move: function () {
  458 + var parentOffset = { top: 0, left: 0 };
  459 + if (!this.parentEl.is('body')) {
  460 + parentOffset = {
  461 + top: this.parentEl.offset().top - this.parentEl.scrollTop(),
  462 + left: this.parentEl.offset().left - this.parentEl.scrollLeft()
  463 + };
  464 + }
  465 +
  466 + if (this.opens == 'left') {
  467 + this.container.css({
  468 + top: this.element.offset().top + this.element.outerHeight() - parentOffset.top,
  469 + right: $(window).width() - this.element.offset().left - this.element.outerWidth() - parentOffset.left,
  470 + left: 'auto'
  471 + });
  472 + if (this.container.offset().left < 0) {
  473 + this.container.css({
  474 + right: 'auto',
  475 + left: 9
  476 + });
  477 + }
  478 + } else {
  479 + this.container.css({
  480 + top: this.element.offset().top + this.element.outerHeight() - parentOffset.top,
  481 + left: this.element.offset().left - parentOffset.left,
  482 + right: 'auto'
  483 + });
  484 + if (this.container.offset().left + this.container.outerWidth() > $(window).width()) {
  485 + this.container.css({
  486 + left: 'auto',
  487 + right: 0
  488 + });
  489 + }
  490 + }
  491 + },
  492 +
  493 + toggle: function (e) {
  494 + if (this.element.hasClass('active')) {
  495 + this.hide();
  496 + } else {
  497 + this.show();
  498 + }
  499 + },
  500 +
  501 + show: function (e) {
  502 + this.element.addClass('active');
  503 + this.container.show();
  504 + this.move();
  505 +
  506 + // Create a click proxy that is private to this instance of datepicker, for unbinding
  507 + this._outsideClickProxy = $.proxy(function (e) { this.outsideClick(e); }, this);
  508 + // Bind global datepicker mousedown for hiding and
  509 + $(document)
  510 + .on('mousedown.daterangepicker', this._outsideClickProxy)
  511 + // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them
  512 + .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy)
  513 + // and also close when focus changes to outside the picker (eg. tabbing between controls)
  514 + .on('focusin.daterangepicker', this._outsideClickProxy);
  515 +
  516 + this.element.trigger('show.daterangepicker', this);
  517 + },
  518 +
  519 + outsideClick: function (e) {
  520 + var target = $(e.target);
  521 + // if the page is clicked anywhere except within the daterangerpicker/button
  522 + // itself then call this.hide()
  523 + if (
  524 + target.closest(this.element).length ||
  525 + target.closest(this.container).length ||
  526 + target.closest('.calendar-date').length
  527 + ) return;
  528 + this.hide();
  529 + },
  530 +
  531 + hide: function (e) {
  532 + $(document)
  533 + .off('mousedown.daterangepicker', this._outsideClickProxy)
  534 + .off('click.daterangepicker', this._outsideClickProxy)
  535 + .off('focusin.daterangepicker', this._outsideClickProxy);
  536 +
  537 + this.element.removeClass('active');
  538 + this.container.hide();
  539 +
  540 + if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
  541 + this.notify();
  542 +
  543 + this.oldStartDate = this.startDate.clone();
  544 + this.oldEndDate = this.endDate.clone();
  545 +
  546 + this.element.trigger('hide.daterangepicker', this);
  547 + },
  548 +
  549 + enterRange: function (e) {
  550 + // mouse pointer has entered a range label
  551 + var label = e.target.innerHTML;
  552 + if (label == this.locale.customRangeLabel) {
  553 + this.updateView();
  554 + } else {
  555 + var dates = this.ranges[label];
  556 + this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.format));
  557 + this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.format));
  558 + }
  559 + },
  560 +
  561 + showCalendars: function() {
  562 + this.container.addClass('show-calendar');
  563 + this.move();
  564 + },
  565 +
  566 + hideCalendars: function() {
  567 + this.container.removeClass('show-calendar');
  568 + },
  569 +
  570 + updateInputText: function() {
  571 + if (this.element.is('input') && !this.singleDatePicker) {
  572 + this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format));
  573 + } else if (this.element.is('input')) {
  574 + this.element.val(this.startDate.format(this.format));
  575 + }
  576 + },
  577 +
  578 + clickRange: function (e) {
  579 + var label = e.target.innerHTML;
  580 + this.chosenLabel = label;
  581 + if (label == this.locale.customRangeLabel) {
  582 + this.showCalendars();
  583 + } else {
  584 + var dates = this.ranges[label];
  585 +
  586 + this.startDate = dates[0];
  587 + this.endDate = dates[1];
  588 +
  589 + if (!this.timePicker) {
  590 + this.startDate.startOf('day');
  591 + this.endDate.endOf('day');
  592 + }
  593 +
  594 + this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute());
  595 + this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute());
  596 + this.updateCalendars();
  597 +
  598 + this.updateInputText();
  599 +
  600 + this.hideCalendars();
  601 + this.hide();
  602 + this.element.trigger('apply.daterangepicker', this);
  603 + }
  604 + },
  605 +
  606 + clickPrev: function (e) {
  607 + var cal = $(e.target).parents('.calendar');
  608 + if (cal.hasClass('left')) {
  609 + this.leftCalendar.month.subtract('month', 1);
  610 + } else {
  611 + this.rightCalendar.month.subtract('month', 1);
  612 + }
  613 + this.updateCalendars();
  614 + },
  615 +
  616 + clickNext: function (e) {
  617 + var cal = $(e.target).parents('.calendar');
  618 + if (cal.hasClass('left')) {
  619 + this.leftCalendar.month.add('month', 1);
  620 + } else {
  621 + this.rightCalendar.month.add('month', 1);
  622 + }
  623 + this.updateCalendars();
  624 + },
  625 +
  626 + enterDate: function (e) {
  627 +
  628 + var title = $(e.target).attr('data-title');
  629 + var row = title.substr(1, 1);
  630 + var col = title.substr(3, 1);
  631 + var cal = $(e.target).parents('.calendar');
  632 +
  633 + if (cal.hasClass('left')) {
  634 + this.container.find('input[name=daterangepicker_start]').val(this.leftCalendar.calendar[row][col].format(this.format));
  635 + } else {
  636 + this.container.find('input[name=daterangepicker_end]').val(this.rightCalendar.calendar[row][col].format(this.format));
  637 + }
  638 +
  639 + },
  640 +
  641 + clickDate: function (e) {
  642 + var title = $(e.target).attr('data-title');
  643 + var row = title.substr(1, 1);
  644 + var col = title.substr(3, 1);
  645 + var cal = $(e.target).parents('.calendar');
  646 +
  647 + var startDate, endDate;
  648 + if (cal.hasClass('left')) {
  649 + startDate = this.leftCalendar.calendar[row][col];
  650 + endDate = this.endDate;
  651 + if (typeof this.dateLimit === 'object') {
  652 + var maxDate = moment(startDate).add(this.dateLimit).startOf('day');
  653 + if (endDate.isAfter(maxDate)) {
  654 + endDate = maxDate;
  655 + }
  656 + }
  657 + } else {
  658 + startDate = this.startDate;
  659 + endDate = this.rightCalendar.calendar[row][col];
  660 + if (typeof this.dateLimit === 'object') {
  661 + var minDate = moment(endDate).subtract(this.dateLimit).startOf('day');
  662 + if (startDate.isBefore(minDate)) {
  663 + startDate = minDate;
  664 + }
  665 + }
  666 + }
  667 +
  668 + if (this.singleDatePicker && cal.hasClass('left')) {
  669 + endDate = startDate.clone();
  670 + } else if (this.singleDatePicker && cal.hasClass('right')) {
  671 + startDate = endDate.clone();
  672 + }
  673 +
  674 + cal.find('td').removeClass('active');
  675 +
  676 + if (startDate.isSame(endDate) || startDate.isBefore(endDate)) {
  677 + $(e.target).addClass('active');
  678 + this.startDate = startDate;
  679 + this.endDate = endDate;
  680 + this.chosenLabel = this.locale.customRangeLabel;
  681 + } else if (startDate.isAfter(endDate)) {
  682 + $(e.target).addClass('active');
  683 + var difference = this.endDate.diff(this.startDate);
  684 + this.startDate = startDate;
  685 + this.endDate = moment(startDate).add('ms', difference);
  686 + this.chosenLabel = this.locale.customRangeLabel;
  687 + }
  688 +
  689 + this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year());
  690 + this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year());
  691 + this.updateCalendars();
  692 +
  693 + if (!this.timePicker)
  694 + endDate.endOf('day');
  695 +
  696 + if (this.singleDatePicker)
  697 + this.clickApply();
  698 + },
  699 +
  700 + clickApply: function (e) {
  701 + this.updateInputText();
  702 + this.hide();
  703 + this.element.trigger('apply.daterangepicker', this);
  704 + },
  705 +
  706 + clickCancel: function (e) {
  707 + this.startDate = this.oldStartDate;
  708 + this.endDate = this.oldEndDate;
  709 + this.chosenLabel = this.oldChosenLabel;
  710 + this.updateView();
  711 + this.updateCalendars();
  712 + this.hide();
  713 + this.element.trigger('cancel.daterangepicker', this);
  714 + },
  715 +
  716 + updateMonthYear: function (e) {
  717 + var isLeft = $(e.target).closest('.calendar').hasClass('left'),
  718 + leftOrRight = isLeft ? 'left' : 'right',
  719 + cal = this.container.find('.calendar.'+leftOrRight);
  720 +
  721 + // Month must be Number for new moment versions
  722 + var month = parseInt(cal.find('.monthselect').val(), 10);
  723 + var year = cal.find('.yearselect').val();
  724 +
  725 + this[leftOrRight+'Calendar'].month.month(month).year(year);
  726 + this.updateCalendars();
  727 + },
  728 +
  729 + updateTime: function(e) {
  730 +
  731 + var cal = $(e.target).closest('.calendar'),
  732 + isLeft = cal.hasClass('left');
  733 +
  734 + var hour = parseInt(cal.find('.hourselect').val(), 10);
  735 + var minute = parseInt(cal.find('.minuteselect').val(), 10);
  736 +
  737 + if (this.timePicker12Hour) {
  738 + var ampm = cal.find('.ampmselect').val();
  739 + if (ampm === 'PM' && hour < 12)
  740 + hour += 12;
  741 + if (ampm === 'AM' && hour === 12)
  742 + hour = 0;
  743 + }
  744 +
  745 + if (isLeft) {
  746 + var start = this.startDate.clone();
  747 + start.hour(hour);
  748 + start.minute(minute);
  749 + this.startDate = start;
  750 + this.leftCalendar.month.hour(hour).minute(minute);
  751 + } else {
  752 + var end = this.endDate.clone();
  753 + end.hour(hour);
  754 + end.minute(minute);
  755 + this.endDate = end;
  756 + this.rightCalendar.month.hour(hour).minute(minute);
  757 + }
  758 +
  759 + this.updateCalendars();
  760 + },
  761 +
  762 + updateCalendars: function () {
  763 + this.leftCalendar.calendar = this.buildCalendar(this.leftCalendar.month.month(), this.leftCalendar.month.year(), this.leftCalendar.month.hour(), this.leftCalendar.month.minute(), 'left');
  764 + this.rightCalendar.calendar = this.buildCalendar(this.rightCalendar.month.month(), this.rightCalendar.month.year(), this.rightCalendar.month.hour(), this.rightCalendar.month.minute(), 'right');
  765 + this.container.find('.calendar.left').empty().html(this.renderCalendar(this.leftCalendar.calendar, this.startDate, this.minDate, this.maxDate));
  766 + this.container.find('.calendar.right').empty().html(this.renderCalendar(this.rightCalendar.calendar, this.endDate, this.startDate, this.maxDate));
  767 +
  768 + this.container.find('.ranges li').removeClass('active');
  769 + var customRange = true;
  770 + var i = 0;
  771 + for (var range in this.ranges) {
  772 + if (this.timePicker) {
  773 + if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) {
  774 + customRange = false;
  775 + this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')')
  776 + .addClass('active').html();
  777 + }
  778 + } else {
  779 + //ignore times when comparing dates if time picker is not enabled
  780 + 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')) {
  781 + customRange = false;
  782 + this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')')
  783 + .addClass('active').html();
  784 + }
  785 + }
  786 + i++;
  787 + }
  788 + if (customRange) {
  789 + this.chosenLabel = this.container.find('.ranges li:last')
  790 + .addClass('active').html();
  791 + }
  792 + },
  793 +
  794 + buildCalendar: function (month, year, hour, minute, side) {
  795 + var firstDay = moment([year, month, 1]);
  796 + var lastMonth = moment(firstDay).subtract('month', 1).month();
  797 + var lastYear = moment(firstDay).subtract('month', 1).year();
  798 +
  799 + var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();
  800 +
  801 + var dayOfWeek = firstDay.day();
  802 +
  803 + var i;
  804 +
  805 + //initialize a 6 rows x 7 columns array for the calendar
  806 + var calendar = [];
  807 + for (i = 0; i < 6; i++) {
  808 + calendar[i] = [];
  809 + }
  810 +
  811 + //populate the calendar with date objects
  812 + var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1;
  813 + if (startDay > daysInLastMonth)
  814 + startDay -= 7;
  815 +
  816 + if (dayOfWeek == this.locale.firstDay)
  817 + startDay = daysInLastMonth - 6;
  818 +
  819 + var curDate = moment([lastYear, lastMonth, startDay, 12, minute]);
  820 + var col, row;
  821 + for (i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add('hour', 24)) {
  822 + if (i > 0 && col % 7 === 0) {
  823 + col = 0;
  824 + row++;
  825 + }
  826 + calendar[row][col] = curDate.clone().hour(hour);
  827 + curDate.hour(12);
  828 + }
  829 +
  830 + return calendar;
  831 + },
  832 +
  833 + renderDropdowns: function (selected, minDate, maxDate) {
  834 + var currentMonth = selected.month();
  835 + var monthHtml = '<select class="monthselect">';
  836 + var inMinYear = false;
  837 + var inMaxYear = false;
  838 +
  839 + for (var m = 0; m < 12; m++) {
  840 + if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) {
  841 + monthHtml += "<option value='" + m + "'" +
  842 + (m === currentMonth ? " selected='selected'" : "") +
  843 + ">" + this.locale.monthNames[m] + "</option>";
  844 + }
  845 + }
  846 + monthHtml += "</select>";
  847 +
  848 + var currentYear = selected.year();
  849 + var maxYear = (maxDate && maxDate.year()) || (currentYear + 5);
  850 + var minYear = (minDate && minDate.year()) || (currentYear - 50);
  851 + var yearHtml = '<select class="yearselect">';
  852 +
  853 + for (var y = minYear; y <= maxYear; y++) {
  854 + yearHtml += '<option value="' + y + '"' +
  855 + (y === currentYear ? ' selected="selected"' : '') +
  856 + '>' + y + '</option>';
  857 + }
  858 +
  859 + yearHtml += '</select>';
  860 +
  861 + return monthHtml + yearHtml;
  862 + },
  863 +
  864 + renderCalendar: function (calendar, selected, minDate, maxDate) {
  865 +
  866 + var html = '<div class="calendar-date">';
  867 + html += '<table class="table-condensed">';
  868 + html += '<thead>';
  869 + html += '<tr>';
  870 +
  871 + // add empty cell for week number
  872 + if (this.showWeekNumbers)
  873 + html += '<th></th>';
  874 +
  875 + if (!minDate || minDate.isBefore(calendar[1][1])) {
  876 + html += '<th class="prev available"><i class="fa fa-arrow-left icon-arrow-left glyphicon glyphicon-arrow-left"></i></th>';
  877 + } else {
  878 + html += '<th></th>';
  879 + }
  880 +
  881 + var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY");
  882 +
  883 + if (this.showDropdowns) {
  884 + dateHtml = this.renderDropdowns(calendar[1][1], minDate, maxDate);
  885 + }
  886 +
  887 + html += '<th colspan="5" class="month">' + dateHtml + '</th>';
  888 + if (!maxDate || maxDate.isAfter(calendar[1][1])) {
  889 + html += '<th class="next available"><i class="fa fa-arrow-right icon-arrow-right glyphicon glyphicon-arrow-right"></i></th>';
  890 + } else {
  891 + html += '<th></th>';
  892 + }
  893 +
  894 + html += '</tr>';
  895 + html += '<tr>';
  896 +
  897 + // add week number label
  898 + if (this.showWeekNumbers)
  899 + html += '<th class="week">' + this.locale.weekLabel + '</th>';
  900 +
  901 + $.each(this.locale.daysOfWeek, function (index, dayOfWeek) {
  902 + html += '<th>' + dayOfWeek + '</th>';
  903 + });
  904 +
  905 + html += '</tr>';
  906 + html += '</thead>';
  907 + html += '<tbody>';
  908 +
  909 + for (var row = 0; row < 6; row++) {
  910 + html += '<tr>';
  911 +
  912 + // add week number
  913 + if (this.showWeekNumbers)
  914 + html += '<td class="week">' + calendar[row][0].week() + '</td>';
  915 +
  916 + for (var col = 0; col < 7; col++) {
  917 + var cname = 'available ';
  918 + cname += (calendar[row][col].month() == calendar[1][1].month()) ? '' : 'off';
  919 +
  920 + if ((minDate && calendar[row][col].isBefore(minDate, 'day')) || (maxDate && calendar[row][col].isAfter(maxDate, 'day'))) {
  921 + cname = ' off disabled ';
  922 + } else if (calendar[row][col].format('YYYY-MM-DD') == selected.format('YYYY-MM-DD')) {
  923 + cname += ' active ';
  924 + if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) {
  925 + cname += ' start-date ';
  926 + }
  927 + if (calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) {
  928 + cname += ' end-date ';
  929 + }
  930 + } else if (calendar[row][col] >= this.startDate && calendar[row][col] <= this.endDate) {
  931 + cname += ' in-range ';
  932 + if (calendar[row][col].isSame(this.startDate)) { cname += ' start-date '; }
  933 + if (calendar[row][col].isSame(this.endDate)) { cname += ' end-date '; }
  934 + }
  935 +
  936 + var title = 'r' + row + 'c' + col;
  937 + html += '<td class="' + cname.replace(/\s+/g, ' ').replace(/^\s?(.*?)\s?$/, '$1') + '" data-title="' + title + '">' + calendar[row][col].date() + '</td>';
  938 + }
  939 + html += '</tr>';
  940 + }
  941 +
  942 + html += '</tbody>';
  943 + html += '</table>';
  944 + html += '</div>';
  945 +
  946 + var i;
  947 + if (this.timePicker) {
  948 +
  949 + html += '<div class="calendar-time">';
  950 + html += '<select class="hourselect">';
  951 + var start = 0;
  952 + var end = 23;
  953 + var selected_hour = selected.hour();
  954 + if (this.timePicker12Hour) {
  955 + start = 1;
  956 + end = 12;
  957 + if (selected_hour >= 12)
  958 + selected_hour -= 12;
  959 + if (selected_hour === 0)
  960 + selected_hour = 12;
  961 + }
  962 +
  963 + for (i = start; i <= end; i++) {
  964 + if (i == selected_hour) {
  965 + html += '<option value="' + i + '" selected="selected">' + i + '</option>';
  966 + } else {
  967 + html += '<option value="' + i + '">' + i + '</option>';
  968 + }
  969 + }
  970 +
  971 + html += '</select> : ';
  972 +
  973 + html += '<select class="minuteselect">';
  974 +
  975 + for (i = 0; i < 60; i += this.timePickerIncrement) {
  976 + var num = i;
  977 + if (num < 10)
  978 + num = '0' + num;
  979 + if (i == selected.minute()) {
  980 + html += '<option value="' + i + '" selected="selected">' + num + '</option>';
  981 + } else {
  982 + html += '<option value="' + i + '">' + num + '</option>';
  983 + }
  984 + }
  985 +
  986 + html += '</select> ';
  987 +
  988 + if (this.timePicker12Hour) {
  989 + html += '<select class="ampmselect">';
  990 + if (selected.hour() >= 12) {
  991 + html += '<option value="AM">AM</option><option value="PM" selected="selected">PM</option>';
  992 + } else {
  993 + html += '<option value="AM" selected="selected">AM</option><option value="PM">PM</option>';
  994 + }
  995 + html += '</select>';
  996 + }
  997 +
  998 + html += '</div>';
  999 +
  1000 + }
  1001 +
  1002 + return html;
  1003 +
  1004 + },
  1005 +
  1006 + remove: function() {
  1007 +
  1008 + this.container.remove();
  1009 + this.element.off('.daterangepicker');
  1010 + this.element.removeData('daterangepicker');
  1011 +
  1012 + }
  1013 +
  1014 + };
  1015 +
  1016 + $.fn.daterangepicker = function (options, cb) {
  1017 + this.each(function () {
  1018 + var el = $(this);
  1019 + if (el.data('daterangepicker'))
  1020 + el.data('daterangepicker').remove();
  1021 + el.data('daterangepicker', new DateRangePicker(el, options, cb));
  1022 + });
  1023 + return this;
  1024 + };
  1025 +
  1026 +}(window.jQuery, window.moment);