date.theme 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. <?php
  2. /**
  3. * @file
  4. * Theme functions.
  5. */
  6. /**
  7. * @addtogroup themeable
  8. * @{
  9. *
  10. * Formatter themes
  11. */
  12. /**
  13. * Returns HTML for a date element formatted as a Start/End combination.
  14. *
  15. * $entity->date_id
  16. * If set, this will show only an individual date on a field with
  17. * multiple dates. The value should be a string that contains
  18. * the following values, separated with periods:
  19. * - module name of the module adding the item
  20. * - node nid
  21. * - field name
  22. * - delta value of the field to be displayed
  23. * - other information the module's custom theme might need
  24. *
  25. * Used by the calendar module and available for other uses.
  26. * example: 'date.217.field_date.3.test'
  27. *
  28. * $entity->date_repeat_show
  29. * If true, tells the theme to show all the computed values of a repeating
  30. * date. If not true or not set, only the start date and the repeat rule
  31. * will be displayed.
  32. *
  33. * $dates['format']
  34. * The format string used on these dates
  35. * $dates['value']['local']['object']
  36. * The local date object for the Start date
  37. * $dates['value2']['local']['object']
  38. * The local date object for the End date
  39. * $dates['value']['local']['datetime']
  40. * The datetime value of the Start date database (GMT) value
  41. * $dates['value2']['local']['datetime']
  42. * The datetime value of the End date database (GMT) value
  43. * $dates['value']['formatted']
  44. * Formatted Start date, i.e. 'February 15, 2007 2:00 pm';
  45. * $dates['value']['formatted_date']
  46. * Only the date part of the formatted Start date
  47. * $dates['value']['formatted_time']
  48. * Only the time part of the formatted Start date
  49. * $dates['value2']['formatted']
  50. * Formatted End date, i.e. 'February 15, 2007 6:00 pm';
  51. * $dates['value2']['formatted_date']
  52. * Only the date part of the formatted End date
  53. * $dates['value2']['formatted_time']
  54. * Only the time part of the formatted End date
  55. */
  56. function theme_date_display_combination($variables) {
  57. static $repeating_ids = array();
  58. $entity_type = $variables['entity_type'];
  59. $entity = $variables['entity'];
  60. $field = $variables['field'];
  61. $instance = $variables['instance'];
  62. $langcode = $variables['langcode'];
  63. $item = $variables['item'];
  64. $delta = $variables['delta'];
  65. $display = $variables['display'];
  66. $field_name = $field['field_name'];
  67. $formatter = $display['type'];
  68. $options = $display['settings'];
  69. $dates = $variables['dates'];
  70. $attributes = $variables['attributes'];
  71. $rdf_mapping = $variables['rdf_mapping'];
  72. $add_rdf = $variables['add_rdf'];
  73. $microdata = $variables['microdata'];
  74. $add_microdata = $variables['add_microdata'];
  75. $precision = date_granularity_precision($field['settings']['granularity']);
  76. $show_remaining_days = $variables['show_remaining_days'];
  77. $output = '';
  78. // If date_id is set for this field and delta doesn't match, don't display it.
  79. if (!empty($entity->date_id)) {
  80. foreach ((array) $entity->date_id as $key => $id) {
  81. list($module, $nid, $field_name, $item_delta, $other) = explode('.', $id . '.');
  82. if ($field_name == $field['field_name'] && isset($delta) && $item_delta != $delta) {
  83. return $output;
  84. }
  85. }
  86. }
  87. // Check the formatter settings to see if the repeat rule should be displayed.
  88. // Show it only with the first multiple value date.
  89. list($id) = entity_extract_ids($entity_type, $entity);
  90. if (!in_array($id, $repeating_ids) && module_exists('date_repeat_field') && !empty($item['rrule']) && $options['show_repeat_rule'] == 'show') {
  91. $repeat_vars = array(
  92. 'field' => $field,
  93. 'item' => $item,
  94. 'entity_type' => $entity_type,
  95. 'entity' => $entity,
  96. );
  97. $output .= theme('date_repeat_display', $repeat_vars);
  98. $repeating_ids[] = $id;
  99. }
  100. // If this is a full node or a pseudo node created by grouping multiple
  101. // values, see exactly which values are supposed to be visible.
  102. if (isset($entity->$field_name)) {
  103. $entity = date_prepare_entity($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display);
  104. // Did the current value get removed by formatter settings?
  105. if (empty($entity->{$field_name}[$langcode][$delta])) {
  106. return $output;
  107. }
  108. // Adjust the $element values to match the changes.
  109. $element['#entity'] = $entity;
  110. }
  111. switch ($options['fromto']) {
  112. case 'value':
  113. $date1 = $dates['value']['formatted'];
  114. $date2 = $date1;
  115. break;
  116. case 'value2':
  117. $date2 = $dates['value2']['formatted'];
  118. $date1 = $date2;
  119. break;
  120. default:
  121. $date1 = $dates['value']['formatted'];
  122. $date2 = $dates['value2']['formatted'];
  123. break;
  124. }
  125. // Pull the timezone, if any, out of the formatted result and tack it back on
  126. // at the end, if it is in the current formatted date.
  127. $timezone = $dates['value']['formatted_timezone'];
  128. if ($timezone) {
  129. $timezone = ' ' . $timezone;
  130. }
  131. $date1 = str_replace($timezone, '', $date1);
  132. $date2 = str_replace($timezone, '', $date2);
  133. $time1 = preg_replace('`^([\(\[])`', '', $dates['value']['formatted_time']);
  134. $time1 = preg_replace('([\)\]]$)', '', $time1);
  135. $time2 = preg_replace('`^([\(\[])`', '', $dates['value2']['formatted_time']);
  136. $time2 = preg_replace('([\)\]]$)', '', $time2);
  137. // A date with a granularity of 'hour' has a time string that is an integer
  138. // value. We can't use that to replace time strings in formatted dates.
  139. $has_time_string = date_has_time($field['settings']['granularity']);
  140. if ($precision == 'hour') {
  141. $has_time_string = FALSE;
  142. }
  143. // Check remaining days.
  144. $show_remaining_days = '';
  145. if (!empty($variables['show_remaining_days'])) {
  146. $remaining_days = floor((strtotime($variables['dates']['value']['formatted_iso'])
  147. - strtotime('now')) / (24 * 3600));
  148. // Show remaining days only for future events.
  149. if ($remaining_days >= 0) {
  150. $show_remaining_days = theme('date_display_remaining', array(
  151. 'remaining_days' => $remaining_days,
  152. ));
  153. }
  154. }
  155. // No date values, display nothing.
  156. if (empty($date1) && empty($date2)) {
  157. $output .= '';
  158. }
  159. // Start and End dates match or there is no End date, display a complete
  160. // single date.
  161. elseif ($date1 == $date2 || empty($date2)) {
  162. $output .= theme('date_display_single', array(
  163. 'date' => $date1,
  164. 'timezone' => $timezone,
  165. 'attributes' => $attributes,
  166. 'rdf_mapping' => $rdf_mapping,
  167. 'add_rdf' => $add_rdf,
  168. 'microdata' => $microdata,
  169. 'add_microdata' => $add_microdata,
  170. 'dates' => $dates,
  171. 'show_remaining_days' => $show_remaining_days,
  172. ));
  173. }
  174. // Same day, different times, don't repeat the date but show both Start and
  175. // End times. We can NOT do this if the replacement value is an integer
  176. // instead of a time string.
  177. elseif ($has_time_string && $dates['value']['formatted_date'] == $dates['value2']['formatted_date']) {
  178. // Replace the original time with the start/end time in the formatted start
  179. // date. Make sure that parentheses or brackets wrapping the time will be
  180. // retained in the final result.
  181. $time = theme('date_display_range', array(
  182. 'date1' => $time1,
  183. 'date2' => $time2,
  184. 'timezone' => $timezone,
  185. 'attributes' => $attributes,
  186. 'rdf_mapping' => $rdf_mapping,
  187. 'add_rdf' => $add_rdf,
  188. 'microdata' => $microdata,
  189. 'add_microdata' => $add_microdata,
  190. 'dates' => $dates,
  191. 'show_remaining_days' => $show_remaining_days,
  192. ));
  193. $replaced = str_replace($time1, $time, $date1);
  194. $output .= theme('date_display_single', array(
  195. 'date' => $replaced,
  196. 'timezone' => $timezone,
  197. 'attributes' => array(),
  198. 'rdf_mapping' => array(),
  199. 'add_rdf' => FALSE,
  200. 'dates' => $dates,
  201. ));
  202. }
  203. // Different days, display both in their entirety.
  204. else {
  205. $output .= theme('date_display_range', array(
  206. 'date1' => $date1,
  207. 'date2' => $date2,
  208. 'timezone' => $timezone,
  209. 'attributes' => $attributes,
  210. 'rdf_mapping' => $rdf_mapping,
  211. 'add_rdf' => $add_rdf,
  212. 'microdata' => $microdata,
  213. 'add_microdata' => $add_microdata,
  214. 'dates' => $dates,
  215. 'show_remaining_days' => $show_remaining_days,
  216. ));
  217. }
  218. return $output;
  219. }
  220. /**
  221. * Template preprocess function for displaying a single date.
  222. */
  223. function template_preprocess_date_display_single(&$variables) {
  224. if ($variables['add_rdf'] || !empty($variables['add_microdata'])) {
  225. // Pass along the rdf mapping for this field, if any. Add some default rdf
  226. // attributes that will be used if not overridden by attributes passed in.
  227. $rdf_mapping = $variables['rdf_mapping'];
  228. $base_attributes = array(
  229. 'property' => array('dc:date'),
  230. 'datatype' => 'xsd:dateTime',
  231. 'content' => $variables['dates']['value']['formatted_iso'],
  232. );
  233. $variables['attributes'] = $variables['attributes'] + $base_attributes;
  234. }
  235. // Pass along microdata attributes, or set display to false if none are set.
  236. if (!empty($variables['add_microdata'])) {
  237. // Because the Entity API integration for Date has a variable data
  238. // structure depending on whether there is an end value, the attributes
  239. // could be attached to the field or to the value property.
  240. if (!empty($variables['microdata']['#attributes']['itemprop'])) {
  241. $variables['microdata']['value']['#attributes'] = $variables['microdata']['#attributes'];
  242. }
  243. // Add the machine readable time using the content attribute.
  244. if (!empty($variables['microdata']['value']['#attributes'])) {
  245. $variables['microdata']['value']['#attributes']['content'] = $variables['dates']['value']['formatted_iso'];
  246. }
  247. else {
  248. $variables['add_microdata'] = FALSE;
  249. }
  250. }
  251. }
  252. /**
  253. * Returns HTML for a date element formatted as a single date.
  254. */
  255. function theme_date_display_single($variables) {
  256. $date = $variables['date'];
  257. $timezone = $variables['timezone'];
  258. $attributes = $variables['attributes'];
  259. $show_remaining_days = isset($variables['show_remaining_days']) ? $variables['show_remaining_days'] : '';
  260. // Wrap the result with the attributes.
  261. $output = '<span class="date-display-single"' . drupal_attributes($attributes) . '>' . $date . $timezone . '</span>';
  262. if (!empty($variables['add_microdata'])) {
  263. $output .= '<meta' . drupal_attributes($variables['microdata']['value']['#attributes']) . '/>';
  264. }
  265. // Add remaining message and return.
  266. return $output . $show_remaining_days;
  267. }
  268. /**
  269. * Template preprocess function for displaying a range of dates.
  270. */
  271. function template_preprocess_date_display_range(&$variables) {
  272. // Merge in the shared attributes for themes to use.
  273. $variables['attributes_start'] += $variables['attributes'];
  274. $variables['attributes_end'] += $variables['attributes'];
  275. if ($variables['add_rdf']) {
  276. // Pass along the rdf mapping for this field, if any. Add some default rdf
  277. // attributes that will be used if not overridden by attributes passed in.
  278. $dates = $variables['dates'];
  279. $base_attributes = array(
  280. 'property' => array('dc:date'),
  281. 'datatype' => 'xsd:dateTime',
  282. 'content' => $dates['value']['formatted_iso'],
  283. );
  284. $variables['attributes_start'] += $base_attributes;
  285. $variables['attributes_end'] += $base_attributes;
  286. $variables['attributes_end']['content'] = $dates['value2']['formatted_iso'];
  287. foreach ($variables['attributes_end']['property'] as $delta => $property) {
  288. $variables['attributes_end']['property'][$delta] = str_replace('start', 'end', $property);
  289. }
  290. }
  291. // Pass along microdata attributes, or set display to false if none are set.
  292. if ($variables['add_microdata']) {
  293. if (!empty($variables['microdata']['value']['#attributes'])) {
  294. $variables['microdata']['value']['#attributes']['content'] = $variables['dates']['value']['formatted_iso'];
  295. $variables['microdata']['value2']['#attributes']['content'] = $variables['dates']['value2']['formatted_iso'];
  296. }
  297. else {
  298. $variables['add_microdata'] = FALSE;
  299. }
  300. }
  301. }
  302. /**
  303. * Returns HTML for a date element formatted as a range.
  304. */
  305. function theme_date_display_range($variables) {
  306. $date1 = $variables['date1'];
  307. $date2 = $variables['date2'];
  308. $timezone = $variables['timezone'];
  309. $attributes_start = $variables['attributes_start'];
  310. $attributes_end = $variables['attributes_end'];
  311. $show_remaining_days = $variables['show_remaining_days'];
  312. $start_date = '<span class="date-display-start"' . drupal_attributes($attributes_start) . '>' . $date1 . '</span>';
  313. $end_date = '<span class="date-display-end"' . drupal_attributes($attributes_end) . '>' . $date2 . $timezone . '</span>';
  314. // If microdata attributes for the start date property have been passed in,
  315. // add the microdata in meta tags.
  316. if (!empty($variables['add_microdata'])) {
  317. $start_date .= '<meta' . drupal_attributes($variables['microdata']['value']['#attributes']) . '/>';
  318. $end_date .= '<meta' . drupal_attributes($variables['microdata']['value2']['#attributes']) . '/>';
  319. }
  320. // Wrap the result with the attributes.
  321. $output = '<span class="date-display-range">' . t('!start-date to !end-date', array(
  322. '!start-date' => $start_date,
  323. '!end-date' => $end_date,
  324. )) . '</span>';
  325. // Add remaining message and return.
  326. return $output . $show_remaining_days;
  327. }
  328. /**
  329. * Returns HTML for a date element formatted as an interval.
  330. */
  331. function theme_date_display_interval($variables) {
  332. $entity = $variables['entity'];
  333. $options = $variables['display']['settings'];
  334. $dates = $variables['dates'];
  335. $attributes = $variables['attributes'];
  336. // Get the formatter settings, either the default settings for this node type
  337. // or the View settings stored in $entity->date_info.
  338. if (!empty($entity->date_info) && !empty($entity->date_info->formatter_settings)) {
  339. $options = $entity->date_info->formatter_settings;
  340. }
  341. $time_ago_vars = array(
  342. 'start_date' => $dates['value']['local']['object'],
  343. 'end_date' => $dates['value2']['local']['object'],
  344. 'interval' => $options['interval'],
  345. 'interval_display' => $options['interval_display'],
  346. 'use_end_date' => !empty($options['use_end_date']) ?
  347. $options['use_end_date'] : FALSE,
  348. );
  349. if ($return = theme('date_time_ago', $time_ago_vars)) {
  350. return '<span class="date-display-interval"' . drupal_attributes($attributes) . ">$return</span>";
  351. }
  352. else {
  353. return '';
  354. }
  355. }
  356. /**
  357. * Returns HTML for a start/end date combination on form.
  358. */
  359. function theme_date_combo($variables) {
  360. $element = $variables['element'];
  361. $field = field_info_field($element['#field_name']);
  362. $instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
  363. // Group start/end items together in fieldset.
  364. $fieldset = array(
  365. '#title' => field_filter_xss(t($element['#title'])) . ($element['#delta'] > 0 ? ' ' . intval($element['#delta'] + 1) : ''),
  366. '#value' => '',
  367. '#description' => !empty($element['#description']) ? $element['#description'] : '',
  368. '#attributes' => array('class' => array('date-combo')),
  369. '#children' => $element['#children'],
  370. );
  371. // Add marker to required date fields.
  372. if ($element['#required']) {
  373. $fieldset['#title'] .= " " . theme('form_required_marker');
  374. }
  375. return theme('fieldset', array('element' => $fieldset));
  376. }
  377. /**
  378. * Returns HTML for the text/select options for date parts in a table.
  379. */
  380. function theme_date_text_parts($variables) {
  381. $element = $variables['element'];
  382. $rows = array();
  383. foreach (date_granularity_names() as $key => $part) {
  384. if ($element[$key]['#type'] == 'hidden') {
  385. $rows[] = drupal_render($element[$key]);
  386. }
  387. else {
  388. $rows[] = array(
  389. $part,
  390. drupal_render($element[$key][0]),
  391. drupal_render($element[$key][1]),
  392. );
  393. }
  394. }
  395. if ($element['year']['#type'] == 'hidden') {
  396. return implode($rows) . drupal_render_children($element);
  397. }
  398. else {
  399. $header = array(t('Date part'), t('Select list'), t('Text field'));
  400. return theme('table', array('header' => $header, 'rows' => $rows)) . drupal_render_children($element);
  401. }
  402. }
  403. /**
  404. * Render a date combo as a form element.
  405. */
  406. function theme_date_form_element($variables) {
  407. $element = &$variables['element'];
  408. // Detect whether element is multiline.
  409. $count = preg_match_all('`<(?:div|span)\b[^>]* class="[^"]*\b(?:date-no-float|date-clear)\b`', $element['#children'], $matches, PREG_OFFSET_CAPTURE);
  410. $multiline = FALSE;
  411. if ($count > 1) {
  412. $multiline = TRUE;
  413. }
  414. elseif ($count) {
  415. $before = substr($element['#children'], 0, $matches[0][0][1]);
  416. if (preg_match('`<(?:div|span)\b[^>]* class="[^"]*\bdate-float\b`', $before)) {
  417. $multiline = TRUE;
  418. }
  419. }
  420. // Detect if there is more than one subfield.
  421. $count = count(explode('<label', $element['#children'])) - 1;
  422. if ($count == 1) {
  423. $element['#title_display'] = 'none';
  424. }
  425. // Wrap children with a div and add an extra class if element is multiline.
  426. $element['#children'] = '<div class="date-form-element-content'. ($multiline ? ' date-form-element-content-multiline' : '') .'">'. $element['#children'] .'</div>';
  427. return theme('form_element', $variables);
  428. }
  429. /**
  430. * Returns HTML for remaining message.
  431. */
  432. function theme_date_display_remaining($variables) {
  433. $remaining_days = $variables['remaining_days'];
  434. $output = '';
  435. $show_remaining_text = t('The upcoming date less then 1 day.');
  436. if ($remaining_days) {
  437. $show_remaining_text = format_plural($remaining_days, 'To event remaining 1 day', 'To event remaining @count days');
  438. }
  439. return '<div class="date-display-remaining"><span class="date-display-remaining">' . $show_remaining_text . '</span></div>';
  440. }
  441. /** @} End of addtogroup themeable */