Index: date.css =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/date/date.css,v retrieving revision 1.20.4.18 diff -u -r1.20.4.18 date.css --- date.css 8 Jun 2009 11:50:42 -0000 1.20.4.18 +++ date.css 24 Nov 2010 20:49:40 -0000 @@ -24,7 +24,8 @@ .container-inline-date .form-item input, .container-inline-date .form-item select, -.container-inline-date .form-item option { +.container-inline-date .form-item option, +.container-inline-date .ui-datepicker-trigger { margin-right: 5px; /* LTR */ } Index: date_popup/date_popup.js =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/date/date_popup/date_popup.js,v retrieving revision 1.1.2.4 diff -u -r1.1.2.4 date_popup.js --- date_popup/date_popup.js 20 Nov 2010 12:03:36 -0000 1.1.2.4 +++ date_popup/date_popup.js 24 Nov 2010 20:49:40 -0000 @@ -4,31 +4,48 @@ * Attaches the calendar behavior to all required fields */ Drupal.behaviors.date_popup = function (context) { - for (var id in Drupal.settings.datePopup) { - $('#'+ id).bind('focus', Drupal.settings.datePopup[id], function(e) { - if (!$(this).hasClass('date-popup-init')) { - var datePopup = e.data; - // Explicitely filter the methods we accept. - switch (datePopup.func) { - case 'datepicker': - $(this) - .datepicker(datePopup.settings) - .addClass('date-popup-init') - $(this).click(function(){ - $(this).focus(); - }); - break; - - case 'timeEntry': - $(this) - .timeEntry(datePopup.settings) - .addClass('date-popup-init') - $(this).click(function(){ - $(this).focus(); - }); - break; + var datePopup = Drupal.settings.datePopup; + + $('input.date-popup-date:not(.date-popup-processed)', context).each(function() { + var inputid = $(this).addClass('date-popup-processed')[0].id; + if (datePopup[inputid]) { + var settings = datePopup[inputid].settings; + var func = datePopup[inputid].func; + + // Explicitely filter the methods we accept. + if (func == 'datepicker') { + // make minDate and maxDate JS Date objects when they are integers + if (typeof settings.minDate == 'number') { + settings.minDate = new Date(settings.minDate * 1000); + } + if (typeof settings.maxDate == 'number') { + settings.maxDate = new Date(settings.maxDate * 1000); + } + + if (settings.weekdayDisable.length > 0 || settings.dayDisable.length > 0) { + settings.beforeShowDay = function(date) { + var dayDisabled = jQuery.inArray(date.getTime() / 1000, settings.dayDisable) != -1; + var weekdayDisabled = jQuery.inArray(date.getDay(), settings.weekdayDisable) != -1; + + return [!(dayDisabled || weekdayDisabled), '', '']; + }; } + + $(this).datepicker(settings); + } + } + }); + + $('input.date-popup-time:not(.date-popup-processed)', context).each(function() { + var inputid = $(this).addClass('date-popup-processed')[0].id; + if (datePopup[inputid]) { + var settings = datePopup[inputid].settings; + var func = datePopup[inputid].func; + + // Explicitely filter the methods we accept. + if (func == 'timeEntry') { + $(this).timeEntry(settings); } - }); - } + } + }); }; Index: date_popup/date_popup.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/date/date_popup/date_popup.module,v retrieving revision 1.42.2.1.2.65 diff -u -r1.42.2.1.2.65 date_popup.module --- date_popup/date_popup.module 20 Nov 2010 11:33:30 -0000 1.42.2.1.2.65 +++ date_popup/date_popup.module 24 Nov 2010 20:49:40 -0000 @@ -116,31 +116,13 @@ static $js_added = FALSE; static $id_count = array(); - // Make sure popup date selector grid is in correct year. - if (!empty($settings['yearRange'])) { - $parts = explode(':', $settings['yearRange']); - // Set the default date to 0 or the lowest bound if the date ranges do not include the current year - // Necessary for the datepicker to render and select dates correctly - $defaultDate = ($parts[0] > 0 || 0 > $parts[1]) ? $parts[0] : 0; - - // The 1.7 version of datepicker renders the range of year options - // relative to the drawn year in the popup, and will re-render the options - // whenever the year changes. - if (strpos(jquery_ui_get_version(), '1.7') === 0 && ($parts[0] >= 0 || 0 >= $parts[1])) { - $range = max($parts) - min($parts); - $defaultDate = $parts[0]; - $settings['yearRange'] = '-' . $range . ':' . '+' . $range; - } - $settings += array('defaultDate' => (string) $defaultDate . 'y'); - } - if (!$js_added) { drupal_add_js(drupal_get_path('module', 'date_popup') .'/date_popup.js'); $js_added = TRUE; } // We use a static array to account for possible multiple form_builder() - // calls in the same request (form instance on 'Preview'). + // calls in the same request (for instance on 'Preview'). if (!isset($id_count[$id])) { $id_count[$id] = 0; } @@ -190,6 +172,27 @@ * The number of years to go back and forward in a year selector, * default is -3:+3 (3 back and 3 forward). * + * #date_date_min + * The minimum selectable date. Give a timestamp or string + * that is parseable by strtotime. + * + * #date_date_max + * The maximum selectable date. Give a timestamp or string + * that is parseable by strtotime. + * + * #date_weekday_disable + * Unselectable weekdays. Give an array of integers, where 0 is + * Sunday, 1 is Monday, etc. + * + * #date_day_disable + * Unselectable days. Give an array of timestamps or strings + * that are parseable by strtotime. + * + * #date_datepicker_attributes + * Additional ui.datepicker attributes can be supplied in this + * attribute. See http://docs.jquery.com/UI/Datepicker + * Example: + * array('changeFirstDay' => FALSE) */ function date_popup_elements() { return array( @@ -200,6 +203,11 @@ '#date_format' => variable_get('date_format_short', 'm/d/Y - H:i'), '#date_increment' => 1, '#date_year_range' => '-3:+3', + '#date_date_min' => NULL, + '#date_date_max' => NULL, + '#date_weekday_disable' => array(), + '#date_day_disable' => array(), + '#date_datepicker_attributes' => array(), '#process' => array('date_popup_process'), ), ); @@ -221,7 +229,7 @@ */ function date_popup_process($element, $edit, $form_state, $form) { date_popup_load(); - require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_elements.inc'); + module_load_include('inc', 'date_api', 'date_api_elements.inc'); $date = NULL; $granularity = date_format_order($element['#date_format']); @@ -261,12 +269,24 @@ $date_format = (date_limit_format($element['#date_format'], $date_granularity)); if (empty($date_granularity)) return array(); - // The datepicker can't handle zero or negative values like 0:+1 - // even though the Date API can handle them, so rework the value - // we pass to the datepicker to use defaults it can accept (such as +0:+1) - // date_range_string() adds the necessary +/- signs to the range string. + // Calculate an absolute year range $range = date_range_years($element['#date_year_range'], $date); - $year_range = date_range_string($range); + $year_range = $range[0] .':'. $range[1]; + $default_date = (floor(($range[0] + $range[1]) / 2) - date('Y')) .'y'; + + // Preprocess minDate and maxDate + $element['#date_date_min'] = date_popup_parse_date($element['#date_date_min']); + $element['#date_date_max'] = date_popup_parse_date($element['#date_date_max']); + + // Preprocess the disabled days + $disabledDays = array(); + foreach($element['#date_day_disable'] as $day) { + $day = date_popup_parse_date($day); + if ($day !== NULL) { + $disabledDays[] = $day; + } + } + $element['#date_day_disable'] = $disabledDays; $settings = array( 'prevText' => '«', @@ -282,26 +302,46 @@ 'dayNamesMin' => date_week_days_abbr(TRUE, TRUE, 2), 'monthNames' => array_values(date_month_names(TRUE)), 'monthNamesShort' => array_values(date_month_names_abbr(TRUE)), - //'buttonImage' => base_path() . drupal_get_path('module', 'date_api') ."/images/calendar.png", - //'buttonImageOnly' => TRUE, + 'buttonImage' => base_path() . drupal_get_path('module', 'date_api') ."/images/calendar.png", + 'buttonImageOnly' => TRUE, + 'showOn' => 'button', + 'mandatory' => isset($element['#required']) && $element['#required'], + 'showButtonPanel' => TRUE, 'autoPopUp' => 'focus', 'closeAtTop' => FALSE, 'speed' => 'immediate', 'dateFormat' => date_popup_format_to_popup($date_format, 'datepicker'), 'yearRange' => $year_range, + 'minDate' => $element['#date_date_min'], + 'maxDate' => $element['#date_date_max'], + 'hideIfNoPrevNext' => TRUE, // Custom setting, will be expanded in Drupal.behaviors.date_popup() 'fromTo' => isset($fromto), - ); - + 'weekdayDisable' => $element['#date_weekday_disable'], + 'dayDisable' => $disabledDays, + 'defaultDate' => $default_date, + ); + + // Additional attributes override defaults + foreach ($element['#date_datepicker_attributes'] as $key => $value) { + $settings[$key] = $value; + } + // Create a unique id for each set of custom settings. $id = date_popup_js_settings_id($element['#id'], 'datepicker', $settings); + $attributes = $element['#attributes']; + if (isset($attributes['class'])) { + $attributes['class'] .= ' date-popup-date'; + } else { + $attributes['class'] = 'date-popup-date'; + } $sub_element = array( '#type' => 'textfield', '#default_value' => (!empty($element['#value']['date']) || !empty($edit['date'])) && is_object($date) ? date_format_date($date, 'custom', $date_format) : '', - '#id' => $id, + '#id' => $id, '#size' => !empty($element['#size']) ? $element['#size'] : 20, '#maxlength' => !empty($element['#maxlength']) ? $element['#maxlength'] : 30, - '#attributes' => $element['#attributes'], + '#attributes' => $attributes, ); // Views exposed filters are treated as submitted even if not, // so force the #default value in that case. @@ -339,6 +379,7 @@ '#id' => $id, '#size' => 10, '#maxlength' => 10, + '#attributes' => array('class' => 'date-popup-time'), ); // Views exposed filters are treated as submitted even if not, // so force the #default value in that case. @@ -387,14 +428,35 @@ return; } - require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_elements.inc'); + module_load_include('inc', 'date_api', 'date_api_elements.inc'); date_popup_load(); $value = date_popup_input_value($element); // If the created date is valid, set it. if (!empty($value)) { - form_set_value($element, $value, $form_state); - return; + // check restrictions + $valuestamp = strtotime($value); + $message = ''; + if ($element['#date_date_min'] !== NULL && $valuestamp < $element['#date_date_min']) { + $message = t('Field %field is invalid.', array('%field' => $label)); + } + elseif ($element['#date_date_max'] !== NULL && $valuestamp > $element['#date_date_max']) { + $message = t('Field %field is invalid.', array('%field' => $label)); + } + elseif (in_array(date('w', $valuestamp), $element['#date_weekday_disable'])) { + $message = t('Field %field is invalid.', array('%field' => $label)); + } + elseif (in_array($valuestamp, $element['#date_day_disable'])) { + $message = t('Field %field is invalid.', array('%field' => $label)); + } + + if ($message != '') { + form_set_error($error_field .'][date', $message); + } + else { + form_set_value($element, $value, $form_state); + return; + } } else { // Set message on both date and time to get them highlighted properly. @@ -573,6 +635,31 @@ } /** + * Parses a date to the following rules: + * - An int is returned as-is + * - A string is converter to an int if it contains only numbers + * - Other strings are parsed with strtotime and the result + * is returned if it is valid + * - Otherwise: NULL is returned + */ +function date_popup_parse_date($input) { + if (is_int($input)) { + return $input; + } + if (is_string($input) && preg_match('#^\d+$#', $input)) { + return intval($input); + } + if (is_string($input)) { + $tmp = strtotime($input); + if ($tmp !== FALSE && $tmp !== -1) { + return $tmp; + } + } + + return NULL; +} + +/** * Format a date popup element. * * Use a class that will float date and time next to each other. Index: date_popup/themes/datepicker.css =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/date/date_popup/themes/Attic/datepicker.css,v retrieving revision 1.1.2.7 diff -u -r1.1.2.7 datepicker.css --- date_popup/themes/datepicker.css 28 Jul 2009 19:43:52 -0000 1.1.2.7 +++ date_popup/themes/datepicker.css 24 Nov 2010 20:49:40 -0000 @@ -1,37 +1,30 @@ -/* Smoothness Theme for jQuery UI Datepicker */ -#ui-datepicker-div table, -#ui-datepicker-div td, -#ui-datepicker-div th { - margin: 0; - padding: 0; -} -#ui-datepicker-div, -#ui-datepicker-div table, -.ui-datepicker-div, -.ui-datepicker-div table, -.ui-datepicker-inline, -.ui-datepicker-inline table { - font-size: 12px !important; +/* Drupal Custom */ +.ui-datepicker-div, .ui-datepicker-inline a, #ui-datepicker-div a { + text-decoration: none; +} + +.ui-datepicker-div, .ui-datepicker-inline tbody, #ui-datepicker-div tbody { + border: 0px; } + +/* Smoothness Theme for jQuery UI Datepicker */ .ui-datepicker-div, .ui-datepicker-inline, #ui-datepicker-div { /*resets*/margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; - background: #ffffff; - border: 2px solid #d3d3d3; - font-family: Verdana, Arial, sans-serif; + font-family: Verdana,Arial,sans-serif; + background: #ffffff url(images/ffffff_40x100_textures_01_flat_75.png) 0 0 repeat-x; font-size: 1.1em; - margin: 0; + border: 4px solid #aaaaaa; + width: 15.5em; padding: 2.5em .5em .5em .5em; position: relative; - width: 15.5em; } -#ui-datepicker-div { - background: #ffffff; - display: none; +.ui-datepicker-div, #ui-datepicker-div { z-index: 9999; /*must have*/ + display: none; } .ui-datepicker-inline { + float: left; display: block; - float: left; /* LTR */ } .ui-datepicker-control { display: none; @@ -40,98 +33,103 @@ display: none; } .ui-datepicker-next, .ui-datepicker-prev { - background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x; /* LTR */ - left: .5em; /* LTR */ position: absolute; + left: .5em; top: .5em; + background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x; } .ui-datepicker-next { left: 14.6em; } .ui-datepicker-next:hover, .ui-datepicker-prev:hover { - background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x; /* LTR */ + background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x; } .ui-datepicker-next a, .ui-datepicker-prev a { - background: url(images/888888_7x7_arrow_left.gif) 50% 50% no-repeat; /* LTR */ - border: 1px solid #d3d3d3; - cursor: pointer; - display: block; - font-size: 1em; - height: 1.4em; text-indent: -999999px; width: 1.3em; + height: 1.4em; + display: block; + font-size: 1em; + background: url(images/888888_7x7_arrow_left.gif) 50% 50% no-repeat; + border: 1px solid #d3d3d3; + cursor: pointer; } .ui-datepicker-next a { - background: url(images/888888_7x7_arrow_right.gif) 50% 50% no-repeat; /* LTR */ + background: url(images/888888_7x7_arrow_right.gif) 50% 50% no-repeat; } .ui-datepicker-prev a:hover { - background: url(images/454545_7x7_arrow_left.gif) 50% 50% no-repeat; /* LTR */ + background: url(images/454545_7x7_arrow_left.gif) 50% 50% no-repeat; } .ui-datepicker-next a:hover { - background: url(images/454545_7x7_arrow_right.gif) 50% 50% no-repeat; /* LTR */ + background: url(images/454545_7x7_arrow_right.gif) 50% 50% no-repeat; } .ui-datepicker-prev a:active { - background: url(images/222222_7x7_arrow_left.gif) 50% 50% no-repeat; /* LTR */ + background: url(images/454545_7x7_arrow_left.gif) 50% 50% no-repeat; } .ui-datepicker-next a:active { - background: url(images/222222_7x7_arrow_right.gif) 50% 50% no-repeat; /* LTR */ + background: url(images/454545_7x7_arrow_right.gif) 50% 50% no-repeat; } .ui-datepicker-header select { - background: #e6e6e6; border: 1px solid #d3d3d3; color: #555555; + background: #e6e6e6; font-size: 1em; line-height: 1.4em; - margin: 0 !important; - padding: 0 !important; position: absolute; top: .5em; + margin: 0 !important; +} +.ui-datepicker-header option:focus, .ui-datepicker-header option:hover { + background: #dadada; } .ui-datepicker-header select.ui-datepicker-new-month { - left: 2.2em; /* LTR */ width: 7em; + left: 2.2em; } .ui-datepicker-header select.ui-datepicker-new-year { - left: 9.4em; /* LTR */ width: 5em; + left: 9.4em; } table.ui-datepicker { - text-align: right; /* LTR */ width: 15.5em; + text-align: right; } table.ui-datepicker td a { - color: #555555; + padding: .1em .3em .1em 0; display: block; - padding: .1em .3em .1em 0; /* LTR */ - text-decoration: none; -} -table.ui-datepicker tbody { - border-top: none; -} -table.ui-datepicker tbody td a { - background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x; /* LTR */ - border: 1px solid #ffffff; + color: #555555; + background: #e6e6e6 url(images/e6e6e6_40x100_textures_02_glass_75.png) 0 50% repeat-x; cursor: pointer; + border: 1px solid #ffffff; } -table.ui-datepicker tbody td a:hover { - background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x; /* LTR */ +table.ui-datepicker td a:hover { border: 1px solid #999999; color: #212121; + background: #dadada url(images/dadada_40x100_textures_02_glass_75.png) 0 50% repeat-x; } -table.ui-datepicker tbody td a:active { - background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x; /* LTR */ - border: 1px solid #dddddd; - color: #222222; +table.ui-datepicker td a:active { + border: 1px solid #aaaaaa; + color: #212121; + background: #ffffff url(images/ffffff_40x100_textures_02_glass_65.png) 0 50% repeat-x; } table.ui-datepicker .ui-datepicker-title-row td { - /*border-bottom: 1px solid #d3d3d3;*/ - color: #222222; - font-size: .9em; padding: .3em 0; text-align: center; + font-size: .9em; + color: #222222; text-transform: uppercase; } - table.ui-datepicker .ui-datepicker-title-row td a { color: #222222; +} +.ui-datepicker-cover { + display: none; + display/**/: block; + position: absolute; + z-index: -1; + filter: mask(); + top: -4px; + left: -4px; + width: 193px; + height: 200px; } \ No newline at end of file