(function ($) { Drupal.behaviors.dateSelect = {}; Drupal.behaviors.dateSelect.attach = function (context, settings) { var $widget = $('.form-type-date-select').parents('fieldset').once('date'); var i; for (i = 0; i < $widget.length; i++) { new Drupal.date.EndDateHandler($widget[i]); } }; Drupal.date = Drupal.date || {}; /** * Constructor for the EndDateHandler object. * * The EndDateHandler is responsible for synchronizing a date select widget's * end date with its start date. This behavior lasts until the user * interacts with the end date widget. * * @param widget * The fieldset DOM element containing the from and to dates. */ Drupal.date.EndDateHandler = function (widget) { this.$widget = $(widget); this.$start = this.$widget.find('.form-type-date-select[class$=value]'); this.$end = this.$widget.find('.form-type-date-select[class$=value2]'); if (this.$end.length == 0) { return; } this.initializeSelects(); // Only act on date fields where the end date is completely blank or already // the same as the start date. Otherwise, we do not want to override whatever // the default value was. if (this.endDateIsBlank() || this.endDateIsSame()) { this.bindClickHandlers(); // Start out with identical start and end dates. this.syncEndDate(); } }; /** * Store all the select dropdowns in an array on the object, for later use. */ Drupal.date.EndDateHandler.prototype.initializeSelects = function () { var $starts = this.$start.find('select'); var $end, $start, endId, i, id; this.selects = {}; for (i = 0; i < $starts.length; i++) { $start = $($starts[i]); id = $start.attr('id'); endId = id.replace('-value-', '-value2-'); $end = $('#' + endId); this.selects[id] = { 'id': id, 'start': $start, 'end': $end }; } }; /** * Returns true if all dropdowns in the end date widget are blank. */ Drupal.date.EndDateHandler.prototype.endDateIsBlank = function () { var id; for (id in this.selects) { if (this.selects.hasOwnProperty(id)) { if (this.selects[id].end.val() != '') { return false; } } } return true; }; /** * Returns true if the end date widget has the same value as the start date. */ Drupal.date.EndDateHandler.prototype.endDateIsSame = function () { var id; for (id in this.selects) { if (this.selects.hasOwnProperty(id)) { if (this.selects[id].end.val() != this.selects[id].start.val()) { return false; } } } return true; }; /** * Add a click handler to each of the start date's select dropdowns. */ Drupal.date.EndDateHandler.prototype.bindClickHandlers = function () { var id; for (id in this.selects) { if (this.selects.hasOwnProperty(id)) { this.selects[id].start.bind('click.endDateHandler', this.startClickHandler.bind(this)); this.selects[id].end.bind('focus', this.endFocusHandler.bind(this)); } } }; /** * Click event handler for each of the start date's select dropdowns. */ Drupal.date.EndDateHandler.prototype.startClickHandler = function (event) { this.syncEndDate(); }; /** * Focus event handler for each of the end date's select dropdowns. */ Drupal.date.EndDateHandler.prototype.endFocusHandler = function (event) { var id; for (id in this.selects) { if (this.selects.hasOwnProperty(id)) { this.selects[id].start.unbind('click.endDateHandler'); } } $(event.target).unbind('focus', this.endFocusHandler); }; Drupal.date.EndDateHandler.prototype.syncEndDate = function () { var id; for (id in this.selects) { if (this.selects.hasOwnProperty(id)) { this.selects[id].end.val(this.selects[id].start.val()); } } }; }(jQuery)); /** * Function.prototype.bind polyfill for older browsers. * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind */ if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") // closest thing possible to the ECMAScript 5 internal IsCallable function throw new TypeError("Function.prototype.bind - what is trying to be fBound is not callable"); var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () {}, fBound = function () { return fToBind.apply(this instanceof fNOP ? this : oThis || window, aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; }; }