views_data_export.theme.inc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. <?php
  2. /**
  3. * @file
  4. * Theme related functions for processing our output style plugins.
  5. *
  6. * Views bug: http://drupal.org/node/593336
  7. */
  8. /**
  9. * Theme a status message
  10. */
  11. function theme_views_data_export_message($var) {
  12. $output = '';
  13. $output .= '<div class="messages status ' . $var['type'] . '">';
  14. $output .= $var['message'];
  15. $output .= '</div>';
  16. return $output;
  17. }
  18. /**
  19. * Theme a feed link.
  20. *
  21. * This theme function uses the theme pattern system to allow it to be
  22. * overidden in a more specific manner. The options for overiding this include
  23. * providing per display id; per type; per display id and per type.
  24. *
  25. * e.g.
  26. * For the view "export_test" with the display "page_1" and the type "csv" you
  27. * would have the following options.
  28. * views_data_export_feed_icon__export_test__page_1__csv
  29. * views_data_export_feed_icon__export_test__page_1
  30. * views_data_export_feed_icon__export_test__csv
  31. * views_data_export_feed_icon__page_1__csv
  32. * views_data_export_feed_icon__page_1
  33. * views_data_export_feed_icon__csv
  34. * views_data_export_feed_icon
  35. *
  36. * @ingroup themeable
  37. */
  38. function theme_views_data_export_feed_icon($variables) {
  39. extract($variables, EXTR_SKIP);
  40. $url_options = array('html' => TRUE);
  41. if ($query) {
  42. $url_options['query'] = $query;
  43. }
  44. $image = theme('image', array('path' => $image_path, 'alt' => $text, 'title' => $text));
  45. return l($image, $url, $url_options);
  46. }
  47. /**
  48. * Theme callback for the export complete page.
  49. *
  50. * @param $file
  51. * Link to output file
  52. */
  53. function theme_views_data_export_complete_page($variables) {
  54. extract($variables, EXTR_SKIP);
  55. drupal_set_title(t('Data export successful'));
  56. drupal_add_html_head(array('#tag' => 'meta', '#attributes' => array('http-equiv' =>"Refresh", 'content' => '3;url='. $file)), 'views_data_export_download');
  57. $output = '';
  58. $output .= '<p>';
  59. $output .= t('Your export has been created. View/download the file <a href="@link">here</a> (will automatically download in 3 seconds.)', array('@link' => $file));
  60. $output .= '</p>';
  61. if (!empty($return_url)) {
  62. $output .= '<p>';
  63. $output .= l(t('Return to previous page'), $return_url);
  64. $output .= '</p>';
  65. }
  66. return $output;
  67. }
  68. function template_preprocess_views_data_export(&$vars) {
  69. $vars['header'] = $vars['rows']['header'];
  70. $vars['body'] = $vars['rows']['body'];
  71. $vars['footer'] = $vars['rows']['footer'];
  72. $view = $vars['view'];
  73. $fields = &$view->field;
  74. }
  75. function template_preprocess_views_data_export_csv_header(&$vars) {
  76. _views_data_export_header_shared_preprocess($vars);
  77. // Make sure we catch saved options that are misspelled. LEGACY
  78. if (isset($vars['options']['seperator'])) {
  79. $vars['options']['separator'] = $vars['options']['seperator'];
  80. }
  81. // Support old misspelled templates. LEGACY
  82. $vars['seperator'] =
  83. $vars['separator'] = $vars['options']['separator'];
  84. // Special handling when quoted values are involved.
  85. if ($vars['options']['quote']) {
  86. $wrap = '"';
  87. $replace_value = '""';
  88. }
  89. else {
  90. $wrap = '';
  91. $replace_value = '';
  92. }
  93. // Format header values.
  94. foreach ($vars['header'] as $key => $value) {
  95. $output = decode_entities($value);
  96. $output = (empty($vars['options']['keep_html'])) ? strip_tags($output) : $output;
  97. if (!empty($vars['options']['trim'])) {
  98. $output = trim($output);
  99. }
  100. if (!empty($vars['options']['encoding']) && function_exists('iconv')) {
  101. switch($vars['options']['encoding']) {
  102. case 'utf8_decode':
  103. $converted = utf8_decode($output);
  104. break;
  105. default:
  106. $converted = iconv("UTF-8", $vars['options']['encoding'], $output);
  107. break;
  108. }
  109. if ($converted !== FALSE) {
  110. $output = $converted;
  111. }
  112. }
  113. $vars['header'][$key] = $wrap . str_replace('"', $replace_value, $output) . $wrap;
  114. }
  115. }
  116. function template_preprocess_views_data_export_csv_body(&$vars) {
  117. _views_data_export_body_shared_preprocess($vars);
  118. // Make sure we catch saved options that are misspelled. LEGACY
  119. if (isset($vars['options']['seperator'])) {
  120. $vars['options']['separator'] = $vars['options']['seperator'];
  121. }
  122. // Support old misspelled templates. LEGACY
  123. $vars['seperator'] =
  124. $vars['separator'] = $vars['options']['separator'];
  125. // Special handling when quoted values are involved.
  126. if ($vars['options']['quote']) {
  127. $wrap = '"';
  128. $replace_value = '""';
  129. }
  130. else {
  131. $wrap = '';
  132. $replace_value = '';
  133. }
  134. // Format row values.
  135. foreach ($vars['themed_rows'] as $i => $values) {
  136. foreach ($values as $j => $value) {
  137. $output = decode_entities($value);
  138. $output = (empty($vars['options']['keep_html'])) ? strip_tags($output) : $output;
  139. if (!empty($vars['options']['trim'])) {
  140. $output = trim($output);
  141. }
  142. if (!empty($vars['options']['encoding']) && function_exists('iconv')) {
  143. switch($vars['options']['encoding']) {
  144. case 'utf8_decode':
  145. $converted = utf8_decode($output);
  146. break;
  147. default:
  148. $converted = iconv("UTF-8", $vars['options']['encoding'], $output);
  149. break;
  150. }
  151. if ($converted !== FALSE) {
  152. $output = $converted;
  153. }
  154. }
  155. if (!empty($vars['options']['replace_newlines'])) {
  156. if (!empty($vars['options']['newline_token'])) {
  157. $output = str_replace( array("\r\n", "\r", "\n"), $vars['options']['newline_replacement'], $output);
  158. }
  159. else {
  160. $output = str_replace("\n", $vars['options']['newline_replacement'], $output);
  161. }
  162. }
  163. $vars['themed_rows'][$i][$j] = $wrap . str_replace('"', $replace_value, $output) . $wrap;
  164. }
  165. }
  166. }
  167. /**
  168. * Preprocess csv output template.
  169. */
  170. function template_preprocess_views_data_export_csv(&$vars) {
  171. // TODO Replace items with themed_rows.
  172. _views_data_export_shared_preprocess($vars);
  173. // Make sure we catch saved options that are misspelled. LEGACY
  174. if (isset($vars['options']['separator'])) {
  175. $vars['options']['separator'] = $vars['options']['seperator'];
  176. }
  177. // Support old misspelled templates. LEGACY
  178. $vars['seperator'] =
  179. $vars['separator'] = $vars['options']['separator'];
  180. // Special handling when quoted values are involved.
  181. if ($vars['options']['quote']) {
  182. $wrap = '"';
  183. $replace_value = '""';
  184. }
  185. else {
  186. $wrap = '';
  187. $replace_value = '';
  188. }
  189. // Format header values.
  190. foreach ($vars['header'] as $key => $value) {
  191. $output = decode_entities(strip_tags($value));
  192. if ($vars['options']['trim']) {
  193. $output = trim($output);
  194. }
  195. if (!empty($vars['options']['encoding']) && function_exists('iconv')) {
  196. switch($vars['options']['encoding']) {
  197. case 'ASCII':
  198. $converted = iconv("UTF-8", "ASCII//TRANSLIT", $output);
  199. if ($converted !== FALSE) {
  200. $output = $converted;
  201. }
  202. break;
  203. }
  204. }
  205. $vars['header'][$key] = $wrap . str_replace('"', $replace_value, $output) . $wrap;
  206. }
  207. // Format row values.
  208. foreach ($vars['themed_rows'] as $i => $values) {
  209. foreach ($values as $j => $value) {
  210. $output = decode_entities(strip_tags($value));
  211. if ($vars['options']['trim']) {
  212. $output = trim($output);
  213. }
  214. if (!empty($vars['options']['encoding']) && function_exists('iconv')) {
  215. switch($vars['options']['encoding']) {
  216. case 'ASCII':
  217. $converted = iconv("UTF-8", "ASCII//TRANSLIT", $output);
  218. if ($converted !== FALSE) {
  219. $output = $converted;
  220. }
  221. break;
  222. }
  223. }
  224. $vars['themed_rows'][$i][$j] = $wrap . str_replace('"', $replace_value, $output) . $wrap;
  225. }
  226. }
  227. }
  228. /**
  229. * Preprocess txt output template.
  230. */
  231. function template_preprocess_views_data_export_txt_body(&$vars) {
  232. _views_data_export_header_shared_preprocess($vars);
  233. // We support not outputting fields when they are empty, so indicate so.
  234. $vars['hide_empty_support'] = TRUE;
  235. _views_data_export_body_shared_preprocess($vars);
  236. }
  237. /**
  238. * Implements hook_preprocess_views_data_export_doc_body().
  239. */
  240. function template_preprocess_views_data_export_doc_body(&$vars) {
  241. // Pass through the generic MS Office preprocess.
  242. template_preprocess_views_data_export_msoffice_body($vars);
  243. }
  244. /**
  245. * Implements hook_preprocess_views_data_export_xls_body().
  246. */
  247. function template_preprocess_views_data_export_xls_body(&$vars) {
  248. // Pass through the generic MS Office preprocess.
  249. template_preprocess_views_data_export_msoffice_body($vars);
  250. }
  251. function template_preprocess_views_data_export_msoffice_body(&$vars) {
  252. _views_data_export_header_shared_preprocess($vars);
  253. _views_data_export_body_shared_preprocess($vars);
  254. }
  255. /**
  256. * Implements hook_process_views_data_export_doc_body().
  257. */
  258. function template_process_views_data_export_doc_body(&$vars) {
  259. // Pass through the generic MS Office process.
  260. template_process_views_data_export_msoffice_body($vars);
  261. }
  262. /**
  263. * Implements hook_process_views_data_export_xls_body().
  264. */
  265. function template_process_views_data_export_xls_body(&$vars) {
  266. // Pass through the generic MS Office process.
  267. template_process_views_data_export_msoffice_body($vars);
  268. }
  269. function template_process_views_data_export_msoffice_body(&$vars) {
  270. $output = '';
  271. // Construct the tbody of a table, see theme_table().
  272. $ts = tablesort_init($vars['header']);
  273. $flip = array(
  274. 'even' => 'odd',
  275. 'odd' => 'even',
  276. );
  277. $class = 'even';
  278. foreach ($vars['themed_rows'] as $number => $row) {
  279. $attributes = array();
  280. // Check if we're dealing with a simple or complex row
  281. if (isset($row['data'])) {
  282. foreach ($row as $key => $value) {
  283. if ($key == 'data') {
  284. $cells = $value;
  285. }
  286. else {
  287. $attributes[$key] = $value;
  288. }
  289. }
  290. }
  291. else {
  292. $cells = $row;
  293. }
  294. if (count($cells)) {
  295. // Add odd/even class
  296. $class = $flip[$class];
  297. if (isset($attributes['class'])) {
  298. $attributes['class'] .= ' ' . $class;
  299. }
  300. else {
  301. $attributes['class'] = $class;
  302. }
  303. // Build row
  304. $output .= ' <tr' . drupal_attributes($attributes) . '>';
  305. $i = 0;
  306. foreach ($cells as $cell) {
  307. $cell = tablesort_cell($cell, $vars['header'], $ts, $i++);
  308. $output .= _theme_table_cell($cell);
  309. }
  310. $output .= " </tr>\n";
  311. }
  312. }
  313. $vars['tbody'] = preg_replace('/<\/?(a|span) ?.*?>/', '', $output); // strip 'a' and 'span' tags
  314. }
  315. function template_preprocess_views_data_export_doc_header(&$vars) {
  316. // Pass through the generic MS Office preprocess.
  317. template_preprocess_views_data_export_msoffice_header($vars);
  318. }
  319. function template_preprocess_views_data_export_xls_header(&$vars) {
  320. // Pass through the generic MS Office preprocess.
  321. template_preprocess_views_data_export_msoffice_header($vars);
  322. }
  323. function template_preprocess_views_data_export_msoffice_header(&$vars) {
  324. _views_data_export_header_shared_preprocess($vars);
  325. // Need to do a little work to construct the table header, see theme_table().
  326. $vars['header_row'] = '';
  327. $vars['header_row'] .= '<thead><tr>';
  328. $ts = tablesort_init($vars['header']);
  329. foreach ($vars['header'] as $cell) {
  330. $cell = tablesort_header($cell, $vars['header'], $ts);
  331. $vars['header_row'] .= _theme_table_cell($cell, TRUE);
  332. }
  333. $vars['header_row'] .= '</tr></thead>';
  334. $vars['header_row'] = preg_replace('/<\/?(a|span) ?.*?>/', '', $vars['header_row']); // strip 'a' and 'span' tags
  335. }
  336. /**
  337. * Preprocess xml output template.
  338. */
  339. function template_preprocess_views_data_export_xml_header(&$vars) {
  340. $vars['root_node'] = _views_data_export_xml_tag_clean($vars['options']['root_node']);
  341. }
  342. /**
  343. * Preprocess xml output template.
  344. */
  345. function template_preprocess_views_data_export_xml_footer(&$vars) {
  346. $vars['root_node'] = _views_data_export_xml_tag_clean($vars['options']['root_node']);
  347. }
  348. /**
  349. * Preprocess xml output template.
  350. */
  351. function template_preprocess_views_data_export_xml_body(&$vars) {
  352. _views_data_export_header_shared_preprocess($vars);
  353. // We support not outputting fields when they are empty, so indicate so.
  354. $vars['hide_empty_support'] = TRUE;
  355. _views_data_export_body_shared_preprocess($vars);
  356. $view = $vars['view'];
  357. $style_options = $view->display_handler->get_option('style_options');
  358. $no_encode = isset($style_options['no_entity_encode']) ? $style_options['no_entity_encode'] : array();
  359. $cdata_wrapper = isset($style_options['cdata_wrapper']) ? $style_options['cdata_wrapper'] : array();
  360. $vars['item_node'] = _views_data_export_xml_tag_clean($vars['options']['item_node']);
  361. foreach ($vars['themed_rows'] as $num => $row) {
  362. foreach ($row as $field => $content) {
  363. // Perform xml entity encoding unless excluded by style options.
  364. if (empty($no_encode[$field]) && empty($cdata_wrapper[$field])) {
  365. // Prevent double encoding of the ampersand. Look for the entities produced by check_plain().
  366. $content = preg_replace('/&(?!(amp|quot|#039|lt|gt);)/', '&amp;', $content);
  367. // Convert < and > to HTML entities.
  368. $content = str_replace(
  369. array('<', '>'),
  370. array('&lt;', '&gt;'),
  371. $content);
  372. }
  373. // Perform wrapping the field data using the CDATA tag
  374. // unless excluded by style options.
  375. if (!empty($cdata_wrapper[$field])) {
  376. // Escape CDATA end sequence only.
  377. $content = '<![CDATA[' . str_replace(']]>', ']]]]><![CDATA[>', $content) . ']]>';
  378. }
  379. $vars['themed_rows'][$num][$field] = $content;
  380. }
  381. }
  382. foreach ($vars['header'] as $field => $header) {
  383. // If there is no field label, use 'no name'.
  384. if (empty($header)) {
  385. $header = 'no name';
  386. }
  387. if ($vars['options']['transform']) {
  388. switch ($vars['options']['transform_type']) {
  389. case 'dash':
  390. $vars['xml_tag'][$field] = str_replace(' ', '-', $header);
  391. break;
  392. case 'underline':
  393. $vars['xml_tag'][$field] = str_replace(' ', '_', $header);
  394. break;
  395. case 'camel':
  396. $vars['xml_tag'][$field] = str_replace(' ', '', ucwords(strtolower($header)));
  397. // Convert the very first character of the string to lowercase.
  398. $vars['xml_tag'][$field][0] = strtolower($vars['xml_tag'][$field][0]);
  399. break;
  400. case 'pascal':
  401. $vars['xml_tag'][$field] = str_replace(' ', '', ucwords(strtolower($header)));
  402. break;
  403. }
  404. }
  405. // We should always try to output valid XML.
  406. $vars['xml_tag'][$field] = _views_data_export_xml_tag_clean($vars['xml_tag'][$field]);
  407. }
  408. }
  409. /**
  410. * Returns a valid XML tag formed from the given input.
  411. *
  412. * @param $tag The string that should be made into a valid XML tag.
  413. * @return The valid XML tag or an empty string if the string contained no valid
  414. * XML tag characters.
  415. */
  416. function _views_data_export_xml_tag_clean($tag) {
  417. // This regex matches characters that are not valid in XML tags, and the
  418. // unicode ones that are. We don't bother with unicode, because it would so
  419. // the preg_replace down a lot.
  420. static $invalid_tag_chars_regex = '#[^\:A-Za-z_\-.0-9]+#';
  421. // These characters are not valid at the start of an XML tag:
  422. static $invalid_start_chars = '-.0123456789';
  423. // Convert invalid chars to '-':
  424. $tag = preg_replace($invalid_tag_chars_regex, '-', $tag);
  425. // Need to trim invalid characters from the start of the string:
  426. $tag = ltrim($tag, $invalid_start_chars);
  427. // As a last line of defense, if we've stripped out everything, set it to
  428. // something.
  429. if (empty($tag)) {
  430. $tag = 'invalid-tag-name';
  431. }
  432. return $tag;
  433. }
  434. /**
  435. * Shared helper function for export preprocess functions.
  436. */
  437. function _views_data_export_header_shared_preprocess(&$vars) {
  438. $view = $vars['view'];
  439. $fields = &$view->field;
  440. $fields_info = $view->display_handler->get_option('fields');
  441. $vars['header'] = array();
  442. foreach ($fields as $key => $field) {
  443. if (empty($field->options['exclude'])) {
  444. if (isset($fields_info) && isset($fields_info[$key]['label'])) {
  445. $vars['header'][$key] = check_plain($fields_info[$key]['label']);
  446. }
  447. else {
  448. $vars['header'][$key] = check_plain($field->label());
  449. }
  450. }
  451. }
  452. }
  453. /**
  454. * Shared helper function for export preprocess functions.
  455. */
  456. function _views_data_export_body_shared_preprocess(&$vars) {
  457. $view = $vars['view'];
  458. $fields = &$view->field;
  459. $hide_empty_support = !empty($vars['hide_empty_support']);
  460. $rows = $vars['rows'];
  461. $vars['themed_rows'] = array();
  462. $keys = array_keys($fields);
  463. foreach ($rows as $num => $row) {
  464. $vars['themed_rows'][$num] = array();
  465. foreach ($keys as $id) {
  466. if (empty($fields[$id]->options['exclude'])) {
  467. $content = $view->style_plugin->rendered_fields[$num][$id];
  468. if ($hide_empty_support && !empty($fields[$id]->options['hide_empty'])) {
  469. if ($fields[$id]->is_value_empty($content, $fields[$id]->options['empty_zero'])) {
  470. continue;
  471. }
  472. }
  473. $vars['themed_rows'][$num][$id] = $content;
  474. }
  475. }
  476. }
  477. }