瀏覽代碼

[search] Added daterangepicker

Enrico Berti 11 年之前
父節點
當前提交
e368eee

+ 71 - 21
apps/search/src/search/templates/search.mako

@@ -314,17 +314,9 @@ ${ commonheader(_('Search'), "search", user, "80px") | n,unicode }
         <div class="slider-cnt" data-bind="slider: {start: properties.start, end: properties.end, gap: properties.gap, min: properties.min, max: properties.max}"></div>
       <!-- /ko -->
       <!-- ko if: properties.isDate() -->
-        ${ _('Start') }:
-        <input type="text" class="input-large" data-bind="value: properties.start" />
-        <br/>
-        ${ _('End') }: <input type="text" class="input-large" data-bind="value: properties.end" />
-        <br/>
-        ${ _('Gap') }: <input type="text" class="input-small" data-bind="value: properties.gap" />
-        <br/>
-        ${ _('Min') }:
-        <input type="text" class="input-medium" data-bind="value: properties.min" />
-        <br/>
-        ${ _('Max') }: <input type="text" class="input-medium" data-bind="value: properties.max" />
+        <div class="input-prepend input-group">
+           <span class="add-on input-group-addon"><i class="fa fa-calendar"></i></span><input type="text" class="input-xxlarge form-control" data-bind="daterangepicker: {start: properties.start, end: properties.end, gap: properties.gap, min: properties.min, max: properties.max}" />
+        </div>
         <br/>
       <!-- /ko -->
     <!-- /ko -->
@@ -944,6 +936,7 @@ ${ commonheader(_('Search'), "search", user, "80px") | n,unicode }
 ## Extra code for style and custom JS
 <span id="extra" data-bind="augmenthtml: $root.collection.template.extracode"></span>
 
+
 <link rel="stylesheet" href="/search/static/css/search.css">
 <link rel="stylesheet" href="/static/ext/css/hue-filetypes.css">
 <link rel="stylesheet" href="/static/ext/css/leaflet.css">
@@ -953,25 +946,28 @@ ${ commonheader(_('Search'), "search", user, "80px") | n,unicode }
 <link rel="stylesheet" href="/static/ext/css/bootstrap-editable.css">
 <link rel="stylesheet" href="/static/css/bootstrap-spinedit.css">
 <link rel="stylesheet" href="/static/css/bootstrap-slider.css">
+<link rel="stylesheet" href="/static/css/bootstrap-daterangepicker.css">
 <link rel="stylesheet" href="/static/ext/css/nv.d3.min.css">
 <link rel="stylesheet" href="/search/static/css/nv.d3.css">
 <link rel="stylesheet" href="/static/ext/chosen/chosen.min.css">
 
+<script src="/static/ext/js/moment-with-langs.min.js" type="text/javascript" charset="utf-8"></script>
+
 <script src="/search/static/js/search.utils.js" type="text/javascript" charset="utf-8"></script>
 <script src="/search/static/js/lzstring.min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/knockout.mapping-2.3.2.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/knockout-sortable.min.js" type="text/javascript" charset="utf-8"></script>
-<script src="/static/ext/js/bootstrap-editable.min.js"></script>
-<script src="/static/js/bootstrap-spinedit.js"></script>
-<script src="/static/js/bootstrap-slider.js"></script>
-<script src="/static/js/ko.editable.js"></script>
+<script src="/static/ext/js/bootstrap-editable.min.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/js/bootstrap-spinedit.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/js/bootstrap-slider.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/js/bootstrap-daterangepicker.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/js/ko.editable.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/shortcut.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/js/freshereditor.js" type="text/javascript" charset="utf-8"></script>
-<script src="/static/ext/js/codemirror-3.11.js"></script>
-<script src="/static/ext/js/moment.min.js" type="text/javascript" charset="utf-8"></script>
-<script src="/static/ext/js/codemirror-xml.js"></script>
-<script src="/static/ext/js/mustache.js"></script>
+<script src="/static/ext/js/codemirror-3.11.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/ext/js/codemirror-xml.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/ext/js/mustache.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/jquery/plugins/jquery-ui-1.10.4.draggable-droppable-sortable.min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/jquery/plugins/jquery.flot.min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/jquery/plugins/jquery.flot.categories.min.js" type="text/javascript" charset="utf-8"></script>
@@ -980,8 +976,8 @@ ${ commonheader(_('Search'), "search", user, "80px") | n,unicode }
 
 <script src="/search/static/js/search.ko.js" type="text/javascript" charset="utf-8"></script>
 
-<script src="/static/js/hue.geo.js"></script>
-<script src="/static/js/hue.colors.js"></script>
+<script src="/static/js/hue.geo.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/js/hue.colors.js" type="text/javascript" charset="utf-8"></script>
 
 <script src="/static/ext/js/d3.v3.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/nv.d3.min.js" type="text/javascript" charset="utf-8"></script>
@@ -1387,6 +1383,60 @@ $(document).ready(function () {
     }
   }
 
+  ko.bindingHandlers.daterangepicker = {
+    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
+      var _el = $(element);
+      var _options = $.extend(valueAccessor(), {});
+      _el.val(_options.min() + ' ${_('to')} ' + _options.max() + ', ' + _options.gap());
+      _el.daterangepicker({
+            startDate: _options.min() ? moment(_options.min()).utc() : moment().subtract('days', 29),
+            endDate: _options.max() ? moment(_options.max()).utc() : moment(),
+            interval: _options.gap() ? _options.gap() : '+30MINUTES',
+            showDropdowns: true,
+            showWeekNumbers: true,
+            timePicker: true,
+            timePickerIncrement: 1,
+            timePicker12Hour: false,
+            ranges: {
+              'Today': [moment(), moment()],
+              'Yesterday': [moment().subtract('days', 1), moment().subtract('days', 1)],
+              'Last 7 Days': [moment().subtract('days', 6), moment()],
+              'Last 30 Days': [moment().subtract('days', 29), moment()],
+              'This Month': [moment().startOf('month'), moment().endOf('month')],
+              'Last Month': [moment().subtract('month', 1).startOf('month'), moment().subtract('month', 1).endOf('month')]
+            },
+            opens: 'right',
+            buttonClasses: ['btn btn-default'],
+            applyClass: 'btn-small btn-primary',
+            cancelClass: 'btn-small',
+            format: 'MM/DD/YYYY HH:mm:ss',
+            separator: ' ${_('to')} ',
+            locale: {
+              applyLabel: '${_('Pick')}',
+              cancelLabel: '${_('Cancel')}',
+              fromLabel: '${_('From')}',
+              toLabel: '${_('To')}',
+              intervalLabel: '${_('Interval')}',
+              customRangeLabel: '${_('Custom')}',
+              daysOfWeek: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
+              monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
+              firstDay: 1
+            }
+          },
+          function (start, end, interval, label) {
+            _options.min(start.utc().format("YYYY-MM-DD[T]HH:mm:ss[Z]"));
+            _options.start(start.utc().format("YYYY-MM-DD[T]HH:mm:ss[Z]"));
+            _options.max(end.utc().format("YYYY-MM-DD[T]HH:mm:ss[Z]"));
+            _options.end(end.utc().format("YYYY-MM-DD[T]HH:mm:ss[Z]"));
+            _options.gap(interval);
+            _el.val(_options.min() + ' ${_('to')} ' + _options.max() + ', ' + _options.gap());
+          });
+    },
+    update: function (element, valueAccessor, allBindingsAccessor) {
+      var _options = $.extend(valueAccessor(), {});
+    }
+  }
+
   ko.bindingHandlers.augmenthtml = {
     render: function (element, valueAccessor, allBindingsAccessor, viewModel) {
       var _val = ko.unwrap(valueAccessor());

+ 279 - 0
desktop/core/static/css/bootstrap-daterangepicker.css

@@ -0,0 +1,279 @@
+/*!
+ * Stylesheet for the Date Range Picker, for use with Bootstrap 2.x
+ *
+ * Copyright 2013 Dan Grossman ( http://www.dangrossman.info )
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Built for http://www.improvely.com
+ *
+ *
+ *
+ * Modified to fit into Hue
+ *
+ */
+
+.daterangepicker.dropdown-menu {
+  max-width: none;
+  z-index: 3000;
+}
+
+.daterangepicker.opensleft .ranges, .daterangepicker.opensleft .calendar {
+  float: left;
+  margin: 4px;
+}
+
+.daterangepicker.opensright .ranges, .daterangepicker.opensright .calendar {
+  float: right;
+  margin: 4px;
+}
+
+.daterangepicker .ranges {
+  width: 190px;
+  text-align: left;
+}
+
+.daterangepicker .range_inputs {
+  clear: both;
+  padding: 10px;
+  text-align: center;
+}
+
+.daterangepicker .range_inputs > div {
+  float: left;
+}
+
+.daterangepicker .range_inputs > div:nth-child(2), .daterangepicker .range_inputs > div:nth-child(3) {
+  padding-left: 11px;
+}
+
+.daterangepicker .calendar {
+  display: none;
+  max-width: 250px;
+}
+
+.daterangepicker.show-calendar .calendar {
+  display: block;
+}
+
+.daterangepicker .calendar.single .calendar-date {
+  border: none;
+}
+
+.daterangepicker .calendar th, .daterangepicker .calendar td {
+  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+  white-space: nowrap;
+  text-align: center;
+}
+
+.daterangepicker .daterangepicker_start_input label,
+.daterangepicker .daterangepicker_end_input label,
+.daterangepicker .daterangepicker_interval_input label {
+  color: #333;
+  font-size: 11px;
+  margin-bottom: 2px;
+  text-transform: uppercase;
+  text-shadow: 1px 1px 0 #fff;
+}
+
+.daterangepicker .ranges input, .daterangepicker .range_inputs input {
+  font-size: 11px;
+  width: 100px;
+}
+
+.daterangepicker .ranges ul {
+  list-style: none;
+  margin: 0;
+  padding: 0;
+}
+
+.daterangepicker .ranges li {
+  font-size: 13px;
+  background: #f5f5f5;
+  border: 1px solid #f5f5f5;
+  color: #08c;
+  padding: 3px 12px;
+  margin-bottom: 8px;
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  border-radius: 5px;
+  cursor: pointer;
+}
+
+.daterangepicker .ranges li.active, .daterangepicker .ranges li:hover {
+  background: #08c;
+  border: 1px solid #08c;
+  color: #fff;
+}
+
+.daterangepicker .calendar-date {
+  border: 1px solid #ddd;
+  padding: 4px;
+  border-radius: 4px;
+  background: #fff;
+}
+
+.daterangepicker .calendar-time {
+  text-align: center;
+  margin: 8px auto 0 auto;
+  line-height: 30px;
+}
+
+.daterangepicker {
+  position: absolute;
+  background: #fff;
+  top: 100px;
+  left: 20px;
+  padding: 4px;
+  margin-top: 1px;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px;
+}
+
+.daterangepicker.opensleft:before {
+  position: absolute;
+  top: -7px;
+  right: 9px;
+  display: inline-block;
+  border-right: 7px solid transparent;
+  border-bottom: 7px solid #ccc;
+  border-left: 7px solid transparent;
+  border-bottom-color: rgba(0, 0, 0, 0.2);
+  content: '';
+}
+
+.daterangepicker.opensleft:after {
+  position: absolute;
+  top: -6px;
+  right: 10px;
+  display: inline-block;
+  border-right: 6px solid transparent;
+  border-bottom: 6px solid #fff;
+  border-left: 6px solid transparent;
+  content: '';
+}
+
+.daterangepicker.opensright:before {
+  position: absolute;
+  top: -7px;
+  left: 9px;
+  display: inline-block;
+  border-right: 7px solid transparent;
+  border-bottom: 7px solid #ccc;
+  border-left: 7px solid transparent;
+  border-bottom-color: rgba(0, 0, 0, 0.2);
+  content: '';
+}
+
+.daterangepicker.opensright:after {
+  position: absolute;
+  top: -6px;
+  left: 10px;
+  display: inline-block;
+  border-right: 6px solid transparent;
+  border-bottom: 6px solid #fff;
+  border-left: 6px solid transparent;
+  content: '';
+}
+
+.daterangepicker table {
+  width: 100%;
+  margin: 0;
+}
+
+.daterangepicker td, .daterangepicker th {
+  text-align: center;
+  width: 20px;
+  height: 20px;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px;
+  cursor: pointer;
+  white-space: nowrap;
+}
+
+.daterangepicker td.off {
+  color: #999;
+}
+
+.daterangepicker td.disabled {
+  color: #999;
+}
+
+.daterangepicker td.available:hover, .daterangepicker th.available:hover {
+  background: #eee;
+}
+
+.daterangepicker td.in-range {
+  background: #ebf4f8;
+  -webkit-border-radius: 0;
+  -moz-border-radius: 0;
+  border-radius: 0;
+}
+
+.daterangepicker td.active, .daterangepicker td.active:hover {
+  background-color: #006dcc;
+  background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
+  background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
+  background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
+  background-image: -o-linear-gradient(top, #0088cc, #0044cc);
+  background-image: linear-gradient(top, #0088cc, #0044cc);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
+  border-color: #0044cc #0044cc #002a80;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+  color: #fff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+
+.daterangepicker td.week, .daterangepicker th.week {
+  font-size: 80%;
+  color: #ccc;
+}
+
+.daterangepicker select.monthselect, .daterangepicker select.yearselect {
+  font-size: 12px;
+  padding: 1px;
+  height: auto;
+  margin: 0;
+  cursor: default;
+}
+
+.daterangepicker select.monthselect {
+  margin-right: 2%;
+  width: 56%;
+}
+
+.daterangepicker select.yearselect {
+  width: 40%;
+}
+
+.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect {
+  width: 60px;
+  margin-bottom: 0;
+}
+
+.daterangepicker_start_input {
+  float: left;
+}
+
+.daterangepicker_end_input {
+  float: left;
+  padding-left: 11px
+}
+
+.daterangepicker_interval_input {
+  float: left;
+  padding-left: 11px
+}
+
+.daterangepicker th.month {
+  width: auto;
+}
+
+.daterangepicker hr {
+  margin: 4px;
+}

文件差異過大導致無法顯示
+ 5 - 0
desktop/core/static/ext/js/moment-with-langs.min.js


+ 1111 - 0
desktop/core/static/js/bootstrap-daterangepicker.js

@@ -0,0 +1,1111 @@
+/**
+* @version: 1.3.7
+* @author: Dan Grossman http://www.dangrossman.info/
+* @date: 2014-04-29
+* @copyright: Copyright (c) 2012-2014 Dan Grossman. All rights reserved.
+* @license: Licensed under Apache License v2.0. See http://www.apache.org/licenses/LICENSE-2.0
+* @website: http://www.improvely.com/
+*
+*
+* Modified to fit into Hue
+*
+*/
+!function ($, moment) {
+
+  var DateRangePicker = function (element, options, cb) {
+
+    // by default, the daterangepicker element is placed at the bottom of HTML body
+    this.parentEl = 'body';
+
+    //element that triggered the date range picker
+    this.element = $(element);
+
+    //create the picker HTML object
+    var DRPTemplate = '<div class="daterangepicker dropdown-menu show-calendar">' +
+        '<div class="calendar left"></div>' +
+        '<div class="calendar right"></div>' +
+        '<div class="ranges">' +
+        '</div>' +
+        '<div class="range_inputs">' +
+          '<hr/>' +
+          '<div class="daterangepicker_start_input">' +
+            '<label for="daterangepicker_start"></label>' +
+            '<input class="input" type="text" name="daterangepicker_start" value="" disabled="disabled" />' +
+          '</div>' +
+          '<div class="daterangepicker_end_input">' +
+            '<label for="daterangepicker_end"></label>' +
+            '<input class="input" type="text" name="daterangepicker_end" value="" disabled="disabled" />' +
+          '</div>' +
+          '<div class="daterangepicker_interval_input">' +
+            '<label for="daterangepicker_interval"></label>' +
+            '<select class="input-small daterangepicker_interval_select" type="text" name="daterangepicker_interval_select" value="" style="margin-right: 6px">' +
+              '<option value="+200MILLISECONDS">200 MILLIS</option>' +
+              '<option value="+30SECONDS">30 SECS</option>' +
+              '<option value="+5MINUTES">5 MIN</option>' +
+              '<option value="+30MINUTES">30 MIN</option>' +
+              '<option value="+1HOURS">1 HOUR</option>' +
+              '<option value="+12HOURS">12 HOURS</option>' +
+              '<option value="+1DAYS">1 DAY</option>' +
+              '<option value="+7DAYS">7 DAYS</option>' +
+              '<option value="+1MONTHS">1 MONTH</option>' +
+              '<option value="+6MONTHS">6 MONTHS</option>' +
+              '<option value="+1YEARS">1 YEAR</option>' +
+              '<option value="">Custom</option>' +
+            '</select>' +
+            '<input class="input daterangepicker_interval" type="text" name="daterangepicker_interval" value="" />' +
+          '</div>' +
+          '<div style="float:right; margin-top: 23px">' +
+            '<button class="cancelBtn"></button>&nbsp;' +
+            '<button class="applyBtn" disabled="disabled"></button>' +
+          '</div>' +
+        '</div>' +
+        '</div>';
+
+    //custom options
+    if (typeof options !== 'object' || options === null)
+      options = {};
+
+    this.parentEl = (typeof options === 'object' && options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl);
+    this.container = $(DRPTemplate).appendTo(this.parentEl);
+
+    this.setOptions(options, cb);
+
+    //apply CSS classes and labels to buttons
+    var c = this.container;
+    $.each(this.buttonClasses, function (idx, val) {
+      c.find('button').addClass(val);
+    });
+    this.container.find('.daterangepicker_start_input label').html(this.locale.fromLabel);
+    this.container.find('.daterangepicker_end_input label').html(this.locale.toLabel);
+    this.container.find('.daterangepicker_interval_input label').html(this.locale.intervalLabel);
+    if (this.applyClass.length)
+      this.container.find('.applyBtn').addClass(this.applyClass);
+    if (this.cancelClass.length)
+      this.container.find('.cancelBtn').addClass(this.cancelClass);
+    this.container.find('.applyBtn').html(this.locale.applyLabel);
+    this.container.find('.cancelBtn').html(this.locale.cancelLabel);
+
+    //event listeners
+
+    this.container.find('.calendar')
+        .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
+        .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
+        .on('click.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
+        .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.enterDate, this))
+        .on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this))
+        .on('change.daterangepicker', 'select.yearselect', $.proxy(this.updateMonthYear, this))
+        .on('change.daterangepicker', 'select.monthselect', $.proxy(this.updateMonthYear, this))
+        .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.updateTime, this));
+
+    this.container.find('.ranges')
+        .on('click.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input,.daterangepicker_interval_input', $.proxy(this.showCalendars, this))
+        .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))
+        .on('mouseenter.daterangepicker', 'li', $.proxy(this.enterRange, this))
+        .on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this));
+
+    this.container.find('.range_inputs')
+        .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))
+        .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))
+        .on('change.daterangepicker', 'select.daterangepicker_interval_select', $.proxy(this.updateIntervalFromSelect, this))
+        .on('change.daterangepicker', 'input.daterangepicker_interval', $.proxy(this.updateIntervalFromInput, this))
+
+
+    if (this.element.is('input')) {
+      this.element.on({
+        'click.daterangepicker': $.proxy(this.show, this),
+        'focus.daterangepicker': $.proxy(this.show, this),
+        'keyup.daterangepicker': $.proxy(this.updateFromControl, this)
+      });
+    } else {
+      this.element.on('click.daterangepicker', $.proxy(this.toggle, this));
+    }
+
+  };
+
+  DateRangePicker.prototype = {
+
+    constructor: DateRangePicker,
+
+    setOptions: function (options, callback) {
+
+      this.startDate = moment().startOf('day');
+      this.endDate = moment().endOf('day');
+      this.interval = '+30MINUTES';
+      this.minDate = false;
+      this.maxDate = false;
+      this.dateLimit = false;
+
+      this.showDropdowns = false;
+      this.showWeekNumbers = false;
+      this.timePicker = false;
+      this.timePickerIncrement = 30;
+      this.timePicker12Hour = true;
+      this.singleDatePicker = false;
+      this.ranges = {};
+
+      this.opens = 'right';
+      if (this.element.hasClass('pull-right'))
+        this.opens = 'left';
+
+      this.buttonClasses = ['btn', 'btn-small'];
+      this.applyClass = 'btn-success';
+      this.cancelClass = 'btn-default';
+
+      this.format = 'MM/DD/YYYY';
+      this.separator = ' - ';
+
+      this.locale = {
+        applyLabel: 'Apply',
+        cancelLabel: 'Cancel',
+        fromLabel: 'From',
+        toLabel: 'To',
+        intervalLabel: 'Interval',
+        weekLabel: 'W',
+        customRangeLabel: 'Custom Range',
+        daysOfWeek: moment()._lang._weekdaysMin.slice(),
+        monthNames: moment()._lang._monthsShort.slice(),
+        firstDay: 0
+      };
+
+      this.cb = function () {
+      };
+
+      if (typeof options.format === 'string')
+        this.format = options.format;
+
+      if (typeof options.separator === 'string')
+        this.separator = options.separator;
+
+      if (typeof options.startDate === 'string')
+        this.startDate = moment(options.startDate, this.format);
+
+      if (typeof options.endDate === 'string')
+        this.endDate = moment(options.endDate, this.format);
+
+      if (typeof options.minDate === 'string')
+        this.minDate = moment(options.minDate, this.format);
+
+      if (typeof options.maxDate === 'string')
+        this.maxDate = moment(options.maxDate, this.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);
+
+      if (typeof options.applyClass === 'string')
+        this.applyClass = options.applyClass;
+
+      if (typeof options.cancelClass === 'string')
+        this.cancelClass = options.cancelClass;
+
+      if (typeof options.dateLimit === 'object')
+        this.dateLimit = options.dateLimit;
+
+      if (typeof options.interval === 'string')
+        this.interval = options.interval;
+
+
+      // update day names order to firstDay
+      if (typeof options.locale === 'object') {
+
+        if (typeof options.locale.daysOfWeek === 'object') {
+          // Create a copy of daysOfWeek to avoid modification of original
+          // options object for reusability in multiple daterangepicker instances
+          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;
+          var iterator = options.locale.firstDay;
+          while (iterator > 0) {
+            this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift());
+            iterator--;
+          }
+        }
+
+        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.fromLabel === 'string') {
+          this.locale.fromLabel = options.locale.fromLabel;
+        }
+
+        if (typeof options.locale.toLabel === 'string') {
+          this.locale.toLabel = options.locale.toLabel;
+        }
+
+        if (typeof options.locale.intervalLabel === 'string') {
+          this.locale.intervalLabel = options.locale.intervalLabel;
+        }
+
+        if (typeof options.locale.weekLabel === 'string') {
+          this.locale.weekLabel = options.locale.weekLabel;
+        }
+
+        if (typeof options.locale.customRangeLabel === 'string') {
+          this.locale.customRangeLabel = options.locale.customRangeLabel;
+        }
+      }
+
+      if (typeof options.opens === 'string')
+        this.opens = options.opens;
+
+      if (typeof options.showWeekNumbers === 'boolean') {
+        this.showWeekNumbers = options.showWeekNumbers;
+      }
+
+      if (typeof options.buttonClasses === 'string') {
+        this.buttonClasses = [options.buttonClasses];
+      }
+
+      if (typeof options.buttonClasses === 'object') {
+        this.buttonClasses = options.buttonClasses;
+      }
+
+      if (typeof options.showDropdowns === 'boolean') {
+        this.showDropdowns = options.showDropdowns;
+      }
+
+      if (typeof options.singleDatePicker === 'boolean') {
+        this.singleDatePicker = options.singleDatePicker;
+      }
+
+      if (typeof options.timePicker === 'boolean') {
+        this.timePicker = options.timePicker;
+      }
+
+      if (typeof options.timePickerIncrement === 'number') {
+        this.timePickerIncrement = options.timePickerIncrement;
+      }
+
+      if (typeof options.timePicker12Hour === 'boolean') {
+        this.timePicker12Hour = options.timePicker12Hour;
+      }
+
+      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('input[type=text]')) {
+          var val = $(this.element).val();
+          var split = val.split(this.separator);
+          start = end = null;
+          if (split.length == 2) {
+            start = moment(split[0], this.format);
+            end = moment(split[1], this.format);
+          } else if (this.singleDatePicker) {
+            start = moment(val, this.format);
+            end = moment(val, this.format);
+          }
+          if (start !== null && end !== null) {
+            this.startDate = start;
+            this.endDate = end;
+          }
+        }
+      }
+
+      if (typeof options.ranges === 'object') {
+        for (range in options.ranges) {
+
+          start = moment(options.ranges[range][0]);
+          end = moment(options.ranges[range][1]);
+
+          // If we have a min/max date set, bound this range
+          // to it, but only if it would otherwise fall
+          // outside of the min/max.
+          if (this.minDate && start.isBefore(this.minDate))
+            start = moment(this.minDate);
+
+          if (this.maxDate && end.isAfter(this.maxDate))
+            end = moment(this.maxDate);
+
+          // If the end of the range is before the minimum (if min is set) OR
+          // the start of the range is after the max (also if set) don't display this
+          // range option.
+          if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) {
+            continue;
+          }
+
+          this.ranges[range] = [start, end];
+        }
+
+        var list = '<ul>';
+        for (range in this.ranges) {
+          list += '<li>' + range + '</li>';
+        }
+        list += '<li>' + this.locale.customRangeLabel + '</li>';
+        list += '</ul>';
+        this.container.find('.ranges ul').remove();
+        this.container.find('.ranges').prepend(list);
+      }
+
+      if (typeof callback === 'function') {
+        this.cb = callback;
+      }
+
+      if (!this.timePicker) {
+        this.startDate = this.startDate.startOf('day');
+        this.endDate = this.endDate.endOf('day');
+      }
+
+      if (this.singleDatePicker) {
+        this.opens = 'right';
+        this.container.find('.calendar.right').show();
+        this.container.find('.calendar.left').hide();
+        this.container.find('.ranges').hide();
+        if (!this.container.find('.calendar.right').hasClass('single'))
+          this.container.find('.calendar.right').addClass('single');
+      } else {
+        this.container.find('.calendar.right').removeClass('single');
+        this.container.find('.ranges').show();
+      }
+
+      this.oldStartDate = this.startDate.clone();
+      this.oldEndDate = this.endDate.clone();
+      this.oldChosenLabel = this.chosenLabel;
+
+      this.leftCalendar = {
+        month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute(), this.startDate.second()]),
+        calendar: []
+      };
+
+      this.rightCalendar = {
+        month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute(), this.endDate.second()]),
+        calendar: []
+      };
+
+      if (this.opens == 'right') {
+        //swap calendar positions
+        var left = this.container.find('.calendar.left');
+        var right = this.container.find('.calendar.right');
+        left.removeClass('left').addClass('right');
+        right.removeClass('right').addClass('left');
+      }
+
+      if (typeof options.ranges === 'undefined' && !this.singleDatePicker) {
+        this.container.addClass('show-calendar');
+      }
+
+      this.container.addClass('opens' + this.opens);
+
+      this.updateView();
+      this.updateCalendars();
+    },
+
+    setStartDate: function (startDate) {
+      if (typeof startDate === 'string')
+        this.startDate = moment(startDate, this.format);
+
+      if (typeof startDate === 'object')
+        this.startDate = moment(startDate);
+
+      if (!this.timePicker)
+        this.startDate = this.startDate.startOf('day');
+
+      this.oldStartDate = this.startDate.clone();
+
+      this.updateView();
+      this.updateCalendars();
+    },
+
+    setEndDate: function (endDate) {
+      if (typeof endDate === 'string')
+        this.endDate = moment(endDate, this.format);
+
+      if (typeof endDate === 'object')
+        this.endDate = moment(endDate);
+
+      if (!this.timePicker)
+        this.endDate = this.endDate.endOf('day');
+
+      this.oldEndDate = this.endDate.clone();
+
+      this.updateView();
+      this.updateCalendars();
+    },
+
+    updateView: function () {
+      this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year());
+      this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year());
+      this.updateFormInputs();
+    },
+
+    updateFormInputs: function () {
+      this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.format));
+      this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.format));
+      this.container.find('input[name=daterangepicker_interval]').val(this.interval);
+      if (this.container.find("select[name='daterangepicker_interval_select'] option[value='"+this.interval+"']").length > 0){
+        this.container.find('select[name=daterangepicker_interval_select]').val(this.interval);
+      }
+      else {
+        this.container.find('select[name=daterangepicker_interval_select]').val("");
+      }
+
+
+      if (this.startDate.isSame(this.endDate) || this.startDate.isBefore(this.endDate)) {
+        this.container.find('button.applyBtn').removeAttr('disabled');
+      } else {
+        this.container.find('button.applyBtn').attr('disabled', 'disabled');
+      }
+    },
+
+    updateFromControl: function () {
+      if (!this.element.is('input')) return;
+      if (!this.element.val().length) return;
+
+      var dateString = this.element.val().split(this.separator),
+          start = null,
+          end = null;
+
+      if (dateString.length === 2) {
+        start = moment(dateString[0], this.format);
+        end = moment(dateString[1], this.format);
+      }
+
+      if (this.singleDatePicker || start === null || end === null) {
+        start = moment(this.element.val(), this.format);
+        end = start;
+      }
+
+      if (end.isBefore(start)) return;
+
+      this.oldStartDate = this.startDate.clone();
+      this.oldEndDate = this.endDate.clone();
+
+      this.startDate = start;
+      this.endDate = end;
+
+      if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
+        this.notify();
+
+      this.updateCalendars();
+    },
+
+    notify: function () {
+      this.updateView();
+      this.cb(this.startDate, this.endDate, this.interval, this.chosenLabel);
+    },
+
+    move: function () {
+      var parentOffset = { top: 0, left: 0 };
+      if (!this.parentEl.is('body')) {
+        parentOffset = {
+          top: this.parentEl.offset().top - this.parentEl.scrollTop(),
+          left: this.parentEl.offset().left - this.parentEl.scrollLeft()
+        };
+      }
+
+      if (this.opens == 'left') {
+        this.container.css({
+          top: this.element.offset().top + this.element.outerHeight() - parentOffset.top,
+          right: $(window).width() - this.element.offset().left - this.element.outerWidth() - parentOffset.left,
+          left: 'auto'
+        });
+        if (this.container.offset().left < 0) {
+          this.container.css({
+            right: 'auto',
+            left: 9
+          });
+        }
+      } else {
+        this.container.css({
+          top: this.element.offset().top + this.element.outerHeight() - parentOffset.top,
+          left: this.element.offset().left - parentOffset.left,
+          right: 'auto'
+        });
+        if (this.container.offset().left + this.container.outerWidth() > $(window).width()) {
+          this.container.css({
+            left: 'auto',
+            right: 0
+          });
+        }
+      }
+    },
+
+    toggle: function (e) {
+      if (this.element.hasClass('actives')) {
+        this.hide();
+      } else {
+        this.show();
+      }
+    },
+
+    show: function (e) {
+      this.element.addClass('actives');
+      this.container.show();
+      this.move();
+
+      // 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 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);
+
+      this.element.trigger('show.daterangepicker', this);
+    },
+
+    outsideClick: function (e) {
+      var target = $(e.target);
+      // if the page is clicked anywhere except within the daterangerpicker/button
+      // itself then call this.hide()
+      if (
+          target.closest(this.element).length ||
+              target.closest(this.container).length ||
+              target.closest('.calendar-date').length
+          ) return;
+      this.hide();
+    },
+
+    hide: function (e) {
+      $(document)
+          .off('mousedown.daterangepicker', this._outsideClickProxy)
+          .off('click.daterangepicker', this._outsideClickProxy)
+          .off('focusin.daterangepicker', this._outsideClickProxy);
+
+      this.element.removeClass('active');
+      this.container.hide();
+
+      if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
+        this.notify();
+
+      this.oldStartDate = this.startDate.clone();
+      this.oldEndDate = this.endDate.clone();
+
+      this.element.trigger('hide.daterangepicker', this);
+    },
+
+    enterRange: function (e) {
+      // mouse pointer has entered a range label
+      var label = e.target.innerHTML;
+      if (label == this.locale.customRangeLabel) {
+        this.updateView();
+      } else {
+        var dates = this.ranges[label];
+        this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.format));
+        this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.format));
+      }
+    },
+
+    showCalendars: function () {
+      this.container.addClass('show-calendar');
+      this.move();
+    },
+
+    hideCalendars: function () {
+      //this.container.removeClass('show-calendar');
+    },
+
+    updateInputText: function () {
+      if (this.element.is('input') && !this.singleDatePicker) {
+        this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format));
+      } else if (this.element.is('input')) {
+        this.element.val(this.startDate.format(this.format));
+      }
+    },
+
+    updateIntervalFromSelect: function () {
+      this.interval = this.container.find('select[name=daterangepicker_interval_select]').val();
+      this.container.find('input[name=daterangepicker_interval]').val(this.interval);
+    },
+
+    updateIntervalFromInput: function () {
+      this.interval = this.container.find('input[name=daterangepicker_interval]').val();
+      this.container.find('select[name=daterangepicker_interval_select]').val("");
+    },
+
+    clickRange: function (e) {
+      var label = e.target.innerHTML;
+      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');
+        }
+
+        this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute()).second(this.startDate.second());
+        this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute()).second(this.endDate.second());
+        this.updateCalendars();
+
+        this.updateInputText();
+
+        this.hideCalendars();
+        this.hide();
+        this.element.trigger('apply.daterangepicker', this);
+      }
+    },
+
+    clickPrev: function (e) {
+      var cal = $(e.target).parents('.calendar');
+      if (cal.hasClass('left')) {
+        this.leftCalendar.month.subtract('month', 1);
+      } else {
+        this.rightCalendar.month.subtract('month', 1);
+      }
+      this.updateCalendars();
+    },
+
+    clickNext: function (e) {
+      var cal = $(e.target).parents('.calendar');
+      if (cal.hasClass('left')) {
+        this.leftCalendar.month.add('month', 1);
+      } else {
+        this.rightCalendar.month.add('month', 1);
+      }
+      this.updateCalendars();
+    },
+
+    enterDate: function (e) {
+
+      var title = $(e.target).attr('data-title');
+      var row = title.substr(1, 1);
+      var col = title.substr(3, 1);
+      var cal = $(e.target).parents('.calendar');
+
+      if (cal.hasClass('left')) {
+        this.container.find('input[name=daterangepicker_start]').val(this.leftCalendar.calendar[row][col].format(this.format));
+      } else {
+        this.container.find('input[name=daterangepicker_end]').val(this.rightCalendar.calendar[row][col].format(this.format));
+      }
+
+    },
+
+    clickDate: function (e) {
+      var title = $(e.target).attr('data-title');
+      var row = title.substr(1, 1);
+      var col = title.substr(3, 1);
+      var cal = $(e.target).parents('.calendar');
+
+      var startDate, endDate;
+      if (cal.hasClass('left')) {
+        startDate = this.leftCalendar.calendar[row][col];
+        endDate = this.endDate;
+        if (typeof this.dateLimit === 'object') {
+          var maxDate = moment(startDate).add(this.dateLimit).startOf('day');
+          if (endDate.isAfter(maxDate)) {
+            endDate = maxDate;
+          }
+        }
+      } else {
+        startDate = this.startDate;
+        endDate = this.rightCalendar.calendar[row][col];
+        if (typeof this.dateLimit === 'object') {
+          var minDate = moment(endDate).subtract(this.dateLimit).startOf('day');
+          if (startDate.isBefore(minDate)) {
+            startDate = minDate;
+          }
+        }
+      }
+
+      if (this.singleDatePicker && cal.hasClass('left')) {
+        endDate = startDate.clone();
+      } else if (this.singleDatePicker && cal.hasClass('right')) {
+        startDate = endDate.clone();
+      }
+
+      cal.find('td').removeClass('active');
+
+      if (startDate.isSame(endDate) || startDate.isBefore(endDate)) {
+        $(e.target).addClass('active');
+        this.startDate = startDate;
+        this.endDate = endDate;
+        this.chosenLabel = this.locale.customRangeLabel;
+      } else if (startDate.isAfter(endDate)) {
+        $(e.target).addClass('active');
+        var difference = this.endDate.diff(this.startDate);
+        this.startDate = startDate;
+        this.endDate = moment(startDate).add('ms', difference);
+        this.chosenLabel = this.locale.customRangeLabel;
+      }
+
+      this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year());
+      this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year());
+      this.updateCalendars();
+
+      if (!this.timePicker)
+        endDate.endOf('day');
+
+      if (this.singleDatePicker)
+        this.clickApply();
+    },
+
+    clickApply: function (e) {
+      this.updateInputText();
+      this.hide();
+      this.notify();
+      this.element.trigger('apply.daterangepicker', this);
+    },
+
+    clickCancel: function (e) {
+      this.startDate = this.oldStartDate;
+      this.endDate = this.oldEndDate;
+      this.chosenLabel = this.oldChosenLabel;
+      this.updateView();
+      this.updateCalendars();
+      this.hide();
+      this.element.trigger('cancel.daterangepicker', this);
+    },
+
+    updateMonthYear: function (e) {
+      var isLeft = $(e.target).closest('.calendar').hasClass('left'),
+          leftOrRight = isLeft ? 'left' : 'right',
+          cal = this.container.find('.calendar.' + leftOrRight);
+
+      // Month must be Number for new moment versions
+      var month = parseInt(cal.find('.monthselect').val(), 10);
+      var year = cal.find('.yearselect').val();
+
+      this[leftOrRight + 'Calendar'].month.month(month).year(year);
+      this.updateCalendars();
+    },
+
+    updateTime: function (e) {
+
+      var cal = $(e.target).closest('.calendar'),
+          isLeft = cal.hasClass('left');
+
+      var hour = parseInt(cal.find('.hourselect').val(), 10);
+      var minute = parseInt(cal.find('.minuteselect').val(), 10);
+      var second = parseInt(cal.find('.secondselect').val(), 10);
+
+      if (this.timePicker12Hour) {
+        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.startDate = start;
+        this.leftCalendar.month.hour(hour).minute(minute).second(second);
+      } else {
+        var end = this.endDate.clone();
+        end.hour(hour);
+        end.minute(minute);
+        end.second(second);
+        this.endDate = end;
+        this.rightCalendar.month.hour(hour).minute(minute).second(second);
+      }
+
+      this.updateCalendars();
+      this.updateFormInputs();
+    },
+
+    updateCalendars: function () {
+      this.leftCalendar.calendar = this.buildCalendar(this.leftCalendar.month.month(), this.leftCalendar.month.year(), this.leftCalendar.month.hour(), this.leftCalendar.month.minute(), this.leftCalendar.month.second(), 'left');
+      this.rightCalendar.calendar = this.buildCalendar(this.rightCalendar.month.month(), this.rightCalendar.month.year(), this.rightCalendar.month.hour(), this.rightCalendar.month.minute(), this.rightCalendar.month.second(), 'right');
+      this.container.find('.calendar.left').empty().html(this.renderCalendar(this.leftCalendar.calendar, this.startDate, this.minDate, this.maxDate));
+      this.container.find('.calendar.right').empty().html(this.renderCalendar(this.rightCalendar.calendar, this.endDate, this.startDate, this.maxDate));
+
+      this.container.find('.ranges li').removeClass('active');
+      var customRange = true;
+      var i = 0;
+      for (var range in this.ranges) {
+        if (this.timePicker) {
+          if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) {
+            customRange = false;
+            this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')')
+                .addClass('active').html();
+          }
+        } else {
+          //ignore times when comparing dates if time picker is not enabled
+          if (this.startDate.format('YYYY-MM-DD HH:mm:ss') == this.ranges[range][0].format('YYYY-MM-DD HH:mm:ss') && this.endDate.format('YYYY-MM-DD HH:mm:ss') == this.ranges[range][1].format('YYYY-MM-DD HH:mm:ss')) {
+            customRange = false;
+            this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')')
+                .addClass('active').html();
+          }
+        }
+        i++;
+      }
+      if (customRange) {
+        this.chosenLabel = this.container.find('.ranges li:last')
+            .addClass('active').html();
+      }
+    },
+
+    buildCalendar: function (month, year, hour, minute, second, side) {
+      var firstDay = moment([year, month, 1]);
+      var lastMonth = moment(firstDay).subtract('month', 1).month();
+      var lastYear = moment(firstDay).subtract('month', 1).year();
+
+      var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();
+
+      var dayOfWeek = firstDay.day();
+
+      var i;
+
+      //initialize a 6 rows x 7 columns array for the calendar
+      var calendar = [];
+      for (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 (i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add('hour', 24)) {
+        if (i > 0 && col % 7 === 0) {
+          col = 0;
+          row++;
+        }
+        calendar[row][col] = curDate.clone().hour(hour);
+        curDate.hour(12);
+      }
+
+      return calendar;
+    },
+
+    renderDropdowns: function (selected, minDate, maxDate) {
+      var currentMonth = selected.month();
+      var monthHtml = '<select class="monthselect">';
+      var inMinYear = false;
+      var inMaxYear = false;
+
+      for (var m = 0; m < 12; m++) {
+        if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) {
+          monthHtml += "<option value='" + m + "'" +
+              (m === currentMonth ? " selected='selected'" : "") +
+              ">" + this.locale.monthNames[m] + "</option>";
+        }
+      }
+      monthHtml += "</select>";
+
+      var currentYear = selected.year();
+      var maxYear = (maxDate && maxDate.year()) || (currentYear + 5);
+      var minYear = (minDate && minDate.year()) || (currentYear - 50);
+      var yearHtml = '<select class="yearselect">';
+
+      for (var y = minYear; y <= maxYear; y++) {
+        yearHtml += '<option value="' + y + '"' +
+            (y === currentYear ? ' selected="selected"' : '') +
+            '>' + y + '</option>';
+      }
+
+      yearHtml += '</select>';
+
+      return monthHtml + yearHtml;
+    },
+
+    renderCalendar: function (calendar, selected, minDate, maxDate) {
+
+      var html = '<div class="calendar-date">';
+      html += '<table class="table-condensed">';
+      html += '<thead>';
+      html += '<tr>';
+
+      // add empty cell for week number
+      if (this.showWeekNumbers)
+        html += '<th></th>';
+
+      if (!minDate || minDate.isBefore(calendar[1][1])) {
+        html += '<th class="prev available"><i class="fa fa-arrow-left icon-arrow-left glyphicon glyphicon-arrow-left"></i></th>';
+      } else {
+        html += '<th></th>';
+      }
+
+      var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY");
+
+      if (this.showDropdowns) {
+        dateHtml = this.renderDropdowns(calendar[1][1], minDate, maxDate);
+      }
+
+      html += '<th colspan="5" class="month">' + dateHtml + '</th>';
+      if (!maxDate || maxDate.isAfter(calendar[1][1])) {
+        html += '<th class="next available"><i class="fa fa-arrow-right icon-arrow-right glyphicon glyphicon-arrow-right"></i></th>';
+      } else {
+        html += '<th></th>';
+      }
+
+      html += '</tr>';
+      html += '<tr>';
+
+      // add week number label
+      if (this.showWeekNumbers)
+        html += '<th class="week">' + this.locale.weekLabel + '</th>';
+
+      $.each(this.locale.daysOfWeek, function (index, dayOfWeek) {
+        html += '<th>' + dayOfWeek + '</th>';
+      });
+
+      html += '</tr>';
+      html += '</thead>';
+      html += '<tbody>';
+
+      for (var row = 0; row < 6; row++) {
+        html += '<tr>';
+
+        // add week number
+        if (this.showWeekNumbers)
+          html += '<td class="week">' + calendar[row][0].week() + '</td>';
+
+        for (var col = 0; col < 7; col++) {
+          var cname = 'available ';
+          cname += (calendar[row][col].month() == calendar[1][1].month()) ? '' : 'off';
+
+          if ((minDate && calendar[row][col].isBefore(minDate, 'day')) || (maxDate && calendar[row][col].isAfter(maxDate, 'day'))) {
+            cname = ' off disabled ';
+          } else if (calendar[row][col].format('YYYY-MM-DD') == selected.format('YYYY-MM-DD')) {
+            cname += ' active ';
+            if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) {
+              cname += ' start-date ';
+            }
+            if (calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) {
+              cname += ' end-date ';
+            }
+          } else if (calendar[row][col] >= this.startDate && calendar[row][col] <= this.endDate) {
+            cname += ' in-range ';
+            if (calendar[row][col].isSame(this.startDate)) {
+              cname += ' start-date ';
+            }
+            if (calendar[row][col].isSame(this.endDate)) {
+              cname += ' end-date ';
+            }
+          }
+
+          var title = 'r' + row + 'c' + col;
+          html += '<td class="' + cname.replace(/\s+/g, ' ').replace(/^\s?(.*?)\s?$/, '$1') + '" data-title="' + title + '">' + calendar[row][col].date() + '</td>';
+        }
+        html += '</tr>';
+      }
+
+      html += '</tbody>';
+      html += '</table>';
+      html += '</div>';
+
+      var i;
+      if (this.timePicker) {
+
+        html += '<div class="calendar-time">';
+        html += '<select class="hourselect">';
+        var start = 0;
+        var end = 23;
+        var selected_hour = selected.hour();
+        if (this.timePicker12Hour) {
+          start = 1;
+          end = 12;
+          if (selected_hour >= 12)
+            selected_hour -= 12;
+          if (selected_hour === 0)
+            selected_hour = 12;
+        }
+
+        for (i = start; i <= end; i++) {
+          if (i == selected_hour) {
+            html += '<option value="' + i + '" selected="selected">' + i + '</option>';
+          } else {
+            html += '<option value="' + i + '">' + i + '</option>';
+          }
+        }
+
+        html += '</select> : ';
+
+        html += '<select class="minuteselect">';
+
+        for (i = 0; i < 60; i += this.timePickerIncrement) {
+          var num = i;
+          if (num < 10)
+            num = '0' + num;
+          if (i == selected.minute()) {
+            html += '<option value="' + i + '" selected="selected">' + num + '</option>';
+          } else {
+            html += '<option value="' + i + '">' + num + '</option>';
+          }
+        }
+
+        html += '</select> : ';
+
+        html += '<select class="secondselect">';
+
+        for (i = 0; i < 60; i++) {
+          var num = i;
+          if (num < 10)
+            num = '0' + num;
+          if (i == selected.second()) {
+            html += '<option value="' + i + '" selected="selected">' + num + '</option>';
+          } else {
+            html += '<option value="' + i + '">' + num + '</option>';
+          }
+        }
+
+        html += '</select> ';
+
+        if (this.timePicker12Hour) {
+          html += '<select class="ampmselect">';
+          if (selected.hour() >= 12) {
+            html += '<option value="AM">AM</option><option value="PM" selected="selected">PM</option>';
+          } else {
+            html += '<option value="AM" selected="selected">AM</option><option value="PM">PM</option>';
+          }
+          html += '</select>';
+        }
+
+        html += '</div>';
+
+      }
+
+      return html;
+
+    },
+
+    remove: function () {
+
+      this.container.remove();
+      this.element.off('.daterangepicker');
+      this.element.removeData('daterangepicker');
+
+    }
+
+  };
+
+  $.fn.daterangepicker = function (options, cb) {
+    this.each(function () {
+      var el = $(this);
+      if (el.data('daterangepicker'))
+        el.data('daterangepicker').remove();
+      el.data('daterangepicker', new DateRangePicker(el, options, cb));
+    });
+    return this;
+  };
+
+}(window.jQuery, window.moment);

部分文件因文件數量過多而無法顯示