Index: includes/date_formats.inc =================================================================== RCS file: includes/date_formats.inc diff -N includes/date_formats.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/date_formats.inc 5 Sep 2009 15:21:47 -0000 @@ -0,0 +1,193 @@ + 'short', + 'format' => 'Y-m-d H:i', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'm/d/Y - H:i', + 'locales' => array('en-us',), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'd/m/Y - H:i', + 'locales' => array('en-gb', 'en-hk', 'en-ie', 'el-gr', 'es-es', 'fr-be', 'fr-fr', 'fr-lu', 'it-it', 'nl-be', 'pt-pt',), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'Y/m/d - H:i', + 'locales' => array('en-ca', 'fr-ca', 'no-no', 'sv-se',), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'd.m.Y - H:i', + 'locales' => array('de-ch', 'de-de', 'de-lu', 'fi-fi', 'fr-ch', 'is-is', 'pl-pl', 'ro-ro', 'ru-ru',), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'm/d/Y - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'd/m/Y - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'Y/m/d - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'M j Y - H:i', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'j M Y - H:i', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'Y M j - H:i', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'M j Y - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'j M Y - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'short', + 'format' => 'Y M j - g:ia', + 'locales' => array(), + ); + + // Medium date formats. + $formats[] = array( + 'type' => 'medium', + 'format' => 'D, Y-m-d H:i', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'D, m/d/Y - H:i', + 'locales' => array('en-us',), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'D, d/m/Y - H:i', + 'locales' => array('en-gb', 'en-hk', 'en-ie', 'el-gr', 'es-es', 'fr-be', 'fr-fr', 'fr-lu', 'it-it', 'nl-be', 'pt-pt',), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'D, Y/m/d - H:i', + 'locales' => array('en-ca', 'fr-ca', 'no-no', 'sv-se',), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'F j, Y - H:i', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'j F, Y - H:i', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'Y, F j - H:i', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'D, m/d/Y - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'D, d/m/Y - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'D, Y/m/d - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'F j, Y - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'j F Y - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'Y, F j - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'medium', + 'format' => 'j. F Y - G:i', + 'locales' => array(), + ); + + // Long date formats. + $formats[] = array( + 'type' => 'long', + 'format' => 'l, F j, Y - H:i', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'long', + 'format' => 'l, j F, Y - H:i', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'long', + 'format' => 'l, Y, F j - H:i', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'long', + 'format' => 'l, F j, Y - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'long', + 'format' => 'l, j F Y - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'long', + 'format' => 'l, Y, F j - g:ia', + 'locales' => array(), + ); + $formats[] = array( + 'type' => 'long', + 'format' => 'l, j. F Y - G:i', + 'locales' => array(), + ); + + return $formats; +} Index: modules/system/system.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v retrieving revision 1.197 diff -u -p -r1.197 system.admin.inc --- modules/system/system.admin.inc 26 Aug 2009 10:53:45 -0000 1.197 +++ modules/system/system.admin.inc 5 Sep 2009 15:21:49 -0000 @@ -1588,7 +1588,7 @@ function system_rss_feeds_settings() { } /** - * Form builder; Configure the site date and time settings. + * Form builder; Configure the site regional settings. * * @ingroup forms * @see system_settings_form() @@ -1596,7 +1596,7 @@ function system_rss_feeds_settings() { */ function system_regional_settings() { drupal_add_js(drupal_get_path('module', 'system') . '/system.js'); - drupal_add_js(array('dateTime' => array('lookup' => url('admin/config/regional/settings/lookup'))), 'setting'); + drupal_add_js(array('dateTime' => array('lookup' => url('admin/config/regional/date-time/formats/lookup'))), 'setting'); include_once DRUPAL_ROOT . '/includes/locale.inc'; $countries = country_get_list(); @@ -1606,31 +1606,6 @@ function system_regional_settings() { // Date settings: $zones = system_time_zones(); - // Date settings: possible date formats - $date_short = array('Y-m-d H:i', 'm/d/Y - H:i', 'd/m/Y - H:i', 'Y/m/d - H:i', - 'd.m.Y - H:i', 'm/d/Y - g:ia', 'd/m/Y - g:ia', 'Y/m/d - g:ia', - 'M j Y - H:i', 'j M Y - H:i', 'Y M j - H:i', - 'M j Y - g:ia', 'j M Y - g:ia', 'Y M j - g:ia'); - $date_medium = array('D, Y-m-d H:i', 'D, m/d/Y - H:i', 'D, d/m/Y - H:i', - 'D, Y/m/d - H:i', 'F j, Y - H:i', 'j F, Y - H:i', 'Y, F j - H:i', - 'D, m/d/Y - g:ia', 'D, d/m/Y - g:ia', 'D, Y/m/d - g:ia', - 'F j, Y - g:ia', 'j F Y - g:ia', 'Y, F j - g:ia', 'j. F Y - G:i'); - $date_long = array('l, F j, Y - H:i', 'l, j F, Y - H:i', 'l, Y, F j - H:i', - 'l, F j, Y - g:ia', 'l, j F Y - g:ia', 'l, Y, F j - g:ia', 'l, j. F Y - G:i'); - - // Date settings: construct choices for user - foreach ($date_short as $f) { - $date_short_choices[$f] = format_date(REQUEST_TIME, 'custom', $f); - } - foreach ($date_medium as $f) { - $date_medium_choices[$f] = format_date(REQUEST_TIME, 'custom', $f); - } - foreach ($date_long as $f) { - $date_long_choices[$f] = format_date(REQUEST_TIME, 'custom', $f); - } - - $date_long_choices['custom'] = $date_medium_choices['custom'] = $date_short_choices['custom'] = t('Custom format'); - $form['locale'] = array( '#type' => 'fieldset', '#title' => t('Locale'), @@ -1695,77 +1670,6 @@ function system_regional_settings() { '#description' => t('Only applied if users may set their own time zone.') ); - $form['date_formats'] = array( - '#type' => 'fieldset', - '#title' => t('Date formats'), - ); - - $date_format_short = variable_get('date_format_short', $date_short[1]); - $form['date_formats']['date_format_short'] = array( - '#prefix' => '
', - '#suffix' => '
', - '#type' => 'select', - '#title' => t('Short date format'), - '#attributes' => array('class' => array('date-format')), - '#default_value' => (isset($date_short_choices[$date_format_short]) ? $date_format_short : 'custom'), - '#options' => $date_short_choices, - ); - - $default_short_custom = variable_get('date_format_short_custom', (isset($date_short_choices[$date_format_short]) ? $date_format_short : '')); - $form['date_formats']['date_format_short_custom'] = array( - '#prefix' => '
', - '#suffix' => '
', - '#type' => 'textfield', - '#title' => t('Custom short date format'), - '#attributes' => array('class' => array('custom-format')), - '#default_value' => $default_short_custom, - '#description' => t('A user-defined short date format. See the PHP manual for available options. This format is currently set to display as %date.', array('@url' => 'http://php.net/manual/function.date.php', '%date' => format_date(REQUEST_TIME, 'custom', $default_short_custom))), - ); - - $date_format_medium = variable_get('date_format_medium', $date_medium[1]); - $form['date_formats']['date_format_medium'] = array( - '#prefix' => '
', - '#suffix' => '
', - '#type' => 'select', - '#title' => t('Medium date format'), - '#attributes' => array('class' => array('date-format')), - '#default_value' => (isset($date_medium_choices[$date_format_medium]) ? $date_format_medium : 'custom'), - '#options' => $date_medium_choices, - ); - - $default_medium_custom = variable_get('date_format_medium_custom', (isset($date_medium_choices[$date_format_medium]) ? $date_format_medium : '')); - $form['date_formats']['date_format_medium_custom'] = array( - '#prefix' => '
', - '#suffix' => '
', - '#type' => 'textfield', - '#title' => t('Custom medium date format'), - '#attributes' => array('class' => array('custom-format')), - '#default_value' => $default_medium_custom, - '#description' => t('A user-defined medium date format. See the PHP manual for available options. This format is currently set to display as %date.', array('@url' => 'http://php.net/manual/function.date.php', '%date' => format_date(REQUEST_TIME, 'custom', $default_medium_custom))), - ); - - $date_format_long = variable_get('date_format_long', $date_long[0]); - $form['date_formats']['date_format_long'] = array( - '#prefix' => '
', - '#suffix' => '
', - '#type' => 'select', - '#title' => t('Long date format'), - '#attributes' => array('class' => array('date-format')), - '#default_value' => (isset($date_long_choices[$date_format_long]) ? $date_format_long : 'custom'), - '#options' => $date_long_choices, - ); - - $default_long_custom = variable_get('date_format_long_custom', (isset($date_long_choices[$date_format_long]) ? $date_format_long : '')); - $form['date_formats']['date_format_long_custom'] = array( - '#prefix' => '
', - '#suffix' => '
', - '#type' => 'textfield', - '#title' => t('Custom long date format'), - '#attributes' => array('class' => array('custom-format')), - '#default_value' => $default_long_custom, - '#description' => t('A user-defined long date format. See the PHP manual for available options. This format is currently set to display as %date.', array('@url' => 'http://php.net/manual/function.date.php', '%date' => format_date(REQUEST_TIME, 'custom', $default_long_custom))), - ); - $form = system_settings_form($form, FALSE); // We will call system_settings_form_submit() manually, so remove it for now. unset($form['#submit']); @@ -1789,6 +1693,162 @@ function system_regional_settings_submit } /** + * Form builder; Configure the site date and time settings. + * + * @ingroup forms + * @see system_settings_form() + * @see system_date_time_settings_submit() + */ +function system_date_time_settings() { + drupal_add_js(drupal_get_path('module', 'system') . '/system.js'); + drupal_add_js(array('dateTime' => array('lookup' => url('admin/config/regional/date-time/formats/lookup'))), 'setting'); + + // Get list of all available date types. + $format_types = system_get_date_types('', TRUE); + + // Get list of all available date formats. + $all_formats = array(); + $date_formats = system_get_date_formats('', TRUE); // Call this to rebuild the list, and to have default list. + foreach ($date_formats as $type => $format_info) { + $all_formats = array_merge($all_formats, $format_info); + } + $custom_formats = system_get_date_formats('custom'); + if (!empty($format_types)) { + foreach ($format_types as $type => $type_info) { + // If a system type, only show the available formats for that type and + // custom ones. + if ($type_info['locked'] == 1) { + $formats = system_get_date_formats($type); + if (empty($formats)) { + $formats = $all_formats; + } + elseif (!empty($custom_formats)) { + $formats = array_merge($formats, $custom_formats); + } + } + // If a user configured type, show all available date formats. + else { + $formats = $all_formats; + } + + $choices = array(); + foreach ($formats as $f => $format) { + $choices[$f] = format_date(REQUEST_TIME, 'custom', $f); + } + $default = variable_get('date_format_' . $type, array_shift(array_keys($formats))); + + // Get date type info for this date type. + $type_info = system_get_date_types($type); + + // Show date format select list. + $form['date_format_' . $type] = array( + '#prefix' => '
', + // Leave the date-container div open if we are going to be adding to and + // then closing it below. + '#suffix' => ($type_info['locked'] == 0) ? '
' : '
', + '#type' => 'select', + '#title' => t('!type date format', array('!type' => $type_info['title'])), + '#attributes' => array('class' => array('date-format')), + '#default_value' => (isset($choices[$default]) ? $default : 'custom'), + '#options' => $choices, + ); + + // If this isn't a system provided type, allow the user to remove it from + // the system. + if ($type_info['locked'] == 0) { + $form['date_format_' . $type . '_delete'] = array( + '#prefix' => '
', + '#suffix' => '
', + '#markup' => l(t('delete'), 'admin/config/regional/date-time/types/delete/' . $type), + ); + } + } + } + + // Display a message if no date types configured. + $form['#empty_text'] = t('No date types available. Add date type.', array('@link' => url('admin/config/regional/date-time/types/add'))); + + $form = system_settings_form($form, FALSE); + // We will call system_settings_form_submit() manually, so remove it for now. + unset($form['#submit']); + return $form; +} + +/** + * Process system_date_time_settings form submissions. + */ +function system_date_time_settings_submit($form, &$form_state) { + return system_settings_form_submit($form, $form_state); +} + +/** + * Add new date type. + * + * @ingroup forms + * @ingroup system_add_date_format_type_form_validate() + * @ingroup system_add_date_format_type_form_submit() + */ +function system_add_date_format_type_form() { + $form['add_date_format_title'] = array( + '#title' => t('Name'), + '#description' => t('The human-readable name for this date type.'), + '#type' => 'textfield', + '#size' => 20, + '#prefix' => '
', + '#suffix' => '
', + ); + + $form['add_date_format_type'] = array( + '#title' => t('Type'), + '#description' => t('The machine-readable name of this date type.
This name must contain only lowercase letters, numbers, and underscores and must be unique.'), + '#type' => 'textfield', + '#size' => 20, + '#prefix' => '
', + '#suffix' => '
', + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), + ); + + $form['#validate'][] = 'system_add_date_format_type_form_validate'; + $form['#submit'][] = 'system_add_date_format_type_form_submit'; + + return $form; +} + +/** + * Validate system_add_date_format_type form submissions. + */ +function system_add_date_format_type_form_validate($form, &$form_state) { + if (!empty($form_state['values']['add_date_format_type']) && !empty($form_state['values']['add_date_format_title'])) { + if (!preg_match("/^[a-zA-Z0-9_]+$/", $form_state['values']['add_date_format_type'])) { + form_set_error('add_date_format_type', t('The date type must contain only alphanumeric characters and underscores.')); + } + $types = system_get_date_types(); + if (in_array($form_state['values']['add_date_format_type'], array_keys($types))) { + form_set_error('add_date_format_type', t('This date type already exists. Please enter a unique type.')); + } + } +} + +/** + * Process system_add_date_format_type form submissions. + */ +function system_add_date_format_type_form_submit($form, &$form_state) { + include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'system') . '/' . 'system.date.inc'; + $format_type = array(); + $format_type['title'] = $form_state['values']['add_date_format_title']; + $format_type['type'] = $form_state['values']['add_date_format_type']; + $format_type['locked'] = 0; + $format_type['is_new'] = 1; + system_date_format_type_save($format_type); + drupal_set_message(t('New date type added successfully.')); + $form_state['redirect'] = 'admin/config/regional/date-time'; +} + +/** * Return the date for a given format string via Ajax. */ function system_date_time_lookup() { @@ -2294,3 +2354,154 @@ function theme_system_themes_form($form) $output .= drupal_render_children($form); return $output; } + +/** + * Menu callback; present a form for deleting a date format. + */ +function system_date_delete_format_form(&$form_state, $dfid) { + $form = array(); + $form['dfid'] = array( + '#type' => 'value', + '#value' => $dfid, + ); + $format = system_get_date_format($dfid); + + $output = confirm_form($form, + t('Are you sure you want to remove the format %format?', array('%format' => format_date(REQUEST_TIME, 'custom', $format->format))), + 'admin/config/regional/date-time/formats', + t('This action cannot be undone.'), + t('Remove'), t('Cancel'), + 'confirm' + ); + + return $output; +} + +/** + * Delete a configured date format. + */ +function system_date_delete_format_form_submit($form, &$form_state) { + include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'system') . '/' . 'system.date.inc'; + if ($form_state['values']['confirm']) { + $format = system_get_date_format($form_state['values']['dfid']); + system_date_format_delete($form_state['values']['dfid']); + drupal_set_message(t('Removed date format %format.', array('%format' => format_date(REQUEST_TIME, 'custom', $format->format)))); + $form_state['redirect'] = 'admin/config/regional/date-time/formats'; + } +} + +/** + * Menu callback; present a form for deleting a date type. + */ +function system_delete_date_format_type_form(&$form_state, $format_type) { + $form = array(); + $form['format_type'] = array( + '#type' => 'value', + '#value' => $format_type, + ); + $type_info = system_get_date_types($format_type); + + $output = confirm_form($form, + t('Are you sure you want to remove the date type %type?', array('%type' => $type_info['title'])), + 'admin/config/regional/date-time', + t('This action cannot be undone.'), + t('Remove'), t('Cancel'), + 'confirm' + ); + + return $output; +} + +/** + * Delete a configured date type. + */ +function system_delete_date_format_type_form_submit($form, &$form_state) { + include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'system') . '/' . 'system.date.inc'; + if ($form_state['values']['confirm']) { + $type_info = system_get_date_types($form_state['values']['format_type']); + system_date_format_type_delete($form_state['values']['format_type']); + drupal_set_message(t('Removed date type %type.', array('%type' => $type_info['title']))); + $form_state['redirect'] = 'admin/config/regional/date-time'; + } +} + + +/** + * Displays the date format strings overview page. + */ +function system_date_time_formats() { + $header = array(t('Format'), t('Operations')); + $rows = array(); + + $formats = system_get_date_formats('custom', TRUE); + if (!empty($formats)) { + foreach ($formats as $format) { + $row = array(); + $row[] = array('data' => format_date(REQUEST_TIME, 'custom', $format['format'])); + $row[] = array('data' => l(t('delete'), 'admin/config/regional/date-time/formats/delete/' . $format['dfid'])); + $rows[] = $row; + } + } + + if (empty($rows)) { + $rows[] = array(array('data' => t('No custom date formats available. Add date format.', array('@link' => url('admin/config/regional/date-time/formats/add'))), 'colspan' => '5', 'class' => array('message'))); + } + + $build['date_formats_table'] = array( + '#theme' => 'table', + '#header' => $header, + '#rows' => $rows + ); + + return $build; +} + +/** + * Allow users to add additional date formats. + */ +function system_add_date_formats_form() { + drupal_add_js(drupal_get_path('module', 'system') . '/system.js'); + drupal_add_js(array('dateTime' => array('lookup' => url('admin/config/regional/date-time/formats/lookup'))), 'setting'); + + $form['add_date_format'] = array( + '#type' => 'textfield', + '#title' => t('Format string'), + '#attributes' => array('class' => array('custom-format')), + '#description' => t('A user-defined date format. See the PHP manual for available options. This format is currently set to display as %date.', array('@url' => 'http://php.net/manual/function.date.php', '%date' => format_date(REQUEST_TIME, 'custom', '-'))), + ); + + $form['update'] = array( + '#type' => 'submit', + '#value' => t('Save configuration'), + ); + + $form['#validate'][] = 'system_add_date_formats_form_validate'; + $form['#submit'][] = 'system_add_date_formats_form_submit'; + + return $form; +} + +/** + * Validate new date format string submission. + */ +function system_add_date_formats_form_validate($form, &$form_state) { + $formats = system_get_date_formats('custom'); + if (!empty($formats) && in_array(trim($form_state['values']['add_date_format']), array_keys($formats))) { + form_set_error('add_date_format', t('This format already exists. Please enter a unique format string.')); + } +} + +/** + * Process new date format string submission. + */ +function system_add_date_formats_form_submit($form, &$form_state) { + $format = array(); + $format['format'] = trim($form_state['values']['add_date_format']); + $format['type'] = 'custom'; + $format['locked'] = 0; + $format['is_new'] = 1; + system_date_format_save($format); + + $form_state['redirect'] = 'admin/config/regional/date-time/formats'; + drupal_set_message(t('Configuration saved.')); +} Index: modules/system/system.date.inc =================================================================== RCS file: modules/system/system.date.inc diff -N modules/system/system.date.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/system/system.date.inc 5 Sep 2009 15:21:49 -0000 @@ -0,0 +1,247 @@ + $type_title) { + $type = array(); + $type['module'] = $module; + $type['type'] = $module_type; + $type['title'] = $type_title; + $type['locked'] = 1; + $type['is_new'] = TRUE; // Will be over-ridden later if in the db. + $types[$module_type] = $type; + } + } + + // Get custom formats added to the database by the end user. + $result = db_query('SELECT dft.type, dft.title, dft.locked FROM {date_format_types} dft ORDER BY dft.title'); + foreach ($result as $record) { + if (!in_array($record->type, $types)) { + $type = array(); + $type['is_new'] = FALSE; + $type['module'] = ''; + $type['type'] = $record->type; + $type['title'] = $record->title; + $type['locked'] = $record->locked; + $types[$record->type] = $type; + } + else { + $type = array(); + $type['is_new'] = FALSE; // Over-riding previous setting. + $types[$record->type] = array_merge($types[$record->type], $type); + } + } + + // Allow other modules to modify these date types. + drupal_alter('date_format_types', $types); + + return $types; +} + +/** + * Builds and returns the list of available date formats. + * + * @return + * Array of date formats. + */ +function _system_date_formats_build() { + $date_formats = array(); + + // First handle hook_date_format_types(). + $types = _system_date_format_types_build(); + foreach ($types as $type => $info) { + system_date_format_type_save($info); + } + + // Get formats supplied by various contrib modules. + $module_formats = module_invoke_all('date_formats'); + + foreach ($module_formats as $module_format) { + $module_format['locked'] = 1; // System types are locked. + // If no date type is specified, assign 'custom'. + if (!isset($module_format['type'])) { + $module_format['type'] = 'custom'; + } + if (!in_array($module_format['type'], array_keys($types))) { + continue; + } + if (!isset($date_formats[$module_format['type']])) { + $date_formats[$module_format['type']] = array(); + } + + // If another module already set this format, merge in the new settings. + if (isset($date_formats[$module_format['type']][$module_format['format']])) { + $date_formats[$module_format['type']][$module_format['format']] = array_merge_recursive($date_formats[$module_format['type']][$module_format['format']], $format); + } + else { + // This setting will be overridden later if it already exists in the db. + $module_format['is_new'] = TRUE; + $date_formats[$module_format['type']][$module_format['format']] = $module_format; + } + } + + // Get custom formats added to the database by the end user. + $result = db_query('SELECT df.dfid, df.format, df.type, df.locked, dfl.language FROM {date_formats} df LEFT JOIN {date_format_types} dft ON df.type = dft.type LEFT JOIN {date_format_locale} dfl ON df.format = dfl.format AND df.type = dfl.type ORDER BY df.type, df.format'); + foreach ($result as $record) { + // If this date type isn't set, initialise the array. + if (!isset($date_formats[$record->type])) { + $date_formats[$record->type] = array(); + } + // If this format not already present, add it to the array. + if (!isset($date_formats[$record->type][$record->format])) { + // We don't set 'is_new' as it is already in the db. + $format = array(); + $format['module'] = ''; + $format['dfid'] = $record->dfid; + $format['format'] = $record->format; + $format['type'] = $record->type; + $format['locked'] = $record->locked; + $format['locales'] = array($record->language); + $date_formats[$record->type][$record->format] = $format; + } + // Format already present, so merge in settings. + else { + $format = array(); + $format['is_new'] = FALSE; // It's in the db, so override this setting. + $format['dfid'] = $record->dfid; + $format['format'] = $record->format; + $format['type'] = $record->type; + $format['locked'] = $record->locked; + if (!empty($record->language)) { + $format['locales'] = array_merge($date_formats[$record->type][$record->format]['locales'], array($record->language)); + } + $date_formats[$record->type][$record->format] = array_merge($date_formats[$record->type][$record->format], $format); + } + } + + // Allow other modules to modify these formats. + drupal_alter('date_formats', $date_formats); + + return $date_formats; +} + +/** + * Save a date type to the database. + * + * @param $date_format_type + * An array of attributes for a date type. + */ +function system_date_format_type_save($date_format_type) { + $type = array(); + $type['type'] = $date_format_type['type']; + $type['title'] = $date_format_type['title']; + $type['locked'] = $date_format_type['locked']; + + // Update date_format table. + if (isset($date_format_type['is_new']) && !empty($date_format_type['is_new'])) { + drupal_write_record('date_format_types', $type); + } + else { + drupal_write_record('date_format_types', $type, 'type'); + } +} + +/** + * Delete a date type from the database. + * + * @param $date_format_type + * The date type name. + */ +function system_date_format_type_delete($date_format_type) { + db_delete('date_formats') + ->condition('type', $date_format_type) + ->execute(); + db_delete('date_format_types') + ->condition('type', $date_format_type) + ->execute(); + db_delete('date_format_locale') + ->condition('type', $date_format_type) + ->execute(); +} + +/** + * Save a date format to the database. + * + * @param $date_format + * An array of attributes for a date format. + */ +function system_date_format_save($date_format) { + $format = array(); + $format['type'] = $date_format['type']; + $format['format'] = $date_format['format']; + $format['locked'] = $date_format['locked']; + + // Update date_format table. + if (isset($date_format['is_new']) && !empty($date_format['is_new'])) { + drupal_write_record('date_formats', $format); + } + else { + drupal_write_record('date_formats', $format, array('format', 'type')); + } + + $languages = language_list('enabled'); + $languages = $languages[1]; + // If site_country module is enabled, add country specific languages to + // languages array. + if (module_exists('site_country')) { + $country_code = variable_get('site_country_default_country', ''); + if (!empty($country_code)) { + foreach ($languages as $langcode => $details) { + $country_language = $langcode . '-' . $country_code; + if (drupal_strlen($langcode) == 2 && !in_array($country_language, array_keys($languages))) { + $name = $details->name; + $languages[$country_language] = "$name ($country_code)"; + } + } + } + } + + $locale_format = array(); + $locale_format['type'] = $date_format['type']; + $locale_format['format'] = $date_format['format']; + + // Check if the suggested language codes are configured and enabled. + if (!empty($date_format['locales'])) { + foreach ($date_format['locales'] as $langcode) { + // Only proceed if language is enabled. + if (in_array($langcode, $languages)) { + $is_existing = (bool) db_query_range('SELECT 1 FROM {date_format_locale} WHERE type = :type AND language = :language', array(':type' => $date_format['type'], ':language' => $langcode), 0, 1)->fetchField(); + if (!$is_existing) { + $locale_format['language'] = $langcode; + drupal_write_record('date_format_locale', $locale_format); + } + } + } + } +} + +/** + * Delete a date format from the database. + * + * @param $date_format_id + * The date format string identifier. + */ +function system_date_format_delete($dfid) { + db_delete('date_formats') + ->condition('dfid', $dfid) + ->execute(); +} + Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.384 diff -u -p -r1.384 system.install --- modules/system/system.install 5 Sep 2009 13:05:31 -0000 1.384 +++ modules/system/system.install 5 Sep 2009 15:21:49 -0000 @@ -688,6 +688,90 @@ function system_schema() { $schema['cache_registry'] = $schema['cache']; $schema['cache_registry']['description'] = 'Cache table for the code registry system to remember what code files need to be loaded on any given page.'; + $schema['date_format_types'] = array( + 'description' => 'For storing configured date format types.', + 'fields' => array( + 'type' => array( + 'description' => 'The date format type, e.g. medium.', + 'type' => 'varchar', + 'length' => 200, + 'not null' => TRUE, + ), + 'title' => array( + 'description' => 'The human readable name of the format type.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ), + 'locked' => array( + 'description' => 'Whether or not this is a system provided format.', + 'type' => 'int', + 'size' => 'tiny', + 'default' => 0, + 'not null' => TRUE, + ), + ), + 'primary key' => array('type'), + ); + + $schema['date_formats'] = array( + 'description' => 'For storing configured date formats.', + 'fields' => array( + 'dfid' => array( + 'description' => 'The date format identifier.', + 'type' => 'serial', + 'not null' => TRUE, + 'unsigned' => TRUE, + ), + 'format' => array( + 'description' => 'The date format string.', + 'type' => 'varchar', + 'length' => 100, + 'not null' => TRUE, + ), + 'type' => array( + 'description' => 'The date format type, e.g. medium.', + 'type' => 'varchar', + 'length' => 200, + 'not null' => TRUE, + ), + 'locked' => array( + 'description' => 'Whether or not this format can be modified.', + 'type' => 'int', + 'size' => 'tiny', + 'default' => 0, + 'not null' => TRUE, + ), + ), + 'primary key' => array('dfid'), + 'unique keys' => array('formats' => array('format', 'type')), + ); + + $schema['date_format_locale'] = array( + 'description' => 'For storing configured date formats for each locale.', + 'fields' => array( + 'format' => array( + 'description' => 'The date format string.', + 'type' => 'varchar', + 'length' => 100, + 'not null' => TRUE, + ), + 'type' => array( + 'description' => 'The date format type, e.g. medium.', + 'type' => 'varchar', + 'length' => 200, + 'not null' => TRUE, + ), + 'language' => array( + 'description' => 'A {languages}.language for this format to be used with.', + 'type' => 'varchar', + 'length' => 12, + 'not null' => TRUE, + ), + ), + 'primary key' => array('type', 'language'), + ); + $schema['file'] = array( 'description' => 'Stores information for uploaded files.', 'fields' => array( @@ -2469,6 +2553,103 @@ function system_update_7037() { } /** + * Create new date format tables. + */ +function system_update_7038() { + $ret = array(); + + $schema['date_format_types'] = array( + 'description' => 'For storing configured date format types.', + 'fields' => array( + 'type' => array( + 'description' => 'The date format type, e.g. medium.', + 'type' => 'varchar', + 'length' => 200, + 'not null' => TRUE, + ), + 'title' => array( + 'description' => 'The human readable name of the format type.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ), + 'locked' => array( + 'description' => 'Whether or not this is a system provided format.', + 'type' => 'int', + 'size' => 'tiny', + 'default' => 0, + 'not null' => TRUE, + ), + ), + 'primary key' => array('type'), + ); + + $schema['date_formats'] = array( + 'description' => 'For storing configured date formats.', + 'fields' => array( + 'dfid' => array( + 'description' => 'The date format identifier.', + 'type' => 'serial', + 'not null' => TRUE, + 'unsigned' => TRUE, + ), + 'format' => array( + 'description' => 'The date format string.', + 'type' => 'varchar', + 'length' => 100, + 'not null' => TRUE, + ), + 'type' => array( + 'description' => 'The date format type, e.g. medium.', + 'type' => 'varchar', + 'length' => 200, + 'not null' => TRUE, + ), + 'locked' => array( + 'description' => 'Whether or not this format can be modified.', + 'type' => 'int', + 'size' => 'tiny', + 'default' => 0, + 'not null' => TRUE, + ), + ), + 'primary key' => array('dfid'), + 'unique keys' => array('formats' => array('format', 'type')), + ); + + $schema['date_format_locale'] = array( + 'description' => 'For storing configured date formats for each locale.', + 'fields' => array( + 'format' => array( + 'description' => 'The date format string.', + 'type' => 'varchar', + 'length' => 100, + 'not null' => TRUE, + ), + 'type' => array( + 'description' => 'The date format type, e.g. medium.', + 'type' => 'varchar', + 'length' => 200, + 'not null' => TRUE, + ), + 'language' => array( + 'description' => 'A {languages}.language for this format to be used with.', + 'type' => 'varchar', + 'length' => 12, + 'not null' => TRUE, + ), + ), + 'primary key' => array('type', 'language'), + ); + + db_create_table($ret, 'date_format_types', $schema['date_format_types']); + db_create_table($ret, 'date_formats', $schema['date_formats']); + db_create_table($ret, 'date_format_locale', $schema['date_format_locale']); + + return $ret; +} + +/** * @} End of "defgroup updates-6.x-to-7.x" * The next series of updates should start at 8000. */ Index: modules/system/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.module,v retrieving revision 1.785 diff -u -p -r1.785 system.module --- modules/system/system.module 5 Sep 2009 15:05:04 -0000 1.785 +++ modules/system/system.module 5 Sep 2009 15:21:50 -0000 @@ -809,6 +809,8 @@ function system_menu() { 'access arguments' => array('administer site configuration'), 'file' => 'system.admin.inc', ); + + // Regional and date settings. $items['admin/config/regional'] = array( 'title' => 'Regional and language', 'description' => 'Regional settings, localization and translation.', @@ -820,20 +822,87 @@ function system_menu() { ); $items['admin/config/regional/settings'] = array( 'title' => 'Regional settings', - 'description' => "Settings for how Drupal displays date and time, as well as the system's default time zone.", + 'description' => "Settings for the site's default time zone and country settings.", 'page callback' => 'drupal_get_form', 'page arguments' => array('system_regional_settings'), 'access arguments' => array('administer site configuration'), 'weight' => -10, 'file' => 'system.admin.inc', ); - $items['admin/config/regional/settings/lookup'] = array( + $items['admin/config/regional/date-time'] = array( + 'title' => 'Date and time', + 'description' => "Configure display formats for date and time.", + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_date_time_settings'), + 'access arguments' => array('administer site configuration'), + 'weight' => -9, + 'file' => 'system.admin.inc', + ); + $items['admin/config/regional/date-time/types'] = array( + 'title' => 'Types', + 'description' => "Configure display formats for date and time.", + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_date_time_settings'), + 'access arguments' => array('administer site configuration'), + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -10, + 'file' => 'system.admin.inc', + ); + $items['admin/config/regional/date-time/types/add'] = array( + 'title' => 'Add date type', + 'description' => "Add new date type.", + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_add_date_format_type_form'), + 'access arguments' => array('administer site configuration'), + 'type' => MENU_LOCAL_ACTION, + 'weight' => -10, + 'file' => 'system.admin.inc', + ); + $items['admin/config/regional/date-time/types/delete/%'] = array( + 'title' => 'Delete date type', + 'description' => 'Allow users to delete a configured date type.', + 'type' => MENU_CALLBACK, + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_delete_date_format_type_form', 6), + 'access arguments' => array('administer site configuration'), + 'file' => 'system.admin.inc', + ); + $items['admin/config/regional/date-time/formats'] = array( + 'title' => 'Formats', + 'description' => "Configure display format strings for date and time.", + 'page callback' => 'system_date_time_formats', + 'access arguments' => array('administer site configuration'), + 'type' => MENU_LOCAL_TASK, + 'weight' => -9, + 'file' => 'system.admin.inc', + ); + $items['admin/config/regional/date-time/formats/add'] = array( + 'title' => 'Add format', + 'description' => 'Allow users to add additional date formats.', + 'type' => MENU_LOCAL_ACTION, + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_add_date_formats_form'), + 'access arguments' => array('administer site configuration'), + 'weight' => -10, + 'file' => 'system.admin.inc', + ); + $items['admin/config/regional/date-time/formats/delete/%'] = array( + 'title' => 'Delete date format', + 'description' => 'Allow users to delete a configured date format.', + 'type' => MENU_CALLBACK, + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_date_delete_format_form', 6), + 'access arguments' => array('administer site configuration'), + 'file' => 'system.admin.inc', + ); + $items['admin/config/regional/date-time/formats/lookup'] = array( 'title' => 'Date and time lookup', 'type' => MENU_CALLBACK, 'page callback' => 'system_date_time_lookup', 'access arguments' => array('administer site configuration'), 'file' => 'system.admin.inc', ); + $items['admin/config/search'] = array( 'title' => 'Search and metadata', 'description' => 'Local site search, metadata and SEO.', @@ -2427,6 +2496,9 @@ function system_cron() { foreach ($cache_tables as $table) { cache_clear_all(NULL, $table); } + + // Rebuild list of date formats. + system_date_formats_rebuild(); // Reset expired items in the default queue implementation table. If that's // not used, this will simply be a no-op. @@ -3194,3 +3266,141 @@ function theme_system_run_cron_image($im return ''; } +/** + * Get the list of available date types and attributes. + * + * @param $type + * The date type, e.g. 'short', 'medium', 'long', 'custom'. If empty, then + * all attributes for that type will be returned. + * @param $reset + * Whether or not to reset this function's internal cache (defaults to FALSE). + * @return + * Array of date types. + */ +function system_get_date_types($type = NULL, $reset = FALSE) { + static $_date_format_types; + + if ($reset || !isset($_date_format_types)) { + include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'system') . '/' . 'system.date.inc'; + $_date_format_types = _system_date_format_types_build(); + } + + return $type ? (isset($_date_format_types[$type]) ? $_date_format_types[$type] : FALSE) : $_date_format_types; +} + +/** + * Implements hook_date_format_types(). + */ +function system_date_format_types() { + return array( + 'long' => t('Long'), + 'medium' => t('Medium'), + 'short' => t('Short'), + ); +} + +/** + * Implements hook_date_formats(). + * + * @return + * An array of date formats with attributes 'type' (short, medium or long), + * 'format' (the format string) and 'locales'. The 'locales' attribute is an + * array of locales, which can include both 2 character language codes like + * 'en', 'fr', but also 5 character language codes like 'en-gb' and 'en-us'. + */ +function system_date_formats() { + include_once DRUPAL_ROOT . '/includes/date_formats.inc'; + return system_default_date_formats(); +} + +/** + * Get the list of date formats for a particular format length. + * + * @param $type + * The date type: 'short', 'medium', 'long', 'custom'. If empty, then all + * available types will be returned. + * @param $reset + * Whether or not to reset this function's internal cache (defaults to FALSE). + * @return + * Array of date formats. + */ +function system_get_date_formats($type = NULL, $reset = FALSE) { + static $_date_formats; + + if ($reset || !isset($_date_formats)) { + include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'system') . '/' . 'system.date.inc'; + $_date_formats = _system_date_formats_build(); + } + + return $type ? (isset($_date_formats[$type]) ? $_date_formats[$type] : FALSE) : $_date_formats; +} + +/** + * Get the format details for a particular id. + * + * @param $dfid + * Identifier of a date format string. + * @return + * Array of date format details. + */ +function system_get_date_format($dfid) { + $format = db_query('SELECT df.dfid, df.format, df.type, df.locked FROM {date_formats} df WHERE df.dfid = :dfid', array(':dfid' => $dfid))->fetch(); + return $format; +} + +/** + * Resets the database cache of date formats, and saves all new date formats to + * the database. + */ +function system_date_formats_rebuild() { + include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'system') . '/' . 'system.date.inc'; + $date_formats = system_get_date_formats(NULL, TRUE); + + foreach ($date_formats as $format_type => $formats) { + foreach ($formats as $format => $info) { + system_date_format_save($info); + } + } + + // Rebuild configured date formats locale list. + system_date_format_locale(NULL, NULL, TRUE); + + _system_date_formats_build(); +} + +/** + * Get the appropriate date format for a type and locale. + * + * @param $langcode + * Language code for the current locale. This can be a 2 character language + * code like 'en', 'fr', or a longer 5 character code like 'en-gb'. + * @param $type + * Date type: short, medium, long, custom. + * @param $reset + * Whether or not to reset this function's internal cache (defaults to FALSE). + * @return + * The format string, or NULL if no matching format found. + */ +function system_date_format_locale($langcode = NULL, $type = NULL, $reset = FALSE) { + static $formats; + + if ($reset || empty($formats)) { + $formats = array(); + $result = db_query("SELECT format, type, language FROM {date_format_locale}"); + foreach ($result as $record) { + if (!isset($formats[$record->language])) { + $formats[$record->language] = array(); + } + $formats[$record->language][$record->type] = $record->format; + } + } + + if ($type && $langcode && !empty($formats[$langcode][$type])) { + return $formats[$langcode][$type]; + } + elseif ($langcode && !empty($formats[$langcode])) { + return $formats[$langcode]; + } + + return FALSE; +}