FINAL suepr merge step : added all modules to this super repos
This commit is contained in:
27
sites/all/modules/contrib/fields/date/date_api/date-rtl.css
Normal file
27
sites/all/modules/contrib/fields/date/date_api/date-rtl.css
Normal file
@@ -0,0 +1,27 @@
|
||||
.container-inline-date > .form-item {
|
||||
margin-left: 0.5em;
|
||||
margin-right: 0;
|
||||
}
|
||||
.container-inline-date .form-item .form-item {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.container-inline-date .form-item input,
|
||||
.container-inline-date .form-item select,
|
||||
.container-inline-date .form-item option {
|
||||
margin-left: 5px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.container-inline-date .date-spacer {
|
||||
margin-left: 0;
|
||||
margin-right: -5px;
|
||||
}
|
||||
|
||||
.form-type-date-select .form-type-select[class$=hour] {
|
||||
margin-right: .75em;
|
||||
}
|
||||
|
||||
#edit-field-settings-granularity .form-type-checkbox {
|
||||
margin-left: .6em;
|
||||
}
|
188
sites/all/modules/contrib/fields/date/date_api/date.css
Normal file
188
sites/all/modules/contrib/fields/date/date_api/date.css
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* @file
|
||||
* Main stylesheet for Date module.
|
||||
*/
|
||||
|
||||
/* Force start/end dates to float using inline-block, where it works, otherwise inline. */
|
||||
.container-inline-date {
|
||||
clear: both;
|
||||
}
|
||||
.container-inline-date .form-item {
|
||||
float: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container-inline-date > .form-item {
|
||||
display: inline-block;
|
||||
margin-right: 0.5em; /* LTR */
|
||||
margin-bottom: 10px;
|
||||
vertical-align: top;
|
||||
}
|
||||
.container-inline-date .form-item .form-item {
|
||||
float: left; /* LTR */
|
||||
}
|
||||
.container-inline-date .form-item,
|
||||
.container-inline-date .form-item input {
|
||||
width: auto;
|
||||
}
|
||||
.container-inline-date .description {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.container-inline-date .form-item input,
|
||||
.container-inline-date .form-item select,
|
||||
.container-inline-date .form-item option {
|
||||
margin-right: 5px; /* LTR */
|
||||
}
|
||||
|
||||
.container-inline-date .date-spacer {
|
||||
margin-left: -5px; /* LTR */
|
||||
}
|
||||
|
||||
.views-right-60 .container-inline-date div {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.container-inline-date .date-timezone .form-item {
|
||||
clear: both;
|
||||
float: none;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* The exposed Views form doesn't need some of these styles */
|
||||
.container-inline-date .date-padding {
|
||||
padding: 10px;
|
||||
float: left;
|
||||
}
|
||||
.views-exposed-form .container-inline-date .date-padding {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Fixes for date popup css so it will behave in Drupal */
|
||||
#calendar_div,
|
||||
#calendar_div td,
|
||||
#calendar_div th {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#calendar_div,
|
||||
.calendar_control,
|
||||
.calendar_links,
|
||||
.calendar_header,
|
||||
.calendar {
|
||||
border-collapse: separate;
|
||||
margin: 0;
|
||||
width: 185px;
|
||||
}
|
||||
|
||||
.calendar td {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* formatting for start/end dates in nodes and views */
|
||||
span.date-display-single {
|
||||
}
|
||||
span.date-display-start {
|
||||
}
|
||||
span.date-display-end {
|
||||
}
|
||||
|
||||
.date-prefix-inline {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.date-clear {
|
||||
clear: both;
|
||||
display: block;
|
||||
float: none;
|
||||
}
|
||||
|
||||
.date-no-float {
|
||||
clear: both;
|
||||
float: none;
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
.date-float {
|
||||
clear: none;
|
||||
float: left;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* Add space between date option checkboxes ('All day' & 'Collect End Date') */
|
||||
.date-float .form-type-checkbox{
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
/* Add space between the date and time portions of the date_select widget. */
|
||||
.form-type-date-select .form-type-select[class$=hour] {
|
||||
margin-left: .75em; /* LTR */
|
||||
}
|
||||
|
||||
.date-container .date-format-delete {
|
||||
float: left;
|
||||
margin-top: 1.8em;
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
.date-container .date-format-name {
|
||||
float: left;
|
||||
}
|
||||
.date-container .date-format-type {
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.date-container .select-container {
|
||||
clear: left;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* Calendar day css */
|
||||
div.date-calendar-day {
|
||||
background: #F3F3F3;
|
||||
border-top: 1px solid #EEE;
|
||||
border-left: 1px solid #EEE;
|
||||
border-right: 1px solid #BBB;
|
||||
border-bottom: 1px solid #BBB;
|
||||
color: #999;
|
||||
float: left;
|
||||
line-height: 1;
|
||||
margin: 6px 10px 0 0;
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
div.date-calendar-day span {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
div.date-calendar-day span.month {
|
||||
background-color: #B5BEBE;
|
||||
color: white;
|
||||
font-size: .9em;
|
||||
padding: 2px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
div.date-calendar-day span.day {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
div.date-calendar-day span.year {
|
||||
font-size: .9em;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
/* Admin styling */
|
||||
.form-item.form-item-instance-widget-settings-input-format-custom,
|
||||
.form-item.form-item-field-settings-enddate-required {
|
||||
margin-left: 1.3em;
|
||||
}
|
||||
|
||||
#edit-field-settings-granularity .form-type-checkbox {
|
||||
margin-right: .6em; /* LTR */
|
||||
}
|
||||
|
||||
.date-year-range-select {
|
||||
margin-right: 1em;
|
||||
}
|
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Administrative page callbacks for the date_api module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create replacement values for deprecated timezone names.
|
||||
*/
|
||||
function _date_timezone_replacement($old) {
|
||||
$replace = array(
|
||||
'Brazil/Acre' => 'America/Rio_Branco',
|
||||
'Brazil/DeNoronha' => 'America/Noronha',
|
||||
'Brazil/East' => 'America/Recife',
|
||||
'Brazil/West' => 'America/Manaus',
|
||||
'Canada/Atlantic' => 'America/Halifax',
|
||||
'Canada/Central' => 'America/Winnipeg',
|
||||
'Canada/East-Saskatchewan' => 'America/Regina',
|
||||
'Canada/Eastern' => 'America/Toronto',
|
||||
'Canada/Mountain' => 'America/Edmonton',
|
||||
'Canada/Newfoundland' => 'America/St_Johns',
|
||||
'Canada/Pacific' => 'America/Vancouver',
|
||||
'Canada/Saskatchewan' => 'America/Regina',
|
||||
'Canada/Yukon' => 'America/Whitehorse',
|
||||
'CET' => 'Europe/Berlin',
|
||||
'Chile/Continental' => 'America/Santiago',
|
||||
'Chile/EasterIsland' => 'Pacific/Easter',
|
||||
'CST6CDT' => 'America/Chicago',
|
||||
'Cuba' => 'America/Havana',
|
||||
'EET' => 'Europe/Bucharest',
|
||||
'Egypt' => 'Africa/Cairo',
|
||||
'Eire' => 'Europe/Belfast',
|
||||
'EST' => 'America/New_York',
|
||||
'EST5EDT' => 'America/New_York',
|
||||
'GB' => 'Europe/London',
|
||||
'GB-Eire' => 'Europe/Belfast',
|
||||
'Etc/GMT' => 'UTC',
|
||||
'Etc/GMT+0' => 'UTC',
|
||||
'Etc/GMT+1' => 'UTC',
|
||||
'Etc/GMT+10' => 'UTC',
|
||||
'Etc/GMT+11' => 'UTC',
|
||||
'Etc/GMT+12' => 'UTC',
|
||||
'Etc/GMT+2' => 'UTC',
|
||||
'Etc/GMT+3' => 'UTC',
|
||||
'Etc/GMT+4' => 'UTC',
|
||||
'Etc/GMT+5' => 'UTC',
|
||||
'Etc/GMT+6' => 'UTC',
|
||||
'Etc/GMT+7' => 'UTC',
|
||||
'Etc/GMT+8' => 'UTC',
|
||||
'Etc/GMT+9' => 'UTC',
|
||||
'Etc/GMT-0' => 'UTC',
|
||||
'Etc/GMT-1' => 'UTC',
|
||||
'Etc/GMT-10' => 'UTC',
|
||||
'Etc/GMT-11' => 'UTC',
|
||||
'Etc/GMT-12' => 'UTC',
|
||||
'Etc/GMT-13' => 'UTC',
|
||||
'Etc/GMT-14' => 'UTC',
|
||||
'Etc/GMT-2' => 'UTC',
|
||||
'Etc/GMT-3' => 'UTC',
|
||||
'Etc/GMT-4' => 'UTC',
|
||||
'Etc/GMT-5' => 'UTC',
|
||||
'Etc/GMT-6' => 'UTC',
|
||||
'Etc/GMT-7' => 'UTC',
|
||||
'Etc/GMT-8' => 'UTC',
|
||||
'Etc/GMT-9' => 'UTC',
|
||||
'Etc/GMT0' => 'UTC',
|
||||
'Etc/Greenwich' => 'UTC',
|
||||
'Etc/UCT' => 'UTC',
|
||||
'Etc/Universal' => 'UTC',
|
||||
'Etc/UTC' => 'UTC',
|
||||
'Etc/Zulu' => 'UTC',
|
||||
'Factory' => 'UTC',
|
||||
'GMT' => 'UTC',
|
||||
'GMT+0' => 'UTC',
|
||||
'GMT-0' => 'UTC',
|
||||
'GMT0' => 'UTC',
|
||||
'Hongkong' => 'Asia/Hong_Kong',
|
||||
'HST' => 'Pacific/Honolulu',
|
||||
'Iceland' => 'Atlantic/Reykjavik',
|
||||
'Iran' => 'Asia/Tehran',
|
||||
'Israel' => 'Asia/Tel_Aviv',
|
||||
'Jamaica' => 'America/Jamaica',
|
||||
'Japan' => 'Asia/Tokyo',
|
||||
'Kwajalein' => 'Pacific/Kwajalein',
|
||||
'Libya' => 'Africa/Tunis',
|
||||
'MET' => 'Europe/Budapest',
|
||||
'Mexico/BajaNorte' => 'America/Tijuana',
|
||||
'Mexico/BajaSur' => 'America/Mazatlan',
|
||||
'Mexico/General' => 'America/Mexico_City',
|
||||
'MST' => 'America/Boise',
|
||||
'MST7MDT' => 'America/Boise',
|
||||
'Navajo' => 'America/Phoenix',
|
||||
'NZ' => 'Pacific/Auckland',
|
||||
'NZ-CHAT' => 'Pacific/Chatham',
|
||||
'Poland' => 'Europe/Warsaw',
|
||||
'Portugal' => 'Europe/Lisbon',
|
||||
'PRC' => 'Asia/Chongqing',
|
||||
'PST8PDT' => 'America/Los_Angeles',
|
||||
'ROC' => 'Asia/Taipei',
|
||||
'ROK' => 'Asia/Seoul',
|
||||
'Singapore' => 'Asia/Singapore',
|
||||
'Turkey' => 'Europe/Istanbul',
|
||||
'US/Alaska' => 'America/Anchorage',
|
||||
'US/Aleutian' => 'America/Adak',
|
||||
'US/Arizona' => 'America/Phoenix',
|
||||
'US/Central' => 'America/Chicago',
|
||||
'US/East-Indiana' => 'America/Indianapolis',
|
||||
'US/Eastern' => 'America/New_York',
|
||||
'US/Hawaii' => 'Pacific/Honolulu',
|
||||
'US/Indiana-Starke' => 'America/Indiana/Knox',
|
||||
'US/Michigan' => 'America/Detroit',
|
||||
'US/Mountain' => 'America/Boise',
|
||||
'US/Pacific' => 'America/Los_Angeles',
|
||||
'US/Pacific-New' => 'America/Los_Angeles',
|
||||
'US/Samoa' => 'Pacific/Samoa',
|
||||
'W-SU' => 'Europe/Moscow',
|
||||
'WET' => 'Europe/Paris',
|
||||
);
|
||||
if (array_key_exists($old, $replace)) {
|
||||
return $replace[$old];
|
||||
}
|
||||
else {
|
||||
return $old;
|
||||
}
|
||||
}
|
17
sites/all/modules/contrib/fields/date/date_api/date_api.info
Normal file
17
sites/all/modules/contrib/fields/date/date_api/date_api.info
Normal file
@@ -0,0 +1,17 @@
|
||||
name = Date API
|
||||
description = A Date API that can be used by other modules.
|
||||
package = Date/Time
|
||||
core = 7.x
|
||||
php = 5.2
|
||||
|
||||
stylesheets[all][] = date.css
|
||||
|
||||
files[] = date_api.module
|
||||
files[] = date_api_sql.inc
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-08-13
|
||||
version = "7.x-2.6"
|
||||
core = "7.x"
|
||||
project = "date"
|
||||
datestamp = "1344850024"
|
||||
|
252
sites/all/modules/contrib/fields/date/date_api/date_api.install
Normal file
252
sites/all/modules/contrib/fields/date/date_api/date_api.install
Normal file
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the date_api module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper function for setting Date variables.
|
||||
*/
|
||||
function date_api_set_variables() {
|
||||
// Set absolute minimum and maximum year for dates on this site.
|
||||
// There is actually no maximum and minimum year in PHP 5, but a date with
|
||||
// a year less than 0 would result in negative ISO and DATETIME dates,
|
||||
// like -1250-01-01T00:00:00, which probably won't make sense or work
|
||||
// correctly anywhere.
|
||||
// The odd construct of using variable_get() instead of variable_set()
|
||||
// is so we don't accidentally write over an existing value. If
|
||||
// no value is set, variable_get() will set it.
|
||||
variable_get('date_max_year', 4000);
|
||||
variable_get('date_min_year', 1);
|
||||
variable_get('date_php_min_year', 1901);
|
||||
|
||||
// Set an API version in a way that other modules can test for compatibility.
|
||||
variable_set('date_api_version', '7.2');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function date_api_requirements($phase) {
|
||||
$requirements = array();
|
||||
|
||||
if ($phase == 'runtime') {
|
||||
$t = get_t();
|
||||
module_load_include('module', 'date_api');
|
||||
$messages = date_api_status();
|
||||
$error_messages = !empty($messages['errors']) ? $messages['errors'] : array();
|
||||
$success_messages = !empty($messages['success']) ? $messages['success'] : array();
|
||||
|
||||
if (!empty($error_messages)) {
|
||||
$requirements['date'] = array(
|
||||
'title' => $t('Date API'),
|
||||
'value' => $t('Missing system date settings'),
|
||||
'description' => implode(' ', array_merge($error_messages, $success_messages)),
|
||||
'severity' => REQUIREMENT_ERROR,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$requirements['date'] = array(
|
||||
'title' => $t('Date API'),
|
||||
'value' => $t('System date settings'),
|
||||
'description' => implode(' ', $success_messages),
|
||||
);
|
||||
}
|
||||
}
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function date_api_install() {
|
||||
// Only set the message if Drupal itself is already installed.
|
||||
if (variable_get('install_task') == 'done') {
|
||||
// Ensure translations don't break at install time.
|
||||
$t = get_t();
|
||||
|
||||
// date_api_set_variables can install date_timezone. The
|
||||
// date_timezone_install() function does a module_enable('date_api'). This
|
||||
// means that date_api_enable() can be called before date_api_install()
|
||||
// finishes! So the date_api schema needs to be installed before this line!
|
||||
date_api_set_variables();
|
||||
|
||||
$message = $t('The Date API requires that you set up the <a href="@regional_settings">site timezone and first day of week settings</a> and the <a href="@regional_date_time">date format settings</a> to function correctly.', array('@regional_settings' => url('admin/config/regional/settings'), '@regional_date_time' => url('admin/config/regional/date-time')));
|
||||
drupal_set_message(filter_xss_admin($message), 'warning');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_enable().
|
||||
*/
|
||||
function date_api_enable() {
|
||||
date_api_set_variables();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function date_api_uninstall() {
|
||||
cache_clear_all('date_timezone_identifiers_list', 'cache');
|
||||
$variables = array(
|
||||
'date_api_version',
|
||||
'date_min_year',
|
||||
'date_max_year',
|
||||
'date_php_min_year',
|
||||
'date_db_tz_support',
|
||||
'date_api_use_iso8601',
|
||||
);
|
||||
foreach ($variables as $variable) {
|
||||
variable_del($variable);
|
||||
}
|
||||
|
||||
if (db_table_exists('views_display')) {
|
||||
$displays = array(
|
||||
'date_nav',
|
||||
);
|
||||
db_query("DELETE FROM {views_display} WHERE display_plugin IN ('" . implode("','", $displays) . "')");
|
||||
db_query("DELETE FROM {cache_views}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_update_last_removed().
|
||||
*/
|
||||
function date_api_update_last_removed() {
|
||||
return 6005;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move old date format data to new date format tables, and delete the old
|
||||
* tables. Insert only values that don't already exist in the new tables, in
|
||||
* case new version of those custom values have already been created.
|
||||
*/
|
||||
function date_api_update_7000() {
|
||||
// Move format data from the old 'date_format_types' table to the new
|
||||
// 'date_format_type' table.
|
||||
if (db_table_exists('date_format_types')) {
|
||||
// Find all the custom entries in the D6 table.
|
||||
$result = db_select('date_format_types', 'old')
|
||||
->fields('old', array('type', 'title', 'locked'))
|
||||
->condition('locked', 0)
|
||||
->execute()
|
||||
->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Iterate over all the old values.
|
||||
foreach ($result as $row) {
|
||||
// See if this value already exists in the new table
|
||||
// (it might have been added manually before this update got run).
|
||||
$count = db_select('date_format_type', 'new')
|
||||
->condition('type', $row['type'])
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
|
||||
// If the value is missing, insert it.
|
||||
// Do nothing if it already exists, assume the value in the
|
||||
// new table trumps the old values.
|
||||
if (empty($count)) {
|
||||
db_insert('date_format_type')
|
||||
->fields(array(
|
||||
'type' => $row['type'],
|
||||
'title' => $row['title'],
|
||||
'locked' => $row['locked'],
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
// Drop the old table.
|
||||
db_drop_table('date_format_types');
|
||||
|
||||
}
|
||||
|
||||
// Move format data from the old 'date_formats' table (which was renamed to
|
||||
// 'd6_date_formats') to the new 'date_formats' table.
|
||||
if (db_table_exists('d6_date_formats')) {
|
||||
// Find all the custom entries in the D6 table.
|
||||
$result = db_select('d6_date_formats', 'old')
|
||||
->fields('old', array('format', 'type', 'locked'))
|
||||
->condition('type', 'custom')
|
||||
->execute()
|
||||
->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Iterate over all the old values.
|
||||
foreach ($result as $row) {
|
||||
// See if this value already exists in the new table (it might have been
|
||||
// added manually before this update got run).
|
||||
$count = db_select('date_formats', 'new')
|
||||
->condition('format', $row['format'])
|
||||
->condition('type', $row['type'])
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
|
||||
// If the value is missing, insert it. Do nothing if it already exists,
|
||||
// assume the value in the new table trumps the old values.
|
||||
if (empty($count)) {
|
||||
db_insert('date_formats')
|
||||
->fields(array(
|
||||
'format' => $row['format'],
|
||||
'type' => $row['type'],
|
||||
'locked' => $row['locked'],
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
// Drop the old table.
|
||||
db_drop_table('d6_date_formats');
|
||||
}
|
||||
|
||||
// Move format data from the old 'date_format_locale' table (which was renamed
|
||||
// to 'd6_date_format_locale') to the new 'date_format_locale' table.
|
||||
if (db_table_exists('d6_date_format_locale')) {
|
||||
// Find all the custom entries in the D6 table.
|
||||
$result = db_select('d6_date_format_locale', 'old')
|
||||
->fields('old', array('format', 'type', 'language'))
|
||||
->condition('type', 'custom')
|
||||
->execute()
|
||||
->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Iterate over all the old values.
|
||||
foreach ($result as $row) {
|
||||
// See if this value already exists in the new table (it might have been
|
||||
// added manually before this update got run).
|
||||
$count = db_select('date_format_locale', 'new')
|
||||
->condition('format', $row['format'])
|
||||
->condition('type', $row['type'])
|
||||
->condition('language', $row['language'])
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
|
||||
// If the value is missing, insert it.
|
||||
// Do nothing if it already exists, assume the value in the
|
||||
// new table trumps the old values.
|
||||
if (empty($count)) {
|
||||
db_insert('date_format_locale')
|
||||
->fields(array(
|
||||
'format' => $row['format'],
|
||||
'type' => $row['type'],
|
||||
'language' => $row['language'],
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
// Drop the old table.
|
||||
db_drop_table('d6_date_format_locale');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Drop D6 timezone_name field on {users} after upgrading to D7.
|
||||
*/
|
||||
function date_api_update_7001() {
|
||||
if (db_field_exists('users', 'timezone_name')) {
|
||||
db_drop_field('users', 'timezone_name');
|
||||
}
|
||||
}
|
2707
sites/all/modules/contrib/fields/date/date_api/date_api.module
Normal file
2707
sites/all/modules/contrib/fields/date/date_api/date_api.module
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,752 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Date API elements themes and validation.
|
||||
* This file is only included during the edit process to reduce memory usage.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_element_info().
|
||||
*
|
||||
* Parameters for date form elements, designed to have sane defaults so any
|
||||
* or all can be omitted.
|
||||
*
|
||||
* Fill the element #default_value with a date in datetime format,
|
||||
* (YYYY-MM-DD HH:MM:SS), adjusted to the proper local timezone.
|
||||
*
|
||||
* NOTE - Converting a date stored in the database from UTC to the local zone
|
||||
* and converting it back to UTC before storing it is not handled by this
|
||||
* element and must be done in pre-form and post-form processing!!
|
||||
*
|
||||
* The date_select element will create a collection of form elements, with a
|
||||
* separate select or textfield for each date part. The whole collection will
|
||||
* get reformatted back to a date value of the requested type during validation.
|
||||
*
|
||||
* The date_text element will create a textfield that can contain a whole
|
||||
* date or any part of a date as text. The user input value will be re-formatted
|
||||
* back into a date value of the requested type during validation.
|
||||
*
|
||||
* The date_timezone element will create a drop-down selector to pick a
|
||||
* timezone name.
|
||||
*
|
||||
* The date_year_range element will create two textfields (for users with
|
||||
* JavaScript enabled they will appear as drop-down selectors with an option
|
||||
* for custom text entry) to pick a range of years that will be passed to form
|
||||
* submit handlers as a single string (e.g., -3:+3).
|
||||
*
|
||||
* #date_timezone
|
||||
* The local timezone to be used to create this date.
|
||||
*
|
||||
* #date_format
|
||||
* A format string that describes the format and order of date parts to
|
||||
* display in the edit form for this element. This makes it possible
|
||||
* to show date parts in a custom order, or to leave some of them out.
|
||||
* Be sure to add 'A' or 'a' to get an am/pm selector. Defaults to the
|
||||
* short site default format.
|
||||
*
|
||||
* #date_label_position
|
||||
* Handling option for date part labels, like 'Year', 'Month', and 'Day',
|
||||
* can be 'above' the date part, 'within' it, or 'none', default is 'above' .
|
||||
* The 'within' option shows the label as the first option in a select list
|
||||
* or the default value for an empty textfield, taking up less screen space.
|
||||
*
|
||||
* #date_increment
|
||||
* Increment minutes and seconds by this amount, default is 1.
|
||||
*
|
||||
* #date_year_range
|
||||
* The number of years to go back and forward in a year selector,
|
||||
* default is -3:+3 (3 back and 3 forward).
|
||||
*
|
||||
* #date_text_parts
|
||||
* Array of date parts that should use textfields instead of selects
|
||||
* i.e. array('year') will format the year as a textfield and other
|
||||
* date parts as drop-down selects.
|
||||
*/
|
||||
function _date_api_element_info() {
|
||||
$date_base = array(
|
||||
'#input' => TRUE, '#tree' => TRUE,
|
||||
'#date_timezone' => date_default_timezone(),
|
||||
'#date_flexible' => 0,
|
||||
'#date_format' => variable_get('date_format_short', 'm/d/Y - H:i'),
|
||||
'#date_text_parts' => array(),
|
||||
'#date_increment' => 1,
|
||||
'#date_year_range' => '-3:+3',
|
||||
'#date_label_position' => 'above',
|
||||
);
|
||||
if (module_exists('ctools')) {
|
||||
$date_base['#pre_render'] = array('ctools_dependent_pre_render');
|
||||
}
|
||||
$type['date_select'] = array_merge($date_base, array(
|
||||
'#process' => array('date_select_element_process'),
|
||||
'#theme_wrappers' => array('date_select'),
|
||||
'#value_callback' => 'date_select_element_value_callback',
|
||||
));
|
||||
$type['date_text'] = array_merge($date_base, array(
|
||||
'#process' => array('date_text_element_process'),
|
||||
'#theme_wrappers' => array('date_text'),
|
||||
'#value_callback' => 'date_text_element_value_callback',
|
||||
));
|
||||
$type['date_timezone'] = array(
|
||||
'#input' => TRUE, '#tree' => TRUE,
|
||||
'#process' => array('date_timezone_element_process'),
|
||||
'#theme_wrappers' => array('date_text'),
|
||||
'#value_callback' => 'date_timezone_element_value_callback',
|
||||
);
|
||||
$type['date_year_range'] = array(
|
||||
'#input' => TRUE,
|
||||
'#process' => array('date_year_range_element_process'),
|
||||
'#value_callback' => 'date_year_range_element_value_callback',
|
||||
'#element_validate' => array('date_year_range_validate'),
|
||||
);
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a date object from a datetime string value.
|
||||
*/
|
||||
function date_default_date($element) {
|
||||
$granularity = date_format_order($element['#date_format']);
|
||||
$default_value = $element['#default_value'];
|
||||
$format = DATE_FORMAT_DATETIME;
|
||||
|
||||
// The text and popup widgets might return less than a full datetime string.
|
||||
if (strlen($element['#default_value']) < 19) {
|
||||
switch (strlen($element['#default_value'])) {
|
||||
case 16:
|
||||
$format = 'Y-m-d H:i';
|
||||
break;
|
||||
case 13:
|
||||
$format = 'Y-m-d H';
|
||||
break;
|
||||
case 10:
|
||||
$format = 'Y-m-d';
|
||||
break;
|
||||
case 7:
|
||||
$format = 'Y-m';
|
||||
break;
|
||||
case 4:
|
||||
$format = 'Y';
|
||||
break;
|
||||
}
|
||||
}
|
||||
$date = new DateObject($default_value, $element['#date_timezone'], $format);
|
||||
if (is_object($date)) {
|
||||
$date->limitGranularity($granularity);
|
||||
if ($date->validGranularity($granularity, $element['#date_flexible'])) {
|
||||
date_increment_round($date, $element['#date_increment']);
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process callback which creates a date_year_range form element.
|
||||
*/
|
||||
function date_year_range_element_process($element, &$form_state, $form) {
|
||||
// Year range is stored in the -3:+3 format, but collected as two separate
|
||||
// textfields.
|
||||
$element['years_back'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Starting year'),
|
||||
'#default_value' => $element['#value']['years_back'],
|
||||
'#size' => 10,
|
||||
'#maxsize' => 10,
|
||||
'#attributes' => array('class' => array('select-list-with-custom-option', 'back')),
|
||||
'#description' => t('Enter a relative value (-9, +9) or an absolute year such as 2015.'),
|
||||
);
|
||||
$element['years_forward'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Ending year'),
|
||||
'#default_value' => $element['#value']['years_forward'],
|
||||
'#size' => 10,
|
||||
'#maxsize' => 10,
|
||||
'#attributes' => array('class' => array('select-list-with-custom-option', 'forward')),
|
||||
'#description' => t('Enter a relative value (-9, +9) or an absolute year such as 2015.'),
|
||||
);
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
$element['#attached']['js'][] = drupal_get_path('module', 'date_api') . '/date_year_range.js';
|
||||
|
||||
$context = array(
|
||||
'form' => $form,
|
||||
);
|
||||
drupal_alter('date_year_range_process', $element, $form_state, $context);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Element value callback for the date_year_range form element.
|
||||
*/
|
||||
function date_year_range_element_value_callback($element, $input = FALSE, &$form_state = array()) {
|
||||
// Convert the element's default value from a string to an array (to match
|
||||
// what we will get from the two textfields when the form is submitted).
|
||||
if ($input === FALSE) {
|
||||
list($years_back, $years_forward) = explode(':', $element['#default_value']);
|
||||
return array(
|
||||
'years_back' => $years_back,
|
||||
'years_forward' => $years_forward,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Element validation function for the date_year_range form element.
|
||||
*/
|
||||
function date_year_range_validate(&$element, &$form_state) {
|
||||
// Recombine the two submitted form values into the -3:+3 format we will
|
||||
// validate and save.
|
||||
$year_range_submitted = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
|
||||
$year_range = $year_range_submitted['years_back'] . ':' . $year_range_submitted['years_forward'];
|
||||
drupal_array_set_nested_value($form_state['values'], $element['#parents'], $year_range);
|
||||
if (!date_range_valid($year_range)) {
|
||||
form_error($element['years_back'], t('Starting year must be in the format -9, or an absolute year such as 1980.'));
|
||||
form_error($element['years_forward'], t('Ending year must be in the format +9, or an absolute year such as 2030.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Element value callback for date_timezone element.
|
||||
*/
|
||||
function date_timezone_element_value_callback($element, $input = FALSE, &$form_state = array()) {
|
||||
$return = '';
|
||||
if ($input !== FALSE) {
|
||||
$return = $input;
|
||||
}
|
||||
elseif (!empty($element['#default_value'])) {
|
||||
$return = array('timezone' => $element['#default_value']);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a timezone form element.
|
||||
*
|
||||
* @param array $element
|
||||
* The timezone form element.
|
||||
*
|
||||
* @return array
|
||||
* the timezone form element
|
||||
*/
|
||||
function date_timezone_element_process($element, &$form_state, $form) {
|
||||
if (date_hidden_element($element)) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
$label = theme('date_part_label_timezone', array('part_type' => 'select', 'element' => $element));
|
||||
$element['timezone'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $element['#date_label_position'] == 'above' ? $label : '',
|
||||
'#options' => date_timezone_names($element['#required']),
|
||||
'#value' => $element['#value'],
|
||||
'#weight' => $element['#weight'],
|
||||
'#required' => $element['#required'],
|
||||
'#theme' => 'date_select_element',
|
||||
'#theme_wrappers' => array('form_element'),
|
||||
);
|
||||
if (isset($element['#element_validate'])) {
|
||||
array_push($element['#element_validate'], 'date_timezone_validate');
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'] = array('date_timezone_validate');
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'form' => $form,
|
||||
);
|
||||
drupal_alter('date_timezone_process', $element, $form_state, $context);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation for timezone input
|
||||
*
|
||||
* Move the timezone value from the nested field back to the original field.
|
||||
*/
|
||||
function date_timezone_validate($element, &$form_state) {
|
||||
if (date_hidden_element($element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
form_set_value($element, $element['#value']['timezone'], $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Element value callback for date_text element.
|
||||
*/
|
||||
function date_text_element_value_callback($element, $input = FALSE, &$form_state = array()) {
|
||||
$return = array('date' => '');
|
||||
$date = NULL;
|
||||
|
||||
// Normal input from submitting the form element.
|
||||
// Check is_array() to skip the string input values created by Views pagers.
|
||||
// Those string values, if present, should be interpreted as empty input.
|
||||
if ($input != FALSE && is_array($input)) {
|
||||
$return = $input;
|
||||
$date = date_text_input_date($element, $input);
|
||||
}
|
||||
// No input? Try the default value.
|
||||
elseif (!empty($element['#default_value'])) {
|
||||
$date = date_default_date($element);
|
||||
}
|
||||
if (date_is_date($date)) {
|
||||
$return['date'] = date_format_date($date, 'custom', $element['#date_format']);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Text date input form.
|
||||
*
|
||||
* Display all or part of a date in a single textfield.
|
||||
*
|
||||
* The exact parts displayed in the field are those in #date_granularity.
|
||||
* The display of each part comes from #date_format.
|
||||
*
|
||||
*/
|
||||
function date_text_element_process($element, &$form_state, $form) {
|
||||
if (date_hidden_element($element)) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
$element['#theme_wrappers'] = array('date_text');
|
||||
$element['date']['#value'] = $element['#value']['date'];
|
||||
$element['date']['#type'] = 'textfield';
|
||||
$element['date']['#weight'] = !empty($element['date']['#weight']) ? $element['date']['#weight'] : $element['#weight'];
|
||||
$element['date']['#attributes'] = array('class' => isset($element['#attributes']['class']) ? $element['#attributes']['class'] += array('date-date') : array('date-date'));
|
||||
$now = date_example_date();
|
||||
$element['date']['#description'] = ' ' . t('Format: @date', array('@date' => date_format_date(date_example_date(), 'custom', $element['#date_format'])));
|
||||
$element['date']['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
|
||||
|
||||
// Keep the system from creating an error message for the sub-element.
|
||||
// We'll set our own message on the parent element.
|
||||
// $element['date']['#required'] = $element['#required'];
|
||||
$element['date']['#theme'] = 'date_textfield_element';
|
||||
if (isset($element['#element_validate'])) {
|
||||
array_push($element['#element_validate'], 'date_text_validate');
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'] = array('date_text_validate');
|
||||
}
|
||||
if (!empty($element['#force_value'])) {
|
||||
$element['date']['#value'] = $element['date']['#default_value'];
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'form' => $form,
|
||||
);
|
||||
drupal_alter('date_text_process', $element, $form_state, $context);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation for text input.
|
||||
*
|
||||
* When used as a Views widget, the validation step always gets triggered,
|
||||
* even with no form submission. Before form submission $element['#value']
|
||||
* contains a string, after submission it contains an array.
|
||||
*
|
||||
*/
|
||||
function date_text_validate($element, &$form_state) {
|
||||
if (date_hidden_element($element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_string($element['#value'])) {
|
||||
return;
|
||||
}
|
||||
$input_exists = NULL;
|
||||
$input = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
|
||||
|
||||
drupal_alter('date_text_pre_validate', $element, $form_state, $input);
|
||||
|
||||
$label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
|
||||
$date = date_text_input_date($element, $input);
|
||||
|
||||
// If the field has errors, display them.
|
||||
// If something was input but there is no date, the date is invalid.
|
||||
// If the field is empty and required, set error message and return.
|
||||
$error_field = implode('][', $element['#parents']);
|
||||
if (empty($date) || !empty($date->errors)) {
|
||||
if (is_object($date) && !empty($date->errors)) {
|
||||
$message = t('The value input for field %field is invalid:', array('%field' => $label));
|
||||
$message .= '<br />' . implode('<br />', $date->errors);
|
||||
form_set_error($error_field, $message);
|
||||
return;
|
||||
}
|
||||
if (!empty($element['#required'])) {
|
||||
$message = t('A valid date is required for %title.', array('%title' => $label));
|
||||
form_set_error($error_field, $message);
|
||||
return;
|
||||
}
|
||||
// Fall through, some other error.
|
||||
if (!empty($input['date'])) {
|
||||
form_error($element, t('%title is invalid.', array('%title' => $label)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
$value = !empty($date) ? $date->format(DATE_FORMAT_DATETIME) : NULL;
|
||||
form_set_value($element, $value, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for creating a date object out of user input.
|
||||
*/
|
||||
function date_text_input_date($element, $input) {
|
||||
if (empty($input) || !is_array($input) || !array_key_exists('date', $input) || empty($input['date'])) {
|
||||
return NULL;
|
||||
}
|
||||
$granularity = date_format_order($element['#date_format']);
|
||||
$date = new DateObject($input['date'], $element['#date_timezone'], $element['#date_format']);
|
||||
if (is_object($date)) {
|
||||
$date->limitGranularity($granularity);
|
||||
if ($date->validGranularity($granularity, $element['#date_flexible'])) {
|
||||
date_increment_round($date, $element['#date_increment']);
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Element value callback for date_select element.
|
||||
*/
|
||||
function date_select_element_value_callback($element, $input = FALSE, &$form_state = array()) {
|
||||
$return = array('year' => '', 'month' => '', 'day' => '', 'hour' => '', 'minute' => '', 'second' => '');
|
||||
$date = NULL;
|
||||
if ($input !== FALSE) {
|
||||
$return = $input;
|
||||
$date = date_select_input_date($element, $input);
|
||||
}
|
||||
elseif (!empty($element['#default_value'])) {
|
||||
$date = date_default_date($element);
|
||||
}
|
||||
$granularity = date_format_order($element['#date_format']);
|
||||
$formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
|
||||
foreach ($granularity as $field) {
|
||||
if ($field != 'timezone') {
|
||||
$return[$field] = date_is_date($date) ? $date->format($formats[$field]) : '';
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flexible date/time drop-down selector.
|
||||
*
|
||||
* Splits date into a collection of date and time sub-elements, one
|
||||
* for each date part. Each sub-element can be either a textfield or a
|
||||
* select, based on the value of ['#date_settings']['text_fields'].
|
||||
*
|
||||
* The exact parts displayed in the field are those in #date_granularity.
|
||||
* The display of each part comes from ['#date_settings']['format'].
|
||||
*
|
||||
*/
|
||||
function date_select_element_process($element, &$form_state, $form) {
|
||||
if (date_hidden_element($element)) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
$date = NULL;
|
||||
$granularity = date_format_order($element['#date_format']);
|
||||
|
||||
if (is_array($element['#default_value'])) {
|
||||
$date = date_select_input_date($element, $element['#default_value']);
|
||||
}
|
||||
elseif (!empty($element['#default_value'])) {
|
||||
$date = date_default_date($element);
|
||||
}
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
$element['#theme_wrappers'] = array('date_select');
|
||||
|
||||
$element += (array) date_parts_element($element, $date, $element['#date_format']);
|
||||
|
||||
// Store a hidden value for all date parts not in the current display.
|
||||
$granularity = date_format_order($element['#date_format']);
|
||||
$formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
|
||||
foreach (date_nongranularity($granularity) as $field) {
|
||||
if ($field != 'timezone') {
|
||||
$element[$field] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (isset($element['#element_validate'])) {
|
||||
array_push($element['#element_validate'], 'date_select_validate');
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'] = array('date_select_validate');
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'form' => $form,
|
||||
);
|
||||
drupal_alter('date_select_process', $element, $form_state, $context);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates form elements for one or more date parts.
|
||||
*
|
||||
* Get the order of date elements from the provided format.
|
||||
* If the format order omits any date parts in the granularity, alter the
|
||||
* granularity array to match the format, then flip the $order array
|
||||
* to get the position for each element. Then iterate through the
|
||||
* elements and create a sub-form for each part.
|
||||
*
|
||||
* @param array $element
|
||||
* The date element.
|
||||
* @param object $date
|
||||
* The date object.
|
||||
* @param string $format
|
||||
* A date format string.
|
||||
*
|
||||
* @return array
|
||||
* The form array for the submitted date parts.
|
||||
*/
|
||||
function date_parts_element($element, $date, $format) {
|
||||
$granularity = date_format_order($format);
|
||||
$sub_element = array('#granularity' => $granularity);
|
||||
$order = array_flip($granularity);
|
||||
|
||||
$hours_format = strpos(strtolower($element['#date_format']), 'a') ? 'g': 'G';
|
||||
$month_function = strpos($element['#date_format'], 'F') !== FALSE ? 'date_month_names' : 'date_month_names_abbr';
|
||||
$count = 0;
|
||||
$increment = min(intval($element['#date_increment']), 1);
|
||||
|
||||
// Allow empty value as option if date is not required or there is no date.
|
||||
$part_required = (bool) $element['#required'] && is_object($date);
|
||||
foreach ($granularity as $field) {
|
||||
$part_type = in_array($field, $element['#date_text_parts']) ? 'textfield' : 'select';
|
||||
$sub_element[$field] = array(
|
||||
'#weight' => $order[$field],
|
||||
'#required' => $part_required,
|
||||
'#attributes' => array('class' => isset($element['#attributes']['class']) ? $element['#attributes']['class'] += array('date-' . $field) : array('date-' . $field)),
|
||||
'#ajax' => !empty($element['#ajax']) ? $element['#ajax'] : FALSE,
|
||||
);
|
||||
switch ($field) {
|
||||
case 'year':
|
||||
$range = date_range_years($element['#date_year_range'], $date);
|
||||
$min_year = $range[0];
|
||||
$max_year = $range[1];
|
||||
|
||||
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('Y') : '';
|
||||
if ($part_type == 'select') {
|
||||
$sub_element[$field]['#options'] = drupal_map_assoc(date_years($min_year, $max_year, $part_required));
|
||||
}
|
||||
break;
|
||||
case 'month':
|
||||
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('n') : '';
|
||||
if ($part_type == 'select') {
|
||||
$sub_element[$field]['#options'] = $month_function($part_required);
|
||||
}
|
||||
break;
|
||||
case 'day':
|
||||
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('j') : '';
|
||||
if ($part_type == 'select') {
|
||||
$sub_element[$field]['#options'] = drupal_map_assoc(date_days($part_required));
|
||||
}
|
||||
break;
|
||||
case 'hour':
|
||||
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format($hours_format) : '';
|
||||
if ($part_type == 'select') {
|
||||
$sub_element[$field]['#options'] = drupal_map_assoc(date_hours($hours_format, $part_required));
|
||||
}
|
||||
$sub_element[$field]['#prefix'] = theme('date_part_hour_prefix', $element);
|
||||
break;
|
||||
case 'minute':
|
||||
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('i') : '';
|
||||
if ($part_type == 'select') {
|
||||
$sub_element[$field]['#options'] = drupal_map_assoc(date_minutes('i', $part_required, $element['#date_increment']));
|
||||
}
|
||||
$sub_element[$field]['#prefix'] = theme('date_part_minsec_prefix', $element);
|
||||
break;
|
||||
case 'second':
|
||||
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('s') : '';
|
||||
if ($part_type == 'select') {
|
||||
$sub_element[$field]['#options'] = drupal_map_assoc(date_seconds('s', $part_required, $element['#date_increment']));
|
||||
}
|
||||
$sub_element[$field]['#prefix'] = theme('date_part_minsec_prefix', $element);
|
||||
break;
|
||||
}
|
||||
|
||||
// Add handling for the date part label.
|
||||
$label = theme('date_part_label_' . $field, array('part_type' => $part_type, 'element' => $element));
|
||||
if (in_array($field, $element['#date_text_parts'])) {
|
||||
$sub_element[$field]['#type'] = 'textfield';
|
||||
$sub_element[$field]['#theme'] = 'date_textfield_element';
|
||||
$sub_element[$field]['#size'] = 7;
|
||||
if ($element['#date_label_position'] == 'within') {
|
||||
if (!empty($sub_element[$field]['#options']) && is_array($sub_element[$field]['#options'])) {
|
||||
$sub_element[$field]['#options'] = array(
|
||||
'-' . $label => '-' . $label) + $sub_element[$field]['#options'];
|
||||
}
|
||||
if (empty($sub_element[$field]['#default_value'])) {
|
||||
$sub_element[$field]['#default_value'] = '-' . $label;
|
||||
}
|
||||
}
|
||||
elseif ($element['#date_label_position'] != 'none') {
|
||||
$sub_element[$field]['#title'] = $label;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$sub_element[$field]['#type'] = 'select';
|
||||
$sub_element[$field]['#theme'] = 'date_select_element';
|
||||
if ($element['#date_label_position'] == 'within') {
|
||||
$sub_element[$field]['#options'] = array(
|
||||
'' => '-' . $label) + $sub_element[$field]['#options'];
|
||||
}
|
||||
elseif ($element['#date_label_position'] != 'none') {
|
||||
$sub_element[$field]['#title'] = $label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Views exposed filters are treated as submitted even if not,
|
||||
// so force the #default value in that case. Make sure we set
|
||||
// a default that is in the option list.
|
||||
if (!empty($element['#force_value'])) {
|
||||
$options = $sub_element[$field]['#options'];
|
||||
$default = !empty($sub_element[$field]['#default_value']) ? $sub_element[$field]['#default_value'] : array_shift($options);
|
||||
$sub_element[$field]['#value'] = $default;
|
||||
}
|
||||
|
||||
if (($hours_format == 'g' || $hours_format == 'h') && date_has_time($granularity)) {
|
||||
$sub_element['ampm'] = array(
|
||||
'#type' => 'select',
|
||||
'#theme' => 'date_select_element',
|
||||
'#default_value' => is_object($date) ? (date_format($date, 'G') >= 12 ? 'pm' : 'am') : '',
|
||||
'#options' => drupal_map_assoc(date_ampm($part_required)),
|
||||
'#required' => $part_required,
|
||||
'#weight' => 8,
|
||||
'#attributes' => array('class' => array('date-ampm')),
|
||||
);
|
||||
if ($element['#date_label_position'] == 'within') {
|
||||
$sub_element['ampm']['#options'] = array('' => '-' . theme('date_part_label_ampm', array('part_type' => 'ampm', 'eleement' => $element))) + $sub_element['ampm']['#options'];
|
||||
}
|
||||
elseif ($element['#date_label_position'] != 'none') {
|
||||
$sub_element['ampm']['#title'] = theme('date_part_label_ampm', array('part_type' => 'ampm', 'element' => $element));
|
||||
}
|
||||
}
|
||||
|
||||
return $sub_element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation function for date selector.
|
||||
*
|
||||
* When used as a Views widget, the validation step always gets triggered,
|
||||
* even with no form submission. Before form submission $element['#value']
|
||||
* contains a string, after submission it contains an array.
|
||||
*/
|
||||
function date_select_validate($element, &$form_state) {
|
||||
if (date_hidden_element($element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_string($element['#value'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$input_exists = NULL;
|
||||
$input = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
|
||||
|
||||
// Strip field labels out of the results.
|
||||
foreach ($element['#value'] as $field => $field_value) {
|
||||
if (substr($field_value, 0, 1) == '-') {
|
||||
$input[$field] = '';
|
||||
}
|
||||
}
|
||||
|
||||
drupal_alter('date_select_pre_validate', $element, $form_state, $input);
|
||||
|
||||
$label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
|
||||
if (isset($input['ampm'])) {
|
||||
if ($input['ampm'] == 'pm' && $input['hour'] < 12) {
|
||||
$input['hour'] += 12;
|
||||
}
|
||||
elseif ($input['ampm'] == 'am' && $input['hour'] == 12) {
|
||||
$input['hour'] -= 12;
|
||||
}
|
||||
}
|
||||
unset($input['ampm']);
|
||||
$date = date_select_input_date($element, $input);
|
||||
|
||||
// If the field has errors, display them.
|
||||
$error_field = implode('][', $element['#parents']);
|
||||
$entered = array_values(array_filter($input));
|
||||
if (empty($date) || !empty($date->errors)) {
|
||||
// The input created a date but it has errors.
|
||||
if (is_object($date) && !empty($date->errors)) {
|
||||
$message = t('The value input for field %field is invalid:', array('%field' => $label));
|
||||
$message .= '<br />' . implode('<br />', $date->errors);
|
||||
form_set_error($error_field, $message);
|
||||
return;
|
||||
}
|
||||
// Nothing was entered but the date is required.
|
||||
elseif (empty($entered) && $element['#required']) {
|
||||
$message = t('A valid date is required for %title.', array('%title' => $label));
|
||||
form_set_error($error_field, $message);
|
||||
return;
|
||||
}
|
||||
// Something was input but it wasn't enough to create a valid date.
|
||||
elseif (!empty($entered)) {
|
||||
$message = t('The value input for field %field is invalid.', array('%field' => $label));
|
||||
form_set_error($error_field, $message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
$value = !empty($date) ? $date->format(DATE_FORMAT_DATETIME) : NULL;
|
||||
form_set_value($element, $value, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for creating a date object out of user input.
|
||||
*/
|
||||
function date_select_input_date($element, $input) {
|
||||
|
||||
// Was anything entered? If not, we have no date.
|
||||
if (!is_array($input)) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
$entered = array_values(array_filter($input));
|
||||
if (empty($entered)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
$granularity = date_format_order($element['#date_format']);
|
||||
if (isset($input['ampm'])) {
|
||||
if ($input['ampm'] == 'pm' && $input['hour'] < 12) {
|
||||
$input['hour'] += 12;
|
||||
}
|
||||
elseif ($input['ampm'] == 'am' && $input['hour'] == 12) {
|
||||
$input['hour'] -= 12;
|
||||
}
|
||||
}
|
||||
unset($input['ampm']);
|
||||
|
||||
// Make the input match the granularity.
|
||||
foreach (date_nongranularity($granularity) as $part) {
|
||||
unset($input[$part]);
|
||||
}
|
||||
|
||||
$date = new DateObject($input, $element['#date_timezone']);
|
||||
if (is_object($date)) {
|
||||
$date->limitGranularity($granularity);
|
||||
if ($date->validGranularity($granularity, $element['#date_flexible'])) {
|
||||
date_increment_round($date, $element['#date_increment']);
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
return NULL;
|
||||
}
|
803
sites/all/modules/contrib/fields/date/date_api/date_api_ical.inc
Normal file
803
sites/all/modules/contrib/fields/date/date_api/date_api_ical.inc
Normal file
@@ -0,0 +1,803 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Parse iCal data.
|
||||
*
|
||||
* This file must be included when these functions are needed.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return an array of iCalendar information from an iCalendar file.
|
||||
*
|
||||
* No timezone adjustment is performed in the import since the timezone
|
||||
* conversion needed will vary depending on whether the value is being
|
||||
* imported into the database (when it needs to be converted to UTC), is being
|
||||
* viewed on a site that has user-configurable timezones (when it needs to be
|
||||
* converted to the user's timezone), if it needs to be converted to the
|
||||
* site timezone, or if it is a date without a timezone which should not have
|
||||
* any timezone conversion applied.
|
||||
*
|
||||
* Properties that have dates and times are converted to sub-arrays like:
|
||||
* 'datetime' => date in YYYY-MM-DD HH:MM format, not timezone adjusted
|
||||
* 'all_day' => whether this is an all-day event
|
||||
* 'tz' => the timezone of the date, could be blank for absolute
|
||||
* times that should get no timezone conversion.
|
||||
*
|
||||
* Exception dates can have muliple values and are returned as arrays
|
||||
* like the above for each exception date.
|
||||
*
|
||||
* Most other properties are returned as PROPERTY => VALUE.
|
||||
*
|
||||
* Each item in the VCALENDAR will return an array like:
|
||||
* [0] => Array (
|
||||
* [TYPE] => VEVENT
|
||||
* [UID] => 104
|
||||
* [SUMMARY] => An example event
|
||||
* [URL] => http://example.com/node/1
|
||||
* [DTSTART] => Array (
|
||||
* [datetime] => 1997-09-07 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* [DTEND] => Array (
|
||||
* [datetime] => 1997-09-07 11:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* [RRULE] => Array (
|
||||
* [FREQ] => Array (
|
||||
* [0] => MONTHLY
|
||||
* )
|
||||
* [BYDAY] => Array (
|
||||
* [0] => 1SU
|
||||
* [1] => -1SU
|
||||
* )
|
||||
* )
|
||||
* [EXDATE] => Array (
|
||||
* [0] = Array (
|
||||
* [datetime] => 1997-09-21 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* [1] = Array (
|
||||
* [datetime] => 1997-10-05 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* )
|
||||
* [RDATE] => Array (
|
||||
* [0] = Array (
|
||||
* [datetime] => 1997-09-21 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* [1] = Array (
|
||||
* [datetime] => 1997-10-05 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @todo
|
||||
* figure out how to handle this if subgroups are nested,
|
||||
* like a VALARM nested inside a VEVENT.
|
||||
*
|
||||
* @param string $filename
|
||||
* Location (local or remote) of a valid iCalendar file.
|
||||
*
|
||||
* @return array
|
||||
* An array with all the elements from the ical.
|
||||
*/
|
||||
function date_ical_import($filename) {
|
||||
// Fetch the iCal data. If file is a URL, use drupal_http_request. fopen
|
||||
// isn't always configured to allow network connections.
|
||||
if (substr($filename, 0, 4) == 'http') {
|
||||
// Fetch the ical data from the specified network location.
|
||||
$icaldatafetch = drupal_http_request($filename);
|
||||
// Check the return result.
|
||||
if ($icaldatafetch->error) {
|
||||
watchdog('date ical', 'HTTP Request Error importing %filename: @error', array('%filename' => $filename, '@error' => $icaldatafetch->error));
|
||||
return FALSE;
|
||||
}
|
||||
// Break the return result into one array entry per lines.
|
||||
$icaldatafolded = explode("\n", $icaldatafetch->data);
|
||||
}
|
||||
else {
|
||||
$icaldatafolded = @file($filename, FILE_IGNORE_NEW_LINES);
|
||||
if ($icaldatafolded === FALSE) {
|
||||
watchdog('date ical', 'Failed to open file: %filename', array('%filename' => $filename));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
// Verify this is iCal data.
|
||||
if (trim($icaldatafolded[0]) != 'BEGIN:VCALENDAR') {
|
||||
watchdog('date ical', 'Invalid calendar file: %filename', array('%filename' => $filename));
|
||||
return FALSE;
|
||||
}
|
||||
return date_ical_parse($icaldatafolded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of iCalendar information from an iCalendar file.
|
||||
*
|
||||
* As date_ical_import() but different param.
|
||||
*
|
||||
* @param array $icaldatafolded
|
||||
* An array of lines from an ical feed.
|
||||
*
|
||||
* @return array
|
||||
* An array with all the elements from the ical.
|
||||
*/
|
||||
function date_ical_parse($icaldatafolded = array()) {
|
||||
$items = array();
|
||||
|
||||
// Verify this is iCal data.
|
||||
if (trim($icaldatafolded[0]) != 'BEGIN:VCALENDAR') {
|
||||
watchdog('date ical', 'Invalid calendar file.');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// "Unfold" wrapped lines.
|
||||
$icaldata = array();
|
||||
foreach ($icaldatafolded as $line) {
|
||||
$out = array();
|
||||
// See if this looks like the beginning of a new property or value. If not,
|
||||
// it is a continuation of the previous line. The regex is to ensure that
|
||||
// wrapped QUOTED-PRINTABLE data is kept intact.
|
||||
if (!preg_match('/([A-Z]+)[:;](.*)/', $line, $out)) {
|
||||
// Trim up to 1 leading space from wrapped line per iCalendar standard.
|
||||
$line = array_pop($icaldata) . (ltrim(substr($line, 0, 1)) . substr($line, 1));
|
||||
}
|
||||
$icaldata[] = $line;
|
||||
}
|
||||
unset($icaldatafolded);
|
||||
|
||||
// Parse the iCal information.
|
||||
$parents = array();
|
||||
$subgroups = array();
|
||||
$vcal = '';
|
||||
foreach ($icaldata as $line) {
|
||||
$line = trim($line);
|
||||
$vcal .= $line . "\n";
|
||||
// Deal with begin/end tags separately.
|
||||
if (preg_match('/(BEGIN|END):V(\S+)/', $line, $matches)) {
|
||||
$closure = $matches[1];
|
||||
$type = 'V' . $matches[2];
|
||||
if ($closure == 'BEGIN') {
|
||||
array_push($parents, $type);
|
||||
array_push($subgroups, array());
|
||||
}
|
||||
elseif ($closure == 'END') {
|
||||
end($subgroups);
|
||||
$subgroup = &$subgroups[key($subgroups)];
|
||||
switch ($type) {
|
||||
case 'VCALENDAR':
|
||||
if (prev($subgroups) == FALSE) {
|
||||
$items[] = array_pop($subgroups);
|
||||
}
|
||||
else {
|
||||
$parent[array_pop($parents)][] = array_pop($subgroups);
|
||||
}
|
||||
break;
|
||||
// Add the timezones in with their index their TZID.
|
||||
case 'VTIMEZONE':
|
||||
$subgroup = end($subgroups);
|
||||
$id = $subgroup['TZID'];
|
||||
unset($subgroup['TZID']);
|
||||
|
||||
// Append this subgroup onto the one above it.
|
||||
prev($subgroups);
|
||||
$parent = &$subgroups[key($subgroups)];
|
||||
|
||||
$parent[$type][$id] = $subgroup;
|
||||
|
||||
array_pop($subgroups);
|
||||
array_pop($parents);
|
||||
break;
|
||||
// Do some fun stuff with durations and all_day events and then append
|
||||
// to parent.
|
||||
case 'VEVENT':
|
||||
case 'VALARM':
|
||||
case 'VTODO':
|
||||
case 'VJOURNAL':
|
||||
case 'VVENUE':
|
||||
case 'VFREEBUSY':
|
||||
default:
|
||||
// Can't be sure whether DTSTART is before or after DURATION, so
|
||||
// parse DURATION at the end.
|
||||
if (isset($subgroup['DURATION'])) {
|
||||
date_ical_parse_duration($subgroup, 'DURATION');
|
||||
}
|
||||
// Add a top-level indication for the 'All day' condition. Leave it
|
||||
// in the individual date components, too, so it is always available
|
||||
// even when you are working with only a portion of the VEVENT
|
||||
// array, like in Feed API parsers.
|
||||
$subgroup['all_day'] = FALSE;
|
||||
|
||||
// iCal spec states 'The "DTEND" property for a "VEVENT" calendar
|
||||
// component specifies the non-inclusive end of the event'. Adjust
|
||||
// multi-day events to remove the extra day because the Date code
|
||||
// assumes the end date is inclusive.
|
||||
if (!empty($subgroup['DTEND']) && (!empty($subgroup['DTEND']['all_day']))) {
|
||||
// Make the end date one day earlier.
|
||||
$date = new DateObject ($subgroup['DTEND']['datetime'] . ' 00:00:00', $subgroup['DTEND']['tz']);
|
||||
date_modify($date, '-1 day');
|
||||
$subgroup['DTEND']['datetime'] = date_format($date, 'Y-m-d');
|
||||
}
|
||||
// If a start datetime is defined AND there is no definition for
|
||||
// the end datetime THEN make the end datetime equal the start
|
||||
// datetime and if it is an all day event define the entire event
|
||||
// as a single all day event.
|
||||
if (!empty($subgroup['DTSTART']) &&
|
||||
(empty($subgroup['DTEND']) && empty($subgroup['RRULE']) && empty($subgroup['RRULE']['COUNT']))) {
|
||||
$subgroup['DTEND'] = $subgroup['DTSTART'];
|
||||
}
|
||||
// Add this element to the parent as an array under the component
|
||||
// name.
|
||||
if (!empty($subgroup['DTSTART']['all_day'])) {
|
||||
$subgroup['all_day'] = TRUE;
|
||||
}
|
||||
// Add this element to the parent as an array under the
|
||||
prev($subgroups);
|
||||
$parent = &$subgroups[key($subgroups)];
|
||||
|
||||
$parent[$type][] = $subgroup;
|
||||
|
||||
array_pop($subgroups);
|
||||
array_pop($parents);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Handle all other possibilities.
|
||||
else {
|
||||
// Grab current subgroup.
|
||||
end($subgroups);
|
||||
$subgroup = &$subgroups[key($subgroups)];
|
||||
|
||||
// Split up the line into nice pieces for PROPERTYNAME,
|
||||
// PROPERTYATTRIBUTES, and PROPERTYVALUE.
|
||||
preg_match('/([^;:]+)(?:;([^:]*))?:(.+)/', $line, $matches);
|
||||
$name = !empty($matches[1]) ? strtoupper(trim($matches[1])) : '';
|
||||
$field = !empty($matches[2]) ? $matches[2] : '';
|
||||
$data = !empty($matches[3]) ? $matches[3] : '';
|
||||
$parse_result = '';
|
||||
switch ($name) {
|
||||
// Keep blank lines out of the results.
|
||||
case '':
|
||||
break;
|
||||
|
||||
// Lots of properties have date values that must be parsed out.
|
||||
case 'CREATED':
|
||||
case 'LAST-MODIFIED':
|
||||
case 'DTSTART':
|
||||
case 'DTEND':
|
||||
case 'DTSTAMP':
|
||||
case 'FREEBUSY':
|
||||
case 'DUE':
|
||||
case 'COMPLETED':
|
||||
$parse_result = date_ical_parse_date($field, $data);
|
||||
break;
|
||||
|
||||
case 'EXDATE':
|
||||
case 'RDATE':
|
||||
$parse_result = date_ical_parse_exceptions($field, $data);
|
||||
break;
|
||||
|
||||
case 'TRIGGER':
|
||||
// A TRIGGER can either be a date or in the form -PT1H.
|
||||
if (!empty($field)) {
|
||||
$parse_result = date_ical_parse_date($field, $data);
|
||||
}
|
||||
else {
|
||||
$parse_result = array('DATA' => $data);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DURATION':
|
||||
// Can't be sure whether DTSTART is before or after DURATION in
|
||||
// the VEVENT, so store the data and parse it at the end.
|
||||
$parse_result = array('DATA' => $data);
|
||||
break;
|
||||
|
||||
case 'RRULE':
|
||||
case 'EXRULE':
|
||||
$parse_result = date_ical_parse_rrule($field, $data);
|
||||
break;
|
||||
|
||||
case 'STATUS':
|
||||
case 'SUMMARY':
|
||||
case 'DESCRIPTION':
|
||||
$parse_result = date_ical_parse_text($field, $data);
|
||||
break;
|
||||
|
||||
case 'LOCATION':
|
||||
$parse_result = date_ical_parse_location($field, $data);
|
||||
break;
|
||||
|
||||
// For all other properties, just store the property and the value.
|
||||
// This can be expanded on in the future if other properties should
|
||||
// be given special treatment.
|
||||
default:
|
||||
$parse_result = $data;
|
||||
break;
|
||||
}
|
||||
|
||||
// Store the result of our parsing.
|
||||
$subgroup[$name] = $parse_result;
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a ical date element.
|
||||
*
|
||||
* Possible formats to parse include:
|
||||
* PROPERTY:YYYYMMDD[T][HH][MM][SS][Z]
|
||||
* PROPERTY;VALUE=DATE:YYYYMMDD[T][HH][MM][SS][Z]
|
||||
* PROPERTY;VALUE=DATE-TIME:YYYYMMDD[T][HH][MM][SS][Z]
|
||||
* PROPERTY;TZID=XXXXXXXX;VALUE=DATE:YYYYMMDD[T][HH][MM][SS]
|
||||
* PROPERTY;TZID=XXXXXXXX:YYYYMMDD[T][HH][MM][SS]
|
||||
*
|
||||
* The property and the colon before the date are removed in the import
|
||||
* process above and we are left with $field and $data.
|
||||
*
|
||||
* @param string $field
|
||||
* The text before the colon and the date, i.e.
|
||||
* ';VALUE=DATE:', ';VALUE=DATE-TIME:', ';TZID='
|
||||
* @param string $data
|
||||
* The date itself, after the colon, in the format YYYYMMDD[T][HH][MM][SS][Z]
|
||||
* 'Z', if supplied, means the date is in UTC.
|
||||
*
|
||||
* @return array
|
||||
* $items array, consisting of:
|
||||
* 'datetime' => date in YYYY-MM-DD HH:MM format, not timezone adjusted
|
||||
* 'all_day' => whether this is an all-day event with no time
|
||||
* 'tz' => the timezone of the date, could be blank if the ical
|
||||
* has no timezone; the ical specs say no timezone
|
||||
* conversion should be done if no timezone info is
|
||||
* supplied
|
||||
* @todo
|
||||
* Another option for dates is the format PROPERTY;VALUE=PERIOD:XXXX. The
|
||||
* period may include a duration, or a date and a duration, or two dates, so
|
||||
* would have to be split into parts and run through date_ical_parse_date()
|
||||
* and date_ical_parse_duration(). This is not commonly used, so ignored for
|
||||
* now. It will take more work to figure how to support that.
|
||||
*/
|
||||
function date_ical_parse_date($field, $data) {
|
||||
|
||||
$items = array('datetime' => '', 'all_day' => '', 'tz' => '');
|
||||
if (empty($data)) {
|
||||
return $items;
|
||||
}
|
||||
// Make this a little more whitespace independent.
|
||||
$data = trim($data);
|
||||
|
||||
// Turn the properties into a nice indexed array of
|
||||
// array(PROPERTYNAME => PROPERTYVALUE);
|
||||
$field_parts = preg_split('/[;:]/', $field);
|
||||
$properties = array();
|
||||
foreach ($field_parts as $part) {
|
||||
if (strpos($part, '=') !== FALSE) {
|
||||
$tmp = explode('=', $part);
|
||||
$properties[$tmp[0]] = $tmp[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Make this a little more whitespace independent.
|
||||
$data = trim($data);
|
||||
|
||||
// Record if a time has been found.
|
||||
$has_time = FALSE;
|
||||
|
||||
// If a format is specified, parse it according to that format.
|
||||
if (isset($properties['VALUE'])) {
|
||||
switch ($properties['VALUE']) {
|
||||
case 'DATE':
|
||||
preg_match(DATE_REGEX_ICAL_DATE, $data, $regs);
|
||||
// Date.
|
||||
$datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
|
||||
break;
|
||||
case 'DATE-TIME':
|
||||
preg_match(DATE_REGEX_ICAL_DATETIME, $data, $regs);
|
||||
// Date.
|
||||
$datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
|
||||
// Time.
|
||||
$datetime .= ' ' . date_pad($regs[4]) . ':' . date_pad($regs[5]) . ':' . date_pad($regs[6]);
|
||||
$has_time = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If no format is specified, attempt a loose match.
|
||||
else {
|
||||
preg_match(DATE_REGEX_LOOSE, $data, $regs);
|
||||
if (!empty($regs) && count($regs) > 2) {
|
||||
// Date.
|
||||
$datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
|
||||
if (isset($regs[4])) {
|
||||
$has_time = TRUE;
|
||||
// Time.
|
||||
$datetime .= ' ' . (!empty($regs[5]) ? date_pad($regs[5]) : '00') .
|
||||
':' . (!empty($regs[6]) ? date_pad($regs[6]) : '00') .
|
||||
':' . (!empty($regs[7]) ? date_pad($regs[7]) : '00');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use timezone if explicitly declared.
|
||||
if (isset($properties['TZID'])) {
|
||||
$tz = $properties['TZID'];
|
||||
// Fix alternatives like US-Eastern which should be US/Eastern.
|
||||
$tz = str_replace('-', '/', $tz);
|
||||
// Unset invalid timezone names.
|
||||
module_load_include('inc', 'date_api', 'date_api.admin');
|
||||
$tz = _date_timezone_replacement($tz);
|
||||
if (!date_timezone_is_valid($tz)) {
|
||||
$tz = '';
|
||||
}
|
||||
}
|
||||
// If declared as UTC with terminating 'Z', use that timezone.
|
||||
elseif (strpos($data, 'Z') !== FALSE) {
|
||||
$tz = 'UTC';
|
||||
}
|
||||
// Otherwise this date is floating.
|
||||
else {
|
||||
$tz = '';
|
||||
}
|
||||
|
||||
$items['datetime'] = $datetime;
|
||||
$items['all_day'] = $has_time ? FALSE : TRUE;
|
||||
$items['tz'] = $tz;
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an ical repeat rule.
|
||||
*
|
||||
* @return array
|
||||
* Array in the form of PROPERTY => array(VALUES)
|
||||
* PROPERTIES include FREQ, INTERVAL, COUNT, BYDAY, BYMONTH, BYYEAR, UNTIL
|
||||
*/
|
||||
function date_ical_parse_rrule($field, $data) {
|
||||
$data = preg_replace("/RRULE.*:/", '', $data);
|
||||
$items = array('DATA' => $data);
|
||||
$rrule = explode(';', $data);
|
||||
foreach ($rrule as $key => $value) {
|
||||
$param = explode('=', $value);
|
||||
// Must be some kind of invalid data.
|
||||
if (count($param) != 2) {
|
||||
continue;
|
||||
}
|
||||
if ($param[0] == 'UNTIL') {
|
||||
$values = date_ical_parse_date('', $param[1]);
|
||||
}
|
||||
else {
|
||||
$values = explode(',', $param[1]);
|
||||
}
|
||||
// Treat items differently if they have multiple or single values.
|
||||
if (in_array($param[0], array('FREQ', 'INTERVAL', 'COUNT', 'WKST'))) {
|
||||
$items[$param[0]] = $param[1];
|
||||
}
|
||||
else {
|
||||
$items[$param[0]] = $values;
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse exception dates (can be multiple values).
|
||||
*
|
||||
* @return array
|
||||
* an array of date value arrays.
|
||||
*/
|
||||
function date_ical_parse_exceptions($field, $data) {
|
||||
$data = str_replace($field . ':', '', $data);
|
||||
$items = array('DATA' => $data);
|
||||
$ex_dates = explode(',', $data);
|
||||
foreach ($ex_dates as $ex_date) {
|
||||
$items[] = date_ical_parse_date('', $ex_date);
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the duration of the event.
|
||||
*
|
||||
* Example:
|
||||
* DURATION:PT1H30M
|
||||
* DURATION:P1Y2M
|
||||
*
|
||||
* @param array $subgroup
|
||||
* Array of other values in the vevent so we can check for DTSTART.
|
||||
*/
|
||||
function date_ical_parse_duration(&$subgroup, $field = 'DURATION') {
|
||||
$items = $subgroup[$field];
|
||||
$data = $items['DATA'];
|
||||
preg_match('/^P(\d{1,4}[Y])?(\d{1,2}[M])?(\d{1,2}[W])?(\d{1,2}[D])?([T]{0,1})?(\d{1,2}[H])?(\d{1,2}[M])?(\d{1,2}[S])?/', $data, $duration);
|
||||
$items['year'] = isset($duration[1]) ? str_replace('Y', '', $duration[1]) : '';
|
||||
$items['month'] = isset($duration[2]) ?str_replace('M', '', $duration[2]) : '';
|
||||
$items['week'] = isset($duration[3]) ?str_replace('W', '', $duration[3]) : '';
|
||||
$items['day'] = isset($duration[4]) ?str_replace('D', '', $duration[4]) : '';
|
||||
$items['hour'] = isset($duration[6]) ?str_replace('H', '', $duration[6]) : '';
|
||||
$items['minute'] = isset($duration[7]) ?str_replace('M', '', $duration[7]) : '';
|
||||
$items['second'] = isset($duration[8]) ?str_replace('S', '', $duration[8]) : '';
|
||||
$start_date = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['datetime'] : date_format(date_now(), DATE_FORMAT_ISO);
|
||||
$timezone = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['tz'] : variable_get('date_default_timezone');
|
||||
if (empty($timezone)) {
|
||||
$timezone = 'UTC';
|
||||
}
|
||||
$date = new DateObject($start_date, $timezone);
|
||||
$date2 = clone($date);
|
||||
foreach ($items as $item => $count) {
|
||||
if ($count > 0) {
|
||||
date_modify($date2, '+' . $count . ' ' . $item);
|
||||
}
|
||||
}
|
||||
$format = isset($subgroup['DTSTART']['type']) && $subgroup['DTSTART']['type'] == 'DATE' ? 'Y-m-d' : 'Y-m-d H:i:s';
|
||||
$subgroup['DTEND'] = array(
|
||||
'datetime' => date_format($date2, DATE_FORMAT_DATETIME),
|
||||
'all_day' => isset($subgroup['DTSTART']['all_day']) ? $subgroup['DTSTART']['all_day'] : 0,
|
||||
'tz' => $timezone,
|
||||
);
|
||||
$duration = date_format($date2, 'U') - date_format($date, 'U');
|
||||
$subgroup['DURATION'] = array('DATA' => $data, 'DURATION' => $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and clean up ical text elements.
|
||||
*/
|
||||
function date_ical_parse_text($field, $data) {
|
||||
if (strstr($field, 'QUOTED-PRINTABLE')) {
|
||||
$data = quoted_printable_decode($data);
|
||||
}
|
||||
// Strip line breaks within element.
|
||||
$data = str_replace(array("\r\n ", "\n ", "\r "), '', $data);
|
||||
// Put in line breaks where encoded.
|
||||
$data = str_replace(array("\\n", "\\N"), "\n", $data);
|
||||
// Remove other escaping.
|
||||
$data = stripslashes($data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse location elements.
|
||||
*
|
||||
* Catch situations like the upcoming.org feed that uses
|
||||
* LOCATION;VENUE-UID="http://upcoming.yahoo.com/venue/104/":111 First Street...
|
||||
* or more normal LOCATION;UID=123:111 First Street...
|
||||
* Upcoming feed would have been improperly broken on the ':' in http://
|
||||
* so we paste the $field and $data back together first.
|
||||
*
|
||||
* Use non-greedy check for ':' in case there are more of them in the address.
|
||||
*/
|
||||
function date_ical_parse_location($field, $data) {
|
||||
if (preg_match('/UID=[?"](.+)[?"][*?:](.+)/', $field . ':' . $data, $matches)) {
|
||||
$location = array();
|
||||
$location['UID'] = $matches[1];
|
||||
$location['DESCRIPTION'] = stripslashes($matches[2]);
|
||||
return $location;
|
||||
}
|
||||
else {
|
||||
// Remove other escaping.
|
||||
$location = stripslashes($data);
|
||||
return $location;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a date object for the ical date, adjusted to its local timezone.
|
||||
*
|
||||
* @param array $ical_date
|
||||
* An array of ical date information created in the ical import.
|
||||
* @param string $to_tz
|
||||
* The timezone to convert the date's value to.
|
||||
*
|
||||
* @return object
|
||||
* A timezone-adjusted date object.
|
||||
*/
|
||||
function date_ical_date($ical_date, $to_tz = FALSE) {
|
||||
|
||||
// If the ical date has no timezone, must assume it is stateless
|
||||
// so treat it as a local date.
|
||||
if (empty($ical_date['datetime'])) {
|
||||
return NULL;
|
||||
}
|
||||
elseif (empty($ical_date['tz'])) {
|
||||
$from_tz = date_default_timezone();
|
||||
}
|
||||
else {
|
||||
$from_tz = $ical_date['tz'];
|
||||
}
|
||||
if (strlen($ical_date['datetime']) < 11) {
|
||||
$ical_date['datetime'] .= ' 00:00:00';
|
||||
}
|
||||
$date = new DateObject($ical_date['datetime'], new DateTimeZone($from_tz));
|
||||
|
||||
if ($to_tz && $ical_date['tz'] != '' && $to_tz != $ical_date['tz']) {
|
||||
date_timezone_set($date, timezone_open($to_tz));
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape #text elements for safe iCal use.
|
||||
*
|
||||
* @param string $text
|
||||
* Text to escape
|
||||
*
|
||||
* @return string
|
||||
* Escaped text
|
||||
*
|
||||
*/
|
||||
function date_ical_escape_text($text) {
|
||||
$text = drupal_html_to_text($text);
|
||||
$text = trim($text);
|
||||
// TODO Per #38130 the iCal specs don't want : and " escaped
|
||||
// but there was some reason for adding this in. Need to watch
|
||||
// this and see if anything breaks.
|
||||
// $text = str_replace('"', '\"', $text);
|
||||
// $text = str_replace(":", "\:", $text);
|
||||
$text = preg_replace("/\\\b/", "\\\\", $text);
|
||||
$text = str_replace(",", "\,", $text);
|
||||
$text = str_replace(";", "\;", $text);
|
||||
$text = str_replace("\n", "\\n ", $text);
|
||||
return trim($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an iCal RULE from $form_values.
|
||||
*
|
||||
* @param array $form_values
|
||||
* An array constructed like the one created by date_ical_parse_rrule().
|
||||
* [RRULE] => Array (
|
||||
* [FREQ] => Array (
|
||||
* [0] => MONTHLY
|
||||
* )
|
||||
* [BYDAY] => Array (
|
||||
* [0] => 1SU
|
||||
* [1] => -1SU
|
||||
* )
|
||||
* [UNTIL] => Array (
|
||||
* [datetime] => 1997-21-31 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* )
|
||||
* [EXDATE] => Array (
|
||||
* [0] = Array (
|
||||
* [datetime] => 1997-09-21 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* [1] = Array (
|
||||
* [datetime] => 1997-10-05 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* )
|
||||
* [RDATE] => Array (
|
||||
* [0] = Array (
|
||||
* [datetime] => 1997-09-21 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* [1] = Array (
|
||||
* [datetime] => 1997-10-05 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
function date_api_ical_build_rrule($form_values) {
|
||||
$RRULE = '';
|
||||
if (empty($form_values) || !is_array($form_values)) {
|
||||
return $RRULE;
|
||||
}
|
||||
|
||||
// Grab the RRULE data and put them into iCal RRULE format.
|
||||
$RRULE .= 'RRULE:FREQ=' . (!array_key_exists('FREQ', $form_values) ? 'DAILY' : $form_values['FREQ']);
|
||||
$RRULE .= ';INTERVAL=' . (!array_key_exists('INTERVAL', $form_values) ? 1 : $form_values['INTERVAL']);
|
||||
|
||||
// Unset the empty 'All' values.
|
||||
if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) {
|
||||
unset($form_values['BYDAY']['']);
|
||||
}
|
||||
if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH'])) {
|
||||
unset($form_values['BYMONTH']['']);
|
||||
}
|
||||
if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY'])) {
|
||||
unset($form_values['BYMONTHDAY']['']);
|
||||
}
|
||||
|
||||
if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY']) && $BYDAY = implode(",", $form_values['BYDAY'])) {
|
||||
$RRULE .= ';BYDAY=' . $BYDAY;
|
||||
}
|
||||
if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH']) && $BYMONTH = implode(",", $form_values['BYMONTH'])) {
|
||||
$RRULE .= ';BYMONTH=' . $BYMONTH;
|
||||
}
|
||||
if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY']) && $BYMONTHDAY = implode(",", $form_values['BYMONTHDAY'])) {
|
||||
$RRULE .= ';BYMONTHDAY=' . $BYMONTHDAY;
|
||||
}
|
||||
// The UNTIL date is supposed to always be expressed in UTC.
|
||||
// The input date values may already have been converted to a date object on a
|
||||
// previous pass, so check for that.
|
||||
if (array_key_exists('UNTIL', $form_values) && array_key_exists('datetime', $form_values['UNTIL']) && !empty($form_values['UNTIL']['datetime'])) {
|
||||
// We only collect a date for UNTIL, but we need it to be inclusive, so
|
||||
// force it to a full datetime element at the last second of the day.
|
||||
if (!is_object($form_values['UNTIL']['datetime'])) {
|
||||
// If this is a date without time, give it time.
|
||||
if (strlen($form_values['UNTIL']['datetime']) < 11) {
|
||||
$form_values['UNTIL']['datetime'] .= ' 23:59:59';
|
||||
$form_values['UNTIL']['granularity'] = serialize(drupal_map_assoc(array('year', 'month', 'day', 'hour', 'minute', 'second')));
|
||||
$form_values['UNTIL']['all_day'] = FALSE;
|
||||
}
|
||||
$until = date_ical_date($form_values['UNTIL'], 'UTC');
|
||||
}
|
||||
else {
|
||||
$until = $form_values['UNTIL']['datetime'];
|
||||
}
|
||||
$RRULE .= ';UNTIL=' . date_format($until, DATE_FORMAT_ICAL) . 'Z';
|
||||
}
|
||||
// Our form doesn't allow a value for COUNT, but it may be needed by
|
||||
// modules using the API, so add it to the rule.
|
||||
if (array_key_exists('COUNT', $form_values)) {
|
||||
$RRULE .= ';COUNT=' . $form_values['COUNT'];
|
||||
}
|
||||
|
||||
// iCal rules presume the week starts on Monday unless otherwise specified,
|
||||
// so we'll specify it.
|
||||
if (array_key_exists('WKST', $form_values)) {
|
||||
$RRULE .= ';WKST=' . $form_values['WKST'];
|
||||
}
|
||||
else {
|
||||
$RRULE .= ';WKST=' . date_repeat_dow2day(variable_get('date_first_day', 0));
|
||||
}
|
||||
|
||||
// Exceptions dates go last, on their own line.
|
||||
// The input date values may already have been converted to a date
|
||||
// object on a previous pass, so check for that.
|
||||
if (isset($form_values['EXDATE']) && is_array($form_values['EXDATE'])) {
|
||||
$ex_dates = array();
|
||||
foreach ($form_values['EXDATE'] as $value) {
|
||||
if (!empty($value['datetime'])) {
|
||||
$date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
|
||||
$ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z': '';
|
||||
if (!empty($ex_date)) {
|
||||
$ex_dates[] = $ex_date;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($ex_dates)) {
|
||||
sort($ex_dates);
|
||||
$RRULE .= chr(13) . chr(10) . 'EXDATE:' . implode(',', $ex_dates);
|
||||
}
|
||||
}
|
||||
elseif (!empty($form_values['EXDATE'])) {
|
||||
$RRULE .= chr(13) . chr(10) . 'EXDATE:' . $form_values['EXDATE'];
|
||||
}
|
||||
|
||||
// Exceptions dates go last, on their own line.
|
||||
if (isset($form_values['RDATE']) && is_array($form_values['RDATE'])) {
|
||||
$ex_dates = array();
|
||||
foreach ($form_values['RDATE'] as $value) {
|
||||
$date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
|
||||
$ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z': '';
|
||||
if (!empty($ex_date)) {
|
||||
$ex_dates[] = $ex_date;
|
||||
}
|
||||
}
|
||||
if (!empty($ex_dates)) {
|
||||
sort($ex_dates);
|
||||
$RRULE .= chr(13) . chr(10) . 'RDATE:' . implode(',', $ex_dates);
|
||||
}
|
||||
}
|
||||
elseif (!empty($form_values['RDATE'])) {
|
||||
$RRULE .= chr(13) . chr(10) . 'RDATE:' . $form_values['RDATE'];
|
||||
}
|
||||
|
||||
return $RRULE;
|
||||
}
|
1156
sites/all/modules/contrib/fields/date/date_api/date_api_sql.inc
Normal file
1156
sites/all/modules/contrib/fields/date/date_api/date_api_sql.inc
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,223 @@
|
||||
(function ($) {
|
||||
|
||||
Drupal.behaviors.dateYearRange = {};
|
||||
|
||||
Drupal.behaviors.dateYearRange.attach = function (context, settings) {
|
||||
var $textfield, $textfields, i;
|
||||
|
||||
// Turn the years back and forward fieldsets into dropdowns.
|
||||
$textfields = $('input.select-list-with-custom-option', context).once('date-year-range');
|
||||
for (i = 0; i < $textfields.length; i++) {
|
||||
$textfield = $($textfields[i]);
|
||||
new Drupal.dateYearRange.SelectListWithCustomOption($textfield);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Drupal.dateYearRange = {};
|
||||
|
||||
/**
|
||||
* Constructor for the SelectListWithCustomOption object.
|
||||
*
|
||||
* This object is responsible for turning the years back and forward textfields
|
||||
* into dropdowns with an 'other' option that lets the user enter a custom
|
||||
* value.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption = function ($textfield) {
|
||||
this.$textfield = $textfield;
|
||||
this.$description = $textfield.next('div.description');
|
||||
this.defaultValue = $textfield.val();
|
||||
this.$dropdown = this.createDropdown();
|
||||
this.$dropdown.insertBefore($textfield);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the value of the textfield as it existed on page load.
|
||||
*
|
||||
* @param {String} type
|
||||
* The type of the variable to be returned. Defaults to string.
|
||||
* @return
|
||||
* The original value of the textfield. Returned as an integer, if the type
|
||||
* parameter was 'int'.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.getOriginal = function (type) {
|
||||
var original;
|
||||
if (type === 'int') {
|
||||
original = parseInt(this.defaultValue, 10);
|
||||
if (window.isNaN(original)) {
|
||||
original = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
original = this.defaultValue;
|
||||
}
|
||||
return original;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the correct first value for the dropdown.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.getStartValue = function () {
|
||||
var direction = this.getDirection();
|
||||
var start;
|
||||
switch (direction) {
|
||||
case 'back':
|
||||
// For the 'years back' dropdown, the first option should be -10, unless
|
||||
// the default value of the textfield is even smaller than that.
|
||||
start = Math.min(this.getOriginal('int'), -10);
|
||||
break;
|
||||
case 'forward':
|
||||
start = 0;
|
||||
break;
|
||||
}
|
||||
return start;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the correct last value for the dropdown.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.getEndValue = function () {
|
||||
var direction = this.getDirection();
|
||||
var end;
|
||||
var originalString = this.getOriginal();
|
||||
switch (direction) {
|
||||
case 'back':
|
||||
end = 0;
|
||||
break;
|
||||
case 'forward':
|
||||
// If the original value of the textfield is an absolute year such as
|
||||
// 2020, don't try to include it in the dropdown.
|
||||
if (originalString.indexOf('+') === -1) {
|
||||
end = 10;
|
||||
}
|
||||
// If the original value is a relative value (+x), we want it to be
|
||||
// included in the possible dropdown values.
|
||||
else {
|
||||
end = Math.max(this.getOriginal('int'), 10);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a dropdown select list with the correct options for this textfield.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.createDropdown = function () {
|
||||
var $dropdown = $('<select>').addClass('form-select date-year-range-select');
|
||||
var $option, i, value;
|
||||
var start = this.getStartValue();
|
||||
var end = this.getEndValue();
|
||||
var direction = this.getDirection();
|
||||
for (i = start; i <= end; i++) {
|
||||
// Make sure we include the +/- sign in the option value.
|
||||
value = i;
|
||||
if (i > 0) {
|
||||
value = '+' + i;
|
||||
}
|
||||
// Zero values must have a + or - in front.
|
||||
if (i === 0) {
|
||||
if (direction === 'back') {
|
||||
value = '-' + i;
|
||||
}
|
||||
else {
|
||||
value = '+' + i;
|
||||
}
|
||||
}
|
||||
$option = $('<option>' + Drupal.formatPlural(value, '@count year from now', '@count years from now') + '</option>').val(value);
|
||||
$dropdown.append($option);
|
||||
}
|
||||
// Create an 'Other' option.
|
||||
$option = $('<option class="custom-option">' + Drupal.t('Other') + '</option>').val('');
|
||||
$dropdown.append($option);
|
||||
|
||||
// When the user changes the selected option in the dropdown, perform
|
||||
// appropriate actions (such as showing or hiding the textfield).
|
||||
$dropdown.bind('change', $.proxy(this.handleDropdownChange, this));
|
||||
|
||||
// Set the initial value of the dropdown.
|
||||
this._setInitialDropdownValue($dropdown);
|
||||
return $dropdown;
|
||||
};
|
||||
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype._setInitialDropdownValue = function ($dropdown) {
|
||||
var textfieldValue = this.getOriginal();
|
||||
// Determine whether the original textfield value exists in the dropdown.
|
||||
var possible = $dropdown.find('option[value="' + textfieldValue + '"]');
|
||||
// If the original textfield value is one of the dropdown options, preselect
|
||||
// it and hide the 'other' textfield.
|
||||
if (possible.length) {
|
||||
$dropdown.val(textfieldValue);
|
||||
this.hideTextfield();
|
||||
}
|
||||
// If the original textfield value isn't one of the dropdown options, choose
|
||||
// the 'Other' option in the dropdown.
|
||||
else {
|
||||
$dropdown.val('');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine whether this is the "years back" or "years forward" textfield.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.getDirection = function () {
|
||||
if (this.direction) {
|
||||
return this.direction;
|
||||
}
|
||||
var direction;
|
||||
if (this.$textfield.hasClass('back')) {
|
||||
direction = 'back';
|
||||
}
|
||||
else if (this.$textfield.hasClass('forward')) {
|
||||
direction = 'forward';
|
||||
}
|
||||
this.direction = direction;
|
||||
return direction;
|
||||
};
|
||||
|
||||
/**
|
||||
* Change handler for the dropdown, to modify the textfield as appropriate.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.handleDropdownChange = function () {
|
||||
// Since the dropdown changed, we need to make the content of the textfield
|
||||
// match the (new) selected option.
|
||||
this.syncTextfield();
|
||||
|
||||
// Show the textfield if the 'Other' option was selected, and hide it if one
|
||||
// of the preset options was selected.
|
||||
if ($(':selected', this.$dropdown).hasClass('custom-option')) {
|
||||
this.revealTextfield();
|
||||
}
|
||||
else {
|
||||
this.hideTextfield();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Display the textfield and its description.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.revealTextfield = function () {
|
||||
this.$textfield.show();
|
||||
this.$description.show();
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the textfield and its description.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.hideTextfield = function () {
|
||||
this.$textfield.hide();
|
||||
this.$description.hide();
|
||||
};
|
||||
|
||||
/**
|
||||
* Copy the selected value of the dropdown to the textfield.
|
||||
*
|
||||
* FAPI doesn't know about the JS-only dropdown, so the textfield needs to
|
||||
* reflect the value of the dropdown.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.syncTextfield = function () {
|
||||
var value = this.$dropdown.val();
|
||||
this.$textfield.val(value);
|
||||
};
|
||||
|
||||
})(jQuery);
|
Binary file not shown.
After Width: | Height: | Size: 440 B |
Binary file not shown.
After Width: | Height: | Size: 357 B |
229
sites/all/modules/contrib/fields/date/date_api/theme/theme.inc
Normal file
229
sites/all/modules/contrib/fields/date/date_api/theme/theme.inc
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Theme files for Date API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns HTML for a date timezone element.
|
||||
*/
|
||||
function theme_date_timezone($variables) {
|
||||
$element = $variables['element'];
|
||||
$attributes = $element['#attributes'];
|
||||
$wrapper_attributes = array();
|
||||
// Add an wrapper to mimic the way a single value field works, for ease in
|
||||
// using #states.
|
||||
if (isset($element['#children'])) {
|
||||
$element['#children'] = '<div id="' . $element['#id'] . '" ' . drupal_attributes($wrapper_attributes) . '>' . $element['#children'] . '</div>';
|
||||
}
|
||||
return '<div ' . drupal_attributes($attributes) . '>' . theme('form_element', $element) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date select element.
|
||||
*/
|
||||
function theme_date_select($variables) {
|
||||
$element = $variables['element'];
|
||||
$attributes = !empty($element['#wrapper_attributes']) ? $element['#wrapper_attributes'] : array('class' => array());
|
||||
$attributes['class'][] = 'container-inline-date';
|
||||
$wrapper_attributes = array('class' => array('date-padding'));
|
||||
$wrapper_attributes['class'][] = 'clearfix';
|
||||
// Add an wrapper to mimic the way a single value field works, for ease in
|
||||
// using #states.
|
||||
if (isset($element['#children'])) {
|
||||
$element['#children'] = '<div id="' . $element['#id'] . '" ' . drupal_attributes($wrapper_attributes) . '>' . $element['#children'] . '</div>';
|
||||
}
|
||||
return '<div ' . drupal_attributes($attributes) . '>' . theme('form_element', $element) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date text element.
|
||||
*/
|
||||
function theme_date_text($variables) {
|
||||
$element = $variables['element'];
|
||||
$attributes = !empty($element['#wrapper_attributes']) ? $element['#wrapper_attributes'] : array('class' => array());
|
||||
$attributes['class'][] = 'container-inline-date';
|
||||
// If there is no description, the floating date elements need some extra
|
||||
// padding below them.
|
||||
$wrapper_attributes = array('class' => array('date-padding'));
|
||||
if (empty($element['date']['#description'])) {
|
||||
$wrapper_attributes['class'][] = 'clearfix';
|
||||
}
|
||||
// Add an wrapper to mimic the way a single value field works, for ease in
|
||||
// using #states.
|
||||
if (isset($element['#children'])) {
|
||||
$element['#children'] = '<div id="' . $element['#id'] . '" ' . drupal_attributes($wrapper_attributes) . '>' . $element['#children'] . '</div>';
|
||||
}
|
||||
return '<div ' . drupal_attributes($attributes) . '>' . theme('form_element', $element) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date select input form element.
|
||||
*/
|
||||
function theme_date_select_element($variables) {
|
||||
$element = $variables['element'];
|
||||
$parents = $element['#parents'];
|
||||
$part = array_pop($parents);
|
||||
return '<div class="date-' . $part . '">' . theme('select', $element) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date textfield input form element.
|
||||
*/
|
||||
function theme_date_textfield_element($variables) {
|
||||
$element = $variables['element'];
|
||||
$parents = $element['#parents'];
|
||||
$part = array_pop($parents);
|
||||
return '<div class="date-' . $part . '">' . theme('textfield', $element) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a 'hour' date part prefix.
|
||||
*/
|
||||
function theme_date_part_hour_prefix($variables) {
|
||||
$element = $variables['element'];
|
||||
if ($element['#date_label_position'] != 'above') {
|
||||
return '<span class="form-item date-spacer"> - </span>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a 'minutes and seconds' date part prefix.
|
||||
*/
|
||||
function theme_date_part_minsec_prefix($variables) {
|
||||
$element = $variables['element'];
|
||||
if ($element['#date_label_position'] != 'above') {
|
||||
return '<span class="form-item date-spacer">:</span>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'year' label.
|
||||
*/
|
||||
function theme_date_part_label_year($variables) {
|
||||
return t('Year', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'month' label.
|
||||
*/
|
||||
function theme_date_part_label_month($variables) {
|
||||
return t('Month', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'day' label.
|
||||
*/
|
||||
function theme_date_part_label_day($variables) {
|
||||
return t('Day', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'hour' label.
|
||||
*/
|
||||
function theme_date_part_label_hour($variables) {
|
||||
return t('Hour', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'minute' label.
|
||||
*/
|
||||
function theme_date_part_label_minute($variables) {
|
||||
return t('Minute', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'second' label.
|
||||
*/
|
||||
function theme_date_part_label_second($variables) {
|
||||
return t('Second', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'ampm' label.
|
||||
*/
|
||||
function theme_date_part_label_ampm($variables) {
|
||||
return ' ';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'timezone' label.
|
||||
*/
|
||||
function theme_date_part_label_timezone($variables) {
|
||||
return t('Timezone');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'date' label.
|
||||
*/
|
||||
function theme_date_part_label_date($variables) {
|
||||
return t('Date', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'time' label.
|
||||
*/
|
||||
function theme_date_part_label_time($variables) {
|
||||
return t('Time', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns HTML for a date block that looks like a mini calendar day.
|
||||
*
|
||||
* Pass in a date object already set to the right timezone, format as a calendar
|
||||
* page date. The calendar styling is created in CSS.
|
||||
*/
|
||||
function theme_date_calendar_day($variables) {
|
||||
$output = '';
|
||||
$date = $variables['date'];
|
||||
if (!empty($date)) {
|
||||
$output .= '<div class="date-calendar-day">';
|
||||
$output .= '<span class="month">' . date_format_date($date, 'custom', 'M') . '</span>';
|
||||
$output .= '<span class="day">' . date_format_date($date, 'custom', 'j') . '</span>';
|
||||
$output .= '<span class="year">' . date_format_date($date, 'custom', 'Y') . '</span>';
|
||||
$output .= '</div>';
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date in the format 'time ago'.
|
||||
*/
|
||||
function theme_date_time_ago($variables) {
|
||||
$start_date = $variables['start_date'];
|
||||
$end_date = $variables['end_date'];
|
||||
$interval = !empty($variables['interval']) ? $variables['interval'] : 2;
|
||||
$display = isset($variables['interval_display']) ? $variables['interval_display'] : 'time ago';
|
||||
|
||||
// If no date is sent, then return nothing.
|
||||
if (empty($start_date) || empty($end_date)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Time to compare dates to.
|
||||
$now = date_format(date_now(), DATE_FORMAT_UNIX);
|
||||
$start = date_format($start_date, DATE_FORMAT_UNIX);
|
||||
|
||||
// will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence)
|
||||
$time_diff = $now - $start;
|
||||
|
||||
// Uses the same options used by Views format_interval.
|
||||
switch ($display) {
|
||||
case 'raw time ago':
|
||||
return format_interval($time_diff, $interval);
|
||||
case 'time ago':
|
||||
return t('%time ago', array('%time' => format_interval($time_diff, $interval)));
|
||||
case 'raw time hence':
|
||||
return format_interval(-$time_diff, $interval);
|
||||
case 'time hence':
|
||||
return t('%time hence', array('%time' => format_interval(-$time_diff, $interval)));
|
||||
case 'raw time span':
|
||||
return ($time_diff < 0 ? '-' : '') . format_interval(abs($time_diff), $interval);
|
||||
case 'inverse time span':
|
||||
return ($time_diff > 0 ? '-' : '') . format_interval(abs($time_diff), $interval);
|
||||
case 'time span':
|
||||
return t(($time_diff < 0 ? '%time hence' : '%time ago'), array('%time' => format_interval(abs($time_diff), $interval)));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user